Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0xF43480afE9863da4AcBD4419A47D9Cc7d25A647F
Balance 0 ETH
Nonce 1
Code Size 6211 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

6211 bytes
0x608060405234801561001057600080fd5b506004361061014d5760003560e01c8063630b5ba1116100c3578063cf42947b1161007c578063cf42947b14610341578063d1c1b4a814610354578063e2bbb15814610367578063e30c39781461037a578063eaa6ef041461038d578063f4cd1b02146103a057600080fd5b8063630b5ba11461028457806378e979251461028c5780638da5cb5b146102b35780638dbb1e3a146102c657806393f1a40b146102d957806398ec8da61461032e57600080fd5b80633197cbb6116101155780633197cbb6146101df578063441a3e70146102045780634c2a860d146102175780634e71e0c81461025657806351eb05a61461025e5780635312ea8e1461027157600080fd5b8063078dfbe714610152578063081e3eda146101675780631526fe271461017e57806317caf6f1146101cd5780631b2e7d55146101d6575b600080fd5b6101656101603660046114f1565b6103b3565b005b6003545b6040519081526020015b60405180910390f35b61019161018c366004611584565b6104c0565b604080516001600160a01b03909616865260208601949094529284019190915263ffffffff16606083015261ffff16608082015260a001610175565b61016b60055481565b61016b60025481565b6006546101ef9063ffffffff1681565b60405163ffffffff9091168152602001610175565b61016561021236600461162b565b610518565b61023e7f000000000000000000000000090185f2135308bad17527004364ebcc2d37e5f681565b6040516001600160a01b039091168152602001610175565b6101656106d8565b61016561026c366004611584565b610795565b61016561027f366004611584565b6108ae565b610165610996565b6101ef7f0000000000000000000000000000000000000000000000000000000060b4ebe081565b60005461023e906001600160a01b031681565b61016b6102d436600461162b565b6109c1565b6103136102e73660046115b4565b600460209081526000928352604080842090915290825290208054600182015460029092015490919083565b60408051938452602084019290925290820152606001610175565b61016561033c366004611557565b610aa7565b61016561034f36600461164c565b610c82565b610165610362366004611607565b610ce8565b61016561037536600461162b565b610dd5565b60015461023e906001600160a01b031681565b61016561039b3660046115e3565b610f2c565b61016b6103ae3660046115b4565b610f6a565b6000546001600160a01b031633146103e65760405162461bcd60e51b81526004016103dd906116bf565b60405180910390fd5b811561049f576001600160a01b0383161515806104005750805b6104445760405162461bcd60e51b81526020600482015260156024820152744f776e61626c653a207a65726f206164647265737360581b60448201526064016103dd565b600080546040516001600160a01b03808716939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0385166001600160a01b0319909116179055505050565b600180546001600160a01b0319166001600160a01b0385161790555b505050565b600381815481106104d057600080fd5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b039092169350919063ffffffff811690640100000000900461ffff1685565b60006003838154811061053b57634e487b7160e01b600052603260045260246000fd5b60009182526020808320868452600480835260408086203387529093529190932080549290910290920192508311156105cc5760405162461bcd60e51b815260206004820152602d60248201527f536f7262657474696572653a20796f752063616e74206561742074686174206d60448201526c75636820706f707369636c657360981b60648201526084016103dd565b6105d584610795565b60008160020154826001015464e8d4a51000856002015485600001546105fb9190611754565b6106059190611734565b61060f9190611773565b61061991906116f4565b905061062533826110b5565b600283015581548490839060009061063e908490611773565b92505081905550838360010160008282546106599190611773565b90915550506002830154825464e8d4a510009161067591611754565b61067f9190611734565b6001830155825461069a906001600160a01b031633866111ed565b604051848152859033907ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b5689060200160405180910390a35050505050565b6001546001600160a01b03163381146107335760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c657220213d2070656e64696e67206f776e657260448201526064016103dd565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b039092166001600160a01b0319928316179055600180549091169055565b6000600382815481106107b857634e487b7160e01b600052603260045260246000fd5b60009182526020909120600490910201600381015490915063ffffffff1642116107e0575050565b600181015461080257600301805463ffffffff19164263ffffffff1617905550565b600381015460009061081a9063ffffffff16426109c1565b905060006005548360030160049054906101000a900461ffff1661ffff16600254846108469190611754565b6108509190611754565b61085a9190611734565b60018401549091506108718264e8d4a51000611754565b61087b9190611734565b83600201600082825461088e91906116f4565b90915550505050600301805463ffffffff19164263ffffffff1617905550565b6000600382815481106108d157634e487b7160e01b600052603260045260246000fd5b6000918252602080832085845260048083526040808620338752909352918420805493909202016001810180549195509193839291610911908490611773565b90915550506000848152600460209081526040808320338085529252822082815560018101839055600201919091558354610958916001600160a01b0390911690836111ed565b604051818152849033907fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae0595906020015b60405180910390a350505050565b60035460005b818110156109bd576109ad81610795565b6109b6816117b6565b905061099c565b5050565b60007f0000000000000000000000000000000000000000000000000000000060b4ebe063ffffffff168311610a1c577f0000000000000000000000000000000000000000000000000000000060b4ebe063ffffffff16610a1e565b825b60065490935063ffffffff16831180610a5c57507f0000000000000000000000000000000000000000000000000000000060b4ebe063ffffffff1682105b15610a6957506000610aa1565b60065463ffffffff16821115610a9457600654610a8d90849063ffffffff16611773565b9050610aa1565b610a9e8383611773565b90505b92915050565b6000546001600160a01b03163314610ad15760405162461bcd60e51b81526004016103dd906116bf565b8015610adf57610adf610996565b60007f0000000000000000000000000000000000000000000000000000000060b4ebe063ffffffff164211610b3a577f0000000000000000000000000000000000000000000000000000000060b4ebe063ffffffff16610b3c565b425b90508361ffff1660056000828254610b5491906116f4565b90915550506040805160a0810182526001600160a01b03948516815260006020820181815292820181815263ffffffff9485166060840190815261ffff98891660808501908152600380546001810182559452935160049093027fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b81018054949099166001600160a01b03199094169390931790975592517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c82015591517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85d83015593517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85e909101805494519095166401000000000265ffffffffffff199094169116179190911790915550565b6000546001600160a01b03163314610cac5760405162461bcd60e51b81526004016103dd906116bf565b60068054829190600090610cc790849063ffffffff1661170c565b92506101000a81548163ffffffff021916908363ffffffff16021790555050565b6000546001600160a01b03163314610d125760405162461bcd60e51b81526004016103dd906116bf565b8015610d2057610d20610996565b8161ffff1660038481548110610d4657634e487b7160e01b600052603260045260246000fd5b6000918252602090912060049091020160030154600554610d7391640100000000900461ffff1690611773565b610d7d91906116f4565b6005819055508160038481548110610da557634e487b7160e01b600052603260045260246000fd5b906000526020600020906004020160030160046101000a81548161ffff021916908361ffff160217905550505050565b600060038381548110610df857634e487b7160e01b600052603260045260246000fd5b60009182526020808320868452600480835260408086203387529093529190932091029091019150610e2984610795565b805415610e875760008160020154826001015464e8d4a5100085600201548560000154610e569190611754565b610e609190611734565b610e6a9190611773565b610e7491906116f4565b9050610e8033826110b5565b6002830155505b8154610e9e906001600160a01b0316333086611250565b82816000016000828254610eb291906116f4565b9250508190555082826001016000828254610ecd91906116f4565b90915550506002820154815464e8d4a5100091610ee991611754565b610ef39190611734565b6001820155604051838152849033907f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a1590602001610988565b6000546001600160a01b03163314610f565760405162461bcd60e51b81526004016103dd906116bf565b8015610f6457610f64610996565b50600255565b60008060038481548110610f8e57634e487b7160e01b600052603260045260246000fd5b60009182526020808320878452600480835260408086206001600160a01b038a168752909352919093209102909101600281015460038201549193509063ffffffff1642118015610fe25750600183015415155b1561106f576003830154600090610fff9063ffffffff16426109c1565b905060006005548560030160049054906101000a900461ffff1661ffff166002548461102b9190611754565b6110359190611754565b61103f9190611734565b60018601549091506110568264e8d4a51000611754565b6110609190611734565b61106a90846116f4565b925050505b60028201546001830154835464e8d4a510009061108d908590611754565b6110979190611734565b6110a19190611773565b6110ab91906116f4565b9695505050505050565b6040516370a0823160e01b815230600482015260009081906001600160a01b037f000000000000000000000000090185f2135308bad17527004364ebcc2d37e5f616906370a082319060240160206040518083038186803b15801561111957600080fd5b505afa15801561112d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611151919061159c565b9050806111615782915050610aa1565b808311156111af5761119d6001600160a01b037f000000000000000000000000090185f2135308bad17527004364ebcc2d37e5f61685836111ed565b6111a78184611773565b915050610aa1565b6111e36001600160a01b037f000000000000000000000000090185f2135308bad17527004364ebcc2d37e5f61685856111ed565b5060009392505050565b6040516001600160a01b0383166024820152604481018290526104bb90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261128e565b6040516001600160a01b03808516602483015283166044820152606481018290526112889085906323b872dd60e01b90608401611219565b50505050565b60006112e3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166113609092919063ffffffff16565b8051909150156104bb5780806020019051810190611301919061153b565b6104bb5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016103dd565b606061136f8484600085611379565b90505b9392505050565b6060824710156113da5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016103dd565b843b6114285760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016103dd565b600080866001600160a01b031685876040516114449190611670565b60006040518083038185875af1925050503d8060008114611481576040519150601f19603f3d011682016040523d82523d6000602084013e611486565b606091505b50915091506114968282866114a1565b979650505050505050565b606083156114b0575081611372565b8251156114c05782518084602001fd5b8160405162461bcd60e51b81526004016103dd919061168c565b803561ffff811681146114ec57600080fd5b919050565b600080600060608486031215611505578283fd5b8335611510816117e7565b92506020840135611520816117ff565b91506040840135611530816117ff565b809150509250925092565b60006020828403121561154c578081fd5b8151611372816117ff565b60008060006060848603121561156b578283fd5b611574846114da565b92506020840135611520816117e7565b600060208284031215611595578081fd5b5035919050565b6000602082840312156115ad578081fd5b5051919050565b600080604083850312156115c6578182fd5b8235915060208301356115d8816117e7565b809150509250929050565b600080604083850312156115f5578182fd5b8235915060208301356115d8816117ff565b60008060006060848603121561161b578283fd5b83359250611520602085016114da565b6000806040838503121561163d578182fd5b50508035926020909101359150565b60006020828403121561165d578081fd5b813563ffffffff81168114611372578182fd5b6000825161168281846020870161178a565b9190910192915050565b60208152600082518060208401526116ab81604085016020870161178a565b601f01601f19169190910160400192915050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60008219821115611707576117076117d1565b500190565b600063ffffffff80831681851680830382111561172b5761172b6117d1565b01949350505050565b60008261174f57634e487b7160e01b81526012600452602481fd5b500490565b600081600019048311821515161561176e5761176e6117d1565b500290565b600082821015611785576117856117d1565b500390565b60005b838110156117a557818101518382015260200161178d565b838111156112885750506000910152565b60006000198214156117ca576117ca6117d1565b5060010190565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b03811681146117fc57600080fd5b50565b80151581146117fc57600080fdfea264697066735822122062d572408b7c1682f0ff85808e121294d807ab44a5aa3841f467da362188e49b64736f6c63430008040033

Verified Source Code Full Match

Compiler: v0.8.4+commit.c7e474f2 EVM: istanbul Optimization: Yes (200 runs)
Sorbittire.sol 638 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @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
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 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://diligence.consensys.net/posts/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.5.11/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");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (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 functionCall(target, data, "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");
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return _verifyCallResult(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) {
        require(isContract(target), "Address: static call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(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) {
        require(isContract(target), "Address: delegate call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
        if (success) {
            return returndata;
        } else {
            // 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

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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 `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @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 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.
 */
contract OwnableData {
    address public owner;
    address public pendingOwner;
}

abstract contract Ownable is OwnableData {
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    constructor () {
        owner = msg.sender;
        emit OwnershipTransferred(address(0), msg.sender);
    }

    function transferOwnership(address newOwner, bool direct, bool renounce) public onlyOwner {
        if (direct) {

            require(newOwner != address(0) || renounce, "Ownable: zero address");

            emit OwnershipTransferred(owner, newOwner);
            owner = newOwner;
        } else {
            pendingOwner = newOwner;
        }
    }

    function claimOwnership() public {
        address _pendingOwner = pendingOwner;

        require(msg.sender == _pendingOwner, "Ownable: caller != pending owner");

        emit OwnershipTransferred(owner, _pendingOwner);
        owner = _pendingOwner;
        pendingOwner = address(0);
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Ownable: caller is not the owner");
        _;
    }
}

/**
 * @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;

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    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'
        // solhint-disable-next-line max-line-length
        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));
    }

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    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");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    /**
     * @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");
        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}
// Sorbettiere is a "semifredo of popsicle stand" this contract is created to provide single side farm for IFO of Popsicle Finance.
// The contract is based on famous Masterchef contract (Ty guys for that)
// It intakes one token and allows the user to farm another token. Due to the crosschain nature of Popsicle Stand we've swapped reward per block
// to reward per second. Moreover, we've implemented safe transfer of reward instead of mint in Masterchef.
// Future is crosschain...

// The contract is ownable untill the DAO will be able to take over. Popsicle community shows that DAO is coming soon.
// And the contract ownership will be transferred to other contract
contract Sorbettiere is Ownable {
    using SafeERC20 for IERC20;
    // Info of each user.
    struct UserInfo {
        uint256 amount; // How many LP tokens the user has provided.
        uint256 rewardDebt; // Reward debt. See explanation below.
        uint256 remainingIceTokenReward;  // ICE Tokens that weren't distributed for user per pool.
        //
        // We do some fancy math here. Basically, any point in time, the amount of ICE
        // entitled to a user but is pending to be distributed is:
        //
        //   pending reward = (user.amount * pool.accICEPerShare) - user.rewardDebt
        //
        // Whenever a user deposits or withdraws Staked tokens to a pool. Here's what happens:
        //   1. The pool's `accICEPerShare` (and `lastRewardTime`) gets updated.
        //   2. User receives the pending reward sent to his/her address.
        //   3. User's `amount` gets updated.
        //   4. User's `rewardDebt` gets updated.
    }
    // Info of each pool.
    struct PoolInfo {
        IERC20 stakingToken; // Contract address of staked token
        uint256 stakingTokenTotalAmount; //Total amount of deposited tokens
        uint256 accIcePerShare; // Accumulated ICE per share, times 1e12. See below.
        uint32 lastRewardTime; // Last timestamp number that ICE distribution occurs.
        uint16 allocPoint; // How many allocation points assigned to this pool. ICE to distribute per second.
        
        
    }
    
    IERC20 immutable public ice; // The ICE TOKEN!!
    
    uint256 public icePerSecond; // Ice tokens vested per second.
    
    PoolInfo[] public poolInfo; // Info of each pool.
    
    mapping(uint256 => mapping(address => UserInfo)) public userInfo; // Info of each user that stakes tokens.
    
    uint256 public totalAllocPoint = 0; // Total allocation poitns. Must be the sum of all allocation points in all pools.
    
    uint32 immutable public startTime; // The timestamp when ICE farming starts.
    
    uint32 public endTime; // Time on which the reward calculation should end

    event Deposit(address indexed user, uint256 indexed pid, uint256 amount);
    event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);
    event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount);

    constructor(
        IERC20 _ice,
        uint256 _icePerSecond,
        uint32 _startTime
    ) {
        ice = _ice;
        
        icePerSecond = _icePerSecond;
        startTime = _startTime;
        endTime = _startTime + 7 days;
    }
    
    function changeEndTime(uint32 addSeconds) external onlyOwner {
        endTime += addSeconds;
    }
    
    // Changes Ice token reward per second. Use this function to moderate the `lockup amount`. Essentially this function changes the amount of the reward
    // which is entitled to the user for his token staking by the time the `endTime` is passed.
    //Good practice to update pools without messing up the contract
    function setIcePerSecond(uint256 _icePerSecond,  bool _withUpdate) external onlyOwner {
        if (_withUpdate) {
            massUpdatePools();
        }
        icePerSecond= _icePerSecond;
    }
// How many pools are in the contract
    function poolLength() external view returns (uint256) {
        return poolInfo.length;
    }

    // Add a new staking token to the pool. Can only be called by the owner.
    // VERY IMPORTANT NOTICE 
    // ----------- DO NOT add the same staking token more than once. Rewards will be messed up if you do. -------------
    // Good practice to update pools without messing up the contract
    function add(
        uint16 _allocPoint,
        IERC20 _stakingToken,
        bool _withUpdate
    ) external onlyOwner {
        if (_withUpdate) {
            massUpdatePools();
        }
        uint256 lastRewardTime =
            block.timestamp > startTime ? block.timestamp : startTime;
        totalAllocPoint +=_allocPoint;
        poolInfo.push(
            PoolInfo({
                stakingToken: _stakingToken,
                stakingTokenTotalAmount: 0,
                allocPoint: _allocPoint,
                lastRewardTime: uint32(lastRewardTime),
                accIcePerShare: 0
            })
        );
    }

    // Update the given pool's ICE allocation point. Can only be called by the owner.
    // Good practice to update pools without messing up the contract
    function set(
        uint256 _pid,
        uint16 _allocPoint,
        bool _withUpdate
    ) external onlyOwner {
        if (_withUpdate) {
            massUpdatePools();
        }
        totalAllocPoint = totalAllocPoint - poolInfo[_pid].allocPoint + _allocPoint;
        poolInfo[_pid].allocPoint = _allocPoint;
    }

    // Return reward multiplier over the given _from to _to time.
    function getMultiplier(uint256 _from, uint256 _to)
        public
        view
        returns (uint256)
    {
        _from = _from > startTime ? _from : startTime;
        if (_from > endTime || _to < startTime) {
            return 0;
        }
        if (_to > endTime) {
            return endTime - _from;
        }
        return _to - _from;
    }

    // View function to see pending ICE on frontend.
    function pendingIce(uint256 _pid, address _user)
        external
        view
        returns (uint256)
    {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][_user];
        uint256 accIcePerShare = pool.accIcePerShare;
       
        if (block.timestamp > pool.lastRewardTime && pool.stakingTokenTotalAmount != 0) {
            uint256 multiplier =
                getMultiplier(pool.lastRewardTime, block.timestamp);
            uint256 iceReward =
                multiplier * icePerSecond * pool.allocPoint / totalAllocPoint;
            accIcePerShare += iceReward * 1e12 / pool.stakingTokenTotalAmount;
        }
        return user.amount * accIcePerShare / 1e12 - user.rewardDebt + user.remainingIceTokenReward;
    }

    // Update reward vairables for all pools. Be careful of gas spending!
    function massUpdatePools() public {
        uint256 length = poolInfo.length;
        for (uint256 pid = 0; pid < length; ++pid) {
            updatePool(pid);
        }
    }

    // Update reward variables of the given pool to be up-to-date.
    function updatePool(uint256 _pid) public {
        PoolInfo storage pool = poolInfo[_pid];
        if (block.timestamp <= pool.lastRewardTime) {
            return;
        }

        if (pool.stakingTokenTotalAmount == 0) {
            pool.lastRewardTime = uint32(block.timestamp);
            return;
        }
        uint256 multiplier = getMultiplier(pool.lastRewardTime, block.timestamp);
        uint256 iceReward =
            multiplier * icePerSecond * pool.allocPoint / totalAllocPoint;
        pool.accIcePerShare += iceReward * 1e12 / pool.stakingTokenTotalAmount;
        pool.lastRewardTime = uint32(block.timestamp);
    }

    // Deposit staking tokens to Sorbettiere for ICE allocation.
    function deposit(uint256 _pid, uint256 _amount) public {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][msg.sender];
        updatePool(_pid);
        if (user.amount > 0) {
            uint256 pending =
                user.amount * pool.accIcePerShare / 1e12 - user.rewardDebt + user.remainingIceTokenReward;
            user.remainingIceTokenReward = safeRewardTransfer(msg.sender, pending);
        }
        pool.stakingToken.safeTransferFrom(
            address(msg.sender),
            address(this),
            _amount
        );
        user.amount += _amount;
        pool.stakingTokenTotalAmount += _amount;
        user.rewardDebt = user.amount * pool.accIcePerShare / 1e12;
        emit Deposit(msg.sender, _pid, _amount);
    }

    // Withdraw staked tokens from Sorbettiere.
    function withdraw(uint256 _pid, uint256 _amount) public {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][msg.sender];
        require(user.amount >= _amount, "Sorbettiere: you cant eat that much popsicles");
        updatePool(_pid);
        uint256 pending =
            user.amount * pool.accIcePerShare / 1e12 - user.rewardDebt + user.remainingIceTokenReward;
        user.remainingIceTokenReward = safeRewardTransfer(msg.sender, pending);
        user.amount -= _amount;
        pool.stakingTokenTotalAmount -= _amount;
        user.rewardDebt = user.amount * pool.accIcePerShare / 1e12;
        pool.stakingToken.safeTransfer(address(msg.sender), _amount);
        emit Withdraw(msg.sender, _pid, _amount);
    }
    
    // Withdraw without caring about rewards. EMERGENCY ONLY.
    function emergencyWithdraw(uint256 _pid) public {
        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][msg.sender];
        uint256 userAmount = user.amount;
        pool.stakingTokenTotalAmount -= userAmount;
        delete userInfo[_pid][msg.sender];
        pool.stakingToken.safeTransfer(address(msg.sender), userAmount);
        emit EmergencyWithdraw(msg.sender, _pid, userAmount);
    }

    // Safe ice transfer function. Just in case if the pool does not have enough ICE token,
    // The function returns the amount which is owed to the user
    function safeRewardTransfer(address _to, uint256 _amount) internal returns(uint256) {
        uint256 iceTokenBalance = ice.balanceOf(address(this));
        if (iceTokenBalance == 0) { //save some gas fee
            return _amount;
        }
        if (_amount > iceTokenBalance) { //save some gas fee
            ice.safeTransfer(_to, iceTokenBalance);
            return _amount - iceTokenBalance;
        }
        ice.safeTransfer(_to, _amount);
        return 0;
    }
}

Read Contract

endTime 0x3197cbb6 → uint32
getMultiplier 0x8dbb1e3a → uint256
ice 0x4c2a860d → address
icePerSecond 0x1b2e7d55 → uint256
owner 0x8da5cb5b → address
pendingIce 0xf4cd1b02 → uint256
pendingOwner 0xe30c3978 → address
poolInfo 0x1526fe27 → address, uint256, uint256, uint32, uint16
poolLength 0x081e3eda → uint256
startTime 0x78e97925 → uint32
totalAllocPoint 0x17caf6f1 → uint256
userInfo 0x93f1a40b → uint256, uint256, uint256

Write Contract 11 functions

These functions modify contract state and require a wallet transaction to execute.

add 0x98ec8da6
uint16 _allocPoint
address _stakingToken
bool _withUpdate
changeEndTime 0xcf42947b
uint32 addSeconds
claimOwnership 0x4e71e0c8
No parameters
deposit 0xe2bbb158
uint256 _pid
uint256 _amount
emergencyWithdraw 0x5312ea8e
uint256 _pid
massUpdatePools 0x630b5ba1
No parameters
set 0xd1c1b4a8
uint256 _pid
uint16 _allocPoint
bool _withUpdate
setIcePerSecond 0xeaa6ef04
uint256 _icePerSecond
bool _withUpdate
transferOwnership 0x078dfbe7
address newOwner
bool direct
bool renounce
updatePool 0x51eb05a6
uint256 _pid
withdraw 0x441a3e70
uint256 _pid
uint256 _amount

Recent Transactions

No transactions found for this address