-
Notifications
You must be signed in to change notification settings - Fork 23
/
QuestBudget.json
1 lines (1 loc) · 96.6 KB
/
QuestBudget.json
1
{"language":"Solidity","sources":{"contracts/QuestBudget.sol":{"content":"// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.19;\n\nimport {IQuestFactory} from \"contracts/interfaces/IQuestFactory.sol\";\n\nimport {IERC1155Receiver} from \"openzeppelin-contracts/token/ERC1155/IERC1155Receiver.sol\";\nimport {IERC1155} from \"openzeppelin-contracts/token/ERC1155/IERC1155.sol\";\nimport {IERC165} from \"openzeppelin-contracts/utils/introspection/IERC165.sol\";\n\nimport {SafeTransferLib} from \"solady/utils/SafeTransferLib.sol\";\nimport {ReentrancyGuard} from \"solady/utils/ReentrancyGuard.sol\";\n\nimport {Budget} from \"contracts/references/Budget.sol\";\nimport {Cloneable} from \"contracts/references/Cloneable.sol\";\n\n/// @title Simple Budget\n/// @notice A minimal budget implementation that simply holds and distributes tokens (ERC20-like and native)\n/// @dev This type of budget supports ETH, ERC20, and ERC1155 assets only\ncontract QuestBudget is Budget, IERC1155Receiver, ReentrancyGuard {\n using SafeTransferLib for address;\n\n /// @notice The payload for initializing a SimpleBudget\n struct InitPayload {\n address owner;\n address questFactory;\n address[] authorized;\n }\n\n // @dev The address of the QuestFactory contract\n address public questFactory;\n\n bool public disburseEnabled;\n\n /// @dev The total amount of each fungible asset distributed from the budget\n mapping(address => uint256) private _distributedFungible;\n\n /// @dev The total amount of each ERC1155 asset and token ID distributed from the budget\n mapping(address => mapping(uint256 => uint256)) private _distributedERC1155;\n\n /// @dev The mapping of authorized addresses\n mapping(address => bool) private _isAuthorized;\n\n /// @notice A modifier that allows only authorized addresses to call the function\n modifier onlyAuthorized() {\n if (!isAuthorized(msg.sender)) revert Unauthorized();\n _;\n }\n\n /// @notice Construct a new SimpleBudget\n /// @dev Because this contract is a base implementation, it should not be initialized through the constructor. Instead, it should be cloned and initialized using the {initialize} function.\n constructor() {\n _disableInitializers();\n }\n\n /// @inheritdoc Cloneable\n /// @param data_ The packed init data for the budget `(address owner, address[] authorized)`\n function initialize(bytes calldata data_) public virtual override initializer {\n InitPayload memory init_ = abi.decode(data_, (InitPayload));\n _initializeOwner(init_.owner);\n questFactory = init_.questFactory;\n for (uint256 i = 0; i < init_.authorized.length; i++) {\n _isAuthorized[init_.authorized[i]] = true;\n }\n }\n\n /// @inheritdoc Budget\n /// @notice Allocates assets to the budget\n /// @param data_ The packed data for the {Transfer} request\n /// @return True if the allocation was successful\n /// @dev The caller must have already approved the contract to transfer the asset\n /// @dev If the asset transfer fails, the allocation will revert\n function allocate(bytes calldata data_) external payable virtual override returns (bool) {\n Transfer memory request = abi.decode(data_, (Transfer));\n if (request.assetType == AssetType.ETH) {\n FungiblePayload memory payload = abi.decode(request.data, (FungiblePayload));\n\n // Ensure the value received is equal to the `payload.amount`\n if (msg.value != payload.amount) {\n revert InvalidAllocation(request.asset, payload.amount);\n }\n } else if (request.assetType == AssetType.ERC20) {\n FungiblePayload memory payload = abi.decode(request.data, (FungiblePayload));\n\n // Transfer `payload.amount` of the token to this contract\n request.asset.safeTransferFrom(request.target, address(this), payload.amount);\n if (request.asset.balanceOf(address(this)) < payload.amount) {\n revert InvalidAllocation(request.asset, payload.amount);\n }\n } else if (request.assetType == AssetType.ERC1155) {\n ERC1155Payload memory payload = abi.decode(request.data, (ERC1155Payload));\n\n // Transfer `payload.amount` of `payload.tokenId` to this contract\n IERC1155(request.asset).safeTransferFrom(\n request.target, address(this), payload.tokenId, payload.amount, payload.data\n );\n if (IERC1155(request.asset).balanceOf(address(this), payload.tokenId) < payload.amount) {\n revert InvalidAllocation(request.asset, payload.amount);\n }\n } else {\n // Unsupported asset type\n return false;\n }\n\n return true;\n }\n\n /// @inheritdoc Budget\n /// @notice Reclaims assets from the budget\n /// @param data_ The packed {Transfer} request\n /// @return True if the request was successful\n /// @dev Only the owner can directly reclaim assets from the budget\n /// @dev If the amount is zero, the entire balance of the asset will be transferred to the receiver\n /// @dev If the asset transfer fails, the reclamation will revert\n function reclaim(bytes calldata data_) external virtual override onlyOwner returns (bool) {\n Transfer memory request = abi.decode(data_, (Transfer));\n if (request.assetType == AssetType.ETH || request.assetType == AssetType.ERC20) {\n FungiblePayload memory payload = abi.decode(request.data, (FungiblePayload));\n _transferFungible(\n request.asset, request.target, payload.amount == 0 ? available(request.asset) : payload.amount\n );\n } else if (request.assetType == AssetType.ERC1155) {\n ERC1155Payload memory payload = abi.decode(request.data, (ERC1155Payload));\n _transferERC1155(\n request.asset,\n request.target,\n payload.tokenId,\n payload.amount == 0 ? IERC1155(request.asset).balanceOf(address(this), payload.tokenId) : payload.amount,\n payload.data\n );\n } else {\n return false;\n }\n\n return true;\n }\n\n /// @notice Create an erc20 quest and start it at the same time. The function will transfer the reward amount to the quest contract\n /// @param txHashChainId_ The chain id of the chain the txHash is on\n /// @param rewardTokenAddress_ The contract address of the reward token\n /// @param endTime_ The end time of the quest\n /// @param startTime_ The start time of the quest\n /// @param totalParticipants_ The total amount of participants (accounts) the quest will have\n /// @param rewardAmount_ The reward amount for an erc20 quest\n /// @param questId_ The id of the quest\n /// @param actionType_ The action type for the quest\n /// @param questName_ The name of the quest\n /// @param projectName_ The name of the project/protocol used for the quest\n /// @param referralRewardFee_ The fee amount for referrals. The value is counted against the `rewardAmount`\n /// @return address the quest contract address\n function createERC20Quest(\n uint32 txHashChainId_,\n address rewardTokenAddress_,\n uint256 endTime_,\n uint256 startTime_,\n uint256 totalParticipants_,\n uint256 rewardAmount_,\n string memory questId_,\n string memory actionType_,\n string memory questName_,\n string memory projectName_,\n uint256 referralRewardFee_\n ) public virtual onlyAuthorized returns (address) {\n uint256 maxTotalRewards = totalParticipants_ * rewardAmount_;\n uint256 questFee = uint256(IQuestFactory(questFactory).questFee());\n uint256 referralRewardFee = uint256(IQuestFactory(questFactory).referralRewardFee());\n uint256 maxProtocolReward = (maxTotalRewards * questFee) / 10_000;\n uint256 maxReferralReward = (maxTotalRewards * referralRewardFee) / 10_000;\n uint256 approvalAmount = maxTotalRewards + maxProtocolReward + maxReferralReward;\n rewardTokenAddress_.safeApprove(address(questFactory), approvalAmount);\n return IQuestFactory(questFactory).createERC20Quest(\n txHashChainId_,\n rewardTokenAddress_,\n endTime_,\n startTime_,\n totalParticipants_,\n rewardAmount_,\n questId_,\n actionType_,\n questName_,\n projectName_,\n referralRewardFee_\n );\n }\n\n /// @notice Cancel a quest\n /// @param questId_ The uuid of the quest\n function cancelQuest(string calldata questId_) public virtual onlyOwner() {\n IQuestFactory(questFactory).cancelQuest(questId_);\n }\n \n /// @inheritdoc Budget\n /// @notice Disburses assets from the budget to a single recipient\n /// @param data_ The packed {Transfer} request\n /// @return True if the disbursement was successful\n /// @dev If the asset transfer fails, the disbursement will revert\n function disburse(bytes calldata data_) public virtual override onlyAuthorized returns (bool) {\n if(!disburseEnabled) {\n revert Unauthorized();\n }\n Transfer memory request = abi.decode(data_, (Transfer));\n if (request.assetType == AssetType.ERC20 || request.assetType == AssetType.ETH) {\n FungiblePayload memory payload = abi.decode(request.data, (FungiblePayload));\n\n uint256 avail = available(request.asset);\n if (payload.amount > avail) {\n revert InsufficientFunds(request.asset, avail, payload.amount);\n }\n\n _transferFungible(request.asset, request.target, payload.amount);\n } else if (request.assetType == AssetType.ERC1155) {\n ERC1155Payload memory payload = abi.decode(request.data, (ERC1155Payload));\n\n uint256 avail = IERC1155(request.asset).balanceOf(address(this), payload.tokenId);\n if (payload.amount > avail) {\n revert InsufficientFunds(request.asset, avail, payload.amount);\n }\n\n _transferERC1155(request.asset, request.target, payload.tokenId, payload.amount, payload.data);\n } else {\n return false;\n }\n\n return true;\n }\n\n /// @inheritdoc Budget\n /// @notice Disburses assets from the budget to multiple recipients\n /// @param data_ The packed array of {Transfer} requests\n /// @return True if all disbursements were successful\n function disburseBatch(bytes[] calldata data_) external virtual override returns (bool) {\n for (uint256 i = 0; i < data_.length; i++) {\n if (!disburse(data_[i])) return false;\n }\n\n return true;\n }\n\n /// @inheritdoc Budget\n function setAuthorized(address[] calldata account_, bool[] calldata authorized_)\n external\n virtual\n override\n onlyOwner\n {\n if (account_.length != authorized_.length) revert LengthMismatch();\n for (uint256 i = 0; i < account_.length; i++) {\n _isAuthorized[account_[i]] = authorized_[i];\n }\n }\n\n /// @inheritdoc Budget\n function isAuthorized(address account_) public view virtual override returns (bool) {\n return _isAuthorized[account_] || account_ == owner();\n }\n\n /// @notice Set the QuestFactory contract address\n /// @param questFactory_ The address of the QuestFactory contract\n function setQuestFactory(address questFactory_) external virtual onlyOwner {\n questFactory = questFactory_;\n }\n\n /// @notice Set the DisburseEnabled flag\n /// @param enabled_ The flag to enable or disable disburse\n function setDisburseEnabled(bool enabled_) external virtual onlyOwner {\n disburseEnabled = enabled_;\n }\n\n /// @inheritdoc Budget\n /// @notice Get the total amount of assets allocated to the budget, including any that have been distributed\n /// @param asset_ The address of the asset\n /// @return The total amount of assets\n /// @dev This is simply the sum of the current balance and the distributed amount\n function total(address asset_) external view virtual override returns (uint256) {\n return available(asset_) + _distributedFungible[asset_];\n }\n\n /// @notice Get the total amount of ERC1155 assets allocated to the budget, including any that have been distributed\n /// @param asset_ The address of the asset\n /// @param tokenId_ The ID of the token\n /// @return The total amount of assets\n function total(address asset_, uint256 tokenId_) external view virtual returns (uint256) {\n return IERC1155(asset_).balanceOf(address(this), tokenId_) + _distributedERC1155[asset_][tokenId_];\n }\n\n /// @inheritdoc Budget\n /// @notice Get the amount of assets available for distribution from the budget\n /// @param asset_ The address of the asset (or the zero address for native assets)\n /// @return The amount of assets available\n /// @dev This is simply the current balance held by the budget\n /// @dev If the zero address is passed, this function will return the native balance\n function available(address asset_) public view virtual override returns (uint256) {\n return asset_ == address(0) ? address(this).balance : asset_.balanceOf(address(this));\n }\n\n /// @notice Get the amount of ERC1155 assets available for distribution from the budget\n /// @param asset_ The address of the asset\n /// @param tokenId_ The ID of the token\n /// @return The amount of assets available\n function available(address asset_, uint256 tokenId_) public view virtual returns (uint256) {\n return IERC1155(asset_).balanceOf(address(this), tokenId_);\n }\n\n /// @inheritdoc Budget\n /// @notice Get the amount of assets that have been distributed from the budget\n /// @param asset_ The address of the asset\n /// @return The amount of assets distributed\n function distributed(address asset_) external view virtual override returns (uint256) {\n return _distributedFungible[asset_];\n }\n\n /// @notice Get the amount of ERC1155 assets that have been distributed from the budget\n /// @param asset_ The address of the asset\n /// @param tokenId_ The ID of the token\n /// @return The amount of assets distributed\n function distributed(address asset_, uint256 tokenId_) external view virtual returns (uint256) {\n return _distributedERC1155[asset_][tokenId_];\n }\n\n /// @inheritdoc Budget\n /// @dev This is a no-op as there is no local balance to reconcile\n function reconcile(bytes calldata) external virtual override returns (uint256) {\n return 0;\n }\n\n /// @notice Transfer assets to the recipient\n /// @param asset_ The address of the asset\n /// @param to_ The address of the recipient\n /// @param amount_ The amount of the asset to transfer\n /// @dev This function is used to transfer assets from the budget to a given recipient (typically an incentive contract)\n /// @dev If the destination address is the zero address, or the transfer fails for any reason, this function will revert\n function _transferFungible(address asset_, address to_, uint256 amount_) internal virtual nonReentrant {\n // Increment the total amount of the asset distributed from the budget\n if (to_ == address(0)) revert TransferFailed(asset_, to_, amount_);\n if (amount_ > available(asset_)) {\n revert InsufficientFunds(asset_, available(asset_), amount_);\n }\n\n _distributedFungible[asset_] += amount_;\n\n // Transfer the asset to the recipient\n if (asset_ == address(0)) {\n SafeTransferLib.safeTransferETH(to_, amount_);\n } else {\n asset_.safeTransfer(to_, amount_);\n }\n\n emit Distributed(asset_, to_, amount_);\n }\n\n function _transferERC1155(address asset_, address to_, uint256 tokenId_, uint256 amount_, bytes memory data_)\n internal\n virtual\n nonReentrant\n {\n // Increment the total amount of the asset distributed from the budget\n if (to_ == address(0)) revert TransferFailed(asset_, to_, amount_);\n if (amount_ > available(asset_, tokenId_)) {\n revert InsufficientFunds(asset_, available(asset_, tokenId_), amount_);\n }\n\n _distributedERC1155[asset_][tokenId_] += amount_;\n\n // Transfer the asset to the recipient\n // wake-disable-next-line reentrancy (`nonReentrant` modifier is applied to the function)\n IERC1155(asset_).safeTransferFrom(address(this), to_, tokenId_, amount_, data_);\n\n emit Distributed(asset_, to_, amount_);\n }\n\n /// @inheritdoc IERC1155Receiver\n /// @dev This contract does not care about the specifics of the inbound token, so we simply return the magic value (i.e. the selector for `onERC1155Received`)\n function onERC1155Received(address, address, uint256, uint256, bytes calldata)\n external\n pure\n override\n returns (bytes4)\n {\n // We don't need to do anything here\n return IERC1155Receiver.onERC1155Received.selector;\n }\n\n /// @inheritdoc IERC1155Receiver\n /// @dev This contract does not care about the specifics of the inbound token, so we simply return the magic value (i.e. the selector for `onERC1155Received`)\n function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata)\n external\n pure\n override\n returns (bytes4)\n {\n // We don't need to do anything here\n return IERC1155Receiver.onERC1155BatchReceived.selector;\n }\n\n /// @inheritdoc Cloneable\n function supportsInterface(bytes4 interfaceId) public view virtual override(Budget, IERC165) returns (bool) {\n return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);\n }\n}"},"contracts/interfaces/IQuestFactory.sol":{"content":"// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.19;\n\ninterface IQuestFactory {\n // Errors\n error AddressAlreadyMinted();\n error AddressNotSigned();\n error AddressZeroNotAllowed();\n error AuthOwnerDiscountToken();\n error Deprecated();\n error Erc20QuestAddressNotSet();\n error InvalidMintFee();\n error MsgValueLessThanQuestNFTFee();\n error OverMaxAllowedToMint();\n error QuestFeeTooHigh();\n error QuestIdUsed();\n error QuestNotQueued();\n error QuestNotStarted();\n error QuestEnded();\n error QuestTypeNotSupported();\n error Reentrancy();\n error ReferralFeeTooHigh();\n error ZeroAddressNotAllowed();\n error QuestAddressMismatch();\n error ClaimFailed();\n error txOriginMismatch();\n\n // Structs\n\n // This struct is used in a mapping - only add new fields to the end\n struct NftQuestFees {\n uint256 fee;\n bool exists;\n }\n\n // This struct is used in a mapping - only add new fields to the end\n struct Quest {\n mapping(address => bool) addressMinted;\n address questAddress;\n uint256 totalParticipants;\n uint256 numberMinted;\n string questType;\n uint40 durationTotal;\n address questCreator;\n address mintFeeRecipient;\n string actionType;\n string questName;\n uint32 txHashChainId;\n uint16 referralRewardFee;\n }\n\n struct QuestData {\n address questAddress;\n address rewardToken;\n bool queued;\n uint16 questFee;\n uint256 startTime;\n uint256 endTime;\n uint256 totalParticipants;\n uint256 numberMinted;\n uint256 redeemedTokens;\n uint256 rewardAmountOrTokenId;\n bool hasWithdrawn;\n }\n\n struct QuestJsonData {\n string actionType;\n string questName;\n uint32 txHashChainId;\n }\n\n struct ClaimData {\n string questId;\n bytes32 hashBytes;\n bytes signature;\n address ref;\n address claimer;\n string extraData;\n }\n\n struct ERC20QuestData {\n uint32 txHashChainId;\n address rewardTokenAddress;\n uint256 endTime;\n uint256 startTime;\n uint256 totalParticipants;\n uint256 rewardAmount;\n string questId;\n string actionType;\n string questName;\n string questType;\n string projectName;\n uint16 referralRewardFee;\n }\n\n struct ERC1155QuestData {\n uint32 txHashChainId;\n address rewardTokenAddress;\n uint256 endTime;\n uint256 startTime;\n uint256 totalParticipants;\n uint256 tokenId;\n string questId;\n string actionType;\n string questName;\n string projectName;\n }\n\n // Events\n event ExtraMintFeeReturned(address indexed recipient, uint256 amount);\n event MintFeeSet(uint256 mintFee);\n event NftQuestFeeListSet(address[] addresses, uint256[] fees);\n event NftQuestFeeSet(uint256 nftQuestFee);\n\n event QuestCancelled(address indexed questAddress, string questId, uint256 endsAt);\n\n event QuestClaimedData(\n address indexed recipient,\n address indexed questAddress,\n string extraData\n );\n event Quest1155Claimed(\n address indexed recipient,\n address indexed questAddress,\n string questId,\n address rewardToken,\n uint256 tokenId\n );\n event QuestClaimed(\n address indexed recipient,\n address indexed questAddress,\n string questId,\n address rewardToken,\n uint256 rewardAmountInWei\n );\n event QuestClaimedReferred(\n address indexed recipient,\n address indexed questAddress,\n string questId,\n address rewardToken,\n uint256 rewardAmountInWeiOrTokenId,\n address referrer,\n uint16 referralFee,\n uint256 mintFeeEthWei\n );\n event QuestClaimReferred(\n address indexed recipient,\n address indexed questAddress,\n string questId,\n address rewardToken,\n uint256 rewardAmountInWeiOrTokenId,\n address referrer,\n uint16 referralFee,\n uint256 mintFeeEthWei,\n uint256 tokenReferralFee,\n uint256 referralClaimAmount\n );\n event MintFeePaid(\n string questId,\n address rabbitHoleAddress,\n uint256 rabbitHoleAmountWei,\n address questCreatorAddress,\n uint256 questCreatorAmountWei,\n address referrerAddress,\n uint256 referrerAmountWei\n );\n event QuestCreated(\n address indexed creator,\n address indexed contractAddress,\n string projectName,\n string questName,\n string questId,\n string questType,\n string actionType,\n uint32 chainId,\n address rewardToken,\n uint256 endTime,\n uint256 startTime,\n uint256 totalParticipants,\n uint256 rewardAmountOrTokenId\n );\n event ReferralFeeSet(uint16 percent);\n\n // Read Functions\n function getAddressMinted(string memory questId_, address address_) external view returns (bool);\n function getNumberMinted(string memory questId_) external view returns (uint256);\n function questData(string memory questId_) external view returns (QuestData memory);\n function questInfo(string memory questId_) external view returns (address, uint256, uint256);\n function recoverSigner(bytes32 hash_, bytes memory signature_) external view returns (address);\n function mintFee() external view returns (uint256);\n function questJsonData(string memory questId_) external view returns (QuestJsonData memory);\n function buildJsonString(\n bytes32 txHash,\n uint32 txHashChainId,\n string memory actionType,\n string memory questName\n ) external pure returns (string memory);\n function questFee() external view returns (uint16);\n function referralRewardFee() external view returns (uint16);\n \n // Create\n function createERC20Boost(\n uint32 txHashChainId_,\n address rewardTokenAddress_,\n uint256 endTime_,\n uint256 startTime_,\n uint256 totalParticipants_,\n uint256 rewardAmount_,\n string memory questId_,\n string memory actionType_,\n string memory questName_,\n string memory projectName_\n ) external returns (address);\n function createERC20Quest(\n uint32 txHashChainId_,\n address rewardTokenAddress_,\n uint256 endTime_,\n uint256 startTime_,\n uint256 totalParticipants_,\n uint256 rewardAmount_,\n string memory questId_,\n string memory actionType_,\n string memory questName_,\n string memory projectName_,\n uint256 referralRewardFee_\n ) external returns (address);\n\n function create1155QuestAndQueue(\n address rewardTokenAddress_,\n uint256 endTime_,\n uint256 startTime_,\n uint256 totalParticipants_,\n uint256 tokenId_,\n string memory questId_,\n string memory\n ) external payable returns (address);\n\n function claimOptimized(bytes calldata signature_, bytes calldata data_) external payable;\n\n function cancelQuest(string calldata questId_) external;\n\n // Set\n function setClaimSignerAddress(address claimSignerAddress_) external;\n function setErc1155QuestAddress(address erc1155QuestAddress_) external;\n function setErc20QuestAddress(address erc20QuestAddress_) external;\n function setMintFee(uint256 mintFee_) external;\n function setDefaultMintFeeRecipient(address mintFeeRecipient_) external;\n function setProtocolFeeRecipient(address protocolFeeRecipient_) external;\n function setQuestFee(uint16 questFee_) external;\n\n // Callbacks\n function withdrawCallback(string calldata questId_, address protocolFeeRecipient_, uint protocolPayout_, address mintFeeRecipient_, uint mintPayout) external;\n}"},"lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev _Available since v3.1._\n */\ninterface IERC1155Receiver is IERC165 {\n /**\n * @dev Handles the receipt of a single ERC1155 token type. This function is\n * called at the end of a `safeTransferFrom` after the balance has been updated.\n *\n * NOTE: To accept the transfer, this must return\n * `bytes4(keccak256(\"onERC1155Received(address,address,uint256,uint256,bytes)\"))`\n * (i.e. 0xf23a6e61, or its own function selector).\n *\n * @param operator The address which initiated the transfer (i.e. msg.sender)\n * @param from The address which previously owned the token\n * @param id The ID of the token being transferred\n * @param value The amount of tokens being transferred\n * @param data Additional data with no specified format\n * @return `bytes4(keccak256(\"onERC1155Received(address,address,uint256,uint256,bytes)\"))` if transfer is allowed\n */\n function onERC1155Received(\n address operator,\n address from,\n uint256 id,\n uint256 value,\n bytes calldata data\n ) external returns (bytes4);\n\n /**\n * @dev Handles the receipt of a multiple ERC1155 token types. This function\n * is called at the end of a `safeBatchTransferFrom` after the balances have\n * been updated.\n *\n * NOTE: To accept the transfer(s), this must return\n * `bytes4(keccak256(\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\"))`\n * (i.e. 0xbc197c81, or its own function selector).\n *\n * @param operator The address which initiated the batch transfer (i.e. msg.sender)\n * @param from The address which previously owned the token\n * @param ids An array containing ids of each token being transferred (order and length must match values array)\n * @param values An array containing amounts of each token being transferred (order and length must match ids array)\n * @param data Additional data with no specified format\n * @return `bytes4(keccak256(\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\"))` if transfer is allowed\n */\n function onERC1155BatchReceived(\n address operator,\n address from,\n uint256[] calldata ids,\n uint256[] calldata values,\n bytes calldata data\n ) external returns (bytes4);\n}\n"},"lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/IERC1155.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\n *\n * _Available since v3.1._\n */\ninterface IERC1155 is IERC165 {\n /**\n * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\n */\n event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\n\n /**\n * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\n * transfers.\n */\n event TransferBatch(\n address indexed operator,\n address indexed from,\n address indexed to,\n uint256[] ids,\n uint256[] values\n );\n\n /**\n * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\n * `approved`.\n */\n event ApprovalForAll(address indexed account, address indexed operator, bool approved);\n\n /**\n * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\n *\n * If an {URI} event was emitted for `id`, the standard\n * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\n * returned by {IERC1155MetadataURI-uri}.\n */\n event URI(string value, uint256 indexed id);\n\n /**\n * @dev Returns the amount of tokens of token type `id` owned by `account`.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n */\n function balanceOf(address account, uint256 id) external view returns (uint256);\n\n /**\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\n *\n * Requirements:\n *\n * - `accounts` and `ids` must have the same length.\n */\n function balanceOfBatch(\n address[] calldata accounts,\n uint256[] calldata ids\n ) external view returns (uint256[] memory);\n\n /**\n * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\n *\n * Emits an {ApprovalForAll} event.\n *\n * Requirements:\n *\n * - `operator` cannot be the caller.\n */\n function setApprovalForAll(address operator, bool approved) external;\n\n /**\n * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\n *\n * See {setApprovalForAll}.\n */\n function isApprovedForAll(address account, address operator) external view returns (bool);\n\n /**\n * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\n *\n * Emits a {TransferSingle} event.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.\n * - `from` must have a balance of tokens of type `id` of at least `amount`.\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\n * acceptance magic value.\n */\n function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;\n\n /**\n * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\n *\n * Emits a {TransferBatch} event.\n *\n * Requirements:\n *\n * - `ids` and `amounts` must have the same length.\n * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\n * acceptance magic value.\n */\n function safeBatchTransferFrom(\n address from,\n address to,\n uint256[] calldata ids,\n uint256[] calldata amounts,\n bytes calldata data\n ) external;\n}\n"},"lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},"lib/solady/src/utils/SafeTransferLib.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)\n/// @author Permit2 operations from (https://github.com/Uniswap/permit2/blob/main/src/libraries/Permit2Lib.sol)\n///\n/// @dev Note:\n/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.\n/// - For ERC20s, this implementation won't check that a token has code,\n/// responsibility is delegated to the caller.\nlibrary SafeTransferLib {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CUSTOM ERRORS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The ETH transfer has failed.\n error ETHTransferFailed();\n\n /// @dev The ERC20 `transferFrom` has failed.\n error TransferFromFailed();\n\n /// @dev The ERC20 `transfer` has failed.\n error TransferFailed();\n\n /// @dev The ERC20 `approve` has failed.\n error ApproveFailed();\n\n /// @dev The Permit2 operation has failed.\n error Permit2Failed();\n\n /// @dev The Permit2 amount must be less than `2**160 - 1`.\n error Permit2AmountOverflow();\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CONSTANTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.\n uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;\n\n /// @dev Suggested gas stipend for contract receiving ETH to perform a few\n /// storage reads and writes, but low enough to prevent griefing.\n uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;\n\n /// @dev The unique EIP-712 domain domain separator for the DAI token contract.\n bytes32 internal constant DAI_DOMAIN_SEPARATOR =\n 0xdbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7;\n\n /// @dev The address for the WETH9 contract on Ethereum mainnet.\n address internal constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;\n\n /// @dev The canonical Permit2 address.\n /// [Github](https://github.com/Uniswap/permit2)\n /// [Etherscan](https://etherscan.io/address/0x000000000022D473030F116dDEE9F6B43aC78BA3)\n address internal constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* ETH OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.\n //\n // The regular variants:\n // - Forwards all remaining gas to the target.\n // - Reverts if the target reverts.\n // - Reverts if the current contract has insufficient balance.\n //\n // The force variants:\n // - Forwards with an optional gas stipend\n // (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).\n // - If the target reverts, or if the gas stipend is exhausted,\n // creates a temporary contract to force send the ETH via `SELFDESTRUCT`.\n // Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.\n // - Reverts if the current contract has insufficient balance.\n //\n // The try variants:\n // - Forwards with a mandatory gas stipend.\n // - Instead of reverting, returns whether the transfer succeeded.\n\n /// @dev Sends `amount` (in wei) ETH to `to`.\n function safeTransferETH(address to, uint256 amount) internal {\n /// @solidity memory-safe-assembly\n assembly {\n if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {\n mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.\n revert(0x1c, 0x04)\n }\n }\n }\n\n /// @dev Sends all the ETH in the current contract to `to`.\n function safeTransferAllETH(address to) internal {\n /// @solidity memory-safe-assembly\n assembly {\n // Transfer all the ETH and check if it succeeded or not.\n if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {\n mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.\n revert(0x1c, 0x04)\n }\n }\n }\n\n /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.\n function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {\n /// @solidity memory-safe-assembly\n assembly {\n if lt(selfbalance(), amount) {\n mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.\n revert(0x1c, 0x04)\n }\n if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {\n mstore(0x00, to) // Store the address in scratch space.\n mstore8(0x0b, 0x73) // Opcode `PUSH20`.\n mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.\n if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.\n }\n }\n }\n\n /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.\n function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {\n /// @solidity memory-safe-assembly\n assembly {\n if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {\n mstore(0x00, to) // Store the address in scratch space.\n mstore8(0x0b, 0x73) // Opcode `PUSH20`.\n mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.\n if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.\n }\n }\n }\n\n /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.\n function forceSafeTransferETH(address to, uint256 amount) internal {\n /// @solidity memory-safe-assembly\n assembly {\n if lt(selfbalance(), amount) {\n mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.\n revert(0x1c, 0x04)\n }\n if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {\n mstore(0x00, to) // Store the address in scratch space.\n mstore8(0x0b, 0x73) // Opcode `PUSH20`.\n mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.\n if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.\n }\n }\n }\n\n /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.\n function forceSafeTransferAllETH(address to) internal {\n /// @solidity memory-safe-assembly\n assembly {\n // forgefmt: disable-next-item\n if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {\n mstore(0x00, to) // Store the address in scratch space.\n mstore8(0x0b, 0x73) // Opcode `PUSH20`.\n mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.\n if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.\n }\n }\n }\n\n /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.\n function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)\n internal\n returns (bool success)\n {\n /// @solidity memory-safe-assembly\n assembly {\n success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)\n }\n }\n\n /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.\n function trySafeTransferAllETH(address to, uint256 gasStipend)\n internal\n returns (bool success)\n {\n /// @solidity memory-safe-assembly\n assembly {\n success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* ERC20 OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.\n /// Reverts upon failure.\n ///\n /// The `from` account must have at least `amount` approved for\n /// the current contract to manage.\n function safeTransferFrom(address token, address from, address to, uint256 amount) internal {\n /// @solidity memory-safe-assembly\n assembly {\n let m := mload(0x40) // Cache the free memory pointer.\n mstore(0x60, amount) // Store the `amount` argument.\n mstore(0x40, to) // Store the `to` argument.\n mstore(0x2c, shl(96, from)) // Store the `from` argument.\n mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.\n // Perform the transfer, reverting upon failure.\n if iszero(\n and( // The arguments of `and` are evaluated from right to left.\n or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)\n )\n ) {\n mstore(0x00, 0x7939f424) // `TransferFromFailed()`.\n revert(0x1c, 0x04)\n }\n mstore(0x60, 0) // Restore the zero slot to zero.\n mstore(0x40, m) // Restore the free memory pointer.\n }\n }\n\n /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.\n ///\n /// The `from` account must have at least `amount` approved for the current contract to manage.\n function trySafeTransferFrom(address token, address from, address to, uint256 amount)\n internal\n returns (bool success)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let m := mload(0x40) // Cache the free memory pointer.\n mstore(0x60, amount) // Store the `amount` argument.\n mstore(0x40, to) // Store the `to` argument.\n mstore(0x2c, shl(96, from)) // Store the `from` argument.\n mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.\n success :=\n and( // The arguments of `and` are evaluated from right to left.\n or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)\n )\n mstore(0x60, 0) // Restore the zero slot to zero.\n mstore(0x40, m) // Restore the free memory pointer.\n }\n }\n\n /// @dev Sends all of ERC20 `token` from `from` to `to`.\n /// Reverts upon failure.\n ///\n /// The `from` account must have their entire balance approved for the current contract to manage.\n function safeTransferAllFrom(address token, address from, address to)\n internal\n returns (uint256 amount)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let m := mload(0x40) // Cache the free memory pointer.\n mstore(0x40, to) // Store the `to` argument.\n mstore(0x2c, shl(96, from)) // Store the `from` argument.\n mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.\n // Read the balance, reverting upon failure.\n if iszero(\n and( // The arguments of `and` are evaluated from right to left.\n gt(returndatasize(), 0x1f), // At least 32 bytes returned.\n staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)\n )\n ) {\n mstore(0x00, 0x7939f424) // `TransferFromFailed()`.\n revert(0x1c, 0x04)\n }\n mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.\n amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.\n // Perform the transfer, reverting upon failure.\n if iszero(\n and( // The arguments of `and` are evaluated from right to left.\n or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)\n )\n ) {\n mstore(0x00, 0x7939f424) // `TransferFromFailed()`.\n revert(0x1c, 0x04)\n }\n mstore(0x60, 0) // Restore the zero slot to zero.\n mstore(0x40, m) // Restore the free memory pointer.\n }\n }\n\n /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.\n /// Reverts upon failure.\n function safeTransfer(address token, address to, uint256 amount) internal {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x14, to) // Store the `to` argument.\n mstore(0x34, amount) // Store the `amount` argument.\n mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.\n // Perform the transfer, reverting upon failure.\n if iszero(\n and( // The arguments of `and` are evaluated from right to left.\n or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n )\n ) {\n mstore(0x00, 0x90b8ec18) // `TransferFailed()`.\n revert(0x1c, 0x04)\n }\n mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.\n }\n }\n\n /// @dev Sends all of ERC20 `token` from the current contract to `to`.\n /// Reverts upon failure.\n function safeTransferAll(address token, address to) internal returns (uint256 amount) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.\n mstore(0x20, address()) // Store the address of the current contract.\n // Read the balance, reverting upon failure.\n if iszero(\n and( // The arguments of `and` are evaluated from right to left.\n gt(returndatasize(), 0x1f), // At least 32 bytes returned.\n staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)\n )\n ) {\n mstore(0x00, 0x90b8ec18) // `TransferFailed()`.\n revert(0x1c, 0x04)\n }\n mstore(0x14, to) // Store the `to` argument.\n amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.\n mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.\n // Perform the transfer, reverting upon failure.\n if iszero(\n and( // The arguments of `and` are evaluated from right to left.\n or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n )\n ) {\n mstore(0x00, 0x90b8ec18) // `TransferFailed()`.\n revert(0x1c, 0x04)\n }\n mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.\n }\n }\n\n /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.\n /// Reverts upon failure.\n function safeApprove(address token, address to, uint256 amount) internal {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x14, to) // Store the `to` argument.\n mstore(0x34, amount) // Store the `amount` argument.\n mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.\n // Perform the approval, reverting upon failure.\n if iszero(\n and( // The arguments of `and` are evaluated from right to left.\n or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n )\n ) {\n mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.\n revert(0x1c, 0x04)\n }\n mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.\n }\n }\n\n /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.\n /// If the initial attempt to approve fails, attempts to reset the approved amount to zero,\n /// then retries the approval again (some tokens, e.g. USDT, requires this).\n /// Reverts upon failure.\n function safeApproveWithRetry(address token, address to, uint256 amount) internal {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x14, to) // Store the `to` argument.\n mstore(0x34, amount) // Store the `amount` argument.\n mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.\n // Perform the approval, retrying upon failure.\n if iszero(\n and( // The arguments of `and` are evaluated from right to left.\n or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n )\n ) {\n mstore(0x34, 0) // Store 0 for the `amount`.\n mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.\n pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.\n mstore(0x34, amount) // Store back the original `amount`.\n // Retry the approval, reverting upon failure.\n if iszero(\n and(\n or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.\n call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)\n )\n ) {\n mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.\n revert(0x1c, 0x04)\n }\n }\n mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.\n }\n }\n\n /// @dev Returns the amount of ERC20 `token` owned by `account`.\n /// Returns zero if the `token` does not exist.\n function balanceOf(address token, address account) internal view returns (uint256 amount) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x14, account) // Store the `account` argument.\n mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.\n amount :=\n mul( // The arguments of `mul` are evaluated from right to left.\n mload(0x20),\n and( // The arguments of `and` are evaluated from right to left.\n gt(returndatasize(), 0x1f), // At least 32 bytes returned.\n staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)\n )\n )\n }\n }\n\n /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.\n /// If the initial attempt fails, try to use Permit2 to transfer the token.\n /// Reverts upon failure.\n ///\n /// The `from` account must have at least `amount` approved for the current contract to manage.\n function safeTransferFrom2(address token, address from, address to, uint256 amount) internal {\n if (!trySafeTransferFrom(token, from, to, amount)) {\n permit2TransferFrom(token, from, to, amount);\n }\n }\n\n /// @dev Sends `amount` of ERC20 `token` from `from` to `to` via Permit2.\n /// Reverts upon failure.\n function permit2TransferFrom(address token, address from, address to, uint256 amount)\n internal\n {\n /// @solidity memory-safe-assembly\n assembly {\n let m := mload(0x40)\n mstore(add(m, 0x74), shr(96, shl(96, token)))\n mstore(add(m, 0x54), amount)\n mstore(add(m, 0x34), to)\n mstore(add(m, 0x20), shl(96, from))\n // `transferFrom(address,address,uint160,address)`.\n mstore(m, 0x36c78516000000000000000000000000)\n let p := PERMIT2\n let exists := eq(chainid(), 1)\n if iszero(exists) { exists := iszero(iszero(extcodesize(p))) }\n if iszero(and(call(gas(), p, 0, add(m, 0x10), 0x84, codesize(), 0x00), exists)) {\n mstore(0x00, 0x7939f4248757f0fd) // `TransferFromFailed()` or `Permit2AmountOverflow()`.\n revert(add(0x18, shl(2, iszero(iszero(shr(160, amount))))), 0x04)\n }\n }\n }\n\n /// @dev Permit a user to spend a given amount of\n /// another user's tokens via native EIP-2612 permit if possible, falling\n /// back to Permit2 if native permit fails or is not implemented on the token.\n function permit2(\n address token,\n address owner,\n address spender,\n uint256 amount,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n bool success;\n /// @solidity memory-safe-assembly\n assembly {\n for {} shl(96, xor(token, WETH9)) {} {\n mstore(0x00, 0x3644e515) // `DOMAIN_SEPARATOR()`.\n if iszero(\n and( // The arguments of `and` are evaluated from right to left.\n lt(iszero(mload(0x00)), eq(returndatasize(), 0x20)), // Returns 1 non-zero word.\n // Gas stipend to limit gas burn for tokens that don't refund gas when\n // an non-existing function is called. 5K should be enough for a SLOAD.\n staticcall(5000, token, 0x1c, 0x04, 0x00, 0x20)\n )\n ) { break }\n // After here, we can be sure that token is a contract.\n let m := mload(0x40)\n mstore(add(m, 0x34), spender)\n mstore(add(m, 0x20), shl(96, owner))\n mstore(add(m, 0x74), deadline)\n if eq(mload(0x00), DAI_DOMAIN_SEPARATOR) {\n mstore(0x14, owner)\n mstore(0x00, 0x7ecebe00000000000000000000000000) // `nonces(address)`.\n mstore(add(m, 0x94), staticcall(gas(), token, 0x10, 0x24, add(m, 0x54), 0x20))\n mstore(m, 0x8fcbaf0c000000000000000000000000) // `IDAIPermit.permit`.\n // `nonces` is already at `add(m, 0x54)`.\n // `1` is already stored at `add(m, 0x94)`.\n mstore(add(m, 0xb4), and(0xff, v))\n mstore(add(m, 0xd4), r)\n mstore(add(m, 0xf4), s)\n success := call(gas(), token, 0, add(m, 0x10), 0x104, codesize(), 0x00)\n break\n }\n mstore(m, 0xd505accf000000000000000000000000) // `IERC20Permit.permit`.\n mstore(add(m, 0x54), amount)\n mstore(add(m, 0x94), and(0xff, v))\n mstore(add(m, 0xb4), r)\n mstore(add(m, 0xd4), s)\n success := call(gas(), token, 0, add(m, 0x10), 0xe4, codesize(), 0x00)\n break\n }\n }\n if (!success) simplePermit2(token, owner, spender, amount, deadline, v, r, s);\n }\n\n /// @dev Simple permit on the Permit2 contract.\n function simplePermit2(\n address token,\n address owner,\n address spender,\n uint256 amount,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal {\n /// @solidity memory-safe-assembly\n assembly {\n let m := mload(0x40)\n mstore(m, 0x927da105) // `allowance(address,address,address)`.\n {\n let addressMask := shr(96, not(0))\n mstore(add(m, 0x20), and(addressMask, owner))\n mstore(add(m, 0x40), and(addressMask, token))\n mstore(add(m, 0x60), and(addressMask, spender))\n mstore(add(m, 0xc0), and(addressMask, spender))\n }\n let p := mul(PERMIT2, iszero(shr(160, amount)))\n if iszero(\n and( // The arguments of `and` are evaluated from right to left.\n gt(returndatasize(), 0x5f), // Returns 3 words: `amount`, `expiration`, `nonce`.\n staticcall(gas(), p, add(m, 0x1c), 0x64, add(m, 0x60), 0x60)\n )\n ) {\n mstore(0x00, 0x6b836e6b8757f0fd) // `Permit2Failed()` or `Permit2AmountOverflow()`.\n revert(add(0x18, shl(2, iszero(p))), 0x04)\n }\n mstore(m, 0x2b67b570) // `Permit2.permit` (PermitSingle variant).\n // `owner` is already `add(m, 0x20)`.\n // `token` is already at `add(m, 0x40)`.\n mstore(add(m, 0x60), amount)\n mstore(add(m, 0x80), 0xffffffffffff) // `expiration = type(uint48).max`.\n // `nonce` is already at `add(m, 0xa0)`.\n // `spender` is already at `add(m, 0xc0)`.\n mstore(add(m, 0xe0), deadline)\n mstore(add(m, 0x100), 0x100) // `signature` offset.\n mstore(add(m, 0x120), 0x41) // `signature` length.\n mstore(add(m, 0x140), r)\n mstore(add(m, 0x160), s)\n mstore(add(m, 0x180), shl(248, v))\n if iszero(call(gas(), p, 0, add(m, 0x1c), 0x184, codesize(), 0x00)) {\n mstore(0x00, 0x6b836e6b) // `Permit2Failed()`.\n revert(0x1c, 0x04)\n }\n }\n }\n}\n"},"lib/solady/src/utils/ReentrancyGuard.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Reentrancy guard mixin.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ReentrancyGuard.sol)\nabstract contract ReentrancyGuard {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CUSTOM ERRORS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Unauthorized reentrant call.\n error Reentrancy();\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* STORAGE */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Equivalent to: `uint72(bytes9(keccak256(\"_REENTRANCY_GUARD_SLOT\")))`.\n /// 9 bytes is large enough to avoid collisions with lower slots,\n /// but not too large to result in excessive bytecode bloat.\n uint256 private constant _REENTRANCY_GUARD_SLOT = 0x929eee149b4bd21268;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* REENTRANCY GUARD */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Guards a function from reentrancy.\n modifier nonReentrant() virtual {\n /// @solidity memory-safe-assembly\n assembly {\n if eq(sload(_REENTRANCY_GUARD_SLOT), address()) {\n mstore(0x00, 0xab143c06) // `Reentrancy()`.\n revert(0x1c, 0x04)\n }\n sstore(_REENTRANCY_GUARD_SLOT, address())\n }\n _;\n /// @solidity memory-safe-assembly\n assembly {\n sstore(_REENTRANCY_GUARD_SLOT, codesize())\n }\n }\n\n /// @dev Guards a view function from read-only reentrancy.\n modifier nonReadReentrant() virtual {\n /// @solidity memory-safe-assembly\n assembly {\n if eq(sload(_REENTRANCY_GUARD_SLOT), address()) {\n mstore(0x00, 0xab143c06) // `Reentrancy()`.\n revert(0x1c, 0x04)\n }\n }\n _;\n }\n}\n"},"contracts/references/Budget.sol":{"content":"// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.19;\n\nimport {Ownable} from \"solady/auth/Ownable.sol\";\nimport {Receiver} from \"solady/accounts/Receiver.sol\";\nimport {SafeTransferLib} from \"solady/utils/SafeTransferLib.sol\";\n\nimport {BoostError} from \"contracts/references/BoostError.sol\";\nimport {Cloneable} from \"contracts/references/Cloneable.sol\";\n\n/// @title Boost Budget\n/// @notice Abstract contract for a generic Budget within the Boost protocol\n/// @dev Budget classes are expected to implement the allocation, reclamation, and disbursement of assets.\n/// @dev WARNING: Budgets currently support only ETH, ERC20, and ERC1155 assets. Other asset types may be added in the future.\nabstract contract Budget is Ownable, Cloneable, Receiver {\n using SafeTransferLib for address;\n\n enum AssetType {\n ETH,\n ERC20,\n ERC1155\n }\n\n /// @notice A struct representing the inputs for an allocation\n /// @param assetType The type of asset to allocate\n /// @param asset The address of the asset to allocate\n /// @param target The address of the payee or payer (from or to, depending on the operation)\n /// @param data The implementation-specific data for the allocation (amount, token ID, etc.)\n struct Transfer {\n AssetType assetType;\n address asset;\n address target;\n bytes data;\n }\n\n /// @notice The payload for an ETH or ERC20 transfer\n /// @param amount The amount of the asset to transfer\n struct FungiblePayload {\n uint256 amount;\n }\n\n /// @notice The payload for an ERC1155 transfer\n /// @param tokenId The ID of the token to transfer\n /// @param amount The amount of the token to transfer\n /// @param data Any additional data to forward to the ERC1155 contract\n struct ERC1155Payload {\n uint256 tokenId;\n uint256 amount;\n bytes data;\n }\n\n /// @notice Emitted when an address's authorization status changes\n event Authorized(address indexed account, bool isAuthorized);\n\n /// @notice Emitted when assets are distributed from the budget\n event Distributed(address indexed asset, address to, uint256 amount);\n\n /// @notice Thrown when the allocation is invalid\n error InvalidAllocation(address asset, uint256 amount);\n\n /// @notice Thrown when there are insufficient funds for an operation\n error InsufficientFunds(address asset, uint256 available, uint256 required);\n\n /// @notice Thrown when the length of two arrays are not equal\n error LengthMismatch();\n\n /// @notice Thrown when a transfer fails for an unknown reason\n error TransferFailed(address asset, address to, uint256 amount);\n\n /// @notice Initialize the budget and set the owner\n /// @dev The owner is set to the contract deployer\n constructor() {\n _initializeOwner(msg.sender);\n }\n\n /// @notice Allocate assets to the budget\n /// @param data_ The compressed data for the allocation (amount, token address, token ID, etc.)\n /// @return True if the allocation was successful\n function allocate(bytes calldata data_) external payable virtual returns (bool);\n\n /// @notice Reclaim assets from the budget\n /// @param data_ The compressed data for the reclamation (amount, token address, token ID, etc.)\n /// @return True if the reclamation was successful\n function reclaim(bytes calldata data_) external virtual returns (bool);\n\n /// @notice Disburse assets from the budget to a single recipient\n /// @param data_ The compressed {Transfer} request\n /// @return True if the disbursement was successful\n function disburse(bytes calldata data_) external virtual returns (bool);\n\n /// @notice Disburse assets from the budget to multiple recipients\n /// @param data_ The array of compressed {Transfer} requests\n /// @return True if all disbursements were successful\n function disburseBatch(bytes[] calldata data_) external virtual returns (bool);\n\n /// @notice Get the total amount of assets allocated to the budget, including any that have been distributed\n /// @param asset_ The address of the asset\n /// @return The total amount of assets\n function total(address asset_) external view virtual returns (uint256);\n\n /// @notice Get the amount of assets available for distribution from the budget\n /// @param asset_ The address of the asset\n /// @return The amount of assets available\n function available(address asset_) external view virtual returns (uint256);\n\n /// @notice Get the amount of assets that have been distributed from the budget\n /// @param asset_ The address of the asset\n /// @return The amount of assets distributed\n function distributed(address asset_) external view virtual returns (uint256);\n\n /// @notice Reconcile the budget to ensure the known state matches the actual state\n /// @param data_ The compressed data for the reconciliation (amount, token address, token ID, etc.)\n /// @return The amount of assets reconciled\n function reconcile(bytes calldata data_) external virtual returns (uint256);\n\n /// @inheritdoc Cloneable\n function supportsInterface(bytes4 interfaceId) public view virtual override(Cloneable) returns (bool) {\n return interfaceId == type(Budget).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /// @notice Set the authorized status of the given accounts\n /// @param accounts_ The accounts to authorize or deauthorize\n /// @param isAuthorized_ The authorization status for the given accounts\n /// @dev The mechanism for managing authorization is left to the implementing contract\n function setAuthorized(address[] calldata accounts_, bool[] calldata isAuthorized_) external virtual;\n\n /// @notice Check if the given account is authorized to use the budget\n /// @param account_ The account to check\n /// @return True if the account is authorized\n /// @dev The mechanism for checking authorization is left to the implementing contract\n function isAuthorized(address account_) external view virtual returns (bool);\n\n /// @inheritdoc Receiver\n receive() external payable virtual override {\n return;\n }\n\n /// @inheritdoc Receiver\n fallback() external payable virtual override {\n return;\n }\n}"},"contracts/references/Cloneable.sol":{"content":"// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.19;\n\nimport {Initializable} from \"solady/utils/Initializable.sol\";\nimport {ERC165} from \"openzeppelin-contracts/utils/introspection/ERC165.sol\";\n\n/// @title Cloneable\n/// @notice A contract that can be cloned and initialized only once\nabstract contract Cloneable is Initializable, ERC165 {\n /// @notice Thrown when an inheriting contract does not implement the initializer function\n error InitializerNotImplemented();\n\n /// @notice Thrown when the provided initialization data is invalid\n /// @dev This error indicates that the given data is not valid for the implementation (i.e. does not decode to the expected types)\n error InvalidInitializationData();\n\n /// @notice Thrown when the contract has already been initialized\n error CloneAlreadyInitialized();\n\n /// @notice A modifier to restrict a function to only be called before initialization\n /// @dev This is intended to enforce that a function can only be called before the contract has been initialized\n modifier onlyBeforeInitialization() {\n if (_getInitializedVersion() != 0) revert CloneAlreadyInitialized();\n _;\n }\n\n /// @notice Initialize the clone with the given arbitrary data\n /// @param - The compressed initialization data (if required)\n /// @dev The data is expected to be ABI encoded bytes compressed using {LibZip-cdCompress}\n /// @dev All implementations must override this function to initialize the contract\n function initialize(bytes calldata) public virtual initializer {\n revert InitializerNotImplemented();\n }\n\n /// @inheritdoc ERC165\n /// @notice Check if the contract supports the given interface\n /// @param interfaceId The interface identifier\n /// @return True if the contract supports the interface\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(Cloneable).interfaceId || super.supportsInterface(interfaceId);\n }\n}"},"lib/solady/src/auth/Ownable.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Simple single owner authorization mixin.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)\n///\n/// @dev Note:\n/// This implementation does NOT auto-initialize the owner to `msg.sender`.\n/// You MUST call the `_initializeOwner` in the constructor / initializer.\n///\n/// While the ownable portion follows\n/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,\n/// the nomenclature for the 2-step ownership handover may be unique to this codebase.\nabstract contract Ownable {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CUSTOM ERRORS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The caller is not authorized to call the function.\n error Unauthorized();\n\n /// @dev The `newOwner` cannot be the zero address.\n error NewOwnerIsZeroAddress();\n\n /// @dev The `pendingOwner` does not have a valid handover request.\n error NoHandoverRequest();\n\n /// @dev Cannot double-initialize.\n error AlreadyInitialized();\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* EVENTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The ownership is transferred from `oldOwner` to `newOwner`.\n /// This event is intentionally kept the same as OpenZeppelin's Ownable to be\n /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),\n /// despite it not being as lightweight as a single argument event.\n event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);\n\n /// @dev An ownership handover to `pendingOwner` has been requested.\n event OwnershipHandoverRequested(address indexed pendingOwner);\n\n /// @dev The ownership handover to `pendingOwner` has been canceled.\n event OwnershipHandoverCanceled(address indexed pendingOwner);\n\n /// @dev `keccak256(bytes(\"OwnershipTransferred(address,address)\"))`.\n uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =\n 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;\n\n /// @dev `keccak256(bytes(\"OwnershipHandoverRequested(address)\"))`.\n uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =\n 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;\n\n /// @dev `keccak256(bytes(\"OwnershipHandoverCanceled(address)\"))`.\n uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =\n 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* STORAGE */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The owner slot is given by:\n /// `bytes32(~uint256(uint32(bytes4(keccak256(\"_OWNER_SLOT_NOT\")))))`.\n /// It is intentionally chosen to be a high value\n /// to avoid collision with lower slots.\n /// The choice of manual storage layout is to enable compatibility\n /// with both regular and upgradeable contracts.\n bytes32 internal constant _OWNER_SLOT =\n 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;\n\n /// The ownership handover slot of `newOwner` is given by:\n /// ```\n /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))\n /// let handoverSlot := keccak256(0x00, 0x20)\n /// ```\n /// It stores the expiry timestamp of the two-step ownership handover.\n uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* INTERNAL FUNCTIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Override to return true to make `_initializeOwner` prevent double-initialization.\n function _guardInitializeOwner() internal pure virtual returns (bool guard) {}\n\n /// @dev Initializes the owner directly without authorization guard.\n /// This function must be called upon initialization,\n /// regardless of whether the contract is upgradeable or not.\n /// This is to enable generalization to both regular and upgradeable contracts,\n /// and to save gas in case the initial owner is not the caller.\n /// For performance reasons, this function will not check if there\n /// is an existing owner.\n function _initializeOwner(address newOwner) internal virtual {\n if (_guardInitializeOwner()) {\n /// @solidity memory-safe-assembly\n assembly {\n let ownerSlot := _OWNER_SLOT\n if sload(ownerSlot) {\n mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`.\n revert(0x1c, 0x04)\n }\n // Clean the upper 96 bits.\n newOwner := shr(96, shl(96, newOwner))\n // Store the new value.\n sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))\n // Emit the {OwnershipTransferred} event.\n log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)\n }\n } else {\n /// @solidity memory-safe-assembly\n assembly {\n // Clean the upper 96 bits.\n newOwner := shr(96, shl(96, newOwner))\n // Store the new value.\n sstore(_OWNER_SLOT, newOwner)\n // Emit the {OwnershipTransferred} event.\n log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)\n }\n }\n }\n\n /// @dev Sets the owner directly without authorization guard.\n function _setOwner(address newOwner) internal virtual {\n if (_guardInitializeOwner()) {\n /// @solidity memory-safe-assembly\n assembly {\n let ownerSlot := _OWNER_SLOT\n // Clean the upper 96 bits.\n newOwner := shr(96, shl(96, newOwner))\n // Emit the {OwnershipTransferred} event.\n log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)\n // Store the new value.\n sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))\n }\n } else {\n /// @solidity memory-safe-assembly\n assembly {\n let ownerSlot := _OWNER_SLOT\n // Clean the upper 96 bits.\n newOwner := shr(96, shl(96, newOwner))\n // Emit the {OwnershipTransferred} event.\n log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)\n // Store the new value.\n sstore(ownerSlot, newOwner)\n }\n }\n }\n\n /// @dev Throws if the sender is not the owner.\n function _checkOwner() internal view virtual {\n /// @solidity memory-safe-assembly\n assembly {\n // If the caller is not the stored owner, revert.\n if iszero(eq(caller(), sload(_OWNER_SLOT))) {\n mstore(0x00, 0x82b42900) // `Unauthorized()`.\n revert(0x1c, 0x04)\n }\n }\n }\n\n /// @dev Returns how long a two-step ownership handover is valid for in seconds.\n /// Override to return a different value if needed.\n /// Made internal to conserve bytecode. Wrap it in a public function if needed.\n function _ownershipHandoverValidFor() internal view virtual returns (uint64) {\n return 48 * 3600;\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* PUBLIC UPDATE FUNCTIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Allows the owner to transfer the ownership to `newOwner`.\n function transferOwnership(address newOwner) public payable virtual onlyOwner {\n /// @solidity memory-safe-assembly\n assembly {\n if iszero(shl(96, newOwner)) {\n mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.\n revert(0x1c, 0x04)\n }\n }\n _setOwner(newOwner);\n }\n\n /// @dev Allows the owner to renounce their ownership.\n function renounceOwnership() public payable virtual onlyOwner {\n _setOwner(address(0));\n }\n\n /// @dev Request a two-step ownership handover to the caller.\n /// The request will automatically expire in 48 hours (172800 seconds) by default.\n function requestOwnershipHandover() public payable virtual {\n unchecked {\n uint256 expires = block.timestamp + _ownershipHandoverValidFor();\n /// @solidity memory-safe-assembly\n assembly {\n // Compute and set the handover slot to `expires`.\n mstore(0x0c, _HANDOVER_SLOT_SEED)\n mstore(0x00, caller())\n sstore(keccak256(0x0c, 0x20), expires)\n // Emit the {OwnershipHandoverRequested} event.\n log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())\n }\n }\n }\n\n /// @dev Cancels the two-step ownership handover to the caller, if any.\n function cancelOwnershipHandover() public payable virtual {\n /// @solidity memory-safe-assembly\n assembly {\n // Compute and set the handover slot to 0.\n mstore(0x0c, _HANDOVER_SLOT_SEED)\n mstore(0x00, caller())\n sstore(keccak256(0x0c, 0x20), 0)\n // Emit the {OwnershipHandoverCanceled} event.\n log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())\n }\n }\n\n /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.\n /// Reverts if there is no existing ownership handover requested by `pendingOwner`.\n function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {\n /// @solidity memory-safe-assembly\n assembly {\n // Compute and set the handover slot to 0.\n mstore(0x0c, _HANDOVER_SLOT_SEED)\n mstore(0x00, pendingOwner)\n let handoverSlot := keccak256(0x0c, 0x20)\n // If the handover does not exist, or has expired.\n if gt(timestamp(), sload(handoverSlot)) {\n mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.\n revert(0x1c, 0x04)\n }\n // Set the handover slot to 0.\n sstore(handoverSlot, 0)\n }\n _setOwner(pendingOwner);\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* PUBLIC READ FUNCTIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the owner of the contract.\n function owner() public view virtual returns (address result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := sload(_OWNER_SLOT)\n }\n }\n\n /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.\n function ownershipHandoverExpiresAt(address pendingOwner)\n public\n view\n virtual\n returns (uint256 result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n // Compute the handover slot.\n mstore(0x0c, _HANDOVER_SLOT_SEED)\n mstore(0x00, pendingOwner)\n // Load the handover slot.\n result := sload(keccak256(0x0c, 0x20))\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* MODIFIERS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Marks a function as only callable by the owner.\n modifier onlyOwner() virtual {\n _checkOwner();\n _;\n }\n}\n"},"lib/solady/src/accounts/Receiver.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Receiver mixin for ETH and safe-transferred ERC721 and ERC1155 tokens.\n/// @author Solady (https://github.com/Vectorized/solady/blob/main/src/accounts/Receiver.sol)\n///\n/// @dev Note:\n/// - Handles all ERC721 and ERC1155 token safety callbacks.\n/// - Collapses function table gas overhead and code size.\n/// - Utilizes fallback so unknown calldata will pass on.\nabstract contract Receiver {\n /// @dev For receiving ETH.\n receive() external payable virtual {}\n\n /// @dev Fallback function with the `receiverFallback` modifier.\n fallback() external payable virtual receiverFallback {}\n\n /// @dev Modifier for the fallback function to handle token callbacks.\n modifier receiverFallback() virtual {\n /// @solidity memory-safe-assembly\n assembly {\n let s := shr(224, calldataload(0))\n // 0x150b7a02: `onERC721Received(address,address,uint256,bytes)`.\n // 0xf23a6e61: `onERC1155Received(address,address,uint256,uint256,bytes)`.\n // 0xbc197c81: `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`.\n if or(eq(s, 0x150b7a02), or(eq(s, 0xf23a6e61), eq(s, 0xbc197c81))) {\n mstore(0x20, s) // Store `msg.sig`.\n return(0x3c, 0x20) // Return `msg.sig`.\n }\n }\n _;\n }\n}\n"},"contracts/references/BoostError.sol":{"content":"// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.19;\n\n/// @title BoostError\n/// @notice Standardized errors for the Boost protocol\n/// @dev Some of these errors are introduced by third-party libraries, rather than Boost contracts directly, and are copied here for clarity and ease of testing.\nlibrary BoostError {\n /// @notice Thrown when a claim attempt fails\n error ClaimFailed(address caller, bytes data);\n\n /// @notice Thrown when there are insufficient funds for an operation\n error InsufficientFunds(address asset, uint256 available, uint256 required);\n\n /// @notice Thrown when a non-conforming instance for a given type is encountered\n error InvalidInstance(bytes4 expectedInterface, address instance);\n\n /// @notice Thrown when an invalid initialization is attempted\n error InvalidInitialization();\n\n /// @notice Thrown when the length of two arrays are not equal\n error LengthMismatch();\n\n /// @notice Thrown when a method is not implemented\n error NotImplemented();\n\n /// @notice Thrown when a previously used signature is replayed\n error Replayed(address signer, bytes32 hash, bytes signature);\n\n /// @notice Thrown when a transfer fails for an unknown reason\n error TransferFailed(address asset, address to, uint256 amount);\n\n /// @notice Thrown when the requested action is unauthorized\n error Unauthorized();\n}"},"lib/solady/src/utils/Initializable.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Initializable mixin for the upgradeable contracts.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Initializable.sol)\n/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/proxy/utils/Initializable.sol)\nabstract contract Initializable {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CUSTOM ERRORS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The contract is already initialized.\n error InvalidInitialization();\n\n /// @dev The contract is not initializing.\n error NotInitializing();\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* EVENTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Triggered when the contract has been initialized.\n event Initialized(uint64 version);\n\n /// @dev `keccak256(bytes(\"Initialized(uint64)\"))`.\n bytes32 private constant _INTIALIZED_EVENT_SIGNATURE =\n 0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* STORAGE */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The default initializable slot is given by:\n /// `bytes32(~uint256(uint32(bytes4(keccak256(\"_INITIALIZABLE_SLOT\")))))`.\n ///\n /// Bits Layout:\n /// - [0] `initializing`\n /// - [1..64] `initializedVersion`\n bytes32 private constant _INITIALIZABLE_SLOT =\n 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf601132;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Override to return a custom storage slot if required.\n function _initializableSlot() internal pure virtual returns (bytes32) {\n return _INITIALIZABLE_SLOT;\n }\n\n /// @dev Guards an initializer function so that it can be invoked at most once.\n ///\n /// You can guard a function with `onlyInitializing` such that it can be called\n /// through a function guarded with `initializer`.\n ///\n /// This is similar to `reinitializer(1)`, except that in the context of a constructor,\n /// an `initializer` guarded function can be invoked multiple times.\n /// This can be useful during testing and is not expected to be used in production.\n ///\n /// Emits an {Initialized} event.\n modifier initializer() virtual {\n bytes32 s = _initializableSlot();\n /// @solidity memory-safe-assembly\n assembly {\n let i := sload(s)\n // Set `initializing` to 1, `initializedVersion` to 1.\n sstore(s, 3)\n // If `!(initializing == 0 && initializedVersion == 0)`.\n if i {\n // If `!(address(this).code.length == 0 && initializedVersion == 1)`.\n if iszero(lt(extcodesize(address()), eq(shr(1, i), 1))) {\n mstore(0x00, 0xf92ee8a9) // `InvalidInitialization()`.\n revert(0x1c, 0x04)\n }\n s := shl(shl(255, i), s) // Skip initializing if `initializing == 1`.\n }\n }\n _;\n /// @solidity memory-safe-assembly\n assembly {\n if s {\n // Set `initializing` to 0, `initializedVersion` to 1.\n sstore(s, 2)\n // Emit the {Initialized} event.\n mstore(0x20, 1)\n log1(0x20, 0x20, _INTIALIZED_EVENT_SIGNATURE)\n }\n }\n }\n\n /// @dev Guards an reinitialzer function so that it can be invoked at most once.\n ///\n /// You can guard a function with `onlyInitializing` such that it can be called\n /// through a function guarded with `reinitializer`.\n ///\n /// Emits an {Initialized} event.\n modifier reinitializer(uint64 version) virtual {\n bytes32 s = _initializableSlot();\n /// @solidity memory-safe-assembly\n assembly {\n version := and(version, 0xffffffffffffffff) // Clean upper bits.\n let i := sload(s)\n // If `initializing == 1 || initializedVersion >= version`.\n if iszero(lt(and(i, 1), lt(shr(1, i), version))) {\n mstore(0x00, 0xf92ee8a9) // `InvalidInitialization()`.\n revert(0x1c, 0x04)\n }\n // Set `initializing` to 1, `initializedVersion` to `version`.\n sstore(s, or(1, shl(1, version)))\n }\n _;\n /// @solidity memory-safe-assembly\n assembly {\n // Set `initializing` to 0, `initializedVersion` to `version`.\n sstore(s, shl(1, version))\n // Emit the {Initialized} event.\n mstore(0x20, version)\n log1(0x20, 0x20, _INTIALIZED_EVENT_SIGNATURE)\n }\n }\n\n /// @dev Guards a function such that it can only be called in the scope\n /// of a function guarded with `initializer` or `reinitializer`.\n modifier onlyInitializing() virtual {\n _checkInitializing();\n _;\n }\n\n /// @dev Reverts if the contract is not initializing.\n function _checkInitializing() internal view virtual {\n bytes32 s = _initializableSlot();\n /// @solidity memory-safe-assembly\n assembly {\n if iszero(and(1, sload(s))) {\n mstore(0x00, 0xd7e6bcf8) // `NotInitializing()`.\n revert(0x1c, 0x04)\n }\n }\n }\n\n /// @dev Locks any future initializations by setting the initialized version to `2**64 - 1`.\n ///\n /// Calling this in the constructor will prevent the contract from being initialized\n /// or reinitialized. It is recommended to use this to lock implementation contracts\n /// that are designed to be called through proxies.\n ///\n /// Emits an {Initialized} event the first time it is successfully called.\n function _disableInitializers() internal virtual {\n bytes32 s = _initializableSlot();\n /// @solidity memory-safe-assembly\n assembly {\n let i := sload(s)\n if and(i, 1) {\n mstore(0x00, 0xf92ee8a9) // `InvalidInitialization()`.\n revert(0x1c, 0x04)\n }\n let uint64max := shr(192, s) // Computed to save bytecode.\n if iszero(eq(shr(1, i), uint64max)) {\n // Set `initializing` to 0, `initializedVersion` to `2**64 - 1`.\n sstore(s, shl(1, uint64max))\n // Emit the {Initialized} event.\n mstore(0x20, uint64max)\n log1(0x20, 0x20, _INTIALIZED_EVENT_SIGNATURE)\n }\n }\n }\n\n /// @dev Returns the highest version that has been initialized.\n function _getInitializedVersion() internal view virtual returns (uint64 version) {\n bytes32 s = _initializableSlot();\n /// @solidity memory-safe-assembly\n assembly {\n version := shr(1, sload(s))\n }\n }\n\n /// @dev Returns whether the contract is currently initializing.\n function _isInitializing() internal view virtual returns (bool result) {\n bytes32 s = _initializableSlot();\n /// @solidity memory-safe-assembly\n assembly {\n result := and(1, sload(s))\n }\n }\n}\n"},"lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n"}},"settings":{"remappings":["forge-std/=lib/forge-std/src/","solady/=lib/solady/src/","openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","@openzeppelin/=node_modules/@openzeppelin/","@openzeppelin/contracts/=lib/v2-core/lib/openzeppelin-contracts/contracts/","@prb/=node_modules/@prb/","@prb/math/=lib/v2-core/lib/prb-math/","@prb/test/=lib/v2-core/lib/prb-test/src/","@sablier/=node_modules/@sablier/","ds-test/=lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","eth-gas-reporter/=node_modules/eth-gas-reporter/","hardhat-deploy/=node_modules/hardhat-deploy/","hardhat/=node_modules/hardhat/","openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/","prb-math/=lib/v2-core/lib/prb-math/src/","prb-test/=lib/v2-core/lib/prb-test/src/","solarray/=lib/v2-core/lib/solarray/src/","v2-core/=lib/v2-core/"],"optimizer":{"enabled":true,"runs":1000},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata","storageLayout"]}},"evmVersion":"paris","viaIR":true,"libraries":{}}}