Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00Multichain Info
N/A
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
4976860 | 96 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
BoringSolver
Compiler Version
v0.8.21+commit.d9974bed
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.21; import {Auth, Authority} from "@solmate/auth/Auth.sol"; import { BoringOnChainQueue, ERC20, SafeTransferLib } from "../../../../src/base/Roles/BoringQueue/BoringOnChainQueue.sol"; import {IBoringSolver} from "../../../../src/base/Roles/BoringQueue/IBoringSolver.sol"; import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol"; import {TellerWithMultiAssetSupport} from "../../../../src/base/Roles/TellerWithMultiAssetSupport.sol"; import {Multicall} from "@openzeppelin/contracts/utils/Multicall.sol"; contract BoringSolver is IBoringSolver, Auth, Multicall { using SafeTransferLib for ERC20; using FixedPointMathLib for uint256; // ========================================= ENUMS ========================================= enum SolveType { BORING_REDEEM, // Fill multiple user requests with a single transaction. BORING_REDEEM_MINT // Fill multiple user requests to redeem shares and mint new shares. } //============================== ERRORS =============================== error BoringSolver___WrongInitiator(); error BoringSolver___BoringVaultTellerMismatch(address boringVault, address teller); error BoringSolver___OnlySelf(); error BoringSolver___FailedToSolve(); error BoringSolver___OnlyQueue(); //============================== IMMUTABLES =============================== BoringOnChainQueue internal immutable queue; constructor(address _owner, address _auth, address _queue) Auth(_owner, Authority(_auth)) { queue = BoringOnChainQueue(_queue); } //============================== ADMIN FUNCTIONS =============================== /** * @notice Allows the owner to rescue tokens from the contract. * @dev This should not normally be used, but it is possible that when performing a MIGRATION_REDEEM, * the redemption of Cellar shares will return assets other than BoringVault shares. * If the amount of assets is significant, it is very likely the solve will revert, but it is * not guaranteed to revert, hence this function. */ function rescueTokens(ERC20 token, uint256 amount) external requiresAuth { if (amount == type(uint256).max) amount = token.balanceOf(address(this)); token.safeTransfer(msg.sender, amount); } //============================== ADMIN SOLVE FUNCTIONS =============================== /** * @notice Solve multiple user requests to redeem Boring Vault shares. */ function boringRedeemSolve(BoringOnChainQueue.OnChainWithdraw[] calldata requests, address teller) external requiresAuth { bytes memory solveData = abi.encode(SolveType.BORING_REDEEM, msg.sender, teller, true); queue.solveOnChainWithdraws(requests, solveData, address(this)); } /** * @notice Solve multiple user requests to redeem Boring Vault shares and mint new Boring Vault shares. * @dev In order for this to work, the fromAccountant must have the toBoringVaults rate provider setup. */ function boringRedeemMintSolve( BoringOnChainQueue.OnChainWithdraw[] calldata requests, address fromTeller, address toTeller, address intermediateAsset ) external requiresAuth { bytes memory solveData = abi.encode(SolveType.BORING_REDEEM_MINT, msg.sender, fromTeller, toTeller, intermediateAsset, true); queue.solveOnChainWithdraws(requests, solveData, address(this)); } //============================== USER SOLVE FUNCTIONS =============================== /** * @notice Allows a user to solve their own request to redeem Boring Vault shares. */ function boringRedeemSelfSolve(BoringOnChainQueue.OnChainWithdraw calldata request, address teller) external requiresAuth { if (request.user != msg.sender) revert BoringSolver___OnlySelf(); BoringOnChainQueue.OnChainWithdraw[] memory requests = new BoringOnChainQueue.OnChainWithdraw[](1); requests[0] = request; bytes memory solveData = abi.encode(SolveType.BORING_REDEEM, msg.sender, teller, false); queue.solveOnChainWithdraws(requests, solveData, address(this)); } /** * @notice Allows a user to solve their own request to redeem Boring Vault shares and mint new Boring Vault shares. * @dev In order for this to work, the fromAccountant must have the toBoringVaults rate provider setup. */ function boringRedeemMintSelfSolve( BoringOnChainQueue.OnChainWithdraw calldata request, address fromTeller, address toTeller, address intermediateAsset ) external requiresAuth { if (request.user != msg.sender) revert BoringSolver___OnlySelf(); BoringOnChainQueue.OnChainWithdraw[] memory requests = new BoringOnChainQueue.OnChainWithdraw[](1); requests[0] = request; bytes memory solveData = abi.encode(SolveType.BORING_REDEEM_MINT, msg.sender, fromTeller, toTeller, intermediateAsset, false); queue.solveOnChainWithdraws(requests, solveData, address(this)); } //============================== IBORINGSOLVER FUNCTIONS =============================== /** * @notice Implementation of the IBoringSolver interface. */ function boringSolve( address initiator, address boringVault, address solveAsset, uint256 totalShares, uint256 requiredAssets, bytes calldata solveData ) external requiresAuth { if (msg.sender != address(queue)) revert BoringSolver___OnlyQueue(); if (initiator != address(this)) revert BoringSolver___WrongInitiator(); SolveType solveType = abi.decode(solveData, (SolveType)); if (solveType == SolveType.BORING_REDEEM) { _boringRedeemSolve(solveData, boringVault, solveAsset, totalShares, requiredAssets); } else if (solveType == SolveType.BORING_REDEEM_MINT) { _boringRedeemMintSolve(solveData, boringVault, solveAsset, totalShares, requiredAssets); } else { // Added for future protection, if another enum is added, txs with that enum will revert, // if no changes are made here. revert BoringSolver___FailedToSolve(); } } //============================== INTERNAL SOLVE FUNCTIONS =============================== /** * @notice Internal helper function to solve multiple user requests to redeem Boring Vault shares. */ function _boringRedeemSolve( bytes calldata solveData, address boringVault, address solveAsset, uint256 totalShares, uint256 requiredAssets ) internal { (, address solverOrigin, TellerWithMultiAssetSupport teller, bool excessToSolver) = abi.decode(solveData, (SolveType, address, TellerWithMultiAssetSupport, bool)); if (boringVault != address(teller.vault())) { revert BoringSolver___BoringVaultTellerMismatch(boringVault, address(teller)); } ERC20 asset = ERC20(solveAsset); // Redeem the Boring Vault shares for Solve Asset. uint256 assetsOut = teller.bulkWithdraw(asset, totalShares, requiredAssets, address(this)); // Transfer excess assets to solver origin or Boring Vault. // Assets are sent to solver to cover gas fees. // But if users are self solving, then the excess assets go to the Boring Vault. if (excessToSolver) { asset.safeTransfer(solverOrigin, assetsOut - requiredAssets); } else { asset.safeTransfer(boringVault, assetsOut - requiredAssets); } // Approve Boring Queue to spend the required assets. asset.approve(address(queue), requiredAssets); } /** * @notice Internal helper function to solve multiple user requests to redeem Boring Vault shares and mint new Boring Vault shares. */ function _boringRedeemMintSolve( bytes calldata solveData, address fromBoringVault, address toBoringVault, uint256 totalShares, uint256 requiredShares ) internal { ( , address solverOrigin, TellerWithMultiAssetSupport fromTeller, TellerWithMultiAssetSupport toTeller, ERC20 intermediateAsset, bool excessToSolver ) = abi.decode( solveData, (SolveType, address, TellerWithMultiAssetSupport, TellerWithMultiAssetSupport, ERC20, bool) ); if (fromBoringVault != address(fromTeller.vault())) { revert BoringSolver___BoringVaultTellerMismatch(fromBoringVault, address(fromTeller)); } if (toBoringVault != address(toTeller.vault())) { revert BoringSolver___BoringVaultTellerMismatch(toBoringVault, address(toTeller)); } // Redeem the fromBoringVault shares for Intermediate Asset. uint256 excessAssets = fromTeller.bulkWithdraw(intermediateAsset, totalShares, 0, address(this)); { // Determine how many assets are needed to mint requiredAssets worth of toBoringVault shares. // Note mulDivUp is used to ensure we always mint enough assets to cover the requiredShares. uint256 assetsToMintRequiredShares = requiredShares.mulDivUp( toTeller.accountant().getRateInQuoteSafe(intermediateAsset), BoringOnChainQueue(queue).ONE_SHARE() ); // Remove assetsToMintRequiredShares from excessAssets. excessAssets = excessAssets - assetsToMintRequiredShares; // Approve toBoringVault to spend the Intermediate Asset. intermediateAsset.safeApprove(toBoringVault, assetsToMintRequiredShares); // Mint to BoringVault shares using Intermediate Asset. toTeller.bulkDeposit(intermediateAsset, assetsToMintRequiredShares, requiredShares, address(this)); } // Transfer excess assets to solver origin or Boring Vault. // Assets are sent to solver to cover gas fees. // But if users are self solving, then the excess assets go to the from Boring Vault. if (excessToSolver) { intermediateAsset.safeTransfer(solverOrigin, excessAssets); } else { intermediateAsset.safeTransfer(fromBoringVault, excessAssets); } // Approve Boring Queue to spend the required assets. ERC20(toBoringVault).approve(address(queue), requiredShares); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/utils/ERC1155Holder.sol) pragma solidity ^0.8.20; import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol"; import {IERC1155Receiver} from "../IERC1155Receiver.sol"; /** * @dev Simple implementation of `IERC1155Receiver` that will allow a contract to hold ERC-1155 tokens. * * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be * stuck. */ abstract contract ERC1155Holder is ERC165, IERC1155Receiver { /// @inheritdoc IERC165 function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); } function onERC1155Received( address, address, uint256, uint256, bytes memory ) public virtual override returns (bytes4) { return this.onERC1155Received.selector; } function onERC1155BatchReceived( address, address, uint256[] memory, uint256[] memory, bytes memory ) public virtual override returns (bytes4) { return this.onERC1155BatchReceived.selector; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.2.0) (utils/Address.sol) pragma solidity ^0.8.20; import {Errors} from "./Errors.sol"; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert Errors.InsufficientBalance(address(this).balance, amount); } (bool success, bytes memory returndata) = recipient.call{value: amount}(""); if (!success) { _revert(returndata); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {Errors.FailedCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert Errors.InsufficientBalance(address(this).balance, value); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case * of an unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {Errors.FailedCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly ("memory-safe") { revert(add(returndata, 0x20), mload(returndata)) } } else { revert Errors.FailedCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` */ abstract contract ERC165 is IERC165 { /// @inheritdoc IERC165 function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Gas optimized reentrancy protection for smart contracts. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ReentrancyGuard.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol) abstract contract ReentrancyGuard { uint256 private locked = 1; modifier nonReentrant() virtual { require(locked == 1, "REENTRANCY"); locked = 2; _; locked = 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/IERC1155Receiver.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Interface that must be implemented by smart contracts in order to receive * ERC-1155 token transfers. */ interface IERC1155Receiver is IERC165 { /** * @dev Handles the receipt of a single ERC-1155 token type. This function is * called at the end of a `safeTransferFrom` after the balance has been updated. * * NOTE: To accept the transfer, this must return * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` * (i.e. 0xf23a6e61, or its own function selector). * * @param operator The address which initiated the transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param id The ID of the token being transferred * @param value The amount of tokens being transferred * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed */ function onERC1155Received( address operator, address from, uint256 id, uint256 value, bytes calldata data ) external returns (bytes4); /** * @dev Handles the receipt of a multiple ERC-1155 token types. This function * is called at the end of a `safeBatchTransferFrom` after the balances have * been updated. * * NOTE: To accept the transfer(s), this must return * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` * (i.e. 0xbc197c81, or its own function selector). * * @param operator The address which initiated the batch transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param ids An array containing ids of each token being transferred (order and length must match values array) * @param values An array containing amounts of each token being transferred (order and length must match ids array) * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed */ function onERC1155BatchReceived( address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.21; interface BeforeTransferHook { function beforeTransfer(address from, address to, address operator) external view; }
// SPDX-License-Identifier: UNLICENSED // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma solidity ^0.8.0; interface IRateProvider { function getRate() external view returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol) pragma solidity ^0.8.20; /** * @dev Collection of common custom errors used in multiple contracts * * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library. * It is recommended to avoid relying on the error API for critical functionality. * * _Available since v5.1._ */ library Errors { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error InsufficientBalance(uint256 balance, uint256 needed); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedCall(); /** * @dev The deployment failed. */ error FailedDeployment(); /** * @dev A necessary precompile is missing. */ error MissingPrecompile(address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol) pragma solidity ^0.8.20; /** * @dev Helper library for emitting standardized panic codes. * * ```solidity * contract Example { * using Panic for uint256; * * // Use any of the declared internal constants * function foo() { Panic.GENERIC.panic(); } * * // Alternatively * function foo() { Panic.panic(Panic.GENERIC); } * } * ``` * * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil]. * * _Available since v5.1._ */ // slither-disable-next-line unused-state library Panic { /// @dev generic / unspecified error uint256 internal constant GENERIC = 0x00; /// @dev used by the assert() builtin uint256 internal constant ASSERT = 0x01; /// @dev arithmetic underflow or overflow uint256 internal constant UNDER_OVERFLOW = 0x11; /// @dev division or modulo by zero uint256 internal constant DIVISION_BY_ZERO = 0x12; /// @dev enum conversion error uint256 internal constant ENUM_CONVERSION_ERROR = 0x21; /// @dev invalid encoding in storage uint256 internal constant STORAGE_ENCODING_ERROR = 0x22; /// @dev empty array pop uint256 internal constant EMPTY_ARRAY_POP = 0x31; /// @dev array out of bounds access uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32; /// @dev resource error (too large allocation or too large array) uint256 internal constant RESOURCE_ERROR = 0x41; /// @dev calling invalid internal function uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51; /// @dev Reverts with a panic code. Recommended to use with /// the internal constants with predefined codes. function panic(uint256 code) internal pure { assembly ("memory-safe") { mstore(0x00, 0x4e487b71) mstore(0x20, code) revert(0x1c, 0x24) } } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. library SafeTransferLib { /*////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool success; /// @solidity memory-safe-assembly assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } require(success, "ETH_TRANSFER_FAILED"); } /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument. mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. success := call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data and token has code. if and(iszero(and(eq(mload(0), 1), gt(returndatasize(), 31))), success) { success := iszero(or(iszero(extcodesize(token)), returndatasize())) } } require(success, "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. success := call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data and token has code. if and(iszero(and(eq(mload(0), 1), gt(returndatasize(), 31))), success) { success := iszero(or(iszero(extcodesize(token)), returndatasize())) } } require(success, "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. success := call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data and token has code. if and(iszero(and(eq(mload(0), 1), gt(returndatasize(), 31))), success) { success := iszero(or(iszero(extcodesize(token)), returndatasize())) } } require(success, "APPROVE_FAILED"); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Provides a flexible and updatable auth pattern which is completely separate from application logic. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol) /// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol) abstract contract Auth { event OwnershipTransferred(address indexed user, address indexed newOwner); event AuthorityUpdated(address indexed user, Authority indexed newAuthority); address public owner; Authority public authority; constructor(address _owner, Authority _authority) { owner = _owner; authority = _authority; emit OwnershipTransferred(msg.sender, _owner); emit AuthorityUpdated(msg.sender, _authority); } modifier requiresAuth() virtual { require(isAuthorized(msg.sender, msg.sig), "UNAUTHORIZED"); _; } function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) { Authority auth = authority; // Memoizing authority saves us a warm SLOAD, around 100 gas. // Checking if the caller is the owner only after calling the authority saves gas in most cases, but be // aware that this makes protected functions uncallable even to the owner if the authority is out of order. return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) || user == owner; } function setAuthority(Authority newAuthority) public virtual { // We check if the caller is the owner first because we want to ensure they can // always swap out the authority even if it's reverting or using up a lot of gas. require(msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig)); authority = newAuthority; emit AuthorityUpdated(msg.sender, newAuthority); } function transferOwnership(address newOwner) public virtual requiresAuth { owner = newOwner; emit OwnershipTransferred(msg.sender, newOwner); } } /// @notice A generic interface for a contract which provides authorization data to an Auth instance. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol) /// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol) interface Authority { function canCall( address user, address target, bytes4 functionSig ) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "./ERC20.sol"; import {SafeTransferLib} from "../utils/SafeTransferLib.sol"; /// @notice Minimalist and modern Wrapped Ether implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/WETH.sol) /// @author Inspired by WETH9 (https://github.com/dapphub/ds-weth/blob/master/src/weth9.sol) contract WETH is ERC20("Wrapped Ether", "WETH", 18) { using SafeTransferLib for address; event Deposit(address indexed from, uint256 amount); event Withdrawal(address indexed to, uint256 amount); function deposit() public payable virtual { _mint(msg.sender, msg.value); emit Deposit(msg.sender, msg.value); } function withdraw(uint256 amount) public virtual { _burn(msg.sender, amount); emit Withdrawal(msg.sender, amount); msg.sender.safeTransferETH(amount); } receive() external payable virtual { deposit(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.3.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.20; import {Arrays} from "../Arrays.sol"; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * - Set can be cleared (all elements removed) in O(n). * * ```solidity * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position is the index of the value in the `values` array plus 1. // Position 0 is used to mean a value is not in the set. mapping(bytes32 value => uint256) _positions; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._positions[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We cache the value's position to prevent multiple reads from the same storage slot uint256 position = set._positions[value]; if (position != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 valueIndex = position - 1; uint256 lastIndex = set._values.length - 1; if (valueIndex != lastIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the lastValue to the index where the value to delete is set._values[valueIndex] = lastValue; // Update the tracked position of the lastValue (that was just moved) set._positions[lastValue] = position; } // Delete the slot where the moved value was stored set._values.pop(); // Delete the tracked position for the deleted slot delete set._positions[value]; return true; } else { return false; } } /** * @dev Removes all the values from a set. O(n). * * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block. */ function _clear(Set storage set) private { uint256 len = _length(set); for (uint256 i = 0; i < len; ++i) { delete set._positions[set._values[i]]; } Arrays.unsafeSetLength(set._values, 0); } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._positions[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Removes all the values from a set. O(n). * * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block. */ function clear(Bytes32Set storage set) internal { _clear(set._inner); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; assembly ("memory-safe") { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes all the values from a set. O(n). * * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block. */ function clear(AddressSet storage set) internal { _clear(set._inner); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; assembly ("memory-safe") { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Removes all the values from a set. O(n). * * WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the * function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block. */ function clear(UintSet storage set) internal { _clear(set._inner); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; assembly ("memory-safe") { result := store } return result; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.21; import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol"; import {IRateProvider} from "../../../src/interfaces/IRateProvider.sol"; import {ERC20} from "@solmate/tokens/ERC20.sol"; import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol"; import {BoringVault} from "../../../src/base/BoringVault.sol"; import {Auth, Authority} from "@solmate/auth/Auth.sol"; import {IPausable} from "../../../src/interfaces/IPausable.sol"; contract AccountantWithRateProviders is Auth, IRateProvider, IPausable { using FixedPointMathLib for uint256; using SafeTransferLib for ERC20; // ========================================= STRUCTS ========================================= /** * @param payoutAddress the address `claimFees` sends fees to * @param highwaterMark the highest value of the BoringVault's share price * @param feesOwedInBase total pending fees owed in terms of base * @param totalSharesLastUpdate total amount of shares the last exchange rate update * @param exchangeRate the current exchange rate in terms of base * @param allowedExchangeRateChangeUpper the max allowed change to exchange rate from an update * @param allowedExchangeRateChangeLower the min allowed change to exchange rate from an update * @param lastUpdateTimestamp the block timestamp of the last exchange rate update * @param isPaused whether or not this contract is paused * @param minimumUpdateDelayInSeconds the minimum amount of time that must pass between * exchange rate updates, such that the update won't trigger the contract to be paused * @param platformFee the platform fee * @param performanceFee the performance fee */ struct AccountantState { address payoutAddress; uint96 highwaterMark; uint128 feesOwedInBase; uint128 totalSharesLastUpdate; uint96 exchangeRate; uint16 allowedExchangeRateChangeUpper; uint16 allowedExchangeRateChangeLower; uint64 lastUpdateTimestamp; bool isPaused; uint24 minimumUpdateDelayInSeconds; uint16 platformFee; uint16 performanceFee; } /** * @param isPeggedToBase whether or not the asset is 1:1 with the base asset * @param rateProvider the rate provider for this asset if `isPeggedToBase` is false */ struct RateProviderData { bool isPeggedToBase; IRateProvider rateProvider; } // ========================================= STATE ========================================= /** * @notice Store the accountant state in 3 packed slots. */ AccountantState public accountantState; /** * @notice Maps ERC20s to their RateProviderData. */ mapping(ERC20 => RateProviderData) public rateProviderData; //============================== ERRORS =============================== error AccountantWithRateProviders__UpperBoundTooSmall(); error AccountantWithRateProviders__LowerBoundTooLarge(); error AccountantWithRateProviders__PlatformFeeTooLarge(); error AccountantWithRateProviders__PerformanceFeeTooLarge(); error AccountantWithRateProviders__Paused(); error AccountantWithRateProviders__ZeroFeesOwed(); error AccountantWithRateProviders__OnlyCallableByBoringVault(); error AccountantWithRateProviders__UpdateDelayTooLarge(); error AccountantWithRateProviders__ExchangeRateAboveHighwaterMark(); //============================== EVENTS =============================== event Paused(); event Unpaused(); event DelayInSecondsUpdated(uint24 oldDelay, uint24 newDelay); event UpperBoundUpdated(uint16 oldBound, uint16 newBound); event LowerBoundUpdated(uint16 oldBound, uint16 newBound); event PlatformFeeUpdated(uint16 oldFee, uint16 newFee); event PerformanceFeeUpdated(uint16 oldFee, uint16 newFee); event PayoutAddressUpdated(address oldPayout, address newPayout); event RateProviderUpdated(address asset, bool isPegged, address rateProvider); event ExchangeRateUpdated(uint96 oldRate, uint96 newRate, uint64 currentTime); event FeesClaimed(address indexed feeAsset, uint256 amount); event HighwaterMarkReset(); //============================== IMMUTABLES =============================== /** * @notice The base asset rates are provided in. */ ERC20 public immutable base; /** * @notice The decimals rates are provided in. */ uint8 public immutable decimals; /** * @notice The BoringVault this accountant is working with. * Used to determine share supply for fee calculation. */ BoringVault public immutable vault; /** * @notice One share of the BoringVault. */ uint256 internal immutable ONE_SHARE; constructor( address _owner, address _vault, address payoutAddress, uint96 startingExchangeRate, address _base, uint16 allowedExchangeRateChangeUpper, uint16 allowedExchangeRateChangeLower, uint24 minimumUpdateDelayInSeconds, uint16 platformFee, uint16 performanceFee ) Auth(_owner, Authority(address(0))) { base = ERC20(_base); decimals = ERC20(_base).decimals(); vault = BoringVault(payable(_vault)); ONE_SHARE = 10 ** vault.decimals(); accountantState = AccountantState({ payoutAddress: payoutAddress, highwaterMark: startingExchangeRate, feesOwedInBase: 0, totalSharesLastUpdate: uint128(vault.totalSupply()), exchangeRate: startingExchangeRate, allowedExchangeRateChangeUpper: allowedExchangeRateChangeUpper, allowedExchangeRateChangeLower: allowedExchangeRateChangeLower, lastUpdateTimestamp: uint64(block.timestamp), isPaused: false, minimumUpdateDelayInSeconds: minimumUpdateDelayInSeconds, platformFee: platformFee, performanceFee: performanceFee }); } // ========================================= ADMIN FUNCTIONS ========================================= /** * @notice Pause this contract, which prevents future calls to `updateExchangeRate`, and any safe rate * calls will revert. * @dev Callable by MULTISIG_ROLE. */ function pause() external requiresAuth { accountantState.isPaused = true; emit Paused(); } /** * @notice Unpause this contract, which allows future calls to `updateExchangeRate`, and any safe rate * calls will stop reverting. * @dev Callable by MULTISIG_ROLE. */ function unpause() external requiresAuth { accountantState.isPaused = false; emit Unpaused(); } /** * @notice Update the minimum time delay between `updateExchangeRate` calls. * @dev There are no input requirements, as it is possible the admin would want * the exchange rate updated as frequently as needed. * @dev Callable by OWNER_ROLE. */ function updateDelay(uint24 minimumUpdateDelayInSeconds) external requiresAuth { if (minimumUpdateDelayInSeconds > 14 days) revert AccountantWithRateProviders__UpdateDelayTooLarge(); uint24 oldDelay = accountantState.minimumUpdateDelayInSeconds; accountantState.minimumUpdateDelayInSeconds = minimumUpdateDelayInSeconds; emit DelayInSecondsUpdated(oldDelay, minimumUpdateDelayInSeconds); } /** * @notice Update the allowed upper bound change of exchange rate between `updateExchangeRateCalls`. * @dev Callable by OWNER_ROLE. */ function updateUpper(uint16 allowedExchangeRateChangeUpper) external requiresAuth { if (allowedExchangeRateChangeUpper < 1e4) revert AccountantWithRateProviders__UpperBoundTooSmall(); uint16 oldBound = accountantState.allowedExchangeRateChangeUpper; accountantState.allowedExchangeRateChangeUpper = allowedExchangeRateChangeUpper; emit UpperBoundUpdated(oldBound, allowedExchangeRateChangeUpper); } /** * @notice Update the allowed lower bound change of exchange rate between `updateExchangeRateCalls`. * @dev Callable by OWNER_ROLE. */ function updateLower(uint16 allowedExchangeRateChangeLower) external requiresAuth { if (allowedExchangeRateChangeLower > 1e4) revert AccountantWithRateProviders__LowerBoundTooLarge(); uint16 oldBound = accountantState.allowedExchangeRateChangeLower; accountantState.allowedExchangeRateChangeLower = allowedExchangeRateChangeLower; emit LowerBoundUpdated(oldBound, allowedExchangeRateChangeLower); } /** * @notice Update the platform fee to a new value. * @dev Callable by OWNER_ROLE. */ function updatePlatformFee(uint16 platformFee) external requiresAuth { if (platformFee > 0.2e4) revert AccountantWithRateProviders__PlatformFeeTooLarge(); uint16 oldFee = accountantState.platformFee; accountantState.platformFee = platformFee; emit PlatformFeeUpdated(oldFee, platformFee); } /** * @notice Update the performance fee to a new value. * @dev Callable by OWNER_ROLE. */ function updatePerformanceFee(uint16 performanceFee) external requiresAuth { if (performanceFee > 0.5e4) revert AccountantWithRateProviders__PerformanceFeeTooLarge(); uint16 oldFee = accountantState.performanceFee; accountantState.performanceFee = performanceFee; emit PerformanceFeeUpdated(oldFee, performanceFee); } /** * @notice Update the payout address fees are sent to. * @dev Callable by OWNER_ROLE. */ function updatePayoutAddress(address payoutAddress) external requiresAuth { address oldPayout = accountantState.payoutAddress; accountantState.payoutAddress = payoutAddress; emit PayoutAddressUpdated(oldPayout, payoutAddress); } /** * @notice Update the rate provider data for a specific `asset`. * @dev Rate providers must return rates in terms of `base` or * an asset pegged to base and they must use the same decimals * as `asset`. * @dev Callable by OWNER_ROLE. */ function setRateProviderData(ERC20 asset, bool isPeggedToBase, address rateProvider) external requiresAuth { rateProviderData[asset] = RateProviderData({isPeggedToBase: isPeggedToBase, rateProvider: IRateProvider(rateProvider)}); emit RateProviderUpdated(address(asset), isPeggedToBase, rateProvider); } /** * @notice Reset the highwater mark to the current exchange rate. * @dev Callable by OWNER_ROLE. */ function resetHighwaterMark() external virtual requiresAuth { AccountantState storage state = accountantState; if (state.exchangeRate > state.highwaterMark) { revert AccountantWithRateProviders__ExchangeRateAboveHighwaterMark(); } uint64 currentTime = uint64(block.timestamp); uint256 currentTotalShares = vault.totalSupply(); _calculateFeesOwed(state, state.exchangeRate, state.exchangeRate, currentTotalShares, currentTime); state.totalSharesLastUpdate = uint128(currentTotalShares); state.highwaterMark = accountantState.exchangeRate; state.lastUpdateTimestamp = currentTime; emit HighwaterMarkReset(); } // ========================================= UPDATE EXCHANGE RATE/FEES FUNCTIONS ========================================= /** * @notice Updates this contract exchangeRate. * @dev If new exchange rate is outside of accepted bounds, or if not enough time has passed, this * will pause the contract, and this function will NOT calculate fees owed. * @dev Callable by UPDATE_EXCHANGE_RATE_ROLE. */ function updateExchangeRate(uint96 newExchangeRate) external virtual requiresAuth { ( bool shouldPause, AccountantState storage state, uint64 currentTime, uint256 currentExchangeRate, uint256 currentTotalShares ) = _beforeUpdateExchangeRate(newExchangeRate); if (shouldPause) { // Instead of reverting, pause the contract. This way the exchange rate updater is able to update the exchange rate // to a better value, and pause it. state.isPaused = true; } else { _calculateFeesOwed(state, newExchangeRate, currentExchangeRate, currentTotalShares, currentTime); } newExchangeRate = _setExchangeRate(newExchangeRate, state); state.totalSharesLastUpdate = uint128(currentTotalShares); state.lastUpdateTimestamp = currentTime; emit ExchangeRateUpdated(uint96(currentExchangeRate), newExchangeRate, currentTime); } /** * @notice Claim pending fees. * @dev This function must be called by the BoringVault. * @dev This function will lose precision if the exchange rate * decimals is greater than the feeAsset's decimals. */ function claimFees(ERC20 feeAsset) external { if (msg.sender != address(vault)) revert AccountantWithRateProviders__OnlyCallableByBoringVault(); AccountantState storage state = accountantState; if (state.isPaused) revert AccountantWithRateProviders__Paused(); if (state.feesOwedInBase == 0) revert AccountantWithRateProviders__ZeroFeesOwed(); // Determine amount of fees owed in feeAsset. uint256 feesOwedInFeeAsset; RateProviderData memory data = rateProviderData[feeAsset]; if (address(feeAsset) == address(base)) { feesOwedInFeeAsset = state.feesOwedInBase; } else { uint8 feeAssetDecimals = ERC20(feeAsset).decimals(); uint256 feesOwedInBaseUsingFeeAssetDecimals = _changeDecimals(state.feesOwedInBase, decimals, feeAssetDecimals); if (data.isPeggedToBase) { feesOwedInFeeAsset = feesOwedInBaseUsingFeeAssetDecimals; } else { uint256 rate = data.rateProvider.getRate(); feesOwedInFeeAsset = feesOwedInBaseUsingFeeAssetDecimals.mulDivDown(10 ** feeAssetDecimals, rate); } } // Zero out fees owed. state.feesOwedInBase = 0; // Transfer fee asset to payout address. feeAsset.safeTransferFrom(msg.sender, state.payoutAddress, feesOwedInFeeAsset); emit FeesClaimed(address(feeAsset), feesOwedInFeeAsset); } // ========================================= VIEW FUNCTIONS ========================================= /** * @notice Get this BoringVault's current rate in the base. */ function getRate() public view returns (uint256 rate) { rate = accountantState.exchangeRate; } /** * @notice Get this BoringVault's current rate in the base. * @dev Revert if paused. */ function getRateSafe() external view returns (uint256 rate) { if (accountantState.isPaused) revert AccountantWithRateProviders__Paused(); rate = getRate(); } /** * @notice Get this BoringVault's current rate in the provided quote. * @dev `quote` must have its RateProviderData set, else this will revert. * @dev This function will lose precision if the exchange rate * decimals is greater than the quote's decimals. */ function getRateInQuote(ERC20 quote) public view returns (uint256 rateInQuote) { if (address(quote) == address(base)) { rateInQuote = accountantState.exchangeRate; } else { RateProviderData memory data = rateProviderData[quote]; uint8 quoteDecimals = ERC20(quote).decimals(); uint256 exchangeRateInQuoteDecimals = _changeDecimals(accountantState.exchangeRate, decimals, quoteDecimals); if (data.isPeggedToBase) { rateInQuote = exchangeRateInQuoteDecimals; } else { uint256 quoteRate = data.rateProvider.getRate(); uint256 oneQuote = 10 ** quoteDecimals; rateInQuote = oneQuote.mulDivDown(exchangeRateInQuoteDecimals, quoteRate); } } } /** * @notice Get this BoringVault's current rate in the provided quote. * @dev `quote` must have its RateProviderData set, else this will revert. * @dev Revert if paused. */ function getRateInQuoteSafe(ERC20 quote) external view returns (uint256 rateInQuote) { if (accountantState.isPaused) revert AccountantWithRateProviders__Paused(); rateInQuote = getRateInQuote(quote); } /** * @notice Preview the result of an update to the exchange rate. * @return updateWillPause Whether the update will pause the contract. * @return newFeesOwedInBase The new fees owed in base. * @return totalFeesOwedInBase The total fees owed in base. */ function previewUpdateExchangeRate(uint96 newExchangeRate) external view virtual returns (bool updateWillPause, uint256 newFeesOwedInBase, uint256 totalFeesOwedInBase) { ( bool shouldPause, AccountantState storage state, uint64 currentTime, uint256 currentExchangeRate, uint256 currentTotalShares ) = _beforeUpdateExchangeRate(newExchangeRate); updateWillPause = shouldPause; totalFeesOwedInBase = state.feesOwedInBase; if (!shouldPause) { (uint256 platformFeesOwedInBase, uint256 shareSupplyToUse) = _calculatePlatformFee( state.totalSharesLastUpdate, state.lastUpdateTimestamp, state.platformFee, newExchangeRate, currentExchangeRate, currentTotalShares, currentTime ); uint256 performanceFeesOwedInBase; if (newExchangeRate > state.highwaterMark) { (performanceFeesOwedInBase,) = _calculatePerformanceFee( newExchangeRate, shareSupplyToUse, state.highwaterMark, state.performanceFee ); } newFeesOwedInBase = platformFeesOwedInBase + performanceFeesOwedInBase; totalFeesOwedInBase += newFeesOwedInBase; } } // ========================================= INTERNAL HELPER FUNCTIONS ========================================= /** * @notice Used to change the decimals of precision used for an amount. */ function _changeDecimals(uint256 amount, uint8 fromDecimals, uint8 toDecimals) internal pure returns (uint256) { if (fromDecimals == toDecimals) { return amount; } else if (fromDecimals < toDecimals) { return amount * 10 ** (toDecimals - fromDecimals); } else { return amount / 10 ** (fromDecimals - toDecimals); } } /** * @notice Check if the new exchange rate is outside of the allowed bounds or if not enough time has passed. */ function _beforeUpdateExchangeRate(uint96 newExchangeRate) internal view returns ( bool shouldPause, AccountantState storage state, uint64 currentTime, uint256 currentExchangeRate, uint256 currentTotalShares ) { state = accountantState; if (state.isPaused) revert AccountantWithRateProviders__Paused(); currentTime = uint64(block.timestamp); currentExchangeRate = state.exchangeRate; currentTotalShares = vault.totalSupply(); shouldPause = currentTime < state.lastUpdateTimestamp + state.minimumUpdateDelayInSeconds || newExchangeRate > currentExchangeRate.mulDivDown(state.allowedExchangeRateChangeUpper, 1e4) || newExchangeRate < currentExchangeRate.mulDivDown(state.allowedExchangeRateChangeLower, 1e4); } /** * @notice Set the exchange rate. */ function _setExchangeRate(uint96 newExchangeRate, AccountantState storage state) internal virtual returns (uint96) { state.exchangeRate = newExchangeRate; return newExchangeRate; } /** * @notice Calculate platform fees. */ function _calculatePlatformFee( uint128 totalSharesLastUpdate, uint64 lastUpdateTimestamp, uint16 platformFee, uint96 newExchangeRate, uint256 currentExchangeRate, uint256 currentTotalShares, uint64 currentTime ) internal view returns (uint256 platformFeesOwedInBase, uint256 shareSupplyToUse) { shareSupplyToUse = currentTotalShares; // Use the minimum between current total supply and total supply for last update. if (totalSharesLastUpdate < shareSupplyToUse) { shareSupplyToUse = totalSharesLastUpdate; } // Determine platform fees owned. if (platformFee > 0) { uint256 timeDelta = currentTime - lastUpdateTimestamp; uint256 minimumAssets = newExchangeRate > currentExchangeRate ? shareSupplyToUse.mulDivDown(currentExchangeRate, ONE_SHARE) : shareSupplyToUse.mulDivDown(newExchangeRate, ONE_SHARE); uint256 platformFeesAnnual = minimumAssets.mulDivDown(platformFee, 1e4); platformFeesOwedInBase = platformFeesAnnual.mulDivDown(timeDelta, 365 days); } } /** * @notice Calculate performance fees. */ function _calculatePerformanceFee( uint96 newExchangeRate, uint256 shareSupplyToUse, uint96 datum, uint16 performanceFee ) internal view returns (uint256 performanceFeesOwedInBase, uint256 yieldEarned) { uint256 changeInExchangeRate = newExchangeRate - datum; yieldEarned = changeInExchangeRate.mulDivDown(shareSupplyToUse, ONE_SHARE); if (performanceFee > 0) { performanceFeesOwedInBase = yieldEarned.mulDivDown(performanceFee, 1e4); } } /** * @notice Calculate fees owed in base. * @dev This function will update the highwater mark if the new exchange rate is higher. */ function _calculateFeesOwed( AccountantState storage state, uint96 newExchangeRate, uint256 currentExchangeRate, uint256 currentTotalShares, uint64 currentTime ) internal virtual { // Only update fees if we are not paused. // Update fee accounting. (uint256 newFeesOwedInBase, uint256 shareSupplyToUse) = _calculatePlatformFee( state.totalSharesLastUpdate, state.lastUpdateTimestamp, state.platformFee, newExchangeRate, currentExchangeRate, currentTotalShares, currentTime ); // Account for performance fees. if (newExchangeRate > state.highwaterMark) { (uint256 performanceFeesOwedInBase,) = _calculatePerformanceFee(newExchangeRate, shareSupplyToUse, state.highwaterMark, state.performanceFee); // Add performance fees to fees owed. newFeesOwedInBase += performanceFeesOwedInBase; // Always update the highwater mark if the new exchange rate is higher. // This way if we are not iniitiall taking performance fees, we can start taking them // without back charging them on past performance. state.highwaterMark = newExchangeRate; } state.feesOwedInBase += uint128(newFeesOwedInBase); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.3.0) (utils/Multicall.sol) pragma solidity ^0.8.20; import {Address} from "./Address.sol"; import {Context} from "./Context.sol"; /** * @dev Provides a function to batch together multiple calls in a single external call. * * Consider any assumption about calldata validation performed by the sender may be violated if it's not especially * careful about sending transactions invoking {multicall}. For example, a relay address that filters function * selectors won't filter calls nested within a {multicall} operation. * * NOTE: Since 5.0.1 and 4.9.4, this contract identifies non-canonical contexts (i.e. `msg.sender` is not {Context-_msgSender}). * If a non-canonical context is identified, the following self `delegatecall` appends the last bytes of `msg.data` * to the subcall. This makes it safe to use with {ERC2771Context}. Contexts that don't affect the resolution of * {Context-_msgSender} are not propagated to subcalls. */ abstract contract Multicall is Context { /** * @dev Receives and executes a batch of function calls on this contract. * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) { bytes memory context = msg.sender == _msgSender() ? new bytes(0) : msg.data[msg.data.length - _contextSuffixLength():]; results = new bytes[](data.length); for (uint256 i = 0; i < data.length; i++) { results[i] = Address.functionDelegateCall(address(this), bytes.concat(data[i], context)); } return results; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.3.0) (utils/SlotDerivation.sol) // This file was procedurally generated from scripts/generate/templates/SlotDerivation.js. pragma solidity ^0.8.20; /** * @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots * corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by * the solidity language / compiler. * * See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity docs for mappings and dynamic arrays.]. * * Example usage: * ```solidity * contract Example { * // Add the library methods * using StorageSlot for bytes32; * using SlotDerivation for bytes32; * * // Declare a namespace * string private constant _NAMESPACE = "<namespace>"; // eg. OpenZeppelin.Slot * * function setValueInNamespace(uint256 key, address newValue) internal { * _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue; * } * * function getValueInNamespace(uint256 key) internal view returns (address) { * return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value; * } * } * ``` * * TIP: Consider using this library along with {StorageSlot}. * * NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking * upgrade safety will ignore the slots accessed through this library. * * _Available since v5.1._ */ library SlotDerivation { /** * @dev Derive an ERC-7201 slot from a string (namespace). */ function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) { assembly ("memory-safe") { mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1)) slot := and(keccak256(0x00, 0x20), not(0xff)) } } /** * @dev Add an offset to a slot to get the n-th element of a structure or an array. */ function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) { unchecked { return bytes32(uint256(slot) + pos); } } /** * @dev Derive the location of the first element in an array from the slot where the length is stored. */ function deriveArray(bytes32 slot) internal pure returns (bytes32 result) { assembly ("memory-safe") { mstore(0x00, slot) result := keccak256(0x00, 0x20) } } /** * @dev Derive the location of a mapping element from the key. */ function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) { assembly ("memory-safe") { mstore(0x00, and(key, shr(96, not(0)))) mstore(0x20, slot) result := keccak256(0x00, 0x40) } } /** * @dev Derive the location of a mapping element from the key. */ function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) { assembly ("memory-safe") { mstore(0x00, iszero(iszero(key))) mstore(0x20, slot) result := keccak256(0x00, 0x40) } } /** * @dev Derive the location of a mapping element from the key. */ function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) { assembly ("memory-safe") { mstore(0x00, key) mstore(0x20, slot) result := keccak256(0x00, 0x40) } } /** * @dev Derive the location of a mapping element from the key. */ function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) { assembly ("memory-safe") { mstore(0x00, key) mstore(0x20, slot) result := keccak256(0x00, 0x40) } } /** * @dev Derive the location of a mapping element from the key. */ function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) { assembly ("memory-safe") { mstore(0x00, key) mstore(0x20, slot) result := keccak256(0x00, 0x40) } } /** * @dev Derive the location of a mapping element from the key. */ function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) { assembly ("memory-safe") { let length := mload(key) let begin := add(key, 0x20) let end := add(begin, length) let cache := mload(end) mstore(end, slot) result := keccak256(begin, add(length, 0x20)) mstore(end, cache) } } /** * @dev Derive the location of a mapping element from the key. */ function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) { assembly ("memory-safe") { let length := mload(key) let begin := add(key, 0x20) let end := add(begin, length) let cache := mload(end) mstore(end, slot) result := keccak256(begin, add(length, 0x20)) mstore(end, cache) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.20; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC-1967 implementation slot: * ```solidity * contract ERC1967 { * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(newImplementation.code.length > 0); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * TIP: Consider using this library along with {SlotDerivation}. */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct Int256Slot { int256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Int256Slot` with member `value` located at `slot`. */ function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { assembly ("memory-safe") { r.slot := store.slot } } /** * @dev Returns a `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { assembly ("memory-safe") { r.slot := store.slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/utils/ERC721Holder.sol) pragma solidity ^0.8.20; import {IERC721Receiver} from "../IERC721Receiver.sol"; /** * @dev Implementation of the {IERC721Receiver} interface. * * Accepts all token transfers. * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or * {IERC721-setApprovalForAll}. */ abstract contract ERC721Holder is IERC721Receiver { /** * @dev See {IERC721Receiver-onERC721Received}. * * Always returns `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) { return this.onERC721Received.selector; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.21; interface IBoringSolver { function boringSolve( address initiator, address boringVault, address solveAsset, uint256 totalShares, uint256 requiredAssets, bytes calldata solveData ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Comparators.sol) pragma solidity ^0.8.20; /** * @dev Provides a set of functions to compare values. * * _Available since v5.1._ */ library Comparators { function lt(uint256 a, uint256 b) internal pure returns (bool) { return a < b; } function gt(uint256 a, uint256 b) internal pure returns (bool) { return a > b; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.21; interface IPausable { function pause() external; function unpause() external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.20; /** * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeCast { /** * @dev Value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); /** * @dev An int value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedIntToUint(int256 value); /** * @dev Value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); /** * @dev An uint value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedUintToInt(uint256 value); /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits */ function toUint248(uint256 value) internal pure returns (uint248) { if (value > type(uint248).max) { revert SafeCastOverflowedUintDowncast(248, value); } return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits */ function toUint240(uint256 value) internal pure returns (uint240) { if (value > type(uint240).max) { revert SafeCastOverflowedUintDowncast(240, value); } return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits */ function toUint232(uint256 value) internal pure returns (uint232) { if (value > type(uint232).max) { revert SafeCastOverflowedUintDowncast(232, value); } return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits */ function toUint224(uint256 value) internal pure returns (uint224) { if (value > type(uint224).max) { revert SafeCastOverflowedUintDowncast(224, value); } return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits */ function toUint216(uint256 value) internal pure returns (uint216) { if (value > type(uint216).max) { revert SafeCastOverflowedUintDowncast(216, value); } return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits */ function toUint208(uint256 value) internal pure returns (uint208) { if (value > type(uint208).max) { revert SafeCastOverflowedUintDowncast(208, value); } return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits */ function toUint200(uint256 value) internal pure returns (uint200) { if (value > type(uint200).max) { revert SafeCastOverflowedUintDowncast(200, value); } return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits */ function toUint192(uint256 value) internal pure returns (uint192) { if (value > type(uint192).max) { revert SafeCastOverflowedUintDowncast(192, value); } return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits */ function toUint184(uint256 value) internal pure returns (uint184) { if (value > type(uint184).max) { revert SafeCastOverflowedUintDowncast(184, value); } return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits */ function toUint176(uint256 value) internal pure returns (uint176) { if (value > type(uint176).max) { revert SafeCastOverflowedUintDowncast(176, value); } return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits */ function toUint168(uint256 value) internal pure returns (uint168) { if (value > type(uint168).max) { revert SafeCastOverflowedUintDowncast(168, value); } return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits */ function toUint160(uint256 value) internal pure returns (uint160) { if (value > type(uint160).max) { revert SafeCastOverflowedUintDowncast(160, value); } return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits */ function toUint152(uint256 value) internal pure returns (uint152) { if (value > type(uint152).max) { revert SafeCastOverflowedUintDowncast(152, value); } return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits */ function toUint144(uint256 value) internal pure returns (uint144) { if (value > type(uint144).max) { revert SafeCastOverflowedUintDowncast(144, value); } return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits */ function toUint136(uint256 value) internal pure returns (uint136) { if (value > type(uint136).max) { revert SafeCastOverflowedUintDowncast(136, value); } return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { if (value > type(uint128).max) { revert SafeCastOverflowedUintDowncast(128, value); } return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits */ function toUint120(uint256 value) internal pure returns (uint120) { if (value > type(uint120).max) { revert SafeCastOverflowedUintDowncast(120, value); } return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits */ function toUint112(uint256 value) internal pure returns (uint112) { if (value > type(uint112).max) { revert SafeCastOverflowedUintDowncast(112, value); } return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits */ function toUint104(uint256 value) internal pure returns (uint104) { if (value > type(uint104).max) { revert SafeCastOverflowedUintDowncast(104, value); } return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits */ function toUint96(uint256 value) internal pure returns (uint96) { if (value > type(uint96).max) { revert SafeCastOverflowedUintDowncast(96, value); } return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits */ function toUint88(uint256 value) internal pure returns (uint88) { if (value > type(uint88).max) { revert SafeCastOverflowedUintDowncast(88, value); } return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits */ function toUint80(uint256 value) internal pure returns (uint80) { if (value > type(uint80).max) { revert SafeCastOverflowedUintDowncast(80, value); } return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits */ function toUint72(uint256 value) internal pure returns (uint72) { if (value > type(uint72).max) { revert SafeCastOverflowedUintDowncast(72, value); } return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { if (value > type(uint64).max) { revert SafeCastOverflowedUintDowncast(64, value); } return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits */ function toUint56(uint256 value) internal pure returns (uint56) { if (value > type(uint56).max) { revert SafeCastOverflowedUintDowncast(56, value); } return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits */ function toUint48(uint256 value) internal pure returns (uint48) { if (value > type(uint48).max) { revert SafeCastOverflowedUintDowncast(48, value); } return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits */ function toUint40(uint256 value) internal pure returns (uint40) { if (value > type(uint40).max) { revert SafeCastOverflowedUintDowncast(40, value); } return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { if (value > type(uint32).max) { revert SafeCastOverflowedUintDowncast(32, value); } return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits */ function toUint24(uint256 value) internal pure returns (uint24) { if (value > type(uint24).max) { revert SafeCastOverflowedUintDowncast(24, value); } return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { if (value > type(uint16).max) { revert SafeCastOverflowedUintDowncast(16, value); } return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits */ function toUint8(uint256 value) internal pure returns (uint8) { if (value > type(uint8).max) { revert SafeCastOverflowedUintDowncast(8, value); } return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { if (value < 0) { revert SafeCastOverflowedIntToUint(value); } return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(248, value); } } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(240, value); } } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(232, value); } } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(224, value); } } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(216, value); } } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(208, value); } } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(200, value); } } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(192, value); } } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(184, value); } } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(176, value); } } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(168, value); } } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(160, value); } } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(152, value); } } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(144, value); } } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(136, value); } } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(128, value); } } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(120, value); } } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(112, value); } } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(104, value); } } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(96, value); } } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(88, value); } } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(80, value); } } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(72, value); } } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(64, value); } } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(56, value); } } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(48, value); } } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(40, value); } } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(32, value); } } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(24, value); } } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(16, value); } } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(8, value); } } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive if (value > uint256(type(int256).max)) { revert SafeCastOverflowedUintToInt(value); } return int256(value); } /** * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump. */ function toUint(bool b) internal pure returns (uint256 u) { assembly ("memory-safe") { u := iszero(iszero(b)) } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.21; import {ERC20} from "@solmate/tokens/ERC20.sol"; import {WETH} from "@solmate/tokens/WETH.sol"; import {BoringVault} from "../../../../src/base/BoringVault.sol"; import {AccountantWithRateProviders} from "../../../../src/base/Roles/AccountantWithRateProviders.sol"; import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol"; import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol"; import {BeforeTransferHook} from "../../../../src/interfaces/BeforeTransferHook.sol"; import {Auth, Authority} from "@solmate/auth/Auth.sol"; import {ReentrancyGuard} from "@solmate/utils/ReentrancyGuard.sol"; import {IPausable} from "../../../../src/interfaces/IPausable.sol"; import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import {IBoringSolver} from "../../../../src/base/Roles/BoringQueue/IBoringSolver.sol"; contract BoringOnChainQueue is Auth, ReentrancyGuard, IPausable { using EnumerableSet for EnumerableSet.Bytes32Set; using SafeTransferLib for BoringVault; using SafeTransferLib for ERC20; using FixedPointMathLib for uint256; // ========================================= STRUCTS ========================================= /** * @param allowWithdraws Whether or not withdraws are allowed for this asset. * @param secondsToMaturity The time in seconds it takes for the asset to mature. * @param minimumSecondsToDeadline The minimum time in seconds a withdraw request must be valid for before it is expired * @param minDiscount The minimum discount allowed for a withdraw request. * @param maxDiscount The maximum discount allowed for a withdraw request. * @param minimumShares The minimum amount of shares that can be withdrawn. */ struct WithdrawAsset { bool allowWithdraws; uint24 secondsToMaturity; uint24 minimumSecondsToDeadline; uint16 minDiscount; uint16 maxDiscount; uint96 minimumShares; } /** * @param nonce The nonce of the request, used to make it impossible for request Ids to be repeated. * @param user The user that made the request. * @param assetOut The asset that the user wants to withdraw. * @param amountOfShares The amount of shares the user wants to withdraw. * @param amountOfAssets The amount of assets the user will receive. * @param creationTime The time the request was made. * @param secondsToMaturity The time in seconds it takes for the asset to mature. * @param secondsToDeadline The time in seconds the request is valid for. */ struct OnChainWithdraw { uint96 nonce; // read from state, used to make it impossible for request Ids to be repeated. address user; // msg.sender address assetOut; // input sanitized uint128 amountOfShares; // input transfered in uint128 amountOfAssets; // derived from amountOfShares and price uint40 creationTime; // time withdraw was made uint24 secondsToMaturity; // in contract, from withdrawAsset? uint24 secondsToDeadline; // in contract, from withdrawAsset? To get the deadline you take the creationTime add seconds to maturity, add the secondsToDeadline } // ========================================= CONSTANTS ========================================= /** * @notice The maximum discount allowed for a withdraw asset. */ uint16 internal constant MAX_DISCOUNT = 0.3e4; /** * @notice The maximum time in seconds a withdraw asset can take to mature. */ uint24 internal constant MAXIMUM_SECONDS_TO_MATURITY = 30 days; /** * @notice Caps the minimum time in seconds a withdraw request must be valid for before it is expired. */ uint24 internal constant MAXIMUM_MINIMUM_SECONDS_TO_DEADLINE = 30 days; // ========================================= MODIFIERS ========================================= /** * @notice Ensure that the request user is the same as the message sender. */ modifier onlyRequestUser(address requestUser, address msgSender) { if (requestUser != msgSender) revert BoringOnChainQueue__BadUser(); _; } // ========================================= GLOBAL STATE ========================================= /** * @notice Open Zeppelin EnumerableSet to store all withdraw requests, by there request Id. */ EnumerableSet.Bytes32Set private _withdrawRequests; /** * @notice Mapping of asset addresses to WithdrawAssets. */ mapping(address => WithdrawAsset) public withdrawAssets; /** * @notice The nonce of the next request. * @dev The purpose of this nonce is to prevent request Ids from being repeated. * @dev Start at 1, since 0 is considered invalid. * @dev When incrementing the nonce, an unchecked block is used to save gas. * This is safe because you can not feasibly make a request, and then cause an overflow * in the same block such that you can make 2 requests with the same request Id. * And even if you did, the tx would revert with a keccak256 collision error. */ uint96 public nonce = 1; /** * @notice Whether or not the contract is paused. */ bool public isPaused; //============================== ERRORS =============================== error BoringOnChainQueue__Paused(); error BoringOnChainQueue__WithdrawsNotAllowedForAsset(); error BoringOnChainQueue__BadDiscount(); error BoringOnChainQueue__BadShareAmount(); error BoringOnChainQueue__BadDeadline(); error BoringOnChainQueue__BadUser(); error BoringOnChainQueue__DeadlinePassed(); error BoringOnChainQueue__NotMatured(); error BoringOnChainQueue__Keccak256Collision(); error BoringOnChainQueue__RequestNotFound(); error BoringOnChainQueue__PermitFailedAndAllowanceTooLow(); error BoringOnChainQueue__MAX_DISCOUNT(); error BoringOnChainQueue__MAXIMUM_MINIMUM_SECONDS_TO_DEADLINE(); error BoringOnChainQueue__SolveAssetMismatch(); error BoringOnChainQueue__Overflow(); error BoringOnChainQueue__MAXIMUM_SECONDS_TO_MATURITY(); error BoringOnChainQueue__BadInput(); error BoringOnChainQueue__RescueCannotTakeSharesFromActiveRequests(); //============================== EVENTS =============================== event OnChainWithdrawRequested( bytes32 indexed requestId, address indexed user, address indexed assetOut, uint96 nonce, uint128 amountOfShares, uint128 amountOfAssets, uint40 creationTime, uint24 secondsToMaturity, uint24 secondsToDeadline ); event OnChainWithdrawCancelled(bytes32 indexed requestId, address indexed user, uint256 timestamp); event OnChainWithdrawSolved(bytes32 indexed requestId, address indexed user, uint256 timestamp); event WithdrawAssetSetup( address indexed assetOut, uint24 secondsToMaturity, uint24 minimumSecondsToDeadline, uint16 minDiscount, uint16 maxDiscount, uint96 minimumShares ); event WithdrawAssetStopped(address indexed assetOut); event WithdrawAssetUpdated( address indexed assetOut, uint24 minimumSecondsToDeadline, uint24 secondsToMaturity, uint16 minDiscount, uint16 maxDiscount, uint96 minimumShares ); event Paused(); event Unpaused(); //============================== IMMUTABLES =============================== /** * @notice The BoringVault contract to withdraw from. */ BoringVault public immutable boringVault; /** * @notice The AccountantWithRateProviders contract to get rates from. */ AccountantWithRateProviders public immutable accountant; /** * @notice One BoringVault share. */ uint256 public immutable ONE_SHARE; constructor(address _owner, address _auth, address payable _boringVault, address _accountant) Auth(_owner, Authority(_auth)) { boringVault = BoringVault(_boringVault); ONE_SHARE = 10 ** boringVault.decimals(); accountant = AccountantWithRateProviders(_accountant); } //=============================== ADMIN FUNCTIONS ================================ /** * @notice Allows the owner to rescue tokens from the contract. * @dev The owner can only withdraw BoringVault shares if they are accidentally sent to this contract. * Shares from active withdraw requests are not withdrawable. * @param token The token to rescue. * @param amount The amount to rescue. * @param to The address to send the rescued tokens to. * @param activeRequests The active withdraw requests, query `getWithdrawRequests`, or read events to get them. * @dev Provided activeRequests must match the order of active requests in the queue. */ function rescueTokens(ERC20 token, uint256 amount, address to, OnChainWithdraw[] calldata activeRequests) external requiresAuth { if (address(token) == address(boringVault)) { bytes32[] memory requestIds = _withdrawRequests.values(); uint256 requestIdsLength = requestIds.length; if (activeRequests.length != requestIdsLength) revert BoringOnChainQueue__BadInput(); // Iterate through provided activeRequests, and hash each one to compare to the requestIds. // Also track the sum of shares to make sure it is less than or equal to the amount. uint256 activeRequestShareSum; for (uint256 i = 0; i < requestIdsLength; ++i) { if (keccak256(abi.encode(activeRequests[i])) != requestIds[i]) revert BoringOnChainQueue__BadInput(); activeRequestShareSum += activeRequests[i].amountOfShares; } uint256 freeShares = boringVault.balanceOf(address(this)) - activeRequestShareSum; if (amount == type(uint256).max) amount = freeShares; else if (amount > freeShares) revert BoringOnChainQueue__RescueCannotTakeSharesFromActiveRequests(); } else { if (amount == type(uint256).max) amount = token.balanceOf(address(this)); } token.safeTransfer(to, amount); } /** * @notice Pause this contract, which prevents future calls to any functions that * create new requests, or solve active requests. * @dev Callable by MULTISIG_ROLE. */ function pause() external requiresAuth { isPaused = true; emit Paused(); } /** * @notice Unpause this contract, which allows future calls to any functions that * create new requests, or solve active requests. * @dev Callable by MULTISIG_ROLE. */ function unpause() external requiresAuth { isPaused = false; emit Unpaused(); } /** * @notice Update a new withdraw asset or existing. * @dev Callable by MULTISIG_ROLE. * @param assetOut The asset to withdraw. * @param secondsToMaturity The time in seconds it takes for the withdraw to mature. * @param minimumSecondsToDeadline The minimum time in seconds a withdraw request must be valid for before it is expired. * @param minDiscount The minimum discount allowed for a withdraw request. * @param maxDiscount The maximum discount allowed for a withdraw request. * @param minimumShares The minimum amount of shares that can be withdrawn. */ function updateWithdrawAsset( address assetOut, uint24 secondsToMaturity, uint24 minimumSecondsToDeadline, uint16 minDiscount, uint16 maxDiscount, uint96 minimumShares ) external requiresAuth { // Validate input. if (maxDiscount > MAX_DISCOUNT) revert BoringOnChainQueue__MAX_DISCOUNT(); if (secondsToMaturity > MAXIMUM_SECONDS_TO_MATURITY) { revert BoringOnChainQueue__MAXIMUM_SECONDS_TO_MATURITY(); } if (minimumSecondsToDeadline > MAXIMUM_MINIMUM_SECONDS_TO_DEADLINE) { revert BoringOnChainQueue__MAXIMUM_MINIMUM_SECONDS_TO_DEADLINE(); } if (minDiscount > maxDiscount) revert BoringOnChainQueue__BadDiscount(); // Make sure accountant can price it. accountant.getRateInQuoteSafe(ERC20(assetOut)); withdrawAssets[assetOut] = WithdrawAsset({ allowWithdraws: true, secondsToMaturity: secondsToMaturity, minimumSecondsToDeadline: minimumSecondsToDeadline, minDiscount: minDiscount, maxDiscount: maxDiscount, minimumShares: minimumShares }); emit WithdrawAssetUpdated( assetOut, secondsToMaturity, minimumSecondsToDeadline, minDiscount, maxDiscount, minimumShares ); } /** * @notice Stop withdraws in an asset. * @dev Callable by MULTISIG_ROLE. * @param assetOut The asset to stop withdraws in. */ function stopWithdrawsInAsset(address assetOut) external requiresAuth { withdrawAssets[assetOut].allowWithdraws = false; emit WithdrawAssetStopped(assetOut); } /** * @notice Cancel multiple user withdraws. * @dev Callable by STRATEGIST_MULTISIG_ROLE. */ function cancelUserWithdraws(OnChainWithdraw[] calldata requests) external requiresAuth returns (bytes32[] memory canceledRequestIds) { uint256 requestsLength = requests.length; canceledRequestIds = new bytes32[](requestsLength); for (uint256 i = 0; i < requestsLength; ++i) { canceledRequestIds[i] = _cancelOnChainWithdraw(requests[i]); } } //=============================== USER FUNCTIONS ================================ /** * @notice Request an on-chain withdraw. * @param assetOut The asset to withdraw. * @param amountOfShares The amount of shares to withdraw. * @param discount The discount to apply to the withdraw in bps. * @param secondsToDeadline The time in seconds the request is valid for. * @return requestId The request Id. */ function requestOnChainWithdraw(address assetOut, uint128 amountOfShares, uint16 discount, uint24 secondsToDeadline) external virtual requiresAuth returns (bytes32 requestId) { WithdrawAsset memory withdrawAsset = withdrawAssets[assetOut]; _beforeNewRequest(withdrawAsset, amountOfShares, discount, secondsToDeadline); boringVault.safeTransferFrom(msg.sender, address(this), amountOfShares); (requestId,) = _queueOnChainWithdraw( msg.sender, assetOut, amountOfShares, discount, withdrawAsset.secondsToMaturity, secondsToDeadline ); } /** * @notice Request an on-chain withdraw with permit. * @param assetOut The asset to withdraw. * @param amountOfShares The amount of shares to withdraw. * @param discount The discount to apply to the withdraw in bps. * @param secondsToDeadline The time in seconds the request is valid for. * @param permitDeadline The deadline for the permit. * @param v The v value of the permit signature. * @param r The r value of the permit signature. * @param s The s value of the permit signature. * @return requestId The request Id. */ function requestOnChainWithdrawWithPermit( address assetOut, uint128 amountOfShares, uint16 discount, uint24 secondsToDeadline, uint256 permitDeadline, uint8 v, bytes32 r, bytes32 s ) external virtual requiresAuth returns (bytes32 requestId) { WithdrawAsset memory withdrawAsset = withdrawAssets[assetOut]; _beforeNewRequest(withdrawAsset, amountOfShares, discount, secondsToDeadline); try boringVault.permit(msg.sender, address(this), amountOfShares, permitDeadline, v, r, s) {} catch { if (boringVault.allowance(msg.sender, address(this)) < amountOfShares) { revert BoringOnChainQueue__PermitFailedAndAllowanceTooLow(); } } boringVault.safeTransferFrom(msg.sender, address(this), amountOfShares); (requestId,) = _queueOnChainWithdraw( msg.sender, assetOut, amountOfShares, discount, withdrawAsset.secondsToMaturity, secondsToDeadline ); } /** * @notice Cancel an on-chain withdraw. * @param request The request to cancel. * @return requestId The request Id. */ function cancelOnChainWithdraw(OnChainWithdraw memory request) external virtual requiresAuth returns (bytes32 requestId) { requestId = _cancelOnChainWithdrawWithUserCheck(request); } /** * @notice Replace an on-chain withdraw. * @param oldRequest The request to replace. * @param discount The discount to apply to the new withdraw request in bps. * @param secondsToDeadline The time in seconds the new withdraw request is valid for. * @return oldRequestId The request Id of the old withdraw request. * @return newRequestId The request Id of the new withdraw request. */ function replaceOnChainWithdraw(OnChainWithdraw memory oldRequest, uint16 discount, uint24 secondsToDeadline) external virtual requiresAuth returns (bytes32 oldRequestId, bytes32 newRequestId) { (oldRequestId, newRequestId) = _replaceOnChainWithdrawWithUserCheck(oldRequest, discount, secondsToDeadline); } //============================== SOLVER FUNCTIONS =============================== /** * @notice Solve multiple on-chain withdraws. * @dev If `solveData` is empty, this contract will skip the callback function. * @param requests The requests to solve. * @param solveData The data to use to solve the requests. * @param solver The address of the solver. */ function solveOnChainWithdraws(OnChainWithdraw[] calldata requests, bytes calldata solveData, address solver) external requiresAuth { if (isPaused) revert BoringOnChainQueue__Paused(); ERC20 solveAsset = ERC20(requests[0].assetOut); uint256 requiredAssets; uint256 totalShares; uint256 requestsLength = requests.length; for (uint256 i = 0; i < requestsLength; ++i) { if (address(solveAsset) != requests[i].assetOut) revert BoringOnChainQueue__SolveAssetMismatch(); uint256 maturity = requests[i].creationTime + requests[i].secondsToMaturity; if (block.timestamp < maturity) revert BoringOnChainQueue__NotMatured(); uint256 deadline = maturity + requests[i].secondsToDeadline; if (block.timestamp > deadline) revert BoringOnChainQueue__DeadlinePassed(); requiredAssets += requests[i].amountOfAssets; totalShares += requests[i].amountOfShares; bytes32 requestId = _dequeueOnChainWithdraw(requests[i]); emit OnChainWithdrawSolved(requestId, requests[i].user, block.timestamp); } // Transfer shares to solver. boringVault.safeTransfer(solver, totalShares); // Run callback function if data is provided. if (solveData.length > 0) { IBoringSolver(solver).boringSolve( msg.sender, address(boringVault), address(solveAsset), totalShares, requiredAssets, solveData ); } for (uint256 i = 0; i < requestsLength; ++i) { solveAsset.safeTransferFrom(solver, requests[i].user, requests[i].amountOfAssets); } } //============================== VIEW FUNCTIONS =============================== /** * @notice Get all request Ids currently in the queue. * @dev Includes requests that are not mature, matured, and expired. But does not include requests that have been solved. * @return requestIds The request Ids. */ function getRequestIds() public view returns (bytes32[] memory) { return _withdrawRequests.values(); } /** * @notice Get the request Id for a request. * @param request The request. * @return requestId The request Id. */ function getRequestId(OnChainWithdraw calldata request) external pure returns (bytes32 requestId) { return keccak256(abi.encode(request)); } /** * @notice Preview assets out from a withdraw request. */ function previewAssetsOut(address assetOut, uint128 amountOfShares, uint16 discount) public view returns (uint128 amountOfAssets128) { uint256 price = accountant.getRateInQuoteSafe(ERC20(assetOut)); price = price.mulDivDown(1e4 - discount, 1e4); uint256 amountOfAssets = uint256(amountOfShares).mulDivDown(price, ONE_SHARE); if (amountOfAssets > type(uint128).max) revert BoringOnChainQueue__Overflow(); amountOfAssets128 = uint128(amountOfAssets); } //============================= INTERNAL FUNCTIONS ============================== /** * @notice Before a new request is made, validate the input. * @param withdrawAsset The withdraw asset. * @param amountOfShares The amount of shares to withdraw. * @param discount The discount to apply to the withdraw in bps. * @param secondsToDeadline The time in seconds the request is valid for. */ function _beforeNewRequest( WithdrawAsset memory withdrawAsset, uint128 amountOfShares, uint16 discount, uint24 secondsToDeadline ) internal view virtual { if (isPaused) revert BoringOnChainQueue__Paused(); if (!withdrawAsset.allowWithdraws) revert BoringOnChainQueue__WithdrawsNotAllowedForAsset(); if (discount < withdrawAsset.minDiscount || discount > withdrawAsset.maxDiscount) { revert BoringOnChainQueue__BadDiscount(); } if (amountOfShares < withdrawAsset.minimumShares) revert BoringOnChainQueue__BadShareAmount(); if (secondsToDeadline < withdrawAsset.minimumSecondsToDeadline) revert BoringOnChainQueue__BadDeadline(); } /** * @notice Cancel an on-chain withdraw. * @dev Verifies that the request user is the same as the msg.sender. * @param request The request to cancel. * @return requestId The request Id. */ function _cancelOnChainWithdrawWithUserCheck(OnChainWithdraw memory request) internal virtual onlyRequestUser(request.user, msg.sender) returns (bytes32 requestId) { requestId = _cancelOnChainWithdraw(request); } /** * @notice Cancel an on-chain withdraw. * @param request The request to cancel. * @return requestId The request Id. */ function _cancelOnChainWithdraw(OnChainWithdraw memory request) internal virtual returns (bytes32 requestId) { requestId = _dequeueOnChainWithdraw(request); boringVault.safeTransfer(request.user, request.amountOfShares); emit OnChainWithdrawCancelled(requestId, request.user, block.timestamp); } /** * @notice Replace an on-chain withdraw. * @dev Verifies that the request user is the same as the msg.sender. * @param oldRequest The request to replace. * @param discount The discount to apply to the new withdraw request in bps. * @param secondsToDeadline The time in seconds the new withdraw request is valid for. * @return oldRequestId The request Id of the old withdraw request. * @return newRequestId The request Id of the new withdraw request. */ function _replaceOnChainWithdrawWithUserCheck( OnChainWithdraw memory oldRequest, uint16 discount, uint24 secondsToDeadline ) internal virtual onlyRequestUser(oldRequest.user, msg.sender) returns (bytes32 oldRequestId, bytes32 newRequestId) { (oldRequestId, newRequestId) = _replaceOnChainWithdraw(oldRequest, discount, secondsToDeadline); } /** * @notice Replace an on-chain withdraw. * @param oldRequest The request to replace. * @param discount The discount to apply to the new withdraw request in bps. * @param secondsToDeadline The time in seconds the new withdraw request is valid for. * @return oldRequestId The request Id of the old withdraw request. * @return newRequestId The request Id of the new withdraw request. */ function _replaceOnChainWithdraw(OnChainWithdraw memory oldRequest, uint16 discount, uint24 secondsToDeadline) internal virtual onlyRequestUser(oldRequest.user, msg.sender) returns (bytes32 oldRequestId, bytes32 newRequestId) { WithdrawAsset memory withdrawAsset = withdrawAssets[oldRequest.assetOut]; _beforeNewRequest(withdrawAsset, oldRequest.amountOfShares, discount, secondsToDeadline); oldRequestId = _dequeueOnChainWithdraw(oldRequest); emit OnChainWithdrawCancelled(oldRequestId, oldRequest.user, block.timestamp); // Create new request. (newRequestId,) = _queueOnChainWithdraw( oldRequest.user, oldRequest.assetOut, oldRequest.amountOfShares, discount, withdrawAsset.secondsToMaturity, secondsToDeadline ); } /** * @notice Queue an on-chain withdraw. * @dev Reverts if the request is already in the queue. Though this should be impossible. * @param user The user that made the request. * @param assetOut The asset to withdraw. * @param amountOfShares The amount of shares to withdraw. * @param discount The discount to apply to the withdraw in bps. * @param secondsToMaturity The time in seconds it takes for the asset to mature. * @param secondsToDeadline The time in seconds the request is valid for. * @return requestId The request Id. */ function _queueOnChainWithdraw( address user, address assetOut, uint128 amountOfShares, uint16 discount, uint24 secondsToMaturity, uint24 secondsToDeadline ) internal virtual returns (bytes32 requestId, OnChainWithdraw memory req) { // Create new request. uint96 requestNonce; // See nonce definition for unchecked safety. unchecked { // Set request nonce as current nonce, then increment nonce. requestNonce = nonce++; } uint128 amountOfAssets128 = previewAssetsOut(assetOut, amountOfShares, discount); uint40 timeNow = uint40(block.timestamp); // Safe to cast to uint40 as it won't overflow for 10s of thousands of years req = OnChainWithdraw({ nonce: requestNonce, user: user, assetOut: assetOut, amountOfShares: amountOfShares, amountOfAssets: amountOfAssets128, creationTime: timeNow, secondsToMaturity: secondsToMaturity, secondsToDeadline: secondsToDeadline }); requestId = keccak256(abi.encode(req)); bool addedToSet = _withdrawRequests.add(requestId); if (!addedToSet) revert BoringOnChainQueue__Keccak256Collision(); emit OnChainWithdrawRequested( requestId, user, assetOut, requestNonce, amountOfShares, amountOfAssets128, timeNow, secondsToMaturity, secondsToDeadline ); } /** * @notice Dequeue an on-chain withdraw. * @dev Reverts if the request is not in the queue. * @dev Does not remove the request from the onChainWithdraws mapping, so that * it can be referenced later by off-chain systems if needed. * @param request The request to dequeue. * @return requestId The request Id. */ function _dequeueOnChainWithdraw(OnChainWithdraw memory request) internal virtual returns (bytes32 requestId) { // Remove request from queue. requestId = keccak256(abi.encode(request)); bool removedFromSet = _withdrawRequests.remove(requestId); if (!removedFromSet) revert BoringOnChainQueue__RequestNotFound(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol) pragma solidity ^0.8.20; import {Panic} from "../Panic.sol"; import {SafeCast} from "./SafeCast.sol"; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Return the 512-bit addition of two uint256. * * The result is stored in two 256 variables such that sum = high * 2²56 + low. */ function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) { assembly ("memory-safe") { low := add(a, b) high := lt(low, a) } } /** * @dev Return the 512-bit multiplication of two uint256. * * The result is stored in two 256 variables such that product = high * 2²56 + low. */ function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) { // 512-bit multiply [high low] = x * y. Compute the product mod 2²56 and mod 2²56 - 1, then use // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = high * 2²56 + low. assembly ("memory-safe") { let mm := mulmod(a, b, not(0)) low := mul(a, b) high := sub(sub(mm, low), lt(mm, low)) } } /** * @dev Returns the addition of two unsigned integers, with a success flag (no overflow). */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { uint256 c = a + b; success = c >= a; result = c * SafeCast.toUint(success); } } /** * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow). */ function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { uint256 c = a - b; success = c <= a; result = c * SafeCast.toUint(success); } } /** * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow). */ function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { uint256 c = a * b; assembly ("memory-safe") { // Only true when the multiplication doesn't overflow // (c / a == b) || (a == 0) success := or(eq(div(c, a), b), iszero(a)) } // equivalent to: success ? c : 0 result = c * SafeCast.toUint(success); } } /** * @dev Returns the division of two unsigned integers, with a success flag (no division by zero). */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { success = b > 0; assembly ("memory-safe") { // The `DIV` opcode returns zero when the denominator is 0. result := div(a, b) } } } /** * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero). */ function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { success = b > 0; assembly ("memory-safe") { // The `MOD` opcode returns zero when the denominator is 0. result := mod(a, b) } } } /** * @dev Unsigned saturating addition, bounds to `2²56 - 1` instead of overflowing. */ function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) { (bool success, uint256 result) = tryAdd(a, b); return ternary(success, result, type(uint256).max); } /** * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing. */ function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) { (, uint256 result) = trySub(a, b); return result; } /** * @dev Unsigned saturating multiplication, bounds to `2²56 - 1` instead of overflowing. */ function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) { (bool success, uint256 result) = tryMul(a, b); return ternary(success, result, type(uint256).max); } /** * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant. * * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone. * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute * one branch when needed, making this function more expensive. */ function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) { unchecked { // branchless ternary works because: // b ^ (a ^ b) == a // b ^ 0 == b return b ^ ((a ^ b) * SafeCast.toUint(condition)); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return ternary(a > b, a, b); } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return ternary(a < b, a, b); } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. Panic.panic(Panic.DIVISION_BY_ZERO); } // The following calculation ensures accurate ceiling division without overflow. // Since a is non-zero, (a - 1) / b will not overflow. // The largest possible result occurs when (a - 1) / b is type(uint256).max, // but the largest value we can obtain is type(uint256).max - 1, which happens // when a = type(uint256).max and b = 1. unchecked { return SafeCast.toUint(a > 0) * ((a - 1) / b + 1); } } /** * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { (uint256 high, uint256 low) = mul512(x, y); // Handle non-overflow cases, 256 by 256 division. if (high == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return low / denominator; } // Make sure the result is less than 2²56. Also prevents denominator == 0. if (denominator <= high) { Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW)); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [high low]. uint256 remainder; assembly ("memory-safe") { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. high := sub(high, gt(remainder, low)) low := sub(low, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly ("memory-safe") { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [high low] by twos. low := div(low, twos) // Flip twos such that it is 2²56 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from high into low. low |= high * twos; // Invert denominator mod 2²56. Now that denominator is an odd number, it has an inverse modulo 2²56 such // that denominator * inv = 1 mod 2²56. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 24. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 28 inverse *= 2 - denominator * inverse; // inverse mod 2¹6 inverse *= 2 - denominator * inverse; // inverse mod 2³² inverse *= 2 - denominator * inverse; // inverse mod 264 inverse *= 2 - denominator * inverse; // inverse mod 2¹²8 inverse *= 2 - denominator * inverse; // inverse mod 2²56 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2²56. Since the preconditions guarantee that the outcome is // less than 2²56, this is the final result. We don't need to compute the high bits of the result and high // is no longer required. result = low * inverse; return result; } } /** * @dev Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0); } /** * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256. */ function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) { unchecked { (uint256 high, uint256 low) = mul512(x, y); if (high >= 1 << n) { Panic.panic(Panic.UNDER_OVERFLOW); } return (high << (256 - n)) | (low >> n); } } /** * @dev Calculates x * y >> n with full precision, following the selected rounding direction. */ function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) { return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0); } /** * @dev Calculate the modular multiplicative inverse of a number in Z/nZ. * * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0. * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible. * * If the input value is not inversible, 0 is returned. * * 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 * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}. */ function invMod(uint256 a, uint256 n) internal pure returns (uint256) { unchecked { if (n == 0) return 0; // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version) // Used to compute integers x and y such that: ax + ny = gcd(a, n). // When the gcd is 1, then the inverse of a modulo n exists and it's x. // ax + ny = 1 // ax = 1 + (-y)n // ax = 1 (mod n) # x is the inverse of a modulo n // If the remainder is 0 the gcd is n right away. uint256 remainder = a % n; uint256 gcd = n; // Therefore the initial coefficients are: // ax + ny = gcd(a, n) = n // 0a + 1n = n int256 x = 0; int256 y = 1; while (remainder != 0) { uint256 quotient = gcd / remainder; (gcd, remainder) = ( // The old remainder is the next gcd to try. remainder, // Compute the next remainder. // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd // where gcd is at most n (capped to type(uint256).max) gcd - remainder * quotient ); (x, y) = ( // Increment the coefficient of a. y, // Decrement the coefficient of n. // Can overflow, but the result is casted to uint256 so that the // next value of y is "wrapped around" to a value between 0 and n - 1. x - y * int256(quotient) ); } if (gcd != 1) return 0; // No inverse exists. return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative. } } /** * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`. * * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is * prime, then `a**(p-1) = 1 mod p`. As a consequence, we have `a * a**(p-2) = 1 mod p`, which means that * `a**(p-2)` is the modular multiplicative inverse of a in Fp. * * NOTE: this function does NOT check that `p` is a prime greater than `2`. */ function invModPrime(uint256 a, uint256 p) internal view returns (uint256) { unchecked { return Math.modExp(a, p - 2, p); } } /** * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m) * * Requirements: * - modulus can't be zero * - underlying staticcall to precompile must succeed * * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make * sure the chain you're using it on supports the precompiled contract for modular exponentiation * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, * the underlying function will succeed given the lack of a revert, but the result may be incorrectly * interpreted as 0. */ function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) { (bool success, uint256 result) = tryModExp(b, e, m); if (!success) { Panic.panic(Panic.DIVISION_BY_ZERO); } return result; } /** * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m). * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying * to operate modulo 0 or if the underlying precompile reverted. * * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack * of a revert, but the result may be incorrectly interpreted as 0. */ function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) { if (m == 0) return (false, 0); assembly ("memory-safe") { let ptr := mload(0x40) // | Offset | Content | Content (Hex) | // |-----------|------------|--------------------------------------------------------------------| // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x60:0x7f | value of b | 0x<.............................................................b> | // | 0x80:0x9f | value of e | 0x<.............................................................e> | // | 0xa0:0xbf | value of m | 0x<.............................................................m> | mstore(ptr, 0x20) mstore(add(ptr, 0x20), 0x20) mstore(add(ptr, 0x40), 0x20) mstore(add(ptr, 0x60), b) mstore(add(ptr, 0x80), e) mstore(add(ptr, 0xa0), m) // Given the result < m, it's guaranteed to fit in 32 bytes, // so we can use the memory scratch space located at offset 0. success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20) result := mload(0x00) } } /** * @dev Variant of {modExp} that supports inputs of arbitrary length. */ function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) { (bool success, bytes memory result) = tryModExp(b, e, m); if (!success) { Panic.panic(Panic.DIVISION_BY_ZERO); } return result; } /** * @dev Variant of {tryModExp} that supports inputs of arbitrary length. */ function tryModExp( bytes memory b, bytes memory e, bytes memory m ) internal view returns (bool success, bytes memory result) { if (_zeroBytes(m)) return (false, new bytes(0)); uint256 mLen = m.length; // Encode call args in result and move the free memory pointer result = abi.encodePacked(b.length, e.length, mLen, b, e, m); assembly ("memory-safe") { let dataPtr := add(result, 0x20) // Write result on top of args to avoid allocating extra memory. success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen) // Overwrite the length. // result.length > returndatasize() is guaranteed because returndatasize() == m.length mstore(result, mLen) // Set the memory pointer after the returned data. mstore(0x40, add(dataPtr, mLen)) } } /** * @dev Returns whether the provided byte array is zero. */ function _zeroBytes(bytes memory byteArray) private pure returns (bool) { for (uint256 i = 0; i < byteArray.length; ++i) { if (byteArray[i] != 0) { return false; } } return true; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * This method is based on Newton's method for computing square roots; the algorithm is restricted to only * using integer operations. */ function sqrt(uint256 a) internal pure returns (uint256) { unchecked { // Take care of easy edge cases when a == 0 or a == 1 if (a <= 1) { return a; } // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between // the current value as `e_n = | x_n - sqrt(a) |`. // // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root // of the target. (i.e. `2**(e-1) = sqrt(a) < 2**e`). We know that `e = 128` because `(2¹²8)² = 2²56` is // bigger than any uint256. // // By noticing that // `2**(e-1) = sqrt(a) < 2**e ? (2**(e-1))² = a < (2**e)² ? 2**(2*e-2) = a < 2**(2*e)` // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar // to the msb function. uint256 aa = a; uint256 xn = 1; if (aa >= (1 << 128)) { aa >>= 128; xn <<= 64; } if (aa >= (1 << 64)) { aa >>= 64; xn <<= 32; } if (aa >= (1 << 32)) { aa >>= 32; xn <<= 16; } if (aa >= (1 << 16)) { aa >>= 16; xn <<= 8; } if (aa >= (1 << 8)) { aa >>= 8; xn <<= 4; } if (aa >= (1 << 4)) { aa >>= 4; xn <<= 2; } if (aa >= (1 << 2)) { xn <<= 1; } // We now have x_n such that `x_n = 2**(e-1) = sqrt(a) < 2**e = 2 * x_n`. This implies e_n = 2**(e-1). // // We can refine our estimation by noticing that the middle of that interval minimizes the error. // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to e_n = 2**(e-2). // This is going to be our x_0 (and e_0) xn = (3 * xn) >> 1; // e_0 := | x_0 - sqrt(a) | = 2**(e-2) // From here, Newton's method give us: // x_{n+1} = (x_n + a / x_n) / 2 // // One should note that: // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a // = ((x_n² + a) / (2 * x_n))² - a // = (x_n4 + 2 * a * x_n² + a²) / (4 * x_n²) - a // = (x_n4 + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²) // = (x_n4 - 2 * a * x_n² + a²) / (4 * x_n²) // = (x_n² - a)² / (2 * x_n)² // = ((x_n² - a) / (2 * x_n))² // = 0 // Which proves that for all n = 1, sqrt(a) = x_n // // This gives us the proof of quadratic convergence of the sequence: // e_{n+1} = | x_{n+1} - sqrt(a) | // = | (x_n + a / x_n) / 2 - sqrt(a) | // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) | // = | (x_n - sqrt(a))² / (2 * x_n) | // = | e_n² / (2 * x_n) | // = e_n² / | (2 * x_n) | // // For the first iteration, we have a special case where x_0 is known: // e_1 = e_0² / | (2 * x_0) | // = (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2))) // = 2**(2*e-4) / (3 * 2**(e-1)) // = 2**(e-3) / 3 // = 2**(e-3-log2(3)) // = 2**(e-4.5) // // For the following iterations, we use the fact that, 2**(e-1) = sqrt(a) = x_n: // e_{n+1} = e_n² / | (2 * x_n) | // = (2**(e-k))² / (2 * 2**(e-1)) // = 2**(2*e-2*k) / 2**e // = 2**(e-2*k) xn = (xn + a / xn) >> 1; // e_1 := | x_1 - sqrt(a) | = 2**(e-4.5) -- special case, see above xn = (xn + a / xn) >> 1; // e_2 := | x_2 - sqrt(a) | = 2**(e-9) -- general case with k = 4.5 xn = (xn + a / xn) >> 1; // e_3 := | x_3 - sqrt(a) | = 2**(e-18) -- general case with k = 9 xn = (xn + a / xn) >> 1; // e_4 := | x_4 - sqrt(a) | = 2**(e-36) -- general case with k = 18 xn = (xn + a / xn) >> 1; // e_5 := | x_5 - sqrt(a) | = 2**(e-72) -- general case with k = 36 xn = (xn + a / xn) >> 1; // e_6 := | x_6 - sqrt(a) | = 2**(e-144) -- general case with k = 72 // Because e = 128 (as discussed during the first estimation phase), we know have reached a precision // e_6 = 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either // sqrt(a) or sqrt(a) + 1. return xn - SafeCast.toUint(xn > a / xn); } } /** * @dev Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 x) internal pure returns (uint256 r) { // If value has upper 128 bits set, log2 result is at least 128 r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7; // If upper 64 bits of 128-bit half set, add 64 to result r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6; // If upper 32 bits of 64-bit half set, add 32 to result r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5; // If upper 16 bits of 32-bit half set, add 16 to result r |= SafeCast.toUint((x >> r) > 0xffff) << 4; // If upper 8 bits of 16-bit half set, add 8 to result r |= SafeCast.toUint((x >> r) > 0xff) << 3; // If upper 4 bits of 8-bit half set, add 4 to result r |= SafeCast.toUint((x >> r) > 0xf) << 2; // Shifts value right by the current result and use it as an index into this lookup table: // // | x (4 bits) | index | table[index] = MSB position | // |------------|---------|-----------------------------| // | 0000 | 0 | table[0] = 0 | // | 0001 | 1 | table[1] = 0 | // | 0010 | 2 | table[2] = 1 | // | 0011 | 3 | table[3] = 1 | // | 0100 | 4 | table[4] = 2 | // | 0101 | 5 | table[5] = 2 | // | 0110 | 6 | table[6] = 2 | // | 0111 | 7 | table[7] = 2 | // | 1000 | 8 | table[8] = 3 | // | 1001 | 9 | table[9] = 3 | // | 1010 | 10 | table[10] = 3 | // | 1011 | 11 | table[11] = 3 | // | 1100 | 12 | table[12] = 3 | // | 1101 | 13 | table[13] = 3 | // | 1110 | 14 | table[14] = 3 | // | 1111 | 15 | table[15] = 3 | // // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes. assembly ("memory-safe") { r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000)) } } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 x) internal pure returns (uint256 r) { // If value has upper 128 bits set, log2 result is at least 128 r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7; // If upper 64 bits of 128-bit half set, add 64 to result r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6; // If upper 32 bits of 64-bit half set, add 32 to result r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5; // If upper 16 bits of 32-bit half set, add 16 to result r |= SafeCast.toUint((x >> r) > 0xffff) << 4; // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8 return (r >> 3) | SafeCast.toUint((x >> r) > 0xff); } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.3.0) (utils/Arrays.sol) // This file was procedurally generated from scripts/generate/templates/Arrays.js. pragma solidity ^0.8.20; import {Comparators} from "./Comparators.sol"; import {SlotDerivation} from "./SlotDerivation.sol"; import {StorageSlot} from "./StorageSlot.sol"; import {Math} from "./math/Math.sol"; /** * @dev Collection of functions related to array types. */ library Arrays { using SlotDerivation for bytes32; using StorageSlot for bytes32; /** * @dev Sort an array of uint256 (in memory) following the provided comparator function. * * This function does the sorting "in place", meaning that it overrides the input. The object is returned for * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array. * * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may * consume more gas than is available in a block, leading to potential DoS. * * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way. */ function sort( uint256[] memory array, function(uint256, uint256) pure returns (bool) comp ) internal pure returns (uint256[] memory) { _quickSort(_begin(array), _end(array), comp); return array; } /** * @dev Variant of {sort} that sorts an array of uint256 in increasing order. */ function sort(uint256[] memory array) internal pure returns (uint256[] memory) { sort(array, Comparators.lt); return array; } /** * @dev Sort an array of address (in memory) following the provided comparator function. * * This function does the sorting "in place", meaning that it overrides the input. The object is returned for * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array. * * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may * consume more gas than is available in a block, leading to potential DoS. * * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way. */ function sort( address[] memory array, function(address, address) pure returns (bool) comp ) internal pure returns (address[] memory) { sort(_castToUint256Array(array), _castToUint256Comp(comp)); return array; } /** * @dev Variant of {sort} that sorts an array of address in increasing order. */ function sort(address[] memory array) internal pure returns (address[] memory) { sort(_castToUint256Array(array), Comparators.lt); return array; } /** * @dev Sort an array of bytes32 (in memory) following the provided comparator function. * * This function does the sorting "in place", meaning that it overrides the input. The object is returned for * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array. * * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may * consume more gas than is available in a block, leading to potential DoS. * * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe way. */ function sort( bytes32[] memory array, function(bytes32, bytes32) pure returns (bool) comp ) internal pure returns (bytes32[] memory) { sort(_castToUint256Array(array), _castToUint256Comp(comp)); return array; } /** * @dev Variant of {sort} that sorts an array of bytes32 in increasing order. */ function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) { sort(_castToUint256Array(array), Comparators.lt); return array; } /** * @dev Performs a quick sort of a segment of memory. The segment sorted starts at `begin` (inclusive), and stops * at end (exclusive). Sorting follows the `comp` comparator. * * Invariant: `begin <= end`. This is the case when initially called by {sort} and is preserved in subcalls. * * IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should * be used only if the limits are within a memory array. */ function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure { unchecked { if (end - begin < 0x40) return; // Use first element as pivot uint256 pivot = _mload(begin); // Position where the pivot should be at the end of the loop uint256 pos = begin; for (uint256 it = begin + 0x20; it < end; it += 0x20) { if (comp(_mload(it), pivot)) { // If the value stored at the iterator's position comes before the pivot, we increment the // position of the pivot and move the value there. pos += 0x20; _swap(pos, it); } } _swap(begin, pos); // Swap pivot into place _quickSort(begin, pos, comp); // Sort the left side of the pivot _quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot } } /** * @dev Pointer to the memory location of the first element of `array`. */ function _begin(uint256[] memory array) private pure returns (uint256 ptr) { assembly ("memory-safe") { ptr := add(array, 0x20) } } /** * @dev Pointer to the memory location of the first memory word (32bytes) after `array`. This is the memory word * that comes just after the last element of the array. */ function _end(uint256[] memory array) private pure returns (uint256 ptr) { unchecked { return _begin(array) + array.length * 0x20; } } /** * @dev Load memory word (as a uint256) at location `ptr`. */ function _mload(uint256 ptr) private pure returns (uint256 value) { assembly { value := mload(ptr) } } /** * @dev Swaps the elements memory location `ptr1` and `ptr2`. */ function _swap(uint256 ptr1, uint256 ptr2) private pure { assembly { let value1 := mload(ptr1) let value2 := mload(ptr2) mstore(ptr1, value2) mstore(ptr2, value1) } } /// @dev Helper: low level cast address memory array to uint256 memory array function _castToUint256Array(address[] memory input) private pure returns (uint256[] memory output) { assembly { output := input } } /// @dev Helper: low level cast bytes32 memory array to uint256 memory array function _castToUint256Array(bytes32[] memory input) private pure returns (uint256[] memory output) { assembly { output := input } } /// @dev Helper: low level cast address comp function to uint256 comp function function _castToUint256Comp( function(address, address) pure returns (bool) input ) private pure returns (function(uint256, uint256) pure returns (bool) output) { assembly { output := input } } /// @dev Helper: low level cast bytes32 comp function to uint256 comp function function _castToUint256Comp( function(bytes32, bytes32) pure returns (bool) input ) private pure returns (function(uint256, uint256) pure returns (bool) output) { assembly { output := input } } /** * @dev Searches a sorted `array` and returns the first index that contains * a value greater or equal to `element`. If no such index exists (i.e. all * values in the array are strictly less than `element`), the array length is * returned. Time complexity O(log n). * * NOTE: The `array` is expected to be sorted in ascending order, and to * contain no repeated elements. * * IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks * support for repeated elements in the array. The {lowerBound} function should * be used instead. */ function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) { uint256 low = 0; uint256 high = array.length; if (high == 0) { return 0; } while (low < high) { uint256 mid = Math.average(low, high); // Note that mid will always be strictly less than high (i.e. it will be a valid array index) // because Math.average rounds towards zero (it does integer division with truncation). if (unsafeAccess(array, mid).value > element) { high = mid; } else { low = mid + 1; } } // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound. if (low > 0 && unsafeAccess(array, low - 1).value == element) { return low - 1; } else { return low; } } /** * @dev Searches an `array` sorted in ascending order and returns the first * index that contains a value greater or equal than `element`. If no such index * exists (i.e. all values in the array are strictly less than `element`), the array * length is returned. Time complexity O(log n). * * See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound]. */ function lowerBound(uint256[] storage array, uint256 element) internal view returns (uint256) { uint256 low = 0; uint256 high = array.length; if (high == 0) { return 0; } while (low < high) { uint256 mid = Math.average(low, high); // Note that mid will always be strictly less than high (i.e. it will be a valid array index) // because Math.average rounds towards zero (it does integer division with truncation). if (unsafeAccess(array, mid).value < element) { // this cannot overflow because mid < high unchecked { low = mid + 1; } } else { high = mid; } } return low; } /** * @dev Searches an `array` sorted in ascending order and returns the first * index that contains a value strictly greater than `element`. If no such index * exists (i.e. all values in the array are strictly less than `element`), the array * length is returned. Time complexity O(log n). * * See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound]. */ function upperBound(uint256[] storage array, uint256 element) internal view returns (uint256) { uint256 low = 0; uint256 high = array.length; if (high == 0) { return 0; } while (low < high) { uint256 mid = Math.average(low, high); // Note that mid will always be strictly less than high (i.e. it will be a valid array index) // because Math.average rounds towards zero (it does integer division with truncation). if (unsafeAccess(array, mid).value > element) { high = mid; } else { // this cannot overflow because mid < high unchecked { low = mid + 1; } } } return low; } /** * @dev Same as {lowerBound}, but with an array in memory. */ function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) { uint256 low = 0; uint256 high = array.length; if (high == 0) { return 0; } while (low < high) { uint256 mid = Math.average(low, high); // Note that mid will always be strictly less than high (i.e. it will be a valid array index) // because Math.average rounds towards zero (it does integer division with truncation). if (unsafeMemoryAccess(array, mid) < element) { // this cannot overflow because mid < high unchecked { low = mid + 1; } } else { high = mid; } } return low; } /** * @dev Same as {upperBound}, but with an array in memory. */ function upperBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) { uint256 low = 0; uint256 high = array.length; if (high == 0) { return 0; } while (low < high) { uint256 mid = Math.average(low, high); // Note that mid will always be strictly less than high (i.e. it will be a valid array index) // because Math.average rounds towards zero (it does integer division with truncation). if (unsafeMemoryAccess(array, mid) > element) { high = mid; } else { // this cannot overflow because mid < high unchecked { low = mid + 1; } } } return low; } /** * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. * * WARNING: Only use if you are certain `pos` is lower than the array length. */ function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) { bytes32 slot; assembly ("memory-safe") { slot := arr.slot } return slot.deriveArray().offset(pos).getAddressSlot(); } /** * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. * * WARNING: Only use if you are certain `pos` is lower than the array length. */ function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) { bytes32 slot; assembly ("memory-safe") { slot := arr.slot } return slot.deriveArray().offset(pos).getBytes32Slot(); } /** * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. * * WARNING: Only use if you are certain `pos` is lower than the array length. */ function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) { bytes32 slot; assembly ("memory-safe") { slot := arr.slot } return slot.deriveArray().offset(pos).getUint256Slot(); } /** * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. * * WARNING: Only use if you are certain `pos` is lower than the array length. */ function unsafeAccess(bytes[] storage arr, uint256 pos) internal pure returns (StorageSlot.BytesSlot storage) { bytes32 slot; assembly ("memory-safe") { slot := arr.slot } return slot.deriveArray().offset(pos).getBytesSlot(); } /** * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. * * WARNING: Only use if you are certain `pos` is lower than the array length. */ function unsafeAccess(string[] storage arr, uint256 pos) internal pure returns (StorageSlot.StringSlot storage) { bytes32 slot; assembly ("memory-safe") { slot := arr.slot } return slot.deriveArray().offset(pos).getStringSlot(); } /** * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. * * WARNING: Only use if you are certain `pos` is lower than the array length. */ function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) { assembly { res := mload(add(add(arr, 0x20), mul(pos, 0x20))) } } /** * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. * * WARNING: Only use if you are certain `pos` is lower than the array length. */ function unsafeMemoryAccess(bytes32[] memory arr, uint256 pos) internal pure returns (bytes32 res) { assembly { res := mload(add(add(arr, 0x20), mul(pos, 0x20))) } } /** * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. * * WARNING: Only use if you are certain `pos` is lower than the array length. */ function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) { assembly { res := mload(add(add(arr, 0x20), mul(pos, 0x20))) } } /** * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. * * WARNING: Only use if you are certain `pos` is lower than the array length. */ function unsafeMemoryAccess(bytes[] memory arr, uint256 pos) internal pure returns (bytes memory res) { assembly { res := mload(add(add(arr, 0x20), mul(pos, 0x20))) } } /** * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. * * WARNING: Only use if you are certain `pos` is lower than the array length. */ function unsafeMemoryAccess(string[] memory arr, uint256 pos) internal pure returns (string memory res) { assembly { res := mload(add(add(arr, 0x20), mul(pos, 0x20))) } } /** * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden. * * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased. */ function unsafeSetLength(address[] storage array, uint256 len) internal { assembly ("memory-safe") { sstore(array.slot, len) } } /** * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden. * * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased. */ function unsafeSetLength(bytes32[] storage array, uint256 len) internal { assembly ("memory-safe") { sstore(array.slot, len) } } /** * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden. * * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased. */ function unsafeSetLength(uint256[] storage array, uint256 len) internal { assembly ("memory-safe") { sstore(array.slot, len) } } /** * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden. * * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased. */ function unsafeSetLength(bytes[] storage array, uint256 len) internal { assembly ("memory-safe") { sstore(array.slot, len) } } /** * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden. * * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased. */ function unsafeSetLength(string[] storage array, uint256 len) internal { assembly ("memory-safe") { sstore(array.slot, len) } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.21; import {ERC20} from "@solmate/tokens/ERC20.sol"; import {WETH} from "@solmate/tokens/WETH.sol"; import {BoringVault} from "../../../src/base/BoringVault.sol"; import {AccountantWithRateProviders} from "../../../src/base/Roles/AccountantWithRateProviders.sol"; import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol"; import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol"; import {BeforeTransferHook} from "../../../src/interfaces/BeforeTransferHook.sol"; import {Auth, Authority} from "@solmate/auth/Auth.sol"; import {ReentrancyGuard} from "@solmate/utils/ReentrancyGuard.sol"; import {IPausable} from "../../../src/interfaces/IPausable.sol"; contract TellerWithMultiAssetSupport is Auth, BeforeTransferHook, ReentrancyGuard, IPausable { using FixedPointMathLib for uint256; using SafeTransferLib for ERC20; using SafeTransferLib for WETH; // ========================================= STRUCTS ========================================= /** * @param allowDeposits bool indicating whether or not deposits are allowed for this asset. * @param allowWithdraws bool indicating whether or not withdraws are allowed for this asset. * @param sharePremium uint16 indicating the premium to apply to the shares minted. * where 40 represents a 40bps reduction in shares minted using this asset. */ struct Asset { bool allowDeposits; bool allowWithdraws; uint16 sharePremium; } // ========================================= CONSTANTS ========================================= /** * @notice Native address used to tell the contract to handle native asset deposits. */ address internal constant NATIVE = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; /** * @notice The maximum possible share lock period. */ uint256 internal constant MAX_SHARE_LOCK_PERIOD = 3 days; /** * @notice The maximum possible share premium that can be set using `updateAssetData`. * @dev 1,000 or 10% */ uint16 internal constant MAX_SHARE_PREMIUM = 1000; // ========================================= STATE ========================================= /** * @notice Mapping ERC20s to their assetData. */ mapping(ERC20 => Asset) public assetData; /** * @notice The deposit nonce used to map to a deposit hash. */ uint96 public depositNonce; /** * @notice After deposits, shares are locked to the msg.sender's address * for `shareLockPeriod`. * @dev During this time all trasnfers from msg.sender will revert, and * deposits are refundable. */ uint64 public shareLockPeriod; /** * @notice Used to pause calls to `deposit` and `depositWithPermit`. */ bool public isPaused; /** * @dev Maps deposit nonce to keccak256(address receiver, address depositAsset, uint256 depositAmount, uint256 shareAmount, uint256 timestamp, uint256 shareLockPeriod). */ mapping(uint256 => bytes32) public publicDepositHistory; /** * @notice Maps user address to the time their shares will be unlocked. */ mapping(address => uint256) public shareUnlockTime; /** * @notice Mapping `from` address to a bool to deny them from transferring shares. */ mapping(address => bool) public fromDenyList; /** * @notice Mapping `to` address to a bool to deny them from receiving shares. */ mapping(address => bool) public toDenyList; /** * @notice Mapping `opeartor` address to a bool to deny them from calling `transfer` or `transferFrom`. */ mapping(address => bool) public operatorDenyList; //============================== ERRORS =============================== error TellerWithMultiAssetSupport__ShareLockPeriodTooLong(); error TellerWithMultiAssetSupport__SharesAreLocked(); error TellerWithMultiAssetSupport__SharesAreUnLocked(); error TellerWithMultiAssetSupport__BadDepositHash(); error TellerWithMultiAssetSupport__AssetNotSupported(); error TellerWithMultiAssetSupport__ZeroAssets(); error TellerWithMultiAssetSupport__MinimumMintNotMet(); error TellerWithMultiAssetSupport__MinimumAssetsNotMet(); error TellerWithMultiAssetSupport__PermitFailedAndAllowanceTooLow(); error TellerWithMultiAssetSupport__ZeroShares(); error TellerWithMultiAssetSupport__DualDeposit(); error TellerWithMultiAssetSupport__Paused(); error TellerWithMultiAssetSupport__TransferDenied(address from, address to, address operator); error TellerWithMultiAssetSupport__SharePremiumTooLarge(); error TellerWithMultiAssetSupport__CannotDepositNative(); //============================== EVENTS =============================== event Paused(); event Unpaused(); event AssetDataUpdated(address indexed asset, bool allowDeposits, bool allowWithdraws, uint16 sharePremium); event Deposit( uint256 indexed nonce, address indexed receiver, address indexed depositAsset, uint256 depositAmount, uint256 shareAmount, uint256 depositTimestamp, uint256 shareLockPeriodAtTimeOfDeposit ); event BulkDeposit(address indexed asset, uint256 depositAmount); event BulkWithdraw(address indexed asset, uint256 shareAmount); event DepositRefunded(uint256 indexed nonce, bytes32 depositHash, address indexed user); event DenyFrom(address indexed user); event DenyTo(address indexed user); event DenyOperator(address indexed user); event AllowFrom(address indexed user); event AllowTo(address indexed user); event AllowOperator(address indexed user); // =============================== MODIFIERS =============================== /** * @notice Reverts if the deposit asset is the native asset. */ modifier revertOnNativeDeposit(address depositAsset) { if (depositAsset == NATIVE) revert TellerWithMultiAssetSupport__CannotDepositNative(); _; } //============================== IMMUTABLES =============================== /** * @notice The BoringVault this contract is working with. */ BoringVault public immutable vault; /** * @notice The AccountantWithRateProviders this contract is working with. */ AccountantWithRateProviders public immutable accountant; /** * @notice One share of the BoringVault. */ uint256 internal immutable ONE_SHARE; /** * @notice The native wrapper contract. */ WETH public immutable nativeWrapper; constructor(address _owner, address _vault, address _accountant, address _weth) Auth(_owner, Authority(address(0))) { vault = BoringVault(payable(_vault)); ONE_SHARE = 10 ** vault.decimals(); accountant = AccountantWithRateProviders(_accountant); nativeWrapper = WETH(payable(_weth)); } // ========================================= ADMIN FUNCTIONS ========================================= /** * @notice Pause this contract, which prevents future calls to `deposit` and `depositWithPermit`. * @dev Callable by MULTISIG_ROLE. */ function pause() external requiresAuth { isPaused = true; emit Paused(); } /** * @notice Unpause this contract, which allows future calls to `deposit` and `depositWithPermit`. * @dev Callable by MULTISIG_ROLE. */ function unpause() external requiresAuth { isPaused = false; emit Unpaused(); } /** * @notice Updates the asset data for a given asset. * @dev The accountant must also support pricing this asset, else the `deposit` call will revert. * @dev Callable by OWNER_ROLE. */ function updateAssetData(ERC20 asset, bool allowDeposits, bool allowWithdraws, uint16 sharePremium) external requiresAuth { if (sharePremium > MAX_SHARE_PREMIUM) revert TellerWithMultiAssetSupport__SharePremiumTooLarge(); assetData[asset] = Asset(allowDeposits, allowWithdraws, sharePremium); emit AssetDataUpdated(address(asset), allowDeposits, allowWithdraws, sharePremium); } /** * @notice Sets the share lock period. * @dev This not only locks shares to the user address, but also serves as the pending deposit period, where deposits can be reverted. * @dev If a new shorter share lock period is set, users with pending share locks could make a new deposit to receive 1 wei shares, * and have their shares unlock sooner than their original deposit allows. This state would allow for the user deposit to be refunded, * but only if they have not transferred their shares out of there wallet. This is an accepted limitation, and should be known when decreasing * the share lock period. * @dev Callable by OWNER_ROLE. */ function setShareLockPeriod(uint64 _shareLockPeriod) external requiresAuth { if (_shareLockPeriod > MAX_SHARE_LOCK_PERIOD) revert TellerWithMultiAssetSupport__ShareLockPeriodTooLong(); shareLockPeriod = _shareLockPeriod; } /** * @notice Deny a user from transferring or receiving shares. * @dev Callable by OWNER_ROLE, and DENIER_ROLE. */ function denyAll(address user) external requiresAuth { fromDenyList[user] = true; toDenyList[user] = true; operatorDenyList[user] = true; emit DenyFrom(user); emit DenyTo(user); emit DenyOperator(user); } /** * @notice Allow a user to transfer or receive shares. * @dev Callable by OWNER_ROLE, and DENIER_ROLE. */ function allowAll(address user) external requiresAuth { fromDenyList[user] = false; toDenyList[user] = false; operatorDenyList[user] = false; emit AllowFrom(user); emit AllowTo(user); emit AllowOperator(user); } /** * @notice Deny a user from transferring shares. * @dev Callable by OWNER_ROLE, and DENIER_ROLE. */ function denyFrom(address user) external requiresAuth { fromDenyList[user] = true; emit DenyFrom(user); } /** * @notice Allow a user to transfer shares. * @dev Callable by OWNER_ROLE, and DENIER_ROLE. */ function allowFrom(address user) external requiresAuth { fromDenyList[user] = false; emit AllowFrom(user); } /** * @notice Deny a user from receiving shares. * @dev Callable by OWNER_ROLE, and DENIER_ROLE. */ function denyTo(address user) external requiresAuth { toDenyList[user] = true; emit DenyTo(user); } /** * @notice Allow a user to receive shares. * @dev Callable by OWNER_ROLE, and DENIER_ROLE. */ function allowTo(address user) external requiresAuth { toDenyList[user] = false; emit AllowTo(user); } /** * @notice Deny an operator from transferring shares. * @dev Callable by OWNER_ROLE, and DENIER_ROLE. */ function denyOperator(address user) external requiresAuth { operatorDenyList[user] = true; emit DenyOperator(user); } /** * @notice Allow an operator to transfer shares. * @dev Callable by OWNER_ROLE, and DENIER_ROLE. */ function allowOperator(address user) external requiresAuth { operatorDenyList[user] = false; emit AllowOperator(user); } // ========================================= BeforeTransferHook FUNCTIONS ========================================= /** * @notice Implement beforeTransfer hook to check if shares are locked, or if `from`, `to`, or `operator` are on the deny list. * @notice If share lock period is set to zero, then users will be able to mint and transfer in the same tx. * if this behavior is not desired then a share lock period of >=1 should be used. */ function beforeTransfer(address from, address to, address operator) public view virtual { if (fromDenyList[from] || toDenyList[to] || operatorDenyList[operator]) { revert TellerWithMultiAssetSupport__TransferDenied(from, to, operator); } if (shareUnlockTime[from] > block.timestamp) revert TellerWithMultiAssetSupport__SharesAreLocked(); } // ========================================= REVERT DEPOSIT FUNCTIONS ========================================= /** * @notice Allows DEPOSIT_REFUNDER_ROLE to revert a pending deposit. * @dev Once a deposit share lock period has passed, it can no longer be reverted. * @dev It is possible the admin does not setup the BoringVault to call the transfer hook, * but this contract can still be saving share lock state. In the event this happens * deposits are still refundable if the user has not transferred their shares. * But there is no guarantee that the user has not transferred their shares. * @dev Callable by STRATEGIST_MULTISIG_ROLE. */ function refundDeposit( uint256 nonce, address receiver, address depositAsset, uint256 depositAmount, uint256 shareAmount, uint256 depositTimestamp, uint256 shareLockUpPeriodAtTimeOfDeposit ) external requiresAuth { if ((block.timestamp - depositTimestamp) >= shareLockUpPeriodAtTimeOfDeposit) { // Shares are already unlocked, so we can not revert deposit. revert TellerWithMultiAssetSupport__SharesAreUnLocked(); } bytes32 depositHash = keccak256( abi.encode( receiver, depositAsset, depositAmount, shareAmount, depositTimestamp, shareLockUpPeriodAtTimeOfDeposit ) ); if (publicDepositHistory[nonce] != depositHash) revert TellerWithMultiAssetSupport__BadDepositHash(); // Delete hash to prevent refund gas. delete publicDepositHistory[nonce]; // If deposit used native asset, send user back wrapped native asset. depositAsset = depositAsset == NATIVE ? address(nativeWrapper) : depositAsset; // Burn shares and refund assets to receiver. vault.exit(receiver, ERC20(depositAsset), depositAmount, receiver, shareAmount); emit DepositRefunded(nonce, depositHash, receiver); } // ========================================= USER FUNCTIONS ========================================= /** * @notice Allows users to deposit into the BoringVault, if this contract is not paused. * @dev Publicly callable. */ function deposit(ERC20 depositAsset, uint256 depositAmount, uint256 minimumMint) external payable requiresAuth nonReentrant returns (uint256 shares) { Asset memory asset = _beforeDeposit(depositAsset); address from; if (address(depositAsset) == NATIVE) { if (msg.value == 0) revert TellerWithMultiAssetSupport__ZeroAssets(); nativeWrapper.deposit{value: msg.value}(); // Set depositAmount to msg.value. depositAmount = msg.value; nativeWrapper.safeApprove(address(vault), depositAmount); // Update depositAsset to nativeWrapper. depositAsset = nativeWrapper; // Set from to this address since user transferred value. from = address(this); } else { if (msg.value > 0) revert TellerWithMultiAssetSupport__DualDeposit(); from = msg.sender; } shares = _erc20Deposit(depositAsset, depositAmount, minimumMint, from, msg.sender, asset); _afterPublicDeposit(msg.sender, depositAsset, depositAmount, shares, shareLockPeriod); } /** * @notice Allows users to deposit into BoringVault using permit. * @dev Publicly callable. */ function depositWithPermit( ERC20 depositAsset, uint256 depositAmount, uint256 minimumMint, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external requiresAuth nonReentrant revertOnNativeDeposit(address(depositAsset)) returns (uint256 shares) { Asset memory asset = _beforeDeposit(depositAsset); _handlePermit(depositAsset, depositAmount, deadline, v, r, s); shares = _erc20Deposit(depositAsset, depositAmount, minimumMint, msg.sender, msg.sender, asset); _afterPublicDeposit(msg.sender, depositAsset, depositAmount, shares, shareLockPeriod); } /** * @notice Allows on ramp role to deposit into this contract. * @dev Does NOT support native deposits. * @dev Callable by SOLVER_ROLE. */ function bulkDeposit(ERC20 depositAsset, uint256 depositAmount, uint256 minimumMint, address to) external requiresAuth nonReentrant returns (uint256 shares) { Asset memory asset = _beforeDeposit(depositAsset); shares = _erc20Deposit(depositAsset, depositAmount, minimumMint, msg.sender, to, asset); emit BulkDeposit(address(depositAsset), depositAmount); } /** * @notice Allows off ramp role to withdraw from this contract. * @dev Callable by SOLVER_ROLE. */ function bulkWithdraw(ERC20 withdrawAsset, uint256 shareAmount, uint256 minimumAssets, address to) external requiresAuth returns (uint256 assetsOut) { if (isPaused) revert TellerWithMultiAssetSupport__Paused(); Asset memory asset = assetData[withdrawAsset]; if (!asset.allowWithdraws) revert TellerWithMultiAssetSupport__AssetNotSupported(); if (shareAmount == 0) revert TellerWithMultiAssetSupport__ZeroShares(); assetsOut = shareAmount.mulDivDown(accountant.getRateInQuoteSafe(withdrawAsset), ONE_SHARE); if (assetsOut < minimumAssets) revert TellerWithMultiAssetSupport__MinimumAssetsNotMet(); vault.exit(to, withdrawAsset, assetsOut, msg.sender, shareAmount); emit BulkWithdraw(address(withdrawAsset), shareAmount); } // ========================================= INTERNAL HELPER FUNCTIONS ========================================= /** * @notice Implements a common ERC20 deposit into BoringVault. */ function _erc20Deposit( ERC20 depositAsset, uint256 depositAmount, uint256 minimumMint, address from, address to, Asset memory asset ) internal returns (uint256 shares) { if (depositAmount == 0) revert TellerWithMultiAssetSupport__ZeroAssets(); shares = depositAmount.mulDivDown(ONE_SHARE, accountant.getRateInQuoteSafe(depositAsset)); shares = asset.sharePremium > 0 ? shares.mulDivDown(1e4 - asset.sharePremium, 1e4) : shares; if (shares < minimumMint) revert TellerWithMultiAssetSupport__MinimumMintNotMet(); vault.enter(from, depositAsset, depositAmount, to, shares); } /** * @notice Handle pre-deposit checks. */ function _beforeDeposit(ERC20 depositAsset) internal view returns (Asset memory asset) { if (isPaused) revert TellerWithMultiAssetSupport__Paused(); asset = assetData[depositAsset]; if (!asset.allowDeposits) revert TellerWithMultiAssetSupport__AssetNotSupported(); } /** * @notice Handle share lock logic, and event. */ function _afterPublicDeposit( address user, ERC20 depositAsset, uint256 depositAmount, uint256 shares, uint256 currentShareLockPeriod ) internal { // Increment then assign as its slightly more gas efficient. uint256 nonce = ++depositNonce; // Only set share unlock time and history if share lock period is greater than 0. if (currentShareLockPeriod > 0) { shareUnlockTime[user] = block.timestamp + currentShareLockPeriod; publicDepositHistory[nonce] = keccak256( abi.encode(user, depositAsset, depositAmount, shares, block.timestamp, currentShareLockPeriod) ); } emit Deposit(nonce, user, address(depositAsset), depositAmount, shares, block.timestamp, currentShareLockPeriod); } /** * @notice Handle permit logic. */ function _handlePermit(ERC20 depositAsset, uint256 depositAmount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) internal { try depositAsset.permit(msg.sender, address(vault), depositAmount, deadline, v, r, s) {} catch { if (depositAsset.allowance(msg.sender, address(vault)) < depositAmount) { revert TellerWithMultiAssetSupport__PermitFailedAndAllowanceTooLow(); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.20; /** * @title ERC-721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC-721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be * reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.21; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol"; import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol"; import {ERC20} from "@solmate/tokens/ERC20.sol"; import {BeforeTransferHook} from "../../src/interfaces/BeforeTransferHook.sol"; import {Auth, Authority} from "@solmate/auth/Auth.sol"; contract BoringVault is ERC20, Auth, ERC721Holder, ERC1155Holder { using Address for address; using SafeTransferLib for ERC20; using FixedPointMathLib for uint256; // ========================================= STATE ========================================= /** * @notice Contract responsbile for implementing `beforeTransfer`. */ BeforeTransferHook public hook; //============================== EVENTS =============================== event Enter(address indexed from, address indexed asset, uint256 amount, address indexed to, uint256 shares); event Exit(address indexed to, address indexed asset, uint256 amount, address indexed from, uint256 shares); //============================== CONSTRUCTOR =============================== constructor(address _owner, string memory _name, string memory _symbol, uint8 _decimals) ERC20(_name, _symbol, _decimals) Auth(_owner, Authority(address(0))) {} //============================== MANAGE =============================== /** * @notice Allows manager to make an arbitrary function call from this contract. * @dev Callable by MANAGER_ROLE. */ function manage(address target, bytes calldata data, uint256 value) external requiresAuth returns (bytes memory result) { result = target.functionCallWithValue(data, value); } /** * @notice Allows manager to make arbitrary function calls from this contract. * @dev Callable by MANAGER_ROLE. */ function manage(address[] calldata targets, bytes[] calldata data, uint256[] calldata values) external requiresAuth returns (bytes[] memory results) { uint256 targetsLength = targets.length; results = new bytes[](targetsLength); for (uint256 i; i < targetsLength; ++i) { results[i] = targets[i].functionCallWithValue(data[i], values[i]); } } //============================== ENTER =============================== /** * @notice Allows minter to mint shares, in exchange for assets. * @dev If assetAmount is zero, no assets are transferred in. * @dev Callable by MINTER_ROLE. */ function enter(address from, ERC20 asset, uint256 assetAmount, address to, uint256 shareAmount) external requiresAuth { // Transfer assets in if (assetAmount > 0) asset.safeTransferFrom(from, address(this), assetAmount); // Mint shares. _mint(to, shareAmount); emit Enter(from, address(asset), assetAmount, to, shareAmount); } //============================== EXIT =============================== /** * @notice Allows burner to burn shares, in exchange for assets. * @dev If assetAmount is zero, no assets are transferred out. * @dev Callable by BURNER_ROLE. */ function exit(address to, ERC20 asset, uint256 assetAmount, address from, uint256 shareAmount) external requiresAuth { // Burn shares. _burn(from, shareAmount); // Transfer assets out. if (assetAmount > 0) asset.safeTransfer(to, assetAmount); emit Exit(to, address(asset), assetAmount, from, shareAmount); } //============================== BEFORE TRANSFER HOOK =============================== /** * @notice Sets the share locker. * @notice If set to zero address, the share locker logic is disabled. * @dev Callable by OWNER_ROLE. */ function setBeforeTransferHook(address _hook) external requiresAuth { hook = BeforeTransferHook(_hook); } /** * @notice Call `beforeTransferHook` passing in `from` `to`, and `msg.sender`. */ function _callBeforeTransfer(address from, address to) internal view { if (address(hook) != address(0)) hook.beforeTransfer(from, to, msg.sender); } function transfer(address to, uint256 amount) public override returns (bool) { _callBeforeTransfer(msg.sender, to); return super.transfer(to, amount); } function transferFrom(address from, address to, uint256 amount) public override returns (bool) { _callBeforeTransfer(from, to); return super.transferFrom(from, to, amount); } //============================== RECEIVE =============================== receive() external payable {} }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) /// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol) library FixedPointMathLib { /*////////////////////////////////////////////////////////////// SIMPLIFIED FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ uint256 internal constant MAX_UINT256 = 2**256 - 1; uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s. function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down. } function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up. } function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down. } function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up. } /*////////////////////////////////////////////////////////////// LOW LEVEL FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ function mulDivDown( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { revert(0, 0) } // Divide x * y by the denominator. z := div(mul(x, y), denominator) } } function mulDivUp( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { revert(0, 0) } // If x * y modulo the denominator is strictly greater than 0, // 1 is added to round up the division of x * y by the denominator. z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator)) } } function rpow( uint256 x, uint256 n, uint256 scalar ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { switch x case 0 { switch n case 0 { // 0 ** 0 = 1 z := scalar } default { // 0 ** n = 0 z := 0 } } default { switch mod(n, 2) case 0 { // If n is even, store scalar in z for now. z := scalar } default { // If n is odd, store x in z for now. z := x } // Shifting right by 1 is like dividing by 2. let half := shr(1, scalar) for { // Shift n right by 1 before looping to halve it. n := shr(1, n) } n { // Shift n right by 1 each iteration to halve it. n := shr(1, n) } { // Revert immediately if x ** 2 would overflow. // Equivalent to iszero(eq(div(xx, x), x)) here. if shr(128, x) { revert(0, 0) } // Store x squared. let xx := mul(x, x) // Round to the nearest number. let xxRound := add(xx, half) // Revert if xx + half overflowed. if lt(xxRound, xx) { revert(0, 0) } // Set x to scaled xxRound. x := div(xxRound, scalar) // If n is even: if mod(n, 2) { // Compute z * x. let zx := mul(z, x) // If z * x overflowed: if iszero(eq(div(zx, x), z)) { // Revert if x is non-zero. if iszero(iszero(x)) { revert(0, 0) } } // Round to the nearest number. let zxRound := add(zx, half) // Revert if zx + half overflowed. if lt(zxRound, zx) { revert(0, 0) } // Return properly scaled zxRound. z := div(zxRound, scalar) } } } } } /*////////////////////////////////////////////////////////////// GENERAL NUMBER UTILITIES //////////////////////////////////////////////////////////////*/ function sqrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { let y := x // We start y at x, which will help us make our initial estimate. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // We check y >= 2^(k + 8) but shift right by k bits // each branch to ensure that if x >= 256, then y >= 256. if iszero(lt(y, 0x10000000000000000000000000000000000)) { y := shr(128, y) z := shl(64, z) } if iszero(lt(y, 0x1000000000000000000)) { y := shr(64, y) z := shl(32, z) } if iszero(lt(y, 0x10000000000)) { y := shr(32, y) z := shl(16, z) } if iszero(lt(y, 0x1000000)) { y := shr(16, y) z := shl(8, z) } // Goal was to get z*z*y within a small factor of x. More iterations could // get y in a tighter range. Currently, we will have y in [256, 256*2^16). // We ensured y >= 256 so that the relative difference between y and y+1 is small. // That's not possible if x < 256 but we can just verify those cases exhaustively. // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256. // Correctness can be checked exhaustively for x < 256, so we assume y >= 256. // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps. // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256. // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18. // There is no overflow risk here since y < 2^136 after the first branch above. z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // If x+1 is a perfect square, the Babylonian method cycles between // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case. // If you don't care whether the floor or ceil square root is returned, you can remove this statement. z := sub(z, lt(div(x, z), z)) } } function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Mod x by y. Note this will return // 0 instead of reverting if y is zero. z := mod(x, y) } } function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { // Divide x by y. Note this will return // 0 instead of reverting if y is zero. r := div(x, y) } } function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Add 1 to x * y if x % y > 0. Note this will // return 0 instead of reverting if y is zero. z := add(gt(mod(x, y), 0), div(x, y)) } } }
{ "evmVersion": "shanghai", "metadata": { "appendCBOR": true, "bytecodeHash": "ipfs", "useLiteralContent": false }, "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "remappings": [ "@ccip/=lib/boring-vault/lib/ccip/", "@devtools-oapp-evm/=lib/boring-vault/lib/OAppAuth/lib/devtools/packages/oapp-evm/contracts/oapp/", "@ds-test/=lib/boring-vault/lib/forge-std/lib/ds-test/src/", "@forge-std/=lib/boring-vault/lib/forge-std/src/", "@layerzerolabs/lz-evm-messagelib-v2/=lib/boring-vault/lib/OAppAuth/node_modules/@layerzerolabs/lz-evm-messagelib-v2/", "@layerzerolabs/lz-evm-protocol-v2/=lib/boring-vault/lib/OAppAuth/lib/LayerZero-V2/packages/layerzero-v2/evm/protocol/", "@layerzerolabs/oapp-evm/=lib/boring-vault/lib/OAppAuth/lib/devtools/packages/oapp-evm/", "@lz-oapp-evm/=lib/boring-vault/lib/OAppAuth/lib/LayerZero-V2/packages/layerzero-v2/evm/oapp/contracts/oapp/", "@oapp-auth/=lib/boring-vault/lib/OAppAuth/src/", "@openzeppelin/=lib/boring-vault/lib/openzeppelin-contracts/", "@solmate/=lib/boring-vault/lib/solmate/src/", "LayerZero-V2/=lib/boring-vault/lib/OAppAuth/lib/", "OAppAuth/=lib/boring-vault/lib/OAppAuth/", "boring-vault/=lib/boring-vault/", "ccip/=lib/boring-vault/lib/ccip/contracts/", "ds-test/=lib/solmate/lib/ds-test/src/", "erc4626-tests/=lib/boring-vault/lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "halmos-cheatcodes/=lib/boring-vault/lib/OAppAuth/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/", "openzeppelin-contracts/=lib/boring-vault/lib/openzeppelin-contracts/", "solady/=lib/solady/src/", "solidity-bytes-utils/=lib/boring-vault/lib/OAppAuth/node_modules/solidity-bytes-utils/", "solmate/=lib/solmate/src/", "yearn-vaults/=lib/yearn-vaults/contracts/", "@sbu/=lib/boring-vault/lib/OAppAuth/lib/solidity-bytes-utils/", "morpho-blue/=lib/boring-vault/lib/morpho-blue/" ], "viaIR": false }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_auth","type":"address"},{"internalType":"address","name":"_queue","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"boringVault","type":"address"},{"internalType":"address","name":"teller","type":"address"}],"name":"BoringSolver___BoringVaultTellerMismatch","type":"error"},{"inputs":[],"name":"BoringSolver___FailedToSolve","type":"error"},{"inputs":[],"name":"BoringSolver___OnlyQueue","type":"error"},{"inputs":[],"name":"BoringSolver___OnlySelf","type":"error"},{"inputs":[],"name":"BoringSolver___WrongInitiator","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"AuthorityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract Authority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint96","name":"nonce","type":"uint96"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"assetOut","type":"address"},{"internalType":"uint128","name":"amountOfShares","type":"uint128"},{"internalType":"uint128","name":"amountOfAssets","type":"uint128"},{"internalType":"uint40","name":"creationTime","type":"uint40"},{"internalType":"uint24","name":"secondsToMaturity","type":"uint24"},{"internalType":"uint24","name":"secondsToDeadline","type":"uint24"}],"internalType":"struct BoringOnChainQueue.OnChainWithdraw","name":"request","type":"tuple"},{"internalType":"address","name":"fromTeller","type":"address"},{"internalType":"address","name":"toTeller","type":"address"},{"internalType":"address","name":"intermediateAsset","type":"address"}],"name":"boringRedeemMintSelfSolve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint96","name":"nonce","type":"uint96"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"assetOut","type":"address"},{"internalType":"uint128","name":"amountOfShares","type":"uint128"},{"internalType":"uint128","name":"amountOfAssets","type":"uint128"},{"internalType":"uint40","name":"creationTime","type":"uint40"},{"internalType":"uint24","name":"secondsToMaturity","type":"uint24"},{"internalType":"uint24","name":"secondsToDeadline","type":"uint24"}],"internalType":"struct BoringOnChainQueue.OnChainWithdraw[]","name":"requests","type":"tuple[]"},{"internalType":"address","name":"fromTeller","type":"address"},{"internalType":"address","name":"toTeller","type":"address"},{"internalType":"address","name":"intermediateAsset","type":"address"}],"name":"boringRedeemMintSolve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint96","name":"nonce","type":"uint96"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"assetOut","type":"address"},{"internalType":"uint128","name":"amountOfShares","type":"uint128"},{"internalType":"uint128","name":"amountOfAssets","type":"uint128"},{"internalType":"uint40","name":"creationTime","type":"uint40"},{"internalType":"uint24","name":"secondsToMaturity","type":"uint24"},{"internalType":"uint24","name":"secondsToDeadline","type":"uint24"}],"internalType":"struct BoringOnChainQueue.OnChainWithdraw","name":"request","type":"tuple"},{"internalType":"address","name":"teller","type":"address"}],"name":"boringRedeemSelfSolve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint96","name":"nonce","type":"uint96"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"assetOut","type":"address"},{"internalType":"uint128","name":"amountOfShares","type":"uint128"},{"internalType":"uint128","name":"amountOfAssets","type":"uint128"},{"internalType":"uint40","name":"creationTime","type":"uint40"},{"internalType":"uint24","name":"secondsToMaturity","type":"uint24"},{"internalType":"uint24","name":"secondsToDeadline","type":"uint24"}],"internalType":"struct BoringOnChainQueue.OnChainWithdraw[]","name":"requests","type":"tuple[]"},{"internalType":"address","name":"teller","type":"address"}],"name":"boringRedeemSolve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"initiator","type":"address"},{"internalType":"address","name":"boringVault","type":"address"},{"internalType":"address","name":"solveAsset","type":"address"},{"internalType":"uint256","name":"totalShares","type":"uint256"},{"internalType":"uint256","name":"requiredAssets","type":"uint256"},{"internalType":"bytes","name":"solveData","type":"bytes"}],"name":"boringSolve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rescueTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a060405234801562000010575f80fd5b5060405162002018380380620020188339810160408190526200003391620000f5565b5f80546001600160a01b03199081166001600160a01b0386811691821784556001805490931690861617909155604051859285929133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a36040516001600160a01b0382169033907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a350506001600160a01b0316608052506200013c9050565b80516001600160a01b0381168114620000f0575f80fd5b919050565b5f805f6060848603121562000108575f80fd5b6200011384620000d9565b92506200012360208501620000d9565b91506200013360408501620000d9565b90509250925092565b608051611e92620001865f395f81816102a501528181610497015281816106e9015281816108ba015281816109e601528181610cd701528181611008015261116e0152611e925ff3fe608060405234801561000f575f80fd5b50600436106100a6575f3560e01c80638f3866081161006e5780638f38660814610127578063ac9650d81461013a578063b7532db21461015a578063bf7e214f1461016d578063f2fde38b14610180578063ff011b6214610193575f80fd5b806357376198146100aa57806367aa0416146100bf57806372faf4a4146100d25780637a9e5e4b146100e55780638da5cb5b146100f8575b5f80fd5b6100bd6100b83660046113f4565b6101a6565b005b6100bd6100cd36600461142e565b610269565b6100bd6100e03660046114fa565b610390565b6100bd6100f3366004611532565b6104f9565b5f5461010a906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6100bd61013536600461154d565b6105dd565b61014d6101483660046115a9565b610757565b60405161011e9190611665565b6100bd61016836600461170d565b610849565b60015461010a906001600160a01b031681565b6100bd61018e366004611532565b6108f5565b6100bd6101a1366004611760565b610970565b6101bb335f356001600160e01b031916610a21565b6101e05760405162461bcd60e51b81526004016101d7906117d8565b60405180910390fd5b5f198103610251576040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa15801561022a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061024e91906117fe565b90505b6102656001600160a01b0383163383610ac7565b5050565b61027e335f356001600160e01b031916610a21565b61029a5760405162461bcd60e51b81526004016101d7906117d8565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146102e3576040516337aab0fd60e11b815260040160405180910390fd5b6001600160a01b038716301461030c5760405163702093cb60e11b815260040160405180910390fd5b5f61031982840184611823565b90505f81600181111561032e5761032e61183c565b0361034657610341838389898989610b56565b610386565b600181600181111561035a5761035a61183c565b0361036d57610341838389898989610d5e565b6040516336ad3b5560e21b815260040160405180910390fd5b5050505050505050565b6103a5335f356001600160e01b031916610a21565b6103c15760405162461bcd60e51b81526004016101d7906117d8565b336103d26040840160208501611532565b6001600160a01b0316146103f9576040516303279bc360e41b815260040160405180910390fd5b6040805160018082528183019092525f91816020015b61041761139d565b81526020019060019003908161040f57905050905061043b368490038401846118b6565b815f8151811061044d5761044d611985565b60200260200101819052505f8033845f60405160200161047094939291906119b9565b60408051601f19818403018152908290526310498e3760e21b825291506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063412638dc906104d0908590859030906004016119f0565b5f604051808303815f87803b1580156104e7575f80fd5b505af1158015610386573d5f803e3d5ffd5b5f546001600160a01b031633148061058a575060015460405163b700961360e01b81526001600160a01b039091169063b70096139061054b90339030906001600160e01b03195f351690600401611ad2565b602060405180830381865afa158015610566573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061058a9190611b0c565b610592575f80fd5b600180546001600160a01b0319166001600160a01b03831690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a350565b6105f2335f356001600160e01b031916610a21565b61060e5760405162461bcd60e51b81526004016101d7906117d8565b3361061f6040860160208701611532565b6001600160a01b031614610646576040516303279bc360e41b815260040160405180910390fd5b6040805160018082528183019092525f91816020015b61066461139d565b81526020019060019003908161065c579050509050610688368690038601866118b6565b815f8151811061069a5761069a611985565b60200260200101819052505f6001338686865f6040516020016106c296959493929190611b27565b60408051601f19818403018152908290526310498e3760e21b825291506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063412638dc90610722908590859030906004016119f0565b5f604051808303815f87803b158015610739575f80fd5b505af115801561074b573d5f803e3d5ffd5b50505050505050505050565b604080515f8152602081019091526060908267ffffffffffffffff81111561078157610781611850565b6040519080825280602002602001820160405280156107b457816020015b606081526020019060019003908161079f5790505b5091505f5b8381101561084057610810308686848181106107d7576107d7611985565b90506020028101906107e99190611b94565b856040516020016107fc93929190611bd7565b6040516020818303038152906040526111f6565b83828151811061082257610822611985565b6020026020010181905250808061083890611bfc565b9150506107b9565b50505b92915050565b61085e335f356001600160e01b031916610a21565b61087a5760405162461bcd60e51b81526004016101d7906117d8565b5f803383600160405160200161089394939291906119b9565b60408051601f19818403018152908290526310498e3760e21b825291506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063412638dc906104d0908790879086903090600401611c14565b61090a335f356001600160e01b031916610a21565b6109265760405162461bcd60e51b81526004016101d7906117d8565b5f80546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b610985335f356001600160e01b031916610a21565b6109a15760405162461bcd60e51b81526004016101d7906117d8565b5f60013385858560016040516020016109bf96959493929190611b27565b60408051601f19818403018152908290526310498e3760e21b825291506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063412638dc90610722908990899086903090600401611c14565b6001545f906001600160a01b03168015801590610aa8575060405163b700961360e01b81526001600160a01b0382169063b700961390610a6990879030908890600401611ad2565b602060405180830381865afa158015610a84573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610aa89190611b0c565b80610abf57505f546001600160a01b038581169116145b949350505050565b5f60405163a9059cbb60e01b81526001600160a01b038416600482015282602482015260205f6044835f895af191505080601f3d1160015f511416151615610b115750823b153d17155b80610b505760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064016101d7565b50505050565b5f8080610b65888a018a611d33565b93509350935050816001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ba8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bcc9190611d7f565b6001600160a01b0316876001600160a01b031614610c1057604051631469fe1360e21b81526001600160a01b038089166004830152831660248201526044016101d7565b604051633e64ce9960e01b815286905f906001600160a01b03851690633e64ce9990610c469085908b908b903090600401611d9a565b6020604051808303815f875af1158015610c62573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c8691906117fe565b90508215610cb257610cad85610c9c8884611b81565b6001600160a01b0385169190610ac7565b610cc0565b610cc089610c9c8884611b81565b60405163095ea7b360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820188905283169063095ea7b3906044016020604051808303815f875af1158015610d2c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d509190611b0c565b505050505050505050505050565b5f80808080610d6f8a8c018c611dc5565b9550955095509550955050836001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610db6573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610dda9190611d7f565b6001600160a01b0316896001600160a01b031614610e1e57604051631469fe1360e21b81526001600160a01b03808b166004830152851660248201526044016101d7565b826001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e5a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e7e9190611d7f565b6001600160a01b0316886001600160a01b031614610ec257604051631469fe1360e21b81526001600160a01b03808a166004830152841660248201526044016101d7565b604051633e64ce9960e01b81525f906001600160a01b03861690633e64ce9990610ef69086908c9086903090600401611d9a565b6020604051808303815f875af1158015610f12573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f3691906117fe565b90505f61108e856001600160a01b0316634fb3ccc56040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f78573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f9c9190611d7f565b604051634104b9ed60e11b81526001600160a01b038781166004830152919091169063820973da90602401602060405180830381865afa158015610fe2573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061100691906117fe565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b7d122b56040518163ffffffff1660e01b8152600401602060405180830381865afa158015611062573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061108691906117fe565b8a9190611268565b905061109a8183611b81565b91506110b06001600160a01b0385168b8361128b565b6040516304eaba2160e51b81526001600160a01b03861690639d574420906110e290879085908d903090600401611d9a565b6020604051808303815f875af11580156110fe573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061112291906117fe565b505081156111435761113e6001600160a01b0384168783610ac7565b611157565b6111576001600160a01b0384168b83610ac7565b60405163095ea7b360e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018990528a169063095ea7b3906044016020604051808303815f875af11580156111c3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111e79190611b0c565b50505050505050505050505050565b60605f80846001600160a01b0316846040516112129190611e41565b5f60405180830381855af49150503d805f811461124a576040519150601f19603f3d011682016040523d82523d5f602084013e61124f565b606091505b509150915061125f858383611313565b95945050505050565b5f825f19048411830215820261127c575f80fd5b50910281810615159190040190565b5f60405163095ea7b360e01b81526001600160a01b038416600482015282602482015260205f6044835f895af191505080601f3d1160015f5114161516156112d55750823b153d17155b80610b505760405162461bcd60e51b815260206004820152600e60248201526d1054141493d59157d1905253115160921b60448201526064016101d7565b6060826113285761132382611372565b61136b565b815115801561133f57506001600160a01b0384163b155b1561136857604051639996b31560e01b81526001600160a01b03851660048201526024016101d7565b50805b9392505050565b80511561138157805160208201fd5b60405163d6bda27560e01b815260040160405180910390fd5b50565b60408051610100810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b6001600160a01b038116811461139a575f80fd5b5f8060408385031215611405575f80fd5b8235611410816113e0565b946020939093013593505050565b8035611429816113e0565b919050565b5f805f805f805f60c0888a031215611444575f80fd5b873561144f816113e0565b9650602088013561145f816113e0565b9550604088013561146f816113e0565b9450606088013593506080880135925060a088013567ffffffffffffffff80821115611499575f80fd5b818a0191508a601f8301126114ac575f80fd5b8135818111156114ba575f80fd5b8b60208285010111156114cb575f80fd5b60208301945080935050505092959891949750929550565b5f61010082840312156114f4575f80fd5b50919050565b5f80610120838503121561150c575f80fd5b61151684846114e3565b9150610100830135611527816113e0565b809150509250929050565b5f60208284031215611542575f80fd5b813561136b816113e0565b5f805f806101608587031215611561575f80fd5b61156b86866114e3565b935061010085013561157c816113e0565b925061012085013561158d816113e0565b915061014085013561159e816113e0565b939692955090935050565b5f80602083850312156115ba575f80fd5b823567ffffffffffffffff808211156115d1575f80fd5b818501915085601f8301126115e4575f80fd5b8135818111156115f2575f80fd5b8660208260051b8501011115611606575f80fd5b60209290920196919550909350505050565b5f5b8381101561163257818101518382015260200161161a565b50505f910152565b5f8151808452611651816020860160208601611618565b601f01601f19169290920160200192915050565b5f602080830181845280855180835260408601915060408160051b87010192508387015f5b828110156116b857603f198886030184526116a685835161163a565b9450928501929085019060010161168a565b5092979650505050505050565b5f8083601f8401126116d5575f80fd5b50813567ffffffffffffffff8111156116ec575f80fd5b6020830191508360208260081b8501011115611706575f80fd5b9250929050565b5f805f6040848603121561171f575f80fd5b833567ffffffffffffffff811115611735575f80fd5b611741868287016116c5565b9094509250506020840135611755816113e0565b809150509250925092565b5f805f805f60808688031215611774575f80fd5b853567ffffffffffffffff81111561178a575f80fd5b611796888289016116c5565b90965094505060208601356117aa816113e0565b925060408601356117ba816113e0565b915060608601356117ca816113e0565b809150509295509295909350565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b5f6020828403121561180e575f80fd5b5051919050565b803560028110611429575f80fd5b5f60208284031215611833575f80fd5b61136b82611815565b634e487b7160e01b5f52602160045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b80356001600160601b0381168114611429575f80fd5b80356001600160801b0381168114611429575f80fd5b803564ffffffffff81168114611429575f80fd5b803562ffffff81168114611429575f80fd5b5f6101008083850312156118c8575f80fd5b6040519081019067ffffffffffffffff821181831017156118f757634e487b7160e01b5f52604160045260245ffd5b8160405261190484611864565b81526119126020850161141e565b60208201526119236040850161141e565b60408201526119346060850161187a565b60608201526119456080850161187a565b608082015261195660a08501611890565b60a082015261196760c085016118a4565b60c082015261197860e085016118a4565b60e0820152949350505050565b634e487b7160e01b5f52603260045260245ffd5b600281106119b557634e487b7160e01b5f52602160045260245ffd5b9052565b608081016119c78287611999565b6001600160a01b0394851660208301529290931660408401521515606090920191909152919050565b606080825284518282018190525f9190608090818501906020808a01865b83811015611aa457815180516001600160601b03168652838101516001600160a01b039081168588015260408083015190911690870152878101516001600160801b039081168988015287820151168787015260a08082015164ffffffffff169087015260c08082015162ffffff9081169188019190915260e09182015116908601526101009094019390820190600101611a0e565b50508683039087015250611ab8818861163a565b9350505050610abf60408301846001600160a01b03169052565b6001600160a01b0393841681529190921660208201526001600160e01b0319909116604082015260600190565b801515811461139a575f80fd5b5f60208284031215611b1c575f80fd5b815161136b81611aff565b60c08101611b358289611999565b6001600160a01b039687166020830152948616604082015292851660608401529316608082015291151560a090920191909152919050565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561084357610843611b6d565b5f808335601e19843603018112611ba9575f80fd5b83018035915067ffffffffffffffff821115611bc3575f80fd5b602001915036819003821315611706575f80fd5b828482375f8382015f81528351611bf2818360208801611618565b0195945050505050565b5f60018201611c0d57611c0d611b6d565b5060010190565b60608082528181018590525f90608080840188845b89811015611d05576001600160601b03611c4283611864565b168352602080830135611c54816113e0565b6001600160a01b031690840152604082810135611c70816113e0565b6001600160a01b031690840152611c8882860161187a565b6001600160801b031685840152611ca082850161187a565b6001600160801b03168484015260a0611cba838201611890565b64ffffffffff169084015260c0611cd28382016118a4565b62ffffff169084015260e0611ce88382016118a4565b62ffffff1690840152610100928301929190910190600101611c29565b50508481036020860152611d19818861163a565b935050505061125f60408301846001600160a01b03169052565b5f805f8060808587031215611d46575f80fd5b611d4f85611815565b93506020850135611d5f816113e0565b92506040850135611d6f816113e0565b9150606085013561159e81611aff565b5f60208284031215611d8f575f80fd5b815161136b816113e0565b6001600160a01b03948516815260208101939093526040830191909152909116606082015260800190565b5f805f805f8060c08789031215611dda575f80fd5b611de387611815565b95506020870135611df3816113e0565b94506040870135611e03816113e0565b93506060870135611e13816113e0565b92506080870135611e23816113e0565b915060a0870135611e3381611aff565b809150509295509295509295565b5f8251611e52818460208701611618565b919091019291505056fea26469706673582212205f6034f2c1792be5f3ab06a566c42a514f4b675002e83b42654158df0f8f1f8064736f6c63430008150033000000000000000000000000771263e3bc6acda5ae388a3f8a0c2dd7a17275fc0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f632c10b19f2a0451cd4a653fc9ca0c15ea1040b
Deployed Bytecode
0x608060405234801561000f575f80fd5b50600436106100a6575f3560e01c80638f3866081161006e5780638f38660814610127578063ac9650d81461013a578063b7532db21461015a578063bf7e214f1461016d578063f2fde38b14610180578063ff011b6214610193575f80fd5b806357376198146100aa57806367aa0416146100bf57806372faf4a4146100d25780637a9e5e4b146100e55780638da5cb5b146100f8575b5f80fd5b6100bd6100b83660046113f4565b6101a6565b005b6100bd6100cd36600461142e565b610269565b6100bd6100e03660046114fa565b610390565b6100bd6100f3366004611532565b6104f9565b5f5461010a906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6100bd61013536600461154d565b6105dd565b61014d6101483660046115a9565b610757565b60405161011e9190611665565b6100bd61016836600461170d565b610849565b60015461010a906001600160a01b031681565b6100bd61018e366004611532565b6108f5565b6100bd6101a1366004611760565b610970565b6101bb335f356001600160e01b031916610a21565b6101e05760405162461bcd60e51b81526004016101d7906117d8565b60405180910390fd5b5f198103610251576040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa15801561022a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061024e91906117fe565b90505b6102656001600160a01b0383163383610ac7565b5050565b61027e335f356001600160e01b031916610a21565b61029a5760405162461bcd60e51b81526004016101d7906117d8565b336001600160a01b037f000000000000000000000000f632c10b19f2a0451cd4a653fc9ca0c15ea1040b16146102e3576040516337aab0fd60e11b815260040160405180910390fd5b6001600160a01b038716301461030c5760405163702093cb60e11b815260040160405180910390fd5b5f61031982840184611823565b90505f81600181111561032e5761032e61183c565b0361034657610341838389898989610b56565b610386565b600181600181111561035a5761035a61183c565b0361036d57610341838389898989610d5e565b6040516336ad3b5560e21b815260040160405180910390fd5b5050505050505050565b6103a5335f356001600160e01b031916610a21565b6103c15760405162461bcd60e51b81526004016101d7906117d8565b336103d26040840160208501611532565b6001600160a01b0316146103f9576040516303279bc360e41b815260040160405180910390fd5b6040805160018082528183019092525f91816020015b61041761139d565b81526020019060019003908161040f57905050905061043b368490038401846118b6565b815f8151811061044d5761044d611985565b60200260200101819052505f8033845f60405160200161047094939291906119b9565b60408051601f19818403018152908290526310498e3760e21b825291506001600160a01b037f000000000000000000000000f632c10b19f2a0451cd4a653fc9ca0c15ea1040b169063412638dc906104d0908590859030906004016119f0565b5f604051808303815f87803b1580156104e7575f80fd5b505af1158015610386573d5f803e3d5ffd5b5f546001600160a01b031633148061058a575060015460405163b700961360e01b81526001600160a01b039091169063b70096139061054b90339030906001600160e01b03195f351690600401611ad2565b602060405180830381865afa158015610566573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061058a9190611b0c565b610592575f80fd5b600180546001600160a01b0319166001600160a01b03831690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a350565b6105f2335f356001600160e01b031916610a21565b61060e5760405162461bcd60e51b81526004016101d7906117d8565b3361061f6040860160208701611532565b6001600160a01b031614610646576040516303279bc360e41b815260040160405180910390fd5b6040805160018082528183019092525f91816020015b61066461139d565b81526020019060019003908161065c579050509050610688368690038601866118b6565b815f8151811061069a5761069a611985565b60200260200101819052505f6001338686865f6040516020016106c296959493929190611b27565b60408051601f19818403018152908290526310498e3760e21b825291506001600160a01b037f000000000000000000000000f632c10b19f2a0451cd4a653fc9ca0c15ea1040b169063412638dc90610722908590859030906004016119f0565b5f604051808303815f87803b158015610739575f80fd5b505af115801561074b573d5f803e3d5ffd5b50505050505050505050565b604080515f8152602081019091526060908267ffffffffffffffff81111561078157610781611850565b6040519080825280602002602001820160405280156107b457816020015b606081526020019060019003908161079f5790505b5091505f5b8381101561084057610810308686848181106107d7576107d7611985565b90506020028101906107e99190611b94565b856040516020016107fc93929190611bd7565b6040516020818303038152906040526111f6565b83828151811061082257610822611985565b6020026020010181905250808061083890611bfc565b9150506107b9565b50505b92915050565b61085e335f356001600160e01b031916610a21565b61087a5760405162461bcd60e51b81526004016101d7906117d8565b5f803383600160405160200161089394939291906119b9565b60408051601f19818403018152908290526310498e3760e21b825291506001600160a01b037f000000000000000000000000f632c10b19f2a0451cd4a653fc9ca0c15ea1040b169063412638dc906104d0908790879086903090600401611c14565b61090a335f356001600160e01b031916610a21565b6109265760405162461bcd60e51b81526004016101d7906117d8565b5f80546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b610985335f356001600160e01b031916610a21565b6109a15760405162461bcd60e51b81526004016101d7906117d8565b5f60013385858560016040516020016109bf96959493929190611b27565b60408051601f19818403018152908290526310498e3760e21b825291506001600160a01b037f000000000000000000000000f632c10b19f2a0451cd4a653fc9ca0c15ea1040b169063412638dc90610722908990899086903090600401611c14565b6001545f906001600160a01b03168015801590610aa8575060405163b700961360e01b81526001600160a01b0382169063b700961390610a6990879030908890600401611ad2565b602060405180830381865afa158015610a84573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610aa89190611b0c565b80610abf57505f546001600160a01b038581169116145b949350505050565b5f60405163a9059cbb60e01b81526001600160a01b038416600482015282602482015260205f6044835f895af191505080601f3d1160015f511416151615610b115750823b153d17155b80610b505760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064016101d7565b50505050565b5f8080610b65888a018a611d33565b93509350935050816001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ba8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bcc9190611d7f565b6001600160a01b0316876001600160a01b031614610c1057604051631469fe1360e21b81526001600160a01b038089166004830152831660248201526044016101d7565b604051633e64ce9960e01b815286905f906001600160a01b03851690633e64ce9990610c469085908b908b903090600401611d9a565b6020604051808303815f875af1158015610c62573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c8691906117fe565b90508215610cb257610cad85610c9c8884611b81565b6001600160a01b0385169190610ac7565b610cc0565b610cc089610c9c8884611b81565b60405163095ea7b360e01b81526001600160a01b037f000000000000000000000000f632c10b19f2a0451cd4a653fc9ca0c15ea1040b811660048301526024820188905283169063095ea7b3906044016020604051808303815f875af1158015610d2c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d509190611b0c565b505050505050505050505050565b5f80808080610d6f8a8c018c611dc5565b9550955095509550955050836001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610db6573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610dda9190611d7f565b6001600160a01b0316896001600160a01b031614610e1e57604051631469fe1360e21b81526001600160a01b03808b166004830152851660248201526044016101d7565b826001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e5a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e7e9190611d7f565b6001600160a01b0316886001600160a01b031614610ec257604051631469fe1360e21b81526001600160a01b03808a166004830152841660248201526044016101d7565b604051633e64ce9960e01b81525f906001600160a01b03861690633e64ce9990610ef69086908c9086903090600401611d9a565b6020604051808303815f875af1158015610f12573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f3691906117fe565b90505f61108e856001600160a01b0316634fb3ccc56040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f78573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f9c9190611d7f565b604051634104b9ed60e11b81526001600160a01b038781166004830152919091169063820973da90602401602060405180830381865afa158015610fe2573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061100691906117fe565b7f000000000000000000000000f632c10b19f2a0451cd4a653fc9ca0c15ea1040b6001600160a01b031663b7d122b56040518163ffffffff1660e01b8152600401602060405180830381865afa158015611062573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061108691906117fe565b8a9190611268565b905061109a8183611b81565b91506110b06001600160a01b0385168b8361128b565b6040516304eaba2160e51b81526001600160a01b03861690639d574420906110e290879085908d903090600401611d9a565b6020604051808303815f875af11580156110fe573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061112291906117fe565b505081156111435761113e6001600160a01b0384168783610ac7565b611157565b6111576001600160a01b0384168b83610ac7565b60405163095ea7b360e01b81526001600160a01b037f000000000000000000000000f632c10b19f2a0451cd4a653fc9ca0c15ea1040b81166004830152602482018990528a169063095ea7b3906044016020604051808303815f875af11580156111c3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111e79190611b0c565b50505050505050505050505050565b60605f80846001600160a01b0316846040516112129190611e41565b5f60405180830381855af49150503d805f811461124a576040519150601f19603f3d011682016040523d82523d5f602084013e61124f565b606091505b509150915061125f858383611313565b95945050505050565b5f825f19048411830215820261127c575f80fd5b50910281810615159190040190565b5f60405163095ea7b360e01b81526001600160a01b038416600482015282602482015260205f6044835f895af191505080601f3d1160015f5114161516156112d55750823b153d17155b80610b505760405162461bcd60e51b815260206004820152600e60248201526d1054141493d59157d1905253115160921b60448201526064016101d7565b6060826113285761132382611372565b61136b565b815115801561133f57506001600160a01b0384163b155b1561136857604051639996b31560e01b81526001600160a01b03851660048201526024016101d7565b50805b9392505050565b80511561138157805160208201fd5b60405163d6bda27560e01b815260040160405180910390fd5b50565b60408051610100810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915290565b6001600160a01b038116811461139a575f80fd5b5f8060408385031215611405575f80fd5b8235611410816113e0565b946020939093013593505050565b8035611429816113e0565b919050565b5f805f805f805f60c0888a031215611444575f80fd5b873561144f816113e0565b9650602088013561145f816113e0565b9550604088013561146f816113e0565b9450606088013593506080880135925060a088013567ffffffffffffffff80821115611499575f80fd5b818a0191508a601f8301126114ac575f80fd5b8135818111156114ba575f80fd5b8b60208285010111156114cb575f80fd5b60208301945080935050505092959891949750929550565b5f61010082840312156114f4575f80fd5b50919050565b5f80610120838503121561150c575f80fd5b61151684846114e3565b9150610100830135611527816113e0565b809150509250929050565b5f60208284031215611542575f80fd5b813561136b816113e0565b5f805f806101608587031215611561575f80fd5b61156b86866114e3565b935061010085013561157c816113e0565b925061012085013561158d816113e0565b915061014085013561159e816113e0565b939692955090935050565b5f80602083850312156115ba575f80fd5b823567ffffffffffffffff808211156115d1575f80fd5b818501915085601f8301126115e4575f80fd5b8135818111156115f2575f80fd5b8660208260051b8501011115611606575f80fd5b60209290920196919550909350505050565b5f5b8381101561163257818101518382015260200161161a565b50505f910152565b5f8151808452611651816020860160208601611618565b601f01601f19169290920160200192915050565b5f602080830181845280855180835260408601915060408160051b87010192508387015f5b828110156116b857603f198886030184526116a685835161163a565b9450928501929085019060010161168a565b5092979650505050505050565b5f8083601f8401126116d5575f80fd5b50813567ffffffffffffffff8111156116ec575f80fd5b6020830191508360208260081b8501011115611706575f80fd5b9250929050565b5f805f6040848603121561171f575f80fd5b833567ffffffffffffffff811115611735575f80fd5b611741868287016116c5565b9094509250506020840135611755816113e0565b809150509250925092565b5f805f805f60808688031215611774575f80fd5b853567ffffffffffffffff81111561178a575f80fd5b611796888289016116c5565b90965094505060208601356117aa816113e0565b925060408601356117ba816113e0565b915060608601356117ca816113e0565b809150509295509295909350565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b5f6020828403121561180e575f80fd5b5051919050565b803560028110611429575f80fd5b5f60208284031215611833575f80fd5b61136b82611815565b634e487b7160e01b5f52602160045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b80356001600160601b0381168114611429575f80fd5b80356001600160801b0381168114611429575f80fd5b803564ffffffffff81168114611429575f80fd5b803562ffffff81168114611429575f80fd5b5f6101008083850312156118c8575f80fd5b6040519081019067ffffffffffffffff821181831017156118f757634e487b7160e01b5f52604160045260245ffd5b8160405261190484611864565b81526119126020850161141e565b60208201526119236040850161141e565b60408201526119346060850161187a565b60608201526119456080850161187a565b608082015261195660a08501611890565b60a082015261196760c085016118a4565b60c082015261197860e085016118a4565b60e0820152949350505050565b634e487b7160e01b5f52603260045260245ffd5b600281106119b557634e487b7160e01b5f52602160045260245ffd5b9052565b608081016119c78287611999565b6001600160a01b0394851660208301529290931660408401521515606090920191909152919050565b606080825284518282018190525f9190608090818501906020808a01865b83811015611aa457815180516001600160601b03168652838101516001600160a01b039081168588015260408083015190911690870152878101516001600160801b039081168988015287820151168787015260a08082015164ffffffffff169087015260c08082015162ffffff9081169188019190915260e09182015116908601526101009094019390820190600101611a0e565b50508683039087015250611ab8818861163a565b9350505050610abf60408301846001600160a01b03169052565b6001600160a01b0393841681529190921660208201526001600160e01b0319909116604082015260600190565b801515811461139a575f80fd5b5f60208284031215611b1c575f80fd5b815161136b81611aff565b60c08101611b358289611999565b6001600160a01b039687166020830152948616604082015292851660608401529316608082015291151560a090920191909152919050565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561084357610843611b6d565b5f808335601e19843603018112611ba9575f80fd5b83018035915067ffffffffffffffff821115611bc3575f80fd5b602001915036819003821315611706575f80fd5b828482375f8382015f81528351611bf2818360208801611618565b0195945050505050565b5f60018201611c0d57611c0d611b6d565b5060010190565b60608082528181018590525f90608080840188845b89811015611d05576001600160601b03611c4283611864565b168352602080830135611c54816113e0565b6001600160a01b031690840152604082810135611c70816113e0565b6001600160a01b031690840152611c8882860161187a565b6001600160801b031685840152611ca082850161187a565b6001600160801b03168484015260a0611cba838201611890565b64ffffffffff169084015260c0611cd28382016118a4565b62ffffff169084015260e0611ce88382016118a4565b62ffffff1690840152610100928301929190910190600101611c29565b50508481036020860152611d19818861163a565b935050505061125f60408301846001600160a01b03169052565b5f805f8060808587031215611d46575f80fd5b611d4f85611815565b93506020850135611d5f816113e0565b92506040850135611d6f816113e0565b9150606085013561159e81611aff565b5f60208284031215611d8f575f80fd5b815161136b816113e0565b6001600160a01b03948516815260208101939093526040830191909152909116606082015260800190565b5f805f805f8060c08789031215611dda575f80fd5b611de387611815565b95506020870135611df3816113e0565b94506040870135611e03816113e0565b93506060870135611e13816113e0565b92506080870135611e23816113e0565b915060a0870135611e3381611aff565b809150509295509295509295565b5f8251611e52818460208701611618565b919091019291505056fea26469706673582212205f6034f2c1792be5f3ab06a566c42a514f4b675002e83b42654158df0f8f1f8064736f6c63430008150033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000771263e3bc6acda5ae388a3f8a0c2dd7a17275fc0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f632c10b19f2a0451cd4a653fc9ca0c15ea1040b
-----Decoded View---------------
Arg [0] : _owner (address): 0x771263e3Bc6aCDa5aE388A3F8A0c2dd7A17275FC
Arg [1] : _auth (address): 0x0000000000000000000000000000000000000000
Arg [2] : _queue (address): 0xF632c10b19f2a0451cD4A653fC9ca0c15eA1040b
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000771263e3bc6acda5ae388a3f8a0c2dd7a17275fc
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [2] : 000000000000000000000000f632c10b19f2a0451cd4a653fc9ca0c15ea1040b
Deployed Bytecode Sourcemap
584:10022:27:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2164:210;;;;;;:::i;:::-;;:::i;:::-;;5377:998;;;;;;:::i;:::-;;:::i;3758:535::-;;;;;;:::i;:::-;;:::i;1523:434:18:-;;;;;;:::i;:::-;;:::i;562:20::-;;;;;-1:-1:-1;;;;;562:20:18;;;;;;-1:-1:-1;;;;;2939:32:33;;;2921:51;;2909:2;2894:18;562:20:18;;;;;;;;4543:656:27;;;;;;:::i;:::-;;:::i;1224:484:9:-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;2563:318:27:-;;;;;;:::i;:::-;;:::i;589:26:18:-;;;;;-1:-1:-1;;;;;589:26:18;;;1963:164;;;;;;:::i;:::-;;:::i;3119:439:27:-;;;;;;:::i;:::-;;:::i;2164:210::-;902:33:18;915:10;927:7;;-1:-1:-1;;;;;;927:7:18;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:18;;;;;;;:::i;:::-;;;;;;;;;-1:-1:-1;;2251:6:27::1;:27:::0;2247:72:::1;;2289:30;::::0;-1:-1:-1;;;2289:30:27;;2313:4:::1;2289:30;::::0;::::1;2921:51:33::0;-1:-1:-1;;;;;2289:15:27;::::1;::::0;::::1;::::0;2894:18:33;;2289:30:27::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2280:39;;2247:72;2329:38;-1:-1:-1::0;;;;;2329:18:27;::::1;2348:10;2360:6:::0;2329:18:::1;:38::i;:::-;2164:210:::0;;:::o;5377:998::-;902:33:18;915:10;927:7;;-1:-1:-1;;;;;;927:7:18;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:18;;;;;;;:::i;:::-;5619:10:27::1;-1:-1:-1::0;;;;;5641:5:27::1;5619:28;;5615:67;;5656:26;;-1:-1:-1::0;;;5656:26:27::1;;;;;;;;;;;5615:67;-1:-1:-1::0;;;;;5696:26:27;::::1;5717:4;5696:26;5692:70;;5731:31;;-1:-1:-1::0;;;5731:31:27::1;;;;;;;;;;;5692:70;5773:19;5795:34;::::0;;::::1;5806:9:::0;5795:34:::1;:::i;:::-;5773:56:::0;-1:-1:-1;5857:23:27::1;5844:9;:36;;;;;;;;:::i;:::-;::::0;5840:529:::1;;5896:83;5915:9;;5926:11;5939:10;5951:11;5964:14;5896:18;:83::i;:::-;5840:529;;;6013:28;6000:9;:41;;;;;;;;:::i;:::-;::::0;5996:373:::1;;6057:87;6080:9;;6091:11;6104:10;6116:11;6129:14;6057:22;:87::i;5996:373::-;6328:30;;-1:-1:-1::0;;;6328:30:27::1;;;;;;;;;;;5996:373;5605:770;5377:998:::0;;;;;;;:::o;3758:535::-;902:33:18;915:10;927:7;;-1:-1:-1;;;;;;927:7:18;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:18;;;;;;;:::i;:::-;3930:10:27::1;3914:12;::::0;;;::::1;::::0;::::1;;:::i;:::-;-1:-1:-1::0;;;;;3914:26:27::1;;3910:64;;3949:25;;-1:-1:-1::0;;;3949:25:27::1;;;;;;;;;;;3910:64;4040:43;::::0;;4081:1:::1;4040:43:::0;;;;;::::1;::::0;;;3985:52:::1;::::0;4040:43:::1;;;;;;:::i;:::-;;;;;;;;;;;;;;;-1:-1:-1::0;3985:98:27;-1:-1:-1;4093:21:27::1;;::::0;;::::1;::::0;::::1;4107:7:::0;4093:21:::1;:::i;:::-;:8;4102:1;4093:11;;;;;;;;:::i;:::-;;;;;;:21;;;;4125:22;4161:23:::0;4186:10:::1;4198:6;4206:5;4150:62;;;;;;;;;;;:::i;:::-;;::::0;;-1:-1:-1;;4150:62:27;;::::1;::::0;;;;;;;-1:-1:-1;;;4223:63:27;;4150:62;-1:-1:-1;;;;;;4223:5:27::1;:27;::::0;::::1;::::0;:63:::1;::::0;4251:8;;4150:62;;4280:4:::1;::::0;4223:63:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;1523:434:18::0;1794:5;;-1:-1:-1;;;;;1794:5:18;1780:10;:19;;:76;;-1:-1:-1;1803:9:18;;:53;;-1:-1:-1;;;1803:53:18;;-1:-1:-1;;;;;1803:9:18;;;;:17;;:53;;1821:10;;1841:4;;-1:-1:-1;;;;;;1803:9:18;1848:7;;;1803:53;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1772:85;;;;;;1868:9;:24;;-1:-1:-1;;;;;;1868:24:18;-1:-1:-1;;;;;1868:24:18;;;;;;;;1908:42;;1925:10;;1908:42;;-1:-1:-1;;1908:42:18;1523:434;:::o;4543:656:27:-;902:33:18;915:10;927:7;;-1:-1:-1;;;;;;927:7:18;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:18;;;;;;;:::i;:::-;4786:10:27::1;4770:12;::::0;;;::::1;::::0;::::1;;:::i;:::-;-1:-1:-1::0;;;;;4770:26:27::1;;4766:64;;4805:25;;-1:-1:-1::0;;;4805:25:27::1;;;;;;;;;;;4766:64;4896:43;::::0;;4937:1:::1;4896:43:::0;;;;;::::1;::::0;;;4841:52:::1;::::0;4896:43:::1;;;;;;:::i;:::-;;;;;;;;;;;;;;;-1:-1:-1::0;4841:98:27;-1:-1:-1;4949:21:27::1;;::::0;;::::1;::::0;::::1;4963:7:::0;4949:21:::1;:::i;:::-;:8;4958:1;4949:11;;;;;;;;:::i;:::-;;;;;;:21;;;;4981:22;5029:28;5059:10;5071;5083:8;5093:17;5112:5;5018:100;;;;;;;;;;;;;:::i;:::-;;::::0;;-1:-1:-1;;5018:100:27;;::::1;::::0;;;;;;;-1:-1:-1;;;5129:63:27;;5018:100;-1:-1:-1;;;;;;5129:5:27::1;:27;::::0;::::1;::::0;:63:::1;::::0;5157:8;;5018:100;;5186:4:::1;::::0;5129:63:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;4756:443;;4543:656:::0;;;;:::o;1224:484:9:-;1390:12;;;1326:20;1390:12;;;;;;;;1292:22;;1501:4;1489:24;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1479:34;;1528:9;1523:155;1543:15;;;1523:155;;;1592:75;1629:4;1649;;1654:1;1649:7;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;1658;1636:30;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;1592:28;:75::i;:::-;1579:7;1587:1;1579:10;;;;;;;;:::i;:::-;;;;;;:88;;;;1560:3;;;;;:::i;:::-;;;;1523:155;;;;1687:14;1224:484;;;;;:::o;2563:318:27:-;902:33:18;915:10;927:7;;-1:-1:-1;;;;;;927:7:18;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:18;;;;;;;:::i;:::-;2714:22:27::1;2750:23:::0;2775:10:::1;2787:6;2795:4;2739:61;;;;;;;;;;;:::i;:::-;;::::0;;-1:-1:-1;;2739:61:27;;::::1;::::0;;;;;;;-1:-1:-1;;;2811:63:27;;2739:61;-1:-1:-1;;;;;;2811:5:27::1;:27;::::0;::::1;::::0;:63:::1;::::0;2839:8;;;;2739:61;;2868:4:::1;::::0;2811:63:::1;;;:::i;1963:164:18:-:0;902:33;915:10;927:7;;-1:-1:-1;;;;;;927:7:18;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:18;;;;;;;:::i;:::-;2046:5:::1;:16:::0;;-1:-1:-1;;;;;;2046:16:18::1;-1:-1:-1::0;;;;;2046:16:18;::::1;::::0;;::::1;::::0;;2078:42:::1;::::0;2046:16;;2099:10:::1;::::0;2078:42:::1;::::0;2046:5;2078:42:::1;1963:164:::0;:::o;3119:439:27:-;902:33:18;915:10;927:7;;-1:-1:-1;;;;;;927:7:18;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:18;;;;;;;:::i;:::-;3341:22:27::1;3389:28;3419:10;3431;3443:8;3453:17;3472:4;3378:99;;;;;;;;;;;;;:::i;:::-;;::::0;;-1:-1:-1;;3378:99:27;;::::1;::::0;;;;;;;-1:-1:-1;;;3488:63:27;;3378:99;-1:-1:-1;;;;;;3488:5:27::1;:27;::::0;::::1;::::0;:63:::1;::::0;3516:8;;;;3378:99;;3545:4:::1;::::0;3488:63:::1;;;:::i;977:540:18:-:0;1097:9;;1064:4;;-1:-1:-1;;;;;1097:9:18;1415:27;;;;;:77;;-1:-1:-1;1446:46:18;;-1:-1:-1;;;1446:46:18;;-1:-1:-1;;;;;1446:12:18;;;;;:46;;1459:4;;1473;;1480:11;;1446:46;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1414:96;;;-1:-1:-1;1505:5:18;;-1:-1:-1;;;;;1497:13:18;;;1505:5;;1497:13;1414:96;1407:103;977:540;-1:-1:-1;;;;977:540:18:o;2832:1464:23:-;2944:12;3114:4;3108:11;-1:-1:-1;;;3237:17:23;3230:93;-1:-1:-1;;;;;3374:2:23;3370:51;3366:1;3347:17;3343:25;3336:86;3508:6;3503:2;3484:17;3480:26;3473:42;3855:2;3852:1;3848:2;3829:17;3826:1;3819:5;3812;3807:51;3796:62;;;4125:7;4118:2;4100:16;4097:24;4093:1;4089;4083:8;4080:15;4076:46;4069:54;4065:68;4062:172;;;-1:-1:-1;4180:18:23;;4173:26;4201:16;4170:48;4163:56;4062:172;4262:7;4254:35;;;;-1:-1:-1;;;4254:35:23;;19624:2:33;4254:35:23;;;19606:21:33;19663:2;19643:18;;;19636:30;-1:-1:-1;;;19682:18:33;;;19675:45;19737:18;;4254:35:23;19422:339:33;4254:35:23;2934:1362;2832:1464;;;:::o;6595:1279:27:-;6803:20;;;6896:78;;;;6907:9;6896:78;:::i;:::-;6800:174;;;;;;;7012:6;-1:-1:-1;;;;;7012:12:27;;:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;6989:38:27;:11;-1:-1:-1;;;;;6989:38:27;;6985:146;;7050:70;;-1:-1:-1;;;7050:70:27;;-1:-1:-1;;;;;20963:15:33;;;7050:70:27;;;20945:34:33;21015:15;;20995:18;;;20988:43;20880:18;;7050:70:27;20733:304:33;6985:146:27;7261:70;;-1:-1:-1;;;7261:70:27;;7161:10;;7141:11;;-1:-1:-1;;;;;7261:19:27;;;;;:70;;7161:10;;7288:11;;7301:14;;7325:4;;7261:70;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7241:90;;7559:14;7555:195;;;7589:60;7608:12;7622:26;7634:14;7622:9;:26;:::i;:::-;-1:-1:-1;;;;;7589:18:27;;;:60;:18;:60::i;:::-;7555:195;;;7680:59;7699:11;7712:26;7724:14;7712:9;:26;:::i;7680:59::-;7822:45;;-1:-1:-1;;;7822:45:27;;-1:-1:-1;;;;;7844:5:27;21700:32:33;;7822:45:27;;;21682:51:33;21749:18;;;21742:34;;;7822:13:27;;;;;21655:18:33;;7822:45:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;6790:1084;;;;;6595:1279;;;;;;:::o;8032:2572::-;8276:20;;;;;8481:136;;;;8505:9;8481:136;:::i;:::-;8248:369;;;;;;;;;;;8659:10;-1:-1:-1;;;;;8659:16:27;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;8632:46:27;:15;-1:-1:-1;;;;;8632:46:27;;8628:162;;8701:78;;-1:-1:-1;;;8701:78:27;;-1:-1:-1;;;;;20963:15:33;;;8701:78:27;;;20945:34:33;21015:15;;20995:18;;;20988:43;20880:18;;8701:78:27;20733:304:33;8628:162:27;8829:8;-1:-1:-1;;;;;8829:14:27;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;8804:42:27;:13;-1:-1:-1;;;;;8804:42:27;;8800:154;;8869:74;;-1:-1:-1;;;8869:74:27;;-1:-1:-1;;;;;20963:15:33;;;8869:74:27;;;20945:34:33;21015:15;;20995:18;;;20988:43;20880:18;;8869:74:27;20733:304:33;8800:154:27;9056:73;;-1:-1:-1;;;9056:73:27;;9033:20;;-1:-1:-1;;;;;9056:23:27;;;;;:73;;9080:17;;9099:11;;9033:20;;9123:4;;9056:73;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;9033:96;;9364:34;9401:153;9442:8;-1:-1:-1;;;;;9442:19:27;;:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:59;;-1:-1:-1;;;9442:59:27;;-1:-1:-1;;;;;2939:32:33;;;9442:59:27;;;2921:51:33;9442:40:27;;;;;;;2894:18:33;;9442:59:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;9522:5;-1:-1:-1;;;;;9503:35:27;;:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;9401:14;;:153;:23;:153::i;:::-;9364:190;-1:-1:-1;9652:41:27;9364:190;9652:12;:41;:::i;:::-;9637:56;-1:-1:-1;9778:72:27;-1:-1:-1;;;;;9778:29:27;;9808:13;9823:26;9778:29;:72::i;:::-;9933:98;;-1:-1:-1;;;9933:98:27;;-1:-1:-1;;;;;9933:20:27;;;;;:98;;9954:17;;9973:26;;10001:14;;10025:4;;9933:98;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;9139:903;10274:14;10270:195;;;10304:58;-1:-1:-1;;;;;10304:30:27;;10335:12;10349;10304:30;:58::i;:::-;10270:195;;;10393:61;-1:-1:-1;;;;;10393:30:27;;10424:15;10441:12;10393:30;:61::i;:::-;10537:60;;-1:-1:-1;;;10537:60:27;;-1:-1:-1;;;;;10574:5:27;21700:32:33;;10537:60:27;;;21682:51:33;21749:18;;;21742:34;;;10537:28:27;;;;;21655:18:33;;10537:60:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;8238:2366;;;;;;8032:2572;;;;;;:::o;3916:253:4:-;3999:12;4024;4038:23;4065:6;-1:-1:-1;;;;;4065:19:4;4085:4;4065:25;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4023:67;;;;4107:55;4134:6;4142:7;4151:10;4107:26;:55::i;:::-;4100:62;3916:253;-1:-1:-1;;;;;3916:253:4:o;2096:672:21:-;2210:9;2458:1;-1:-1:-1;;2441:19:21;2438:1;2435:26;2432:1;2428:34;2421:42;2408:11;2404:60;2394:116;;2494:1;2491;2484:12;2394:116;-1:-1:-1;2728:9:21;;2691:27;;;2688:34;;2724:27;;;2684:68;;2096:672::o;4302:1462:23:-;4413:12;4583:4;4577:11;-1:-1:-1;;;4706:17:23;4699:93;-1:-1:-1;;;;;4843:2:23;4839:51;4835:1;4816:17;4812:25;4805:86;4977:6;4972:2;4953:17;4949:26;4942:42;5324:2;5321:1;5317:2;5298:17;5295:1;5288:5;5281;5276:51;5265:62;;;5594:7;5587:2;5569:16;5566:24;5562:1;5558;5552:8;5549:15;5545:46;5538:54;5534:68;5531:172;;;-1:-1:-1;5649:18:23;;5642:26;5670:16;5639:48;5632:56;5531:172;5731:7;5723:34;;;;-1:-1:-1;;;5723:34:23;;24309:2:33;5723:34:23;;;24291:21:33;24348:2;24328:18;;;24321:30;-1:-1:-1;;;24367:18:33;;;24360:44;24421:18;;5723:34:23;24107:338:33;4437:582:4;4581:12;4610:7;4605:408;;4633:19;4641:10;4633:7;:19::i;:::-;4605:408;;;4857:17;;:22;:49;;;;-1:-1:-1;;;;;;4883:18:4;;;:23;4857:49;4853:119;;;4933:24;;-1:-1:-1;;;4933:24:4;;-1:-1:-1;;;;;2939:32:33;;4933:24:4;;;2921:51:33;2894:18;;4933:24:4;2775:203:33;4853:119:4;-1:-1:-1;4992:10:4;4605:408;4437:582;;;;;:::o;5559:434::-;5690:17;;:21;5686:301;;5894:10;5888:17;5881:4;5869:10;5865:21;5858:48;5686:301;5957:19;;-1:-1:-1;;;5957:19:4;;;;;;;;;;;5686:301;5559:434;:::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;14:138:33:-;-1:-1:-1;;;;;96:31:33;;86:42;;76:70;;142:1;139;132:12;157:336;239:6;247;300:2;288:9;279:7;275:23;271:32;268:52;;;316:1;313;306:12;268:52;355:9;342:23;374:38;406:5;374:38;:::i;:::-;431:5;483:2;468:18;;;;455:32;;-1:-1:-1;;;157:336:33:o;498:141::-;566:20;;595:38;566:20;595:38;:::i;:::-;498:141;;;:::o;644:1168::-;759:6;767;775;783;791;799;807;860:3;848:9;839:7;835:23;831:33;828:53;;;877:1;874;867:12;828:53;916:9;903:23;935:38;967:5;935:38;:::i;:::-;992:5;-1:-1:-1;1049:2:33;1034:18;;1021:32;1062:40;1021:32;1062:40;:::i;:::-;1121:7;-1:-1:-1;1180:2:33;1165:18;;1152:32;1193:40;1152:32;1193:40;:::i;:::-;1252:7;-1:-1:-1;1306:2:33;1291:18;;1278:32;;-1:-1:-1;1357:3:33;1342:19;;1329:33;;-1:-1:-1;1413:3:33;1398:19;;1385:33;1437:18;1467:14;;;1464:34;;;1494:1;1491;1484:12;1464:34;1532:6;1521:9;1517:22;1507:32;;1577:7;1570:4;1566:2;1562:13;1558:27;1548:55;;1599:1;1596;1589:12;1548:55;1639:2;1626:16;1665:2;1657:6;1654:14;1651:34;;;1681:1;1678;1671:12;1651:34;1726:7;1721:2;1712:6;1708:2;1704:15;1700:24;1697:37;1694:57;;;1747:1;1744;1737:12;1694:57;1778:2;1774;1770:11;1760:21;;1800:6;1790:16;;;;;644:1168;;;;;;;;;;:::o;1817:164::-;1885:5;1930:3;1921:6;1916:3;1912:16;1908:26;1905:46;;;1947:1;1944;1937:12;1905:46;-1:-1:-1;1969:6:33;1817:164;-1:-1:-1;1817:164:33:o;1986:398::-;2089:6;2097;2150:3;2138:9;2129:7;2125:23;2121:33;2118:53;;;2167:1;2164;2157:12;2118:53;2190:62;2244:7;2233:9;2190:62;:::i;:::-;2180:72;;2302:3;2291:9;2287:19;2274:33;2316:38;2348:5;2316:38;:::i;:::-;2373:5;2363:15;;;1986:398;;;;;:::o;2389:272::-;2466:6;2519:2;2507:9;2498:7;2494:23;2490:32;2487:52;;;2535:1;2532;2525:12;2487:52;2574:9;2561:23;2593:38;2625:5;2593:38;:::i;2983:696::-;3104:6;3112;3120;3128;3181:3;3169:9;3160:7;3156:23;3152:33;3149:53;;;3198:1;3195;3188:12;3149:53;3221:62;3275:7;3264:9;3221:62;:::i;:::-;3211:72;;3333:3;3322:9;3318:19;3305:33;3347:38;3379:5;3347:38;:::i;:::-;3404:5;-1:-1:-1;3461:3:33;3446:19;;3433:33;3475:40;3433:33;3475:40;:::i;:::-;3534:7;-1:-1:-1;3593:3:33;3578:19;;3565:33;3607:40;3565:33;3607:40;:::i;:::-;2983:696;;;;-1:-1:-1;2983:696:33;;-1:-1:-1;;2983:696:33:o;3684:626::-;3781:6;3789;3842:2;3830:9;3821:7;3817:23;3813:32;3810:52;;;3858:1;3855;3848:12;3810:52;3898:9;3885:23;3927:18;3968:2;3960:6;3957:14;3954:34;;;3984:1;3981;3974:12;3954:34;4022:6;4011:9;4007:22;3997:32;;4067:7;4060:4;4056:2;4052:13;4048:27;4038:55;;4089:1;4086;4079:12;4038:55;4129:2;4116:16;4155:2;4147:6;4144:14;4141:34;;;4171:1;4168;4161:12;4141:34;4224:7;4219:2;4209:6;4206:1;4202:14;4198:2;4194:23;4190:32;4187:45;4184:65;;;4245:1;4242;4235:12;4184:65;4276:2;4268:11;;;;;4298:6;;-1:-1:-1;3684:626:33;;-1:-1:-1;;;;3684:626:33:o;4315:250::-;4400:1;4410:113;4424:6;4421:1;4418:13;4410:113;;;4500:11;;;4494:18;4481:11;;;4474:39;4446:2;4439:10;4410:113;;;-1:-1:-1;;4557:1:33;4539:16;;4532:27;4315:250::o;4570:270::-;4611:3;4649:5;4643:12;4676:6;4671:3;4664:19;4692:76;4761:6;4754:4;4749:3;4745:14;4738:4;4731:5;4727:16;4692:76;:::i;:::-;4822:2;4801:15;-1:-1:-1;;4797:29:33;4788:39;;;;4829:4;4784:50;;4570:270;-1:-1:-1;;4570:270:33:o;4845:800::-;5005:4;5034:2;5074;5063:9;5059:18;5104:2;5093:9;5086:21;5127:6;5162;5156:13;5193:6;5185;5178:22;5231:2;5220:9;5216:18;5209:25;;5293:2;5283:6;5280:1;5276:14;5265:9;5261:30;5257:39;5243:53;;5331:2;5323:6;5319:15;5352:1;5362:254;5376:6;5373:1;5370:13;5362:254;;;5469:2;5465:7;5453:9;5445:6;5441:22;5437:36;5432:3;5425:49;5497:39;5529:6;5520;5514:13;5497:39;:::i;:::-;5487:49;-1:-1:-1;5594:12:33;;;;5559:15;;;;5398:1;5391:9;5362:254;;;-1:-1:-1;5633:6:33;;4845:800;-1:-1:-1;;;;;;;4845:800:33:o;5650:391::-;5737:8;5747:6;5801:3;5794:4;5786:6;5782:17;5778:27;5768:55;;5819:1;5816;5809:12;5768:55;-1:-1:-1;5842:20:33;;5885:18;5874:30;;5871:50;;;5917:1;5914;5907:12;5871:50;5954:4;5946:6;5942:17;5930:29;;6014:3;6007:4;5997:6;5994:1;5990:14;5982:6;5978:27;5974:38;5971:47;5968:67;;;6031:1;6028;6021:12;5968:67;5650:391;;;;;:::o;6046:638::-;6176:6;6184;6192;6245:2;6233:9;6224:7;6220:23;6216:32;6213:52;;;6261:1;6258;6251:12;6213:52;6301:9;6288:23;6334:18;6326:6;6323:30;6320:50;;;6366:1;6363;6356:12;6320:50;6405:94;6491:7;6482:6;6471:9;6467:22;6405:94;:::i;:::-;6518:8;;-1:-1:-1;6379:120:33;-1:-1:-1;;6603:2:33;6588:18;;6575:32;6616:38;6575:32;6616:38;:::i;:::-;6673:5;6663:15;;;6046:638;;;;;:::o;7174:935::-;7322:6;7330;7338;7346;7354;7407:3;7395:9;7386:7;7382:23;7378:33;7375:53;;;7424:1;7421;7414:12;7375:53;7464:9;7451:23;7497:18;7489:6;7486:30;7483:50;;;7529:1;7526;7519:12;7483:50;7568:94;7654:7;7645:6;7634:9;7630:22;7568:94;:::i;:::-;7681:8;;-1:-1:-1;7542:120:33;-1:-1:-1;;7766:2:33;7751:18;;7738:32;7779:38;7738:32;7779:38;:::i;:::-;7836:5;-1:-1:-1;7893:2:33;7878:18;;7865:32;7906:40;7865:32;7906:40;:::i;:::-;7965:7;-1:-1:-1;8024:2:33;8009:18;;7996:32;8037:40;7996:32;8037:40;:::i;:::-;8096:7;8086:17;;;7174:935;;;;;;;;:::o;8114:336::-;8316:2;8298:21;;;8355:2;8335:18;;;8328:30;-1:-1:-1;;;8389:2:33;8374:18;;8367:42;8441:2;8426:18;;8114:336::o;8455:184::-;8525:6;8578:2;8566:9;8557:7;8553:23;8549:32;8546:52;;;8594:1;8591;8584:12;8546:52;-1:-1:-1;8617:16:33;;8455:184;-1:-1:-1;8455:184:33:o;8644:150::-;8719:20;;8768:1;8758:12;;8748:40;;8784:1;8781;8774:12;8799:208;8873:6;8926:2;8914:9;8905:7;8901:23;8897:32;8894:52;;;8942:1;8939;8932:12;8894:52;8965:36;8991:9;8965:36;:::i;9012:127::-;9073:10;9068:3;9064:20;9061:1;9054:31;9104:4;9101:1;9094:15;9128:4;9125:1;9118:15;9144:127;9205:10;9200:3;9196:20;9193:1;9186:31;9236:4;9233:1;9226:15;9260:4;9257:1;9250:15;9276:179;9343:20;;-1:-1:-1;;;;;9392:38:33;;9382:49;;9372:77;;9445:1;9442;9435:12;9460:188;9528:20;;-1:-1:-1;;;;;9577:46:33;;9567:57;;9557:85;;9638:1;9635;9628:12;9653:165;9720:20;;9780:12;9769:24;;9759:35;;9749:63;;9808:1;9805;9798:12;9823:161;9890:20;;9950:8;9939:20;;9929:31;;9919:59;;9974:1;9971;9964:12;9989:1079;10081:6;10112:3;10156:2;10144:9;10135:7;10131:23;10127:32;10124:52;;;10172:1;10169;10162:12;10124:52;10205:2;10199:9;10235:15;;;;10280:18;10265:34;;10301:22;;;10262:62;10259:185;;;10366:10;10361:3;10357:20;10354:1;10347:31;10401:4;10398:1;10391:15;10429:4;10426:1;10419:15;10259:185;10464:10;10460:2;10453:22;10499:28;10517:9;10499:28;:::i;:::-;10491:6;10484:44;10561:38;10595:2;10584:9;10580:18;10561:38;:::i;:::-;10556:2;10548:6;10544:15;10537:63;10633:38;10667:2;10656:9;10652:18;10633:38;:::i;:::-;10628:2;10620:6;10616:15;10609:63;10705:38;10739:2;10728:9;10724:18;10705:38;:::i;:::-;10700:2;10692:6;10688:15;10681:63;10778:39;10812:3;10801:9;10797:19;10778:39;:::i;:::-;10772:3;10764:6;10760:16;10753:65;10852:38;10885:3;10874:9;10870:19;10852:38;:::i;:::-;10846:3;10838:6;10834:16;10827:64;10925:38;10958:3;10947:9;10943:19;10925:38;:::i;:::-;10919:3;10911:6;10907:16;10900:64;10998:38;11031:3;11020:9;11016:19;10998:38;:::i;:::-;10992:3;10980:16;;10973:64;10984:6;9989:1079;-1:-1:-1;;;;9989:1079:33:o;11073:127::-;11134:10;11129:3;11125:20;11122:1;11115:31;11165:4;11162:1;11155:15;11189:4;11186:1;11179:15;11205:237;11286:1;11279:5;11276:12;11266:143;;11331:10;11326:3;11322:20;11319:1;11312:31;11366:4;11363:1;11356:15;11394:4;11391:1;11384:15;11266:143;11418:18;;11205:237::o;11447:489::-;11672:3;11657:19;;11685:44;11661:9;11711:6;11685:44;:::i;:::-;-1:-1:-1;;;;;11803:15:33;;;11798:2;11783:18;;11776:43;11855:15;;;;11850:2;11835:18;;11828:43;11914:14;11907:22;11902:2;11887:18;;;11880:50;;;;11447:489;;-1:-1:-1;11447:489:33:o;12263:1911::-;12574:2;12626:21;;;12696:13;;12599:18;;;12718:22;;;12545:4;;12574:2;12759:3;;12778:18;;;;12815:4;12842:15;;;12545:4;12885:1124;12899:6;12896:1;12893:13;12885:1124;;;12958:13;;13000:9;;-1:-1:-1;;;;;12996:42:33;12984:55;;13078:11;;;13072:18;-1:-1:-1;;;;;13166:21:33;;;13152:12;;;13145:43;13211:4;13259:11;;;13253:18;13249:27;;;13235:12;;;13228:49;13318:11;;;13312:18;-1:-1:-1;;;;;12007:46:33;;;13378:12;;;11995:59;13432:11;;;13426:18;12007:46;13492:12;;;11995:59;13528:4;13573:11;;;13567:18;12141:12;12130:24;13632:12;;;12118:37;13668:4;13713:11;;;13707:18;12242:8;12231:20;;;13772:12;;;12219:33;;;;13808:4;13853:11;;;13847:18;12231:20;13912:12;;;12219:33;13954:6;13945:16;;;;13984:15;;;;12921:1;12914:9;12885:1124;;;-1:-1:-1;;14045:19:33;;;14025:18;;;14018:47;-1:-1:-1;14082:29:33;14049:3;14099:6;14082:29;:::i;:::-;14074:37;;;;;14120:48;14162:4;14151:9;14147:20;14139:6;-1:-1:-1;;;;;2732:31:33;2720:44;;2666:104;14179:400;-1:-1:-1;;;;;14435:15:33;;;14417:34;;14487:15;;;;14482:2;14467:18;;14460:43;-1:-1:-1;;;;;;14539:33:33;;;14534:2;14519:18;;14512:61;14367:2;14352:18;;14179:400::o;14584:118::-;14670:5;14663:13;14656:21;14649:5;14646:32;14636:60;;14692:1;14689;14682:12;14707:245;14774:6;14827:2;14815:9;14806:7;14802:23;14798:32;14795:52;;;14843:1;14840;14833:12;14795:52;14875:9;14869:16;14894:28;14916:5;14894:28;:::i;14957:651::-;15238:3;15223:19;;15251:44;15227:9;15277:6;15251:44;:::i;:::-;-1:-1:-1;;;;;15369:15:33;;;15364:2;15349:18;;15342:43;15421:15;;;15416:2;15401:18;;15394:43;15473:15;;;15468:2;15453:18;;15446:43;15526:15;;15520:3;15505:19;;15498:44;15586:14;;15579:22;15322:3;15558:19;;;15551:51;;;;15421:15;14957:651;-1:-1:-1;14957:651:33:o;15613:127::-;15674:10;15669:3;15665:20;15662:1;15655:31;15705:4;15702:1;15695:15;15729:4;15726:1;15719:15;15745:128;15812:9;;;15833:11;;;15830:37;;;15847:18;;:::i;16214:521::-;16291:4;16297:6;16357:11;16344:25;16451:2;16447:7;16436:8;16420:14;16416:29;16412:43;16392:18;16388:68;16378:96;;16470:1;16467;16460:12;16378:96;16497:33;;16549:20;;;-1:-1:-1;16592:18:33;16581:30;;16578:50;;;16624:1;16621;16614:12;16578:50;16657:4;16645:17;;-1:-1:-1;16688:14:33;16684:27;;;16674:38;;16671:58;;;16725:1;16722;16715:12;16740:440;16969:6;16961;16956:3;16943:33;16925:3;17004:6;16999:3;16995:16;17031:1;17027:2;17020:13;17062:6;17056:13;17078:65;17136:6;17132:2;17125:4;17117:6;17113:17;17078:65;:::i;:::-;17159:15;;16740:440;-1:-1:-1;;;;;16740:440:33:o;17185:135::-;17224:3;17245:17;;;17242:43;;17265:18;;:::i;:::-;-1:-1:-1;17312:1:33;17301:13;;17185:135::o;17325:2092::-;17648:2;17700:21;;;17673:18;;;17756:22;;;17619:4;;17797:3;17816:18;;;17857:6;17619:4;17891:1359;17905:6;17902:1;17899:13;17891:1359;;;-1:-1:-1;;;;;17970:25:33;17988:6;17970:25;:::i;:::-;17966:58;17961:3;17954:71;18048:4;18103:2;18095:6;18091:15;18078:29;18120:38;18152:5;18120:38;:::i;:::-;-1:-1:-1;;;;;18192:31:33;18178:12;;;18171:53;18247:4;18292:15;;;18279:29;18321:40;18279:29;18321:40;:::i;:::-;-1:-1:-1;;;;;2732:31:33;18402:12;;;2720:44;18448:35;18467:15;;;18448:35;:::i;:::-;-1:-1:-1;;;;;12007:46:33;18529:12;;;11995:59;18577:35;18596:15;;;18577:35;:::i;:::-;-1:-1:-1;;;;;12007:46:33;18660:12;;;11995:59;18696:4;18735:34;18753:15;;;18735:34;:::i;:::-;12141:12;12130:24;18816:12;;;12118:37;18852:4;18891:34;18909:15;;;18891:34;:::i;:::-;12242:8;12231:20;18972:12;;;12219:33;19008:4;19047:34;19065:15;;;19047:34;:::i;:::-;12242:8;12231:20;19128:12;;;12219:33;19164:6;19190:12;;;;19225:15;;;;;17927:1;17920:9;17891:1359;;;17895:3;;19297:9;19292:3;19288:19;19281:4;19270:9;19266:20;19259:49;19325:29;19350:3;19342:6;19325:29;:::i;:::-;19317:37;;;;;19363:48;19405:4;19394:9;19390:20;19382:6;-1:-1:-1;;;;;2732:31:33;2720:44;;2666:104;19766:679;19909:6;19917;19925;19933;19986:3;19974:9;19965:7;19961:23;19957:33;19954:53;;;20003:1;20000;19993:12;19954:53;20026:36;20052:9;20026:36;:::i;:::-;20016:46;;20112:2;20101:9;20097:18;20084:32;20125:38;20157:5;20125:38;:::i;:::-;20182:5;-1:-1:-1;20239:2:33;20224:18;;20211:32;20252:40;20211:32;20252:40;:::i;:::-;20311:7;-1:-1:-1;20370:2:33;20355:18;;20342:32;20383:30;20342:32;20383:30;:::i;20450:278::-;20540:6;20593:2;20581:9;20572:7;20568:23;20564:32;20561:52;;;20609:1;20606;20599:12;20561:52;20641:9;20635:16;20660:38;20692:5;20660:38;:::i;21042:461::-;-1:-1:-1;;;;;21343:15:33;;;21325:34;;21390:2;21375:18;;21368:34;;;;21433:2;21418:18;;21411:34;;;;21481:15;;;21476:2;21461:18;;21454:43;21274:3;21259:19;;21042:461::o;21787:1028::-;21999:6;22007;22015;22023;22031;22039;22092:3;22080:9;22071:7;22067:23;22063:33;22060:53;;;22109:1;22106;22099:12;22060:53;22132:36;22158:9;22132:36;:::i;:::-;22122:46;;22218:2;22207:9;22203:18;22190:32;22231:38;22263:5;22231:38;:::i;:::-;22288:5;-1:-1:-1;22345:2:33;22330:18;;22317:32;22358:40;22317:32;22358:40;:::i;:::-;22417:7;-1:-1:-1;22476:2:33;22461:18;;22448:32;22489:40;22448:32;22489:40;:::i;:::-;22548:7;-1:-1:-1;22607:3:33;22592:19;;22579:33;22621:40;22579:33;22621:40;:::i;:::-;22680:7;-1:-1:-1;22739:3:33;22724:19;;22711:33;22753:30;22711:33;22753:30;:::i;:::-;22802:7;22792:17;;;21787:1028;;;;;;;;:::o;23815:287::-;23944:3;23982:6;23976:13;23998:66;24057:6;24052:3;24045:4;24037:6;24033:17;23998:66;:::i;:::-;24080:16;;;;;23815:287;-1:-1:-1;;23815:287:33:o
Swarm Source
ipfs://5f6034f2c1792be5f3ab06a566c42a514f4b675002e83b42654158df0f8f1f80
Loading...
Loading
Loading...
Loading

Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.