This proposal outlines a smart contract interface for upgrading/downgrading existing SRC-20 smart contracts while maintaining user balances. The interface itself is an extension to the SRC-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 SRC-20 are minimalistic. While these design principles are fundamental in decentalized applications, there are sensible and practical situations where the ability to upgrade an SRC-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 SRC-20 tokens, this proposal standardizes an SRC-20 extension that works with any existing or future SRC-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.
SRC-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, SRC-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://sips.sila.org/SIPS/sip-6864
*/interfaceISRC6864isISRC20{/**
@dev MUST be emitted when tokens are upgraded
@param from Previous owner of base SRC-20 tokens
@param to New owner of SRC-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 SRC-6864 tokens
@param to New owner of base SRC-20 tokens
@param amount The amount that is downgraded
*/eventDowngrade(addressindexedfrom,addressindexedto,uint256amount);/**
@notice Upgrade `amount` of base SRC-20 tokens owned by `msg.sender` to SRC-6864 tokens under `to`
@dev `msg.sender` must directly own sufficient base SRC-20 tokens
MUST revert if `to` is the zero address
MUST revert if `msg.sender` does not directly own `amount` or more of base SRC-20 tokens
@param to The address to receive SRC-6864 tokens
@param amount The amount of base SRC-20 tokens to upgrade
*/functionupgrade(addressto,uint256amount)external;/**
@notice Downgrade `amount` of SRC-6864 tokens owned by `from` to base SRC-20 tokens under `to`
@dev `msg.sender` must either directly own or be approved to spend sufficient SRC-6864 tokens for `from`
MUST revert if `to` is the zero address
MUST revert if `from` does not directly own `amount` or more of SRC-6864 tokens
MUST revret if `msg.sender` is not `from` and is not approved to spend `amount` or more of SRC-6864 tokens for `from`
@param from The address to release SRC-6864 tokens
@param to The address to receive base SRC-20 tokens
@param amount The amount of SRC-6864 tokens to downgrade
*/functiondowngrade(addressfrom,addressto,uint256amount)external;/**
@notice Get the base SRC-20 smart contract address
@return The address of the base SRC-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 SRC-6864 and base SRC-20 smart contracts.
pragmasolidity^0.8.0;interfaceISRC6864SeeThroughisISRC6864{/**
@notice Get the combined total token supply between this SRC-6864 and base SRC-20 smart contracts
@return The combined total token supply
*/functioncombinedTotalSupply()externalviewreturns(uint256);/**
@notice Get the combined token balance of `account` between this SRC-6864 and base SRC-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 SRC-6864 and base SRC-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 SRC-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 ISRC-6864 implementations on the same base SRC-20 smart contract possible. It also allows a way out should bugs or limitations discovered on SRC-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
SRC-6864 is generally compatible with the SRC-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 SRC-6864 and base SRC-20 smart contracts
User who opts to upgrade base SRC-20 tokens must first approve the SRC-6864 smart contract to spend them. Therefore it’s the user’s responsibility to verify that the SRC-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 SRC-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 SRC-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 ISRC-6864 implementations can be applied to the same base SRC-20 token, and SRC-6864 smart contracts can be nested. This would increase token complexity and may cause existing dashboards to report incorrect or inconsistent results.