-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstandard-json-input.json
More file actions
155 lines (155 loc) · 360 KB
/
standard-json-input.json
File metadata and controls
155 lines (155 loc) · 360 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
{
"language": "Solidity",
"sources": {
"@openzeppelin/contracts/access/AccessControl.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.20;\n\nimport {IAccessControl} from \"./IAccessControl.sol\";\nimport {Context} from \"../utils/Context.sol\";\nimport {IERC165, ERC165} from \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account => bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n"
},
"@openzeppelin/contracts/access/IAccessControl.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (access/IAccessControl.sol)\n\npragma solidity >=0.8.4;\n\n/**\n * @dev External interface of AccessControl declared to support ERC-165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted to signal this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).\n * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n"
},
"@openzeppelin/contracts/governance/TimelockController.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (governance/TimelockController.sol)\n\npragma solidity ^0.8.20;\n\nimport {AccessControl} from \"../access/AccessControl.sol\";\nimport {ERC721Holder} from \"../token/ERC721/utils/ERC721Holder.sol\";\nimport {ERC1155Holder} from \"../token/ERC1155/utils/ERC1155Holder.sol\";\nimport {Address} from \"../utils/Address.sol\";\nimport {IERC165} from \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module which acts as a timelocked controller. When set as the\n * owner of an `Ownable` smart contract, it enforces a timelock on all\n * `onlyOwner` maintenance operations. This gives time for users of the\n * controlled contract to exit before a potentially dangerous maintenance\n * operation is applied.\n *\n * By default, this contract is self administered, meaning administration tasks\n * have to go through the timelock process. The proposer (resp executor) role\n * is in charge of proposing (resp executing) operations. A common use case is\n * to position this {TimelockController} as the owner of a smart contract, with\n * a multisig or a DAO as the sole proposer.\n */\ncontract TimelockController is AccessControl, ERC721Holder, ERC1155Holder {\n bytes32 public constant PROPOSER_ROLE = keccak256(\"PROPOSER_ROLE\");\n bytes32 public constant EXECUTOR_ROLE = keccak256(\"EXECUTOR_ROLE\");\n bytes32 public constant CANCELLER_ROLE = keccak256(\"CANCELLER_ROLE\");\n uint256 internal constant _DONE_TIMESTAMP = uint256(1);\n\n mapping(bytes32 id => uint256) private _timestamps;\n uint256 private _minDelay;\n\n enum OperationState {\n Unset,\n Waiting,\n Ready,\n Done\n }\n\n /**\n * @dev Mismatch between the parameters length for an operation call.\n */\n error TimelockInvalidOperationLength(uint256 targets, uint256 payloads, uint256 values);\n\n /**\n * @dev The schedule operation doesn't meet the minimum delay.\n */\n error TimelockInsufficientDelay(uint256 delay, uint256 minDelay);\n\n /**\n * @dev The current state of an operation is not as required.\n * The `expectedStates` is a bitmap with the bits enabled for each OperationState enum position\n * counting from right to left.\n *\n * See {_encodeStateBitmap}.\n */\n error TimelockUnexpectedOperationState(bytes32 operationId, bytes32 expectedStates);\n\n /**\n * @dev The predecessor to an operation not yet done.\n */\n error TimelockUnexecutedPredecessor(bytes32 predecessorId);\n\n /**\n * @dev The caller account is not authorized.\n */\n error TimelockUnauthorizedCaller(address caller);\n\n /**\n * @dev Emitted when a call is scheduled as part of operation `id`.\n */\n event CallScheduled(\n bytes32 indexed id,\n uint256 indexed index,\n address target,\n uint256 value,\n bytes data,\n bytes32 predecessor,\n uint256 delay\n );\n\n /**\n * @dev Emitted when a call is performed as part of operation `id`.\n */\n event CallExecuted(bytes32 indexed id, uint256 indexed index, address target, uint256 value, bytes data);\n\n /**\n * @dev Emitted when new proposal is scheduled with non-zero salt.\n */\n event CallSalt(bytes32 indexed id, bytes32 salt);\n\n /**\n * @dev Emitted when operation `id` is cancelled.\n */\n event Cancelled(bytes32 indexed id);\n\n /**\n * @dev Emitted when the minimum delay for future operations is modified.\n */\n event MinDelayChange(uint256 oldDuration, uint256 newDuration);\n\n /**\n * @dev Initializes the contract with the following parameters:\n *\n * - `minDelay`: initial minimum delay in seconds for operations\n * - `proposers`: accounts to be granted proposer and canceller roles\n * - `executors`: accounts to be granted executor role\n * - `admin`: optional account to be granted admin role; disable with zero address\n *\n * IMPORTANT: The optional admin can aid with initial configuration of roles after deployment\n * without being subject to delay, but this role should be subsequently renounced in favor of\n * administration through timelocked proposals. Previous versions of this contract would assign\n * this admin to the deployer automatically and should be renounced as well.\n */\n constructor(uint256 minDelay, address[] memory proposers, address[] memory executors, address admin) {\n // self administration\n _grantRole(DEFAULT_ADMIN_ROLE, address(this));\n\n // optional admin\n if (admin != address(0)) {\n _grantRole(DEFAULT_ADMIN_ROLE, admin);\n }\n\n // register proposers and cancellers\n for (uint256 i = 0; i < proposers.length; ++i) {\n _grantRole(PROPOSER_ROLE, proposers[i]);\n _grantRole(CANCELLER_ROLE, proposers[i]);\n }\n\n // register executors\n for (uint256 i = 0; i < executors.length; ++i) {\n _grantRole(EXECUTOR_ROLE, executors[i]);\n }\n\n _minDelay = minDelay;\n emit MinDelayChange(0, minDelay);\n }\n\n /**\n * @dev Modifier to make a function callable only by a certain role. In\n * addition to checking the sender's role, `address(0)` 's role is also\n * considered. Granting a role to `address(0)` is equivalent to enabling\n * this role for everyone.\n */\n modifier onlyRoleOrOpenRole(bytes32 role) {\n if (!hasRole(role, address(0))) {\n _checkRole(role, _msgSender());\n }\n _;\n }\n\n /**\n * @dev Contract might receive/hold ETH as part of the maintenance process.\n */\n receive() external payable virtual {}\n\n /// @inheritdoc IERC165\n function supportsInterface(\n bytes4 interfaceId\n ) public view virtual override(AccessControl, ERC1155Holder) returns (bool) {\n return super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns whether an id corresponds to a registered operation. This\n * includes both Waiting, Ready, and Done operations.\n */\n function isOperation(bytes32 id) public view returns (bool) {\n return getOperationState(id) != OperationState.Unset;\n }\n\n /**\n * @dev Returns whether an operation is pending or not. Note that a \"pending\" operation may also be \"ready\".\n */\n function isOperationPending(bytes32 id) public view returns (bool) {\n OperationState state = getOperationState(id);\n return state == OperationState.Waiting || state == OperationState.Ready;\n }\n\n /**\n * @dev Returns whether an operation is ready for execution. Note that a \"ready\" operation is also \"pending\".\n */\n function isOperationReady(bytes32 id) public view returns (bool) {\n return getOperationState(id) == OperationState.Ready;\n }\n\n /**\n * @dev Returns whether an operation is done or not.\n */\n function isOperationDone(bytes32 id) public view returns (bool) {\n return getOperationState(id) == OperationState.Done;\n }\n\n /**\n * @dev Returns the timestamp at which an operation becomes ready (0 for\n * unset operations, 1 for done operations).\n */\n function getTimestamp(bytes32 id) public view virtual returns (uint256) {\n return _timestamps[id];\n }\n\n /**\n * @dev Returns operation state.\n */\n function getOperationState(bytes32 id) public view virtual returns (OperationState) {\n uint256 timestamp = getTimestamp(id);\n if (timestamp == 0) {\n return OperationState.Unset;\n } else if (timestamp == _DONE_TIMESTAMP) {\n return OperationState.Done;\n } else if (timestamp > block.timestamp) {\n return OperationState.Waiting;\n } else {\n return OperationState.Ready;\n }\n }\n\n /**\n * @dev Returns the minimum delay in seconds for an operation to become valid.\n *\n * This value can be changed by executing an operation that calls `updateDelay`.\n */\n function getMinDelay() public view virtual returns (uint256) {\n return _minDelay;\n }\n\n /**\n * @dev Returns the identifier of an operation containing a single\n * transaction.\n */\n function hashOperation(\n address target,\n uint256 value,\n bytes calldata data,\n bytes32 predecessor,\n bytes32 salt\n ) public pure virtual returns (bytes32) {\n return keccak256(abi.encode(target, value, data, predecessor, salt));\n }\n\n /**\n * @dev Returns the identifier of an operation containing a batch of\n * transactions.\n */\n function hashOperationBatch(\n address[] calldata targets,\n uint256[] calldata values,\n bytes[] calldata payloads,\n bytes32 predecessor,\n bytes32 salt\n ) public pure virtual returns (bytes32) {\n return keccak256(abi.encode(targets, values, payloads, predecessor, salt));\n }\n\n /**\n * @dev Schedule an operation containing a single transaction.\n *\n * Emits {CallSalt} if salt is nonzero, and {CallScheduled}.\n *\n * Requirements:\n *\n * - the caller must have the 'proposer' role.\n */\n function schedule(\n address target,\n uint256 value,\n bytes calldata data,\n bytes32 predecessor,\n bytes32 salt,\n uint256 delay\n ) public virtual onlyRole(PROPOSER_ROLE) {\n bytes32 id = hashOperation(target, value, data, predecessor, salt);\n _schedule(id, delay);\n emit CallScheduled(id, 0, target, value, data, predecessor, delay);\n if (salt != bytes32(0)) {\n emit CallSalt(id, salt);\n }\n }\n\n /**\n * @dev Schedule an operation containing a batch of transactions.\n *\n * Emits {CallSalt} if salt is nonzero, and one {CallScheduled} event per transaction in the batch.\n *\n * Requirements:\n *\n * - the caller must have the 'proposer' role.\n */\n function scheduleBatch(\n address[] calldata targets,\n uint256[] calldata values,\n bytes[] calldata payloads,\n bytes32 predecessor,\n bytes32 salt,\n uint256 delay\n ) public virtual onlyRole(PROPOSER_ROLE) {\n if (targets.length != values.length || targets.length != payloads.length) {\n revert TimelockInvalidOperationLength(targets.length, payloads.length, values.length);\n }\n\n bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt);\n _schedule(id, delay);\n for (uint256 i = 0; i < targets.length; ++i) {\n emit CallScheduled(id, i, targets[i], values[i], payloads[i], predecessor, delay);\n }\n if (salt != bytes32(0)) {\n emit CallSalt(id, salt);\n }\n }\n\n /**\n * @dev Schedule an operation that is to become valid after a given delay.\n */\n function _schedule(bytes32 id, uint256 delay) private {\n if (isOperation(id)) {\n revert TimelockUnexpectedOperationState(id, _encodeStateBitmap(OperationState.Unset));\n }\n uint256 minDelay = getMinDelay();\n if (delay < minDelay) {\n revert TimelockInsufficientDelay(delay, minDelay);\n }\n _timestamps[id] = block.timestamp + delay;\n }\n\n /**\n * @dev Cancel an operation.\n *\n * Requirements:\n *\n * - the caller must have the 'canceller' role.\n */\n function cancel(bytes32 id) public virtual onlyRole(CANCELLER_ROLE) {\n if (!isOperationPending(id)) {\n revert TimelockUnexpectedOperationState(\n id,\n _encodeStateBitmap(OperationState.Waiting) | _encodeStateBitmap(OperationState.Ready)\n );\n }\n delete _timestamps[id];\n\n emit Cancelled(id);\n }\n\n /**\n * @dev Execute an (ready) operation containing a single transaction.\n *\n * Emits a {CallExecuted} event.\n *\n * Requirements:\n *\n * - the caller must have the 'executor' role.\n */\n // This function can reenter, but it doesn't pose a risk because _afterCall checks that the proposal is pending,\n // thus any modifications to the operation during reentrancy should be caught.\n // slither-disable-next-line reentrancy-eth\n function execute(\n address target,\n uint256 value,\n bytes calldata payload,\n bytes32 predecessor,\n bytes32 salt\n ) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE) {\n bytes32 id = hashOperation(target, value, payload, predecessor, salt);\n\n _beforeCall(id, predecessor);\n _execute(target, value, payload);\n emit CallExecuted(id, 0, target, value, payload);\n _afterCall(id);\n }\n\n /**\n * @dev Execute an (ready) operation containing a batch of transactions.\n *\n * Emits one {CallExecuted} event per transaction in the batch.\n *\n * Requirements:\n *\n * - the caller must have the 'executor' role.\n */\n // This function can reenter, but it doesn't pose a risk because _afterCall checks that the proposal is pending,\n // thus any modifications to the operation during reentrancy should be caught.\n // slither-disable-next-line reentrancy-eth\n function executeBatch(\n address[] calldata targets,\n uint256[] calldata values,\n bytes[] calldata payloads,\n bytes32 predecessor,\n bytes32 salt\n ) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE) {\n if (targets.length != values.length || targets.length != payloads.length) {\n revert TimelockInvalidOperationLength(targets.length, payloads.length, values.length);\n }\n\n bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt);\n\n _beforeCall(id, predecessor);\n for (uint256 i = 0; i < targets.length; ++i) {\n address target = targets[i];\n uint256 value = values[i];\n bytes calldata payload = payloads[i];\n _execute(target, value, payload);\n emit CallExecuted(id, i, target, value, payload);\n }\n _afterCall(id);\n }\n\n /**\n * @dev Execute an operation's call.\n */\n function _execute(address target, uint256 value, bytes calldata data) internal virtual {\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n Address.verifyCallResult(success, returndata);\n }\n\n /**\n * @dev Checks before execution of an operation's calls.\n */\n function _beforeCall(bytes32 id, bytes32 predecessor) private view {\n if (!isOperationReady(id)) {\n revert TimelockUnexpectedOperationState(id, _encodeStateBitmap(OperationState.Ready));\n }\n if (predecessor != bytes32(0) && !isOperationDone(predecessor)) {\n revert TimelockUnexecutedPredecessor(predecessor);\n }\n }\n\n /**\n * @dev Checks after execution of an operation's calls.\n */\n function _afterCall(bytes32 id) private {\n if (!isOperationReady(id)) {\n revert TimelockUnexpectedOperationState(id, _encodeStateBitmap(OperationState.Ready));\n }\n _timestamps[id] = _DONE_TIMESTAMP;\n }\n\n /**\n * @dev Changes the minimum timelock duration for future operations.\n *\n * Emits a {MinDelayChange} event.\n *\n * Requirements:\n *\n * - the caller must be the timelock itself. This can only be achieved by scheduling and later executing\n * an operation where the timelock is the target and the data is the ABI-encoded call to this function.\n */\n function updateDelay(uint256 newDelay) external virtual {\n address sender = _msgSender();\n if (sender != address(this)) {\n revert TimelockUnauthorizedCaller(sender);\n }\n emit MinDelayChange(_minDelay, newDelay);\n _minDelay = newDelay;\n }\n\n /**\n * @dev Encodes a `OperationState` into a `bytes32` representation where each bit enabled corresponds to\n * the underlying position in the `OperationState` enum. For example:\n *\n * 0x000...1000\n * ^^^^^^----- ...\n * ^---- Done\n * ^--- Ready\n * ^-- Waiting\n * ^- Unset\n */\n function _encodeStateBitmap(OperationState operationState) internal pure returns (bytes32) {\n return bytes32(1 << uint8(operationState));\n }\n}\n"
},
"@openzeppelin/contracts/interfaces/draft-IERC6093.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC6093.sol)\npragma solidity >=0.8.4;\n\n/**\n * @dev Standard ERC-20 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.\n */\ninterface IERC20Errors {\n /**\n * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n * @param balance Current balance for the interacting account.\n * @param needed Minimum amount required to perform a transfer.\n */\n error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);\n\n /**\n * @dev Indicates a failure with the token `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n */\n error ERC20InvalidSender(address sender);\n\n /**\n * @dev Indicates a failure with the token `receiver`. Used in transfers.\n * @param receiver Address to which tokens are being transferred.\n */\n error ERC20InvalidReceiver(address receiver);\n\n /**\n * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.\n * @param spender Address that may be allowed to operate on tokens without being their owner.\n * @param allowance Amount of tokens a `spender` is allowed to operate with.\n * @param needed Minimum amount required to perform a transfer.\n */\n error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);\n\n /**\n * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n * @param approver Address initiating an approval operation.\n */\n error ERC20InvalidApprover(address approver);\n\n /**\n * @dev Indicates a failure with the `spender` to be approved. Used in approvals.\n * @param spender Address that may be allowed to operate on tokens without being their owner.\n */\n error ERC20InvalidSpender(address spender);\n}\n\n/**\n * @dev Standard ERC-721 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.\n */\ninterface IERC721Errors {\n /**\n * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20.\n * Used in balance queries.\n * @param owner Address of the current owner of a token.\n */\n error ERC721InvalidOwner(address owner);\n\n /**\n * @dev Indicates a `tokenId` whose `owner` is the zero address.\n * @param tokenId Identifier number of a token.\n */\n error ERC721NonexistentToken(uint256 tokenId);\n\n /**\n * @dev Indicates an error related to the ownership over a particular token. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n * @param tokenId Identifier number of a token.\n * @param owner Address of the current owner of a token.\n */\n error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);\n\n /**\n * @dev Indicates a failure with the token `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n */\n error ERC721InvalidSender(address sender);\n\n /**\n * @dev Indicates a failure with the token `receiver`. Used in transfers.\n * @param receiver Address to which tokens are being transferred.\n */\n error ERC721InvalidReceiver(address receiver);\n\n /**\n * @dev Indicates a failure with the `operator`’s approval. Used in transfers.\n * @param operator Address that may be allowed to operate on tokens without being their owner.\n * @param tokenId Identifier number of a token.\n */\n error ERC721InsufficientApproval(address operator, uint256 tokenId);\n\n /**\n * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n * @param approver Address initiating an approval operation.\n */\n error ERC721InvalidApprover(address approver);\n\n /**\n * @dev Indicates a failure with the `operator` to be approved. Used in approvals.\n * @param operator Address that may be allowed to operate on tokens without being their owner.\n */\n error ERC721InvalidOperator(address operator);\n}\n\n/**\n * @dev Standard ERC-1155 Errors\n * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.\n */\ninterface IERC1155Errors {\n /**\n * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n * @param balance Current balance for the interacting account.\n * @param needed Minimum amount required to perform a transfer.\n * @param tokenId Identifier number of a token.\n */\n error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);\n\n /**\n * @dev Indicates a failure with the token `sender`. Used in transfers.\n * @param sender Address whose tokens are being transferred.\n */\n error ERC1155InvalidSender(address sender);\n\n /**\n * @dev Indicates a failure with the token `receiver`. Used in transfers.\n * @param receiver Address to which tokens are being transferred.\n */\n error ERC1155InvalidReceiver(address receiver);\n\n /**\n * @dev Indicates a failure with the `operator`’s approval. Used in transfers.\n * @param operator Address that may be allowed to operate on tokens without being their owner.\n * @param owner Address of the current owner of a token.\n */\n error ERC1155MissingApprovalForAll(address operator, address owner);\n\n /**\n * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.\n * @param approver Address initiating an approval operation.\n */\n error ERC1155InvalidApprover(address approver);\n\n /**\n * @dev Indicates a failure with the `operator` to be approved. Used in approvals.\n * @param operator Address that may be allowed to operate on tokens without being their owner.\n */\n error ERC1155InvalidOperator(address operator);\n\n /**\n * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.\n * Used in batch transfers.\n * @param idsLength Length of the array of token identifiers\n * @param valuesLength Length of the array of token amounts\n */\n error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);\n}\n"
},
"@openzeppelin/contracts/interfaces/IERC1363.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @title IERC1363\n * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].\n *\n * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract\n * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.\n */\ninterface IERC1363 is IERC20, IERC165 {\n /*\n * Note: the ERC-165 identifier for this interface is 0xb0202a11.\n * 0xb0202a11 ===\n * bytes4(keccak256('transferAndCall(address,uint256)')) ^\n * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^\n * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^\n * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^\n * bytes4(keccak256('approveAndCall(address,uint256)')) ^\n * bytes4(keccak256('approveAndCall(address,uint256,bytes)'))\n */\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferAndCall(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @param data Additional data with no specified format, sent in call to `to`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param from The address which you want to send tokens from.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferFromAndCall(address from, address to, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n * @param from The address which you want to send tokens from.\n * @param to The address which you want to transfer to.\n * @param value The amount of tokens to be transferred.\n * @param data Additional data with no specified format, sent in call to `to`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n * @param spender The address which will spend the funds.\n * @param value The amount of tokens to be spent.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function approveAndCall(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n * @param spender The address which will spend the funds.\n * @param value The amount of tokens to be spent.\n * @param data Additional data with no specified format, sent in call to `spender`.\n * @return A boolean value indicating whether the operation succeeded unless throwing.\n */\n function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);\n}\n"
},
"@openzeppelin/contracts/interfaces/IERC165.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n"
},
"@openzeppelin/contracts/interfaces/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n"
},
"@openzeppelin/contracts/interfaces/IERC4626.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC4626.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\nimport {IERC20Metadata} from \"../token/ERC20/extensions/IERC20Metadata.sol\";\n\n/**\n * @dev Interface of the ERC-4626 \"Tokenized Vault Standard\", as defined in\n * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].\n */\ninterface IERC4626 is IERC20, IERC20Metadata {\n event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n\n event Withdraw(\n address indexed sender,\n address indexed receiver,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n\n /**\n * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n *\n * - MUST be an ERC-20 token contract.\n * - MUST NOT revert.\n */\n function asset() external view returns (address assetTokenAddress);\n\n /**\n * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n *\n * - SHOULD include any compounding that occurs from yield.\n * - MUST be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT revert.\n */\n function totalAssets() external view returns (uint256 totalManagedAssets);\n\n /**\n * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n * scenario where all the conditions are met.\n *\n * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n * - MUST NOT show any variations depending on the caller.\n * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n * - MUST NOT revert.\n *\n * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n * from.\n */\n function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n * through a deposit call.\n *\n * - MUST return a limited value if receiver is subject to some deposit limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n * - MUST NOT revert.\n */\n function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n * in the same transaction.\n * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n * deposit would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * deposit execution, and are accounted for during deposit.\n * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n * - MUST return a limited value if receiver is subject to some mint limit.\n * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n * - MUST NOT revert.\n */\n function maxMint(address receiver) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n * current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n * same transaction.\n * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n * would be accepted, regardless if the user has enough tokens approved, etc.\n * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by minting.\n */\n function previewMint(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n *\n * - MUST emit the Deposit event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n * execution, and are accounted for during mint.\n * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n * approving enough underlying tokens to the Vault contract, etc).\n *\n * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n */\n function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n /**\n * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n * Vault, through a withdraw call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n * called\n * in the same transaction.\n * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n * the withdrawal would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n /**\n * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * withdraw execution, and are accounted for during withdraw.\n * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);\n\n /**\n * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n * through a redeem call.\n *\n * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n * - MUST NOT revert.\n */\n function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n /**\n * @dev Allows an on-chain or off-chain user to simulate the effects of their redemption at the current block,\n * given current on-chain conditions.\n *\n * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n * same transaction.\n * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n * redemption would be accepted, regardless if the user has enough shares, etc.\n * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n * - MUST NOT revert.\n *\n * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n */\n function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n /**\n * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n *\n * - MUST emit the Withdraw event.\n * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n * redeem execution, and are accounted for during redeem.\n * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n * not having enough shares, etc).\n *\n * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n * Those methods should be performed separately.\n */\n function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);\n}\n"
},
"@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC1155/IERC1155Receiver.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC165} from \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Interface that must be implemented by smart contracts in order to receive\n * ERC-1155 token transfers.\n */\ninterface IERC1155Receiver is IERC165 {\n /**\n * @dev Handles the receipt of a single ERC-1155 token type. This function is\n * called at the end of a `safeTransferFrom` after the balance has been updated.\n *\n * NOTE: To accept the transfer, this must return\n * `bytes4(keccak256(\"onERC1155Received(address,address,uint256,uint256,bytes)\"))`\n * (i.e. 0xf23a6e61, or its own function selector).\n *\n * @param operator The address which initiated the transfer (i.e. msg.sender)\n * @param from The address which previously owned the token\n * @param id The ID of the token being transferred\n * @param value The amount of tokens being transferred\n * @param data Additional data with no specified format\n * @return `bytes4(keccak256(\"onERC1155Received(address,address,uint256,uint256,bytes)\"))` if transfer is allowed\n */\n function onERC1155Received(\n address operator,\n address from,\n uint256 id,\n uint256 value,\n bytes calldata data\n ) external returns (bytes4);\n\n /**\n * @dev Handles the receipt of a multiple ERC-1155 token types. This function\n * is called at the end of a `safeBatchTransferFrom` after the balances have\n * been updated.\n *\n * NOTE: To accept the transfer(s), this must return\n * `bytes4(keccak256(\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\"))`\n * (i.e. 0xbc197c81, or its own function selector).\n *\n * @param operator The address which initiated the batch transfer (i.e. msg.sender)\n * @param from The address which previously owned the token\n * @param ids An array containing ids of each token being transferred (order and length must match values array)\n * @param values An array containing amounts of each token being transferred (order and length must match ids array)\n * @param data Additional data with no specified format\n * @return `bytes4(keccak256(\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\"))` if transfer is allowed\n */\n function onERC1155BatchReceived(\n address operator,\n address from,\n uint256[] calldata ids,\n uint256[] calldata values,\n bytes calldata data\n ) external returns (bytes4);\n}\n"
},
"@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC1155/utils/ERC1155Holder.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165, ERC165} from \"../../../utils/introspection/ERC165.sol\";\nimport {IERC1155Receiver} from \"../IERC1155Receiver.sol\";\n\n/**\n * @dev Simple implementation of `IERC1155Receiver` that will allow a contract to hold ERC-1155 tokens.\n *\n * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be\n * stuck.\n */\nabstract contract ERC1155Holder is ERC165, IERC1155Receiver {\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\n return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);\n }\n\n function onERC1155Received(\n address,\n address,\n uint256,\n uint256,\n bytes memory\n ) public virtual override returns (bytes4) {\n return this.onERC1155Received.selector;\n }\n\n function onERC1155BatchReceived(\n address,\n address,\n uint256[] memory,\n uint256[] memory,\n bytes memory\n ) public virtual override returns (bytes4) {\n return this.onERC1155BatchReceived.selector;\n }\n}\n"
},
"@openzeppelin/contracts/token/ERC20/ERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC20Metadata} from \"./extensions/IERC20Metadata.sol\";\nimport {Context} from \"../../utils/Context.sol\";\nimport {IERC20Errors} from \"../../interfaces/draft-IERC6093.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * The default value of {decimals} is 18. To change this, you should override\n * this function so it returns a different value.\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC-20\n * applications.\n */\nabstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {\n mapping(address account => uint256) private _balances;\n\n mapping(address account => mapping(address spender => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n\n /**\n * @dev Sets the values for {name} and {symbol}.\n *\n * Both values are immutable: they can only be set once during construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view virtual returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view virtual returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the default value returned by this function, unless\n * it's overridden.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view virtual returns (uint8) {\n return 18;\n }\n\n /// @inheritdoc IERC20\n function totalSupply() public view virtual returns (uint256) {\n return _totalSupply;\n }\n\n /// @inheritdoc IERC20\n function balanceOf(address account) public view virtual returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - the caller must have a balance of at least `value`.\n */\n function transfer(address to, uint256 value) public virtual returns (bool) {\n address owner = _msgSender();\n _transfer(owner, to, value);\n return true;\n }\n\n /// @inheritdoc IERC20\n function allowance(address owner, address spender) public view virtual returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 value) public virtual returns (bool) {\n address owner = _msgSender();\n _approve(owner, spender, value);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Skips emitting an {Approval} event indicating an allowance update. This is not\n * required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `from` must have a balance of at least `value`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `value`.\n */\n function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {\n address spender = _msgSender();\n _spendAllowance(from, spender, value);\n _transfer(from, to, value);\n return true;\n }\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * NOTE: This function is not virtual, {_update} should be overridden instead.\n */\n function _transfer(address from, address to, uint256 value) internal {\n if (from == address(0)) {\n revert ERC20InvalidSender(address(0));\n }\n if (to == address(0)) {\n revert ERC20InvalidReceiver(address(0));\n }\n _update(from, to, value);\n }\n\n /**\n * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`\n * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding\n * this function.\n *\n * Emits a {Transfer} event.\n */\n function _update(address from, address to, uint256 value) internal virtual {\n if (from == address(0)) {\n // Overflow check required: The rest of the code assumes that totalSupply never overflows\n _totalSupply += value;\n } else {\n uint256 fromBalance = _balances[from];\n if (fromBalance < value) {\n revert ERC20InsufficientBalance(from, fromBalance, value);\n }\n unchecked {\n // Overflow not possible: value <= fromBalance <= totalSupply.\n _balances[from] = fromBalance - value;\n }\n }\n\n if (to == address(0)) {\n unchecked {\n // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.\n _totalSupply -= value;\n }\n } else {\n unchecked {\n // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.\n _balances[to] += value;\n }\n }\n\n emit Transfer(from, to, value);\n }\n\n /**\n * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).\n * Relies on the `_update` mechanism\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * NOTE: This function is not virtual, {_update} should be overridden instead.\n */\n function _mint(address account, uint256 value) internal {\n if (account == address(0)) {\n revert ERC20InvalidReceiver(address(0));\n }\n _update(address(0), account, value);\n }\n\n /**\n * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.\n * Relies on the `_update` mechanism.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * NOTE: This function is not virtual, {_update} should be overridden instead\n */\n function _burn(address account, uint256 value) internal {\n if (account == address(0)) {\n revert ERC20InvalidSender(address(0));\n }\n _update(account, address(0), value);\n }\n\n /**\n * @dev Sets `value` as the allowance of `spender` over the `owner`'s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n *\n * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.\n */\n function _approve(address owner, address spender, uint256 value) internal {\n _approve(owner, spender, value, true);\n }\n\n /**\n * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.\n *\n * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by\n * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any\n * `Approval` event during `transferFrom` operations.\n *\n * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to\n * true using the following override:\n *\n * ```solidity\n * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {\n * super._approve(owner, spender, value, true);\n * }\n * ```\n *\n * Requirements are the same as {_approve}.\n */\n function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {\n if (owner == address(0)) {\n revert ERC20InvalidApprover(address(0));\n }\n if (spender == address(0)) {\n revert ERC20InvalidSpender(address(0));\n }\n _allowances[owner][spender] = value;\n if (emitEvent) {\n emit Approval(owner, spender, value);\n }\n }\n\n /**\n * @dev Updates `owner`'s allowance for `spender` based on spent `value`.\n *\n * Does not update the allowance value in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Does not emit an {Approval} event.\n */\n function _spendAllowance(address owner, address spender, uint256 value) internal virtual {\n uint256 currentAllowance = allowance(owner, spender);\n if (currentAllowance < type(uint256).max) {\n if (currentAllowance < value) {\n revert ERC20InsufficientAllowance(spender, currentAllowance, value);\n }\n unchecked {\n _approve(owner, spender, currentAllowance - value, false);\n }\n }\n }\n}\n"
},
"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC-20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n /**\n * @dev Returns the name of the token.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the symbol of the token.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the decimals places of the token.\n */\n function decimals() external view returns (uint8);\n}\n"
},
"@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Permit.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC-20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * ==== Security Considerations\n *\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\n * generally recommended is:\n *\n * ```solidity\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\n * doThing(..., value);\n * }\n *\n * function doThing(..., uint256 value) public {\n * token.safeTransferFrom(msg.sender, address(this), value);\n * ...\n * }\n * ```\n *\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\n * {SafeERC20-safeTransferFrom}).\n *\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\n * contracts should have entry points that don't rely on permit.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n *\n * CAUTION: See Security Considerations above.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"
},
"@openzeppelin/contracts/token/ERC20/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"
},
"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC1363} from \"../../../interfaces/IERC1363.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC-20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n /**\n * @dev An operation with an ERC-20 token failed.\n */\n error SafeERC20FailedOperation(address token);\n\n /**\n * @dev Indicates a failed `decreaseAllowance` request.\n */\n error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n /**\n * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n */\n function safeTransfer(IERC20 token, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n */\n function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.\n */\n function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {\n return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));\n }\n\n /**\n * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.\n */\n function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {\n return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n }\n\n /**\n * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful.\n *\n * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n */\n function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n uint256 oldAllowance = token.allowance(address(this), spender);\n forceApprove(token, spender, oldAllowance + value);\n }\n\n /**\n * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n * value, non-reverting calls are assumed to be successful.\n *\n * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n */\n function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n unchecked {\n uint256 currentAllowance = token.allowance(address(this), spender);\n if (currentAllowance < requestedDecrease) {\n revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n }\n forceApprove(token, spender, currentAllowance - requestedDecrease);\n }\n }\n\n /**\n * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n * to be set to zero before setting it to a non-zero value, such as USDT.\n *\n * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function\n * only sets the \"standard\" allowance. Any temporary allowance will remain active, in addition to the value being\n * set here.\n */\n function forceApprove(IERC20 token, address spender, uint256 value) internal {\n bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n if (!_callOptionalReturnBool(token, approvalCall)) {\n _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n _callOptionalReturn(token, approvalCall);\n }\n }\n\n /**\n * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no\n * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * Reverts if the returned value is other than `true`.\n */\n function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n if (to.code.length == 0) {\n safeTransfer(token, to, value);\n } else if (!token.transferAndCall(to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target\n * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * Reverts if the returned value is other than `true`.\n */\n function transferFromAndCallRelaxed(\n IERC1363 token,\n address from,\n address to,\n uint256 value,\n bytes memory data\n ) internal {\n if (to.code.length == 0) {\n safeTransferFrom(token, from, to, value);\n } else if (!token.transferFromAndCall(from, to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no\n * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n * targeting contracts.\n *\n * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.\n * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}\n * once without retrying, and relies on the returned value to be true.\n *\n * Reverts if the returned value is other than `true`.\n */\n function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n if (to.code.length == 0) {\n forceApprove(token, to, value);\n } else if (!token.approveAndCall(to, value, data)) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.\n */\n function _callOptionalReturn(IERC20 token, bytes memory data) private {\n uint256 returnSize;\n uint256 returnValue;\n assembly (\"memory-safe\") {\n let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n // bubble errors\n if iszero(success) {\n let ptr := mload(0x40)\n returndatacopy(ptr, 0, returndatasize())\n revert(ptr, returndatasize())\n }\n returnSize := returndatasize()\n returnValue := mload(0)\n }\n\n if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {\n revert SafeERC20FailedOperation(address(token));\n }\n }\n\n /**\n * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n * on the return value: the return value is optional (but if data is returned, it must not be false).\n * @param token The token targeted by the call.\n * @param data The call data (encoded using abi.encode or one of its variants).\n *\n * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.\n */\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n bool success;\n uint256 returnSize;\n uint256 returnValue;\n assembly (\"memory-safe\") {\n success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n returnSize := returndatasize()\n returnValue := mload(0)\n }\n return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);\n }\n}\n"
},
"@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/IERC721Receiver.sol)\n\npragma solidity >=0.5.0;\n\n/**\n * @title ERC-721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC-721 asset contracts.\n */\ninterface IERC721Receiver {\n /**\n * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n * by `operator` from `from`, this function is called.\n *\n * It must return its Solidity selector to confirm the token transfer.\n * If any other value is returned or the interface is not implemented by the recipient, the transfer will be\n * reverted.\n *\n * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.\n */\n function onERC721Received(\n address operator,\n address from,\n uint256 tokenId,\n bytes calldata data\n ) external returns (bytes4);\n}\n"
},
"@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/utils/ERC721Holder.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC721Receiver} from \"../IERC721Receiver.sol\";\n\n/**\n * @dev Implementation of the {IERC721Receiver} interface.\n *\n * Accepts all token transfers.\n * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or\n * {IERC721-setApprovalForAll}.\n */\nabstract contract ERC721Holder is IERC721Receiver {\n /**\n * @dev See {IERC721Receiver-onERC721Received}.\n *\n * Always returns `IERC721Receiver.onERC721Received.selector`.\n */\n function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) {\n return this.onERC721Received.selector;\n }\n}\n"
},
"@openzeppelin/contracts/utils/Address.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (utils/Address.sol)\n\npragma solidity ^0.8.20;\n\nimport {Errors} from \"./Errors.sol\";\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance < amount) {\n revert Errors.InsufficientBalance(address(this).balance, amount);\n }\n\n (bool success, bytes memory returndata) = recipient.call{value: amount}(\"\");\n if (!success) {\n _revert(returndata);\n }\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {Errors.FailedCall} error.\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n */\n function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance < value) {\n revert Errors.InsufficientBalance(address(this).balance, value);\n }\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n (bool success, bytes memory returndata) = target.delegatecall(data);\n return verifyCallResultFromTarget(target, success, returndata);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case\n * of an unsuccessful call.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (returndata.length == 0 && target.code.length == 0) {\n revert AddressEmptyCode(target);\n }\n return returndata;\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {Errors.FailedCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (!success) {\n _revert(returndata);\n } else {\n return returndata;\n }\n }\n\n /**\n * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.\n */\n function _revert(bytes memory returndata) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n assembly (\"memory-safe\") {\n revert(add(returndata, 0x20), mload(returndata))\n }\n } else {\n revert Errors.FailedCall();\n }\n }\n}\n"
},
"@openzeppelin/contracts/utils/Context.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n"
},
"@openzeppelin/contracts/utils/Errors.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Collection of common custom errors used in multiple contracts\n *\n * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.\n * It is recommended to avoid relying on the error API for critical functionality.\n *\n * _Available since v5.1._\n */\nlibrary Errors {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error InsufficientBalance(uint256 balance, uint256 needed);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedCall();\n\n /**\n * @dev The deployment failed.\n */\n error FailedDeployment();\n\n /**\n * @dev A necessary precompile is missing.\n */\n error MissingPrecompile(address);\n}\n"
},
"@openzeppelin/contracts/utils/introspection/ERC165.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n"
},
"@openzeppelin/contracts/utils/introspection/IERC165.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
},
"@openzeppelin/contracts/utils/math/Math.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.20;\n\nimport {Panic} from \"../Panic.sol\";\nimport {SafeCast} from \"./SafeCast.sol\";\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Floor, // Toward negative infinity\n Ceil, // Toward positive infinity\n Trunc, // Toward zero\n Expand // Away from zero\n }\n\n /**\n * @dev Return the 512-bit addition of two uint256.\n *\n * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.\n */\n function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n assembly (\"memory-safe\") {\n low := add(a, b)\n high := lt(low, a)\n }\n }\n\n /**\n * @dev Return the 512-bit multiplication of two uint256.\n *\n * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.\n */\n function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use\n // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = high * 2²⁵⁶ + low.\n assembly (\"memory-safe\") {\n let mm := mulmod(a, b, not(0))\n low := mul(a, b)\n high := sub(sub(mm, low), lt(mm, low))\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, with a success flag (no overflow).\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a + b;\n success = c >= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a - b;\n success = c <= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a * b;\n assembly (\"memory-safe\") {\n // Only true when the multiplication doesn't overflow\n // (c / a == b) || (a == 0)\n success := or(eq(div(c, a), b), iszero(a))\n }\n // equivalent to: success ? c : 0\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `DIV` opcode returns zero when the denominator is 0.\n result := div(a, b)\n }\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `MOD` opcode returns zero when the denominator is 0.\n result := mod(a, b)\n }\n }\n }\n\n /**\n * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryAdd(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.\n */\n function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {\n (, uint256 result) = trySub(a, b);\n return result;\n }\n\n /**\n * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryMul(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.\n *\n * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.\n * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute\n * one branch when needed, making this function more expensive.\n */\n function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {\n unchecked {\n // branchless ternary works because:\n // b ^ (a ^ b) == a\n // b ^ 0 == b\n return b ^ ((a ^ b) * SafeCast.toUint(condition));\n }\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return ternary(a > b, a, b);\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return ternary(a < b, a, b);\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds towards infinity instead\n * of rounding towards zero.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n if (b == 0) {\n // Guarantee the same behavior as in a regular Solidity division.\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n\n // The following calculation ensures accurate ceiling division without overflow.\n // Since a is non-zero, (a - 1) / b will not overflow.\n // The largest possible result occurs when (a - 1) / b is type(uint256).max,\n // but the largest value we can obtain is type(uint256).max - 1, which happens\n // when a = type(uint256).max and b = 1.\n unchecked {\n return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);\n }\n }\n\n /**\n * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n * denominator == 0.\n *\n * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by\n * Uniswap Labs also under MIT license.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n\n // Handle non-overflow cases, 256 by 256 division.\n if (high == 0) {\n // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n // The surrounding unchecked block does not change this fact.\n // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n return low / denominator;\n }\n\n // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.\n if (denominator <= high) {\n Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));\n }\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [high low].\n uint256 remainder;\n assembly (\"memory-safe\") {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n high := sub(high, gt(remainder, low))\n low := sub(low, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.\n\n uint256 twos = denominator & (0 - denominator);\n assembly (\"memory-safe\") {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [high low] by twos.\n low := div(low, twos)\n\n // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from high into low.\n low |= high * twos;\n\n // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such\n // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv ≡ 1 mod 2⁴.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n // works in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶\n inverse *= 2 - denominator * inverse; // inverse mod 2³²\n inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴\n inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is\n // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high\n // is no longer required.\n result = low * inverse;\n return result;\n }\n }\n\n /**\n * @dev Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);\n }\n\n /**\n * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.\n */\n function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n if (high >= 1 << n) {\n Panic.panic(Panic.UNDER_OVERFLOW);\n }\n return (high << (256 - n)) | (low >> n);\n }\n }\n\n /**\n * @dev Calculates x * y >> n with full precision, following the selected rounding direction.\n */\n function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {\n return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);\n }\n\n /**\n * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.\n *\n * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.\n * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.\n *\n * If the input value is not inversible, 0 is returned.\n *\n * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the\n * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.\n */\n function invMod(uint256 a, uint256 n) internal pure returns (uint256) {\n unchecked {\n if (n == 0) return 0;\n\n // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)\n // Used to compute integers x and y such that: ax + ny = gcd(a, n).\n // When the gcd is 1, then the inverse of a modulo n exists and it's x.\n // ax + ny = 1\n // ax = 1 + (-y)n\n // ax ≡ 1 (mod n) # x is the inverse of a modulo n\n\n // If the remainder is 0 the gcd is n right away.\n uint256 remainder = a % n;\n uint256 gcd = n;\n\n // Therefore the initial coefficients are:\n // ax + ny = gcd(a, n) = n\n // 0a + 1n = n\n int256 x = 0;\n int256 y = 1;\n\n while (remainder != 0) {\n uint256 quotient = gcd / remainder;\n\n (gcd, remainder) = (\n // The old remainder is the next gcd to try.\n remainder,\n // Compute the next remainder.\n // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd\n // where gcd is at most n (capped to type(uint256).max)\n gcd - remainder * quotient\n );\n\n (x, y) = (\n // Increment the coefficient of a.\n y,\n // Decrement the coefficient of n.\n // Can overflow, but the result is casted to uint256 so that the\n // next value of y is \"wrapped around\" to a value between 0 and n - 1.\n x - y * int256(quotient)\n );\n }\n\n if (gcd != 1) return 0; // No inverse exists.\n return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.\n }\n }\n\n /**\n * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.\n *\n * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is\n * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that\n * `a**(p-2)` is the modular multiplicative inverse of a in Fp.\n *\n * NOTE: this function does NOT check that `p` is a prime greater than `2`.\n */\n function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {\n unchecked {\n return Math.modExp(a, p - 2, p);\n }\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)\n *\n * Requirements:\n * - modulus can't be zero\n * - underlying staticcall to precompile must succeed\n *\n * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make\n * sure the chain you're using it on supports the precompiled contract for modular exponentiation\n * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,\n * the underlying function will succeed given the lack of a revert, but the result may be incorrectly\n * interpreted as 0.\n */\n function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {\n (bool success, uint256 result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).\n * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying\n * to operate modulo 0 or if the underlying precompile reverted.\n *\n * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain\n * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in\n * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack\n * of a revert, but the result may be incorrectly interpreted as 0.\n */\n function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {\n if (m == 0) return (false, 0);\n assembly (\"memory-safe\") {\n let ptr := mload(0x40)\n // | Offset | Content | Content (Hex) |\n // |-----------|------------|--------------------------------------------------------------------|\n // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x60:0x7f | value of b | 0x<.............................................................b> |\n // | 0x80:0x9f | value of e | 0x<.............................................................e> |\n // | 0xa0:0xbf | value of m | 0x<.............................................................m> |\n mstore(ptr, 0x20)\n mstore(add(ptr, 0x20), 0x20)\n mstore(add(ptr, 0x40), 0x20)\n mstore(add(ptr, 0x60), b)\n mstore(add(ptr, 0x80), e)\n mstore(add(ptr, 0xa0), m)\n\n // Given the result < m, it's guaranteed to fit in 32 bytes,\n // so we can use the memory scratch space located at offset 0.\n success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)\n result := mload(0x00)\n }\n }\n\n /**\n * @dev Variant of {modExp} that supports inputs of arbitrary length.\n */\n function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {\n (bool success, bytes memory result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Variant of {tryModExp} that supports inputs of arbitrary length.\n */\n function tryModExp(\n bytes memory b,\n bytes memory e,\n bytes memory m\n ) internal view returns (bool success, bytes memory result) {\n if (_zeroBytes(m)) return (false, new bytes(0));\n\n uint256 mLen = m.length;\n\n // Encode call args in result and move the free memory pointer\n result = abi.encodePacked(b.length, e.length, mLen, b, e, m);\n\n assembly (\"memory-safe\") {\n let dataPtr := add(result, 0x20)\n // Write result on top of args to avoid allocating extra memory.\n success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)\n // Overwrite the length.\n // result.length > returndatasize() is guaranteed because returndatasize() == m.length\n mstore(result, mLen)\n // Set the memory pointer after the returned data.\n mstore(0x40, add(dataPtr, mLen))\n }\n }\n\n /**\n * @dev Returns whether the provided byte array is zero.\n */\n function _zeroBytes(bytes memory byteArray) private pure returns (bool) {\n for (uint256 i = 0; i < byteArray.length; ++i) {\n if (byteArray[i] != 0) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded\n * towards zero.\n *\n * This method is based on Newton's method for computing square roots; the algorithm is restricted to only\n * using integer operations.\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n unchecked {\n // Take care of easy edge cases when a == 0 or a == 1\n if (a <= 1) {\n return a;\n }\n\n // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a\n // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between\n // the current value as `ε_n = | x_n - sqrt(a) |`.\n //\n // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root\n // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is\n // bigger than any uint256.\n //\n // By noticing that\n // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`\n // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar\n // to the msb function.\n uint256 aa = a;\n uint256 xn = 1;\n\n if (aa >= (1 << 128)) {\n aa >>= 128;\n xn <<= 64;\n }\n if (aa >= (1 << 64)) {\n aa >>= 64;\n xn <<= 32;\n }\n if (aa >= (1 << 32)) {\n aa >>= 32;\n xn <<= 16;\n }\n if (aa >= (1 << 16)) {\n aa >>= 16;\n xn <<= 8;\n }\n if (aa >= (1 << 8)) {\n aa >>= 8;\n xn <<= 4;\n }\n if (aa >= (1 << 4)) {\n aa >>= 4;\n xn <<= 2;\n }\n if (aa >= (1 << 2)) {\n xn <<= 1;\n }\n\n // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).\n //\n // We can refine our estimation by noticing that the middle of that interval minimizes the error.\n // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).\n // This is going to be our x_0 (and ε_0)\n xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)\n\n // From here, Newton's method give us:\n // x_{n+1} = (x_n + a / x_n) / 2\n //\n // One should note that:\n // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a\n // = ((x_n² + a) / (2 * x_n))² - a\n // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a\n // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)\n // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)\n // = (x_n² - a)² / (2 * x_n)²\n // = ((x_n² - a) / (2 * x_n))²\n // ≥ 0\n // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n\n //\n // This gives us the proof of quadratic convergence of the sequence:\n // ε_{n+1} = | x_{n+1} - sqrt(a) |\n // = | (x_n + a / x_n) / 2 - sqrt(a) |\n // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |\n // = | (x_n - sqrt(a))² / (2 * x_n) |\n // = | ε_n² / (2 * x_n) |\n // = ε_n² / | (2 * x_n) |\n //\n // For the first iteration, we have a special case where x_0 is known:\n // ε_1 = ε_0² / | (2 * x_0) |\n // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))\n // ≤ 2**(2*e-4) / (3 * 2**(e-1))\n // ≤ 2**(e-3) / 3\n // ≤ 2**(e-3-log2(3))\n // ≤ 2**(e-4.5)\n //\n // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:\n // ε_{n+1} = ε_n² / | (2 * x_n) |\n // ≤ (2**(e-k))² / (2 * 2**(e-1))\n // ≤ 2**(2*e-2*k) / 2**e\n // ≤ 2**(e-2*k)\n xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above\n xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5\n xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9\n xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18\n xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36\n xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72\n\n // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision\n // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either\n // sqrt(a) or sqrt(a) + 1.\n return xn - SafeCast.toUint(xn > a / xn);\n }\n }\n\n /**\n * @dev Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);\n }\n }\n\n /**\n * @dev Return the log in base 2 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log2(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // If upper 8 bits of 16-bit half set, add 8 to result\n r |= SafeCast.toUint((x >> r) > 0xff) << 3;\n // If upper 4 bits of 8-bit half set, add 4 to result\n r |= SafeCast.toUint((x >> r) > 0xf) << 2;\n\n // Shifts value right by the current result and use it as an index into this lookup table:\n //\n // | x (4 bits) | index | table[index] = MSB position |\n // |------------|---------|-----------------------------|\n // | 0000 | 0 | table[0] = 0 |\n // | 0001 | 1 | table[1] = 0 |\n // | 0010 | 2 | table[2] = 1 |\n // | 0011 | 3 | table[3] = 1 |\n // | 0100 | 4 | table[4] = 2 |\n // | 0101 | 5 | table[5] = 2 |\n // | 0110 | 6 | table[6] = 2 |\n // | 0111 | 7 | table[7] = 2 |\n // | 1000 | 8 | table[8] = 3 |\n // | 1001 | 9 | table[9] = 3 |\n // | 1010 | 10 | table[10] = 3 |\n // | 1011 | 11 | table[11] = 3 |\n // | 1100 | 12 | table[12] = 3 |\n // | 1101 | 13 | table[13] = 3 |\n // | 1110 | 14 | table[14] = 3 |\n // | 1111 | 15 | table[15] = 3 |\n //\n // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.\n assembly (\"memory-safe\") {\n r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))\n }\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);\n }\n }\n\n /**\n * @dev Return the log in base 10 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10 ** 64) {\n value /= 10 ** 64;\n result += 64;\n }\n if (value >= 10 ** 32) {\n value /= 10 ** 32;\n result += 32;\n }\n if (value >= 10 ** 16) {\n value /= 10 ** 16;\n result += 16;\n }\n if (value >= 10 ** 8) {\n value /= 10 ** 8;\n result += 8;\n }\n if (value >= 10 ** 4) {\n value /= 10 ** 4;\n result += 4;\n }\n if (value >= 10 ** 2) {\n value /= 10 ** 2;\n result += 2;\n }\n if (value >= 10 ** 1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);\n }\n }\n\n /**\n * @dev Return the log in base 256 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8\n return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);\n }\n\n /**\n * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);\n }\n }\n\n /**\n * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.\n */\n function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {\n return uint8(rounding) % 2 == 1;\n }\n}\n"
},
"@openzeppelin/contracts/utils/math/SafeCast.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeCast {\n /**\n * @dev Value doesn't fit in an uint of `bits` size.\n */\n error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);\n\n /**\n * @dev An int value doesn't fit in an uint of `bits` size.\n */\n error SafeCastOverflowedIntToUint(int256 value);\n\n /**\n * @dev Value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);\n\n /**\n * @dev An uint value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedUintToInt(uint256 value);\n\n /**\n * @dev Returns the downcasted uint248 from uint256, reverting on\n * overflow (when the input is greater than largest uint248).\n *\n * Counterpart to Solidity's `uint248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n */\n function toUint248(uint256 value) internal pure returns (uint248) {\n if (value > type(uint248).max) {\n revert SafeCastOverflowedUintDowncast(248, value);\n }\n return uint248(value);\n }\n\n /**\n * @dev Returns the downcasted uint240 from uint256, reverting on\n * overflow (when the input is greater than largest uint240).\n *\n * Counterpart to Solidity's `uint240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n */\n function toUint240(uint256 value) internal pure returns (uint240) {\n if (value > type(uint240).max) {\n revert SafeCastOverflowedUintDowncast(240, value);\n }\n return uint240(value);\n }\n\n /**\n * @dev Returns the downcasted uint232 from uint256, reverting on\n * overflow (when the input is greater than largest uint232).\n *\n * Counterpart to Solidity's `uint232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n */\n function toUint232(uint256 value) internal pure returns (uint232) {\n if (value > type(uint232).max) {\n revert SafeCastOverflowedUintDowncast(232, value);\n }\n return uint232(value);\n }\n\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n if (value > type(uint224).max) {\n revert SafeCastOverflowedUintDowncast(224, value);\n }\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint216 from uint256, reverting on\n * overflow (when the input is greater than largest uint216).\n *\n * Counterpart to Solidity's `uint216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n */\n function toUint216(uint256 value) internal pure returns (uint216) {\n if (value > type(uint216).max) {\n revert SafeCastOverflowedUintDowncast(216, value);\n }\n return uint216(value);\n }\n\n /**\n * @dev Returns the downcasted uint208 from uint256, reverting on\n * overflow (when the input is greater than largest uint208).\n *\n * Counterpart to Solidity's `uint208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n */\n function toUint208(uint256 value) internal pure returns (uint208) {\n if (value > type(uint208).max) {\n revert SafeCastOverflowedUintDowncast(208, value);\n }\n return uint208(value);\n }\n\n /**\n * @dev Returns the downcasted uint200 from uint256, reverting on\n * overflow (when the input is greater than largest uint200).\n *\n * Counterpart to Solidity's `uint200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n */\n function toUint200(uint256 value) internal pure returns (uint200) {\n if (value > type(uint200).max) {\n revert SafeCastOverflowedUintDowncast(200, value);\n }\n return uint200(value);\n }\n\n /**\n * @dev Returns the downcasted uint192 from uint256, reverting on\n * overflow (when the input is greater than largest uint192).\n *\n * Counterpart to Solidity's `uint192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n */\n function toUint192(uint256 value) internal pure returns (uint192) {\n if (value > type(uint192).max) {\n revert SafeCastOverflowedUintDowncast(192, value);\n }\n return uint192(value);\n }\n\n /**\n * @dev Returns the downcasted uint184 from uint256, reverting on\n * overflow (when the input is greater than largest uint184).\n *\n * Counterpart to Solidity's `uint184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n */\n function toUint184(uint256 value) internal pure returns (uint184) {\n if (value > type(uint184).max) {\n revert SafeCastOverflowedUintDowncast(184, value);\n }\n return uint184(value);\n }\n\n /**\n * @dev Returns the downcasted uint176 from uint256, reverting on\n * overflow (when the input is greater than largest uint176).\n *\n * Counterpart to Solidity's `uint176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n */\n function toUint176(uint256 value) internal pure returns (uint176) {\n if (value > type(uint176).max) {\n revert SafeCastOverflowedUintDowncast(176, value);\n }\n return uint176(value);\n }\n\n /**\n * @dev Returns the downcasted uint168 from uint256, reverting on\n * overflow (when the input is greater than largest uint168).\n *\n * Counterpart to Solidity's `uint168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n */\n function toUint168(uint256 value) internal pure returns (uint168) {\n if (value > type(uint168).max) {\n revert SafeCastOverflowedUintDowncast(168, value);\n }\n return uint168(value);\n }\n\n /**\n * @dev Returns the downcasted uint160 from uint256, reverting on\n * overflow (when the input is greater than largest uint160).\n *\n * Counterpart to Solidity's `uint160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n */\n function toUint160(uint256 value) internal pure returns (uint160) {\n if (value > type(uint160).max) {\n revert SafeCastOverflowedUintDowncast(160, value);\n }\n return uint160(value);\n }\n\n /**\n * @dev Returns the downcasted uint152 from uint256, reverting on\n * overflow (when the input is greater than largest uint152).\n *\n * Counterpart to Solidity's `uint152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n */\n function toUint152(uint256 value) internal pure returns (uint152) {\n if (value > type(uint152).max) {\n revert SafeCastOverflowedUintDowncast(152, value);\n }\n return uint152(value);\n }\n\n /**\n * @dev Returns the downcasted uint144 from uint256, reverting on\n * overflow (when the input is greater than largest uint144).\n *\n * Counterpart to Solidity's `uint144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n */\n function toUint144(uint256 value) internal pure returns (uint144) {\n if (value > type(uint144).max) {\n revert SafeCastOverflowedUintDowncast(144, value);\n }\n return uint144(value);\n }\n\n /**\n * @dev Returns the downcasted uint136 from uint256, reverting on\n * overflow (when the input is greater than largest uint136).\n *\n * Counterpart to Solidity's `uint136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n */\n function toUint136(uint256 value) internal pure returns (uint136) {\n if (value > type(uint136).max) {\n revert SafeCastOverflowedUintDowncast(136, value);\n }\n return uint136(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n if (value > type(uint128).max) {\n revert SafeCastOverflowedUintDowncast(128, value);\n }\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint120 from uint256, reverting on\n * overflow (when the input is greater than largest uint120).\n *\n * Counterpart to Solidity's `uint120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n */\n function toUint120(uint256 value) internal pure returns (uint120) {\n if (value > type(uint120).max) {\n revert SafeCastOverflowedUintDowncast(120, value);\n }\n return uint120(value);\n }\n\n /**\n * @dev Returns the downcasted uint112 from uint256, reverting on\n * overflow (when the input is greater than largest uint112).\n *\n * Counterpart to Solidity's `uint112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n */\n function toUint112(uint256 value) internal pure returns (uint112) {\n if (value > type(uint112).max) {\n revert SafeCastOverflowedUintDowncast(112, value);\n }\n return uint112(value);\n }\n\n /**\n * @dev Returns the downcasted uint104 from uint256, reverting on\n * overflow (when the input is greater than largest uint104).\n *\n * Counterpart to Solidity's `uint104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n */\n function toUint104(uint256 value) internal pure returns (uint104) {\n if (value > type(uint104).max) {\n revert SafeCastOverflowedUintDowncast(104, value);\n }\n return uint104(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n if (value > type(uint96).max) {\n revert SafeCastOverflowedUintDowncast(96, value);\n }\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint88 from uint256, reverting on\n * overflow (when the input is greater than largest uint88).\n *\n * Counterpart to Solidity's `uint88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n */\n function toUint88(uint256 value) internal pure returns (uint88) {\n if (value > type(uint88).max) {\n revert SafeCastOverflowedUintDowncast(88, value);\n }\n return uint88(value);\n }\n\n /**\n * @dev Returns the downcasted uint80 from uint256, reverting on\n * overflow (when the input is greater than largest uint80).\n *\n * Counterpart to Solidity's `uint80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n */\n function toUint80(uint256 value) internal pure returns (uint80) {\n if (value > type(uint80).max) {\n revert SafeCastOverflowedUintDowncast(80, value);\n }\n return uint80(value);\n }\n\n /**\n * @dev Returns the downcasted uint72 from uint256, reverting on\n * overflow (when the input is greater than largest uint72).\n *\n * Counterpart to Solidity's `uint72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n */\n function toUint72(uint256 value) internal pure returns (uint72) {\n if (value > type(uint72).max) {\n revert SafeCastOverflowedUintDowncast(72, value);\n }\n return uint72(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n if (value > type(uint64).max) {\n revert SafeCastOverflowedUintDowncast(64, value);\n }\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint56 from uint256, reverting on\n * overflow (when the input is greater than largest uint56).\n *\n * Counterpart to Solidity's `uint56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n */\n function toUint56(uint256 value) internal pure returns (uint56) {\n if (value > type(uint56).max) {\n revert SafeCastOverflowedUintDowncast(56, value);\n }\n return uint56(value);\n }\n\n /**\n * @dev Returns the downcasted uint48 from uint256, reverting on\n * overflow (when the input is greater than largest uint48).\n *\n * Counterpart to Solidity's `uint48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n */\n function toUint48(uint256 value) internal pure returns (uint48) {\n if (value > type(uint48).max) {\n revert SafeCastOverflowedUintDowncast(48, value);\n }\n return uint48(value);\n }\n\n /**\n * @dev Returns the downcasted uint40 from uint256, reverting on\n * overflow (when the input is greater than largest uint40).\n *\n * Counterpart to Solidity's `uint40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n */\n function toUint40(uint256 value) internal pure returns (uint40) {\n if (value > type(uint40).max) {\n revert SafeCastOverflowedUintDowncast(40, value);\n }\n return uint40(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n if (value > type(uint32).max) {\n revert SafeCastOverflowedUintDowncast(32, value);\n }\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint24 from uint256, reverting on\n * overflow (when the input is greater than largest uint24).\n *\n * Counterpart to Solidity's `uint24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n */\n function toUint24(uint256 value) internal pure returns (uint24) {\n if (value > type(uint24).max) {\n revert SafeCastOverflowedUintDowncast(24, value);\n }\n return uint24(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n if (value > type(uint16).max) {\n revert SafeCastOverflowedUintDowncast(16, value);\n }\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n if (value > type(uint8).max) {\n revert SafeCastOverflowedUintDowncast(8, value);\n }\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n if (value < 0) {\n revert SafeCastOverflowedIntToUint(value);\n }\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int248 from int256, reverting on\n * overflow (when the input is less than smallest int248 or\n * greater than largest int248).\n *\n * Counterpart to Solidity's `int248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n */\n function toInt248(int256 value) internal pure returns (int248 downcasted) {\n downcasted = int248(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(248, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int240 from int256, reverting on\n * overflow (when the input is less than smallest int240 or\n * greater than largest int240).\n *\n * Counterpart to Solidity's `int240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n */\n function toInt240(int256 value) internal pure returns (int240 downcasted) {\n downcasted = int240(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(240, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int232 from int256, reverting on\n * overflow (when the input is less than smallest int232 or\n * greater than largest int232).\n *\n * Counterpart to Solidity's `int232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n */\n function toInt232(int256 value) internal pure returns (int232 downcasted) {\n downcasted = int232(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(232, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int224 from int256, reverting on\n * overflow (when the input is less than smallest int224 or\n * greater than largest int224).\n *\n * Counterpart to Solidity's `int224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toInt224(int256 value) internal pure returns (int224 downcasted) {\n downcasted = int224(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(224, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int216 from int256, reverting on\n * overflow (when the input is less than smallest int216 or\n * greater than largest int216).\n *\n * Counterpart to Solidity's `int216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n */\n function toInt216(int256 value) internal pure returns (int216 downcasted) {\n downcasted = int216(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(216, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int208 from int256, reverting on\n * overflow (when the input is less than smallest int208 or\n * greater than largest int208).\n *\n * Counterpart to Solidity's `int208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n */\n function toInt208(int256 value) internal pure returns (int208 downcasted) {\n downcasted = int208(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(208, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int200 from int256, reverting on\n * overflow (when the input is less than smallest int200 or\n * greater than largest int200).\n *\n * Counterpart to Solidity's `int200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n */\n function toInt200(int256 value) internal pure returns (int200 downcasted) {\n downcasted = int200(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(200, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int192 from int256, reverting on\n * overflow (when the input is less than smallest int192 or\n * greater than largest int192).\n *\n * Counterpart to Solidity's `int192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n */\n function toInt192(int256 value) internal pure returns (int192 downcasted) {\n downcasted = int192(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(192, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int184 from int256, reverting on\n * overflow (when the input is less than smallest int184 or\n * greater than largest int184).\n *\n * Counterpart to Solidity's `int184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n */\n function toInt184(int256 value) internal pure returns (int184 downcasted) {\n downcasted = int184(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(184, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int176 from int256, reverting on\n * overflow (when the input is less than smallest int176 or\n * greater than largest int176).\n *\n * Counterpart to Solidity's `int176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n */\n function toInt176(int256 value) internal pure returns (int176 downcasted) {\n downcasted = int176(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(176, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int168 from int256, reverting on\n * overflow (when the input is less than smallest int168 or\n * greater than largest int168).\n *\n * Counterpart to Solidity's `int168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n */\n function toInt168(int256 value) internal pure returns (int168 downcasted) {\n downcasted = int168(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(168, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int160 from int256, reverting on\n * overflow (when the input is less than smallest int160 or\n * greater than largest int160).\n *\n * Counterpart to Solidity's `int160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n */\n function toInt160(int256 value) internal pure returns (int160 downcasted) {\n downcasted = int160(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(160, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int152 from int256, reverting on\n * overflow (when the input is less than smallest int152 or\n * greater than largest int152).\n *\n * Counterpart to Solidity's `int152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n */\n function toInt152(int256 value) internal pure returns (int152 downcasted) {\n downcasted = int152(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(152, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int144 from int256, reverting on\n * overflow (when the input is less than smallest int144 or\n * greater than largest int144).\n *\n * Counterpart to Solidity's `int144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n */\n function toInt144(int256 value) internal pure returns (int144 downcasted) {\n downcasted = int144(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(144, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int136 from int256, reverting on\n * overflow (when the input is less than smallest int136 or\n * greater than largest int136).\n *\n * Counterpart to Solidity's `int136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n */\n function toInt136(int256 value) internal pure returns (int136 downcasted) {\n downcasted = int136(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(136, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toInt128(int256 value) internal pure returns (int128 downcasted) {\n downcasted = int128(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(128, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int120 from int256, reverting on\n * overflow (when the input is less than smallest int120 or\n * greater than largest int120).\n *\n * Counterpart to Solidity's `int120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n */\n function toInt120(int256 value) internal pure returns (int120 downcasted) {\n downcasted = int120(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(120, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int112 from int256, reverting on\n * overflow (when the input is less than smallest int112 or\n * greater than largest int112).\n *\n * Counterpart to Solidity's `int112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n */\n function toInt112(int256 value) internal pure returns (int112 downcasted) {\n downcasted = int112(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(112, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int104 from int256, reverting on\n * overflow (when the input is less than smallest int104 or\n * greater than largest int104).\n *\n * Counterpart to Solidity's `int104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n */\n function toInt104(int256 value) internal pure returns (int104 downcasted) {\n downcasted = int104(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(104, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int96 from int256, reverting on\n * overflow (when the input is less than smallest int96 or\n * greater than largest int96).\n *\n * Counterpart to Solidity's `int96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toInt96(int256 value) internal pure returns (int96 downcasted) {\n downcasted = int96(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(96, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int88 from int256, reverting on\n * overflow (when the input is less than smallest int88 or\n * greater than largest int88).\n *\n * Counterpart to Solidity's `int88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n */\n function toInt88(int256 value) internal pure returns (int88 downcasted) {\n downcasted = int88(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(88, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int80 from int256, reverting on\n * overflow (when the input is less than smallest int80 or\n * greater than largest int80).\n *\n * Counterpart to Solidity's `int80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n */\n function toInt80(int256 value) internal pure returns (int80 downcasted) {\n downcasted = int80(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(80, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int72 from int256, reverting on\n * overflow (when the input is less than smallest int72 or\n * greater than largest int72).\n *\n * Counterpart to Solidity's `int72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n */\n function toInt72(int256 value) internal pure returns (int72 downcasted) {\n downcasted = int72(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(72, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toInt64(int256 value) internal pure returns (int64 downcasted) {\n downcasted = int64(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(64, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int56 from int256, reverting on\n * overflow (when the input is less than smallest int56 or\n * greater than largest int56).\n *\n * Counterpart to Solidity's `int56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n */\n function toInt56(int256 value) internal pure returns (int56 downcasted) {\n downcasted = int56(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(56, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int48 from int256, reverting on\n * overflow (when the input is less than smallest int48 or\n * greater than largest int48).\n *\n * Counterpart to Solidity's `int48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n */\n function toInt48(int256 value) internal pure returns (int48 downcasted) {\n downcasted = int48(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(48, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int40 from int256, reverting on\n * overflow (when the input is less than smallest int40 or\n * greater than largest int40).\n *\n * Counterpart to Solidity's `int40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n */\n function toInt40(int256 value) internal pure returns (int40 downcasted) {\n downcasted = int40(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(40, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toInt32(int256 value) internal pure returns (int32 downcasted) {\n downcasted = int32(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(32, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int24 from int256, reverting on\n * overflow (when the input is less than smallest int24 or\n * greater than largest int24).\n *\n * Counterpart to Solidity's `int24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n */\n function toInt24(int256 value) internal pure returns (int24 downcasted) {\n downcasted = int24(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(24, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toInt16(int256 value) internal pure returns (int16 downcasted) {\n downcasted = int16(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(16, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n */\n function toInt8(int256 value) internal pure returns (int8 downcasted) {\n downcasted = int8(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(8, value);\n }\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n if (value > uint256(type(int256).max)) {\n revert SafeCastOverflowedUintToInt(value);\n }\n return int256(value);\n }\n\n /**\n * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.\n */\n function toUint(bool b) internal pure returns (uint256 u) {\n assembly (\"memory-safe\") {\n u := iszero(iszero(b))\n }\n }\n}\n"
},
"@openzeppelin/contracts/utils/Panic.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Helper library for emitting standardized panic codes.\n *\n * ```solidity\n * contract Example {\n * using Panic for uint256;\n *\n * // Use any of the declared internal constants\n * function foo() { Panic.GENERIC.panic(); }\n *\n * // Alternatively\n * function foo() { Panic.panic(Panic.GENERIC); }\n * }\n * ```\n *\n * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].\n *\n * _Available since v5.1._\n */\n// slither-disable-next-line unused-state\nlibrary Panic {\n /// @dev generic / unspecified error\n uint256 internal constant GENERIC = 0x00;\n /// @dev used by the assert() builtin\n uint256 internal constant ASSERT = 0x01;\n /// @dev arithmetic underflow or overflow\n uint256 internal constant UNDER_OVERFLOW = 0x11;\n /// @dev division or modulo by zero\n uint256 internal constant DIVISION_BY_ZERO = 0x12;\n /// @dev enum conversion error\n uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;\n /// @dev invalid encoding in storage\n uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;\n /// @dev empty array pop\n uint256 internal constant EMPTY_ARRAY_POP = 0x31;\n /// @dev array out of bounds access\n uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;\n /// @dev resource error (too large allocation or too large array)\n uint256 internal constant RESOURCE_ERROR = 0x41;\n /// @dev calling invalid internal function\n uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;\n\n /// @dev Reverts with a panic code. Recommended to use with\n /// the internal constants with predefined codes.\n function panic(uint256 code) internal pure {\n assembly (\"memory-safe\") {\n mstore(0x00, 0x4e487b71)\n mstore(0x20, code)\n revert(0x1c, 0x24)\n }\n }\n}\n"
},
"@openzeppelin/contracts/utils/ReentrancyGuard.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,\n * consider using {ReentrancyGuardTransient} instead.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant NOT_ENTERED = 1;\n uint256 private constant ENTERED = 2;\n\n uint256 private _status;\n\n /**\n * @dev Unauthorized reentrant call.\n */\n error ReentrancyGuardReentrantCall();\n\n constructor() {\n _status = NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n _nonReentrantBefore();\n _;\n _nonReentrantAfter();\n }\n\n function _nonReentrantBefore() private {\n // On the first call to nonReentrant, _status will be NOT_ENTERED\n if (_status == ENTERED) {\n revert ReentrancyGuardReentrantCall();\n }\n\n // Any calls to nonReentrant after this point will fail\n _status = ENTERED;\n }\n\n function _nonReentrantAfter() private {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = NOT_ENTERED;\n }\n\n /**\n * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n * `nonReentrant` function in the call stack.\n */\n function _reentrancyGuardEntered() internal view returns (bool) {\n return _status == ENTERED;\n }\n}\n"
},
"contracts/JubileeTimelock.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport \"@openzeppelin/contracts/governance/TimelockController.sol\";\n\n/**\n * @title JubileeTimelock\n * @notice 24-hour timelock for jBTCi strategy management\n * @dev Wraps OpenZeppelin's TimelockController for strategy governance\n *\n * Usage:\n * 1. Deploy this contract\n * 2. Transfer strategy management to this timelock\n * 3. All admin calls now require 24hr delay\n *\n * Emergency functions (pause, oracle mode) bypass timelock\n * by using the emergencyAdmin role directly on the strategy.\n */\ncontract JubileeTimelock is TimelockController {\n uint256 public constant MIN_DELAY = 1 days; // 24 hours\n\n /**\n * @notice Deploy the timelock\n * @param admin The address that can propose, execute, and cancel\n * @dev In production, consider separating proposer/executor roles\n */\n constructor(\n address admin\n )\n TimelockController(\n MIN_DELAY, // Minimum delay: 24 hours\n _toArray(admin), // Proposers: admin only\n _toArray(admin), // Executors: admin only\n address(0) // No separate admin (deployer manages)\n )\n {}\n\n /**\n * @dev Helper to create single-element array\n */\n function _toArray(address addr) internal pure returns (address[] memory) {\n address[] memory arr = new address[](1);\n arr[0] = addr;\n return arr;\n }\n}\n"
},
"contracts/lib/tokenized-strategy/BaseStrategy.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity >=0.8.18;\n\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\n// TokenizedStrategy interface used for internal view delegateCalls.\nimport {ITokenizedStrategy} from \"./interfaces/ITokenizedStrategy.sol\";\n\n/**\n * @title YearnV3 Base Strategy\n * @author yearn.finance\n * @notice\n * BaseStrategy implements all of the required functionality to\n * seamlessly integrate with the `TokenizedStrategy` implementation contract\n * allowing anyone to easily build a fully permissionless ERC-4626 compliant\n * Vault by inheriting this contract and overriding three simple functions.\n\n * It utilizes an immutable proxy pattern that allows the BaseStrategy\n * to remain simple and small. All standard logic is held within the\n * `TokenizedStrategy` and is reused over any n strategies all using the\n * `fallback` function to delegatecall the implementation so that strategists\n * can only be concerned with writing their strategy specific code.\n *\n * This contract should be inherited and the three main abstract methods\n * `_deployFunds`, `_freeFunds` and `_harvestAndReport` implemented to adapt\n * the Strategy to the particular needs it has to generate yield. There are\n * other optional methods that can be implemented to further customize\n * the strategy if desired.\n *\n * All default storage for the strategy is controlled and updated by the\n * `TokenizedStrategy`. The implementation holds a storage struct that\n * contains all needed global variables in a manual storage slot. This\n * means strategists can feel free to implement their own custom storage\n * variables as they need with no concern of collisions. All global variables\n * can be viewed within the Strategy by a simple call using the\n * `TokenizedStrategy` variable. IE: TokenizedStrategy.globalVariable();.\n */\nabstract contract BaseStrategy {\n /*//////////////////////////////////////////////////////////////\n MODIFIERS\n //////////////////////////////////////////////////////////////*/\n /**\n * @dev Used on TokenizedStrategy callback functions to make sure it is post\n * a delegateCall from this address to the TokenizedStrategy.\n */\n modifier onlySelf() {\n _onlySelf();\n _;\n }\n\n /**\n * @dev Use to assure that the call is coming from the strategies management.\n */\n modifier onlyManagement() {\n TokenizedStrategy.requireManagement(msg.sender);\n _;\n }\n\n /**\n * @dev Use to assure that the call is coming from either the strategies\n * management or the keeper.\n */\n modifier onlyKeepers() {\n TokenizedStrategy.requireKeeperOrManagement(msg.sender);\n _;\n }\n\n /**\n * @dev Use to assure that the call is coming from either the strategies\n * management or the emergency admin.\n */\n modifier onlyEmergencyAuthorized() {\n TokenizedStrategy.requireEmergencyAuthorized(msg.sender);\n _;\n }\n\n /**\n * @dev Require that the msg.sender is this address.\n */\n function _onlySelf() internal view {\n require(msg.sender == address(this), \"!self\");\n }\n\n /*//////////////////////////////////////////////////////////////\n CONSTANTS\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @dev This is the address of the TokenizedStrategy implementation\n * contract that will be used by all strategies to handle the\n * accounting, logic, storage etc.\n *\n * Any external calls to the that don't hit one of the functions\n * defined in this base or the strategy will end up being forwarded\n * through the fallback function, which will delegateCall this address.\n *\n * This address should be the same for every strategy, never be adjusted\n * and always be checked before any integration with the Strategy.\n */\n // NOTE: This is a holder address based on expected deterministic location for testing\n address public constant tokenizedStrategyAddress =\n 0x2e234DAe75C793f67A35089C9d99245E1C58470b;\n\n /*//////////////////////////////////////////////////////////////\n IMMUTABLES\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @dev Underlying asset the Strategy is earning yield on.\n * Stored here for cheap retrievals within the strategy.\n */\n ERC20 internal immutable asset;\n\n /**\n * @dev This variable is set to address(this) during initialization of each strategy.\n *\n * This can be used to retrieve storage data within the strategy\n * contract as if it were a linked library.\n *\n * i.e. uint256 totalAssets = TokenizedStrategy.totalAssets()\n *\n * Using address(this) will mean any calls using this variable will lead\n * to a call to itself. Which will hit the fallback function and\n * delegateCall that to the actual TokenizedStrategy.\n */\n ITokenizedStrategy internal immutable TokenizedStrategy;\n\n /**\n * @notice Used to initialize the strategy on deployment.\n *\n * This will set the `TokenizedStrategy` variable for easy\n * internal view calls to the implementation. As well as\n * initializing the default storage variables based on the\n * parameters and using the deployer for the permissioned roles.\n *\n * @param _asset Address of the underlying asset.\n * @param _name Name the strategy will use.\n */\n constructor(address _asset, string memory _name) {\n asset = ERC20(_asset);\n\n // Set instance of the implementation for internal use.\n TokenizedStrategy = ITokenizedStrategy(address(this));\n\n // Initialize the strategy's storage variables.\n _delegateCall(\n abi.encodeCall(\n ITokenizedStrategy.initialize,\n (_asset, _name, msg.sender, msg.sender, msg.sender)\n )\n );\n\n // Store the tokenizedStrategyAddress at the standard implementation\n // address storage slot so etherscan picks up the interface. This gets\n // stored on initialization and never updated.\n assembly {\n sstore(\n // keccak256('eip1967.proxy.implementation' - 1)\n 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc,\n tokenizedStrategyAddress\n )\n }\n }\n\n /*//////////////////////////////////////////////////////////////\n NEEDED TO BE OVERRIDDEN BY STRATEGIST\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @dev Can deploy up to '_amount' of 'asset' in the yield source.\n *\n * This function is called at the end of a {deposit} or {mint}\n * call. Meaning that unless a whitelist is implemented it will\n * be entirely permissionless and thus can be sandwiched or otherwise\n * manipulated.\n *\n * @param _amount The amount of 'asset' that the strategy can attempt\n * to deposit in the yield source.\n */\n function _deployFunds(uint256 _amount) internal virtual;\n\n /**\n * @dev Should attempt to free the '_amount' of 'asset'.\n *\n * NOTE: The amount of 'asset' that is already loose has already\n * been accounted for.\n *\n * This function is called during {withdraw} and {redeem} calls.\n * Meaning that unless a whitelist is implemented it will be\n * entirely permissionless and thus can be sandwiched or otherwise\n * manipulated.\n *\n * Should not rely on asset.balanceOf(address(this)) calls other than\n * for diff accounting purposes.\n *\n * Any difference between `_amount` and what is actually freed will be\n * counted as a loss and passed on to the withdrawer. This means\n * care should be taken in times of illiquidity. It may be better to revert\n * if withdraws are simply illiquid so not to realize incorrect losses.\n *\n * @param _amount, The amount of 'asset' to be freed.\n */\n function _freeFunds(uint256 _amount) internal virtual;\n\n /**\n * @dev Internal function to harvest all rewards, redeploy any idle\n * funds and return an accurate accounting of all funds currently\n * held by the Strategy.\n *\n * This should do any needed harvesting, rewards selling, accrual,\n * redepositing etc. to get the most accurate view of current assets.\n *\n * NOTE: All applicable assets including loose assets should be\n * accounted for in this function.\n *\n * Care should be taken when relying on oracles or swap values rather\n * than actual amounts as all Strategy profit/loss accounting will\n * be done based on this returned value.\n *\n * This can still be called post a shutdown, a strategist can check\n * `TokenizedStrategy.isShutdown()` to decide if funds should be\n * redeployed or simply realize any profits/losses.\n *\n * @return _totalAssets A trusted and accurate account for the total\n * amount of 'asset' the strategy currently holds including idle funds.\n */\n function _harvestAndReport()\n internal\n virtual\n returns (uint256 _totalAssets);\n\n /*//////////////////////////////////////////////////////////////\n OPTIONAL TO OVERRIDE BY STRATEGIST\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @dev Optional function for strategist to override that can\n * be called in between reports.\n *\n * If '_tend' is used tendTrigger() will also need to be overridden.\n *\n * This call can only be called by a permissioned role so may be\n * through protected relays.\n *\n * This can be used to harvest and compound rewards, deposit idle funds,\n * perform needed position maintenance or anything else that doesn't need\n * a full report for.\n *\n * EX: A strategy that can not deposit funds without getting\n * sandwiched can use the tend when a certain threshold\n * of idle to totalAssets has been reached.\n *\n * This will have no effect on PPS of the strategy till report() is called.\n *\n * @param _totalIdle The current amount of idle funds that are available to deploy.\n */\n function _tend(uint256 _totalIdle) internal virtual {}\n\n /**\n * @dev Optional trigger to override if tend() will be used by the strategy.\n * This must be implemented if the strategy hopes to invoke _tend().\n *\n * @return . Should return true if tend() should be called by keeper or false if not.\n */\n function _tendTrigger() internal view virtual returns (bool) {\n return false;\n }\n\n /**\n * @notice Returns if tend() should be called by a keeper.\n *\n * @return . Should return true if tend() should be called by keeper or false if not.\n * @return . Calldata for the tend call.\n */\n function tendTrigger() external view virtual returns (bool, bytes memory) {\n return (\n // Return the status of the tend trigger.\n _tendTrigger(),\n // And the needed calldata either way.\n abi.encodeWithSelector(ITokenizedStrategy.tend.selector)\n );\n }\n\n /**\n * @notice Gets the max amount of `asset` that an address can deposit.\n * @dev Defaults to an unlimited amount for any address. But can\n * be overridden by strategists.\n *\n * This function will be called before any deposit or mints to enforce\n * any limits desired by the strategist. This can be used for either a\n * traditional deposit limit or for implementing a whitelist etc.\n *\n * EX:\n * if(isAllowed[_owner]) return super.availableDepositLimit(_owner);\n *\n * This does not need to take into account any conversion rates\n * from shares to assets. But should know that any non max uint256\n * amounts may be converted to shares. So it is recommended to keep\n * custom amounts low enough as not to cause overflow when multiplied\n * by `totalSupply`.\n *\n * @param . The address that is depositing into the strategy.\n * @return . The available amount the `_owner` can deposit in terms of `asset`\n */\n function availableDepositLimit(\n address /*_owner*/\n ) public view virtual returns (uint256) {\n return type(uint256).max;\n }\n\n /**\n * @notice Gets the max amount of `asset` that can be withdrawn.\n * @dev Defaults to an unlimited amount for any address. But can\n * be overridden by strategists.\n *\n * This function will be called before any withdraw or redeem to enforce\n * any limits desired by the strategist. This can be used for illiquid\n * or sandwichable strategies. It should never be lower than `totalIdle`.\n *\n * EX:\n * return TokenIzedStrategy.totalIdle();\n *\n * This does not need to take into account the `_owner`'s share balance\n * or conversion rates from shares to assets.\n *\n * @param . The address that is withdrawing from the strategy.\n * @return . The available amount that can be withdrawn in terms of `asset`\n */\n function availableWithdrawLimit(\n address /*_owner*/\n ) public view virtual returns (uint256) {\n return type(uint256).max;\n }\n\n /**\n * @dev Optional function for a strategist to override that will\n * allow management to manually withdraw deployed funds from the\n * yield source if a strategy is shutdown.\n *\n * This should attempt to free `_amount`, noting that `_amount` may\n * be more than is currently deployed.\n *\n * NOTE: This will not realize any profits or losses. A separate\n * {report} will be needed in order to record any profit/loss. If\n * a report may need to be called after a shutdown it is important\n * to check if the strategy is shutdown during {_harvestAndReport}\n * so that it does not simply re-deploy all funds that had been freed.\n *\n * EX:\n * if(freeAsset > 0 && !TokenizedStrategy.isShutdown()) {\n * depositFunds...\n * }\n *\n * @param _amount The amount of asset to attempt to free.\n */\n function _emergencyWithdraw(uint256 _amount) internal virtual {}\n\n /*//////////////////////////////////////////////////////////////\n TokenizedStrategy HOOKS\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @notice Can deploy up to '_amount' of 'asset' in yield source.\n * @dev Callback for the TokenizedStrategy to call during a {deposit}\n * or {mint} to tell the strategy it can deploy funds.\n *\n * Since this can only be called after a {deposit} or {mint}\n * delegateCall to the TokenizedStrategy msg.sender == address(this).\n *\n * Unless a whitelist is implemented this will be entirely permissionless\n * and thus can be sandwiched or otherwise manipulated.\n *\n * @param _amount The amount of 'asset' that the strategy can\n * attempt to deposit in the yield source.\n */\n function deployFunds(uint256 _amount) external virtual onlySelf {\n _deployFunds(_amount);\n }\n\n /**\n * @notice Should attempt to free the '_amount' of 'asset'.\n * @dev Callback for the TokenizedStrategy to call during a withdraw\n * or redeem to free the needed funds to service the withdraw.\n *\n * This can only be called after a 'withdraw' or 'redeem' delegateCall\n * to the TokenizedStrategy so msg.sender == address(this).\n *\n * @param _amount The amount of 'asset' that the strategy should attempt to free up.\n */\n function freeFunds(uint256 _amount) external virtual onlySelf {\n _freeFunds(_amount);\n }\n\n /**\n * @notice Returns the accurate amount of all funds currently\n * held by the Strategy.\n * @dev Callback for the TokenizedStrategy to call during a report to\n * get an accurate accounting of assets the strategy controls.\n *\n * This can only be called after a report() delegateCall to the\n * TokenizedStrategy so msg.sender == address(this).\n *\n * @return . A trusted and accurate account for the total amount\n * of 'asset' the strategy currently holds including idle funds.\n */\n function harvestAndReport() external virtual onlySelf returns (uint256) {\n return _harvestAndReport();\n }\n\n /**\n * @notice Will call the internal '_tend' when a keeper tends the strategy.\n * @dev Callback for the TokenizedStrategy to initiate a _tend call in the strategy.\n *\n * This can only be called after a tend() delegateCall to the TokenizedStrategy\n * so msg.sender == address(this).\n *\n * We name the function `tendThis` so that `tend` calls are forwarded to\n * the TokenizedStrategy.\n\n * @param _totalIdle The amount of current idle funds that can be\n * deployed during the tend\n */\n function tendThis(uint256 _totalIdle) external virtual onlySelf {\n _tend(_totalIdle);\n }\n\n /**\n * @notice Will call the internal '_emergencyWithdraw' function.\n * @dev Callback for the TokenizedStrategy during an emergency withdraw.\n *\n * This can only be called after a emergencyWithdraw() delegateCall to\n * the TokenizedStrategy so msg.sender == address(this).\n *\n * We name the function `shutdownWithdraw` so that `emergencyWithdraw`\n * calls are forwarded to the TokenizedStrategy.\n *\n * @param _amount The amount of asset to attempt to free.\n */\n function shutdownWithdraw(uint256 _amount) external virtual onlySelf {\n _emergencyWithdraw(_amount);\n }\n\n /**\n * @dev Function used to delegate call the TokenizedStrategy with\n * certain `_calldata` and return any return values.\n *\n * This is used to setup the initial storage of the strategy, and\n * can be used by strategist to forward any other call to the\n * TokenizedStrategy implementation.\n *\n * @param _calldata The abi encoded calldata to use in delegatecall.\n * @return . The return value if the call was successful in bytes.\n */\n function _delegateCall(\n bytes memory _calldata\n ) internal returns (bytes memory) {\n // Delegate call the tokenized strategy with provided calldata.\n (bool success, bytes memory result) = tokenizedStrategyAddress\n .delegatecall(_calldata);\n\n // If the call reverted. Return the error.\n if (!success) {\n assembly {\n let ptr := mload(0x40)\n let size := returndatasize()\n returndatacopy(ptr, 0, size)\n revert(ptr, size)\n }\n }\n\n // Return the result.\n return result;\n }\n\n /**\n * @dev Execute a function on the TokenizedStrategy and return any value.\n *\n * This fallback function will be executed when any of the standard functions\n * defined in the TokenizedStrategy are called since they wont be defined in\n * this contract.\n *\n * It will delegatecall the TokenizedStrategy implementation with the exact\n * calldata and return any relevant values.\n *\n */\n fallback() external {\n // load our target address\n address _tokenizedStrategyAddress = tokenizedStrategyAddress;\n // Execute external function using delegatecall and return any value.\n assembly {\n // Copy function selector and any arguments.\n calldatacopy(0, 0, calldatasize())\n // Execute function delegatecall.\n let result := delegatecall(\n gas(),\n _tokenizedStrategyAddress,\n 0,\n calldatasize(),\n 0,\n 0\n )\n // Get any return value\n returndatacopy(0, 0, returndatasize())\n // Return any return value or error back to the caller\n switch result\n case 0 {\n revert(0, returndatasize())\n }\n default {\n return(0, returndatasize())\n }\n }\n }\n}\n"
},
"contracts/lib/tokenized-strategy/BaseTokenizedStrategy.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity >=0.8.18;\n\n// Re-export BaseStrategy as BaseTokenizedStrategy for backward compatibility\nimport {BaseStrategy as BaseTokenizedStrategy} from \"./BaseStrategy.sol\";\n"
},
"contracts/lib/tokenized-strategy/interfaces/IBaseStrategy.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity >=0.8.18;\n\ninterface IBaseStrategy {\n function tokenizedStrategyAddress() external view returns (address);\n\n /*//////////////////////////////////////////////////////////////\n IMMUTABLE FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n function availableDepositLimit(\n address _owner\n ) external view returns (uint256);\n\n function availableWithdrawLimit(\n address _owner\n ) external view returns (uint256);\n\n function deployFunds(uint256 _assets) external;\n\n function freeFunds(uint256 _amount) external;\n\n function harvestAndReport() external returns (uint256);\n\n function tendThis(uint256 _totalIdle) external;\n\n function shutdownWithdraw(uint256 _amount) external;\n\n function tendTrigger() external view returns (bool, bytes memory);\n}\n"
},
"contracts/lib/tokenized-strategy/interfaces/IEvents.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity >=0.8.18;\n\ninterface IEvents {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @notice Emitted when a strategy is shutdown.\n */\n event StrategyShutdown();\n\n /**\n * @notice Emitted on the initialization of any new `strategy` that uses `asset`\n * with this specific `apiVersion`.\n */\n event NewTokenizedStrategy(\n address indexed strategy,\n address indexed asset,\n string apiVersion\n );\n\n /**\n * @notice Emitted when the strategy reports `profit` or `loss` and\n * `performanceFees` and `protocolFees` are paid out.\n */\n event Reported(\n uint256 profit,\n uint256 loss,\n uint256 protocolFees,\n uint256 performanceFees\n );\n\n /**\n * @notice Emitted when the 'performanceFeeRecipient' address is\n * updated to 'newPerformanceFeeRecipient'.\n */\n event UpdatePerformanceFeeRecipient(\n address indexed newPerformanceFeeRecipient\n );\n\n /**\n * @notice Emitted when the 'keeper' address is updated to 'newKeeper'.\n */\n event UpdateKeeper(address indexed newKeeper);\n\n /**\n * @notice Emitted when the 'performanceFee' is updated to 'newPerformanceFee'.\n */\n event UpdatePerformanceFee(uint16 newPerformanceFee);\n\n /**\n * @notice Emitted when the 'management' address is updated to 'newManagement'.\n */\n event UpdateManagement(address indexed newManagement);\n\n /**\n * @notice Emitted when the 'emergencyAdmin' address is updated to 'newEmergencyAdmin'.\n */\n event UpdateEmergencyAdmin(address indexed newEmergencyAdmin);\n\n /**\n * @notice Emitted when the 'profitMaxUnlockTime' is updated to 'newProfitMaxUnlockTime'.\n */\n event UpdateProfitMaxUnlockTime(uint256 newProfitMaxUnlockTime);\n\n /**\n * @notice Emitted when the 'pendingManagement' address is updated to 'newPendingManagement'.\n */\n event UpdatePendingManagement(address indexed newPendingManagement);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the `caller` has exchanged `assets` for `shares`,\n * and transferred those `shares` to `owner`.\n */\n event Deposit(\n address indexed caller,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n\n /**\n * @dev Emitted when the `caller` has exchanged `owner`s `shares` for `assets`,\n * and transferred those `assets` to `receiver`.\n */\n event Withdraw(\n address indexed caller,\n address indexed receiver,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n}\n"
},
"contracts/lib/tokenized-strategy/interfaces/IFactory.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity >=0.8.18;\n\ninterface IFactory {\n function protocol_fee_config() external view returns (uint16, address);\n}\n"
},
"contracts/lib/tokenized-strategy/interfaces/IStrategy.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity >=0.8.18;\n\nimport {ITokenizedStrategy} from \"./ITokenizedStrategy.sol\";\nimport {IBaseStrategy} from \"./IBaseStrategy.sol\";\n\ninterface IStrategy is IBaseStrategy, ITokenizedStrategy {}\n"
},
"contracts/lib/tokenized-strategy/interfaces/ITokenizedStrategy.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity >=0.8.18;\n\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {IERC4626} from \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\nimport {IERC20Permit} from \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\";\n\n// Interface that implements the 4626 standard and the implementation functions\ninterface ITokenizedStrategy is IERC4626, IERC20Permit {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event StrategyShutdown();\n\n event NewTokenizedStrategy(\n address indexed strategy,\n address indexed asset,\n string apiVersion\n );\n\n event Reported(\n uint256 profit,\n uint256 loss,\n uint256 protocolFees,\n uint256 performanceFees\n );\n\n event UpdatePerformanceFeeRecipient(\n address indexed newPerformanceFeeRecipient\n );\n\n event UpdateKeeper(address indexed newKeeper);\n\n event UpdatePerformanceFee(uint16 newPerformanceFee);\n\n event UpdateManagement(address indexed newManagement);\n\n event UpdateEmergencyAdmin(address indexed newEmergencyAdmin);\n\n event UpdateProfitMaxUnlockTime(uint256 newProfitMaxUnlockTime);\n\n event UpdatePendingManagement(address indexed newPendingManagement);\n\n /*//////////////////////////////////////////////////////////////\n INITIALIZATION\n //////////////////////////////////////////////////////////////*/\n\n function initialize(\n address _asset,\n string memory _name,\n address _management,\n address _performanceFeeRecipient,\n address _keeper\n ) external;\n\n /*//////////////////////////////////////////////////////////////\n NON-STANDARD 4626 OPTIONS\n //////////////////////////////////////////////////////////////*/\n\n function withdraw(\n uint256 assets,\n address receiver,\n address owner,\n uint256 maxLoss\n ) external returns (uint256);\n\n function redeem(\n uint256 shares,\n address receiver,\n address owner,\n uint256 maxLoss\n ) external returns (uint256);\n\n function maxWithdraw(\n address owner,\n uint256 /*maxLoss*/\n ) external view returns (uint256);\n\n function maxRedeem(\n address owner,\n uint256 /*maxLoss*/\n ) external view returns (uint256);\n\n /*//////////////////////////////////////////////////////////////\n MODIFIER HELPERS\n //////////////////////////////////////////////////////////////*/\n\n function requireManagement(address _sender) external view;\n\n function requireKeeperOrManagement(address _sender) external view;\n\n function requireEmergencyAuthorized(address _sender) external view;\n\n /*//////////////////////////////////////////////////////////////\n KEEPERS FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n function tend() external;\n\n function report() external returns (uint256 _profit, uint256 _loss);\n\n /*//////////////////////////////////////////////////////////////\n CONSTANTS\n //////////////////////////////////////////////////////////////*/\n\n function MAX_FEE() external view returns (uint16);\n\n function FACTORY() external view returns (address);\n\n /*//////////////////////////////////////////////////////////////\n GETTERS\n //////////////////////////////////////////////////////////////*/\n\n function apiVersion() external view returns (string memory);\n\n function pricePerShare() external view returns (uint256);\n\n function management() external view returns (address);\n\n function pendingManagement() external view returns (address);\n\n function keeper() external view returns (address);\n\n function emergencyAdmin() external view returns (address);\n\n function performanceFee() external view returns (uint16);\n\n function performanceFeeRecipient() external view returns (address);\n\n function fullProfitUnlockDate() external view returns (uint256);\n\n function profitUnlockingRate() external view returns (uint256);\n\n function profitMaxUnlockTime() external view returns (uint256);\n\n function lastReport() external view returns (uint256);\n\n function isShutdown() external view returns (bool);\n\n function unlockedShares() external view returns (uint256);\n\n /*//////////////////////////////////////////////////////////////\n SETTERS\n //////////////////////////////////////////////////////////////*/\n\n function setPendingManagement(address) external;\n\n function acceptManagement() external;\n\n function setKeeper(address _keeper) external;\n\n function setEmergencyAdmin(address _emergencyAdmin) external;\n\n function setPerformanceFee(uint16 _performanceFee) external;\n\n function setPerformanceFeeRecipient(\n address _performanceFeeRecipient\n ) external;\n\n function setProfitMaxUnlockTime(uint256 _profitMaxUnlockTime) external;\n\n function setName(string calldata _newName) external;\n\n function shutdownStrategy() external;\n\n function emergencyWithdraw(uint256 _amount) external;\n}\n"
},
"contracts/lib/tokenized-strategy/TokenizedStrategy.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0\npragma solidity >=0.8.18;\n\n/**$$$$$$$$$$$$$$$$$$$$$$$$$$$&Mr/|1+~>>iiiiiiiiiii>~+{|tuMW$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n$$$$$$$$$$$$$$$$$$$$$$$$$B#j]->iiiiiiiiiiiiiiiiiiiiiiiiiiii>-?f*B$$$$$$$$$$$$$$$$$$$$$$$$$\n$$$$$$$$$$$$$$$$$$$$$@zj}~iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii~}fv@$$$$$$$$$$$$$$$$$$$$$\n$$$$$$$$$$$$$$$$$$@z(+iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii+)zB$$$$$$$$$$$$$$$$$$\n$$$$$$$$$$$$$$$$Mf~iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii~t#@$$$$$$$$$$$$$$$\n$$$$$$$$$$$$$@u[iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii?n@$$$$$$$$$$$$$\n$$$$$$$$$$$@z]iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii?u@$$$$$$$$$$$\n$$$$$$$$$$v]iiiiiiiiiiiiiiii,.';iiiiiiiiiiiiiiiiiiiiiiiiii;'.\"iiiiiiiiiiiiiiii?u$$$$$$$$$$\n$$$$$$$$%)>iiiiiiiiiiiiiii,. ';iiiiiiiiiiiiiiiiiiiiii;' .\"iiiiiiiiiiiiiiii1%$$$$$$$$\n$$$$$$$c~iiiiiiiiiiiiiii,. ';iiiiiiiiiiiiiiiiii;' .\"iiiiiiiiiiiiiii~u$$$$$$$\n$$$$$B/>iiiiiiiiiiiiii!' `IiiiiiiiiiiiiiiI` .Iiiiiiiiiiiiiii>|%$$$$$\n$$$$@)iiiiiiiiiiiiiiiii;' `Iiiiiiiiiiil` ';iiiiiiiiiiiiiiiii}@$$$$\n$$$B|iiiiiiiiiiiiiiiiiiii;' `Iiiiiiil` ';iiiiiiiiiiiiiiiiiiii1B$$$\n$$@)iiiiiiiiiiiiiiiiiiiiiii:' `;iiI` ':iiiiiiiiiiiiiiiiiiiiiii{B$$\n$$|iiiiiiiiiiiiiiiiiiiiiiiiii;' `` ':iiiiiiiiiiiiiiiiiiiiiiiiii1$$\n$v>iiiiiiiiiiiiiiiiiiiiiiiiiiii:' ':iiiiiiiiiiiiiiiiiiiiiiiiiiii>x$\n&?iiiiiiiiiiiiiiiiiiiiiiiiiiiiiii:' .,iiiiiiiiiiiiiiiiiiiiiiiiiiiiiii-W\nziiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii:' .,iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiv\n-iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii:' .,iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii-\n<iiiiiiiiiiiiiiiiiiii!.':iiiiiiiiiiiiii, \"iiiiiiiiiiiiii;'.Iiiiiiiiiiiiiiiiiiiii<\niiiiiiiiiiiiiiiiiiiii' ';iiiiiiiiiiiii Iiiiiiiiiiiii;' .iiiiiiiiiiiiiiiiiiiii\niiiiiiiiiiiiiiiiiiii, ';iiiiiiiiiii IiiiiiiiiiiI` `iiiiiiiiiiiiiiiiiiii\niiiiiiiiiiiiiiiiiiii. `Iiiiiiiiii Iiiiiiiii!` !iiiiiiiiiiiiiiiiiii\niiiiiiiiiiiiiiiiiii; :iiiiiiiii Iiiiiiiii! ,iiiiiiiiiiiiiiiiiii\niiiiiiiiiiiiiiiiiii, iiiiiiiiii Iiiiiiiiii. ^iiiiiiiiiiiiiiiiiii\n<iiiiiiiiiiiiiiiiii, iiiiiiiiii Iiiiiiiiii' ^iiiiiiiiiiiiiiiiii<\n-iiiiiiiiiiiiiiiiii; Iiiiiiiiii Iiiiiiiiii. \"iiiiiiiiiiiiiiiiii-\nziiiiiiiiiiiiiiiiiii. 'iiiiiiiii''''''''''liiiiiiii^ liiiiiiiiiiiiiiiiiiv\n&?iiiiiiiiiiiiiiiiii^ ^iiiiiiiiiiiiiiiiiiiiiiiiii, `iiiiiiiiiiiiiiiiii_W\n$u>iiiiiiiiiiiiiiiiii. `!iiiiiiiiiiiiiiiiiiiiiii^ .liiiiiiiiiiiiiiiiiir$\n$$(iiiiiiiiiiiiiiiiii;. .\"iiiiiiiiiiiiiiiiiiii,. :iiiiiiiiiiiiiiiiii}$$\n$$@{iiiiiiiiiiiiiiiiii;. .`:iiiiiiiiiiiiii;^. :iiiiiiiiiiiiiiiiii}B$$\n$$$B)iiiiiiiiiiiiiiiiii!' '`\",::::,\"`'. .Iiiiiiiiiiiiiiiiiii{%$$$\n$$$$@1iiiiiiiiiiiiiiiiiii,. ^iiiiiiiiiiiiiiiiiii[@$$$$\n$$$$$B|>iiiiiiiiiiiiiiiiii!^. `liiiiiiiiiiiiiiiiii>)%$$$$$\n$$$$$$$c~iiiiiiiiiiiiiiiiiiii\"' .\"!iiiiiiiiiiiiiiiiiii~n$$$$$$$\n$$$$$$$$B)iiiiiiiiiiiiiiiiiiiii!,`. .'\"liiiiiiiiiiiiiiiiiiiii1%$$$$$$$$\n$$$$$$$$$@u]iiiiiiiiiiiiiiiiiiiiiiil,^`'.. ..''^,liiiiiiiiiiiiiiiiiiiiiii-x@$$$$$$$$$\n$$$$$$$$$$$@v?iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii-x$$$$$$$$$$$$\n$$$$$$$$$$$$$@n?iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii-rB$$$$$$$$$$$$$\n$$$$$$$$$$$$$$$$/~iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii<\\*@$$$$$$$$$$$$$$$$\n$$$$$$$$$$$$$$$$$$Bc1~iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii~{v%$$$$$$$$$$$$$$$$$$\n$$$$$$$$$$$$$$$$$$$$$Bvf]<iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii<]tuB$$$$$$$$$$$$$$$$$$$$$\n$$$$$$$$$$$$$$$$$$$$$$$$$%zt-+>iiiiiiiiiiiiiiiiiiiiiiiiiiiii+_tc%$$$$$$$$$$$$$$$$$$$$$$$$$\n$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$W#u/|{+~>iiiiiiiiiiii><+{|/n#W$$$$$$$$$$$$$$$$$$$$$$$$$$$$*/\n\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport {IFactory} from \"./interfaces/IFactory.sol\";\nimport {IBaseStrategy} from \"./interfaces/IBaseStrategy.sol\";\n\n/**\n * @title Yearn Tokenized Strategy\n * @author yearn.finance\n * @notice\n * This TokenizedStrategy can be used by anyone wishing to easily build\n * and deploy their own custom ERC4626 compliant single strategy Vault.\n *\n * The TokenizedStrategy contract is meant to be used as the proxy\n * implementation contract that will handle all logic, storage and\n * management for a custom strategy that inherits the `BaseStrategy`.\n * Any function calls to the strategy that are not defined within that\n * strategy will be forwarded through a delegateCall to this contract.\n\n * A strategist only needs to override a few simple functions that are\n * focused entirely on the strategy specific needs to easily and cheaply\n * deploy their own permissionless 4626 compliant vault.\n */\ncontract TokenizedStrategy {\n using Math for uint256;\n using SafeERC20 for ERC20;\n\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n /**\n * @notice Emitted when a strategy is shutdown.\n */\n event StrategyShutdown();\n\n /**\n * @notice Emitted on the initialization of any new `strategy` that uses `asset`\n * with this specific `apiVersion`.\n */\n event NewTokenizedStrategy(\n address indexed strategy,\n address indexed asset,\n string apiVersion\n );\n\n /**\n * @notice Emitted when the strategy reports `profit` or `loss` and\n * `performanceFees` and `protocolFees` are paid out.\n */\n event Reported(\n uint256 profit,\n uint256 loss,\n uint256 protocolFees,\n uint256 performanceFees\n );\n\n /**\n * @notice Emitted when the 'performanceFeeRecipient' address is\n * updated to 'newPerformanceFeeRecipient'.\n */\n event UpdatePerformanceFeeRecipient(\n address indexed newPerformanceFeeRecipient\n );\n\n /**\n * @notice Emitted when the 'keeper' address is updated to 'newKeeper'.\n */\n event UpdateKeeper(address indexed newKeeper);\n\n /**\n * @notice Emitted when the 'performanceFee' is updated to 'newPerformanceFee'.\n */\n event UpdatePerformanceFee(uint16 newPerformanceFee);\n\n /**\n * @notice Emitted when the 'management' address is updated to 'newManagement'.\n */\n event UpdateManagement(address indexed newManagement);\n\n /**\n * @notice Emitted when the 'emergencyAdmin' address is updated to 'newEmergencyAdmin'.\n */\n event UpdateEmergencyAdmin(address indexed newEmergencyAdmin);\n\n /**\n * @notice Emitted when the 'profitMaxUnlockTime' is updated to 'newProfitMaxUnlockTime'.\n */\n event UpdateProfitMaxUnlockTime(uint256 newProfitMaxUnlockTime);\n\n /**\n * @notice Emitted when the 'pendingManagement' address is updated to 'newPendingManagement'.\n */\n event UpdatePendingManagement(address indexed newPendingManagement);\n\n /**\n * @notice Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(\n address indexed owner,\n address indexed spender,\n uint256 value\n );\n\n /**\n * @notice Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @notice Emitted when the `caller` has exchanged `assets` for `shares`,\n * and transferred those `shares` to `owner`.\n */\n event Deposit(\n address indexed caller,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n\n /**\n * @notice Emitted when the `caller` has exchanged `owner`s `shares` for `assets`,\n * and transferred those `assets` to `receiver`.\n */\n event Withdraw(\n address indexed caller,\n address indexed receiver,\n address indexed owner,\n uint256 assets,\n uint256 shares\n );\n\n /*//////////////////////////////////////////////////////////////\n STORAGE STRUCT\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @dev The struct that will hold all the storage data for each strategy\n * that uses this implementation.\n *\n * This replaces all state variables for a traditional contract. This\n * full struct will be initialized on the creation of the strategy\n * and continually updated and read from for the life of the contract.\n *\n * We combine all the variables into one struct to limit the amount of\n * times the custom storage slots need to be loaded during complex functions.\n *\n * Loading the corresponding storage slot for the struct does not\n * load any of the contents of the struct into memory. So the size\n * will not increase memory related gas usage.\n */\n // prettier-ignore\n struct StrategyData {\n // The ERC20 compliant underlying asset that will be\n // used by the Strategy\n ERC20 asset;\n\n\n // These are the corresponding ERC20 variables needed for the\n // strategies token that is issued and burned on each deposit or withdraw.\n uint8 decimals; // The amount of decimals that `asset` and strategy use.\n string name; // The name of the token for the strategy.\n uint256 totalSupply; // The total amount of shares currently issued.\n mapping(address => uint256) nonces; // Mapping of nonces used for permit functions.\n mapping(address => uint256) balances; // Mapping to track current balances for each account that holds shares.\n mapping(address => mapping(address => uint256)) allowances; // Mapping to track the allowances for the strategies shares.\n\n\n // We manually track `totalAssets` to prevent PPS manipulation through airdrops.\n uint256 totalAssets;\n\n\n // Variables for profit reporting and locking.\n // We use uint96 for timestamps to fit in the same slot as an address. That overflows in 2.5e+21 years.\n // I know Yearn moves slowly but surely V4 will be out by then.\n // If the timestamps ever overflow tell the cyborgs still using this code I'm sorry for being cheap.\n uint256 profitUnlockingRate; // The rate at which locked profit is unlocking.\n uint96 fullProfitUnlockDate; // The timestamp at which all locked shares will unlock.\n address keeper; // Address given permission to call {report} and {tend}.\n uint32 profitMaxUnlockTime; // The amount of seconds that the reported profit unlocks over.\n uint16 performanceFee; // The percent in basis points of profit that is charged as a fee.\n address performanceFeeRecipient; // The address to pay the `performanceFee` to.\n uint96 lastReport; // The last time a {report} was called.\n\n\n // Access management variables.\n address management; // Main address that can set all configurable variables.\n address pendingManagement; // Address that is pending to take over `management`.\n address emergencyAdmin; // Address to act in emergencies as well as `management`.\n\n // Strategy Status\n uint8 entered; // To prevent reentrancy. Use uint8 for gas savings.\n bool shutdown; // Bool that can be used to stop deposits into the strategy.\n }\n\n /*//////////////////////////////////////////////////////////////\n MODIFIERS\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @dev Require that the call is coming from the strategies management.\n */\n modifier onlyManagement() {\n requireManagement(msg.sender);\n _;\n }\n\n /**\n * @dev Require that the call is coming from either the strategies\n * management or the keeper.\n */\n modifier onlyKeepers() {\n requireKeeperOrManagement(msg.sender);\n _;\n }\n\n /**\n * @dev Require that the call is coming from either the strategies\n * management or the emergencyAdmin.\n */\n modifier onlyEmergencyAuthorized() {\n requireEmergencyAuthorized(msg.sender);\n _;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Placed over all state changing functions for increased safety.\n */\n modifier nonReentrant() {\n StrategyData storage S = _strategyStorage();\n // On the first call to nonReentrant, `entered` will be false (2)\n require(S.entered != ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n S.entered = ENTERED;\n\n _;\n\n // Reset to false (1) once call has finished.\n S.entered = NOT_ENTERED;\n }\n\n /**\n * @notice Require a caller is `management`.\n * @dev Is left public so that it can be used by the Strategy.\n *\n * When the Strategy calls this the msg.sender would be the\n * address of the strategy so we need to specify the sender.\n *\n * @param _sender The original msg.sender.\n */\n function requireManagement(address _sender) public view {\n require(_sender == _strategyStorage().management, \"!management\");\n }\n\n /**\n * @notice Require a caller is the `keeper` or `management`.\n * @dev Is left public so that it can be used by the Strategy.\n *\n * When the Strategy calls this the msg.sender would be the\n * address of the strategy so we need to specify the sender.\n *\n * @param _sender The original msg.sender.\n */\n function requireKeeperOrManagement(address _sender) public view {\n StrategyData storage S = _strategyStorage();\n require(_sender == S.keeper || _sender == S.management, \"!keeper\");\n }\n\n /**\n * @notice Require a caller is the `management` or `emergencyAdmin`.\n * @dev Is left public so that it can be used by the Strategy.\n *\n * When the Strategy calls this the msg.sender would be the\n * address of the strategy so we need to specify the sender.\n *\n * @param _sender The original msg.sender.\n */\n function requireEmergencyAuthorized(address _sender) public view {\n StrategyData storage S = _strategyStorage();\n require(\n _sender == S.emergencyAdmin || _sender == S.management,\n \"!emergency authorized\"\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n CONSTANTS\n //////////////////////////////////////////////////////////////*/\n\n /// @notice API version this TokenizedStrategy implements.\n string internal constant API_VERSION = \"3.0.4\";\n\n /// @notice Value to set the `entered` flag to during a call.\n uint8 internal constant ENTERED = 2;\n /// @notice Value to set the `entered` flag to at the end of the call.\n uint8 internal constant NOT_ENTERED = 1;\n\n /// @notice Maximum in Basis Points the Performance Fee can be set to.\n uint16 public constant MAX_FEE = 5_000; // 50%\n\n /// @notice Used for fee calculations.\n uint256 internal constant MAX_BPS = 10_000;\n /// @notice Used for profit unlocking rate calculations.\n uint256 internal constant MAX_BPS_EXTENDED = 1_000_000_000_000;\n\n /// @notice Seconds per year for max profit unlocking time.\n uint256 internal constant SECONDS_PER_YEAR = 31_556_952; // 365.2425 days\n\n /**\n * @dev Custom storage slot that will be used to store the\n * `StrategyData` struct that holds each strategies\n * specific storage variables.\n *\n * Any storage updates done by the TokenizedStrategy actually update\n * the storage of the calling contract. This variable points\n * to the specific location that will be used to store the\n * struct that holds all that data.\n *\n * We use a custom string in order to get a random\n * storage slot that will allow for strategists to use any\n * amount of storage in their strategy without worrying\n * about collisions.\n */\n bytes32 internal constant BASE_STRATEGY_STORAGE =\n bytes32(uint256(keccak256(\"yearn.base.strategy.storage\")) - 1);\n\n /*//////////////////////////////////////////////////////////////\n IMMUTABLE\n //////////////////////////////////////////////////////////////*/\n\n /// @notice Address of the previously deployed Vault factory that the\n // protocol fee config is retrieved from.\n address public immutable FACTORY;\n\n /*//////////////////////////////////////////////////////////////\n STORAGE GETTER\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @dev will return the actual storage slot where the strategy\n * specific `StrategyData` struct is stored for both read\n * and write operations.\n *\n * This loads just the slot location, not the full struct\n * so it can be used in a gas efficient manner.\n */\n function _strategyStorage() internal pure returns (StrategyData storage S) {\n // Since STORAGE_SLOT is a constant, we have to put a variable\n // on the stack to access it from an inline assembly block.\n bytes32 slot = BASE_STRATEGY_STORAGE;\n assembly {\n S.slot := slot\n }\n }\n\n /*//////////////////////////////////////////////////////////////\n INITIALIZATION\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @notice Used to initialize storage for a newly deployed strategy.\n * @dev This should be called atomically whenever a new strategy is\n * deployed and can only be called once for each strategy.\n *\n * This will set all the default storage that must be set for a\n * strategy to function. Any changes can be made post deployment\n * through external calls from `management`.\n *\n * The function will also emit an event that off chain indexers can\n * look for to track any new deployments using this TokenizedStrategy.\n *\n * @param _asset Address of the underlying asset.\n * @param _name Name the strategy will use.\n * @param _management Address to set as the strategies `management`.\n * @param _performanceFeeRecipient Address to receive performance fees.\n * @param _keeper Address to set as strategies `keeper`.\n */\n function initialize(\n address _asset,\n string memory _name,\n address _management,\n address _performanceFeeRecipient,\n address _keeper\n ) external {\n // Cache storage pointer.\n StrategyData storage S = _strategyStorage();\n\n // Make sure we aren't initialized.\n require(address(S.asset) == address(0), \"initialized\");\n\n // Set the strategy's underlying asset.\n S.asset = ERC20(_asset);\n // Set the Strategy Tokens name.\n S.name = _name;\n // Set decimals based off the `asset`.\n S.decimals = ERC20(_asset).decimals();\n\n // Default to a 10 day profit unlock period.\n S.profitMaxUnlockTime = 10 days;\n // Set address to receive performance fees.\n // Can't be address(0) or we will be burning fees.\n require(_performanceFeeRecipient != address(0), \"ZERO ADDRESS\");\n // Can't mint shares to its self because of profit locking.\n require(_performanceFeeRecipient != address(this), \"self\");\n S.performanceFeeRecipient = _performanceFeeRecipient;\n // Default to a 10% performance fee.\n S.performanceFee = 1_000;\n // Set last report to this block.\n S.lastReport = uint96(block.timestamp);\n\n // Set the default management address. Can't be 0.\n require(_management != address(0), \"ZERO ADDRESS\");\n S.management = _management;\n // Set the keeper address\n S.keeper = _keeper;\n\n // Emit event to signal a new strategy has been initialized.\n emit NewTokenizedStrategy(address(this), _asset, API_VERSION);\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC4626 WRITE METHODS\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @notice Mints `shares` of strategy shares to `receiver` by\n * depositing exactly `assets` of underlying tokens.\n * @param assets The amount of underlying to deposit in.\n * @param receiver The address to receive the `shares`.\n * @return shares The actual amount of shares issued.\n */\n function deposit(\n uint256 assets,\n address receiver\n ) external nonReentrant returns (uint256 shares) {\n // Get the storage slot for all following calls.\n StrategyData storage S = _strategyStorage();\n\n // Deposit full balance if using max uint.\n if (assets == type(uint256).max) {\n assets = S.asset.balanceOf(msg.sender);\n }\n\n // Checking max deposit will also check if shutdown.\n require(\n assets <= _maxDeposit(S, receiver),\n \"ERC4626: deposit more than max\"\n );\n // Check for rounding error.\n require(\n (shares = _convertToShares(S, assets, Math.Rounding.Floor)) != 0,\n \"ZERO_SHARES\"\n );\n\n _deposit(S, receiver, assets, shares);\n }\n\n /**\n * @notice Mints exactly `shares` of strategy shares to\n * `receiver` by depositing `assets` of underlying tokens.\n * @param shares The amount of strategy shares mint.\n * @param receiver The address to receive the `shares`.\n * @return assets The actual amount of asset deposited.\n */\n function mint(\n uint256 shares,\n address receiver\n ) external nonReentrant returns (uint256 assets) {\n // Get the storage slot for all following calls.\n StrategyData storage S = _strategyStorage();\n\n // Checking max mint will also check if shutdown.\n require(shares <= _maxMint(S, receiver), \"ERC4626: mint more than max\");\n // Check for rounding error.\n require(\n (assets = _convertToAssets(S, shares, Math.Rounding.Ceil)) != 0,\n \"ZERO_ASSETS\"\n );\n\n _deposit(S, receiver, assets, shares);\n }\n\n /**\n * @notice Withdraws exactly `assets` from `owners` shares and sends\n * the underlying tokens to `receiver`.\n * @dev This will default to not allowing any loss to be taken.\n * @param assets The amount of underlying to withdraw.\n * @param receiver The address to receive `assets`.\n * @param owner The address whose shares are burnt.\n * @return shares The actual amount of shares burnt.\n */\n function withdraw(\n uint256 assets,\n address receiver,\n address owner\n ) external returns (uint256 shares) {\n return withdraw(assets, receiver, owner, 0);\n }\n\n /**\n * @notice Withdraws `assets` from `owners` shares and sends\n * the underlying tokens to `receiver`.\n * @dev This includes an added parameter to allow for losses.\n * @param assets The amount of underlying to withdraw.\n * @param receiver The address to receive `assets`.\n * @param owner The address whose shares are burnt.\n * @param maxLoss The amount of acceptable loss in Basis points.\n * @return shares The actual amount of shares burnt.\n */\n function withdraw(\n uint256 assets,\n address receiver,\n address owner,\n uint256 maxLoss\n ) public nonReentrant returns (uint256 shares) {\n // Get the storage slot for all following calls.\n StrategyData storage S = _strategyStorage();\n require(\n assets <= _maxWithdraw(S, owner),\n \"ERC4626: withdraw more than max\"\n );\n // Check for rounding error or 0 value.\n require(\n (shares = _convertToShares(S, assets, Math.Rounding.Ceil)) != 0,\n \"ZERO_SHARES\"\n );\n\n // Withdraw and track the actual amount withdrawn for loss check.\n _withdraw(S, receiver, owner, assets, shares, maxLoss);\n }\n\n /**\n * @notice Redeems exactly `shares` from `owner` and\n * sends `assets` of underlying tokens to `receiver`.\n * @dev This will default to allowing any loss passed to be realized.\n * @param shares The amount of shares burnt.\n * @param receiver The address to receive `assets`.\n * @param owner The address whose shares are burnt.\n * @return assets The actual amount of underlying withdrawn.\n */\n function redeem(\n uint256 shares,\n address receiver,\n address owner\n ) external returns (uint256) {\n // We default to not limiting a potential loss.\n return redeem(shares, receiver, owner, MAX_BPS);\n }\n\n /**\n * @notice Redeems exactly `shares` from `owner` and\n * sends `assets` of underlying tokens to `receiver`.\n * @dev This includes an added parameter to allow for losses.\n * @param shares The amount of shares burnt.\n * @param receiver The address to receive `assets`.\n * @param owner The address whose shares are burnt.\n * @param maxLoss The amount of acceptable loss in Basis points.\n * @return . The actual amount of underlying withdrawn.\n */\n function redeem(\n uint256 shares,\n address receiver,\n address owner,\n uint256 maxLoss\n ) public nonReentrant returns (uint256) {\n // Get the storage slot for all following calls.\n StrategyData storage S = _strategyStorage();\n require(\n shares <= _maxRedeem(S, owner),\n \"ERC4626: redeem more than max\"\n );\n uint256 assets;\n // Check for rounding error or 0 value.\n require(\n (assets = _convertToAssets(S, shares, Math.Rounding.Floor)) != 0,\n \"ZERO_ASSETS\"\n );\n\n // We need to return the actual amount withdrawn in case of a loss.\n return _withdraw(S, receiver, owner, assets, shares, maxLoss);\n }\n\n /*//////////////////////////////////////////////////////////////\n EXTERNAL 4626 VIEW METHODS\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @notice Get the total amount of assets this strategy holds\n * as of the last report.\n *\n * We manually track `totalAssets` to avoid any PPS manipulation.\n *\n * @return . Total assets the strategy holds.\n */\n function totalAssets() external view returns (uint256) {\n return _totalAssets(_strategyStorage());\n }\n\n /**\n * @notice Get the current supply of the strategies shares.\n *\n * Locked shares issued to the strategy from profits are not\n * counted towards the full supply until they are unlocked.\n *\n * As more shares slowly unlock the totalSupply will decrease\n * causing the PPS of the strategy to increase.\n *\n * @return . Total amount of shares outstanding.\n */\n function totalSupply() external view returns (uint256) {\n return _totalSupply(_strategyStorage());\n }\n\n /**\n * @notice The amount of shares that the strategy would\n * exchange for the amount of assets provided, in an\n * ideal scenario where all the conditions are met.\n *\n * @param assets The amount of underlying.\n * @return . Expected shares that `assets` represents.\n */\n function convertToShares(uint256 assets) external view returns (uint256) {\n return _convertToShares(_strategyStorage(), assets, Math.Rounding.Floor);\n }\n\n /**\n * @notice The amount of assets that the strategy would\n * exchange for the amount of shares provided, in an\n * ideal scenario where all the conditions are met.\n *\n * @param shares The amount of the strategies shares.\n * @return . Expected amount of `asset` the shares represents.\n */\n function convertToAssets(uint256 shares) external view returns (uint256) {\n return _convertToAssets(_strategyStorage(), shares, Math.Rounding.Floor);\n }\n\n /**\n * @notice Allows an on-chain or off-chain user to simulate\n * the effects of their deposit at the current block, given\n * current on-chain conditions.\n * @dev This will round down.\n *\n * @param assets The amount of `asset` to deposits.\n * @return . Expected shares that would be issued.\n */\n function previewDeposit(uint256 assets) external view returns (uint256) {\n return _convertToShares(_strategyStorage(), assets, Math.Rounding.Floor);\n }\n\n /**\n * @notice Allows an on-chain or off-chain user to simulate\n * the effects of their mint at the current block, given\n * current on-chain conditions.\n * @dev This is used instead of convertToAssets so that it can\n * round up for safer mints.\n *\n * @param shares The amount of shares to mint.\n * @return . The needed amount of `asset` for the mint.\n */\n function previewMint(uint256 shares) external view returns (uint256) {\n return _convertToAssets(_strategyStorage(), shares, Math.Rounding.Ceil);\n }\n\n /**\n * @notice Allows an on-chain or off-chain user to simulate\n * the effects of their withdrawal at the current block,\n * given current on-chain conditions.\n * @dev This is used instead of convertToShares so that it can\n * round up for safer withdraws.\n *\n * @param assets The amount of `asset` that would be withdrawn.\n * @return . The amount of shares that would be burnt.\n */\n function previewWithdraw(uint256 assets) external view returns (uint256) {\n return _convertToShares(_strategyStorage(), assets, Math.Rounding.Ceil);\n }\n\n /**\n * @notice Allows an on-chain or off-chain user to simulate\n * the effects of their redemption at the current block,\n * given current on-chain conditions.\n * @dev This will round down.\n *\n * @param shares The amount of shares that would be redeemed.\n * @return . The amount of `asset` that would be returned.\n */\n function previewRedeem(uint256 shares) external view returns (uint256) {\n return _convertToAssets(_strategyStorage(), shares, Math.Rounding.Floor);\n }\n\n /**\n * @notice Total number of underlying assets that can\n * be deposited into the strategy, where `receiver`\n * corresponds to the receiver of the shares of a {deposit} call.\n *\n * @param receiver The address receiving the shares.\n * @return . The max that `receiver` can deposit in `asset`.\n */\n function maxDeposit(address receiver) external view returns (uint256) {\n return _maxDeposit(_strategyStorage(), receiver);\n }\n\n /**\n * @notice Total number of shares that can be minted to `receiver`\n * of a {mint} call.\n *\n * @param receiver The address receiving the shares.\n * @return _maxMint The max that `receiver` can mint in shares.\n */\n function maxMint(address receiver) external view returns (uint256) {\n return _maxMint(_strategyStorage(), receiver);\n }\n\n /**\n * @notice Total number of underlying assets that can be\n * withdrawn from the strategy by `owner`, where `owner`\n * corresponds to the msg.sender of a {redeem} call.\n *\n * @param owner The owner of the shares.\n * @return _maxWithdraw Max amount of `asset` that can be withdrawn.\n */\n function maxWithdraw(address owner) external view returns (uint256) {\n return _maxWithdraw(_strategyStorage(), owner);\n }\n\n /**\n * @notice Variable `maxLoss` is ignored.\n * @dev Accepts a `maxLoss` variable in order to match the multi\n * strategy vaults ABI.\n */\n function maxWithdraw(\n address owner,\n uint256 /*maxLoss*/\n ) external view returns (uint256) {\n return _maxWithdraw(_strategyStorage(), owner);\n }\n\n /**\n * @notice Total number of strategy shares that can be\n * redeemed from the strategy by `owner`, where `owner`\n * corresponds to the msg.sender of a {redeem} call.\n *\n * @param owner The owner of the shares.\n * @return _maxRedeem Max amount of shares that can be redeemed.\n */\n function maxRedeem(address owner) external view returns (uint256) {\n return _maxRedeem(_strategyStorage(), owner);\n }\n\n /**\n * @notice Variable `maxLoss` is ignored.\n * @dev Accepts a `maxLoss` variable in order to match the multi\n * strategy vaults ABI.\n */\n function maxRedeem(\n address owner,\n uint256 /*maxLoss*/\n ) external view returns (uint256) {\n return _maxRedeem(_strategyStorage(), owner);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL 4626 VIEW METHODS\n //////////////////////////////////////////////////////////////*/\n\n /// @dev Internal implementation of {totalAssets}.\n function _totalAssets(\n StrategyData storage S\n ) internal view returns (uint256) {\n return S.totalAssets;\n }\n\n /// @dev Internal implementation of {totalSupply}.\n function _totalSupply(\n StrategyData storage S\n ) internal view returns (uint256) {\n return S.totalSupply - _unlockedShares(S);\n }\n\n /// @dev Internal implementation of {convertToShares}.\n function _convertToShares(\n StrategyData storage S,\n uint256 assets,\n Math.Rounding _rounding\n ) internal view returns (uint256) {\n // Saves an extra SLOAD if values are non-zero.\n uint256 totalSupply_ = _totalSupply(S);\n // If supply is 0, PPS = 1.\n if (totalSupply_ == 0) return assets;\n\n uint256 totalAssets_ = _totalAssets(S);\n // If assets are 0 but supply is not PPS = 0.\n if (totalAssets_ == 0) return 0;\n\n return assets.mulDiv(totalSupply_, totalAssets_, _rounding);\n }\n\n /// @dev Internal implementation of {convertToAssets}.\n function _convertToAssets(\n StrategyData storage S,\n uint256 shares,\n Math.Rounding _rounding\n ) internal view returns (uint256) {\n // Saves an extra SLOAD if totalSupply() is non-zero.\n uint256 supply = _totalSupply(S);\n\n return\n supply == 0\n ? shares\n : shares.mulDiv(_totalAssets(S), supply, _rounding);\n }\n\n /// @dev Internal implementation of {maxDeposit}.\n function _maxDeposit(\n StrategyData storage S,\n address receiver\n ) internal view returns (uint256) {\n // Cannot deposit when shutdown or to the strategy.\n if (S.shutdown || receiver == address(this)) return 0;\n\n return IBaseStrategy(address(this)).availableDepositLimit(receiver);\n }\n\n /// @dev Internal implementation of {maxMint}.\n function _maxMint(\n StrategyData storage S,\n address receiver\n ) internal view returns (uint256 maxMint_) {\n // Cannot mint when shutdown or to the strategy.\n if (S.shutdown || receiver == address(this)) return 0;\n\n maxMint_ = IBaseStrategy(address(this)).availableDepositLimit(receiver);\n if (maxMint_ != type(uint256).max) {\n maxMint_ = _convertToShares(S, maxMint_, Math.Rounding.Floor);\n }\n }\n\n /// @dev Internal implementation of {maxWithdraw}.\n function _maxWithdraw(\n StrategyData storage S,\n address owner\n ) internal view returns (uint256 maxWithdraw_) {\n // Get the max the owner could withdraw currently.\n maxWithdraw_ = IBaseStrategy(address(this)).availableWithdrawLimit(\n owner\n );\n\n // If there is no limit enforced.\n if (maxWithdraw_ == type(uint256).max) {\n // Saves a min check if there is no withdrawal limit.\n maxWithdraw_ = _convertToAssets(\n S,\n _balanceOf(S, owner),\n Math.Rounding.Floor\n );\n } else {\n maxWithdraw_ = Math.min(\n _convertToAssets(S, _balanceOf(S, owner), Math.Rounding.Floor),\n maxWithdraw_\n );\n }\n }\n\n /// @dev Internal implementation of {maxRedeem}.\n function _maxRedeem(\n StrategyData storage S,\n address owner\n ) internal view returns (uint256 maxRedeem_) {\n // Get the max the owner could withdraw currently.\n maxRedeem_ = IBaseStrategy(address(this)).availableWithdrawLimit(owner);\n\n // Conversion would overflow and saves a min check if there is no withdrawal limit.\n if (maxRedeem_ == type(uint256).max) {\n maxRedeem_ = _balanceOf(S, owner);\n } else {\n maxRedeem_ = Math.min(\n // Can't redeem more than the balance.\n _convertToShares(S, maxRedeem_, Math.Rounding.Floor),\n _balanceOf(S, owner)\n );\n }\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL 4626 WRITE METHODS\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @dev Function to be called during {deposit} and {mint}.\n *\n * This function handles all logic including transfers,\n * minting and accounting.\n *\n * We do all external calls before updating any internal\n * values to prevent view reentrancy issues from the token\n * transfers or the _deployFunds() calls.\n */\n function _deposit(\n StrategyData storage S,\n address receiver,\n uint256 assets,\n uint256 shares\n ) internal {\n // Cache storage variables used more than once.\n ERC20 _asset = S.asset;\n\n // Need to transfer before minting or ERC777s could reenter.\n _asset.safeTransferFrom(msg.sender, address(this), assets);\n\n // We can deploy the full loose balance currently held.\n IBaseStrategy(address(this)).deployFunds(\n _asset.balanceOf(address(this))\n );\n\n // Adjust total Assets.\n S.totalAssets += assets;\n\n // mint shares\n _mint(S, receiver, shares);\n\n emit Deposit(msg.sender, receiver, assets, shares);\n }\n\n /**\n * @dev To be called during {redeem} and {withdraw}.\n *\n * This will handle all logic, transfers and accounting\n * in order to service the withdraw request.\n *\n * If we are not able to withdraw the full amount needed, it will\n * be counted as a loss and passed on to the user.\n */\n function _withdraw(\n StrategyData storage S,\n address receiver,\n address owner,\n uint256 assets,\n uint256 shares,\n uint256 maxLoss\n ) internal returns (uint256) {\n require(receiver != address(0), \"ZERO ADDRESS\");\n require(maxLoss <= MAX_BPS, \"exceeds MAX_BPS\");\n\n // Spend allowance if applicable.\n if (msg.sender != owner) {\n _spendAllowance(S, owner, msg.sender, shares);\n }\n\n // Cache `asset` since it is used multiple times..\n ERC20 _asset = S.asset;\n\n uint256 idle = _asset.balanceOf(address(this));\n uint256 loss;\n // Check if we need to withdraw funds.\n if (idle < assets) {\n // Tell Strategy to free what we need.\n unchecked {\n IBaseStrategy(address(this)).freeFunds(assets - idle);\n }\n\n // Return the actual amount withdrawn. Adjust for potential under withdraws.\n idle = _asset.balanceOf(address(this));\n\n // If we didn't get enough out then we have a loss.\n if (idle < assets) {\n unchecked {\n loss = assets - idle;\n }\n // If a non-default max loss parameter was set.\n if (maxLoss < MAX_BPS) {\n // Make sure we are within the acceptable range.\n require(\n loss <= (assets * maxLoss) / MAX_BPS,\n \"too much loss\"\n );\n }\n // Lower the amount to be withdrawn.\n assets = idle;\n }\n }\n\n // Update assets based on how much we took.\n S.totalAssets -= (assets + loss);\n\n _burn(S, owner, shares);\n\n // Transfer the amount of underlying to the receiver.\n _asset.safeTransfer(receiver, assets);\n\n emit Withdraw(msg.sender, receiver, owner, assets, shares);\n\n // Return the actual amount of assets withdrawn.\n return assets;\n }\n\n /*//////////////////////////////////////////////////////////////\n PROFIT REPORTING\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @notice Function for keepers to call to harvest and record all\n * profits accrued.\n *\n * @dev This will account for any gains/losses since the last report\n * and charge fees accordingly.\n *\n * Any profit over the fees charged will be immediately locked\n * so there is no change in PricePerShare. Then slowly unlocked\n * over the `maxProfitUnlockTime` each second based on the\n * calculated `profitUnlockingRate`.\n *\n * In case of a loss it will first attempt to offset the loss\n * with any remaining locked shares from the last report in\n * order to reduce any negative impact to PPS.\n *\n * Will then recalculate the new time to unlock profits over and the\n * rate based on a weighted average of any remaining time from the\n * last report and the new amount of shares to be locked.\n *\n * @return profit The notional amount of gain if any since the last\n * report in terms of `asset`.\n * @return loss The notional amount of loss if any since the last\n * report in terms of `asset`.\n */\n function report()\n external\n nonReentrant\n onlyKeepers\n returns (uint256 profit, uint256 loss)\n {\n // Cache storage pointer since its used repeatedly.\n StrategyData storage S = _strategyStorage();\n\n // Tell the strategy to report the real total assets it has.\n // It should do all reward selling and redepositing now and\n // account for deployed and loose `asset` so we can accurately\n // account for all funds including those potentially airdropped\n // and then have any profits immediately locked.\n uint256 newTotalAssets = IBaseStrategy(address(this))\n .harvestAndReport();\n\n uint256 oldTotalAssets = _totalAssets(S);\n\n // Get the amount of shares we need to burn from previous reports.\n uint256 sharesToBurn = _unlockedShares(S);\n\n // Initialize variables needed throughout.\n uint256 totalFees;\n uint256 protocolFees;\n uint256 sharesToLock;\n uint256 _profitMaxUnlockTime = S.profitMaxUnlockTime;\n // Calculate profit/loss.\n if (newTotalAssets > oldTotalAssets) {\n // We have a profit.\n unchecked {\n profit = newTotalAssets - oldTotalAssets;\n }\n\n // We need to get the equivalent amount of shares\n // at the current PPS before any minting or burning.\n sharesToLock = _convertToShares(S, profit, Math.Rounding.Floor);\n\n // Cache the performance fee.\n uint16 fee = S.performanceFee;\n uint256 totalFeeShares;\n // If we are charging a performance fee\n if (fee != 0) {\n // Asses performance fees.\n unchecked {\n // Get in `asset` for the event.\n totalFees = (profit * fee) / MAX_BPS;\n // And in shares for the payment.\n totalFeeShares = (sharesToLock * fee) / MAX_BPS;\n }\n\n // Get the protocol fee config from the factory.\n (\n uint16 protocolFeeBps,\n address protocolFeesRecipient\n ) = IFactory(FACTORY).protocol_fee_config();\n\n uint256 protocolFeeShares;\n // Check if there is a protocol fee to charge.\n if (protocolFeeBps != 0) {\n unchecked {\n // Calculate protocol fees based on the performance Fees.\n protocolFeeShares =\n (totalFeeShares * protocolFeeBps) /\n MAX_BPS;\n // Need amount in underlying for event.\n protocolFees = (totalFees * protocolFeeBps) / MAX_BPS;\n }\n\n // Mint the protocol fees to the recipient.\n _mint(S, protocolFeesRecipient, protocolFeeShares);\n }\n\n // Mint the difference to the strategy fee recipient.\n unchecked {\n _mint(\n S,\n S.performanceFeeRecipient,\n totalFeeShares - protocolFeeShares\n );\n }\n }\n\n // Check if we are locking profit.\n if (_profitMaxUnlockTime != 0) {\n // lock (profit - fees)\n unchecked {\n sharesToLock -= totalFeeShares;\n }\n\n // If we are burning more than re-locking.\n if (sharesToBurn > sharesToLock) {\n // Burn the difference\n unchecked {\n _burn(S, address(this), sharesToBurn - sharesToLock);\n }\n } else if (sharesToLock > sharesToBurn) {\n // Mint the shares to lock the strategy.\n unchecked {\n _mint(S, address(this), sharesToLock - sharesToBurn);\n }\n }\n }\n } else {\n // Expect we have a loss.\n unchecked {\n loss = oldTotalAssets - newTotalAssets;\n }\n\n // Check in case `else` was due to being equal.\n if (loss != 0) {\n // We will try and burn the unlocked shares and as much from any\n // pending profit still unlocking to offset the loss to prevent any PPS decline post report.\n sharesToBurn = Math.min(\n // Cannot burn more than we have.\n S.balances[address(this)],\n // Try and burn both the shares already unlocked and the amount for the loss.\n _convertToShares(S, loss, Math.Rounding.Floor) + sharesToBurn\n );\n }\n\n // Check if there is anything to burn.\n if (sharesToBurn != 0) {\n _burn(S, address(this), sharesToBurn);\n }\n }\n\n // Update unlocking rate and time to fully unlocked.\n uint256 totalLockedShares = S.balances[address(this)];\n if (totalLockedShares != 0) {\n uint256 previouslyLockedTime;\n uint96 _fullProfitUnlockDate = S.fullProfitUnlockDate;\n // Check if we need to account for shares still unlocking.\n if (_fullProfitUnlockDate > block.timestamp) {\n unchecked {\n // There will only be previously locked shares if time remains.\n // We calculate this here since it should be rare.\n previouslyLockedTime =\n (_fullProfitUnlockDate - block.timestamp) *\n (totalLockedShares - sharesToLock);\n }\n }\n\n // newProfitLockingPeriod is a weighted average between the remaining\n // time of the previously locked shares and the profitMaxUnlockTime.\n uint256 newProfitLockingPeriod = (previouslyLockedTime +\n sharesToLock *\n _profitMaxUnlockTime) / totalLockedShares;\n\n // Calculate how many shares unlock per second.\n S.profitUnlockingRate =\n (totalLockedShares * MAX_BPS_EXTENDED) /\n newProfitLockingPeriod;\n\n // Calculate how long until the full amount of shares is unlocked.\n S.fullProfitUnlockDate = uint96(\n block.timestamp + newProfitLockingPeriod\n );\n } else {\n // Only setting this to 0 will turn in the desired effect,\n // no need to update profitUnlockingRate.\n S.fullProfitUnlockDate = 0;\n }\n\n // Update the new total assets value.\n S.totalAssets = newTotalAssets;\n S.lastReport = uint96(block.timestamp);\n\n // Emit event with info\n emit Reported(\n profit,\n loss,\n protocolFees, // Protocol fees\n totalFees - protocolFees // Performance Fees\n );\n }\n\n /**\n * @notice Get how many shares have been unlocked since last report.\n * @return . The amount of shares that have unlocked.\n */\n function unlockedShares() external view returns (uint256) {\n return _unlockedShares(_strategyStorage());\n }\n\n /**\n * @dev To determine how many of the shares that were locked during the last\n * report have since unlocked.\n *\n * If the `fullProfitUnlockDate` has passed the full strategy's balance will\n * count as unlocked.\n *\n * @return unlocked The amount of shares that have unlocked.\n */\n function _unlockedShares(\n StrategyData storage S\n ) internal view returns (uint256 unlocked) {\n uint96 _fullProfitUnlockDate = S.fullProfitUnlockDate;\n if (_fullProfitUnlockDate > block.timestamp) {\n unchecked {\n unlocked =\n (S.profitUnlockingRate * (block.timestamp - S.lastReport)) /\n MAX_BPS_EXTENDED;\n }\n } else if (_fullProfitUnlockDate != 0) {\n // All shares have been unlocked.\n unlocked = S.balances[address(this)];\n }\n }\n\n /*//////////////////////////////////////////////////////////////\n TENDING\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @notice For a 'keeper' to 'tend' the strategy if a custom\n * tendTrigger() is implemented.\n *\n * @dev Both 'tendTrigger' and '_tend' will need to be overridden\n * for this to be used.\n *\n * This will callback the internal '_tend' call in the BaseStrategy\n * with the total current amount available to the strategy to deploy.\n *\n * This is a permissioned function so if desired it could\n * be used for illiquid or manipulatable strategies to compound\n * rewards, perform maintenance or deposit/withdraw funds.\n *\n * This will not cause any change in PPS. Total assets will\n * be the same before and after.\n *\n * A report() call will be needed to record any profits or losses.\n */\n function tend() external nonReentrant onlyKeepers {\n // Tend the strategy with the current loose balance.\n IBaseStrategy(address(this)).tendThis(\n _strategyStorage().asset.balanceOf(address(this))\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n STRATEGY SHUTDOWN\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @notice Used to shutdown the strategy preventing any further deposits.\n * @dev Can only be called by the current `management` or `emergencyAdmin`.\n *\n * This will stop any new {deposit} or {mint} calls but will\n * not prevent {withdraw} or {redeem}. It will also still allow for\n * {tend} and {report} so that management can report any last losses\n * in an emergency as well as provide any maintenance to allow for full\n * withdraw.\n *\n * This is a one way switch and can never be set back once shutdown.\n */\n function shutdownStrategy() external onlyEmergencyAuthorized {\n _strategyStorage().shutdown = true;\n\n emit StrategyShutdown();\n }\n\n /**\n * @notice To manually withdraw funds from the yield source after a\n * strategy has been shutdown.\n * @dev This can only be called post {shutdownStrategy}.\n *\n * This will never cause a change in PPS. Total assets will\n * be the same before and after.\n *\n * A strategist will need to override the {_emergencyWithdraw} function\n * in their strategy for this to work.\n *\n * @param amount The amount of asset to attempt to free.\n */\n function emergencyWithdraw(\n uint256 amount\n ) external nonReentrant onlyEmergencyAuthorized {\n // Make sure the strategy has been shutdown.\n require(_strategyStorage().shutdown, \"not shutdown\");\n\n // Withdraw from the yield source.\n IBaseStrategy(address(this)).shutdownWithdraw(amount);\n }\n\n /*//////////////////////////////////////////////////////////////\n GETTER FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @notice Get the underlying asset for the strategy.\n * @return . The underlying asset.\n */\n function asset() external view returns (address) {\n return address(_strategyStorage().asset);\n }\n\n /**\n * @notice Get the API version for this TokenizedStrategy.\n * @return . The API version for this TokenizedStrategy\n */\n function apiVersion() external pure returns (string memory) {\n return API_VERSION;\n }\n\n /**\n * @notice Get the current address that controls the strategy.\n * @return . Address of management\n */\n function management() external view returns (address) {\n return _strategyStorage().management;\n }\n\n /**\n * @notice Get the current pending management address if any.\n * @return . Address of pendingManagement\n */\n function pendingManagement() external view returns (address) {\n return _strategyStorage().pendingManagement;\n }\n\n /**\n * @notice Get the current address that can call tend and report.\n * @return . Address of the keeper\n */\n function keeper() external view returns (address) {\n return _strategyStorage().keeper;\n }\n\n /**\n * @notice Get the current address that can shutdown and emergency withdraw.\n * @return . Address of the emergencyAdmin\n */\n function emergencyAdmin() external view returns (address) {\n return _strategyStorage().emergencyAdmin;\n }\n\n /**\n * @notice Get the current performance fee charged on profits.\n * denominated in Basis Points where 10_000 == 100%\n * @return . Current performance fee.\n */\n function performanceFee() external view returns (uint16) {\n return _strategyStorage().performanceFee;\n }\n\n /**\n * @notice Get the current address that receives the performance fees.\n * @return . Address of performanceFeeRecipient\n */\n function performanceFeeRecipient() external view returns (address) {\n return _strategyStorage().performanceFeeRecipient;\n }\n\n /**\n * @notice Gets the timestamp at which all profits will be unlocked.\n * @return . The full profit unlocking timestamp\n */\n function fullProfitUnlockDate() external view returns (uint256) {\n return uint256(_strategyStorage().fullProfitUnlockDate);\n }\n\n /**\n * @notice The per second rate at which profits are unlocking.\n * @dev This is denominated in EXTENDED_BPS decimals.\n * @return . The current profit unlocking rate.\n */\n function profitUnlockingRate() external view returns (uint256) {\n return _strategyStorage().profitUnlockingRate;\n }\n\n /**\n * @notice Gets the current time profits are set to unlock over.\n * @return . The current profit max unlock time.\n */\n function profitMaxUnlockTime() external view returns (uint256) {\n return _strategyStorage().profitMaxUnlockTime;\n }\n\n /**\n * @notice The timestamp of the last time protocol fees were charged.\n * @return . The last report.\n */\n function lastReport() external view returns (uint256) {\n return uint256(_strategyStorage().lastReport);\n }\n\n /**\n * @notice Get the price per share.\n * @dev This value offers limited precision. Integrations that require\n * exact precision should use convertToAssets or convertToShares instead.\n *\n * @return . The price per share.\n */\n function pricePerShare() external view returns (uint256) {\n StrategyData storage S = _strategyStorage();\n return _convertToAssets(S, 10 ** S.decimals, Math.Rounding.Floor);\n }\n\n /**\n * @notice To check if the strategy has been shutdown.\n * @return . Whether or not the strategy is shutdown.\n */\n function isShutdown() external view returns (bool) {\n return _strategyStorage().shutdown;\n }\n\n /*//////////////////////////////////////////////////////////////\n SETTER FUNCTIONS\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @notice Step one of two to set a new address to be in charge of the strategy.\n * @dev Can only be called by the current `management`. The address is\n * set to pending management and will then have to call {acceptManagement}\n * in order for the 'management' to officially change.\n *\n * Cannot set `management` to address(0).\n *\n * @param _management New address to set `pendingManagement` to.\n */\n function setPendingManagement(address _management) external onlyManagement {\n require(_management != address(0), \"ZERO ADDRESS\");\n _strategyStorage().pendingManagement = _management;\n\n emit UpdatePendingManagement(_management);\n }\n\n /**\n * @notice Step two of two to set a new 'management' of the strategy.\n * @dev Can only be called by the current `pendingManagement`.\n */\n function acceptManagement() external {\n StrategyData storage S = _strategyStorage();\n require(msg.sender == S.pendingManagement, \"!pending\");\n S.management = msg.sender;\n S.pendingManagement = address(0);\n\n emit UpdateManagement(msg.sender);\n }\n\n /**\n * @notice Sets a new address to be in charge of tend and reports.\n * @dev Can only be called by the current `management`.\n *\n * @param _keeper New address to set `keeper` to.\n */\n function setKeeper(address _keeper) external onlyManagement {\n _strategyStorage().keeper = _keeper;\n\n emit UpdateKeeper(_keeper);\n }\n\n /**\n * @notice Sets a new address to be able to shutdown the strategy.\n * @dev Can only be called by the current `management`.\n *\n * @param _emergencyAdmin New address to set `emergencyAdmin` to.\n */\n function setEmergencyAdmin(\n address _emergencyAdmin\n ) external onlyManagement {\n _strategyStorage().emergencyAdmin = _emergencyAdmin;\n\n emit UpdateEmergencyAdmin(_emergencyAdmin);\n }\n\n /**\n * @notice Sets the performance fee to be charged on reported gains.\n * @dev Can only be called by the current `management`.\n *\n * Denominated in Basis Points. So 100% == 10_000.\n * Cannot set greater than to MAX_FEE.\n *\n * @param _performanceFee New performance fee.\n */\n function setPerformanceFee(uint16 _performanceFee) external onlyManagement {\n require(_performanceFee <= MAX_FEE, \"MAX FEE\");\n _strategyStorage().performanceFee = _performanceFee;\n\n emit UpdatePerformanceFee(_performanceFee);\n }\n\n /**\n * @notice Sets a new address to receive performance fees.\n * @dev Can only be called by the current `management`.\n *\n * Cannot set to address(0).\n *\n * @param _performanceFeeRecipient New address to set `management` to.\n */\n function setPerformanceFeeRecipient(\n address _performanceFeeRecipient\n ) external onlyManagement {\n require(_performanceFeeRecipient != address(0), \"ZERO ADDRESS\");\n require(_performanceFeeRecipient != address(this), \"Cannot be self\");\n _strategyStorage().performanceFeeRecipient = _performanceFeeRecipient;\n\n emit UpdatePerformanceFeeRecipient(_performanceFeeRecipient);\n }\n\n /**\n * @notice Sets the time for profits to be unlocked over.\n * @dev Can only be called by the current `management`.\n *\n * Denominated in seconds and cannot be greater than 1 year.\n *\n * NOTE: Setting to 0 will cause all currently locked profit\n * to be unlocked instantly and should be done with care.\n *\n * `profitMaxUnlockTime` is stored as a uint32 for packing but can\n * be passed in as uint256 for simplicity.\n *\n * @param _profitMaxUnlockTime New `profitMaxUnlockTime`.\n */\n function setProfitMaxUnlockTime(\n uint256 _profitMaxUnlockTime\n ) external onlyManagement {\n // Must be less than a year.\n require(_profitMaxUnlockTime <= SECONDS_PER_YEAR, \"too long\");\n StrategyData storage S = _strategyStorage();\n\n // If we are setting to 0 we need to adjust amounts.\n if (_profitMaxUnlockTime == 0) {\n uint256 shares = S.balances[address(this)];\n if (shares != 0) {\n // Burn all shares if applicable.\n _burn(S, address(this), shares);\n }\n // Reset unlocking variables\n S.profitUnlockingRate = 0;\n S.fullProfitUnlockDate = 0;\n }\n\n S.profitMaxUnlockTime = uint32(_profitMaxUnlockTime);\n\n emit UpdateProfitMaxUnlockTime(_profitMaxUnlockTime);\n }\n\n /**\n * @notice Updates the name for the strategy.\n * @param _name The new name for the strategy.\n */\n function setName(string calldata _name) external onlyManagement {\n _strategyStorage().name = _name;\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC20 METHODS\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @notice Returns the name of the token.\n * @return . The name the strategy is using for its token.\n */\n function name() external view returns (string memory) {\n return _strategyStorage().name;\n }\n\n /**\n * @notice Returns the symbol of the strategies token.\n * @dev Will be 'ys + asset symbol'.\n * @return . The symbol the strategy is using for its tokens.\n */\n function symbol() external view returns (string memory) {\n return\n string(abi.encodePacked(\"ys\", _strategyStorage().asset.symbol()));\n }\n\n /**\n * @notice Returns the number of decimals used to get its user representation.\n * @return . The decimals used for the strategy and `asset`.\n */\n function decimals() external view returns (uint8) {\n return _strategyStorage().decimals;\n }\n\n /**\n * @notice Returns the current balance for a given '_account'.\n * @dev If the '_account` is the strategy then this will subtract\n * the amount of shares that have been unlocked since the last profit first.\n * @param account the address to return the balance for.\n * @return . The current balance in y shares of the '_account'.\n */\n function balanceOf(address account) external view returns (uint256) {\n return _balanceOf(_strategyStorage(), account);\n }\n\n /// @dev Internal implementation of {balanceOf}.\n function _balanceOf(\n StrategyData storage S,\n address account\n ) internal view returns (uint256) {\n if (account == address(this)) {\n return S.balances[account] - _unlockedShares(S);\n }\n return S.balances[account];\n }\n\n /**\n * @notice Transfer '_amount` of shares from `msg.sender` to `to`.\n * @dev\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - `to` cannot be the address of the strategy.\n * - the caller must have a balance of at least `_amount`.\n *\n * @param to The address shares will be transferred to.\n * @param amount The amount of shares to be transferred from sender.\n * @return . a boolean value indicating whether the operation succeeded.\n */\n function transfer(address to, uint256 amount) external returns (bool) {\n _transfer(_strategyStorage(), msg.sender, to, amount);\n return true;\n }\n\n /**\n * @notice Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n * @param owner The address who owns the shares.\n * @param spender The address who would be moving the owners shares.\n * @return . The remaining amount of shares of `owner` that could be moved by `spender`.\n */\n function allowance(\n address owner,\n address spender\n ) external view returns (uint256) {\n return _allowance(_strategyStorage(), owner, spender);\n }\n\n /// @dev Internal implementation of {allowance}.\n function _allowance(\n StrategyData storage S,\n address owner,\n address spender\n ) internal view returns (uint256) {\n return S.allowances[owner][spender];\n }\n\n /**\n * @notice Sets `amount` as the allowance of `spender` over the caller's tokens.\n * @dev\n *\n * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n * `transferFrom`. This is semantically equivalent to an infinite approval.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n *\n * @param spender the address to allow the shares to be moved by.\n * @param amount the amount of shares to allow `spender` to move.\n * @return . a boolean value indicating whether the operation succeeded.\n */\n function approve(address spender, uint256 amount) external returns (bool) {\n _approve(_strategyStorage(), msg.sender, spender, amount);\n return true;\n }\n\n /**\n * @notice `amount` tokens from `from` to `to` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * @dev\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP.\n *\n * NOTE: Does not update the allowance if the current allowance\n * is the maximum `uint256`.\n *\n * Requirements:\n *\n * - `from` and `to` cannot be the zero address.\n * - `to` cannot be the address of the strategy.\n * - `from` must have a balance of at least `amount`.\n * - the caller must have allowance for ``from``'s tokens of at least\n * `amount`.\n *\n * Emits a {Transfer} event.\n *\n * @param from the address to be moving shares from.\n * @param to the address to be moving shares to.\n * @param amount the quantity of shares to move.\n * @return . a boolean value indicating whether the operation succeeded.\n */\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) external returns (bool) {\n StrategyData storage S = _strategyStorage();\n _spendAllowance(S, from, msg.sender, amount);\n _transfer(S, from, to, amount);\n return true;\n }\n\n /**\n * @dev Moves `amount` of tokens from `from` to `to`.\n *\n * This internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `to` cannot be the strategies address\n * - `from` must have a balance of at least `amount`.\n *\n */\n function _transfer(\n StrategyData storage S,\n address from,\n address to,\n uint256 amount\n ) internal {\n require(from != address(0), \"ERC20: transfer from the zero address\");\n require(to != address(0), \"ERC20: transfer to the zero address\");\n require(to != address(this), \"ERC20 transfer to strategy\");\n\n S.balances[from] -= amount;\n unchecked {\n S.balances[to] += amount;\n }\n\n emit Transfer(from, to, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n *\n */\n function _mint(\n StrategyData storage S,\n address account,\n uint256 amount\n ) internal {\n require(account != address(0), \"ERC20: mint to the zero address\");\n\n S.totalSupply += amount;\n unchecked {\n S.balances[account] += amount;\n }\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(\n StrategyData storage S,\n address account,\n uint256 amount\n ) internal {\n require(account != address(0), \"ERC20: burn from the zero address\");\n\n S.balances[account] -= amount;\n unchecked {\n S.totalSupply -= amount;\n }\n emit Transfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n StrategyData storage S,\n address owner,\n address spender,\n uint256 amount\n ) internal {\n require(owner != address(0), \"ERC20: approve from the zero address\");\n require(spender != address(0), \"ERC20: approve to the zero address\");\n\n S.allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n *\n * Does not update the allowance amount in case of infinite allowance.\n * Revert if not enough allowance is available.\n *\n * Might emit an {Approval} event.\n */\n function _spendAllowance(\n StrategyData storage S,\n address owner,\n address spender,\n uint256 amount\n ) internal {\n uint256 currentAllowance = _allowance(S, owner, spender);\n if (currentAllowance != type(uint256).max) {\n require(\n currentAllowance >= amount,\n \"ERC20: insufficient allowance\"\n );\n unchecked {\n _approve(S, owner, spender, currentAllowance - amount);\n }\n }\n }\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @notice Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * @dev Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n *\n * @param _owner the address of the account to return the nonce for.\n * @return . the current nonce for the account.\n */\n function nonces(address _owner) external view returns (uint256) {\n return _strategyStorage().nonces[_owner];\n }\n\n /**\n * @notice Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n * given ``owner``'s signed approval.\n *\n * @dev IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external {\n require(deadline >= block.timestamp, \"ERC20: PERMIT_DEADLINE_EXPIRED\");\n\n // Unchecked because the only math done is incrementing\n // the owner's nonce which cannot realistically overflow.\n unchecked {\n address recoveredAddress = ecrecover(\n keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR(),\n keccak256(\n abi.encode(\n keccak256(\n \"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\"\n ),\n owner,\n spender,\n value,\n _strategyStorage().nonces[owner]++,\n deadline\n )\n )\n )\n ),\n v,\n r,\n s\n );\n\n require(\n recoveredAddress != address(0) && recoveredAddress == owner,\n \"ERC20: INVALID_SIGNER\"\n );\n\n _approve(_strategyStorage(), recoveredAddress, spender, value);\n }\n }\n\n /**\n * @notice Returns the domain separator used in the encoding of the signature\n * for {permit}, as defined by {EIP712}.\n *\n * @return . The domain separator that will be used for any {permit} calls.\n */\n function DOMAIN_SEPARATOR() public view returns (bytes32) {\n return\n keccak256(\n abi.encode(\n keccak256(\n \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"\n ),\n keccak256(\"Yearn Vault\"),\n keccak256(bytes(API_VERSION)),\n block.chainid,\n address(this)\n )\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n DEPLOYMENT\n //////////////////////////////////////////////////////////////*/\n\n /**\n * @dev On contract creation we set `asset` for this contract to address(1).\n * This prevents it from ever being initialized in the future.\n * @param _factory Address of the factory of the same version for protocol fees.\n */\n constructor(address _factory) {\n FACTORY = _factory;\n _strategyStorage().asset = ERC20(address(1));\n }\n}\n"
},
"contracts/libraries/FullMath.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\n/// @title Contains 512-bit math functions\n/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision\n/// @dev Handles \"phantom overflow\" i.e., allows multiplication and division where an intermediate value overflows 256 bits\n/// @dev From Uniswap V3 - https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol\nlibrary FullMath {\n /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n /// @param a The multiplicand\n /// @param b The multiplier\n /// @param denominator The divisor\n /// @return result The 256-bit result\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv\n function mulDiv(\n uint256 a,\n uint256 b,\n uint256 denominator\n ) internal pure returns (uint256 result) {\n unchecked {\n // 512-bit multiply [prod1 prod0] = a * b\n // Compute the product mod 2**256 and mod 2**256 - 1\n // then use the Chinese Remainder Theorem to reconstruct\n // the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2**256 + prod0\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(a, b, not(0))\n prod0 := mul(a, b)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division\n if (prod1 == 0) {\n require(denominator > 0);\n assembly {\n result := div(prod0, denominator)\n }\n return result;\n }\n\n // Make sure the result is less than 2**256.\n // Also prevents denominator == 0\n require(denominator > prod1);\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0]\n // Compute remainder using mulmod\n uint256 remainder;\n assembly {\n remainder := mulmod(a, b, denominator)\n }\n // Subtract 256 bit number from 512 bit number\n assembly {\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator\n // Compute largest power of two divisor of denominator.\n // Always >= 1.\n uint256 twos = denominator & (~denominator + 1);\n // Divide denominator by power of two\n assembly {\n denominator := div(denominator, twos)\n }\n\n // Divide [prod1 prod0] by the factors of two\n assembly {\n prod0 := div(prod0, twos)\n }\n // Shift in bits from prod1 into prod0. For this we need\n // to flip `twos` such that it is 2**256 / twos.\n // If twos is zero, then it becomes one\n assembly {\n twos := add(div(sub(0, twos), twos), 1)\n }\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2**256\n // Now that denominator is an odd number, it has an inverse\n // modulo 2**256 such that denominator * inv = 1 mod 2**256.\n // Compute the inverse by starting with a seed that is correct\n // correct for four bits. That is, denominator * inv = 1 mod 2**4\n uint256 inv = (3 * denominator) ^ 2;\n // Now use Newton-Raphson iteration to improve the precision.\n // Thanks to Hensel's lifting lemma, this also works in modular\n // arithmetic, doubling the correct bits in each step.\n inv *= 2 - denominator * inv; // inverse mod 2**8\n inv *= 2 - denominator * inv; // inverse mod 2**16\n inv *= 2 - denominator * inv; // inverse mod 2**32\n inv *= 2 - denominator * inv; // inverse mod 2**64\n inv *= 2 - denominator * inv; // inverse mod 2**128\n inv *= 2 - denominator * inv; // inverse mod 2**256\n\n // Because the division is now exact we can divide by multiplying\n // with the modular inverse of denominator. This will give us the\n // correct result modulo 2**256. Since the precoditions guarantee\n // that the outcome is less than 2**256, this is the final result.\n // We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inv;\n return result;\n }\n }\n\n /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n /// @param a The multiplicand\n /// @param b The multiplier\n /// @param denominator The divisor\n /// @return result The 256-bit result\n function mulDivRoundingUp(\n uint256 a,\n uint256 b,\n uint256 denominator\n ) internal pure returns (uint256 result) {\n unchecked {\n result = mulDiv(a, b, denominator);\n if (mulmod(a, b, denominator) > 0) {\n require(result < type(uint256).max);\n result++;\n }\n }\n }\n}\n"
},
"contracts/mocks/MockChainlinkOracle.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\ncontract MockChainlinkOracle {\n int256 public price;\n uint8 public decimalsVal;\n\n constructor(int256 _initialPrice, uint8 _decimals) {\n price = _initialPrice;\n decimalsVal = _decimals;\n }\n\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n )\n {\n return (\n 1, // roundId\n price, // answer\n block.timestamp, // startedAt\n block.timestamp, // updatedAt\n 1 // answeredInRound\n );\n }\n\n function decimals() external view returns (uint8) {\n return decimalsVal;\n }\n\n // Helper to update price\n function setPrice(int256 _price) external {\n price = _price;\n }\n}\n"
},
"contracts/mocks/MockERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract MockERC20 is ERC20 {\n uint8 private _decimals;\n\n constructor(\n string memory name,\n string memory symbol,\n uint8 decimals_\n ) ERC20(name, symbol) {\n _decimals = decimals_;\n }\n\n function mint(address to, uint256 amount) external {\n _mint(to, amount);\n }\n\n function decimals() public view override returns (uint8) {\n return _decimals;\n }\n}\n"
},
"contracts/mocks/MockRouter.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IMintableERC20 {\n function mint(address to, uint256 amount) external;\n}\n\ncontract MockRouter {\n // 1:1 swap rate by default for simplicity, or just mint exact amount requested as minOut\n\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts) {\n require(path.length >= 2, \"Invalid path\");\n\n // Transfer input tokens from sender to this router (simulate swap logic)\n IERC20(path[0]).transferFrom(msg.sender, address(this), amountIn);\n\n // In a real mock environment for these tests, we want to ensure the swap succeeds\n // and gives us back enough tokens to pass the Zap checks.\n // We'll simulate a perfect swap that gives exactly amountIn * 1 (ignoring decimals in this naive mock)\n // OR better: we utilize the IMintableERC20 interface since we use mocks.\n\n address tokenOut = path[path.length - 1];\n\n // We assume tokenOut is our MockERC20 which has a mint function.\n // We mint `amountOutMin` + 1 to the recipient to ensure we pass slippage checks.\n // In reality, we should respect prices, but for unit testing the *Zap flow*, passing checks is key.\n\n uint256 amountOut = amountOutMin == 0 ? amountIn : amountOutMin;\n\n try IMintableERC20(tokenOut).mint(to, amountOut) {\n // Success\n } catch {\n // Fallback for non-mintable tokens (e.g. if we test with real tokens later)\n // Just assume the router was pre-funded\n IERC20(tokenOut).transfer(to, amountOut);\n }\n amounts = new uint256[](path.length);\n amounts[0] = amountIn;\n amounts[amounts.length - 1] = amountOut;\n\n return amounts;\n }\n\n struct ExactInputSingleParams {\n address tokenIn;\n address tokenOut;\n uint24 fee;\n address recipient;\n uint256 deadline;\n uint256 amountIn;\n uint256 amountOutMinimum;\n uint160 sqrtPriceLimitX96;\n }\n\n function exactInputSingle(\n ExactInputSingleParams calldata params\n ) external payable returns (uint256 amountOut) {\n // Transfer inputs to router\n IERC20(params.tokenIn).transferFrom(\n msg.sender,\n address(this),\n params.amountIn\n );\n\n // Calculate amountOut (1:1 for testing)\n amountOut = params.amountOutMinimum == 0\n ? params.amountIn\n : params.amountOutMinimum;\n\n // Mint or Transfer output\n try IMintableERC20(params.tokenOut).mint(params.recipient, amountOut) {\n // Success\n } catch {\n IERC20(params.tokenOut).transfer(params.recipient, amountOut);\n }\n }\n\n function getAmountsOut(\n uint256 amountIn,\n address[] calldata path\n ) external pure returns (uint256[] memory amounts) {\n amounts = new uint256[](path.length);\n amounts[0] = amountIn;\n for (uint256 i = 1; i < path.length; i++) {\n amounts[i] = amountIn; // 1:1 ratio for testing\n }\n }\n}\n"
},
"contracts/mocks/MockUniswapV3Pool.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\ncontract MockUniswapV3Pool {\n uint160 public sqrtPriceX96;\n address public token0;\n address public token1;\n int24 public mockTick; // Store the tick for TWAP calculation\n\n constructor(address _token0, address _token1, uint160 _sqrtPriceX96) {\n token0 = _token0;\n token1 = _token1;\n sqrtPriceX96 = _sqrtPriceX96;\n mockTick = 0; // Tick 0 = 1:1 price ratio\n }\n\n function slot0()\n external\n view\n returns (uint160, int24, uint16, uint16, uint16, uint8, bool)\n {\n return (\n sqrtPriceX96,\n mockTick, // Return the mock tick\n 0, // observationIndex\n 100, // observationCardinality (high enough to pass check)\n 100, // observationCardinalityNext\n 0, // feeProtocol\n true // unlocked\n );\n }\n\n // Mock observe function that returns consistent tick cumulatives\n // This simulates a stable TWAP that matches the spot price\n function observe(\n uint32[] calldata secondsAgos\n )\n external\n view\n returns (\n int56[] memory tickCumulatives,\n uint160[] memory secondsPerLiquidityCumulativeX128s\n )\n {\n tickCumulatives = new int56[](secondsAgos.length);\n secondsPerLiquidityCumulativeX128s = new uint160[](secondsAgos.length);\n\n // Return tick cumulatives that produce the same price as spot\n // tickCumulative = tick * time, so for stable price:\n // (tickCumulative[0] - tickCumulative[1]) / (secondsAgos[1] - secondsAgos[0]) = mockTick\n for (uint256 i = 0; i < secondsAgos.length; i++) {\n // Mock cumulative ticks based on elapsed time\n // This ensures TWAP calculation returns mockTick\n int56 elapsedTime = int56(uint56(block.timestamp)) -\n int56(uint56(secondsAgos[i]));\n tickCumulatives[i] = int56(mockTick) * elapsedTime;\n secondsPerLiquidityCumulativeX128s[i] = uint160(\n block.timestamp - uint256(secondsAgos[i])\n );\n }\n }\n\n // Helper to update price for testing\n function setPrice(uint160 _sqrtPriceX96, int24 _tick) external {\n sqrtPriceX96 = _sqrtPriceX96;\n mockTick = _tick;\n }\n}\n"
},
"contracts/YearnJBTCiStrategy.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport {BaseStrategy} from \"./lib/tokenized-strategy/BaseStrategy.sol\";\nimport {\n SafeERC20,\n IERC20\n} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {Math} from \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport {\n ReentrancyGuard\n} from \"@openzeppelin/contracts/utils/ReentrancyGuard.sol\";\nimport {FullMath} from \"./libraries/FullMath.sol\";\n\n/**\n * @title JBTCi\n * @author Jubilee Labs on behalf of Jubilee Protocol & Hundredfold Foundation\n * @notice The first Bitcoin Index Fund on Base via Yearn V3\n */\n\n// ============================================================================\n// CUSTOM ERRORS\n// ============================================================================\n\n/// @dev Zero address provided\nerror ZeroAddress();\nerror SameAddress();\nerror InvalidPrice();\nerror StalePrice();\nerror PriceDeviation();\nerror PriceOutOfRange();\nerror InsufficientBalance();\nerror PositionTooSmall();\nerror PositionTooLarge();\nerror SlippageExceeded();\nerror AmountExceedsLimit();\nerror AmountIsZero();\nerror InternalOnly();\nerror AlreadyPaused();\nerror NotPaused();\nerror AlreadyInFailureMode();\nerror NotInFailureMode();\nerror BelowMinimum();\nerror ExceedsMaximum();\nerror DuplicateTokens();\nerror InvalidTick();\nerror InvalidPool();\n\n// ============================================================================\n// INTERFACES\n// ============================================================================\n\ninterface IChainlinkOracle {\n function latestRoundData()\n external\n view\n returns (\n uint80 roundId,\n int256 answer,\n uint256 startedAt,\n uint256 updatedAt,\n uint80 answeredInRound\n );\n\n function decimals() external view returns (uint8);\n}\n\ninterface IUniswapV3Pool {\n function slot0()\n external\n view\n returns (\n uint160 sqrtPriceX96,\n int24 tick,\n uint16 observationIndex,\n uint16 observationCardinality,\n uint16 observationCardinalityNext,\n uint8 feeProtocol,\n bool unlocked\n );\n\n function observe(\n uint32[] calldata secondsAgos\n )\n external\n view\n returns (\n int56[] memory tickCumulatives,\n uint160[] memory secondsPerLiquidityCumulativeX128s\n );\n\n function token0() external view returns (address);\n function token1() external view returns (address);\n}\n\ninterface IDEXRouter {\n function swapExactTokensForTokens(\n uint256 amountIn,\n uint256 amountOutMin,\n address[] calldata path,\n address to,\n uint256 deadline\n ) external returns (uint256[] memory amounts);\n\n function getAmountsOut(\n uint256 amountIn,\n address[] calldata path\n ) external view returns (uint256[] memory amounts);\n}\n\n// ============================================================================\n// LIBRARIES\n// ============================================================================\n\n/**\n * @notice Uniswap V3 Tick Math Library (not approximation)\n */\nlibrary TickMath {\n int24 internal constant MIN_TICK = -887272;\n int24 internal constant MAX_TICK = 887272;\n\n uint160 internal constant MIN_SQRT_RATIO = 4295128739;\n uint160 internal constant MAX_SQRT_RATIO =\n 1461446703485210103287273052203988822378723720583;\n\n function getSqrtRatioAtTick(\n int24 tick\n ) internal pure returns (uint160 sqrtPriceX96) {\n uint256 absTick = tick < 0\n ? uint256(-int256(tick))\n : uint256(int256(tick));\n if (absTick > uint256(int256(MAX_TICK))) revert InvalidTick();\n\n uint256 ratio = absTick & 0x1 != 0\n ? 0xfffcb933bd6fad37aa2d162d1a594001\n : 0x100000000000000000000000000000000;\n if (absTick & 0x2 != 0)\n ratio = (ratio * 0xfff97272373d413108a59cd6c9a98ca) >> 128;\n if (absTick & 0x4 != 0)\n ratio = (ratio * 0xfff2e50f5f656932ef12357cf3893ae3) >> 128;\n if (absTick & 0x8 != 0)\n ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;\n if (absTick & 0x10 != 0)\n ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;\n if (absTick & 0x20 != 0)\n ratio = (ratio * 0xff973b41fa98c081472684c4ef8f63a) >> 128;\n if (absTick & 0x40 != 0)\n ratio = (ratio * 0xff2ea16466c96a3fed829ccc0aeca9ac) >> 128;\n if (absTick & 0x80 != 0)\n ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;\n if (absTick & 0x100 != 0)\n ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;\n if (absTick & 0x200 != 0)\n ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e3a) >> 128;\n if (absTick & 0x400 != 0)\n ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;\n if (absTick & 0x800 != 0)\n ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;\n if (absTick & 0x1000 != 0)\n ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792b985b7) >> 128;\n if (absTick & 0x2000 != 0)\n ratio = (ratio * 0xa9f746462d870fdf8865dc1910d7fd8b) >> 128;\n if (absTick & 0x4000 != 0)\n ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;\n if (absTick & 0x8000 != 0)\n ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;\n if (absTick & 0x10000 != 0)\n ratio = (ratio * 0x9aa508b5b7a84e1c6d0b7f2d4f4d3d3d) >> 128;\n\n if (tick > 0) ratio = type(uint256).max / ratio;\n\n sqrtPriceX96 = uint160(\n (ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1)\n );\n }\n}\n\n// ============================================================================\n// MAIN CONTRACT\n// ============================================================================\n\ncontract YearnJBTCiStrategy is BaseStrategy, ReentrancyGuard {\n using SafeERC20 for IERC20;\n using Math for uint256;\n\n // ========================================================================\n // STATE VARIABLES - TOKENS\n // ========================================================================\n\n IERC20 public immutable WBTC;\n IERC20 public immutable CBBTC;\n\n // ========================================================================\n // STATE VARIABLES - ORACLES\n // ========================================================================\n\n IChainlinkOracle public immutable BTC_USD_ORACLE;\n IChainlinkOracle public immutable ETH_USD_ORACLE;\n IUniswapV3Pool public immutable UNISWAP_V3_POOL_WBTC_ETH;\n IUniswapV3Pool public immutable UNISWAP_V3_POOL_CBBTC_USDC;\n\n // Fallback oracle addresses (for recovery)\n address public fallbackBtcOracle;\n address public fallbackEthOracle;\n\n // ========================================================================\n // STATE VARIABLES - ROUTERS\n // ========================================================================\n\n IDEXRouter public immutable AERODROME_ROUTER;\n IDEXRouter public immutable UNISWAP_ROUTER;\n\n // ========================================================================\n // STATE VARIABLES - STRATEGY PARAMETERS\n // ========================================================================\n\n uint256 public depositCap = 50e8;\n uint256 public rebalanceThreshold = 200;\n uint256 public minArbitrageProfit = 0.005e8;\n\n // Dynamic gas tracking\n uint256 public lastEstimatedGasInBTC;\n uint256 public maxGasPerRebalancePercent = 500; // 5%\n\n // Approval management\n mapping(address => mapping(address => uint256)) public swapApprovals;\n mapping(address => mapping(address => uint256)) public approvalTimestamps;\n mapping(address => mapping(address => bool)) public approvalExpired;\n uint256 public maxApprovalPerSwap = 10e8;\n\n // Circuit breaker - multi-level\n uint256 public failedRebalanceCount;\n uint256 public lastFailedRebalance;\n uint256 public constant MAX_FAILED_REBALANCES = 3;\n uint256 public circuitBreakerCooldown = 1 days;\n bool public circuitBreakerTriggered;\n bool public gradualRecoveryActive;\n uint256 public preRecoveryDailyLimit;\n\n // Emergency state\n uint256 public emergencyWithdrawCount;\n uint256 public lastEmergencyWithdraw;\n\n // Position limits\n uint256 public maxPositionSize = 1000e8; // 1000 BTC maximum position\n uint256 public minPositionSize = 0.01e8; // 0.01 BTC minimum\n\n // Rate limiting with tracking\n uint256 public dailySwapLimitBTC = 2000e8; // 2000 BTC daily swap limit\n uint256 public swapLimitResetTime;\n uint256 public dailySwapVolumeUsed;\n\n uint256 public lastRebalanceTime;\n uint256 public minRebalanceInterval = 1 hours;\n uint256 public lastSwapTime;\n uint256 public minSwapInterval = 10 minutes;\n\n // Operational flags\n bool public rebalancingPaused;\n bool public emergencyWithdrawActive;\n bool public oracleFailureMode; // Use fallback oracles\n\n // Historical tracking for monitoring\n uint256 public totalRebalancesExecuted;\n uint256 public totalRebalancesFailed;\n uint256 public totalSwapsExecuted;\n uint256 public totalSwapsFailed;\n\n // ========================================================================\n // CONSTANTS\n // ========================================================================\n\n uint256 private constant BASIS_POINTS = 10_000;\n uint256 private constant ORACLE_STALE_THRESHOLD = 1 hours;\n uint256 private constant ORACLE_STALE_THRESHOLD_FALLBACK = 24 hours;\n uint256 private constant ORACLE_PRICE_DEVIATION_THRESHOLD = 200; // 2%\n uint256 private constant TWAP_DEVIATION_THRESHOLD = 100; // 1%\n uint256 public maxSlippage = 100; // 1% default, configurable\n uint256 private constant EMERGENCY_SLIPPAGE = 500; // 5%\n uint256 public swapFee = 25; // 0.25% default, configurable\n uint256 private constant MIN_REBALANCE_THRESHOLD = 50;\n uint256 private constant MAX_REBALANCE_THRESHOLD = 1000;\n uint256 private constant MIN_DEPOSIT_CAP = 1e8;\n uint256 private constant MAX_DEPOSIT_CAP = 1000e8; // 1000 BTC maximum\n uint256 private constant TWAP_PERIOD = 30 minutes;\n uint256 private constant GAS_ESTIMATION_BASE = 400_000;\n uint256 private constant GAS_ESTIMATION_BUFFER = 200_000;\n\n // Price safety bounds\n uint256 private constant MAX_PRICE_CHANGE_PERCENT = 1000; // 10% max per block\n uint256 private constant MIN_ORACLE_PRICE = 1e7; // $10K minimum\n uint256 private constant MAX_ORACLE_PRICE = 1e9; // $10M maximum\n\n struct StrategyStatus {\n bool isPaused;\n bool isCBTriggered;\n bool isInOracleFailureMode;\n uint256 totalHoldings;\n uint256 dailySwapUsed;\n uint256 dailySwapLimit;\n uint256 lastGasCost;\n uint256 rebalancesExecuted;\n uint256 rebalancesFailed;\n uint256 swapsExecuted;\n uint256 swapsFailed;\n uint256 wbtcAlloc;\n uint256 cbbtcAlloc;\n uint256 failCount;\n uint256 timeUntilReset;\n }\n\n // ========================================================================\n // EVENTS\n // ========================================================================\n\n event Rebalanced(\n address indexed fromToken,\n address indexed toToken,\n uint256 amountIn,\n uint256 amountOut,\n uint256 profit,\n uint256 timestamp\n );\n\n event RebalancingCompleted(\n uint256 indexed rebalanceId,\n uint256 timestamp,\n uint256 totalImbalance,\n uint256 gasCost\n );\n\n event RebalancingFailed(\n uint256 indexed rebalanceId,\n uint256 timestamp,\n uint256 failCount,\n string reason\n );\n\n event CircuitBreakerTriggered(string indexed reason, uint256 timestamp);\n event CircuitBreakerReset(uint256 timestamp);\n event OracleModeChanged(bool failureMode, uint256 timestamp);\n event DailyLimitReset(uint256 newLimit, uint256 timestamp);\n\n event ParametersUpdated(\n uint256 depositCap,\n uint256 rebalanceThreshold,\n uint256 minProfit,\n uint256 timestamp\n );\n\n event EmergencyAction(string indexed action, uint256 timestamp);\n event ApprovalIssued(\n address indexed token,\n address indexed spender,\n uint256 amount,\n uint256 expiry,\n uint256 timestamp\n );\n event ApprovalRevoked(\n address indexed token,\n address indexed spender,\n uint256 timestamp\n );\n event SwapExecuted(\n address indexed fromToken,\n address indexed toToken,\n uint256 amountIn,\n uint256 amountOut,\n uint256 slippageUsed,\n uint256 oraclePrice,\n uint256 dexPrice,\n uint256 timestamp\n );\n\n event MEVProtectionTriggered(\n string indexed reason,\n uint256 oraclePrice,\n uint256 dexPrice,\n uint256 deviation,\n uint256 timestamp\n );\n\n event RateLimitExceeded(\n string indexed reason,\n uint256 value,\n uint256 timestamp\n );\n event GasCostCalculated(\n uint256 gasCostWei,\n uint256 gasCostBTC,\n uint256 timestamp\n );\n event OraclePriceUpdate(\n address indexed tokenPair,\n uint256 priceFromOracle,\n uint256 priceFromDEX,\n uint256 deviationBps,\n uint256 timestamp\n );\n event OracleFailureDetected(\n address indexed oracle,\n string reason,\n uint256 timestamp\n );\n event HealthCheck(\n uint256 timestamp,\n bool oraclesHealthy,\n bool routersHealthy,\n uint256 positionSize,\n uint256 allocWBTC,\n uint256 allocCBBTC\n );\n\n // ========================================================================\n // CONSTRUCTOR\n // ========================================================================\n\n constructor(\n address _asset,\n string memory _name,\n address _wbtc,\n address _cbbtc,\n address _btcUsdOracle,\n address _ethUsdOracle,\n address _uniswapV3PoolWbtcEth,\n address _uniswapV3PoolCbbtcUsdc,\n address _aerodromeRouter,\n address _uniswapRouter,\n address _fallbackBtcOracle,\n address _fallbackEthOracle\n ) BaseStrategy(_asset, _name) {\n // Validate all inputs\n _validateConstructorInputs(\n _wbtc,\n _cbbtc,\n _btcUsdOracle,\n _ethUsdOracle,\n _uniswapV3PoolWbtcEth,\n _uniswapV3PoolCbbtcUsdc,\n _aerodromeRouter,\n _uniswapRouter,\n _fallbackBtcOracle,\n _fallbackEthOracle\n );\n\n WBTC = IERC20(_wbtc);\n CBBTC = IERC20(_cbbtc);\n\n BTC_USD_ORACLE = IChainlinkOracle(_btcUsdOracle);\n ETH_USD_ORACLE = IChainlinkOracle(_ethUsdOracle);\n\n UNISWAP_V3_POOL_WBTC_ETH = IUniswapV3Pool(_uniswapV3PoolWbtcEth);\n UNISWAP_V3_POOL_CBBTC_USDC = IUniswapV3Pool(_uniswapV3PoolCbbtcUsdc);\n\n AERODROME_ROUTER = IDEXRouter(_aerodromeRouter);\n UNISWAP_ROUTER = IDEXRouter(_uniswapRouter);\n\n fallbackBtcOracle = _fallbackBtcOracle;\n fallbackEthOracle = _fallbackEthOracle;\n\n swapLimitResetTime = block.timestamp + 1 days;\n }\n\n /**\n * @notice Validate all constructor inputs\n * @dev CRITICAL: Prevents initialization with invalid parameters\n */\n function _validateConstructorInputs(\n address _wbtc,\n address _cbbtc,\n address _btcUsdOracle,\n address _ethUsdOracle,\n address _uniswapV3PoolWbtcEth,\n address _uniswapV3PoolCbbtcUsdc,\n address _aerodromeRouter,\n address _uniswapRouter,\n address _fallbackBtcOracle,\n address _fallbackEthOracle\n ) internal view {\n if (_wbtc == address(0)) revert ZeroAddress();\n if (_cbbtc == address(0)) revert ZeroAddress();\n if (_btcUsdOracle == address(0)) revert ZeroAddress();\n if (_ethUsdOracle == address(0)) revert ZeroAddress();\n if (_uniswapV3PoolWbtcEth == address(0)) revert ZeroAddress();\n if (_uniswapV3PoolCbbtcUsdc == address(0)) revert ZeroAddress();\n if (_aerodromeRouter == address(0)) revert ZeroAddress();\n if (_uniswapRouter == address(0)) revert ZeroAddress();\n if (_fallbackBtcOracle == address(0)) revert ZeroAddress();\n if (_fallbackEthOracle == address(0)) revert ZeroAddress();\n\n // Verify tokens are different\n if (_wbtc == _cbbtc) revert DuplicateTokens();\n\n // Verify oracles are different\n if (_btcUsdOracle == _ethUsdOracle) revert SameAddress();\n if (_btcUsdOracle == _fallbackBtcOracle) revert SameAddress();\n if (_ethUsdOracle == _fallbackEthOracle) revert SameAddress();\n\n // Verify routers are different\n if (_aerodromeRouter == _uniswapRouter) revert SameAddress();\n\n // Validate WBTC/ETH pool contains WBTC\n address token0 = IUniswapV3Pool(_uniswapV3PoolWbtcEth).token0();\n address token1 = IUniswapV3Pool(_uniswapV3PoolWbtcEth).token1();\n if (token0 != _wbtc && token1 != _wbtc) revert InvalidPool();\n\n // Validate cbBTC/USDC pool contains cbBTC\n address cbToken0 = IUniswapV3Pool(_uniswapV3PoolCbbtcUsdc).token0();\n address cbToken1 = IUniswapV3Pool(_uniswapV3PoolCbbtcUsdc).token1();\n if (cbToken0 != _cbbtc && cbToken1 != _cbbtc) revert InvalidPool();\n }\n\n // ========================================================================\n // YEARN STRATEGY REQUIRED FUNCTIONS\n // ========================================================================\n\n function _deployFunds(\n uint256 /* _amount */\n ) internal override nonReentrant {\n // Safety checks\n if (\n rebalancingPaused ||\n TokenizedStrategy.isShutdown() ||\n circuitBreakerTriggered\n ) {\n return;\n }\n\n // Rate limiting\n if (block.timestamp < lastRebalanceTime + minRebalanceInterval) {\n emit RateLimitExceeded(\n \"RebalInt\",\n minRebalanceInterval,\n block.timestamp\n );\n return;\n }\n\n // Health check\n if (!_performHealthCheck()) {\n return;\n }\n\n // Check rebalancing is needed\n if (!_shouldRebalance()) {\n return;\n }\n\n _executeRebalance();\n }\n\n function _freeFunds(uint256 _amount) internal override nonReentrant {\n uint256 totalBalance = _calculateTotalHoldings();\n if (totalBalance < _amount) revert InsufficientBalance();\n\n uint256 wbtcBalance = WBTC.balanceOf(address(this));\n uint256 cbbtcBalance = CBBTC.balanceOf(address(this));\n\n // Proportional withdrawal with safety (50/50 split)\n if (wbtcBalance > 0) {\n uint256 wbtcToWithdraw = (_amount * wbtcBalance) / totalBalance;\n if (wbtcToWithdraw > 0 && wbtcToWithdraw <= wbtcBalance) {\n _swapIfNeeded(\n address(WBTC),\n address(asset),\n wbtcToWithdraw,\n false\n );\n }\n }\n\n if (cbbtcBalance > 0) {\n uint256 cbbtcToWithdraw = (_amount * cbbtcBalance) / totalBalance;\n if (cbbtcToWithdraw > 0 && cbbtcToWithdraw <= cbbtcBalance) {\n _swapIfNeeded(\n address(CBBTC),\n address(asset),\n cbbtcToWithdraw,\n false\n );\n }\n }\n }\n\n function _harvestAndReport()\n internal\n override\n nonReentrant\n returns (uint256 _totalAssets)\n {\n if (!TokenizedStrategy.isShutdown() && !rebalancingPaused) {\n _checkCircuitBreaker();\n\n if (\n !circuitBreakerTriggered &&\n _shouldRebalance() &&\n failedRebalanceCount < MAX_FAILED_REBALANCES\n ) {\n try this._executeRebalanceInternal() {\n failedRebalanceCount = 0;\n lastRebalanceTime = block.timestamp;\n totalRebalancesExecuted++;\n } catch Error(string memory reason) {\n _handleRebalanceFailure(reason);\n }\n }\n }\n\n _totalAssets = _calculateTotalHoldings();\n return _totalAssets;\n }\n\n function availableDepositLimit(\n address\n ) public view override returns (uint256) {\n uint256 positionSize = _calculateTotalHoldings();\n uint256 effectiveCap = Math.min(depositCap, maxPositionSize);\n\n return positionSize >= effectiveCap ? 0 : effectiveCap - positionSize;\n }\n\n function availableWithdrawLimit(\n address\n ) public view override returns (uint256) {\n return TokenizedStrategy.totalAssets();\n }\n\n function _emergencyWithdraw(\n uint256 _amount\n ) internal override nonReentrant {\n emergencyWithdrawActive = true;\n emergencyWithdrawCount++;\n lastEmergencyWithdraw = block.timestamp;\n\n _amount = Math.min(_amount, _calculateTotalHoldings());\n\n uint256 wbtcBalance = WBTC.balanceOf(address(this));\n if (wbtcBalance > 0) {\n _swapEmergency(address(WBTC), address(asset), wbtcBalance);\n }\n\n uint256 cbbtcBalance = CBBTC.balanceOf(address(this));\n if (cbbtcBalance > 0) {\n _swapEmergency(address(CBBTC), address(asset), cbbtcBalance);\n }\n\n _revokeAllApprovals();\n emergencyWithdrawActive = false;\n emit EmergencyAction(\"Withdraw\", block.timestamp);\n }\n\n // ========================================================================\n // HEALTH CHECK SYSTEM\n // ========================================================================\n\n /**\n * @notice Perform comprehensive health check on strategy\n * @return healthy True if all systems operational\n */\n function _performHealthCheck() internal returns (bool healthy) {\n // Check oracles\n bool oraclesHealthy = true;\n try this.getBTCPrice() returns (uint256) {\n // Oracle working\n } catch {\n oraclesHealthy = false;\n emit OracleFailureDetected(\n address(BTC_USD_ORACLE),\n \"OracleFail\",\n block.timestamp\n );\n }\n // Check routers by attempting simulation\n bool routersHealthy = true;\n try this._checkRouterHealth() returns (bool healthy_) {\n routersHealthy = healthy_;\n } catch {\n routersHealthy = false;\n emit OracleFailureDetected(\n address(AERODROME_ROUTER),\n \"RouterFail\",\n block.timestamp\n );\n }\n // Get allocations (2-asset model: WBTC + cbBTC)\n (uint256 wbtcAlloc, uint256 cbbtcAlloc) = _getCurrentAllocations();\n\n emit HealthCheck(\n block.timestamp,\n oraclesHealthy,\n routersHealthy,\n _calculateTotalHoldings(),\n wbtcAlloc,\n cbbtcAlloc\n );\n\n return oraclesHealthy && routersHealthy;\n }\n\n /**\n * @notice Check if routers are operational\n */\n function _checkRouterHealth() external view returns (bool) {\n try AERODROME_ROUTER.getAmountsOut(1e8, new address[](2)) {\n return true;\n } catch {\n return false;\n }\n }\n\n // ========================================================================\n // ORACLE & PRICE VALIDATION (PRODUCTION GRADE)\n // ========================================================================\n\n /**\n * @notice Get BTC price with comprehensive oracle validation\n * @return price BTC/USD price in 8 decimals\n */\n function getBTCPrice() public view returns (uint256 price) {\n uint256 chainlinkPrice;\n\n // Try primary oracle first\n try this._getChainlinkPrice(address(BTC_USD_ORACLE)) returns (\n uint256 price_\n ) {\n chainlinkPrice = price_;\n } catch {\n // Fallback to backup oracle\n try this._getChainlinkPrice(fallbackBtcOracle) returns (\n uint256 fallbackPrice\n ) {\n chainlinkPrice = fallbackPrice;\n } catch {\n revert InvalidPrice();\n }\n }\n // Get TWAP price\n uint256 twapPrice;\n try this._getTWAPPrice() returns (uint256 twap_) {\n twapPrice = twap_;\n } catch {\n // If TWAP fails, use Chainlink with warning\n twapPrice = chainlinkPrice;\n }\n // Validate deviation\n uint256 priceDiff = chainlinkPrice > twapPrice\n ? chainlinkPrice - twapPrice\n : twapPrice - chainlinkPrice;\n\n uint256 deviationBps = (priceDiff * BASIS_POINTS) / chainlinkPrice;\n\n if (deviationBps > ORACLE_PRICE_DEVIATION_THRESHOLD)\n revert PriceDeviation();\n\n // Sanity check on absolute price\n if (\n chainlinkPrice < MIN_ORACLE_PRICE ||\n chainlinkPrice > MAX_ORACLE_PRICE\n ) revert PriceOutOfRange();\n\n return chainlinkPrice;\n }\n\n /**\n * @notice Get price from Chainlink oracle with staleness check\n * @param oracle Oracle address to query\n */\n function _getChainlinkPrice(\n address oracle\n ) external view returns (uint256) {\n (, int256 answer, , uint256 updatedAt, ) = IChainlinkOracle(oracle)\n .latestRoundData();\n\n if (answer <= 0) revert InvalidPrice();\n\n uint256 staleThreshold = oracleFailureMode\n ? ORACLE_STALE_THRESHOLD_FALLBACK\n : ORACLE_STALE_THRESHOLD;\n\n if (block.timestamp - updatedAt >= staleThreshold) revert StalePrice();\n\n return uint256(answer);\n }\n\n /**\n * @notice Get TWAP price from Uniswap V3 with safety checks\n */\n function _getTWAPPrice() external view returns (uint256) {\n try this._calculateTWAP() returns (uint256 twapPrice) {\n if (twapPrice == 0) revert InvalidPrice();\n\n // Check TWAP hasn't moved too much from spot (prevents oracle manipulation)\n (uint160 sqrtPriceX96, , , , , , ) = UNISWAP_V3_POOL_WBTC_ETH\n .slot0();\n uint256 spotPrice = _sqrtPriceToPrice(sqrtPriceX96);\n\n uint256 priceDiff = spotPrice > twapPrice\n ? spotPrice - twapPrice\n : twapPrice - spotPrice;\n\n uint256 changePercent = (priceDiff * BASIS_POINTS) / spotPrice;\n if (changePercent > MAX_PRICE_CHANGE_PERCENT)\n revert PriceDeviation();\n\n return twapPrice;\n } catch {\n revert InvalidPrice();\n }\n }\n\n /**\n * @notice Calculate 10-minute TWAP from Uniswap V3\n */\n function _calculateTWAP() external view returns (uint256) {\n uint32[] memory secondsAgos = new uint32[](2);\n secondsAgos[0] = uint32(TWAP_PERIOD);\n secondsAgos[1] = 0;\n\n (int56[] memory tickCumulatives, ) = UNISWAP_V3_POOL_WBTC_ETH.observe(\n secondsAgos\n );\n\n int56 tickCumulativesDelta = tickCumulatives[1] - tickCumulatives[0];\n int24 tick = int24(tickCumulativesDelta / int56(uint56(TWAP_PERIOD)));\n\n uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(tick);\n return _sqrtPriceToPrice(sqrtPriceX96);\n }\n\n /**\n * @notice Convert sqrt price to actual price\n */\n /**\n * @notice Convert Uniswap V3 sqrtPriceX96 to 8-decimal price format\n * @dev Safe implementation that avoids arithmetic overflow\n * @param sqrtPriceX96 The sqrt price in X96 format from Uniswap V3\n * @return price The price in 8 decimal format (oracle compatible)\n */\n function _sqrtPriceToPrice(\n uint160 sqrtPriceX96\n ) internal pure returns (uint256 price) {\n // Uniswap V3 price formula: price = (sqrtPriceX96 / 2^96)^2\n // Using FullMath to prevent overflow in intermediate calculations\n\n uint256 sqrtPrice = uint256(sqrtPriceX96);\n\n // Calculate sqrtPrice^2 / 2^192 safely using FullMath\n // We split: (sqrtPrice^2 * 10^8) / 2^192\n // = FullMath.mulDiv(sqrtPrice * sqrtPrice, 10^8, 2^192)\n // But sqrtPrice * sqrtPrice can overflow, so we do it in stages:\n // = FullMath.mulDiv(sqrtPrice, sqrtPrice, 2^96) * 10^8 / 2^96\n\n uint256 priceX96 = FullMath.mulDiv(sqrtPrice, sqrtPrice, 1 << 96);\n price = FullMath.mulDiv(priceX96, 10 ** 8, 1 << 96);\n\n return price;\n }\n /**\n * @notice Spot price for token pair from Uniswap V3 x Simplified for 2-asset model (WBTC + cbBTC) x For WBTC/cbBTC price, we use Chainlink BTC/USD (both track BTC ~1:1)\n */\n function _getSpotPrice(\n address _tokenA,\n address _tokenB\n ) internal view returns (uint256 spotPrice) {\n // For WBTC/cbBTC pairs, assume 1:1 peg (both are wrapped BTC)\n // Real price difference is minimal and handled by slippage tolerance\n if (\n (_tokenA == address(WBTC) && _tokenB == address(CBBTC)) ||\n (_tokenA == address(CBBTC) && _tokenB == address(WBTC))\n ) {\n // Return 1:1 ratio (1e8 for 8 decimal precision)\n return 1e8;\n } else {\n revert(\"Unsupported token pair\");\n }\n }\n\n /**\n * @notice Get price from Uniswap V3 pool x Staleness check and precision handling\n */\n function _getPriceFromPool(\n IUniswapV3Pool pool,\n bool token0IsNumerator\n ) internal view returns (uint256) {\n (\n uint160 sqrtPriceX96,\n , // tick (unused)\n , // observationIndex (unused)\n uint16 observationCardinality,\n ,\n ,\n\n ) = pool.slot0();\n\n // Require sufficient observations for TWAP\n if (observationCardinality < 10) revert InvalidPrice();\n\n // Convert sqrt price to price\n uint256 price = _sqrtPriceToPrice(sqrtPriceX96);\n\n // Invert if needed\n if (!token0IsNumerator && price > 0) {\n price = (1e8 * 1e8) / price;\n }\n\n return price;\n }\n\n // ========================================================================\n // DYNAMIC GAS COST CALCULATION\n // ========================================================================\n\n /**\n * @notice Calculate dynamic gas cost in BTC\n * @return estimatedGasInBTC Gas cost in BTC (8 decimals)\n */\n function _calculateDynamicGasCostInBTC()\n internal\n returns (uint256 estimatedGasInBTC)\n {\n uint256 currentGasPrice = tx.gasprice;\n uint256 estimatedGasUsage = GAS_ESTIMATION_BASE + GAS_ESTIMATION_BUFFER;\n\n uint256 gasCostInWei = currentGasPrice * estimatedGasUsage;\n\n uint256 ethPriceUSD;\n try this._getChainlinkPrice(address(ETH_USD_ORACLE)) returns (\n uint256 price_\n ) {\n ethPriceUSD = price_;\n } catch {\n try this._getChainlinkPrice(fallbackEthOracle) returns (\n uint256 fallbackPrice\n ) {\n ethPriceUSD = fallbackPrice;\n } catch {\n // Fallback to safe assumption if both oracles fail\n ethPriceUSD = 2000e8; // $2000 ETH\n }\n }\n uint256 btcPriceUSD = getBTCPrice();\n\n if (btcPriceUSD == 0) revert InvalidPrice();\n\n // SafeMath for price conversion\n // Formula: (gasCostInWei / 1e18) * (ethPriceUSD / btcPriceUSD)\n estimatedGasInBTC = (gasCostInWei * ethPriceUSD) / (1e18 * btcPriceUSD);\n\n // Sanity check: gas cost shouldn't exceed 10 BTC because that's literally insane\n if (estimatedGasInBTC >= 10e8) revert AmountExceedsLimit();\n\n lastEstimatedGasInBTC = estimatedGasInBTC;\n emit GasCostCalculated(\n gasCostInWei,\n estimatedGasInBTC,\n block.timestamp\n );\n\n return estimatedGasInBTC;\n }\n\n // ========================================================================\n // MEV PROTECTION & VALIDATION\n // ========================================================================\n\n /**\n * @notice Validate swap price against oracle to detect MEV x Oracle-backed validation\n */\n function _validateSwapPrice(\n address _from,\n address _to,\n uint256 _amountIn,\n uint256 _expectedOut\n ) internal {\n // Get oracle spot price\n uint256 spotPrice = _getSpotPrice(_from, _to);\n\n // Calculate DEX implied price\n uint256 priceFromDEX = (_expectedOut * 1e8) / _amountIn;\n\n // Check deviation\n uint256 priceDiff = spotPrice > priceFromDEX\n ? spotPrice - priceFromDEX\n : priceFromDEX - spotPrice;\n\n uint256 deviationBps = (priceDiff * BASIS_POINTS) / spotPrice;\n\n emit OraclePriceUpdate(\n _from,\n spotPrice,\n priceFromDEX,\n deviationBps,\n block.timestamp\n );\n\n // MEV protection: revert if deviation too high\n if (deviationBps > TWAP_DEVIATION_THRESHOLD) {\n emit MEVProtectionTriggered(\n \"DEX price deviation\",\n spotPrice,\n priceFromDEX,\n deviationBps,\n block.timestamp\n );\n revert(\"MEV: price deviation exceeds threshold\");\n }\n }\n\n // ========================================================================\n // CIRCUIT BREAKER SYSTEM\n // ========================================================================\n\n function _checkCircuitBreaker() internal {\n // Check for gradual recovery completion FIRST (runs even after CB is reset)\n if (gradualRecoveryActive) {\n if (\n block.timestamp >=\n lastFailedRebalance + circuitBreakerCooldown + 1 hours\n ) {\n dailySwapLimitBTC = preRecoveryDailyLimit;\n gradualRecoveryActive = false;\n emit DailyLimitReset(dailySwapLimitBTC, block.timestamp);\n }\n }\n\n // Then check if circuit breaker needs to be reset\n if (circuitBreakerTriggered) {\n if (\n block.timestamp >= lastFailedRebalance + circuitBreakerCooldown\n ) {\n // ONE-TIME limit reduction\n if (!gradualRecoveryActive) {\n preRecoveryDailyLimit = dailySwapLimitBTC;\n dailySwapLimitBTC = dailySwapLimitBTC / 2;\n gradualRecoveryActive = true;\n emit DailyLimitReset(dailySwapLimitBTC, block.timestamp);\n }\n\n circuitBreakerTriggered = false;\n failedRebalanceCount = 0;\n emit CircuitBreakerReset(block.timestamp);\n }\n }\n }\n\n function _handleRebalanceFailure(string memory reason) internal {\n failedRebalanceCount++;\n lastFailedRebalance = block.timestamp;\n totalRebalancesFailed++;\n\n emit RebalancingFailed(\n totalRebalancesFailed,\n block.timestamp,\n failedRebalanceCount,\n reason\n );\n\n if (failedRebalanceCount >= MAX_FAILED_REBALANCES) {\n circuitBreakerTriggered = true;\n rebalancingPaused = true;\n emit CircuitBreakerTriggered(\"MaxFail\", block.timestamp);\n }\n }\n\n function getCircuitBreakerStatus()\n external\n view\n returns (\n bool isTriggered,\n uint256 failCount,\n uint256 timeSinceLastFailure,\n uint256 timeUntilReset\n )\n {\n isTriggered = circuitBreakerTriggered;\n failCount = failedRebalanceCount;\n timeSinceLastFailure = lastFailedRebalance > 0\n ? block.timestamp - lastFailedRebalance\n : 0;\n timeUntilReset = lastFailedRebalance > 0 && isTriggered\n ? lastFailedRebalance + circuitBreakerCooldown > block.timestamp\n ? (lastFailedRebalance + circuitBreakerCooldown) -\n block.timestamp\n : 0\n : 0;\n }\n\n // ========================================================================\n // REBALANCING LOGIC\n // ========================================================================\n\n function _shouldRebalance() internal view returns (bool) {\n try this.getBTCPrice() returns (uint256) {\n // Oracle working\n } catch {\n return false;\n }\n (uint256 wbtcAlloc, uint256 cbbtcAlloc) = _getCurrentAllocations();\n // 50/50 target for 2-asset index\n uint256 targetAlloc = BASIS_POINTS / 2;\n\n uint256 wbtcDev = wbtcAlloc > targetAlloc\n ? wbtcAlloc - targetAlloc\n : targetAlloc - wbtcAlloc;\n uint256 cbbtcDev = cbbtcAlloc > targetAlloc\n ? cbbtcAlloc - targetAlloc\n : targetAlloc - cbbtcAlloc;\n\n return wbtcDev > rebalanceThreshold || cbbtcDev > rebalanceThreshold;\n }\n\n /**\n * @notice Execute rebalance with comprehensive safety checks\n */\n function _executeRebalance() internal {\n uint256 totalBalance = _calculateTotalHoldings();\n if (totalBalance == 0) return;\n\n // Validate position size\n if (totalBalance < minPositionSize) revert PositionTooSmall();\n if (totalBalance > maxPositionSize) revert PositionTooLarge();\n\n // Dynamic gas cost\n uint256 dynamicGasCost = _calculateDynamicGasCostInBTC();\n\n // 50/50 split for 2-asset index\n uint256 targetPerAsset = totalBalance / 2;\n\n uint256 wbtcBalance = WBTC.balanceOf(address(this));\n uint256 cbbtcBalance = CBBTC.balanceOf(address(this));\n\n int256 wbtcDelta = int256(wbtcBalance) - int256(targetPerAsset);\n int256 cbbtcDelta = int256(cbbtcBalance) - int256(targetPerAsset);\n\n uint256 totalImbalance = _abs(wbtcDelta) + _abs(cbbtcDelta);\n\n // Profitability check with dynamic gas\n if (totalImbalance < (dynamicGasCost + minArbitrageProfit)) {\n return;\n }\n\n _resetDailySwapLimit();\n\n // Simple 2-asset rebalancing: swap excess from one to the other\n if (wbtcDelta > 0 && cbbtcDelta < 0) {\n // Too much WBTC, too little cbBTC - swap WBTC to cbBTC\n uint256 toSwap = Math.min(uint256(wbtcDelta), uint256(-cbbtcDelta));\n if (!_trySwapWithLimit(address(WBTC), address(CBBTC), toSwap)) {\n return;\n }\n } else if (cbbtcDelta > 0 && wbtcDelta < 0) {\n // Too much cbBTC, too little WBTC - swap cbBTC to WBTC\n uint256 toSwap = Math.min(uint256(cbbtcDelta), uint256(-wbtcDelta));\n if (!_trySwapWithLimit(address(CBBTC), address(WBTC), toSwap)) {\n return;\n }\n }\n\n emit RebalancingCompleted(\n totalRebalancesExecuted,\n block.timestamp,\n totalImbalance,\n dynamicGasCost\n );\n }\n\n /**\n * @notice Try swap with limit checking\n */\n function _trySwapWithLimit(\n address _from,\n address _to,\n uint256 _amount\n ) internal returns (bool success) {\n // Check daily limit\n if (dailySwapVolumeUsed + _amount > dailySwapLimitBTC) {\n emit RateLimitExceeded(\n \"DayLimit\",\n dailySwapLimitBTC,\n block.timestamp\n );\n return false;\n }\n\n // Check rate limit\n if (block.timestamp < lastSwapTime + minSwapInterval) {\n emit RateLimitExceeded(\"SwapInt\", minSwapInterval, block.timestamp);\n return false;\n }\n\n try this._swapWithProfitCheckInternal(_from, _to, _amount) {\n dailySwapVolumeUsed += _amount;\n lastSwapTime = block.timestamp;\n totalSwapsExecuted++;\n return true;\n } catch Error(string memory reason) {\n totalSwapsFailed++;\n emit RebalancingFailed(\n totalSwapsFailed,\n block.timestamp,\n failedRebalanceCount,\n reason\n );\n return false;\n }\n }\n\n function _resetDailySwapLimit() internal {\n if (block.timestamp >= swapLimitResetTime) {\n dailySwapVolumeUsed = 0;\n swapLimitResetTime = block.timestamp + 1 days;\n }\n }\n\n function _swapWithProfitCheckInternal(\n address _from,\n address _to,\n uint256 _amount\n ) external {\n if (msg.sender != address(this)) revert InternalOnly();\n _swapWithProfitCheck(_from, _to, _amount);\n }\n\n /**\n * @notice Execute swap with MEV protection\n */\n function _swapWithProfitCheck(\n address _from,\n address _to,\n uint256 _amount\n ) internal nonReentrant {\n if (_amount == 0 || _from == _to) return;\n\n if (_amount > maxApprovalPerSwap) revert AmountExceedsLimit();\n\n _issueTimeLimitedApproval(\n IERC20(_from),\n address(AERODROME_ROUTER),\n _amount\n );\n _issueTimeLimitedApproval(\n IERC20(_from),\n address(UNISWAP_ROUTER),\n _amount\n );\n\n address[] memory path = new address[](2);\n path[0] = _from;\n path[1] = _to;\n\n uint256[] memory aerodromeAmounts = AERODROME_ROUTER.getAmountsOut(\n _amount,\n path\n );\n uint256[] memory uniswapAmounts = UNISWAP_ROUTER.getAmountsOut(\n _amount,\n path\n );\n\n uint256 expectedOut = Math.max(aerodromeAmounts[1], uniswapAmounts[1]);\n IDEXRouter selectedRouter = aerodromeAmounts[1] > uniswapAmounts[1]\n ? AERODROME_ROUTER\n : UNISWAP_ROUTER;\n\n // MEV validation\n _validateSwapPrice(_from, _to, _amount, expectedOut);\n\n // Slippage protection\n uint256 minOut = (expectedOut * (BASIS_POINTS - maxSlippage)) /\n BASIS_POINTS;\n\n // Profitability check using configurable swapFee\n uint256 breakEven = (_amount * (BASIS_POINTS - swapFee)) / BASIS_POINTS;\n if (minOut < breakEven + minArbitrageProfit) revert SlippageExceeded();\n\n uint256 balanceBefore = IERC20(_to).balanceOf(address(this));\n\n // Execute\n selectedRouter.swapExactTokensForTokens(\n _amount,\n minOut,\n path,\n address(this),\n block.timestamp + 60\n );\n\n uint256 balanceAfter = IERC20(_to).balanceOf(address(this));\n uint256 actualOut = balanceAfter - balanceBefore;\n\n if (actualOut < minOut) revert SlippageExceeded();\n\n uint256 profit = actualOut > _amount ? actualOut - _amount : 0;\n uint256 slippageUsed = expectedOut > actualOut\n ? expectedOut - actualOut\n : 0;\n\n // Revoke approvals\n _revokeApproval(IERC20(_from), address(AERODROME_ROUTER));\n _revokeApproval(IERC20(_from), address(UNISWAP_ROUTER));\n\n emit SwapExecuted(\n _from,\n _to,\n _amount,\n actualOut,\n slippageUsed,\n _getSpotPrice(_from, _to),\n expectedOut,\n block.timestamp\n );\n emit Rebalanced(\n _from,\n _to,\n _amount,\n actualOut,\n profit,\n block.timestamp\n );\n }\n\n /**\n * @notice Emergency swap with higher slippage tolerance\n */\n function _swapEmergency(\n address _from,\n address _to,\n uint256 _amount\n ) internal nonReentrant {\n if (_amount == 0 || _from == _to) return;\n\n _issueTimeLimitedApproval(\n IERC20(_from),\n address(AERODROME_ROUTER),\n _amount\n );\n _issueTimeLimitedApproval(\n IERC20(_from),\n address(UNISWAP_ROUTER),\n _amount\n );\n\n address[] memory path = new address[](2);\n path[0] = _from;\n path[1] = _to;\n\n uint256[] memory aerodromeAmounts = AERODROME_ROUTER.getAmountsOut(\n _amount,\n path\n );\n uint256[] memory uniswapAmounts = UNISWAP_ROUTER.getAmountsOut(\n _amount,\n path\n );\n\n uint256 expectedOut = Math.max(aerodromeAmounts[1], uniswapAmounts[1]);\n IDEXRouter router = aerodromeAmounts[1] > uniswapAmounts[1]\n ? AERODROME_ROUTER\n : UNISWAP_ROUTER;\n\n uint256 minOut = (expectedOut * (BASIS_POINTS - EMERGENCY_SLIPPAGE)) /\n BASIS_POINTS;\n\n router.swapExactTokensForTokens(\n _amount,\n minOut,\n path,\n address(this),\n block.timestamp + 60\n );\n\n _revokeApproval(IERC20(_from), address(AERODROME_ROUTER));\n _revokeApproval(IERC20(_from), address(UNISWAP_ROUTER));\n }\n\n function _executeRebalanceInternal() external {\n if (msg.sender != address(this)) revert InternalOnly();\n _executeRebalance();\n }\n\n // ========================================================================\n // APPROVAL MANAGEMENT\n // ========================================================================\n\n /**\n * @notice Issue time-limited approval for swap\n */\n function _issueTimeLimitedApproval(\n IERC20 token,\n address spender,\n uint256 amount\n ) internal {\n if (amount > maxApprovalPerSwap) revert AmountExceedsLimit();\n if (amount == 0) revert AmountIsZero();\n\n uint256 expiryTime = block.timestamp + 1 hours;\n\n // Atomic clear and issue\n token.forceApprove(spender, 0);\n token.forceApprove(spender, amount);\n\n swapApprovals[address(token)][spender] = amount;\n approvalTimestamps[address(token)][spender] = expiryTime;\n approvalExpired[address(token)][spender] = false;\n\n emit ApprovalIssued(\n address(token),\n spender,\n amount,\n expiryTime,\n block.timestamp\n );\n }\n\n /**\n * @notice Revoke approval\n */\n function _revokeApproval(IERC20 token, address spender) internal {\n token.forceApprove(spender, 0);\n swapApprovals[address(token)][spender] = 0;\n approvalTimestamps[address(token)][spender] = 0;\n approvalExpired[address(token)][spender] = true;\n\n emit ApprovalRevoked(address(token), spender, block.timestamp);\n }\n\n /**\n * @notice Revoke all approvals in emergency\n */\n function _revokeAllApprovals() internal {\n _revokeApproval(WBTC, address(AERODROME_ROUTER));\n _revokeApproval(WBTC, address(UNISWAP_ROUTER));\n _revokeApproval(CBBTC, address(AERODROME_ROUTER));\n _revokeApproval(CBBTC, address(UNISWAP_ROUTER));\n }\n\n // ========================================================================\n // HELPER FUNCTIONS\n // ========================================================================\n\n function _swapIfNeeded(\n address _from,\n address _to,\n uint256 _amount,\n bool _isEmergency\n ) internal {\n if (_from != _to && _amount > 0) {\n if (_isEmergency) {\n _swapEmergency(_from, _to, _amount);\n } else {\n _swapWithProfitCheck(_from, _to, _amount);\n }\n }\n }\n\n function _getCurrentAllocations()\n internal\n view\n returns (uint256 wbtcAlloc, uint256 cbbtcAlloc)\n {\n uint256 totalBalance = _calculateTotalHoldings();\n if (totalBalance == 0) return (0, 0);\n\n uint256 wbtcBalance = WBTC.balanceOf(address(this));\n uint256 cbbtcBalance = CBBTC.balanceOf(address(this));\n\n wbtcAlloc = (wbtcBalance * BASIS_POINTS) / totalBalance;\n cbbtcAlloc = (cbbtcBalance * BASIS_POINTS) / totalBalance;\n }\n\n function _calculateTotalHoldings() internal view returns (uint256) {\n return\n WBTC.balanceOf(address(this)) +\n CBBTC.balanceOf(address(this)) +\n asset.balanceOf(address(this));\n }\n\n function _abs(int256 x) internal pure returns (uint256) {\n return x >= 0 ? uint256(x) : uint256(-x);\n }\n\n // ========================================================================\n // MANAGEMENT & ADMIN FUNCTIONS (CONTINUED)\n // ========================================================================\n\n /**\n * @notice Update fallback oracles\n */\n function setFallbackOracles(\n address _btcOracle,\n address _ethOracle\n ) external onlyManagement {\n if (_btcOracle == address(0)) revert ZeroAddress();\n if (_ethOracle == address(0)) revert ZeroAddress();\n if (_btcOracle == address(BTC_USD_ORACLE)) revert SameAddress();\n if (_ethOracle == address(ETH_USD_ORACLE)) revert SameAddress();\n\n fallbackBtcOracle = _btcOracle;\n fallbackEthOracle = _ethOracle;\n }\n\n /**\n * @notice Pause rebalancing (emergency)\n */\n function pauseRebalancing() external onlyEmergencyAuthorized {\n if (rebalancingPaused) revert AlreadyPaused();\n rebalancingPaused = true;\n emit EmergencyAction(\"Paused\", block.timestamp);\n }\n\n /**\n * @notice Unpause rebalancing\n */\n function unpauseRebalancing() external onlyManagement {\n if (!rebalancingPaused) revert NotPaused();\n rebalancingPaused = false;\n emit EmergencyAction(\"Unpaused\", block.timestamp);\n }\n\n /**\n * @notice Reset circuit breaker (only after cooldown)\n */\n function resetCircuitBreaker() external onlyManagement {\n if (block.timestamp < lastFailedRebalance + circuitBreakerCooldown)\n revert BelowMinimum();\n circuitBreakerTriggered = false;\n failedRebalanceCount = 0;\n emit CircuitBreakerReset(block.timestamp);\n }\n\n /**\n * @notice Enable oracle failure mode (use fallback oracles)\n */\n function enableOracleFailureMode() external onlyEmergencyAuthorized {\n if (oracleFailureMode) revert AlreadyInFailureMode();\n oracleFailureMode = true;\n emit OracleModeChanged(true, block.timestamp);\n emit EmergencyAction(\"OracleFailOn\", block.timestamp);\n }\n\n /**\n * @notice Disable oracle failure mode (resume normal operation)\n */\n function disableOracleFailureMode() external onlyManagement {\n if (!oracleFailureMode) revert NotInFailureMode();\n oracleFailureMode = false;\n emit OracleModeChanged(false, block.timestamp);\n emit EmergencyAction(\"OracleFailOff\", block.timestamp);\n }\n\n /**\n * @notice Set swap fee for profitability calculations\n * @param _newFee Fee in basis points (e.g., 25 = 0.25%)\n * @dev Bounded between 5 bps (0.05%) and 100 bps (1%)\n */\n function setSwapFee(uint256 _newFee) external onlyManagement {\n if (_newFee < 5) revert BelowMinimum();\n if (_newFee > 100) revert ExceedsMaximum();\n swapFee = _newFee;\n emit ParametersUpdated(\n depositCap,\n rebalanceThreshold,\n minArbitrageProfit,\n block.timestamp\n );\n }\n\n /**\n * @notice Update deposit cap within allowed bounds\n * @param _newCap New deposit cap in BTC with 8 decimals (e.g., 100e8 = 100 BTC)\n * @dev Bounded by MIN_DEPOSIT_CAP (1 BTC) and MAX_DEPOSIT_CAP (1000 BTC)\n */\n function setDepositCap(uint256 _newCap) external onlyManagement {\n if (_newCap < MIN_DEPOSIT_CAP) revert BelowMinimum();\n if (_newCap > MAX_DEPOSIT_CAP) revert ExceedsMaximum();\n\n depositCap = _newCap;\n\n emit ParametersUpdated(\n depositCap,\n rebalanceThreshold,\n minArbitrageProfit,\n block.timestamp\n );\n }\n\n /**\n * @notice Set maximum slippage for swaps\n * @param _newSlippage New slippage in basis points (e.g., 100 = 1%)\n * @dev Bounded between 10 bps (0.1%) and 500 bps (5%)\n */\n function setMaxSlippage(uint256 _newSlippage) external onlyManagement {\n if (_newSlippage < 10) revert BelowMinimum();\n if (_newSlippage > 1000) revert ExceedsMaximum(); // 10% max for market stress\n\n maxSlippage = _newSlippage;\n\n emit ParametersUpdated(\n depositCap,\n rebalanceThreshold,\n minArbitrageProfit,\n block.timestamp\n );\n }\n\n // ========================================================================\n // MONITORING & STATUS\n // ========================================================================\n\n /**\n * @notice Get comprehensive strategy status\n */\n function getStrategyStatus()\n external\n view\n returns (StrategyStatus memory status)\n {\n // Scope 1: Holdings & Allocations\n {\n uint256 total = _calculateTotalHoldings();\n status.totalHoldings = total;\n\n (status.wbtcAlloc, status.cbbtcAlloc) = _getCurrentAllocations();\n }\n\n // Scope 2: Circuit Breaker\n {\n (bool cb, uint256 fails, , uint256 resetTime) = this\n .getCircuitBreakerStatus();\n status.isCBTriggered = cb;\n status.failCount = fails;\n status.timeUntilReset = resetTime;\n }\n\n // Scope 3: State Variables\n status.isPaused = rebalancingPaused;\n status.isInOracleFailureMode = oracleFailureMode;\n status.dailySwapUsed = dailySwapVolumeUsed;\n status.dailySwapLimit = dailySwapLimitBTC;\n status.lastGasCost = lastEstimatedGasInBTC;\n status.rebalancesExecuted = totalRebalancesExecuted;\n status.rebalancesFailed = totalRebalancesFailed;\n status.swapsExecuted = totalSwapsExecuted;\n status.swapsFailed = totalSwapsFailed;\n }\n\n /**\n * @notice Get detailed allocation status\n */\n function getAllocationDetails()\n external\n view\n returns (\n uint256 wbtcBalance,\n uint256 cbbtcBalance,\n uint256 assetBalance,\n uint256 totalBalance,\n uint256 wbtcPercent,\n uint256 cbbtcPercent,\n uint256 assetPercent\n )\n {\n wbtcBalance = WBTC.balanceOf(address(this));\n cbbtcBalance = CBBTC.balanceOf(address(this));\n assetBalance = asset.balanceOf(address(this));\n totalBalance = wbtcBalance + cbbtcBalance + assetBalance;\n\n if (totalBalance > 0) {\n wbtcPercent = (wbtcBalance * BASIS_POINTS) / totalBalance;\n cbbtcPercent = (cbbtcBalance * BASIS_POINTS) / totalBalance;\n assetPercent = (assetBalance * BASIS_POINTS) / totalBalance;\n }\n }\n\n /**\n * @notice Get rate limit status\n */\n function getRateLimitStatus()\n external\n view\n returns (\n uint256 dailySwapUsed,\n uint256 dailySwapLimit,\n uint256 timeUntilDailyReset,\n uint256 timeSinceLastRebalance,\n uint256 minRebalanceIntervalSec,\n uint256 timeSinceLastSwap,\n uint256 minSwapIntervalSec\n )\n {\n dailySwapUsed = dailySwapVolumeUsed;\n dailySwapLimit = dailySwapLimitBTC;\n timeUntilDailyReset = swapLimitResetTime > block.timestamp\n ? swapLimitResetTime - block.timestamp\n : 0;\n timeSinceLastRebalance = lastRebalanceTime > 0\n ? block.timestamp - lastRebalanceTime\n : 0;\n minRebalanceIntervalSec = minRebalanceInterval;\n timeSinceLastSwap = lastSwapTime > 0\n ? block.timestamp - lastSwapTime\n : 0;\n minSwapIntervalSec = minSwapInterval;\n }\n\n /**\n * @notice Get approval status\n */\n function getApprovalStatus(\n address token,\n address spender\n )\n external\n view\n returns (\n uint256 currentAllowance,\n uint256 issuedAmount,\n uint256 expiryTime,\n bool hasExpired,\n uint256 timeUntilExpiry\n )\n {\n currentAllowance = IERC20(token).allowance(address(this), spender);\n issuedAmount = swapApprovals[token][spender];\n expiryTime = approvalTimestamps[token][spender];\n hasExpired = approvalExpired[token][spender];\n\n if (expiryTime > block.timestamp) {\n timeUntilExpiry = expiryTime - block.timestamp;\n } else {\n timeUntilExpiry = 0;\n }\n }\n\n /**\n * @notice Get oracle status\n */\n function getOracleStatus()\n external\n view\n returns (\n uint256 btcPriceUSD,\n uint256 ethPriceUSD,\n bool primaryBtcOracleHealthy,\n bool primaryEthOracleHealthy,\n bool inFailureMode\n )\n {\n try this.getBTCPrice() returns (uint256 btcPrice) {\n btcPriceUSD = btcPrice;\n primaryBtcOracleHealthy = true;\n } catch {\n btcPriceUSD = 0;\n primaryBtcOracleHealthy = false;\n }\n try this._getChainlinkPrice(address(ETH_USD_ORACLE)) returns (\n uint256 ethPrice\n ) {\n ethPriceUSD = ethPrice;\n primaryEthOracleHealthy = true;\n } catch {\n ethPriceUSD = 0;\n primaryEthOracleHealthy = false;\n }\n inFailureMode = oracleFailureMode;\n }\n\n /**\n * @notice Estimate profitability of rebalance\n */\n function estimateRebalanceProfitability()\n external\n returns (\n bool isProfitable,\n uint256 estimatedGasCost,\n uint256 minImbalanceRequired,\n uint256 currentImbalance\n )\n {\n estimatedGasCost = _calculateDynamicGasCostInBTC();\n\n minImbalanceRequired = estimatedGasCost + minArbitrageProfit;\n\n (uint256 wbtcAlloc, uint256 cbbtcAlloc) = _getCurrentAllocations();\n // 50/50 target for 2-asset index\n uint256 targetAlloc = BASIS_POINTS / 2;\n\n uint256 wbtcDev = wbtcAlloc > targetAlloc\n ? wbtcAlloc - targetAlloc\n : targetAlloc - wbtcAlloc;\n uint256 cbbtcDev = cbbtcAlloc > targetAlloc\n ? cbbtcAlloc - targetAlloc\n : targetAlloc - cbbtcAlloc;\n\n currentImbalance = wbtcDev + cbbtcDev;\n\n isProfitable = currentImbalance >= minImbalanceRequired;\n }\n\n // ========================================================================\n // ADVANCED MONITORING\n // ========================================================================\n\n /**\n * @notice Get swap execution statistics\n */\n function getSwapStatistics()\n external\n view\n returns (\n uint256 totalExecuted,\n uint256 totalFailed,\n uint256 successRate,\n uint256 lastSwapTimestamp,\n uint256 dailyVolumeUsed,\n uint256 dailyVolumeLimit\n )\n {\n totalExecuted = totalSwapsExecuted;\n totalFailed = totalSwapsFailed;\n\n if (totalExecuted + totalFailed > 0) {\n successRate =\n (totalExecuted * BASIS_POINTS) /\n (totalExecuted + totalFailed);\n }\n\n lastSwapTimestamp = lastSwapTime;\n dailyVolumeUsed = dailySwapVolumeUsed;\n dailyVolumeLimit = dailySwapLimitBTC;\n }\n\n /**\n * @notice Get rebalance execution statistics\n */\n function getRebalanceStatistics()\n external\n view\n returns (\n uint256 totalExecuted,\n uint256 totalFailed,\n uint256 successRate,\n uint256 lastRebalanceTimestamp,\n uint256 minIntervalRequired,\n uint256 timeSinceLastRebalance\n )\n {\n totalExecuted = totalRebalancesExecuted;\n totalFailed = totalRebalancesFailed;\n\n if (totalExecuted + totalFailed > 0) {\n successRate =\n (totalExecuted * BASIS_POINTS) /\n (totalExecuted + totalFailed);\n }\n\n lastRebalanceTimestamp = lastRebalanceTime;\n minIntervalRequired = minRebalanceInterval;\n timeSinceLastRebalance = lastRebalanceTime > 0\n ? block.timestamp - lastRebalanceTime\n : 0;\n }\n\n /**\n * @notice Get emergency withdrawal statistics\n */\n function getEmergencyWithdrawalStatus()\n external\n view\n returns (\n uint256 totalEmergencyWithdrawals,\n uint256 lastEmergencyWithdrawalTime,\n bool isCurrentlyActive,\n uint256 timeSinceLastEmergency\n )\n {\n totalEmergencyWithdrawals = emergencyWithdrawCount;\n lastEmergencyWithdrawalTime = lastEmergencyWithdraw;\n isCurrentlyActive = emergencyWithdrawActive;\n timeSinceLastEmergency = lastEmergencyWithdraw > 0\n ? block.timestamp - lastEmergencyWithdraw\n : 0;\n }\n\n /**\n * @notice Get comprehensive system diagnostics\n */\n function getSystemDiagnostics()\n external\n view\n returns (\n bool systemHealthy,\n bool oraclesOperational,\n bool routersOperational,\n bool approvalsValid,\n bool positionSizeValid,\n string memory overallStatus\n )\n {\n // Check oracles\n bool oraclesOp = true;\n try this.getBTCPrice() returns (uint256) {\n oraclesOp = true;\n } catch {\n oraclesOp = false;\n }\n // Check position size\n uint256 totalHoldings = _calculateTotalHoldings();\n bool positionOk = totalHoldings >= minPositionSize &&\n totalHoldings <= maxPositionSize;\n\n // Check if paused\n bool approvalsOk = !emergencyWithdrawActive;\n\n // Check routers\n bool routersOp = true;\n try this._checkRouterHealth() returns (bool healthy) {\n routersOp = healthy;\n } catch {\n routersOp = false;\n }\n systemHealthy = oraclesOp && routersOp && positionOk && approvalsOk;\n\n // Determine overall status\n string memory status;\n if (circuitBreakerTriggered) {\n status = \"CIRCUIT_BREAKER_ACTIVE\";\n } else if (rebalancingPaused) {\n status = \"PAUSED\";\n } else if (systemHealthy) {\n status = \"HEALTHY\";\n } else if (oracleFailureMode) {\n status = \"DEGRADED_MODE\";\n } else {\n status = \"UNHEALTHY\";\n }\n\n return (\n systemHealthy,\n oraclesOp,\n routersOp,\n approvalsOk,\n positionOk,\n status\n );\n }\n\n /**\n * @notice Calculate estimated daily profit\n */\n function estimateDailyProfit()\n external\n view\n returns (\n uint256 estimatedProfitBTC,\n uint256 estimatedProfitUSD,\n uint256 annualizedAPY,\n uint256 dataPoints\n )\n {\n uint256 totalHoldings = _calculateTotalHoldings();\n\n if (totalHoldings == 0) {\n return (0, 0, 0, 0);\n }\n\n // Base estimate on min profit per rebalance\n // Assume rebalance happens every 1 hour = 24 rebalances/day\n uint256 estimatedRebalancesPerDay = 24;\n estimatedProfitBTC = minArbitrageProfit * estimatedRebalancesPerDay;\n\n // Convert to USD using actual oracle price\n uint256 btcPriceUSD = getBTCPrice();\n estimatedProfitUSD = (estimatedProfitBTC * btcPriceUSD) / 1e8;\n\n // Calculate APY\n uint256 annualProfit = estimatedProfitBTC * 365;\n annualizedAPY = (annualProfit * BASIS_POINTS) / totalHoldings;\n\n dataPoints = totalRebalancesExecuted + totalSwapsExecuted;\n }\n\n /**\n * @notice Get next expected rebalance time\n */\n function getNextRebalanceTime()\n external\n view\n returns (\n uint256 nextRebalanceTime,\n uint256 secondsUntilNextRebalance,\n bool rebalanceReady,\n string memory reason\n )\n {\n nextRebalanceTime = lastRebalanceTime + minRebalanceInterval;\n\n if (block.timestamp >= nextRebalanceTime) {\n secondsUntilNextRebalance = 0;\n } else {\n secondsUntilNextRebalance = nextRebalanceTime - block.timestamp;\n }\n\n if (rebalancingPaused) {\n rebalanceReady = false;\n reason = \"PAUSED\";\n } else if (circuitBreakerTriggered) {\n rebalanceReady = false;\n reason = \"CIRCUIT_BREAKER_ACTIVE\";\n } else if (secondsUntilNextRebalance > 0) {\n rebalanceReady = false;\n reason = \"RATE_LIMIT_ACTIVE\";\n } else if (!_shouldRebalance()) {\n rebalanceReady = false;\n reason = \"ALLOCATION_IN_TOLERANCE\";\n } else {\n rebalanceReady = true;\n reason = \"READY\";\n }\n }\n\n // ========================================================================\n // CLOSING BRACE\n // ========================================================================\n}\n\n// \"For what shall it profit a man, if he shall gain the whole world, and lose his own soul?\" - Mark 8:36 (KJV)\n\n// “No one can serve two masters. For you will hate one and love the other; you will be devoted to one and despise the other. You cannot serve God and be enslaved to money.\" - Matthew 6:24 (NLT)\n\n// “For God so loved the world, that He gave his only Son, that whoever believes in Him should not perish but have eternal life.” - John 3:16 (ESV)\n\n// \"if you acknowledge and confess with your mouth that Jesus is Lord [recognizing His power, authority, and majesty as God], and believe in your heart that God raised Him from the dead, you will be saved.\" - Romans 10:9 (AMP)\n\n// Repent, for the Kingdom of Heaven is at hand.\n\n// Jesus loves you, and so does Jubilee Labs. Grace and peace.\n\n// P.S. Seek first the Kingdom of God! Matthew 6:33\n"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 1
},
"evmVersion": "cancun",
"viaIR": true,
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata"
],
"": [
"ast"
]
}
},
"libraries": {
"": {
"__CACHE_BREAKER__": "0x0000000000000031373637383035333131323039"
}
}
}
}