You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The following document describes a proposal on how to migrate an existing ERC20 (#20) token to a rent compatible implementation of the ERC20 (#20) standard.
Motivation
The implementation of any rent mechanism in the Ethereum network (#35) (#87) (#88) (#755) (#1418) may open a griefing channel on almost all existing ERC20 tokens.
Most of the existing implementations relay on the main contract to store all balances and allowances, this can be exploited to bloat the contract storage, rendering the rent expensive or impossible to pay.
This proposal describes a process to migrate an ERC20 token to a new contract, invulnerable to such griefing.
Glossary
This document references to the Distributed implementation of ERC20 as ERC20D.
Implementation
There is no need to change the existing ERC20 interface; the problem can be solved by splitting each balance/allowance registry into its own storage space.
The CREATE2 opcode allows us to use contracts as storage slots, without using any of the parent contract storage.
Storage unit contract
This is a Solidity implementation of a storage contract, the deployer of the contract is the owner, and can write values to the storage.
The library is used to read and write storage units with a syntax similar to the native storage of Solidity.
libraryDistributedStorage {
// Returns true if _addr is not a contractfunction _isNotContract(address_addr) internalviewreturns (booli) {
assembly {
i :=iszero(extcodesize(_addr))
}
}
// Returns the address of a contract slot for a given _spacefunction _contractSlot(bytes32_space) privateviewreturns (address) {
returnaddress(
uint256(
keccak256(
abi.encodePacked(
byte(0xff),
address(this),
_space,
keccak256(type(StorageUnit).creationCode)
)
)
)
);
}
// Deploys the contract for the _space slotfunction _deploy(bytes32_space) private {
bytesmemory slotcode =type(StorageUnit).creationCode;
assembly{
pop(create2(0, add(slotcode, 0x20), mload(slotcode), _space))
}
}
// Writes a value using another contract storage// the contract used is determined by the _space value// the storage slot is determined by the _key valuefunction write(
bytes32_space,
bytes32_key,
bytes32_value
) internal {
address store =_contractSlot(_space);
// If the contract does not exist// deploy it before writing to the storageif (_isNotContract(store)) {
deploy(_struct);
}
StorageUnit(store).write(_key, _value);
}
// Reads a value from another contract storage// the contract used is determined by the _space value// the storage slot is determined by the _key valuefunction read(
bytes32_space,
bytes32_key
) internalviewreturns (bytes32) {
address store =_contractSlot(_space);
// If the contract does not exist// the readed value must be zeroif (_isNotContract(store)) {
returnbytes32(0x0);
}
returnStorageUnit(store).read(_key);
}
}
ERC20D Implementation
The ERC20 interface can be implemented using the DistributedStorage library.
Underflow and overflow checks must be added before using in production
Please note that the contracts above are an example only. It is not the standard.
Migration
The ERC20 to ERC20D migration should be performed in a progressive manner to avoid disruptions and loss of funds.
Migration interface
function origin() publicviewreturns (address);
function migrate(uint256_value) public;
function immigrate(uint256_value) public;
Origin
Returns the address of the original ERC20 token.
function origin() publicviewreturns (address);
Native migration methods
Total supply
At the beginning of the migration, the totalSupply of the origin ERC20 is minted to the address of the original ERC20 contract to maintain an equal total supply.
All subsequent migrations and immigrations are transferred from and to the origin ERC20 token.
constructor(ERC20_origin) public {
origin = _origin;
_mint(address(_origin), _origin.totalSupply());
}
Migrate
It pulls ERC20 tokens and mints the same amount in ERC20D tokens, it should revert on failure.
It burs ERC20D and transfers back the original ERC20 tokens, it should revert on failure.
function _immigrate(address_from, uint256_value) internal {
_transfer(_from, address(origin), _value);
require(origin.transfer(_from, _value));
emitImmigrated(_from, _value);
}
function immigrate(uint256_value) external {
_immigrate(msg.sender, _value);
}
Live swap migration
The following would allow transferring ERC20D without having to migrate the ERC20 tokens previously.
If the user approved the ERC20D contract on the original ERC20 contract, his balance on the origin ERC20 contract could also be accessed with the transfer and transferFrom functions of ERC20D.
Abstract
The following document describes a proposal on how to migrate an existing ERC20 (#20) token to a rent compatible implementation of the ERC20 (#20) standard.
Motivation
The implementation of any rent mechanism in the Ethereum network (#35) (#87) (#88) (#755) (#1418) may open a griefing channel on almost all existing ERC20 tokens.
Most of the existing implementations relay on the main contract to store all balances and allowances, this can be exploited to bloat the contract storage, rendering the rent expensive or impossible to pay.
This proposal describes a process to migrate an ERC20 token to a new contract, invulnerable to such griefing.
Glossary
This document references to the Distributed implementation of ERC20 as ERC20D.
Implementation
There is no need to change the existing ERC20 interface; the problem can be solved by splitting each balance/allowance registry into its own storage space.
The CREATE2 opcode allows us to use contracts as storage slots, without using any of the parent contract storage.
Storage unit contract
This is a Solidity implementation of a storage contract, the deployer of the contract is the owner, and can write values to the storage.
Library to read and write storage units
The library is used to read and write storage units with a syntax similar to the native storage of Solidity.
ERC20D Implementation
The ERC20 interface can be implemented using the DistributedStorage library.
Please note that the contracts above are an example only. It is not the standard.
Migration
The ERC20 to ERC20D migration should be performed in a progressive manner to avoid disruptions and loss of funds.
Migration interface
Origin
Returns the address of the original ERC20 token.
Native migration methods
Total supply
At the beginning of the migration, the totalSupply of the origin ERC20 is minted to the address of the original ERC20 contract to maintain an equal total supply.
All subsequent migrations and immigrations are transferred from and to the origin ERC20 token.
Migrate
It pulls ERC20 tokens and mints the same amount in ERC20D tokens, it should revert on failure.
Immigrate
It burs ERC20D and transfers back the original ERC20 tokens, it should revert on failure.
Live swap migration
The following would allow transferring ERC20D without having to migrate the ERC20 tokens previously.
If the user approved the ERC20D contract on the original ERC20 contract, his balance on the origin ERC20 contract could also be accessed with the transfer and transferFrom functions of ERC20D.
Events
Migrated
Triggered when tokens are migrated from ERC20 to ERC20D.
Immigrated
Triggered when tokens are migrated from ERC20D to ERC20.
LiveSwapMigrated
Triggered when tokens are migrated by a LiveSwap.
Backwards compatibility
The ERC20D is fully compliant with the ERC20 specification and can be treated as any other implementation.
The text was updated successfully, but these errors were encountered: