ETH Price: $2,152.93 (-0.53%)

Transaction Decoder

Block:
5092993 at Feb-15-2018 05:46:44 AM +UTC
Transaction Fee:
0.00048391 ETH $1.04
Gas Used:
48,391 Gas / 10 Gwei

Emitted Events:

36 MultiEventsHistory.0x8f1b83868d2ecc962fd90cfee71c9c52455fe10940937bc7571d90ba404c5c3b( 0x8f1b83868d2ecc962fd90cfee71c9c52455fe10940937bc7571d90ba404c5c3b, 0x000000000000000000000000915e687400b8ae7d64f4a2e5718db178283f8502, 0x0000000000000000000000005e575279bf9f4acf0a130c186861454247394c06, 0x424d430000000000000000000000000000000000000000000000000000000000, 000000000000000000000000000000000000000000000000000000073e2316fd, 0000000000000000000000000000000000000000000000000000000000000040, 0000000000000000000000000000000000000000000000000000000000000000 )
37 BMCAssetProxy.Transfer( from=[Sender] 0x915e687400b8ae7d64f4a2e5718db178283f8502, to=0x5E575279bf9f4acf0A130c186861454247394C06, value=31107258109 )

Account State Difference:

  Address   Before After State Difference Code
0x915E6874...8283f8502
0.009399322 Eth
Nonce: 1
0.008915412 Eth
Nonce: 2
0.00048391
0x939C0304...bebc983BA
(Ethermine)
918.326198632483802377 Eth918.326682542483802377 Eth0.00048391

Execution Trace

BMCAssetProxy.transfer( _to=0x5E575279bf9f4acf0A130c186861454247394C06, _value=31107258109 ) => ( True )
  • BMC.__transferWithReference( _to=0x5E575279bf9f4acf0A130c186861454247394C06, _value=31107258109, _reference=, _sender=0x915E687400b8aE7D64F4A2E5718dB178283f8502 ) => ( True )
    • BMCAssetProxy.__transferWithReference( _to=0x5E575279bf9f4acf0A130c186861454247394C06, _value=31107258109, _reference=, _sender=0x915E687400b8aE7D64F4A2E5718dB178283f8502 ) => ( True )
      • BMCPlatform.proxyTransferWithReference( _to=0x5E575279bf9f4acf0A130c186861454247394C06, _value=31107258109, _symbol=424D430000000000000000000000000000000000000000000000000000000000, _reference=, _sender=0x915E687400b8aE7D64F4A2E5718dB178283f8502 ) => ( errorCode=1 )
        • MultiEventsHistory.515c1457( )
          • BMCPlatform.emitTransfer( _from=0x915E687400b8aE7D64F4A2E5718dB178283f8502, _to=0x5E575279bf9f4acf0A130c186861454247394C06, _symbol=424D430000000000000000000000000000000000000000000000000000000000, _value=31107258109, _reference= )
          • BMCAssetProxy.emitTransfer( _from=0x915E687400b8aE7D64F4A2E5718dB178283f8502, _to=0x5E575279bf9f4acf0A130c186861454247394C06, _value=31107258109 )
            File 1 of 4: BMCAssetProxy
            pragma solidity ^0.4.11;
            
            contract BMCPlatform {
                mapping(bytes32 => address) public proxies;
                function name(bytes32 _symbol) returns(string);
                function setProxy(address _address, bytes32 _symbol) returns(uint errorCode);
                function isOwner(address _owner, bytes32 _symbol) returns(bool);
                function totalSupply(bytes32 _symbol) returns(uint);
                function balanceOf(address _holder, bytes32 _symbol) returns(uint);
                function allowance(address _from, address _spender, bytes32 _symbol) returns(uint);
                function baseUnit(bytes32 _symbol) returns(uint8);
                function proxyTransferWithReference(address _to, uint _value, bytes32 _symbol, string _reference, address _sender) returns(uint errorCode);
                function proxyTransferFromWithReference(address _from, address _to, uint _value, bytes32 _symbol, string _reference, address _sender) returns(uint errorCode);
                function proxyApprove(address _spender, uint _value, bytes32 _symbol, address _sender) returns(uint errorCode);
                function issueAsset(bytes32 _symbol, uint _value, string _name, string _description, uint8 _baseUnit, bool _isReissuable) returns(uint errorCode);
                function reissueAsset(bytes32 _symbol, uint _value) returns(uint errorCode);
                function revokeAsset(bytes32 _symbol, uint _value) returns(uint errorCode);
                function isReissuable(bytes32 _symbol) returns(bool);
                function changeOwnership(bytes32 _symbol, address _newOwner) returns(uint errorCode);
            }
            
            contract BMCAsset {
                function __transferWithReference(address _to, uint _value, string _reference, address _sender) returns(bool);
                function __transferFromWithReference(address _from, address _to, uint _value, string _reference, address _sender) returns(bool);
                function __approve(address _spender, uint _value, address _sender) returns(bool);
                function __process(bytes _data, address _sender) payable {
                    throw;
                }
            }
            
            contract ERC20 {
                event Transfer(address indexed from, address indexed to, uint256 value);
                event Approval(address indexed from, address indexed spender, uint256 value);
                string public symbol;
            
                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);
            }
            
            /**
             * @title BMC Asset Proxy.
             *
             * Proxy implements ERC20 interface and acts as a gateway to a single platform asset.
             * Proxy adds symbol and caller(sender) when forwarding requests to platform.
             * Every request that is made by caller first sent to the specific asset implementation
             * contract, which then calls back to be forwarded onto platform.
             *
             * Calls flow: Caller ->
             *             Proxy.func(...) ->
             *             Asset.__func(..., Caller.address) ->
             *             Proxy.__func(..., Caller.address) ->
             *             Platform.proxyFunc(..., symbol, Caller.address)
             *
             * 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 BMCAssetProxy is ERC20 {
            
                // Supports BMCPlatform ability to return error codes from methods
                uint constant OK = 1;
            
                // Assigned platform, immutable.
                BMCPlatform public bmcPlatform;
            
                // Assigned symbol, immutable.
                bytes32 public smbl;
            
                // Assigned name, immutable.
                string public name;
            
                string public symbol;
            
                /**
                 * Sets platform address, assigns symbol and name.
                 *
                 * Can be set only once.
                 *
                 * @param _bmcPlatform platform contract address.
                 * @param _symbol assigned symbol.
                 * @param _name assigned name.
                 *
                 * @return success.
                 */
                function init(BMCPlatform _bmcPlatform, string _symbol, string _name) returns(bool) {
                    if (address(bmcPlatform) != 0x0) {
                        return false;
                    }
                    bmcPlatform = _bmcPlatform;
                    symbol = _symbol;
                    smbl = stringToBytes32(_symbol);
                    name = _name;
                    return true;
                }
            
                function stringToBytes32(string memory source) returns (bytes32 result) {
                    assembly {
                       result := mload(add(source, 32))
                    }
                }
            
                /**
                 * Only platform is allowed to call.
                 */
                modifier onlyBMCPlatform() {
                    if (msg.sender == address(bmcPlatform)) {
                        _;
                    }
                }
            
                /**
                 * Only current asset owner is allowed to call.
                 */
                modifier onlyAssetOwner() {
                    if (bmcPlatform.isOwner(msg.sender, smbl)) {
                        _;
                    }
                }
            
                /**
                 * Returns asset implementation contract for current caller.
                 *
                 * @return asset implementation contract.
                 */
                function _getAsset() internal returns(BMCAsset) {
                    return BMCAsset(getVersionFor(msg.sender));
                }
            
                /**
                 * Returns asset total supply.
                 *
                 * @return asset total supply.
                 */
                function totalSupply() constant returns(uint) {
                    return bmcPlatform.totalSupply(smbl);
                }
            
                /**
                 * Returns asset balance for a particular holder.
                 *
                 * @param _owner holder address.
                 *
                 * @return holder balance.
                 */
                function balanceOf(address _owner) constant returns(uint) {
                    return bmcPlatform.balanceOf(_owner, smbl);
                }
            
                /**
                 * 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 bmcPlatform.allowance(_from, _spender, smbl);
                }
            
                /**
                 * Returns asset decimals.
                 *
                 * @return asset decimals.
                 */
                function decimals() constant returns(uint8) {
                    return bmcPlatform.baseUnit(smbl);
                }
            
                /**
                 * 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) {
                    if (_to != 0x0) {
                      return _transferWithReference(_to, _value, "");
                    }
                    else {
                        return false;
                    }
                }
            
                /**
                 * Transfers asset balance from the caller to specified receiver adding specified comment.
                 *
                 * @param _to holder address to give to.
                 * @param _value amount to transfer.
                 * @param _reference transfer comment to be included in a platform's Transfer event.
                 *
                 * @return success.
                 */
                function transferWithReference(address _to, uint _value, string _reference) returns(bool) {
                    if (_to != 0x0) {
                        return _transferWithReference(_to, _value, _reference);
                    }
                    else {
                        return false;
                    }
                }
            
                /**
                 * Resolves asset implementation contract for the caller and forwards there arguments along with
                 * the caller address.
                 *
                 * @return success.
                 */
                function _transferWithReference(address _to, uint _value, string _reference) internal returns(bool) {
                    return _getAsset().__transferWithReference(_to, _value, _reference, msg.sender);
                }
            
                /**
                 * Performs transfer call on the platform by the name of specified sender.
                 *
                 * Can only be called by asset implementation contract assigned to sender.
                 *
                 * @param _to holder address to give to.
                 * @param _value amount to transfer.
                 * @param _reference transfer comment to be included in a platform's Transfer event.
                 * @param _sender initial caller.
                 *
                 * @return success.
                 */
                function __transferWithReference(address _to, uint _value, string _reference, address _sender) onlyAccess(_sender) returns(bool) {
                    return bmcPlatform.proxyTransferWithReference(_to, _value, smbl, _reference, _sender) == OK;
                }
            
                /**
                 * 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) {
                    if (_to != 0x0) {
                        return _getAsset().__transferFromWithReference(_from, _to, _value, "", msg.sender);
                     }
                     else {
                         return false;
                     }
                }
            
                /**
                 * Performs allowance transfer call on the platform 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 platform's Transfer event.
                 * @param _sender initial caller.
                 *
                 * @return success.
                 */
                function __transferFromWithReference(address _from, address _to, uint _value, string _reference, address _sender) onlyAccess(_sender) returns(bool) {
                    return bmcPlatform.proxyTransferFromWithReference(_from, _to, _value, smbl, _reference, _sender) == OK;
                }
            
                /**
                 * Sets asset spending allowance for a specified spender.
                 *
                 * @param _spender holder address to set allowance to.
                 * @param _value amount to allow.
                 *
                 * @return success.
                 */
                function approve(address _spender, uint _value) returns(bool) {
                    if (_spender != 0x0) {
                         return _getAsset().__approve(_spender, _value, msg.sender);
                    }
                    else {
                        return false;
                    }
                }
            
                /**
                 * Performs allowance setting call on the platform 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 __approve(address _spender, uint _value, address _sender) onlyAccess(_sender) returns(bool) {
                    return bmcPlatform.proxyApprove(_spender, _value, smbl, _sender) == OK;
                }
            
                /**
                 * Emits ERC20 Transfer event on this contract.
                 *
                 * Can only be, and, called by assigned platform when asset transfer happens.
                 */
                function emitTransfer(address _from, address _to, uint _value) onlyBMCPlatform() {
                    Transfer(_from, _to, _value);
                }
            
                /**
                 * Emits ERC20 Approval event on this contract.
                 *
                 * Can only be, and, called by assigned platform when asset allowance set happens.
                 */
                function emitApprove(address _from, address _spender, uint _value) onlyBMCPlatform() {
                    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 {
                    _getAsset().__process.value(msg.value)(msg.data, msg.sender);
                }
            
                /**
                 * 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 onlyAccess(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;
                }
            }

            File 2 of 4: MultiEventsHistory
            pragma solidity ^0.4.11;
            
            /**
             * @title Owned contract with safe ownership pass.
             *
             * Note: all the non constant functions return false instead of throwing in case if state change
             * didn't happen yet.
             */
            contract Owned {
                /**
                 * Contract owner address
                 */
                address public contractOwner;
            
                /**
                 * Contract owner address
                 */
                address public pendingContractOwner;
            
                function Owned() {
                    contractOwner = msg.sender;
                }
            
                /**
                * @dev Owner check modifier
                */
                modifier onlyContractOwner() {
                    if (contractOwner == msg.sender) {
                        _;
                    }
                }
            
                /**
                 * @dev Destroy contract and scrub a data
                 * @notice Only owner can call it
                 */
                function destroy() onlyContractOwner {
                    suicide(msg.sender);
                }
            
                /**
                 * Prepares ownership pass.
                 *
                 * Can only be called by current owner.
                 *
                 * @param _to address of the next owner. 0x0 is not allowed.
                 *
                 * @return success.
                 */
                function changeContractOwnership(address _to) onlyContractOwner() returns(bool) {
                    if (_to  == 0x0) {
                        return false;
                    }
            
                    pendingContractOwner = _to;
                    return true;
                }
            
                /**
                 * Finalize ownership pass.
                 *
                 * Can only be called by pending owner.
                 *
                 * @return success.
                 */
                function claimContractOwnership() returns(bool) {
                    if (pendingContractOwner != msg.sender) {
                        return false;
                    }
            
                    contractOwner = pendingContractOwner;
                    delete pendingContractOwner;
            
                    return true;
                }
            }
            
            contract ERC20Interface {
                event Transfer(address indexed from, address indexed to, uint256 value);
                event Approval(address indexed from, address indexed spender, uint256 value);
                string public symbol;
            
                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);
            }
            
            /**
             * @title Generic owned destroyable contract
             */
            contract Object is Owned {
                /**
                *  Common result code. Means everything is fine.
                */
                uint constant OK = 1;
                uint constant OWNED_ACCESS_DENIED_ONLY_CONTRACT_OWNER = 8;
            
                function withdrawnTokens(address[] tokens, address _to) onlyContractOwner returns(uint) {
                    for(uint i=0;i<tokens.length;i++) {
                        address token = tokens[i];
                        uint balance = ERC20Interface(token).balanceOf(this);
                        if(balance != 0)
                            ERC20Interface(token).transfer(_to,balance);
                    }
                    return OK;
                }
            
                function checkOnlyContractOwner() internal constant returns(uint) {
                    if (contractOwner == msg.sender) {
                        return OK;
                    }
            
                    return OWNED_ACCESS_DENIED_ONLY_CONTRACT_OWNER;
                }
            }
            
            
            /**
             * @title Events History universal multi contract.
             *
             * Contract serves as an Events storage for any type of contracts.
             * Events appear on this contract address but their definitions provided by calling contracts.
             *
             * Note: all the non constant functions return false instead of throwing in case if state change
             * didn't happen yet.
             */
            contract MultiEventsHistory is Object {
                // Authorized calling contracts.
                mapping(address => bool) public isAuthorized;
            
                /**
                 * Authorize new caller contract.
                 *
                 * @param _caller address of the new caller.
                 *
                 * @return success.
                 */
                function authorize(address _caller) onlyContractOwner() returns(bool) {
                    if (isAuthorized[_caller]) {
                        return false;
                    }
                    isAuthorized[_caller] = true;
                    return true;
                }
            
                /**
                 * Reject access.
                 *
                 * @param _caller address of the caller.
                 */
                function reject(address _caller) onlyContractOwner() {
                    delete isAuthorized[_caller];
                }
            
                /**
                 * Event emitting fallback.
                 *
                 * Can be and only called by authorized caller.
                 * Delegate calls back with provided msg.data to emit an event.
                 *
                 * Throws if call failed.
                 */
                function () {
                    if (!isAuthorized[msg.sender]) {
                        return;
                    }
                    // Internal Out Of Gas/Throw: revert this transaction too;
                    // Recursive Call: safe, all changes already made.
                    if (!msg.sender.delegatecall(msg.data)) {
                        throw;
                    }
                }
            }

            File 3 of 4: BMC
            pragma solidity ^0.4.11;
            
            contract BMCAssetInterface {
                function __transferWithReference(address _to, uint _value, string _reference, address _sender) returns(bool);
                function __transferFromWithReference(address _from, address _to, uint _value, string _reference, address _sender) returns(bool);
                function __approve(address _spender, uint _value, address _sender) returns(bool);
                function __process(bytes _data, address _sender) payable {
                    throw;
                }
            }
            
            contract BMCAssetProxy {
                address public bmcPlatform;
                function __transferWithReference(address _to, uint _value, string _reference, address _sender) returns(bool);
                function __transferFromWithReference(address _from, address _to, uint _value, string _reference, address _sender) returns(bool);
                function __approve(address _spender, uint _value, address _sender) returns(bool);    
                function getLatestVersion() returns(address);
                function init(address _bmcPlatform, string _symbol, string _name);
                function proposeUpgrade(address _newVersion);
            }
            
            /**
             * @title BMC 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 immediatly without arguments modification.
             *
             * Note: all the non constant functions return false instead of throwing in case if state change
             * didn't happen yet.
             */
            contract BMCAsset is BMCAssetInterface {
                // Assigned asset proxy contract, immutable.
                BMCAssetProxy 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(BMCAssetProxy _proxy) 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 __transferWithReference(address _to, uint _value, string _reference, address _sender) onlyProxy() returns(bool) {
                    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.__transferWithReference(_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 __transferFromWithReference(address _from, address _to, uint _value, string _reference, address _sender) onlyProxy() returns(bool) {
                    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.__transferFromWithReference(_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 __approve(address _spender, uint _value, address _sender) 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.__approve(_spender, _value, _sender);
                }
            }
            
            
            /**
             * @title Blackmooncrypto.com BMC tokens contract.
             *
             * The official Blackmooncrypto.com token implementation.
             */
            contract BMC is BMCAsset {
            
                uint public icoUsd;
                uint public icoEth;
                uint public icoBtc;
                uint public icoLtc;
            
                function initBMC(BMCAssetProxy _proxy, uint _icoUsd, uint _icoEth, uint _icoBtc, uint _icoLtc) returns(bool) {
                    if(icoUsd != 0 || icoEth != 0 || icoBtc != 0 || icoLtc != 0) {
                        return false;
                    }
                    icoUsd = _icoUsd;
                    icoEth = _icoEth;
                    icoBtc = _icoBtc;
                    icoLtc = _icoLtc;
                    super.init(_proxy);
                    return true;
                }
            
            }

            File 4 of 4: BMCPlatform
            pragma solidity ^0.4.11;
            
            /**
             * @title Owned contract with safe ownership pass.
             *
             * Note: all the non constant functions return false instead of throwing in case if state change
             * didn't happen yet.
             */
            contract Owned {
                /**
                 * Contract owner address
                 */
                address public contractOwner;
            
                /**
                 * Contract owner address
                 */
                address public pendingContractOwner;
            
                function Owned() {
                    contractOwner = msg.sender;
                }
            
                /**
                * @dev Owner check modifier
                */
                modifier onlyContractOwner() {
                    if (contractOwner == msg.sender) {
                        _;
                    }
                }
            
                /**
                 * @dev Destroy contract and scrub a data
                 * @notice Only owner can call it
                 */
                function destroy() onlyContractOwner {
                    suicide(msg.sender);
                }
            
                /**
                 * Prepares ownership pass.
                 *
                 * Can only be called by current owner.
                 *
                 * @param _to address of the next owner. 0x0 is not allowed.
                 *
                 * @return success.
                 */
                function changeContractOwnership(address _to) onlyContractOwner() returns(bool) {
                    if (_to  == 0x0) {
                        return false;
                    }
            
                    pendingContractOwner = _to;
                    return true;
                }
            
                /**
                 * Finalize ownership pass.
                 *
                 * Can only be called by pending owner.
                 *
                 * @return success.
                 */
                function claimContractOwnership() returns(bool) {
                    if (pendingContractOwner != msg.sender) {
                        return false;
                    }
            
                    contractOwner = pendingContractOwner;
                    delete pendingContractOwner;
            
                    return true;
                }
            }
            
            
            contract ERC20Interface {
                event Transfer(address indexed from, address indexed to, uint256 value);
                event Approval(address indexed from, address indexed spender, uint256 value);
                string public symbol;
            
                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);
            }
            
            /**
             * @title Generic owned destroyable contract
             */
            contract Object is Owned {
                /**
                *  Common result code. Means everything is fine.
                */
                uint constant OK = 1;
                uint constant OWNED_ACCESS_DENIED_ONLY_CONTRACT_OWNER = 8;
            
                function withdrawnTokens(address[] tokens, address _to) onlyContractOwner returns(uint) {
                    for(uint i=0;i<tokens.length;i++) {
                        address token = tokens[i];
                        uint balance = ERC20Interface(token).balanceOf(this);
                        if(balance != 0)
                            ERC20Interface(token).transfer(_to,balance);
                    }
                    return OK;
                }
            
                function checkOnlyContractOwner() internal constant returns(uint) {
                    if (contractOwner == msg.sender) {
                        return OK;
                    }
            
                    return OWNED_ACCESS_DENIED_ONLY_CONTRACT_OWNER;
                }
            }
            
            
            /**
             * @title General MultiEventsHistory user.
             *
             */
            contract MultiEventsHistoryAdapter {
            
                /**
                *   @dev It is address of MultiEventsHistory caller assuming we are inside of delegate call.
                */
                function _self() constant internal returns (address) {
                    return msg.sender;
                }
            }
            
            /**
             * @title BMC Platform 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.
             */
            
            contract BMCPlatformEmitter is MultiEventsHistoryAdapter {
                event Transfer(address indexed from, address indexed to, bytes32 indexed symbol, uint value, string reference);
                event Issue(bytes32 indexed symbol, uint value, address by);
                event Revoke(bytes32 indexed symbol, uint value, address by);
                event OwnershipChange(address indexed from, address indexed to, bytes32 indexed symbol);
                event Approve(address indexed from, address indexed spender, bytes32 indexed symbol, uint value);
                event Recovery(address indexed from, address indexed to, address by);
                event Error(bytes32 message);
            
                function emitTransfer(address _from, address _to, bytes32 _symbol, uint _value, string _reference) {
                    Transfer(_from, _to, _symbol, _value, _reference);
                }
            
                function emitIssue(bytes32 _symbol, uint _value, address _by) {
                    Issue(_symbol, _value, _by);
                }
            
                function emitRevoke(bytes32 _symbol, uint _value, address _by) {
                    Revoke(_symbol, _value, _by);
                }
            
                function emitOwnershipChange(address _from, address _to, bytes32 _symbol) {
                    OwnershipChange(_from, _to, _symbol);
                }
            
                function emitApprove(address _from, address _spender, bytes32 _symbol, uint _value) {
                    Approve(_from, _spender, _symbol, _value);
                }
            
                function emitRecovery(address _from, address _to, address _by) {
                    Recovery(_from, _to, _by);
                }
            
                function emitError(bytes32 _message) {
                    Error(_message);
                }
            }
            
            
            /**
             * @title SafeMath
             * @dev Math operations with safety checks that throw on error
             */
            library SafeMath {
              function mul(uint256 a, uint256 b) internal constant returns (uint256) {
                uint256 c = a * b;
                assert(a == 0 || c / a == b);
                return c;
              }
            
              function div(uint256 a, uint256 b) internal constant returns (uint256) {
                // assert(b > 0); // Solidity automatically throws when dividing by 0
                uint256 c = a / b;
                // assert(a == b * c + a % b); // There is no case in which this doesn't hold
                return c;
              }
            
              function sub(uint256 a, uint256 b) internal constant returns (uint256) {
                assert(b <= a);
                return a - b;
              }
            
              function add(uint256 a, uint256 b) internal constant returns (uint256) {
                uint256 c = a + b;
                assert(c >= a);
                return c;
              }
            }
            
            contract Proxy {
                function emitTransfer(address _from, address _to, uint _value);
                function emitApprove(address _from, address _spender, uint _value);
            }
            
            /**
             * @title BMC Platform.
             *
             * The official BMC assets platform powering BMC token, and possibly
             * other unknown tokens needed later.
             * Platform uses MultiEventsHistory 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: transfers, allowances, supply adjustments, lost wallet access recovery.
             *
             * Note: all the non constant functions return false instead of throwing in case if state change
             * didn't happen yet.
             */
            contract BMCPlatform is Object, BMCPlatformEmitter {
            
                using SafeMath for uint;
            
                uint constant BMC_PLATFORM_SCOPE = 15000;
                uint constant BMC_PLATFORM_PROXY_ALREADY_EXISTS = BMC_PLATFORM_SCOPE + 0;
                uint constant BMC_PLATFORM_CANNOT_APPLY_TO_ONESELF = BMC_PLATFORM_SCOPE + 1;
                uint constant BMC_PLATFORM_INVALID_VALUE = BMC_PLATFORM_SCOPE + 2;
                uint constant BMC_PLATFORM_INSUFFICIENT_BALANCE = BMC_PLATFORM_SCOPE + 3;
                uint constant BMC_PLATFORM_NOT_ENOUGH_ALLOWANCE = BMC_PLATFORM_SCOPE + 4;
                uint constant BMC_PLATFORM_ASSET_ALREADY_ISSUED = BMC_PLATFORM_SCOPE + 5;
                uint constant BMC_PLATFORM_CANNOT_ISSUE_FIXED_ASSET_WITH_INVALID_VALUE = BMC_PLATFORM_SCOPE + 6;
                uint constant BMC_PLATFORM_CANNOT_REISSUE_FIXED_ASSET = BMC_PLATFORM_SCOPE + 7;
                uint constant BMC_PLATFORM_SUPPLY_OVERFLOW = BMC_PLATFORM_SCOPE + 8;
                uint constant BMC_PLATFORM_NOT_ENOUGH_TOKENS = BMC_PLATFORM_SCOPE + 9;
                uint constant BMC_PLATFORM_INVALID_NEW_OWNER = BMC_PLATFORM_SCOPE + 10;
                uint constant BMC_PLATFORM_ALREADY_TRUSTED = BMC_PLATFORM_SCOPE + 11;
                uint constant BMC_PLATFORM_SHOULD_RECOVER_TO_NEW_ADDRESS = BMC_PLATFORM_SCOPE + 12;
                uint constant BMC_PLATFORM_ASSET_IS_NOT_ISSUED = BMC_PLATFORM_SCOPE + 13;
                uint constant BMC_PLATFORM_ACCESS_DENIED_ONLY_OWNER = BMC_PLATFORM_SCOPE + 14;
                uint constant BMC_PLATFORM_ACCESS_DENIED_ONLY_PROXY = BMC_PLATFORM_SCOPE + 15;
                uint constant BMC_PLATFORM_ACCESS_DENIED_ONLY_TRUSTED = BMC_PLATFORM_SCOPE + 16;
                uint constant BMC_PLATFORM_INVALID_INVOCATION = BMC_PLATFORM_SCOPE + 17;
                uint constant BMC_PLATFORM_HOLDER_EXISTS = BMC_PLATFORM_SCOPE + 18;
            
                // 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 or fixed supply.
                    uint8 baseUnit;                   // Proposed number of decimals.
                    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.
                    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;
            
                // Should use interface of the emitter, but address of events history.
                address public eventsHistory;
            
                /**
                 * Emits Error event with specified error message.
                 *
                 * Should only be used if no state changes happened.
                 *
                 * @param _errorCode code of an error
                 * @param _message error message.
                 */
                function _error(uint _errorCode, bytes32 _message) internal returns(uint) {
                    BMCPlatformEmitter(eventsHistory).emitError(_message);
                    return _errorCode;
                }
            
                /**
                 * Sets EventsHstory contract address.
                 *
                 * Can be set only once, and only by contract owner.
                 *
                 * @param _eventsHistory MultiEventsHistory contract address.
                 *
                 * @return success.
                 */
                function setupEventsHistory(address _eventsHistory) returns(uint errorCode) {
                    errorCode = checkOnlyContractOwner();
                    if (errorCode != OK) {
                        return errorCode;
                    }
                    if (eventsHistory != 0x0 && eventsHistory != _eventsHistory) {
                        return BMC_PLATFORM_INVALID_INVOCATION;
                    }
                    eventsHistory = _eventsHistory;
                    return OK;
                }
            
                /**
                 * Emits Error if called not by asset owner.
                 */
                modifier onlyOwner(bytes32 _symbol) {
                    if (checkIsOnlyOwner(_symbol) == OK) {
                        _;
                    }
                }
            
                /**
                 * Emits Error if called not by asset proxy.
                 */
                modifier onlyProxy(bytes32 _symbol) {
                    if (checkIsOnlyProxy(_symbol) == OK) {
                        _;
                    }
                }
            
                /**
                 * Emits Error if _from doesn't trust _to.
                 */
                modifier checkTrust(address _from, address _to) {
                    if (shouldBeTrusted(_from, _to) == OK) {
                        _;
                    }
                }
            
                function checkIsOnlyOwner(bytes32 _symbol) internal constant returns(uint errorCode) {
                    if (isOwner(msg.sender, _symbol)) {
                        return OK;
                    }
                    return _error(BMC_PLATFORM_ACCESS_DENIED_ONLY_OWNER, "Only owner: access denied");
                }
            
                function checkIsOnlyProxy(bytes32 _symbol) internal constant returns(uint errorCode) {
                    if (proxies[_symbol] == msg.sender) {
                        return OK;
                    }
                    return _error(BMC_PLATFORM_ACCESS_DENIED_ONLY_PROXY, "Only proxy: access denied");
                }
            
                function shouldBeTrusted(address _from, address _to) internal constant returns(uint errorCode) {
                    if (isTrusted(_from, _to)) {
                        return OK;
                    }
                    return _error(BMC_PLATFORM_ACCESS_DENIED_ONLY_TRUSTED, "Only trusted: access denied");
                }
            
                /**
                 * Check asset existance.
                 *
                 * @param _symbol asset symbol.
                 *
                 * @return asset existance.
                 */
                function isCreated(bytes32 _symbol) constant returns(bool) {
                    return assets[_symbol].owner != 0;
                }
            
                /**
                 * 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 a particular holder.
                 *
                 * @param _holder holder address.
                 * @param _symbol asset symbol.
                 *
                 * @return holder balance.
                 */
                function balanceOf(address _holder, bytes32 _symbol) constant returns(uint) {
                    return _balanceOf(getHolderId(_holder), _symbol);
                }
            
                /**
                 * 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 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 returns(address) {
                    return holders[_holderId].addr;
                }
            
                /**
                 * 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) returns(uint errorCode) {
                    errorCode = checkOnlyContractOwner();
                    if (errorCode != OK) {
                        return errorCode;
                    }
            
                    if (proxies[_symbol] != 0x0) {
                        return BMC_PLATFORM_PROXY_ALREADY_EXISTS;
                    }
                    proxies[_symbol] = _address;
                    return OK;
                }
            
                function massTransfer(address[] addresses, uint[] values, bytes32 _symbol) external
                returns (uint errorCode, uint count)
                {
                    require(checkIsOnlyOwner(_symbol) == OK);
                    require(addresses.length == values.length);
                    require(_symbol != 0x0);
            
                    // TODO: ahiatsevich checkIsOnlyProxy
            
                    uint senderId = _createHolderId(msg.sender);
            
                    uint success = 0;
                    for(uint idx = 0; idx < addresses.length && msg.gas > 110000; idx++) {
                        uint value = values[idx];
            
                        if (value == 0) {
                            _error(BMC_PLATFORM_INVALID_VALUE, "Cannot send 0 value");
                            continue;
                        }
            
                        if (getHolderId(addresses[idx]) > 0) {
                            _error(BMC_PLATFORM_HOLDER_EXISTS, "Already transfered");
                            continue;
                        }
            
                        if (_balanceOf(senderId, _symbol) < value) {
                            _error(BMC_PLATFORM_INSUFFICIENT_BALANCE, "Insufficient balance");
                            continue;
                        }
            
                        if (msg.sender == addresses[idx]) {
                            _error(BMC_PLATFORM_CANNOT_APPLY_TO_ONESELF, "Cannot send to oneself");
                            continue;
                        }
            
                        uint holderId = _createHolderId(addresses[idx]);
            
                        _transferDirect(senderId, holderId, value, _symbol);
                        BMCPlatformEmitter(eventsHistory).emitTransfer(msg.sender, addresses[idx], _symbol, value, "");
                        
                        success++;
                    }
            
                    return (OK, success);
                }
            
                /**
                 * 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 = assets[_symbol].wallets[_fromId].balance.sub(_value);
                    assets[_symbol].wallets[_toId].balance = assets[_symbol].wallets[_toId].balance.add(_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 returns(uint) {
                    // Should not allow to send to oneself.
                    if (_fromId == _toId) {
                        return _error(BMC_PLATFORM_CANNOT_APPLY_TO_ONESELF, "Cannot send to oneself");
                    }
                    // Should have positive value.
                    if (_value == 0) {
                        return _error(BMC_PLATFORM_INVALID_VALUE, "Cannot send 0 value");
                    }
                    // Should have enough balance.
                    if (_balanceOf(_fromId, _symbol) < _value) {
                        return _error(BMC_PLATFORM_INSUFFICIENT_BALANCE, "Insufficient balance");
                    }
                    // Should have enough allowance.
                    if (_fromId != _senderId && _allowance(_fromId, _senderId, _symbol) < _value) {
                        return _error(BMC_PLATFORM_NOT_ENOUGH_ALLOWANCE, "Not enough allowance");
                    }
            
                    _transferDirect(_fromId, _toId, _value, _symbol);
                    // Adjust allowance.
                    if (_fromId != _senderId) {
                        uint senderAllowance = assets[_symbol].wallets[_fromId].allowance[_senderId];
                        assets[_symbol].wallets[_fromId].allowance[_senderId] = senderAllowance.sub(_value);
                    }
                    // Internal Out Of Gas/Throw: revert this transaction too;
                    // Call Stack Depth Limit reached: n/a after HF 4;
                    // Recursive Call: safe, all changes already made.
                    BMCPlatformEmitter(eventsHistory).emitTransfer(_address(_fromId), _address(_toId), _symbol, _value, _reference);
                    _proxyTransferEvent(_fromId, _toId, _value, _symbol);
                    return OK;
                }
            
                /**
                 * Transfers asset balance between holders wallets.
                 *
                 * Can only be called by asset proxy.
                 *
                 * @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 transfer initiator address.
                 *
                 * @return success.
                 */
                function proxyTransferWithReference(address _to, uint _value, bytes32 _symbol, string _reference, address _sender) returns(uint errorCode) {
                    errorCode = checkIsOnlyProxy(_symbol);
                    if (errorCode != OK) {
                        return errorCode;
                    }
            
                    return _transfer(getHolderId(_sender), _createHolderId(_to), _value, _symbol, _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;
                        // Call Stack Depth Limit reached: n/a after HF 4;
                        // 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.
                 *
                 * @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) returns(uint errorCode) {
                    errorCode = checkOnlyContractOwner();
                    if (errorCode != OK) {
                        return errorCode;
                    }
                    // Should have positive value if supply is going to be fixed.
                    if (_value == 0 && !_isReissuable) {
                        return _error(BMC_PLATFORM_CANNOT_ISSUE_FIXED_ASSET_WITH_INVALID_VALUE, "Cannot issue 0 value fixed asset");
                    }
                    // Should not be issued yet.
                    if (isCreated(_symbol)) {
                        return _error(BMC_PLATFORM_ASSET_ALREADY_ISSUED, "Asset already issued");
                    }
                    uint holderId = _createHolderId(msg.sender);
            
                    assets[_symbol] = Asset(holderId, _value, _name, _description, _isReissuable, _baseUnit);
                    assets[_symbol].wallets[holderId].balance = _value;
                    // Internal Out Of Gas/Throw: revert this transaction too;
                    // Call Stack Depth Limit reached: n/a after HF 4;
                    // Recursive Call: safe, all changes already made.
                    BMCPlatformEmitter(eventsHistory).emitIssue(_symbol, _value, _address(holderId));
                    return OK;
                }
            
                /**
                 * 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) returns(uint errorCode) {
                    errorCode = checkIsOnlyOwner(_symbol);
                    if (errorCode != OK) {
                        return errorCode;
                    }
                    // Should have positive value.
                    if (_value == 0) {
                        return _error(BMC_PLATFORM_INVALID_VALUE, "Cannot reissue 0 value");
                    }
                    Asset asset = assets[_symbol];
                    // Should have dynamic supply.
                    if (!asset.isReissuable) {
                        return _error(BMC_PLATFORM_CANNOT_REISSUE_FIXED_ASSET, "Cannot reissue fixed asset");
                    }
                    // Resulting total supply should not overflow.
                    if (asset.totalSupply + _value < asset.totalSupply) {
                        return _error(BMC_PLATFORM_SUPPLY_OVERFLOW, "Total supply overflow");
                    }
                    uint holderId = getHolderId(msg.sender);
                    asset.wallets[holderId].balance = asset.wallets[holderId].balance.add(_value);
                    asset.totalSupply = asset.totalSupply.add(_value);
                    // Internal Out Of Gas/Throw: revert this transaction too;
                    // Call Stack Depth Limit reached: n/a after HF 4;
                    // Recursive Call: safe, all changes already made.
                    BMCPlatformEmitter(eventsHistory).emitIssue(_symbol, _value, _address(holderId));
                    _proxyTransferEvent(0, holderId, _value, _symbol);
                    return OK;
                }
            
                /**
                 * 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) returns(uint) {
                    // Should have positive value.
                    if (_value == 0) {
                        return _error(BMC_PLATFORM_INVALID_VALUE, "Cannot revoke 0 value");
                    }
                    Asset asset = assets[_symbol];
                    uint holderId = getHolderId(msg.sender);
                    // Should have enough tokens.
                    if (asset.wallets[holderId].balance < _value) {
                        return _error(BMC_PLATFORM_NOT_ENOUGH_TOKENS, "Not enough tokens to revoke");
                    }
                    asset.wallets[holderId].balance = asset.wallets[holderId].balance.sub(_value);
                    asset.totalSupply = asset.totalSupply.sub(_value);
                    // Internal Out Of Gas/Throw: revert this transaction too;
                    // Call Stack Depth Limit reached: n/a after HF 4;
                    // Recursive Call: safe, all changes already made.
                    BMCPlatformEmitter(eventsHistory).emitRevoke(_symbol, _value, _address(holderId));
                    _proxyTransferEvent(holderId, 0, _value, _symbol);
                    return OK;
                }
            
                /**
                 * 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) returns(uint errorCode) {
                    errorCode = checkIsOnlyOwner(_symbol);
                    if (errorCode != OK) {
                        return errorCode;
                    }
            
                    if (_newOwner == 0x0) {
                        return _error(BMC_PLATFORM_INVALID_NEW_OWNER, "Can't change ownership to 0x0");
                    }
            
                    Asset asset = assets[_symbol];
                    uint newOwnerId = _createHolderId(_newOwner);
                    // Should pass ownership to another holder.
                    if (asset.owner == newOwnerId) {
                        return _error(BMC_PLATFORM_CANNOT_APPLY_TO_ONESELF, "Cannot pass ownership to oneself");
                    }
                    address oldOwner = _address(asset.owner);
                    asset.owner = newOwnerId;
                    // Internal Out Of Gas/Throw: revert this transaction too;
                    // Call Stack Depth Limit reached: n/a after HF 4;
                    // Recursive Call: safe, all changes already made.
                    BMCPlatformEmitter(eventsHistory).emitOwnershipChange(oldOwner, _address(newOwnerId), _symbol);
                    return OK;
                }
            
                /**
                 * 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(uint) {
                    uint fromId = _createHolderId(msg.sender);
                    // Should trust to another address.
                    if (fromId == getHolderId(_to)) {
                        return _error(BMC_PLATFORM_CANNOT_APPLY_TO_ONESELF, "Cannot trust to oneself");
                    }
                    // Should trust to yet untrusted.
                    if (isTrusted(msg.sender, _to)) {
                        return _error(BMC_PLATFORM_ALREADY_TRUSTED, "Already trusted");
                    }
            
                    holders[fromId].trust[_to] = true;
                    return OK;
                }
            
                /**
                 * Revoke trust to perform recovery procedure from an address.
                 *
                 * @param _to trustee.
                 *
                 * @return success.
                 */
                function distrust(address _to) returns(uint errorCode) {
                    errorCode = shouldBeTrusted(msg.sender, _to);
                    if (errorCode != OK) {
                        return errorCode;
                    }
                    holders[getHolderId(msg.sender)].trust[_to] = false;
                    return OK;
                }
            
                /**
                 * Perform recovery procedure.
                 *
                 * This function logic is actually more of an addAccess(uint _holderId, address _to).
                 * It grants another address access to recovery subject wallets.
                 * Can only be called by trustee of recovery subject.
                 *
                 * @param _from holder address to recover from.
                 * @param _to address to grant access to.
                 *
                 * @return success.
                 */
                function recover(address _from, address _to) returns(uint errorCode) {
                    errorCode = shouldBeTrusted(_from, msg.sender);
                    if (errorCode != OK) {
                        return errorCode;
                    }
                    // Should recover to previously unused address.
                    if (getHolderId(_to) != 0) {
                        return _error(BMC_PLATFORM_SHOULD_RECOVER_TO_NEW_ADDRESS, "Should recover to new address");
                    }
                    // 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[getHolderId(_from)].addr;
                    holders[getHolderId(_from)].addr = _to;
                    holderIndex[_to] = getHolderId(_from);
                    // 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.
                    BMCPlatformEmitter(eventsHistory).emitRecovery(from, _to, msg.sender);
                    return OK;
                }
            
                /**
                 * 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 returns(uint) {
                    // Asset should exist.
                    if (!isCreated(_symbol)) {
                        return _error(BMC_PLATFORM_ASSET_IS_NOT_ISSUED, "Asset is not issued");
                    }
                    // Should allow to another holder.
                    if (_senderId == _spenderId) {
                        return _error(BMC_PLATFORM_CANNOT_APPLY_TO_ONESELF, "Cannot approve to oneself");
                    }
                    assets[_symbol].wallets[_senderId].allowance[_spenderId] = _value;
                    // 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.
                    BMCPlatformEmitter(eventsHistory).emitApprove(_address(_senderId), _address(_spenderId), _symbol, _value);
                    if (proxies[_symbol] != 0x0) {
                        // Internal Out Of Gas/Throw: revert this transaction too;
                        // Call Stack Depth Limit reached: n/a after HF 4;
                        // Recursive Call: safe, all changes already made.
                        Proxy(proxies[_symbol]).emitApprove(_address(_senderId), _address(_spenderId), _value);
                    }
                    return OK;
                }
            
                /**
                 * 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) returns(uint errorCode) {
                    errorCode = checkIsOnlyProxy(_symbol);
                    if (errorCode != OK) {
                        return errorCode;
                    }
                    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) returns(uint errorCode) {
                    errorCode = checkIsOnlyProxy(_symbol);
                    if (errorCode != OK) {
                        return errorCode;
                    }
                    return _transfer(getHolderId(_from), _createHolderId(_to), _value, _symbol, _reference, getHolderId(_sender));
                }
            }