这篇文章上次修改于 499 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

    场景:eth的智能合约规定是发布后不可修改的,但是在实际场景中,由于业务的不断升级,需求不断变化,可能需要去修改合约已满足业务需要。

   思路:编写2个合约,一个合约用来保存数据,一份合约用来实现逻辑,当业务变化时,数据合约不用变,只需要用新的逻辑合约替换老的逻辑合约。

下面是我写的一个合约样例:

    pragma solidity ^0.4.18;
    /**
     * 数据合约
     *
     */
    contract KccData{
        mapping ( address => uint256 )  public balances;
        mapping (address => bool) accessAllowed;
        mapping ( address => uint8 )  public lockAccounts;

        uint256 public totalNum;
        address owner;
        uint8 public decimals = 18;

        function KccData( uint256 totalB ) public{
            totalNum    = totalB * 10 ** uint256(decimals);
            owner       = msg.sender;
            balances[owner] = totalNum;
            accessAllowed[owner] = true;
        }

        /*权限检查修饰符*/
        modifier platform() {
            require(accessAllowed[msg.sender] == true);
            _;
        }

        /*设置允许调用此合约的地址*/
        function allowAccess(address _addr) platform public {
            accessAllowed[_addr] = true;
        }

        /*设置不允许调用此合约的地址*/
        function denyAccess(address _addr) platform public {
            accessAllowed[_addr] = false;
        }

        /*增加代币*/
        function incr(address _addr, uint256 num) platform public returns (bool){
            require( num > 0 );
            balances[_addr] += num;
        }

        /*减少代币*/
        function decr(address _addr, uint256 num) platform public returns (bool){
            require( num > 0 );
            require( balances[_addr] >= num );
            balances[_addr] -= num;
        }

        /*冻结账户*/
        function freezeAccount(address _addr) platform public returns (bool){
            require( _addr != owner );
            lockAccounts[_addr] = 1;
            return true;
        }

        /*解冻账户*/
        function unfreezeAccount( address _addr ) platform public returns (bool){
            lockAccounts[_addr] = 0;
            return true;
        }

        /*增加总数量*/
        function incrTotalNum( uint256 num ) platform public returns (bool){
            totalNum += num;
            return true;
        }
    }


    /**
     * 逻辑合约
     *
     */
    contract Kcc{
        address owner;
        KccData dataContract;

        event SendEvent(address to, uint value, bool result);
        event Transfer(address indexed from, address indexed to, uint256 value, uint256 fees);

        /**
         * KccDataContractAddr 数据合约的合约地址
         * 部署完此逻辑合约后,需要调用数据合约的allowAccess 方法,将此逻辑合约的合约地址加入到数据合约的可调用白名单中
         *
         */
        function Kcc( address KccDataContractAddr ) public{
            dataContract = KccData(KccDataContractAddr);
            owner        = msg.sender;
        }

        /*向当前合约存款*/
        function deposit() payable public {
        }

        /*发送eth给地址to*/
        function sendEther(address to, uint value) public {
            require(msg.sender==owner);
            bool result = to.send(value);
            emit SendEvent(to, value, result);
        }

        /*增发代币*/
        function addTotalNum( uint256 addNum ) public returns (bool){
            require( addNum > 0 );
            require( msg.sender == owner );
            dataContract.incrTotalNum(addNum);
            dataContract.incr(owner, addNum);
            return true;
        }

        /*空投代币*/
        function issue( address to, uint256 num )public returns (bool){
            require( msg.sender == owner );
            require( num > 0 );
            require( num < dataContract.balances(owner) );
            require( dataContract.lockAccounts(to) != 1 );
            dataContract.incr(to,num);
            dataContract.decr(owner, num);
            emit Transfer(owner, to, num, 0);
        }

        /*转账,gas由个人[消息发送者]支付*/
        function transfer( address to, uint256 num )public returns (bool){
            _transfer( msg.sender, to, num, 0 );
            return true;
        }

        /*
         * 转账,gas由合约创建者支付 即平台支付
         * fees 平台收取的手续费
        */
        function p2pTrans( address from, address to, uint256 num, uint256 fees )  public returns (bool success) {
            require( msg.sender == owner );
            require( from != owner );
            require( to != owner );
            _transfer(from, to, num, fees);
            return true;
        }

        /*内部转账方法*/
        function _transfer(address _from, address _to, uint _value, uint _fees ) internal {
            require(_to != 0x0);
            require(dataContract.balances(_from) >= _value);
            require(dataContract.balances(_to) + _value >= dataContract.balances(_to));
            require(dataContract.lockAccounts(_from) != 1 );
            require(dataContract.lockAccounts(_to) != 1 );
            require(_fees >= 0);
            require(_value > _fees);
            dataContract.decr(_from, _value);
            dataContract.incr(_to, _value - _fees);
            if( _fees > 0 ){
                dataContract.incr(owner,_fees);
            }
            emit Transfer(_from, _to, _value, _fees);
        }

        /*获取指定账户代币余额*/
        function getBalance(address account) public constant returns (uint256) {
            return dataContract.balances(account);
        }

        /*冻结账户*/
        function freezeAccount(address account) public returns (bool){
            require( msg.sender == owner );
            require( account != owner );
            dataContract.freezeAccount( account );
            return true;
        }

        /*解冻账户*/
        function unfreezeAccount( address account ) public returns (bool){
            require( msg.sender == owner );
            dataContract.unfreezeAccount( account );
            return true;
        }

        /*检查某个账户是否被冻结*/
        function getAccountIsFreeze( address account ) public constant returns (uint8){
            uint8 r ;
            if( dataContract.lockAccounts(account) == 1 ){
                r = 1;
            }
            return r;
        }

        /*获取合约创建者的地址*/
        function getOwnerAddr() public constant returns (address) {
            return owner;
        }

        /*获取合约的总发行量*/
        function getTotalNum() public constant returns (uint256){
            return dataContract.totalNum();
        }

        /*获取合约剩余可用代币数量*/
        function getHasNum() public constant returns (uint256){
            return dataContract.balances(owner);
        }

    }