LiFiClaimer

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "@mimic-fi/v3-authorizer/contracts/Authorized.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity ^0.8.17;

import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';

import './AuthorizedHelpers.sol';
import './interfaces/IAuthorized.sol';
import './interfaces/IAuthorizer.sol';

/**
 * @title Authorized
 * @dev Implementation using an authorizer as its access-control mechanism. It offers `auth` and `authP` modifiers to
 * tag its own functions in order to control who can access them against the authorizer referenced.
 */
contract Authorized is IAuthorized, Initializable, AuthorizedHelpers {
    // Authorizer reference
    address public override authorizer;

    /**
     * @dev Modifier that should be used to tag protected functions
     */
    modifier auth() {
        _authenticate(msg.sender, msg.sig);
        _;
    }

    /**
     * @dev Modifier that should be used to tag protected functions with params
     */
    modifier authP(uint256[] memory params) {
        _authenticate(msg.sender, msg.sig, params);
        _;
    }

    /**
     * @dev Creates a new authorized contract. Note that initializers are disabled at creation time.
     */
    constructor() {
        _disableInitializers();
    }

    /**
     * @dev Initializes the authorized contract. It does call upper contracts initializers.
     * @param _authorizer Address of the authorizer to be set
     */
    function __Authorized_init(address _authorizer) internal onlyInitializing {
        __Authorized_init_unchained(_authorizer);
    }

    /**
     * @dev Initializes the authorized contract. It does not call upper contracts initializers.
     * @param _authorizer Address of the authorizer to be set
     */
    function __Authorized_init_unchained(address _authorizer) internal onlyInitializing {
        authorizer = _authorizer;
    }

    /**
     * @dev Reverts if `who` is not allowed to call `what`
     * @param who Address to be authenticated
     * @param what Function selector to be authenticated
     */
    function _authenticate(address who, bytes4 what) internal view {
        _authenticate(who, what, new uint256[](0));
    }

    /**
     * @dev Reverts if `who` is not allowed to call `what` with `how`
     * @param who Address to be authenticated
     * @param what Function selector to be authenticated
     * @param how Params to be authenticated
     */
    function _authenticate(address who, bytes4 what, uint256[] memory how) internal view {
        if (!_isAuthorized(who, what, how)) revert AuthSenderNotAllowed(who, what, how);
    }

    /**
     * @dev Tells whether `who` has any permission on this contract
     * @param who Address asking permissions for
     */
    function _hasPermissions(address who) internal view returns (bool) {
        return IAuthorizer(authorizer).hasPermissions(who, address(this));
    }

    /**
     * @dev Tells whether `who` is allowed to call `what`
     * @param who Address asking permission for
     * @param what Function selector asking permission for
     */
    function _isAuthorized(address who, bytes4 what) internal view returns (bool) {
        return _isAuthorized(who, what, new uint256[](0));
    }

    /**
     * @dev Tells whether `who` is allowed to call `what` with `how`
     * @param who Address asking permission for
     * @param what Function selector asking permission for
     * @param how Params asking permission for
     */
    function _isAuthorized(address who, bytes4 what, uint256[] memory how) internal view returns (bool) {
        return IAuthorizer(authorizer).isAuthorized(who, address(this), what, how);
    }
}
"
    },
    "@mimic-fi/v3-authorizer/contracts/AuthorizedHelpers.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity ^0.8.17;

/**
 * @title AuthorizedHelpers
 * @dev Syntax sugar methods to operate with authorizer params easily
 */
contract AuthorizedHelpers {
    function authParams(address p1) internal pure returns (uint256[] memory r) {
        return authParams(uint256(uint160(p1)));
    }

    function authParams(bytes32 p1) internal pure returns (uint256[] memory r) {
        return authParams(uint256(p1));
    }

    function authParams(uint256 p1) internal pure returns (uint256[] memory r) {
        r = new uint256[](1);
        r[0] = p1;
    }

    function authParams(address p1, bool p2) internal pure returns (uint256[] memory r) {
        r = new uint256[](2);
        r[0] = uint256(uint160(p1));
        r[1] = p2 ? 1 : 0;
    }

    function authParams(address p1, uint256 p2) internal pure returns (uint256[] memory r) {
        r = new uint256[](2);
        r[0] = uint256(uint160(p1));
        r[1] = p2;
    }

    function authParams(address p1, address p2) internal pure returns (uint256[] memory r) {
        r = new uint256[](2);
        r[0] = uint256(uint160(p1));
        r[1] = uint256(uint160(p2));
    }

    function authParams(bytes32 p1, bytes32 p2) internal pure returns (uint256[] memory r) {
        r = new uint256[](2);
        r[0] = uint256(p1);
        r[1] = uint256(p2);
    }

    function authParams(address p1, address p2, uint256 p3) internal pure returns (uint256[] memory r) {
        r = new uint256[](3);
        r[0] = uint256(uint160(p1));
        r[1] = uint256(uint160(p2));
        r[2] = p3;
    }

    function authParams(address p1, address p2, address p3) internal pure returns (uint256[] memory r) {
        r = new uint256[](3);
        r[0] = uint256(uint160(p1));
        r[1] = uint256(uint160(p2));
        r[2] = uint256(uint160(p3));
    }

    function authParams(address p1, address p2, bytes4 p3) internal pure returns (uint256[] memory r) {
        r = new uint256[](3);
        r[0] = uint256(uint160(p1));
        r[1] = uint256(uint160(p2));
        r[2] = uint256(uint32(p3));
    }

    function authParams(address p1, uint256 p2, uint256 p3) internal pure returns (uint256[] memory r) {
        r = new uint256[](3);
        r[0] = uint256(uint160(p1));
        r[1] = p2;
        r[2] = p3;
    }

    function authParams(uint256 p1, uint256 p2, uint256 p3, uint256 p4) internal pure returns (uint256[] memory r) {
        r = new uint256[](4);
        r[0] = p1;
        r[1] = p2;
        r[2] = p3;
        r[3] = p4;
    }

    function authParams(address p1, address p2, uint256 p3, uint256 p4) internal pure returns (uint256[] memory r) {
        r = new uint256[](4);
        r[0] = uint256(uint160(p1));
        r[1] = uint256(uint160(p2));
        r[2] = p3;
        r[3] = p4;
    }

    function authParams(address p1, uint256 p2, uint256 p3, uint256 p4) internal pure returns (uint256[] memory r) {
        r = new uint256[](4);
        r[0] = uint256(uint160(p1));
        r[1] = p2;
        r[2] = p3;
        r[3] = p4;
    }

    function authParams(bytes32 p1, address p2, uint256 p3, bool p4) internal pure returns (uint256[] memory r) {
        r = new uint256[](4);
        r[0] = uint256(p1);
        r[1] = uint256(uint160(p2));
        r[2] = p3;
        r[3] = p4 ? 1 : 0;
    }

    function authParams(address p1, uint256 p2, uint256 p3, uint256 p4, uint256 p5)
        internal
        pure
        returns (uint256[] memory r)
    {
        r = new uint256[](5);
        r[0] = uint256(uint160(p1));
        r[1] = p2;
        r[2] = p3;
        r[3] = p4;
        r[4] = p5;
    }
}
"
    },
    "@mimic-fi/v3-authorizer/contracts/interfaces/IAuthorized.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity >=0.8.0;

/**
 * @dev Authorized interface
 */
interface IAuthorized {
    /**
     * @dev Sender `who` is not allowed to call `what` with `how`
     */
    error AuthSenderNotAllowed(address who, bytes4 what, uint256[] how);

    /**
     * @dev Tells the address of the authorizer reference
     */
    function authorizer() external view returns (address);
}
"
    },
    "@mimic-fi/v3-authorizer/contracts/interfaces/IAuthorizer.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity >=0.8.0;

/**
 * @dev Authorizer interface
 */
interface IAuthorizer {
    /**
     * @dev Permission change
     * @param where Address of the contract to change a permission for
     * @param changes List of permission changes to be executed
     */
    struct PermissionChange {
        address where;
        GrantPermission[] grants;
        RevokePermission[] revokes;
    }

    /**
     * @dev Grant permission data
     * @param who Address to be authorized
     * @param what Function selector to be authorized
     * @param params List of params to restrict the given permission
     */
    struct GrantPermission {
        address who;
        bytes4 what;
        Param[] params;
    }

    /**
     * @dev Revoke permission data
     * @param who Address to be unauthorized
     * @param what Function selector to be unauthorized
     */
    struct RevokePermission {
        address who;
        bytes4 what;
    }

    /**
     * @dev Params used to validate permissions params against
     * @param op ID of the operation to compute in order to validate a permission param
     * @param value Comparison value
     */
    struct Param {
        uint8 op;
        uint248 value;
    }

    /**
     * @dev Sender is not authorized to call `what` on `where` with `how`
     */
    error AuthorizerSenderNotAllowed(address who, address where, bytes4 what, uint256[] how);

    /**
     * @dev The operation param is invalid
     */
    error AuthorizerInvalidParamOp(uint8 op);

    /**
     * @dev Emitted every time `who`'s permission to perform `what` on `where` is granted with `params`
     */
    event Authorized(address indexed who, address indexed where, bytes4 indexed what, Param[] params);

    /**
     * @dev Emitted every time `who`'s permission to perform `what` on `where` is revoked
     */
    event Unauthorized(address indexed who, address indexed where, bytes4 indexed what);

    /**
     * @dev Tells whether `who` has any permission on `where`
     * @param who Address asking permission for
     * @param where Target address asking permission for
     */
    function hasPermissions(address who, address where) external view returns (bool);

    /**
     * @dev Tells the number of permissions `who` has on `where`
     * @param who Address asking permission for
     * @param where Target address asking permission for
     */
    function getPermissionsLength(address who, address where) external view returns (uint256);

    /**
     * @dev Tells whether `who` has permission to call `what` on `where`. Note `how` is not evaluated here,
     * which means `who` might be authorized on or not depending on the call at the moment of the execution
     * @param who Address asking permission for
     * @param where Target address asking permission for
     * @param what Function selector asking permission for
     */
    function hasPermission(address who, address where, bytes4 what) external view returns (bool);

    /**
     * @dev Tells whether `who` is allowed to call `what` on `where` with `how`
     * @param who Address asking permission for
     * @param where Target address asking permission for
     * @param what Function selector asking permission for
     * @param how Params asking permission for
     */
    function isAuthorized(address who, address where, bytes4 what, uint256[] memory how) external view returns (bool);

    /**
     * @dev Tells the params set for a given permission
     * @param who Address asking permission params of
     * @param where Target address asking permission params of
     * @param what Function selector asking permission params of
     */
    function getPermissionParams(address who, address where, bytes4 what) external view returns (Param[] memory);

    /**
     * @dev Executes a list of permission changes
     * @param changes List of permission changes to be executed
     */
    function changePermissions(PermissionChange[] memory changes) external;

    /**
     * @dev Authorizes `who` to call `what` on `where` restricted by `params`
     * @param who Address to be authorized
     * @param where Target address to be granted for
     * @param what Function selector to be granted
     * @param params Optional params to restrict a permission attempt
     */
    function authorize(address who, address where, bytes4 what, Param[] memory params) external;

    /**
     * @dev Unauthorizes `who` to call `what` on `where`. Sender must be authorized.
     * @param who Address to be authorized
     * @param where Target address to be revoked for
     * @param what Function selector to be revoked
     */
    function unauthorize(address who, address where, bytes4 what) external;
}
"
    },
    "@mimic-fi/v3-helpers/contracts/math/FixedPoint.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity ^0.8.0;

/**
 * @title FixedPoint
 * @dev Math library to operate with fixed point values with 18 decimals
 */
library FixedPoint {
    // 1 in fixed point value: 18 decimal places
    uint256 internal constant ONE = 1e18;

    /**
     * @dev Multiplication overflow
     */
    error FixedPointMulOverflow(uint256 a, uint256 b);

    /**
     * @dev Division by zero
     */
    error FixedPointZeroDivision();

    /**
     * @dev Division internal error
     */
    error FixedPointDivInternal(uint256 a, uint256 aInflated);

    /**
     * @dev Multiplies two fixed point numbers rounding down
     */
    function mulDown(uint256 a, uint256 b) internal pure returns (uint256) {
        unchecked {
            uint256 product = a * b;
            if (a != 0 && product / a != b) revert FixedPointMulOverflow(a, b);
            return product / ONE;
        }
    }

    /**
     * @dev Multiplies two fixed point numbers rounding up
     */
    function mulUp(uint256 a, uint256 b) internal pure returns (uint256) {
        unchecked {
            uint256 product = a * b;
            if (a != 0 && product / a != b) revert FixedPointMulOverflow(a, b);
            return product == 0 ? 0 : (((product - 1) / ONE) + 1);
        }
    }

    /**
     * @dev Divides two fixed point numbers rounding down
     */
    function divDown(uint256 a, uint256 b) internal pure returns (uint256) {
        unchecked {
            if (b == 0) revert FixedPointZeroDivision();
            if (a == 0) return 0;
            uint256 aInflated = a * ONE;
            if (aInflated / a != ONE) revert FixedPointDivInternal(a, aInflated);
            return aInflated / b;
        }
    }

    /**
     * @dev Divides two fixed point numbers rounding up
     */
    function divUp(uint256 a, uint256 b) internal pure returns (uint256) {
        unchecked {
            if (b == 0) revert FixedPointZeroDivision();
            if (a == 0) return 0;
            uint256 aInflated = a * ONE;
            if (aInflated / a != ONE) revert FixedPointDivInternal(a, aInflated);
            return ((aInflated - 1) / b) + 1;
        }
    }
}
"
    },
    "@mimic-fi/v3-helpers/contracts/utils/Denominations.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity ^0.8.0;

/**
 * @title Denominations
 * @dev Provides a list of ground denominations for those tokens that cannot be represented by an ERC20.
 * For now, the only needed is the native token that could be ETH, MATIC, or other depending on the layer being operated.
 */
library Denominations {
    address internal constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

    // Fiat currencies follow https://en.wikipedia.org/wiki/ISO_4217
    address internal constant USD = address(840);

    function isNativeToken(address token) internal pure returns (bool) {
        return token == NATIVE_TOKEN;
    }
}
"
    },
    "@mimic-fi/v3-price-oracle/contracts/interfaces/IPriceOracle.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity >=0.8.0;

import '@mimic-fi/v3-authorizer/contracts/interfaces/IAuthorized.sol';

/**
 * @title IPriceOracle
 * @dev Price oracle interface
 *
 * Tells the price of a token (base) in a given quote based the following rule: the response is expressed using the
 * corresponding number of decimals so that when performing a fixed point product of it by a `base` amount it results
 * in a value expressed in `quote` decimals. For example, if `base` is ETH and `quote` is USDC, then the returned
 * value is expected to be expressed using 6 decimals:
 *
 * FixedPoint.mul(X[ETH], price[USDC/ETH]) = FixedPoint.mul(X[18], price[6]) = X * price [6]
 */
interface IPriceOracle is IAuthorized {
    /**
     * @dev Price data
     * @param base Token to rate
     * @param quote Token used for the price rate
     * @param rate Price of a token (base) expressed in `quote`
     * @param deadline Expiration timestamp until when the given quote is considered valid
     */
    struct PriceData {
        address base;
        address quote;
        uint256 rate;
        uint256 deadline;
    }

    /**
     * @dev The signer is not allowed
     */
    error PriceOracleInvalidSigner(address signer);

    /**
     * @dev The feed for the given (base, quote) pair doesn't exist
     */
    error PriceOracleMissingFeed(address base, address quote);

    /**
     * @dev The price deadline is in the past
     */
    error PriceOracleOutdatedPrice(address base, address quote, uint256 deadline, uint256 currentTimestamp);

    /**
     * @dev The base decimals are bigger than the quote decimals plus the fixed point decimals
     */
    error PriceOracleBaseDecimalsTooBig(address base, uint256 baseDecimals, address quote, uint256 quoteDecimals);

    /**
     * @dev The inverse feed decimals are bigger than the maximum inverse feed decimals
     */
    error PriceOracleInverseFeedDecimalsTooBig(address inverseFeed, uint256 inverseFeedDecimals);

    /**
     * @dev The quote feed decimals are bigger than the base feed decimals plus the fixed point decimals
     */
    error PriceOracleQuoteFeedDecimalsTooBig(uint256 quoteFeedDecimals, uint256 baseFeedDecimals);

    /**
     * @dev Emitted every time a signer is changed
     */
    event SignerSet(address indexed signer, bool allowed);

    /**
     * @dev Emitted every time a feed is set for (base, quote) pair
     */
    event FeedSet(address indexed base, address indexed quote, address feed);

    /**
     * @dev Tells whether an address is as an allowed signer or not
     * @param signer Address of the signer being queried
     */
    function isSignerAllowed(address signer) external view returns (bool);

    /**
     * @dev Tells the list of allowed signers
     */
    function getAllowedSigners() external view returns (address[] memory);

    /**
     * @dev Tells the digest expected to be signed by the off-chain oracle signers for a list of prices
     * @param prices List of prices to be signed
     */
    function getPricesDigest(PriceData[] memory prices) external view returns (bytes32);

    /**
     * @dev Tells the price of a token `base` expressed in a token `quote`
     * @param base Token to rate
     * @param quote Token used for the price rate
     */
    function getPrice(address base, address quote) external view returns (uint256);

    /**
     * @dev Tells the price of a token `base` expressed in a token `quote`
     * @param base Token to rate
     * @param quote Token used for the price rate
     * @param data Encoded data to validate in order to compute the requested rate
     */
    function getPrice(address base, address quote, bytes memory data) external view returns (uint256);

    /**
     * @dev Tells the feed address for (base, quote) pair. It returns the zero address if there is no one set.
     * @param base Token to be rated
     * @param quote Token used for the price rate
     */
    function getFeed(address base, address quote) external view returns (address);

    /**
     * @dev Sets a signer condition
     * @param signer Address of the signer to be set
     * @param allowed Whether the requested signer is allowed
     */
    function setSigner(address signer, bool allowed) external;

    /**
     * @dev Sets a feed for a (base, quote) pair
     * @param base Token base to be set
     * @param quote Token quote to be set
     * @param feed Feed to be set
     */
    function setFeed(address base, address quote, address feed) external;
}
"
    },
    "@mimic-fi/v3-smart-vault/contracts/interfaces/ISmartVault.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity >=0.8.0;

import '@mimic-fi/v3-authorizer/contracts/interfaces/IAuthorized.sol';

/**
 * @dev Smart Vault interface
 */
interface ISmartVault is IAuthorized {
    /**
     * @dev The smart vault is paused
     */
    error SmartVaultPaused();

    /**
     * @dev The smart vault is unpaused
     */
    error SmartVaultUnpaused();

    /**
     * @dev The token is zero
     */
    error SmartVaultTokenZero();

    /**
     * @dev The amount is zero
     */
    error SmartVaultAmountZero();

    /**
     * @dev The recipient is zero
     */
    error SmartVaultRecipientZero();

    /**
     * @dev The connector is deprecated
     */
    error SmartVaultConnectorDeprecated(address connector);

    /**
     * @dev The connector is not registered
     */
    error SmartVaultConnectorNotRegistered(address connector);

    /**
     * @dev The connector is not stateless
     */
    error SmartVaultConnectorNotStateless(address connector);

    /**
     * @dev The connector ID is zero
     */
    error SmartVaultBalanceConnectorIdZero();

    /**
     * @dev The balance connector's balance is lower than the requested amount to be deducted
     */
    error SmartVaultBalanceConnectorInsufficientBalance(bytes32 id, address token, uint256 balance, uint256 amount);

    /**
     * @dev The smart vault's native token balance is lower than the requested amount to be deducted
     */
    error SmartVaultInsufficientNativeTokenBalance(uint256 balance, uint256 amount);

    /**
     * @dev Emitted every time a smart vault is paused
     */
    event Paused();

    /**
     * @dev Emitted every time a smart vault is unpaused
     */
    event Unpaused();

    /**
     * @dev Emitted every time the price oracle is set
     */
    event PriceOracleSet(address indexed priceOracle);

    /**
     * @dev Emitted every time a connector check is overridden
     */
    event ConnectorCheckOverridden(address indexed connector, bool ignored);

    /**
     * @dev Emitted every time a balance connector is updated
     */
    event BalanceConnectorUpdated(bytes32 indexed id, address indexed token, uint256 amount, bool added);

    /**
     * @dev Emitted every time `execute` is called
     */
    event Executed(address indexed connector, bytes data, bytes result);

    /**
     * @dev Emitted every time `call` is called
     */
    event Called(address indexed target, bytes data, uint256 value, bytes result);

    /**
     * @dev Emitted every time `wrap` is called
     */
    event Wrapped(uint256 amount);

    /**
     * @dev Emitted every time `unwrap` is called
     */
    event Unwrapped(uint256 amount);

    /**
     * @dev Emitted every time `collect` is called
     */
    event Collected(address indexed token, address indexed from, uint256 amount);

    /**
     * @dev Emitted every time `withdraw` is called
     */
    event Withdrawn(address indexed token, address indexed recipient, uint256 amount, uint256 fee);

    /**
     * @dev Tells if the smart vault is paused or not
     */
    function isPaused() external view returns (bool);

    /**
     * @dev Tells the address of the price oracle
     */
    function priceOracle() external view returns (address);

    /**
     * @dev Tells the address of the Mimic's registry
     */
    function registry() external view returns (address);

    /**
     * @dev Tells the address of the Mimic's fee controller
     */
    function feeController() external view returns (address);

    /**
     * @dev Tells the address of the wrapped native token
     */
    function wrappedNativeToken() external view returns (address);

    /**
     * @dev Tells if a connector check is ignored
     * @param connector Address of the connector being queried
     */
    function isConnectorCheckIgnored(address connector) external view returns (bool);

    /**
     * @dev Tells the balance to a balance connector for a token
     * @param id Balance connector identifier
     * @param token Address of the token querying the balance connector for
     */
    function getBalanceConnector(bytes32 id, address token) external view returns (uint256);

    /**
     * @dev Tells whether someone has any permission over the smart vault
     */
    function hasPermissions(address who) external view returns (bool);

    /**
     * @dev Pauses a smart vault
     */
    function pause() external;

    /**
     * @dev Unpauses a smart vault
     */
    function unpause() external;

    /**
     * @dev Sets the price oracle
     * @param newPriceOracle Address of the new price oracle to be set
     */
    function setPriceOracle(address newPriceOracle) external;

    /**
     * @dev Overrides connector checks
     * @param connector Address of the connector to override its check
     * @param ignored Whether the connector check should be ignored
     */
    function overrideConnectorCheck(address connector, bool ignored) external;

    /**
     * @dev Updates a balance connector
     * @param id Balance connector identifier to be updated
     * @param token Address of the token to update the balance connector for
     * @param amount Amount to be updated to the balance connector
     * @param add Whether the balance connector should be increased or decreased
     */
    function updateBalanceConnector(bytes32 id, address token, uint256 amount, bool add) external;

    /**
     * @dev Executes a connector inside of the Smart Vault context
     * @param connector Address of the connector that will be executed
     * @param data Call data to be used for the delegate-call
     * @return result Call response if it was successful, otherwise it reverts
     */
    function execute(address connector, bytes memory data) external returns (bytes memory result);

    /**
     * @dev Executes an arbitrary call from the Smart Vault
     * @param target Address where the call will be sent
     * @param data Call data to be used for the call
     * @param value Value in wei that will be attached to the call
     * @return result Call response if it was successful, otherwise it reverts
     */
    function call(address target, bytes memory data, uint256 value) external returns (bytes memory result);

    /**
     * @dev Wrap an amount of native tokens to the wrapped ERC20 version of it
     * @param amount Amount of native tokens to be wrapped
     */
    function wrap(uint256 amount) external;

    /**
     * @dev Unwrap an amount of wrapped native tokens
     * @param amount Amount of wrapped native tokens to unwrapped
     */
    function unwrap(uint256 amount) external;

    /**
     * @dev Collect tokens from an external account to the Smart Vault
     * @param token Address of the token to be collected
     * @param from Address where the tokens will be transferred from
     * @param amount Amount of tokens to be transferred
     */
    function collect(address token, address from, uint256 amount) external;

    /**
     * @dev Withdraw tokens to an external account
     * @param token Address of the token to be withdrawn
     * @param recipient Address where the tokens will be transferred to
     * @param amount Amount of tokens to withdraw
     */
    function withdraw(address token, address recipient, uint256 amount) external;
}
"
    },
    "@mimic-fi/v3-tasks/contracts/base/BaseTask.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity ^0.8.0;

import '@mimic-fi/v3-authorizer/contracts/Authorized.sol';
import '@mimic-fi/v3-helpers/contracts/math/FixedPoint.sol';
import '@mimic-fi/v3-helpers/contracts/utils/Denominations.sol';
import '@mimic-fi/v3-price-oracle/contracts/interfaces/IPriceOracle.sol';
import '@mimic-fi/v3-smart-vault/contracts/interfaces/ISmartVault.sol';

import '../interfaces/base/IBaseTask.sol';

/**
 * @title BaseTask
 * @dev Base task implementation with a Smart Vault reference and using the Authorizer
 */
abstract contract BaseTask is IBaseTask, Authorized {
    // Smart Vault reference
    address public override smartVault;

    // Optional balance connector id for the previous task in the workflow
    bytes32 internal previousBalanceConnectorId;

    // Optional balance connector id for the next task in the workflow
    bytes32 internal nextBalanceConnectorId;

    /**
     * @dev Base task config. Only used in the initializer.
     * @param smartVault Address of the smart vault this task will reference, it cannot be changed once set
     * @param previousBalanceConnectorId Balance connector id for the previous task in the workflow
     * @param nextBalanceConnectorId Balance connector id for the next task in the workflow
     */
    struct BaseConfig {
        address smartVault;
        bytes32 previousBalanceConnectorId;
        bytes32 nextBalanceConnectorId;
    }

    /**
     * @dev Initializes the base task. It does call upper contracts initializers.
     * @param config Base task config
     */
    function __BaseTask_init(BaseConfig memory config) internal onlyInitializing {
        __Authorized_init(ISmartVault(config.smartVault).authorizer());
        __BaseTask_init_unchained(config);
    }

    /**
     * @dev Initializes the base task. It does not call upper contracts initializers.
     * @param config Base task config
     */
    function __BaseTask_init_unchained(BaseConfig memory config) internal onlyInitializing {
        smartVault = config.smartVault;
        _setBalanceConnectors(config.previousBalanceConnectorId, config.nextBalanceConnectorId);
    }

    /**
     * @dev Tells the address from where the token amounts to execute this task are fetched.
     * Since by default tasks are supposed to use balance connectors, the tokens source has to be the smart vault.
     * In case a task does not need to rely on a previous balance connector, it must override this function to specify
     * where it is getting its tokens from.
     */
    function getTokensSource() external view virtual override returns (address) {
        return smartVault;
    }

    /**
     * @dev Tells the amount a task should use for a token. By default tasks are expected to use balance connectors.
     * In case a task relies on an external tokens source, it must override how the task amount is calculated.
     * @param token Address of the token being queried
     */
    function getTaskAmount(address token) public view virtual override returns (uint256) {
        return ISmartVault(smartVault).getBalanceConnector(previousBalanceConnectorId, token);
    }

    /**
     * @dev Tells the previous and next balance connectors id of the previous task in the workflow
     */
    function getBalanceConnectors() external view returns (bytes32 previous, bytes32 next) {
        previous = previousBalanceConnectorId;
        next = nextBalanceConnectorId;
    }

    /**
     * @dev Sets the balance connectors
     * @param previous Balance connector id of the previous task in the workflow
     * @param next Balance connector id of the next task in the workflow
     */
    function setBalanceConnectors(bytes32 previous, bytes32 next) external override authP(authParams(previous, next)) {
        _setBalanceConnectors(previous, next);
    }

    /**
     * @dev Tells the wrapped native token address if the given address is the native token
     * @param token Address of the token to be checked
     */
    function _wrappedIfNative(address token) internal view returns (address) {
        return Denominations.isNativeToken(token) ? _wrappedNativeToken() : token;
    }

    /**
     * @dev Tells whether a token is the native or the wrapped native token
     * @param token Address of the token to be checked
     */
    function _isWrappedOrNative(address token) internal view returns (bool) {
        return Denominations.isNativeToken(token) || token == _wrappedNativeToken();
    }

    /**
     * @dev Tells the wrapped native token address
     */
    function _wrappedNativeToken() internal view returns (address) {
        return ISmartVault(smartVault).wrappedNativeToken();
    }

    /**
     * @dev Fetches a base/quote price from the smart vault's price oracle
     * @param base Token to rate
     * @param quote Token used for the price rate
     */
    function _getPrice(address base, address quote) internal view virtual returns (uint256) {
        address priceOracle = ISmartVault(smartVault).priceOracle();
        if (priceOracle == address(0)) revert TaskSmartVaultPriceOracleNotSet(smartVault);
        bytes memory extraCallData = _decodeExtraCallData();
        return
            extraCallData.length == 0
                ? IPriceOracle(priceOracle).getPrice(_wrappedIfNative(base), _wrappedIfNative(quote))
                : IPriceOracle(priceOracle).getPrice(_wrappedIfNative(base), _wrappedIfNative(quote), extraCallData);
    }

    /**
     * @dev Before base task hook
     */
    function _beforeBaseTask(address token, uint256 amount) internal virtual {
        _decreaseBalanceConnector(token, amount);
    }

    /**
     * @dev After base task hook
     */
    function _afterBaseTask(address, uint256) internal virtual {
        emit Executed();
    }

    /**
     * @dev Decreases the previous balance connector in the smart vault if defined
     * @param token Address of the token to update the previous balance connector of
     * @param amount Amount to be updated
     */
    function _decreaseBalanceConnector(address token, uint256 amount) internal {
        if (previousBalanceConnectorId != bytes32(0)) {
            ISmartVault(smartVault).updateBalanceConnector(previousBalanceConnectorId, token, amount, false);
        }
    }

    /**
     * @dev Increases the next balance connector in the smart vault if defined
     * @param token Address of the token to update the next balance connector of
     * @param amount Amount to be updated
     */
    function _increaseBalanceConnector(address token, uint256 amount) internal {
        if (nextBalanceConnectorId != bytes32(0)) {
            ISmartVault(smartVault).updateBalanceConnector(nextBalanceConnectorId, token, amount, true);
        }
    }

    /**
     * @dev Sets the balance connectors
     * @param previous Balance connector id of the previous task in the workflow
     * @param next Balance connector id of the next task in the workflow
     */
    function _setBalanceConnectors(bytes32 previous, bytes32 next) internal virtual {
        if (previous == next && previous != bytes32(0)) revert TaskSameBalanceConnectors(previous);
        previousBalanceConnectorId = previous;
        nextBalanceConnectorId = next;
        emit BalanceConnectorsSet(previous, next);
    }

    /**
     * @dev Decodes any potential extra calldata stored in the calldata space. Tasks relying on the extra calldata
     * pattern, assume that the last word of the calldata stores the extra calldata length so it can be decoded. Note
     * that tasks relying on this pattern must contemplate this function may return bogus data if no extra calldata
     * was given.
     */
    function _decodeExtraCallData() private pure returns (bytes memory data) {
        uint256 length = uint256(_decodeLastCallDataWord());
        if (msg.data.length < length) return new bytes(0);
        data = new bytes(length);
        assembly {
            calldatacopy(add(data, 0x20), sub(sub(calldatasize(), length), 0x20), length)
        }
    }

    /**
     * @dev Returns the last calldata word. This function returns zero if the calldata is not long enough.
     */
    function _decodeLastCallDataWord() private pure returns (bytes32 result) {
        if (msg.data.length < 36) return bytes32(0);
        assembly {
            result := calldataload(sub(calldatasize(), 0x20))
        }
    }
}
"
    },
    "@mimic-fi/v3-tasks/contracts/base/GasLimitedTask.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity ^0.8.17;

import '@mimic-fi/v3-authorizer/contracts/Authorized.sol';
import '@mimic-fi/v3-helpers/contracts/math/FixedPoint.sol';
import '@mimic-fi/v3-smart-vault/contracts/interfaces/ISmartVault.sol';

import '../interfaces/base/IGasLimitedTask.sol';

/**
 * @dev Gas config for tasks. It allows setting different gas-related configs, specially useful to control relayed txs.
 */
abstract contract GasLimitedTask is IGasLimitedTask, Authorized {
    using FixedPoint for uint256;

    // Variable used to allow a better developer experience to reimburse tx gas cost
    // solhint-disable-next-line var-name-mixedcase
    uint256 private __initialGas__;

    // Gas limits config
    GasLimitConfig internal gasLimits;

    /**
     * @dev Gas limits config
     * @param gasPriceLimit Gas price limit expressed in the native token
     * @param priorityFeeLimit Priority fee limit expressed in the native token
     * @param txCostLimit Transaction cost limit to be set
     * @param txCostLimitPct Transaction cost limit percentage to be set
     */
    struct GasLimitConfig {
        uint256 gasPriceLimit;
        uint256 priorityFeeLimit;
        uint256 txCostLimit;
        uint256 txCostLimitPct;
    }

    /**
     * @dev Initializes the gas limited task. It does call upper contracts initializers.
     * @param config Gas limited task config
     */
    function __GasLimitedTask_init(GasLimitConfig memory config) internal onlyInitializing {
        __GasLimitedTask_init_unchained(config);
    }

    /**
     * @dev Initializes the gas limited task. It does not call upper contracts initializers.
     * @param config Gas limited task config
     */
    function __GasLimitedTask_init_unchained(GasLimitConfig memory config) internal onlyInitializing {
        _setGasLimits(config.gasPriceLimit, config.priorityFeeLimit, config.txCostLimit, config.txCostLimitPct);
    }

    /**
     * @dev Tells the gas limits config
     */
    function getGasLimits()
        external
        view
        returns (uint256 gasPriceLimit, uint256 priorityFeeLimit, uint256 txCostLimit, uint256 txCostLimitPct)
    {
        return (gasLimits.gasPriceLimit, gasLimits.priorityFeeLimit, gasLimits.txCostLimit, gasLimits.txCostLimitPct);
    }

    /**
     * @dev Sets the gas limits config
     * @param newGasPriceLimit New gas price limit to be set
     * @param newPriorityFeeLimit New priority fee limit to be set
     * @param newTxCostLimit New tx cost limit to be set
     * @param newTxCostLimitPct New tx cost percentage limit to be set
     */
    function setGasLimits(
        uint256 newGasPriceLimit,
        uint256 newPriorityFeeLimit,
        uint256 newTxCostLimit,
        uint256 newTxCostLimitPct
    ) external override authP(authParams(newGasPriceLimit, newPriorityFeeLimit, newTxCostLimit, newTxCostLimitPct)) {
        _setGasLimits(newGasPriceLimit, newPriorityFeeLimit, newTxCostLimit, newTxCostLimitPct);
    }

    /**
     * @dev Fetches a base/quote price
     */
    function _getPrice(address base, address quote) internal view virtual returns (uint256);

    /**
     * @dev Initializes gas limited tasks and validates gas price limit
     */
    function _beforeGasLimitedTask(address, uint256) internal virtual {
        __initialGas__ = gasleft();
        GasLimitConfig memory config = gasLimits;
        bool isGasPriceAllowed = config.gasPriceLimit == 0 || tx.gasprice <= config.gasPriceLimit;
        if (!isGasPriceAllowed) revert TaskGasPriceLimitExceeded(tx.gasprice, config.gasPriceLimit);

        if (config.priorityFeeLimit > 0) {
            uint256 priorityFee = tx.gasprice - block.basefee;
            bool isPriorityFeeAllowed = priorityFee <= config.priorityFeeLimit;
            if (!isPriorityFeeAllowed) revert TaskPriorityFeeLimitExceeded(priorityFee, config.priorityFeeLimit);
        }
    }

    /**
     * @dev Validates transaction cost limit
     */
    function _afterGasLimitedTask(address token, uint256 amount) internal virtual {
        if (__initialGas__ == 0) revert TaskGasNotInitialized();

        GasLimitConfig memory config = gasLimits;
        uint256 totalGas = __initialGas__ - gasleft();
        uint256 totalCost = totalGas * tx.gasprice;
        bool isTxCostAllowed = config.txCostLimit == 0 || totalCost <= config.txCostLimit;
        if (!isTxCostAllowed) revert TaskTxCostLimitExceeded(totalCost, config.txCostLimit);
        delete __initialGas__;

        if (config.txCostLimitPct > 0 && amount > 0) {
            uint256 price = _getPrice(ISmartVault(this.smartVault()).wrappedNativeToken(), token);
            uint256 totalCostInToken = totalCost.mulUp(price);
            uint256 txCostPct = totalCostInToken.divUp(amount);
            if (txCostPct > config.txCostLimitPct) revert TaskTxCostLimitPctExceeded(txCostPct, config.txCostLimitPct);
        }
    }

    /**
     * @dev Sets the gas limits config
     * @param newGasPriceLimit New gas price limit to be set
     * @param newPriorityFeeLimit New priority fee limit to be set
     * @param newTxCostLimit New tx cost limit to be set
     * @param newTxCostLimitPct New tx cost percentage limit to be set
     */
    function _setGasLimits(
        uint256 newGasPriceLimit,
        uint256 newPriorityFeeLimit,
        uint256 newTxCostLimit,
        uint256 newTxCostLimitPct
    ) internal {
        if (newTxCostLimitPct > FixedPoint.ONE) revert TaskTxCostLimitPctAboveOne();

        gasLimits.gasPriceLimit = newGasPriceLimit;
        gasLimits.priorityFeeLimit = newPriorityFeeLimit;
        gasLimits.txCostLimit = newTxCostLimit;
        gasLimits.txCostLimitPct = newTxCostLimitPct;
        emit GasLimitsSet(newGasPriceLimit, newPriorityFeeLimit, newTxCostLimit, newTxCostLimitPct);
    }
}
"
    },
    "@mimic-fi/v3-tasks/contracts/base/PausableTask.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity ^0.8.17;

import '@mimic-fi/v3-authorizer/contracts/Authorized.sol';
import '@mimic-fi/v3-helpers/contracts/math/FixedPoint.sol';

import '../interfaces/base/IPausableTask.sol';

/**
 * @dev Pausable config for tasks
 */
abstract contract PausableTask is IPausableTask, Authorized {
    using FixedPoint for uint256;

    // Whether the task is paused or not
    bool public override isPaused;

    /**
     * @dev Initializes the pausable task. It does call upper contracts initializers.
     */
    function __PausableTask_init() internal onlyInitializing {
        __PausableTask_init_unchained();
    }

    /**
     * @dev Initializes the pausable task. It does not call upper contracts initializers.
     */
    function __PausableTask_init_unchained() internal onlyInitializing {
        // solhint-disable-previous-line no-empty-blocks
    }

    /**
     * @dev Pauses a task
     */
    function pause() external override auth {
        if (isPaused) revert TaskPaused();
        isPaused = true;
        emit Paused();
    }

    /**
     * @dev Unpauses a task
     */
    function unpause() external override auth {
        if (!isPaused) revert TaskUnpaused();
        isPaused = false;
        emit Unpaused();
    }

    /**
     * @dev Before pausable task hook
     */
    function _beforePausableTask(address, uint256) internal virtual {
        if (isPaused) revert TaskPaused();
    }

    /**
     * @dev After pausable task hook
     */
    function _afterPausableTask(address, uint256) internal virtual {
        // solhint-disable-previous-line no-empty-blocks
    }
}
"
    },
    "@mimic-fi/v3-tasks/contracts/base/TimeLockedTask.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity ^0.8.3;

import '@quant-finance/solidity-datetime/contracts/DateTime.sol';
import '@mimic-fi/v3-authorizer/contracts/Authorized.sol';

import '../interfaces/base/ITimeLockedTask.sol';

/**
 * @dev Time lock config for tasks. It allows limiting the frequency of a task.
 */
abstract contract TimeLockedTask is ITimeLockedTask, Authorized {
    using DateTime for uint256;

    uint256 private constant DAYS_28 = 60 * 60 * 24 * 28;

    /**
     * @dev Time-locks supports different frequency modes
     * @param Seconds To indicate the execution must occur every certain number of seconds
     * @param OnDay To indicate the execution must occur on day number from 1 to 28 every certain months
     * @param OnLastMonthDay To indicate the execution must occur on the last day of the month every certain months
     */
    enum Mode {
        Seconds,
        OnDay,
        OnLastMonthDay
    }

    // Time lock mode
    Mode internal _mode;

    // Time lock frequency
    uint256 internal _frequency;

    // Future timestamp since when the task can be executed
    uint256 internal _allowedAt;

    // Next future timestamp since when the task can be executed to be set, only used internally
    uint256 internal _nextAllowedAt;

    // Period in seconds during when a time-locked task can be executed since the allowed timestamp
    uint256 internal _window;

    /**
     * @dev Time lock config params. Only used in the initializer.
     * @param mode Time lock mode
     * @param frequency Time lock frequency value
     * @param allowedAt Time lock allowed date
     * @param window Time lock execution window
     */
    struct TimeLockConfig {
        uint8 mode;
        uint256 frequency;
        uint256 allowedAt;
        uint256 window;
    }

    /**
     * @dev Initializes the time locked task. It does not call upper contracts initializers.
     * @param config Time locked task config
     */
    function __TimeLockedTask_init(TimeLockConfig memory config) internal onlyInitializing {
        __TimeLockedTask_init_unchained(config);
    }

    /**
     * @dev Initializes the time locked task. It does call upper contracts initializers.
     * @param config Time locked task config
     */
    function __TimeLockedTask_init_unchained(TimeLockConfig memory config) internal onlyInitializing {
        _setTimeLock(config.mode, config.frequency, config.allowedAt, config.window);
    }

    /**
     * @dev Tells the time-lock related information
     */
    function getTimeLock() external view returns (uint8 mode, uint256 frequency, uint256 allowedAt, uint256 window) {
        return (uint8(_mode), _frequency, _allowedAt, _window);
    }

    /**
     * @dev Sets a new time lock
     */
    function setTimeLock(uint8 mode, uint256 frequency, uint256 allowedAt, uint256 window)
        external
        override
        authP(authParams(mode, frequency, allowedAt, window))
    {
        _setTimeLock(mode, frequency, allowedAt, window);
    }

    /**
     * @dev Before time locked task hook
     */
    function _beforeTimeLockedTask(address, uint256) internal virtual {
        // Load storage variables
        Mode mode = _mode;
        uint256 frequency = _frequency;
        uint256 allowedAt = _allowedAt;
        uint256 window = _window;

        // First we check the current timestamp is not in the past
        if (block.timestamp < allowedAt) revert TaskTimeLockActive(block.timestamp, allowedAt);

        if (mode == Mode.Seconds) {
            if (frequency == 0) return;

            // If no window is set, the next allowed date is simply moved the number of seconds set as frequency.
            // Otherwise, the offset must be validated and the next allowed date is set to the next period.
            if (window == 0) _nextAllowedAt = block.timestamp + frequency;
            else {
                uint256 diff = block.timestamp - allowedAt;
                uint256 periods = diff / frequency;
                uint256 offset = diff - (periods * frequency);
                if (offset > window) revert TaskTimeLockActive(block.timestamp, allowedAt);
                _nextAllowedAt = allowedAt + ((periods + 1) * frequency);
            }
        } else {
            if (block.timestamp >= allowedAt && block.timestamp <= allowedAt + window) {
                // Check the current timestamp has not passed the allowed date set
                _nextAllowedAt = _getNextAllowedDate(allowedAt, frequency);
            } else {
                // Check the current timestamp is not before the current allowed date
                uint256 currentAllowedDay = mode == Mode.OnDay ? allowedAt.getDay() : block.timestamp.getDaysInMonth();
                uint256 currentAllowedAt = _getCurrentAllowedDate(allowedAt, currentAllowedDay);
                if (block.timestamp < currentAllowedAt) revert TaskTimeLockActive(block.timestamp, currentAllowedAt);

                // Check the current timestamp has not passed the allowed execution window
                uint256 extendedCurrentAllowedAt = currentAllowedAt + window;
                bool exceedsExecutionWindow = block.timestamp > extendedCurrentAllowedAt;
                if (exceedsExecutionWindow) revert TaskTimeLockActive(block.timestamp, extendedCurrentAllowedAt);

                // Finally set the next allowed date to the corresponding number of months from the current date
                _nextAllowedAt = _getNextAllowedDate(currentAllowedAt, frequency);
            }
        }
    }

    /**
     * @dev After time locked task hook
     */
    function _afterTimeLockedTask(address, uint256) internal virtual {
        if (_nextAllowedAt == 0) return;
        _setTimeLockAllowedAt(_nextAllowedAt);
        _nextAllowedAt = 0;
    }

    /**
     * @dev Sets a new time lock
     */
    function _setTimeLock(uint8 mode, uint256 frequency, uint256 allowedAt, uint256 window) internal {
        if (mode == uint8(Mode.Seconds)) {
            // The execution window and timestamp are optional, but both must be given or none
            // If given the execution window cannot be larger than the number of seconds
            // Also, if these are given the frequency must be checked as well, otherwise it could be unsetting the lock
            if (window > 0 || allowedAt > 0) {
                if (frequency == 0) revert TaskInvalidFrequency(mode, frequency);
                if (window == 0 || window > frequency) revert TaskInvalidAllowedWindow(mode, window);
                if (allowedAt == 0) revert TaskInvalidAllowedDate(mode, allowedAt);
            }
        } else {
            // The other modes can be "on-day" or "on-last-day" where the frequency represents a number of months
            // There is no limit for the frequency, it simply cannot be zero
            if (frequency == 0) revert TaskInvalidFrequency(mode, frequency);

            // The execution window cannot be larger than the number of months considering months of 28 days
            if (window == 0 || window > frequency * DAYS_28) revert TaskInvalidAllowedWindow(mode, window);

            // The allowed date cannot be zero
            if (allowedAt == 0) revert TaskInvalidAllowedDate(mode, allowedAt);

            // If the mode is "on-day", the allowed date must be valid for every month, then the allowed day cannot be
            // larger than 28. But if the mode is "on-last-day", the allowed date day must be the last day of the month
            if (mode == uint8(Mode.OnDay)) {
                if (allowedAt.getDay() > 28) revert TaskInvalidAllowedDate(mode, allowedAt);
            } else if (mode == uint8(Mode.OnLastMonthDay)) {
                if (allowedAt.getDay() != allowedAt.getDaysInMonth()) revert TaskInvalidAllowedDate(mode, allowedAt);
            } else {
                revert TaskInvalidFrequencyMode(mode);
            }
        }

        _mode = Mode(mode);
        _frequency = frequency;
        _allowedAt = allowedAt;
        _window = window;

        emit TimeLockSet(mode, frequency, allowedAt, window);
    }

    /**
     * @dev Sets the time-lock execution allowed timestamp
     * @param allowedAt New execution allowed timestamp to be set
     */
    function _setTimeLockAllowedAt(uint256 allowedAt) internal {
        _allowedAt = allowedAt;
        emit TimeLockAllowedAtSet(allowedAt);
    }

    /**
     * @dev Tells the corresponding allowed date based on a current timestamp
     */
    function _getCurrentAllowedDate(uint256 allowedAt, uint256 day) private view returns (uint256) {
        (uint256 year, uint256 month, ) = block.timestamp.timestampToDate();
        return _getAllowedDateFor(allowedAt, year, month, day);
    }

    /**
     * @dev Tells the next allowed date based on a current allowed date considering a number of months to increase
     */
    function _getNextAllowedDate(uint256 allowedAt, uint256 monthsToIncrease) private view returns (uint256) {
        (uint256 year, uint256 month, uint256 day) = allowedAt.timestampToDate();
        uint256 increasedMonth = month + monthsToIncrease;
        uint256 nextMonth = increasedMonth % 12;
        uint256 nextYear = year + (increasedMonth / 12);
        uint256 nextDay = _mode == Mode.OnLastMonthDay ? DateTime._getDaysInMonth(nextYear, nextMonth) : day;
        return _getAllowedDateFor(allowedAt, nextYear, nextMonth, nextDay);
    }

    /**
     * @dev Builds an allowed date using a specific year, month, and day
     */
    function _getAllowedDateFor(uint256 allowedAt, uint256 year, uint256 month, uint256 day)
        private
        pure
        returns (uint256)
    {
        return
            DateTime.timestampFromDateTime(
                year,
                month,
                day,
                allowedAt.getHour(),
                allowedAt.getMinute(),
                allowedAt.getSecond()
            );
    }
}
"
    },
    "@mimic-fi/v3-tasks/contracts/base/TokenIndexedTask.sol": {
      "content": "// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity ^0.8.3;

import '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';

import '@mimic-fi/v3-authorizer/contracts/Authorized.sol';

import '../interfaces/base/ITokenIndexedTask.sol';

/**
 * @dev Token indexed task. It defines a token acceptance list to tell which are the tokens supported by the
 * task. Tokens acceptance can be configured either as an allow list or as a deny list.
 */
abstract contract TokenIndexedTask is ITokenIndexedTask, Authorized {
    using EnumerableSet for EnumerableSet.AddressSet;

    // Acceptance list type
    TokensAcceptanceType public override tokensAcceptanceType;

    // Enumerable set of tokens included in the acceptance list
    EnumerableSet.AddressSet internal _tokens;

    /**
     * @dev Token index config. Only used in the initializer.
     * @param acceptanceType Token acceptance type to be set
     * @param tokens List of token addresses to be set for the acceptance list
     */
    struct TokenIndexConfig {
        TokensAcceptanceType acceptanceType;
        address[] tokens;
    }

    /**
     * @dev Initializes the token indexed task. It does not call upper contracts initializers.
     * @param config Token indexed task config
     */
    function __TokenIndex

Tags:
ERC20, Multisig, Pausable, Swap, Upgradeable, Multi-Signature, Factory, Oracle|addr:0xd8b2588ccb669c828cc12b0ae405424481e2f1c2|verified:true|block:23393039|tx:0x8d991ccd750c6cf43e5e1642ed45d71b9ab3da63356926b137565ff120b08fa8|first_check:1758275091

Submitted on: 2025-09-19 11:44:52

Comments

Log in to comment.

No comments yet.