A familiar contract address does not necessarily mean a meme token still runs the code you reviewed last week. In a proxy deployment, users keep interacting with one address while the implementation supplying its behavior can change. The useful question is not merely whether the token has an owner. It is which route can replace the implementation, who controls that route and what evidence establishes its state at a particular block.
This is a read-only investigation method, not a finding about any named token. Upgradeability can support repairs and product changes; its existence alone does not establish deception or a rug pull. Conversely, an unchanged ticker, address or verified-source badge is not evidence that the upgrade route has disappeared.
Separate the address from the implementation
OpenZeppelin's proxy-pattern explanation describes two contracts with different jobs. The proxy is the address users call. The implementation supplies code executed through delegation in the proxy's context, including its storage. An upgrade can redirect that delegation to another implementation without moving users to a new token address.
For a hypothetical meme token called SOUP, imagine that yesterday's implementation permitted ordinary transfers. A later implementation could contain different transfer conditions. That is an illustrative possibility, not evidence that a particular issuer has made such a change. The point is that yesterday's code review describes yesterday's implementation; it cannot automatically describe a replacement nobody has inspected.
Save both addresses. If an explorer offers “Read as Proxy,” distinguish calls through the proxy from calls directly to the implementation. The latter can expose a different storage context and produce misleading conclusions about the deployed token's permissions.
Find the route before naming the controller
ERC-1967 specifies storage locations for implementation, beacon and optional admin addresses. These are useful starting points for compatible deployments, not a universal detector for every custom proxy.
| Deployment pattern | Where the upgrade investigation leads |
|---|---|
| Transparent proxy | The proxy's administrative route and the controller of its ProxyAdmin, if used. |
| UUPS proxy | The implementation's upgrade function and its authorization logic. |
| Beacon proxy | The referenced beacon, its current implementation and its upgrade controller. |
The distinction is practical. In OpenZeppelin's pinned v5.4.0 transparent-proxy source, construction creates a ProxyAdmin with an initial owner. The proxy also stores its operative admin as an immutable value. Its own comments warn that implementation code could overwrite the ERC-1967 admin slot, leaving the displayed slot different from the actual admin. Reading that slot alone is therefore not a complete control check.
In the pinned UUPS source, upgradeToAndCall invokes _authorizeUpgrade. The base contract leaves that authorization function for the implementation to define. You must read the override, not assume that every UUPS deployment uses a single owner.
The pinned UpgradeableBeacon source restricts its upgrade function to the beacon's owner. Several proxies can rely on that beacon. Checking one token's visible owner while ignoring the beacon misses the shared replacement route.
These examples establish library behavior at the cited version. A deployed contract may use another version, modified code or a different design.
Make the observation block-specific
Ethereum's JSON-RPC documentation gives eth_getStorageAt, eth_getCode and eth_call a block parameter. Use a consistent block when reading the proxy's slots, resolving the implementation and checking the controller. Otherwise, an upgrade between requests can leave your notes describing a combination that never existed together.
Record the network, block number, proxy address, implementation address, code and authorization route. An unavailable historical response is an evidence gap, not proof that the old implementation had no upgrade power. Keep provider errors distinct from an actual returned value.
For an ERC-1967 beacon arrangement, resolve the beacon's implementation() at the same observation block. An empty implementation slot can be expected when the beacon route supplies the logic; it does not by itself establish immutability.
Follow authority beyond the first address
OpenZeppelin's FAQ distinguishes the ProxyAdmin owner from the implementation contract. Its access-control API also documents roles and their administrators. A role authorized to upgrade can have a separate account capable of granting or revoking it.
Follow that chain. If the controller is another contract, inspect its authorization rather than treating “contract-controlled” as a safety verdict. If it is described as a multisignature or timelock, obtain the actual configuration and executable rules before repeating those labels. An address does not identify a person, and several signer addresses do not automatically establish independent human decision-makers.
This goes beyond our lesson on what contract renunciation leaves unresolved. Here the object is the replacement-code route itself, not the fairness of the original token distribution.
Treat an upgrade event as the beginning of review
ERC-1967 recommends events for implementation, beacon and admin-slot changes. Such events help locate transitions, but the standard's recommendation is not a guarantee that every custom deployment emits a complete history. Compare events with the relevant state and transaction evidence.
An upgrade event identifies a change to investigate; it does not certify the new code. OpenZeppelin's FAQ discusses storage compatibility as an upgrade requirement. Compatibility checks address whether existing state is preserved correctly, not whether the replacement's economic rules are desirable for holders.
For a suspected incident, preserve the before-and-after implementation, control configuration and exact upgrade transaction before attributing effects. Our five-layer receipt guide explains why successful execution is narrower than safety. The holder-attribution lesson explains why controller addresses cannot settle identities. More foundations are in Learn.
The strongest short conclusion is bounded: at a stated block, a documented controller could invoke a documented replacement route. That is useful evidence. It is neither a promise of future behavior nor proof that the controller has abused the power.
Sources and artwork
This educational article uses standards, official documentation and pinned library source reviewed October 14, 2026. SOUP is hypothetical. No live token was scanned, no wallet was connected and no transaction was sent for this lesson. The method is not a complete security audit.
The cover reproduces the Ethereum Foundation's actual 2014 logo under CC BY 3.0. Its geometry and colors were retained inside a decorative composition, then rendered as responsive WebP files. It is not a token-specific logo, deployment screenshot or endorsement.
