ETH Price: $2,535.06 (-3.75%)

Transaction Decoder

Block:
7917765 at Jun-08-2019 10:16:00 AM +UTC
Transaction Fee:
0.00212876 ETH $5.40
Gas Used:
106,438 Gas / 20 Gwei

Account State Difference:

  Address   Before After State Difference Code
(Spark Pool)
2,462.209822973313050795 Eth2,462.211951733313050795 Eth0.00212876
0xD26205A5...ec43B3802
0.046070344542555599 Eth
Nonce: 60
0.043941584542555599 Eth
Nonce: 61
0.00212876

Execution Trace

IOTW.transfer( _to=0x4C77aEF67feC6815Eb5d78Dd68a3FD4b1cfE2d66, _value=1900000000 )
  • Asset._performTransferWithReference( _to=0x4C77aEF67feC6815Eb5d78Dd68a3FD4b1cfE2d66, _value=1900000000, _reference=, _sender=0xD26205A544EC45d8611DF4D3f22b1b3ec43B3802 )
    • IOTW._forwardTransferFromWithReference( _from=0xD26205A544EC45d8611DF4D3f22b1b3ec43B3802, _to=0x4C77aEF67feC6815Eb5d78Dd68a3FD4b1cfE2d66, _value=1900000000, _reference=, _sender=0xD26205A544EC45d8611DF4D3f22b1b3ec43B3802 )
      • EToken2.proxyTransferFromWithReference( _from=0xD26205A544EC45d8611DF4D3f22b1b3ec43B3802, _to=0x4C77aEF67feC6815Eb5d78Dd68a3FD4b1cfE2d66, _value=1900000000, _symbol=494F545700000000000000000000000000000000000000000000000000000000, _reference=, _sender=0xD26205A544EC45d8611DF4D3f22b1b3ec43B3802 )
        transfer[IOTW (ln:363)]
        File 1 of 3: IOTW
        // File: contracts/EToken2Interface.sol
        
        pragma solidity 0.4.23;
        
        
        contract RegistryICAPInterface {
            function parse(bytes32 _icap) public view returns(address, bytes32, bool);
            function institutions(bytes32 _institution) public view returns(address);
        }
        
        
        contract EToken2Interface {
            function registryICAP() public view returns(RegistryICAPInterface);
            function baseUnit(bytes32 _symbol) public view returns(uint8);
            function description(bytes32 _symbol) public view returns(string);
            function owner(bytes32 _symbol) public view returns(address);
            function isOwner(address _owner, bytes32 _symbol) public view returns(bool);
            function totalSupply(bytes32 _symbol) public view returns(uint);
            function balanceOf(address _holder, bytes32 _symbol) public view returns(uint);
            function isLocked(bytes32 _symbol) public view returns(bool);
        
            function issueAsset(
                bytes32 _symbol,
                uint _value,
                string _name,
                string _description,
                uint8 _baseUnit,
                bool _isReissuable)
            public returns(bool);
        
            function reissueAsset(bytes32 _symbol, uint _value) public returns(bool);
            function revokeAsset(bytes32 _symbol, uint _value) public returns(bool);
            function setProxy(address _address, bytes32 _symbol) public returns(bool);
            function lockAsset(bytes32 _symbol) public returns(bool);
        
            function proxyTransferFromToICAPWithReference(
                address _from,
                bytes32 _icap,
                uint _value,
                string _reference,
                address _sender)
            public returns(bool);
        
            function proxyApprove(address _spender, uint _value, bytes32 _symbol, address _sender)
            public returns(bool);
            
            function allowance(address _from, address _spender, bytes32 _symbol) public view returns(uint);
        
            function proxyTransferFromWithReference(
                address _from,
                address _to,
                uint _value,
                bytes32 _symbol,
                string _reference,
                address _sender)
            public returns(bool);
        
            function changeOwnership(bytes32 _symbol, address _newOwner) public returns(bool);
        }
        
        // File: contracts/AssetInterface.sol
        
        pragma solidity 0.4.23;
        
        
        contract AssetInterface {
            function _performTransferWithReference(
                address _to,
                uint _value,
                string _reference,
                address _sender)
            public returns(bool);
        
            function _performTransferToICAPWithReference(
                bytes32 _icap,
                uint _value,
                string _reference,
                address _sender)
            public returns(bool);
        
            function _performApprove(address _spender, uint _value, address _sender)
            public returns(bool);
        
            function _performTransferFromWithReference(
                address _from,
                address _to,
                uint _value,
                string _reference,
                address _sender)
            public returns(bool);
        
            function _performTransferFromToICAPWithReference(
                address _from,
                bytes32 _icap,
                uint _value,
                string _reference,
                address _sender)
            public returns(bool);
        
            function _performGeneric(bytes, address) public payable {
                revert();
            }
        }
        
        // File: contracts/ERC20Interface.sol
        
        pragma solidity 0.4.23;
        
        
        contract ERC20Interface {
            event Transfer(address indexed from, address indexed to, uint256 value);
            event Approval(address indexed from, address indexed spender, uint256 value);
        
            function totalSupply() public view returns(uint256 supply);
            function balanceOf(address _owner) public view returns(uint256 balance);
            // solhint-disable-next-line no-simple-event-func-name
            function transfer(address _to, uint256 _value) public returns(bool success);
            function transferFrom(address _from, address _to, uint256 _value) public returns(bool success);
            function approve(address _spender, uint256 _value) public returns(bool success);
            function allowance(address _owner, address _spender) public view returns(uint256 remaining);
        
            // function symbol() constant returns(string);
            function decimals() public view returns(uint8);
            // function name() constant returns(string);
        }
        
        // File: contracts/AssetProxyInterface.sol
        
        pragma solidity 0.4.23;
        
        
        
        contract AssetProxyInterface is ERC20Interface {
            function _forwardApprove(address _spender, uint _value, address _sender)
            public returns(bool);
        
            function _forwardTransferFromWithReference(
                address _from,
                address _to,
                uint _value,
                string _reference,
                address _sender)
            public returns(bool);
        
            function _forwardTransferFromToICAPWithReference(
                address _from,
                bytes32 _icap,
                uint _value,
                string _reference,
                address _sender)
            public returns(bool);
        
            function recoverTokens(ERC20Interface _asset, address _receiver, uint _value)
            public returns(bool);
        
            // solhint-disable-next-line no-empty-blocks
            function etoken2() public pure returns(address) {} // To be replaced by the implicit getter;
        
            // To be replaced by the implicit getter;
            // solhint-disable-next-line no-empty-blocks
            function etoken2Symbol() public pure returns(bytes32) {}
        }
        
        // File: contracts/helpers/Bytes32.sol
        
        pragma solidity 0.4.23;
        
        
        contract Bytes32 {
            function _bytes32(string _input) internal pure returns(bytes32 result) {
                assembly {
                    result := mload(add(_input, 32))
                }
            }
        }
        
        // File: contracts/helpers/ReturnData.sol
        
        pragma solidity 0.4.23;
        
        
        contract ReturnData {
            function _returnReturnData(bool _success) internal pure {
                assembly {
                    let returndatastart := 0
                    returndatacopy(returndatastart, 0, returndatasize)
                    switch _success case 0 { revert(returndatastart, returndatasize) }
                        default { return(returndatastart, returndatasize) }
                }
            }
        
            function _assemblyCall(address _destination, uint _value, bytes _data)
            internal returns(bool success) {
                assembly {
                    success := call(gas, _destination, _value, add(_data, 32), mload(_data), 0, 0)
                }
            }
        }
        
        // File: contracts/AssetProxy.sol
        
        pragma solidity 0.4.23;
        
        
        
        
        
        
        
        
        /**
         * @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 IOTW is ERC20Interface, AssetProxyInterface, Bytes32, ReturnData {
            // Assigned EToken2, immutable.
            EToken2Interface 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(EToken2Interface _etoken2, string _symbol, string _name) public 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 view returns(AssetInterface) {
                return AssetInterface(getVersionFor(msg.sender));
            }
        
            /**
             * Recovers tokens on proxy contract
             *
             * @param _asset type of tokens to recover.
             * @param _value tokens that will be recovered.
             * @param _receiver address where to send recovered tokens.
             *
             * @return success.
             */
            function recoverTokens(ERC20Interface _asset, address _receiver, uint _value)
            public onlyAssetOwner() returns(bool) {
                return _asset.transfer(_receiver, _value);
            }
        
            /**
             * Returns asset total supply.
             *
             * @return asset total supply.
             */
            function totalSupply() public view returns(uint) {
                return etoken2.totalSupply(etoken2Symbol);
            }
        
            /**
             * Returns asset balance for a particular holder.
             *
             * @param _owner holder address.
             *
             * @return holder balance.
             */
            function balanceOf(address _owner) public view 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) public view returns(uint) {
                return etoken2.allowance(_from, _spender, etoken2Symbol);
            }
        
            /**
             * Returns asset decimals.
             *
             * @return asset decimals.
             */
            function decimals() public view 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) public 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)
            public 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) public 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)
            public 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) public 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)
            public 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)
            public 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)
            public 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)
            public 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)
            public 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) public 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)
            public 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) public onlyEToken2() {
                emit 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) public onlyEToken2() {
                emit 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 () public payable {
                _getAsset()._performGeneric.value(msg.value)(msg.data, msg.sender);
                _returnReturnData(true);
            }
        
            // Interface functions to allow specifying ICAP addresses as strings.
            function transferToICAP(string _icap, uint _value) public returns(bool) {
                return transferToICAPWithReference(_icap, _value, '');
            }
        
            function transferToICAPWithReference(string _icap, uint _value, string _reference)
            public returns(bool) {
                return transferToICAPWithReference(_bytes32(_icap), _value, _reference);
            }
        
            function transferFromToICAP(address _from, string _icap, uint _value) public returns(bool) {
                return transferFromToICAPWithReference(_from, _icap, _value, '');
            }
        
            function transferFromToICAPWithReference(
                address _from,
                string _icap,
                uint _value,
                string _reference)
            public returns(bool) {
                return transferFromToICAPWithReference(_from, _bytes32(_icap), _value, _reference);
            }
        
            /**
             * Indicates an upgrade freeze-time start, and the next asset implementation contract.
             */
            event UpgradeProposed(address newVersion);
            event UpgradePurged(address newVersion);
            event UpgradeCommited(address newVersion);
            event OptedOut(address sender, address version);
            event OptedIn(address sender, address version);
        
            // Current asset implementation contract address.
            address internal latestVersion;
        
            // Proposed next asset implementation contract address.
            address internal pendingVersion;
        
            // Upgrade freeze-time start.
            uint internal pendingVersionTimestamp;
        
            // Timespan for users to review the new implementation and make decision.
            uint internal 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) internal 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) public view returns(address) {
                return userOptOutVersion[_sender] == 0 ? latestVersion : userOptOutVersion[_sender];
            }
        
            /**
             * Returns current asset implementation contract address.
             *
             * @return asset implementation contract address.
             */
            function getLatestVersion() public view returns(address) {
                return latestVersion;
            }
        
            /**
             * Returns proposed next asset implementation contract address.
             *
             * @return asset implementation contract address.
             */
            function getPendingVersion() public view returns(address) {
                return pendingVersion;
            }
        
            /**
             * Returns upgrade freeze-time start.
             *
             * @return freeze-time start.
             */
            function getPendingVersionTimestamp() public view 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) public 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;
                // solhint-disable-next-line not-rely-on-time
                pendingVersionTimestamp = now;
                emit UpgradeProposed(_newVersion);
                return true;
            }
        
            /**
             * Cancel the pending upgrade process.
             *
             * Can only be called by current asset owner.
             *
             * @return success.
             */
            function purgeUpgrade() public onlyAssetOwner() returns(bool) {
                if (pendingVersion == 0x0) {
                    return false;
                }
                emit UpgradePurged(pendingVersion);
                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() public returns(bool) {
                if (pendingVersion == 0x0) {
                    return false;
                }
                // solhint-disable-next-line not-rely-on-time
                if (pendingVersionTimestamp + UPGRADE_FREEZE_TIME > now) {
                    return false;
                }
                latestVersion = pendingVersion;
                delete pendingVersion;
                delete pendingVersionTimestamp;
                emit UpgradeCommited(latestVersion);
                return true;
            }
        
            /**
             * Disagree with proposed upgrade, and stick with current asset implementation
             * until further explicit agreement to upgrade.
             *
             * @return success.
             */
            function optOut() public returns(bool) {
                if (userOptOutVersion[msg.sender] != 0x0) {
                    return false;
                }
                userOptOutVersion[msg.sender] = latestVersion;
                emit OptedOut(msg.sender, latestVersion);
                return true;
            }
        
            /**
             * Implicitly agree to upgrade to current and future asset implementation upgrades,
             * until further explicit disagreement.
             *
             * @return success.
             */
            function optIn() public returns(bool) {
                delete userOptOutVersion[msg.sender];
                emit OptedIn(msg.sender, latestVersion);
                return true;
            }
        
            // Backwards compatibility.
            function multiAsset() public view returns(EToken2Interface) {
                return etoken2;
            }
        }
        

        File 2 of 3: Asset
        // File: contracts/AssetInterface.sol
        
        pragma solidity 0.4.23;
        
        
        contract AssetInterface {
            function _performTransferWithReference(
                address _to,
                uint _value,
                string _reference,
                address _sender)
            public returns(bool);
        
            function _performTransferToICAPWithReference(
                bytes32 _icap,
                uint _value,
                string _reference,
                address _sender)
            public returns(bool);
        
            function _performApprove(address _spender, uint _value, address _sender)
            public returns(bool);
        
            function _performTransferFromWithReference(
                address _from,
                address _to,
                uint _value,
                string _reference,
                address _sender)
            public returns(bool);
        
            function _performTransferFromToICAPWithReference(
                address _from,
                bytes32 _icap,
                uint _value,
                string _reference,
                address _sender)
            public returns(bool);
        
            function _performGeneric(bytes, address) public payable {
                revert();
            }
        }
        
        // File: contracts/ERC20Interface.sol
        
        pragma solidity 0.4.23;
        
        
        contract ERC20Interface {
            event Transfer(address indexed from, address indexed to, uint256 value);
            event Approval(address indexed from, address indexed spender, uint256 value);
        
            function totalSupply() public view returns(uint256 supply);
            function balanceOf(address _owner) public view returns(uint256 balance);
            // solhint-disable-next-line no-simple-event-func-name
            function transfer(address _to, uint256 _value) public returns(bool success);
            function transferFrom(address _from, address _to, uint256 _value) public returns(bool success);
            function approve(address _spender, uint256 _value) public returns(bool success);
            function allowance(address _owner, address _spender) public view returns(uint256 remaining);
        
            // function symbol() constant returns(string);
            function decimals() public view returns(uint8);
            // function name() constant returns(string);
        }
        
        // File: contracts/AssetProxyInterface.sol
        
        pragma solidity 0.4.23;
        
        
        
        contract AssetProxyInterface is ERC20Interface {
            function _forwardApprove(address _spender, uint _value, address _sender)
            public returns(bool);
        
            function _forwardTransferFromWithReference(
                address _from,
                address _to,
                uint _value,
                string _reference,
                address _sender)
            public returns(bool);
        
            function _forwardTransferFromToICAPWithReference(
                address _from,
                bytes32 _icap,
                uint _value,
                string _reference,
                address _sender)
            public returns(bool);
        
            function recoverTokens(ERC20Interface _asset, address _receiver, uint _value)
            public returns(bool);
        
            // solhint-disable-next-line no-empty-blocks
            function etoken2() public pure returns(address) {} // To be replaced by the implicit getter;
        
            // To be replaced by the implicit getter;
            // solhint-disable-next-line no-empty-blocks
            function etoken2Symbol() public pure returns(bytes32) {}
        }
        
        // File: contracts/helpers/Bytes32.sol
        
        pragma solidity 0.4.23;
        
        
        contract Bytes32 {
            function _bytes32(string _input) internal pure returns(bytes32 result) {
                assembly {
                    result := mload(add(_input, 32))
                }
            }
        }
        
        // File: contracts/helpers/ReturnData.sol
        
        pragma solidity 0.4.23;
        
        
        contract ReturnData {
            function _returnReturnData(bool _success) internal pure {
                assembly {
                    let returndatastart := 0
                    returndatacopy(returndatastart, 0, returndatasize)
                    switch _success case 0 { revert(returndatastart, returndatasize) }
                        default { return(returndatastart, returndatasize) }
                }
            }
        
            function _assemblyCall(address _destination, uint _value, bytes _data)
            internal returns(bool success) {
                assembly {
                    success := call(gas, _destination, _value, add(_data, 32), mload(_data), 0, 0)
                }
            }
        }
        
        // File: contracts/Asset.sol
        
        pragma solidity 0.4.23;
        
        
        
        
        
        
        /**
         * @title EToken2 Asset implementation contract.
         *
         * Basic asset implementation contract, without any additional logic.
         * Every other asset implementation contracts should derive from this one.
         * Receives calls from the proxy, and calls back immediately without arguments modification.
         *
         * Note: all the non constant functions return false instead of throwing in case if state change
         * didn't happen yet.
         */
        contract Asset is AssetInterface, Bytes32, ReturnData {
            // Assigned asset proxy contract, immutable.
            AssetProxyInterface public proxy;
        
            /**
             * Only assigned proxy is allowed to call.
             */
            modifier onlyProxy() {
                if (proxy == msg.sender) {
                    _;
                }
            }
        
            /**
             * Sets asset proxy address.
             *
             * Can be set only once.
             *
             * @param _proxy asset proxy contract address.
             *
             * @return success.
             * @dev function is final, and must not be overridden.
             */
            function init(AssetProxyInterface _proxy) public returns(bool) {
                if (address(proxy) != 0x0) {
                    return false;
                }
                proxy = _proxy;
                return true;
            }
        
            /**
             * Passes execution into virtual function.
             *
             * Can only be called by assigned asset proxy.
             *
             * @return success.
             * @dev function is final, and must not be overridden.
             */
            function _performTransferWithReference(
                address _to,
                uint _value,
                string _reference,
                address _sender)
            public onlyProxy() returns(bool) {
                if (isICAP(_to)) {
                    return _transferToICAPWithReference(
                        bytes32(_to) << 96, _value, _reference, _sender);
                }
                return _transferWithReference(_to, _value, _reference, _sender);
            }
        
            /**
             * Calls back without modifications.
             *
             * @return success.
             * @dev function is virtual, and meant to be overridden.
             */
            function _transferWithReference(
                address _to,
                uint _value,
                string _reference,
                address _sender)
            internal returns(bool) {
                return proxy._forwardTransferFromWithReference(
                    _sender, _to, _value, _reference, _sender);
            }
        
            /**
             * Passes execution into virtual function.
             *
             * Can only be called by assigned asset proxy.
             *
             * @return success.
             * @dev function is final, and must not be overridden.
             */
            function _performTransferToICAPWithReference(
                bytes32 _icap,
                uint _value,
                string _reference,
                address _sender)
            public onlyProxy() returns(bool) {
                return _transferToICAPWithReference(_icap, _value, _reference, _sender);
            }
        
            /**
             * Calls back without modifications.
             *
             * @return success.
             * @dev function is virtual, and meant to be overridden.
             */
            function _transferToICAPWithReference(
                bytes32 _icap,
                uint _value,
                string _reference,
                address _sender)
            internal returns(bool) {
                return proxy._forwardTransferFromToICAPWithReference(
                    _sender, _icap, _value, _reference, _sender);
            }
        
            /**
             * Passes execution into virtual function.
             *
             * Can only be called by assigned asset proxy.
             *
             * @return success.
             * @dev function is final, and must not be overridden.
             */
            function _performTransferFromWithReference(
                address _from,
                address _to,
                uint _value,
                string _reference,
                address _sender)
            public onlyProxy() returns(bool) {
                if (isICAP(_to)) {
                    return _transferFromToICAPWithReference(
                        _from, bytes32(_to) << 96, _value, _reference, _sender);
                }
                return _transferFromWithReference(_from, _to, _value, _reference, _sender);
            }
        
            /**
             * Calls back without modifications.
             *
             * @return success.
             * @dev function is virtual, and meant to be overridden.
             */
            function _transferFromWithReference(
                address _from,
                address _to,
                uint _value,
                string _reference,
                address _sender)
            internal returns(bool) {
                return proxy._forwardTransferFromWithReference(
                    _from, _to, _value, _reference, _sender);
            }
        
            /**
             * Passes execution into virtual function.
             *
             * Can only be called by assigned asset proxy.
             *
             * @return success.
             * @dev function is final, and must not be overridden.
             */
            function _performTransferFromToICAPWithReference(
                address _from,
                bytes32 _icap,
                uint _value,
                string _reference,
                address _sender)
            public onlyProxy() returns(bool) {
                return _transferFromToICAPWithReference(
                    _from, _icap, _value, _reference, _sender);
            }
        
            /**
             * Calls back without modifications.
             *
             * @return success.
             * @dev function is virtual, and meant to be overridden.
             */
            function _transferFromToICAPWithReference(
                address _from,
                bytes32 _icap,
                uint _value,
                string _reference,
                address _sender)
            internal returns(bool) {
                return proxy._forwardTransferFromToICAPWithReference(
                    _from, _icap, _value, _reference, _sender);
            }
        
            /**
             * Passes execution into virtual function.
             *
             * Can only be called by assigned asset proxy.
             *
             * @return success.
             * @dev function is final, and must not be overridden.
             */
            function _performApprove(address _spender, uint _value, address _sender)
            public onlyProxy() returns(bool) {
                return _approve(_spender, _value, _sender);
            }
        
            /**
             * Calls back without modifications.
             *
             * @return success.
             * @dev function is virtual, and meant to be overridden.
             */
            function _approve(address _spender, uint _value, address _sender) 
            internal returns(bool) {
                return proxy._forwardApprove(_spender, _value, _sender);
            }
        
            /**
             * Passes execution into virtual function.
             *
             * Can only be called by assigned asset proxy.
             *
             * @return bytes32 result.
             * @dev function is final, and must not be overridden.
             */
            function _performGeneric(bytes _data, address _sender)
            public payable onlyProxy() {
                _generic(_data, msg.value, _sender);
            }
        
            modifier onlyMe() {
                if (this == msg.sender) {
                    _;
                }
            }
        
            // Most probably the following should never be redefined in child contracts.
            address public genericSender;
        
            function _generic(bytes _data, uint _value, address _msgSender) internal {
                // Restrict reentrancy.
                require(genericSender == 0x0);
                genericSender = _msgSender;
                bool success = _assemblyCall(address(this), _value, _data);
                delete genericSender;
                _returnReturnData(success);
            }
        
            // Decsendants should use _sender() instead of msg.sender to properly process proxied calls.
            function _sender() internal view returns(address) {
                return this == msg.sender ? genericSender : msg.sender;
            }
        
            // Interface functions to allow specifying ICAP addresses as strings.
            function transferToICAP(string _icap, uint _value) public returns(bool) {
                return transferToICAPWithReference(_icap, _value, '');
            }
        
            function transferToICAPWithReference(string _icap, uint _value, string _reference)
            public returns(bool) {
                return _transferToICAPWithReference(
                    _bytes32(_icap), _value, _reference, _sender());
            }
        
            function transferFromToICAP(address _from, string _icap, uint _value)
            public returns(bool) {
                return transferFromToICAPWithReference(_from, _icap, _value, '');
            }
        
            function transferFromToICAPWithReference(
                address _from,
                string _icap,
                uint _value,
                string _reference)
            public returns(bool) {
                return _transferFromToICAPWithReference(
                    _from, _bytes32(_icap), _value, _reference, _sender());
            }
        
            function isICAP(address _address) public pure returns(bool) {
                bytes32 a = bytes32(_address) << 96;
                if (a[0] != 'X' || a[1] != 'E') {
                    return false;
                }
                if (a[2] < 48 || a[2] > 57 || a[3] < 48 || a[3] > 57) {
                    return false;
                }
                for (uint i = 4; i < 20; i++) {
                    uint char = uint(a[i]);
                    if (char < 48 || char > 90 || (char > 57 && char < 65)) {
                        return false;
                    }
                }
                return true;
            }
        }
        

        File 3 of 3: 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));
            }
        }