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
Submitted on: 2025-09-19 11:44:41
Comments
Log in to comment.
No comments yet.