ETH Price: $3,135.39 (-4.25%)

Contract

0xE5D3d7da4b24bc9D2FDA0e206680CD8A00C0FeBD
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Withdraw Asset211875572024-11-14 17:55:1124 mins ago1731606911IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0039647934.36206366
Withdraw Asset211875542024-11-14 17:54:3525 mins ago1731606875IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0049024837.00463065
Withdraw Asset211812722024-11-13 20:50:4721 hrs ago1731531047IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0076805663.65196727
Withdraw Asset211773522024-11-13 7:43:2334 hrs ago1731483803IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0026041822.06378713
Withdraw Asset211751022024-11-13 0:11:2342 hrs ago1731456683IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0031563423.36200449
Liquidate Asset211740012024-11-12 20:30:2345 hrs ago1731443423IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0028717530.5919201
Withdraw Asset211733492024-11-12 18:19:352 days ago1731435575IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0031228626.45821968
Withdraw Asset211732372024-11-12 17:56:472 days ago1731434207IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0035172429.1488446
Withdraw Asset211680362024-11-12 0:30:352 days ago1731371435IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0043343235.15610959
Withdraw Asset211680172024-11-12 0:26:472 days ago1731371207IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0046537237.74680582
Withdraw Asset211680122024-11-12 0:25:472 days ago1731371147IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0051867536.94902267
Make Payment211673072024-11-11 22:04:232 days ago1731362663IN
0xE5D3d7da...A00C0FeBD
0 ETH0.006411549.28817012
Liquidate Asset211594612024-11-10 19:48:113 days ago1731268091IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0030699132.7028081
Liquidate Asset211518312024-11-09 18:16:475 days ago1731176207IN
0xE5D3d7da...A00C0FeBD
0 ETH0.000856697.7198264
Liquidate Asset211440112024-11-08 16:06:596 days ago1731082019IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0024737726.35240089
Liquidate Asset211440112024-11-08 16:06:596 days ago1731082019IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0024740926.35240089
Liquidate Asset211440102024-11-08 16:06:476 days ago1731082007IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0024640726.25573556
Liquidate Asset211440102024-11-08 16:06:476 days ago1731082007IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0024650126.25573556
Liquidate Asset211440102024-11-08 16:06:476 days ago1731082007IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0024650126.25573556
Liquidate Asset211440092024-11-08 16:06:356 days ago1731081995IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0025291626.93892826
Liquidate Asset211440082024-11-08 16:06:236 days ago1731081983IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0024543326.1452394
Liquidate Asset211440082024-11-08 16:06:236 days ago1731081983IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0024543326.1452394
Liquidate Asset211440082024-11-08 16:06:236 days ago1731081983IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0024543326.1452394
Liquidate Asset211440082024-11-08 16:06:236 days ago1731081983IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0024546426.1452394
Liquidate Asset211440072024-11-08 16:06:116 days ago1731081971IN
0xE5D3d7da...A00C0FeBD
0 ETH0.0024438226.03335
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
RainCollateralController

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion
File 1 of 7 : RainCollateralController.sol
// SPDX-License-Identifier: Unlicense
pragma solidity 0.8.17;

import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "./interfaces/IRainCollateral.sol";

/**
 *  @title RainCollateralController contract
 *  @notice Used to manage RainCollateral contracts.
 *          Most operational logics are implemented here
 *          while RainCollateral is mainly used to keep collateral.
 *          This contract will be owned by Rain company.
 */
contract RainCollateralController is Ownable {
    /// @notice Elliptic Curve Digital Signature Algorithm Used to validate signature
    using ECDSA for bytes32;

    // Struct of required fields for EIP-712 domain separator
    struct EIP712Domain {
        string name;
        string version;
        uint256 chainId;
        address verifyingContract;
        bytes32 salt;
    }

    // Struct of required fields for Pay signature
    struct Pay {
        address user;
        address collateral;
        address[] assets;
        uint256[] amounts;
        uint256 nonce;
        uint256 expiresAt;
    }

    // Struct of required fields for Withdraw signature
    struct Withdraw {
        address user;
        address collateral;
        address asset;
        uint256 amount;
        address recipient;
        uint256 nonce;
        uint256 expiresAt;
    }

    // User readable name of signing domain
    string public constant EIP712_DOMAIN_NAME = "Rain Collateral";

    // Current major version of signing domain
    string public constant EIP712_DOMAIN_VERSION = "1";

    // Type hash to check EIP712 domain separator validity in signature
    bytes32 public constant EIP712_DOMAIN_TYPE_HASH =
        keccak256(
            "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)"
        );

    // Type hash to check pay signature validity
    bytes32 public constant PAY_TYPE_HASH =
        keccak256(
            "Pay(address user,address collateral,address[] assets,uint[] amounts,uint nonce,uint expiresAt)"
        );

    // Type hash to check withdraw signature validity
    bytes32 public constant WITHDRAW_TYPE_HASH =
        keccak256(
            "Withdraw(address user,address collateral,address asset,uint amount,address recipient,uint nonce,uint expiresAt)"
        );

    /// @notice Address that runs admin functions.
    ///         Signature should be created by this address.
    address public controllerAdmin;

    /// @notice Treasury contract address where Rain Company keeps its treasury.
    ///         Payment and liqudation moves assets to treasury.
    address public treasury;

    /// @notice A counter to prevent duplicate transaction with same signature
    /// @dev using single nonce for all type of transactions
    ///      to ensure their order.
    /// key: address of RainCollateral
    /// value: counter of past transactions
    mapping(address => uint256) public nonce;

    /**
     * @notice Emitted when withdrawAsset is called
     * @param _collateralProxy RainCollateral proxy contract address
     * @param _asset Asset contract address
     * @param _amount Amount of assets withdrawn
     */
    event Withdrawal(
        address indexed _collateralProxy,
        address _asset,
        uint256 _amount
    );

    /**
     * @notice Emitted when makePayment is called
     * @param _collateralProxy RainCollateral proxy contract address
     * @param _assets Array of asset contract addresses paid from.
     *                Must be the same length with _amounts.
     * @param _amounts Array of amount of assets paid.
     *                 Must be the same length with _assets.
     */
    event Payment(
        address indexed _collateralProxy,
        address[] _assets,
        uint256[] _amounts
    );

    /**
     * @notice Emitted when liquidateAsset is called
     * @param _collateralProxy RainCollateral proxy contract address
     * @param _assets Array of asset contract addresses liquidated from.
     *                Must be the same length with _amounts.
     * @param _amounts Array of amount of assets liquidated.
     *                 Must be the same length with _assets.
     */
    event Liquidation(
        address indexed _collateralProxy,
        address[] _assets,
        uint256[] _amounts
    );

    /**
     * @notice Used to authorize only RainCollateral admin
     * @dev Throws if called by any account other than RainCollateral admin.
     */
    modifier isCollateralAdmin(address _collateralProxy) {
        require(
            IRainCollateral(_collateralProxy).isAdmin(address(msg.sender)),
            "Unauthorized"
        );
        _;
    }

    /**
     * @notice Check if the signature is expired
     * @param _expiresAt timestamp when the signature expires
     */
    modifier activeSignature(uint256 _expiresAt) {
        // _expiresAt will be within 30 minutes to an hour since the signature was issued.
        require(block.timestamp < _expiresAt, "Expired signature");
        _;
    }

    /**
     * @notice Used to initialize
     * @dev Called only once and sets admin and treasury addresses
     * @param _controllerAdmin controller admin address to operate collateralProxies
     * @param _treasury Rain Company's treasury contract address
     */
    constructor(address _controllerAdmin, address _treasury) {
        controllerAdmin = _controllerAdmin;
        treasury = _treasury;
    }

    /**
     * @notice Used to withdraw assets owned by RainCollateral contract
     * @dev Checks {isCollateralAdmin} first
     * @param _collateralProxy targeting RainCollateral proxy address
     * @param _asset asset's contract address
     * @param _amount amount to withdraw
     * @param _recipient address to receive assets
     * @param _expiresAt timestamp when signature expires, in unix seconds
     * @param _salt disambiguating salt for signature
     * @param _signature controllerAdmin's signature for this action (generated by ECDSA)
     * NOTE: `_asset` can be only ERC20 token. ETHER is not supported in V1.
     *       see {ERC20-allowance} and {ERC20-transferFrom}
     *       see {_verifyWithdrawalSignature} function
     * Requirements:
     * - `_expiresAt` should be less than block timestamp.
     * - `_signature` should be valid.
     * - RainCollateral must have balance of asset >= `_amount`.
     */
    function withdrawAsset(
        address _collateralProxy,
        address _asset,
        uint256 _amount,
        address _recipient,
        uint256 _expiresAt,
        bytes32 _salt,
        bytes memory _signature
    ) external isCollateralAdmin(_collateralProxy) activeSignature(_expiresAt) {
        bytes32 messageHash = _hash(
            Withdraw({
                user: msg.sender,
                collateral: _collateralProxy,
                asset: _asset,
                amount: _amount,
                recipient: _recipient,
                nonce: nonce[_collateralProxy],
                expiresAt: _expiresAt
            })
        );
        _verifySignature(_collateralProxy, messageHash, _salt, _signature);

        IRainCollateral(_collateralProxy).withdrawAsset(
            _asset,
            _recipient,
            _amount
        );

        emit Withdrawal(_collateralProxy, _asset, _amount);
    }

    /**
     * @notice Used to make payment with  collateral assets owned by RainCollateral contract
     * @dev Use {_verifyPaymentSignature} to verify signature
     * @param _collateralProxy targeting RainCollateral proxy address
     * @param _assets array of asset's contract addresses
     * @param _amounts array of amounts corresponding to _assets
     * @param _expiresAt timestamp when signature expires as unix seconds
     * @param _salt disambiguating salt for signature
     * @param _signature controllerAdmin's signature for this action (generated by ECDSA)
     * Requirements:
     *
     * - `_expiresAt` should be less than block timestamp.
     * - `_signature` should be valid .
     */
    function makePayment(
        address _collateralProxy,
        address[] calldata _assets,
        uint256[] calldata _amounts,
        uint256 _expiresAt,
        bytes32 _salt,
        bytes memory _signature
    ) external activeSignature(_expiresAt) {
        require(_assets.length == _amounts.length, "Invalid Params");

        bytes32 messageHash = _hash(
            Pay({
                user: msg.sender,
                collateral: _collateralProxy,
                assets: _assets,
                amounts: _amounts,
                nonce: nonce[_collateralProxy],
                expiresAt: _expiresAt
            })
        );
        _verifySignature(_collateralProxy, messageHash, _salt, _signature);

        for (uint256 i = 0; i < _assets.length; i++) {
            _transferToTreasury(_collateralProxy, _assets[i], _amounts[i]);
        }

        emit Payment(_collateralProxy, _assets, _amounts);
    }

    /**
     * @notice Used to transfer an amount of asset from RainCollateral contract to treasury contract
     * @param _collateralProxy targeting RainCollateral proxy address
     * @param _asset asset's contract address
     * @param _amount asset amount to transfer
     */

    function _transferToTreasury(
        address _collateralProxy,
        address _asset,
        uint256 _amount
    ) internal {
        IRainCollateral(_collateralProxy).withdrawAsset(
            _asset,
            treasury,
            _amount
        );
    }

    /**
     * @notice Sub function of _verifyPaymentSignature and _verifyWithdrawal
     *         used to verify signature is from controller admin
     * @dev increment nonce when signature is valid
     * @param _collateralProxy targeting RainCollateral proxy address
     * @param _messageHash keccak256 hashed message
     * @param _salt disambiguating salt for signature
     * @param _signature signature generated by controllerAdmin
     */
    function _verifySignature(
        address _collateralProxy,
        bytes32 _messageHash,
        bytes32 _salt,
        bytes memory _signature
    ) internal {
        bytes32 domainSeparator = _hash(
            EIP712Domain({
                name: EIP712_DOMAIN_NAME,
                version: EIP712_DOMAIN_VERSION,
                chainId: block.chainid,
                verifyingContract: address(this),
                salt: _salt
            })
        );

        bytes32 digest = keccak256(
            abi.encodePacked("\x19\x01", domainSeparator, _messageHash)
        );

        // verify that the signature was generated by controllerAdmin
        require(
            digest.recover(_signature) == controllerAdmin,
            "Invalid signature"
        );

        // update nonce
        nonce[_collateralProxy] += 1;
    }

    /**
     * @notice Build hash of EIP712 domain separator
     * @return bytes32 hash value
     */
    function _hash(EIP712Domain memory eip712Domain)
        internal
        pure
        returns (bytes32)
    {
        return
            keccak256(
                abi.encode(
                    EIP712_DOMAIN_TYPE_HASH,
                    keccak256(bytes(eip712Domain.name)),
                    keccak256(bytes(eip712Domain.version)),
                    eip712Domain.chainId,
                    eip712Domain.verifyingContract,
                    eip712Domain.salt
                )
            );
    }

    /**
     * @notice Build hash of withdraw signature fields
     * @return bytes32 hash value
     */
    function _hash(Withdraw memory withdraw) internal pure returns (bytes32) {
        return
            keccak256(
                bytes.concat(
                    abi.encode(
                        WITHDRAW_TYPE_HASH,
                        withdraw.user,
                        withdraw.collateral,
                        withdraw.asset,
                        withdraw.amount
                    ),
                    abi.encode(
                        withdraw.recipient,
                        withdraw.nonce,
                        withdraw.expiresAt
                    )
                )
            );
    }

    /**
     * @notice Build hash of pay signature fields
     * @return bytes32 hash value
     */
    function _hash(Pay memory pay) internal pure returns (bytes32) {
        return
            keccak256(
                bytes.concat(
                    abi.encode(
                        PAY_TYPE_HASH,
                        pay.user,
                        pay.collateral,
                        keccak256(abi.encodePacked(pay.assets)),
                        keccak256(abi.encodePacked(pay.amounts))
                    ),
                    abi.encode(pay.nonce, pay.expiresAt)
                )
            );
    }

    /**
     * @notice Used to liquidate assets owned by RainCollateral contract
     * @dev loop to the assets and transfer them to treasury
     * Requirements:
     * - only controllerAdmin can call this function.
     * @param _collateralProxy targeting RainCollateral contract address
     * @param _assets array of asset's contract addresses
     * @param _amounts array of amounts corresponding to _assets
     */
    function liquidateAsset(
        address _collateralProxy,
        address[] calldata _assets,
        uint256[] calldata _amounts
    ) external {
        require(msg.sender == controllerAdmin, "Not controller admin");
        require(_assets.length == _amounts.length, "Invalid Params");
        for (uint256 i = 0; i < _assets.length; i++) {
            _transferToTreasury(_collateralProxy, _assets[i], _amounts[i]);
        }

        emit Liquidation(_collateralProxy, _assets, _amounts);
    }

    /**
     * @notice Used to update controller admin address
     * @dev only owner can call this function
     * @param _controllerAdmin new controller admin address
     * Requirements:
     * - `_controllerAdmin` should not be NullAddress.
     */
    function updateControllerAdmin(address _controllerAdmin)
        external
        onlyOwner
    {
        require(_controllerAdmin != address(0), "Zero Address");
        controllerAdmin = _controllerAdmin;
    }

    /**
     * @notice Used to update treasury contract address
     * @dev only owner can call this function
     * @param _treasury new treasury contract address
     * Requirements:
     * - `_newAddress` should not be NullAddress.
     */
    function updateTreasury(address _treasury) external onlyOwner {
        require(_treasury != address(0), "Zero Address");
        treasury = _treasury;
    }

    /**
     * @notice Increase nonce of a collateral proxy by onwer
     * @dev can be used to invalidate a signature
     */
    function increaseNonce(address _collateralProxy) external onlyOwner {
        nonce[_collateralProxy]++;
    }
}

File 2 of 7 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../Strings.sol";

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV // Deprecated in v4.8
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
    }
}

File 3 of 7 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 4 of 7 : IRainCollateral.sol
//SPDX-License-Identifier: Unlicense
pragma solidity 0.8.17;

interface IRainCollateral {
    function isAdmin(address) external view returns (bool);

    function withdrawAsset(
        address,
        address,
        uint256
    ) external;
}

File 5 of 7 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}

File 6 of 7 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator,
        Rounding rounding
    ) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10**64) {
                value /= 10**64;
                result += 64;
            }
            if (value >= 10**32) {
                value /= 10**32;
                result += 32;
            }
            if (value >= 10**16) {
                value /= 10**16;
                result += 16;
            }
            if (value >= 10**8) {
                value /= 10**8;
                result += 8;
            }
            if (value >= 10**4) {
                value /= 10**4;
                result += 4;
            }
            if (value >= 10**2) {
                value /= 10**2;
                result += 2;
            }
            if (value >= 10**1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
        }
    }
}

File 7 of 7 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

Settings
{
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_controllerAdmin","type":"address"},{"internalType":"address","name":"_treasury","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_collateralProxy","type":"address"},{"indexed":false,"internalType":"address[]","name":"_assets","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"Liquidation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_collateralProxy","type":"address"},{"indexed":false,"internalType":"address[]","name":"_assets","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"Payment","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_collateralProxy","type":"address"},{"indexed":false,"internalType":"address","name":"_asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Withdrawal","type":"event"},{"inputs":[],"name":"EIP712_DOMAIN_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_DOMAIN_TYPE_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_DOMAIN_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAY_TYPE_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WITHDRAW_TYPE_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"controllerAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_collateralProxy","type":"address"}],"name":"increaseNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_collateralProxy","type":"address"},{"internalType":"address[]","name":"_assets","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"liquidateAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_collateralProxy","type":"address"},{"internalType":"address[]","name":"_assets","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"uint256","name":"_expiresAt","type":"uint256"},{"internalType":"bytes32","name":"_salt","type":"bytes32"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"makePayment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_controllerAdmin","type":"address"}],"name":"updateControllerAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"}],"name":"updateTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_collateralProxy","type":"address"},{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_expiresAt","type":"uint256"},{"internalType":"bytes32","name":"_salt","type":"bytes32"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"withdrawAsset","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60806040523480156200001157600080fd5b5060405162002c1c38038062002c1c833981810160405281019062000037919062000217565b620000576200004b620000e160201b60201c565b620000e960201b60201c565b81600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050506200025e565b600033905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620001df82620001b2565b9050919050565b620001f181620001d2565b8114620001fd57600080fd5b50565b6000815190506200021181620001e6565b92915050565b60008060408385031215620002315762000230620001ad565b5b6000620002418582860162000200565b9250506020620002548582860162000200565b9150509250929050565b6129ae806200026e6000396000f3fe608060405234801561001057600080fd5b506004361061010b5760003560e01c80637f51bb1f116100a2578063b0dc1df711610071578063b0dc1df71461026e578063b727b5791461028a578063e167d26a146102a8578063f2fde38b146102c4578063fd070296146102e05761010b565b80637f51bb1f146101fc5780638247a97c146102185780638605352e146102345780638da5cb5b146102505761010b565b80635cc33321116100de5780635cc333211461018657806361d027b3146101a457806370ae92d2146101c2578063715018a6146101f25761010b565b806305c6eb6e14610110578063213bc2181461012e57806324c244eb1461014c5780632523551114610168575b600080fd5b6101186102fe565b6040516101259190611676565b60405180910390f35b610136610322565b6040516101439190611676565b60405180910390f35b610166600480360381019061016191906117be565b610346565b005b6101706104e6565b60405161017d9190611862565b60405180910390f35b61018e61050c565b60405161019b919061190d565b60405180910390f35b6101ac610545565b6040516101b99190611862565b60405180910390f35b6101dc60048036038101906101d7919061192f565b61056b565b6040516101e99190611975565b60405180910390f35b6101fa610583565b005b6102166004803603810190610211919061192f565b610597565b005b610232600480360381019061022d919061192f565b610652565b005b61024e6004803603810190610249919061192f565b6106b2565b005b61025861076d565b6040516102659190611862565b60405180910390f35b61028860048036038101906102839190611b18565b610796565b005b610292610a20565b60405161029f9190611676565b60405180910390f35b6102c260048036038101906102bd9190611c03565b610a44565b005b6102de60048036038101906102d9919061192f565b610cee565b005b6102e8610d71565b6040516102f5919061190d565b60405180910390f35b7f648852f8933e9e64f56213b02c92318987996d695f62f77ede2b6947f9c1fbb881565b7fa4e7339277875d8215224c9e0402e9330d4da2927790347e75150d777dbc3c3781565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146103d6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103cd90611d0d565b60405180910390fd5b81819050848490501461041e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161041590611d79565b60405180910390fd5b60005b8484905081101561048a576104778686868481811061044357610442611d99565b5b9050602002016020810190610458919061192f565b85858581811061046b5761046a611d99565b5b90506020020135610daa565b808061048290611df7565b915050610421565b508473ffffffffffffffffffffffffffffffffffffffff167f246873b6476f9c2a33e0de31e3a9a0d3d6e9268b413d04928209351193ed31fb858585856040516104d79493929190611f7d565b60405180910390a25050505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60036020528060005260406000206000915090505481565b61058b610e40565b6105956000610ebe565b565b61059f610e40565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361060e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161060590612004565b60405180910390fd5b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61065a610e40565b600360008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008154809291906106aa90611df7565b919050555050565b6106ba610e40565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610729576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161072090612004565b60405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b828042106107d9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107d090612070565b60405180910390fd5b858590508888905014610821576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161081890611d79565b60405180910390fd5b60006109456040518060c001604052803373ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8b80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508152602001898980806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508152602001600360008e73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054815260200187815250610f82565b90506109538a828686611080565b60005b898990508110156109bf576109ac8b8b8b8481811061097857610977611d99565b5b905060200201602081019061098d919061192f565b8a8a858181106109a05761099f611d99565b5b90506020020135610daa565b80806109b790611df7565b915050610956565b508973ffffffffffffffffffffffffffffffffffffffff167f775a441e8ac51cfd0f6cdd75586b7987d7bd88d401a5db8f20f1db91639976e38a8a8a8a604051610a0c9493929190611f7d565b60405180910390a250505050505050505050565b7fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac5647281565b868073ffffffffffffffffffffffffffffffffffffffff166324d7806c336040518263ffffffff1660e01b8152600401610a7e9190611862565b602060405180830381865afa158015610a9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610abf91906120c8565b610afe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610af590612141565b60405180910390fd5b83804210610b41576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b3890612070565b60405180910390fd5b6000610c156040518060e001604052803373ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018973ffffffffffffffffffffffffffffffffffffffff168152602001600360008e73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054815260200188815250611261565b9050610c238a828787611080565b8973ffffffffffffffffffffffffffffffffffffffff1663092ae4dc8a898b6040518463ffffffff1660e01b8152600401610c6093929190612161565b600060405180830381600087803b158015610c7a57600080fd5b505af1158015610c8e573d6000803e3d6000fd5b505050508973ffffffffffffffffffffffffffffffffffffffff167f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b63988a8a604051610cda929190612198565b60405180910390a250505050505050505050565b610cf6610e40565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610d65576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d5c90612233565b60405180910390fd5b610d6e81610ebe565b50565b6040518060400160405280600f81526020017f5261696e20436f6c6c61746572616c000000000000000000000000000000000081525081565b8273ffffffffffffffffffffffffffffffffffffffff1663092ae4dc83600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16846040518463ffffffff1660e01b8152600401610e0993929190612161565b600060405180830381600087803b158015610e2357600080fd5b505af1158015610e37573d6000803e3d6000fd5b50505050505050565b610e48611319565b73ffffffffffffffffffffffffffffffffffffffff16610e6661076d565b73ffffffffffffffffffffffffffffffffffffffff1614610ebc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610eb39061229f565b60405180910390fd5b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60007f648852f8933e9e64f56213b02c92318987996d695f62f77ede2b6947f9c1fbb8826000015183602001518460400151604051602001610fc49190612377565b604051602081830303815290604052805190602001208560600151604051602001610fef9190612446565b6040516020818303038152906040528051906020012060405160200161101995949392919061245d565b60405160208183030381529060405282608001518360a001516040516020016110439291906124b0565b604051602081830303815290604052604051602001611063929190612520565b604051602081830303815290604052805190602001209050919050565b60006111316040518060a001604052806040518060400160405280600f81526020017f5261696e20436f6c6c61746572616c000000000000000000000000000000000081525081526020016040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081526020014681526020013073ffffffffffffffffffffffffffffffffffffffff16815260200185815250611321565b9050600081856040516020016111489291906125bc565b604051602081830303815290604052805190602001209050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166111ac848361139d90919063ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff1614611202576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111f99061263f565b60405180910390fd5b6001600360008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611252919061265f565b92505081905550505050505050565b60007fa4e7339277875d8215224c9e0402e9330d4da2927790347e75150d777dbc3c3782600001518360200151846040015185606001516040516020016112ac959493929190612693565b60405160208183030381529060405282608001518360a001518460c001516040516020016112dc939291906126e6565b6040516020818303038152906040526040516020016112fc929190612520565b604051602081830303815290604052805190602001209050919050565b600033905090565b60007fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac564728260000151805190602001208360200151805190602001208460400151856060015186608001516040516020016113809695949392919061271d565b604051602081830303815290604052805190602001209050919050565b60008060006113ac85856113c4565b915091506113b981611415565b819250505092915050565b60008060418351036114055760008060006020860151925060408601519150606086015160001a90506113f98782858561157b565b9450945050505061140e565b60006002915091505b9250929050565b600060048111156114295761142861277e565b5b81600481111561143c5761143b61277e565b5b031561157857600160048111156114565761145561277e565b5b8160048111156114695761146861277e565b5b036114a9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114a0906127f9565b60405180910390fd5b600260048111156114bd576114bc61277e565b5b8160048111156114d0576114cf61277e565b5b03611510576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161150790612865565b60405180910390fd5b600360048111156115245761152361277e565b5b8160048111156115375761153661277e565b5b03611577576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161156e906128f7565b60405180910390fd5b5b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08360001c11156115b6576000600391509150611654565b6000600187878787604051600081526020016040526040516115db9493929190612933565b6020604051602081039080840390855afa1580156115fd573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361164b57600060019250925050611654565b80600092509250505b94509492505050565b6000819050919050565b6116708161165d565b82525050565b600060208201905061168b6000830184611667565b92915050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006116d0826116a5565b9050919050565b6116e0816116c5565b81146116eb57600080fd5b50565b6000813590506116fd816116d7565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f84011261172857611727611703565b5b8235905067ffffffffffffffff81111561174557611744611708565b5b6020830191508360208202830111156117615761176061170d565b5b9250929050565b60008083601f84011261177e5761177d611703565b5b8235905067ffffffffffffffff81111561179b5761179a611708565b5b6020830191508360208202830111156117b7576117b661170d565b5b9250929050565b6000806000806000606086880312156117da576117d961169b565b5b60006117e8888289016116ee565b955050602086013567ffffffffffffffff811115611809576118086116a0565b5b61181588828901611712565b9450945050604086013567ffffffffffffffff811115611838576118376116a0565b5b61184488828901611768565b92509250509295509295909350565b61185c816116c5565b82525050565b60006020820190506118776000830184611853565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156118b757808201518184015260208101905061189c565b60008484015250505050565b6000601f19601f8301169050919050565b60006118df8261187d565b6118e98185611888565b93506118f9818560208601611899565b611902816118c3565b840191505092915050565b6000602082019050818103600083015261192781846118d4565b905092915050565b6000602082840312156119455761194461169b565b5b6000611953848285016116ee565b91505092915050565b6000819050919050565b61196f8161195c565b82525050565b600060208201905061198a6000830184611966565b92915050565b6119998161195c565b81146119a457600080fd5b50565b6000813590506119b681611990565b92915050565b6119c58161165d565b81146119d057600080fd5b50565b6000813590506119e2816119bc565b92915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b611a25826118c3565b810181811067ffffffffffffffff82111715611a4457611a436119ed565b5b80604052505050565b6000611a57611691565b9050611a638282611a1c565b919050565b600067ffffffffffffffff821115611a8357611a826119ed565b5b611a8c826118c3565b9050602081019050919050565b82818337600083830152505050565b6000611abb611ab684611a68565b611a4d565b905082815260208101848484011115611ad757611ad66119e8565b5b611ae2848285611a99565b509392505050565b600082601f830112611aff57611afe611703565b5b8135611b0f848260208601611aa8565b91505092915050565b60008060008060008060008060c0898b031215611b3857611b3761169b565b5b6000611b468b828c016116ee565b985050602089013567ffffffffffffffff811115611b6757611b666116a0565b5b611b738b828c01611712565b9750975050604089013567ffffffffffffffff811115611b9657611b956116a0565b5b611ba28b828c01611768565b95509550506060611bb58b828c016119a7565b9350506080611bc68b828c016119d3565b92505060a089013567ffffffffffffffff811115611be757611be66116a0565b5b611bf38b828c01611aea565b9150509295985092959890939650565b600080600080600080600060e0888a031215611c2257611c2161169b565b5b6000611c308a828b016116ee565b9750506020611c418a828b016116ee565b9650506040611c528a828b016119a7565b9550506060611c638a828b016116ee565b9450506080611c748a828b016119a7565b93505060a0611c858a828b016119d3565b92505060c088013567ffffffffffffffff811115611ca657611ca56116a0565b5b611cb28a828b01611aea565b91505092959891949750929550565b7f4e6f7420636f6e74726f6c6c65722061646d696e000000000000000000000000600082015250565b6000611cf7601483611888565b9150611d0282611cc1565b602082019050919050565b60006020820190508181036000830152611d2681611cea565b9050919050565b7f496e76616c696420506172616d73000000000000000000000000000000000000600082015250565b6000611d63600e83611888565b9150611d6e82611d2d565b602082019050919050565b60006020820190508181036000830152611d9281611d56565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000611e028261195c565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e3457611e33611dc8565b5b600182019050919050565b600082825260208201905092915050565b6000819050919050565b611e63816116c5565b82525050565b6000611e758383611e5a565b60208301905092915050565b6000611e9060208401846116ee565b905092915050565b6000602082019050919050565b6000611eb18385611e3f565b9350611ebc82611e50565b8060005b85811015611ef557611ed28284611e81565b611edc8882611e69565b9750611ee783611e98565b925050600181019050611ec0565b5085925050509392505050565b600082825260208201905092915050565b600080fd5b82818337505050565b6000611f2d8385611f02565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115611f6057611f5f611f13565b5b602083029250611f71838584611f18565b82840190509392505050565b60006040820190508181036000830152611f98818688611ea5565b90508181036020830152611fad818486611f21565b905095945050505050565b7f5a65726f20416464726573730000000000000000000000000000000000000000600082015250565b6000611fee600c83611888565b9150611ff982611fb8565b602082019050919050565b6000602082019050818103600083015261201d81611fe1565b9050919050565b7f45787069726564207369676e6174757265000000000000000000000000000000600082015250565b600061205a601183611888565b915061206582612024565b602082019050919050565b600060208201905081810360008301526120898161204d565b9050919050565b60008115159050919050565b6120a581612090565b81146120b057600080fd5b50565b6000815190506120c28161209c565b92915050565b6000602082840312156120de576120dd61169b565b5b60006120ec848285016120b3565b91505092915050565b7f556e617574686f72697a65640000000000000000000000000000000000000000600082015250565b600061212b600c83611888565b9150612136826120f5565b602082019050919050565b6000602082019050818103600083015261215a8161211e565b9050919050565b60006060820190506121766000830186611853565b6121836020830185611853565b6121906040830184611966565b949350505050565b60006040820190506121ad6000830185611853565b6121ba6020830184611966565b9392505050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b600061221d602683611888565b9150612228826121c1565b604082019050919050565b6000602082019050818103600083015261224c81612210565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000612289602083611888565b915061229482612253565b602082019050919050565b600060208201905081810360008301526122b88161227c565b9050919050565b600081519050919050565b600081905092915050565b6000819050602082019050919050565b6122ee816116c5565b82525050565b600061230083836122e5565b60208301905092915050565b6000602082019050919050565b6000612324826122bf565b61232e81856122ca565b9350612339836122d5565b8060005b8381101561236a57815161235188826122f4565b975061235c8361230c565b92505060018101905061233d565b5085935050505092915050565b60006123838284612319565b915081905092915050565b600081519050919050565b600081905092915050565b6000819050602082019050919050565b6123bd8161195c565b82525050565b60006123cf83836123b4565b60208301905092915050565b6000602082019050919050565b60006123f38261238e565b6123fd8185612399565b9350612408836123a4565b8060005b8381101561243957815161242088826123c3565b975061242b836123db565b92505060018101905061240c565b5085935050505092915050565b600061245282846123e8565b915081905092915050565b600060a0820190506124726000830188611667565b61247f6020830187611853565b61248c6040830186611853565b6124996060830185611667565b6124a66080830184611667565b9695505050505050565b60006040820190506124c56000830185611966565b6124d26020830184611966565b9392505050565b600081519050919050565b600081905092915050565b60006124fa826124d9565b61250481856124e4565b9350612514818560208601611899565b80840191505092915050565b600061252c82856124ef565b915061253882846124ef565b91508190509392505050565b600081905092915050565b7f1901000000000000000000000000000000000000000000000000000000000000600082015250565b6000612585600283612544565b91506125908261254f565b600282019050919050565b6000819050919050565b6125b66125b18261165d565b61259b565b82525050565b60006125c782612578565b91506125d382856125a5565b6020820191506125e382846125a5565b6020820191508190509392505050565b7f496e76616c6964207369676e6174757265000000000000000000000000000000600082015250565b6000612629601183611888565b9150612634826125f3565b602082019050919050565b600060208201905081810360008301526126588161261c565b9050919050565b600061266a8261195c565b91506126758361195c565b925082820190508082111561268d5761268c611dc8565b5b92915050565b600060a0820190506126a86000830188611667565b6126b56020830187611853565b6126c26040830186611853565b6126cf6060830185611853565b6126dc6080830184611966565b9695505050505050565b60006060820190506126fb6000830186611853565b6127086020830185611966565b6127156040830184611966565b949350505050565b600060c0820190506127326000830189611667565b61273f6020830188611667565b61274c6040830187611667565b6127596060830186611966565b6127666080830185611853565b61277360a0830184611667565b979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f45434453413a20696e76616c6964207369676e61747572650000000000000000600082015250565b60006127e3601883611888565b91506127ee826127ad565b602082019050919050565b60006020820190508181036000830152612812816127d6565b9050919050565b7f45434453413a20696e76616c6964207369676e6174757265206c656e67746800600082015250565b600061284f601f83611888565b915061285a82612819565b602082019050919050565b6000602082019050818103600083015261287e81612842565b9050919050565b7f45434453413a20696e76616c6964207369676e6174757265202773272076616c60008201527f7565000000000000000000000000000000000000000000000000000000000000602082015250565b60006128e1602283611888565b91506128ec82612885565b604082019050919050565b60006020820190508181036000830152612910816128d4565b9050919050565b600060ff82169050919050565b61292d81612917565b82525050565b60006080820190506129486000830187611667565b6129556020830186612924565b6129626040830185611667565b61296f6060830184611667565b9594505050505056fea26469706673582212201e6ba7352303d644fe078843270009603ccf86a248508324ae738b0055268b2164736f6c63430008110033000000000000000000000000b92949bdf09f4193599ae7700211751ab5f74acd0000000000000000000000000204c22be67968c3b787d2699bd05cf2b9432c60

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061010b5760003560e01c80637f51bb1f116100a2578063b0dc1df711610071578063b0dc1df71461026e578063b727b5791461028a578063e167d26a146102a8578063f2fde38b146102c4578063fd070296146102e05761010b565b80637f51bb1f146101fc5780638247a97c146102185780638605352e146102345780638da5cb5b146102505761010b565b80635cc33321116100de5780635cc333211461018657806361d027b3146101a457806370ae92d2146101c2578063715018a6146101f25761010b565b806305c6eb6e14610110578063213bc2181461012e57806324c244eb1461014c5780632523551114610168575b600080fd5b6101186102fe565b6040516101259190611676565b60405180910390f35b610136610322565b6040516101439190611676565b60405180910390f35b610166600480360381019061016191906117be565b610346565b005b6101706104e6565b60405161017d9190611862565b60405180910390f35b61018e61050c565b60405161019b919061190d565b60405180910390f35b6101ac610545565b6040516101b99190611862565b60405180910390f35b6101dc60048036038101906101d7919061192f565b61056b565b6040516101e99190611975565b60405180910390f35b6101fa610583565b005b6102166004803603810190610211919061192f565b610597565b005b610232600480360381019061022d919061192f565b610652565b005b61024e6004803603810190610249919061192f565b6106b2565b005b61025861076d565b6040516102659190611862565b60405180910390f35b61028860048036038101906102839190611b18565b610796565b005b610292610a20565b60405161029f9190611676565b60405180910390f35b6102c260048036038101906102bd9190611c03565b610a44565b005b6102de60048036038101906102d9919061192f565b610cee565b005b6102e8610d71565b6040516102f5919061190d565b60405180910390f35b7f648852f8933e9e64f56213b02c92318987996d695f62f77ede2b6947f9c1fbb881565b7fa4e7339277875d8215224c9e0402e9330d4da2927790347e75150d777dbc3c3781565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146103d6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103cd90611d0d565b60405180910390fd5b81819050848490501461041e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161041590611d79565b60405180910390fd5b60005b8484905081101561048a576104778686868481811061044357610442611d99565b5b9050602002016020810190610458919061192f565b85858581811061046b5761046a611d99565b5b90506020020135610daa565b808061048290611df7565b915050610421565b508473ffffffffffffffffffffffffffffffffffffffff167f246873b6476f9c2a33e0de31e3a9a0d3d6e9268b413d04928209351193ed31fb858585856040516104d79493929190611f7d565b60405180910390a25050505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60036020528060005260406000206000915090505481565b61058b610e40565b6105956000610ebe565b565b61059f610e40565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361060e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161060590612004565b60405180910390fd5b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61065a610e40565b600360008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008154809291906106aa90611df7565b919050555050565b6106ba610e40565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610729576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161072090612004565b60405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b828042106107d9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107d090612070565b60405180910390fd5b858590508888905014610821576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161081890611d79565b60405180910390fd5b60006109456040518060c001604052803373ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b8b80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508152602001898980806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508152602001600360008e73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054815260200187815250610f82565b90506109538a828686611080565b60005b898990508110156109bf576109ac8b8b8b8481811061097857610977611d99565b5b905060200201602081019061098d919061192f565b8a8a858181106109a05761099f611d99565b5b90506020020135610daa565b80806109b790611df7565b915050610956565b508973ffffffffffffffffffffffffffffffffffffffff167f775a441e8ac51cfd0f6cdd75586b7987d7bd88d401a5db8f20f1db91639976e38a8a8a8a604051610a0c9493929190611f7d565b60405180910390a250505050505050505050565b7fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac5647281565b868073ffffffffffffffffffffffffffffffffffffffff166324d7806c336040518263ffffffff1660e01b8152600401610a7e9190611862565b602060405180830381865afa158015610a9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610abf91906120c8565b610afe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610af590612141565b60405180910390fd5b83804210610b41576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b3890612070565b60405180910390fd5b6000610c156040518060e001604052803373ffffffffffffffffffffffffffffffffffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b73ffffffffffffffffffffffffffffffffffffffff1681526020018a81526020018973ffffffffffffffffffffffffffffffffffffffff168152602001600360008e73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054815260200188815250611261565b9050610c238a828787611080565b8973ffffffffffffffffffffffffffffffffffffffff1663092ae4dc8a898b6040518463ffffffff1660e01b8152600401610c6093929190612161565b600060405180830381600087803b158015610c7a57600080fd5b505af1158015610c8e573d6000803e3d6000fd5b505050508973ffffffffffffffffffffffffffffffffffffffff167f2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b63988a8a604051610cda929190612198565b60405180910390a250505050505050505050565b610cf6610e40565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610d65576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d5c90612233565b60405180910390fd5b610d6e81610ebe565b50565b6040518060400160405280600f81526020017f5261696e20436f6c6c61746572616c000000000000000000000000000000000081525081565b8273ffffffffffffffffffffffffffffffffffffffff1663092ae4dc83600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16846040518463ffffffff1660e01b8152600401610e0993929190612161565b600060405180830381600087803b158015610e2357600080fd5b505af1158015610e37573d6000803e3d6000fd5b50505050505050565b610e48611319565b73ffffffffffffffffffffffffffffffffffffffff16610e6661076d565b73ffffffffffffffffffffffffffffffffffffffff1614610ebc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610eb39061229f565b60405180910390fd5b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60007f648852f8933e9e64f56213b02c92318987996d695f62f77ede2b6947f9c1fbb8826000015183602001518460400151604051602001610fc49190612377565b604051602081830303815290604052805190602001208560600151604051602001610fef9190612446565b6040516020818303038152906040528051906020012060405160200161101995949392919061245d565b60405160208183030381529060405282608001518360a001516040516020016110439291906124b0565b604051602081830303815290604052604051602001611063929190612520565b604051602081830303815290604052805190602001209050919050565b60006111316040518060a001604052806040518060400160405280600f81526020017f5261696e20436f6c6c61746572616c000000000000000000000000000000000081525081526020016040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081526020014681526020013073ffffffffffffffffffffffffffffffffffffffff16815260200185815250611321565b9050600081856040516020016111489291906125bc565b604051602081830303815290604052805190602001209050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166111ac848361139d90919063ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff1614611202576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111f99061263f565b60405180910390fd5b6001600360008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611252919061265f565b92505081905550505050505050565b60007fa4e7339277875d8215224c9e0402e9330d4da2927790347e75150d777dbc3c3782600001518360200151846040015185606001516040516020016112ac959493929190612693565b60405160208183030381529060405282608001518360a001518460c001516040516020016112dc939291906126e6565b6040516020818303038152906040526040516020016112fc929190612520565b604051602081830303815290604052805190602001209050919050565b600033905090565b60007fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac564728260000151805190602001208360200151805190602001208460400151856060015186608001516040516020016113809695949392919061271d565b604051602081830303815290604052805190602001209050919050565b60008060006113ac85856113c4565b915091506113b981611415565b819250505092915050565b60008060418351036114055760008060006020860151925060408601519150606086015160001a90506113f98782858561157b565b9450945050505061140e565b60006002915091505b9250929050565b600060048111156114295761142861277e565b5b81600481111561143c5761143b61277e565b5b031561157857600160048111156114565761145561277e565b5b8160048111156114695761146861277e565b5b036114a9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114a0906127f9565b60405180910390fd5b600260048111156114bd576114bc61277e565b5b8160048111156114d0576114cf61277e565b5b03611510576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161150790612865565b60405180910390fd5b600360048111156115245761152361277e565b5b8160048111156115375761153661277e565b5b03611577576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161156e906128f7565b60405180910390fd5b5b50565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08360001c11156115b6576000600391509150611654565b6000600187878787604051600081526020016040526040516115db9493929190612933565b6020604051602081039080840390855afa1580156115fd573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361164b57600060019250925050611654565b80600092509250505b94509492505050565b6000819050919050565b6116708161165d565b82525050565b600060208201905061168b6000830184611667565b92915050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006116d0826116a5565b9050919050565b6116e0816116c5565b81146116eb57600080fd5b50565b6000813590506116fd816116d7565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f84011261172857611727611703565b5b8235905067ffffffffffffffff81111561174557611744611708565b5b6020830191508360208202830111156117615761176061170d565b5b9250929050565b60008083601f84011261177e5761177d611703565b5b8235905067ffffffffffffffff81111561179b5761179a611708565b5b6020830191508360208202830111156117b7576117b661170d565b5b9250929050565b6000806000806000606086880312156117da576117d961169b565b5b60006117e8888289016116ee565b955050602086013567ffffffffffffffff811115611809576118086116a0565b5b61181588828901611712565b9450945050604086013567ffffffffffffffff811115611838576118376116a0565b5b61184488828901611768565b92509250509295509295909350565b61185c816116c5565b82525050565b60006020820190506118776000830184611853565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156118b757808201518184015260208101905061189c565b60008484015250505050565b6000601f19601f8301169050919050565b60006118df8261187d565b6118e98185611888565b93506118f9818560208601611899565b611902816118c3565b840191505092915050565b6000602082019050818103600083015261192781846118d4565b905092915050565b6000602082840312156119455761194461169b565b5b6000611953848285016116ee565b91505092915050565b6000819050919050565b61196f8161195c565b82525050565b600060208201905061198a6000830184611966565b92915050565b6119998161195c565b81146119a457600080fd5b50565b6000813590506119b681611990565b92915050565b6119c58161165d565b81146119d057600080fd5b50565b6000813590506119e2816119bc565b92915050565b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b611a25826118c3565b810181811067ffffffffffffffff82111715611a4457611a436119ed565b5b80604052505050565b6000611a57611691565b9050611a638282611a1c565b919050565b600067ffffffffffffffff821115611a8357611a826119ed565b5b611a8c826118c3565b9050602081019050919050565b82818337600083830152505050565b6000611abb611ab684611a68565b611a4d565b905082815260208101848484011115611ad757611ad66119e8565b5b611ae2848285611a99565b509392505050565b600082601f830112611aff57611afe611703565b5b8135611b0f848260208601611aa8565b91505092915050565b60008060008060008060008060c0898b031215611b3857611b3761169b565b5b6000611b468b828c016116ee565b985050602089013567ffffffffffffffff811115611b6757611b666116a0565b5b611b738b828c01611712565b9750975050604089013567ffffffffffffffff811115611b9657611b956116a0565b5b611ba28b828c01611768565b95509550506060611bb58b828c016119a7565b9350506080611bc68b828c016119d3565b92505060a089013567ffffffffffffffff811115611be757611be66116a0565b5b611bf38b828c01611aea565b9150509295985092959890939650565b600080600080600080600060e0888a031215611c2257611c2161169b565b5b6000611c308a828b016116ee565b9750506020611c418a828b016116ee565b9650506040611c528a828b016119a7565b9550506060611c638a828b016116ee565b9450506080611c748a828b016119a7565b93505060a0611c858a828b016119d3565b92505060c088013567ffffffffffffffff811115611ca657611ca56116a0565b5b611cb28a828b01611aea565b91505092959891949750929550565b7f4e6f7420636f6e74726f6c6c65722061646d696e000000000000000000000000600082015250565b6000611cf7601483611888565b9150611d0282611cc1565b602082019050919050565b60006020820190508181036000830152611d2681611cea565b9050919050565b7f496e76616c696420506172616d73000000000000000000000000000000000000600082015250565b6000611d63600e83611888565b9150611d6e82611d2d565b602082019050919050565b60006020820190508181036000830152611d9281611d56565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000611e028261195c565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611e3457611e33611dc8565b5b600182019050919050565b600082825260208201905092915050565b6000819050919050565b611e63816116c5565b82525050565b6000611e758383611e5a565b60208301905092915050565b6000611e9060208401846116ee565b905092915050565b6000602082019050919050565b6000611eb18385611e3f565b9350611ebc82611e50565b8060005b85811015611ef557611ed28284611e81565b611edc8882611e69565b9750611ee783611e98565b925050600181019050611ec0565b5085925050509392505050565b600082825260208201905092915050565b600080fd5b82818337505050565b6000611f2d8385611f02565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115611f6057611f5f611f13565b5b602083029250611f71838584611f18565b82840190509392505050565b60006040820190508181036000830152611f98818688611ea5565b90508181036020830152611fad818486611f21565b905095945050505050565b7f5a65726f20416464726573730000000000000000000000000000000000000000600082015250565b6000611fee600c83611888565b9150611ff982611fb8565b602082019050919050565b6000602082019050818103600083015261201d81611fe1565b9050919050565b7f45787069726564207369676e6174757265000000000000000000000000000000600082015250565b600061205a601183611888565b915061206582612024565b602082019050919050565b600060208201905081810360008301526120898161204d565b9050919050565b60008115159050919050565b6120a581612090565b81146120b057600080fd5b50565b6000815190506120c28161209c565b92915050565b6000602082840312156120de576120dd61169b565b5b60006120ec848285016120b3565b91505092915050565b7f556e617574686f72697a65640000000000000000000000000000000000000000600082015250565b600061212b600c83611888565b9150612136826120f5565b602082019050919050565b6000602082019050818103600083015261215a8161211e565b9050919050565b60006060820190506121766000830186611853565b6121836020830185611853565b6121906040830184611966565b949350505050565b60006040820190506121ad6000830185611853565b6121ba6020830184611966565b9392505050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b600061221d602683611888565b9150612228826121c1565b604082019050919050565b6000602082019050818103600083015261224c81612210565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000612289602083611888565b915061229482612253565b602082019050919050565b600060208201905081810360008301526122b88161227c565b9050919050565b600081519050919050565b600081905092915050565b6000819050602082019050919050565b6122ee816116c5565b82525050565b600061230083836122e5565b60208301905092915050565b6000602082019050919050565b6000612324826122bf565b61232e81856122ca565b9350612339836122d5565b8060005b8381101561236a57815161235188826122f4565b975061235c8361230c565b92505060018101905061233d565b5085935050505092915050565b60006123838284612319565b915081905092915050565b600081519050919050565b600081905092915050565b6000819050602082019050919050565b6123bd8161195c565b82525050565b60006123cf83836123b4565b60208301905092915050565b6000602082019050919050565b60006123f38261238e565b6123fd8185612399565b9350612408836123a4565b8060005b8381101561243957815161242088826123c3565b975061242b836123db565b92505060018101905061240c565b5085935050505092915050565b600061245282846123e8565b915081905092915050565b600060a0820190506124726000830188611667565b61247f6020830187611853565b61248c6040830186611853565b6124996060830185611667565b6124a66080830184611667565b9695505050505050565b60006040820190506124c56000830185611966565b6124d26020830184611966565b9392505050565b600081519050919050565b600081905092915050565b60006124fa826124d9565b61250481856124e4565b9350612514818560208601611899565b80840191505092915050565b600061252c82856124ef565b915061253882846124ef565b91508190509392505050565b600081905092915050565b7f1901000000000000000000000000000000000000000000000000000000000000600082015250565b6000612585600283612544565b91506125908261254f565b600282019050919050565b6000819050919050565b6125b66125b18261165d565b61259b565b82525050565b60006125c782612578565b91506125d382856125a5565b6020820191506125e382846125a5565b6020820191508190509392505050565b7f496e76616c6964207369676e6174757265000000000000000000000000000000600082015250565b6000612629601183611888565b9150612634826125f3565b602082019050919050565b600060208201905081810360008301526126588161261c565b9050919050565b600061266a8261195c565b91506126758361195c565b925082820190508082111561268d5761268c611dc8565b5b92915050565b600060a0820190506126a86000830188611667565b6126b56020830187611853565b6126c26040830186611853565b6126cf6060830185611853565b6126dc6080830184611966565b9695505050505050565b60006060820190506126fb6000830186611853565b6127086020830185611966565b6127156040830184611966565b949350505050565b600060c0820190506127326000830189611667565b61273f6020830188611667565b61274c6040830187611667565b6127596060830186611966565b6127666080830185611853565b61277360a0830184611667565b979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f45434453413a20696e76616c6964207369676e61747572650000000000000000600082015250565b60006127e3601883611888565b91506127ee826127ad565b602082019050919050565b60006020820190508181036000830152612812816127d6565b9050919050565b7f45434453413a20696e76616c6964207369676e6174757265206c656e67746800600082015250565b600061284f601f83611888565b915061285a82612819565b602082019050919050565b6000602082019050818103600083015261287e81612842565b9050919050565b7f45434453413a20696e76616c6964207369676e6174757265202773272076616c60008201527f7565000000000000000000000000000000000000000000000000000000000000602082015250565b60006128e1602283611888565b91506128ec82612885565b604082019050919050565b60006020820190508181036000830152612910816128d4565b9050919050565b600060ff82169050919050565b61292d81612917565b82525050565b60006080820190506129486000830187611667565b6129556020830186612924565b6129626040830185611667565b61296f6060830184611667565b9594505050505056fea26469706673582212201e6ba7352303d644fe078843270009603ccf86a248508324ae738b0055268b2164736f6c63430008110033

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

000000000000000000000000b92949bdf09f4193599ae7700211751ab5f74acd0000000000000000000000000204c22be67968c3b787d2699bd05cf2b9432c60

-----Decoded View---------------
Arg [0] : _controllerAdmin (address): 0xB92949bdF09F4193599Ae7700211751ab5F74aCd
Arg [1] : _treasury (address): 0x0204C22BE67968C3B787D2699Bd05cf2b9432c60

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000b92949bdf09f4193599ae7700211751ab5f74acd
Arg [1] : 0000000000000000000000000204c22be67968c3b787d2699bd05cf2b9432c60


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ 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.