Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ERC-1067 (ERC extension) #1067

Closed
techracers-blockchain opened this issue May 8, 2018 · 6 comments
Closed

ERC-1067 (ERC extension) #1067

techracers-blockchain opened this issue May 8, 2018 · 6 comments
Labels

Comments

@techracers-blockchain
Copy link

techracers-blockchain commented May 8, 2018

ERC: 1067
Title: Token standard
Author: Techracers
Status: Draft
Type: ERC
Created: 5-08.2018
Recommended implementation: https://github.com/techracers-blockchain/ERC-1067

Abstract

Token contract usually have a monolithic design that is not friendly to upgrades. The following proposal describes a more distributed token contract architecture that has a simple upgrade-ability protocol and allows to bring in new functions after being deployed.

Motivation

There have been countless number of tokens where due to the inability to upgrade and fix bugs, contract holders have lost millions of dollars. A simple bug that might take days, months, or years to solve, can be solved simply and quickly using the ERC-1067 standard.

There exist approaches that includes an upgrade agent, which has its own limitations and restrictions and sometimes might not lead to a successful upgrade implementation. It has to include all token holders, and might cost a lot.

If there is a simple bug that was left out during the deployment of a token contract, it might result in the loss of millions of dollars. There have been a number of token contracts owners, who have come to us after the token sale with bugs that have no workaround but to cost a lot of time and money. If instead, we had an upgrade-ability protocol that allows rapid fast upgrades at low cost, such accidents can be rectified.

This will allow contracts to pause and handle bugs and allow them to fix bugs or upgrade the ERC standard to a newer one.
This standard has the ability to be cross compatible with any other monolithic ERC interface like the ERC20, ERC223, ERC721, ERC827 etc.

Specification

The following Upgradeable Token approach requires

  • a DataCentre contract that has a few sets of getter setter methods that allows us to keep the data at a separate location
  • that the token contract interacts with, reads and writes all the data into the DataCentre.

Methods

All of the ERC20 functions remain the same in essence. We interact with the DataCentre and write all the data into our DataCentre.

All the calls fetch data from the DataCentre, the supporting DataCentre function is written below each call-

totalSupply
Token-

function totalSupply() public constant returns (uint256) {
	return DataCentre(dataCentreAddr).getValue("STK", "totalSupply");
}

DataCentre-

function getValue(bytes32 _container, bytes32 _key) public {
	containers[_container].values[_key] = _value;
}

balanceOf(address)

Get the account balance of another account with address _owner

Token-

function balanceOf(address _owner) public constant returns (uint256) {
	return DataCentre(dataCentreAddr).getBalanace("STK", _owner);
}

DataCentre-

function getBalance(bytes32 _container, address _key) public constant returns(uint256) {
	return containers[_container].balances[_key];
}

transfer(address, uint)
Token-

function transfer(address to, uint value) public returns (bool) {
	require(_to != address(this));
	require(_to != address(0));
	require(_amount > 0);
	_setBalanceOf(_from, balanceOf(_from).sub(_amount));
	_setBalanceOf(_to, balanceOf(_to).add(_amount));
	Transfer(_from, _to, _amount);
	return true;
}

Internal Function-

function _setBalanceOf(address _owner, uint256 _newValue) internal {
        DataCentre(dataCentreAddr).setBalanace("STK", _owner, _newValue);
}

DataCentre-

function setBalance(bytes32 _container, address _key, uint256 _value) public onlyOwner {
	containers[_container].balances[_key] = _value;
}

The owner of the DataCentre contract is always the Token contract.

Upgradeability Protocol

The token contract has some simple measures through which an upgrade can be made in just 2 transactions-

  1. Deploy new token contract
  2. Kill the old token contract.

The kill function looks like below-


function kill(address _newTokenContract) public onlyOwner {
	if (dataCentreAddr != address(0)) {
		Ownable(dataCentreAddr).transferOwnership(_newTokenContract);
	}
	selfdestruct(_newTokenContract);
}

Recommended implementation

This is highly recommended implementation of ERC-1067 token:
https://github.com/techracers-blockchain/ERC-1067

@techracers-blockchain techracers-blockchain changed the title ERC (ERC20 extension) ERC-1067 (ERC extension) May 8, 2018
@LucasAschenbach
Copy link

LucasAschenbach commented May 10, 2018

I just developed a token with this particular structure and it works seamlessly for updates - totally recommend it!

However, we would have to add, aside from the getters and setters inside the DataCentre (I called it Storage) a Communicator contract, storing all contract addresses which may access the setters, provided by the Storage contract, to make sure that the variables cannot be manipulated by unknown sources.

pragma solidity ^0.4.21;

import "./Owned.sol";


contract Communicator is Owned {

    mapping(bytes32 => address) public communicatorContract;

    event CommunicatorContractAdded(address indexed addedCommunicatorContract);
    event CommunicatorContractRemoved(address indexed oldCommunicatorContract);



    modifier communicatorContractOnly {
        require(communicatorContract[keccak256(msg.sender)] != 0x0);
        _;
    }

    modifier communicatorOrOwner {
        require(communicatorContract[keccak256(msg.sender)] != 0x0 || msg.sender == contractOwner);
        _;
    }

    function addCommunicatorContract(address _newCommunicatorContract) external communicatorOrOwner {
        communicatorContract[keccak256(_newCommunicatorContract)] = _newCommunicatorContract;
        emit CommunicatorContractAdded(_newCommunicatorContract);
    }

    function removeCommunicatorContract(address _oldCommunicatorContract) external communicatorOrOwner {
        communicatorContract[keccak256(_oldCommunicatorContract)] = 0x0;
        emit CommunicatorContractRemoved(_oldCommunicatorContract);
    }
}

Furthermore, every contract, listed as a communicatorContract would need to inherit a Linked contract, providing the underlying contract with the address of the Storage contract and implementing the functionality of the owner contract, inherited by Storage.

pragma solidity ^0.4.21;

import "./Storage.sol";


contract Linked {

    Storage public core;

    constructor(address _storageContract) public {
        core = Storage(_storageContract);
    }

    modifier contractOwnerOnly {
        address contractOwner = core.contractOwner();
        require(contractOwner == msg.sender);
        _;
    }
}

Yet, this would really put the trust of the token users to test as the contract owner could now arbitrarily change the entire smart contract structure and potentially render the token overnight worthless.
To prevent this from happening, this structure requires another contract to which, immediately after deployment, the ownership of the Storage contract is transferred to. This contract would feature a shareholder structure so that the number of shares, one address owns, is directly proportional to the number of votes it gets to vote for update/withdraw/... proposals.
The map, storing the number of shares would then also be stored inside the storage contract and if the shareholders would want to alter the contract, they could vote to transfer the ownership to a different contract and, subsequently, terminate this one.

@techracers-blockchain
Copy link
Author

Thanks a lot for sharing your views on this token architecture, Lucas!
Coming back to your suggestions, all of which are really good ones, we believe that those can be add-ones rather than build them right into the interface.

  • The Communicator contract would be a requirement if we want multiple contracts to interact with our DataCentre. For a simple ERC20 like token architecture, I think just 1 owner should more than suffice the requirements. I would definitely use that in case we have multiple token contracts using the same Data Centre.

  • Similarly, the Linked contract spawns out of our Communicator contract addition and would be something that we would like to omit.

  • The 3rd suggestion is something we have already thought about because a voting mechanism would more than help token stakeholders to reach a consensus on the upgrade process. But it has its own loopholes and that is why we didn't want to build it right into the interface. The major problems are-

    1. Majority of tokens with founders.
    2. Token holders might keep transferring tokens to different addresses and continue voting, which is unidentifiable with non-fungible tokens.
    3. In order to circumvent 2, we might have to build in a transfer lock mechanism so that multiple votes cannot come through using the same tokens, but it will simply make the interface heavier and people might not like locking down their tokens.

I think the proposal more than provides a very standard interface and protocols on which other methods and add-ones can be implemented.

@LucasAschenbach
Copy link

Thank you for the feedback on my suggestions and especially for the issues you raised about the shareholder contract!

I just have one more remark I would like to share, regarding my first and second suggestion. Seeing as the sole purpose of this contract structure lies in providing updatability, it can safely be implied that its adapters will want to actually update their contract from time to time. However, in this case, every update would require the contract owner to delete the entire 'functions contract', add changes as desired, and then deploy the contract again on the blockchain. In most cases, though, the contract owner will probably merely add new functions to the contract and, still, will not just have to pay for deploying the added functions but also all the other functions which have been previously contained by the contract. When talking about a very basic token, these additional costs may be noticeable but not earth-shattering. However, with more complex tokens, this will create substantial additional costs for updates.

If new functions, on the other hand, would be added in a new contract, the update costs would be reduced significantly. Therefore, I think, the Communicator contract would in fact provide a true upside for this structure, regardless of whether there are multiple tokens stored in the DataCentre or just one.

@guylando
Copy link

  1. Seems there is no reason for investors to trust a token implementing this concept since the token code can change at any moment (I believe a pause+migrate method has more trust and security ERC 644: Token Standard for Modular and Upgradeable Tokens  #644 (comment)).
  2. Also seems as a duplicate of ERC 644: Token Standard for Modular and Upgradeable Tokens  #644 (more specifically: ERC 644: Token Standard for Modular and Upgradeable Tokens  #644 (comment)) in the sense that eip 644 is a draft so maybe instead of two drafts with the same goal they could be merged into one which could be moved to final.
  3. It is a best practice security wise usually to not interact with economically sensitive contract which contains selfdestruct.

@github-actions
Copy link

github-actions bot commented Dec 6, 2021

There has been no activity on this issue for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review.

@github-actions github-actions bot added the stale label Dec 6, 2021
@github-actions
Copy link

This issue was closed due to inactivity. If you are still pursuing it, feel free to reopen it and respond to any feedback or request a review in a comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants