This proposal outlines a smart contract interface for upgrading/downgrading existing ERC-20 smart contracts while maintaining user balances. The interface itself is an extension to the ERC-20 standard so that other smart contracts can continue to interact with the upgraded smart contract without changing anything other than the address.
Motivation
By design, smart contracts are immutable and token standards like ERC-20 are minimalistic. While these design principles are fundamental in decentalized applications, there are sensible and practical situations where the ability to upgrade an ERC-20 token is desirable, such as:
to address bugs and remove limitations
to adopt new features and standards
to comply w/ changing regulations
Proxy pattern using delegatecall opcode offers a reasonable, generalized solution to reconcile the immutability and upgradability features but has its own shortcomings:
the smart contracts must support proxy pattern from the get go, i.e. it cannot be used on contracts that were not deployed with proxies
upgrades are silent and irreversible, i.e. users do not have the option to opt-out
In contrast, by reducing the scope to specifically ERC-20 tokens, this proposal standardizes an ERC-20 extension that works with any existing or future ERC-20 smart contracts, is much simpler to implement and to maintain, can be reversed or nested, and offers a double confirmation opportunity for any and all users to explicitly opt-in on the upgrade.
ERC-4931 attepts to address the same problem by introducing a third “bridge” contract to help facilitate the upgrade/downgrade operations. While this design decouples upgrade/downgrade logic from token logic, ERC-4931 would require tokens to be pre-minted at the destination smart contract and owned by the bridge contrtact rather then just-in-time when upgrade is invoked. It also would not be able to support upgrade-while-transfer and see-through functions as described below.
Specification
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119 and RFC 8174.
pragmasolidity^0.8.0;/**
@title Upgradable Fungible Token
@dev See https://eips.ethereum.org/EIPS/eip-6864
*/interfaceIERC6864isIERC20{/**
@dev MUST be emitted when tokens are upgraded
@param from Previous owner of base ERC-20 tokens
@param to New owner of ERC-6864 tokens
@param amount The amount that is upgraded
*/eventUpgrade(addressindexedfrom,addressindexedto,uint256amount);/**
@dev MUST be emitted when tokens are downgraded
@param from Previous owner of ERC-6864 tokens
@param to New owner of base ERC-20 tokens
@param amount The amount that is downgraded
*/eventDowngrade(addressindexedfrom,addressindexedto,uint256amount);/**
@notice Upgrade `amount` of base ERC-20 tokens owned by `msg.sender` to ERC-6864 tokens under `to`
@dev `msg.sender` must directly own sufficient base ERC-20 tokens
MUST revert if `to` is the zero address
MUST revert if `msg.sender` does not directly own `amount` or more of base ERC-20 tokens
@param to The address to receive ERC-6864 tokens
@param amount The amount of base ERC-20 tokens to upgrade
*/functionupgrade(addressto,uint256amount)external;/**
@notice Downgrade `amount` of ERC-6864 tokens owned by `from` to base ERC-20 tokens under `to`
@dev `msg.sender` must either directly own or be approved to spend sufficient ERC-6864 tokens for `from`
MUST revert if `to` is the zero address
MUST revert if `from` does not directly own `amount` or more of ERC-6864 tokens
MUST revret if `msg.sender` is not `from` and is not approved to spend `amount` or more of ERC-6864 tokens for `from`
@param from The address to release ERC-6864 tokens
@param to The address to receive base ERC-20 tokens
@param amount The amount of ERC-6864 tokens to downgrade
*/functiondowngrade(addressfrom,addressto,uint256amount)external;/**
@notice Get the base ERC-20 smart contract address
@return The address of the base ERC-20 smart contract
*/functionbaseToken()externalviewreturns(address);}
See-through Extension
The see-through extension is OPTIONAL. It allows for easy viewing of combined states between this ERC-6864 and base ERC-20 smart contracts.
pragmasolidity^0.8.0;interfaceIERC6864SeeThroughisIERC6864{/**
@notice Get the combined total token supply between this ERC-6864 and base ERC-20 smart contracts
@return The combined total token supply
*/functioncombinedTotalSupply()externalviewreturns(uint256);/**
@notice Get the combined token balance of `account` between this ERC-6864 and base ERC-20 smart contracts
@param account The address that owns the tokens
@return The combined token balance
*/functioncombinedBalanceOf(addressaccount)externalviewreturns(uint256);/**
@notice Get the combined allowance that `spender` is allowed to spend for `owner` between this ERC-6864 and base ERC-20 smart contracts
@param owner The address that owns the tokens
@param spender The address that is approve to spend the tokens
@return The combined spending allowance
*/functioncombinedAllowance(addressowner,addressspender)externalviewreturns(uint256);}
Rationale
Extending ERC-20 standard
The goal of this proposal is to upgrade without affecting user balances, therefore leveraging existing data structure and methods is the path of the least engineering efforts as well as the most interoperability.
Supporting downgrade
The ability to downgrade makes moving between multiple IERC-6864 implementations on the same base ERC-20 smart contract possible. It also allows a way out should bugs or limitations discovered on ERC-6864 smart contract, or the user simply changes his or her mind.
Optional see-through extension
While these functions are useful in many situations, they are trivial to implement and results can be calculated via other public functions, hence the decision to include them in an optional extension rather than the core interface.
Backwards Compatibility
ERC-6864 is generally compatible with the ERC-20 standard. The only caveat is that some smart contracts may opt to implement transfer to work with the entire combined balance (this reduces user friction, see reference implementation) rather than the standard balanceOf amount. In this case it is RECOMMENDED that such contract to implement totalSupply and balanceOf to return combined amount between this ERC-6864 and base ERC-20 smart contracts
User who opts to upgrade base ERC-20 tokens must first approve the ERC-6864 smart contract to spend them. Therefore it’s the user’s responsibility to verify that the ERC-6864 smart contract is sound and secure, and the amount that he or she is approving is approperiate. This represents the same security considerations as with any approve operation.
The ERC-6864 smart contract may implement any conversion function for upgrade/downgrade as approperiate: 1-to-1, linear, non-linear. In the case of a non-linear conversion function, upgrade and downgrade may be vulnerable for front running or sandwich attacks (whether or not to the attacker’s benefit). This represents the same security considerations as with any automated market maker (AMM) that uses a similar non-linear curve for conversion.
The ERC-6864 smart contract may ask user to approve unlimited allowance and/or attempt to automatically upgrade during transfer (see reference implementation). This removes the chance for user to triple confirm his or her intension to upgrade (approve being the double confirmation).
Multiple IERC-6864 implementations can be applied to the same base ERC-20 token, and ERC-6864 smart contracts can be nested. This would increase token complexity and may cause existing dashboards to report incorrect or inconsistent results.