ETH Price: $2,026.43 (+0.10%)

Transaction Decoder

Block:
4007806 at Jul-11-2017 01:55:23 PM +UTC
Transaction Fee:
0.000331460000082865 ETH $0.67
Gas Used:
82,865 Gas / 4.000000001 Gwei

Emitted Events:

67 EventsHistory.0x940c4b3549ef0aaff95807dc27f62d88ca15532d1bf535d7d63800f40395d16c( 0x940c4b3549ef0aaff95807dc27f62d88ca15532d1bf535d7d63800f40395d16c, 0x0000000000000000000000005731fecb4d3ffab589e92762f731320b6d4bcde1, 0x0000000000000000000000006c6b8d1a209c28ddb989319d80578aea56a80a43, 0x504c425400000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000005f5e100, 0000000000000000000000000000000000000000000000000000000000000060, 0000000000000000000000000000000000000000000000000000000000000002, 0000000000000000000000000000000000000000000000000000000000000004, 7465737400000000000000000000000000000000000000000000000000000000 )
68 PolybiusToken.Transfer( from=[Sender] 0x5731fecb4d3ffab589e92762f731320b6d4bcde1, to=0x6C6B8d1A209C28DDB989319D80578aeA56A80a43, value=100000000 )
69 0x4b9e0d224dabcc96191cace2d367a8d8b75c9c81.0xae7443ddaf98d964198bed69ffecbbdeea67363d04c21a72f94bcb1a10fae229( 0xae7443ddaf98d964198bed69ffecbbdeea67363d04c21a72f94bcb1a10fae229, 0x000000000000000000000000468575ae349dea001f938727f87e65e9488f10f2, 0x0000000000000000000000005731fecb4d3ffab589e92762f731320b6d4bcde1, 0x7375625f4168664f316133537a56535851700000000000000000000000000000, 00000000000000000000000000000000000000000000000000012da767bf33e6, 0000000000000000000000000000000000000000000000000000000000000040, 0000000000000000000000000000000000000000000000000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
(ethfans.org)
1,593.835359790159975813 Eth1,593.835691250160058678 Eth0.000331460000082865
0x331d0775...84c411F84
0x4B9e0d22...8B75C9C81
30.063902871515815059 Eth30.063571199515732141 Eth0.000331672000082918
0x5731feCb...b6D4BcDE1
0.00089287800000081 Eth
Nonce: 2
0.000893090000000863 Eth
Nonce: 3
0.000000212000000053

Execution Trace

PolybiusToken.transferWithReference( _to=0x6C6B8d1A209C28DDB989319D80578aeA56A80a43, _value=100000000, _reference=test ) => ( True )
  • 0x468575ae349dea001f938727f87e65e9488f10f2.1962df71( )
    • PolybiusToken._forwardTransferFromWithReference( _from=0x5731feCb4D3FfAB589e92762F731320b6D4BcDE1, _to=0x6C6B8d1A209C28DDB989319D80578aeA56A80a43, _value=100000000, _reference=test, _sender=0x5731feCb4D3FfAB589e92762F731320b6D4BcDE1 ) => ( True )
      • EToken2.proxyTransferFromWithReference( _from=0x5731feCb4D3FfAB589e92762F731320b6D4BcDE1, _to=0x6C6B8d1A209C28DDB989319D80578aeA56A80a43, _value=100000000, _symbol=504C425400000000000000000000000000000000000000000000000000000000, _reference=test, _sender=0x5731feCb4D3FfAB589e92762F731320b6D4BcDE1 ) => ( True )
        • EventsHistory.515c1457( )
          • MultiAssetEmitter.emitTransfer( _from=0x5731feCb4D3FfAB589e92762F731320b6D4BcDE1, _to=0x6C6B8d1A209C28DDB989319D80578aeA56A80a43, _symbol=504C425400000000000000000000000000000000000000000000000000000000, _value=100000000, _reference=test )
            • EventsHistory.versions( 0x331d077518216c07C87f4f18bA64cd384c411F84 ) => ( 2 )
            • Null: 0x000...004.CALL( )
            • PolybiusToken.emitTransfer( _from=0x5731feCb4D3FfAB589e92762F731320b6D4BcDE1, _to=0x6C6B8d1A209C28DDB989319D80578aeA56A80a43, _value=100000000 )
            • 0x4b9e0d224dabcc96191cace2d367a8d8b75c9c81.f3fef3a3( )
              • ETH 0.000331672000082918 0x5731fecb4d3ffab589e92762f731320b6d4bcde1.CALL( )
              • Null: 0x000...004.CALL( )
                transferWithReference[PolybiusToken (ln:217)]
                File 1 of 4: PolybiusToken
                /**
                 * This software is a subject to Ambisafe License Agreement.
                 * No use or distribution is allowed without written permission from Ambisafe.
                 * https://www.ambisafe.co/terms-of-use/
                 */
                
                pragma solidity 0.4.8;
                
                contract EToken2 {
                    function baseUnit(bytes32 _symbol) constant returns(uint8);
                    function name(bytes32 _symbol) constant returns(string);
                    function description(bytes32 _symbol) constant returns(string);
                    function owner(bytes32 _symbol) constant returns(address);
                    function isOwner(address _owner, bytes32 _symbol) constant returns(bool);
                    function totalSupply(bytes32 _symbol) constant returns(uint);
                    function balanceOf(address _holder, bytes32 _symbol) constant returns(uint);
                    function proxyTransferFromToICAPWithReference(address _from, bytes32 _icap, uint _value, string _reference, address _sender) returns(bool);
                    function proxyApprove(address _spender, uint _value, bytes32 _symbol, address _sender) returns(bool);
                    function allowance(address _from, address _spender, bytes32 _symbol) constant returns(uint);
                    function proxyTransferFromWithReference(address _from, address _to, uint _value, bytes32 _symbol, string _reference, address _sender) returns(bool);
                }
                
                contract Asset {
                    function _performTransferWithReference(address _to, uint _value, string _reference, address _sender) returns(bool);
                    function _performTransferToICAPWithReference(bytes32 _icap, uint _value, string _reference, address _sender) returns(bool);
                    function _performApprove(address _spender, uint _value, address _sender) returns(bool);    
                    function _performTransferFromWithReference(address _from, address _to, uint _value, string _reference, address _sender) returns(bool);
                    function _performTransferFromToICAPWithReference(address _from, bytes32 _icap, uint _value, string _reference, address _sender) returns(bool);
                    function _performGeneric(bytes _data, address _sender) payable returns(bytes32) {
                        throw;
                    }
                }
                
                contract ERC20 {
                    event Transfer(address indexed from, address indexed to, uint256 value);
                    event Approval(address indexed from, address indexed spender, uint256 value);
                
                    function totalSupply() constant returns(uint256 supply);
                    function balanceOf(address _owner) constant returns(uint256 balance);
                    function transfer(address _to, uint256 _value) returns(bool success);
                    function transferFrom(address _from, address _to, uint256 _value) returns(bool success);
                    function approve(address _spender, uint256 _value) returns(bool success);
                    function allowance(address _owner, address _spender) constant returns(uint256 remaining);
                    function decimals() constant returns(uint8);
                }
                
                contract AssetProxyInterface {
                    function _forwardApprove(address _spender, uint _value, address _sender) returns(bool);    
                    function _forwardTransferFromWithReference(address _from, address _to, uint _value, string _reference, address _sender) returns(bool);
                    function _forwardTransferFromToICAPWithReference(address _from, bytes32 _icap, uint _value, string _reference, address _sender) returns(bool);
                }
                
                contract Bytes32 {
                    function _bytes32(string _input) internal constant returns(bytes32 result) {
                        assembly {
                            result := mload(add(_input, 32))
                        }
                    }
                }
                
                /**
                 * @title EToken2 Asset Proxy.
                 *
                 * Proxy implements ERC20 interface and acts as a gateway to a single EToken2 asset.
                 * Proxy adds etoken2Symbol and caller(sender) when forwarding requests to EToken2.
                 * Every request that is made by caller first sent to the specific asset implementation
                 * contract, which then calls back to be forwarded onto EToken2.
                 *
                 * Calls flow: Caller ->
                 *             Proxy.func(...) ->
                 *             Asset._performFunc(..., Caller.address) ->
                 *             Proxy._forwardFunc(..., Caller.address) ->
                 *             Platform.proxyFunc(..., symbol, Caller.address)
                 *
                 * Generic call flow: Caller ->
                 *             Proxy.unknownFunc(...) ->
                 *             Asset._performGeneric(..., Caller.address) ->
                 *             Asset.unknownFunc(...)
                 *
                 * Asset implementation contract is mutable, but each user have an option to stick with
                 * old implementation, through explicit decision made in timely manner, if he doesn't agree
                 * with new rules.
                 * Each user have a possibility to upgrade to latest asset contract implementation, without the
                 * possibility to rollback.
                 *
                 * Note: all the non constant functions return false instead of throwing in case if state change
                 * didn't happen yet.
                 */
                contract PolybiusToken is ERC20, AssetProxyInterface, Bytes32 {
                    // Assigned EToken2, immutable.
                    EToken2 public etoken2;
                
                    // Assigned symbol, immutable.
                    bytes32 public etoken2Symbol;
                
                    // Assigned name, immutable. For UI.
                    string public name;
                    string public symbol;
                
                    /**
                     * Sets EToken2 address, assigns symbol and name.
                     *
                     * Can be set only once.
                     *
                     * @param _etoken2 EToken2 contract address.
                     * @param _symbol assigned symbol.
                     * @param _name assigned name.
                     *
                     * @return success.
                     */
                    function init(EToken2 _etoken2, string _symbol, string _name) returns(bool) {
                        if (address(etoken2) != 0x0) {
                            return false;
                        }
                        etoken2 = _etoken2;
                        etoken2Symbol = _bytes32(_symbol);
                        name = _name;
                        symbol = _symbol;
                        return true;
                    }
                
                    /**
                     * Only EToken2 is allowed to call.
                     */
                    modifier onlyEToken2() {
                        if (msg.sender == address(etoken2)) {
                            _;
                        }
                    }
                
                    /**
                     * Only current asset owner is allowed to call.
                     */
                    modifier onlyAssetOwner() {
                        if (etoken2.isOwner(msg.sender, etoken2Symbol)) {
                            _;
                        }
                    }
                
                    /**
                     * Returns asset implementation contract for current caller.
                     *
                     * @return asset implementation contract.
                     */
                    function _getAsset() internal returns(Asset) {
                        return Asset(getVersionFor(msg.sender));
                    }
                
                    function recoverTokens(uint _value) onlyAssetOwner() returns(bool) {
                        return this.transferWithReference(msg.sender, _value, 'Tokens recovery');
                    }
                
                    /**
                     * Returns asset total supply.
                     *
                     * @return asset total supply.
                     */
                    function totalSupply() constant returns(uint) {
                        return etoken2.totalSupply(etoken2Symbol);
                    }
                
                    /**
                     * Returns asset balance for a particular holder.
                     *
                     * @param _owner holder address.
                     *
                     * @return holder balance.
                     */
                    function balanceOf(address _owner) constant returns(uint) {
                        return etoken2.balanceOf(_owner, etoken2Symbol);
                    }
                
                    /**
                     * Returns asset allowance from one holder to another.
                     *
                     * @param _from holder that allowed spending.
                     * @param _spender holder that is allowed to spend.
                     *
                     * @return holder to spender allowance.
                     */
                    function allowance(address _from, address _spender) constant returns(uint) {
                        return etoken2.allowance(_from, _spender, etoken2Symbol);
                    }
                
                    /**
                     * Returns asset decimals.
                     *
                     * @return asset decimals.
                     */
                    function decimals() constant returns(uint8) {
                        return etoken2.baseUnit(etoken2Symbol);
                    }
                
                    /**
                     * Transfers asset balance from the caller to specified receiver.
                     *
                     * @param _to holder address to give to.
                     * @param _value amount to transfer.
                     *
                     * @return success.
                     */
                    function transfer(address _to, uint _value) returns(bool) {
                        return transferWithReference(_to, _value, '');
                    }
                
                    /**
                     * Transfers asset balance from the caller to specified receiver adding specified comment.
                     * Resolves asset implementation contract for the caller and forwards there arguments along with
                     * the caller address.
                     *
                     * @param _to holder address to give to.
                     * @param _value amount to transfer.
                     * @param _reference transfer comment to be included in a EToken2's Transfer event.
                     *
                     * @return success.
                     */
                    function transferWithReference(address _to, uint _value, string _reference) returns(bool) {
                        return _getAsset()._performTransferWithReference(_to, _value, _reference, msg.sender);
                    }
                
                    /**
                     * Transfers asset balance from the caller to specified ICAP.
                     *
                     * @param _icap recipient ICAP to give to.
                     * @param _value amount to transfer.
                     *
                     * @return success.
                     */
                    function transferToICAP(bytes32 _icap, uint _value) returns(bool) {
                        return transferToICAPWithReference(_icap, _value, '');
                    }
                
                    /**
                     * Transfers asset balance from the caller to specified ICAP adding specified comment.
                     * Resolves asset implementation contract for the caller and forwards there arguments along with
                     * the caller address.
                     *
                     * @param _icap recipient ICAP to give to.
                     * @param _value amount to transfer.
                     * @param _reference transfer comment to be included in a EToken2's Transfer event.
                     *
                     * @return success.
                     */
                    function transferToICAPWithReference(bytes32 _icap, uint _value, string _reference) returns(bool) {
                        return _getAsset()._performTransferToICAPWithReference(_icap, _value, _reference, msg.sender);
                    }
                
                    /**
                     * Prforms allowance transfer of asset balance between holders.
                     *
                     * @param _from holder address to take from.
                     * @param _to holder address to give to.
                     * @param _value amount to transfer.
                     *
                     * @return success.
                     */
                    function transferFrom(address _from, address _to, uint _value) returns(bool) {
                        return transferFromWithReference(_from, _to, _value, '');
                    }
                
                    /**
                     * Prforms allowance transfer of asset balance between holders adding specified comment.
                     * Resolves asset implementation contract for the caller and forwards there arguments along with
                     * the caller address.
                     *
                     * @param _from holder address to take from.
                     * @param _to holder address to give to.
                     * @param _value amount to transfer.
                     * @param _reference transfer comment to be included in a EToken2's Transfer event.
                     *
                     * @return success.
                     */
                    function transferFromWithReference(address _from, address _to, uint _value, string _reference) returns(bool) {
                        return _getAsset()._performTransferFromWithReference(_from, _to, _value, _reference, msg.sender);
                    }
                
                    /**
                     * Performs transfer call on the EToken2 by the name of specified sender.
                     *
                     * Can only be called by asset implementation contract assigned to sender.
                     *
                     * @param _from holder address to take from.
                     * @param _to holder address to give to.
                     * @param _value amount to transfer.
                     * @param _reference transfer comment to be included in a EToken2's Transfer event.
                     * @param _sender initial caller.
                     *
                     * @return success.
                     */
                    function _forwardTransferFromWithReference(address _from, address _to, uint _value, string _reference, address _sender) onlyImplementationFor(_sender) returns(bool) {
                        return etoken2.proxyTransferFromWithReference(_from, _to, _value, etoken2Symbol, _reference, _sender);
                    }
                
                    /**
                     * Prforms allowance transfer of asset balance between holders.
                     *
                     * @param _from holder address to take from.
                     * @param _icap recipient ICAP address to give to.
                     * @param _value amount to transfer.
                     *
                     * @return success.
                     */
                    function transferFromToICAP(address _from, bytes32 _icap, uint _value) returns(bool) {
                        return transferFromToICAPWithReference(_from, _icap, _value, '');
                    }
                
                    /**
                     * Prforms allowance transfer of asset balance between holders adding specified comment.
                     * Resolves asset implementation contract for the caller and forwards there arguments along with
                     * the caller address.
                     *
                     * @param _from holder address to take from.
                     * @param _icap recipient ICAP address to give to.
                     * @param _value amount to transfer.
                     * @param _reference transfer comment to be included in a EToken2's Transfer event.
                     *
                     * @return success.
                     */
                    function transferFromToICAPWithReference(address _from, bytes32 _icap, uint _value, string _reference) returns(bool) {
                        return _getAsset()._performTransferFromToICAPWithReference(_from, _icap, _value, _reference, msg.sender);
                    }
                
                    /**
                     * Performs allowance transfer to ICAP call on the EToken2 by the name of specified sender.
                     *
                     * Can only be called by asset implementation contract assigned to sender.
                     *
                     * @param _from holder address to take from.
                     * @param _icap recipient ICAP address to give to.
                     * @param _value amount to transfer.
                     * @param _reference transfer comment to be included in a EToken2's Transfer event.
                     * @param _sender initial caller.
                     *
                     * @return success.
                     */
                    function _forwardTransferFromToICAPWithReference(address _from, bytes32 _icap, uint _value, string _reference, address _sender) onlyImplementationFor(_sender) returns(bool) {
                        return etoken2.proxyTransferFromToICAPWithReference(_from, _icap, _value, _reference, _sender);
                    }
                
                    /**
                     * Sets asset spending allowance for a specified spender.
                     * Resolves asset implementation contract for the caller and forwards there arguments along with
                     * the caller address.
                     *
                     * @param _spender holder address to set allowance to.
                     * @param _value amount to allow.
                     *
                     * @return success.
                     */
                    function approve(address _spender, uint _value) returns(bool) {
                        return _getAsset()._performApprove(_spender, _value, msg.sender);
                    }
                
                    /**
                     * Performs allowance setting call on the EToken2 by the name of specified sender.
                     *
                     * Can only be called by asset implementation contract assigned to sender.
                     *
                     * @param _spender holder address to set allowance to.
                     * @param _value amount to allow.
                     * @param _sender initial caller.
                     *
                     * @return success.
                     */
                    function _forwardApprove(address _spender, uint _value, address _sender) onlyImplementationFor(_sender) returns(bool) {
                        return etoken2.proxyApprove(_spender, _value, etoken2Symbol, _sender);
                    }
                
                    /**
                     * Emits ERC20 Transfer event on this contract.
                     *
                     * Can only be, and, called by assigned EToken2 when asset transfer happens.
                     */
                    function emitTransfer(address _from, address _to, uint _value) onlyEToken2() {
                        Transfer(_from, _to, _value);
                    }
                
                    /**
                     * Emits ERC20 Approval event on this contract.
                     *
                     * Can only be, and, called by assigned EToken2 when asset allowance set happens.
                     */
                    function emitApprove(address _from, address _spender, uint _value) onlyEToken2() {
                        Approval(_from, _spender, _value);
                    }
                
                    /**
                     * Resolves asset implementation contract for the caller and forwards there transaction data,
                     * along with the value. This allows for proxy interface growth.
                     */
                    function () payable {
                        bytes32 result = _getAsset()._performGeneric.value(msg.value)(msg.data, msg.sender);
                        assembly {
                            mstore(0, result)
                            return(0, 32)
                        }
                    }
                
                    /**
                     * Indicates an upgrade freeze-time start, and the next asset implementation contract.
                     */
                    event UpgradeProposal(address newVersion);
                
                    // Current asset implementation contract address.
                    address latestVersion;
                
                    // Proposed next asset implementation contract address.
                    address pendingVersion;
                
                    // Upgrade freeze-time start.
                    uint pendingVersionTimestamp;
                
                    // Timespan for users to review the new implementation and make decision.
                    uint constant UPGRADE_FREEZE_TIME = 3 days;
                
                    // Asset implementation contract address that user decided to stick with.
                    // 0x0 means that user uses latest version.
                    mapping(address => address) userOptOutVersion;
                
                    /**
                     * Only asset implementation contract assigned to sender is allowed to call.
                     */
                    modifier onlyImplementationFor(address _sender) {
                        if (getVersionFor(_sender) == msg.sender) {
                            _;
                        }
                    }
                
                    /**
                     * Returns asset implementation contract address assigned to sender.
                     *
                     * @param _sender sender address.
                     *
                     * @return asset implementation contract address.
                     */
                    function getVersionFor(address _sender) constant returns(address) {
                        return userOptOutVersion[_sender] == 0 ? latestVersion : userOptOutVersion[_sender];
                    }
                
                    /**
                     * Returns current asset implementation contract address.
                     *
                     * @return asset implementation contract address.
                     */
                    function getLatestVersion() constant returns(address) {
                        return latestVersion;
                    }
                
                    /**
                     * Returns proposed next asset implementation contract address.
                     *
                     * @return asset implementation contract address.
                     */
                    function getPendingVersion() constant returns(address) {
                        return pendingVersion;
                    }
                
                    /**
                     * Returns upgrade freeze-time start.
                     *
                     * @return freeze-time start.
                     */
                    function getPendingVersionTimestamp() constant returns(uint) {
                        return pendingVersionTimestamp;
                    }
                
                    /**
                     * Propose next asset implementation contract address.
                     *
                     * Can only be called by current asset owner.
                     *
                     * Note: freeze-time should not be applied for the initial setup.
                     *
                     * @param _newVersion asset implementation contract address.
                     *
                     * @return success.
                     */
                    function proposeUpgrade(address _newVersion) onlyAssetOwner() returns(bool) {
                        // Should not already be in the upgrading process.
                        if (pendingVersion != 0x0) {
                            return false;
                        }
                        // New version address should be other than 0x0.
                        if (_newVersion == 0x0) {
                            return false;
                        }
                        // Don't apply freeze-time for the initial setup.
                        if (latestVersion == 0x0) {
                            latestVersion = _newVersion;
                            return true;
                        }
                        pendingVersion = _newVersion;
                        pendingVersionTimestamp = now;
                        UpgradeProposal(_newVersion);
                        return true;
                    }
                
                    /**
                     * Cancel the pending upgrade process.
                     *
                     * Can only be called by current asset owner.
                     *
                     * @return success.
                     */
                    function purgeUpgrade() onlyAssetOwner() returns(bool) {
                        if (pendingVersion == 0x0) {
                            return false;
                        }
                        delete pendingVersion;
                        delete pendingVersionTimestamp;
                        return true;
                    }
                
                    /**
                     * Finalize an upgrade process setting new asset implementation contract address.
                     *
                     * Can only be called after an upgrade freeze-time.
                     *
                     * @return success.
                     */
                    function commitUpgrade() returns(bool) {
                        if (pendingVersion == 0x0) {
                            return false;
                        }
                        if (pendingVersionTimestamp + UPGRADE_FREEZE_TIME > now) {
                            return false;
                        }
                        latestVersion = pendingVersion;
                        delete pendingVersion;
                        delete pendingVersionTimestamp;
                        return true;
                    }
                
                    /**
                     * Disagree with proposed upgrade, and stick with current asset implementation
                     * until further explicit agreement to upgrade.
                     *
                     * @return success.
                     */
                    function optOut() returns(bool) {
                        if (userOptOutVersion[msg.sender] != 0x0) {
                            return false;
                        }
                        userOptOutVersion[msg.sender] = latestVersion;
                        return true;
                    }
                
                    /**
                     * Implicitly agree to upgrade to current and future asset implementation upgrades,
                     * until further explicit disagreement.
                     *
                     * @return success.
                     */
                    function optIn() returns(bool) {
                        delete userOptOutVersion[msg.sender];
                        return true;
                    }
                
                    // Backwards compatibility.
                    function multiAsset() constant returns(EToken2) {
                        return etoken2;
                    }
                }

                File 2 of 4: EventsHistory
                // This software is a subject to Ambisafe License Agreement.
                // No use or distribution is allowed without written permission from Ambisafe.
                // https://ambisafe.com/terms.pdf
                
                contract Ambi {
                    function getNodeAddress(bytes32 _nodeName) constant returns(address);
                    function hasRelation(bytes32 _nodeName, bytes32 _relation, address _to) constant returns(bool);
                    function addNode(bytes32 _nodeName, address _nodeAddress) constant returns(bool);
                }
                
                contract AmbiEnabled {
                    Ambi public ambiC;
                    bool public isImmortal;
                    bytes32 public name;
                
                    modifier checkAccess(bytes32 _role) {
                        if(address(ambiC) != 0x0 && ambiC.hasRelation(name, _role, msg.sender)){
                            _
                        }
                    }
                    
                    function getAddress(bytes32 _name) constant returns (address) {
                        return ambiC.getNodeAddress(_name);
                    }
                
                    function setAmbiAddress(address _ambi, bytes32 _name) returns (bool){
                        if(address(ambiC) != 0x0){
                            return false;
                        }
                        Ambi ambiContract = Ambi(_ambi);
                        if(ambiContract.getNodeAddress(_name)!=address(this)) {
                            if (!ambiContract.addNode(_name, address(this))){
                                return false;
                            }
                        }
                        name = _name;
                        ambiC = ambiContract;
                        return true;
                    }
                
                    function immortality() checkAccess("owner") returns(bool) {
                        isImmortal = true;
                        return true;
                    }
                
                    function remove() checkAccess("owner") returns(bool) {
                        if (isImmortal) {
                            return false;
                        }
                        selfdestruct(msg.sender);
                        return true;
                    }
                }
                
                library StackDepthLib {
                    // This will probably work with a value of 390 but no need to cut it
                    // that close in the case that the optimizer changes slightly or
                    // something causing that number to rise slightly.
                    uint constant GAS_PER_DEPTH = 400;
                
                    function checkDepth(address self, uint n) constant returns(bool) {
                        if (n == 0) return true;
                        return self.call.gas(GAS_PER_DEPTH * n)(0x21835af6, n - 1);
                    }
                
                    function __dig(uint n) constant {
                        if (n == 0) return;
                        if (!address(this).delegatecall(0x21835af6, n - 1)) throw;
                    }
                }
                
                contract Safe {
                    // Should always be placed as first modifier!
                    modifier noValue {
                        if (msg.value > 0) {
                            // Internal Out Of Gas/Throw: revert this transaction too;
                            // Call Stack Depth Limit reached: revert this transaction too;
                            // Recursive Call: safe, no any changes applied yet, we are inside of modifier.
                            _safeSend(msg.sender, msg.value);
                        }
                        _
                    }
                
                    modifier onlyHuman {
                        if (_isHuman()) {
                            _
                        }
                    }
                
                    modifier noCallback {
                        if (!isCall) {
                            _
                        }
                    }
                
                    modifier immutable(address _address) {
                        if (_address == 0) {
                            _
                        }
                    }
                
                    address stackDepthLib;
                    function setupStackDepthLib(address _stackDepthLib) immutable(address(stackDepthLib)) returns(bool) {
                        stackDepthLib = _stackDepthLib;
                        return true;
                    }
                
                    modifier requireStackDepth(uint16 _depth) {
                        if (stackDepthLib == 0x0) {
                            throw;
                        }
                        if (_depth > 1023) {
                            throw;
                        }
                        if (!stackDepthLib.delegatecall(0x32921690, stackDepthLib, _depth)) {
                            throw;
                        }
                        _
                    }
                
                    // Must not be used inside the functions that have noValue() modifier!
                    function _safeFalse() internal noValue() returns(bool) {
                        return false;
                    }
                
                    function _safeSend(address _to, uint _value) internal {
                        if (!_unsafeSend(_to, _value)) {
                            throw;
                        }
                    }
                
                    function _unsafeSend(address _to, uint _value) internal returns(bool) {
                        return _to.call.value(_value)();
                    }
                
                    function _isContract() constant internal returns(bool) {
                        return msg.sender != tx.origin;
                    }
                
                    function _isHuman() constant internal returns(bool) {
                        return !_isContract();
                    }
                
                    bool private isCall = false;
                    function _setupNoCallback() internal {
                        isCall = true;
                    }
                
                    function _finishNoCallback() internal {
                        isCall = false;
                    }
                }
                
                /**
                 * @title Events History universal contract.
                 *
                 * Contract serves as an Events storage and version history for a particular contract type.
                 * Events appear on this contract address but their definitions provided by other contracts/libraries.
                 * Version info is provided for historical and informational purposes.
                 *
                 * Note: all the non constant functions return false instead of throwing in case if state change
                 * didn't happen yet.
                 */
                contract EventsHistory is AmbiEnabled, Safe {
                    // Event emitter signature to address with Event definiton mapping.
                    mapping(bytes4 => address) public emitters;
                
                    // Calling contract address to version mapping.
                    mapping(address => uint) public versions;
                
                    // Version to info mapping.
                    mapping(uint => VersionInfo) public versionInfo;
                
                    // Latest verion number.
                    uint public latestVersion;
                
                    struct VersionInfo {
                        uint block;        // Block number in which version has been introduced.
                        address by;        // Contract owner address who added version.
                        address caller;    // Address of this version calling contract.
                        string name;       // Version name, informative.
                        string changelog;  // Version changelog, informative.
                    }
                
                    /**
                     * Assign emitter address to a specified emit function signature.
                     *
                     * Can be set only once for each signature, and only by contract owner.
                     * Caller contract should be sure that emitter for a particular signature will never change.
                     *
                     * @param _eventSignature signature of the event emitting function.
                     * @param _emitter address with Event definition.
                     *
                     * @return success.
                     */
                    function addEmitter(bytes4 _eventSignature, address _emitter) noValue() checkAccess("admin") returns(bool) {
                        if (emitters[_eventSignature] != 0x0) {
                            return false;
                        }
                        emitters[_eventSignature] = _emitter;
                        return true;
                    }
                
                    /**
                     * Introduce new caller contract version specifing version information.
                     *
                     * Can be set only once for each caller, and only by contract owner.
                     * Name and changelog should not be empty.
                     *
                     * @param _caller address of the new caller.
                     * @param _name version name.
                     * @param _changelog version changelog.
                     *
                     * @return success.
                     */
                    function addVersion(address _caller, string _name, string _changelog) noValue() checkAccess("admin") returns(bool) {
                        if (versions[_caller] != 0) {
                            return false;
                        }
                        if (bytes(_name).length == 0) {
                            return false;
                        }
                        if (bytes(_changelog).length == 0) {
                            return false;
                        }
                        uint version = ++latestVersion;
                        versions[_caller] = version;
                        versionInfo[version] = VersionInfo(block.number, msg.sender, _caller, _name, _changelog);
                        return true;
                    }
                
                    /**
                     * Event emitting fallback.
                     *
                     * Can be and only called caller with assigned version.
                     * Resolves msg.sig to an emitter address, and calls it to emit an event.
                     *
                     * Throws if emit function signature is not registered, or call failed.
                     */
                    function () noValue() {
                        if (versions[msg.sender] == 0) {
                            return;
                        }
                        // Internal Out Of Gas/Throw: revert this transaction too;
                        // Call Stack Depth Limit reached: revert this transaction too;
                        // Recursive Call: safe, all changes already made.
                        if (!emitters[msg.sig].delegatecall(msg.data)) {
                            throw;
                        }
                    }
                }

                File 3 of 4: EToken2
                // This software is a subject to Ambisafe License Agreement.
                // No use or distribution is allowed without written permission from Ambisafe.
                // https://ambisafe.com/terms.pdf
                
                pragma solidity 0.4.8;
                
                contract Ambi2 {
                    function claimFor(address _address, address _owner) returns(bool);
                    function hasRole(address _from, bytes32 _role, address _to) constant returns(bool);
                    function isOwner(address _node, address _owner) constant returns(bool);
                }
                
                contract Ambi2Enabled {
                    Ambi2 ambi2;
                
                    modifier onlyRole(bytes32 _role) {
                        if (address(ambi2) != 0x0 && ambi2.hasRole(this, _role, msg.sender)) {
                            _;
                        }
                    }
                
                    // Perform only after claiming the node, or claim in the same tx.
                    function setupAmbi2(Ambi2 _ambi2) returns(bool) {
                        if (address(ambi2) != 0x0) {
                            return false;
                        }
                
                        ambi2 = _ambi2;
                        return true;
                    }
                }
                
                contract Ambi2EnabledFull is Ambi2Enabled {
                    // Setup and claim atomically.
                    function setupAmbi2(Ambi2 _ambi2) returns(bool) {
                        if (address(ambi2) != 0x0) {
                            return false;
                        }
                        if (!_ambi2.claimFor(this, msg.sender) && !_ambi2.isOwner(this, msg.sender)) {
                            return false;
                        }
                
                        ambi2 = _ambi2;
                        return true;
                    }
                }
                
                contract RegistryICAPInterface {
                    function parse(bytes32 _icap) constant returns(address, bytes32, bool);
                    function institutions(bytes32 _institution) constant returns(address);
                }
                
                contract Cosigner {
                    function consumeOperation(bytes32 _opHash, uint _required) returns(bool);
                }
                
                contract Emitter {
                    function emitTransfer(address _from, address _to, bytes32 _symbol, uint _value, string _reference);
                    function emitTransferToICAP(address _from, address _to, bytes32 _icap, uint _value, string _reference);
                    function emitIssue(bytes32 _symbol, uint _value, address _by);
                    function emitRevoke(bytes32 _symbol, uint _value, address _by);
                    function emitOwnershipChange(address _from, address _to, bytes32 _symbol);
                    function emitApprove(address _from, address _spender, bytes32 _symbol, uint _value);
                    function emitRecovery(address _from, address _to, address _by);
                    function emitError(bytes32 _message);
                    function emitChange(bytes32 _symbol);
                }
                
                contract Proxy {
                    function emitTransfer(address _from, address _to, uint _value);
                    function emitApprove(address _from, address _spender, uint _value);
                }
                
                /**
                 * @title EToken2.
                 *
                 * The official Ambisafe assets platform powering all kinds of tokens.
                 * EToken2 uses EventsHistory contract to keep events, so that in case it needs to be redeployed
                 * at some point, all the events keep appearing at the same place.
                 *
                 * Every asset is meant to be used through a proxy contract. Only one proxy contract have access
                 * rights for a particular asset.
                 *
                 * Features: assets issuance, transfers, allowances, supply adjustments, lost wallet access recovery.
                 *           cosignature check, ICAP.
                 *
                 * Note: all the non constant functions return false instead of throwing in case if state change
                 * didn't happen yet.
                 */
                contract EToken2 is Ambi2EnabledFull {
                    mapping(bytes32 => bool) switches;
                
                    function isEnabled(bytes32 _switch) constant returns(bool) {
                        return switches[_switch];
                    }
                
                    function enableSwitch(bytes32 _switch) onlyRole('issuance') returns(bool) {
                        switches[_switch] = true;
                        return true;
                    }
                
                    modifier checkEnabledSwitch(bytes32 _switch) {
                        if (!isEnabled(_switch)) {
                            _error('Feature is disabled');
                        } else {
                            _;
                        }
                    }
                
                    enum Features { Issue, TransferWithReference, Revoke, ChangeOwnership, Allowances, ICAP }
                
                    // Structure of a particular asset.
                    struct Asset {
                        uint owner;                       // Asset's owner id.
                        uint totalSupply;                 // Asset's total supply.
                        string name;                      // Asset's name, for information purposes.
                        string description;               // Asset's description, for information purposes.
                        bool isReissuable;                // Indicates if asset have dynamic of fixed supply.
                        uint8 baseUnit;                   // Proposed number of decimals.
                        bool isLocked;                    // Are changes still allowed.
                        mapping(uint => Wallet) wallets;  // Holders wallets.
                    }
                
                    // Structure of an asset holder wallet for particular asset.
                    struct Wallet {
                        uint balance;
                        mapping(uint => uint) allowance;
                    }
                
                    // Structure of an asset holder.
                    struct Holder {
                        address addr;                    // Current address of the holder.
                        Cosigner cosigner;               // Cosigner contract for 2FA and recovery.
                        mapping(address => bool) trust;  // Addresses that are trusted with recovery proocedure.
                    }
                
                    // Iterable mapping pattern is used for holders.
                    uint public holdersCount;
                    mapping(uint => Holder) public holders;
                
                    // This is an access address mapping. Many addresses may have access to a single holder.
                    mapping(address => uint) holderIndex;
                
                    // Asset symbol to asset mapping.
                    mapping(bytes32 => Asset) public assets;
                
                    // Asset symbol to asset proxy mapping.
                    mapping(bytes32 => address) public proxies;
                
                    // ICAP registry contract.
                    RegistryICAPInterface public registryICAP;
                
                    // Should use interface of the emitter, but address of events history.
                    Emitter public eventsHistory;
                
                    /**
                     * Emits Error event with specified error message.
                     *
                     * Should only be used if no state changes happened.
                     *
                     * @param _message error message.
                     */
                    function _error(bytes32 _message) internal {
                        eventsHistory.emitError(_message);
                    }
                
                    /**
                     * Sets EventsHstory contract address.
                     *
                     * Can be set only once, and only by contract owner.
                     *
                     * @param _eventsHistory EventsHistory contract address.
                     *
                     * @return success.
                     */
                    function setupEventsHistory(Emitter _eventsHistory) onlyRole('setup') returns(bool) {
                        if (address(eventsHistory) != 0) {
                            return false;
                        }
                        eventsHistory = _eventsHistory;
                        return true;
                    }
                
                    /**
                     * Sets RegistryICAP contract address.
                     *
                     * Can be set only once, and only by contract owner.
                     *
                     * @param _registryICAP RegistryICAP contract address.
                     *
                     * @return success.
                     */
                    function setupRegistryICAP(RegistryICAPInterface _registryICAP) onlyRole('setup') returns(bool) {
                        if (address(registryICAP) != 0) {
                            return false;
                        }
                        registryICAP = _registryICAP;
                        return true;
                    }
                
                    /**
                     * Emits Error if called not by asset owner.
                     */
                    modifier onlyOwner(bytes32 _symbol) {
                        if (_isSignedOwner(_symbol)) {
                            _;
                        } else {
                            _error('Only owner: access denied');
                        }
                    }
                
                    /**
                     * Emits Error if called not by asset proxy.
                     */
                    modifier onlyProxy(bytes32 _symbol) {
                        if (_isProxy(_symbol)) {
                            _;
                        } else {
                            _error('Only proxy: access denied');
                        }
                    }
                
                    /**
                     * Emits Error if _from doesn't trust _to.
                     */
                    modifier checkTrust(address _from, address _to) {
                        if (isTrusted(_from, _to)) {
                            _;
                        } else {
                            _error('Only trusted: access denied');
                        }
                    }
                
                    function _isSignedOwner(bytes32 _symbol) internal checkSigned(getHolderId(msg.sender), 1) returns(bool) {
                        return isOwner(msg.sender, _symbol);
                    }
                
                    /**
                     * Check asset existance.
                     *
                     * @param _symbol asset symbol.
                     *
                     * @return asset existance.
                     */
                    function isCreated(bytes32 _symbol) constant returns(bool) {
                        return assets[_symbol].owner != 0;
                    }
                
                    function isLocked(bytes32 _symbol) constant returns(bool) {
                        return assets[_symbol].isLocked;
                    }
                
                    /**
                     * Returns asset decimals.
                     *
                     * @param _symbol asset symbol.
                     *
                     * @return asset decimals.
                     */
                    function baseUnit(bytes32 _symbol) constant returns(uint8) {
                        return assets[_symbol].baseUnit;
                    }
                
                    /**
                     * Returns asset name.
                     *
                     * @param _symbol asset symbol.
                     *
                     * @return asset name.
                     */
                    function name(bytes32 _symbol) constant returns(string) {
                        return assets[_symbol].name;
                    }
                
                    /**
                     * Returns asset description.
                     *
                     * @param _symbol asset symbol.
                     *
                     * @return asset description.
                     */
                    function description(bytes32 _symbol) constant returns(string) {
                        return assets[_symbol].description;
                    }
                
                    /**
                     * Returns asset reissuability.
                     *
                     * @param _symbol asset symbol.
                     *
                     * @return asset reissuability.
                     */
                    function isReissuable(bytes32 _symbol) constant returns(bool) {
                        return assets[_symbol].isReissuable;
                    }
                
                    /**
                     * Returns asset owner address.
                     *
                     * @param _symbol asset symbol.
                     *
                     * @return asset owner address.
                     */
                    function owner(bytes32 _symbol) constant returns(address) {
                        return holders[assets[_symbol].owner].addr;
                    }
                
                    /**
                     * Check if specified address has asset owner rights.
                     *
                     * @param _owner address to check.
                     * @param _symbol asset symbol.
                     *
                     * @return owner rights availability.
                     */
                    function isOwner(address _owner, bytes32 _symbol) constant returns(bool) {
                        return isCreated(_symbol) && (assets[_symbol].owner == getHolderId(_owner));
                    }
                
                    /**
                     * Returns asset total supply.
                     *
                     * @param _symbol asset symbol.
                     *
                     * @return asset total supply.
                     */
                    function totalSupply(bytes32 _symbol) constant returns(uint) {
                        return assets[_symbol].totalSupply;
                    }
                
                    /**
                     * Returns asset balance for current address of a particular holder.
                     *
                     * @param _holder holder address.
                     * @param _symbol asset symbol.
                     *
                     * @return holder balance.
                     */
                    function balanceOf(address _holder, bytes32 _symbol) constant returns(uint) {
                        uint holderId = getHolderId(_holder);
                        return holders[holderId].addr == _holder ? _balanceOf(holderId, _symbol) : 0;
                    }
                
                    /**
                     * Returns asset balance for a particular holder id.
                     *
                     * @param _holderId holder id.
                     * @param _symbol asset symbol.
                     *
                     * @return holder balance.
                     */
                    function _balanceOf(uint _holderId, bytes32 _symbol) constant internal returns(uint) {
                        return assets[_symbol].wallets[_holderId].balance;
                    }
                
                    /**
                     * Returns current address for a particular holder id.
                     *
                     * @param _holderId holder id.
                     *
                     * @return holder address.
                     */
                    function _address(uint _holderId) constant internal returns(address) {
                        return holders[_holderId].addr;
                    }
                
                    function _isProxy(bytes32 _symbol) constant internal returns(bool) {
                        return proxies[_symbol] == msg.sender;
                    }
                
                    /**
                     * Sets Proxy contract address for a particular asset.
                     *
                     * Can be set only once for each asset, and only by contract owner.
                     *
                     * @param _address Proxy contract address.
                     * @param _symbol asset symbol.
                     *
                     * @return success.
                     */
                    function setProxy(address _address, bytes32 _symbol) onlyOwner(_symbol) returns(bool) {
                        if (proxies[_symbol] != 0x0 && assets[_symbol].isLocked) {
                            return false;
                        }
                        proxies[_symbol] = _address;
                        return true;
                    }
                
                    /**
                     * Transfers asset balance between holders wallets.
                     *
                     * @param _fromId holder id to take from.
                     * @param _toId holder id to give to.
                     * @param _value amount to transfer.
                     * @param _symbol asset symbol.
                     */
                    function _transferDirect(uint _fromId, uint _toId, uint _value, bytes32 _symbol) internal {
                        assets[_symbol].wallets[_fromId].balance -= _value;
                        assets[_symbol].wallets[_toId].balance += _value;
                    }
                
                    /**
                     * Transfers asset balance between holders wallets.
                     *
                     * Performs sanity checks and takes care of allowances adjustment.
                     *
                     * @param _fromId holder id to take from.
                     * @param _toId holder id to give to.
                     * @param _value amount to transfer.
                     * @param _symbol asset symbol.
                     * @param _reference transfer comment to be included in a Transfer event.
                     * @param _senderId transfer initiator holder id.
                     *
                     * @return success.
                     */
                    function _transfer(uint _fromId, uint _toId, uint _value, bytes32 _symbol, string _reference, uint _senderId) internal checkSigned(_senderId, 1) returns(bool) {
                        // Should not allow to send to oneself.
                        if (_fromId == _toId) {
                            _error('Cannot send to oneself');
                            return false;
                        }
                        // Should have positive value.
                        if (_value == 0) {
                            _error('Cannot send 0 value');
                            return false;
                        }
                        // Should have enough balance.
                        if (_balanceOf(_fromId, _symbol) < _value) {
                            _error('Insufficient balance');
                            return false;
                        }
                        // Should allow references.
                        if (bytes(_reference).length > 0 && !isEnabled(sha3(_symbol, Features.TransferWithReference))) {
                            _error('References feature is disabled');
                            return false;
                        }
                        // Should have enough allowance.
                        if (_fromId != _senderId && _allowance(_fromId, _senderId, _symbol) < _value) {
                            _error('Not enough allowance');
                            return false;
                        }
                        // Adjust allowance.
                        if (_fromId != _senderId) {
                            assets[_symbol].wallets[_fromId].allowance[_senderId] -= _value;
                        }
                        _transferDirect(_fromId, _toId, _value, _symbol);
                        // Internal Out Of Gas/Throw: revert this transaction too;
                        // Recursive Call: safe, all changes already made.
                        eventsHistory.emitTransfer(_address(_fromId), _address(_toId), _symbol, _value, _reference);
                        _proxyTransferEvent(_fromId, _toId, _value, _symbol);
                        return true;
                    }
                
                    // Feature and proxy checks done internally due to unknown symbol when the function is called.
                    function _transferToICAP(uint _fromId, bytes32 _icap, uint _value, string _reference, uint _senderId) internal returns(bool) {
                        var (to, symbol, success) = registryICAP.parse(_icap);
                        if (!success) {
                            _error('ICAP is not registered');
                            return false;
                        }
                        if (!isEnabled(sha3(symbol, Features.ICAP))) {
                            _error('ICAP feature is disabled');
                            return false;
                        }
                        if (!_isProxy(symbol)) {
                            _error('Only proxy: access denied');
                            return false;
                        }
                        uint toId = _createHolderId(to);
                        if (!_transfer(_fromId, toId, _value, symbol, _reference, _senderId)) {
                            return false;
                        }
                        // Internal Out Of Gas/Throw: revert this transaction too;
                        // Recursive Call: safe, all changes already made.
                        eventsHistory.emitTransferToICAP(_address(_fromId), _address(toId), _icap, _value, _reference);
                        return true;
                    }
                
                    function proxyTransferFromToICAPWithReference(address _from, bytes32 _icap, uint _value, string _reference, address _sender) returns(bool) {
                        return _transferToICAP(getHolderId(_from), _icap, _value, _reference, getHolderId(_sender));
                    }
                
                    /**
                     * Ask asset Proxy contract to emit ERC20 compliant Transfer event.
                     *
                     * @param _fromId holder id to take from.
                     * @param _toId holder id to give to.
                     * @param _value amount to transfer.
                     * @param _symbol asset symbol.
                     */
                    function _proxyTransferEvent(uint _fromId, uint _toId, uint _value, bytes32 _symbol) internal {
                        if (proxies[_symbol] != 0x0) {
                            // Internal Out Of Gas/Throw: revert this transaction too;
                            // Recursive Call: safe, all changes already made.
                            Proxy(proxies[_symbol]).emitTransfer(_address(_fromId), _address(_toId), _value);
                        }
                    }
                
                    /**
                     * Returns holder id for the specified address.
                     *
                     * @param _holder holder address.
                     *
                     * @return holder id.
                     */
                    function getHolderId(address _holder) constant returns(uint) {
                        return holderIndex[_holder];
                    }
                
                    /**
                     * Returns holder id for the specified address, creates it if needed.
                     *
                     * @param _holder holder address.
                     *
                     * @return holder id.
                     */
                    function _createHolderId(address _holder) internal returns(uint) {
                        uint holderId = holderIndex[_holder];
                        if (holderId == 0) {
                            holderId = ++holdersCount;
                            holders[holderId].addr = _holder;
                            holderIndex[_holder] = holderId;
                        }
                        return holderId;
                    }
                
                    /**
                     * Issues new asset token on the platform.
                     *
                     * Tokens issued with this call go straight to contract owner.
                     * Each symbol can be issued only once, and only by contract owner.
                     *
                     * _isReissuable is included in checkEnabledSwitch because it should be
                     * explicitly allowed before issuing new asset.
                     *
                     * @param _symbol asset symbol.
                     * @param _value amount of tokens to issue immediately.
                     * @param _name name of the asset.
                     * @param _description description for the asset.
                     * @param _baseUnit number of decimals.
                     * @param _isReissuable dynamic or fixed supply.
                     *
                     * @return success.
                     */
                    function issueAsset(bytes32 _symbol, uint _value, string _name, string _description, uint8 _baseUnit, bool _isReissuable) checkEnabledSwitch(sha3(_symbol, _isReissuable, Features.Issue)) returns(bool) {
                        // Should have positive value if supply is going to be fixed.
                        if (_value == 0 && !_isReissuable) {
                            _error('Cannot issue 0 value fixed asset');
                            return false;
                        }
                        // Should not be issued yet.
                        if (isCreated(_symbol)) {
                            _error('Asset already issued');
                            return false;
                        }
                        uint holderId = _createHolderId(msg.sender);
                
                        assets[_symbol] = Asset(holderId, _value, _name, _description, _isReissuable, _baseUnit, false);
                        assets[_symbol].wallets[holderId].balance = _value;
                        // Internal Out Of Gas/Throw: revert this transaction too;
                        // Recursive Call: safe, all changes already made.
                        eventsHistory.emitIssue(_symbol, _value, _address(holderId));
                        return true;
                    }
                
                    function changeAsset(bytes32 _symbol, string _name, string _description, uint8 _baseUnit) onlyOwner(_symbol) returns(bool) {
                        if (isLocked(_symbol)) {
                            _error('Asset is locked');
                            return false;
                        }
                        assets[_symbol].name = _name;
                        assets[_symbol].description = _description;
                        assets[_symbol].baseUnit = _baseUnit;
                        eventsHistory.emitChange(_symbol);
                        return true;
                    }
                
                    function lockAsset(bytes32 _symbol) onlyOwner(_symbol) returns(bool) {
                        if (isLocked(_symbol)) {
                            _error('Asset is locked');
                            return false;
                        }
                        assets[_symbol].isLocked = true;
                        return true;
                    }
                
                    /**
                     * Issues additional asset tokens if the asset have dynamic supply.
                     *
                     * Tokens issued with this call go straight to asset owner.
                     * Can only be called by asset owner.
                     *
                     * @param _symbol asset symbol.
                     * @param _value amount of additional tokens to issue.
                     *
                     * @return success.
                     */
                    function reissueAsset(bytes32 _symbol, uint _value) onlyOwner(_symbol) returns(bool) {
                        // Should have positive value.
                        if (_value == 0) {
                            _error('Cannot reissue 0 value');
                            return false;
                        }
                        Asset asset = assets[_symbol];
                        // Should have dynamic supply.
                        if (!asset.isReissuable) {
                            _error('Cannot reissue fixed asset');
                            return false;
                        }
                        // Resulting total supply should not overflow.
                        if (asset.totalSupply + _value < asset.totalSupply) {
                            _error('Total supply overflow');
                            return false;
                        }
                        uint holderId = getHolderId(msg.sender);
                        asset.wallets[holderId].balance += _value;
                        asset.totalSupply += _value;
                        // Internal Out Of Gas/Throw: revert this transaction too;
                        // Recursive Call: safe, all changes already made.
                        eventsHistory.emitIssue(_symbol, _value, _address(holderId));
                        _proxyTransferEvent(0, holderId, _value, _symbol);
                        return true;
                    }
                
                    /**
                     * Destroys specified amount of senders asset tokens.
                     *
                     * @param _symbol asset symbol.
                     * @param _value amount of tokens to destroy.
                     *
                     * @return success.
                     */
                    function revokeAsset(bytes32 _symbol, uint _value) checkEnabledSwitch(sha3(_symbol, Features.Revoke)) checkSigned(getHolderId(msg.sender), 1) returns(bool) {
                        // Should have positive value.
                        if (_value == 0) {
                            _error('Cannot revoke 0 value');
                            return false;
                        }
                        Asset asset = assets[_symbol];
                        uint holderId = getHolderId(msg.sender);
                        // Should have enough tokens.
                        if (asset.wallets[holderId].balance < _value) {
                            _error('Not enough tokens to revoke');
                            return false;
                        }
                        asset.wallets[holderId].balance -= _value;
                        asset.totalSupply -= _value;
                        // Internal Out Of Gas/Throw: revert this transaction too;
                        // Recursive Call: safe, all changes already made.
                        eventsHistory.emitRevoke(_symbol, _value, _address(holderId));
                        _proxyTransferEvent(holderId, 0, _value, _symbol);
                        return true;
                    }
                
                    /**
                     * Passes asset ownership to specified address.
                     *
                     * Only ownership is changed, balances are not touched.
                     * Can only be called by asset owner.
                     *
                     * @param _symbol asset symbol.
                     * @param _newOwner address to become a new owner.
                     *
                     * @return success.
                     */
                    function changeOwnership(bytes32 _symbol, address _newOwner) checkEnabledSwitch(sha3(_symbol, Features.ChangeOwnership)) onlyOwner(_symbol) returns(bool) {
                        Asset asset = assets[_symbol];
                        uint newOwnerId = _createHolderId(_newOwner);
                        // Should pass ownership to another holder.
                        if (asset.owner == newOwnerId) {
                            _error('Cannot pass ownership to oneself');
                            return false;
                        }
                        address oldOwner = _address(asset.owner);
                        asset.owner = newOwnerId;
                        // Internal Out Of Gas/Throw: revert this transaction too;
                        // Recursive Call: safe, all changes already made.
                        eventsHistory.emitOwnershipChange(oldOwner, _address(newOwnerId), _symbol);
                        return true;
                    }
                
                    function setCosignerAddress(Cosigner _cosigner) checkSigned(_createHolderId(msg.sender), 1) returns(bool) {
                        if (!_checkSigned(_cosigner, getHolderId(msg.sender), 1)) {
                            _error('Invalid cosigner');
                            return false;
                        }
                        holders[_createHolderId(msg.sender)].cosigner = _cosigner;
                        return true;
                    }
                
                    function isCosignerSet(uint _holderId) constant returns(bool) {
                        return address(holders[_holderId].cosigner) != 0x0;
                    }
                
                    function _checkSigned(Cosigner _cosigner, uint _holderId, uint _required) internal returns(bool) {
                        return _cosigner.consumeOperation(sha3(msg.data, _holderId), _required);
                    }
                
                    modifier checkSigned(uint _holderId, uint _required) {
                        if (!isCosignerSet(_holderId) || _checkSigned(holders[_holderId].cosigner, _holderId, _required)) {
                            _;
                        } else {
                            _error('Cosigner: access denied');
                        }
                    }
                
                    /**
                     * Check if specified holder trusts an address with recovery procedure.
                     *
                     * @param _from truster.
                     * @param _to trustee.
                     *
                     * @return trust existance.
                     */
                    function isTrusted(address _from, address _to) constant returns(bool) {
                        return holders[getHolderId(_from)].trust[_to];
                    }
                
                    /**
                     * Trust an address to perform recovery procedure for the caller.
                     *
                     * @param _to trustee.
                     *
                     * @return success.
                     */
                    function trust(address _to) returns(bool) {
                        uint fromId = _createHolderId(msg.sender);
                        // Should trust to another address.
                        if (fromId == getHolderId(_to)) {
                            _error('Cannot trust to oneself');
                            return false;
                        }
                        // Should trust to yet untrusted.
                        if (isTrusted(msg.sender, _to)) {
                            _error('Already trusted');
                            return false;
                        }
                        holders[fromId].trust[_to] = true;
                        return true;
                    }
                
                    /**
                     * Revoke trust to perform recovery procedure from an address.
                     *
                     * @param _to trustee.
                     *
                     * @return success.
                     */
                    function distrust(address _to) checkTrust(msg.sender, _to) returns(bool) {
                        holders[getHolderId(msg.sender)].trust[_to] = false;
                        return true;
                    }
                
                    /**
                     * Perform recovery procedure.
                     *
                     * This function logic is actually more of an grantAccess(uint _holderId, address _to).
                     * It grants another address access to recovery subject wallets.
                     * Can only be called by trustee of recovery subject.
                     * If cosigning is enabled, should have atleast 2 confirmations.
                     *
                     * @dev Deprecated. Backward compatibility.
                     *
                     * @param _from holder address to recover from.
                     * @param _to address to grant access to.
                     *
                     * @return success.
                     */
                    function recover(address _from, address _to) checkTrust(_from, msg.sender) returns(bool) {
                        return _grantAccess(getHolderId(_from), _to);
                    }
                
                    /**
                     * Perform recovery procedure.
                     *
                     * This function logic is actually more of an grantAccess(uint _holderId, address _to).
                     * It grants another address access to subject holder wallets.
                     * Can only be called if pre-confirmed by atleast 2 cosign oracles.
                     *
                     * @param _from holder address to recover from.
                     * @param _to address to grant access to.
                     *
                     * @return success.
                     */
                    function grantAccess(address _from, address _to) returns(bool) {
                        if (!isCosignerSet(getHolderId(_from))) {
                            _error('Cosigner not set');
                            return false;
                        }
                        return _grantAccess(getHolderId(_from), _to);
                    }
                
                    function _grantAccess(uint _fromId, address _to) internal checkSigned(_fromId, 2) returns(bool) {
                        // Should recover to previously unused address.
                        if (getHolderId(_to) != 0) {
                            _error('Should recover to new address');
                            return false;
                        }
                        // We take current holder address because it might not equal _from.
                        // It is possible to recover from any old holder address, but event should have the current one.
                        address from = holders[_fromId].addr;
                        holders[_fromId].addr = _to;
                        holderIndex[_to] = _fromId;
                        // Internal Out Of Gas/Throw: revert this transaction too;
                        // Recursive Call: safe, all changes already made.
                        eventsHistory.emitRecovery(from, _to, msg.sender);
                        return true;
                    }
                
                    /**
                     * Sets asset spending allowance for a specified spender.
                     *
                     * Note: to revoke allowance, one needs to set allowance to 0.
                     *
                     * @param _spenderId holder id to set allowance for.
                     * @param _value amount to allow.
                     * @param _symbol asset symbol.
                     * @param _senderId approve initiator holder id.
                     *
                     * @return success.
                     */
                    function _approve(uint _spenderId, uint _value, bytes32 _symbol, uint _senderId) internal checkEnabledSwitch(sha3(_symbol, Features.Allowances)) checkSigned(_senderId, 1) returns(bool) {
                        // Asset should exist.
                        if (!isCreated(_symbol)) {
                            _error('Asset is not issued');
                            return false;
                        }
                        // Should allow to another holder.
                        if (_senderId == _spenderId) {
                            _error('Cannot approve to oneself');
                            return false;
                        }
                        assets[_symbol].wallets[_senderId].allowance[_spenderId] = _value;
                        // Internal Out Of Gas/Throw: revert this transaction too;
                        // Recursive Call: safe, all changes already made.
                        eventsHistory.emitApprove(_address(_senderId), _address(_spenderId), _symbol, _value);
                        if (proxies[_symbol] != 0x0) {
                            // Internal Out Of Gas/Throw: revert this transaction too;
                            // Recursive Call: safe, all changes already made.
                            Proxy(proxies[_symbol]).emitApprove(_address(_senderId), _address(_spenderId), _value);
                        }
                        return true;
                    }
                
                    /**
                     * Sets asset spending allowance for a specified spender.
                     *
                     * Can only be called by asset proxy.
                     *
                     * @param _spender holder address to set allowance to.
                     * @param _value amount to allow.
                     * @param _symbol asset symbol.
                     * @param _sender approve initiator address.
                     *
                     * @return success.
                     */
                    function proxyApprove(address _spender, uint _value, bytes32 _symbol, address _sender) onlyProxy(_symbol) returns(bool) {
                        return _approve(_createHolderId(_spender), _value, _symbol, _createHolderId(_sender));
                    }
                
                    /**
                     * Returns asset allowance from one holder to another.
                     *
                     * @param _from holder that allowed spending.
                     * @param _spender holder that is allowed to spend.
                     * @param _symbol asset symbol.
                     *
                     * @return holder to spender allowance.
                     */
                    function allowance(address _from, address _spender, bytes32 _symbol) constant returns(uint) {
                        return _allowance(getHolderId(_from), getHolderId(_spender), _symbol);
                    }
                
                    /**
                     * Returns asset allowance from one holder to another.
                     *
                     * @param _fromId holder id that allowed spending.
                     * @param _toId holder id that is allowed to spend.
                     * @param _symbol asset symbol.
                     *
                     * @return holder to spender allowance.
                     */
                    function _allowance(uint _fromId, uint _toId, bytes32 _symbol) constant internal returns(uint) {
                        return assets[_symbol].wallets[_fromId].allowance[_toId];
                    }
                
                    /**
                     * Prforms allowance transfer of asset balance between holders wallets.
                     *
                     * Can only be called by asset proxy.
                     *
                     * @param _from holder address to take from.
                     * @param _to holder address to give to.
                     * @param _value amount to transfer.
                     * @param _symbol asset symbol.
                     * @param _reference transfer comment to be included in a Transfer event.
                     * @param _sender allowance transfer initiator address.
                     *
                     * @return success.
                     */
                    function proxyTransferFromWithReference(address _from, address _to, uint _value, bytes32 _symbol, string _reference, address _sender) onlyProxy(_symbol) returns(bool) {
                        return _transfer(getHolderId(_from), _createHolderId(_to), _value, _symbol, _reference, getHolderId(_sender));
                    }
                }

                File 4 of 4: MultiAssetEmitter
                // This software is a subject to Ambisafe License Agreement.
                // No use or distribution is allowed without written permission from Ambisafe.
                // https://ambisafe.com/terms.pdf
                
                contract EventsHistory {
                    function versions(address) constant returns(uint);
                }
                
                /**
                 * @title MultiAsset Emitter.
                 *
                 * Contains all the original event emitting function definitions and events.
                 * In case of new events needed later, additional emitters can be developed.
                 * All the functions is meant to be called using delegatecall.
                 */
                library MultiAssetEmitter {
                    event Transfer(address indexed from, address indexed to, bytes32 indexed symbol, uint value, string reference, uint version);
                    event Issue(bytes32 indexed symbol, uint value, address by, uint version);
                    event Revoke(bytes32 indexed symbol, uint value, address by, uint version);
                    event OwnershipChange(address indexed from, address indexed to, bytes32 indexed symbol, uint version);
                    event Approve(address indexed from, address indexed spender, bytes32 indexed symbol, uint value, uint version);
                    event Recovery(address indexed from, address indexed to, address by, uint version);
                    event TransferToICAP(address indexed from, address indexed to, bytes32 indexed icap, uint value, string reference, uint version);
                    event Error(bytes32 message, uint version);
                    
                    function emitTransfer(address _from, address _to, bytes32 _symbol, uint _value, string _reference) {
                        Transfer(_from, _to, _symbol, _value, _reference, _getVersion());
                    }
                
                    function emitIssue(bytes32 _symbol, uint _value, address _by) {
                        Issue(_symbol, _value, _by, _getVersion());
                    }
                
                    function emitRevoke(bytes32 _symbol, uint _value, address _by) {
                        Revoke(_symbol, _value, _by, _getVersion());
                    }
                
                    function emitOwnershipChange(address _from, address _to, bytes32 _symbol) {
                        OwnershipChange(_from, _to, _symbol, _getVersion());
                    }
                
                    function emitApprove(address _from, address _spender, bytes32 _symbol, uint _value) {
                        Approve(_from, _spender, _symbol, _value, _getVersion());
                    }
                
                    function emitRecovery(address _from, address _to, address _by) {
                        Recovery(_from, _to, _by, _getVersion());
                    }
                
                    function emitTransferToICAP(address _from, address _to, bytes32 _icap, uint _value, string _reference) {
                        TransferToICAP(_from, _to, _icap, _value, _reference, _getVersion());
                    }
                
                    function emitError(bytes32 _message) {
                        Error(_message, _getVersion());
                    }
                
                    /**
                     * Get version number of the caller.
                     *
                     * Assuming that the call is made by EventsHistory using delegate call,
                     * context was not changed, so the caller is the address that called
                     * EventsHistory.
                     *
                     * @return current context caller version number.
                     */
                    function _getVersion() constant internal returns(uint) {
                        return EventsHistory(address(this)).versions(msg.sender);
                    }
                }