ETH Price: $1,625.85 (+1.81%)
Gas: 0.4 Gwei
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

TokenTracker

Revain (REV) (@$0.00)

Multichain Info

1 address found via
Transaction Hash
Method
Block
From
To
Transfer222590772025-04-13 9:12:4739 mins ago1744535567IN
Revain: REV Token
0 ETH0.000252913.43565686
Approve222587872025-04-13 8:14:351 hr ago1744532075IN
Revain: REV Token
0 ETH0.000031790.4748251
Transfer222573742025-04-13 3:30:596 hrs ago1744515059IN
Revain: REV Token
0 ETH0.000251953.4225541
Transfer222571942025-04-13 2:54:596 hrs ago1744512899IN
Revain: REV Token
0 ETH0.000194473.44037602
Transfer222571842025-04-13 2:52:596 hrs ago1744512779IN
Revain: REV Token
0 ETH0.000250573.40386534
Transfer222571342025-04-13 2:42:597 hrs ago1744512179IN
Revain: REV Token
0 ETH0.000254173.4526883
Transfer222560812025-04-12 23:11:2310 hrs ago1744499483IN
Revain: REV Token
0 ETH0.00017562.38545674
Transfer222560102025-04-12 22:56:5910 hrs ago1744498619IN
Revain: REV Token
0 ETH0.000248833.38073888
Transfer222548342025-04-12 19:00:5914 hrs ago1744484459IN
Revain: REV Token
0 ETH0.000257813.50218765
Transfer222538922025-04-12 15:50:5918 hrs ago1744473059IN
Revain: REV Token
0 ETH0.000316974.30580718
Transfer222535632025-04-12 14:44:5919 hrs ago1744469099IN
Revain: REV Token
0 ETH0.000473226.42939811
Transfer222534532025-04-12 14:22:5919 hrs ago1744467779IN
Revain: REV Token
0 ETH0.000398455.41260153
Transfer222531232025-04-12 13:16:5920 hrs ago1744463819IN
Revain: REV Token
0 ETH0.000213263.77426302
Transfer222529742025-04-12 12:46:5921 hrs ago1744462019IN
Revain: REV Token
0 ETH0.000195063.45146102
Transfer222526842025-04-12 11:48:5922 hrs ago1744458539IN
Revain: REV Token
0 ETH0.000195143.45286307
Transfer222526742025-04-12 11:46:5922 hrs ago1744458419IN
Revain: REV Token
0 ETH0.000195713.46297784
Transfer222524452025-04-12 11:00:5922 hrs ago1744455659IN
Revain: REV Token
0 ETH0.000194923.44909659
Transfer222524352025-04-12 10:58:5922 hrs ago1744455539IN
Revain: REV Token
0 ETH0.000191493.38910867
Transfer222524352025-04-12 10:58:5922 hrs ago1744455539IN
Revain: REV Token
0 ETH0.000249453.38910867
Transfer222524252025-04-12 10:56:5922 hrs ago1744455419IN
Revain: REV Token
0 ETH0.000252363.42809554
Transfer222524152025-04-12 10:54:5922 hrs ago1744455299IN
Revain: REV Token
0 ETH0.000253273.44104059
Transfer222523652025-04-12 10:44:5923 hrs ago1744454699IN
Revain: REV Token
0 ETH0.000255443.47001534
Transfer222519172025-04-12 9:14:5924 hrs ago1744449299IN
Revain: REV Token
0 ETH0.000254823.46098465
Transfer222497192025-04-12 1:54:5931 hrs ago1744422899IN
Revain: REV Token
0 ETH0.000196233.47211697
Transfer222481522025-04-11 20:40:5937 hrs ago1744404059IN
Revain: REV Token
0 ETH0.000257233.49430485
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Method Block
From
To
Transfer193309102024-02-29 4:52:11409 days ago1709182331
Revain: REV Token
0.00144939 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ERC20Proxy

Compiler Version
v0.5.10+commit.5a6ea5b1

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, None license

Contract Source Code (Solidity Multiple files format)

File 1 of 2: source.sol
pragma solidity ^0.5.10;

/** @title  A contract for generating unique identifiers
  *
  * @notice  A contract that provides an identifier generation scheme,
  * guaranteeing uniqueness across all contracts that inherit from it,
  * as well as the unpredictability of future identifiers.
  *
  * @dev  This contract is intended to be inherited by any contract that
  * implements the callback software pattern for cooperative custodianship.
  *
*/
contract LockRequestable {

    // MEMBERS
    /// @notice  the count of all invocations of `generateLockId`.
    uint256 public lockRequestCount;

    // CONSTRUCTOR
    constructor() public {
        lockRequestCount = 0;
    }

    // FUNCTIONS
    /** @notice  Returns a fresh unique identifier.
      *
      * @dev the generation scheme uses three components.
      * First, the blockhash of the previous block.
      * Second, the deployed address.
      * Third, the next value of the counter.
      * This ensures that identifiers are unique across all contracts
      * following this scheme, and that future identifiers are
      * unpredictable.
      *
      * @return a 32-byte unique identifier.
    */
    function generateLockId() internal returns (bytes32 lockId) {
        return keccak256(abi.encodePacked(blockhash(block.number - 1), address(this), ++lockRequestCount));
    }
}

contract ERC20Interface {

    // METHODS

    // NOTE:
    //   public getter functions are not currently recognised as an
    //   implementation of the matching abstract function by the compiler.

    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#name
    // function name() public view returns (string);

    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#symbol
    // function symbol() public view returns (string);

    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#totalsupply
    // function decimals() public view returns (uint8);

    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#totalsupply
    function totalSupply() public view returns (uint256);

    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#balanceof
    function balanceOf(address _owner) public view returns (uint256 balance);

    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transfer
    function transfer(address _to, uint256 _value) public returns (bool success);

    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transferfrom
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);

    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#approve
    function approve(address _spender, uint256 _value) public returns (bool success);

    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#allowance
    function allowance(address _owner, address _spender) public view returns (uint256 remaining);

    // EVENTS
    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transfer-1
    event Transfer(address indexed _from, address indexed _to, uint256 _value);

    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#approval
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}

/** @title  A dual control contract.
  *
  * @notice  A general-purpose contract that implements dual control over
  * co-operating contracts through a callback mechanism.
  *
  * @dev  This contract implements dual control through a 2-of-N
  * threshold multi-signature scheme. The contract recognizes a set of N signers,
  * and will unlock requests with signatures from any distinct pair of them.
  * This contract signals the unlocking through a co-operative callback
  * scheme.
  * This contract also provides time lock and revocation features.
  * Requests made by a 'primary' account have a default time lock applied.
  * All other requests must pay a 1 ETH stake and have an extended time lock
  * applied.
  * A request that is completed will prevent all previous pending requests
  * that share the same callback from being completed: this is the
  * revocation feature.
  *
  */
contract Custodian {

    // TYPES
    /** @dev  The `Request` struct stores a pending unlocking.
      * `callbackAddress` and `callbackSelector` are the data required to
      * make a callback. The custodian completes the process by
      * calling `callbackAddress.call(callbackSelector, lockId)`, which
      * signals to the contract co-operating with the Custodian that
      * the 2-of-N signatures have been provided and verified.
      */
    struct Request {
        bytes32 lockId;
        bytes4 callbackSelector;  // bytes4 and address can be packed into 1 word
        address callbackAddress;
        uint256 idx;
        uint256 timestamp;
        bool extended;
    }

    // EVENTS
    /// @dev  Emitted by successful `requestUnlock` calls.
    event Requested(
        bytes32 _lockId,
        address _callbackAddress,
        bytes4 _callbackSelector,
        uint256 _nonce,
        address _whitelistedAddress,
        bytes32 _requestMsgHash,
        uint256 _timeLockExpiry
    );

    /// @dev  Emitted by `completeUnlock` calls on requests in the time-locked state.
    event TimeLocked(
        uint256 _timeLockExpiry,
        bytes32 _requestMsgHash
    );

    /// @dev  Emitted by successful `completeUnlock` calls.
    event Completed(
        bytes32 _lockId,
        bytes32 _requestMsgHash,
        address _signer1,
        address _signer2
    );

    /// @dev  Emitted by `completeUnlock` calls where the callback failed.
    event Failed(
        bytes32 _lockId,
        bytes32 _requestMsgHash,
        address _signer1,
        address _signer2
    );

    /// @dev  Emitted by successful `extendRequestTimeLock` calls.
    event TimeLockExtended(
        uint256 _timeLockExpiry,
        bytes32 _requestMsgHash
    );

     // MEMBERS
    /** @dev  The count of all requests.
      * This value is used as a nonce, incorporated into the request hash.
      */
    uint256 public requestCount;

    /// @dev  The set of signers: signatures from two signers unlock a pending request.
    mapping (address => bool) public signerSet;

    /// @dev  The map of request hashes to pending requests.
    mapping (bytes32 => Request) public requestMap;

    /// @dev  The map of callback addresses to callback selectors to request indexes.
    mapping (address => mapping (bytes4 => uint256)) public lastCompletedIdxs;

    /** @dev  The default period (in seconds) to time-lock requests.
      * All requests will be subject to this default time lock, and the duration
      * is fixed at contract creation.
      */
    uint256 public defaultTimeLock;

    /** @dev  The extended period (in seconds) to time-lock requests.
      * Requests not from the primary account are subject to this time lock.
      * The primary account may also elect to extend the time lock on requests
      * that originally received the default.
      */
    uint256 public extendedTimeLock;

    /// @dev  The primary account is the privileged account for making requests.
    address public primary;

    // CONSTRUCTOR
    constructor(
        address[] memory _signers,
        uint256 _defaultTimeLock,
        uint256 _extendedTimeLock,
        address _primary
    )
        public
    {
        // check for at least two `_signers`
        require(_signers.length >= 2, "at least two `_signers`");

         // validate time lock params
        require(_defaultTimeLock <= _extendedTimeLock, "valid timelock params");
        defaultTimeLock = _defaultTimeLock;
        extendedTimeLock = _extendedTimeLock;

        primary = _primary;

        // explicitly initialize `requestCount` to zero
        requestCount = 0;
        // turn the array into a set
        for (uint i = 0; i < _signers.length; i++) {
            // no zero addresses or duplicates
            require(_signers[i] != address(0) && !signerSet[_signers[i]], "no zero addresses or duplicates");
            signerSet[_signers[i]] = true;
        }
    }

    // MODIFIERS
    modifier onlyPrimary {
        require(msg.sender == primary, "only primary");
        _;
    }

     modifier onlySigner {
        require(signerSet[msg.sender], "only signer");
        _;
    }

    // METHODS
    /** @notice  Requests an unlocking with a lock identifier and a callback.
      *
      * @dev  If called by an account other than the primary a 1 ETH stake
      * must be paid. When the request is unlocked stake will be transferred to the message sender.
      * This is an anti-spam measure. As well as the callback
      * and the lock identifier parameters a 'whitelisted address' is required
      * for compatibility with existing signature schemes.
      *
      * @param  _lockId  The identifier of a pending request in a co-operating contract.
      * @param  _callbackAddress  The address of a co-operating contract.
      * @param  _callbackSelector  The function selector of a function within
      * the co-operating contract at address `_callbackAddress`.
      * @param  _whitelistedAddress  An address whitelisted in existing
      * offline control protocols.
      *
      * @return  requestMsgHash  The hash of a request message to be signed.
    */
    function requestUnlock(
        bytes32 _lockId,
        address _callbackAddress,
        bytes4 _callbackSelector,
        address _whitelistedAddress
    )
        public
        payable
        returns (bytes32 requestMsgHash)
    {
        require(msg.sender == primary || msg.value >= 1 ether, "sender is primary or stake is paid");

        // disallow using a zero value for the callback address
        require(_callbackAddress != address(0), "no zero value for callback address");

        uint256 requestIdx = ++requestCount;
        // compute a nonce value
        // - the blockhash prevents prediction of future nonces
        // - the address of this contract prevents conflicts with co-operating contracts using this scheme
        // - the counter prevents conflicts arising from multiple txs within the same block
        uint256 nonce = uint256(keccak256(abi.encodePacked(blockhash(block.number - 1), address(this), requestIdx)));

        requestMsgHash = keccak256(
            abi.encodePacked(
                nonce,
                _whitelistedAddress,
                uint256(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
            )
        );
        requestMap[requestMsgHash] = Request({
            lockId: _lockId,
            callbackSelector: _callbackSelector,
            callbackAddress: _callbackAddress,
            idx: requestIdx,
            timestamp: block.timestamp,
            extended: false
        });

        // compute the expiry time
        uint256 timeLockExpiry = block.timestamp;
        if (msg.sender == primary) {
            timeLockExpiry += defaultTimeLock;
        } else {
            timeLockExpiry += extendedTimeLock;

            // any sender that is not the creator will get the extended time lock
            requestMap[requestMsgHash].extended = true;
        }

        emit Requested(_lockId, _callbackAddress, _callbackSelector, nonce, _whitelistedAddress, requestMsgHash, timeLockExpiry);
    }

    /** @notice  Completes a pending unlocking with two signatures.
      *
      * @dev  Given a request message hash as two signatures of it from
      * two distinct signers in the signer set, this function completes the
      * unlocking of the pending request by executing the callback.
      *
      * @param  _requestMsgHash  The request message hash of a pending request.
      * @param  _recoveryByte1  The public key recovery byte (27 or 28)
      * @param  _ecdsaR1  The R component of an ECDSA signature (R, S) pair
      * @param  _ecdsaS1  The S component of an ECDSA signature (R, S) pair
      * @param  _recoveryByte2  The public key recovery byte (27 or 28)
      * @param  _ecdsaR2  The R component of an ECDSA signature (R, S) pair
      * @param  _ecdsaS2  The S component of an ECDSA signature (R, S) pair
      *
      * @return  success  True if the callback successfully executed.
    */
    function completeUnlock(
        bytes32 _requestMsgHash,
        uint8 _recoveryByte1, bytes32 _ecdsaR1, bytes32 _ecdsaS1,
        uint8 _recoveryByte2, bytes32 _ecdsaR2, bytes32 _ecdsaS2
    )
        public
        onlySigner
        returns (bool success)
    {
        Request storage request = requestMap[_requestMsgHash];

        // copy storage to locals before `delete`
        bytes32 lockId = request.lockId;
        address callbackAddress = request.callbackAddress;
        bytes4 callbackSelector = request.callbackSelector;

        // failing case of the lookup if the callback address is zero
        require(callbackAddress != address(0), "no zero value for callback address");

        // reject confirms of earlier withdrawals buried under later confirmed withdrawals
        require(request.idx > lastCompletedIdxs[callbackAddress][callbackSelector],
        "reject confirms of earlier withdrawals buried under later confirmed withdrawals");

        address signer1 = ecrecover(
            keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _requestMsgHash)),
            _recoveryByte1,
            _ecdsaR1,
            _ecdsaS1
        );
        require(signerSet[signer1], "signer is set");

        address signer2 = ecrecover(
            keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _requestMsgHash)),
            _recoveryByte2,
            _ecdsaR2,
            _ecdsaS2
        );
        require(signerSet[signer2], "signer is set");
        require(signer1 != signer2, "signers are different");

        if (request.extended && ((block.timestamp - request.timestamp) < extendedTimeLock)) {
            emit TimeLocked(request.timestamp + extendedTimeLock, _requestMsgHash);
            return false;
        } else if ((block.timestamp - request.timestamp) < defaultTimeLock) {
            emit TimeLocked(request.timestamp + defaultTimeLock, _requestMsgHash);
            return false;
        } else {
            if (address(this).balance > 0) {
                // reward sender with anti-spam payments
                msg.sender.transfer(address(this).balance);
            }

            // raise the waterline for the last completed unlocking
            lastCompletedIdxs[callbackAddress][callbackSelector] = request.idx;
            // and delete the request
            delete requestMap[_requestMsgHash];

            // invoke callback
            (success,) = callbackAddress.call(abi.encodeWithSelector(callbackSelector, lockId));

            if (success) {
                emit Completed(lockId, _requestMsgHash, signer1, signer2);
            } else {
                emit Failed(lockId, _requestMsgHash, signer1, signer2);
            }
        }
    }

    /** @notice  Reclaim the storage of a pending request that is uncompletable.
      *
      * @dev  If a pending request shares the callback (address and selector) of
      * a later request has been completed, then the request can no longer
      * be completed. This function will reclaim the contract storage of the
      * pending request.
      *
      * @param  _requestMsgHash  The request message hash of a pending request.
    */
    function deleteUncompletableRequest(bytes32 _requestMsgHash) public {
        Request storage request = requestMap[_requestMsgHash];

        uint256 idx = request.idx;

        require(0 < idx && idx < lastCompletedIdxs[request.callbackAddress][request.callbackSelector],
        "there must be a completed latter request with same callback");

        delete requestMap[_requestMsgHash];
    }

    /** @notice  Extend the time lock of a pending request.
      *
      * @dev  Requests made by the primary account receive the default time lock.
      * This function allows the primary account to apply the extended time lock
      * to one its own requests.
      *
      * @param  _requestMsgHash  The request message hash of a pending request.
    */
    function extendRequestTimeLock(bytes32 _requestMsgHash) public onlyPrimary {
        Request storage request = requestMap[_requestMsgHash];

        // reject ‘null’ results from the map lookup
        // this can only be the case if an unknown `_requestMsgHash` is received
        require(request.callbackAddress != address(0), "reject ‘null’ results from the map lookup");

        // `extendRequestTimeLock` must be idempotent
        require(request.extended != true, "`extendRequestTimeLock` must be idempotent");

        // set the `extended` flag; note that this is never unset
        request.extended = true;

        emit TimeLockExtended(request.timestamp + extendedTimeLock, _requestMsgHash);
    }
}

/** @title  A contract to inherit upgradeable custodianship.
  *
  * @notice  A contract that provides re-usable code for upgradeable
  * custodianship. That custodian may be an account or another contract.
  *
  * @dev  This contract is intended to be inherited by any contract
  * requiring a custodian to control some aspect of its functionality.
  * This contract provides the mechanism for that custodianship to be
  * passed from one custodian to the next.
  *
*/
contract CustodianUpgradeable is LockRequestable {

    // TYPES
    /// @dev  The struct type for pending custodian changes.
    struct CustodianChangeRequest {
        address proposedNew;
    }

    // MEMBERS
    /// @dev  The address of the account or contract that acts as the custodian.
    address public custodian;

    /// @dev  The map of lock ids to pending custodian changes.
    mapping (bytes32 => CustodianChangeRequest) public custodianChangeReqs;

    // CONSTRUCTOR
    constructor(
        address _custodian
    )
      LockRequestable()
      public
    {
        custodian = _custodian;
    }

    // MODIFIERS
    modifier onlyCustodian {
        require(msg.sender == custodian, "only custodian");
        _;
    }

    // PUBLIC FUNCTIONS
    // (UPGRADE)

    /** @notice  Requests a change of the custodian associated with this contract.
      *
      * @dev  Returns a unique lock id associated with the request.
      * Anyone can call this function, but confirming the request is authorized
      * by the custodian.
      *
      * @param  _proposedCustodian  The address of the new custodian.
      * @return  lockId  A unique identifier for this request.
      */
    function requestCustodianChange(address _proposedCustodian) public returns (bytes32 lockId) {
        require(_proposedCustodian != address(0), "no null value for `_proposedCustodian`");

        lockId = generateLockId();

        custodianChangeReqs[lockId] = CustodianChangeRequest({
            proposedNew: _proposedCustodian
        });

        emit CustodianChangeRequested(lockId, msg.sender, _proposedCustodian);
    }

    /** @notice  Confirms a pending change of the custodian associated with this contract.
      *
      * @dev  When called by the current custodian with a lock id associated with a
      * pending custodian change, the `address custodian` member will be updated with the
      * requested address.
      *
      * @param  _lockId  The identifier of a pending change request.
      */
    function confirmCustodianChange(bytes32 _lockId) public onlyCustodian {
        custodian = getCustodianChangeReq(_lockId);

        delete custodianChangeReqs[_lockId];

        emit CustodianChangeConfirmed(_lockId, custodian);
    }

    // PRIVATE FUNCTIONS
    function getCustodianChangeReq(bytes32 _lockId) private view returns (address _proposedNew) {
        CustodianChangeRequest storage changeRequest = custodianChangeReqs[_lockId];

        // reject ‘null’ results from the map lookup
        // this can only be the case if an unknown `_lockId` is received
        require(changeRequest.proposedNew != address(0), "reject ‘null’ results from the map lookup");

        return changeRequest.proposedNew;
    }

    //EVENTS
    /// @dev  Emitted by successful `requestCustodianChange` calls.
    event CustodianChangeRequested(
        bytes32 _lockId,
        address _msgSender,
        address _proposedCustodian
    );

    /// @dev Emitted by successful `confirmCustodianChange` calls.
    event CustodianChangeConfirmed(bytes32 _lockId, address _newCustodian);
}

/** @title  A contract to inherit upgradeable token implementations.
  *
  * @notice  A contract that provides re-usable code for upgradeable
  * token implementations. It itself inherits from `CustodianUpgradable`
  * as the upgrade process is controlled by the custodian.
  *
  * @dev  This contract is intended to be inherited by any contract
  * requiring a reference to the active token implementation, either
  * to delegate calls to it, or authorize calls from it. This contract
  * provides the mechanism for that implementation to be replaced,
  * which constitutes an implementation upgrade.
  *
  */
contract ERC20ImplUpgradeable is CustodianUpgradeable  {

    // TYPES
    /// @dev  The struct type for pending implementation changes.
    struct ImplChangeRequest {
        address proposedNew;
    }

    // MEMBERS
    // @dev  The reference to the active token implementation.
    ERC20Impl public erc20Impl;

    /// @dev  The map of lock ids to pending implementation changes.
    mapping (bytes32 => ImplChangeRequest) public implChangeReqs;

    // CONSTRUCTOR
    constructor(address _custodian) CustodianUpgradeable(_custodian) public {
        erc20Impl = ERC20Impl(0x0);
    }

    // MODIFIERS
    modifier onlyImpl {
        require(msg.sender == address(erc20Impl), "only ERC20Impl");
        _;
    }

    // PUBLIC FUNCTIONS
    // (UPGRADE)
    /** @notice  Requests a change of the active implementation associated
      * with this contract.
      *
      * @dev  Returns a unique lock id associated with the request.
      * Anyone can call this function, but confirming the request is authorized
      * by the custodian.
      *
      * @param  _proposedImpl  The address of the new active implementation.
      * @return  lockId  A unique identifier for this request.
      */
    function requestImplChange(address _proposedImpl) public returns (bytes32 lockId) {
        require(_proposedImpl != address(0), "no null value for `_proposedImpl`");

        lockId = generateLockId();

        implChangeReqs[lockId] = ImplChangeRequest({
            proposedNew: _proposedImpl
        });

        emit ImplChangeRequested(lockId, msg.sender, _proposedImpl);
    }

    /** @notice  Confirms a pending change of the active implementation
      * associated with this contract.
      *
      * @dev  When called by the custodian with a lock id associated with a
      * pending change, the `ERC20Impl erc20Impl` member will be updated
      * with the requested address.
      *
      * @param  _lockId  The identifier of a pending change request.
      */
    function confirmImplChange(bytes32 _lockId) public onlyCustodian {
        erc20Impl = getImplChangeReq(_lockId);

        delete implChangeReqs[_lockId];

        emit ImplChangeConfirmed(_lockId, address(erc20Impl));
    }

    // PRIVATE FUNCTIONS
    function getImplChangeReq(bytes32 _lockId) private view returns (ERC20Impl _proposedNew) {
        ImplChangeRequest storage changeRequest = implChangeReqs[_lockId];

        // reject ‘null’ results from the map lookup
        // this can only be the case if an unknown `_lockId` is received
        require(changeRequest.proposedNew != address(0), "reject ‘null’ results from the map lookup");

        return ERC20Impl(changeRequest.proposedNew);
    }

    //EVENTS
    /// @dev  Emitted by successful `requestImplChange` calls.
    event ImplChangeRequested(
        bytes32 _lockId,
        address _msgSender,
        address _proposedImpl
    );

    /// @dev Emitted by successful `confirmImplChange` calls.
    event ImplChangeConfirmed(bytes32 _lockId, address _newImpl);
}

/** @title  Public interface to ERC20 compliant token.
  *
  * @notice  This contract is a permanent entry point to an ERC20 compliant
  * system of contracts.
  *
  * @dev  This contract contains no business logic and instead
  * delegates to an instance of ERC20Impl. This contract also has no storage
  * that constitutes the operational state of the token. This contract is
  * upgradeable in the sense that the `custodian` can update the
  * `erc20Impl` address, thus redirecting the delegation of business logic.
  * The `custodian` is also authorized to pass custodianship.
  *
*/
contract ERC20Proxy is ERC20Interface, ERC20ImplUpgradeable {

    // MEMBERS
    /// @notice  Returns the name of the token.
    string public name;

    /// @notice  Returns the symbol of the token.
    string public symbol;

    /// @notice  Returns the number of decimals the token uses.
    uint8 public decimals;

    // CONSTRUCTOR
    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals,
        address _custodian
    )
        ERC20ImplUpgradeable(_custodian)
        public
    {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;
    }

    // PUBLIC FUNCTIONS
    // (ERC20Interface)
    /** @notice  Returns the total token supply.
      *
      * @return  the total token supply.
      */
    function totalSupply() public view returns (uint256) {
        return erc20Impl.totalSupply();
    }

    /** @notice  Returns the account balance of another account with an address
      * `_owner`.
      *
      * @return  balance  the balance of account with address `_owner`.
      */
    function balanceOf(address _owner) public view returns (uint256 balance) {
        return erc20Impl.balanceOf(_owner);
    }

    /** @dev Internal use only.
      */
    function emitTransfer(address _from, address _to, uint256 _value) public onlyImpl {
        emit Transfer(_from, _to, _value);
    }

    /** @notice  Transfers `_value` amount of tokens to address `_to`.
      *
      * @dev Will fire the `Transfer` event. Will revert if the `_from`
      * account balance does not have enough tokens to spend.
      *
      * @return  success  true if transfer completes.
      */
    function transfer(address _to, uint256 _value) public returns (bool success) {
        return erc20Impl.transferWithSender(msg.sender, _to, _value);
    }

    /** @notice  Transfers `_value` amount of tokens from address `_from`
      * to address `_to`.
      *
      * @dev  Will fire the `Transfer` event. Will revert unless the `_from`
      * account has deliberately authorized the sender of the message
      * via some mechanism.
      *
      * @return  success  true if transfer completes.
      */
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
        return erc20Impl.transferFromWithSender(msg.sender, _from, _to, _value);
    }

    /** @dev Internal use only.
      */
    function emitApproval(address _owner, address _spender, uint256 _value) public onlyImpl {
        emit Approval(_owner, _spender, _value);
    }

    /** @notice  Allows `_spender` to withdraw from your account multiple times,
      * up to the `_value` amount. If this function is called again it
      * overwrites the current allowance with _value.
      *
      * @dev  Will fire the `Approval` event.
      *
      * @return  success  true if approval completes.
      */
    function approve(address _spender, uint256 _value) public returns (bool success) {
        return erc20Impl.approveWithSender(msg.sender, _spender, _value);
    }

    /** @notice Increases the amount `_spender` is allowed to withdraw from
      * your account.
      * This function is implemented to avoid the race condition in standard
      * ERC20 contracts surrounding the `approve` method.
      *
      * @dev  Will fire the `Approval` event. This function should be used instead of
      * `approve`.
      *
      * @return  success  true if approval completes.
      */
    function increaseApproval(address _spender, uint256 _addedValue) public returns (bool success) {
        return erc20Impl.increaseApprovalWithSender(msg.sender, _spender, _addedValue);
    }

    /** @notice  Decreases the amount `_spender` is allowed to withdraw from
      * your account. This function is implemented to avoid the race
      * condition in standard ERC20 contracts surrounding the `approve` method.
      *
      * @dev  Will fire the `Approval` event. This function should be used
      * instead of `approve`.
      *
      * @return  success  true if approval completes.
      */
    function decreaseApproval(address _spender, uint256 _subtractedValue) public returns (bool success) {
        return erc20Impl.decreaseApprovalWithSender(msg.sender, _spender, _subtractedValue);
    }

    /** @notice  Returns how much `_spender` is currently allowed to spend from
      * `_owner`'s balance.
      *
      * @return  remaining  the remaining allowance.
      */
    function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
        return erc20Impl.allowance(_owner, _spender);
    }
}

/** @title  ERC20 compliant token balance store.
  *
  * @notice  This contract serves as the store of balances, allowances, and
  * supply for the ERC20 compliant token. No business logic exists here.
  *
  * @dev  This contract contains no business logic and instead
  * is the final destination for any change in balances, allowances, or token
  * supply. This contract is upgradeable in the sense that its custodian can
  * update the `erc20Impl` address, thus redirecting the source of logic that
  * determines how the balances will be updated.
  *
  */
contract ERC20Store is ERC20ImplUpgradeable {

    // MEMBERS
    /// @dev  The total token supply.
    uint256 public totalSupply;

    /// @dev  The mapping of balances.
    mapping (address => uint256) public balances;

    /// @dev  The mapping of allowances.
    mapping (address => mapping (address => uint256)) public allowed;

    // CONSTRUCTOR
    constructor(address _custodian) ERC20ImplUpgradeable(_custodian) public {
        totalSupply = 0;
    }

    // PUBLIC FUNCTIONS
    // (ERC20 Ledger)

    /** @notice  The function to set the total supply of tokens.
      *
      * @dev  Intended for use by token implementation functions
      * that update the total supply. The only authorized caller
      * is the active implementation.
      *
      * @param _newTotalSupply the value to set as the new total supply
      */
    function setTotalSupply(
        uint256 _newTotalSupply
    )
        public
        onlyImpl
    {
        totalSupply = _newTotalSupply;
    }

    /** @notice  Sets how much `_owner` allows `_spender` to transfer on behalf
      * of `_owner`.
      *
      * @dev  Intended for use by token implementation functions
      * that update spending allowances. The only authorized caller
      * is the active implementation.
      *
      * @param  _owner  The account that will allow an on-behalf-of spend.
      * @param  _spender  The account that will spend on behalf of the owner.
      * @param  _value  The limit of what can be spent.
      */
    function setAllowance(
        address _owner,
        address _spender,
        uint256 _value
    )
        public
        onlyImpl
    {
        allowed[_owner][_spender] = _value;
    }

    /** @notice  Sets the balance of `_owner` to `_newBalance`.
      *
      * @dev  Intended for use by token implementation functions
      * that update balances. The only authorized caller
      * is the active implementation.
      *
      * @param  _owner  The account that will hold a new balance.
      * @param  _newBalance  The balance to set.
      */
    function setBalance(
        address _owner,
        uint256 _newBalance
    )
        public
        onlyImpl
    {
        balances[_owner] = _newBalance;
    }

    /** @notice Adds `_balanceIncrease` to `_owner`'s balance.
      *
      * @dev  Intended for use by token implementation functions
      * that update balances. The only authorized caller
      * is the active implementation.
      * WARNING: the caller is responsible for preventing overflow.
      *
      * @param  _owner  The account that will hold a new balance.
      * @param  _balanceIncrease  The balance to add.
      */
    function addBalance(
        address _owner,
        uint256 _balanceIncrease
    )
        public
        onlyImpl
    {
        balances[_owner] = balances[_owner] + _balanceIncrease;
    }
}

/** @title  ERC20 compliant token intermediary contract holding core logic.
  *
  * @notice  This contract serves as an intermediary between the exposed ERC20
  * interface in ERC20Proxy and the store of balances in ERC20Store. This
  * contract contains core logic that the proxy can delegate to
  * and that the store is called by.
  *
  * @dev  This contract contains the core logic to implement the
  * ERC20 specification as well as several extensions.
  * 1. Changes to the token supply.
  * 2. Batched transfers.
  * 3. Relative changes to spending approvals.
  * 4. Delegated transfer control ('sweeping').
  *
  */
contract ERC20Impl is CustodianUpgradeable {

    // TYPES
    /// @dev  The struct type for pending increases to the token supply (print).
    struct PendingPrint {
        address receiver;
        uint256 value;
    }

    // MEMBERS
    /// @dev  The reference to the proxy.
    ERC20Proxy public erc20Proxy;

    /// @dev  The reference to the store.
    ERC20Store public erc20Store;

    /// @dev  The sole authorized caller of delegated transfer control ('sweeping').
    address public sweeper;

    /** @dev  The static message to be signed by an external account that
      * signifies their permission to forward their balance to any arbitrary
      * address. This is used to consolidate the control of all accounts
      * backed by a shared keychain into the control of a single key.
      * Initialized as the concatenation of the address of this contract
      * and the word "sweep". This concatenation is done to prevent a replay
      * attack in a subsequent contract, where the sweeping message could
      * potentially be replayed to re-enable sweeping ability.
      */
    bytes32 public sweepMsg;

    /** @dev  The mapping that stores whether the address in question has
      * enabled sweeping its contents to another account or not.
      * If an address maps to "true", it has already enabled sweeping,
      * and thus does not need to re-sign the `sweepMsg` to enact the sweep.
      */
    mapping (address => bool) public sweptSet;

    /// @dev  The map of lock ids to pending token increases.
    mapping (bytes32 => PendingPrint) public pendingPrintMap;

    /// @dev The map of blocked addresses.
    mapping (address => bool) public blocked;

    // CONSTRUCTOR
    constructor(
          address _erc20Proxy,
          address _erc20Store,
          address _custodian,
          address _sweeper
    )
        CustodianUpgradeable(_custodian)
        public
    {
        require(_sweeper != address(0), "no null value for `_sweeper`");
        erc20Proxy = ERC20Proxy(_erc20Proxy);
        erc20Store = ERC20Store(_erc20Store);

        sweeper = _sweeper;
        sweepMsg = keccak256(abi.encodePacked(address(this), "sweep"));
    }

    // MODIFIERS
    modifier onlyProxy {
        require(msg.sender == address(erc20Proxy), "only ERC20Proxy");
        _;
    }
    modifier onlySweeper {
        require(msg.sender == sweeper, "only sweeper");
        _;
    }


    /** @notice  Core logic of the ERC20 `approve` function.
      *
      * @dev  This function can only be called by the referenced proxy,
      * which has an `approve` function.
      * Every argument passed to that function as well as the original
      * `msg.sender` gets passed to this function.
      * NOTE: approvals for the zero address (unspendable) are disallowed.
      *
      * @param  _sender  The address initiating the approval in a proxy.
      */
    function approveWithSender(
        address _sender,
        address _spender,
        uint256 _value
    )
        public
        onlyProxy
        returns (bool success)
    {
        require(_spender != address(0), "no null value for `_spender`");
        require(blocked[_sender] != true, "_sender must not be blocked");
        require(blocked[_spender] != true, "_spender must not be blocked");
        erc20Store.setAllowance(_sender, _spender, _value);
        erc20Proxy.emitApproval(_sender, _spender, _value);
        return true;
    }

    /** @notice  Core logic of the `increaseApproval` function.
      *
      * @dev  This function can only be called by the referenced proxy,
      * which has an `increaseApproval` function.
      * Every argument passed to that function as well as the original
      * `msg.sender` gets passed to this function.
      * NOTE: approvals for the zero address (unspendable) are disallowed.
      *
      * @param  _sender  The address initiating the approval.
      */
    function increaseApprovalWithSender(
        address _sender,
        address _spender,
        uint256 _addedValue
    )
        public
        onlyProxy
        returns (bool success)
    {
        require(_spender != address(0),"no null value for_spender");
        require(blocked[_sender] != true, "_sender must not be blocked");
        require(blocked[_spender] != true, "_spender must not be blocked");
        uint256 currentAllowance = erc20Store.allowed(_sender, _spender);
        uint256 newAllowance = currentAllowance + _addedValue;

        require(newAllowance >= currentAllowance, "new allowance must not be smaller than previous");

        erc20Store.setAllowance(_sender, _spender, newAllowance);
        erc20Proxy.emitApproval(_sender, _spender, newAllowance);
        return true;
    }

    /** @notice  Core logic of the `decreaseApproval` function.
      *
      * @dev  This function can only be called by the referenced proxy,
      * which has a `decreaseApproval` function.
      * Every argument passed to that function as well as the original
      * `msg.sender` gets passed to this function.
      * NOTE: approvals for the zero address (unspendable) are disallowed.
      *
      * @param  _sender  The address initiating the approval.
      */
    function decreaseApprovalWithSender(
        address _sender,
        address _spender,
        uint256 _subtractedValue
    )
        public
        onlyProxy
        returns (bool success)
    {
        require(_spender != address(0), "no unspendable approvals"); // disallow unspendable approvals
        require(blocked[_sender] != true, "_sender must not be blocked");
        require(blocked[_spender] != true, "_spender must not be blocked");
        uint256 currentAllowance = erc20Store.allowed(_sender, _spender);
        uint256 newAllowance = currentAllowance - _subtractedValue;

        require(newAllowance <= currentAllowance, "new allowance must not be smaller than previous");

        erc20Store.setAllowance(_sender, _spender, newAllowance);
        erc20Proxy.emitApproval(_sender, _spender, newAllowance);
        return true;
    }

    /** @notice  Requests an increase in the token supply, with the newly created
      * tokens to be added to the balance of the specified account.
      *
      * @dev  Returns a unique lock id associated with the request.
      * Anyone can call this function, but confirming the request is authorized
      * by the custodian.
      * NOTE: printing to the zero address is disallowed.
      *
      * @param  _receiver  The receiving address of the print, if confirmed.
      * @param  _value  The number of tokens to add to the total supply and the
      * balance of the receiving address, if confirmed.
      *
      * @return  lockId  A unique identifier for this request.
      */
    function requestPrint(address _receiver, uint256 _value) public returns (bytes32 lockId) {
        require(_receiver != address(0), "no null value for `_receiver`");
        require(blocked[msg.sender] != true, "account blocked");
        require(blocked[_receiver] != true, "_receiver must not be blocked");
        lockId = generateLockId();

        pendingPrintMap[lockId] = PendingPrint({
            receiver: _receiver,
            value: _value
        });

        emit PrintingLocked(lockId, _receiver, _value);
    }

    /** @notice  Confirms a pending increase in the token supply.
      *
      * @dev  When called by the custodian with a lock id associated with a
      * pending increase, the amount requested to be printed in the print request
      * is printed to the receiving address specified in that same request.
      * NOTE: this function will not execute any print that would overflow the
      * total supply, but it will not revert either.
      *
      * @param  _lockId  The identifier of a pending print request.
      */
    function confirmPrint(bytes32 _lockId) public onlyCustodian {
        PendingPrint storage print = pendingPrintMap[_lockId];

        // reject ‘null’ results from the map lookup
        // this can only be the case if an unknown `_lockId` is received
        address receiver = print.receiver;
        require (receiver != address(0), "unknown `_lockId`");
        uint256 value = print.value;

        delete pendingPrintMap[_lockId];

        uint256 supply = erc20Store.totalSupply();
        uint256 newSupply = supply + value;
        if (newSupply >= supply) {
          erc20Store.setTotalSupply(newSupply);
          erc20Store.addBalance(receiver, value);

          emit PrintingConfirmed(_lockId, receiver, value);
          erc20Proxy.emitTransfer(address(0), receiver, value);
        }
    }

    /** @notice  Burns the specified value from the sender's balance.
      *
      * @dev  Sender's balanced is subtracted by the amount they wish to burn.
      *
      * @param  _value  The amount to burn.
      *
      * @return success true if the burn succeeded.
      */
    function burn(uint256 _value) public returns (bool success) {
        require(blocked[msg.sender] != true, "account blocked");
        uint256 balanceOfSender = erc20Store.balances(msg.sender);
        require(_value <= balanceOfSender, "disallow burning more, than amount of the balance");

        erc20Store.setBalance(msg.sender, balanceOfSender - _value);
        erc20Store.setTotalSupply(erc20Store.totalSupply() - _value);

        erc20Proxy.emitTransfer(msg.sender, address(0), _value);

        return true;
    }

     /** @notice  Burns the specified value from the balance in question.
      *
      * @dev  Suspected balance is subtracted by the amount which will be burnt.
      *
      * @dev If the suspected balance has less than the amount requested, it will be set to 0.
      *
      * @param  _from  The address of suspected balance.
      *
      * @param  _value  The amount to burn.
      *
      * @return success true if the burn succeeded.
      */
    function burn(address _from, uint256 _value) public onlyCustodian returns (bool success) {
        uint256 balance = erc20Store.balances(_from);
        if(_value <= balance){
            erc20Store.setBalance(_from, balance - _value);
            erc20Store.setTotalSupply(erc20Store.totalSupply() - _value);
            erc20Proxy.emitTransfer(_from, address(0), _value);
            emit Wiped(_from, _value, _value, balance - _value);
        }
        else {
            erc20Store.setBalance(_from,0);
            erc20Store.setTotalSupply(erc20Store.totalSupply() - balance);
            erc20Proxy.emitTransfer(_from, address(0), balance);
            emit Wiped(_from, _value, balance, 0);
        }
        return true;
    }

    /** @notice  A function for a sender to issue multiple transfers to multiple
      * different addresses at once. This function is implemented for gas
      * considerations when someone wishes to transfer, as one transaction is
      * cheaper than issuing several distinct individual `transfer` transactions.
      *
      * @dev  By specifying a set of destination addresses and values, the
      * sender can issue one transaction to transfer multiple amounts to
      * distinct addresses, rather than issuing each as a separate
      * transaction. The `_tos` and `_values` arrays must be equal length, and
      * an index in one array corresponds to the same index in the other array
      * (e.g. `_tos[0]` will receive `_values[0]`, `_tos[1]` will receive
      * `_values[1]`, and so on.)
      * NOTE: transfers to the zero address are disallowed.
      *
      * @param  _tos  The destination addresses to receive the transfers.
      * @param  _values  The values for each destination address.
      * @return  success  If transfers succeeded.
      */
    function batchTransfer(address[] memory _tos, uint256[] memory _values) public returns (bool success) {
        require(_tos.length == _values.length, "_tos and _values must be the same length");
        require(blocked[msg.sender] != true, "account blocked");
        uint256 numTransfers = _tos.length;
        uint256 senderBalance = erc20Store.balances(msg.sender);

        for (uint256 i = 0; i < numTransfers; i++) {
          address to = _tos[i];
          require(to != address(0), "no null values for _tos");
          require(blocked[to] != true, "_tos must not be blocked");
          uint256 v = _values[i];
          require(senderBalance >= v, "insufficient funds");

          if (msg.sender != to) {
            senderBalance -= v;
            erc20Store.addBalance(to, v);
          }
          erc20Proxy.emitTransfer(msg.sender, to, v);
        }

        erc20Store.setBalance(msg.sender, senderBalance);

        return true;
    }

    /** @notice  Enables the delegation of transfer control for many
      * accounts to the sweeper account, transferring any balances
      * as well to the given destination.
      *
      * @dev  An account delegates transfer control by signing the
      * value of `sweepMsg`. The sweeper account is the only authorized
      * caller of this function, so it must relay signatures on behalf
      * of accounts that delegate transfer control to it. Enabling
      * delegation is idempotent and permanent. If the account has a
      * balance at the time of enabling delegation, its balance is
      * also transferred to the given destination account `_to`.
      * NOTE: transfers to the zero address are disallowed.
      *
      * @param  _vs  The array of recovery byte components of the ECDSA signatures.
      * @param  _rs  The array of 'R' components of the ECDSA signatures.
      * @param  _ss  The array of 'S' components of the ECDSA signatures.
      * @param  _to  The destination for swept balances.
      */
    function enableSweep(uint8[] memory _vs, bytes32[] memory _rs, bytes32[] memory _ss, address _to) public onlySweeper {
        require(_to != address(0), "no null value for `_to`");
        require(blocked[_to] != true, "_to must not be blocked");
        require((_vs.length == _rs.length) && (_vs.length == _ss.length), "_vs[], _rs[], _ss lengths are different");

        uint256 numSignatures = _vs.length;
        uint256 sweptBalance = 0;

        for (uint256 i = 0; i < numSignatures; ++i) {
            address from = ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32",sweepMsg)), _vs[i], _rs[i], _ss[i]);
            require(blocked[from] != true, "_froms must not be blocked");
            // ecrecover returns 0 on malformed input
            if (from != address(0)) {
                sweptSet[from] = true;

                uint256 fromBalance = erc20Store.balances(from);

                if (fromBalance > 0) {
                    sweptBalance += fromBalance;

                    erc20Store.setBalance(from, 0);

                    erc20Proxy.emitTransfer(from, _to, fromBalance);
                }
            }
        }

        if (sweptBalance > 0) {
          erc20Store.addBalance(_to, sweptBalance);
        }
    }

    /** @notice  For accounts that have delegated, transfer control
      * to the sweeper, this function transfers their balances to the given
      * destination.
      *
      * @dev The sweeper account is the only authorized caller of
      * this function. This function accepts an array of addresses to have their
      * balances transferred for gas efficiency purposes.
      * NOTE: any address for an account that has not been previously enabled
      * will be ignored.
      * NOTE: transfers to the zero address are disallowed.
      *
      * @param  _froms  The addresses to have their balances swept.
      * @param  _to  The destination address of all these transfers.
      */
    function replaySweep(address[] memory _froms, address _to) public onlySweeper {
        require(_to != address(0), "no null value for `_to`");
        require(blocked[_to] != true, "_to must not be blocked");
        uint256 lenFroms = _froms.length;
        uint256 sweptBalance = 0;

        for (uint256 i = 0; i < lenFroms; ++i) {
            address from = _froms[i];
            require(blocked[from] != true, "_froms must not be blocked");
            if (sweptSet[from]) {
                uint256 fromBalance = erc20Store.balances(from);

                if (fromBalance > 0) {
                    sweptBalance += fromBalance;

                    erc20Store.setBalance(from, 0);

                    erc20Proxy.emitTransfer(from, _to, fromBalance);
                }
            }
        }

        if (sweptBalance > 0) {
            erc20Store.addBalance(_to, sweptBalance);
        }
    }

    /** @notice  Core logic of the ERC20 `transferFrom` function.
      *
      * @dev  This function can only be called by the referenced proxy,
      * which has a `transferFrom` function.
      * Every argument passed to that function as well as the original
      * `msg.sender` gets passed to this function.
      * NOTE: transfers to the zero address are disallowed.
      *
      * @param  _sender  The address initiating the transfer in a proxy.
      */
    function transferFromWithSender(
        address _sender,
        address _from,
        address _to,
        uint256 _value
    )
        public
        onlyProxy
        returns (bool success)
    {
        require(_to != address(0), "no null values for `_to`");
        require(blocked[_sender] != true, "_sender must not be blocked");
        require(blocked[_from] != true, "_from must not be blocked");
        require(blocked[_to] != true, "_to must not be blocked");

        uint256 balanceOfFrom = erc20Store.balances(_from);
        require(_value <= balanceOfFrom, "insufficient funds on `_from` balance");

        uint256 senderAllowance = erc20Store.allowed(_from, _sender);
        require(_value <= senderAllowance, "insufficient allowance amount");

        erc20Store.setBalance(_from, balanceOfFrom - _value);
        erc20Store.addBalance(_to, _value);

        erc20Store.setAllowance(_from, _sender, senderAllowance - _value);

        erc20Proxy.emitTransfer(_from, _to, _value);

        return true;
    }

    /** @notice  Core logic of the ERC20 `transfer` function.
      *
      * @dev  This function can only be called by the referenced proxy,
      * which has a `transfer` function.
      * Every argument passed to that function as well as the original
      * `msg.sender` gets passed to this function.
      * NOTE: transfers to the zero address are disallowed.
      *
      * @param  _sender  The address initiating the transfer in a proxy.
      */
    function transferWithSender(
        address _sender,
        address _to,
        uint256 _value
    )
        public
        onlyProxy
        returns (bool success)
    {
        require(_to != address(0), "no null value for `_to`");
        require(blocked[_sender] != true, "_sender must not be blocked");
        require(blocked[_to] != true, "_to must not be blocked");

        uint256 balanceOfSender = erc20Store.balances(_sender);
        require(_value <= balanceOfSender, "insufficient funds");

        erc20Store.setBalance(_sender, balanceOfSender - _value);
        erc20Store.addBalance(_to, _value);

        erc20Proxy.emitTransfer(_sender, _to, _value);

        return true;
    }

    /** @notice  Transfers the specified value from the balance in question.
      *
      * @dev  Suspected balance is subtracted by the amount which will be transferred.
      *
      * @dev If the suspected balance has less than the amount requested, it will be set to 0.
      *
      * @param  _from  The address of suspected balance.
      *
      * @param  _value  The amount to transfer.
      *
      * @return success true if the transfer succeeded.
      */
    function forceTransfer(
        address _from,
        address _to,
        uint256 _value
    )
        public
        onlyCustodian
        returns (bool success)
    {
        require(_to != address(0), "no null value for `_to`");
        uint256 balanceOfSender = erc20Store.balances(_from);
        if(_value <= balanceOfSender) {
            erc20Store.setBalance(_from, balanceOfSender - _value);
            erc20Store.addBalance(_to, _value);

            erc20Proxy.emitTransfer(_from, _to, _value);
        } else {
            erc20Store.setBalance(_from, 0);
            erc20Store.addBalance(_to, balanceOfSender);

            erc20Proxy.emitTransfer(_from, _to, balanceOfSender);
        }

        return true;
    }

    // METHODS (ERC20 sub interface impl.)
    /// @notice  Core logic of the ERC20 `totalSupply` function.
    function totalSupply() public view returns (uint256) {
        return erc20Store.totalSupply();
    }

    /// @notice  Core logic of the ERC20 `balanceOf` function.
    function balanceOf(address _owner) public view returns (uint256 balance) {
        return erc20Store.balances(_owner);
    }

    /// @notice  Core logic of the ERC20 `allowance` function.
    function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
        return erc20Store.allowed(_owner, _spender);
    }

    /// @dev internal use only.
    function blockWallet(address wallet) public onlyCustodian returns (bool success) {
        blocked[wallet] = true;
        return true;
    }

    /// @dev internal use only.
    function unblockWallet(address wallet) public onlyCustodian returns (bool success) {
        blocked[wallet] = false;
        return true;
    }

    // EVENTS
    /// @dev  Emitted by successful `requestPrint` calls.
    event PrintingLocked(bytes32 _lockId, address _receiver, uint256 _value);

    /// @dev Emitted by successful `confirmPrint` calls.
    event PrintingConfirmed(bytes32 _lockId, address _receiver, uint256 _value);

    /** @dev Emitted by successful `confirmWipe` calls.
      *
      * @param _value Amount requested to be burned.
      *
      * @param _burned Amount which was burned.
      *
      * @param _balance Amount left on account after burn.
      *
      * @param _from Account which balance was burned.
      */
     event Wiped(address _from, uint256 _value, uint256 _burned, uint _balance);
}

/** @title  A contact to govern hybrid control over increases to the token supply and managing accounts.
  *
  * @notice  A contract that acts as a custodian of the active token
  * implementation, and an intermediary between it and the ‘true’ custodian.
  * It preserves the functionality of direct custodianship as well as granting
  * limited control of token supply increases to an additional key.
  *
  * @dev  This contract is a layer of indirection between an instance of
  * ERC20Impl and a custodian. The functionality of the custodianship over
  * the token implementation is preserved (printing and custodian changes),
  * but this contract adds the ability for an additional key
  * (the 'controller') to increase the token supply up to a ceiling,
  * and this supply ceiling can only be raised by the custodian.
  *
  */
contract Controller is LockRequestable {

    // TYPES
    /// @dev The struct type for pending ceiling raises.
    struct PendingCeilingRaise {
        uint256 raiseBy;
    }

    /// @dev The struct type for pending wipes.
    struct wipeAddress {
        uint256 value;
        address from;
    }

    /// @dev The struct type for pending force transfer requests.
    struct forceTransferRequest {
        uint256 value;
        address from;
        address to;
    }

    // MEMBERS
    /// @dev  The reference to the active token implementation.
    ERC20Impl public erc20Impl;

    /// @dev  The address of the account or contract that acts as the custodian.
    Custodian public custodian;

    /** @dev  The sole authorized caller of limited printing.
      * This account is also authorized to lower the supply ceiling and
      * wiping suspected accounts or force transferring funds from them.
      */
    address public controller;

    /** @dev  The maximum that the token supply can be increased to
      * through the use of the limited printing feature.
      * The difference between the current total supply and the supply
      * ceiling is what is available to the 'controller' account.
      * The value of the ceiling can only be increased by the custodian.
      */
    uint256 public totalSupplyCeiling;

    /// @dev  The map of lock ids to pending ceiling raises.
    mapping (bytes32 => PendingCeilingRaise) public pendingRaiseMap;

    /// @dev  The map of lock ids to pending wipes.
    mapping (bytes32 => wipeAddress[]) public pendingWipeMap;

    /// @dev  The map of lock ids to pending force transfer requests.
    mapping (bytes32 => forceTransferRequest) public pendingForceTransferRequestMap;

    // CONSTRUCTOR
    constructor(
        address _erc20Impl,
        address _custodian,
        address _controller,
        uint256 _initialCeiling
    )
        public
    {
        erc20Impl = ERC20Impl(_erc20Impl);
        custodian = Custodian(_custodian);
        controller = _controller;
        totalSupplyCeiling = _initialCeiling;
    }

    // MODIFIERS
    modifier onlyCustodian {
        require(msg.sender == address(custodian), "only custodian");
        _;
    }
    modifier onlyController {
        require(msg.sender == controller, "only controller");
        _;
    }

    modifier onlySigner {
        require(custodian.signerSet(msg.sender) == true, "only signer");
        _;
    }

    /** @notice  Increases the token supply, with the newly created tokens
      * being added to the balance of the specified account.
      *
      * @dev  The function checks that the value to print does not
      * exceed the supply ceiling when added to the current total supply.
      * NOTE: printing to the zero address is disallowed.
      *
      * @param  _receiver  The receiving address of the print.
      * @param  _value  The number of tokens to add to the total supply and the
      * balance of the receiving address.
      */
    function limitedPrint(address _receiver, uint256 _value) public onlyController {
        uint256 totalSupply = erc20Impl.totalSupply();
        uint256 newTotalSupply = totalSupply + _value;

        require(newTotalSupply >= totalSupply, "new total supply overflow");
        require(newTotalSupply <= totalSupplyCeiling, "total supply ceiling overflow");
        erc20Impl.confirmPrint(erc20Impl.requestPrint(_receiver, _value));
    }

    /** @notice  Requests wipe of suspected accounts.
      *
      * @dev  Returns a unique lock id associated with the request.
      * Only controller can call this function, and only the custodian
      * can confirm the request.
      *
      * @param  _froms  The array of suspected accounts.
      *
      * @param  _values  array of amounts by which suspected accounts will be wiped.
      *
      * @return  lockId  A unique identifier for this request.
      */
    function requestWipe(address[] memory _froms, uint256[] memory _values) public onlyController returns (bytes32 lockId) {
        require(_froms.length == _values.length, "_froms[] and _values[] must be same length");
        lockId = generateLockId();
        uint256 amount = _froms.length;

        for(uint256 i = 0; i < amount; i++) {
            address from = _froms[i];
            uint256 value = _values[i];
            pendingWipeMap[lockId].push(wipeAddress(value, from));
        }

        emit WipeRequested(lockId);

        return lockId;
    }

    /** @notice  Confirms a pending wipe of suspected accounts.
      *
      * @dev  When called by the custodian with a lock id associated with a
      * pending wipe, the amount requested is burned from the suspected accounts.
      *
      * @param  _lockId  The identifier of a pending wipe request.
      */
    function confirmWipe(bytes32 _lockId) public onlyCustodian {
        uint256 amount = pendingWipeMap[_lockId].length;
        for(uint256 i = 0; i < amount; i++) {
            wipeAddress memory addr = pendingWipeMap[_lockId][i];
            address from = addr.from;
            uint256 value = addr.value;
            erc20Impl.burn(from, value);
        }

        delete pendingWipeMap[_lockId];

        emit WipeCompleted(_lockId);
    }

    /** @notice  Requests force transfer from the suspected account.
      *
      * @dev  Returns a unique lock id associated with the request.
      * Only controller can call this function, and only the custodian
      * can confirm the request.
      *
      * @param  _from  address of suspected account.
      *
      * @param  _to  address of reciever.
      *
      * @param  _value  amount which will be transferred.
      *
      * @return  lockId  A unique identifier for this request.
      */
    function requestForceTransfer(address _from, address _to, uint256 _value) public onlyController returns (bytes32 lockId) {
        lockId = generateLockId();
        require (_value != 0, "no zero value transfers");
        pendingForceTransferRequestMap[lockId] = forceTransferRequest(_value, _from, _to);

        emit ForceTransferRequested(lockId, _from, _to, _value);

        return lockId;
    }

    /** @notice  Confirms a pending force transfer request.
      *
      * @dev  When called by the custodian with a lock id associated with a
      * pending transfer request, the amount requested is transferred from the suspected account.
      *
      * @param  _lockId  The identifier of a pending transfer request.
      */
    function confirmForceTransfer(bytes32 _lockId) public onlyCustodian {
        address from = pendingForceTransferRequestMap[_lockId].from;
        address to = pendingForceTransferRequestMap[_lockId].to;
        uint256 value = pendingForceTransferRequestMap[_lockId].value;

        delete pendingForceTransferRequestMap[_lockId];

        erc20Impl.forceTransfer(from, to, value);

        emit ForceTransferCompleted(_lockId, from, to, value);
    }

    /** @notice  Requests an increase to the supply ceiling.
      *
      * @dev  Returns a unique lock id associated with the request.
      * Anyone can call this function, but confirming the request is authorized
      * by the custodian.
      *
      * @param  _raiseBy  The amount by which to raise the ceiling.
      *
      * @return  lockId  A unique identifier for this request.
      */
    function requestCeilingRaise(uint256 _raiseBy) public returns (bytes32 lockId) {
        require(_raiseBy != 0, "no zero ceiling raise");

        lockId = generateLockId();

        pendingRaiseMap[lockId] = PendingCeilingRaise({
            raiseBy: _raiseBy
        });

        emit CeilingRaiseLocked(lockId, _raiseBy);
    }

    /** @notice  Confirms a pending increase in the token supply.
      *
      * @dev  When called by the custodian with a lock id associated with a
      * pending ceiling increase, the amount requested is added to the
      * current supply ceiling.
      * NOTE: this function will not execute any raise that would overflow the
      * supply ceiling, but it will not revert either.
      *
      * @param  _lockId  The identifier of a pending ceiling raise request.
      */
    function confirmCeilingRaise(bytes32 _lockId) public onlyCustodian {
        PendingCeilingRaise storage pendingRaise = pendingRaiseMap[_lockId];

        // copy locals of references to struct members
        uint256 raiseBy = pendingRaise.raiseBy;
        // accounts for a gibberish _lockId
        require(raiseBy != 0, "no gibberish _lockId");

        delete pendingRaiseMap[_lockId];

        uint256 newCeiling = totalSupplyCeiling + raiseBy;
        // overflow check
        if (newCeiling >= totalSupplyCeiling) {
            totalSupplyCeiling = newCeiling;

            emit CeilingRaiseConfirmed(_lockId, raiseBy, newCeiling);
        }
    }

    /** @notice  Lowers the supply ceiling, further constraining the bound of
      * what can be printed by the controller.
      *
      * @dev  The controller is the sole authorized caller of this function,
      * so it is the only account that can elect to lower its limit to increase
      * the token supply.
      *
      * @param  _lowerBy  The amount by which to lower the supply ceiling.
      */
    function lowerCeiling(uint256 _lowerBy) public onlyController {
        uint256 newCeiling = totalSupplyCeiling - _lowerBy;
        // overflow check
        require(newCeiling <= totalSupplyCeiling, "totalSupplyCeiling overflow");
        totalSupplyCeiling = newCeiling;

        emit CeilingLowered(_lowerBy, newCeiling);
    }

    /** @notice  Pass-through control of print confirmation, allowing this
      * contract's custodian to act as the custodian of the associated
      * active token implementation.
      *
      * @dev  This contract is the direct custodian of the active token
      * implementation, but this function allows this contract's custodian
      * to act as though it were the direct custodian of the active
      * token implementation. Therefore the custodian retains control of
      * unlimited printing.
      *
      * @param  _lockId  The identifier of a pending print request in
      * the associated active token implementation.
      */
    function confirmPrintProxy(bytes32 _lockId) public onlyCustodian {
        erc20Impl.confirmPrint(_lockId);
    }

    /** @notice  Pass-through control of custodian change confirmation,
      * allowing this contract's custodian to act as the custodian of
      * the associated active token implementation.
      *
      * @dev  This contract is the direct custodian of the active token
      * implementation, but this function allows this contract's custodian
      * to act as though it were the direct custodian of the active
      * token implementation. Therefore the custodian retains control of
      * custodian changes.
      *
      * @param  _lockId  The identifier of a pending custodian change request
      * in the associated active token implementation.
      */
    function confirmCustodianChangeProxy(bytes32 _lockId) public onlyCustodian {
        erc20Impl.confirmCustodianChange(_lockId);
    }

    /** @notice  Blocks all transactions with a wallet.
      *
      * @dev Only signers from custodian are authorized to call this function
      *
      * @param  wallet account which will be blocked.
      */
    function blockWallet(address wallet) public onlySigner {
        erc20Impl.blockWallet(wallet);
        emit Blocked(wallet);
    }

    /** @notice Unblocks all transactions with a wallet.
      *
      * @dev Only signers from custodian are authorized to call this function
      *
      * @param  wallet account which will be unblocked.
      */
    function unblockWallet(address wallet) public onlySigner {
        erc20Impl.unblockWallet(wallet);
        emit Unblocked(wallet);
    }

    // EVENTS
    /// @dev  Emitted by successful `requestCeilingRaise` calls.
    event CeilingRaiseLocked(bytes32 _lockId, uint256 _raiseBy);

    /// @dev  Emitted by successful `confirmCeilingRaise` calls.
    event CeilingRaiseConfirmed(bytes32 _lockId, uint256 _raiseBy, uint256 _newCeiling);

    /// @dev  Emitted by successful `lowerCeiling` calls.
    event CeilingLowered(uint256 _lowerBy, uint256 _newCeiling);

    /// @dev  Emitted by successful `blockWallet` calls.
    event Blocked(address _wallet);

    /// @dev  Emitted by successful `unblockWallet` calls.
    event Unblocked(address _wallet);

     /// @dev  Emitted by successful `requestForceTransfer` calls.
    event ForceTransferRequested(bytes32 _lockId, address _from, address _to, uint256 _value);

    /// @dev  Emitted by successful `confirmForceTransfer` calls.
    event ForceTransferCompleted(bytes32 _lockId, address _from, address _to, uint256 _value);

    /// @dev  Emitted by successful `requestWipe` calls.
    event WipeRequested(bytes32 _lockId);

    /// @dev  Emitted by successful `confirmWipe` calls.
    event WipeCompleted(bytes32 _lockId);
}

File 2 of 2: callbackSelector.sol
pragma solidity ^0.5.10;

/**
  * @title contract for generating HEX pointer
  * for functions.
  *
  * @dev this contract is a tool meant to be used
  * on local JavaScript VM.
  *
  */
contract callbackSelector {

    /**
      * @notice function which returns function HEX pointer (callbackSelector)
      *
      * @param _function function name with parameter types. Case and whitespace sensitive.
      *
      * @dev example: `function get(string memory _function)`
      *    _function: `get(string)`
      *       result: `0x693ec85e`
      */
    function get(string memory _function) public pure returns (bytes4) {
        return bytes4(keccak256(abi.encodePacked(_function)));
    }
}

Contract Security Audit

Contract ABI

API
[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_proposedCustodian","type":"address"}],"name":"requestCustodianChange","outputs":[{"name":"lockId","type":"bytes32"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"emitTransfer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"custodian","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lockId","type":"bytes32"}],"name":"confirmCustodianChange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"erc20Impl","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_proposedImpl","type":"address"}],"name":"requestImplChange","outputs":[{"name":"lockId","type":"bytes32"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"emitApproval","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseApproval","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_lockId","type":"bytes32"}],"name":"confirmImplChange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"implChangeReqs","outputs":[{"name":"proposedNew","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lockRequestCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"custodianChangeReqs","outputs":[{"name":"proposedNew","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseApproval","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_name","type":"string"},{"name":"_symbol","type":"string"},{"name":"_decimals","type":"uint8"},{"name":"_custodian","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_lockId","type":"bytes32"},{"indexed":false,"name":"_msgSender","type":"address"},{"indexed":false,"name":"_proposedImpl","type":"address"}],"name":"ImplChangeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_lockId","type":"bytes32"},{"indexed":false,"name":"_newImpl","type":"address"}],"name":"ImplChangeConfirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_lockId","type":"bytes32"},{"indexed":false,"name":"_msgSender","type":"address"},{"indexed":false,"name":"_proposedCustodian","type":"address"}],"name":"CustodianChangeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_lockId","type":"bytes32"},{"indexed":false,"name":"_newCustodian","type":"address"}],"name":"CustodianChangeConfirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}]

60806040523480156200001157600080fd5b50604051620011e7380380620011e7833981810160405260808110156200003757600080fd5b8101908080516401000000008111156200005057600080fd5b820160208101848111156200006457600080fd5b81516401000000008111828201871017156200007f57600080fd5b505092919060200180516401000000008111156200009c57600080fd5b82016020810184811115620000b057600080fd5b8151640100000000811182820187101715620000cb57600080fd5b505060208083015160409093015160008055600180546001600160a01b0383166001600160a01b03199182161790915560038054909116905586519295509293506200011d9160059187019062000152565b5082516200013390600690602086019062000152565b50506007805460ff191660ff9290921691909117905550620001f79050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200019557805160ff1916838001178555620001c5565b82800160010185558215620001c5579182015b82811115620001c5578251825591602001919060010190620001a8565b50620001d3929150620001d7565b5090565b620001f491905b80821115620001d35760008155600101620001de565b90565b610fe080620002076000396000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c80635687f2b8116100b8578063a9059cbb1161007c578063a9059cbb146103ec578063b508069b14610418578063cb81fecf14610435578063cf6e44881461043d578063d73dd6231461045a578063dd62ed3e1461048657610142565b80635687f2b81461033f578063661884631461037557806370a08231146103a15780638181b029146103c757806395d89b41146103e457610142565b806323de66511161010a57806323de66511461027a578063313ce567146102b2578063375b74c3146102d05780633a8343ee146102f45780633c389cc41461031157806348f9e2461461031957610142565b806306fdde0314610147578063095ea7b3146101c457806315b210821461020457806318160ddd1461023c57806323b872dd14610244575b600080fd5b61014f6104b4565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610189578181015183820152602001610171565b50505050905090810190601f1680156101b65780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101f0600480360360408110156101da57600080fd5b506001600160a01b038135169060200135610542565b604080519115158252519081900360200190f35b61022a6004803603602081101561021a57600080fd5b50356001600160a01b03166105d4565b60408051918252519081900360200190f35b61022a6106aa565b6101f06004803603606081101561025a57600080fd5b506001600160a01b03813581169160208101359091169060400135610720565b6102b06004803603606081101561029057600080fd5b506001600160a01b038135811691602081013590911690604001356107bb565b005b6102ba61085b565b6040805160ff9092168252519081900360200190f35b6102d8610864565b604080516001600160a01b039092168252519081900360200190f35b6102b06004803603602081101561030a57600080fd5b5035610873565b6102d8610940565b61022a6004803603602081101561032f57600080fd5b50356001600160a01b031661094f565b6102b06004803603606081101561035557600080fd5b506001600160a01b03813581169160208101359091169060400135610a25565b6101f06004803603604081101561038b57600080fd5b506001600160a01b038135169060200135610ac5565b61022a600480360360208110156103b757600080fd5b50356001600160a01b0316610b24565b6102b0600480360360208110156103dd57600080fd5b5035610ba7565b61014f610c74565b6101f06004803603604081101561040257600080fd5b506001600160a01b038135169060200135610ccf565b6102d86004803603602081101561042e57600080fd5b5035610d2e565b61022a610d49565b6102d86004803603602081101561045357600080fd5b5035610d4f565b6101f06004803603604081101561047057600080fd5b506001600160a01b038135169060200135610d6a565b61022a6004803603604081101561049c57600080fd5b506001600160a01b0381358116916020013516610dc9565b6005805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152929183018282801561053a5780601f1061050f5761010080835404028352916020019161053a565b820191906000526020600020905b81548152906001019060200180831161051d57829003601f168201915b505050505081565b6003546040805163448327e960e11b81523360048201526001600160a01b03858116602483015260448201859052915160009392909216916389064fd29160648082019260209290919082900301818787803b1580156105a157600080fd5b505af11580156105b5573d6000803e3d6000fd5b505050506040513d60208110156105cb57600080fd5b50519392505050565b60006001600160a01b03821661061b5760405162461bcd60e51b8152600401808060200182810382526026815260200180610f386026913960400191505060405180910390fd5b610623610e36565b60408051602080820183526001600160a01b038087168084526000868152600284528590209351845492166001600160a01b031990921691909117909255825184815233918101919091528083019190915290519192507fd76fc900a7e1a6fcf11d54b7ba943918df6c53a3128140658c389b3da1e997ba919081900360600190a1919050565b600354604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b1580156106ef57600080fd5b505afa158015610703573d6000803e3d6000fd5b505050506040513d602081101561071957600080fd5b5051905090565b60035460408051635d5e22cd60e01b81523360048201526001600160a01b03868116602483015285811660448301526064820185905291516000939290921691635d5e22cd9160848082019260209290919082900301818787803b15801561078757600080fd5b505af115801561079b573d6000803e3d6000fd5b505050506040513d60208110156107b157600080fd5b5051949350505050565b6003546001600160a01b0316331461080b576040805162461bcd60e51b815260206004820152600e60248201526d1bdb9b1e48115490cc8c125b5c1b60921b604482015290519081900360640190fd5b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b60075460ff1681565b6001546001600160a01b031681565b6001546001600160a01b031633146108c3576040805162461bcd60e51b815260206004820152600e60248201526d37b7363c9031bab9ba37b234b0b760911b604482015290519081900360640190fd5b6108cc81610e7f565b600180546001600160a01b039283166001600160a01b031991821617825560008481526002602090815260409182902080549093169092559154825185815293169083015280517f9a99272c0f6b7a30ef9e76e684a7cd408bfd4f11a72f36a8e276253c920e442d9281900390910190a150565b6003546001600160a01b031681565b60006001600160a01b0382166109965760405162461bcd60e51b8152600401808060200182810382526021815260200180610f5e6021913960400191505060405180910390fd5b61099e610e36565b60408051602080820183526001600160a01b038087168084526000868152600484528590209351845492166001600160a01b031990921691909117909255825184815233918101919091528083019190915290519192507f5df12834436b8dc248df3f7f1796a3e39f851d610be49cdcd92514fa821b9f97919081900360600190a1919050565b6003546001600160a01b03163314610a75576040805162461bcd60e51b815260206004820152600e60248201526d1bdb9b1e48115490cc8c125b5c1b60921b604482015290519081900360640190fd5b816001600160a01b0316836001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a3505050565b600354604080516361e1077d60e01b81523360048201526001600160a01b03858116602483015260448201859052915160009392909216916361e1077d9160648082019260209290919082900301818787803b1580156105a157600080fd5b600354604080516370a0823160e01b81526001600160a01b038481166004830152915160009392909216916370a0823191602480820192602092909190829003018186803b158015610b7557600080fd5b505afa158015610b89573d6000803e3d6000fd5b505050506040513d6020811015610b9f57600080fd5b505192915050565b6001546001600160a01b03163314610bf7576040805162461bcd60e51b815260206004820152600e60248201526d37b7363c9031bab9ba37b234b0b760911b604482015290519081900360640190fd5b610c0081610ee3565b600380546001600160a01b039283166001600160a01b031991821617825560008481526004602090815260409182902080549093169092559154825185815293169083015280517f9d55b0349a0a4c5b511f72228170bb91d45c9ac78dba8ab5b4175d3ed42f06b39281900390910190a150565b6006805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152929183018282801561053a5780601f1061050f5761010080835404028352916020019161053a565b60035460408051636ff0786560e11b81523360048201526001600160a01b038581166024830152604482018590529151600093929092169163dfe0f0ca9160648082019260209290919082900301818787803b1580156105a157600080fd5b6004602052600090815260409020546001600160a01b031681565b60005481565b6002602052600090815260409020546001600160a01b031681565b60035460408051632e0179b560e01b81523360048201526001600160a01b0385811660248301526044820185905291516000939290921691632e0179b59160648082019260209290919082900301818787803b1580156105a157600080fd5b60035460408051636eb1769f60e11b81526001600160a01b03858116600483015284811660248301529151600093929092169163dd62ed3e91604480820192602092909190829003018186803b158015610e2257600080fd5b505afa1580156105b5573d6000803e3d6000fd5b6000805460010190819055604080516000194301406020808301919091523060601b82840152605480830194909452825180830390940184526074909101909152815191012090565b600081815260026020526040812080546001600160a01b0316610ed35760405162461bcd60e51b815260040180806020018281038252602d815260200180610f7f602d913960400191505060405180910390fd5b546001600160a01b031692915050565b600081815260046020526040812080546001600160a01b0316610ed35760405162461bcd60e51b815260040180806020018281038252602d815260200180610f7f602d913960400191505060405180910390fdfe6e6f206e756c6c2076616c756520666f7220605f70726f706f736564437573746f6469616e606e6f206e756c6c2076616c756520666f7220605f70726f706f736564496d706c6072656a65637420e280986e756c6ce2809920726573756c74732066726f6d20746865206d6170206c6f6f6b7570a265627a7a72305820baabbacc8ceca23a4dae3f8ac5b64485590af765813d6aa70a3b3d801f959a4564736f6c634300050a0032000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000d95096d10dc3f7d9a6e583381a56ee69913e87a000000000000000000000000000000000000000000000000000000000000000652657661696e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035245560000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101425760003560e01c80635687f2b8116100b8578063a9059cbb1161007c578063a9059cbb146103ec578063b508069b14610418578063cb81fecf14610435578063cf6e44881461043d578063d73dd6231461045a578063dd62ed3e1461048657610142565b80635687f2b81461033f578063661884631461037557806370a08231146103a15780638181b029146103c757806395d89b41146103e457610142565b806323de66511161010a57806323de66511461027a578063313ce567146102b2578063375b74c3146102d05780633a8343ee146102f45780633c389cc41461031157806348f9e2461461031957610142565b806306fdde0314610147578063095ea7b3146101c457806315b210821461020457806318160ddd1461023c57806323b872dd14610244575b600080fd5b61014f6104b4565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610189578181015183820152602001610171565b50505050905090810190601f1680156101b65780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101f0600480360360408110156101da57600080fd5b506001600160a01b038135169060200135610542565b604080519115158252519081900360200190f35b61022a6004803603602081101561021a57600080fd5b50356001600160a01b03166105d4565b60408051918252519081900360200190f35b61022a6106aa565b6101f06004803603606081101561025a57600080fd5b506001600160a01b03813581169160208101359091169060400135610720565b6102b06004803603606081101561029057600080fd5b506001600160a01b038135811691602081013590911690604001356107bb565b005b6102ba61085b565b6040805160ff9092168252519081900360200190f35b6102d8610864565b604080516001600160a01b039092168252519081900360200190f35b6102b06004803603602081101561030a57600080fd5b5035610873565b6102d8610940565b61022a6004803603602081101561032f57600080fd5b50356001600160a01b031661094f565b6102b06004803603606081101561035557600080fd5b506001600160a01b03813581169160208101359091169060400135610a25565b6101f06004803603604081101561038b57600080fd5b506001600160a01b038135169060200135610ac5565b61022a600480360360208110156103b757600080fd5b50356001600160a01b0316610b24565b6102b0600480360360208110156103dd57600080fd5b5035610ba7565b61014f610c74565b6101f06004803603604081101561040257600080fd5b506001600160a01b038135169060200135610ccf565b6102d86004803603602081101561042e57600080fd5b5035610d2e565b61022a610d49565b6102d86004803603602081101561045357600080fd5b5035610d4f565b6101f06004803603604081101561047057600080fd5b506001600160a01b038135169060200135610d6a565b61022a6004803603604081101561049c57600080fd5b506001600160a01b0381358116916020013516610dc9565b6005805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152929183018282801561053a5780601f1061050f5761010080835404028352916020019161053a565b820191906000526020600020905b81548152906001019060200180831161051d57829003601f168201915b505050505081565b6003546040805163448327e960e11b81523360048201526001600160a01b03858116602483015260448201859052915160009392909216916389064fd29160648082019260209290919082900301818787803b1580156105a157600080fd5b505af11580156105b5573d6000803e3d6000fd5b505050506040513d60208110156105cb57600080fd5b50519392505050565b60006001600160a01b03821661061b5760405162461bcd60e51b8152600401808060200182810382526026815260200180610f386026913960400191505060405180910390fd5b610623610e36565b60408051602080820183526001600160a01b038087168084526000868152600284528590209351845492166001600160a01b031990921691909117909255825184815233918101919091528083019190915290519192507fd76fc900a7e1a6fcf11d54b7ba943918df6c53a3128140658c389b3da1e997ba919081900360600190a1919050565b600354604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b1580156106ef57600080fd5b505afa158015610703573d6000803e3d6000fd5b505050506040513d602081101561071957600080fd5b5051905090565b60035460408051635d5e22cd60e01b81523360048201526001600160a01b03868116602483015285811660448301526064820185905291516000939290921691635d5e22cd9160848082019260209290919082900301818787803b15801561078757600080fd5b505af115801561079b573d6000803e3d6000fd5b505050506040513d60208110156107b157600080fd5b5051949350505050565b6003546001600160a01b0316331461080b576040805162461bcd60e51b815260206004820152600e60248201526d1bdb9b1e48115490cc8c125b5c1b60921b604482015290519081900360640190fd5b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b60075460ff1681565b6001546001600160a01b031681565b6001546001600160a01b031633146108c3576040805162461bcd60e51b815260206004820152600e60248201526d37b7363c9031bab9ba37b234b0b760911b604482015290519081900360640190fd5b6108cc81610e7f565b600180546001600160a01b039283166001600160a01b031991821617825560008481526002602090815260409182902080549093169092559154825185815293169083015280517f9a99272c0f6b7a30ef9e76e684a7cd408bfd4f11a72f36a8e276253c920e442d9281900390910190a150565b6003546001600160a01b031681565b60006001600160a01b0382166109965760405162461bcd60e51b8152600401808060200182810382526021815260200180610f5e6021913960400191505060405180910390fd5b61099e610e36565b60408051602080820183526001600160a01b038087168084526000868152600484528590209351845492166001600160a01b031990921691909117909255825184815233918101919091528083019190915290519192507f5df12834436b8dc248df3f7f1796a3e39f851d610be49cdcd92514fa821b9f97919081900360600190a1919050565b6003546001600160a01b03163314610a75576040805162461bcd60e51b815260206004820152600e60248201526d1bdb9b1e48115490cc8c125b5c1b60921b604482015290519081900360640190fd5b816001600160a01b0316836001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a3505050565b600354604080516361e1077d60e01b81523360048201526001600160a01b03858116602483015260448201859052915160009392909216916361e1077d9160648082019260209290919082900301818787803b1580156105a157600080fd5b600354604080516370a0823160e01b81526001600160a01b038481166004830152915160009392909216916370a0823191602480820192602092909190829003018186803b158015610b7557600080fd5b505afa158015610b89573d6000803e3d6000fd5b505050506040513d6020811015610b9f57600080fd5b505192915050565b6001546001600160a01b03163314610bf7576040805162461bcd60e51b815260206004820152600e60248201526d37b7363c9031bab9ba37b234b0b760911b604482015290519081900360640190fd5b610c0081610ee3565b600380546001600160a01b039283166001600160a01b031991821617825560008481526004602090815260409182902080549093169092559154825185815293169083015280517f9d55b0349a0a4c5b511f72228170bb91d45c9ac78dba8ab5b4175d3ed42f06b39281900390910190a150565b6006805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152929183018282801561053a5780601f1061050f5761010080835404028352916020019161053a565b60035460408051636ff0786560e11b81523360048201526001600160a01b038581166024830152604482018590529151600093929092169163dfe0f0ca9160648082019260209290919082900301818787803b1580156105a157600080fd5b6004602052600090815260409020546001600160a01b031681565b60005481565b6002602052600090815260409020546001600160a01b031681565b60035460408051632e0179b560e01b81523360048201526001600160a01b0385811660248301526044820185905291516000939290921691632e0179b59160648082019260209290919082900301818787803b1580156105a157600080fd5b60035460408051636eb1769f60e11b81526001600160a01b03858116600483015284811660248301529151600093929092169163dd62ed3e91604480820192602092909190829003018186803b158015610e2257600080fd5b505afa1580156105b5573d6000803e3d6000fd5b6000805460010190819055604080516000194301406020808301919091523060601b82840152605480830194909452825180830390940184526074909101909152815191012090565b600081815260026020526040812080546001600160a01b0316610ed35760405162461bcd60e51b815260040180806020018281038252602d815260200180610f7f602d913960400191505060405180910390fd5b546001600160a01b031692915050565b600081815260046020526040812080546001600160a01b0316610ed35760405162461bcd60e51b815260040180806020018281038252602d815260200180610f7f602d913960400191505060405180910390fdfe6e6f206e756c6c2076616c756520666f7220605f70726f706f736564437573746f6469616e606e6f206e756c6c2076616c756520666f7220605f70726f706f736564496d706c6072656a65637420e280986e756c6ce2809920726573756c74732066726f6d20746865206d6170206c6f6f6b7570a265627a7a72305820baabbacc8ceca23a4dae3f8ac5b64485590af765813d6aa70a3b3d801f959a4564736f6c634300050a0032

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000d95096d10dc3f7d9a6e583381a56ee69913e87a000000000000000000000000000000000000000000000000000000000000000652657661696e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035245560000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _name (string): Revain
Arg [1] : _symbol (string): REV
Arg [2] : _decimals (uint8): 6
Arg [3] : _custodian (address): 0x0D95096d10DC3f7d9a6e583381A56EE69913e87a

-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [3] : 0000000000000000000000000d95096d10dc3f7d9a6e583381a56ee69913e87a
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [5] : 52657661696e0000000000000000000000000000000000000000000000000000
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [7] : 5245560000000000000000000000000000000000000000000000000000000000


Deployed Bytecode Sourcemap

24708:4623:1:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;24708:4623:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;24838:18;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;24838:18:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;27600:162;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;27600:162:1;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;18563:428;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;18563:428:1;-1:-1:-1;;;;;18563:428:1;;:::i;:::-;;;;;;;;;;;;;;;;25488:100;;;:::i;26888:184::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;26888:184:1;;;;;;;;;;;;;;;;;:::i;25952:132::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;25952:132:1;;;;;;;;;;;;;;;;;:::i;:::-;;25004:21;;;:::i;:::-;;;;;;;;;;;;;;;;;;;17659:24;;;:::i;:::-;;;;-1:-1:-1;;;;;17659:24:1;;;;;;;;;;;;;;19383:235;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;19383:235:1;;:::i;21372:26::-;;;:::i;22292:383::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;22292:383:1;-1:-1:-1;;;;;22292:383:1;;:::i;27119:144::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;27119:144:1;;;;;;;;;;;;;;;;;:::i;28791:200::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;28791:200:1;;;;;;;;:::i;25781:124::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;25781:124:1;-1:-1:-1;;;;;25781:124:1;;:::i;23071:224::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;23071:224:1;;:::i;24913:20::-;;;:::i;26374:154::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;26374:154:1;;;;;;;;:::i;21474:60::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;21474:60:1;;:::i;562:31::-;;;:::i;17754:70::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;17754:70:1;;:::i;28185:190::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;28185:190:1;;;;;;;;:::i;29175:154::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;;;;;;29175:154:1;;;;;;;;;;:::i;24838:18::-;;;;;;;;;;;;;;;-1:-1:-1;;24838:18:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;27600:162::-;27698:9;;:57;;;-1:-1:-1;;;27698:57:1;;27726:10;27698:57;;;;-1:-1:-1;;;;;27698:57:1;;;;;;;;;;;;;;;27667:12;;27698:9;;;;;:27;;:57;;;;;;;;;;;;;;;27667:12;27698:9;:57;;;5:2:-1;;;;30:1;27;20:12;5:2;27698:57:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;27698:57:1;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;27698:57:1;;27600:162;-1:-1:-1;;;27600:162:1:o;18563:428::-;18639:14;-1:-1:-1;;;;;18673:32:1;;18665:83;;;;-1:-1:-1;;;18665:83:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;18768:16;:14;:16::i;:::-;18825:79;;;;;;;;;-1:-1:-1;;;;;18825:79:1;;;;;;-1:-1:-1;18795:27:1;;;:19;:27;;;;;:109;;;;;;-1:-1:-1;;;;;;18795:109:1;;;;;;;;;;18920:64;;;;;18953:10;18920:64;;;;;;;;;;;;;;;;18759:25;;-1:-1:-1;18920:64:1;;;;;;;;;;18563:428;;;:::o;25488:100::-;25558:9;;:23;;;-1:-1:-1;;;25558:23:1;;;;25532:7;;-1:-1:-1;;;;;25558:9:1;;:21;;:23;;;;;;;;;;;;;;:9;:23;;;5:2:-1;;;;30:1;27;20:12;5:2;25558:23:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;25558:23:1;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;25558:23:1;;-1:-1:-1;25488:100:1;:::o;26888:184::-;27001:9;;:64;;;-1:-1:-1;;;27001:64:1;;27034:10;27001:64;;;;-1:-1:-1;;;;;27001:64:1;;;;;;;;;;;;;;;;;;;;;;26970:12;;27001:9;;;;;:32;;:64;;;;;;;;;;;;;;;26970:12;27001:9;:64;;;5:2:-1;;;;30:1;27;20:12;5:2;27001:64:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;27001:64:1;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;27001:64:1;;26888:184;-1:-1:-1;;;;26888:184:1:o;25952:132::-;21756:9;;-1:-1:-1;;;;;21756:9:1;21734:10;:32;21726:59;;;;;-1:-1:-1;;;21726:59:1;;;;;;;;;;;;-1:-1:-1;;;21726:59:1;;;;;;;;;;;;;;;26065:3;-1:-1:-1;;;;;26049:28:1;26058:5;-1:-1:-1;;;;;26049:28:1;;26070:6;26049:28;;;;;;;;;;;;;;;;;;25952:132;;;:::o;25004:21::-;;;;;;:::o;17659:24::-;;;-1:-1:-1;;;;;17659:24:1;;:::o;19383:235::-;18054:9;;-1:-1:-1;;;;;18054:9:1;18040:10;:23;18032:50;;;;;-1:-1:-1;;;18032:50:1;;;;;;;;;;;;-1:-1:-1;;;18032:50:1;;;;;;;;;;;;;;;19475:30;19497:7;19475:21;:30::i;:::-;19463:9;:42;;-1:-1:-1;;;;;19463:42:1;;;-1:-1:-1;;;;;;19463:42:1;;;;;;:9;19523:28;;;:19;:28;;;;;;;;;19516:35;;;;;;;;19601:9;;19567:44;;;;;19601:9;;19567:44;;;;;;;;;;;;;;;;19383:235;:::o;21372:26::-;;;-1:-1:-1;;;;;21372:26:1;;:::o;22292:383::-;22358:14;-1:-1:-1;;;;;22392:27:1;;22384:73;;;;-1:-1:-1;;;22384:73:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;22477:16;:14;:16::i;:::-;22529:69;;;;;;;;;-1:-1:-1;;;;;22529:69:1;;;;;;-1:-1:-1;22504:22:1;;;:14;:22;;;;;:94;;;;;;-1:-1:-1;;;;;;22504:94:1;;;;;;;;;;22614:54;;;;;22642:10;22614:54;;;;;;;;;;;;;;;;22468:25;;-1:-1:-1;22614:54:1;;;;;;;;;;22292:383;;;:::o;27119:144::-;21756:9;;-1:-1:-1;;;;;21756:9:1;21734:10;:32;21726:59;;;;;-1:-1:-1;;;21726:59:1;;;;;;;;;;;;-1:-1:-1;;;21726:59:1;;;;;;;;;;;;;;;27239:8;-1:-1:-1;;;;;27222:34:1;27231:6;-1:-1:-1;;;;;27222:34:1;;27249:6;27222:34;;;;;;;;;;;;;;;;;;27119:144;;;:::o;28791:200::-;28908:9;;:76;;;-1:-1:-1;;;28908:76:1;;28945:10;28908:76;;;;-1:-1:-1;;;;;28908:76:1;;;;;;;;;;;;;;;28877:12;;28908:9;;;;;:36;;:76;;;;;;;;;;;;;;;28877:12;28908:9;:76;;;5:2:-1;;;;30:1;27;20:12;25781:124:1;25871:9;;:27;;;-1:-1:-1;;;25871:27:1;;-1:-1:-1;;;;;25871:27:1;;;;;;;;;25837:15;;25871:9;;;;;:19;;:27;;;;;;;;;;;;;;;:9;:27;;;5:2:-1;;;;30:1;27;20:12;5:2;25871:27:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;25871:27:1;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;25871:27:1;;25781:124;-1:-1:-1;;25781:124:1:o;23071:224::-;18054:9;;-1:-1:-1;;;;;18054:9:1;18040:10;:23;18032:50;;;;;-1:-1:-1;;;18032:50:1;;;;;;;;;;;;-1:-1:-1;;;18032:50:1;;;;;;;;;;;;;;;23158:25;23175:7;23158:16;:25::i;:::-;23146:9;:37;;-1:-1:-1;;;;;23146:37:1;;;-1:-1:-1;;;;;;23146:37:1;;;;;;:9;23201:23;;;:14;:23;;;;;;;;;23194:30;;;;;;;;23277:9;;23240:48;;;;;23277:9;;23240:48;;;;;;;;;;;;;;;;23071:224;:::o;24913:20::-;;;;;;;;;;;;;;;-1:-1:-1;;24913:20:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;26374:154;26468:9;;:53;;;-1:-1:-1;;;26468:53:1;;26497:10;26468:53;;;;-1:-1:-1;;;;;26468:53:1;;;;;;;;;;;;;;;26437:12;;26468:9;;;;;:28;;:53;;;;;;;;;;;;;;;26437:12;26468:9;:53;;;5:2:-1;;;;30:1;27;20:12;21474:60:1;;;;;;;;;;;;-1:-1:-1;;;;;21474:60:1;;:::o;562:31::-;;;;:::o;17754:70::-;;;;;;;;;;;;-1:-1:-1;;;;;17754:70:1;;:::o;28185:190::-;28297:9;;:71;;;-1:-1:-1;;;28297:71:1;;28334:10;28297:71;;;;-1:-1:-1;;;;;28297:71:1;;;;;;;;;;;;;;;28266:12;;28297:9;;;;;:36;;:71;;;;;;;;;;;;;;;28266:12;28297:9;:71;;;5:2:-1;;;;30:1;27;20:12;29175:154:1;29285:9;;:37;;;-1:-1:-1;;;29285:37:1;;-1:-1:-1;;;;;29285:37:1;;;;;;;;;;;;;;;;29249:17;;29285:9;;;;;:19;;:37;;;;;;;;;;;;;;;:9;:37;;;5:2:-1;;;;30:1;27;20:12;5:2;29285:37:1;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;1170:175:1;1214:14;1318:18;;1299:1;1318:18;;;;;1257:80;;;-1:-1:-1;;1284:12:1;:16;1274:27;1257:80;;;;;;;;1311:4;1257:80;;;;;;;;;;;;;;;;26:21:-1;;;22:32;;;6:49;;1257:80:1;;;;;;;1247:91;;;;;1170:175;:::o;19649:465::-;19719:20;19798:28;;;:19;:28;;;;;19975:25;;-1:-1:-1;;;;;19975:25:1;19967:97;;;;-1:-1:-1;;;19967:97:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;20082:25;-1:-1:-1;;;;;20082:25:1;;19649:465;-1:-1:-1;;19649:465:1:o;23326:463::-;23391:22;23467:23;;;:14;:23;;;;;23639:25;;-1:-1:-1;;;;;23639:25:1;23631:97;;;;-1:-1:-1;;;23631:97:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Swarm Source

bzzr://baabbacc8ceca23a4dae3f8ac5b64485590af765813d6aa70a3b3d801f959a45

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

OVERVIEW

Revain is a blockchain-based review platform for the crypto community. Revain's ultimate goal is to provide high-quality reviews on all global products and services using emerging technologies like blockchain and AI.

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.