ETH Price: $1,863.12 (-0.52%)

Transaction Decoder

Block:
12075304 at Mar-20-2021 11:01:56 AM +UTC
Transaction Fee:
0.0099585612 ETH $18.55
Gas Used:
83,196 Gas / 119.7 Gwei

Emitted Events:

201 EventsHistory.0x940c4b3549ef0aaff95807dc27f62d88ca15532d1bf535d7d63800f40395d16c( 0x940c4b3549ef0aaff95807dc27f62d88ca15532d1bf535d7d63800f40395d16c, 0x0000000000000000000000000d0707963952f2fba59dd06f2b425ace40b492fe, 0x00000000000000000000000011a885a7258628f976d484eba9ecb5fff855bbe2, 0x5246520000000000000000000000000000000000000000000000000000000000, 00000000000000000000000000000000000000000000000000000000b910c08a, 0000000000000000000000000000000000000000000000000000000000000060, 0000000000000000000000000000000000000000000000000000000000000002, 0000000000000000000000000000000000000000000000000000000000000000 )
202 Refereum.Transfer( from=[Sender] 0x0d0707963952f2fba59dd06f2b425ace40b492fe, to=0x11a885a7258628f976d484eBa9eCb5FFf855BbE2, value=3104882826 )

Account State Difference:

  Address   Before After State Difference Code
0x0D070796...e40b492Fe
(Gate.io 1)
6,526.044880085518995226 Eth
Nonce: 2389915
6,526.034921524318995226 Eth
Nonce: 2389916
0.0099585612
0x331d0775...84c411F84
(Spark Pool)
5.184534867145152735 Eth5.194493428345152735 Eth0.0099585612

Execution Trace

Refereum.transfer( _to=0x11a885a7258628f976d484eBa9eCb5FFf855BbE2, _value=3104882826 ) => ( True )
  • 0xdfb0acd77b0a9538d2d1b05399a1f254a541076f.1962df71( )
    • 0x79f8818d98e6f6eb33aa3468091281c2576e969d.f7ebc39a( )
    • Refereum._forwardTransferFromWithReference( _from=0x0D0707963952f2fBA59dD06f2b425ace40b492Fe, _to=0x11a885a7258628f976d484eBa9eCb5FFf855BbE2, _value=3104882826, _reference=, _sender=0x0D0707963952f2fBA59dD06f2b425ace40b492Fe ) => ( True )
      • EToken2.proxyTransferFromWithReference( _from=0x0D0707963952f2fBA59dD06f2b425ace40b492Fe, _to=0x11a885a7258628f976d484eBa9eCb5FFf855BbE2, _value=3104882826, _symbol=5246520000000000000000000000000000000000000000000000000000000000, _reference=, _sender=0x0D0707963952f2fBA59dD06f2b425ace40b492Fe ) => ( True )
        • EventsHistory.515c1457( )
          • MultiAssetEmitter.emitTransfer( _from=0x0D0707963952f2fBA59dD06f2b425ace40b492Fe, _to=0x11a885a7258628f976d484eBa9eCb5FFf855BbE2, _symbol=5246520000000000000000000000000000000000000000000000000000000000, _value=3104882826, _reference= )
            • EventsHistory.versions( 0x331d077518216c07C87f4f18bA64cd384c411F84 ) => ( 2 )
            • Null: 0x000...004.CALL( )
            • Refereum.emitTransfer( _from=0x0D0707963952f2fBA59dD06f2b425ace40b492Fe, _to=0x11a885a7258628f976d484eBa9eCb5FFf855BbE2, _value=3104882826 )
              transfer[Refereum (ln:211)]
              File 1 of 4: Refereum
              pragma solidity 0.4.11;
              
              contract RegistryICAPInterface {
                  function parse(bytes32 _icap) constant returns(address, bytes32, bool);
                  function institutions(bytes32 _institution) constant returns(address);
              }
              
              contract EToken2Interface {
                  function registryICAP() constant returns(RegistryICAPInterface);
                  function baseUnit(bytes32 _symbol) constant returns(uint8);
                  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 isLocked(bytes32 _symbol) constant returns(bool);
                  function issueAsset(bytes32 _symbol, uint _value, string _name, string _description, uint8 _baseUnit, bool _isReissuable) returns(bool);
                  function reissueAsset(bytes32 _symbol, uint _value) returns(bool);
                  function revokeAsset(bytes32 _symbol, uint _value) returns(bool);
                  function setProxy(address _address, bytes32 _symbol) returns(bool);
                  function lockAsset(bytes32 _symbol) returns(bool);
                  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 AssetInterface {
                  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 ERC20Interface {
                  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 symbol() constant returns(string);
                  function decimals() constant returns(uint8);
                  // function name() constant returns(string);
              }
              
              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);
                  function balanceOf(address _owner) constant returns(uint);
              }
              
              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 Refereum is ERC20Interface, AssetProxyInterface, Bytes32 {
                  // 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) 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(AssetInterface) {
                      return AssetInterface(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(EToken2Interface) {
                      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);
                  }
              }