false
false
0

Contract Address Details

0xc9a90cB6A2Fc63baBC93f08Ea30B1C056F66461d

Contract Name
StableAssetStakeUtil
Creator
0x454d79–a33fa0 at 0x0cb89a–8287d8
Balance
0 ACA
Tokens
Fetching tokens...
Transactions
0 Transactions
Transfers
0 Transfers
Gas Used
Fetching gas used...
Last Balance Update
12275777
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
StableAssetStakeUtil




Optimization enabled
true
Compiler version
v0.8.17+commit.8df45f5f




Optimization runs
200
EVM Version
default




Verified at
2024-01-05T05:29:25.161771Z

Constructor Arguments

0x0000000000000000000000007fe92ec600f15cd25253b421bc151c51b0276b7d000000000000000000000000000000000000000000000000000000000000080400000000000000000000000000000000000000000000000000000000000008050000000000000000000000000000000000000000000100000000000000000003

Arg [0] (address) : 0x7fe92ec600f15cd25253b421bc151c51b0276b7d
Arg [1] (address) : 0x0000000000000000000000000000000000000804
Arg [2] (address) : 0x0000000000000000000000000000000000000805
Arg [3] (address) : 0x0000000000000000000100000000000000000003

              

Contract source code

Sol2uml
new
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.17;

// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol)

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)

// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to
     * 0 before setting it to a non-zero value.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return
            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
    }
}

/// @title StableAsset Predeploy Contract Interface
/// @author Acala Developers
/// @notice You can use this predeploy contract to call stable-asset pallet
/// @dev The interface through which solidity contracts will interact with stable-asset pallet
interface IStableAsset {
    /// @notice The stable asset swapped event.
    /// @param sender The sender of the transaction.
    /// @param poolId The ID of the pool.
    /// @param i The array index of the input token in stableAsset tokens.
    /// @param j The array index of the output token in stableAsset tokens.
    /// @param dx The amount of input token.
    /// @param minDY The minimum amount of output token received.
    /// @param assetLength The length of array in stableAsset tokens.
    event StableAssetSwapped(
        address indexed sender,
        uint32 indexed poolId,
        uint32 i,
        uint32 j,
        uint256 dx,
        uint256 minDY,
        uint32 assetLength
    );

    /// @notice The stable asset minted event.
    /// @param sender The sender of the transaction.
    /// @param poolId The ID of the pool.
    /// @param amounts amount of tokens to be put in the pool.
    /// @param minMintAmount amount of minimum pool token received.
    event StableAssetMinted(
        address indexed sender,
        uint32 indexed poolId,
        uint256[] amounts,
        uint256 minMintAmount
    );

    /// @notice The scheduled call event.
    /// @param sender The sender of the transaction.
    /// @param poolId The ID of the pool.
    /// @param redeemAmount The amount of pool token to be redeemed.
    /// @param amounts The minimum amounts of redeemed token received.
    event StableAssetRedeemed(
        address indexed sender,
        uint32 indexed poolId,
        uint256 redeemAmount,
        uint256[] amounts
    );

    /// @notice The scheduled call event.
    /// @param sender The sender of the transaction.
    /// @param poolId The ID of the pool.
    /// @param redeemAmount The amount of pool token to be redeemed.
    /// @param i The the array index of the input token in stable pool.
    /// @param minRedeemAmount The minimum amount of token recieved.
    /// @param assetLength The length of array of tokens in stable pool.
    event StableAssetRedeemedSingle(
        address indexed sender,
        uint32 indexed poolId,
        uint256 redeemAmount,
        uint32 i,
        uint256 minRedeemAmount,
        uint32 assetLength
    );

    /// @notice The scheduled call event.
    /// @param sender The sender of the transaction.
    /// @param poolId The ID of the pool.
    /// @param amounts The amount of underlying token to be recieved.
    /// @param maxRedeemAmount The maximum amount of pool token to be input.
    event StableAssetRedeemedMulti(
        address indexed sender,
        uint32 indexed poolId,
        uint256[] amounts,
        uint256 maxRedeemAmount
    );

    /// @notice Get stable asset pool tokens.
    /// @param poolId The ID of the pool.
    /// @return poolExists whether pool exists or not.
    /// @return tokens stabel asset pool tokens.
    function getStableAssetPoolTokens(
        uint32 poolId
    ) external view returns (bool, address[] memory);

    /// @notice Get stable asset pool total supply.
    /// @param poolId The ID of the pool.
    /// @return poolExists whether pool exists or not.
    /// @return totalSupply total supply value.
    function getStableAssetPoolTotalSupply(
        uint32 poolId
    ) external view returns (bool, uint256);

    /// @notice Get stable asset pool precision.
    /// @param poolId The ID of the pool.
    /// @return poolExists whether pool exists or not.
    /// @return precision precision value.
    function getStableAssetPoolPrecision(
        uint32 poolId
    ) external view returns (bool, uint256);

    /// @notice Get stable asset pool mint fee.
    /// @param poolId The ID of the pool.
    /// @return poolExists whether pool exists or not.
    /// @return mintFee mint fee value.
    function getStableAssetPoolMintFee(
        uint32 poolId
    ) external view returns (bool, uint256);

    /// @notice Get stable asset pool swap fee.
    /// @param poolId The ID of the pool.
    /// @return poolExists whether pool exists or not.
    /// @return swapFee swap fee value.
    function getStableAssetPoolSwapFee(
        uint32 poolId
    ) external view returns (bool, uint256);

    /// @notice Get stable asset pool redeem fee.
    /// @param poolId The ID of the pool.
    /// @return poolExists whether pool exists or not.
    /// @return redeemFee redeem fee value.
    function getStableAssetPoolRedeemFee(
        uint32 poolId
    ) external view returns (bool, uint256);

    /// @notice Stable asset swap tokens.
    /// @dev It'll emit an {StableAssetSwapped} event.
    /// @param poolId The ID of the pool.
    /// @param i The array index of the input token in stableAsset tokens.
    /// @param j The array index of the output token in stableAsset tokens.
    /// @param dx The amount of input token.
    /// @param minDY The minimum amount of output token received.
    /// @param assetLength The length of array in stableAsset tokens.
    /// @return Returns a boolean value indicating whether the operation succeeded.
    function stableAssetSwap(
        uint32 poolId,
        uint32 i,
        uint32 j,
        uint256 dx,
        uint256 minDY,
        uint32 assetLength
    ) external returns (bool);

    /// @notice Stable asset mint.
    /// @dev It'll emit an {StableAssetMinted} event.
    /// @param poolId The ID of the pool.
    /// @param amounts amount of tokens to be put in the pool.
    /// @param minMintAmount amount of minimum pool token received.
    /// @return Returns a boolean value indicating whether the operation succeeded.
    function stableAssetMint(
        uint32 poolId,
        uint256[] calldata amounts,
        uint256 minMintAmount
    ) external returns (bool);

    /// @notice Stable asset redeem, redeems the token proportionally.
    /// @dev It'll emit an {StableAssetRedeemed} event.
    /// @param poolId The ID of the pool.
    /// @param redeemAmount The amount of pool token to be redeemed.
    /// @param amounts The minimum amounts of redeemed token received.
    /// @return Returns a boolean value indicating whether the operation succeeded.
    function stableAssetRedeem(
        uint32 poolId,
        uint256 redeemAmount,
        uint256[] calldata amounts
    ) external returns (bool);

    /// @notice Stable asset redeem single, Redeems token into single token from pool.
    /// @dev It'll emit an {StableAssetRedeemedSingle} event.
    /// @param poolId The ID of the pool.
    /// @param redeemAmount The amount of pool token to be redeemed.
    /// @param i The the array index of the input token in stable pool.
    /// @param minRedeemAmount The minimum amount of token recieved.
    /// @param assetLength The length of array of tokens in stable pool.
    /// @return Returns a boolean value indicating whether the operation succeeded.
    function stableAssetRedeemSingle(
        uint32 poolId,
        uint256 redeemAmount,
        uint32 i,
        uint256 minRedeemAmount,
        uint32 assetLength
    ) external returns (bool);

    /// @notice Stable asset redeem multi, Redeems token into single token from pool.
    /// @dev It'll emit an {StableAssetRedeemedMulti} event.
    /// @param poolId The ID of the pool.
    /// @param amounts The amount of underlying token to be recieved.
    /// @param maxRedeemAmount The maximum amount of pool token to be input.
    /// @return Returns a boolean value indicating whether the operation succeeded.
    function stableAssetRedeemMulti(
        uint32 poolId,
        uint256[] calldata amounts,
        uint256 maxRedeemAmount
    ) external returns (bool);
}

/// @title Homa Predeploy Contract Interface
/// @author Acala Developers
/// @notice You can use this predeploy contract to call homa pallet
/// @dev The interface through which solidity contracts will interact with homa pallet
interface IHoma {
    /// @notice Minted liquid currency event.
    /// @param sender The sender of the transaction.
    /// @param amount The minted amount.
    event Minted(address indexed sender, uint256 amount);

    /// @notice Requested redeem event.
    /// @param sender The sender of the transaction.
    /// @param amount The requested amount.
    /// @param fastMatch Allow the request to be fast matched.
    event RequestedRedeem(
        address indexed sender,
        uint256 amount,
        bool fastMatch
    );

    /// @notice Mint liquid currency with staking currency.
    /// @dev It'll emit an {Minted} event.
    /// @param mintAmount The amount of staking currency used to mint liquid currency.
    /// @return Returns a boolean value indicating whether the operation succeeded.
    function mint(uint256 mintAmount) external returns (bool);

    /// @notice Request to redeem liquid curency for staking currency.
    /// @dev It'll emit an {RequestedRedeem} event.
    /// @param redeemAmount The amount of liquid currency to be requested  redeemed into Staking currency.
    /// @param fastMatch Allow the request to be fast matched, fast match will take a fixed rate as fee.
    /// @return Returns a boolean value indicating whether the operation succeeded.
    function requestRedeem(
        uint256 redeemAmount,
        bool fastMatch
    ) external returns (bool);

    /// @notice Get exchange rate.
    /// @return returns (exchange_rate), value is FixedU128 with a range of
    /// [0.000000000000000000, 340282366920938463463.374607431768211455]
    function getExchangeRate() external view returns (uint256);

    /// @notice Get estimated reward rate.
    /// @return returns (reward_rate), value is FixedU128 with a range of
    /// [0.000000000000000000, 340282366920938463463.374607431768211455].
    function getEstimatedRewardRate() external view returns (uint256);

    /// @notice Get commission rate.
    /// @return returns (commission_rate) is a FixedU128 representing a decimal.
    function getCommissionRate() external view returns (uint256);

    /// @notice Get fast match fee rate.
    /// @return returns (fast_match_fee) is a FixedU128 representing a decimal.
    function getFastMatchFee() external view returns (uint256);
}

/// @title IWrappedStableAssetShare Interface
/// @author Acala Developers
/// @notice You can use this to wrapped stable asset pool LP token to received market profit.
interface IWrappedStableAssetShare {
    /// @notice Deposit share token to mint wrapped share token.
    /// @param who The sender of the transaction.
    /// @param shareAmount The share token amount to deposit.
    /// @param wrappedShareAmount The wrapped share token amount received.
    event Deposit(address indexed who, uint256 shareAmount, uint256 wrappedShareAmount);

    /// @notice Withdraw share token by burn wrapped share token.
    /// @param who The sender of the transaction.
    /// @param wrappedShareAmount The wrapped share token amount to burn.
    /// @param shareAmount The share token amount received.
    event Withdraw(address indexed who, uint256 wrappedShareAmount, uint256 shareAmount);

    /// @notice Get the deposit rate(the exchange rate for share token to wrapped share token).
    /// @return Returns (exchangeRate). Deposit rate, 1e18 is 100%
    function depositRate() external view returns (uint256);

    /// @notice Get the withdraw rate(the exchange rate for wrapped share token to share token).
    /// @return Returns (exchangeRate). Withdraw rate, 1e18 is 100%
    function withdrawRate() external view returns (uint256);

    /// @notice Deposit `shareAmount` share token to mint wrapped share token.
    /// @param shareAmount The share token amount to deposit.
    /// @return Returns (wrappedShareAmount). The wrapped share token amount received.
    function deposit(uint256 shareAmount) external returns (uint256);

    /// @notice Withdraw share token by burn `wrappedShareAmount` wrapped share token.
    /// @param wrappedShareAmount The wrapped share token amount to burn.
    /// @return Returns (shareAmount). The share token amount received.
    function withdraw(uint256 wrappedShareAmount) external returns (uint256);
}

/// @title IStaking Interface
/// @author Acala Developers
/// @notice You can use this integrate Acala LST staking into your contract.
interface IStaking {
    /// @notice Claim reward from staking pool.
    /// @param sender The sender of the transaction.
    /// @param poolId The index of staking pool.
    /// @param rewardType The reward token address.
    /// @param amount The claimed reward amount.
    event ClaimReward(address indexed sender, uint256 poolId, IERC20 indexed rewardType, uint256 amount);

    /// @notice Unstake share from staking pool.
    /// @param sender The sender of the transaction.
    /// @param poolId The index of staking pool.
    /// @param amount The share amount of unstake.
    event Unstake(address indexed sender, uint256 poolId, uint256 amount);

    /// @notice Stake share into staking pool.
    /// @param sender The sender of the transaction.
    /// @param poolId The index of staking pool.
    /// @param amount The share amount of stake.
    event Stake(address indexed sender, uint256 poolId, uint256 amount);

    /// @notice Get the share token address of the `poolId` pool.
    /// @param poolId The index of staking pool.
    /// @return Returns (shareToken). If pool hasn't been initialized, return address(0x0).
    function shareTypes(uint256 poolId) external view returns (IERC20);

    /// @notice Get the total share amount of the `poolId` pool.
    /// @param poolId The index of staking pool.
    /// @return Returns (totalShare).
    function totalShares(uint256 poolId) external view returns (uint256);

    /// @notice Get the all reward token types of the `poolId` pool.
    /// @param poolId The index of staking pool.
    /// @return Returns (rewardTypesArr). Return all rewarded token types in this pool.
    function rewardTypes(uint256 poolId) external view returns (IERC20[] memory);

    /// @notice Get the share amount of `who` at `poolId` pool.
    /// @param poolId The index of staking pool.
    /// @param who The address of staker.
    /// @return Returns (shareAmount).
    function shares(uint256 poolId, address who) external view returns (uint256);

    /// @notice Get `who`'s unclaimed reward amount of specific `rewardType` at `poolId` pool.
    /// @param poolId The index of staking pool.
    /// @param who The address of staker.
    /// @param rewardType The reward token.
    /// @return Returns (rewardAmount).
    function earned(uint256 poolId, address who, IERC20 rewardType) external view returns (uint256);

    /// @notice Stake share into staking pool.
    /// @param poolId The index of staking pool.
    /// @param amount The share amount to stake.
    /// @return Returns (success).
    function stake(uint256 poolId, uint256 amount) external returns (bool);

    /// @notice Withdraw share from staking pool.
    /// @param poolId The index of staking pool.
    /// @return Returns (success).
    function unstake(uint256 poolId, uint256 amount) external returns (bool);

    /// @notice Claim all rewards from staking pool.
    /// @param poolId The index of staking pool.
    /// @return Returns (success).
    function claimRewards(uint256 poolId) external returns (bool);

    /// @notice Unstake all staked share and claim all unclaimed rewards from staking pool.
    /// @param poolId The index of staking pool.
    /// @return Returns (success).
    function exit(uint256 poolId) external returns (bool);
}

/// @title IStakingTo Interface
/// @author Acala Developers
/// @notice You can use this integrate Acala LST staking into your contract.
interface IStakingTo is IStaking {
    /// @notice Stake share to other.
    /// @param poolId The index of staking pool.
    /// @param amount The share amount to stake.
    /// @param receiver The share receiver.
    /// @return Returns (success).
    function stakeTo(uint256 poolId, uint256 amount, address receiver) external returns (bool);
}

/// @title StableAssetStakeUtil Contract
/// @author Acala Developers
/// @notice Utilitity contract support batch these operation:
/// 1. mint StaleAsset LP token
/// 2. wrap LP token to Wrapped LP token
/// 3. stake Wrapped LP token to Euphrates pool
contract StableAssetStakeUtil {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    /// @notice The token address of Euphrates.
    IStakingTo public immutable euphrates;

    /// @notice The StableAsset predeploy contract address.
    IStableAsset public immutable stableAsset;

    /// @notice The Homa predeploy contract address.
    IHoma public immutable homa;

    /// @notice The LDOT token address.
    address public immutable ldot;

    /// @notice Deploys StableAssetStakeUtil contract.
    /// @param euphratesAddr The contract address of Euphrates.
    /// @param stableAssetAddr The contract address of StableAsset predeploy contract.
    /// @param homaAddr The contract address of Homa predeploy contract.
    /// @param ldotAddr The LDOT token address.
    constructor(address euphratesAddr, address stableAssetAddr, address homaAddr, address ldotAddr) {
        euphrates = IStakingTo(euphratesAddr);
        stableAsset = IStableAsset(stableAssetAddr);
        homa = IHoma(homaAddr);
        ldot = ldotAddr;
    }

    /// @notice Mint StalbeAsset LP token and stake it's wrapped token to Euphrates pool.
    /// @param stableAssetPoolId The id of StableAsset pool.
    /// @param assetsAmount The amounts of assets of StableAsset pool used to mint.
    /// @param stableAssetShareToken The LP token of StableAsset pool.
    /// @param wrappedShareToken The wrapper for StableAsset LP token.
    /// @param poolId The if of Euphrates pool.
    /// @return Returns (success).
    function mintAndStake(
        uint32 stableAssetPoolId,
        uint256[] memory assetsAmount,
        IERC20 stableAssetShareToken,
        IWrappedStableAssetShare wrappedShareToken,
        uint256 poolId
    ) public returns (bool) {
        // StableAsset check
        (bool valid, address[] memory assets) = stableAsset.getStableAssetPoolTokens(stableAssetPoolId);
        require(valid && assetsAmount.length == assets.length, "StableAssetStakeUtil: invalid stable asset pool");

        uint256[] memory paramAmounts = assetsAmount;
        // transfer assets from msg.sender
        for (uint256 i = 0; i < assets.length; i++) {
            if (assetsAmount[i] != 0) {
                IERC20(assets[i]).safeTransferFrom(msg.sender, address(this), assetsAmount[i]);
            }
            // convert LDOT amount to rebased LDOT amount as the param
            // NOTE: the precision of Homa.getExchangeRate is 1e18
            if (assets[i] == ldot) {
                paramAmounts[i] = assetsAmount[i].mul(homa.getExchangeRate()).div(1e18);
            }
        }

        // StableAsset mint, no need to approve assets to stable-asset
        uint256 beforeStableAssetShareAmount = IERC20(stableAssetShareToken).balanceOf(address(this));
        // NOTE: allow max slippage here
        bool success = stableAsset.stableAssetMint(stableAssetPoolId, paramAmounts, 0);
        require(success, "StableAssetStakeUtil: stable-asset mint failed");
        uint256 afterStableAssetShareAmount = IERC20(stableAssetShareToken).balanceOf(address(this));
        uint256 mintedShareAmount = afterStableAssetShareAmount.sub(beforeStableAssetShareAmount);
        require(mintedShareAmount != 0, "StableAssetStakeUtil: zero minted share amount is not allowed");

        // wrap share token
        stableAssetShareToken.safeApprove(address(wrappedShareToken), mintedShareAmount);
        uint256 wrappedShareAmount = wrappedShareToken.deposit(mintedShareAmount);
        require(wrappedShareAmount != 0, "StableAssetStakeUtil: zero wrapped share amount is not allowed");

        // stake wrapped share token to Euphrates pool
        IERC20(address(wrappedShareToken)).safeApprove(address(euphrates), wrappedShareAmount);
        return euphrates.stakeTo(poolId, wrappedShareAmount, msg.sender);
    }

    /// @notice Wrap StalbeAsset LP token and stake to Euphrates pool.
    /// @param stableAssetShareToken The LP token of StableAsset pool.
    /// @param amount The amount of LP token.
    /// @param wrappedShareToken The wrapper for StableAsset LP token.
    /// @param poolId The if of Euphrates pool.
    /// @return Returns (success).
    function wrapAndStake(
        IERC20 stableAssetShareToken,
        uint256 amount,
        IWrappedStableAssetShare wrappedShareToken,
        uint256 poolId
    ) public returns (bool) {
        require(amount != 0, "StableAssetStakeUtil: zero share amount is not allowed");
        stableAssetShareToken.safeTransferFrom(msg.sender, address(this), amount);
        stableAssetShareToken.safeApprove(address(wrappedShareToken), amount);
        uint256 wrappedShareAmount = wrappedShareToken.deposit(amount);
        require(wrappedShareAmount != 0, "StableAssetStakeUtil: zero wrapped share amount is not allowed");

        // stake wrapped share token to Euphrates pool
        IERC20(address(wrappedShareToken)).safeApprove(address(euphrates), wrappedShareAmount);
        return euphrates.stakeTo(poolId, wrappedShareAmount, msg.sender);
    }
}
        

Contract ABI

[{"type":"constructor","inputs":[{"type":"address","name":"euphratesAddr","internalType":"address"},{"type":"address","name":"stableAssetAddr","internalType":"address"},{"type":"address","name":"homaAddr","internalType":"address"},{"type":"address","name":"ldotAddr","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IStakingTo"}],"name":"euphrates","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IHoma"}],"name":"homa","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"ldot","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"mintAndStake","inputs":[{"type":"uint32","name":"stableAssetPoolId","internalType":"uint32"},{"type":"uint256[]","name":"assetsAmount","internalType":"uint256[]"},{"type":"address","name":"stableAssetShareToken","internalType":"contract IERC20"},{"type":"address","name":"wrappedShareToken","internalType":"contract IWrappedStableAssetShare"},{"type":"uint256","name":"poolId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IStableAsset"}],"name":"stableAsset","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"wrapAndStake","inputs":[{"type":"address","name":"stableAssetShareToken","internalType":"contract IERC20"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"address","name":"wrappedShareToken","internalType":"contract IWrappedStableAssetShare"},{"type":"uint256","name":"poolId","internalType":"uint256"}]}]
              

Contract Creation Code

Verify & Publish
0x6101006040523480156200001257600080fd5b506040516200139938038062001399833981016040819052620000359162000075565b6001600160a01b0393841660805291831660a052821660c0521660e052620000d2565b80516001600160a01b03811681146200007057600080fd5b919050565b600080600080608085870312156200008c57600080fd5b620000978562000058565b9350620000a76020860162000058565b9250620000b76040860162000058565b9150620000c76060860162000058565b905092959194509250565b60805160a05160c05160e051611258620001416000396000818161012101526102ec01526000818160d3015261034d01526000818160fa01528181610180015261049e015260008181606c0152818161073a0152818161078201528181610942015261098a01526112586000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c80631a7c38fc14610067578063543beaa2146100ab57806366940522146100ce5780636813f999146100f5578063aa0ea9921461011c578063be02e2da14610143575b600080fd5b61008e7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6100be6100b9366004610e4e565b610156565b60405190151581526020016100a2565b61008e7f000000000000000000000000000000000000000000000000000000000000000081565b61008e7f000000000000000000000000000000000000000000000000000000000000000081565b61008e7f000000000000000000000000000000000000000000000000000000000000000081565b6100be610151366004610f2b565b610809565b604051633ec3c3cd60e21b815263ffffffff86166004820152600090819081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fb0f0f3490602401600060405180830381865afa1580156101c7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526101ef9190810190610f83565b91509150818015610201575080518751145b61026a5760405162461bcd60e51b815260206004820152602f60248201527f537461626c6541737365745374616b655574696c3a20696e76616c696420737460448201526e18589b1948185cdcd95d081c1bdbdb608a1b60648201526084015b60405180910390fd5b8660005b825181101561042c5788818151811061028957610289611030565b60200260200101516000146102ea576102ea33308b84815181106102af576102af611030565b60200260200101518685815181106102c9576102c9611030565b60200260200101516001600160a01b0316610a0b909392919063ffffffff16565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031683828151811061032657610326611030565b60200260200101516001600160a01b03160361041a576103fb670de0b6b3a76400006103f57f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e6aa216c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103cd9190611046565b8c85815181106103df576103df611030565b6020026020010151610a7c90919063ffffffff16565b90610a91565b82828151811061040d5761040d611030565b6020026020010181815250505b8061042481611075565b91505061026e565b506040516370a0823160e01b81523060048201526000906001600160a01b038916906370a0823190602401602060405180830381865afa158015610474573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104989190611046565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ba510ad68c8560006040518463ffffffff1660e01b81526004016104ed9392919061108e565b6020604051808303816000875af115801561050c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061053091906110eb565b9050806105965760405162461bcd60e51b815260206004820152602e60248201527f537461626c6541737365745374616b655574696c3a20737461626c652d61737360448201526d195d081b5a5b9d0819985a5b195960921b6064820152608401610261565b6040516370a0823160e01b81523060048201526000906001600160a01b038b16906370a0823190602401602060405180830381865afa1580156105dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106019190611046565b9050600061060f8285610a9d565b9050806000036106875760405162461bcd60e51b815260206004820152603d60248201527f537461626c6541737365745374616b655574696c3a207a65726f206d696e746560448201527f6420736861726520616d6f756e74206973206e6f7420616c6c6f7765640000006064820152608401610261565b61069b6001600160a01b038c168b83610aa9565b60405163b6b55f2560e01b8152600481018290526000906001600160a01b038c169063b6b55f25906024016020604051808303816000875af11580156106e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107099190611046565b90508060000361072b5760405162461bcd60e51b815260040161026190611106565b61075f6001600160a01b038c167f000000000000000000000000000000000000000000000000000000000000000083610aa9565b60405163ebf4168760e01b8152600481018b9052602481018290523360448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063ebf41687906064016020604051808303816000875af11580156107d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107f791906110eb565b9e9d5050505050505050505050505050565b60008360000361087a5760405162461bcd60e51b815260206004820152603660248201527f537461626c6541737365745374616b655574696c3a207a65726f20736861726560448201527508185b5bdd5b9d081a5cc81b9bdd08185b1b1bddd95960521b6064820152608401610261565b61088f6001600160a01b038616333087610a0b565b6108a36001600160a01b0386168486610aa9565b60405163b6b55f2560e01b8152600481018590526000906001600160a01b0385169063b6b55f25906024016020604051808303816000875af11580156108ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109119190611046565b9050806000036109335760405162461bcd60e51b815260040161026190611106565b6109676001600160a01b0385167f000000000000000000000000000000000000000000000000000000000000000083610aa9565b60405163ebf4168760e01b815260048101849052602481018290523360448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063ebf41687906064016020604051808303816000875af11580156109db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ff91906110eb565b9150505b949350505050565b6040516001600160a01b0380851660248301528316604482015260648101829052610a769085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610bc3565b50505050565b6000610a888284611163565b90505b92915050565b6000610a88828461117a565b6000610a88828461119c565b801580610b235750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015610afd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b219190611046565b155b610b8e5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610261565b6040516001600160a01b038316602482015260448101829052610bbe90849063095ea7b360e01b90606401610a3f565b505050565b6000610c18826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610c989092919063ffffffff16565b9050805160001480610c39575080806020019051810190610c3991906110eb565b610bbe5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610261565b6060610a03848460008585600080866001600160a01b03168587604051610cbf91906111d3565b60006040518083038185875af1925050503d8060008114610cfc576040519150601f19603f3d011682016040523d82523d6000602084013e610d01565b606091505b5091509150610d1287838387610d1d565b979650505050505050565b60608315610d8c578251600003610d85576001600160a01b0385163b610d855760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610261565b5081610a03565b610a038383815115610da15781518083602001fd5b8060405162461bcd60e51b815260040161026191906111ef565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715610dfa57610dfa610dbb565b604052919050565b600067ffffffffffffffff821115610e1c57610e1c610dbb565b5060051b60200190565b6001600160a01b0381168114610e3b57600080fd5b50565b8035610e4981610e26565b919050565b600080600080600060a08688031215610e6657600080fd5b853563ffffffff81168114610e7a57600080fd5b945060208681013567ffffffffffffffff811115610e9757600080fd5b8701601f81018913610ea857600080fd5b8035610ebb610eb682610e02565b610dd1565b81815260059190911b8201830190838101908b831115610eda57600080fd5b928401925b82841015610ef857833582529284019290840190610edf565b8098505050505050610f0c60408701610e3e565b9250610f1a60608701610e3e565b949793965091946080013592915050565b60008060008060808587031215610f4157600080fd5b8435610f4c81610e26565b9350602085013592506040850135610f6381610e26565b9396929550929360600135925050565b80518015158114610e4957600080fd5b60008060408385031215610f9657600080fd5b610f9f83610f73565b915060208084015167ffffffffffffffff811115610fbc57600080fd5b8401601f81018613610fcd57600080fd5b8051610fdb610eb682610e02565b81815260059190911b82018301908381019088831115610ffa57600080fd5b928401925b8284101561102157835161101281610e26565b82529284019290840190610fff565b80955050505050509250929050565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561105857600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b6000600182016110875761108761105f565b5060010190565b60006060820163ffffffff861683526020606081850152818651808452608086019150828801935060005b818110156110d5578451835293830193918301916001016110b9565b5050809350505050826040830152949350505050565b6000602082840312156110fd57600080fd5b610a8882610f73565b6020808252603e908201527f537461626c6541737365745374616b655574696c3a207a65726f20777261707060408201527f656420736861726520616d6f756e74206973206e6f7420616c6c6f7765640000606082015260800190565b8082028115828204841417610a8b57610a8b61105f565b60008261119757634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115610a8b57610a8b61105f565b60005b838110156111ca5781810151838201526020016111b2565b50506000910152565b600082516111e58184602087016111af565b9190910192915050565b602081526000825180602084015261120e8160408501602087016111af565b601f01601f1916919091016040019291505056fea2646970667358221220aab4eab3382df0d016004c2dc1e2fb810688f8f52c1717c285efbd6d41dde2f764736f6c634300081100330000000000000000000000007fe92ec600f15cd25253b421bc151c51b0276b7d000000000000000000000000000000000000000000000000000000000000080400000000000000000000000000000000000000000000000000000000000008050000000000000000000000000000000000000000000100000000000000000003

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106100625760003560e01c80631a7c38fc14610067578063543beaa2146100ab57806366940522146100ce5780636813f999146100f5578063aa0ea9921461011c578063be02e2da14610143575b600080fd5b61008e7f0000000000000000000000007fe92ec600f15cd25253b421bc151c51b0276b7d81565b6040516001600160a01b0390911681526020015b60405180910390f35b6100be6100b9366004610e4e565b610156565b60405190151581526020016100a2565b61008e7f000000000000000000000000000000000000000000000000000000000000080581565b61008e7f000000000000000000000000000000000000000000000000000000000000080481565b61008e7f000000000000000000000000000000000000000000010000000000000000000381565b6100be610151366004610f2b565b610809565b604051633ec3c3cd60e21b815263ffffffff86166004820152600090819081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000804169063fb0f0f3490602401600060405180830381865afa1580156101c7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526101ef9190810190610f83565b91509150818015610201575080518751145b61026a5760405162461bcd60e51b815260206004820152602f60248201527f537461626c6541737365745374616b655574696c3a20696e76616c696420737460448201526e18589b1948185cdcd95d081c1bdbdb608a1b60648201526084015b60405180910390fd5b8660005b825181101561042c5788818151811061028957610289611030565b60200260200101516000146102ea576102ea33308b84815181106102af576102af611030565b60200260200101518685815181106102c9576102c9611030565b60200260200101516001600160a01b0316610a0b909392919063ffffffff16565b7f00000000000000000000000000000000000000000001000000000000000000036001600160a01b031683828151811061032657610326611030565b60200260200101516001600160a01b03160361041a576103fb670de0b6b3a76400006103f57f00000000000000000000000000000000000000000000000000000000000008056001600160a01b031663e6aa216c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103cd9190611046565b8c85815181106103df576103df611030565b6020026020010151610a7c90919063ffffffff16565b90610a91565b82828151811061040d5761040d611030565b6020026020010181815250505b8061042481611075565b91505061026e565b506040516370a0823160e01b81523060048201526000906001600160a01b038916906370a0823190602401602060405180830381865afa158015610474573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104989190611046565b905060007f00000000000000000000000000000000000000000000000000000000000008046001600160a01b031663ba510ad68c8560006040518463ffffffff1660e01b81526004016104ed9392919061108e565b6020604051808303816000875af115801561050c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061053091906110eb565b9050806105965760405162461bcd60e51b815260206004820152602e60248201527f537461626c6541737365745374616b655574696c3a20737461626c652d61737360448201526d195d081b5a5b9d0819985a5b195960921b6064820152608401610261565b6040516370a0823160e01b81523060048201526000906001600160a01b038b16906370a0823190602401602060405180830381865afa1580156105dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106019190611046565b9050600061060f8285610a9d565b9050806000036106875760405162461bcd60e51b815260206004820152603d60248201527f537461626c6541737365745374616b655574696c3a207a65726f206d696e746560448201527f6420736861726520616d6f756e74206973206e6f7420616c6c6f7765640000006064820152608401610261565b61069b6001600160a01b038c168b83610aa9565b60405163b6b55f2560e01b8152600481018290526000906001600160a01b038c169063b6b55f25906024016020604051808303816000875af11580156106e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107099190611046565b90508060000361072b5760405162461bcd60e51b815260040161026190611106565b61075f6001600160a01b038c167f0000000000000000000000007fe92ec600f15cd25253b421bc151c51b0276b7d83610aa9565b60405163ebf4168760e01b8152600481018b9052602481018290523360448201527f0000000000000000000000007fe92ec600f15cd25253b421bc151c51b0276b7d6001600160a01b03169063ebf41687906064016020604051808303816000875af11580156107d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107f791906110eb565b9e9d5050505050505050505050505050565b60008360000361087a5760405162461bcd60e51b815260206004820152603660248201527f537461626c6541737365745374616b655574696c3a207a65726f20736861726560448201527508185b5bdd5b9d081a5cc81b9bdd08185b1b1bddd95960521b6064820152608401610261565b61088f6001600160a01b038616333087610a0b565b6108a36001600160a01b0386168486610aa9565b60405163b6b55f2560e01b8152600481018590526000906001600160a01b0385169063b6b55f25906024016020604051808303816000875af11580156108ed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109119190611046565b9050806000036109335760405162461bcd60e51b815260040161026190611106565b6109676001600160a01b0385167f0000000000000000000000007fe92ec600f15cd25253b421bc151c51b0276b7d83610aa9565b60405163ebf4168760e01b815260048101849052602481018290523360448201527f0000000000000000000000007fe92ec600f15cd25253b421bc151c51b0276b7d6001600160a01b03169063ebf41687906064016020604051808303816000875af11580156109db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ff91906110eb565b9150505b949350505050565b6040516001600160a01b0380851660248301528316604482015260648101829052610a769085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610bc3565b50505050565b6000610a888284611163565b90505b92915050565b6000610a88828461117a565b6000610a88828461119c565b801580610b235750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015610afd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b219190611046565b155b610b8e5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610261565b6040516001600160a01b038316602482015260448101829052610bbe90849063095ea7b360e01b90606401610a3f565b505050565b6000610c18826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316610c989092919063ffffffff16565b9050805160001480610c39575080806020019051810190610c3991906110eb565b610bbe5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610261565b6060610a03848460008585600080866001600160a01b03168587604051610cbf91906111d3565b60006040518083038185875af1925050503d8060008114610cfc576040519150601f19603f3d011682016040523d82523d6000602084013e610d01565b606091505b5091509150610d1287838387610d1d565b979650505050505050565b60608315610d8c578251600003610d85576001600160a01b0385163b610d855760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610261565b5081610a03565b610a038383815115610da15781518083602001fd5b8060405162461bcd60e51b815260040161026191906111ef565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715610dfa57610dfa610dbb565b604052919050565b600067ffffffffffffffff821115610e1c57610e1c610dbb565b5060051b60200190565b6001600160a01b0381168114610e3b57600080fd5b50565b8035610e4981610e26565b919050565b600080600080600060a08688031215610e6657600080fd5b853563ffffffff81168114610e7a57600080fd5b945060208681013567ffffffffffffffff811115610e9757600080fd5b8701601f81018913610ea857600080fd5b8035610ebb610eb682610e02565b610dd1565b81815260059190911b8201830190838101908b831115610eda57600080fd5b928401925b82841015610ef857833582529284019290840190610edf565b8098505050505050610f0c60408701610e3e565b9250610f1a60608701610e3e565b949793965091946080013592915050565b60008060008060808587031215610f4157600080fd5b8435610f4c81610e26565b9350602085013592506040850135610f6381610e26565b9396929550929360600135925050565b80518015158114610e4957600080fd5b60008060408385031215610f9657600080fd5b610f9f83610f73565b915060208084015167ffffffffffffffff811115610fbc57600080fd5b8401601f81018613610fcd57600080fd5b8051610fdb610eb682610e02565b81815260059190911b82018301908381019088831115610ffa57600080fd5b928401925b8284101561102157835161101281610e26565b82529284019290840190610fff565b80955050505050509250929050565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561105857600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b6000600182016110875761108761105f565b5060010190565b60006060820163ffffffff861683526020606081850152818651808452608086019150828801935060005b818110156110d5578451835293830193918301916001016110b9565b5050809350505050826040830152949350505050565b6000602082840312156110fd57600080fd5b610a8882610f73565b6020808252603e908201527f537461626c6541737365745374616b655574696c3a207a65726f20777261707060408201527f656420736861726520616d6f756e74206973206e6f7420616c6c6f7765640000606082015260800190565b8082028115828204841417610a8b57610a8b61105f565b60008261119757634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115610a8b57610a8b61105f565b60005b838110156111ca5781810151838201526020016111b2565b50506000910152565b600082516111e58184602087016111af565b9190910192915050565b602081526000825180602084015261120e8160408501602087016111af565b601f01601f1916919091016040019291505056fea2646970667358221220aab4eab3382df0d016004c2dc1e2fb810688f8f52c1717c285efbd6d41dde2f764736f6c63430008110033