From 058c2d1b46e42b9a632a9cd42c39897915ebe871 Mon Sep 17 00:00:00 2001 From: 0age <37939117+0age@users.noreply.github.com> Date: Thu, 7 Nov 2024 09:03:59 -0800 Subject: [PATCH 1/2] add files back --- src/TheCompact.sol | 240 +++++ src/interfaces/IAllocator.sol | 8 + src/interfaces/ITheCompact.sol | 570 ++++++++++++ src/interfaces/ITheCompactClaims.sol | 291 ++++++ src/lib/AllocatorLogic.sol | 104 +++ src/lib/ClaimHashFunctionCastLib.sol | 1021 +++++++++++++++++++++ src/lib/ClaimHashLib.sol | 439 +++++++++ src/lib/ClaimProcessor.sol | 448 +++++++++ src/lib/ClaimProcessorFunctionCastLib.sol | 935 +++++++++++++++++++ src/lib/ClaimProcessorLib.sol | 546 +++++++++++ src/lib/ClaimProcessorLogic.sol | 493 ++++++++++ src/lib/ComponentLib.sol | 408 ++++++++ src/lib/ConstructorLogic.sol | 150 +++ src/lib/ConsumerLib.sol | 126 +++ src/lib/DepositLogic.sol | 92 ++ src/lib/DepositViaPermit2Lib.sol | 364 ++++++++ src/lib/DepositViaPermit2Logic.sol | 538 +++++++++++ src/lib/DirectDepositLogic.sol | 230 +++++ src/lib/DomainLib.sol | 77 ++ src/lib/EfficiencyLib.sol | 184 ++++ src/lib/EmissaryLib.sol | 97 ++ src/lib/EventLib.sol | 55 ++ src/lib/Extsload.sol | 46 + src/lib/HashLib.sol | 783 ++++++++++++++++ src/lib/IdLib.sol | 378 ++++++++ src/lib/MetadataLib.sol | 126 +++ src/lib/MetadataRenderer.sol | 49 + src/lib/RegistrationLib.sol | 155 ++++ src/lib/RegistrationLogic.sol | 63 ++ src/lib/SharedLogic.sol | 156 ++++ src/lib/TheCompactLogic.sol | 17 + src/lib/TransferFunctionCastLib.sol | 86 ++ src/lib/TransferLogic.sol | 253 +++++ src/lib/ValidityLib.sol | 183 ++++ src/lib/WithdrawalLogic.sol | 160 ++++ src/types/BatchClaims.sol | 111 +++ src/types/BatchMultichainClaims.sol | 220 +++++ src/types/Claims.sol | 129 +++ src/types/CompactCategory.sol | 8 + src/types/Components.sol | 29 + src/types/EIP712Types.sol | 215 +++++ src/types/ForcedWithdrawalStatus.sol | 9 + src/types/Lock.sol | 12 + src/types/MultichainClaims.sol | 252 +++++ src/types/ResetPeriod.sol | 13 + src/types/Scope.sol | 7 + 46 files changed, 10876 insertions(+) create mode 100644 src/TheCompact.sol create mode 100644 src/interfaces/IAllocator.sol create mode 100644 src/interfaces/ITheCompact.sol create mode 100644 src/interfaces/ITheCompactClaims.sol create mode 100644 src/lib/AllocatorLogic.sol create mode 100644 src/lib/ClaimHashFunctionCastLib.sol create mode 100644 src/lib/ClaimHashLib.sol create mode 100644 src/lib/ClaimProcessor.sol create mode 100644 src/lib/ClaimProcessorFunctionCastLib.sol create mode 100644 src/lib/ClaimProcessorLib.sol create mode 100644 src/lib/ClaimProcessorLogic.sol create mode 100644 src/lib/ComponentLib.sol create mode 100644 src/lib/ConstructorLogic.sol create mode 100644 src/lib/ConsumerLib.sol create mode 100644 src/lib/DepositLogic.sol create mode 100644 src/lib/DepositViaPermit2Lib.sol create mode 100644 src/lib/DepositViaPermit2Logic.sol create mode 100644 src/lib/DirectDepositLogic.sol create mode 100644 src/lib/DomainLib.sol create mode 100644 src/lib/EfficiencyLib.sol create mode 100644 src/lib/EmissaryLib.sol create mode 100644 src/lib/EventLib.sol create mode 100644 src/lib/Extsload.sol create mode 100644 src/lib/HashLib.sol create mode 100644 src/lib/IdLib.sol create mode 100644 src/lib/MetadataLib.sol create mode 100644 src/lib/MetadataRenderer.sol create mode 100644 src/lib/RegistrationLib.sol create mode 100644 src/lib/RegistrationLogic.sol create mode 100644 src/lib/SharedLogic.sol create mode 100644 src/lib/TheCompactLogic.sol create mode 100644 src/lib/TransferFunctionCastLib.sol create mode 100644 src/lib/TransferLogic.sol create mode 100644 src/lib/ValidityLib.sol create mode 100644 src/lib/WithdrawalLogic.sol create mode 100644 src/types/BatchClaims.sol create mode 100644 src/types/BatchMultichainClaims.sol create mode 100644 src/types/Claims.sol create mode 100644 src/types/CompactCategory.sol create mode 100644 src/types/Components.sol create mode 100644 src/types/EIP712Types.sol create mode 100644 src/types/ForcedWithdrawalStatus.sol create mode 100644 src/types/Lock.sol create mode 100644 src/types/MultichainClaims.sol create mode 100644 src/types/ResetPeriod.sol create mode 100644 src/types/Scope.sol diff --git a/src/TheCompact.sol b/src/TheCompact.sol new file mode 100644 index 0000000..0fc8a18 --- /dev/null +++ b/src/TheCompact.sol @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { ITheCompact } from "./interfaces/ITheCompact.sol"; + +import { BatchTransfer, SplitBatchTransfer } from "./types/BatchClaims.sol"; +import { BasicTransfer, SplitTransfer } from "./types/Claims.sol"; +import { CompactCategory } from "./types/CompactCategory.sol"; +import { Lock } from "./types/Lock.sol"; +import { Scope } from "./types/Scope.sol"; +import { ResetPeriod } from "./types/ResetPeriod.sol"; +import { ForcedWithdrawalStatus } from "./types/ForcedWithdrawalStatus.sol"; + +import { TheCompactLogic } from "./lib/TheCompactLogic.sol"; + +import { ERC6909 } from "solady/tokens/ERC6909.sol"; +import { ISignatureTransfer } from "permit2/src/interfaces/ISignatureTransfer.sol"; + +/** + * @title The Compact + * @custom:version 0 (early-stage proof-of-concept) + * @author 0age (0age.eth) + * @notice The Compact is an ownerless ERC6909 contract that facilitates the voluntary + * formation and mediation of reusable "resource locks." + * This contract has not yet been properly tested, audited, or reviewed. + */ +contract TheCompact is ITheCompact, ERC6909, TheCompactLogic { + function deposit(address allocator) external payable returns (uint256) { + return _performBasicNativeTokenDeposit(allocator); + } + + function depositAndRegister(address allocator, bytes32 claimHash, bytes32 typehash) external payable returns (uint256 id) { + id = _performBasicNativeTokenDeposit(allocator); + + _registerWithDefaults(claimHash, typehash); + } + + function deposit(address token, address allocator, uint256 amount) external returns (uint256) { + return _performBasicERC20Deposit(token, allocator, amount); + } + + function depositAndRegister(address token, address allocator, uint256 amount, bytes32 claimHash, bytes32 typehash) external returns (uint256 id) { + id = _performBasicERC20Deposit(token, allocator, amount); + + _registerWithDefaults(claimHash, typehash); + } + + function deposit(address allocator, ResetPeriod resetPeriod, Scope scope, address recipient) external payable returns (uint256) { + return _performCustomNativeTokenDeposit(allocator, resetPeriod, scope, recipient); + } + + function deposit(address token, address allocator, ResetPeriod resetPeriod, Scope scope, uint256 amount, address recipient) external returns (uint256) { + return _performCustomERC20Deposit(token, allocator, resetPeriod, scope, amount, recipient); + } + + function deposit(uint256[2][] calldata idsAndAmounts, address recipient) external payable returns (bool) { + _processBatchDeposit(idsAndAmounts, recipient); + + return true; + } + + function depositAndRegister(uint256[2][] calldata idsAndAmounts, bytes32[2][] calldata claimHashesAndTypehashes, uint256 duration) external payable returns (bool) { + _processBatchDeposit(idsAndAmounts, msg.sender); + + return _registerBatch(claimHashesAndTypehashes, duration); + } + + function deposit( + address token, + uint256, // amount + uint256, // nonce + uint256, // deadline + address, // depositor + address, // allocator + ResetPeriod, // resetPeriod + Scope, //scope + address recipient, + bytes calldata signature + ) external returns (uint256) { + return _depositViaPermit2(token, recipient, signature); + } + + function depositAndRegister( + address token, + uint256, // amount + uint256, // nonce + uint256, // deadline + address depositor, // also recipient + address, // allocator + ResetPeriod resetPeriod, + Scope, //scope + bytes32 claimHash, + CompactCategory compactCategory, + string calldata witness, + bytes calldata signature + ) external returns (uint256) { + return _depositAndRegisterViaPermit2(token, depositor, resetPeriod, claimHash, compactCategory, witness, signature); + } + + function deposit( + address, // depositor + ISignatureTransfer.TokenPermissions[] calldata permitted, + uint256, // nonce + uint256, // deadline + address, // allocator + ResetPeriod, // resetPeriod + Scope, //scope + address recipient, + bytes calldata signature + ) external payable returns (uint256[] memory) { + return _depositBatchViaPermit2(permitted, recipient, signature); + } + + function depositAndRegister( + address depositor, + ISignatureTransfer.TokenPermissions[] calldata permitted, + uint256, // nonce + uint256, // deadline + address, // allocator + ResetPeriod resetPeriod, + Scope, //scope + bytes32 claimHash, + CompactCategory compactCategory, + string calldata witness, + bytes calldata signature + ) external payable returns (uint256[] memory) { + return _depositBatchAndRegisterViaPermit2(depositor, permitted, resetPeriod, claimHash, compactCategory, witness, signature); + } + + function allocatedTransfer(BasicTransfer calldata transfer) external returns (bool) { + return _processBasicTransfer(transfer, _release); + } + + function allocatedWithdrawal(BasicTransfer calldata withdrawal) external returns (bool) { + return _processBasicTransfer(withdrawal, _withdraw); + } + + function allocatedTransfer(SplitTransfer calldata transfer) external returns (bool) { + return _processSplitTransfer(transfer, _release); + } + + function allocatedWithdrawal(SplitTransfer calldata withdrawal) external returns (bool) { + return _processSplitTransfer(withdrawal, _withdraw); + } + + function allocatedTransfer(BatchTransfer calldata transfer) external returns (bool) { + return _processBatchTransfer(transfer, _release); + } + + function allocatedWithdrawal(BatchTransfer calldata withdrawal) external returns (bool) { + return _processBatchTransfer(withdrawal, _withdraw); + } + + function allocatedTransfer(SplitBatchTransfer calldata transfer) external returns (bool) { + return _processSplitBatchTransfer(transfer, _release); + } + + function allocatedWithdrawal(SplitBatchTransfer calldata withdrawal) external returns (bool) { + return _processSplitBatchTransfer(withdrawal, _withdraw); + } + + function enableForcedWithdrawal(uint256 id) external returns (uint256) { + return _enableForcedWithdrawal(id); + } + + function disableForcedWithdrawal(uint256 id) external returns (bool) { + return _disableForcedWithdrawal(id); + } + + function forcedWithdrawal(uint256 id, address recipient, uint256 amount) external returns (bool) { + return _processForcedWithdrawal(id, recipient, amount); + } + + function register(bytes32 claimHash, bytes32 typehash, uint256 duration) external returns (bool) { + _register(msg.sender, claimHash, typehash, duration); + return true; + } + + function getRegistrationStatus(address sponsor, bytes32 claimHash, bytes32 typehash) external view returns (bool isActive, uint256 expires) { + expires = _getRegistrationStatus(sponsor, claimHash, typehash); + isActive = expires > block.timestamp; + } + + function register(bytes32[2][] calldata claimHashesAndTypehashes, uint256 duration) external returns (bool) { + return _registerBatch(claimHashesAndTypehashes, duration); + } + + function consume(uint256[] calldata nonces) external returns (bool) { + return _consume(nonces); + } + + function __registerAllocator(address allocator, bytes calldata proof) external returns (uint96) { + return _registerAllocator(allocator, proof); + } + + function getForcedWithdrawalStatus(address account, uint256 id) external view returns (ForcedWithdrawalStatus, uint256) { + return _getForcedWithdrawalStatus(account, id); + } + + function getLockDetails(uint256 id) external view returns (address, address, ResetPeriod, Scope) { + return _getLockDetails(id); + } + + function hasConsumedAllocatorNonce(uint256 nonce, address allocator) external view returns (bool) { + return _hasConsumedAllocatorNonce(nonce, allocator); + } + + function DOMAIN_SEPARATOR() external view returns (bytes32) { + return _domainSeparator(); + } + + /// @dev Returns the symbol for token `id`. + function name(uint256 id) public view virtual override returns (string memory) { + return _name(id); + } + + /// @dev Returns the symbol for token `id`. + function symbol(uint256 id) public view virtual override returns (string memory) { + return _symbol(id); + } + + /// @dev Returns the Uniform Resource Identifier (URI) for token `id`. + function tokenURI(uint256 id) public view virtual override returns (string memory) { + return _tokenURI(id); + } + + /// @dev Returns the name for the contract. + function name() external pure returns (string memory) { + // Return the name of the contract. + assembly ("memory-safe") { + mstore(0x20, 0x20) + mstore(0x4b, 0x0b54686520436f6d70616374) + return(0x20, 0x60) + } + } + + function _beforeTokenTransfer(address from, address to, uint256 id, uint256 amount) internal virtual override { + _ensureAttested(from, to, id, amount); + } +} diff --git a/src/interfaces/IAllocator.sol b/src/interfaces/IAllocator.sol new file mode 100644 index 0000000..9a488a1 --- /dev/null +++ b/src/interfaces/IAllocator.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +// NOTE: Allocators with smart contract implementations should also implement EIP1271. +interface IAllocator { + // Called on standard transfers; must return this function selector (0x1a808f91). + function attest(address operator, address from, address to, uint256 id, uint256 amount) external returns (bytes4); +} diff --git a/src/interfaces/ITheCompact.sol b/src/interfaces/ITheCompact.sol new file mode 100644 index 0000000..c3056fa --- /dev/null +++ b/src/interfaces/ITheCompact.sol @@ -0,0 +1,570 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { ForcedWithdrawalStatus } from "../types/ForcedWithdrawalStatus.sol"; +import { ResetPeriod } from "../types/ResetPeriod.sol"; +import { Scope } from "../types/Scope.sol"; +import { CompactCategory } from "../types/CompactCategory.sol"; +import { ISignatureTransfer } from "permit2/src/interfaces/ISignatureTransfer.sol"; +import { BasicTransfer, SplitTransfer } from "../types/Claims.sol"; + +import { BatchTransfer, SplitBatchTransfer } from "../types/BatchClaims.sol"; + +/** + * @title The Compact — Core Interface + * @custom:version 0 (early-stage proof-of-concept) + * @author 0age (0age.eth) + * @notice The Compact is an ownerless ERC6909 contract that facilitates the voluntary + * formation and mediation of reusable "resource locks." This interface contract specifies + * external functions for making deposits, for performing allocated transfers and + * withdrawals, for initiating and performing forced withdrawals, and for registering + * compact claim hashes and typehashes directly. It also contains methods for registering + * allocators and for enabling allocators to consume nonces directly. Finally, it specifies + * a number of view functions, events and errors. + */ +interface ITheCompact { + /** + * @notice Event indicating that a claim has been processed for a given compact. + * @param sponsor The account sponsoring the claimed compact. + * @param allocator The account mediating the resource locks utilized by the claim. + * @param arbiter The account verifying and initiating the settlement of the claim. + * @param claimHash A bytes32 hash derived from the details of the claimed compact. + */ + event Claim(address indexed sponsor, address indexed allocator, address indexed arbiter, bytes32 claimHash); + + /** + * @notice Event indicating a change in forced withdrawal status. + * @param account The account for which the withdrawal status has changed. + * @param id The ERC6909 token identifier of the associated resource lock. + * @param activating Whether the forced withdrawal is being activated or has been deactivated. + * @param withdrawableAt The timestamp when tokens become withdrawable if it is being activated. + */ + event ForcedWithdrawalStatusUpdated(address indexed account, uint256 indexed id, bool activating, uint256 withdrawableAt); + + /** + * @notice Event indicating that a compact has been registered directly. + * @param sponsor The address registering the compact in question. + * @param claimHash A bytes32 hash derived from the details of the compact. + * @param typehash The EIP-712 typehash associated with the registered compact. + * @param expires The timestamp at which the compact can no longer be claimed. + */ + event CompactRegistered(address indexed sponsor, bytes32 claimHash, bytes32 typehash, uint256 expires); + + /** + * @notice Event indicating an allocator has been registered. + * @param allocatorId The unique identifier assigned to the allocator. + * @param allocator The address of the registered allocator. + */ + event AllocatorRegistered(uint96 allocatorId, address allocator); + + /** + * @notice External payable function for depositing native tokens into a resource lock + * and receiving back ERC6909 tokens representing the underlying locked balance controlled + * by the depositor. The allocator mediating the lock is provided as an argument, and the + * default reset period (ten minutes) and scope (multichain) will be used for the resource + * lock. The ERC6909 token amount received by the caller will match the amount of native + * tokens sent with the transaction. + * @param allocator The address of the allocator. + * @return id The ERC6909 token identifier of the associated resource lock. + */ + function deposit(address allocator) external payable returns (uint256 id); + + /** + * @notice External payable function for depositing native tokens into a resource lock + * and simultaneously registering a compact. The allocator, the claim hash, and the typehash + * used for the claim hash are provided as additional arguments, and the default reset period + * (ten minutes) and scope (multichain) will be used for the resource lock. The ERC6909 token + * amount received by the caller will match the amount of native tokens sent with the transaction. + * @param allocator The address of the allocator. + * @param claimHash A bytes32 hash derived from the details of the compact. + * @param typehash The EIP-712 typehash associated with the registered compact. + * @return id The ERC6909 token identifier of the associated resource lock. + */ + function depositAndRegister(address allocator, bytes32 claimHash, bytes32 typehash) external payable returns (uint256 id); + + /** + * @notice External function for depositing ERC20 tokens into a resource lock. The default + * reset period (ten minutes) and scope (multichain) will be used. The caller must directly + * approve The Compact to transfer a sufficient amount of the ERC20 token on its behalf. The + * ERC6909 token amount received back by the caller is derived from the difference between + * the starting and ending balance held in the resource lock, which may differ from the amount + * transferred depending on the implementation details of the respective token. + * @param token The address of the ERC20 token to deposit. + * @param allocator The address of the allocator mediating the resource lock. + * @param amount The amount of tokens to deposit. + * @return id The ERC6909 token identifier of the associated resource lock. + */ + function deposit(address token, address allocator, uint256 amount) external returns (uint256 id); + + /** + * @notice External function for depositing ERC20 tokens and simultaneously registering a + * compact. The default reset period (ten minutes) and scope (multichain) will be used. The + * caller must directly approve The Compact to transfer a sufficient amount of the ERC20 token + * on its behalf. The ERC6909 token amount received back by the caller is derived from the + * difference between the starting and ending balance held in the resource lock, which may differ + * from the amount transferred depending on the implementation details of the respective token. + * @param token The address of the ERC20 token to deposit. + * @param allocator The address of the allocator mediating the resource lock. + * @param amount The amount of tokens to deposit. + * @param claimHash A bytes32 hash derived from the details of the compact. + * @param typehash The EIP-712 typehash associated with the registered compact. + * @return id The ERC6909 token identifier of the associated resource lock. + */ + function depositAndRegister(address token, address allocator, uint256 amount, bytes32 claimHash, bytes32 typehash) external returns (uint256 id); + + /** + * @notice External payable function for depositing native tokens into a resource lock with + * custom reset period and scope parameters. The ERC6909 token amount received by the recipient + * will match the amount of native tokens sent with the transaction. + * @param allocator The address of the allocator mediating the resource lock. + * @param resetPeriod The duration after which the resource lock can be reset once a forced withdrawal is initiated. + * @param scope The scope of the resource lock (multichain or single chain). + * @param recipient The address that will receive the corresponding ERC6909 tokens. + * @return id The ERC6909 token identifier of the associated resource lock. + */ + function deposit(address allocator, ResetPeriod resetPeriod, Scope scope, address recipient) external payable returns (uint256 id); + + /** + * @notice External function for depositing ERC20 tokens into a resource lock with custom reset + * period and scope parameters. The caller must directly approve The Compact to transfer a + * sufficient amount of the ERC20 token on its behalf. The ERC6909 token amount received by + * the recipient is derived from the difference between the starting and ending balance held + * in the resource lock, which may differ from the amount transferred depending on the + * implementation details of the respective token. + * @param token The address of the ERC20 token to deposit. + * @param allocator The address of the allocator mediating the resource lock. + * @param resetPeriod The duration after which the resource lock can be reset once a forced withdrawal is initiated. + * @param scope The scope of the resource lock (multichain or single chain). + * @param amount The amount of tokens to deposit. + * @param recipient The address that will receive the corresponding ERC6909 tokens. + * @return id The ERC6909 token identifier of the associated resource lock. + */ + function deposit(address token, address allocator, ResetPeriod resetPeriod, Scope scope, uint256 amount, address recipient) external returns (uint256 id); + + /** + * @notice External payable function for depositing multiple tokens in a single transaction. + * The first entry in idsAndAmounts can optionally represent native tokens by providing the + * null address and an amount matching msg.value. For ERC20 tokens, the caller must directly + * approve The Compact to transfer sufficient amounts on its behalf. The ERC6909 token amounts + * received by the recipient are derived from the differences between starting and ending + * balances held in the resource locks, which may differ from the amounts transferred depending + * on the implementation details of the respective tokens. + * @param idsAndAmounts Array of [id, amount] pairs with each pair indicating the resource lock and amount to deposit. + * @param recipient The address that will receive the corresponding ERC6909 tokens. + * @return Whether the batch deposit was successfully completed. + */ + function deposit(uint256[2][] calldata idsAndAmounts, address recipient) external payable returns (bool); + + /** + * @notice External payable function for depositing multiple tokens in a single transaction + * and registering a set of claim hashes. The first entry in idsAndAmounts can optionally + * represent native tokens by providing the null address and an amount matching msg.value. For + * ERC20 tokens, the caller must directly approve The Compact to transfer sufficient amounts + * on its behalf. The ERC6909 token amounts received by the recipient are derived from the + * differences between starting and ending balances held in the resource locks, which may + * differ from the amounts transferred depending on the implementation details of the + * respective tokens. Note that resource lock ids must be supplied in alphanumeric order. + * @param idsAndAmounts Array of [id, amount] pairs with each pair indicating the resource lock and amount to deposit. + * @param claimHashesAndTypehashes Array of [claimHash, typehash] pairs for registration. + * @param duration The duration for which the claim hashes remain valid. + * @return Whether the batch deposit and claim hash registration was successfully completed. + */ + function depositAndRegister(uint256[2][] calldata idsAndAmounts, bytes32[2][] calldata claimHashesAndTypehashes, uint256 duration) external payable returns (bool); + + /** + * @notice External function for depositing ERC20 tokens using Permit2 authorization. The + * depositor must approve Permit2 to transfer the tokens on its behalf unless the token in + * question automatically grants approval to Permit2. The ERC6909 token amount received by the + * by the recipient is derived from the difference between the starting and ending balance held + * in the resource lock, which may differ from the amount transferred depending on the + * implementation details of the respective token. The Permit2 authorization signed by the + * depositor must contain a CompactDeposit witness containing the allocator, the reset period, + * the scope, and the intended recipient of the deposit. + * @param token The address of the ERC20 token to deposit. + * @param amount The amount of tokens to deposit. + * @param nonce The Permit2 nonce for the signature. + * @param deadline The timestamp until which the signature is valid. + * @param depositor The account signing the permit2 authorization and depositing the tokens. + * @param allocator The address of the allocator mediating the resource lock. + * @param resetPeriod The duration after which the resource lock can be reset once a forced withdrawal is initiated. + * @param scope The scope of the resource lock (multichain or single chain). + * @param recipient The address that will receive the corresponding the ERC6909 tokens. + * @param signature The Permit2 signature from the depositor authorizing the deposit. + * @return id The ERC6909 token identifier of the associated resource lock. + */ + function deposit(address token, uint256 amount, uint256 nonce, uint256 deadline, address depositor, address allocator, ResetPeriod resetPeriod, Scope scope, address recipient, bytes calldata signature) + external + returns (uint256 id); + + /** + * @notice External function for depositing ERC20 tokens using Permit2 authorization and + * registering a compact. The depositor must approve Permit2 to transfer the tokens on its + * behalf unless the token in question automatically grants approval to Permit2. The ERC6909 + * token amount received by the depositor is derived from the difference between the starting + * and ending balance held in the resource lock, which may differ from the amount transferred + * depending on the implementation details of the respective token. The Permit2 authorization + * signed by the depositor must contain an Activation witness containing the id of the resource + * lock and an associated Compact, BatchCompact, or MultichainCompact payload matching the + * specified compact category. + * @param token The address of the ERC20 token to deposit. + * @param amount The amount of tokens to deposit. + * @param nonce The Permit2 nonce for the signature. + * @param deadline The timestamp until which the signature is valid. + * @param depositor The account signing the permit2 authorization and depositing the tokens. + * @param allocator The address of the allocator mediating the resource lock. + * @param resetPeriod The duration after which the resource lock can be reset once a forced withdrawal is initiated. + * @param scope The scope of the resource lock (multichain or single chain). + * @param claimHash A bytes32 hash derived from the details of the compact. + * @param compactCategory The category of the compact being registered (Compact, BatchCompact, or MultichainCompact). + * @param witness Additional data used in generating the claim hash. + * @param signature The Permit2 signature from the depositor authorizing the deposit. + * @return id The ERC6909 token identifier of the associated resource lock. + */ + function depositAndRegister( + address token, + uint256 amount, + uint256 nonce, + uint256 deadline, + address depositor, + address allocator, + ResetPeriod resetPeriod, + Scope scope, + bytes32 claimHash, + CompactCategory compactCategory, + string calldata witness, + bytes calldata signature + ) external returns (uint256 id); + + /** + * @notice External payable function for depositing multiple tokens using Permit2 + * authorization in a single transaction. The first token id can optionally represent native + * tokens by providing the null address and an amount matching msg.value. The depositor must + * approve Permit2 to transfer the tokens on its behalf unless the tokens automatically + * grant approval to Permit2. The ERC6909 token amounts received by the recipient are derived + * from the differences between starting and ending balances held in the resource locks, + * which may differ from the amounts transferred depending on the implementation details of + * the respective tokens. The Permit2 authorization signed by the depositor must contain a + * CompactDeposit witness containing the allocator, the reset period, the scope, and the + * intended recipient of the deposits. + * @param depositor The account signing the permit2 authorization and depositing the tokens. + * @param permitted Array of token permissions specifying the deposited tokens and amounts. + * @param nonce The Permit2 nonce for the signature. + * @param deadline The timestamp until which the signature is valid. + * @param allocator The address of the allocator mediating the resource locks. + * @param resetPeriod The duration after which the resource locks can be reset once forced withdrawals are initiated. + * @param scope The scope of the resource locks (multichain or single chain). + * @param recipient The address that will receive the corresponding ERC6909 tokens. + * @param signature The Permit2 signature from the depositor authorizing the deposits. + * @return ids Array of ERC6909 token identifiers for the associated resource locks. + */ + function deposit( + address depositor, + ISignatureTransfer.TokenPermissions[] calldata permitted, + uint256 nonce, + uint256 deadline, + address allocator, + ResetPeriod resetPeriod, + Scope scope, + address recipient, + bytes calldata signature + ) external payable returns (uint256[] memory ids); + + /** + * @notice External payable function for depositing multiple tokens using Permit2 + * authorization and registering a compact in a single transaction. The first token id can + * optionally represent native tokens by providing the null address and an amount matching + * msg.value. The depositor must approve Permit2 to transfer the tokens on its behalf unless + * the tokens automatically grant approval to Permit2. The ERC6909 token amounts received by + * the depositor are derived from the differences between starting and ending balances held + * in the resource locks, which may differ from the amounts transferred depending on the + * implementation details of the respective tokens. The Permit2 authorization signed by the + * depositor must contain a BatchActivation witness containing the ids of the resource locks + * and an associated Compact, BatchCompact, or MultichainCompact payload matching the + * specified compact category. + * @param depositor The account signing the permit2 authorization and depositing the tokens. + * @param permitted Array of token permissions specifying the deposited tokens and amounts. + * @param nonce The Permit2 nonce for the signature. + * @param deadline The timestamp until which the signature is valid. + * @param allocator The address of the allocator mediating the resource locks. + * @param resetPeriod The duration after which the resource locks can be reset once forced withdrawals are initiated. + * @param scope The scope of the resource locks (multichain or single chain). + * @param claimHash A bytes32 hash derived from the details of the compact. + * @param compactCategory The category of the compact being registered (Compact, BatchCompact, or MultichainCompact). + * @param witness Additional data used in generating the claim hash. + * @param signature The Permit2 signature from the depositor authorizing the deposits. + * @return ids Array of ERC6909 token identifiers for the associated resource locks. + */ + function depositAndRegister( + address depositor, + ISignatureTransfer.TokenPermissions[] calldata permitted, + uint256 nonce, + uint256 deadline, + address allocator, + ResetPeriod resetPeriod, + Scope scope, + bytes32 claimHash, + CompactCategory compactCategory, + string calldata witness, + bytes calldata signature + ) external payable returns (uint256[] memory ids); + + /** + * @notice Transfers ERC6909 tokens to a single recipient with allocator approval. + * @param transfer A BasicTransfer struct containing the following: + * - allocatorSignature Authorization signature from the allocator. + * - nonce Parameter enforcing replay protection, scoped to the allocator. + * - expires Timestamp after which the transfer cannot be executed. + * - id The ERC6909 token identifier of the resource lock. + * - amount The amount of tokens to transfer. + * - recipient The account that will receive the tokens. + * @return Whether the transfer was successful. + */ + function allocatedTransfer(BasicTransfer calldata transfer) external returns (bool); + + /** + * @notice Withdraws underlying tokens to a single recipient with allocator approval. + * @param withdrawal A BasicTransfer struct containing the following: + * - allocatorSignature Authorization signature from the allocator. + * - nonce Parameter enforcing replay protection, scoped to the allocator. + * - expires Timestamp after which the withdrawal cannot be executed. + * - id The ERC6909 token identifier of the resource lock. + * - amount The amount of tokens to withdraw. + * - recipient The account that will receive the tokens. + * @return Whether the withdrawal was successful. + */ + function allocatedWithdrawal(BasicTransfer calldata withdrawal) external returns (bool); + + /** + * @notice Transfers ERC6909 tokens to multiple recipients with allocator approval. + * @param transfer A SplitTransfer struct containing the following: + * - allocatorSignature Authorization signature from the allocator. + * - nonce Parameter enforcing replay protection, scoped to the allocator. + * - expires Timestamp after which the transfer cannot be executed. + * - id The ERC6909 token identifier of the resource lock. + * - recipients Array of SplitComponents, each containing: + * - claimant The account that will receive tokens. + * - amount The amount of tokens the claimant will receive. + * @return Whether the transfer was successful. + */ + function allocatedTransfer(SplitTransfer calldata transfer) external returns (bool); + + /** + * @notice Withdraws underlying tokens to multiple recipients with allocator approval. + * @param withdrawal A SplitTransfer struct containing the following: + * - allocatorSignature Authorization signature from the allocator. + * - nonce Parameter enforcing replay protection, scoped to the allocator. + * - expires Timestamp after which the withdrawal cannot be executed. + * - id The ERC6909 token identifier of the resource lock. + * - recipients Array of SplitComponents, each containing: + * - claimant The account that will receive tokens. + * - amount The amount of tokens the claimant will receive. + * @return Whether the withdrawal was successful. + */ + function allocatedWithdrawal(SplitTransfer calldata withdrawal) external returns (bool); + + /** + * @notice Transfers ERC6909 tokens from multiple resource locks to a single recipient with + * allocator approval. + * @param transfer A BatchTransfer struct containing the following: + * - allocatorSignature Authorization signature from the allocator. + * - nonce Parameter enforcing replay protection, scoped to the allocator. + * - expires Timestamp after which the transfer cannot be executed. + * - transfers Array of TransferComponents, each containing: + * - id The ERC6909 token identifier of the resource lock. + * - amount The amount of tokens to transfer. + * - recipient The account that will receive all tokens. + * @return Whether the transfer was successful. + */ + function allocatedTransfer(BatchTransfer calldata transfer) external returns (bool); + + /** + * @notice Withdraws underlying tokens from multiple resource locks to a single recipient + * with allocator approval. + * @param withdrawal A BatchTransfer struct containing the following: + * - allocatorSignature Authorization signature from the allocator. + * - nonce Parameter enforcing replay protection, scoped to the allocator. + * - expires Timestamp after which the withdrawal cannot be executed. + * - transfers Array of TransferComponents, each containing: + * - id The ERC6909 token identifier of the resource lock. + * - amount The amount of tokens to withdraw. + * - recipient The account that will receive all tokens. + * @return Whether the withdrawal was successful. + */ + function allocatedWithdrawal(BatchTransfer calldata withdrawal) external returns (bool); + + /** + * @notice Transfers ERC6909 tokens from multiple resource locks to multiple recipients + * with allocator approval. + * @param transfer A SplitBatchTransfer struct containing the following: + * - allocatorSignature Authorization signature from the allocator. + * - nonce Parameter enforcing replay protection, scoped to the allocator. + * - expires Timestamp after which the transfer cannot be executed. + * - transfers Array of SplitByIdComponents, each containing: + * - id The ERC6909 token identifier of the resource lock. + * - portions Array of SplitComponents, each containing: + * - claimant The account that will receive tokens. + * - amount The amount of tokens the claimant will receive. + * @return Whether the transfer was successful. + */ + function allocatedTransfer(SplitBatchTransfer calldata transfer) external returns (bool); + + /** + * @notice Withdraws underlying tokens from multiple resource locks to multiple recipients + * with allocator approval. + * @param withdrawal A SplitBatchTransfer struct containing the following: + * - allocatorSignature Authorization signature from the allocator. + * - nonce Parameter enforcing replay protection, scoped to the allocator. + * - expires Timestamp after which the withdrawal cannot be executed. + * - transfers Array of SplitByIdComponents, each containing: + * - id The ERC6909 token identifier of the resource lock. + * - portions Array of SplitComponents, each containing: + * - claimant The account that will receive tokens. + * - amount The amount of tokens the claimant will receive. + * @return Whether the withdrawal was successful. + */ + function allocatedWithdrawal(SplitBatchTransfer calldata withdrawal) external returns (bool); + + /** + * @notice External function to initiate a forced withdrawal for a resource lock. Once + * enabled, forced withdrawals can be executed after the reset period has elapsed. The + * withdrawableAt timestamp returned will be the current timestamp plus the reset period + * associated with the resource lock. + * @param id The ERC6909 token identifier for the resource lock. + * @return withdrawableAt The timestamp at which tokens become withdrawable. + */ + function enableForcedWithdrawal(uint256 id) external returns (uint256 withdrawableAt); + + /** + * @notice External function to disable a previously enabled forced withdrawal for a + * resource lock. + * @param id The ERC6909 token identifier for the resource lock. + * @return Whether the forced withdrawal was successfully disabled. + */ + function disableForcedWithdrawal(uint256 id) external returns (bool); + + /** + * @notice External function to execute a forced withdrawal from a resource lock after the + * reset period has elapsed. The tokens will be withdrawn to the specified recipient in the + * amount requested. The ERC6909 token balance of the caller will be reduced by the + * difference in the balance held by the resource lock before and after the withdrawal, + * which may differ from the provided amount depending on the underlying token in question. + * @param id The ERC6909 token identifier for the resource lock. + * @param recipient The account that will receive the withdrawn tokens. + * @param amount The amount of tokens to withdraw. + * @return Whether the forced withdrawal was successfully executed. + */ + function forcedWithdrawal(uint256 id, address recipient, uint256 amount) external returns (bool); + + /** + * @notice External function to register a claim hash and its associated EIP-712 typehash. + * The registered claim hash will remain valid for the specified duration. Once expired, the + * claim hash can no longer be used to initiate claims. + * @param claimHash A bytes32 hash derived from the details of the compact. + * @param typehash The EIP-712 typehash associated with the registered claim hash. + * @param duration The duration for which the claim hash remains valid. + * @return Whether the claim hash was successfully registered. + */ + function register(bytes32 claimHash, bytes32 typehash, uint256 duration) external returns (bool); + + /** + * @notice External function to register multiple claim hashes and their associated EIP-712 + * typehashes in a single call. All registered claim hashes will remain valid for the + * specified duration. Once expired, the claim hashes can no longer be used to initiate + * claims. + * @param claimHashesAndTypehashes Array of [claimHash, typehash] pairs for registration. + * @param duration The duration for which the claim hashes remain valid. + * @return Whether all claim hashes were successfully registered. + */ + function register(bytes32[2][] calldata claimHashesAndTypehashes, uint256 duration) external returns (bool); + + /** + * @notice External function for consuming allocator nonces. Only callable by a registered + * allocator. Once consumed, any compact payloads that utilize those nonces cannot be claimed. + * @param nonces Array of nonces to be consumed. + * @return Whether all nonces were successfully consumed. + */ + function consume(uint256[] calldata nonces) external returns (bool); + + /** + * @notice External function for registering an allocator. Can be called by anyone if one + * of three conditions is met: the caller is the allocator address being registered, the + * allocator address contains code, or a proof is supplied representing valid create2 + * deployment parameters that resolve to the supplied allocator address. + * @param allocator The address to register as an allocator. + * @param proof An 85-byte value containing create2 address derivation parameters (0xff ++ factory ++ salt ++ initcode hash). + * @return allocatorId A unique identifier assigned to the registered allocator. + */ + function __registerAllocator(address allocator, bytes calldata proof) external returns (uint96 allocatorId); + + /** + * @notice External view function for checking the forced withdrawal status of a resource + * lock for a given account. Returns both the current status (disabled, pending, or enabled) + * and the timestamp at which forced withdrawals will be enabled (if status is pending) or + * became enabled (if status is enabled). + * @param account The account to get the forced withdrawal status for. + * @param id The ERC6909 token identifier of the resource lock. + * @return status The current ForcedWithdrawalStatus (disabled, pending, or enabled). + * @return forcedWithdrawalAvailableAt The timestamp at which tokens become withdrawable if status is pending. + */ + function getForcedWithdrawalStatus(address account, uint256 id) external view returns (ForcedWithdrawalStatus status, uint256 forcedWithdrawalAvailableAt); + + /** + * @notice External view function for checking the registration status of a compact. Returns + * both whether the claim hash is currently active and when it expires (if it is active). + * @param sponsor The account that registered the compact. + * @param claimHash A bytes32 hash derived from the details of the compact. + * @param typehash The EIP-712 typehash associated with the registered claim hash. + * @return isActive Whether the compact registration is currently active. + * @return expires The timestamp at which the compact registration expires. + */ + function getRegistrationStatus(address sponsor, bytes32 claimHash, bytes32 typehash) external view returns (bool isActive, uint256 expires); + + /** + * @notice External view function for retrieving the details of a resource lock. Returns the + * underlying token, the mediating allocator, the reset period, and the scope. + * @param id The ERC6909 token identifier of the resource lock. + * @return token The address of the underlying token (or address(0) for native tokens). + * @return allocator The account of the allocator mediating the resource lock. + * @return resetPeriod The duration after which the resource lock can be reset once a forced withdrawal is initiated. + * @return scope The scope of the resource lock (multichain or single chain). + */ + function getLockDetails(uint256 id) external view returns (address token, address allocator, ResetPeriod resetPeriod, Scope scope); + + /** + * @notice External view function for checking whether a specific nonce has been consumed by + * an allocator. Once consumed, a nonce cannot be reused for claims mediated by that allocator. + * @param nonce The nonce to check. + * @param allocator The account of the allocator. + * @return consumed Whether the nonce has been consumed. + */ + function hasConsumedAllocatorNonce(uint256 nonce, address allocator) external view returns (bool consumed); + + /** + * @notice External pure function for returning the domain separator of the contract. + * @return domainSeparator A bytes32 representing the domain separator for the contract. + */ + function DOMAIN_SEPARATOR() external view returns (bytes32 domainSeparator); + + /** + * @notice External pure function for returning the name of the contract. + * @return A string representing the name of the contract. + */ + function name() external pure returns (string memory); + + error InvalidToken(address token); + error Expired(uint256 expiration); + error InvalidSignature(); + error PrematureWithdrawal(uint256 id); + error ForcedWithdrawalAlreadyDisabled(address account, uint256 id); + error UnallocatedTransfer(address operator, address from, address to, uint256 id, uint256 amount); + error InvalidBatchAllocation(); + error InvalidRegistrationProof(address allocator); + error InvalidBatchDepositStructure(); + error AllocatedAmountExceeded(uint256 allocatedAmount, uint256 providedAmount); + error InvalidScope(uint256 id); + error InvalidDepositTokenOrdering(); + error InvalidDepositBalanceChange(); + error Permit2CallFailed(); + error InvalidRegistrationDuration(uint256 duration); + error ReentrantCall(address existingCaller); +} diff --git a/src/interfaces/ITheCompactClaims.sol b/src/interfaces/ITheCompactClaims.sol new file mode 100644 index 0000000..a12a8f2 --- /dev/null +++ b/src/interfaces/ITheCompactClaims.sol @@ -0,0 +1,291 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { BasicClaim, QualifiedClaim, ClaimWithWitness, QualifiedClaimWithWitness, SplitClaim, SplitClaimWithWitness, QualifiedSplitClaim, QualifiedSplitClaimWithWitness } from "../types/Claims.sol"; + +import { + BatchClaim, + QualifiedBatchClaim, + BatchClaimWithWitness, + QualifiedBatchClaimWithWitness, + SplitBatchClaim, + SplitBatchClaimWithWitness, + QualifiedSplitBatchClaim, + QualifiedSplitBatchClaimWithWitness +} from "../types/BatchClaims.sol"; + +import { + MultichainClaim, + QualifiedMultichainClaim, + MultichainClaimWithWitness, + QualifiedMultichainClaimWithWitness, + SplitMultichainClaim, + SplitMultichainClaimWithWitness, + QualifiedSplitMultichainClaim, + QualifiedSplitMultichainClaimWithWitness, + ExogenousMultichainClaim, + ExogenousQualifiedMultichainClaim, + ExogenousMultichainClaimWithWitness, + ExogenousQualifiedMultichainClaimWithWitness, + ExogenousSplitMultichainClaim, + ExogenousSplitMultichainClaimWithWitness, + ExogenousQualifiedSplitMultichainClaim, + ExogenousQualifiedSplitMultichainClaimWithWitness +} from "../types/MultichainClaims.sol"; + +import { + BatchMultichainClaim, + QualifiedBatchMultichainClaim, + BatchMultichainClaimWithWitness, + QualifiedBatchMultichainClaimWithWitness, + SplitBatchMultichainClaim, + SplitBatchMultichainClaimWithWitness, + QualifiedSplitBatchMultichainClaim, + QualifiedSplitBatchMultichainClaimWithWitness, + ExogenousBatchMultichainClaim, + ExogenousQualifiedBatchMultichainClaim, + ExogenousBatchMultichainClaimWithWitness, + ExogenousQualifiedBatchMultichainClaimWithWitness, + ExogenousSplitBatchMultichainClaim, + ExogenousSplitBatchMultichainClaimWithWitness, + ExogenousQualifiedSplitBatchMultichainClaim, + ExogenousQualifiedSplitBatchMultichainClaimWithWitness +} from "../types/BatchMultichainClaims.sol"; + +/** + * @title The Compact — Claims Interface + * @custom:version 0 (early-stage proof-of-concept) + * @author 0age (0age.eth) + * @notice Claim endpoints can only be called by the arbiter indicated on the associated + * compact, and are used to settle the compact in question. There are 96 endpoints in total, + * based on all the various possible combinations of a number of factors: + * - transfer vs. withdrawal: whether to transfer the claimed ERC6909 tokens directly, or to + * withdraw the underlying claimed tokens (e.g. calling `claim` or `claimAndWithdraw`) + * - unqualified vs qualified: whether the allocator is cosigning the same claim hash as the + * sponsor, or if they are signing for additional data. This can be an arbitrary EIP-712 + * payload, with one exception: the first element must be the claim hash, which will be + * provided by The Compact directly as part of signature verification. These claims take + * two additional arguments: the EIP-712 typehash used in the qualification, and the data + * payload (not including the first claim hash argument). This data can then be utilized + * by the arbiter to inform and constrain the claim. + * - no witness vs. witness: whether or not the sponsor has elected to extend the Compact + * EIP-712 payload with an additional witness argument (generally using a new struct). + * When witness data is utilized, the call takes two additional arguments: one + * representing the EIP-712 hash of the witness data (or the direct data if it is a single + * value) and one representing the additional EIP-712 typestring that will extend the + * default arguments to include the witness. + * - whether or not to perform a "split": with no split, the caller specifies a single + * recipient, whereas with a split the caller specifies multiple recipients and respective + * amounts. + * - whether or not to utilize a "batch" of resource locks on a specific chain: When the + * sponsor is utilizing multiple resource locks on a specific chain, they will sign or + * register a `BatchCompact` EIP-712 payload. (Single-chain claims sign or register a + * `Compact` EIP-712 payload). + * - whether or not to include resource locks on a single chain or multiple chains; in + * the event of a multichain compact, there are _two_ additional endpoints per option, + * one for claims against the first referenced chain where the domain matches the one + * signed for or registered against (the "notarized" chain) and one for claims against + * other chains where the resource locks indicate a multichain scope (the "exogenous" + * chains). When the sponsor is utilizing multiple resource locks across multiple chains, + * they will sign a `MultichainCompact` EIP-712 payload. When claiming these for the + * notarized chain, an array of bytes32 values representing additional chain "segments" + * is provided. When claiming against an exogenous chain, the additional chains array + * begins with the notarized chain and then includes values for all exogenous chains + * excluding the one being claimed against, and a chain index is supplied indicating the + * location in the list of segments of the current chain (a value of 0 means that it is) + * the first exogenous chain) as well as a `notarizedChainId` representing the chainId + * for the domain that the multichain claim was signed against. + */ +interface ITheCompactClaims { + function claim(BasicClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(BasicClaim calldata claimPayload) external returns (bool); + + function claim(QualifiedClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(QualifiedClaim calldata claimPayload) external returns (bool); + + function claim(ClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(ClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(QualifiedClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(QualifiedClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(SplitClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(SplitClaim calldata claimPayload) external returns (bool); + + function claim(QualifiedSplitClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(QualifiedSplitClaim calldata claimPayload) external returns (bool); + + function claim(SplitClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(SplitClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(QualifiedSplitClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(QualifiedSplitClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(BatchClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(BatchClaim calldata claimPayload) external returns (bool); + + function claim(QualifiedBatchClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(QualifiedBatchClaim calldata claimPayload) external returns (bool); + + function claim(BatchClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(BatchClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(QualifiedBatchClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(QualifiedBatchClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(SplitBatchClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(SplitBatchClaim calldata claimPayload) external returns (bool); + + function claim(QualifiedSplitBatchClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(QualifiedSplitBatchClaim calldata claimPayload) external returns (bool); + + function claim(SplitBatchClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(SplitBatchClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(QualifiedSplitBatchClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(QualifiedSplitBatchClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(MultichainClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(MultichainClaim calldata claimPayload) external returns (bool); + + function claim(ExogenousMultichainClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(ExogenousMultichainClaim calldata claimPayload) external returns (bool); + + function claim(QualifiedMultichainClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(QualifiedMultichainClaim calldata claimPayload) external returns (bool); + + function claim(ExogenousQualifiedMultichainClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(ExogenousQualifiedMultichainClaim calldata claimPayload) external returns (bool); + + function claim(MultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(MultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(ExogenousMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(ExogenousMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(QualifiedMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(QualifiedMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(ExogenousQualifiedMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(ExogenousQualifiedMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(SplitMultichainClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(SplitMultichainClaim calldata claimPayload) external returns (bool); + + function claim(ExogenousSplitMultichainClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(ExogenousSplitMultichainClaim calldata claimPayload) external returns (bool); + + function claim(QualifiedSplitMultichainClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(QualifiedSplitMultichainClaim calldata claimPayload) external returns (bool); + + function claim(ExogenousQualifiedSplitMultichainClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(ExogenousQualifiedSplitMultichainClaim calldata claimPayload) external returns (bool); + + function claim(SplitMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(SplitMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(ExogenousSplitMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(ExogenousSplitMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(QualifiedSplitMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(QualifiedSplitMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(ExogenousQualifiedSplitMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(ExogenousQualifiedSplitMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(BatchMultichainClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(BatchMultichainClaim calldata claimPayload) external returns (bool); + + function claim(ExogenousBatchMultichainClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(ExogenousBatchMultichainClaim calldata claimPayload) external returns (bool); + + function claim(QualifiedBatchMultichainClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(QualifiedBatchMultichainClaim calldata claimPayload) external returns (bool); + + function claim(ExogenousQualifiedBatchMultichainClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(ExogenousQualifiedBatchMultichainClaim calldata claimPayload) external returns (bool); + + function claim(BatchMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(BatchMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(ExogenousBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(ExogenousBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(QualifiedBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(QualifiedBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(ExogenousQualifiedBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(ExogenousQualifiedBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(SplitBatchMultichainClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(SplitBatchMultichainClaim calldata claimPayload) external returns (bool); + + function claim(ExogenousSplitBatchMultichainClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(ExogenousSplitBatchMultichainClaim calldata claimPayload) external returns (bool); + + function claim(QualifiedSplitBatchMultichainClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(QualifiedSplitBatchMultichainClaim calldata claimPayload) external returns (bool); + + function claim(ExogenousQualifiedSplitBatchMultichainClaim calldata claimPayload) external returns (bool); + + function claimAndWithdraw(ExogenousQualifiedSplitBatchMultichainClaim calldata claimPayload) external returns (bool); + + function claim(SplitBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(SplitBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(ExogenousSplitBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(ExogenousSplitBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(QualifiedSplitBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(QualifiedSplitBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claim(ExogenousQualifiedSplitBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool); + + function claimAndWithdraw(ExogenousQualifiedSplitBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool); +} diff --git a/src/lib/AllocatorLogic.sol b/src/lib/AllocatorLogic.sol new file mode 100644 index 0000000..72d8927 --- /dev/null +++ b/src/lib/AllocatorLogic.sol @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { ResetPeriod } from "../types/ResetPeriod.sol"; +import { Scope } from "../types/Scope.sol"; + +import { ConsumerLib } from "./ConsumerLib.sol"; +import { EfficiencyLib } from "./EfficiencyLib.sol"; +import { IdLib } from "./IdLib.sol"; +import { ValidityLib } from "./ValidityLib.sol"; + +/** + * @title AllocatorLogic + * @notice Inherited contract implementing internal functions with logic for registering + * new allocators, allowing registered allocators to directly consume nonces within their + * scope, and querying for information on nonce consumption and lock details. + */ +contract AllocatorLogic { + using IdLib for uint96; + using IdLib for uint256; + using IdLib for address; + using ConsumerLib for uint256; + using EfficiencyLib for uint256; + using ValidityLib for address; + + /** + * @notice Internal function for marking allocator nonces as consumed. Once consumed, a nonce + * cannot be reused to claim resource locks referencing that allocator. Called by the external + * consume function and during claim processing to prevent replay attacks. + * @param nonces Array of nonces to mark as consumed for the calling allocator. + * @return Whether all nonces were successfully marked as consumed. + */ + function _consume(uint256[] calldata nonces) internal returns (bool) { + // NOTE: this may not be necessary, consider removing + msg.sender.usingAllocatorId().mustHaveARegisteredAllocator(); + + unchecked { + uint256 i; + + assembly ("memory-safe") { + i := nonces.offset + } + + uint256 end = i + (nonces.length << 5); + uint256 nonce; + for (; i < end; i += 0x20) { + assembly ("memory-safe") { + nonce := calldataload(i) + } + nonce.consumeNonceAsAllocator(msg.sender); + } + } + + return true; + } + + /** + * @notice Internal function for registering an allocator. Validates that one of three + * conditions is met: caller is the allocator address, allocator address contains code, or + * proof represents valid create2 deployment parameters that derive the allocator address. + * @param allocator The address to register as an allocator. + * @param proof An 85-byte value containing create2 address derivation parameters. + * @return allocatorId A unique identifier assigned to the registered allocator. + */ + function _registerAllocator(address allocator, bytes calldata proof) internal returns (uint96 allocatorId) { + allocator = uint256(uint160(allocator)).asSanitizedAddress(); + if (!allocator.canBeRegistered(proof)) { + assembly ("memory-safe") { + // revert InvalidRegistrationProof(allocator) + mstore(0, 0x4e7f492b) + mstore(0x20, allocator) + revert(0x1c, 0x24) + } + } + + allocatorId = allocator.register(); + } + + /** + * @notice Internal view function for checking whether a specific nonce has been consumed by + * an allocator. + * @param nonce The nonce to check. + * @param allocator The address of the allocator. + * @return Whether the nonce has been consumed. + */ + function _hasConsumedAllocatorNonce(uint256 nonce, address allocator) internal view returns (bool) { + return allocator.hasConsumedAllocatorNonce(nonce); + } + + /** + * @notice Internal view function for retrieving the details of a resource lock. + * @param id The ERC6909 token identifier for the resource lock. + * @return token The address of the underlying token (or address(0) for native tokens). + * @return allocator The address of the allocator mediating the resource lock. + * @return resetPeriod The duration after which the underlying tokens can be withdrawn once a forced withdrawal is initiated. + * @return scope The scope of the resource lock (multichain or single chain). + */ + function _getLockDetails(uint256 id) internal view returns (address token, address allocator, ResetPeriod resetPeriod, Scope scope) { + token = id.toToken(); + allocator = id.toAllocatorId().toRegisteredAllocator(); + resetPeriod = id.toResetPeriod(); + scope = id.toScope(); + } +} diff --git a/src/lib/ClaimHashFunctionCastLib.sol b/src/lib/ClaimHashFunctionCastLib.sol new file mode 100644 index 0000000..e318de9 --- /dev/null +++ b/src/lib/ClaimHashFunctionCastLib.sol @@ -0,0 +1,1021 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { BasicClaim, QualifiedClaim, ClaimWithWitness, QualifiedClaimWithWitness, SplitClaim, SplitClaimWithWitness, QualifiedSplitClaim, QualifiedSplitClaimWithWitness } from "../types/Claims.sol"; + +import { + BatchClaim, + QualifiedBatchClaim, + BatchClaimWithWitness, + QualifiedBatchClaimWithWitness, + SplitBatchClaim, + SplitBatchClaimWithWitness, + QualifiedSplitBatchClaim, + QualifiedSplitBatchClaimWithWitness +} from "../types/BatchClaims.sol"; + +import { + MultichainClaim, + QualifiedMultichainClaim, + MultichainClaimWithWitness, + QualifiedMultichainClaimWithWitness, + SplitMultichainClaim, + SplitMultichainClaimWithWitness, + QualifiedSplitMultichainClaim, + QualifiedSplitMultichainClaimWithWitness, + ExogenousMultichainClaim, + ExogenousQualifiedMultichainClaim, + ExogenousMultichainClaimWithWitness, + ExogenousQualifiedMultichainClaimWithWitness, + ExogenousSplitMultichainClaim, + ExogenousSplitMultichainClaimWithWitness, + ExogenousQualifiedSplitMultichainClaim, + ExogenousQualifiedSplitMultichainClaimWithWitness +} from "../types/MultichainClaims.sol"; + +import { + BatchMultichainClaim, + QualifiedBatchMultichainClaim, + BatchMultichainClaimWithWitness, + QualifiedBatchMultichainClaimWithWitness, + SplitBatchMultichainClaim, + SplitBatchMultichainClaimWithWitness, + QualifiedSplitBatchMultichainClaim, + QualifiedSplitBatchMultichainClaimWithWitness, + ExogenousBatchMultichainClaim, + ExogenousQualifiedBatchMultichainClaim, + ExogenousBatchMultichainClaimWithWitness, + ExogenousQualifiedBatchMultichainClaimWithWitness, + ExogenousSplitBatchMultichainClaim, + ExogenousSplitBatchMultichainClaimWithWitness, + ExogenousQualifiedSplitBatchMultichainClaim, + ExogenousQualifiedSplitBatchMultichainClaimWithWitness +} from "../types/BatchMultichainClaims.sol"; + +/** + * @title ClaimHashFunctionCastLib + * @notice Libray contract implementing function casts used throughout the codebase, + * particularly as part of processing claims. The input function operates on a + * function that takes some argument that differs from what is currently available. + * The output function modifies one or more argument types so that they match the + * arguments that are being used to call the function. Note that from the perspective + * of the function being modified, the original type is still in force; great care + * should be taken to preserve offsets and general structure between the two structs. + * @dev Note that some of these function casts may no longer be in use. + */ +library ClaimHashFunctionCastLib { + /** + * @notice Function cast to provide a BasicClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib._toBasicMessageHash`. + */ + function usingBasicClaim(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32) fnIn) + internal + pure + returns (function (BasicClaim calldata, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a SplitClaim calldata struct while + * treating it as a BasicClaim calldata struct. + * @param fnIn Function pointer to `ClaimHashLib._toBasicMessageHash(BasicClaim calldata)`. + * @return fnOut Modified function used in `ClaimHashLib.toClaimHash(SplitClaim calldata)`. + */ + function usingSplitClaim(function (BasicClaim calldata) internal view returns (bytes32) fnIn) internal pure returns (function (SplitClaim calldata) internal view returns (bytes32) fnOut) { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a BatchClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib._toBasicMessageHash(BatchClaim calldata)`. + */ + function usingBatchClaim(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32) fnIn) + internal + pure + returns (function (BatchClaim calldata, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a SplitBatchClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toClaimHash(SplitBatchClaim calldata)`. + */ + function usingSplitBatchClaim(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32) fnIn) + internal + pure + returns (function (SplitBatchClaim calldata, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a MultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib._toMultichainMessageHash(MultichainClaim calldata)`. + */ + function usingMultichainClaim(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32) fnIn) + internal + pure + returns (function (MultichainClaim calldata, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a SplitMultichainClaim calldata struct while + * treating it as a MultichainClaim calldata struct. + * @param fnIn Function pointer to `ClaimHashLib._toMultichainMessageHash(MultichainClaim calldata)`. + * @return fnOut Modified function used in `ClaimHashLib.toClaimHash(SplitMultichainClaim calldata)`. + */ + function usingSplitMultichainClaim(function (MultichainClaim calldata) internal view returns (bytes32) fnIn) + internal + pure + returns (function (SplitMultichainClaim calldata) internal view returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a BatchMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toClaimHash(BatchMultichainClaim calldata)`. + */ + function usingBatchMultichainClaim(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32) fnIn) + internal + pure + returns (function (BatchMultichainClaim calldata, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a SplitBatchMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toClaimHash(SplitBatchMultichainClaim calldata)`. + */ + function usingSplitBatchMultichainClaim(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32) fnIn) + internal + pure + returns (function (SplitBatchMultichainClaim calldata, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide an ExogenousMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toClaimHash(ExogenousMultichainClaim calldata)`. + */ + function usingExogenousMultichainClaim(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32) fnIn) + internal + pure + returns (function (ExogenousMultichainClaim calldata, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide an ExogenousSplitMultichainClaim calldata struct while + * treating it as an ExogenousMultichainClaim calldata struct. + * @param fnIn Function pointer to `ClaimHashLib._toExogenousMultichainMessageHash(ExogenousMultichainClaim calldata)`. + * @return fnOut Modified function used in `ClaimHashLib.toClaimHash(ExogenousSplitMultichainClaim calldata)`. + */ + function usingExogenousSplitMultichainClaim(function (ExogenousMultichainClaim calldata) internal view returns (bytes32) fnIn) + internal + pure + returns (function (ExogenousSplitMultichainClaim calldata) internal view returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide an ExogenousBatchMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toClaimHash(ExogenousBatchMultichainClaim calldata)`. + */ + function usingExogenousBatchMultichainClaim(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32) fnIn) + internal + pure + returns (function (ExogenousBatchMultichainClaim calldata, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide an ExogenousSplitBatchMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toClaimHash(ExogenousSplitBatchMultichainClaim calldata)`. + */ + function usingExogenousSplitBatchMultichainClaim(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32) fnIn) + internal + pure + returns (function (ExogenousSplitBatchMultichainClaim calldata, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMessageHashWithQualificationHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(QualifiedClaim calldata)`. + */ + function usingQualifiedClaim(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (QualifiedClaim calldata, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedSplitClaim calldata struct while + * treating it as a QualifiedClaim calldata struct. + * @param fnIn Function pointer to `ClaimHashLib._toQualifiedMessageHash(QualifiedClaim calldata)`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(QualifiedSplitClaim calldata)`. + */ + function usingQualifiedSplitClaim(function (QualifiedClaim calldata) internal view returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (QualifiedSplitClaim calldata) internal view returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedBatchClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMessageHashWithQualificationHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(QualifiedBatchClaim calldata)`. + */ + function usingQualifiedBatchClaim(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (QualifiedBatchClaim calldata, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedSplitBatchClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMessageHashWithQualificationHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(QualifiedSplitBatchClaim calldata)`. + */ + function usingQualifiedSplitBatchClaim(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (QualifiedSplitBatchClaim calldata, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMessageHashWithQualificationHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(QualifiedMultichainClaim calldata)`. + */ + function usingQualifiedMultichainClaim(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (QualifiedMultichainClaim calldata, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedSplitMultichainClaim calldata struct while + * treating it as a QualifiedMultichainClaim calldata struct. + * @param fnIn Function pointer to `ClaimHashLib._toQualifiedMultichainMessageHash(QualifiedMultichainClaim calldata)`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(QualifiedSplitMultichainClaim calldata)`. + */ + function usingQualifiedSplitMultichainClaim(function (QualifiedMultichainClaim calldata) internal view returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (QualifiedSplitMultichainClaim calldata) internal view returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedBatchMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMessageHashWithQualificationHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(QualifiedBatchMultichainClaim calldata)`. + */ + function usingQualifiedBatchMultichainClaim(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (QualifiedBatchMultichainClaim calldata, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedSplitBatchMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMessageHashWithQualificationHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(QualifiedSplitBatchMultichainClaim calldata)`. + */ + function usingQualifiedSplitBatchMultichainClaim(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (QualifiedSplitBatchMultichainClaim calldata, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide an ExogenousQualifiedMultichainClaim calldata struct + * while treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMessageHashWithQualificationHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(ExogenousQualifiedMultichainClaim calldata)`. + */ + function usingExogenousQualifiedMultichainClaim(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (ExogenousQualifiedMultichainClaim calldata, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide an ExogenousQualifiedSplitMultichainClaim calldata + * struct while treating it as an ExogenousQualifiedMultichainClaim calldata struct. + * @param fnIn Function pointer to `ClaimHashLib._toExogenousQualifiedMultichainMessageHash(ExogenousQualifiedMultichainClaim calldata)`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(ExogenousQualifiedSplitMultichainClaim calldata)`. + */ + function usingExogenousQualifiedSplitMultichainClaim(function (ExogenousQualifiedMultichainClaim calldata) internal view returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (ExogenousQualifiedSplitMultichainClaim calldata) internal view returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide an ExogenousQualifiedBatchMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMessageHashWithQualificationHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(ExogenousQualifiedBatchMultichainClaim calldata)`. + */ + function usingExogenousQualifiedBatchMultichainClaim(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (ExogenousQualifiedBatchMultichainClaim calldata, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide an ExogenousQualifiedSplitBatchMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMessageHashWithQualificationHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(ExogenousQualifiedSplitBatchMultichainClaim calldata)`. + */ + function usingExogenousQualifiedSplitBatchMultichainClaim(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (ExogenousQualifiedSplitBatchMultichainClaim calldata, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a MultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location with witness data. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMultichainClaimWithWitnessMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(MultichainClaimWithWitness calldata)`. + */ + function usingMultichainClaimWithWitness(function (uint256, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (MultichainClaimWithWitness calldata, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a SplitMultichainClaimWithWitness calldata struct while + * treating it as a MultichainClaimWithWitness calldata struct. + * @param fnIn Function pointer to `ClaimHashLib._toMultichainClaimWithWitnessMessageHash(MultichainClaimWithWitness calldata)`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(MultichainClaimWithWitness calldata)`. + */ + function usingSplitMultichainClaimWithWitness(function (MultichainClaimWithWitness calldata) internal view returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (SplitMultichainClaimWithWitness calldata) internal view returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a BatchMultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location with witness data. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMultichainClaimWithWitnessMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(BatchMultichainClaimWithWitness calldata)`. + */ + function usingBatchMultichainClaimWithWitness( + function (uint256, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnIn + ) + internal + pure + returns ( + function (BatchMultichainClaimWithWitness calldata, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a SplitBatchMultichainClaimWithWitness calldata struct + * while treating it as a uint256 representing a calldata pointer location with witness data. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMultichainClaimWithWitnessMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(SplitBatchMultichainClaimWithWitness calldata)`. + */ + function usingSplitBatchMultichainClaimWithWitness( + function (uint256, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnIn + ) + internal + pure + returns ( + function (SplitBatchMultichainClaimWithWitness calldata, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide an ExogenousMultichainClaimWithWitness calldata struct + * while treating it as a uint256 representing a calldata pointer location with witness data. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMultichainClaimWithWitnessMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(ExogenousMultichainClaimWithWitness calldata)`. + */ + function usingExogenousMultichainClaimWithWitness( + function (uint256, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnIn + ) + internal + pure + returns ( + function (ExogenousMultichainClaimWithWitness calldata, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide an ExogenousSplitMultichainClaimWithWitness calldata + * struct while treating it as an ExogenousMultichainClaimWithWitness calldata struct. + * @param fnIn Function pointer to `ClaimHashLib._toExogenousMultichainClaimWithWitnessMessageHash(ExogenousMultichainClaimWithWitness calldata)`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(ExogenousSplitMultichainClaimWithWitness calldata)`. + */ + function usingExogenousSplitMultichainClaimWithWitness(function (ExogenousMultichainClaimWithWitness calldata) internal view returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (ExogenousSplitMultichainClaimWithWitness calldata) internal view returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide an ExogenousBatchMultichainClaimWithWitness calldata + * struct while treating it as a uint256 representing a calldata pointer location with witness data. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMultichainClaimWithWitnessMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(ExogenousBatchMultichainClaimWithWitness calldata)`. + */ + function usingExogenousBatchMultichainClaimWithWitness( + function (uint256, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnIn + ) + internal + pure + returns ( + function (ExogenousBatchMultichainClaimWithWitness calldata, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide an ExogenousSplitBatchMultichainClaimWithWitness calldata + * struct while treating it as a uint256 representing a calldata pointer location with witness data. + * @param fnIn Function pointer to `ClaimHashLib._toGenericMultichainClaimWithWitnessMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(ExogenousSplitBatchMultichainClaimWithWitness calldata)`. + */ + function usingExogenousSplitBatchMultichainClaimWithWitness( + function (uint256, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) fnIn + ) + internal + pure + returns ( + function (ExogenousSplitBatchMultichainClaimWithWitness calldata, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32) + fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location with witness data. + * @param fnIn Function pointer to `ClaimHashLib._toGenericQualifiedClaimWithWitnessMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(QualifiedClaimWithWitness calldata)`. + */ + function usingQualifiedClaimWithWitness(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32, bytes32)) internal view returns (bytes32, bytes32, bytes32) fnIn) + internal + pure + returns (function (QualifiedClaimWithWitness calldata, uint256, function(uint256, uint256) internal view returns (bytes32, bytes32)) internal view returns (bytes32, bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedSplitClaimWithWitness calldata struct while + * treating it as a QualifiedClaimWithWitness calldata struct. + * @param fnIn Function pointer to `ClaimHashLib._toQualifiedClaimWithWitnessMessageHash(QualifiedClaimWithWitness calldata)`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(QualifiedSplitClaimWithWitness calldata)`. + */ + function usingQualifiedSplitClaimWithWitness(function (QualifiedClaimWithWitness calldata) internal view returns (bytes32) fnIn) + internal + pure + returns (function (QualifiedSplitClaimWithWitness calldata) internal view returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedBatchClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location with witness data. + * @param fnIn Function pointer to `ClaimHashLib._toGenericQualifiedClaimWithWitnessMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(QualifiedBatchClaimWithWitness calldata)`. + */ + function usingQualifiedBatchClaimWithWitness(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32, bytes32)) internal view returns (bytes32, bytes32, bytes32) fnIn) + internal + pure + returns (function (QualifiedBatchClaimWithWitness calldata, uint256, function(uint256, uint256) internal view returns (bytes32, bytes32)) internal view returns (bytes32, bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedSplitBatchClaimWithWitness calldata struct + * while treating it as a uint256 representing a calldata pointer location with witness data. + * @param fnIn Function pointer to `ClaimHashLib._toGenericQualifiedClaimWithWitnessMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(QualifiedSplitBatchClaimWithWitness calldata)`. + */ + function usingQualifiedSplitBatchClaimWithWitness(function (uint256, uint256, function(uint256, uint256) internal view returns (bytes32, bytes32)) internal view returns (bytes32, bytes32, bytes32) fnIn) + internal + pure + returns (function (QualifiedSplitBatchClaimWithWitness calldata, uint256, function(uint256, uint256) internal view returns (bytes32, bytes32)) internal view returns (bytes32, bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedMultichainClaimWithWitness calldata struct + * while treating it as a uint256 representing a calldata pointer location with witness data. + * @param fnIn Function pointer to `ClaimHashLib._toGenericQualifiedMultichainClaimWithWitnessMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(QualifiedMultichainClaimWithWitness calldata)`. + */ + function usingQualifiedMultichainClaimWithWitness( + function (uint256, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32, bytes32) fnIn + ) + internal + pure + returns ( + function (QualifiedMultichainClaimWithWitness calldata, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32, bytes32) + fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedSplitMultichainClaimWithWitness calldata struct + * while treating it as a QualifiedMultichainClaimWithWitness calldata struct. + * @param fnIn Function pointer to `ClaimHashLib._toQualifiedMultichainClaimWithWitnessMessageHash(QualifiedMultichainClaimWithWitness calldata)`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(QualifiedSplitMultichainClaimWithWitness calldata)`. + */ + function usingQualifiedSplitMultichainClaimWithWitness(function (QualifiedMultichainClaimWithWitness calldata) internal view returns (bytes32, bytes32, bytes32) fnIn) + internal + pure + returns (function (QualifiedSplitMultichainClaimWithWitness calldata) internal view returns (bytes32, bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedBatchMultichainClaimWithWitness calldata struct + * while treating it as a uint256 representing a calldata pointer location with witness data. + * @param fnIn Function pointer to `ClaimHashLib._toGenericQualifiedMultichainClaimWithWitnessMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(QualifiedBatchMultichainClaimWithWitness calldata)`. + */ + function usingQualifiedBatchMultichainClaimWithWitness( + function (uint256, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32, bytes32) fnIn + ) + internal + pure + returns ( + function (QualifiedBatchMultichainClaimWithWitness calldata, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32, bytes32) + fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedSplitBatchMultichainClaimWithWitness calldata struct + * while treating it as a uint256 representing a calldata pointer location with witness data. + * @param fnIn Function pointer to `ClaimHashLib._toGenericQualifiedMultichainClaimWithWitnessMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(QualifiedSplitBatchMultichainClaimWithWitness calldata)`. + */ + function usingQualifiedSplitBatchMultichainClaimWithWitness( + function (uint256, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32, bytes32) fnIn + ) + internal + pure + returns ( + function (QualifiedSplitBatchMultichainClaimWithWitness calldata, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32, bytes32) + fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide an ExogenousQualifiedMultichainClaimWithWitness calldata struct + * while treating it as a uint256 representing a calldata pointer location with witness data. + * @param fnIn Function pointer to `ClaimHashLib._toGenericQualifiedMultichainClaimWithWitnessMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(ExogenousQualifiedMultichainClaimWithWitness calldata)`. + */ + function usingExogenousQualifiedMultichainClaimWithWitness( + function (uint256, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32, bytes32) fnIn + ) + internal + pure + returns ( + function (ExogenousQualifiedMultichainClaimWithWitness calldata, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32, bytes32) + fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide an ExogenousQualifiedSplitMultichainClaimWithWitness calldata struct + * while treating it as an ExogenousQualifiedMultichainClaimWithWitness calldata struct. + * @param fnIn Function pointer to `ClaimHashLib._toExogenousQualifiedMultichainClaimWithWitnessMessageHash(ExogenousQualifiedMultichainClaimWithWitness calldata)`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(ExogenousQualifiedSplitMultichainClaimWithWitness calldata)`. + */ + function usingExogenousQualifiedSplitMultichainClaimWithWitness(function (ExogenousQualifiedMultichainClaimWithWitness calldata) internal view returns (bytes32, bytes32, bytes32) fnIn) + internal + pure + returns (function (ExogenousQualifiedSplitMultichainClaimWithWitness calldata) internal view returns (bytes32, bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide an ExogenousQualifiedBatchMultichainClaimWithWitness calldata struct + * while treating it as a uint256 representing a calldata pointer location with witness data. + * @param fnIn Function pointer to `ClaimHashLib._toGenericQualifiedMultichainClaimWithWitnessMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(ExogenousQualifiedBatchMultichainClaimWithWitness calldata)`. + */ + function usingExogenousQualifiedBatchMultichainClaimWithWitness( + function (uint256, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32, bytes32) fnIn + ) + internal + pure + returns ( + function (ExogenousQualifiedBatchMultichainClaimWithWitness calldata, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32, bytes32) + fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide an ExogenousQualifiedSplitBatchMultichainClaimWithWitness calldata struct + * while treating it as a uint256 representing a calldata pointer location with witness data. + * @param fnIn Function pointer to `ClaimHashLib._toGenericQualifiedMultichainClaimWithWitnessMessageHash`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(ExogenousQualifiedSplitBatchMultichainClaimWithWitness calldata)`. + */ + function usingExogenousQualifiedSplitBatchMultichainClaimWithWitness( + function (uint256, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32, bytes32) fnIn + ) + internal + pure + returns ( + function (ExogenousQualifiedSplitBatchMultichainClaimWithWitness calldata, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32, bytes32) + fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedSplitClaimWithWitness calldata struct while + * treating it as a QualifiedClaimWithWitness calldata struct. + * @param fnIn Function pointer to `ClaimHashLib._toQualifiedClaimWithWitnessMessageHash(QualifiedClaimWithWitness calldata)`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(QualifiedSplitClaimWithWitness calldata)`. + */ + function usingQualifiedSplitClaimWithWitness(function (QualifiedClaimWithWitness calldata) internal view returns (bytes32, bytes32, bytes32) fnIn) + internal + pure + returns (function (QualifiedSplitClaimWithWitness calldata) internal view returns (bytes32, bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a ClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `HashLib.toMessageHashWithWitness(uint256, uint256)`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(ClaimWithWitness calldata)`. + */ + function usingClaimWithWitness(function (uint256, uint256) internal view returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (ClaimWithWitness calldata, uint256) internal view returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a SplitClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `HashLib.toMessageHashWithWitness(uint256, uint256)`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(SplitClaimWithWitness calldata)`. + */ + function usingSplitClaimWithWitness(function (uint256, uint256) internal view returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (SplitClaimWithWitness calldata, uint256) internal view returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a BatchClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `HashLib.toMessageHashWithWitness(uint256, uint256)`. + * @return fnOut Modified function used in `ClaimHashLib.toMessageHashes(BatchClaimWithWitness calldata)`. + */ + function usingBatchClaimWithWitness(function (uint256, uint256) internal view returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (BatchClaimWithWitness calldata, uint256) internal view returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a SplitBatchClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `HashLib.toMessageHashWithWitness(uint256, uint256)`. + * @return fnOut Modified function used in `SplitBatchClaimWithWitness.toMessageHashes(BatchClaimWithWitness calldata)`. + */ + function usingSplitBatchClaimWithWitness(function (uint256, uint256) internal view returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (SplitBatchClaimWithWitness calldata, uint256) internal view returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide an ExogenousQualifiedMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toExogenousQualifiedMultichainMessageHash(ExogenousQualifiedMultichainClaim calldata)`. + * @return fnOut Modified function used in `ClaimHashLib._toExogenousQualifiedMultichainMessageHash(ExogenousQualifiedMultichainClaim calldata)`. + */ + function usingExogenousQualifiedMultichainClaim(function(uint256, uint256) internal pure returns (uint256) fnIn) + internal + pure + returns (function(ExogenousQualifiedMultichainClaim calldata, uint256) internal pure returns (uint256) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toQualifiedMultichainMessageHash(QualifiedMultichainClaim calldata)`. + * @return fnOut Modified function used in `ClaimHashLib._toQualifiedMultichainMessageHash(QualifiedMultichainClaim calldata)`. + */ + function usingQualifiedMultichainClaim(function (uint256, uint256) internal pure returns (uint256) fnIn) + internal + pure + returns (function (QualifiedMultichainClaim calldata, uint256) internal pure returns (uint256) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedMultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toQualifiedMultichainClaimWithWitnessMessageHash(QualifiedMultichainClaimWithWitness calldata)`. + * @return fnOut Modified function used in `ClaimHashLib._toQualifiedMultichainClaimWithWitnessMessageHash(QualifiedMultichainClaimWithWitness calldata)`. + */ + function usingQualifiedMultichainClaimWithWitness(function (uint256, uint256) internal pure returns (uint256) fnIn) + internal + pure + returns (function (QualifiedMultichainClaimWithWitness calldata, uint256) internal pure returns (uint256) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide an ExogenousQualifiedMultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toExogenousQualifiedMultichainClaimWithWitnessMessageHash(ExogenousQualifiedMultichainClaimWithWitness calldata)`. + * @return fnOut Modified function used in `ClaimHashLib._toExogenousQualifiedMultichainClaimWithWitnessMessageHash(ExogenousQualifiedMultichainClaimWithWitness calldata)`. + */ + function usingExogenousQualifiedMultichainClaimWithWitness(function (uint256, uint256) internal pure returns (uint256) fnIn) + internal + pure + returns (function (ExogenousQualifiedMultichainClaimWithWitness calldata, uint256) internal pure returns (uint256) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a MultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toMultichainMessageHash(MultichainClaim calldata)`. + * @return fnOut Modified function used in `ClaimHashLib._toMultichainMessageHash(MultichainClaim calldata)`. + */ + function usingMultichainClaim(function (uint256, uint256) internal pure returns (uint256) fnIn) internal pure returns (function (MultichainClaim calldata, uint256) internal pure returns (uint256) fnOut) { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a MultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toMultichainClaimWithWitnessMessageHash(MultichainClaimWithWitness calldata)`. + * @return fnOut Modified function used in `ClaimHashLib._toMultichainClaimWithWitnessMessageHash(MultichainClaimWithWitness calldata)`. + */ + function usingMultichainClaimWithWitness(function (uint256, uint256) internal pure returns (uint256) fnIn) + internal + pure + returns (function (MultichainClaimWithWitness calldata, uint256) internal pure returns (uint256) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide an ExogenousMultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toExogenousMultichainClaimWithWitnessMessageHash(ExogenousMultichainClaimWithWitness calldata)`. + * @return fnOut Modified function used in `ClaimHashLib._toExogenousMultichainClaimWithWitnessMessageHash(ExogenousMultichainClaimWithWitness calldata)`. + */ + function usingExogenousMultichainClaimWithWitness(function (uint256, uint256) internal pure returns (uint256) fnIn) + internal + pure + returns (function (ExogenousMultichainClaimWithWitness calldata, uint256) internal pure returns (uint256) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide an ExogenousMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimHashLib._toExogenousMultichainMessageHash(ExogenousMultichainClaim calldata)`. + * @return fnOut Modified function used in `ClaimHashLib._toExogenousMultichainMessageHash(ExogenousMultichainClaim calldata)`. + */ + function usingExogenousMultichainClaim(function (uint256, uint256) internal pure returns (uint256) fnIn) + internal + pure + returns (function (ExogenousMultichainClaim calldata, uint256) internal pure returns (uint256) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } +} diff --git a/src/lib/ClaimHashLib.sol b/src/lib/ClaimHashLib.sol new file mode 100644 index 0000000..e5a36ab --- /dev/null +++ b/src/lib/ClaimHashLib.sol @@ -0,0 +1,439 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { + BasicTransfer, + SplitTransfer, + BasicClaim, + QualifiedClaim, + ClaimWithWitness, + QualifiedClaimWithWitness, + SplitClaim, + SplitClaimWithWitness, + QualifiedSplitClaim, + QualifiedSplitClaimWithWitness +} from "../types/Claims.sol"; + +import { + BatchTransfer, + SplitBatchTransfer, + BatchClaim, + QualifiedBatchClaim, + BatchClaimWithWitness, + QualifiedBatchClaimWithWitness, + SplitBatchClaim, + SplitBatchClaimWithWitness, + QualifiedSplitBatchClaim, + QualifiedSplitBatchClaimWithWitness +} from "../types/BatchClaims.sol"; + +import { + MultichainClaim, + QualifiedMultichainClaim, + MultichainClaimWithWitness, + QualifiedMultichainClaimWithWitness, + SplitMultichainClaim, + SplitMultichainClaimWithWitness, + QualifiedSplitMultichainClaim, + QualifiedSplitMultichainClaimWithWitness, + ExogenousMultichainClaim, + ExogenousQualifiedMultichainClaim, + ExogenousMultichainClaimWithWitness, + ExogenousQualifiedMultichainClaimWithWitness, + ExogenousSplitMultichainClaim, + ExogenousSplitMultichainClaimWithWitness, + ExogenousQualifiedSplitMultichainClaim, + ExogenousQualifiedSplitMultichainClaimWithWitness +} from "../types/MultichainClaims.sol"; + +import { + BatchMultichainClaim, + QualifiedBatchMultichainClaim, + BatchMultichainClaimWithWitness, + QualifiedBatchMultichainClaimWithWitness, + SplitBatchMultichainClaim, + SplitBatchMultichainClaimWithWitness, + QualifiedSplitBatchMultichainClaim, + QualifiedSplitBatchMultichainClaimWithWitness, + ExogenousBatchMultichainClaim, + ExogenousQualifiedBatchMultichainClaim, + ExogenousBatchMultichainClaimWithWitness, + ExogenousQualifiedBatchMultichainClaimWithWitness, + ExogenousSplitBatchMultichainClaim, + ExogenousSplitBatchMultichainClaimWithWitness, + ExogenousQualifiedSplitBatchMultichainClaim, + ExogenousQualifiedSplitBatchMultichainClaimWithWitness +} from "../types/BatchMultichainClaims.sol"; + +import { BatchClaimComponent, SplitBatchClaimComponent } from "../types/Components.sol"; + +import { ResetPeriod } from "../types/ResetPeriod.sol"; +import { Scope } from "../types/Scope.sol"; + +import { EfficiencyLib } from "./EfficiencyLib.sol"; +import { ClaimHashFunctionCastLib } from "./ClaimHashFunctionCastLib.sol"; +import { HashLib } from "./HashLib.sol"; + +/** + * @title ClaimHashLib + * @notice Libray contract implementing logic for deriving hashes as part of processing + * claims, allocated transfers, and withdrawals. + */ +library ClaimHashLib { + using ClaimHashFunctionCastLib for function(uint256, uint256) internal pure returns (uint256); + using ClaimHashFunctionCastLib for function(uint256, uint256) internal view returns (bytes32, bytes32); + using ClaimHashFunctionCastLib for function(uint256, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32); + using ClaimHashFunctionCastLib for function(uint256, uint256, function(uint256, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32); + using ClaimHashFunctionCastLib for function(uint256, uint256, function(uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32); + using ClaimHashFunctionCastLib for function(uint256, uint256, function(uint256, uint256) internal view returns (bytes32, bytes32)) internal view returns (bytes32, bytes32, bytes32); + using ClaimHashFunctionCastLib for function(uint256, uint256, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32)) internal view returns (bytes32, bytes32, bytes32); + using ClaimHashFunctionCastLib for function(BasicClaim calldata) internal view returns (bytes32); + using ClaimHashFunctionCastLib for function(MultichainClaim calldata) internal view returns (bytes32); + using ClaimHashFunctionCastLib for function(ExogenousMultichainClaim calldata) internal view returns (bytes32); + using ClaimHashFunctionCastLib for function(QualifiedClaim calldata) internal view returns (bytes32, bytes32); + using ClaimHashFunctionCastLib for function(QualifiedMultichainClaim calldata) internal view returns (bytes32, bytes32); + using ClaimHashFunctionCastLib for function(ExogenousQualifiedMultichainClaim calldata) internal view returns (bytes32, bytes32); + using ClaimHashFunctionCastLib for function(MultichainClaimWithWitness calldata) internal view returns (bytes32, bytes32); + using ClaimHashFunctionCastLib for function(ExogenousMultichainClaimWithWitness calldata) internal view returns (bytes32, bytes32); + using ClaimHashFunctionCastLib for function(QualifiedClaimWithWitness calldata) internal view returns (bytes32, bytes32, bytes32); + using ClaimHashFunctionCastLib for function(QualifiedMultichainClaimWithWitness calldata) internal view returns (bytes32, bytes32, bytes32); + using ClaimHashFunctionCastLib for function(ExogenousQualifiedMultichainClaimWithWitness calldata) internal view returns (bytes32, bytes32, bytes32); + using EfficiencyLib for uint256; + using HashLib for uint256; + using HashLib for BatchClaimComponent[]; + using HashLib for SplitBatchClaimComponent[]; + using HashLib for BasicTransfer; + using HashLib for SplitTransfer; + using HashLib for BatchTransfer; + using HashLib for SplitBatchTransfer; + + ///// CATEGORY 1: Transfer claim hashes ///// + function toClaimHash(BasicTransfer calldata transfer) internal view returns (bytes32 claimHash) { + return transfer.toBasicTransferMessageHash(); + } + + function toClaimHash(SplitTransfer calldata transfer) internal view returns (bytes32 claimHash) { + return transfer.toSplitTransferMessageHash(); + } + + function toClaimHash(BatchTransfer calldata transfer) internal view returns (bytes32 claimHash) { + return transfer.toBatchTransferMessageHash(); + } + + function toClaimHash(SplitBatchTransfer calldata transfer) internal view returns (bytes32 claimHash) { + return transfer.toSplitBatchTransferMessageHash(); + } + + ///// CATEGORY 2: "Simple" Claim hashes ///// + function toClaimHash(BasicClaim calldata claim) internal view returns (bytes32 claimHash) { + return _toBasicMessageHash(claim); + } + + function toClaimHash(SplitClaim calldata claim) internal view returns (bytes32 claimHash) { + return _toBasicMessageHash.usingSplitClaim()(claim); + } + + function toClaimHash(BatchClaim calldata claim) internal view returns (bytes32 claimHash) { + return _toGenericMessageHash.usingBatchClaim()(claim, claim.claims.toIdsAndAmountsHash(), HashLib.toBatchMessageHash); + } + + function toClaimHash(SplitBatchClaim calldata claim) internal view returns (bytes32 claimHash) { + return _toGenericMessageHash.usingSplitBatchClaim()(claim, claim.claims.toSplitIdsAndAmountsHash(), HashLib.toBatchMessageHash); + } + + function toClaimHash(MultichainClaim calldata claim) internal view returns (bytes32 claimHash) { + return _toMultichainMessageHash(claim); + } + + function toClaimHash(SplitMultichainClaim calldata claim) internal view returns (bytes32 claimHash) { + return _toMultichainMessageHash.usingSplitMultichainClaim()(claim); + } + + function toClaimHash(BatchMultichainClaim calldata claim) internal view returns (bytes32 claimHash) { + return _toGenericMessageHash.usingBatchMultichainClaim()(claim, claim.claims.toIdsAndAmountsHash(), HashLib.toSimpleMultichainClaimMessageHash); + } + + function toClaimHash(SplitBatchMultichainClaim calldata claim) internal view returns (bytes32 claimHash) { + return _toGenericMessageHash.usingSplitBatchMultichainClaim()(claim, claim.claims.toSplitIdsAndAmountsHash(), HashLib.toSimpleMultichainClaimMessageHash); + } + + function toClaimHash(ExogenousMultichainClaim calldata claim) internal view returns (bytes32 claimHash) { + return _toExogenousMultichainMessageHash(claim); + } + + function toClaimHash(ExogenousSplitMultichainClaim calldata claim) internal view returns (bytes32 claimHash) { + return _toExogenousMultichainMessageHash.usingExogenousSplitMultichainClaim()(claim); + } + + function toClaimHash(ExogenousBatchMultichainClaim calldata claim) internal view returns (bytes32 claimHash) { + return _toGenericMessageHash.usingExogenousBatchMultichainClaim()(claim, claim.claims.toIdsAndAmountsHash(), HashLib.toSimpleExogenousMultichainClaimMessageHash); + } + + function toClaimHash(ExogenousSplitBatchMultichainClaim calldata claim) internal view returns (bytes32 claimHash) { + return _toGenericMessageHash.usingExogenousSplitBatchMultichainClaim()(claim, claim.claims.toSplitIdsAndAmountsHash(), HashLib.toSimpleExogenousMultichainClaimMessageHash); + } + + ///// CATEGORY 3: Qualified claim message & qualification hashes ///// + function toMessageHashes(QualifiedClaim calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash) { + return _toQualifiedMessageHash(claim); + } + + function toMessageHashes(QualifiedSplitClaim calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash) { + return _toQualifiedMessageHash.usingQualifiedSplitClaim()(claim); + } + + function toMessageHashes(QualifiedBatchClaim calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash) { + return _toGenericMessageHashWithQualificationHash.usingQualifiedBatchClaim()(claim, claim.claims.toIdsAndAmountsHash(), HashLib.toBatchMessageHash); + } + + function toMessageHashes(QualifiedSplitBatchClaim calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash) { + return _toGenericMessageHashWithQualificationHash.usingQualifiedSplitBatchClaim()(claim, claim.claims.toSplitIdsAndAmountsHash(), HashLib.toBatchMessageHash); + } + + function toMessageHashes(QualifiedMultichainClaim calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash) { + return _toQualifiedMultichainMessageHash(claim); + } + + function toMessageHashes(QualifiedSplitMultichainClaim calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash) { + return _toQualifiedMultichainMessageHash.usingQualifiedSplitMultichainClaim()(claim); + } + + function toMessageHashes(QualifiedBatchMultichainClaim calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash) { + return _toGenericMessageHashWithQualificationHash.usingQualifiedBatchMultichainClaim()(claim, claim.claims.toIdsAndAmountsHash(), HashLib.toQualifiedMultichainClaimMessageHash); + } + + function toMessageHashes(QualifiedSplitBatchMultichainClaim calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash) { + return _toGenericMessageHashWithQualificationHash.usingQualifiedSplitBatchMultichainClaim()(claim, claim.claims.toSplitIdsAndAmountsHash(), HashLib.toQualifiedMultichainClaimMessageHash); + } + + function toMessageHashes(ExogenousQualifiedMultichainClaim calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash) { + return _toExogenousQualifiedMultichainMessageHash(claim); + } + + function toMessageHashes(ExogenousQualifiedSplitMultichainClaim calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash) { + return _toExogenousQualifiedMultichainMessageHash.usingExogenousQualifiedSplitMultichainClaim()(claim); + } + + function toMessageHashes(ExogenousQualifiedBatchMultichainClaim calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash) { + return _toGenericMessageHashWithQualificationHash.usingExogenousQualifiedBatchMultichainClaim()(claim, claim.claims.toIdsAndAmountsHash(), HashLib.toExogenousQualifiedMultichainClaimMessageHash); + } + + function toMessageHashes(ExogenousQualifiedSplitBatchMultichainClaim calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash) { + return + _toGenericMessageHashWithQualificationHash.usingExogenousQualifiedSplitBatchMultichainClaim()(claim, claim.claims.toSplitIdsAndAmountsHash(), HashLib.toExogenousQualifiedMultichainClaimMessageHash); + } + + ///// CATEGORY 4: Claim with witness message & type hashes ///// + function toMessageHashes(ClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 typehash) { + return HashLib.toMessageHashWithWitness.usingClaimWithWitness()(claim, 0); + } + + function toMessageHashes(SplitClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 typehash) { + return HashLib.toMessageHashWithWitness.usingSplitClaimWithWitness()(claim, 0); + } + + function toMessageHashes(BatchClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 typehash) { + return HashLib.toBatchClaimWithWitnessMessageHash.usingBatchClaimWithWitness()(claim, claim.claims.toIdsAndAmountsHash()); + } + + function toMessageHashes(SplitBatchClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 typehash) { + return HashLib.toBatchClaimWithWitnessMessageHash.usingSplitBatchClaimWithWitness()(claim, claim.claims.toSplitIdsAndAmountsHash()); + } + + function toMessageHashes(MultichainClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 typehash) { + return _toMultichainClaimWithWitnessMessageHash(claim); + } + + function toMessageHashes(SplitMultichainClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 typehash) { + return _toMultichainClaimWithWitnessMessageHash.usingSplitMultichainClaimWithWitness()(claim); + } + + function toMessageHashes(BatchMultichainClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 typehash) { + return _toGenericMultichainClaimWithWitnessMessageHash.usingBatchMultichainClaimWithWitness()(claim, claim.claims.toIdsAndAmountsHash(), HashLib.toMultichainClaimMessageHash); + } + + function toMessageHashes(SplitBatchMultichainClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 typehash) { + return _toGenericMultichainClaimWithWitnessMessageHash.usingSplitBatchMultichainClaimWithWitness()(claim, claim.claims.toSplitIdsAndAmountsHash(), HashLib.toMultichainClaimMessageHash); + } + + function toMessageHashes(ExogenousMultichainClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 typehash) { + return _toExogenousMultichainClaimWithWitnessMessageHash(claim); + } + + function toMessageHashes(ExogenousSplitMultichainClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 typehash) { + return _toExogenousMultichainClaimWithWitnessMessageHash.usingExogenousSplitMultichainClaimWithWitness()(claim); + } + + function toMessageHashes(ExogenousBatchMultichainClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 typehash) { + return _toGenericMultichainClaimWithWitnessMessageHash.usingExogenousBatchMultichainClaimWithWitness()(claim, claim.claims.toIdsAndAmountsHash(), HashLib.toExogenousMultichainClaimMessageHash); + } + + function toMessageHashes(ExogenousSplitBatchMultichainClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 typehash) { + return _toGenericMultichainClaimWithWitnessMessageHash.usingExogenousSplitBatchMultichainClaimWithWitness()(claim, claim.claims.toSplitIdsAndAmountsHash(), HashLib.toExogenousMultichainClaimMessageHash); + } + + ///// CATEGORY 5: Qualified claim with witness message, qualification, & type hashes ///// + function toMessageHashes(QualifiedClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash, bytes32 typehash) { + return _toQualifiedClaimWithWitnessMessageHash(claim); + } + + function toMessageHashes(QualifiedSplitClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash, bytes32 typehash) { + return _toQualifiedClaimWithWitnessMessageHash.usingQualifiedSplitClaimWithWitness()(claim); + } + + function toMessageHashes(QualifiedBatchClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash, bytes32 typehash) { + return _toGenericQualifiedClaimWithWitnessMessageHash.usingQualifiedBatchClaimWithWitness()(claim, claim.claims.toIdsAndAmountsHash(), HashLib.toBatchClaimWithWitnessMessageHash); + } + + function toMessageHashes(QualifiedSplitBatchClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash, bytes32 typehash) { + return _toGenericQualifiedClaimWithWitnessMessageHash.usingQualifiedSplitBatchClaimWithWitness()(claim, claim.claims.toSplitIdsAndAmountsHash(), HashLib.toBatchClaimWithWitnessMessageHash); + } + + function toMessageHashes(QualifiedMultichainClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash, bytes32 typehash) { + return _toQualifiedMultichainClaimWithWitnessMessageHash(claim); + } + + function toMessageHashes(QualifiedSplitMultichainClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash, bytes32 typehash) { + return _toQualifiedMultichainClaimWithWitnessMessageHash.usingQualifiedSplitMultichainClaimWithWitness()(claim); + } + + function toMessageHashes(QualifiedBatchMultichainClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash, bytes32 typehash) { + return _toGenericQualifiedMultichainClaimWithWitnessMessageHash.usingQualifiedBatchMultichainClaimWithWitness()(claim, claim.claims.toIdsAndAmountsHash(), HashLib.toMultichainClaimMessageHash); + } + + function toMessageHashes(QualifiedSplitBatchMultichainClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash, bytes32 typehash) { + return _toGenericQualifiedMultichainClaimWithWitnessMessageHash.usingQualifiedSplitBatchMultichainClaimWithWitness()(claim, claim.claims.toSplitIdsAndAmountsHash(), HashLib.toMultichainClaimMessageHash); + } + + function toMessageHashes(ExogenousQualifiedMultichainClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash, bytes32 typehash) { + return _toExogenousQualifiedMultichainClaimWithWitnessMessageHash(claim); + } + + function toMessageHashes(ExogenousQualifiedSplitMultichainClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash, bytes32 typehash) { + return _toExogenousQualifiedMultichainClaimWithWitnessMessageHash.usingExogenousQualifiedSplitMultichainClaimWithWitness()(claim); + } + + function toMessageHashes(ExogenousQualifiedBatchMultichainClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash, bytes32 typehash) { + return _toGenericQualifiedMultichainClaimWithWitnessMessageHash.usingExogenousQualifiedBatchMultichainClaimWithWitness()( + claim, claim.claims.toIdsAndAmountsHash(), HashLib.toExogenousMultichainClaimMessageHash + ); + } + + function toMessageHashes(ExogenousQualifiedSplitBatchMultichainClaimWithWitness calldata claim) internal view returns (bytes32 claimHash, bytes32 qualificationHash, bytes32 typehash) { + return _toGenericQualifiedMultichainClaimWithWitnessMessageHash.usingExogenousQualifiedSplitBatchMultichainClaimWithWitness()( + claim, claim.claims.toSplitIdsAndAmountsHash(), HashLib.toExogenousMultichainClaimMessageHash + ); + } + + ///// Private helper functions ///// + function _toGenericMessageHash(uint256 claim, uint256 additionalInput, function(uint256, uint256) internal view returns (bytes32) hashFn) private view returns (bytes32 claimHash) { + return hashFn(claim, additionalInput); + } + + function _toBasicMessageHash(BasicClaim calldata claim) private view returns (bytes32 claimHash) { + return _toGenericMessageHash.usingBasicClaim()(claim, uint256(0).asStubborn(), HashLib.toClaimMessageHash); + } + + function _toMultichainMessageHash(MultichainClaim calldata claim) private view returns (bytes32 claimHash) { + return _toGenericMessageHash.usingMultichainClaim()(claim, HashLib.toSingleIdAndAmountHash.usingMultichainClaim()(claim, 0), HashLib.toSimpleMultichainClaimMessageHash); + } + + function _toExogenousMultichainMessageHash(ExogenousMultichainClaim calldata claim) private view returns (bytes32 claimHash) { + return _toGenericMessageHash.usingExogenousMultichainClaim()( + claim, HashLib.toSingleIdAndAmountHash.usingExogenousMultichainClaim()(claim, uint256(0x40).asStubborn()), HashLib.toSimpleExogenousMultichainClaimMessageHash + ); + } + + function _toGenericMessageHashWithQualificationHash(uint256 claim, uint256 additionalInput, function(uint256, uint256) internal view returns (bytes32) hashFn) + private + view + returns (bytes32 claimHash, bytes32 qualificationHash) + { + claimHash = _toGenericMessageHash(claim, additionalInput, hashFn); + return (claimHash, claim.toQualificationMessageHash(claimHash, uint256(0).asStubborn())); + } + + function _toQualifiedMessageHash(QualifiedClaim calldata claim) private view returns (bytes32 claimHash, bytes32 qualificationHash) { + return _toGenericMessageHashWithQualificationHash.usingQualifiedClaim()(claim, uint256(0x40).asStubborn(), HashLib.toClaimMessageHash); + } + + function _toQualifiedMultichainMessageHash(QualifiedMultichainClaim calldata claim) private view returns (bytes32 claimHash, bytes32 qualificationHash) { + return _toGenericMessageHashWithQualificationHash.usingQualifiedMultichainClaim()( + claim, HashLib.toSingleIdAndAmountHash.usingQualifiedMultichainClaim()(claim, uint256(0x40).asStubborn()), HashLib.toQualifiedMultichainClaimMessageHash + ); + } + + function _toExogenousQualifiedMultichainMessageHash(ExogenousQualifiedMultichainClaim calldata claim) private view returns (bytes32 claimHash, bytes32 qualificationHash) { + return _toGenericMessageHashWithQualificationHash.usingExogenousQualifiedMultichainClaim()( + claim, HashLib.toSingleIdAndAmountHash.usingExogenousQualifiedMultichainClaim()(claim, uint256(0x80).asStubborn()), HashLib.toExogenousQualifiedMultichainClaimMessageHash + ); + } + + function _toGenericMultichainClaimWithWitnessMessageHash(uint256 claim, uint256 additionalInput, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32) hashFn) + private + view + returns (bytes32 claimHash, bytes32 /* typehash */ ) + { + (bytes32 allocationTypehash, bytes32 typehash) = claim.toMultichainTypehashes(); + return (hashFn(claim, uint256(0x40).asStubborn(), allocationTypehash, typehash, additionalInput), typehash); + } + + function _toGenericMultichainClaimWithWitnessMessageHashPriorToQualification( + uint256 claim, + uint256 additionalInput, + function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32) hashFn + ) private view returns (bytes32 claimHash, bytes32 /* typehash */ ) { + (bytes32 allocationTypehash, bytes32 typehash) = claim.toMultichainTypehashes(); + return (hashFn(claim, uint256(0x80).asStubborn(), allocationTypehash, typehash, additionalInput), typehash); + } + + function _toMultichainClaimWithWitnessMessageHash(MultichainClaimWithWitness calldata claim) private view returns (bytes32 claimHash, bytes32 typehash) { + return _toGenericMultichainClaimWithWitnessMessageHash.usingMultichainClaimWithWitness()( + claim, HashLib.toSingleIdAndAmountHash.usingMultichainClaimWithWitness()(claim, uint256(0x40).asStubborn()), HashLib.toMultichainClaimMessageHash + ); + } + + function _toExogenousMultichainClaimWithWitnessMessageHash(ExogenousMultichainClaimWithWitness calldata claim) private view returns (bytes32 claimHash, bytes32 typehash) { + return _toGenericMultichainClaimWithWitnessMessageHash.usingExogenousMultichainClaimWithWitness()( + claim, HashLib.toSingleIdAndAmountHash.usingExogenousMultichainClaimWithWitness()(claim, uint256(0x80).asStubborn()), HashLib.toExogenousMultichainClaimMessageHash + ); + } + + function _toGenericQualifiedClaimWithWitnessMessageHash(uint256 claim, uint256 additionalInput, function (uint256, uint256) internal view returns (bytes32, bytes32) hashFn) + private + view + returns (bytes32, /* claimHash */ bytes32 qualificationHash, bytes32 /* typehash */ ) + { + (bytes32 messageHash, bytes32 typehash) = hashFn(claim, additionalInput); + return (messageHash, claim.toQualificationMessageHash(messageHash, uint256(0x40).asStubborn()), typehash); + } + + function _toQualifiedClaimWithWitnessMessageHash(QualifiedClaimWithWitness calldata claim) private view returns (bytes32 claimHash, bytes32 qualificationHash, bytes32 typehash) { + return _toGenericQualifiedClaimWithWitnessMessageHash.usingQualifiedClaimWithWitness()(claim, uint256(0x40).asStubborn(), HashLib.toMessageHashWithWitness); + } + + function _toGenericQualifiedMultichainClaimWithWitnessMessageHash(uint256 claim, uint256 additionalInput, function (uint256, uint256, bytes32, bytes32, uint256) internal view returns (bytes32) hashFn) + private + view + returns (bytes32, /* claimHash */ bytes32 qualificationHash, bytes32 /* typehash */ ) + { + (bytes32 messageHash, bytes32 typehash) = _toGenericMultichainClaimWithWitnessMessageHashPriorToQualification(claim, additionalInput, hashFn); + return (messageHash, claim.toQualificationMessageHash(messageHash, uint256(0x40).asStubborn()), typehash); + } + + function _toQualifiedMultichainClaimWithWitnessMessageHash(QualifiedMultichainClaimWithWitness calldata claim) private view returns (bytes32 claimHash, bytes32 qualificationHash, bytes32 typehash) { + return _toGenericQualifiedMultichainClaimWithWitnessMessageHash.usingQualifiedMultichainClaimWithWitness()( + claim, HashLib.toSingleIdAndAmountHash.usingQualifiedMultichainClaimWithWitness()(claim, uint256(0x80).asStubborn()), HashLib.toMultichainClaimMessageHash + ); + } + + function _toExogenousQualifiedMultichainClaimWithWitnessMessageHash(ExogenousQualifiedMultichainClaimWithWitness calldata claim) + private + view + returns (bytes32 claimHash, bytes32 qualificationHash, bytes32 typehash) + { + return _toGenericQualifiedMultichainClaimWithWitnessMessageHash.usingExogenousQualifiedMultichainClaimWithWitness()( + claim, HashLib.toSingleIdAndAmountHash.usingExogenousQualifiedMultichainClaimWithWitness()(claim, uint256(0xc0).asStubborn()), HashLib.toExogenousMultichainClaimMessageHash + ); + } +} diff --git a/src/lib/ClaimProcessor.sol b/src/lib/ClaimProcessor.sol new file mode 100644 index 0000000..56232b0 --- /dev/null +++ b/src/lib/ClaimProcessor.sol @@ -0,0 +1,448 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { ITheCompactClaims } from "../interfaces/ITheCompactClaims.sol"; +import { ClaimProcessorLogic } from "./ClaimProcessorLogic.sol"; + +import { BasicClaim, QualifiedClaim, ClaimWithWitness, QualifiedClaimWithWitness, SplitClaim, SplitClaimWithWitness, QualifiedSplitClaim, QualifiedSplitClaimWithWitness } from "../types/Claims.sol"; + +import { + BatchClaim, + QualifiedBatchClaim, + BatchClaimWithWitness, + QualifiedBatchClaimWithWitness, + SplitBatchClaim, + SplitBatchClaimWithWitness, + QualifiedSplitBatchClaim, + QualifiedSplitBatchClaimWithWitness +} from "../types/BatchClaims.sol"; + +import { + MultichainClaim, + QualifiedMultichainClaim, + MultichainClaimWithWitness, + QualifiedMultichainClaimWithWitness, + SplitMultichainClaim, + SplitMultichainClaimWithWitness, + QualifiedSplitMultichainClaim, + QualifiedSplitMultichainClaimWithWitness, + ExogenousMultichainClaim, + ExogenousQualifiedMultichainClaim, + ExogenousMultichainClaimWithWitness, + ExogenousQualifiedMultichainClaimWithWitness, + ExogenousSplitMultichainClaim, + ExogenousSplitMultichainClaimWithWitness, + ExogenousQualifiedSplitMultichainClaim, + ExogenousQualifiedSplitMultichainClaimWithWitness +} from "../types/MultichainClaims.sol"; + +import { + BatchMultichainClaim, + QualifiedBatchMultichainClaim, + BatchMultichainClaimWithWitness, + QualifiedBatchMultichainClaimWithWitness, + SplitBatchMultichainClaim, + SplitBatchMultichainClaimWithWitness, + QualifiedSplitBatchMultichainClaim, + QualifiedSplitBatchMultichainClaimWithWitness, + ExogenousBatchMultichainClaim, + ExogenousQualifiedBatchMultichainClaim, + ExogenousBatchMultichainClaimWithWitness, + ExogenousQualifiedBatchMultichainClaimWithWitness, + ExogenousSplitBatchMultichainClaim, + ExogenousSplitBatchMultichainClaimWithWitness, + ExogenousQualifiedSplitBatchMultichainClaim, + ExogenousQualifiedSplitBatchMultichainClaimWithWitness +} from "../types/BatchMultichainClaims.sol"; + +/** + * @title ClaimProcessor + * @notice Inherited contract implementing external functions for processing claims against + * a signed or registered compact. Each of these functions is only callable by the arbiter + * indicated by the respective compact. + */ +contract ClaimProcessor is ITheCompactClaims, ClaimProcessorLogic { + function claim(BasicClaim calldata claimPayload) external returns (bool) { + return _processBasicClaim(claimPayload, _release); + } + + function claimAndWithdraw(BasicClaim calldata claimPayload) external returns (bool) { + return _processBasicClaim(claimPayload, _withdraw); + } + + function claim(QualifiedClaim calldata claimPayload) external returns (bool) { + return _processQualifiedClaim(claimPayload, _release); + } + + function claimAndWithdraw(QualifiedClaim calldata claimPayload) external returns (bool) { + return _processQualifiedClaim(claimPayload, _withdraw); + } + + function claim(ClaimWithWitness calldata claimPayload) external returns (bool) { + return _processClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(ClaimWithWitness calldata claimPayload) external returns (bool) { + return _processClaimWithWitness(claimPayload, _withdraw); + } + + function claim(QualifiedClaimWithWitness calldata claimPayload) external returns (bool) { + return _processQualifiedClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(QualifiedClaimWithWitness calldata claimPayload) external returns (bool) { + return _processQualifiedClaimWithWitness(claimPayload, _withdraw); + } + + function claim(SplitClaim calldata claimPayload) external returns (bool) { + return _processSplitClaim(claimPayload, _release); + } + + function claimAndWithdraw(SplitClaim calldata claimPayload) external returns (bool) { + return _processSplitClaim(claimPayload, _withdraw); + } + + function claim(QualifiedSplitClaim calldata claimPayload) external returns (bool) { + return _processQualifiedSplitClaim(claimPayload, _release); + } + + function claimAndWithdraw(QualifiedSplitClaim calldata claimPayload) external returns (bool) { + return _processQualifiedSplitClaim(claimPayload, _withdraw); + } + + function claim(SplitClaimWithWitness calldata claimPayload) external returns (bool) { + return _processSplitClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(SplitClaimWithWitness calldata claimPayload) external returns (bool) { + return _processSplitClaimWithWitness(claimPayload, _withdraw); + } + + function claim(QualifiedSplitClaimWithWitness calldata claimPayload) external returns (bool) { + return _processQualifiedSplitClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(QualifiedSplitClaimWithWitness calldata claimPayload) external returns (bool) { + return _processQualifiedSplitClaimWithWitness(claimPayload, _withdraw); + } + + function claim(BatchClaim calldata claimPayload) external returns (bool) { + return _processBatchClaim(claimPayload, _release); + } + + function claimAndWithdraw(BatchClaim calldata claimPayload) external returns (bool) { + return _processBatchClaim(claimPayload, _withdraw); + } + + function claim(QualifiedBatchClaim calldata claimPayload) external returns (bool) { + return _processQualifiedBatchClaim(claimPayload, _release); + } + + function claimAndWithdraw(QualifiedBatchClaim calldata claimPayload) external returns (bool) { + return _processQualifiedBatchClaim(claimPayload, _withdraw); + } + + function claim(BatchClaimWithWitness calldata claimPayload) external returns (bool) { + return _processBatchClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(BatchClaimWithWitness calldata claimPayload) external returns (bool) { + return _processBatchClaimWithWitness(claimPayload, _withdraw); + } + + function claim(QualifiedBatchClaimWithWitness calldata claimPayload) external returns (bool) { + return _processQualifiedBatchClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(QualifiedBatchClaimWithWitness calldata claimPayload) external returns (bool) { + return _processQualifiedBatchClaimWithWitness(claimPayload, _withdraw); + } + + function claim(SplitBatchClaim calldata claimPayload) external returns (bool) { + return _processSplitBatchClaim(claimPayload, _release); + } + + function claimAndWithdraw(SplitBatchClaim calldata claimPayload) external returns (bool) { + return _processSplitBatchClaim(claimPayload, _withdraw); + } + + function claim(QualifiedSplitBatchClaim calldata claimPayload) external returns (bool) { + return _processQualifiedSplitBatchClaim(claimPayload, _release); + } + + function claimAndWithdraw(QualifiedSplitBatchClaim calldata claimPayload) external returns (bool) { + return _processQualifiedSplitBatchClaim(claimPayload, _withdraw); + } + + function claim(SplitBatchClaimWithWitness calldata claimPayload) external returns (bool) { + return _processSplitBatchClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(SplitBatchClaimWithWitness calldata claimPayload) external returns (bool) { + return _processSplitBatchClaimWithWitness(claimPayload, _withdraw); + } + + function claim(QualifiedSplitBatchClaimWithWitness calldata claimPayload) external returns (bool) { + return _processQualifiedSplitBatchClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(QualifiedSplitBatchClaimWithWitness calldata claimPayload) external returns (bool) { + return _processQualifiedSplitBatchClaimWithWitness(claimPayload, _withdraw); + } + + function claim(MultichainClaim calldata claimPayload) external returns (bool) { + return _processMultichainClaim(claimPayload, _release); + } + + function claimAndWithdraw(MultichainClaim calldata claimPayload) external returns (bool) { + return _processMultichainClaim(claimPayload, _withdraw); + } + + function claim(ExogenousMultichainClaim calldata claimPayload) external returns (bool) { + return _processExogenousMultichainClaim(claimPayload, _release); + } + + function claimAndWithdraw(ExogenousMultichainClaim calldata claimPayload) external returns (bool) { + return _processExogenousMultichainClaim(claimPayload, _withdraw); + } + + function claim(QualifiedMultichainClaim calldata claimPayload) external returns (bool) { + return _processQualifiedMultichainClaim(claimPayload, _release); + } + + function claimAndWithdraw(QualifiedMultichainClaim calldata claimPayload) external returns (bool) { + return _processQualifiedMultichainClaim(claimPayload, _withdraw); + } + + function claim(ExogenousQualifiedMultichainClaim calldata claimPayload) external returns (bool) { + return _processExogenousQualifiedMultichainClaim(claimPayload, _release); + } + + function claimAndWithdraw(ExogenousQualifiedMultichainClaim calldata claimPayload) external returns (bool) { + return _processExogenousQualifiedMultichainClaim(claimPayload, _withdraw); + } + + function claim(MultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processMultichainClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(MultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processMultichainClaimWithWitness(claimPayload, _withdraw); + } + + function claim(ExogenousMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processExogenousMultichainClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(ExogenousMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processExogenousMultichainClaimWithWitness(claimPayload, _withdraw); + } + + function claim(QualifiedMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processQualifiedMultichainClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(QualifiedMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processQualifiedMultichainClaimWithWitness(claimPayload, _withdraw); + } + + function claim(ExogenousQualifiedMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processExogenousQualifiedMultichainClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(ExogenousQualifiedMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processExogenousQualifiedMultichainClaimWithWitness(claimPayload, _withdraw); + } + + function claim(SplitMultichainClaim calldata claimPayload) external returns (bool) { + return _processSplitMultichainClaim(claimPayload, _release); + } + + function claimAndWithdraw(SplitMultichainClaim calldata claimPayload) external returns (bool) { + return _processSplitMultichainClaim(claimPayload, _withdraw); + } + + function claim(ExogenousSplitMultichainClaim calldata claimPayload) external returns (bool) { + return _processExogenousSplitMultichainClaim(claimPayload, _release); + } + + function claimAndWithdraw(ExogenousSplitMultichainClaim calldata claimPayload) external returns (bool) { + return _processExogenousSplitMultichainClaim(claimPayload, _withdraw); + } + + function claim(QualifiedSplitMultichainClaim calldata claimPayload) external returns (bool) { + return _processQualifiedSplitMultichainClaim(claimPayload, _release); + } + + function claimAndWithdraw(QualifiedSplitMultichainClaim calldata claimPayload) external returns (bool) { + return _processQualifiedSplitMultichainClaim(claimPayload, _withdraw); + } + + function claim(ExogenousQualifiedSplitMultichainClaim calldata claimPayload) external returns (bool) { + return _processExogenousQualifiedSplitMultichainClaim(claimPayload, _release); + } + + function claimAndWithdraw(ExogenousQualifiedSplitMultichainClaim calldata claimPayload) external returns (bool) { + return _processExogenousQualifiedSplitMultichainClaim(claimPayload, _withdraw); + } + + function claim(SplitMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processSplitMultichainClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(SplitMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processSplitMultichainClaimWithWitness(claimPayload, _withdraw); + } + + function claim(ExogenousSplitMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processExogenousSplitMultichainClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(ExogenousSplitMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processExogenousSplitMultichainClaimWithWitness(claimPayload, _withdraw); + } + + function claim(QualifiedSplitMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processQualifiedSplitMultichainClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(QualifiedSplitMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processQualifiedSplitMultichainClaimWithWitness(claimPayload, _withdraw); + } + + function claim(ExogenousQualifiedSplitMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processExogenousQualifiedSplitMultichainClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(ExogenousQualifiedSplitMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processExogenousQualifiedSplitMultichainClaimWithWitness(claimPayload, _withdraw); + } + + function claim(BatchMultichainClaim calldata claimPayload) external returns (bool) { + return _processBatchMultichainClaim(claimPayload, _release); + } + + function claimAndWithdraw(BatchMultichainClaim calldata claimPayload) external returns (bool) { + return _processBatchMultichainClaim(claimPayload, _withdraw); + } + + function claim(ExogenousBatchMultichainClaim calldata claimPayload) external returns (bool) { + return _processExogenousBatchMultichainClaim(claimPayload, _release); + } + + function claimAndWithdraw(ExogenousBatchMultichainClaim calldata claimPayload) external returns (bool) { + return _processExogenousBatchMultichainClaim(claimPayload, _withdraw); + } + + function claim(QualifiedBatchMultichainClaim calldata claimPayload) external returns (bool) { + return _processQualifiedBatchMultichainClaim(claimPayload, _release); + } + + function claimAndWithdraw(QualifiedBatchMultichainClaim calldata claimPayload) external returns (bool) { + return _processQualifiedBatchMultichainClaim(claimPayload, _withdraw); + } + + function claim(ExogenousQualifiedBatchMultichainClaim calldata claimPayload) external returns (bool) { + return _processExogenousQualifiedBatchMultichainClaim(claimPayload, _release); + } + + function claimAndWithdraw(ExogenousQualifiedBatchMultichainClaim calldata claimPayload) external returns (bool) { + return _processExogenousQualifiedBatchMultichainClaim(claimPayload, _withdraw); + } + + function claim(BatchMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processBatchMultichainClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(BatchMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processBatchMultichainClaimWithWitness(claimPayload, _withdraw); + } + + function claim(ExogenousBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processExogenousBatchMultichainClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(ExogenousBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processExogenousBatchMultichainClaimWithWitness(claimPayload, _withdraw); + } + + function claim(QualifiedBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processQualifiedBatchMultichainClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(QualifiedBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processQualifiedBatchMultichainClaimWithWitness(claimPayload, _withdraw); + } + + function claim(ExogenousQualifiedBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processExogenousQualifiedBatchMultichainClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(ExogenousQualifiedBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processExogenousQualifiedBatchMultichainClaimWithWitness(claimPayload, _withdraw); + } + + function claim(SplitBatchMultichainClaim calldata claimPayload) external returns (bool) { + return _processSplitBatchMultichainClaim(claimPayload, _release); + } + + function claimAndWithdraw(SplitBatchMultichainClaim calldata claimPayload) external returns (bool) { + return _processSplitBatchMultichainClaim(claimPayload, _withdraw); + } + + function claim(ExogenousSplitBatchMultichainClaim calldata claimPayload) external returns (bool) { + return _processExogenousSplitBatchMultichainClaim(claimPayload, _release); + } + + function claimAndWithdraw(ExogenousSplitBatchMultichainClaim calldata claimPayload) external returns (bool) { + return _processExogenousSplitBatchMultichainClaim(claimPayload, _withdraw); + } + + function claim(QualifiedSplitBatchMultichainClaim calldata claimPayload) external returns (bool) { + return _processQualifiedSplitBatchMultichainClaim(claimPayload, _release); + } + + function claimAndWithdraw(QualifiedSplitBatchMultichainClaim calldata claimPayload) external returns (bool) { + return _processQualifiedSplitBatchMultichainClaim(claimPayload, _withdraw); + } + + function claim(ExogenousQualifiedSplitBatchMultichainClaim calldata claimPayload) external returns (bool) { + return _processExogenousQualifiedSplitBatchMultichainClaim(claimPayload, _release); + } + + function claimAndWithdraw(ExogenousQualifiedSplitBatchMultichainClaim calldata claimPayload) external returns (bool) { + return _processExogenousQualifiedSplitBatchMultichainClaim(claimPayload, _withdraw); + } + + function claim(SplitBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processSplitBatchMultichainClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(SplitBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processSplitBatchMultichainClaimWithWitness(claimPayload, _withdraw); + } + + function claim(ExogenousSplitBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processExogenousSplitBatchMultichainClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(ExogenousSplitBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processExogenousSplitBatchMultichainClaimWithWitness(claimPayload, _withdraw); + } + + function claim(QualifiedSplitBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processQualifiedSplitBatchMultichainClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(QualifiedSplitBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processQualifiedSplitBatchMultichainClaimWithWitness(claimPayload, _withdraw); + } + + function claim(ExogenousQualifiedSplitBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processExogenousQualifiedSplitBatchMultichainClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(ExogenousQualifiedSplitBatchMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processExogenousQualifiedSplitBatchMultichainClaimWithWitness(claimPayload, _withdraw); + } +} diff --git a/src/lib/ClaimProcessorFunctionCastLib.sol b/src/lib/ClaimProcessorFunctionCastLib.sol new file mode 100644 index 0000000..55d5b4d --- /dev/null +++ b/src/lib/ClaimProcessorFunctionCastLib.sol @@ -0,0 +1,935 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { BasicClaim, QualifiedClaim, ClaimWithWitness, QualifiedClaimWithWitness, SplitClaim, SplitClaimWithWitness, QualifiedSplitClaim, QualifiedSplitClaimWithWitness } from "../types/Claims.sol"; + +import { + BatchClaim, + QualifiedBatchClaim, + BatchClaimWithWitness, + QualifiedBatchClaimWithWitness, + SplitBatchClaim, + SplitBatchClaimWithWitness, + QualifiedSplitBatchClaim, + QualifiedSplitBatchClaimWithWitness +} from "../types/BatchClaims.sol"; + +import { + MultichainClaim, + QualifiedMultichainClaim, + MultichainClaimWithWitness, + QualifiedMultichainClaimWithWitness, + SplitMultichainClaim, + SplitMultichainClaimWithWitness, + QualifiedSplitMultichainClaim, + QualifiedSplitMultichainClaimWithWitness, + ExogenousMultichainClaim, + ExogenousQualifiedMultichainClaim, + ExogenousMultichainClaimWithWitness, + ExogenousQualifiedMultichainClaimWithWitness, + ExogenousSplitMultichainClaim, + ExogenousSplitMultichainClaimWithWitness, + ExogenousQualifiedSplitMultichainClaim, + ExogenousQualifiedSplitMultichainClaimWithWitness +} from "../types/MultichainClaims.sol"; + +import { + BatchMultichainClaim, + QualifiedBatchMultichainClaim, + BatchMultichainClaimWithWitness, + QualifiedBatchMultichainClaimWithWitness, + SplitBatchMultichainClaim, + SplitBatchMultichainClaimWithWitness, + QualifiedSplitBatchMultichainClaim, + QualifiedSplitBatchMultichainClaimWithWitness, + ExogenousBatchMultichainClaim, + ExogenousQualifiedBatchMultichainClaim, + ExogenousBatchMultichainClaimWithWitness, + ExogenousQualifiedBatchMultichainClaimWithWitness, + ExogenousSplitBatchMultichainClaim, + ExogenousSplitBatchMultichainClaimWithWitness, + ExogenousQualifiedSplitBatchMultichainClaim, + ExogenousQualifiedSplitBatchMultichainClaimWithWitness +} from "../types/BatchMultichainClaims.sol"; + +/** + * @title ClaimProcessorFunctionCastLib + * @notice Libray contract implementing function casts used in ClaimProcessorLogic. + * The input function operates on a function that takes some argument that differs + * from what is currently available. The output function modifies one or more + * argument types so that they match the arguments that are being used to call the + * function. Note that from the perspective of the function being modified, the + * original type is still in force; great care should be taken to preserve offsets + * and general structure between the two structs. + * @dev Note that some of these function casts may no longer be in use. + */ +library ClaimProcessorFunctionCastLib { + /** + * @notice Function cast to provide a BasicClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSimpleClaim`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processBasicClaim`. + */ + function usingBasicClaim(function(bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, BasicClaim calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processClaimWithQualification`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processQualifiedClaim`. + */ + function usingQualifiedClaim(function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, bytes32, QualifiedClaim calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a ClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSimpleClaim`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processClaimWithWitness`. + */ + function usingClaimWithWitness(function(bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, ClaimWithWitness calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processClaimWithQualification`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processQualifiedClaimWithWitness`. + */ + function usingQualifiedClaimWithWitness(function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, bytes32, QualifiedClaimWithWitness calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a SplitClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSimpleSplitClaim`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processSplitClaim`. + */ + function usingSplitClaim(function(bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, SplitClaim calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedSplitClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSplitClaimWithQualification`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processQualifiedSplitClaim`. + */ + function usingQualifiedSplitClaim(function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, bytes32, QualifiedSplitClaim calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a SplitClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSimpleSplitClaim`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processSplitClaimWithWitness`. + */ + function usingSplitClaimWithWitness(function(bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, SplitClaimWithWitness calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedSplitClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSplitClaimWithQualification`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processQualifiedSplitClaimWithWitness`. + */ + function usingQualifiedSplitClaimWithWitness( + function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, bytes32, QualifiedSplitClaimWithWitness calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a BatchClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSimpleBatchClaim`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processBatchClaim`. + */ + function usingBatchClaim(function(bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, BatchClaim calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedBatchClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processBatchClaimWithQualification`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processQualifiedBatchClaim`. + */ + function usingQualifiedBatchClaim(function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, bytes32, QualifiedBatchClaim calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a BatchClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSimpleBatchClaim`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processBatchClaimWithWitness`. + */ + function usingBatchClaimWithWitness(function(bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, BatchClaimWithWitness calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedBatchClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processBatchClaimWithQualification`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processQualifiedBatchClaimWithWitness`. + */ + function usingQualifiedBatchClaimWithWitness( + function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, bytes32, QualifiedBatchClaimWithWitness calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a SplitBatchClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSimpleSplitBatchClaim`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processSplitBatchClaim`. + */ + function usingSplitBatchClaim(function(bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, SplitBatchClaim calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedSplitBatchClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSplitBatchClaimWithQualification`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processQualifiedSplitBatchClaim`. + */ + function usingQualifiedSplitBatchClaim(function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, bytes32, QualifiedSplitBatchClaim calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a SplitBatchClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSimpleSplitBatchClaim`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processSplitBatchClaimWithWitness`. + */ + function usingSplitBatchClaimWithWitness(function(bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, SplitBatchClaimWithWitness calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedSplitBatchClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSplitBatchClaimWithQualification`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processQualifiedSplitBatchClaimWithWitness`. + */ + function usingQualifiedSplitBatchClaimWithWitness( + function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, bytes32, QualifiedSplitBatchClaimWithWitness calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a MultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSimpleClaim`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processMultichainClaim`. + */ + function usingMultichainClaim(function(bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, MultichainClaim calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processClaimWithQualification`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processQualifiedMultichainClaim`. + */ + function usingQualifiedMultichainClaim(function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, bytes32, QualifiedMultichainClaim calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a MultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSimpleClaim`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processMultichainClaimWithWitness`. + */ + function usingMultichainClaimWithWitness(function(bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, MultichainClaimWithWitness calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedMultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processClaimWithQualification`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processQualifiedMultichainClaimWithWitness`. + */ + function usingQualifiedMultichainClaimWithWitness( + function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, bytes32, QualifiedMultichainClaimWithWitness calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a SplitMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSimpleSplitClaim`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processSplitMultichainClaim`. + */ + function usingSplitMultichainClaim(function(bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, SplitMultichainClaim calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedSplitMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSplitClaimWithQualification`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processQualifiedSplitMultichainClaim`. + */ + function usingQualifiedSplitMultichainClaim(function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns ( + function(bytes32, bytes32, QualifiedSplitMultichainClaim calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a SplitMultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSimpleSplitClaim`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processSplitMultichainClaimWithWitness`. + */ + function usingSplitMultichainClaimWithWitness(function(bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, SplitMultichainClaimWithWitness calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedSplitMultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSplitClaimWithQualification`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processQualifiedSplitMultichainClaimWithWitness`. + */ + function usingQualifiedSplitMultichainClaimWithWitness( + function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, bytes32, QualifiedSplitMultichainClaimWithWitness calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a BatchMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSimpleBatchClaim`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processBatchMultichainClaim`. + */ + function usingBatchMultichainClaim(function(bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, BatchMultichainClaim calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedBatchMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processBatchClaimWithQualification`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processQualifiedBatchMultichainClaim`. + */ + function usingQualifiedBatchMultichainClaim(function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns ( + function(bytes32, bytes32, QualifiedBatchMultichainClaim calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a BatchMultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSimpleBatchClaim`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processBatchMultichainClaimWithWitness`. + */ + function usingBatchMultichainClaimWithWitness(function(bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, BatchMultichainClaimWithWitness calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedBatchMultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processBatchClaimWithQualification`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processQualifiedBatchMultichainClaimWithWitness`. + */ + function usingQualifiedBatchMultichainClaimWithWitness( + function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, bytes32, QualifiedBatchMultichainClaimWithWitness calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a SplitBatchMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSimpleSplitBatchClaim`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processSplitBatchMultichainClaim`. + */ + function usingSplitBatchMultichainClaim(function(bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, SplitBatchMultichainClaim calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedSplitBatchMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSplitBatchClaimWithQualification`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processQualifiedSplitBatchMultichainClaim`. + */ + function usingQualifiedSplitBatchMultichainClaim( + function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, bytes32, QualifiedSplitBatchMultichainClaim calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a SplitBatchMultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSimpleSplitBatchClaim`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processSplitBatchMultichainClaimWithWitness`. + */ + function usingSplitBatchMultichainClaimWithWitness(function(bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, SplitBatchMultichainClaimWithWitness calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a QualifiedSplitBatchMultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSplitBatchClaimWithQualification`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processQualifiedSplitBatchMultichainClaimWithWitness`. + */ + function usingQualifiedSplitBatchMultichainClaimWithWitness( + function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, bytes32, QualifiedSplitBatchMultichainClaimWithWitness calldata, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) + fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a ExogenousMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processClaimWithSponsorDomain`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processExogenousMultichainClaim`. + */ + function usingExogenousMultichainClaim(function(bytes32, uint256, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns (function(bytes32, ExogenousMultichainClaim calldata, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a ExogenousQualifiedMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processClaimWithQualificationAndSponsorDomain`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processExogenousQualifiedMultichainClaim`. + */ + function usingExogenousQualifiedMultichainClaim( + function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, bytes32, ExogenousQualifiedMultichainClaim calldata, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a ExogenousMultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processClaimWithSponsorDomain`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processExogenousMultichainClaimWithWitness`. + */ + function usingExogenousMultichainClaimWithWitness( + function(bytes32, uint256, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, ExogenousMultichainClaimWithWitness calldata, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a ExogenousQualifiedMultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processClaimWithQualificationAndSponsorDomain`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processExogenousQualifiedMultichainClaimWithWitness`. + */ + function usingExogenousQualifiedMultichainClaimWithWitness( + function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, bytes32, ExogenousQualifiedMultichainClaimWithWitness calldata, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) + fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a ExogenousSplitMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSplitClaimWithSponsorDomain`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processExogenousSplitMultichainClaim`. + */ + function usingExogenousSplitMultichainClaim(function(bytes32, uint256, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns ( + function(bytes32, ExogenousSplitMultichainClaim calldata, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a ExogenousQualifiedSplitMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSplitClaimWithQualificationAndSponsorDomain`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processExogenousQualifiedSplitMultichainClaim`. + */ + function usingExogenousQualifiedSplitMultichainClaim( + function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, bytes32, ExogenousQualifiedSplitMultichainClaim calldata, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) + fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a ExogenousSplitMultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSplitClaimWithSponsorDomain`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processExogenousSplitMultichainClaimWithWitness`. + */ + function usingExogenousSplitMultichainClaimWithWitness( + function(bytes32, uint256, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, ExogenousSplitMultichainClaimWithWitness calldata, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a ExogenousQualifiedSplitMultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSplitClaimWithQualificationAndSponsorDomain`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processExogenousQualifiedSplitMultichainClaimWithWitness`. + */ + function usingExogenousQualifiedSplitMultichainClaimWithWitness( + function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, bytes32, ExogenousQualifiedSplitMultichainClaimWithWitness calldata, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) + fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a ExogenousBatchMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processBatchClaimWithSponsorDomain`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processExogenousBatchMultichainClaim`. + */ + function usingExogenousBatchMultichainClaim(function(bytes32, uint256, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn) + internal + pure + returns ( + function(bytes32, ExogenousBatchMultichainClaim calldata, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a ExogenousQualifiedBatchMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processBatchClaimWithQualificationAndSponsorDomain`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processExogenousQualifiedBatchMultichainClaim`. + */ + function usingExogenousQualifiedBatchMultichainClaim( + function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, bytes32, ExogenousQualifiedBatchMultichainClaim calldata, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) + fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a ExogenousBatchMultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processBatchClaimWithSponsorDomain`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processExogenousBatchMultichainClaimWithWitness`. + */ + function usingExogenousBatchMultichainClaimWithWitness( + function(bytes32, uint256, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, ExogenousBatchMultichainClaimWithWitness calldata, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a ExogenousQualifiedBatchMultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processBatchClaimWithQualificationAndSponsorDomain`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processExogenousQualifiedBatchMultichainClaimWithWitness`. + */ + function usingExogenousQualifiedBatchMultichainClaimWithWitness( + function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, bytes32, ExogenousQualifiedBatchMultichainClaimWithWitness calldata, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) + fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a ExogenousSplitBatchMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSplitBatchClaimWithSponsorDomain`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processExogenousSplitBatchMultichainClaim`. + */ + function usingExogenousSplitBatchMultichainClaim( + function(bytes32, uint256, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, ExogenousSplitBatchMultichainClaim calldata, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a ExogenousQualifiedSplitBatchMultichainClaim calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSplitBatchClaimWithQualificationAndSponsorDomain`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processExogenousQualifiedSplitBatchMultichainClaim`. + */ + function usingExogenousQualifiedSplitBatchMultichainClaim( + function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, bytes32, ExogenousQualifiedSplitBatchMultichainClaim calldata, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) + fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a ExogenousSplitBatchMultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSplitBatchClaimWithSponsorDomain`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processExogenousSplitBatchMultichainClaimWithWitness`. + */ + function usingExogenousSplitBatchMultichainClaimWithWitness( + function(bytes32, uint256, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, ExogenousSplitBatchMultichainClaimWithWitness calldata, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) + fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a ExogenousQualifiedSplitBatchMultichainClaimWithWitness calldata struct while + * treating it as a uint256 representing a calldata pointer location. + * @param fnIn Function pointer to `ClaimProcessorLib.processSplitBatchClaimWithQualificationAndSponsorDomain`. + * @return fnOut Modified function used in `ClaimProcessorLogic._processExogenousQualifiedSplitBatchMultichainClaimWithWitness`. + */ + function usingExogenousQualifiedSplitBatchMultichainClaimWithWitness( + function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) fnIn + ) + internal + pure + returns ( + function(bytes32, bytes32, ExogenousQualifiedSplitBatchMultichainClaimWithWitness calldata, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool) + fnOut + ) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } +} diff --git a/src/lib/ClaimProcessorLib.sol b/src/lib/ClaimProcessorLib.sol new file mode 100644 index 0000000..fa36490 --- /dev/null +++ b/src/lib/ClaimProcessorLib.sol @@ -0,0 +1,546 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { ComponentLib } from "./ComponentLib.sol"; +import { EfficiencyLib } from "./EfficiencyLib.sol"; +import { EventLib } from "./EventLib.sol"; +import { HashLib } from "./HashLib.sol"; +import { IdLib } from "./IdLib.sol"; +import { RegistrationLib } from "./RegistrationLib.sol"; +import { ValidityLib } from "./ValidityLib.sol"; + +/** + * @title ClaimProcessorLib + * @notice Library contract implementing internal functions with helper logic for + * processing claims against a signed or registered compact. + * @dev IMPORTANT NOTE: logic for processing claims assumes that the utilized structs are + * formatted in a very specific manner — if parameters are rearranged or new parameters + * are inserted, much of this functionality will break. Proceed with caution when making + * any changes. + */ +library ClaimProcessorLib { + using ComponentLib for bytes32; + using ClaimProcessorLib for uint256; + using ClaimProcessorLib for bytes32; + using EfficiencyLib for bool; + using EfficiencyLib for uint256; + using EfficiencyLib for bytes32; + using EventLib for address; + using HashLib for uint256; + using IdLib for uint256; + using ValidityLib for uint256; + using ValidityLib for uint96; + using ValidityLib for bytes32; + using RegistrationLib for address; + + /** + * @notice Internal function for validating claim execution parameters. Extracts and validates + * signatures from calldata, checks expiration, verifies allocator registration, consumes the + * nonce, derives the domain separator, and validates both the sponsor authorization (either + * through direct registration or a provided signature or EIP-1271 call) and the (potentially + * qualified) allocator authorization. Finally, emits a Claim event. + * @param messageHash The EIP-712 hash of the claim message. + * @param allocatorId The unique identifier for the allocator mediating the claim. + * @param qualificationMessageHash The EIP-712 hash of the allocator's qualification message. + * @param calldataPointer Pointer to the location of the associated struct in calldata. + * @param domainSeparator The local domain separator. + * @param sponsorDomainSeparator The domain separator for the sponsor's signature, or zero for non-exogenous claims. + * @param typehash The EIP-712 typehash used for the claim message. + * @return sponsor The extracted address of the claim sponsor. + */ + function validate(bytes32 messageHash, uint96 allocatorId, bytes32 qualificationMessageHash, uint256 calldataPointer, bytes32 domainSeparator, bytes32 sponsorDomainSeparator, bytes32 typehash) + internal + returns (address sponsor) + { + // Declare variables for signatures and parameters that will be extracted from calldata. + bytes calldata allocatorSignature; + bytes calldata sponsorSignature; + uint256 nonce; + uint256 expires; + + assembly ("memory-safe") { + // Extract allocator signature from calldata using offset stored at calldataPointer. + let allocatorSignaturePtr := add(calldataPointer, calldataload(calldataPointer)) + allocatorSignature.offset := add(0x20, allocatorSignaturePtr) + allocatorSignature.length := calldataload(allocatorSignaturePtr) + + // Extract sponsor signature from calldata using offset stored at calldataPointer + 0x20. + let sponsorSignaturePtr := add(calldataPointer, calldataload(add(calldataPointer, 0x20))) + sponsorSignature.offset := add(0x20, sponsorSignaturePtr) + sponsorSignature.length := calldataload(sponsorSignaturePtr) + + // Extract sponsor address, sanitizing upper 96 bits. + sponsor := shr(96, shl(96, calldataload(add(calldataPointer, 0x40)))) + + // Extract nonce and expiration timestamp. + nonce := calldataload(add(calldataPointer, 0x60)) + expires := calldataload(add(calldataPointer, 0x80)) + } + + // Ensure that the claim hasn't expired. + expires.later(); + + // Retrieve allocator address and consume nonce, ensuring it has not already been consumed. + address allocator = allocatorId.fromRegisteredAllocatorIdWithConsumed(nonce); + + assembly ("memory-safe") { + // Swap domain separator for provided sponsorDomainSeparator if a nonzero value was supplied. + sponsorDomainSeparator := add(sponsorDomainSeparator, mul(iszero(sponsorDomainSeparator), domainSeparator)) + } + + // Validate sponsor authorization through either ECDSA, EIP-1271, or direct registration. + if ((sponsorDomainSeparator != domainSeparator).or(sponsorSignature.length != 0) || sponsor.hasNoActiveRegistration(messageHash, typehash)) { + messageHash.signedBy(sponsor, sponsorSignature, sponsorDomainSeparator); + } + + // Validate allocator authorization against qualification message. + qualificationMessageHash.signedBy(allocator, allocatorSignature, domainSeparator); + + // Emit claim event. + sponsor.emitClaim(messageHash, allocator); + } + + /** + * @notice Internal function for processing qualified claims with potentially exogenous + * sponsor signatures. Extracts claim parameters from calldata, validates the scope, + * ensures the claimed amount is within the allocated amount, validates the claim, + * and executes either a release of ERC6909 tokens or a withdrawal of underlying tokens. + * @param messageHash The EIP-712 hash of the claim message. + * @param qualificationMessageHash The EIP-712 hash of the allocator's qualification message. + * @param calldataPointer Pointer to the location of the associated struct in calldata. + * @param offsetToId Offset to segment of calldata where relevant claim parameters begin. + * @param sponsorDomainSeparator The domain separator for the sponsor's signature, or zero for non-exogenous claims. + * @param typehash The EIP-712 typehash used for the claim message. + * @param domainSeparator The local domain separator. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the claim was successfully processed. + */ + function processClaimWithQualificationAndSponsorDomain( + bytes32 messageHash, + bytes32 qualificationMessageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 sponsorDomainSeparator, + bytes32 typehash, + bytes32 domainSeparator, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + // Declare variables for parameters that will be extracted from calldata. + uint256 id; + uint256 allocatedAmount; + address claimant; + uint256 amount; + + assembly ("memory-safe") { + // Calculate pointer to claim parameters using provided offset. + let calldataPointerWithOffset := add(calldataPointer, offsetToId) + + // Extract resource lock id, allocated amount, claimant address, and claim amount. + id := calldataload(calldataPointerWithOffset) + allocatedAmount := calldataload(add(calldataPointerWithOffset, 0x20)) + claimant := shr(96, shl(96, calldataload(add(calldataPointerWithOffset, 0x40)))) + amount := calldataload(add(calldataPointerWithOffset, 0x60)) + } + + // Verify the resource lock scope is compatible with the provided domain separator. + sponsorDomainSeparator.ensureValidScope(id); + + // Ensure the claimed amount does not exceed the allocated amount. + amount.withinAllocated(allocatedAmount); + + // Validate the claim and execute the specified operation (either release or withdraw). + return operation(messageHash.validate(id.toAllocatorId(), qualificationMessageHash, calldataPointer, domainSeparator, sponsorDomainSeparator, typehash), claimant, id, amount); + } + + /** + * @notice Internal function for processing qualified split claims with potentially exogenous + * sponsor signatures. Extracts claim parameters from calldata, validates the claim, + * validates the scope, and executes either releases of ERC6909 tokens or withdrawals of + * underlying tokens to multiple recipients. + * @param messageHash The EIP-712 hash of the claim message. + * @param qualificationMessageHash The EIP-712 hash of the allocator's qualification message. + * @param calldataPointer Pointer to the location of the associated struct in calldata. + * @param offsetToId Offset to segment of calldata where relevant claim parameters begin. + * @param sponsorDomainSeparator The domain separator for the sponsor's signature, or zero for non-exogenous claims. + * @param typehash The EIP-712 typehash used for the claim message. + * @param domainSeparator The local domain separator. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the split claim was successfully processed. + */ + function processSplitClaimWithQualificationAndSponsorDomain( + bytes32 messageHash, + bytes32 qualificationMessageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 sponsorDomainSeparator, + bytes32 typehash, + bytes32 domainSeparator, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + return messageHash.processClaimWithSplitComponents(qualificationMessageHash, calldataPointer, offsetToId, sponsorDomainSeparator, typehash, domainSeparator, operation, validate); + } + + /** + * @notice Internal function for processing qualified batch claims with potentially exogenous + * sponsor signatures. Extracts batch claim parameters from calldata, validates the claim, + * executes operations, and performs optimized validation of allocator consistency, amounts, + * and scopes. If any validation fails, all operations are reverted after explicitly + * identifying the specific validation failures. + * @param messageHash The EIP-712 hash of the claim message. + * @param qualificationMessageHash The EIP-712 hash of the allocator's qualification message. + * @param calldataPointer Pointer to the location of the associated struct in calldata. + * @param offsetToId Offset to segment of calldata where relevant claim parameters begin. + * @param sponsorDomainSeparator The domain separator for the sponsor's signature, or zero for non-exogenous claims. + * @param typehash The EIP-712 typehash used for the claim message. + * @param domainSeparator The local domain separator. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the batch claim was successfully processed. + */ + function processBatchClaimWithQualificationAndSponsorDomain( + bytes32 messageHash, + bytes32 qualificationMessageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 sponsorDomainSeparator, + bytes32 typehash, + bytes32 domainSeparator, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + return messageHash.processClaimWithBatchComponents(qualificationMessageHash, calldataPointer, offsetToId, sponsorDomainSeparator, typehash, domainSeparator, operation, validate); + } + + /** + * @notice Internal function for processing qualified split batch claims with potentially + * exogenous sponsor signatures. Extracts split batch claim parameters from calldata, + * validates the claim, and executes split operations for each resource lock. Uses optimized + * validation of allocator consistency and scopes, with explicit validation on failure to + * identify specific issues. Each resource lock can be split among multiple recipients. + * @param messageHash The EIP-712 hash of the claim message. + * @param qualificationMessageHash The EIP-712 hash of the allocator's qualification message. + * @param calldataPointer Pointer to the location of the associated struct in calldata. + * @param offsetToId Offset to segment of calldata where relevant claim parameters begin. + * @param sponsorDomainSeparator The domain separator for the sponsor's signature, or zero for non-exogenous claims. + * @param typehash The EIP-712 typehash used for the claim message. + * @param domainSeparator The local domain separator. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the split batch claim was successfully processed. + */ + function processSplitBatchClaimWithQualificationAndSponsorDomain( + bytes32 messageHash, + bytes32 qualificationMessageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 sponsorDomainSeparator, + bytes32 typehash, + bytes32 domainSeparator, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + return messageHash.processClaimWithSplitBatchComponents(qualificationMessageHash, calldataPointer, offsetToId, sponsorDomainSeparator, typehash, domainSeparator, operation, validate); + } + + /** + * @notice Internal function for processing simple claims with local domain signatures. + * Extracts claim parameters from calldata, validates the claim, and executes the + * operation. Uses the message hash itself as the qualification message and a zero + * sponsor domain separator. + * @param messageHash The EIP-712 hash of the claim message. + * @param calldataPointer Pointer to the location of the associated struct in calldata. + * @param offsetToId Offset to segment of calldata where relevant claim parameters begin. + * @param typehash The EIP-712 typehash used for the claim message. + * @param domainSeparator The local domain separator. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the claim was successfully processed. + */ + function processSimpleClaim( + bytes32 messageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 typehash, + bytes32 domainSeparator, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + return messageHash.processClaimWithQualificationAndSponsorDomain(messageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, domainSeparator, operation); + } + + /** + * @notice Internal function for processing simple split claims with local domain + * signatures. Extracts split claim parameters from calldata, validates the claim, + * and executes operations for multiple recipients. Uses the message hash itself as + * the qualification message and a zero sponsor domain separator. + * @param messageHash The EIP-712 hash of the claim message. + * @param calldataPointer Pointer to the location of the associated struct in calldata. + * @param offsetToId Offset to segment of calldata where relevant claim parameters begin. + * @param typehash The EIP-712 typehash used for the claim message. + * @param domainSeparator The local domain separator. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the split claim was successfully processed. + */ + function processSimpleSplitClaim( + bytes32 messageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 typehash, + bytes32 domainSeparator, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + return messageHash.processSplitClaimWithQualificationAndSponsorDomain(messageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, domainSeparator, operation); + } + + /** + * @notice Internal function for processing simple batch claims with local domain + * signatures. Extracts batch claim parameters from calldata, validates the claim, + * and executes operations for multiple resource locks to a single recipient. Uses + * the message hash itself as the qualification message and a zero sponsor domain + * separator. + * @param messageHash The EIP-712 hash of the claim message. + * @param calldataPointer Pointer to the location of the associated struct in calldata. + * @param offsetToId Offset to segment of calldata where relevant claim parameters begin. + * @param typehash The EIP-712 typehash used for the claim message. + * @param domainSeparator The local domain separator. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the batch claim was successfully processed. + */ + function processSimpleBatchClaim( + bytes32 messageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 typehash, + bytes32 domainSeparator, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + return messageHash.processBatchClaimWithQualificationAndSponsorDomain(messageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, domainSeparator, operation); + } + + /** + * @notice Internal function for processing batch claims with qualification messages. + * Extracts batch claim parameters from calldata, validates the claim using the provided + * qualification message, and executes operations for multiple resource locks to a single + * recipient. Uses a zero sponsor domain separator. + * @param messageHash The EIP-712 hash of the claim message. + * @param qualificationMessageHash The EIP-712 hash of the allocator's qualification message. + * @param calldataPointer Pointer to the location of the associated struct in calldata. + * @param offsetToId Offset to segment of calldata where relevant claim parameters begin. + * @param typehash The EIP-712 typehash used for the claim message. + * @param domainSeparator The local domain separator. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the batch claim was successfully processed. + */ + function processBatchClaimWithQualification( + bytes32 messageHash, + bytes32 qualificationMessageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 typehash, + bytes32 domainSeparator, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + return messageHash.processBatchClaimWithQualificationAndSponsorDomain(qualificationMessageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, domainSeparator, operation); + } + + /** + * @notice Internal function for processing simple split batch claims with local domain + * signatures. Extracts split batch claim parameters from calldata, validates the claim, + * and executes operations for multiple resource locks to multiple recipients. Uses the + * message hash itself as the qualification message and a zero sponsor domain separator. + * @param messageHash The EIP-712 hash of the claim message. + * @param calldataPointer Pointer to the location of the associated struct in calldata. + * @param offsetToId Offset to segment of calldata where relevant claim parameters begin. + * @param typehash The EIP-712 typehash used for the claim message. + * @param domainSeparator The local domain separator. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the split batch claim was successfully processed. + */ + function processSimpleSplitBatchClaim( + bytes32 messageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 typehash, + bytes32 domainSeparator, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + return messageHash.processSplitBatchClaimWithQualificationAndSponsorDomain(messageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, domainSeparator, operation); + } + + /** + * @notice Internal function for processing split batch claims with qualification + * messages. Extracts split batch claim parameters from calldata, validates the claim + * using the provided qualification message, and executes operations for multiple + * resource locks to multiple recipients. Uses a zero sponsor domain separator. + * @param messageHash The EIP-712 hash of the claim message. + * @param qualificationMessageHash The EIP-712 hash of the allocator's qualification message. + * @param calldataPointer Pointer to the location of the associated struct in calldata. + * @param offsetToId Offset to segment of calldata where relevant claim parameters begin. + * @param typehash The EIP-712 typehash used for the claim message. + * @param domainSeparator The local domain separator. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the split batch claim was successfully processed. + */ + function processSplitBatchClaimWithQualification( + bytes32 messageHash, + bytes32 qualificationMessageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 typehash, + bytes32 domainSeparator, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + return messageHash.processSplitBatchClaimWithQualificationAndSponsorDomain(qualificationMessageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, domainSeparator, operation); + } + + /** + * @notice Internal function for processing claims with sponsor domain signatures. + * Extracts claim parameters from calldata, validates the claim using the provided + * sponsor domain, and executes the operation. Uses the message hash itself as the + * qualification message. + * @param messageHash The EIP-712 hash of the claim message. + * @param calldataPointer Pointer to the location of the associated struct in calldata. + * @param offsetToId Offset to segment of calldata where relevant claim parameters begin. + * @param sponsorDomain The domain separator for the sponsor's signature. + * @param typehash The EIP-712 typehash used for the claim message. + * @param domainSeparator The local domain separator. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the claim was successfully processed. + */ + function processClaimWithSponsorDomain( + bytes32 messageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 sponsorDomain, + bytes32 typehash, + bytes32 domainSeparator, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + return messageHash.processClaimWithQualificationAndSponsorDomain(messageHash, calldataPointer, offsetToId, sponsorDomain, typehash, domainSeparator, operation); + } + + /** + * @notice Internal function for processing claims with qualification messages. + * Extracts claim parameters from calldata, validates the claim using the provided + * qualification message, and executes the operation. Uses a zero sponsor domain + * separator. + * @param messageHash The EIP-712 hash of the claim message. + * @param qualificationMessageHash The EIP-712 hash of the allocator's qualification message. + * @param calldataPointer Pointer to the location of the associated struct in calldata. + * @param offsetToId Offset to segment of calldata where relevant claim parameters begin. + * @param typehash The EIP-712 typehash used for the claim message. + * @param domainSeparator The local domain separator. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the claim was successfully processed. + */ + function processClaimWithQualification( + bytes32 messageHash, + bytes32 qualificationMessageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 typehash, + bytes32 domainSeparator, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + return messageHash.processClaimWithQualificationAndSponsorDomain(qualificationMessageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, domainSeparator, operation); + } + + /** + * @notice Internal function for processing split claims with qualification messages. + * Extracts split claim parameters from calldata, validates the claim using the provided + * qualification message, and executes operations for multiple recipients. Uses a zero + * sponsor domain separator. + * @param messageHash The EIP-712 hash of the claim message. + * @param qualificationMessageHash The EIP-712 hash of the allocator's qualification message. + * @param calldataPointer Pointer to the location of the associated struct in calldata. + * @param offsetToId Offset to segment of calldata where relevant claim parameters begin. + * @param typehash The EIP-712 typehash used for the claim message. + * @param domainSeparator The local domain separator. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the split claim was successfully processed. + */ + function processSplitClaimWithQualification( + bytes32 messageHash, + bytes32 qualificationMessageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 typehash, + bytes32 domainSeparator, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + return messageHash.processSplitClaimWithQualificationAndSponsorDomain(qualificationMessageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, domainSeparator, operation); + } + + /** + * @notice Internal function for processing split claims with sponsor domain signatures. + * Extracts split claim parameters from calldata, validates the claim using the provided + * sponsor domain, and executes operations for multiple recipients. Uses the message + * hash itself as the qualification message. + * @param messageHash The EIP-712 hash of the claim message. + * @param calldataPointer Pointer to the location of the associated struct in calldata. + * @param offsetToId Offset to segment of calldata where relevant claim parameters begin. + * @param sponsorDomain The domain separator for the sponsor's signature. + * @param typehash The EIP-712 typehash used for the claim message. + * @param domainSeparator The local domain separator. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the split claim was successfully processed. + */ + function processSplitClaimWithSponsorDomain( + bytes32 messageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 sponsorDomain, + bytes32 typehash, + bytes32 domainSeparator, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + return messageHash.processSplitClaimWithQualificationAndSponsorDomain(messageHash, calldataPointer, offsetToId, sponsorDomain, typehash, domainSeparator, operation); + } + + /** + * @notice Internal function for processing batch claims with sponsor domain signatures. + * Extracts batch claim parameters from calldata, validates the claim using the provided + * sponsor domain, and executes operations for multiple resource locks to a single + * recipient. Uses the message hash itself as the qualification message. + * @param messageHash The EIP-712 hash of the claim message. + * @param calldataPointer Pointer to the location of the associated struct in calldata. + * @param offsetToId Offset to segment of calldata where relevant claim parameters begin. + * @param sponsorDomain The domain separator for the sponsor's signature. + * @param typehash The EIP-712 typehash used for the claim message. + * @param domainSeparator The local domain separator. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the batch claim was successfully processed. + */ + function processBatchClaimWithSponsorDomain( + bytes32 messageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 sponsorDomain, + bytes32 typehash, + bytes32 domainSeparator, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + return messageHash.processBatchClaimWithQualificationAndSponsorDomain(messageHash, calldataPointer, offsetToId, sponsorDomain, typehash, domainSeparator, operation); + } + + /** + * @notice Internal function for processing split batch claims with sponsor domain + * signatures. Extracts split batch claim parameters from calldata, validates the claim + * using the provided sponsor domain, and executes operations for multiple resource + * locks to multiple recipients. Uses the message hash itself as the qualification + * message. + * @param messageHash The EIP-712 hash of the claim message. + * @param calldataPointer Pointer to the location of the associated struct in calldata. + * @param offsetToId Offset to segment of calldata where relevant claim parameters begin. + * @param sponsorDomain The domain separator for the sponsor's signature. + * @param typehash The EIP-712 typehash used for the claim message. + * @param domainSeparator The local domain separator. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the split batch claim was successfully processed. + */ + function processSplitBatchClaimWithSponsorDomain( + bytes32 messageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 sponsorDomain, + bytes32 typehash, + bytes32 domainSeparator, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + return messageHash.processSplitBatchClaimWithQualificationAndSponsorDomain(messageHash, calldataPointer, offsetToId, sponsorDomain, typehash, domainSeparator, operation); + } +} diff --git a/src/lib/ClaimProcessorLogic.sol b/src/lib/ClaimProcessorLogic.sol new file mode 100644 index 0000000..4ffa533 --- /dev/null +++ b/src/lib/ClaimProcessorLogic.sol @@ -0,0 +1,493 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { BasicClaim, QualifiedClaim, ClaimWithWitness, QualifiedClaimWithWitness, SplitClaim, SplitClaimWithWitness, QualifiedSplitClaim, QualifiedSplitClaimWithWitness } from "../types/Claims.sol"; +import { + BatchClaim, + QualifiedBatchClaim, + BatchClaimWithWitness, + QualifiedBatchClaimWithWitness, + SplitBatchClaim, + SplitBatchClaimWithWitness, + QualifiedSplitBatchClaim, + QualifiedSplitBatchClaimWithWitness +} from "../types/BatchClaims.sol"; +import { + MultichainClaim, + QualifiedMultichainClaim, + MultichainClaimWithWitness, + QualifiedMultichainClaimWithWitness, + SplitMultichainClaim, + SplitMultichainClaimWithWitness, + QualifiedSplitMultichainClaim, + QualifiedSplitMultichainClaimWithWitness, + ExogenousMultichainClaim, + ExogenousQualifiedMultichainClaim, + ExogenousMultichainClaimWithWitness, + ExogenousQualifiedMultichainClaimWithWitness, + ExogenousSplitMultichainClaim, + ExogenousSplitMultichainClaimWithWitness, + ExogenousQualifiedSplitMultichainClaim, + ExogenousQualifiedSplitMultichainClaimWithWitness +} from "../types/MultichainClaims.sol"; +import { + BatchMultichainClaim, + QualifiedBatchMultichainClaim, + BatchMultichainClaimWithWitness, + QualifiedBatchMultichainClaimWithWitness, + SplitBatchMultichainClaim, + SplitBatchMultichainClaimWithWitness, + QualifiedSplitBatchMultichainClaim, + QualifiedSplitBatchMultichainClaimWithWitness, + ExogenousBatchMultichainClaim, + ExogenousQualifiedBatchMultichainClaim, + ExogenousBatchMultichainClaimWithWitness, + ExogenousQualifiedBatchMultichainClaimWithWitness, + ExogenousSplitBatchMultichainClaim, + ExogenousSplitBatchMultichainClaimWithWitness, + ExogenousQualifiedSplitBatchMultichainClaim, + ExogenousQualifiedSplitBatchMultichainClaimWithWitness +} from "../types/BatchMultichainClaims.sol"; + +import { ClaimHashLib } from "./ClaimHashLib.sol"; +import { ClaimProcessorLib } from "./ClaimProcessorLib.sol"; +import { ClaimProcessorFunctionCastLib } from "./ClaimProcessorFunctionCastLib.sol"; +import { DomainLib } from "./DomainLib.sol"; +import { HashLib } from "./HashLib.sol"; +import { EfficiencyLib } from "./EfficiencyLib.sol"; +import { SharedLogic } from "./SharedLogic.sol"; +import { ValidityLib } from "./ValidityLib.sol"; + +/** + * @title ClaimProcessorLogic + * @notice Inherited contract implementing internal functions with logic for processing + * claims against a signed or registered compact. Each function derives the respective + * claim hash as well as a qualification hash or typehash if applicable, then processes + * the claim. + * @dev IMPORTANT NOTE: this logic assumes that the utilized structs are formatted in a + * very specific manner — if parameters are rearranged or new parameters are inserted, + * much of this functionality will break. Proceed with caution when making any changes. + */ +contract ClaimProcessorLogic is SharedLogic { + using ClaimHashLib for BasicClaim; + using ClaimHashLib for QualifiedClaim; + using ClaimHashLib for ClaimWithWitness; + using ClaimHashLib for QualifiedClaimWithWitness; + using ClaimHashLib for SplitClaim; + using ClaimHashLib for SplitClaimWithWitness; + using ClaimHashLib for QualifiedSplitClaim; + using ClaimHashLib for QualifiedSplitClaimWithWitness; + using ClaimHashLib for BatchClaim; + using ClaimHashLib for QualifiedBatchClaim; + using ClaimHashLib for BatchClaimWithWitness; + using ClaimHashLib for QualifiedBatchClaimWithWitness; + using ClaimHashLib for SplitBatchClaim; + using ClaimHashLib for SplitBatchClaimWithWitness; + using ClaimHashLib for QualifiedSplitBatchClaim; + using ClaimHashLib for QualifiedSplitBatchClaimWithWitness; + using ClaimHashLib for MultichainClaim; + using ClaimHashLib for QualifiedMultichainClaim; + using ClaimHashLib for MultichainClaimWithWitness; + using ClaimHashLib for QualifiedMultichainClaimWithWitness; + using ClaimHashLib for SplitMultichainClaim; + using ClaimHashLib for SplitMultichainClaimWithWitness; + using ClaimHashLib for QualifiedSplitMultichainClaim; + using ClaimHashLib for QualifiedSplitMultichainClaimWithWitness; + using ClaimHashLib for ExogenousMultichainClaim; + using ClaimHashLib for ExogenousQualifiedMultichainClaim; + using ClaimHashLib for ExogenousMultichainClaimWithWitness; + using ClaimHashLib for ExogenousQualifiedMultichainClaimWithWitness; + using ClaimHashLib for ExogenousSplitMultichainClaim; + using ClaimHashLib for ExogenousSplitMultichainClaimWithWitness; + using ClaimHashLib for ExogenousQualifiedSplitMultichainClaim; + using ClaimHashLib for ExogenousQualifiedSplitMultichainClaimWithWitness; + using ClaimHashLib for BatchMultichainClaim; + using ClaimHashLib for QualifiedBatchMultichainClaim; + using ClaimHashLib for BatchMultichainClaimWithWitness; + using ClaimHashLib for QualifiedBatchMultichainClaimWithWitness; + using ClaimHashLib for SplitBatchMultichainClaim; + using ClaimHashLib for SplitBatchMultichainClaimWithWitness; + using ClaimHashLib for QualifiedSplitBatchMultichainClaim; + using ClaimHashLib for QualifiedSplitBatchMultichainClaimWithWitness; + using ClaimHashLib for ExogenousBatchMultichainClaim; + using ClaimHashLib for ExogenousQualifiedBatchMultichainClaim; + using ClaimHashLib for ExogenousBatchMultichainClaimWithWitness; + using ClaimHashLib for ExogenousQualifiedBatchMultichainClaimWithWitness; + using ClaimHashLib for ExogenousSplitBatchMultichainClaim; + using ClaimHashLib for ExogenousSplitBatchMultichainClaimWithWitness; + using ClaimHashLib for ExogenousQualifiedSplitBatchMultichainClaim; + using ClaimHashLib for ExogenousQualifiedSplitBatchMultichainClaimWithWitness; + using ClaimProcessorLib for uint256; + using ClaimProcessorFunctionCastLib for function(bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool); + using ClaimProcessorFunctionCastLib for function(bytes32, uint256, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool); + using ClaimProcessorFunctionCastLib for function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool); + using ClaimProcessorFunctionCastLib for function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool); + using DomainLib for uint256; + using HashLib for uint256; + using EfficiencyLib for uint256; + using ValidityLib for uint96; + using ValidityLib for uint256; + using ValidityLib for bytes32; + + ///// 1. Claims ///// + function _processBasicClaim(BasicClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + return ClaimProcessorLib.processSimpleClaim.usingBasicClaim()(claimPayload.toClaimHash(), claimPayload, uint256(0xa0).asStubborn(), uint256(0).asStubborn().typehashes(), _domainSeparator(), operation); + } + + function _processQualifiedClaim(QualifiedClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHashes(); + return + ClaimProcessorLib.processClaimWithQualification.usingQualifiedClaim()(messageHash, qualificationMessageHash, claimPayload, 0xe0, uint256(0).asStubborn().typehashes(), _domainSeparator(), operation); + } + + function _processClaimWithWitness(ClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSimpleClaim.usingClaimWithWitness()(messageHash, claimPayload, 0xe0, typehash, _domainSeparator(), operation); + } + + function _processQualifiedClaimWithWitness(QualifiedClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processClaimWithQualification.usingQualifiedClaimWithWitness()(messageHash, qualificationMessageHash, claimPayload, 0x120, typehash, _domainSeparator(), operation); + } + + function _processSplitClaim(SplitClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + return ClaimProcessorLib.processSimpleSplitClaim.usingSplitClaim()(claimPayload.toClaimHash(), claimPayload, 0xa0, uint256(0).asStubborn().typehashes(), _domainSeparator(), operation); + } + + function _processQualifiedSplitClaim(QualifiedSplitClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSplitClaimWithQualification.usingQualifiedSplitClaim()( + messageHash, qualificationMessageHash, claimPayload, 0xe0, uint256(0).asStubborn().typehashes(), _domainSeparator(), operation + ); + } + + function _processSplitClaimWithWitness(SplitClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSimpleSplitClaim.usingSplitClaimWithWitness()(messageHash, claimPayload, 0xe0, typehash, _domainSeparator(), operation); + } + + function _processQualifiedSplitClaimWithWitness(QualifiedSplitClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSplitClaimWithQualification.usingQualifiedSplitClaimWithWitness()(messageHash, qualificationMessageHash, claimPayload, 0x120, typehash, _domainSeparator(), operation); + } + + ///// 2. Batch Claims ///// + function _processBatchClaim(BatchClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + return ClaimProcessorLib.processSimpleBatchClaim.usingBatchClaim()(claimPayload.toClaimHash(), claimPayload, 0xa0, uint256(1).asStubborn().typehashes(), _domainSeparator(), operation); + } + + function _processQualifiedBatchClaim(QualifiedBatchClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processBatchClaimWithQualification.usingQualifiedBatchClaim()( + messageHash, qualificationMessageHash, claimPayload, 0xe0, uint256(1).asStubborn().typehashes(), _domainSeparator(), operation + ); + } + + function _processBatchClaimWithWitness(BatchClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSimpleBatchClaim.usingBatchClaimWithWitness()(messageHash, claimPayload, 0xe0, typehash, _domainSeparator(), operation); + } + + function _processQualifiedBatchClaimWithWitness(QualifiedBatchClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processBatchClaimWithQualification.usingQualifiedBatchClaimWithWitness()(messageHash, qualificationMessageHash, claimPayload, 0x120, typehash, _domainSeparator(), operation); + } + + function _processSplitBatchClaim(SplitBatchClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + return ClaimProcessorLib.processSimpleSplitBatchClaim.usingSplitBatchClaim()(claimPayload.toClaimHash(), claimPayload, 0xa0, uint256(1).asStubborn().typehashes(), _domainSeparator(), operation); + } + + function _processQualifiedSplitBatchClaim(QualifiedSplitBatchClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSplitBatchClaimWithQualification.usingQualifiedSplitBatchClaim()( + messageHash, qualificationMessageHash, claimPayload, 0xe0, uint256(1).asStubborn().typehashes(), _domainSeparator(), operation + ); + } + + function _processSplitBatchClaimWithWitness(SplitBatchClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSimpleSplitBatchClaim.usingSplitBatchClaimWithWitness()(messageHash, claimPayload, 0xe0, typehash, _domainSeparator(), operation); + } + + function _processQualifiedSplitBatchClaimWithWitness(QualifiedSplitBatchClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSplitBatchClaimWithQualification.usingQualifiedSplitBatchClaimWithWitness()( + messageHash, qualificationMessageHash, claimPayload, 0x120, typehash, _domainSeparator(), operation + ); + } + + ///// 3. Multichain Claims ///// + function _processMultichainClaim(MultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + return ClaimProcessorLib.processSimpleClaim.usingMultichainClaim()(claimPayload.toClaimHash(), claimPayload, 0xc0, uint256(2).asStubborn().typehashes(), _domainSeparator(), operation); + } + + function _processQualifiedMultichainClaim(QualifiedMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processClaimWithQualification.usingQualifiedMultichainClaim()( + messageHash, qualificationMessageHash, claimPayload, 0x100, uint256(2).asStubborn().typehashes(), _domainSeparator(), operation + ); + } + + function _processMultichainClaimWithWitness(MultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSimpleClaim.usingMultichainClaimWithWitness()(messageHash, claimPayload, 0x100, typehash, _domainSeparator(), operation); + } + + function _processQualifiedMultichainClaimWithWitness(QualifiedMultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processClaimWithQualification.usingQualifiedMultichainClaimWithWitness()(messageHash, qualificationMessageHash, claimPayload, 0x140, typehash, _domainSeparator(), operation); + } + + function _processSplitMultichainClaim(SplitMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + return ClaimProcessorLib.processSimpleSplitClaim.usingSplitMultichainClaim()(claimPayload.toClaimHash(), claimPayload, 0xc0, uint256(2).asStubborn().typehashes(), _domainSeparator(), operation); + } + + function _processQualifiedSplitMultichainClaim(QualifiedSplitMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSplitClaimWithQualification.usingQualifiedSplitMultichainClaim()( + messageHash, qualificationMessageHash, claimPayload, 0x100, uint256(2).asStubborn().typehashes(), _domainSeparator(), operation + ); + } + + function _processSplitMultichainClaimWithWitness(SplitMultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSimpleSplitClaim.usingSplitMultichainClaimWithWitness()(messageHash, claimPayload, 0x100, typehash, _domainSeparator(), operation); + } + + function _processQualifiedSplitMultichainClaimWithWitness(QualifiedSplitMultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSplitClaimWithQualification.usingQualifiedSplitMultichainClaimWithWitness()( + messageHash, qualificationMessageHash, claimPayload, 0x140, typehash, _domainSeparator(), operation + ); + } + + ///// 4. Batch Multichain Claims ///// + function _processBatchMultichainClaim(BatchMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + return ClaimProcessorLib.processSimpleBatchClaim.usingBatchMultichainClaim()(claimPayload.toClaimHash(), claimPayload, 0xc0, uint256(2).asStubborn().typehashes(), _domainSeparator(), operation); + } + + function _processQualifiedBatchMultichainClaim(QualifiedBatchMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processBatchClaimWithQualification.usingQualifiedBatchMultichainClaim()( + messageHash, qualificationMessageHash, claimPayload, 0x100, uint256(2).asStubborn().typehashes(), _domainSeparator(), operation + ); + } + + function _processBatchMultichainClaimWithWitness(BatchMultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSimpleBatchClaim.usingBatchMultichainClaimWithWitness()(messageHash, claimPayload, 0x100, typehash, _domainSeparator(), operation); + } + + function _processQualifiedBatchMultichainClaimWithWitness(QualifiedBatchMultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processBatchClaimWithQualification.usingQualifiedBatchMultichainClaimWithWitness()( + messageHash, qualificationMessageHash, claimPayload, 0x140, typehash, _domainSeparator(), operation + ); + } + + function _processSplitBatchMultichainClaim(SplitBatchMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + return + ClaimProcessorLib.processSimpleSplitBatchClaim.usingSplitBatchMultichainClaim()(claimPayload.toClaimHash(), claimPayload, 0xc0, uint256(2).asStubborn().typehashes(), _domainSeparator(), operation); + } + + function _processQualifiedSplitBatchMultichainClaim(QualifiedSplitBatchMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSplitBatchClaimWithQualification.usingQualifiedSplitBatchMultichainClaim()( + messageHash, qualificationMessageHash, claimPayload, 0x100, uint256(1).asStubborn().typehashes(), _domainSeparator(), operation + ); + } + + function _processSplitBatchMultichainClaimWithWitness(SplitBatchMultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSimpleSplitBatchClaim.usingSplitBatchMultichainClaimWithWitness()(messageHash, claimPayload, 0x100, typehash, _domainSeparator(), operation); + } + + function _processQualifiedSplitBatchMultichainClaimWithWitness( + QualifiedSplitBatchMultichainClaimWithWitness calldata claimPayload, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSplitBatchClaimWithQualification.usingQualifiedSplitBatchMultichainClaimWithWitness()( + messageHash, qualificationMessageHash, claimPayload, 0x140, typehash, _domainSeparator(), operation + ); + } + + ///// 5. Exogenous Multichain Claims ///// + function _processExogenousMultichainClaim(ExogenousMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + return ClaimProcessorLib.processClaimWithSponsorDomain.usingExogenousMultichainClaim()( + claimPayload.toClaimHash(), claimPayload, 0x100, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), uint256(2).asStubborn().typehashes(), _domainSeparator(), operation + ); + } + + function _processExogenousQualifiedMultichainClaim(ExogenousQualifiedMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedMultichainClaim()( + messageHash, qualificationMessageHash, claimPayload, 0x140, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), uint256(2).asStubborn().typehashes(), _domainSeparator(), operation + ); + } + + function _processExogenousMultichainClaimWithWitness(ExogenousMultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processClaimWithSponsorDomain.usingExogenousMultichainClaimWithWitness()( + messageHash, claimPayload, 0x140, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), typehash, _domainSeparator(), operation + ); + } + + function _processExogenousQualifiedMultichainClaimWithWitness( + ExogenousQualifiedMultichainClaimWithWitness calldata claimPayload, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedMultichainClaimWithWitness()( + messageHash, qualificationMessageHash, claimPayload, 0x180, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), typehash, _domainSeparator(), operation + ); + } + + function _processExogenousSplitMultichainClaim(ExogenousSplitMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + return ClaimProcessorLib.processSplitClaimWithSponsorDomain.usingExogenousSplitMultichainClaim()( + claimPayload.toClaimHash(), claimPayload, 0x100, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), uint256(2).asStubborn().typehashes(), _domainSeparator(), operation + ); + } + + function _processExogenousQualifiedSplitMultichainClaim(ExogenousQualifiedSplitMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSplitClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedSplitMultichainClaim()( + messageHash, qualificationMessageHash, claimPayload, 0x140, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), uint256(2).asStubborn().typehashes(), _domainSeparator(), operation + ); + } + + function _processExogenousSplitMultichainClaimWithWitness(ExogenousSplitMultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSplitClaimWithSponsorDomain.usingExogenousSplitMultichainClaimWithWitness()( + messageHash, claimPayload, 0x140, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), typehash, _domainSeparator(), operation + ); + } + + function _processExogenousQualifiedSplitMultichainClaimWithWitness( + ExogenousQualifiedSplitMultichainClaimWithWitness calldata claimPayload, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSplitClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedSplitMultichainClaimWithWitness()( + messageHash, qualificationMessageHash, claimPayload, 0x180, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), typehash, _domainSeparator(), operation + ); + } + + ///// 6. Exogenous Batch Multichain Claims ///// + function _processExogenousBatchMultichainClaim(ExogenousBatchMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + return ClaimProcessorLib.processBatchClaimWithSponsorDomain.usingExogenousBatchMultichainClaim()( + claimPayload.toClaimHash(), claimPayload, 0x100, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), uint256(2).asStubborn().typehashes(), _domainSeparator(), operation + ); + } + + function _processExogenousQualifiedBatchMultichainClaim(ExogenousQualifiedBatchMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processBatchClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedBatchMultichainClaim()( + messageHash, qualificationMessageHash, claimPayload, 0x140, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), uint256(2).asStubborn().typehashes(), _domainSeparator(), operation + ); + } + + function _processExogenousBatchMultichainClaimWithWitness(ExogenousBatchMultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processBatchClaimWithSponsorDomain.usingExogenousBatchMultichainClaimWithWitness()( + messageHash, claimPayload, 0x140, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), typehash, _domainSeparator(), operation + ); + } + + function _processExogenousQualifiedBatchMultichainClaimWithWitness( + ExogenousQualifiedBatchMultichainClaimWithWitness calldata claimPayload, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processBatchClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedBatchMultichainClaimWithWitness()( + messageHash, qualificationMessageHash, claimPayload, 0x180, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), typehash, _domainSeparator(), operation + ); + } + + function _processExogenousSplitBatchMultichainClaim(ExogenousSplitBatchMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + return ClaimProcessorLib.processSplitBatchClaimWithSponsorDomain.usingExogenousSplitBatchMultichainClaim()( + claimPayload.toClaimHash(), claimPayload, 0x100, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), uint256(2).asStubborn().typehashes(), _domainSeparator(), operation + ); + } + + function _processExogenousQualifiedSplitBatchMultichainClaim( + ExogenousQualifiedSplitBatchMultichainClaim calldata claimPayload, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSplitBatchClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedSplitBatchMultichainClaim()( + messageHash, qualificationMessageHash, claimPayload, 0x140, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), uint256(2).asStubborn().typehashes(), _domainSeparator(), operation + ); + } + + function _processExogenousSplitBatchMultichainClaimWithWitness( + ExogenousSplitBatchMultichainClaimWithWitness calldata claimPayload, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSplitBatchClaimWithSponsorDomain.usingExogenousSplitBatchMultichainClaimWithWitness()( + messageHash, claimPayload, 0x140, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), typehash, _domainSeparator(), operation + ); + } + + function _processExogenousQualifiedSplitBatchMultichainClaimWithWitness( + ExogenousQualifiedSplitBatchMultichainClaimWithWitness calldata claimPayload, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHashes(); + return ClaimProcessorLib.processSplitBatchClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedSplitBatchMultichainClaimWithWitness()( + messageHash, qualificationMessageHash, claimPayload, 0x180, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), typehash, _domainSeparator(), operation + ); + } +} diff --git a/src/lib/ComponentLib.sol b/src/lib/ComponentLib.sol new file mode 100644 index 0000000..7599abc --- /dev/null +++ b/src/lib/ComponentLib.sol @@ -0,0 +1,408 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { SplitTransfer } from "../types/Claims.sol"; +import { BatchTransfer, SplitBatchTransfer } from "../types/BatchClaims.sol"; + +import { TransferComponent, SplitComponent, SplitByIdComponent, BatchClaimComponent, SplitBatchClaimComponent } from "../types/Components.sol"; + +import { EfficiencyLib } from "./EfficiencyLib.sol"; +import { EventLib } from "./EventLib.sol"; +import { HashLib } from "./HashLib.sol"; +import { IdLib } from "./IdLib.sol"; +import { RegistrationLib } from "./RegistrationLib.sol"; +import { ValidityLib } from "./ValidityLib.sol"; + +/** + * @title ComponentLib + * @notice Library contract implementing internal functions with helper logic for + * processing claims that incorporate split and/or batch components. + * @dev IMPORTANT NOTE: logic for processing claims assumes that the utilized structs are + * formatted in a very specific manner — if parameters are rearranged or new parameters + * are inserted, much of this functionality will break. Proceed with caution when making + * any changes. + */ +library ComponentLib { + using ComponentLib for SplitComponent[]; + using EfficiencyLib for bool; + using EfficiencyLib for uint256; + using EfficiencyLib for bytes32; + using EventLib for address; + using HashLib for uint256; + using IdLib for uint256; + using ValidityLib for uint256; + using ValidityLib for uint96; + using ValidityLib for bytes32; + using RegistrationLib for address; + + /** + * @notice Internal function for performing a set of split transfers or withdrawals. + * Executes the transfer or withdrawal operation targeting multiple recipients from + * a single resource lock. + * @param transfer A SplitTransfer struct containing split transfer details. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the transfer was successfully processed. + */ + function processSplitTransfer(SplitTransfer calldata transfer, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + // Process the transfer for each split component. + _processSplitTransferComponents(transfer.recipients, transfer.id, operation); + + return true; + } + + /** + * @notice Internal function for performing a set of batch transfer or withdrawal operations. + * Executes the transfer or withdrawal operation for a single recipient from multiple + * resource locks. + * @param transfer A BatchTransfer struct containing batch transfer details. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the transfer was successfully processed. + */ + function performBatchTransfer(BatchTransfer calldata transfer, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + // Navigate to the transfer components in calldata. + TransferComponent[] calldata transfers = transfer.transfers; + + // Retrieve the recipient and the total number of components. + address recipient = transfer.recipient; + uint256 totalTransfers = transfers.length; + + unchecked { + // Iterate over each component in calldata. + for (uint256 i = 0; i < totalTransfers; ++i) { + // Navigate to location of the component in calldata. + TransferComponent calldata component = transfers[i]; + + // Perform the transfer or withdrawal for the component. + operation(msg.sender, recipient, component.id, component.amount); + } + } + + return true; + } + + /** + * @notice Internal function for performing a set of split batch transfers or withdrawals. + * Executes the transfer or withdrawal operation for multiple recipients from multiple + * resource locks. + * @param transfer A SplitBatchTransfer struct containing split batch transfer details. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the transfer was successfully processed. + */ + function performSplitBatchTransfer(SplitBatchTransfer calldata transfer, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + // Navigate to the split batch components array in calldata. + SplitByIdComponent[] calldata transfers = transfer.transfers; + + // Retrieve the total number of components. + uint256 totalIds = transfers.length; + + unchecked { + // Iterate over each component in calldata. + for (uint256 i = 0; i < totalIds; ++i) { + // Navigate to location of the component in calldata. + SplitByIdComponent calldata component = transfers[i]; + + // Process transfer for each split component in the set. + _processSplitTransferComponents(component.portions, component.id, operation); + } + } + + return true; + } + + /** + * @notice Internal function for processing qualified split claims with potentially exogenous + * sponsor signatures. Extracts claim parameters from calldata, validates the claim, + * validates the scope, and executes either releases of ERC6909 tokens or withdrawals of + * underlying tokens to multiple recipients. + * @param messageHash The EIP-712 hash of the claim message. + * @param qualificationMessageHash The EIP-712 hash of the allocator's qualification message. + * @param calldataPointer Pointer to the location of the associated struct in calldata. + * @param offsetToId Offset to segment of calldata where relevant claim parameters begin. + * @param sponsorDomainSeparator The domain separator for the sponsor's signature, or zero for non-exogenous claims. + * @param typehash The EIP-712 typehash used for the claim message. + * @param domainSeparator The local domain separator. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @param validation Function pointer to the _validate function. + * @return Whether the split claim was successfully processed. + */ + function processClaimWithSplitComponents( + bytes32 messageHash, + bytes32 qualificationMessageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 sponsorDomainSeparator, + bytes32 typehash, + bytes32 domainSeparator, + function(address, address, uint256, uint256) internal returns (bool) operation, + function(bytes32, uint96, bytes32, uint256, bytes32, bytes32, bytes32) internal returns (address) validation + ) internal returns (bool) { + // Declare variables for parameters that will be extracted from calldata. + uint256 id; + uint256 allocatedAmount; + SplitComponent[] calldata components; + + assembly ("memory-safe") { + // Calculate pointer to claim parameters using provided offset. + let calldataPointerWithOffset := add(calldataPointer, offsetToId) + + // Extract resource lock id and allocated amount. + id := calldataload(calldataPointerWithOffset) + allocatedAmount := calldataload(add(calldataPointerWithOffset, 0x20)) + + // Extract array of split components containing claimant addresses and amounts. + let componentsPtr := add(calldataPointer, calldataload(add(calldataPointerWithOffset, 0x40))) + components.offset := add(0x20, componentsPtr) + components.length := calldataload(componentsPtr) + } + + // Validate the claim and extract the sponsor address. + address sponsor = validation(messageHash, id.toAllocatorId(), qualificationMessageHash, calldataPointer, domainSeparator, sponsorDomainSeparator, typehash); + + // Verify the resource lock scope is compatible with the provided domain separator. + sponsorDomainSeparator.ensureValidScope(id); + + // Process each split component, verifying total amount and executing operations. + return components.verifyAndProcessSplitComponents(sponsor, id, allocatedAmount, operation); + } + + /** + * @notice Internal function for processing qualified batch claims with potentially exogenous + * sponsor signatures. Extracts batch claim parameters from calldata, validates the claim, + * executes operations, and performs optimized validation of allocator consistency, amounts, + * and scopes. If any validation fails, all operations are reverted after explicitly + * identifying the specific validation failures. + * @param messageHash The EIP-712 hash of the claim message. + * @param qualificationMessageHash The EIP-712 hash of the allocator's qualification message. + * @param calldataPointer Pointer to the location of the associated struct in calldata. + * @param offsetToId Offset to segment of calldata where relevant claim parameters begin. + * @param sponsorDomainSeparator The domain separator for the sponsor's signature, or zero for non-exogenous claims. + * @param typehash The EIP-712 typehash used for the claim message. + * @param domainSeparator The local domain separator. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @param validation Function pointer to the _validate function. + * @return Whether the batch claim was successfully processed. + */ + function processClaimWithBatchComponents( + bytes32 messageHash, + bytes32 qualificationMessageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 sponsorDomainSeparator, + bytes32 typehash, + bytes32 domainSeparator, + function(address, address, uint256, uint256) internal returns (bool) operation, + function(bytes32, uint96, bytes32, uint256, bytes32, bytes32, bytes32) internal returns (address) validation + ) internal returns (bool) { + // Declare variables for parameters that will be extracted from calldata. + BatchClaimComponent[] calldata claims; + address claimant; + + assembly ("memory-safe") { + // Calculate pointer to claim parameters using provided offset. + let calldataPointerWithOffset := add(calldataPointer, offsetToId) + + // Extract array of batch claim components and claimant address. + let claimsPtr := add(calldataPointer, calldataload(calldataPointerWithOffset)) + claims.offset := add(0x20, claimsPtr) + claims.length := calldataload(claimsPtr) + claimant := calldataload(add(calldataPointerWithOffset, 0x20)) + } + + // Extract allocator id from first claim for validation. + uint96 firstAllocatorId = claims[0].id.toAllocatorId(); + + // Validate the claim and extract the sponsor address. + address sponsor = validation(messageHash, firstAllocatorId, qualificationMessageHash, calldataPointer, domainSeparator, sponsorDomainSeparator, typehash); + + // Revert if the batch is empty. + uint256 totalClaims = claims.length; + + // Process first claim and initialize error tracking. + // NOTE: many of the bounds checks on these array accesses can be skipped as an optimization + BatchClaimComponent calldata component = claims[0]; + uint256 id = component.id; + uint256 amount = component.amount; + uint256 errorBuffer = (totalClaims == 0).or(component.allocatedAmount.allocationExceededOrScopeNotMultichain(amount, id, sponsorDomainSeparator)).asUint256(); + + // Execute transfer or withdrawal for first claim. + operation(sponsor, claimant, id, amount); + + unchecked { + // Process remaining claims while accumulating potential errors. + for (uint256 i = 1; i < totalClaims; ++i) { + component = claims[i]; + id = component.id; + amount = component.amount; + errorBuffer |= (id.toAllocatorId() != firstAllocatorId).or(component.allocatedAmount.allocationExceededOrScopeNotMultichain(amount, id, sponsorDomainSeparator)).asUint256(); + + operation(sponsor, claimant, id, amount); + } + + _revertWithInvalidBatchAllocationIfError(errorBuffer); + } + + return true; + } + + /** + * @notice Internal function for processing qualified split batch claims with potentially + * exogenous sponsor signatures. Extracts split batch claim parameters from calldata, + * validates the claim, and executes split operations for each resource lock. Uses optimized + * validation of allocator consistency and scopes, with explicit validation on failure to + * identify specific issues. Each resource lock can be split among multiple recipients. + * @param messageHash The EIP-712 hash of the claim message. + * @param qualificationMessageHash The EIP-712 hash of the allocator's qualification message. + * @param calldataPointer Pointer to the location of the associated struct in calldata. + * @param offsetToId Offset to segment of calldata where relevant claim parameters begin. + * @param sponsorDomainSeparator The domain separator for the sponsor's signature, or zero for non-exogenous claims. + * @param typehash The EIP-712 typehash used for the claim message. + * @param domainSeparator The local domain separator. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @param validation Function pointer to the _validate function. + * @return Whether the split batch claim was successfully processed. + */ + function processClaimWithSplitBatchComponents( + bytes32 messageHash, + bytes32 qualificationMessageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 sponsorDomainSeparator, + bytes32 typehash, + bytes32 domainSeparator, + function(address, address, uint256, uint256) internal returns (bool) operation, + function(bytes32, uint96, bytes32, uint256, bytes32, bytes32, bytes32) internal returns (address) validation + ) internal returns (bool) { + // Declare variable for SplitBatchClaimComponent array that will be extracted from calldata. + SplitBatchClaimComponent[] calldata claims; + + assembly ("memory-safe") { + // Extract array of split batch claim components. + let claimsPtr := add(calldataPointer, calldataload(add(calldataPointer, offsetToId))) + claims.offset := add(0x20, claimsPtr) + claims.length := calldataload(claimsPtr) + } + + // Extract allocator id from first claim for validation. + uint96 firstAllocatorId = claims[0].id.toAllocatorId(); + + // Validate the claim and extract the sponsor address. + address sponsor = validation(messageHash, firstAllocatorId, qualificationMessageHash, calldataPointer, domainSeparator, sponsorDomainSeparator, typehash); + + // Initialize tracking variables. + uint256 totalClaims = claims.length; + uint256 errorBuffer = (totalClaims == 0).asUint256(); + uint256 id; + + unchecked { + // Process each claim component while accumulating potential errors. + for (uint256 i = 0; i < totalClaims; ++i) { + SplitBatchClaimComponent calldata claimComponent = claims[i]; + id = claimComponent.id; + errorBuffer |= (id.toAllocatorId() != firstAllocatorId).or(id.scopeNotMultichain(sponsorDomainSeparator)).asUint256(); + + // Process each split component, verifying total amount and executing operations. + claimComponent.portions.verifyAndProcessSplitComponents(sponsor, id, claimComponent.allocatedAmount, operation); + } + + // Revert if any errors occurred. + _revertWithInvalidBatchAllocationIfError(errorBuffer); + } + + return true; + } + + /** + * @notice Internal function for verifying and processing split components. Ensures that the + * sum of split amounts doesn't exceed the allocated amount, checks for arithmetic overflow, + * and executes the specified operation for each split recipient. Reverts if the total + * claimed amount exceeds the allocation or if arithmetic overflow occurs during summation. + * @param claimants Array of split components specifying recipients and their amounts. + * @param sponsor The address of the claim sponsor. + * @param id The ERC6909 token identifier of the resource lock. + * @param allocatedAmount The total amount allocated for this claim. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether all split components were successfully processed. + */ + function verifyAndProcessSplitComponents( + SplitComponent[] calldata claimants, + address sponsor, + uint256 id, + uint256 allocatedAmount, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + // Initialize tracking variables. + uint256 totalClaims = claimants.length; + uint256 spentAmount = 0; + uint256 errorBuffer = (totalClaims == 0).asUint256(); + + unchecked { + // Process each split component while tracking total amount and checking for overflow. + for (uint256 i = 0; i < totalClaims; ++i) { + SplitComponent calldata component = claimants[i]; + uint256 amount = component.amount; + + // Track total amount claimed, checking for overflow. + uint256 updatedSpentAmount = amount + spentAmount; + errorBuffer |= (updatedSpentAmount < spentAmount).asUint256(); + spentAmount = updatedSpentAmount; + + // Execute transfer or withdrawal for the split component. + operation(sponsor, component.claimant, id, amount); + } + } + + // Revert if an overflow occurred or if total claimed amount exceeds allocation. + errorBuffer |= (allocatedAmount < spentAmount).asUint256(); + assembly ("memory-safe") { + if errorBuffer { + // revert AllocatedAmountExceeded(allocatedAmount, amount); + mstore(0, 0x3078b2f6) + mstore(0x20, allocatedAmount) + mstore(0x40, spentAmount) + revert(0x1c, 0x44) + } + } + + return true; + } + + /** + * @notice Private function for performing a set of split transfers or withdrawals + * given an array of split components and an ID for an associated resource lock. + * Executes the transfer or withdrawal operation targeting multiple recipients. + * @param recipients A SplitComponent struct array containing split transfer details. + * @param id The ERC6909 token identifier of the resource lock. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + */ + function _processSplitTransferComponents(SplitComponent[] calldata recipients, uint256 id, function(address, address, uint256, uint256) internal returns (bool) operation) private { + // Retrieve the total number of components. + uint256 totalSplits = recipients.length; + + unchecked { + // Iterate over each additional component in calldata. + for (uint256 i = 0; i < totalSplits; ++i) { + // Navigate to location of the component in calldata. + SplitComponent calldata component = recipients[i]; + + // Perform the transfer or withdrawal for the portion. + operation(msg.sender, component.claimant, id, component.amount); + } + } + } + + /** + * @notice Private pure function that reverts with an InvalidBatchAllocation error + * if an error buffer is nonzero. + * @param errorBuffer The error buffer to check. + */ + function _revertWithInvalidBatchAllocationIfError(uint256 errorBuffer) private pure { + // Revert if any errors occurred. + assembly ("memory-safe") { + if errorBuffer { + // revert InvalidBatchAllocation() + mstore(0, 0x3a03d3bb) + revert(0x1c, 0x04) + } + } + } +} diff --git a/src/lib/ConstructorLogic.sol b/src/lib/ConstructorLogic.sol new file mode 100644 index 0000000..a74858b --- /dev/null +++ b/src/lib/ConstructorLogic.sol @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { Lock } from "../types/Lock.sol"; +import { ResetPeriod } from "../types/ResetPeriod.sol"; +import { Scope } from "../types/Scope.sol"; + +import { DomainLib } from "./DomainLib.sol"; +import { IdLib } from "./IdLib.sol"; +import { MetadataRenderer } from "./MetadataRenderer.sol"; + +import { Tstorish } from "tstorish/Tstorish.sol"; + +/** + * @title ConstructorLogic + * @notice Inherited contract implementing internal functions with logic for initializing + * immutable variables and deploying the metadata renderer contract, as well as for setting + * and clearing resource locks, retrieving metadata from the metadata renderer, and safely + * interacting with Permit2. Note that TSTORE will be used for the reentrancy lock on chains + * that support it, with a fallback to SSTORE where it is not supported along with a utility + * for activating TSTORE support if the chain eventually adds support for it. + */ +contract ConstructorLogic is Tstorish { + using DomainLib for bytes32; + using DomainLib for uint256; + using IdLib for uint256; + + // Address of the Permit2 contract, optionally used for depositing ERC20 tokens. + address private constant _PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3; + + // Storage slot used for the reentrancy guard, whether using TSTORE or SSTORE. + uint256 private constant _REENTRANCY_GUARD_SLOT = 0x929eee149b4bd21268; + + // Chain ID at deployment, used for triggering EIP-712 domain separator updates. + uint256 private immutable _INITIAL_CHAIN_ID; + + // Initial EIP-712 domain separator, computed at deployment time. + bytes32 private immutable _INITIAL_DOMAIN_SEPARATOR; + + // Instance of the metadata renderer contract deployed during construction. + MetadataRenderer private immutable _METADATA_RENDERER; + + // Whether Permit2 was deployed on the chain at construction time. + bool private immutable _PERMIT2_INITIALLY_DEPLOYED; + + /** + * @notice Constructor that initializes immutable variables and deploys the metadata + * renderer. Captures the initial chain ID and domain separator, deploys the metadata + * renderer, and checks for Permit2 deployment. + */ + constructor() { + _INITIAL_CHAIN_ID = block.chainid; + _INITIAL_DOMAIN_SEPARATOR = block.chainid.toNotarizedDomainSeparator(); + _METADATA_RENDERER = new MetadataRenderer(); + _PERMIT2_INITIALLY_DEPLOYED = _checkPermit2Deployment(); + } + + /** + * @notice Internal function to set the reentrancy guard using either TSTORE or SSTORE. + * Called as part of functions that require reentrancy protection. Reverts if called + * again before the reentrancy guard has been cleared. + * @dev Note that the caller is set to the value; this enables external contracts to + * ascertain the account originating the ongoing call while handling the call as long + * as exttload is available. + */ + function _setReentrancyGuard() internal { + uint256 entered = _getTstorish(_REENTRANCY_GUARD_SLOT); + + assembly ("memory-safe") { + if entered { + // revert ReentrantCall(address existingCaller) + mstore(0, 0xf57c448b) + mstore(0x20, entered) + revert(0x1c, 0x24) + } + + entered := caller() + } + + _setTstorish(_REENTRANCY_GUARD_SLOT, entered); + } + + /** + * @notice Internal function to clear the reentrancy guard using either TSTORE or SSTORE. + * Called as part of functions that require reentrancy protection. + */ + function _clearReentrancyGuard() internal { + _clearTstorish(_REENTRANCY_GUARD_SLOT); + } + + /** + * @notice Internal view function that checks whether Permit2 is deployed. Returns true + * if Permit2 was deployed at construction time, otherwise checks current deployment status. + * @return Whether Permit2 is currently deployed. + */ + function _isPermit2Deployed() internal view returns (bool) { + if (_PERMIT2_INITIALLY_DEPLOYED) { + return true; + } + + return _checkPermit2Deployment(); + } + + /** + * @notice Internal view function that returns the current EIP-712 domain separator, + * updating it if the chain ID has changed since deployment. + * @return The current domain separator. + */ + function _domainSeparator() internal view returns (bytes32) { + return _INITIAL_DOMAIN_SEPARATOR.toLatest(_INITIAL_CHAIN_ID); + } + + /** + * @notice Internal view function for retrieving the name for a given token ID. + * @param id The ERC6909 token identifier. + * @return The token's name. + */ + function _name(uint256 id) internal view returns (string memory) { + return _METADATA_RENDERER.name(id); + } + + /** + * @notice Internal view function for retrieving the symbol for a given token ID. + * @param id The ERC6909 token identifier. + * @return The token's symbol. + */ + function _symbol(uint256 id) internal view returns (string memory) { + return _METADATA_RENDERER.symbol(id); + } + + /** + * @notice Internal view function for retrieving the URI for a given token ID. + * @param id The ERC6909 token identifier. + * @return The token's URI. + */ + function _tokenURI(uint256 id) internal view returns (string memory) { + return _METADATA_RENDERER.uri(id.toLock(), id); + } + + /** + * @notice Private view function that checks whether Permit2 is currently deployed by + * checking for code at the Permit2 address. + * @return permit2Deployed Whether there is code at the Permit2 address. + */ + function _checkPermit2Deployment() private view returns (bool permit2Deployed) { + assembly ("memory-safe") { + permit2Deployed := iszero(iszero(extcodesize(_PERMIT2))) + } + } +} diff --git a/src/lib/ConsumerLib.sol b/src/lib/ConsumerLib.sol new file mode 100644 index 0000000..6d18526 --- /dev/null +++ b/src/lib/ConsumerLib.sol @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +/** + * @title ConsumerLib + * @notice Libray contract implementing logic for consuming bitpacked nonces scoped to + * specific accounts and for querying for the state of those nonces. Note that only the + * allocator nonce scope is currently in use in The Compact. + */ +library ConsumerLib { + // Storage scope identifiers for nonce buckets. + uint256 private constant _ALLOCATOR_NONCE_SCOPE = 0x03f37b1a; + uint256 private constant _SPONSOR_NONCE_SCOPE = 0x8ccd9613; + + // Error thrown when attempting to consume an already-consumed nonce. + error InvalidNonce(address account, uint256 nonce); + + /** + * @notice Internal function for consuming a nonce in the allocator's scope. + * @param nonce The nonce to consume. + * @param allocator The address of the allocator whose scope to consume the nonce in. + */ + function consumeNonceAsAllocator(uint256 nonce, address allocator) internal { + _consumeNonce(nonce, allocator, _ALLOCATOR_NONCE_SCOPE); + } + + /** + * @notice Internal view function for checking if a nonce has been consumed in the + * allocator's scope. + * @param nonceToCheck The nonce to check. + * @param allocator The address of the allocator whose scope to check. + * @return consumed Whether the nonce has been consumed. + */ + function isConsumedByAllocator(uint256 nonceToCheck, address allocator) internal view returns (bool consumed) { + return _isConsumedBy(nonceToCheck, allocator, _ALLOCATOR_NONCE_SCOPE); + } + + /** + * @notice Internal function for consuming a nonce in the sponsor's scope. + * @param nonce The nonce to consume. + * @param sponsor The address of the sponsor whose scope to consume the nonce in. + */ + function consumeNonceAsSponsor(uint256 nonce, address sponsor) internal { + _consumeNonce(nonce, sponsor, _SPONSOR_NONCE_SCOPE); + } + + /** + * @notice Internal view function for checking if a nonce has been consumed in the + * sponsor's scope. + * @param nonceToCheck The nonce to check. + * @param sponsor The address of the sponsor whose scope to check. + * @return consumed Whether the nonce has been consumed. + */ + function isConsumedBySponsor(uint256 nonceToCheck, address sponsor) internal view returns (bool consumed) { + return _isConsumedBy(nonceToCheck, sponsor, _SPONSOR_NONCE_SCOPE); + } + + /** + * @notice Private function implementing nonce consumption logic. Uses the last byte + * of the nonce to determine which bit to set in a 256-bit storage bucket unique to + * the account and scope. Reverts if the nonce has already been consumed. + * @param nonce The nonce to consume. + * @param account The address of the account whose scope to consume the nonce in. + * @param scope The scope identifier to consume the nonce in. + */ + function _consumeNonce(uint256 nonce, address account, uint256 scope) private { + // The last byte of the nonce is used to assign a bit in a 256-bit bucket; + // specific nonces are consumed for each account and can only be used once. + // NOTE: this function temporarily overwrites the free memory pointer, but + // restores it before returning. + assembly ("memory-safe") { + // Store free memory pointer; its memory location will be overwritten. + let freeMemoryPointer := mload(0x40) + + // derive the nonce bucket slot: + // keccak256(_CONSUMER_NONCE_SCOPE ++ account ++ nonce[0:31]) + mstore(0x20, account) + mstore(0x0c, scope) + mstore(0x40, nonce) + let bucketSlot := keccak256(0x28, 0x37) + + // Retrieve nonce bucket and check if nonce has been consumed. + let bucketValue := sload(bucketSlot) + let bit := shl(and(0xff, nonce), 1) + if and(bit, bucketValue) { + // `InvalidNonce(address,uint256)` with padding for `account`. + mstore(0x0c, 0xdbc205b1000000000000000000000000) + revert(0x1c, 0x44) + } + + // Invalidate the nonce by setting its bit. + sstore(bucketSlot, or(bucketValue, bit)) + + // Restore the free memory pointer. + mstore(0x40, freeMemoryPointer) + } + } + + /** + * @notice Private view function implementing nonce consumption checking logic. + * Uses the last byte of the nonce to determine which bit to check in a 256-bit + * storage bucket unique to the account and scope. + * @param nonceToCheck The nonce to check. + * @param account The address of the account whose scope to check. + * @param scope The scope identifier to check. + * @return consumed Whether the nonce has been consumed. + */ + function _isConsumedBy(uint256 nonceToCheck, address account, uint256 scope) private view returns (bool consumed) { + assembly ("memory-safe") { + // Store free memory pointer; its memory location will be overwritten. + let freeMemoryPointer := mload(0x40) + + // derive the nonce bucket slot: + // keccak256(_CONSUMER_NONCE_SCOPE ++ account ++ nonce[0:31]) + mstore(0x20, account) + mstore(0x0c, scope) + mstore(0x40, nonceToCheck) + + // Retrieve nonce bucket value and determine whether the nonce is set. + consumed := and(shl(and(0xff, nonceToCheck), 1), sload(keccak256(0x28, 0x37))) + + // Restore the free memory pointer. + mstore(0x40, freeMemoryPointer) + } + } +} diff --git a/src/lib/DepositLogic.sol b/src/lib/DepositLogic.sol new file mode 100644 index 0000000..a14cc8c --- /dev/null +++ b/src/lib/DepositLogic.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { ConstructorLogic } from "./ConstructorLogic.sol"; + +import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol"; + +/** + * @title DepositLogic + * @notice Inherited contract implementing internal functions with low-level shared logic for + * processing token deposits. + */ +contract DepositLogic is ConstructorLogic { + using SafeTransferLib for address; + + // Storage slot seed for ERC6909 state, used in computing balance slots. + uint256 private constant _ERC6909_MASTER_SLOT_SEED = 0xedcaa89a82293940; + + // keccak256(bytes("Transfer(address,address,address,uint256,uint256)")). + uint256 private constant _TRANSFER_EVENT_SIGNATURE = 0x1b3d7edb2e9c0b0e7c525b20aaaef0f5940d2ed71663c7d39266ecafac728859; + + /** + * @notice Internal function that verifies a token balance increase and mints the + * corresponding amount of ERC6909 tokens. Checks that the token balance has increased + * from the provided initial balance, and mints the difference to the specified recipient. + * Reverts if the balance has not increased. Finally, emits a Transfer event. + * @param token The address of the token to check the balance of. + * @param to The account to mint ERC6909 tokens to. + * @param id The ERC6909 token identifier to mint. + * @param initialBalance The token balance before the deposit operation. + */ + function _checkBalanceAndDeposit(address token, address to, uint256 id, uint256 initialBalance) internal { + // Get the current token balance to compare against initial balance. + uint256 tokenBalance = token.balanceOf(address(this)); + + // Revert if the balance hasn't increased. + assembly ("memory-safe") { + if iszero(lt(initialBalance, tokenBalance)) { + // revert InvalidDepositBalanceChange() + mstore(0, 0x426d8dcf) + revert(0x1c, 0x04) + } + } + + // Skip underflow check as balance increase has been confirmed. + unchecked { + // Mint the balance difference as ERC6909 tokens. + _deposit(to, id, tokenBalance - initialBalance); + } + } + + /** + * @notice Internal function for minting ERC6909 tokens. Updates the recipient's balance, + * checking for overflow, and emits a Transfer event. This function bypasses transfer + * hooks and allowance checks as it is only called in trusted deposit contexts. + * @param to The address to mint tokens to. + * @param id The ERC6909 token identifier to mint. + * @param amount The amount of tokens to mint. + */ + function _deposit(address to, uint256 id, uint256 amount) internal { + assembly ("memory-safe") { + // Compute the recipient's balance slot using the master slot seed. + mstore(0x20, _ERC6909_MASTER_SLOT_SEED) + mstore(0x14, to) + mstore(0x00, id) + let toBalanceSlot := keccak256(0x00, 0x40) + + // Load current balance and compute new balance. + let toBalanceBefore := sload(toBalanceSlot) + let toBalanceAfter := add(toBalanceBefore, amount) + + // Revert on balance overflow. + if lt(toBalanceAfter, toBalanceBefore) { + mstore(0x00, 0x89560ca1) // `BalanceOverflow()`. + revert(0x1c, 0x04) + } + + // Store the updated balance. + sstore(toBalanceSlot, toBalanceAfter) + + // Emit the Transfer event: + // - topic1: Transfer event signature + // - topic2: address(0) signifying a mint + // - topic3: recipient address (sanitized) + // - topic4: token id + // - data: [caller, amount] + mstore(0x00, caller()) + mstore(0x20, amount) + log4(0, 0x40, _TRANSFER_EVENT_SIGNATURE, 0, shr(0x60, shl(0x60, to)), id) + } + } +} diff --git a/src/lib/DepositViaPermit2Lib.sol b/src/lib/DepositViaPermit2Lib.sol new file mode 100644 index 0000000..9f15929 --- /dev/null +++ b/src/lib/DepositViaPermit2Lib.sol @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { CompactCategory } from "../types/CompactCategory.sol"; +import { + COMPACT_TYPEHASH, + BATCH_COMPACT_TYPEHASH, + MULTICHAIN_COMPACT_TYPEHASH, + PERMIT2_DEPOSIT_WITNESS_FRAGMENT_HASH, + PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE, + PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO, + PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE, + PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO, + TOKEN_PERMISSIONS_TYPESTRING_FRAGMENT_ONE, + TOKEN_PERMISSIONS_TYPESTRING_FRAGMENT_TWO, + COMPACT_ACTIVATION_TYPEHASH, + BATCH_COMPACT_ACTIVATION_TYPEHASH, + MULTICHAIN_COMPACT_ACTIVATION_TYPEHASH, + COMPACT_BATCH_ACTIVATION_TYPEHASH, + BATCH_COMPACT_BATCH_ACTIVATION_TYPEHASH, + MULTICHAIN_COMPACT_BATCH_ACTIVATION_TYPEHASH, + PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_ONE, + PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_TWO, + PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_THREE, + PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_FOUR, + PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_ONE, + PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_TWO, + PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_THREE, + PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_FOUR, + PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_ONE, + PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_TWO, + PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_THREE, + PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_FOUR, + PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_FIVE, + PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_SIX, + COMPACT_DEPOSIT_TYPESTRING_FRAGMENT_ONE, + COMPACT_DEPOSIT_TYPESTRING_FRAGMENT_TWO, + COMPACT_DEPOSIT_TYPESTRING_FRAGMENT_THREE, + COMPACT_DEPOSIT_TYPESTRING_FRAGMENT_FOUR, + COMPACT_DEPOSIT_TYPESTRING_FRAGMENT_FIVE +} from "../types/EIP712Types.sol"; + +/** + * @title DepositViaPermit2Lib + * @notice Library contract implementing internal functions with logic for processing + * token deposits via permit2. These deposits leverage Permit2 witness data to either + * indicate the parameters of the lock to deposit into and the recipient of the deposit, + * or the parameters of the compact to register alongside the deposit. Deposits can also + * involve a single ERC20 token or a batch of tokens in a single Permit2 authorization. + * @dev IMPORTANT NOTE: this logic operates directly on unallocated memory, and reads + * directly from fixed calldata offsets; proceed with EXTREME caution when making any + * modifications to either this logic contract (including the insertion of new logic) or + * to the associated permit2 deposit function interfaces! + */ +library DepositViaPermit2Lib { + // Selector for the batch `permit2.permitWitnessTransferFrom` function. + uint256 private constant _BATCH_PERMIT_WITNESS_TRANSFER_FROM_SELECTOR = 0xfe8ec1a7; + + /** + * @notice Internal view function for preparing batch deposit permit2 calldata. + * Prepares known arguments and offsets in memory and returns pointers to the start + * of the prepared calldata as well as to the start of the witness typestring. + * @param totalTokensLessInitialNative The number of non-native tokens to deposit. + * @param firstUnderlyingTokenIsNative Whether the first underlying token is native. + * @return m The memory pointer to the start of the prepared calldata. + * @return typestringMemoryLocation The memory pointer to the start of the typestring. + */ + function beginPreparingBatchDepositPermit2Calldata(uint256 totalTokensLessInitialNative, bool firstUnderlyingTokenIsNative) internal view returns (uint256 m, uint256 typestringMemoryLocation) { + assembly ("memory-safe") { + // Retrieve the free memory pointer; memory will be left dirtied. + m := mload(0x40) + + // Derive size of each token chunk (2 words per token). + let tokenChunk := shl(6, totalTokensLessInitialNative) + + // Derive size of two token chunks (4 words per token). + let twoTokenChunks := shl(1, tokenChunk) + + // Derive memory location of the `permitted` calldata struct. + let permittedCalldataLocation := add(add(0x24, calldataload(0x24)), shl(6, firstUnderlyingTokenIsNative)) + + // Prepare the initial fragment of the witness typestring. + mstore(m, _BATCH_PERMIT_WITNESS_TRANSFER_FROM_SELECTOR) + mstore(add(m, 0x20), 0xc0) // permitted offset + mstore(add(m, 0x40), add(0x140, tokenChunk)) // details offset + mstore(add(m, 0x60), calldataload(0x04)) // depositor + // Skip witnessHash at 0x80 as it is not yet known. + mstore(add(m, 0xa0), add(0x160, twoTokenChunks)) // witness offset + // Skip signatureOffset at 0xc0 as it is not yet known. + mstore(add(m, 0xe0), 0x60) // permitted tokens relative offset + mstore(add(m, 0x100), calldataload(0x44)) // nonce + mstore(add(m, 0x120), calldataload(0x64)) // deadline + mstore(add(m, 0x140), totalTokensLessInitialNative) // permitted.length + + // Copy permitted data from calldata to memory. + calldatacopy(add(m, 0x160), permittedCalldataLocation, tokenChunk) + + // Derive memory location of the `details` calldata struct. + let detailsOffset := add(add(m, 0x160), tokenChunk) + + // Store the length of the `details` array. + mstore(detailsOffset, totalTokensLessInitialNative) + + // Derive start, next, & end locations for iterating through `details` array. + let starting := add(detailsOffset, 0x20) + let next := add(detailsOffset, 0x40) + let end := shl(6, totalTokensLessInitialNative) + + // Iterate through `details` array and copy data from calldata to memory. + for { let i := 0 } lt(i, end) { i := add(i, 0x40) } { + // Copy this contract as the recipient address. + mstore(add(starting, i), address()) + + // Copy full token amount as the requested amount. + mstore(add(next, i), calldataload(add(permittedCalldataLocation, add(0x20, i)))) + } + + // Derive memory location of the witness typestring. + typestringMemoryLocation := add(m, add(0x180, twoTokenChunks)) + + // NOTE: strongly consider allocating memory here as the inline assembly scope + // is being left (it *should* be fine for now as the function between assembly + // blocks does not allocate any new memory). + } + } + + /** + * @notice Internal pure function for deriving typehashes and simultaneously + * preparing the witness typestring component of the call to permit2. + * @param memoryLocation The memory pointer to the start of the typestring. + * @param category The CompactCategory of the deposit. + * @param witness The witness string to insert. + * @param usingBatch Whether the deposit involves a batch. + * @return activationTypehash The derived activation typehash. + * @return compactTypehash The derived compact typehash. + */ + function writeWitnessAndGetTypehashes(uint256 memoryLocation, CompactCategory category, string calldata witness, bool usingBatch) + internal + pure + returns (bytes32 activationTypehash, bytes32 compactTypehash) + { + assembly ("memory-safe") { + // Internal assembly function for writing the witness and typehashes. + // Used to enable leaving the inline assembly scope early when the + // witness is empty (no-witness case). + function writeWitnessAndGetTypehashes(memLocation, c, witnessOffset, witnessLength, usesBatch) -> derivedActivationTypehash, derivedCompactTypehash { + // Derive memory offset for the witness typestring data. + let memoryOffset := add(memLocation, 0x20) + + // Declare variables for start of Activation and Category-specific data. + let activationStart + let categorySpecificStart + + // Handle non-batch cases. + if iszero(usesBatch) { + // Prepare initial Activation witness typestring fragment. + mstore(add(memoryOffset, 0x09), PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO) + mstore(memoryOffset, PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE) + + // Set memory pointers for Activation and Category-specific data start. + activationStart := add(memoryOffset, 0x13) + categorySpecificStart := add(memoryOffset, 0x29) + } + + // Proceed with batch case if preparation of activation has not begun. + if iszero(activationStart) { + // Prepare initial BatchActivation witness typestring fragment. + mstore(add(memoryOffset, 0x16), PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO) + mstore(memoryOffset, PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE) + + // Set memory pointers for Activation and Category-specific data. + activationStart := add(memoryOffset, 0x18) + categorySpecificStart := add(memoryOffset, 0x36) + } + + // Declare variable for end of Category-specific data. + let categorySpecificEnd + + // Handle Compact (non-batch, single-chain) case. + if iszero(c) { + // Prepare next typestring fragment using Compact witness typestring. + mstore(categorySpecificStart, PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_ONE) + mstore(add(categorySpecificStart, 0x20), PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_TWO) + mstore(add(categorySpecificStart, 0x50), PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_FOUR) + mstore(add(categorySpecificStart, 0x40), PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_THREE) + + // Set memory pointers for Activation and Category-specific data end. + categorySpecificEnd := add(categorySpecificStart, 0x70) + categorySpecificStart := add(categorySpecificStart, 0x10) + } + + // Handle BatchCompact (single-chain) case. + if iszero(sub(c, 1)) { + // Prepare next typestring fragment using BatchCompact witness typestring. + mstore(categorySpecificStart, PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_ONE) + mstore(add(categorySpecificStart, 0x20), PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_TWO) + mstore(add(categorySpecificStart, 0x5b), PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_FOUR) + mstore(add(categorySpecificStart, 0x40), PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_THREE) + + // Set memory pointers for Activation and Category-specific data end. + categorySpecificEnd := add(categorySpecificStart, 0x7b) + categorySpecificStart := add(categorySpecificStart, 0x15) + } + + // Handle MultichainCompact case if preparation of compact fragment has not begun. + if iszero(categorySpecificEnd) { + // Prepare next typestring fragment using Multichain & Segment witness typestring. + mstore(categorySpecificStart, PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_ONE) + mstore(add(categorySpecificStart, 0x20), PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_TWO) + mstore(add(categorySpecificStart, 0x40), PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_THREE) + mstore(add(categorySpecificStart, 0x60), PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_FOUR) + mstore(add(categorySpecificStart, 0x70), PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_SIX) + mstore(add(categorySpecificStart, 0x60), PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_FIVE) + + // Set memory pointers for Activation and Category-specific data end. + categorySpecificEnd := add(categorySpecificStart, 0x90) + categorySpecificStart := add(categorySpecificStart, 0x1a) + } + + // Handle no-witness cases. + if iszero(witnessLength) { + // Derive memory offset for region used to retrieve typestring fragment by index. + let indexWords := shl(5, c) + + // Prepare token permissions typestring fragment. + mstore(add(categorySpecificEnd, 0x0e), TOKEN_PERMISSIONS_TYPESTRING_FRAGMENT_TWO) + mstore(sub(categorySpecificEnd, 1), TOKEN_PERMISSIONS_TYPESTRING_FRAGMENT_ONE) + + // Derive total length of typestring and store at start of memory. + mstore(memLocation, sub(add(categorySpecificEnd, 0x2e), memoryOffset)) + + // Retrieve and cache free memory pointer. + let m := mload(0x40) + + // Derive activation typehash based on the compact category for non-batch cases. + if iszero(usesBatch) { + // Prepare typehashes for Activation. + mstore(0, COMPACT_ACTIVATION_TYPEHASH) + mstore(0x20, BATCH_COMPACT_ACTIVATION_TYPEHASH) + mstore(0x40, MULTICHAIN_COMPACT_ACTIVATION_TYPEHASH) + + // Retrieve respective typehash by index. + derivedActivationTypehash := mload(indexWords) + } + + // Derive activation typehash for batch cases if typehash is not yet derived. + if iszero(derivedActivationTypehash) { + // Prepare typehashes for BatchActivation. + mstore(0, COMPACT_BATCH_ACTIVATION_TYPEHASH) + mstore(0x20, BATCH_COMPACT_BATCH_ACTIVATION_TYPEHASH) + mstore(0x40, MULTICHAIN_COMPACT_BATCH_ACTIVATION_TYPEHASH) + + // Retrieve respective typehash by index. + derivedActivationTypehash := mload(indexWords) + } + + // Prepare compact typehashes. + mstore(0, COMPACT_TYPEHASH) + mstore(0x20, BATCH_COMPACT_TYPEHASH) + mstore(0x40, MULTICHAIN_COMPACT_TYPEHASH) + + // Retrieve respective typehash by index. + derivedCompactTypehash := mload(indexWords) + + // Restore the free memory pointer. + mstore(0x40, m) + + // Leave the inline assembly scope early. + leave + } + + // Copy the supplied compact witness from calldata. + calldatacopy(categorySpecificEnd, witnessOffset, witnessLength) + + // Insert tokenPermissions typestring fragment. + let tokenPermissionsFragmentStart := add(categorySpecificEnd, witnessLength) + mstore(add(tokenPermissionsFragmentStart, 0x0e), TOKEN_PERMISSIONS_TYPESTRING_FRAGMENT_TWO) + mstore(sub(tokenPermissionsFragmentStart, 1), TOKEN_PERMISSIONS_TYPESTRING_FRAGMENT_ONE) + + // Derive total length of typestring and store at start of memory. + mstore(memLocation, sub(add(tokenPermissionsFragmentStart, 0x2e), memoryOffset)) + + // Derive activation typehash. + derivedActivationTypehash := keccak256(activationStart, sub(tokenPermissionsFragmentStart, activationStart)) + + // Derive compact typehash. + derivedCompactTypehash := keccak256(categorySpecificStart, sub(tokenPermissionsFragmentStart, categorySpecificStart)) + } + + // Execute internal assembly function and store derived typehashes. + activationTypehash, compactTypehash := writeWitnessAndGetTypehashes(memoryLocation, category, witness.offset, witness.length, usingBatch) + } + } + + /** + * @notice Internal pure function for deriving the activation witness hash and + * writing it to a specified memory location. + * @param activationTypehash The derived activation typehash. + * @param idOrIdsHash Resource lock ID or uint256 representation of the hash of each ID. + * @param claimHash The claim hash. + * @param memoryPointer The memory pointer to the start of the memory region. + * @param offset The offset within the memory region to write the witness hash. + */ + function deriveAndWriteWitnessHash(bytes32 activationTypehash, uint256 idOrIdsHash, bytes32 claimHash, uint256 memoryPointer, uint256 offset) internal pure { + assembly ("memory-safe") { + // Retrieve and cache free memory pointer. + let m := mload(0x40) + + // Prepare data for the witness hash: activationTypehash, idOrIdsHash & claimHash. + mstore(0, activationTypehash) + mstore(0x20, idOrIdsHash) + mstore(0x40, claimHash) + + // Derive activation witness hash and write it to specified memory location. + mstore(add(memoryPointer, offset), keccak256(0, 0x60)) + + // Restore the free memory pointer. + mstore(0x40, m) + } + } + + /** + * @notice Internal pure function for deriving the CompactDeposit witness hash. + * @param calldataOffset The offset of the CompactDeposit calldata. + * @return witnessHash The derived CompactDeposit witness hash. + */ + function deriveCompactDepositWitnessHash(uint256 calldataOffset) internal pure returns (bytes32 witnessHash) { + assembly ("memory-safe") { + // Retrieve the free memory pointer; memory will be left dirtied. + let m := mload(0x40) + + // Prepare the initial fragment of the witness typestring. + mstore(m, PERMIT2_DEPOSIT_WITNESS_FRAGMENT_HASH) + + // Copy allocator, resetPeriod, scope, & recipient directly from calldata. + // NOTE: none of these arguments are sanitized; the assumption is that they have to + // match the signed values anyway, so *should* be fine not to sanitize them but could + // optionally check that there are no dirty upper bits on any of them. + calldatacopy(add(m, 0x20), calldataOffset, 0x80) + + // Derive the CompactDeposit witness hash from the prepared data. + witnessHash := keccak256(m, 0xa0) + } + } + + /** + * @notice Internal pure function for inserting the CompactDeposit typestring + * (used for deposits that do not involve a compact registration) into memory. + * @param memoryLocation The memory pointer to the start of the typestring. + */ + function insertCompactDepositTypestring(uint256 memoryLocation) internal pure { + assembly ("memory-safe") { + // Write the length of the typestring. + mstore(memoryLocation, 0x96) + + // Write the data for the typestring. + mstore(add(memoryLocation, 0x20), COMPACT_DEPOSIT_TYPESTRING_FRAGMENT_ONE) + mstore(add(memoryLocation, 0x40), COMPACT_DEPOSIT_TYPESTRING_FRAGMENT_TWO) + mstore(add(memoryLocation, 0x60), COMPACT_DEPOSIT_TYPESTRING_FRAGMENT_THREE) + mstore(add(memoryLocation, 0x96), COMPACT_DEPOSIT_TYPESTRING_FRAGMENT_FIVE) + mstore(add(memoryLocation, 0x80), COMPACT_DEPOSIT_TYPESTRING_FRAGMENT_FOUR) + } + } +} diff --git a/src/lib/DepositViaPermit2Logic.sol b/src/lib/DepositViaPermit2Logic.sol new file mode 100644 index 0000000..c272083 --- /dev/null +++ b/src/lib/DepositViaPermit2Logic.sol @@ -0,0 +1,538 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { CompactCategory } from "../types/CompactCategory.sol"; +import { ResetPeriod } from "../types/ResetPeriod.sol"; +import { Scope } from "../types/Scope.sol"; + +import { DepositLogic } from "./DepositLogic.sol"; +import { DepositViaPermit2Lib } from "./DepositViaPermit2Lib.sol"; +import { RegistrationLib } from "./RegistrationLib.sol"; +import { EfficiencyLib } from "./EfficiencyLib.sol"; +import { IdLib } from "./IdLib.sol"; +import { ValidityLib } from "./ValidityLib.sol"; + +import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol"; +import { ISignatureTransfer } from "permit2/src/interfaces/ISignatureTransfer.sol"; + +/** + * @title DepositViaPermit2Logic + * @notice Inherited contract implementing internal functions with logic for processing + * token deposits via permit2. These deposits leverage Permit2 witness data to either + * indicate the parameters of the lock to deposit into and the recipient of the deposit, + * or the parameters of the compact to register alongside the deposit. Deposits can also + * involve a single ERC20 token or a batch of tokens in a single Permit2 authorization. + * @dev IMPORTANT NOTE: this logic operates directly on unallocated memory, and reads + * directly from fixed calldata offsets; proceed with EXTREME caution when making any + * modifications to either this logic contract (including the insertion of new logic) or + * to the associated permit2 deposit function interfaces! + */ +contract DepositViaPermit2Logic is DepositLogic { + using DepositViaPermit2Lib for bytes32; + using DepositViaPermit2Lib for uint256; + using IdLib for uint256; + using IdLib for address; + using IdLib for ResetPeriod; + using EfficiencyLib for bool; + using EfficiencyLib for uint256; + using RegistrationLib for address; + using ValidityLib for address; + using SafeTransferLib for address; + + // Selector for the single token `permit2.permitWitnessTransferFrom` function. + uint32 private constant _PERMIT_WITNESS_TRANSFER_FROM_SELECTOR = 0x137c29fe; + + // Address of the Permit2 contract. + address private constant _PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3; + + /** + * @notice Internal function for depositing ERC20 tokens using Permit2 authorization. The + * depositor must approve Permit2 to transfer the tokens on its behalf unless the token in + * question automatically grants approval to Permit2. The ERC6909 token amount received by the + * by the recipient is derived from the difference between the starting and ending balance held + * in the resource lock, which may differ from the amount transferred depending on the + * implementation details of the respective token. The Permit2 authorization signed by the + * depositor must contain a CompactDeposit witness containing the allocator, the reset period, + * the scope, and the intended recipient of the deposit. + * @param token The address of the ERC20 token to deposit. + * @param recipient The address that will receive the corresponding the ERC6909 tokens. + * @param signature The Permit2 signature from the depositor authorizing the deposit. + * @return The ERC6909 token identifier of the associated resource lock. + */ + function _depositViaPermit2(address token, address recipient, bytes calldata signature) internal returns (uint256) { + // Derive the CompactDeposit witness hash. + bytes32 witness = uint256(0xa4).asStubborn().deriveCompactDepositWitnessHash(); + + // Set reentrancy lock, get initial balance, and begin preparing Permit2 call data. + (uint256 id, uint256 initialBalance, uint256 m, uint256 typestringMemoryLocation) = _setReentrancyLockAndStartPreparingPermit2Call(token); + + // Insert the CompactDeposit typestring fragment. + typestringMemoryLocation.insertCompactDepositTypestring(); + + // Store the CompactDeposit witness hash. + assembly ("memory-safe") { + mstore(add(m, 0x100), witness) + } + + // Write the signature and perform the Permit2 call. + _writeSignatureAndPerformPermit2Call(m, uint256(0x140).asStubborn(), uint256(0x200).asStubborn(), signature); + + // Deposit tokens based on the balance change from the Permit2 call. + _checkBalanceAndDeposit(token, recipient, id, initialBalance); + + // Clear reentrancy lock. + _clearReentrancyGuard(); + + // Return the ERC6909 token identifier of the associated resource lock. + return id; + } + + /** + * @notice Internal function for depositing ERC20 tokens using Permit2 authorization and + * registering a compact. The depositor must approve Permit2 to transfer the tokens on its + * behalf unless the token in question automatically grants approval to Permit2. The ERC6909 + * token amount received by the depositor is derived from the difference between the starting + * and ending balance held in the resource lock, which may differ from the amount transferred + * depending on the implementation details of the respective token. The Permit2 authorization + * signed by the depositor must contain an Activation witness containing the id of the resource + * lock and an associated Compact, BatchCompact, or MultichainCompact payload matching the + * specified compact category. + * @param token The address of the ERC20 token to deposit. + * @param depositor The account signing the permit2 authorization and depositing the tokens. + * @param resetPeriod The duration after which the resource lock can be reset once a forced withdrawal is initiated. + * @param claimHash A bytes32 hash derived from the details of the compact. + * @param compactCategory The category of the compact being registered (Compact, BatchCompact, or MultichainCompact). + * @param witness Additional data used in generating the claim hash. + * @param signature The Permit2 signature from the depositor authorizing the deposit. + * @return The ERC6909 token identifier of the associated resource lock. + */ + function _depositAndRegisterViaPermit2( + address token, + address depositor, // also recipient + ResetPeriod resetPeriod, + bytes32 claimHash, + CompactCategory compactCategory, + string calldata witness, + bytes calldata signature + ) internal returns (uint256) { + // Set reentrancy lock, get initial balance, and begin preparing Permit2 call data. + (uint256 id, uint256 initialBalance, uint256 m, uint256 typestringMemoryLocation) = _setReentrancyLockAndStartPreparingPermit2Call(token); + + // Continue preparing Permit2 call data and get activation and compact typehashes. + (bytes32 activationTypehash, bytes32 compactTypehash) = typestringMemoryLocation.writeWitnessAndGetTypehashes(compactCategory, witness, bool(false).asStubborn()); + + // Derive the activation witness hash and store it. + activationTypehash.deriveAndWriteWitnessHash(id, claimHash, m, 0x100); + + // Derive signature offset value. + uint256 signatureOffsetValue; + assembly ("memory-safe") { + signatureOffsetValue := and(add(mload(add(m, 0x160)), 0x17f), not(0x1f)) + } + + // Write the signature and perform the Permit2 call. + _writeSignatureAndPerformPermit2Call(m, uint256(0x140).asStubborn(), signatureOffsetValue, signature); + + // Deposit tokens based on the balance change from the Permit2 call. + _checkBalanceAndDeposit(token, depositor, id, initialBalance); + + // Register the compact. + depositor.registerCompact(claimHash, compactTypehash, resetPeriod); + + // Clear reentrancy lock. + _clearReentrancyGuard(); + + // Return the ERC6909 token identifier of the associated resource lock. + return id; + } + + /** + * @notice Internal function for depositing multiple tokens using Permit2 authorization in a + * single transaction. The first token id can optionally represent native tokens by providing + * the null address and an amount matching msg.value. The depositor must approve Permit2 to + * transfer the tokens on its behalf unless the tokens automatically grant approval to + * Permit2. The ERC6909 token amounts received by the recipient are derived from the + * differences between starting and ending balances held in the resource locks, which may + * differ from the amounts transferred depending on the implementation details of the + * respective tokens. The Permit2 authorization signed by the depositor must contain a + * CompactDeposit witness containing the allocator, the reset period, the scope, and the + * intended recipient of the deposits. + * @param permitted Array of token permissions specifying the deposited tokens and amounts. + * @param recipient The address that will receive the corresponding ERC6909 tokens. + * @param signature The Permit2 signature from the depositor authorizing the deposits. + * @return Array of ERC6909 token identifiers for the associated resource locks. + */ + function _depositBatchViaPermit2(ISignatureTransfer.TokenPermissions[] calldata permitted, address recipient, bytes calldata signature) internal returns (uint256[] memory) { + // Set reentrancy guard, perform initial native deposit if present, and get initial token balances. + (uint256 totalTokensLessInitialNative, bool firstUnderlyingTokenIsNative, uint256[] memory ids, uint256[] memory initialTokenBalances) = _preprocessAndPerformInitialNativeDeposit(permitted, recipient); + + // Derive the CompactDeposit witness hash. + bytes32 witness = uint256(0x84).asStubborn().deriveCompactDepositWitnessHash(); + + // Begin preparing Permit2 call data. + (uint256 m, uint256 typestringMemoryLocation) = totalTokensLessInitialNative.beginPreparingBatchDepositPermit2Calldata(firstUnderlyingTokenIsNative); + + // Insert the CompactDeposit typestring fragment. + typestringMemoryLocation.insertCompactDepositTypestring(); + + // Declare variable for signature offset value. + uint256 signatureOffsetValue; + assembly ("memory-safe") { + // Store the CompactDeposit witness hash. + mstore(add(m, 0x80), witness) + + // Derive signature offset value. + signatureOffsetValue := add(0x220, shl(7, totalTokensLessInitialNative)) + } + + // Write the signature and perform the Permit2 call. + _writeSignatureAndPerformPermit2Call(m, uint256(0xc0).asStubborn(), signatureOffsetValue, signature); + + // Deposit tokens based on balance changes from Permit2 call and clear reentrancy lock. + _verifyBalancesAndPerformDeposits(ids, permitted, initialTokenBalances, recipient, firstUnderlyingTokenIsNative); + + // Return the ERC6909 token identifiers of the associated resource locks. + return ids; + } + + /** + * @notice Internal function for depositing multiple tokens using Permit2 authorization and + * registering a compact in a single transaction. The first token id can optionally represent + * native tokens by providing the null address and an amount matching msg.value. The depositor + * must approve Permit2 to transfer the tokens on its behalf unless the tokens automatically + * grant approval to Permit2. The ERC6909 token amounts received by the depositor are derived + * from the differences between starting and ending balances held in the resource locks, which + * may differ from the amounts transferred depending on the implementation details of the + * respective tokens. The Permit2 authorization signed by the depositor must contain a + * BatchActivation witness containing the ids of the resource locks and an associated + * Compact, BatchCompact, or MultichainCompact payload matching the specified compact category. + * @param depositor The account signing the permit2 authorization and depositing the tokens. + * @param permitted Array of token permissions specifying the deposited tokens and amounts. + * @param resetPeriod The duration after which the resource locks can be reset once forced withdrawals are initiated. + * @param claimHash A bytes32 hash derived from the details of the compact. + * @param compactCategory The category of the compact being registered (Compact, BatchCompact, or MultichainCompact). + * @param witness Additional data used in generating the claim hash. + * @param signature The Permit2 signature from the depositor authorizing the deposits. + * @return Array of ERC6909 token identifiers for the associated resource locks. + */ + function _depositBatchAndRegisterViaPermit2( + address depositor, + ISignatureTransfer.TokenPermissions[] calldata permitted, + ResetPeriod resetPeriod, + bytes32 claimHash, + CompactCategory compactCategory, + string calldata witness, + bytes calldata signature + ) internal returns (uint256[] memory) { + // Set reentrancy guard, perform initial native deposit if present, and get initial token balances. + (uint256 totalTokensLessInitialNative, bool firstUnderlyingTokenIsNative, uint256[] memory ids, uint256[] memory initialTokenBalances) = _preprocessAndPerformInitialNativeDeposit(permitted, depositor); + + // Derive the hash of the resource lock ids. + uint256 idsHash; + assembly ("memory-safe") { + idsHash := keccak256(add(ids, 0x20), shl(5, add(totalTokensLessInitialNative, firstUnderlyingTokenIsNative))) + } + + // Begin preparing Permit2 call data. + (uint256 m, uint256 typestringMemoryLocation) = totalTokensLessInitialNative.beginPreparingBatchDepositPermit2Calldata(firstUnderlyingTokenIsNative); + + // Prepare the typestring fragment and get batch activation and compact typehashes. + (bytes32 activationTypehash, bytes32 compactTypehash) = typestringMemoryLocation.writeWitnessAndGetTypehashes(compactCategory, witness, bool(true).asStubborn()); + + // Derive the batch activation witness hash and store it. + activationTypehash.deriveAndWriteWitnessHash(idsHash, claimHash, m, 0x80); + + // Declare variable for signature offset value. + uint256 signatureOffsetValue; + assembly ("memory-safe") { + // Get the length of the witness. + let witnessLength := witness.length + + // Derive the total memory offset for the witness. + let totalWitnessMemoryOffset := and(add(add(0xf3, add(witnessLength, iszero(iszero(witnessLength)))), add(mul(eq(compactCategory, 1), 0x0b), shl(6, eq(compactCategory, 2)))), not(0x1f)) + + // Derive the signature offset value. + signatureOffsetValue := add(add(0x180, shl(7, totalTokensLessInitialNative)), totalWitnessMemoryOffset) + } + + // Write the signature and perform the Permit2 call. + _writeSignatureAndPerformPermit2Call(m, uint256(0xc0).asStubborn(), signatureOffsetValue, signature); + + // Deposit tokens based on balance changes from Permit2 call and clear reentrancy lock. + _verifyBalancesAndPerformDeposits(ids, permitted, initialTokenBalances, depositor, firstUnderlyingTokenIsNative); + + // Register the compact. + depositor.registerCompact(claimHash, compactTypehash, resetPeriod); + + // Return the ERC6909 token identifiers of the associated resource locks. + return ids; + } + + /** + * @notice Private function for pre-processing and performing an initial native deposit. + * @param permitted Array of token permissions specifying the deposited tokens and amounts. + * @param recipient The address that will receive the corresponding ERC6909 tokens. + * @return totalTokensLessInitialNative The total number of tokens less the initial native deposit. + * @return firstUnderlyingTokenIsNative A boolean indicating whether the first underlying token is native. + * @return ids Array of ERC6909 token identifiers. + * @return initialTokenBalances Array of initial token balances. + */ + function _preprocessAndPerformInitialNativeDeposit(ISignatureTransfer.TokenPermissions[] calldata permitted, address recipient) + private + returns (uint256 totalTokensLessInitialNative, bool firstUnderlyingTokenIsNative, uint256[] memory ids, uint256[] memory initialTokenBalances) + { + // Set reentrancy guard. + _setReentrancyGuard(); + + // Get total number of tokens and declare allocator, reset period, & scope variables. + uint256 totalTokens = permitted.length; + address allocator; + ResetPeriod resetPeriod; + Scope scope; + + assembly ("memory-safe") { + // Get the offset of the permitted calldata struct. + let permittedOffset := permitted.offset + + // Determine if the first underlying token is native. + firstUnderlyingTokenIsNative := iszero(shr(96, shl(96, calldataload(permittedOffset)))) + + // Revert if: + // * the array is empty + // * the callvalue is zero but the first token is native + // * the callvalue is nonzero but the first token is non-native + // * the first token is non-native and the callvalue doesn't equal the first amount + if or(iszero(totalTokens), or(eq(firstUnderlyingTokenIsNative, iszero(callvalue())), and(firstUnderlyingTokenIsNative, iszero(eq(callvalue(), calldataload(add(permittedOffset, 0x20))))))) { + // revert InvalidBatchDepositStructure() + mstore(0, 0xca0fc08e) + revert(0x1c, 0x04) + } + + // Retrieve allocator, reset period, & scope. + // NOTE: these may need to be sanitized if toIdIfRegistered doesn't already handle for it + allocator := calldataload(0x84) + resetPeriod := calldataload(0xa4) + scope := calldataload(0xc4) + } + + // Get the initial resource lock id. + uint256 initialId = address(0).toIdIfRegistered(scope, resetPeriod, allocator); + + // Allocate ids array. + ids = new uint256[](totalTokens); + + // Perform initial native deposit if present. + if (firstUnderlyingTokenIsNative) { + _deposit(recipient, initialId, msg.value); + + // Set the initial id using the native resource lock. + ids[0] = initialId; + } + + // Calculate total number of tokens less the initial native deposit. + unchecked { + totalTokensLessInitialNative = totalTokens - firstUnderlyingTokenIsNative.asUint256(); + } + + // Prepare ids and get initial token balances. + initialTokenBalances = _prepareIdsAndGetBalances(ids, totalTokensLessInitialNative, firstUnderlyingTokenIsNative, permitted, initialId); + } + + /** + * @notice Private function for setting the reentrancy guard and starting the process + * of preparing a Permit2 call. + * @param token The address of the token to be deposited. + * @return id The ERC6909 token identifier of the associated resource lock. + * @return initialBalance The initial balance of the token in the contract. + * @return m The memory pointer for the Permit2 call data. + * @return typestringMemoryLocation The memory location for the typestring. + */ + function _setReentrancyLockAndStartPreparingPermit2Call(address token) private returns (uint256 id, uint256 initialBalance, uint256 m, uint256 typestringMemoryLocation) { + // Set reentrancy guard. + _setReentrancyGuard(); + + // Declare allocator, reset period, & scope variables. + address allocator; + ResetPeriod resetPeriod; + Scope scope; + + // Retrieve allocator, reset period, & scope. + assembly ("memory-safe") { + allocator := calldataload(0xa4) + resetPeriod := calldataload(0xc4) + scope := calldataload(0xe4) + } + + // Get the ERC6909 token identifier of the associated resource lock. + id = token.excludingNative().toIdIfRegistered(scope, resetPeriod, allocator); + + // Get the initial balance of the token in the contract. + initialBalance = token.balanceOf(address(this)); + + assembly ("memory-safe") { + // Retrieve the free memory pointer; memory will be left dirtied. + m := mload(0x40) + + // Begin preparing Permit2 call data. + mstore(m, _PERMIT_WITNESS_TRANSFER_FROM_SELECTOR) + calldatacopy(add(m, 0x20), 0x04, 0x80) // token, amount, nonce, deadline + mstore(add(m, 0xa0), address()) + mstore(add(m, 0xc0), calldataload(0x24)) // amount + mstore(add(m, 0xe0), calldataload(0x84)) // depositor + mstore(add(m, 0x120), 0x140) + + // Derive the memory location for the typestring. + typestringMemoryLocation := add(m, 0x160) + + // NOTE: strongly consider allocating memory here as the inline assembly scope + // is being left (it *should* be fine for now as the function between assembly + // blocks does not allocate any new memory). + } + } + + /** + * @notice Private function for writing the signature and performing the Permit2 call. + * @param m The memory pointer for the Permit2 call data. + * @param signatureOffsetLocation The memory location for the signature offset. + * @param signatureOffsetValue The signature offset value. + * @param signature The Permit2 signature. + */ + function _writeSignatureAndPerformPermit2Call(uint256 m, uint256 signatureOffsetLocation, uint256 signatureOffsetValue, bytes calldata signature) private { + // Determine if Permit2 is deployed. + bool isPermit2Deployed = _isPermit2Deployed(); + + assembly ("memory-safe") { + // Write the signature offset. + mstore(add(m, signatureOffsetLocation), signatureOffsetValue) // signature offset + + // Retrieve signature length and derive signature memory offset. + let signatureLength := signature.length + let signatureMemoryOffset := add(m, add(0x20, signatureOffsetValue)) + + // Write the signature length. + mstore(signatureMemoryOffset, signatureLength) + + // Copy the signature from calldata to memory. + calldatacopy(add(signatureMemoryOffset, 0x20), signature.offset, signatureLength) + + // Perform the Permit2 call. + if iszero(and(isPermit2Deployed, call(gas(), _PERMIT2, 0, add(m, 0x1c), add(0x24, add(signatureOffsetValue, signatureLength)), 0, 0))) { + // Bubble up if the call failed and there's data. + // NOTE: consider evaluating remaining gas to protect against revert bombing + if returndatasize() { + returndatacopy(0, 0, returndatasize()) + revert(0, returndatasize()) + } + + // revert Permit2CallFailed(); + mstore(0, 0x7f28c61e) + revert(0x1c, 0x04) + } + } + } + + /** + * @notice Private function for verifying balance changes and performing deposits. + * @param ids The ERC6909 token identifiers of the associated resource locks. + * @param permittedTokens The token permissions specifying the deposited tokens and amounts. + * @param initialTokenBalances The initial token balances in the contract. + * @param recipient The address that will receive the corresponding ERC6909 tokens. + * @param firstUnderlyingTokenIsNative A boolean indicating whether the first underlying token is native. + */ + function _verifyBalancesAndPerformDeposits( + uint256[] memory ids, + ISignatureTransfer.TokenPermissions[] calldata permittedTokens, + uint256[] memory initialTokenBalances, + address recipient, + bool firstUnderlyingTokenIsNative + ) private { + // Declare token balance, initial balance, and error buffer variables. + uint256 tokenBalance; + uint256 initialBalance; + uint256 errorBuffer; + + // Retrieve total initial token balances (equal to total tokens less initial native deposit). + uint256 totalTokensLessInitialNative = initialTokenBalances.length; + + unchecked { + // Iterate through each token. + for (uint256 i = 0; i < totalTokensLessInitialNative; ++i) { + // Get the token balance and initial balance. + tokenBalance = permittedTokens[i + firstUnderlyingTokenIsNative.asUint256()].token.balanceOf(address(this)); + initialBalance = initialTokenBalances[i]; + + // Set the error buffer if the initial balance is greater than or equal to the token balance. + errorBuffer |= (initialBalance >= tokenBalance).asUint256(); + + // Perform the deposit. + _deposit(recipient, ids[i + firstUnderlyingTokenIsNative.asUint256()], tokenBalance - initialBalance); + } + } + + assembly ("memory-safe") { + // Revert if the error buffer is set. + if errorBuffer { + // revert InvalidDepositBalanceChange() + mstore(0, 0x426d8dcf) + revert(0x1c, 0x04) + } + } + + // Clear reentrancy guard. + _clearReentrancyGuard(); + } + + /** + * @notice Private function for preparing ids and getting token balances. + * Note that all tokens must be supplied in ascending order and cannot be duplicated. + * @param ids The ERC6909 token identifiers of the associated resource locks. + * @param totalTokensLessInitialNative The total number of tokens less the initial native deposit. + * @param firstUnderlyingTokenIsNative A boolean indicating whether the first underlying token is native. + * @param permitted The token permissions specifying the deposited tokens and amounts. + * @param id The ERC6909 token identifier of the associated resource lock. + * @return tokenBalances The token balances in the contract. + */ + function _prepareIdsAndGetBalances(uint256[] memory ids, uint256 totalTokensLessInitialNative, bool firstUnderlyingTokenIsNative, ISignatureTransfer.TokenPermissions[] calldata permitted, uint256 id) + private + view + returns (uint256[] memory tokenBalances) + { + unchecked { + // Allocate token balances array. + tokenBalances = new uint256[](totalTokensLessInitialNative); + + // Declare token, candidate id, and error buffer variables. + address token; + uint256 candidateId; + uint256 errorBuffer; + + // Iterate over each token. + for (uint256 i = 0; i < totalTokensLessInitialNative; ++i) { + // Retrieve the token and derive the candidate id. + token = permitted[i + firstUnderlyingTokenIsNative.asUint256()].token; + candidateId = id.withReplacedToken(token); + + // Set the error buffer if the candidate id is less than or equal to the current id. + errorBuffer |= (candidateId <= id).asUint256(); + + // Update the id. + id = candidateId; + + // Set the id in the ids array. + ids[i + firstUnderlyingTokenIsNative.asUint256()] = id; + + // Get the token balance and set it in the token balances array. + tokenBalances[i] = token.balanceOf(address(this)); + } + + assembly ("memory-safe") { + // Revert if the error buffer is set. + if errorBuffer { + // revert InvalidDepositTokenOrdering() + mstore(0, 0x0f2f1e51) + revert(0x1c, 0x04) + } + } + } + } +} diff --git a/src/lib/DirectDepositLogic.sol b/src/lib/DirectDepositLogic.sol new file mode 100644 index 0000000..721ee5b --- /dev/null +++ b/src/lib/DirectDepositLogic.sol @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { ResetPeriod } from "../types/ResetPeriod.sol"; +import { Scope } from "../types/Scope.sol"; + +import { EfficiencyLib } from "./EfficiencyLib.sol"; +import { IdLib } from "./IdLib.sol"; +import { DepositLogic } from "./DepositLogic.sol"; +import { ValidityLib } from "./ValidityLib.sol"; + +import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol"; +import { ISignatureTransfer } from "permit2/src/interfaces/ISignatureTransfer.sol"; + +/** + * @title DirectDepositLogic + * @notice Inherited contract implementing internal functions with logic for processing + * direct token deposits (or deposits that do not involve Permit2). This includes both + * single-token deposits and batch token deposits. + */ +contract DirectDepositLogic is DepositLogic { + using IdLib for uint96; + using IdLib for uint256; + using IdLib for address; + using EfficiencyLib for bool; + using ValidityLib for address; + using SafeTransferLib for address; + + /** + * @notice Internal function for depositing native tokens into a resource lock and + * receiving back ERC6909 tokens representing the underlying locked balance controlled + * by the depositor. The allocator mediating the lock is provided as an argument, and the + * default reset period (ten minutes) and scope (multichain) will be used for the resource + * lock. The ERC6909 token amount received by the caller will match the amount of native + * tokens sent with the transaction. + * @param allocator The address of the allocator. + * @return id The ERC6909 token identifier of the associated resource lock. + */ + function _performBasicNativeTokenDeposit(address allocator) internal returns (uint256 id) { + // Derive the resource lock ID using the null address and default parameters. + id = address(0).toIdIfRegistered(Scope.Multichain, ResetPeriod.TenMinutes, allocator); + + // Mint ERC6909 tokens to caller using derived ID and supplied native tokens. + _deposit(msg.sender, id, msg.value); + } + + /** + * @notice Internal function for depositing multiple tokens in a single transaction. The + * first entry in idsAndAmounts can optionally represent native tokens by providing the null + * address and an amount matching msg.value. For ERC20 tokens, the caller must directly + * approve The Compact to transfer sufficient amounts on its behalf. The ERC6909 token amounts + * received by the recipient are derived from the differences between starting and ending + * balances held in the resource locks, which may differ from the amounts transferred depending + * on the implementation details of the respective tokens. + * @param idsAndAmounts Array of [id, amount] pairs with each pair indicating the resource lock and amount to deposit. + * @param recipient The address that will receive the corresponding ERC6909 tokens. + */ + function _processBatchDeposit(uint256[2][] calldata idsAndAmounts, address recipient) internal { + // Set reentrancy guard. + _setReentrancyGuard(); + + // Retrieve the total number of IDs and amounts in the batch. + uint256 totalIds = idsAndAmounts.length; + + // Declare variables for ID, amount, and whether first token is native. + uint256 id; + uint256 amount; + bool firstUnderlyingTokenIsNative; + + assembly ("memory-safe") { + // Determine the offset of idsAndAmounts in calldata. + let idsAndAmountsOffset := idsAndAmounts.offset + + // Load the first ID from idsAndAmounts. + id := calldataload(idsAndAmountsOffset) + + // Determine if token encoded in first ID is the null address. + firstUnderlyingTokenIsNative := iszero(shr(96, shl(96, id))) + + // Revert if: + // * the array is empty + // * the callvalue is zero but the first token is native + // * the callvalue is nonzero but the first token is non-native + // * the first token is non-native and the callvalue doesn't equal the first amount + if or(iszero(totalIds), or(eq(firstUnderlyingTokenIsNative, iszero(callvalue())), and(firstUnderlyingTokenIsNative, iszero(eq(callvalue(), calldataload(add(idsAndAmountsOffset, 0x20))))))) { + // revert InvalidBatchDepositStructure() + mstore(0, 0xca0fc08e) + revert(0x1c, 0x04) + } + } + + // Derive current allocator ID from first resource lock ID. + uint96 currentAllocatorId = id.toRegisteredAllocatorId(); + + // Declare variable for subsequent allocator IDs. + uint96 newAllocatorId; + + // Deposit native tokens directly if first underlying token is native. + if (firstUnderlyingTokenIsNative) { + _deposit(recipient, id, msg.value); + } + + // Iterate over remaining IDs and amounts. + unchecked { + for (uint256 i = firstUnderlyingTokenIsNative.asUint256(); i < totalIds; ++i) { + // Navigate to the current ID and amount pair in calldata. + uint256[2] calldata idAndAmount = idsAndAmounts[i]; + + // Retrieve the current ID and amount. + id = idAndAmount[0]; + amount = idAndAmount[1]; + + // Derive new allocator ID from current resource lock ID. + newAllocatorId = id.toAllocatorId(); + + // Determine if new allocator ID differs from current allocator ID. + if (newAllocatorId != currentAllocatorId) { + // Ensure new allocator ID is registered. + newAllocatorId.mustHaveARegisteredAllocator(); + + // Update current allocator ID. + currentAllocatorId = newAllocatorId; + } + + // Transfer underlying tokens in and mint ERC6909 tokens to recipient. + _transferAndDeposit(id.toToken(), recipient, id, amount); + } + } + + // Clear reentrancy guard. + _clearReentrancyGuard(); + } + + /** + * @notice Internal function for depositing native tokens into a resource lock and + * receiving back ERC6909 tokens representing the underlying locked balance controlled + * by the depositor. The allocator mediating the lock is provided as an argument, and the + * default reset period (ten minutes) and scope (multichain) will be used for the resource + * lock. The ERC6909 token amount received by the caller will match the amount of native + * tokens sent with the transaction. + * @param allocator The address of the allocator. + * @return id The ERC6909 token identifier of the associated resource lock. + */ + function _performBasicERC20Deposit(address token, address allocator, uint256 amount) internal returns (uint256 id) { + // Derive resource lock ID using provided token, default parameters, and allocator. + id = token.excludingNative().toIdIfRegistered(Scope.Multichain, ResetPeriod.TenMinutes, allocator); + + // Transfer underlying tokens in and mint ERC6909 tokens to caller. + _transferAndDepositWithReentrancyGuard(token, msg.sender, id, amount); + } + + /** + * @notice Internal function for depositing native tokens into a resource lock with custom + * reset period and scope parameters. The ERC6909 token amount received by the recipient + * will match the amount of native tokens sent with the transaction. + * @param allocator The address of the allocator mediating the resource lock. + * @param resetPeriod The duration after which the resource lock can be reset once a forced withdrawal is initiated. + * @param scope The scope of the resource lock (multichain or single chain). + * @param recipient The address that will receive the corresponding ERC6909 tokens. + * @return id The ERC6909 token identifier of the associated resource lock. + */ + function _performCustomNativeTokenDeposit(address allocator, ResetPeriod resetPeriod, Scope scope, address recipient) internal returns (uint256 id) { + // Derive resource lock ID using null address, provided parameters, and allocator. + id = address(0).toIdIfRegistered(scope, resetPeriod, allocator); + + // Deposit native tokens and mint ERC6909 tokens to recipient. + _deposit(recipient, id, msg.value); + } + + /** + * @notice Internal function for depositing ERC20 tokens into a resource lock with custom reset + * period and scope parameters. The caller must directly approve The Compact to transfer a + * sufficient amount of the ERC20 token on its behalf. The ERC6909 token amount received by + * the recipient is derived from the difference between the starting and ending balance held + * in the resource lock, which may differ from the amount transferred depending on the + * implementation details of the respective token. + * @param token The address of the ERC20 token to deposit. + * @param allocator The address of the allocator mediating the resource lock. + * @param resetPeriod The duration after which the resource lock can be reset once a forced withdrawal is initiated. + * @param scope The scope of the resource lock (multichain or single chain). + * @param amount The amount of tokens to deposit. + * @param recipient The address that will receive the corresponding ERC6909 tokens. + * @return id The ERC6909 token identifier of the associated resource lock. + */ + function _performCustomERC20Deposit(address token, address allocator, ResetPeriod resetPeriod, Scope scope, uint256 amount, address recipient) internal returns (uint256 id) { + // Derive resource lock ID using provided token, parameters, and allocator. + id = token.excludingNative().toIdIfRegistered(scope, resetPeriod, allocator); + + // Transfer ERC20 tokens in and mint ERC6909 tokens to recipient. + _transferAndDepositWithReentrancyGuard(token, recipient, id, amount); + } + + /** + * @notice Private function for transferring ERC20 tokens in and minting the resulting balance + * change of `id` to `to`. Emits a Transfer event. + * @param token The address of the ERC20 token to transfer. + * @param to The address that will receive the corresponding ERC6909 tokens. + * @param id The ERC6909 token identifier of the associated resource lock. + * @param amount The amount of tokens to transfer. + */ + function _transferAndDeposit(address token, address to, uint256 id, uint256 amount) private { + // Retrieve initial token balance of this contract. + uint256 initialBalance = token.balanceOf(address(this)); + + // Transfer tokens from caller to this contract. + token.safeTransferFrom(msg.sender, address(this), amount); + + // Compare new balance to initial balance and deposit ERC6909 tokens to recipient. + _checkBalanceAndDeposit(token, to, id, initialBalance); + } + + /** + * @notice Private function for transferring ERC20 tokens in and minting the resulting balance + * change of `id` to `to`. Emits a Transfer event. + * @param token The address of the ERC20 token to transfer. + * @param to The address that will receive the corresponding ERC6909 tokens. + * @param id The ERC6909 token identifier of the associated resource lock. + * @param amount The amount of tokens to transfer. + */ + function _transferAndDepositWithReentrancyGuard(address token, address to, uint256 id, uint256 amount) private { + // Set reentrancy guard. + _setReentrancyGuard(); + + // Transfer tokens in and mint ERC6909 tokens to recipient. + _transferAndDeposit(token, to, id, amount); + + // Clear reentrancy guard. + _clearReentrancyGuard(); + } +} diff --git a/src/lib/DomainLib.sol b/src/lib/DomainLib.sol new file mode 100644 index 0000000..509f0ab --- /dev/null +++ b/src/lib/DomainLib.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +/** + * @title DomainLib + * @notice Libray contract implementing logic for deriving domain hashes. + */ +library DomainLib { + /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`. + bytes32 internal constant _DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; + + /// @dev `keccak256(bytes("The Compact"))`. + bytes32 internal constant _NAME_HASH = 0x5e6f7b4e1ac3d625bac418bc955510b3e054cb6cc23cc27885107f080180b292; + + /// @dev `keccak256("0")`. + bytes32 internal constant _VERSION_HASH = 0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d; + + function toLatest(bytes32 initialDomainSeparator, uint256 initialChainId) internal view returns (bytes32 domainSeparator) { + // Set the initial domain separator as the default domain separator. + domainSeparator = initialDomainSeparator; + + assembly ("memory-safe") { + // Rederive the domain separator if the initial chain ID differs from the current one. + if xor(chainid(), initialChainId) { + // Retrieve the free memory pointer. + let m := mload(0x40) + + // Prepare domain data: EIP-712 typehash, name hash, version hash, chain ID, and verifying contract. + mstore(m, _DOMAIN_TYPEHASH) + mstore(add(m, 0x20), _NAME_HASH) + mstore(add(m, 0x40), _VERSION_HASH) + mstore(add(m, 0x60), chainid()) + mstore(add(m, 0x80), address()) + + // Derive the domain separator. + domainSeparator := keccak256(m, 0xa0) + } + } + } + + function toNotarizedDomainSeparator(uint256 notarizedChainId) internal view returns (bytes32 notarizedDomainSeparator) { + assembly ("memory-safe") { + // Retrieve the free memory pointer. + let m := mload(0x40) + + // Prepare domain data: EIP-712 typehash, name hash, version hash, notarizing chain ID, and verifying contract. + mstore(m, _DOMAIN_TYPEHASH) + mstore(add(m, 0x20), _NAME_HASH) + mstore(add(m, 0x40), _VERSION_HASH) + mstore(add(m, 0x60), notarizedChainId) + mstore(add(m, 0x80), address()) + + // Derive the domain separator. + notarizedDomainSeparator := keccak256(m, 0xa0) + } + } + + function withDomain(bytes32 messageHash, bytes32 domainSeparator) internal pure returns (bytes32 domainHash) { + assembly ("memory-safe") { + // Retrieve and cache the free memory pointer. + let m := mload(0x40) + + // Prepare the 712 prefix. + mstore(0, 0x1901) + + // Prepare the domain separator. + mstore(0x20, domainSeparator) + + // Prepare the message hash and compute the domain hash. + mstore(0x40, messageHash) + domainHash := keccak256(0x1e, 0x42) + + // Restore the free memory pointer. + mstore(0x40, m) + } + } +} diff --git a/src/lib/EfficiencyLib.sol b/src/lib/EfficiencyLib.sol new file mode 100644 index 0000000..bb7754f --- /dev/null +++ b/src/lib/EfficiencyLib.sol @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { Scope } from "../types/Scope.sol"; +import { ResetPeriod } from "../types/ResetPeriod.sol"; + +/** + * @title EfficiencyLib + * @notice Library contract implementing logic for efficient value comparisons, + * conversions, typecasting, and sanitization. Also provides functions to prevent + * the function specializer from being triggered when using static arguments. + */ +library EfficiencyLib { + /** + * @notice Internal pure function that performs a bitwise AND on two booleans. + * Avoids Solidity's conditional evaluation of logical AND. Only safe when + * inputs are known to be exactly 0 or 1 with no dirty bits. + * @param a The first boolean value. + * @param b The second boolean value. + * @return c The result of the bitwise AND. + */ + function and(bool a, bool b) internal pure returns (bool c) { + assembly ("memory-safe") { + c := and(a, b) + } + } + + /** + * @notice Internal pure function that performs a bitwise OR on two booleans. + * Avoids Solidity's conditional evaluation of logical OR. Only safe when + * inputs are known to be exactly 0 or 1 with no dirty bits. + * @param a The first boolean value. + * @param b The second boolean value. + * @return c The result of the bitwise OR. + */ + function or(bool a, bool b) internal pure returns (bool c) { + assembly ("memory-safe") { + c := or(a, b) + } + } + + /** + * @notice Internal pure function that converts a uint256 to a boolean. Only + * safe when the input is known to be exactly 0 or 1 with no dirty bits. + * @param a The uint256 to convert. + * @return b The resulting boolean. + */ + function asBool(uint256 a) internal pure returns (bool b) { + assembly ("memory-safe") { + b := a + } + } + + /** + * @notice Internal pure function that sanitizes an address by clearing the + * upper 96 bits. Used for ensuring consistent address handling. + * @param accountValue The value to sanitize. + * @return account The sanitized address. + */ + function asSanitizedAddress(uint256 accountValue) internal pure returns (address account) { + assembly ("memory-safe") { + account := shr(96, shl(96, accountValue)) + } + } + + /** + * @notice Internal pure function that checks if an address has its lower 160 + * bits set to zero. + * @param account The address to check. + * @return isNull Whether the address is null. + */ + function isNullAddress(address account) internal pure returns (bool isNull) { + assembly ("memory-safe") { + isNull := iszero(shl(96, account)) + } + } + + /** + * @notice Internal pure function that converts a boolean to a uint256. + * @param a The boolean to convert. + * @return b The resulting uint256. + */ + function asUint256(bool a) internal pure returns (uint256 b) { + assembly ("memory-safe") { + b := a + } + } + + /** + * @notice Internal pure function that converts a uint8 to a uint256. + * @param a The uint8 to convert. + * @return b The resulting uint256. + */ + function asUint256(uint8 a) internal pure returns (uint256 b) { + assembly ("memory-safe") { + b := a + } + } + + /** + * @notice Internal pure function that converts a uint96 to a uint256. + * @param a The uint96 to convert. + * @return b The resulting uint256. + */ + function asUint256(uint96 a) internal pure returns (uint256 b) { + assembly ("memory-safe") { + b := a + } + } + + /** + * @notice Internal pure function that converts a Scope enum to a uint256. + * @param a The Scope enum to convert. + * @return b The resulting uint256. + */ + function asUint256(Scope a) internal pure returns (uint256 b) { + assembly ("memory-safe") { + b := a + } + } + + /** + * @notice Internal pure function that converts an address to a uint256. + * @param a The address to convert. + * @return b The resulting uint256. + */ + function asUint256(address a) internal pure returns (uint256 b) { + assembly ("memory-safe") { + b := a + } + } + + /** + * @notice Internal pure function that converts a ResetPeriod enum to a uint256. + * @param a The ResetPeriod enum to convert. + * @return b The resulting uint256. + */ + function asUint256(ResetPeriod a) internal pure returns (uint256 b) { + assembly ("memory-safe") { + b := a + } + } + + /** + * @notice Internal pure function that prevents the function specializer from + * optimizing uint256 arguments. XORs the value with calldatasize(), which + * will always be non-zero in a real call. + * @param a The uint256 value to make stubborn. + * @return b The original value, preventing specialization. + */ + function asStubborn(uint256 a) internal pure returns (uint256 b) { + assembly ("memory-safe") { + b := or(iszero(calldatasize()), a) + } + } + + /** + * @notice Internal pure function that prevents the function specializer from + * inlining functions that take fixed bytes32 arguments. Since calldatasize() + * will always be non-zero when making a standard function call, an OR + * against iszero(calldatasize()) will always result in the original value. + * @param a The bytes32 value to make stubborn. + * @return b The original value, preventing specialization. + */ + function asStubborn(bytes32 a) internal pure returns (bytes32 b) { + assembly ("memory-safe") { + b := or(iszero(calldatasize()), a) + } + } + + /** + * @notice Internal pure function that prevents the function specializer from + * inlining functions that take fixed boolean arguments. Since calldatasize() + * will always be non-zero when making a standard function call, an OR + * against iszero(calldatasize()) will always result in the original value. + * @param a The boolean value to make stubborn. + * @return b The original value, preventing specialization. + */ + function asStubborn(bool a) internal pure returns (bool b) { + assembly ("memory-safe") { + b := or(iszero(calldatasize()), a) + } + } +} diff --git a/src/lib/EmissaryLib.sol b/src/lib/EmissaryLib.sol new file mode 100644 index 0000000..c96362c --- /dev/null +++ b/src/lib/EmissaryLib.sol @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { ConsumerLib } from "./ConsumerLib.sol"; +import { ValidityLib } from "./ValidityLib.sol"; +import { EMISSARY_ASSIGNMENT_TYPEHASH } from "../types/EIP712Types.sol"; + +// An emissary can register claims on behalf of a sponsor that has assigned them. +// It works kind of like setApprovalForAll and applies to all locks. One caveat +// is that allocators still have to authorize any claims, which reduces the risk +// of a fully rogue emissary depending on the allocator in question. +// NOTE: this idea is inherently risky; think about whether it's worth it! Right +// now this functionality is not included in The Compact. +abstract contract EmissaryLib { + using ValidityLib for uint256; + using ValidityLib for address; + using ConsumerLib for uint256; + + event EmissaryAssignment(address indexed sponsor, address indexed emissary, bool assigned); + + error InvalidEmissary(address sponsor, address emissary); + + // TODO: optimize + mapping(address => mapping(address => bool)) private _emissaries; + + // TODO: this mapping already exists on The Compact; just use one of them! + mapping(address => mapping(bytes32 => bytes32)) private _registeredClaimHashes; + + function registerFor(address sponsor, bytes32 claimHash, bytes32 typehash) external returns (bool) { + // TODO: optimize + if (!_emissaries[sponsor][msg.sender]) { + revert InvalidEmissary(sponsor, msg.sender); + } + _registeredClaimHashes[sponsor][claimHash] = typehash; + return true; + } + + function registerFor(address sponsor, bytes32[2][] calldata claimHashesAndTypehashes) external returns (bool) { + // TODO: optimize + if (!_emissaries[sponsor][msg.sender]) { + revert InvalidEmissary(sponsor, msg.sender); + } + + return _registerFor(sponsor, claimHashesAndTypehashes); + } + + function assignEmissary(address sponsor, address emissary, uint256 nonce, uint256 expires, bool assigned, bytes calldata /*sponsorSignature*/ ) external returns (bool) { + expires.later(); + + bytes32 messageHash; + assembly ("memory-safe") { + let m := mload(0x40) // Grab the free memory pointer; memory will be left dirtied. + mstore(m, EMISSARY_ASSIGNMENT_TYPEHASH) + mstore(add(m, 0x20), emissary) + mstore(add(m, 0x40), nonce) + mstore(add(m, 0x60), expires) + mstore(add(m, 0x80), assigned) + messageHash := keccak256(m, 0xa0) + } + + // TODO: this function should be colocated with the rest of The Compact as it has the immutable args here + // messageHash.signedBy(sponsor, sponsorSignature, _INITIAL_DOMAIN_SEPARATOR.toLatest(_INITIAL_CHAIN_ID)); + + nonce.consumeNonceAsSponsor(sponsor); + + return _assignEmissary(sponsor, emissary, assigned); + } + + function assignEmissary(address emissary, bool assigned) external returns (bool) { + return _assignEmissary(msg.sender, emissary, assigned); + } + + function hasConsumedEmissaryAssignmentNonce(uint256 nonce, address sponsor) external view returns (bool consumed) { + consumed = nonce.isConsumedBySponsor(sponsor); + } + + function _assignEmissary(address sponsor, address emissary, bool assigned) internal returns (bool) { + _emissaries[sponsor][emissary] = assigned; + + emit EmissaryAssignment(sponsor, emissary, assigned); + + return true; + } + + // TODO: this is already on the compact, just use one of them + function _registerFor(address sponsor, bytes32[2][] calldata claimHashesAndTypehashes) internal returns (bool) { + unchecked { + uint256 totalClaimHashes = claimHashesAndTypehashes.length; + for (uint256 i = 0; i < totalClaimHashes; ++i) { + bytes32[2] calldata claimHashAndTypehash = claimHashesAndTypehashes[i]; + _registeredClaimHashes[sponsor][claimHashAndTypehash[0]] = claimHashAndTypehash[1]; + } + } + + return true; + } +} diff --git a/src/lib/EventLib.sol b/src/lib/EventLib.sol new file mode 100644 index 0000000..4f7728e --- /dev/null +++ b/src/lib/EventLib.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +/** + * @title EventLib + * @notice Library contract implementing logic for internal functions to + * emit various events. + * @dev Note that most events are still emitted using inline logic; this + * library only implements a few events. + */ +library EventLib { + // keccak256(bytes("Claim(address,address,address,bytes32)")). + uint256 private constant _CLAIM_EVENT_SIGNATURE = 0x770c32a2314b700d6239ee35ba23a9690f2fceb93a55d8c753e953059b3b18d4; + + // keccak256(bytes("ForcedWithdrawalStatusUpdated(address,uint256,bool,uint256)")). + uint256 private constant _FORCED_WITHDRAWAL_STATUS_UPDATED_SIGNATURE = 0xe27f5e0382cf5347965fc81d5c81cd141897fe9ce402d22c496b7c2ddc84e5fd; + + /** + * @notice Internal function for emitting claim events. The sponsor and allocator + * addresses are sanitized before emission. + * @param sponsor The account sponsoring the compact that the claim is for. + * @param messageHash The EIP-712 hash of the claim message. + * @param allocator The account mediating the claim. + */ + function emitClaim(address sponsor, bytes32 messageHash, address allocator) internal { + assembly ("memory-safe") { + // Emit the Claim event: + // - topic1: Claim event signature + // - topic2: sponsor address (sanitized) + // - topic3: allocator address (sanitized) + // - topic4: caller address + // - data: messageHash + mstore(0, messageHash) + log4(0, 0x20, _CLAIM_EVENT_SIGNATURE, shr(0x60, shl(0x60, sponsor)), shr(0x60, shl(0x60, allocator)), caller()) + } + } + + /** + * @notice Internal function for emitting forced withdrawal status update events. + * @param id The ERC6909 token identifier of the resource lock. + * @param withdrawableAt The timestamp when withdrawal becomes possible. + */ + function emitForcedWithdrawalStatusUpdatedEvent(uint256 id, uint256 withdrawableAt) internal { + assembly ("memory-safe") { + // Emit ForcedWithdrawalStatusUpdated event: + // - topic1: Event signature + // - topic2: Caller address + // - topic3: Token id + // - data: [activating flag, withdrawableAt timestamp] + mstore(0, iszero(iszero(withdrawableAt))) + mstore(0x20, withdrawableAt) + log3(0, 0x40, _FORCED_WITHDRAWAL_STATUS_UPDATED_SIGNATURE, caller(), id) + } + } +} diff --git a/src/lib/Extsload.sol b/src/lib/Extsload.sol new file mode 100644 index 0000000..2718c78 --- /dev/null +++ b/src/lib/Extsload.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +/** + * @title Extsload + * @notice Contract implementing external functions for reading values from + * storage or transient storage directly. + */ +contract Extsload { + function exttload(bytes32 slot) external view returns (bytes32) { + assembly ("memory-safe") { + mstore(0, tload(slot)) + return(0, 0x20) + } + } + + function extsload(bytes32 slot) external view returns (bytes32) { + assembly ("memory-safe") { + mstore(0, sload(slot)) + return(0, 0x20) + } + } + + function extsload(bytes32[] calldata slots) external view returns (bytes32[] memory) { + assembly ("memory-safe") { + let memptr := mload(0x40) + let start := memptr + // for abi encoding the response - the array will be found at 0x20 + mstore(memptr, 0x20) + // next we store the length of the return array + mstore(add(memptr, 0x20), slots.length) + // update memptr to the first location to hold an array entry + memptr := add(memptr, 0x40) + // A left bit-shift of 5 is equivalent to multiplying by 32 but costs less gas. + let end := add(memptr, shl(5, slots.length)) + let calldataptr := slots.offset + for { } 1 { } { + mstore(memptr, sload(calldataload(calldataptr))) + memptr := add(memptr, 0x20) + calldataptr := add(calldataptr, 0x20) + if iszero(lt(memptr, end)) { break } + } + return(start, sub(end, start)) + } + } +} diff --git a/src/lib/HashLib.sol b/src/lib/HashLib.sol new file mode 100644 index 0000000..fde0eb3 --- /dev/null +++ b/src/lib/HashLib.sol @@ -0,0 +1,783 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { BatchTransfer, SplitBatchTransfer } from "../types/BatchClaims.sol"; +import { BasicTransfer, SplitTransfer } from "../types/Claims.sol"; +import { TransferComponent, SplitComponent, SplitByIdComponent, BatchClaimComponent, SplitBatchClaimComponent } from "../types/Components.sol"; +import { + COMPACT_TYPEHASH, + COMPACT_TYPESTRING_FRAGMENT_ONE, + COMPACT_TYPESTRING_FRAGMENT_TWO, + COMPACT_TYPESTRING_FRAGMENT_THREE, + BATCH_COMPACT_TYPEHASH, + BATCH_COMPACT_TYPESTRING_FRAGMENT_ONE, + BATCH_COMPACT_TYPESTRING_FRAGMENT_TWO, + BATCH_COMPACT_TYPESTRING_FRAGMENT_THREE, + BATCH_COMPACT_TYPESTRING_FRAGMENT_FOUR, + SEGMENT_TYPEHASH, + MULTICHAIN_COMPACT_TYPEHASH, + MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_ONE, + MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_TWO, + MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_THREE, + MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_FOUR, + MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_FIVE, + TOKEN_PERMISSIONS_TYPESTRING_FRAGMENT_ONE, + TOKEN_PERMISSIONS_TYPESTRING_FRAGMENT_TWO, + PERMIT2_DEPOSIT_WITNESS_FRAGMENT_HASH +} from "../types/EIP712Types.sol"; + +import { EfficiencyLib } from "./EfficiencyLib.sol"; +import { TransferFunctionCastLib } from "./TransferFunctionCastLib.sol"; + +/** + * @title HashLib + * @notice Libray contract implementing logic for deriving hashes as part of processing + * claims, allocated transfers, and withdrawals, including deriving typehashes when + * witness data is utilized and qualification hashes when claims have been qualified by + * the allocator. + */ +library HashLib { + using EfficiencyLib for bool; + using EfficiencyLib for uint256; + using TransferFunctionCastLib for function(BatchTransfer calldata, uint256) internal view returns (bytes32); + using HashLib for uint256; + using HashLib for BatchTransfer; + + /** + * @notice Internal view function for deriving the EIP-712 message hash for + * a basic transfer or withdrawal where the arbiter is the sponsor. + * @param transfer A BasicTransfer struct containing the transfer details. + * @return messageHash The EIP-712 compliant message hash. + */ + function toBasicTransferMessageHash(BasicTransfer calldata transfer) internal view returns (bytes32 messageHash) { + assembly ("memory-safe") { + // Retrieve the free memory pointer; memory will be left dirtied. + let m := mload(0x40) + + // Prepare initial components of message data: typehash, arbiter, & sponsor. + mstore(m, COMPACT_TYPEHASH) + mstore(add(m, 0x20), caller()) // arbiter: msg.sender + mstore(add(m, 0x40), caller()) // sponsor: msg.sender + + // Remaining data copied from calldata: nonce, expires, id & amount. + calldatacopy(add(m, 0x60), add(transfer, 0x20), 0x80) + + // Derive the message hash from the prepared data. + messageHash := keccak256(m, 0xe0) + } + } + + /** + * @notice Internal view function for deriving the EIP-712 message hash for + * a split transfer or withdrawal. + * @param transfer A SplitTransfer struct containing the transfer details. + * @return messageHash The EIP-712 compliant message hash. + */ + function toSplitTransferMessageHash(SplitTransfer calldata transfer) internal view returns (bytes32 messageHash) { + // Declare variables for tracking, total amount, current amount, and errors. + uint256 amount = 0; + uint256 currentAmount; + uint256 errorBuffer; + + // Navigate to the split components array in calldata. + SplitComponent[] calldata recipients = transfer.recipients; + + // Retrieve the length of the array. + uint256 totalRecipients = recipients.length; + + unchecked { + // Iterate over each split component. + for (uint256 i = 0; i < totalRecipients; ++i) { + // Retrieve the current amount of the component. + currentAmount = recipients[i].amount; + + // Add current amount to total amount and check for overflow. + amount += currentAmount; + errorBuffer |= (amount < currentAmount).asUint256(); + } + } + + assembly ("memory-safe") { + // Revert if an arithmetic overflow was detected. + if errorBuffer { + // Revert Panic(0x11) (arithmetic overflow) + mstore(0, 0x4e487b71) + mstore(0x20, 0x11) + revert(0x1c, 0x24) + } + + // Retrieve the free memory pointer; memory will be left dirtied. + let m := mload(0x40) + + // Prepare initial components of message data: typehash, arbiter, & sponsor. + mstore(m, COMPACT_TYPEHASH) + mstore(add(m, 0x20), caller()) // arbiter: msg.sender + mstore(add(m, 0x40), caller()) // sponsor: msg.sender + + // Subsequent data copied from calldata: nonce, expires & id. + calldatacopy(add(m, 0x60), add(transfer, 0x20), 0x60) + + // Prepare final component of message data: aggregate amount. + mstore(add(m, 0xc0), amount) + + // Derive the message hash from the prepared data. + messageHash := keccak256(m, 0xe0) + } + } + + /** + * @notice Internal view function for deriving the EIP-712 message hash for + * a batch transfer or withdrawal. + * @param transfer A BatchTransfer struct containing the transfer details. + * @return messageHash The EIP-712 compliant message hash. + */ + function toBatchTransferMessageHash(BatchTransfer calldata transfer) internal view returns (bytes32) { + // Navigate to the transfer components array in calldata. + TransferComponent[] calldata transfers = transfer.transfers; + + // Declare a variable for the ids and amounts hash. + uint256 idsAndAmountsHash; + + assembly ("memory-safe") { + // Retrieve the free memory pointer; memory will be left dirtied. + let m := mload(0x40) + + // Calculate the total size of the transfer data. + let totalTransferData := mul(transfers.length, 0x40) + + // Copy the transfer data from calldata to memory. + calldatacopy(m, transfers.offset, totalTransferData) + + // Derive the ids and amounts hash from the transfer data. + idsAndAmountsHash := keccak256(m, totalTransferData) + } + + // Derive message hash from transfer data and idsAndAmounts hash. + return transfer.toBatchTransferMessageHashUsingIdsAndAmountsHash(idsAndAmountsHash); + } + + /** + * @notice Internal view function for deriving the EIP-712 message hash for + * a split batch transfer or withdrawal. + * @param transfer A SplitBatchTransfer struct containing the transfer details. + * @return messageHash The EIP-712 compliant message hash. + */ + function toSplitBatchTransferMessageHash(SplitBatchTransfer calldata transfer) internal view returns (bytes32) { + // Navigate to the transfer components array in calldata. + SplitByIdComponent[] calldata transfers = transfer.transfers; + + // Retrieve the length of the array. + uint256 totalIds = transfers.length; + + // Allocate memory region for ids and amounts. + bytes memory idsAndAmounts = new bytes(totalIds * 0x40); + + // Declare a buffer for arithmetic errors. + uint256 errorBuffer; + + unchecked { + // Iterate over each transfer component. + for (uint256 i = 0; i < totalIds; ++i) { + // Navigate to the current transfer component. + SplitByIdComponent calldata transferComponent = transfers[i]; + + // Retrieve the id from the current transfer component. + uint256 id = transferComponent.id; + + // Declare a variable for the aggregate amount. + uint256 amount = 0; + + // Declare a variable for the current amount. + uint256 singleAmount; + + // Navigate to the portions array in the current transfer component. + SplitComponent[] calldata portions = transferComponent.portions; + + // Retrieve the length of the portions array. + uint256 portionsLength = portions.length; + + // Iterate over each portion. + for (uint256 j = 0; j < portionsLength; ++j) { + // Retrieve the current amount of the portion. + singleAmount = portions[j].amount; + + // Add current amount to aggregate amount and check for overflow. + amount += singleAmount; + errorBuffer |= (amount < singleAmount).asUint256(); + } + + assembly ("memory-safe") { + // Derive offset to id and amount based on total split components. + let extraOffset := add(add(idsAndAmounts, 0x20), mul(i, 0x40)) + + // Store the id and aggregate amount at the derived offset. + mstore(extraOffset, id) + mstore(add(extraOffset, 0x20), amount) + } + } + } + + // Declare a variable for the ids and amounts hash. + uint256 idsAndAmountsHash; + assembly ("memory-safe") { + // Revert if an arithmetic overflow was detected. + if errorBuffer { + // Revert Panic(0x11) (arithmetic overflow) + mstore(0, 0x4e487b71) + mstore(0x20, 0x11) + revert(0x1c, 0x24) + } + + // Derive the ids and amounts hash from the stored data. + idsAndAmountsHash := keccak256(add(idsAndAmounts, 0x20), mload(idsAndAmounts)) + } + + // Derive message hash from transfer data and idsAndAmounts hash. + return toBatchTransferMessageHashUsingIdsAndAmountsHash.usingSplitBatchTransfer()(transfer, idsAndAmountsHash); + } + + /** + * @notice Internal view function for deriving the EIP-712 message hash for + * a claim. + * @param claim Pointer to the claim location in calldata. + * @param additionalOffset Additional offset from claim pointer to ID from most compact case. + * @return messageHash The EIP-712 compliant message hash. + */ + function toClaimMessageHash(uint256 claim, uint256 additionalOffset) internal view returns (bytes32 messageHash) { + assembly ("memory-safe") { + // Retrieve the free memory pointer; memory will be left dirtied. + let m := mload(0x40) + + // Derive the calldata pointer for the offset values. + let claimWithAdditionalOffset := add(claim, additionalOffset) + + // Prepare initial components of message data: typehash & arbiter. + mstore(m, COMPACT_TYPEHASH) + mstore(add(m, 0x20), caller()) // arbiter: msg.sender + + // Next data segment copied from calldata: sponsor, nonce & expires. + calldatacopy(add(m, 0x40), add(claim, 0x40), 0x60) + + // Prepare final components of message data: id and amount. + mstore(add(m, 0xa0), calldataload(add(claimWithAdditionalOffset, 0xa0))) // id + mstore(add(m, 0xc0), calldataload(add(claimWithAdditionalOffset, 0xc0))) // amount + + // Derive the message hash from the prepared data. + messageHash := keccak256(m, 0xe0) + } + } + + /** + * @notice Internal view function for deriving the EIP-712 message hash for + * a claim with a witness. + * @param claim Pointer to the claim location in calldata. + * @param qualificationOffset Additional offset from claim pointer to ID from most compact case. + * @return messageHash The EIP-712 compliant message hash. + * @return typehash The EIP-712 typehash. + */ + function toMessageHashWithWitness(uint256 claim, uint256 qualificationOffset) internal view returns (bytes32 messageHash, bytes32 typehash) { + assembly ("memory-safe") { + // Retrieve the free memory pointer; memory will be left dirtied. + let m := mload(0x40) + + // Derive the pointer to the witness typestring. + let witnessTypestringPtr := add(claim, calldataload(add(claim, 0xc0))) + + // Retrieve the length of the witness typestring. + let witnessTypestringLength := calldataload(witnessTypestringPtr) + + // Prepare first component of typestring from three one-word fragments. + mstore(m, COMPACT_TYPESTRING_FRAGMENT_ONE) + mstore(add(m, 0x20), COMPACT_TYPESTRING_FRAGMENT_TWO) + mstore(add(m, 0x40), COMPACT_TYPESTRING_FRAGMENT_THREE) + + // Copy remaining typestring data from calldata to memory. + calldatacopy(add(m, 0x60), add(0x20, witnessTypestringPtr), witnessTypestringLength) + + // Derive the typehash from the prepared data. + typehash := keccak256(m, add(0x60, witnessTypestringLength)) + + // Prepare initial components of message data: typehash & arbiter. + mstore(m, typehash) + mstore(add(m, 0x20), caller()) // arbiter: msg.sender + + // Next data segment copied from calldata: sponsor, nonce, expires. + calldatacopy(add(m, 0x40), add(claim, 0x40), 0x60) + + // Prepare final components of message data: id, amount, & witness. + mstore(add(m, 0xa0), calldataload(add(claim, add(0xe0, qualificationOffset)))) // id + mstore(add(m, 0xc0), calldataload(add(claim, add(0x100, qualificationOffset)))) // amount + mstore(add(m, 0xe0), calldataload(add(claim, 0xa0))) // witness + + // Derive the message hash from the prepared data. + messageHash := keccak256(m, 0x100) + } + } + + /** + * @notice Internal view function for deriving the EIP-712 message hash for + * a batch transfer or withdrawal once an idsAndAmounts hash is available. + * @param transfer A BatchTransfer struct containing the transfer details. + * @param idsAndAmountsHash A hash of the ids and amounts. + * @return messageHash The EIP-712 compliant message hash. + */ + function toBatchTransferMessageHashUsingIdsAndAmountsHash(BatchTransfer calldata transfer, uint256 idsAndAmountsHash) internal view returns (bytes32 messageHash) { + assembly ("memory-safe") { + // Retrieve the free memory pointer; memory will be left dirtied. + let m := mload(0x40) + + // Prepare initial components of message data: typehash, arbiter, & sponsor. + mstore(m, BATCH_COMPACT_TYPEHASH) + mstore(add(m, 0x20), caller()) // arbiter: msg.sender + mstore(add(m, 0x40), caller()) // sponsor: msg.sender + + // Next data segment copied from calldata: nonce & expires. + mstore(add(m, 0x60), calldataload(add(transfer, 0x20))) // nonce + mstore(add(m, 0x80), calldataload(add(transfer, 0x40))) // expires + + // Prepare final component of message data: idsAndAmountsHash. + mstore(add(m, 0xa0), idsAndAmountsHash) + + // Derive the message hash from the prepared data. + messageHash := keccak256(m, 0xc0) + } + } + + /** + * @notice Internal view function for deriving the EIP-712 message hash for + * a batch transfer or withdrawal. + * @param claim Pointer to the claim location in calldata. + * @param idsAndAmountsHash A hash of the ids and amounts. + * @return messageHash The EIP-712 compliant message hash. + */ + function toBatchMessageHash(uint256 claim, uint256 idsAndAmountsHash) internal view returns (bytes32 messageHash) { + assembly ("memory-safe") { + // Retrieve the free memory pointer; memory will be left dirtied. + let m := mload(0x40) + + // Prepare initial components of message data: typehash & arbiter. + mstore(m, BATCH_COMPACT_TYPEHASH) + mstore(add(m, 0x20), caller()) // arbiter: msg.sender + + // Next data segment copied from calldata: sponsor, nonce, expires. + calldatacopy(add(m, 0x40), add(claim, 0x40), 0x60) // sponsor, nonce, expires + + // Prepare final component of message data: idsAndAmountsHash. + mstore(add(m, 0xa0), idsAndAmountsHash) + + // Derive the message hash from the prepared data. + messageHash := keccak256(m, 0xc0) + } + } + + /** + * @notice Internal view function for deriving the EIP-712 message hash for + * a batch claim with a witness. + * @param claim Pointer to the claim location in calldata. + * @param idsAndAmountsHash A hash of the ids and amounts. + * @return messageHash The EIP-712 compliant message hash. + * @return typehash The EIP-712 typehash. + */ + function toBatchClaimWithWitnessMessageHash(uint256 claim, uint256 idsAndAmountsHash) internal view returns (bytes32 messageHash, bytes32 typehash) { + assembly ("memory-safe") { + // Retrieve the free memory pointer; memory will be left dirtied. + let m := mload(0x40) + + // Derive the pointer to the witness typestring. + let witnessTypestringPtr := add(claim, calldataload(add(claim, 0xc0))) + + // Retrieve the length of the witness typestring. + let witnessTypestringLength := calldataload(witnessTypestringPtr) + + // Prepare first component of typestring from four one-word fragments. + mstore(m, BATCH_COMPACT_TYPESTRING_FRAGMENT_ONE) + mstore(add(m, 0x20), BATCH_COMPACT_TYPESTRING_FRAGMENT_TWO) + mstore(add(m, 0x46), BATCH_COMPACT_TYPESTRING_FRAGMENT_FOUR) + mstore(add(m, 0x40), BATCH_COMPACT_TYPESTRING_FRAGMENT_THREE) + + // Copy remaining typestring data from calldata to memory. + calldatacopy(add(m, 0x66), add(0x20, witnessTypestringPtr), witnessTypestringLength) + + // Derive the typehash from the prepared data. + typehash := keccak256(m, add(0x66, witnessTypestringLength)) + + // Prepare initial components of message data: typehash & arbiter. + mstore(m, typehash) + mstore(add(m, 0x20), caller()) // arbiter: msg.sender + + // Next data segment copied from calldata: sponsor, nonce, expires. + calldatacopy(add(m, 0x40), add(claim, 0x40), 0x60) + + // Prepare final components of message data: idsAndAmountsHash & witness. + mstore(add(m, 0xa0), idsAndAmountsHash) + mstore(add(m, 0xc0), calldataload(add(claim, 0xa0))) // witness + + // Derive the message hash from the prepared data. + messageHash := keccak256(m, 0xe0) + } + } + + /** + * @notice Internal view function for deriving the EIP-712 message hash for + * a multichain claim. + * @param claim Pointer to the claim location in calldata. + * @param additionalOffset Additional offset from claim pointer to ID from most compact case. + * @param segmentTypehash The segment typehash. + * @param multichainCompactTypehash The multichain compact typehash. + * @param idsAndAmountsHash A hash of the ids and amounts. + * @return messageHash The EIP-712 compliant message hash. + */ + function toMultichainClaimMessageHash(uint256 claim, uint256 additionalOffset, bytes32 segmentTypehash, bytes32 multichainCompactTypehash, uint256 idsAndAmountsHash) + internal + view + returns (bytes32 messageHash) + { + assembly ("memory-safe") { + // Retrieve the free memory pointer; memory will be left dirtied. + let m := mload(0x40) + + // Store the idsAndAmounts hash at the beginning of the memory region. + mstore(add(m, 0x60), idsAndAmountsHash) + + // Prepare initial components of segment data: segment typehash, arbiter, & chainid. + mstore(m, segmentTypehash) + mstore(add(m, 0x20), caller()) // arbiter + mstore(add(m, 0x40), chainid()) + + // Determine if the segment typestring has a witness. + let hasWitness := iszero(eq(segmentTypehash, SEGMENT_TYPEHASH)) + + // If the segment has a witness, store the witness in memory.` + if hasWitness { mstore(add(m, 0x80), calldataload(add(claim, 0xa0))) } // witness + + // Derive the first segment hash from the prepared data and write it to memory. + mstore(m, keccak256(m, add(0x80, mul(0x20, hasWitness)))) // first segment hash + + // Derive the pointer to the additional chains and retrieve the length. + let additionalChainsPtr := add(claim, calldataload(add(add(claim, additionalOffset), 0xa0))) + let additionalChainsLength := shl(5, calldataload(additionalChainsPtr)) + + // Copy the segment hashes in the additional chains array from calldata to memory. + calldatacopy(add(m, 0x20), add(0x20, additionalChainsPtr), additionalChainsLength) + + // Derive hash of segment hashes from prepared data and write it to memory. + mstore(add(m, 0x80), keccak256(m, add(0x20, additionalChainsLength))) + + // Prepare next component of message data: multichain compact typehash. + mstore(m, multichainCompactTypehash) + + // Copy final message data components from calldata: sponsor, nonce & expires. + calldatacopy(add(m, 0x20), add(claim, 0x40), 0x60) + + // Derive the message hash from the prepared data. + messageHash := keccak256(m, 0xa0) + } + } + + /** + * @notice Internal view function for deriving the EIP-712 message hash for + * an exogenous multichain claim. + * @param claim Pointer to the claim location in calldata. + * @param additionalOffset Additional offset from claim pointer to ID from most compact case. + * @param segmentTypehash The segment typehash. + * @param multichainCompactTypehash The multichain compact typehash. + * @param idsAndAmountsHash A hash of the ids and amounts. + * @return messageHash The EIP-712 compliant message hash. + */ + function toExogenousMultichainClaimMessageHash(uint256 claim, uint256 additionalOffset, bytes32 segmentTypehash, bytes32 multichainCompactTypehash, uint256 idsAndAmountsHash) + internal + view + returns (bytes32 messageHash) + { + assembly ("memory-safe") { + // Retrieve the free memory pointer; memory will be left dirtied. + let m := mload(0x40) + + // Store the idsAndAmounts hash at the beginning of the memory region. + mstore(add(m, 0x60), idsAndAmountsHash) + + // Prepare initial components of segment data: segment typehash, arbiter, & chainid. + mstore(m, segmentTypehash) + mstore(add(m, 0x20), caller()) // arbiter + mstore(add(m, 0x40), chainid()) + + // Determine if the segment typestring has a witness. + let hasWitness := iszero(eq(segmentTypehash, SEGMENT_TYPEHASH)) + + // If the segment has a witness, store the witness in memory. + if hasWitness { mstore(add(m, 0x80), calldataload(add(claim, 0xa0))) } // witness + + // Derive the segment hash from the prepared data and write it to memory. + let segmentHash := keccak256(m, add(0x80, mul(0x20, hasWitness))) + + // Derive the pointer to the additional chains and retrieve the length. + let claimWithAdditionalOffset := add(claim, additionalOffset) + let additionalChainsPtr := add(claim, calldataload(add(claimWithAdditionalOffset, 0xa0))) + + // Retrieve the length of the additional chains array. + let additionalChainsLength := shl(5, calldataload(additionalChainsPtr)) + + // Derive the pointer to the additional chains data array in calldata. + let additionalChainsData := add(0x20, additionalChainsPtr) + + // Retrieve the chain index from calldata. + let chainIndex := shl(5, calldataload(add(claimWithAdditionalOffset, 0xc0))) + + // NOTE: rather than using extraOffset, consider breaking into two distinct + // loops or potentially even two calldatacopy operations based on chainIndex + let extraOffset := 0 + + // Iterate over the additional chains array and store each segment hash in memory. + for { let i := 0 } lt(i, additionalChainsLength) { i := add(i, 0x20) } { + mstore(add(m, i), calldataload(add(additionalChainsData, add(i, extraOffset)))) + // If current index matches chain index, store derived hash and increment offset. + if eq(i, chainIndex) { + extraOffset := 0x20 + mstore(add(m, add(i, extraOffset)), segmentHash) + } + } + + // Derive the hash of the segment hashes from the prepared data and write it to memory. + mstore(add(m, 0x80), keccak256(m, add(0x20, additionalChainsLength))) + + // Prepare next component of message data: multichain compact typehash. + mstore(m, multichainCompactTypehash) + + // Copy final message data components from calldata: sponsor, nonce & expires. + calldatacopy(add(m, 0x20), add(claim, 0x40), 0x60) + + // Derive the message hash from the prepared data. + messageHash := keccak256(m, 0xa0) + } + } + + /** + * @notice Internal view function for deriving the EIP-712 message hash for + * a simple multichain claim. + * @param claim Pointer to the claim location in calldata. + * @param idsAndAmountsHash A hash of the ids and amounts (formatted as a uint256). + * @return messageHash The EIP-712 compliant message hash. + */ + function toSimpleMultichainClaimMessageHash(uint256 claim, uint256 idsAndAmountsHash) internal view returns (bytes32 messageHash) { + // Derive the message hash from the claim and idsAndAmounts hash. + return claim.toMultichainClaimMessageHash(uint256(0).asStubborn(), SEGMENT_TYPEHASH, MULTICHAIN_COMPACT_TYPEHASH, idsAndAmountsHash); + } + + /** + * @notice Internal view function for deriving the EIP-712 message hash for + * a qualified multichain claim. + * @param claim Pointer to the claim location in calldata. + * @param idsAndAmountsHash A hash of the ids and amounts (formatted as a uint256). + * @return messageHash The EIP-712 compliant message hash. + */ + function toQualifiedMultichainClaimMessageHash(uint256 claim, uint256 idsAndAmountsHash) internal view returns (bytes32 messageHash) { + // Derive the message hash from the claim and idsAndAmounts hash. + return claim.toMultichainClaimMessageHash(uint256(0x40).asStubborn(), SEGMENT_TYPEHASH, MULTICHAIN_COMPACT_TYPEHASH, idsAndAmountsHash); + } + + /** + * @notice Internal view function for deriving the EIP-712 message hash for + * a simple exogenous multichain claim. + * @param claim Pointer to the claim location in calldata. + * @param idsAndAmountsHash A hash of the ids and amounts. + * @return messageHash The EIP-712 compliant message hash. + */ + function toSimpleExogenousMultichainClaimMessageHash(uint256 claim, uint256 idsAndAmountsHash) internal view returns (bytes32 messageHash) { + // Derive the message hash from the claim and idsAndAmounts hash. + return claim.toExogenousMultichainClaimMessageHash(uint256(0).asStubborn(), SEGMENT_TYPEHASH, MULTICHAIN_COMPACT_TYPEHASH, idsAndAmountsHash); + } + + /** + * @notice Internal view function for deriving the EIP-712 message hash for + * a qualified exogenous multichain claim. + * @param claim Pointer to the claim location in calldata. + * @param idsAndAmountsHash A hash of the ids and amounts. + * @return messageHash The EIP-712 compliant message hash. + */ + function toExogenousQualifiedMultichainClaimMessageHash(uint256 claim, uint256 idsAndAmountsHash) internal view returns (bytes32 messageHash) { + // Derive the message hash from the claim and idsAndAmounts hash. + return claim.toExogenousMultichainClaimMessageHash(uint256(0x40).asStubborn(), SEGMENT_TYPEHASH, MULTICHAIN_COMPACT_TYPEHASH, idsAndAmountsHash); + } + + /** + * @notice Internal pure function for deriving the EIP-712 typehashes for + * multichain claims. + * @param claim Pointer to the claim location in calldata. + * @return segmentTypehash The segment typehash. + * @return multichainCompactTypehash The multichain compact typehash. + */ + function toMultichainTypehashes(uint256 claim) internal pure returns (bytes32 segmentTypehash, bytes32 multichainCompactTypehash) { + assembly ("memory-safe") { + // Retrieve the free memory pointer; memory will be left dirtied. + let m := mload(0x40) + + // Derive the pointer to the witness typestring and retrieve the length. + let witnessTypestringPtr := add(claim, calldataload(add(claim, 0xc0))) + let witnessTypestringLength := calldataload(witnessTypestringPtr) + + // Prepare the first five fragments of the multichain compact typehash. + mstore(m, MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_ONE) + mstore(add(m, 0x20), MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_TWO) + mstore(add(m, 0x40), MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_THREE) + mstore(add(m, 0x76), MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_FIVE) + mstore(add(m, 0x60), MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_FOUR) + + // Copy remaining witness typestring from calldata to memory. + calldatacopy(add(m, 0x96), add(0x20, witnessTypestringPtr), witnessTypestringLength) + + // Derive the segment typehash and multichain compact typehash from the prepared data. + segmentTypehash := keccak256(add(m, 0x53), add(0x43, witnessTypestringLength)) + multichainCompactTypehash := keccak256(m, add(0x96, witnessTypestringLength)) + } + } + + /** + * @notice Internal pure function for deriving the EIP-712 message hash for + * a qualification. + * @param claim Pointer to the claim location in calldata. + * @param messageHash A bytes32 representing the message hash. + * @param witnessOffset Additional offset from claim pointer to witness from most compact case. + * @return qualificationMessageHash The EIP-712 compliant message hash. + */ + function toQualificationMessageHash(uint256 claim, bytes32 messageHash, uint256 witnessOffset) internal pure returns (bytes32 qualificationMessageHash) { + assembly ("memory-safe") { + // Retrieve the free memory pointer; memory will be left dirtied. + let m := mload(0x40) + + // Derive the pointer to the qualification payload and retrieve the length. + let qualificationPayloadPtr := add(claim, calldataload(add(claim, add(0xc0, witnessOffset)))) + let qualificationPayloadLength := calldataload(qualificationPayloadPtr) + + // Prepare first qualification message data component: qualification typehash. + mstore(m, calldataload(add(claim, add(0xa0, witnessOffset)))) // qualificationTypehash + + // Prepare second qualification message data component: message hash. + mstore(add(m, 0x20), messageHash) + + // Copy remaining qualification payload from calldata to memory. + calldatacopy(add(m, 0x40), add(0x20, qualificationPayloadPtr), qualificationPayloadLength) + + // Derive the qualification message hash from the prepared data. + qualificationMessageHash := keccak256(m, add(0x40, qualificationPayloadLength)) + } + } + + /** + * @notice Internal pure function for deriving the EIP-712 message hash for + * a single id and amount. + * @param claim Pointer to the claim location in calldata. + * @param additionalOffset Additional offset from claim pointer to ID from most compact case. + * @return idsAndAmountsHash The hash of the id and amount. + */ + function toSingleIdAndAmountHash(uint256 claim, uint256 additionalOffset) internal pure returns (uint256 idsAndAmountsHash) { + assembly ("memory-safe") { + // Derive the pointer to the claim with additional offset. + let claimWithAdditionalOffset := add(claim, additionalOffset) + + // Store the id and amount at the beginning of the memory region. + mstore(0, calldataload(add(claimWithAdditionalOffset, 0xc0))) + mstore(0x20, calldataload(add(claimWithAdditionalOffset, 0xe0))) + + // Derive the idsAndAmounts hash from the stored data. + idsAndAmountsHash := keccak256(0, 0x40) + } + } + + /** + * @notice Internal pure function for deriving the hash of the ids and amounts. + * @param claims An array of BatchClaimComponent structs. + * @return idsAndAmountsHash The hash of the ids and amounts. + */ + function toIdsAndAmountsHash(BatchClaimComponent[] calldata claims) internal pure returns (uint256 idsAndAmountsHash) { + // Retrieve the total number of ids in the claims array. + uint256 totalIds = claims.length; + + // Prepare a memory region for storing the ids and amounts. + bytes memory idsAndAmounts = new bytes(totalIds * 0x40); + + unchecked { + // Iterate over the claims array. + for (uint256 i = 0; i < totalIds; ++i) { + // Navigate to the current claim component in calldata. + BatchClaimComponent calldata claimComponent = claims[i]; + + assembly ("memory-safe") { + // Derive the offset to the current position in the memory region. + let extraOffset := add(add(idsAndAmounts, 0x20), mul(i, 0x40)) + + // Retrieve and store the id and amount at the current position. + mstore(extraOffset, calldataload(claimComponent)) + mstore(add(extraOffset, 0x20), calldataload(add(claimComponent, 0x20))) + } + } + } + + assembly ("memory-safe") { + // Derive the hash of the ids and amounts from the prepared data. + idsAndAmountsHash := keccak256(add(idsAndAmounts, 0x20), mload(idsAndAmounts)) + } + } + + /** + * @notice Internal pure function for deriving the hash of the ids and amounts. + * @param claims An array of SplitBatchClaimComponent structs. + * @return idsAndAmountsHash The hash of the ids and amounts. + */ + function toSplitIdsAndAmountsHash(SplitBatchClaimComponent[] calldata claims) internal pure returns (uint256 idsAndAmountsHash) { + // Retrieve the total number of ids in the claims array. + uint256 totalIds = claims.length; + + // Prepare a memory region for storing the ids and amounts. + bytes memory idsAndAmounts = new bytes(totalIds * 0x40); + + unchecked { + // Iterate over the claims array. + for (uint256 i = 0; i < totalIds; ++i) { + // Navigate to the current claim component in calldata. + SplitBatchClaimComponent calldata claimComponent = claims[i]; + + assembly ("memory-safe") { + // Derive the offset to the current position in the memory region. + let extraOffset := add(add(idsAndAmounts, 0x20), mul(i, 0x40)) + + // Retrieve and store the id and amount at the current position. + mstore(extraOffset, calldataload(claimComponent)) // id + mstore(add(extraOffset, 0x20), calldataload(add(claimComponent, 0x20))) // amount + } + } + } + + assembly ("memory-safe") { + // Derive the hash of the ids and amounts from the prepared data. + idsAndAmountsHash := keccak256(add(idsAndAmounts, 0x20), mload(idsAndAmounts)) + } + } + + /** + * @notice Internal pure function for retrieving EIP-712 typehashes where no witness data is + * provided, returning the corresponding typehash based on the index provided. The available + * typehashes are: + * - 0: COMPACT_TYPEHASH + * - 1: BATCH_COMPACT_TYPEHASH + * - 2: MULTICHAIN_COMPACT_TYPEHASH + * @param i The index of the EIP-712 typehash to retrieve. + * @return typehash The corresponding EIP-712 typehash. + */ + function typehashes(uint256 i) internal pure returns (bytes32 typehash) { + assembly ("memory-safe") { + // Retrieve and cache the free memory pointer. + let m := mload(0x40) + + // Prepare the typehashes in memory. + mstore(0, COMPACT_TYPEHASH) + mstore(0x20, BATCH_COMPACT_TYPEHASH) + mstore(0x40, MULTICHAIN_COMPACT_TYPEHASH) + + // Retrieve the typehash from memory based on the provided index. + typehash := mload(shl(5, i)) + + // Restore the free memory pointer. + mstore(0x40, m) + } + } +} diff --git a/src/lib/IdLib.sol b/src/lib/IdLib.sol new file mode 100644 index 0000000..57905c1 --- /dev/null +++ b/src/lib/IdLib.sol @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { ResetPeriod } from "../types/ResetPeriod.sol"; +import { Scope } from "../types/Scope.sol"; +import { Lock } from "../types/Lock.sol"; +import { MetadataLib } from "./MetadataLib.sol"; +import { EfficiencyLib } from "./EfficiencyLib.sol"; +import { SignatureCheckerLib } from "solady/utils/SignatureCheckerLib.sol"; +import { CompactCategory } from "../types/CompactCategory.sol"; + +import { EfficientHashLib } from "solady/utils/EfficientHashLib.sol"; + +/** + * @title IdLib + * @notice Libray contract implementing logic for deriving IDs for allocators and + * for resource locks, converting between various IDs, and for extracting details + * related to those IDs. This includes logic for registering allocators and for + * assigning them an allocator ID. + */ +library IdLib { + using IdLib for uint96; + using IdLib for uint256; + using IdLib for address; + using IdLib for ResetPeriod; + using MetadataLib for Lock; + using EfficiencyLib for bool; + using EfficiencyLib for uint8; + using EfficiencyLib for uint96; + using EfficiencyLib for uint256; + using EfficiencyLib for address; + using EfficiencyLib for ResetPeriod; + using EfficiencyLib for Scope; + using SignatureCheckerLib for address; + using EfficientHashLib for bytes; + + error NoAllocatorRegistered(uint96 allocatorId); + error AllocatorAlreadyRegistered(uint96 allocatorId, address allocator); + + // Storage slot seed for mapping allocator IDs to allocator addresses. + uint256 private constant _ALLOCATOR_BY_ALLOCATOR_ID_SLOT_SEED = 0x000044036fc77deaed2300000000000000000000000; + + // keccak256(bytes("AllocatorRegistered(uint96,address)")). + uint256 private constant _ALLOCATOR_REGISTERED_EVENT_SIGNATURE = 0xc54dcaa67a8fd7b4a9aa6fd57351934c792613d5ec1acbd65274270e6de8f7e4; + + // Error selectors for NoAllocatorRegistered and AllocatorAlreadyRegistered. + uint256 private constant _NO_ALLOCATOR_REGISTERED_ERROR_SIGNATURE = 0xcf90c3a8; + uint256 private constant _ALLOCATOR_ALREADY_REGISTERED_ERROR_SIGNATURE = 0xc18b0e97; + + /** + * @notice Internal function for registering an allocator. Derives an ID for the + * allocator and stores the allocator's address for that ID, reverting if an + * allocator has already been registered for the ID in question. + * @param allocator The address to register as an allocator. + * @return allocatorId The derived ID for the registered allocator. + */ + function register(address allocator) internal returns (uint96 allocatorId) { + // Derive the allocator ID for the provided allocator address. + allocatorId = allocator.usingAllocatorId(); + + assembly ("memory-safe") { + // Derive storage slot for allocator registration by ID. + let allocatorSlot := or(_ALLOCATOR_BY_ALLOCATOR_ID_SLOT_SEED, allocatorId) + + // Retrieve the allocator value at the derived storage slot. + let registeredAllocator := sload(allocatorSlot) + + // Revert if an allocator has already been registered for the ID. + if registeredAllocator { + mstore(0, _ALLOCATOR_ALREADY_REGISTERED_ERROR_SIGNATURE) + mstore(0x20, allocatorId) + mstore(0x40, registeredAllocator) + revert(0x1c, 0x44) + } + + // Store allocator address (sanitize first as an added precaution). + allocator := shr(0x60, shl(0x60, allocator)) + sstore(allocatorSlot, allocator) + + // Emit AllocatorRegistered(allocatorId, allocator) event. + mstore(0x00, allocatorId) + mstore(0x20, allocator) + log1(0x00, 0x40, _ALLOCATOR_REGISTERED_EVENT_SIGNATURE) + } + } + + /** + * @notice Internal view function for constructing a resource lock ID assuming that the + * provided allocator has been registered. Derives the allocator ID from the registered + * allocator, and combines it with the provided scope, reset period, and token address + * to form a single ID value. Reverts if the allocator is not registered. + * @param token The address of the underlying token. + * @param scope The scope of the resource lock (multichain or single chain). + * @param resetPeriod The duration after which the resource lock can be reset. + * @param allocator The address of the allocator mediating the resource lock. + * @return id The derived resource lock ID. + */ + function toIdIfRegistered(address token, Scope scope, ResetPeriod resetPeriod, address allocator) internal view returns (uint256 id) { + // Derive the allocator ID for the provided allocator address. + uint96 allocatorId = allocator.toAllocatorIdIfRegistered(); + + // Derive resource lock ID (pack scope, reset period, allocator ID, & token). + id = ((scope.asUint256() << 255) | (resetPeriod.asUint256() << 252) | (allocatorId.asUint256() << 160) | token.asUint256()); + } + + /** + * @notice Internal view function for retrieving an allocator's address from their ID. + * Reverts if no allocator is registered with the provided ID. + * @param allocatorId The ID to look up. + * @return allocator The registered allocator's address. + */ + function toRegisteredAllocator(uint96 allocatorId) internal view returns (address allocator) { + assembly ("memory-safe") { + // Retrieve allocator from storage based on allocator ID. + allocator := sload(or(_ALLOCATOR_BY_ALLOCATOR_ID_SLOT_SEED, allocatorId)) + + // Revert if no registered allocator is located. + if iszero(allocator) { + mstore(0, _NO_ALLOCATOR_REGISTERED_ERROR_SIGNATURE) + mstore(0x20, allocatorId) + revert(0x1c, 0x24) + } + } + } + + /** + * @notice Internal view function that verifies an allocator is registered and + * returns their ID. Derives the allocator ID from the address and reverts if the + * stored address doesn't exactly match the provided one. + * @param allocator The address to check registration for. + * @return allocatorId The derived allocator ID. + */ + function toAllocatorIdIfRegistered(address allocator) internal view returns (uint96 allocatorId) { + // Derive the allocator ID for the provided allocator address. + allocatorId = allocator.usingAllocatorId(); + + assembly ("memory-safe") { + // Revert on any difference between original address and stored address. + if xor(allocator, sload(or(_ALLOCATOR_BY_ALLOCATOR_ID_SLOT_SEED, allocatorId))) { + mstore(0, _NO_ALLOCATOR_REGISTERED_ERROR_SIGNATURE) + mstore(0x20, allocatorId) + revert(0x1c, 0x24) + } + } + } + + /** + * @notice Internal view function for extracting and validating an allocator ID from + * a resource lock ID. Reverts if the allocator is not registered. + * @param id The resource lock ID to extract from. + * @return allocatorId The validated allocator ID. + */ + function toRegisteredAllocatorId(uint256 id) internal view returns (uint96 allocatorId) { + allocatorId = id.toAllocatorId(); + allocatorId.mustHaveARegisteredAllocator(); + } + + /** + * @notice Internal view function that checks if an allocator ID has a registered + * allocator. Reverts if no allocator is registered. + * @param allocatorId The allocator ID to check. + */ + function mustHaveARegisteredAllocator(uint96 allocatorId) internal view { + assembly ("memory-safe") { + // NOTE: consider an SLOAD bypass for a fully compact allocator + if iszero(sload(or(_ALLOCATOR_BY_ALLOCATOR_ID_SLOT_SEED, allocatorId))) { + mstore(0, _NO_ALLOCATOR_REGISTERED_ERROR_SIGNATURE) + mstore(0x20, allocatorId) + revert(0x1c, 0x24) + } + } + } + + /** + * @notice Internal view function that checks if an allocator can be registered. + * Returns true if any of the following are true: + * - The caller is the allocator + * - The allocator address contains code + * - The proof is a valid create2 deployment that derives the allocator address + * (e.g. proof must take the form of 0xff ++ factory ++ salt ++ initcode hash) + * @param allocator The address to check. + * @param proof An 85-byte value containing create2 address derivation parameters. + * @return Whether the allocator can be registered. + */ + function canBeRegistered(address allocator, bytes calldata proof) internal view returns (bool) { + return (msg.sender == allocator).or(allocator.code.length > 0).or(proof.length == 85 && (proof[0] == 0xff).and(allocator == address(uint160(uint256(proof.hashCalldata()))))); + } + + /** + * @notice Internal view function for retrieving an allocator's address from a + * resource lock ID. Reverts if no allocator has been registered for the ID. + * @param id The resource lock ID to extract the allocator from. + * @return allocator The address of the allocator. + */ + function toAllocator(uint256 id) internal view returns (address allocator) { + allocator = id.toAllocatorId().toRegisteredAllocator(); + } + + /** + * @notice Internal view function for extracting the full Lock struct from a + * resource lock ID. + * @param id The resource lock ID to extract from. + * @return lock A Lock struct containing token, allocator, reset period, and scope. + */ + function toLock(uint256 id) internal view returns (Lock memory lock) { + lock.token = id.toToken(); + lock.allocator = id.toAllocator(); + lock.resetPeriod = id.toResetPeriod(); + lock.scope = id.toScope(); + } + + /** + * @notice Internal pure function for extracting the address of the + * underlying token from a resource lock ID. + * @param id The resource lock ID to extract from. + * @return The underlying token address. + */ + function toToken(uint256 id) internal pure returns (address) { + return id.asSanitizedAddress(); + } + + /** + * @notice Internal pure function for creating a new resource lock ID with a + * different token address. + * @param id The resource lock ID to modify. + * @param token The new token address. + * @return updatedId The modified resource lock ID. + */ + function withReplacedToken(uint256 id, address token) internal pure returns (uint256 updatedId) { + assembly ("memory-safe") { + updatedId := or(shl(160, shr(160, id)), shr(96, shl(96, token))) + } + } + + /** + * @notice Internal pure function for extracting the scope from a resource lock ID. + * @param id The resource lock ID to extract from. + * @return scope The scope (uppermost bit). + */ + function toScope(uint256 id) internal pure returns (Scope scope) { + assembly ("memory-safe") { + // extract uppermost bit + scope := shr(255, id) + } + } + + /** + * @notice Internal pure function for extracting the reset period from a resource + * lock ID. + * @param id The resource lock ID to extract from. + * @return resetPeriod The reset period (bits 252-254). + */ + function toResetPeriod(uint256 id) internal pure returns (ResetPeriod resetPeriod) { + assembly ("memory-safe") { + // extract 2nd, 3rd & 4th uppermost bits + resetPeriod := and(shr(252, id), 7) + } + } + + /** + * @notice Internal pure function for extracting the compact flag from a resource + * lock ID. The compact flag is a 4-bit component of the allocator ID. + * @param id The resource lock ID to extract from. + * @return compactFlag The compact flag (bits 248-251). + */ + function toCompactFlag(uint256 id) internal pure returns (uint8 compactFlag) { + assembly ("memory-safe") { + // extract 5th, 6th, 7th & 8th uppermost bits + compactFlag := and(shr(248, id), 15) + } + } + + /** + * @notice Internal pure function for extracting the allocator ID from a resource + * lock ID. The allocator ID is a 92-bit value, with the first 4 bits representing + * the compact flag and the last 88 bits matching the last 88 bits of the underlying + * allocator, but is represented by a uint96 as solidity only supports uint values + * for multiples of 8 bits. + * @param id The resource lock ID to extract from. + * @return allocatorId The allocator ID (bits 160-251). + */ + function toAllocatorId(uint256 id) internal pure returns (uint96 allocatorId) { + assembly ("memory-safe") { + // extract bits 5-96 + allocatorId := shr(164, shl(4, id)) + } + } + + /** + * @notice Internal pure function for converting a reset period to its duration in + * seconds. There are eight distinct reset periods ranging from one second to + * thirty days. Specific periods include some additional padding: + * - One hour is padded by five minutes + * - Seven days is padded by one hour + * @dev No bounds check performed; ensure that the enum value is in range. + * @param resetPeriod The reset period to convert. + * @return duration The duration in seconds. + */ + function toSeconds(ResetPeriod resetPeriod) internal pure returns (uint256 duration) { + assembly ("memory-safe") { + // Bitpacked durations in 24-bit segments: + // 278d00 094890 015180 000f3c 000258 00003c 00000f 000001 + // 30 days 7 days 1 day 1 hour 10 min 1 min 15 sec 1 sec + let bitpacked := 0x278d00094890015180000f3c00025800003c00000f000001 + + // Shift right by period * 24 bits & mask the least significant 24 bits. + duration := and(shr(mul(resetPeriod, 24), bitpacked), 0xffffff) + } + } + + /** + * @notice Internal pure function for computing an address's compact flag. The flag + * is a 4-bit value that represents how "compact" the address of an allocator is. A + * fully "compact" allocator address will have nine leading zero bytes, or eighteen + * leading zero nibbles. To be considered even partially compact, the account must + * have at least two leading zero bytes, or four leading zero nibbles. The full + * scoring formula is therefore: + * - 0-3 leading zero nibbles: 0 + * - 4-17 leading zero nibbles: number of leading zeros minus 3 + * - 18+ leading zero nibbles: 15 + * @param allocator The address to compute the flag for. + * @return compactFlag The computed compact flag. + */ + function toCompactFlag(address allocator) internal pure returns (uint8 compactFlag) { + assembly ("memory-safe") { + // Extract the uppermost 72 bits of the address. + let x := shr(168, shl(96, allocator)) + + // Propagate the highest set bit. + x := or(x, shr(1, x)) + x := or(x, shr(2, x)) + x := or(x, shr(4, x)) + x := or(x, shr(8, x)) + x := or(x, shr(16, x)) + x := or(x, shr(32, x)) + + // Count set bits to derive most significant bit in the last byte. + let y := sub(x, and(shr(1, x), 0x5555555555555555)) + y := add(and(y, 0x3333333333333333), and(shr(2, y), 0x3333333333333333)) + y := and(add(y, shr(4, y)), 0x0f0f0f0f0f0f0f0f) + y := add(y, shr(8, y)) + y := add(y, shr(16, y)) + y := add(y, shr(32, y)) + + // Look up final value in the sequence. + compactFlag := and(shr(and(sub(72, and(y, 127)), not(3)), 0xfedcba9876543210000), 15) + } + } + + /** + * @notice Internal pure function for computing an allocator's ID from their address. + * Combines the compact flag (4 bits) with the last 88 bits of the address. + * @param allocator The address to compute the ID for. + * @return allocatorId The computed allocator ID. + */ + function usingAllocatorId(address allocator) internal pure returns (uint96 allocatorId) { + uint8 compactFlag = allocator.toCompactFlag(); + + assembly ("memory-safe") { + allocatorId := or(shl(88, compactFlag), shr(168, shl(168, allocator))) + } + } + + /** + * @notice Internal pure function for deriving a resource lock ID from a Lock struct. + * The ID consists of: + * - Bit 255: scope + * - Bits 252-254: reset period + * - Bits 160-251: allocator ID (first 4 bits are compact flag, next 88 from allocator address) + * - Bits 0-159: token address + * @dev Note that this will return an ID even if the allocator is unregistered. + * @param lock The Lock struct containing the resource lock's components. + * @return id The derived resource lock ID. + */ + function toId(Lock memory lock) internal pure returns (uint256 id) { + id = ((lock.scope.asUint256() << 255) | (lock.resetPeriod.asUint256() << 252) | (lock.allocator.usingAllocatorId().asUint256() << 160) | lock.token.asUint256()); + } +} diff --git a/src/lib/MetadataLib.sol b/src/lib/MetadataLib.sol new file mode 100644 index 0000000..074e937 --- /dev/null +++ b/src/lib/MetadataLib.sol @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { Lock } from "../types/Lock.sol"; +import { ResetPeriod } from "../types/ResetPeriod.sol"; +import { Scope } from "../types/Scope.sol"; +import { IdLib } from "./IdLib.sol"; +import { EfficiencyLib } from "./EfficiencyLib.sol"; +import { LibString } from "solady/utils/LibString.sol"; +import { MetadataReaderLib } from "solady/utils/MetadataReaderLib.sol"; + +/** + * @title MetadataLib + * @notice Libray contract implementing logic for deriving and displaying + * ERC6909 metadata as well as metadata specific to various underlying tokens. + */ +library MetadataLib { + using MetadataLib for address; + using MetadataLib for string; + using IdLib for Lock; + using IdLib for ResetPeriod; + using EfficiencyLib for address; + using LibString for uint256; + using LibString for address; + using MetadataReaderLib for address; + using MetadataLib for ResetPeriod; + using MetadataLib for Scope; + + function toString(ResetPeriod resetPeriod) internal pure returns (string memory) { + if (resetPeriod == ResetPeriod.OneSecond) { + return "One second"; + } else if (resetPeriod == ResetPeriod.FifteenSeconds) { + return "Fifteen seconds"; + } else if (resetPeriod == ResetPeriod.OneMinute) { + return "One minute"; + } else if (resetPeriod == ResetPeriod.TenMinutes) { + return "Ten minutes"; + } else if (resetPeriod == ResetPeriod.OneHourAndFiveMinutes) { + return "One hour and five minutes"; + } else if (resetPeriod == ResetPeriod.OneDay) { + return "One day"; + } else if (resetPeriod == ResetPeriod.SevenDaysAndOneHour) { + return "Seven days and one hour"; + } else if (resetPeriod == ResetPeriod.ThirtyDays) { + return "Thirty days"; + } else { + revert("Unknown reset period"); + } + } + + function toString(Scope scope) internal pure returns (string memory) { + if (scope == Scope.Multichain) { + return "Multichain"; + } else if (scope == Scope.ChainSpecific) { + return "Chain-specific"; + } else { + revert("Unknown scope"); + } + } + + function toURI(Lock memory lock, uint256 id) internal view returns (string memory uri) { + string memory tokenAddress = lock.token.isNullAddress() ? "Native Token" : lock.token.toHexStringChecksummed(); + string memory allocator = lock.allocator.toHexStringChecksummed(); + string memory resetPeriod = lock.resetPeriod.toString(); + string memory scope = lock.scope.toString(); + string memory tokenName = lock.token.readNameWithDefaultValue(); + string memory tokenSymbol = lock.token.readSymbolWithDefaultValue(); + string memory tokenDecimals = uint256(lock.token.readDecimals()).toString(); + + string memory name = string.concat("{\"name\": \"Compact ", tokenSymbol, "\","); + string memory description = string.concat("\"description\": \"Compact ", tokenName, " (", tokenAddress, ") resource lock with allocator ", allocator, " and reset period of ", resetPeriod, "\","); + string memory attributes = string.concat( + "\"attributes\": [", + toAttributeString("ID", id.toString(), false), + toAttributeString("Token Address", tokenAddress, false), + toAttributeString("Token Name", tokenName, false), + toAttributeString("Token Symbol", tokenSymbol, false), + toAttributeString("Token Decimals", tokenDecimals, false), + toAttributeString("Allocator", allocator, false), + toAttributeString("Scope", scope, false), + toAttributeString("Reset Period", resetPeriod, true), + "]}" + ); + + // Note: this just returns a default image; replace with a dynamic image based on attributes + string memory image = + "\"image\": \"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDIzLjAuNSwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgNDkyIDQ5MiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDkyIDQ5MjsiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPGcgaWQ9Ik1hc3Rlcl9MYXllcl8yIj4NCjwvZz4NCjxnIGlkPSJMYXllcl8xIj4NCgk8Zz4NCgkJPGc+DQoJCQk8Zz4NCgkJCQk8Zz4NCgkJCQkJPHBhdGggc3R5bGU9ImZpbGwtcnVsZTpldmVub2RkO2NsaXAtcnVsZTpldmVub2RkO2ZpbGw6IzIxMjEyMTsiIGQ9Ik0zMjEuMzA4LDI5NC44NjRjNS4zNTIsNS4zMjgsOS40NTYsMTIuMTQ0LDE1Ljc5Miw4LjgzMg0KCQkJCQkJYzIuNDQ4LTEuMjcyLDUuMDY0LTMuMDk2LDcuMzItNS4yNTZjMy43NDQtMy41NzYsOC4yNTYtOS41MjgsNC42NTYtMTQuMjhjLTEyLjQ1Ni0xMS45NzYtMzYuMzg0LTMyLjExMi0zNi40NTYtMzIuMTYNCgkJCQkJCWw3LjU2LTguNTY4YzAuMDI0LDAuMDI0LDUuMTYsNC41MzYsMTEuODMyLDEwLjgyNGM4LjY4OCw4LjIwOCwyMC44NTYsMTYuMiwyNi43MzYsMjQuNDA4DQoJCQkJCQljMy4zMTIsNC42MDgsMi42MTYsMTIuNzQ0LDAuODY0LDE3LjUyYy0xLjM5MiwzLjg0LTQuMTA0LDcuNDY0LTcuMzIsMTAuNTM2Yy0zLjAyNCwyLjkwNC02LjYsNS40LTkuOTYsNy4xMjgNCgkJCQkJCWMtMy4zODQsMS43NTItNi43OTIsMi43Ni05LjY5NiwyLjc4NGMtMC4wOTYsMC40NTYtMC4yMTYsMC45MzYtMC4zMzYsMS4zOTJjLTAuOTYsMy4yNC0zLjAyNCw2LjA3Mi01LjYxNiw4LjQNCgkJCQkJCWMtMi4zMjgsMi4wODgtNS4xMzYsMy44MTYtNy45NDQsNS4wNjRjLTMuMDcyLDEuMzQ0LTYuMjg4LDIuMTEyLTkuMTY4LDIuMTZjLTAuMDk2LDAuOTM2LTAuMjg4LDEuODQ4LTAuNTUyLDIuNzYNCgkJCQkJCWMtMC45NiwzLjI0LTMuMDI0LDYuMDcyLTUuNjE2LDguNGMtMi4zMjgsMi4wODgtNS4xMzYsMy44MTYtNy45NDQsNS4wNjRjLTQuMTI4LDEuODI0LTguNTQ0LDIuNTY4LTEyLDEuOTY4DQoJCQkJCQljLTAuMTIsMS4yMjQtMC4zNiwyLjQtMC42OTYsMy41MDR2MC4wMjRjLTEuMDMyLDMuMzg0LTMsNi4yNC01LjUyLDguMzUyYy0yLjUyLDIuMTEyLTUuNTkyLDMuNDgtOC44NTYsMy45MzYNCgkJCQkJCWMtMy45NiwwLjU1Mi04LjE2LTAuMjQtMTEuOTA0LTIuNjg4Yy0xLjAzMi0wLjY3Mi0yLjE2LTEuNTM2LTMuNDgtMi41OTJsLTAuNzQ0LTAuNTc2bC0xMS4xNi04LjYxNmw2Ljk2LTkuMDI0bDExLjE2LDguNjE2DQoJCQkJCQlsMC43NDQsMC41NzZjMS4wMzIsMC43OTIsMS44OTYsMS40ODgsMi43ODQsMi4wNGMxLjI5NiwwLjg2NCwyLjczNiwxLjEyOCw0LjA4LDAuOTZjMS4xMjgtMC4xNjgsMi4xODQtMC42NDgsMy4wNzItMS4zOTINCgkJCQkJCWMwLjg2NC0wLjcyLDEuNTYtMS43MjgsMS45Mi0yLjkwNGwwLDBjMC40NTYtMS41NiwwLjM4NC0zLjUwNC0wLjQ1Ni01Ljc2Yy05LjUyOC0xMy4yOTYtMjkuNDQ4LTI5LjQyNC0yOS40OTYtMjkuNDcyDQoJCQkJCQlsNy4yLTguODU2YzAuMDQ4LDAuMDI0LDguMTEyLDYuNTc2LDE2Ljc1MiwxNS4wMjRjMi4zMDQsMi4yNTYsNC44NDgsNC43NTIsNy41MTIsNy4xMjhjMC40OCwwLjQzMiwwLjk4NCwwLjg2NCwxLjQ2NCwxLjI5Ng0KCQkJCQkJbDAsMGwwLDBjMC4wOTYsMC4wOTYsMC4yMTYsMC4xOTIsMC4zMTIsMC4yODhjMC42MjQsMC41NTIsMS4yNDgsMS4xMjgsMS44NzIsMS43MDRjMi4xMTIsMS44OTYsNC4yLDMuODE2LDYuMzg0LDUuNDk2DQoJCQkJCQljMi41OTIsMS44NDgsMi41NDQsMi4yMzIsNS40OTYsMS4zNDRjMC42MjQtMC4xOTIsMS4yOTYtMC41MjgsMi4wMTYtMC44NGMxLjc3Ni0wLjc2OCwzLjUwNC0xLjg0OCw0Ljg5Ni0zLjA5Ng0KCQkJCQkJYzEuMTI4LTEuMDMyLDEuOTkyLTIuMTEyLDIuMzA0LTMuMTY4YzAuMjQtMC44NCwwLjA3Mi0xLjg0OC0wLjc0NC0yLjk3NmMtOS41NzYtMTMuMzItMzUuOTA0LTM2LjQ1Ni0zNS45NzYtMzYuNTI4bDcuNTYtOC41NjgNCgkJCQkJCWMwLjA0OCwwLjA0OCwxNC42ODgsMTIuOTEyLDI2LjYxNiwyNS40ODhjMy4yNCwzLjE5Miw4LjA2NCw3LjU2LDExLjU0NCwxMC4yNzJjMS4yNzIsMC45MTIsMi4xNiwyLjA4OCw0LjA4LDEuNDE2DQoJCQkJCQljMC44MTYtMC4yODgsMS44NDgtMC42OTYsMy0xLjJjMS43NzYtMC43NjgsMy41MDQtMS44NDgsNC44OTYtMy4wOTZjMS4xMjgtMS4wMDgsMS45OTItMi4xMTIsMi4zMDQtMy4xNjgNCgkJCQkJCWMwLjI0LTAuODQsMC4wNzItMS44NDgtMC43NDQtM2MtOS41NzYtMTMuMzItMzUuOTA0LTM2LjQ1Ni0zNS45NzYtMzYuNTI4bDcuNTYtOC41NjgNCgkJCQkJCUMyOTIuMjIsMjY2LjY4OCwzMDkuMDQ0LDI4MS40OTYsMzIxLjMwOCwyOTQuODY0eiIvPg0KCQkJCTwvZz4NCgkJCQk8Zz4NCgkJCQkJPHBhdGggc3R5bGU9ImZpbGwtcnVsZTpldmVub2RkO2NsaXAtcnVsZTpldmVub2RkO2ZpbGw6IzIxMjEyMTsiIGQ9Ik00MjkuMDIsMjU0LjQyNEwzOTMuNjkyLDEyOS43MmwtMS41MzYtNS40NDhsLTUuNDQ4LDEuNDg4DQoJCQkJCQlsLTQ1LjIxNiwxMi40MDhsLTUuNTY4LDEuNTM2bDEuNTYsNS41MmwyLjEzNiw3LjUzNmMtMjEuNjk2LDEuOTY4LTQyLjg0LTIuNjY0LTYyLjU2OC02Ljk2DQoJCQkJCQljLTM5LjI2NC04LjU2OC03My4yOTYtMTUuOTg0LTk5LjU3NiwyNS44OTZsMCwwYy03LjEwNCwxMS4zNTItMTQuODU2LDI0Ljg0LTE2LjY1NiwzNS4xNg0KCQkJCQkJYy0yLjQ3MiwxNC4wNCwzLjAyNCwyMy4wNCwyNS4yNDgsMTguOTZjMTMuNjU2LTIuNDk2LDIyLjA4LTkuMzYsMjkuOTI4LTE1Ljc2OGM4Ljg4LTcuMjQ4LDE2Ljg3Mi0xMy43NTIsMzIuMzc2LTkuMTQ0DQoJCQkJCQljOC4xMzYsMy4zNiw4Ljg4LDMuNjcyLDE1LjI0LDkuMDI0YzIxLjE0NCwxNy43MzYsNzEuNCw2MS41MzYsNzIsNjIuMDRsMCwwbDEwLjQxNiw5LjE2OGwyLjkwNCwyLjU0NGwzLjQzMi0xLjc1Mg0KCQkJCQkJbDIwLjg4LTEwLjYwOGwxLjI3Miw0LjQ4OGw1LjQ3Mi0xLjU2bDQ1LjA5Ni0xMi43NjhsNS40OTYtMS41Nkw0MjkuMDIsMjU0LjQyNEw0MjkuMDIsMjU0LjQyNHogTTM1MC42MzYsMjY5Ljk3NmwtNy41MTItNi42DQoJCQkJCQlIMzQzLjFjLTAuMTQ0LTAuMTItNTEuNjI0LTQ1LTcyLjE5Mi02Mi4yMzJjLTcuNzA0LTYuNDU2LTguNTY4LTYuODE2LTE4LjM2LTEwLjg3MmwtMC4yNC0wLjA5NmwtMC41MjgtMC4xOTINCgkJCQkJCWMtMjEuMzYtNi40NTYtMzEuNjA4LDEuOTItNDIuOTg0LDExLjIwOGMtNi43NjgsNS41Mi0xMy45OTIsMTEuNDI0LTI0Ljc2OCwxMy4zOTJjLTEwLjA4LDEuODQ4LTEyLjc2OC0xLjAzMi0xMS45MjgtNS43ODQNCgkJCQkJCWMxLjQ4OC04LjQ3Miw4LjU0NC0yMC42NjQsMTUuMDQ4LTMxLjA1NnYtMC4wMjRjMjEuOTYtMzUuMDY0LDUyLjM5Mi0yOC40NCw4Ny40OC0yMC43ODQNCgkJCQkJCWMyMS4xOTIsNC42MDgsNDMuOTQ0LDkuNTc2LDY4LjE2LDYuOTM2bDI3LjI2NCw5Ni4yNEwzNTAuNjM2LDI2OS45NzZMMzUwLjYzNiwyNjkuOTc2eiBNMzgyLjM2NCwyNjEuNjk2TDM1MC4wNiwxNDcuNjI1DQoJCQkJCQlsMzQuMi05LjM4NGwzMi4yMzIsMTEzLjc4NEwzODIuMzY0LDI2MS42OTZ6Ii8+DQoJCQkJPC9nPg0KCQkJCTxnPg0KCQkJCQk8cGF0aCBzdHlsZT0iZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7ZmlsbDojMjEyMTIxOyIgZD0iTTE1NS4wMTMsMTQ1LjJsLTIuMjgsOC4wMTYNCgkJCQkJCWMxMC4yMjQsMC4yMTYsMjkuNTkyLDAuMDQ4LDQ1LjcyLTMuNmwyLjQ5NiwxMS4xMzZjLTE4Ljk2LDQuMjk2LTQxLjgwOCw0LjEwNC01MS40MDgsMy43OTJsLTI1LjQ4OCw4OS45NzYNCgkJCQkJCWM5LjY3MiwzLjA0OCwyNy44ODgsMTAuOTY4LDI5LjM1MiwyNy43MmwtMTEuNCwwLjk4NGMtMC44ODgtMTAuMTUyLTEzLjcyOC0xNS41MDQtMjEuMDcyLTE3Ljc2bC0xLjM2OCw0LjgyNGwtMS41Niw1LjQ5Ng0KCQkJCQkJbC01LjQ3Mi0xLjU2bC00NS4wOTYtMTIuNzY4bC01LjQ5Ni0xLjU2bDEuNTYtNS40NzJsMzUuMzI4LTEyNC43MDRsMS41MzYtNS40NDhsNS40NDgsMS40ODhsNDUuMjE2LDEyLjQwOGw1LjU2OCwxLjUzNg0KCQkJCQkJTDE1NS4wMTMsMTQ1LjJMMTU1LjAxMywxNDUuMkwxNTUuMDEzLDE0NS4yeiBNMTEwLjE1NywyNjEuNjk2bDMyLjMwNC0xMTQuMDcybC0zNC4yLTkuMzg0TDc2LjAyOSwyNTIuMDI0TDExMC4xNTcsMjYxLjY5NnoiLz4NCgkJCQk8L2c+DQoJCQkJPGc+DQoJCQkJCTxwYXRoIHN0eWxlPSJmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiMyMTIxMjE7IiBkPSJNMjQwLjc2NCwzMzYuNjcyTDI0MC43NjQsMzM2LjY3Mg0KCQkJCQkJYy0xLjEwNC0wLjgxNi0yLjQ0OC0xLjA4LTMuNzQ0LTAuODg4cy0yLjQ5NiwwLjg2NC0zLjMxMiwxLjk0NGwtOC44MzIsMTEuOTc2aDAuMDI0Yy0wLjgxNiwxLjEwNC0xLjEwNCwyLjQ3Mi0wLjkxMiwzLjc0NA0KCQkJCQkJYzAuMTkyLDEuMjcyLDAuODY0LDIuNDcyLDEuOTQ0LDMuMjg4bDAuMTY4LDAuMTQ0YzEuMDU2LDAuNzIsMi4zNTIsMC45NiwzLjU3NiwwLjc2OGMxLjI5Ni0wLjE5MiwyLjQ5Ni0wLjg2NCwzLjMxMi0xLjk0NA0KCQkJCQkJbDguODU2LTEyYzAuODE2LTEuMTA0LDEuMDgtMi40NDgsMC44ODgtMy43NDRDMjQyLjUxNiwzMzguNjg4LDI0MS44NDQsMzM3LjQ4OCwyNDAuNzY0LDMzNi42NzJMMjQwLjc2NCwzMzYuNjcyDQoJCQkJCQlMMjQwLjc2NCwzMzYuNjcyeiBNMTc2LjQyMSwyNjYuMjhjNC4yMjQsMy4xMiw2LjgxNiw3LjY4LDcuNTM2LDEyLjUwNGMwLjMxMiwyLjA2NCwwLjI4OCw0LjE3Ni0wLjA5Niw2LjI0DQoJCQkJCQljMS44OTYtMC45NiwzLjkzNi0xLjYwOCw2LjAyNC0xLjkyYzUuMDE2LTAuNzQ0LDEwLjI5NiwwLjM4NCwxNC42ODgsMy42MjR2MC4wMjRjNC40MTYsMy4yNCw3LjA4LDcuOTY4LDcuODI0LDEyLjk4NA0KCQkJCQkJYzAuMzEyLDEuOTkyLDAuMjg4LDQuMDMyLTAuMDI0LDYuMDQ4YzAuNi0wLjE0NCwxLjE3Ni0wLjI2NCwxLjc3Ni0wLjM2YzQuNTM2LTAuNjcyLDkuMzM2LDAuMzYsMTMuMjk2LDMuMjg4bDAuMjg4LDAuMjQNCgkJCQkJCWMzLjgxNiwyLjkyOCw2LjE0NCw3LjEyOCw2LjgxNiwxMS41MmMwLjIxNiwxLjM2OCwwLjI2NCwyLjc2LDAuMTQ0LDQuMTUyYzAuMjE2LTAuMDQ4LDAuNDA4LTAuMDcyLDAuNjI0LTAuMDk2DQoJCQkJCQljNC4xMjgtMC42MjQsOC41NDQsMC4zMzYsMTIuMTkyLDMuMDI0bDAsMGMzLjY3MiwyLjcxMiw1Ljg4LDYuNjI0LDYuNTA0LDEwLjc3NmMwLjYyNCw0LjEyOC0wLjMzNiw4LjU0NC0zLjA0OCwxMi4xOTINCgkJCQkJCWwtOC44NTYsMTJjLTIuNzEyLDMuNjcyLTYuNjI0LDUuODgtMTAuNzc2LDYuNTA0Yy00LjEyOCwwLjYyNC04LjUyLTAuMzM2LTEyLjE5Mi0zLjAyNHYwLjAyNA0KCQkJCQkJYy0zLjY0OC0yLjY4OC01Ljg4LTYuNjI0LTYuNTA0LTEwLjhjLTAuMDcyLTAuNDgtMC4xMi0wLjk2LTAuMTQ0LTEuNDRjLTEuMDA4LDAuMzM2LTIuMDQsMC42LTMuMDcyLDAuNzQ0DQoJCQkJCQljLTQuNTEyLDAuNjcyLTkuMzEyLTAuMzYtMTMuMjk2LTMuMzEybDAsMGMtMy45ODQtMi45NTItNi40MDgtNy4yMjQtNy4wOC0xMS43MzZjLTAuMTQ0LTAuOTEyLTAuMjE2LTEuODI0LTAuMTkyLTIuNzYNCgkJCQkJCWMtMS41MTIsMC42MjQtMy4wNzIsMS4wOC00LjY4LDEuMzJjLTUuMDE2LDAuNzQ0LTEwLjI5Ni0wLjM4NC0xNC42ODgtMy42MjRsMCwwYy00LjM5Mi0zLjI0LTcuMDgtNy45OTItNy44MjQtMTMuMDA4DQoJCQkJCQljLTAuMzg0LTIuNDcyLTAuMjg4LTUuMDE2LDAuMzEyLTcuNDg4Yy0xLjU4NCwwLjcyLTMuMjY0LDEuMi00Ljk2OCwxLjQ2NGMtNC44MjQsMC43Mi05LjkxMi0wLjM4NC0xNC4xMzYtMy40OA0KCQkJCQkJYy00LjIyNC0zLjEyLTYuODE2LTcuNjgtNy41MzYtMTIuNTA0czAuMzg0LTkuOTEyLDMuNDgtMTQuMTM2aDAuMDI0bDEwLjk5Mi0xNC45MDRjMy4xMi00LjI0OCw3LjY4LTYuODE2LDEyLjQ4LTcuNTM2DQoJCQkJCQlDMTY3LjA4NSwyNjIuMDU2LDE3Mi4xNzMsMjYzLjE2LDE3Ni40MjEsMjY2LjI4TDE3Ni40MjEsMjY2LjI4TDE3Ni40MjEsMjY2LjI4TDE3Ni40MjEsMjY2LjI4eiBNMTcyLjY1MywyODAuNDY0DQoJCQkJCQljLTAuMjg4LTEuOTQ0LTEuMzItMy43NjgtMi45NzYtNC45OTJ2LTAuMDI0Yy0xLjY4LTEuMjI0LTMuNzItMS42NTYtNS42ODgtMS4zNjhjLTEuOTY4LDAuMjg4LTMuNzkyLDEuMzItNS4wMTYsMi45NzYNCgkJCQkJCWwtMTAuOTkyLDE0Ljg4aDAuMDI0Yy0xLjI0OCwxLjY4LTEuNjgsMy43NDQtMS4zOTIsNS42ODhjMC4yODgsMS45NDQsMS4zMiwzLjc2OCwyLjk3Niw0Ljk5Mg0KCQkJCQkJYzEuNjgsMS4yNDgsMy43NDQsMS42OCw1LjY4OCwxLjM5MnMzLjc2OC0xLjMyLDQuOTkyLTIuOTc2bDAuMDI0LDBsMTAuOTkyLTE0Ljg4aC0wLjAyNA0KCQkJCQkJQzE3Mi40ODUsMjg0LjQ3MiwxNzIuOTQxLDI4Mi40MDgsMTcyLjY1MywyODAuNDY0TDE3Mi42NTMsMjgwLjQ2NEwxNzIuNjUzLDI4MC40NjR6IE0yMDEuMDkyLDMwMS40MTYNCgkJCQkJCWMtMC4zMTItMi4xMzYtMS40NC00LjE1Mi0zLjI2NC01LjQ5NnYwLjAyNGMtMS44NDgtMS4zNjgtNC4xMDQtMS44NDgtNi4yNC0xLjUzNmMtMi4xNiwwLjMzNi00LjE1MiwxLjQ0LTUuNTIsMy4yNjQNCgkJCQkJCWwtMTEuNjE2LDE1Ljc0NGMtMS4zNDQsMS44NDgtMS44MjQsNC4xMDQtMS41MTIsNi4yNGMwLjMxMiwyLjEzNiwxLjQ0LDQuMTI4LDMuMjY0LDUuNDk2bDAsMA0KCQkJCQkJYzEuODQ4LDEuMzY4LDQuMTA0LDEuODQ4LDYuMjQsMS41MzZjMi4xNi0wLjMxMiw0LjE1Mi0xLjQ0LDUuNTItMy4yNjRsMCwwbDExLjYxNi0xNS43NDQNCgkJCQkJCUMyMDAuOTQ4LDMwNS44MzIsMjAxLjQyOCwzMDMuNTc2LDIwMS4wOTIsMzAxLjQxNkwyMDEuMDkyLDMwMS40MTZMMjAxLjA5MiwzMDEuNDE2eiBNMjIzLjI0NCwzMjIuMTUyDQoJCQkJCQljLTAuMjQtMS42OC0xLjEwNC0zLjI0LTIuNTItNC4yNzJ2MC4wMjRjLTEuNDQtMS4wNTYtMy4xOTItMS40NC00Ljg0OC0xLjE3NmMtMS42NTYsMC4yNC0zLjIxNiwxLjEwNC00LjI0OCwyLjU0NGwtMC4xOTIsMC4yNA0KCQkJCQkJbC05Ljg4OCwxMy40MTZ2MC4wMjRjLTEuMDU2LDEuNDE2LTEuNDE2LDMuMTY4LTEuMTUyLDQuODI0YzAuMjY0LDEuNjgsMS4xMjgsMy4yNCwyLjU0NCw0LjI3MmwwLDANCgkJCQkJCWMxLjQxNiwxLjA1NiwzLjE2OCwxLjQxNiw0Ljg0OCwxLjE1MmMxLjY4LTAuMjY0LDMuMjQtMS4xMjgsNC4yNzItMi41NDRMMjIyLjE0MSwzMjcNCgkJCQkJCUMyMjMuMTI0LDMyNS41ODQsMjIzLjUwOCwzMjMuODMyLDIyMy4yNDQsMzIyLjE1MnoiLz4NCgkJCQk8L2c+DQoJCQk8L2c+DQoJCTwvZz4NCgk8L2c+DQo8L2c+DQo8L3N2Zz4NCg==\","; + + uri = string.concat(name, description, image, attributes); + } + + function readNameWithDefaultValue(address token) internal view returns (string memory name) { + // NOTE: this will not take into account the correct symbol on many chains + if (token == address(0)) { + return "Ether"; + } + + name = token.readName(); + if (bytes(name).length == 0) { + name = "unknown token"; + } + } + + function readSymbolWithDefaultValue(address token) internal view returns (string memory symbol) { + // NOTE: this will not take into account the correct symbol on many chains + if (token.isNullAddress()) { + return "ETH"; + } + + symbol = token.readSymbol(); + if (bytes(symbol).length == 0) { + symbol = "???"; + } + } + + function readDecimalsWithDefaultValue(address token) internal view returns (string memory decimals) { + if (token.isNullAddress()) { + return "18"; + } + return uint256(token.readDecimals()).toString(); + } + + function toAttributeString(string memory trait, string memory value, bool terminal) internal pure returns (string memory attribute) { + return string.concat("{\"trait_type\": \"", trait, "\", \"value\": \"", value, "\"}", terminal ? "" : ","); + } +} diff --git a/src/lib/MetadataRenderer.sol b/src/lib/MetadataRenderer.sol new file mode 100644 index 0000000..7866b46 --- /dev/null +++ b/src/lib/MetadataRenderer.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { EfficiencyLib } from "./EfficiencyLib.sol"; +import { MetadataLib } from "./MetadataLib.sol"; +import { Lock } from "../types/Lock.sol"; + +/** + * @title MetadataRenderer + * @notice Deployed contract implementing functionality for deriving and displaying + * ERC6909 metadata as well as metadata specific to various underlying tokens. + */ +contract MetadataRenderer { + using EfficiencyLib for uint256; + using MetadataLib for Lock; + using MetadataLib for address; + + /** + * @notice External view function for generating the URI for a resource lock's ERC6909 + * token. The URI is derived from the lock's details and token identifier. + * @param lock The Lock struct containing the resource lock's details. + * @param id The ERC6909 token identifier. + * @return The generated URI string. + */ + function uri(Lock memory lock, uint256 id) external view returns (string memory) { + return lock.toURI(id); + } + + /** + * @notice External view function for generating the name of an ERC6909 token. Combines + * "Compact" with the underlying token's name, falling back to a default if needed. + * @param id The ERC6909 token identifier. + * @return The generated name string. + */ + function name(uint256 id) external view returns (string memory) { + return string.concat("Compact ", id.asSanitizedAddress().readNameWithDefaultValue()); + } + + /** + * @notice External view function for generating the symbol of an ERC6909 token. Combines + * a handshake emoji with the underlying token's symbol, falling back to a default if + * needed. + * @param id The ERC6909 token identifier. + * @return The generated symbol string. + */ + function symbol(uint256 id) external view returns (string memory) { + return string.concat(unicode"🤝-", id.asSanitizedAddress().readSymbolWithDefaultValue()); + } +} diff --git a/src/lib/RegistrationLib.sol b/src/lib/RegistrationLib.sol new file mode 100644 index 0000000..9b397f2 --- /dev/null +++ b/src/lib/RegistrationLib.sol @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { ResetPeriod } from "../types/ResetPeriod.sol"; + +import { EfficiencyLib } from "./EfficiencyLib.sol"; +import { IdLib } from "./IdLib.sol"; + +/** + * @title RegistrationLib + * @notice Libray contract implementing logic for registering compact claim hashes + * and typehashes and querying for whether given claim hashes and typehashes have + * been registered. + */ +library RegistrationLib { + using RegistrationLib for address; + using EfficiencyLib for uint256; + using IdLib for ResetPeriod; + + // keccak256(bytes("CompactRegistered(address,bytes32,bytes32,uint256)")). + uint256 private constant _COMPACT_REGISTERED_SIGNATURE = 0xf78a2f33ff80ef4391f7449c748dc2d577a62cd645108f4f4069f4a7e0635b6a; + + // Storage scope for active registrations: + // slot: keccak256(_ACTIVE_REGISTRATIONS_SCOPE ++ sponsor ++ claimHash ++ typehash) => expires. + uint256 private constant _ACTIVE_REGISTRATIONS_SCOPE = 0x68a30dd0; + + /** + * @notice Internal function for registering a claim hash with a specific duration. The + * claim hash and its associated typehash will remain valid until the specified duration + * has elapsed. Reverts if the duration would result in an expiration earlier than an + * existing registration or if it exceeds 30 days. + * @param sponsor The account registering the claim hash. + * @param claimHash A bytes32 hash derived from the details of the compact. + * @param typehash The EIP-712 typehash associated with the claim hash. + * @param duration The duration in seconds for which the registration remains valid. + */ + function registerCompactWithSpecificDuration(address sponsor, bytes32 claimHash, bytes32 typehash, uint256 duration) internal { + assembly ("memory-safe") { + // Retrieve the current free memory pointer. + let m := mload(0x40) + + // Pack data for deriving active registration storage slot. + mstore(add(m, 0x14), sponsor) + mstore(m, _ACTIVE_REGISTRATIONS_SCOPE) + mstore(add(m, 0x34), claimHash) + mstore(add(m, 0x54), typehash) + + // Derive and load active registration storage slot to get current expiration. + let cutoffSlot := keccak256(add(m, 0x1c), 0x58) + + // Compute new expiration based on current timestamp and supplied duration. + let expires := add(timestamp(), duration) + + // Ensure new expiration does not exceed current and duration does not exceed 30 days. + if or(lt(expires, sload(cutoffSlot)), gt(duration, 0x278d00)) { + // revert InvalidRegistrationDuration(uint256 duration) + mstore(0, 0x1f9a96f4) + mstore(0x20, duration) + revert(0x1c, 0x24) + } + + // Store new expiration in active registration storage slot. + sstore(cutoffSlot, expires) + + // Emit the CompactRegistered event: + // - topic1: CompactRegistered event signature + // - topic2: sponsor address (sanitized) + // - data: [claimHash, typehash, expires] + mstore(add(m, 0x74), expires) + log2(add(m, 0x34), 0x60, _COMPACT_REGISTERED_SIGNATURE, shr(0x60, shl(0x60, sponsor))) + } + } + + /** + * @notice Internal function for registering a claim hash with a duration specified as a + * ResetPeriod enum value. + * @param sponsor The account registering the claim hash. + * @param claimHash A bytes32 hash derived from the details of the compact. + * @param typehash The EIP-712 typehash associated with the claim hash. + * @param duration The ResetPeriod enum value specifying the registration duration. + */ + function registerCompact(address sponsor, bytes32 claimHash, bytes32 typehash, ResetPeriod duration) internal { + sponsor.registerCompactWithSpecificDuration(claimHash, typehash, duration.toSeconds()); + } + + /** + * @notice Internal function for registering a claim hash with the default duration (10 + * minutes) using the caller as the sponsor. + * @param claimHash A bytes32 hash derived from the details of the compact. + * @param typehash The EIP-712 typehash associated with the claim hash. + */ + function registerAsCallerWithDefaultDuration(bytes32 claimHash, bytes32 typehash) internal { + msg.sender.registerCompactWithSpecificDuration(claimHash, typehash, uint256(0x258).asStubborn()); + } + + /** + * @notice Internal function for registering multiple claim hashes in a single call. All + * claim hashes will be registered with the same duration using the caller as the sponsor. + * @param claimHashesAndTypehashes Array of [claimHash, typehash] pairs for registration. + * @param duration The duration for which the claim hashes remain valid. + * @return Whether all claim hashes were successfully registered. + */ + function registerBatchAsCaller(bytes32[2][] calldata claimHashesAndTypehashes, uint256 duration) internal returns (bool) { + unchecked { + // Retrieve the total number of claim hashes and typehashes to register. + uint256 totalClaimHashes = claimHashesAndTypehashes.length; + + // Iterate over each pair of claim hashes and typehashes. + for (uint256 i = 0; i < totalClaimHashes; ++i) { + // Retrieve the claim hash and typehash from calldata. + bytes32[2] calldata claimHashAndTypehash = claimHashesAndTypehashes[i]; + + // Register the compact as the caller with the specified duration. + msg.sender.registerCompactWithSpecificDuration(claimHashAndTypehash[0], claimHashAndTypehash[1], duration); + } + } + + return true; + } + + /** + * @notice Internal view function for retrieving the expiration timestamp of a + * registration. + * @param sponsor The account that registered the claim hash. + * @param claimHash A bytes32 hash derived from the details of the compact. + * @param typehash The EIP-712 typehash associated with the claim hash. + * @return expires The timestamp at which the registration expires. + */ + function toRegistrationExpiration(address sponsor, bytes32 claimHash, bytes32 typehash) internal view returns (uint256 expires) { + assembly ("memory-safe") { + // Retrieve the current free memory pointer. + let m := mload(0x40) + + // Pack data for deriving active registration storage slot. + mstore(add(m, 0x14), sponsor) + mstore(m, _ACTIVE_REGISTRATIONS_SCOPE) + mstore(add(m, 0x34), claimHash) + mstore(add(m, 0x54), typehash) + + // Derive and load active registration storage slot to get current expiration. + expires := sload(keccak256(add(m, 0x1c), 0x58)) + } + } + + /** + * @notice Internal view function for checking if a registration is inactive or expired. + * @param sponsor The account that registered the claim hash. + * @param claimHash A bytes32 hash derived from the details of the compact. + * @param typehash The EIP-712 typehash associated with the claim hash. + * @return Whether the registration is inactive or has expired. + */ + function hasNoActiveRegistration(address sponsor, bytes32 claimHash, bytes32 typehash) internal view returns (bool) { + return sponsor.toRegistrationExpiration(claimHash, typehash) <= block.timestamp; + } +} diff --git a/src/lib/RegistrationLogic.sol b/src/lib/RegistrationLogic.sol new file mode 100644 index 0000000..81e5726 --- /dev/null +++ b/src/lib/RegistrationLogic.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { RegistrationLib } from "./RegistrationLib.sol"; + +/** + * @title RegistrationLogic + * @notice Inherited contract implementing logic for registering compact claim hashes + * and typehashes and querying for whether given claim hashes and typehashes have + * been registered. + */ +contract RegistrationLogic { + using RegistrationLib for address; + using RegistrationLib for bytes32; + using RegistrationLib for bytes32[2][]; + + /** + * @notice Internal function for registering a claim hash with a specific duration. The + * claim hash and its associated typehash will remain valid until the specified duration + * has elapsed. Reverts if the duration would result in an expiration earlier than an + * existing registration or if it exceeds 30 days. + * @param sponsor The account registering the claim hash. + * @param claimHash A bytes32 hash derived from the details of the compact. + * @param typehash The EIP-712 typehash associated with the claim hash. + * @param duration The duration for which the registration remains valid. + */ + function _register(address sponsor, bytes32 claimHash, bytes32 typehash, uint256 duration) internal { + sponsor.registerCompactWithSpecificDuration(claimHash, typehash, duration); + } + + /** + * @notice Internal function for registering a claim hash using the default duration + * (10 minutes) and the caller as the sponsor. + * @param claimHash A bytes32 hash derived from the details of the compact. + * @param typehash The EIP-712 typehash associated with the claim hash. + */ + function _registerWithDefaults(bytes32 claimHash, bytes32 typehash) internal { + claimHash.registerAsCallerWithDefaultDuration(typehash); + } + + /** + * @notice Internal function for registering multiple claim hashes in a single call. All + * claim hashes will be registered with the same duration using the caller as the sponsor. + * @param claimHashesAndTypehashes Array of [claimHash, typehash] pairs for registration. + * @param duration The duration for which the claim hashes remain valid. + * @return Whether all claim hashes were successfully registered. + */ + function _registerBatch(bytes32[2][] calldata claimHashesAndTypehashes, uint256 duration) internal returns (bool) { + return claimHashesAndTypehashes.registerBatchAsCaller(duration); + } + + /** + * @notice Internal view function for retrieving the expiration timestamp of a + * registration. + * @param sponsor The account that registered the claim hash. + * @param claimHash A bytes32 hash derived from the details of the compact. + * @param typehash The EIP-712 typehash associated with the claim hash. + * @return expires The timestamp at which the registration expires. + */ + function _getRegistrationStatus(address sponsor, bytes32 claimHash, bytes32 typehash) internal view returns (uint256 expires) { + return sponsor.toRegistrationExpiration(claimHash, typehash); + } +} diff --git a/src/lib/SharedLogic.sol b/src/lib/SharedLogic.sol new file mode 100644 index 0000000..87a32b6 --- /dev/null +++ b/src/lib/SharedLogic.sol @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { ConstructorLogic } from "./ConstructorLogic.sol"; +import { IdLib } from "./IdLib.sol"; + +import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol"; + +/** + * @title SharedLogic + * @notice Inherited contract implementing logic for internal functions with + * low-level shared logic for processing transfers and withdrawals. + */ +contract SharedLogic is ConstructorLogic { + using IdLib for uint256; + using SafeTransferLib for address; + + // Storage slot seed for ERC6909 state, used in computing balance slots. + uint256 private constant _ERC6909_MASTER_SLOT_SEED = 0xedcaa89a82293940; + + // keccak256(bytes("Transfer(address,address,address,uint256,uint256)")). + uint256 private constant _TRANSFER_EVENT_SIGNATURE = 0x1b3d7edb2e9c0b0e7c525b20aaaef0f5940d2ed71663c7d39266ecafac728859; + + /** + * @notice Internal function for transferring ERC6909 tokens between accounts. Updates + * both balances, checking for overflow and insufficient balance. This function bypasses + * transfer hooks and allowance checks as it is only called in trusted contexts. Emits + * a Transfer event. + * @param from The account to transfer tokens from. + * @param to The account to transfer tokens to. + * @param id The ERC6909 token identifier to transfer. + * @param amount The amount of tokens to transfer. + * @return Whether the transfer was successful. + */ + function _release(address from, address to, uint256 id, uint256 amount) internal returns (bool) { + assembly ("memory-safe") { + // Compute the sender's balance slot using the master slot seed. + mstore(0x20, _ERC6909_MASTER_SLOT_SEED) + mstore(0x14, from) + mstore(0x00, id) + let fromBalanceSlot := keccak256(0x00, 0x40) + + // Load from sender's current balance. + let fromBalance := sload(fromBalanceSlot) + + // Revert if amount is zero or exceeds balance. + if or(iszero(amount), gt(amount, fromBalance)) { + mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. + revert(0x1c, 0x04) + } + + // Subtract from current balance and store the updated balance. + sstore(fromBalanceSlot, sub(fromBalance, amount)) + + // Compute the recipient's balance slot and update balance. + mstore(0x14, to) + mstore(0x00, id) + let toBalanceSlot := keccak256(0x00, 0x40) + let toBalanceBefore := sload(toBalanceSlot) + let toBalanceAfter := add(toBalanceBefore, amount) + + // Revert if the balance overflows. + if lt(toBalanceAfter, toBalanceBefore) { + mstore(0x00, 0x89560ca1) // `BalanceOverflow()`. + revert(0x1c, 0x04) + } + + // Store the recipient's updated balance. + sstore(toBalanceSlot, toBalanceAfter) + + // Emit the Transfer event: + // - topic1: Transfer event signature + // - topic2: sender address (sanitized) + // - topic3: recipient address (sanitized) + // - topic4: token id + // - data: [caller, amount] + mstore(0x00, caller()) + mstore(0x20, amount) + log4(0x00, 0x40, _TRANSFER_EVENT_SIGNATURE, shr(0x60, shl(0x60, from)), shr(0x60, shl(0x60, to)), id) + } + + return true; + } + + /** + * @notice Internal function for burning ERC6909 tokens and withdrawing the underlying + * tokens. Updates the sender's balance and transfers either native tokens or ERC20 + * tokens to the recipient. For ERC20 withdrawals, the actual amount burned is derived + * from the balance change. Uses a reentrancy guard due to external calls. Emits a + * Transfer event. + * @param from The account to burn tokens from. + * @param to The account to send underlying tokens to. + * @param id The ERC6909 token identifier to burn. + * @param amount The amount of tokens to burn and withdraw. + * @return Whether the withdrawal was successful. + */ + function _withdraw(address from, address to, uint256 id, uint256 amount) internal returns (bool) { + // Set reentrancy guard due to external token transfers. + _setReentrancyGuard(); + + // Derive the underlying token from the id of the resource lock. + address token = id.toToken(); + + // Handle native token withdrawals directly. + if (token == address(0)) { + to.safeTransferETH(amount); + } else { + // For ERC20s, track balance change to determine actual withdrawal amount. + uint256 initialBalance = token.balanceOf(address(this)); + + // Perform the token withdrawal. + token.safeTransfer(to, amount); + + // Derive actual amount from balance change. A balance increase would cause + // a massive underflow, resulting in a failure during the subsequent burn. + unchecked { + amount = initialBalance - token.balanceOf(address(this)); + } + } + + assembly ("memory-safe") { + // Compute the sender's balance slot using the master slot seed. + mstore(0x20, _ERC6909_MASTER_SLOT_SEED) + mstore(0x14, from) + mstore(0x00, id) + let fromBalanceSlot := keccak256(0x00, 0x40) + + // Load from sender's current balance. + let fromBalance := sload(fromBalanceSlot) + + // Revert if insufficient balance. + if gt(amount, fromBalance) { + mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. + revert(0x1c, 0x04) + } + + // Subtract from current balance and store the updated balance. + sstore(fromBalanceSlot, sub(fromBalance, amount)) + + // Emit the Transfer event: + // - topic1: Transfer event signature + // - topic2: sender address (sanitized) + // - topic3: address(0) signifying a burn + // - topic4: token id + // - data: [caller, amount] + mstore(0x00, caller()) + mstore(0x20, amount) + log4(0x00, 0x40, _TRANSFER_EVENT_SIGNATURE, shr(0x60, shl(0x60, from)), 0, id) + } + + // Clear the reentrancy guard. + _clearReentrancyGuard(); + + return true; + } +} diff --git a/src/lib/TheCompactLogic.sol b/src/lib/TheCompactLogic.sol new file mode 100644 index 0000000..16967dd --- /dev/null +++ b/src/lib/TheCompactLogic.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { AllocatorLogic } from "./AllocatorLogic.sol"; +import { ClaimProcessor } from "./ClaimProcessor.sol"; +import { DepositViaPermit2Logic } from "./DepositViaPermit2Logic.sol"; +import { DirectDepositLogic } from "./DirectDepositLogic.sol"; +import { Extsload } from "./Extsload.sol"; +import { RegistrationLogic } from "./RegistrationLogic.sol"; +import { TransferLogic } from "./TransferLogic.sol"; +import { WithdrawalLogic } from "./WithdrawalLogic.sol"; + +/** + * @title TheCompactLogic + * @notice Inherited contract that aggregates a number of other inherited contracts. + */ +contract TheCompactLogic is AllocatorLogic, ClaimProcessor, DepositViaPermit2Logic, DirectDepositLogic, Extsload, RegistrationLogic, TransferLogic, WithdrawalLogic { } diff --git a/src/lib/TransferFunctionCastLib.sol b/src/lib/TransferFunctionCastLib.sol new file mode 100644 index 0000000..4db7b1f --- /dev/null +++ b/src/lib/TransferFunctionCastLib.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { BatchTransfer, SplitBatchTransfer } from "../types/BatchClaims.sol"; +import { BasicTransfer, SplitTransfer } from "../types/Claims.sol"; +import { TransferComponent, SplitByIdComponent } from "../types/Components.sol"; + +/** + * @title TransferFunctionCastLib + * @notice Libray contract implementing function casts used in TransferLogic as well as + * in HashLib. The input function operates on a function that takes some argument that + * differs from what is currently available. The output function modifies one or more + * argument types so that they match the arguments that are being used to call the + * function. Note that from the perspective of the function being modified, the original + * type is still in force; great care should be taken to preserve offsets and general + * structure between the two structs. + */ +library TransferFunctionCastLib { + /** + * @notice Function cast to provide a SplitTransfer calldata struct while + * treating it as a BasicTransfer calldata struct. + * @param fnIn Function pointer to `TransferLogic._notExpiredAndSignedByAllocator`. + * @return fnOut Modified function used in `TransferLogic._processSplitTransfer`. + */ + function usingSplitTransfer(function (bytes32, address, BasicTransfer calldata) internal fnIn) internal pure returns (function (bytes32, address, SplitTransfer calldata) internal fnOut) { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a BatchTransfer calldata struct while + * treating it as a BasicTransfer calldata struct. + * @param fnIn Function pointer to `TransferLogic._notExpiredAndSignedByAllocator`. + * @return fnOut Modified function used in `TransferLogic._processBatchTransfer`. + */ + function usingBatchTransfer(function (bytes32, address, BasicTransfer calldata) internal fnIn) internal pure returns (function (bytes32, address, BatchTransfer calldata) internal fnOut) { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a SplitBatchTransfer calldata struct while + * treating it as a BasicTransfer calldata struct. + * @param fnIn Function pointer to `TransferLogic._notExpiredAndSignedByAllocator`. + * @return fnOut Modified function used in `TransferLogic._processSplitBatchTransfer`. + */ + function usingSplitBatchTransfer(function (bytes32, address, BasicTransfer calldata) internal fnIn) internal pure returns (function (bytes32, address, SplitBatchTransfer calldata) internal fnOut) { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a SplitByIdComponent array while treating it + * as a TransferComponent array. + * @param fnIn Function pointer to `TransferLogic._deriveConsistentAllocatorAndConsumeNonce`. + * @return fnOut Modified function used in `TransferLogic._processSplitBatchTransfer`. + */ + function usingSplitByIdComponent(function(TransferComponent[] calldata, uint256, function (TransferComponent[] calldata, uint256) internal pure returns (uint96)) internal returns (address) fnIn) + internal + pure + returns (function(SplitByIdComponent[] calldata, uint256, function (SplitByIdComponent[] calldata, uint256) internal pure returns (uint96)) internal returns (address) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + /** + * @notice Function cast to provide a SplitBatchTransfer calldata struct while + * treating it as a BatchTransfer calldata struct. + * @param fnIn Function pointer to `HashLib.toBatchTransferMessageHashUsingIdsAndAmountsHash`. + * @return fnOut Modified function for `HashLib.toSplitBatchTransferMessageHash`. + */ + function usingSplitBatchTransfer(function(BatchTransfer calldata, uint256) internal view returns (bytes32) fnIn) + internal + pure + returns (function(SplitBatchTransfer calldata, uint256) internal view returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } +} diff --git a/src/lib/TransferLogic.sol b/src/lib/TransferLogic.sol new file mode 100644 index 0000000..102b975 --- /dev/null +++ b/src/lib/TransferLogic.sol @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { BatchTransfer, SplitBatchTransfer } from "../types/BatchClaims.sol"; +import { BasicTransfer, SplitTransfer } from "../types/Claims.sol"; +import { TransferComponent, SplitByIdComponent } from "../types/Components.sol"; + +import { ClaimHashLib } from "./ClaimHashLib.sol"; +import { ComponentLib } from "./ComponentLib.sol"; +import { EfficiencyLib } from "./EfficiencyLib.sol"; +import { EventLib } from "./EventLib.sol"; +import { TransferFunctionCastLib } from "./TransferFunctionCastLib.sol"; +import { IdLib } from "./IdLib.sol"; +import { SharedLogic } from "./SharedLogic.sol"; +import { ValidityLib } from "./ValidityLib.sol"; + +/** + * @title TransferLogic + * @notice Inherited contract implementing internal functions with logic for processing + * allocated token transfers and withdrawals. These calls are submitted directly by the + * sponsor and therefore only need to be independently authorized by the allocator. To + * construct the authorizing Compact or BatchCompact payload, the arbiter is set as the + * sponsor. + */ +contract TransferLogic is SharedLogic { + using ClaimHashLib for BasicTransfer; + using ClaimHashLib for SplitTransfer; + using ClaimHashLib for BatchTransfer; + using ClaimHashLib for SplitBatchTransfer; + using ComponentLib for SplitTransfer; + using ComponentLib for BatchTransfer; + using ComponentLib for SplitBatchTransfer; + using IdLib for uint256; + using EfficiencyLib for bool; + using EventLib for address; + using ValidityLib for uint96; + using ValidityLib for uint256; + using ValidityLib for bytes32; + using TransferFunctionCastLib for function(bytes32, address, BasicTransfer calldata) internal; + using TransferFunctionCastLib for function(TransferComponent[] calldata, uint256, function (TransferComponent[] calldata, uint256) internal pure returns (uint96)) internal returns (address); + + // bytes4(keccak256("attest(address,address,address,uint256,uint256)")). + uint32 private constant _ATTEST_SELECTOR = 0x1a808f91; + + /** + * @notice Internal function for processing a basic allocated transfer or withdrawal. + * Validates the allocator signature, checks expiration, consumes the nonce, and executes + * the transfer or withdrawal operation for a single recipient. + * @param transfer A BasicTransfer struct containing signature, nonce, expiry, and transfer details. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the transfer or withdrawal was successfully processed. + */ + function _processBasicTransfer(BasicTransfer calldata transfer, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + // Derive hash, validate expiry, consume nonce, and check allocator signature. + _notExpiredAndSignedByAllocator(transfer.toClaimHash(), transfer.id.toRegisteredAllocatorWithConsumed(transfer.nonce), transfer); + + // Perform the transfer or withdrawal. + return operation(msg.sender, transfer.recipient, transfer.id, transfer.amount); + } + + /** + * @notice Internal function for processing a split transfer or withdrawal. Validates the + * allocator signature, checks expiration, consumes the nonce, and executes the transfer + * or withdrawal operation targeting multiple recipients from a single resource lock. + * @param transfer A SplitTransfer struct containing signature, nonce, expiry, and split transfer details. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the transfer was successfully processed. + */ + function _processSplitTransfer(SplitTransfer calldata transfer, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + // Derive hash, validate expiry, consume nonce, and check allocator signature. + _notExpiredAndSignedByAllocator.usingSplitTransfer()(transfer.toClaimHash(), transfer.id.toRegisteredAllocatorWithConsumed(transfer.nonce), transfer); + + // Perform the split transfers or withdrawals. + return transfer.processSplitTransfer(operation); + } + + /** + * @notice Internal function for processing a batch transfer or withdrawal. Validates the + * allocator signature, checks expiration, consumes the nonce, ensures consistent allocator + * across all resource locks, and executes the transfer or withdrawal operation for a single + * recipient from multiple resource locks. + * @param transfer A BatchTransfer struct containing signature, nonce, expiry, and batch transfer details. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the transfer was successfully processed. + */ + function _processBatchTransfer(BatchTransfer calldata transfer, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + // Derive hash, validate expiry, consume nonce, and check allocator signature. + _notExpiredAndSignedByAllocator.usingBatchTransfer()(transfer.toClaimHash(), _deriveConsistentAllocatorAndConsumeNonce(transfer.transfers, transfer.nonce, _allocatorIdOfTransferComponentId), transfer); + + // Perform the batch transfers or withdrawals. + return transfer.performBatchTransfer(operation); + } + + /** + * @notice Internal function for processing a split batch transfer or withdrawal. Validates + * the allocator signature, checks expiration, consumes the nonce, ensures consistent + * allocator across all resource locks, and executes the transfer or withdrawal operation + * for multiple recipients from multiple resource locks. + * @param transfer A SplitBatchTransfer struct containing signature, nonce, expiry, and split batch transfer details. + * @param operation Function pointer to either _release or _withdraw for executing the claim. + * @return Whether the transfer was successfully processed. + */ + function _processSplitBatchTransfer(SplitBatchTransfer calldata transfer, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + // Derive hash, validate expiry, consume nonce, and check allocator signature. + _notExpiredAndSignedByAllocator.usingSplitBatchTransfer()( + transfer.toClaimHash(), _deriveConsistentAllocatorAndConsumeNonce.usingSplitByIdComponent()(transfer.transfers, transfer.nonce, _allocatorIdOfSplitByIdComponent), transfer + ); + + // Perform the split batch transfers or withdrawals. + return transfer.performSplitBatchTransfer(operation); + } + + /** + * @notice Internal function for ensuring a transfer has been attested by its allocator. + * Makes a call to the allocator's attest function and reverts if the attestation fails + * due to a reverted call or due to the call not returning the required magic value. Note + * that this call is stateful. + * @param from The account transferring tokens. + * @param to The account receiving tokens. + * @param id The ERC6909 token identifier of the resource lock. + * @param amount The amount of tokens being transferred. + */ + function _ensureAttested(address from, address to, uint256 id, uint256 amount) internal { + // Derive the allocator address from the supplied id. + address allocator = id.toAllocator(); + + assembly ("memory-safe") { + // Sanitize from and to addresses. + from := shr(0x60, shl(0x60, from)) + to := shr(0x60, shl(0x60, to)) + + // Retrieve the free memory pointer; memory will be left dirtied. + let m := mload(0x40) + + // Ensure sure initial scratch space is cleared as an added precaution. + mstore(0, 0) + + // Derive offset to start of data for the call from memory pointer. + let dataStart := add(m, 0x1c) + + // Prepare calldata: attest(caller(), from, to, id, amount). + mstore(m, _ATTEST_SELECTOR) + mstore(add(m, 0x20), caller()) + mstore(add(m, 0x40), from) + mstore(add(m, 0x60), to) + mstore(add(m, 0x80), id) + mstore(add(m, 0xa0), amount) + + // Perform call to allocator and write response to scratch space. + let success := call(gas(), allocator, 0, dataStart, 0xa4, 0, 0x20) + + // Revert if the required magic value was not received back. + if iszero(eq(mload(0), shl(224, _ATTEST_SELECTOR))) { + // Bubble up revert if the call failed and there's data. + // NOTE: consider evaluating remaining gas to protect against revert bombing. + if iszero(or(success, iszero(returndatasize()))) { + returndatacopy(0, 0, returndatasize()) + revert(0, returndatasize()) + } + + // revert UnallocatedTransfer(msg.sender, from, to, id, amount) + mstore(m, 0x014c9310) + revert(dataStart, 0xa4) + } + } + } + + /** + * @notice Private function that checks expiration, verifies the allocator's signature, + * and emits a claim event. + * @param messageHash The EIP-712 hash of the transfer message. + * @param allocator The address of the allocator. + * @param transferPayload The BasicTransfer struct containing signature and expiry. + */ + function _notExpiredAndSignedByAllocator(bytes32 messageHash, address allocator, BasicTransfer calldata transferPayload) private { + // Ensure that the expiration timestamp is still in the future. + transferPayload.expires.later(); + + // Derive domain separator and domain hash and validate allocator signature. + messageHash.signedBy(allocator, transferPayload.allocatorSignature, _domainSeparator()); + + // Emit Claim event. + msg.sender.emitClaim(messageHash, allocator); + } + + /** + * @notice Private function that ensures all components in a batch transfer share the + * same allocator and consumes the nonce. Reverts if any component has a different + * allocator or if the batch is empty. + * @param components Array of transfer components to check. + * @param nonce The nonce to consume. + * @param allocatorIdRetrieval Function pointer to retrieve allocatorId from components array (handles split components). + * @return allocator The validated allocator address. + */ + function _deriveConsistentAllocatorAndConsumeNonce( + TransferComponent[] calldata components, + uint256 nonce, + function (TransferComponent[] calldata, uint256) internal pure returns (uint96) allocatorIdRetrieval + ) private returns (address allocator) { + // Retrieve the total number of components. + uint256 totalComponents = components.length; + + // Track errors, starting with whether total number of components is zero. + uint256 errorBuffer = (totalComponents == 0).asUint256(); + + // Retrieve the ID of the initial component and derive the allocator ID. + uint96 allocatorId = allocatorIdRetrieval(components, 0); + + // Retrieve the allocator address and consume the nonce. + allocator = allocatorId.fromRegisteredAllocatorIdWithConsumed(nonce); + + unchecked { + // Iterate over each additional component in calldata. + for (uint256 i = 1; i < totalComponents; ++i) { + // Retrieve ID and mark error if derived allocatorId differs from initial one. + errorBuffer |= (allocatorIdRetrieval(components, i) != allocatorId).asUint256(); + } + } + + // Revert if an error was encountered. + assembly ("memory-safe") { + if errorBuffer { + // revert InvalidBatchAllocation() + mstore(0, 0x3a03d3bb) + revert(0x1c, 0x04) + } + } + } + + /** + * @notice Private pure function that retrieves the ID of a batch transfer component from + * an array of components at a specific index and uses it to derive an allocator ID. + * @param components Array of batch transfer components. + * @param index The index of the batch transfer component to retrieve. + * @return allocatorId The allocator ID derived from the transfer component at the given index. + */ + function _allocatorIdOfTransferComponentId(TransferComponent[] calldata components, uint256 index) private pure returns (uint96) { + // Retrieve ID from the component and derive corresponding allocator ID. + return components[index].id.toAllocatorId(); + } + + /** + * @notice Private pure function that retrieves the ID of a split batch transfer component + * from an array of components at a specific index and uses it to derive an allocator ID. + * @param components Array of split batch transfer components. + * @param index The index of the split batch transfer component to retrieve. + * @return allocatorId The allocator ID derived from the transfer component at the given index. + */ + function _allocatorIdOfSplitByIdComponent(SplitByIdComponent[] calldata components, uint256 index) private pure returns (uint96) { + // Retrieve ID from the component and derive corresponding allocator ID. + return components[index].id.toAllocatorId(); + } +} diff --git a/src/lib/ValidityLib.sol b/src/lib/ValidityLib.sol new file mode 100644 index 0000000..d88ec1e --- /dev/null +++ b/src/lib/ValidityLib.sol @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { Scope } from "../types/Scope.sol"; + +import { IdLib } from "./IdLib.sol"; +import { ConsumerLib } from "./ConsumerLib.sol"; +import { EfficiencyLib } from "./EfficiencyLib.sol"; +import { DomainLib } from "./DomainLib.sol"; +import { SignatureCheckerLib } from "solady/utils/SignatureCheckerLib.sol"; + +/** + * @title ValidityLib + * @notice Libray contract implementing logic for validating expirations, + * signatures, nonces (including consuming unused nonces), and token addresses. + */ +library ValidityLib { + using IdLib for uint96; + using IdLib for uint256; + using ConsumerLib for uint256; + using EfficiencyLib for bool; + using DomainLib for bytes32; + using SignatureCheckerLib for address; + using ValidityLib for uint256; + + /** + * @notice Internal function that retrieves an allocator's address from their ID and + * consumes a nonce in their scope. Reverts if the allocator is not registered. + * @param allocatorId The unique identifier for a registered allocator. + * @param nonce The nonce to consume in the allocator's scope. + * @return allocator The address of the registered allocator. + */ + function fromRegisteredAllocatorIdWithConsumed(uint96 allocatorId, uint256 nonce) internal returns (address allocator) { + allocator = allocatorId.toRegisteredAllocator(); + nonce.consumeNonceAsAllocator(allocator); + } + + /** + * @notice Internal function that retrieves an allocator's address from a resource lock ID + * and consumes a nonce in their scope. Reverts if the allocator is not registered. + * @param id The ERC6909 token identifier containing the allocator ID. + * @param nonce The nonce to consume in the allocator's scope. + * @return allocator The address of the registered allocator. + */ + function toRegisteredAllocatorWithConsumed(uint256 id, uint256 nonce) internal returns (address allocator) { + allocator = id.toAllocator(); + nonce.consumeNonceAsAllocator(allocator); + } + + /** + * @notice Internal view function that ensures that a timestamp has not yet passed. + * Reverts if the provided timestamp is not in the future. + * @param expires The timestamp to check. + */ + function later(uint256 expires) internal view { + assembly ("memory-safe") { + if iszero(gt(expires, timestamp())) { + // revert Expired(expiration); + mstore(0, 0xf80dbaea) + mstore(0x20, expires) + revert(0x1c, 0x24) + } + } + } + + /** + * @notice Internal view function that validates a signature against an expected signer. + * Returns if the signature is valid or if the caller is the expected signer, otherwise + * reverts. The message hash is combined with the domain separator before verification. + * If ECDSA recovery fails, an EIP-1271 isValidSignature check is performed. + * @param messageHash The EIP-712 hash of the message to verify. + * @param expectedSigner The address that should have signed the message. + * @param signature The signature to verify. + * @param domainSeparator The domain separator to combine with the message hash. + */ + function signedBy(bytes32 messageHash, address expectedSigner, bytes calldata signature, bytes32 domainSeparator) internal view { + // Apply domain separator to message hash and verify it was signed correctly. + bool hasValidSigner = expectedSigner.isValidSignatureNowCalldata(messageHash.withDomain(domainSeparator), signature); + + assembly ("memory-safe") { + // Allow signature check to be bypassed if caller is the expected signer. + if iszero(or(hasValidSigner, eq(expectedSigner, caller()))) { + // revert InvalidSignature(); + mstore(0, 0x8baa579f) + revert(0x1c, 0x04) + } + } + } + + /** + * @notice Internal view function to check if a nonce has been consumed in an + * allocator's scope. + * @param allocator The allocator whose scope to check. + * @param nonce The nonce to check. + * @return Whether the nonce has been consumed. + */ + function hasConsumedAllocatorNonce(address allocator, uint256 nonce) internal view returns (bool) { + return nonce.isConsumedByAllocator(allocator); + } + + /** + * @notice Internal pure function that validates a token address is not the zero + * address (which represents native tokens). Reverts if the address is zero. + * @param token The token address to validate. + * @return The validated token address. + */ + function excludingNative(address token) internal pure returns (address) { + assembly ("memory-safe") { + if iszero(shl(96, token)) { + // revert InvalidToken(0); + mstore(0x40, 0x961c9a4f) + revert(0x5c, 0x24) + } + } + + return token; + } + + /** + * @notice Internal pure function that checks if an amount is within an allocated + * amount. Reverts if the amount exceeds the allocation. + * @param amount The amount to validate. + * @param allocatedAmount The maximum allowed amount. + */ + function withinAllocated(uint256 amount, uint256 allocatedAmount) internal pure { + assembly ("memory-safe") { + if lt(allocatedAmount, amount) { + // revert AllocatedAmountExceeded(allocatedAmount, amount); + mstore(0, 0x3078b2f6) + mstore(0x20, allocatedAmount) + mstore(0x40, amount) + revert(0x1c, 0x44) + } + } + } + + /** + * @notice Internal pure function for validating that a resource lock's scope is compatible + * with the provided sponsor domain separator. Reverts if an exogenous claim (indicated by + * a non-zero sponsor domain separator) attempts to claim against a chain-specific resource + * lock (indicated by the most significant bit of the id). + * @param sponsorDomainSeparator The domain separator for the sponsor's signature, or zero for non-exogenous claims. + * @param id The ERC6909 token identifier of the resource lock. + */ + function ensureValidScope(bytes32 sponsorDomainSeparator, uint256 id) internal pure { + assembly ("memory-safe") { + if iszero(or(iszero(sponsorDomainSeparator), iszero(shr(255, id)))) { + // revert InvalidScope(id) + mstore(0, 0xa06356f5) + mstore(0x20, id) + revert(0x1c, 0x24) + } + } + } + + /** + * @notice Internal pure function for determining if a resource lock has chain-specific + * scope in the context of an exogenous claim. Returns true if the claim is exogenous + * (indicated by a non-zero sponsor domain separator) and the resource lock is + * chain-specific. + * @param id The ERC6909 token identifier of the resource lock. + * @param sponsorDomainSeparator The domain separator for the sponsor's signature, or zero for non-exogenous claims. + * @return Whether the resource lock's scope is incompatible with the claim context. + */ + function scopeNotMultichain(uint256 id, bytes32 sponsorDomainSeparator) internal pure returns (bool) { + return (sponsorDomainSeparator != bytes32(0)).and(id.toScope() == Scope.ChainSpecific); + } + + /** + * @notice Internal function that combines two claim validations: whether the amount exceeds + * allocation and whether the resource lock's scope is compatible with the claim context. + * Returns true if either the allocated amount is exceeded or if the claim is exogenous but + * the resource lock is chain-specific. + * @param allocatedAmount The total amount allocated for the claim. + * @param amount The amount being claimed. + * @param id The ERC6909 token identifier of the resource lock. + * @param sponsorDomainSeparator The domain separator for the sponsor's signature, or zero for non-exogenous claims. + * @return Whether either validation fails. + */ + function allocationExceededOrScopeNotMultichain(uint256 allocatedAmount, uint256 amount, uint256 id, bytes32 sponsorDomainSeparator) internal pure returns (bool) { + return (allocatedAmount < amount).or(id.scopeNotMultichain(sponsorDomainSeparator)); + } +} diff --git a/src/lib/WithdrawalLogic.sol b/src/lib/WithdrawalLogic.sol new file mode 100644 index 0000000..59b8512 --- /dev/null +++ b/src/lib/WithdrawalLogic.sol @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { ForcedWithdrawalStatus } from "../types/ForcedWithdrawalStatus.sol"; +import { ResetPeriod } from "../types/ResetPeriod.sol"; + +import { SharedLogic } from "./SharedLogic.sol"; +import { EfficiencyLib } from "./EfficiencyLib.sol"; +import { EventLib } from "./EventLib.sol"; +import { IdLib } from "./IdLib.sol"; + +/** + * @title WithdrawalLogic + * @notice Inherited contract implementing internal functions with logic for processing + * forced withdrawals, including initiation and the actual withdrawal, and for querying + * for the forced withdrawal status for given resource locks. + */ +contract WithdrawalLogic is SharedLogic { + using IdLib for uint256; + using IdLib for ResetPeriod; + using EfficiencyLib for uint256; + using EventLib for uint256; + + // Storage scope for forced withdrawal activation times: + // slot: keccak256(_FORCED_WITHDRAWAL_ACTIVATIONS_SCOPE ++ account ++ id) => activates. + uint256 private constant _FORCED_WITHDRAWAL_ACTIVATIONS_SCOPE = 0x41d0e04b; + + /** + * @notice Internal function for initiating a forced withdrawal. Computes the withdrawable + * timestamp by adding the current block timestamp to the reset period associated with the + * resource lock, stores the sum, and emits a ForcedWithdrawalStatusUpdated event. + * @param id The ERC6909 token identifier of the resource lock. + * @return withdrawableAt The timestamp at which tokens become withdrawable. + */ + function _enableForcedWithdrawal(uint256 id) internal returns (uint256 withdrawableAt) { + // Skip overflow check as reset period is bounded. + unchecked { + // Derive the time at which the forced withdrawal is enabled. + withdrawableAt = block.timestamp + id.toResetPeriod().toSeconds(); + } + + // Derive storage slot containing time withdrawal is enabled. + uint256 cutoffTimeSlotLocation = _getCutoffTimeSlot(msg.sender, id); + assembly ("memory-safe") { + // Store the time at which the forced withdrawal is enabled. + sstore(cutoffTimeSlotLocation, withdrawableAt) + } + + // emit the ForcedWithdrawalStatusUpdated event. + id.emitForcedWithdrawalStatusUpdatedEvent(withdrawableAt); + } + + /** + * @notice Internal function for disabling a forced withdrawal. Reverts if the withdrawal + * is already disabled, clears the withdrawable timestamp, and emits a + * ForcedWithdrawalStatusUpdated event. + * @param id The ERC6909 token identifier of the resource lock. + * @return Whether the forced withdrawal was successfully disabled. + */ + function _disableForcedWithdrawal(uint256 id) internal returns (bool) { + // Derive storage slot containing time withdrawal is enabled. + uint256 cutoffTimeSlotLocation = _getCutoffTimeSlot(msg.sender, id); + + assembly ("memory-safe") { + // Revert if withdrawal is already disabled. + if iszero(sload(cutoffTimeSlotLocation)) { + // revert ForcedWithdrawalAlreadyDisabled(msg.sender, id) + mstore(0, 0xe632dbad) + mstore(0x20, caller()) + mstore(0x40, id) + revert(0x1c, 0x44) + } + + // Clear the value for the stored time the withdrawal is enabled. + sstore(cutoffTimeSlotLocation, 0) + } + + // emit the ForcedWithdrawalStatusUpdated event. + id.emitForcedWithdrawalStatusUpdatedEvent(uint256(0).asStubborn()); + + return true; + } + + /** + * @notice Internal function for executing a forced withdrawal. Checks that the withdrawal + * is enabled and the reset period has elapsed, then processes the withdrawal by burning + * ERC6909 tokens and transferring the underlying tokens to the specified recipient. + * @param id The ERC6909 token identifier of the resource lock. + * @param recipient The account that will receive the withdrawn tokens. + * @param amount The amount of tokens to withdraw. + * @return Whether the forced withdrawal was successfully executed. + */ + function _processForcedWithdrawal(uint256 id, address recipient, uint256 amount) internal returns (bool) { + // Derive the storage slot containing the time the withdrawal is enabled. + uint256 cutoffTimeSlotLocation = _getCutoffTimeSlot(msg.sender, id); + + assembly ("memory-safe") { + // Retrieve the value for the time the withdrawal is enabled. + let withdrawableAt := sload(cutoffTimeSlotLocation) + + // Check that withdrawal is not disabled and that reset period has elapsed. + if or(iszero(withdrawableAt), gt(withdrawableAt, timestamp())) { + // revert PrematureWithdrawal(id) + mstore(0, 0x9287bcb0) + mstore(0x20, id) + revert(0x1c, 0x24) + } + } + + // Process the withdrawal. + return _withdraw(msg.sender, recipient, id, amount); + } + + /** + * @notice Internal view function for checking the forced withdrawal status. Returns the + * status (disabled, pending, or enabled) based on whether a withdrawable timestamp exists + * and whether it has elapsed. + * @param account The account to check the status for. + * @param id The ERC6909 token identifier of the resource lock. + * @return status The current ForcedWithdrawalStatus (disabled, pending, or enabled). + * @return enabledAt The timestamp when forced withdrawal becomes possible. + */ + function _getForcedWithdrawalStatus(address account, uint256 id) internal view returns (ForcedWithdrawalStatus status, uint256 enabledAt) { + // Derive the storage slot containing the time the withdrawal is enabled. + uint256 cutoffTimeSlotLocation = _getCutoffTimeSlot(account, id); + + assembly ("memory-safe") { + // Retrieve the value for the time the withdrawal is enabled. + enabledAt := sload(cutoffTimeSlotLocation) + + // Compute status: 0 if disabled, 1 if pending, 2 if enabled. + status := mul(iszero(iszero(enabledAt)), sub(2, gt(enabledAt, timestamp()))) + } + } + + /** + * @notice Private pure function for computing the storage slot for a forced + * withdrawal activation timestamp. + * @param account The account that initiated the forced withdrawal. + * @param id The ERC6909 token identifier of the resource lock. + * @return cutoffTimeSlotLocation The storage slot for the activation timestamp. + */ + function _getCutoffTimeSlot(address account, uint256 id) private pure returns (uint256 cutoffTimeSlotLocation) { + assembly ("memory-safe") { + // Retrieve the current free memory pointer. + let m := mload(0x40) + + // Pack data for computing storage slot. + mstore(0x14, account) + mstore(0, _FORCED_WITHDRAWAL_ACTIVATIONS_SCOPE) + mstore(0x34, id) + + // Compute storage slot from packed data. + cutoffTimeSlotLocation := keccak256(0x1c, 0x38) + + // Restore the free memory pointer. + mstore(0x40, m) + } + } +} diff --git a/src/types/BatchClaims.sol b/src/types/BatchClaims.sol new file mode 100644 index 0000000..1e041e1 --- /dev/null +++ b/src/types/BatchClaims.sol @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { SplitByIdComponent, TransferComponent, BatchClaimComponent, SplitBatchClaimComponent } from "./Components.sol"; + +struct BatchTransfer { + bytes allocatorSignature; // Authorization from the allocator. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the transfer or withdrawal expires. + TransferComponent[] transfers; // The token IDs and amounts to transfer. + address recipient; // The recipient of the batch transfers. +} + +struct SplitBatchTransfer { + bytes allocatorSignature; // Authorization from the allocator. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the transfer or withdrawal expires. + SplitByIdComponent[] transfers; // The recipients and amounts of each transfer for each ID. +} + +struct BatchClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + BatchClaimComponent[] claims; // IDs and amounts. + address claimant; // The claim recipient; specified by the arbiter. +} + +struct QualifiedBatchClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + BatchClaimComponent[] claims; // IDs and amounts. + address claimant; // The claim recipient; specified by the arbiter. +} + +struct BatchClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + BatchClaimComponent[] claims; // IDs and amounts. + address claimant; // The claim recipient; specified by the arbiter. +} + +struct QualifiedBatchClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + BatchClaimComponent[] claims; // IDs and amounts. + address claimant; // The claim recipient; specified by the arbiter. +} + +struct SplitBatchClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + SplitBatchClaimComponent[] claims; // The claim token IDs, recipients and amounts. +} + +struct SplitBatchClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + SplitBatchClaimComponent[] claims; // The claim token IDs, recipients and amounts. +} + +struct QualifiedSplitBatchClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + SplitBatchClaimComponent[] claims; // The claim token IDs, recipients and amounts. +} + +struct QualifiedSplitBatchClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + SplitBatchClaimComponent[] claims; // The claim token IDs, recipients and amounts. +} diff --git a/src/types/BatchMultichainClaims.sol b/src/types/BatchMultichainClaims.sol new file mode 100644 index 0000000..61828e5 --- /dev/null +++ b/src/types/BatchMultichainClaims.sol @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { BatchClaimComponent, SplitBatchClaimComponent } from "./Components.sol"; + +struct BatchMultichainClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32[] additionalChains; // The allocation hashes from additional chains. + BatchClaimComponent[] claims; // IDs and amounts. + address claimant; // The claim recipient; specified by the arbiter. +} + +struct QualifiedBatchMultichainClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + bytes32[] additionalChains; // The allocation hashes from additional chains. + BatchClaimComponent[] claims; // IDs and amounts. + address claimant; // The claim recipient; specified by the arbiter. +} + +struct BatchMultichainClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + bytes32[] additionalChains; // The allocation hashes from additional chains. + BatchClaimComponent[] claims; // IDs and amounts. + address claimant; // The claim recipient; specified by the arbiter. +} + +struct QualifiedBatchMultichainClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + bytes32[] additionalChains; // The allocation hashes from additional chains. + BatchClaimComponent[] claims; // IDs and amounts. + address claimant; // The claim recipient; specified by the arbiter. +} + +struct SplitBatchMultichainClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32[] additionalChains; // The allocation hashes from additional chains. + SplitBatchClaimComponent[] claims; // The claim token IDs, recipients and amounts. +} + +struct SplitBatchMultichainClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + bytes32[] additionalChains; // The allocation hashes from additional chains. + SplitBatchClaimComponent[] claims; // The claim token IDs, recipients and amounts. +} + +struct QualifiedSplitBatchMultichainClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + bytes32[] additionalChains; // The allocation hashes from additional chains. + SplitBatchClaimComponent[] claims; // The claim token IDs, recipients and amounts. +} + +struct QualifiedSplitBatchMultichainClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + bytes32[] additionalChains; // The allocation hashes from additional chains. + SplitBatchClaimComponent[] claims; // The claim token IDs, recipients and amounts. +} + +struct ExogenousBatchMultichainClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 chainIndex; // The index after which to insert the current allocation hash. + uint256 notarizedChainId; // The chain id used to sign the multichain claim. + BatchClaimComponent[] claims; // IDs and amounts. + address claimant; // The claim recipient; specified by the arbiter. +} + +struct ExogenousQualifiedBatchMultichainClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 chainIndex; // The index after which to insert the current allocation hash. + uint256 notarizedChainId; // The chain id used to sign the multichain claim. + BatchClaimComponent[] claims; // IDs and amounts. + address claimant; // The claim recipient; specified by the arbiter. +} + +struct ExogenousBatchMultichainClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 chainIndex; // The index after which to insert the current allocation hash. + uint256 notarizedChainId; // The chain id used to sign the multichain claim. + BatchClaimComponent[] claims; // IDs and amounts. + address claimant; // The claim recipient; specified by the arbiter. +} + +struct ExogenousQualifiedBatchMultichainClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 chainIndex; // The index after which to insert the current allocation hash. + uint256 notarizedChainId; // The chain id used to sign the multichain claim. + BatchClaimComponent[] claims; // IDs and amounts. + address claimant; // The claim recipient; specified by the arbiter. +} + +struct ExogenousSplitBatchMultichainClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 chainIndex; // The index after which to insert the current allocation hash. + uint256 notarizedChainId; // The chain id used to sign the multichain claim. + SplitBatchClaimComponent[] claims; // The claim token IDs, recipients and amounts. +} + +struct ExogenousSplitBatchMultichainClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 chainIndex; // The index after which to insert the current allocation hash. + uint256 notarizedChainId; // The chain id used to sign the multichain claim. + SplitBatchClaimComponent[] claims; // The claim token IDs, recipients and amounts. +} + +struct ExogenousQualifiedSplitBatchMultichainClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 chainIndex; // The index after which to insert the current allocation hash. + uint256 notarizedChainId; // The chain id used to sign the multichain claim. + SplitBatchClaimComponent[] claims; // The claim token IDs, recipients and amounts. +} + +struct ExogenousQualifiedSplitBatchMultichainClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 chainIndex; // The index after which to insert the current allocation hash. + uint256 notarizedChainId; // The chain id used to sign the multichain claim. + SplitBatchClaimComponent[] claims; // The claim token IDs, recipients and amounts. +} diff --git a/src/types/Claims.sol b/src/types/Claims.sol new file mode 100644 index 0000000..df4fb87 --- /dev/null +++ b/src/types/Claims.sol @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { SplitComponent } from "./Components.sol"; + +struct BasicTransfer { + bytes allocatorSignature; // Authorization from the allocator. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the transfer or withdrawal expires. + uint256 id; // The token ID of the ERC6909 token to transfer or withdraw. + uint256 amount; // The token amount to transfer or withdraw. + address recipient; // The recipient of the transfer or withdrawal. +} + +struct SplitTransfer { + bytes allocatorSignature; // Authorization from the allocator. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the transfer or withdrawal expires. + uint256 id; // The token ID of the ERC6909 token to transfer or withdraw. + SplitComponent[] recipients; // The recipients and amounts of each transfer. +} + +struct BasicClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + address claimant; // The claim recipient; specified by the arbiter. + uint256 amount; // The claimed token amount; specified by the arbiter. +} + +struct QualifiedClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + address claimant; // The claim recipient; specified by the arbiter. + uint256 amount; // The claimed token amount; specified by the arbiter. +} + +struct ClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + address claimant; // The claim recipient; specified by the arbiter. + uint256 amount; // The claimed token amount; specified by the arbiter. +} + +struct QualifiedClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + address claimant; // The claim recipient; specified by the arbiter. + uint256 amount; // The claimed token amount; specified by the arbiter. +} + +struct SplitClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + SplitComponent[] claimants; // The claim recipients and amounts; specified by the arbiter. +} + +struct SplitClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + SplitComponent[] claimants; // The claim recipients and amounts; specified by the arbiter. +} + +struct QualifiedSplitClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + SplitComponent[] claimants; // The claim recipients and amounts; specified by the arbiter. +} + +struct QualifiedSplitClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + SplitComponent[] claimants; // The claim recipients and amounts; specified by the arbiter. +} diff --git a/src/types/CompactCategory.sol b/src/types/CompactCategory.sol new file mode 100644 index 0000000..f345f5e --- /dev/null +++ b/src/types/CompactCategory.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +enum CompactCategory { + Compact, + BatchCompact, + MultichainCompact +} diff --git a/src/types/Components.sol b/src/types/Components.sol new file mode 100644 index 0000000..39f04e2 --- /dev/null +++ b/src/types/Components.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +struct SplitComponent { + address claimant; // The recipient of the transfer or withdrawal. + uint256 amount; // The amount of tokens to transfer or withdraw. +} + +struct SplitByIdComponent { + uint256 id; // The token ID of the ERC6909 token to transfer or withdraw. + SplitComponent[] portions; // claimants and amounts. +} + +struct TransferComponent { + uint256 id; // The token ID of the ERC6909 token to transfer or withdraw. + uint256 amount; // The token amount to transfer or withdraw. +} + +struct BatchClaimComponent { + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + uint256 amount; // The claimed token amount; specified by the arbiter. +} + +struct SplitBatchClaimComponent { + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + SplitComponent[] portions; // claimants and amounts. +} diff --git a/src/types/EIP712Types.sol b/src/types/EIP712Types.sol new file mode 100644 index 0000000..9ae66a9 --- /dev/null +++ b/src/types/EIP712Types.sol @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +// Message signed by the sponsor that specifies the conditions under which their +// tokens can be claimed; the specified arbiter verifies that those conditions +// have been met and specifies a set of beneficiaries that will receive up to the +// specified amount of tokens. +struct Compact { + address arbiter; // The account tasked with verifying and submitting the claim. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 amount; // The amount of ERC6909 tokens to allocate. + // Optional witness may follow. +} + +// keccak256(bytes("Compact(address arbiter,address sponsor,uint256 nonce,uint256 expires,uint256 id,uint256 amount)")) +bytes32 constant COMPACT_TYPEHASH = 0xcdca950b17b5efc016b74b912d8527dfba5e404a688cbc3dab16cb943287fec2; + +// abi.decode(bytes("Compact(address arbiter,address "), (bytes32)) +bytes32 constant COMPACT_TYPESTRING_FRAGMENT_ONE = 0x436f6d70616374286164647265737320617262697465722c6164647265737320; + +// abi.decode(bytes("sponsor,uint256 nonce,uint256 ex"), (bytes32)) +bytes32 constant COMPACT_TYPESTRING_FRAGMENT_TWO = 0x73706f6e736f722c75696e74323536206e6f6e63652c75696e74323536206578; + +// abi.decode(bytes("pires,uint256 id,uint256 amount,"), (bytes32)) +bytes32 constant COMPACT_TYPESTRING_FRAGMENT_THREE = 0x70697265732c75696e743235362069642c75696e7432353620616d6f756e742c; + +// Message signed by the sponsor that specifies the conditions under which a set of +// tokens, each sharing an allocator, can be claimed; the specified arbiter verifies +// that those conditions have been met and specifies a set of beneficiaries that will +// receive up to the specified amounts of each token. +struct BatchCompact { + address arbiter; // The account tasked with verifying and submitting the claim. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + uint256[2][] idsAndAmounts; // The allocated token IDs and amounts. + // Optional witness may follow. +} + +// keccak256(bytes("BatchCompact(address arbiter,address sponsor,uint256 nonce,uint256 expires,uint256[2][] idsAndAmounts)")) +bytes32 constant BATCH_COMPACT_TYPEHASH = 0x5a7fee8000a237929ef9be08f2933c4b4f320b00b38809f3c7aa104d5421049f; + +// abi.decode(bytes("BatchCompact(address arbiter,add"), (bytes32)) +bytes32 constant BATCH_COMPACT_TYPESTRING_FRAGMENT_ONE = 0x4261746368436f6d70616374286164647265737320617262697465722c616464; + +// abi.decode(bytes("ress sponsor,uint256 nonce,uint2"), (bytes32)) +bytes32 constant BATCH_COMPACT_TYPESTRING_FRAGMENT_TWO = 0x726573732073706f6e736f722c75696e74323536206e6f6e63652c75696e7432; + +// abi.decode(bytes("56 expires,uint256[2][] idsAndAm"), (bytes32)) +bytes32 constant BATCH_COMPACT_TYPESTRING_FRAGMENT_THREE = 0x353620657870697265732c75696e743235365b325d5b5d20696473416e64416d; + +// uint48(abi.decode(bytes("ounts,"), (bytes6))) +uint48 constant BATCH_COMPACT_TYPESTRING_FRAGMENT_FOUR = 0x6f756e74732c; + +// A multichain compact can declare tokens and amounts to allocate from multiple chains, +// each designated by their chainId. Any allocated tokens on an exogenous domain (e.g. all +// but the first segment) must designate the Multichain scope. Each segment may designate +// a unique arbiter for the chain in question. Note that the witness data is distinct for +// each segment, but all segments must share the same EIP-712 witness typestring. +struct Segment { + address arbiter; // The account tasked with verifying and submitting the claim. + uint256 chainId; // The chainId where the tokens are located. + uint256[2][] idsAndAmounts; // The allocated token IDs and amounts. + // Optional witness may follow. +} + +// keccak256(bytes("Segment(address arbiter,uint256 chainId,uint256[2][] idsAndAmounts)")) +bytes32 constant SEGMENT_TYPEHASH = 0x295feb095767cc67d7e74695da0adaddede54d7b7194a8a5426fe8f0351e0337; + +// Message signed by the sponsor that specifies the conditions under which a set of +// tokens across a number of different chains can be claimed; the specified arbiter on +// each chain verifies that those conditions have been met and specifies a set of +// beneficiaries that will receive up to the specified amounts of each token. +struct MultichainCompact { + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + Segment[] segments; // Arbiter, chainId, ids & amounts, and witness for each chain. +} + +// keccak256(bytes("MultichainCompact(address sponsor,uint256 nonce,uint256 expires,Segment[] segments)Segment(address arbiter,uint256 chainId,uint256[2][] idsAndAmounts)")) +bytes32 constant MULTICHAIN_COMPACT_TYPEHASH = 0x5ca9a66b8bbf0d2316e90dfa3df465f0790b277b25393a3ef4d67e1f50865057; + +// abi.decode(bytes("MultichainCompact(address sponso"), (bytes32)) +bytes32 constant MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_ONE = 0x4d756c7469636861696e436f6d7061637428616464726573732073706f6e736f; + +// abi.decode(bytes("r,uint256 nonce,uint256 expires,"), (bytes32)) +bytes32 constant MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_TWO = 0x722c75696e74323536206e6f6e63652c75696e7432353620657870697265732c; + +// abi.decode(bytes("Segment[] segments)Segment(addre"), (bytes32)) +bytes32 constant MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_THREE = 0x5365676d656e745b5d207365676d656e7473295365676d656e74286164647265; + +// abi.decode(bytes("ss arbiter,uint256 chainId,uint2"), (bytes32)) +bytes32 constant MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_FOUR = 0x737320617262697465722c75696e7432353620636861696e49642c75696e7432; + +// uint176(abi.decode(bytes("56[2][] idsAndAmounts,"), (bytes22))) +uint176 constant MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_FIVE = 0x35365b325d5b5d20696473416e64416d6f756e74732c; + +// The allocator can optionally attest to arbitrary parameters. Any EIP-712 data +// type can be utilized as long as the first argument is the message hash of the +// associated compact signed by the sponsor, which will be supplied by The Compact. +// If additional parameters are not required, the allocator instead signs the same +// payload as the sponsor. + +// An Emissary is an account that is authorized by a sponsor to register claims. +// This could be a contract that facilitates the creation of dynamic claims, or +// could relay multichain claims registerd on other domains. +struct EmissaryAssignment { + address emissary; // The account to assign as the emissary. + uint256 nonce; // A parameter to enforce replay protection, scoped to sponsor. + uint256 expires; // The time at which the assignment expires. + bool assigned; // Whether to assign the emissary or to unassign them. +} + +// keccak256(bytes("EmissaryAssignment(address emissary,uint256 nonce,uint256 expires)")) +bytes32 constant EMISSARY_ASSIGNMENT_TYPEHASH = 0x5ca9a66b8bbf0d2316e90dfa3df465f0790b277b25393a3ef4d67e1f50865057; + +/// @dev `keccak256(bytes("CompactDeposit(address allocator,uint8 resetPeriod,uint8 scope,address recipient)"))`. +bytes32 constant PERMIT2_DEPOSIT_WITNESS_FRAGMENT_HASH = 0xe055493563385cc588fffacbffe2dab023fef807baa449530431169b0eeb5b69; + +/// @dev `keccak256(bytes("Activation(uint256 id,Compact compact)Compact(address arbiter,address sponsor,uint256 nonce,uint256 expires,uint256 id,uint256 amount)"))`. +bytes32 constant COMPACT_ACTIVATION_TYPEHASH = 0x2bf981c42c7f423b06fa49ba996d2930887e2f1f53d9a26b8c7423ac1cf83e61; + +/// @dev `keccak256(bytes("Activation(uint256 id,BatchCompact compact)BatchCompact(address arbiter,address sponsor,uint256 nonce,uint256 expires,uint256[2][] idsAndAmounts)"))`. +bytes32 constant BATCH_COMPACT_ACTIVATION_TYPEHASH = 0xd14445d78213a5acddfa89171b0199de521c3b36738b835264cae18f5a53dbf3; + +/// @dev `keccak256(bytes("Activation(uint256 id,MultichainCompact compact)MultichainCompact(address sponsor,uint256 nonce,uint256 expires,Segment[] segments)Segment(address arbiter,uint256 chainId,uint256[2][] idsAndAmounts)"))`. +bytes32 constant MULTICHAIN_COMPACT_ACTIVATION_TYPEHASH = 0x329b3c527a3c74b8cabc51c304669d1866b87352cafdf440ef2becd6dc261d1e; + +/// @dev `keccak256(bytes("BatchActivation(uint256[] ids,Compact compact)Compact(address arbiter,address sponsor,uint256 nonce,uint256 expires,uint256 id,uint256 amount)"))`. +bytes32 constant COMPACT_BATCH_ACTIVATION_TYPEHASH = 0x45012d42fad8c9e937cff5a2d750ee18713dd45aadcd718660d5523056618d99; + +/// @dev `keccak256(bytes("BatchActivation(uint256[] ids,BatchCompact compact)BatchCompact(address arbiter,address sponsor,uint256 nonce,uint256 expires,uint256[2][] idsAndAmounts)"))`. +bytes32 constant BATCH_COMPACT_BATCH_ACTIVATION_TYPEHASH = 0xc2e16a823b8cdddfdf889991d7a461f0a19faf1f8e608f1c164495a52151cc3e; + +/// @dev `keccak256(bytes("BatchActivation(uint256[] ids,MultichainCompact compact)MultichainCompact(address sponsor,uint256 nonce,uint256 expires,Segment[] segments)Segment(address arbiter,uint256 chainId,uint256[2][] idsAndAmounts)"))`. +bytes32 constant MULTICHAIN_COMPACT_BATCH_ACTIVATION_TYPEHASH = 0xd2f6ad391328936f118250f231e63c7e639f9756a9ebf972d81763870a772d87; + +// abi.decode(bytes("Activation witness)Activation(ui"), (bytes32)) +bytes32 constant PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE = 0x41637469766174696f6e207769746e6573732941637469766174696f6e287569; + +// uint72(abi.decode(bytes("nt256 id,"), (bytes9))) +uint72 constant PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO = 0x6e743235362069642c; + +// abi.decode(bytes("BatchActivation witness)BatchAct"), (bytes32)) +bytes32 constant PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE = 0x426174636841637469766174696f6e207769746e657373294261746368416374; + +// uint176(abi.decode(bytes("ivation(uint256[] ids,"), (bytes22))) +uint176 constant PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO = 0x69766174696f6e2875696e743235365b5d206964732c; + +// abi.decode(bytes("Compact compact)Compact(address "), (bytes32)) +bytes32 constant PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_ONE = 0x436f6d7061637420636f6d7061637429436f6d70616374286164647265737320; + +// abi.decode(bytes("arbiter,address sponsor,uint256 "), (bytes32)) +bytes32 constant PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_TWO = 0x617262697465722c616464726573732073706f6e736f722c75696e7432353620; + +// abi.decode(bytes("nonce,uint256 expires,uint256 id"), (bytes32)) +bytes32 constant PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_THREE = 0x6e6f6e63652c75696e7432353620657870697265732c75696e74323536206964; + +// uint128(abi.decode(bytes(",uint256 amount,"), (bytes16))) +uint128 constant PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_FOUR = 0x2c75696e7432353620616d6f756e742c; + +// abi.decode(bytes("BatchCompact compact)BatchCompac"), (bytes32)) +bytes32 constant PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_ONE = 0x4261746368436f6d7061637420636f6d70616374294261746368436f6d706163; + +// abi.decode(bytes("t(address arbiter,address sponso"), (bytes32)) +bytes32 constant PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_TWO = 0x74286164647265737320617262697465722c616464726573732073706f6e736f; + +// abi.decode(bytes("r,uint256 nonce,uint256 expires,"), (bytes32)) +bytes32 constant PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_THREE = 0x722c75696e74323536206e6f6e63652c75696e7432353620657870697265732c; + +// uint216(abi.decode(bytes("uint256[2][] idsAndAmounts,"), (bytes27))) +uint216 constant PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_FOUR = 0x75696e743235365b325d5b5d20696473416e64416d6f756e74732c; + +// abi.decode(bytes("MultichainCompact compact)Multic"), (bytes32)) +bytes32 constant PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_ONE = 0x4d756c7469636861696e436f6d7061637420636f6d70616374294d756c746963; + +// abi.decode(bytes("hainCompact(address sponsor,uint"), (bytes32)) +bytes32 constant PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_TWO = 0x6861696e436f6d7061637428616464726573732073706f6e736f722c75696e74; + +// abi.decode(bytes("256 nonce,uint256 expires,Segmen"), (bytes32)) +bytes32 constant PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_THREE = 0x323536206e6f6e63652c75696e7432353620657870697265732c5365676d656e; + +// abi.decode(bytes("t[] segments)Segment(address arb"), (bytes32)) +bytes32 constant PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_FOUR = 0x745b5d207365676d656e7473295365676d656e74286164647265737320617262; + +// abi.decode(bytes("iter,uint256 chainId,uint256[2]["), (bytes32)) +bytes32 constant PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_FIVE = 0x697465722c75696e7432353620636861696e49642c75696e743235365b325d5b; + +// uint128(abi.decode(bytes("] idsAndAmounts,"), (bytes16))) +uint128 constant PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_SIX = 0x5d20696473416e64416d6f756e74732c; + +// abi.decode(bytes(")TokenPermissions(address token,"), (bytes32)) +bytes32 constant TOKEN_PERMISSIONS_TYPESTRING_FRAGMENT_ONE = 0x29546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c; + +// uint120(abi.decode(bytes("uint256 amount)"), (bytes15))) +uint120 constant TOKEN_PERMISSIONS_TYPESTRING_FRAGMENT_TWO = 0x75696e7432353620616d6f756e7429; + +// abi.decode(bytes("CompactDeposit witness)CompactDe"), (bytes32)) +uint256 constant COMPACT_DEPOSIT_TYPESTRING_FRAGMENT_ONE = 0x436f6d706163744465706f736974207769746e65737329436f6d706163744465; + +// abi.decode(bytes("posit(address allocator,uint8 re"), (bytes32)) +uint256 constant COMPACT_DEPOSIT_TYPESTRING_FRAGMENT_TWO = 0x706f736974286164647265737320616c6c6f6361746f722c75696e7438207265; + +// abi.decode(bytes("setPeriod,uint8 scope,address re"), (bytes32)) +uint256 constant COMPACT_DEPOSIT_TYPESTRING_FRAGMENT_THREE = 0x736574506572696f642c75696e74382073636f70652c61646472657373207265; + +// abi.decode(bytes("cipient)TokenPermissions(address"), (bytes32)) +uint256 constant COMPACT_DEPOSIT_TYPESTRING_FRAGMENT_FOUR = 0x63697069656e7429546f6b656e5065726d697373696f6e732861646472657373; + +// uint176(abi.decode(bytes(" token,uint256 amount)"), (bytes32)) +uint176 constant COMPACT_DEPOSIT_TYPESTRING_FRAGMENT_FIVE = 0x20746f6b656e2c75696e7432353620616d6f756e7429; diff --git a/src/types/ForcedWithdrawalStatus.sol b/src/types/ForcedWithdrawalStatus.sol new file mode 100644 index 0000000..b0e35c3 --- /dev/null +++ b/src/types/ForcedWithdrawalStatus.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +enum ForcedWithdrawalStatus { + Disabled, // Not pending or enabled for forced withdrawal + Pending, // Not yet available, but initiated + Enabled // Available for forced withdrawal on demand + +} diff --git a/src/types/Lock.sol b/src/types/Lock.sol new file mode 100644 index 0000000..7494878 --- /dev/null +++ b/src/types/Lock.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { ResetPeriod } from "./ResetPeriod.sol"; +import { Scope } from "./Scope.sol"; + +struct Lock { + address token; + address allocator; + ResetPeriod resetPeriod; + Scope scope; +} diff --git a/src/types/MultichainClaims.sol b/src/types/MultichainClaims.sol new file mode 100644 index 0000000..adb3d65 --- /dev/null +++ b/src/types/MultichainClaims.sol @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import { SplitComponent } from "./Components.sol"; + +struct MultichainClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + address claimant; // The claim recipient; specified by the arbiter. + uint256 amount; // The claimed token amount; specified by the arbiter. +} + +struct QualifiedMultichainClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + address claimant; // The claim recipient; specified by the arbiter. + uint256 amount; // The claimed token amount; specified by the arbiter. +} + +struct MultichainClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + address claimant; // The claim recipient; specified by the arbiter. + uint256 amount; // The claimed token amount; specified by the arbiter. +} + +struct QualifiedMultichainClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + address claimant; // The claim recipient; specified by the arbiter. + uint256 amount; // The claimed token amount; specified by the arbiter. +} + +struct SplitMultichainClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + SplitComponent[] claimants; // The claim recipients and amounts; specified by the arbiter. +} + +struct SplitMultichainClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + SplitComponent[] claimants; // The claim recipients and amounts; specified by the arbiter. +} + +struct QualifiedSplitMultichainClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + SplitComponent[] claimants; // The claim recipients and amounts; specified by the arbiter. +} + +struct QualifiedSplitMultichainClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + SplitComponent[] claimants; // The claim recipients and amounts; specified by the arbiter. +} + +struct ExogenousMultichainClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 chainIndex; // The index after which to insert the current allocation hash. + uint256 notarizedChainId; // The chain id used to sign the multichain claim. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + address claimant; // The claim recipient; specified by the arbiter. + uint256 amount; // The claimed token amount; specified by the arbiter. +} + +struct ExogenousQualifiedMultichainClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 chainIndex; // The index after which to insert the current allocation hash. + uint256 notarizedChainId; // The chain id used to sign the multichain claim. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + address claimant; // The claim recipient; specified by the arbiter. + uint256 amount; // The claimed token amount; specified by the arbiter. +} + +struct ExogenousMultichainClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 chainIndex; // The index after which to insert the current allocation hash. + uint256 notarizedChainId; // The chain id used to sign the multichain claim. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + address claimant; // The claim recipient; specified by the arbiter. + uint256 amount; // The claimed token amount; specified by the arbiter. +} + +struct ExogenousQualifiedMultichainClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 chainIndex; // The index after which to insert the current allocation hash. + uint256 notarizedChainId; // The chain id used to sign the multichain claim. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + address claimant; // The claim recipient; specified by the arbiter. + uint256 amount; // The claimed token amount; specified by the arbiter. +} + +struct ExogenousSplitMultichainClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 chainIndex; // The index after which to insert the current allocation hash. + uint256 notarizedChainId; // The chain id used to sign the multichain claim. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + SplitComponent[] claimants; // The claim recipients and amounts; specified by the arbiter. +} + +struct ExogenousSplitMultichainClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 chainIndex; // The index after which to insert the current allocation hash. + uint256 notarizedChainId; // The chain id used to sign the multichain claim. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + SplitComponent[] claimants; // The claim recipients and amounts; specified by the arbiter. +} + +struct ExogenousQualifiedSplitMultichainClaim { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 chainIndex; // The index after which to insert the current allocation hash. + uint256 notarizedChainId; // The chain id used to sign the multichain claim. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + SplitComponent[] claimants; // The claim recipients and amounts; specified by the arbiter. +} + +struct ExogenousQualifiedSplitMultichainClaimWithWitness { + bytes allocatorSignature; // Authorization from the allocator. + bytes sponsorSignature; // Authorization from the sponsor. + address sponsor; // The account to source the tokens from. + uint256 nonce; // A parameter to enforce replay protection, scoped to allocator. + uint256 expires; // The time at which the claim expires. + bytes32 witness; // Hash of the witness data. + string witnessTypestring; // Witness typestring appended to existing typestring. + bytes32 qualificationTypehash; // Typehash of the qualification payload. + bytes qualificationPayload; // Data used to derive qualification hash. + bytes32[] additionalChains; // The allocation hashes from additional chains. + uint256 chainIndex; // The index after which to insert the current allocation hash. + uint256 notarizedChainId; // The chain id used to sign the multichain claim. + uint256 id; // The token ID of the ERC6909 token to allocate. + uint256 allocatedAmount; // The original allocated amount of ERC6909 tokens. + SplitComponent[] claimants; // The claim recipients and amounts; specified by the arbiter. +} diff --git a/src/types/ResetPeriod.sol b/src/types/ResetPeriod.sol new file mode 100644 index 0000000..5bf0eca --- /dev/null +++ b/src/types/ResetPeriod.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +enum ResetPeriod { + OneSecond, + FifteenSeconds, + OneMinute, + TenMinutes, + OneHourAndFiveMinutes, + OneDay, + SevenDaysAndOneHour, + ThirtyDays +} diff --git a/src/types/Scope.sol b/src/types/Scope.sol new file mode 100644 index 0000000..842e8ef --- /dev/null +++ b/src/types/Scope.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +enum Scope { + Multichain, + ChainSpecific +} From 5a5b649ec39ab8f0e84289e6333df5960d6ed65a Mon Sep 17 00:00:00 2001 From: 0age <37939117+0age@users.noreply.github.com> Date: Thu, 7 Nov 2024 11:18:42 -0800 Subject: [PATCH 2/2] Fix typos --- src/lib/ClaimHashFunctionCastLib.sol | 2 +- src/lib/ClaimHashLib.sol | 2 +- src/lib/ClaimProcessorFunctionCastLib.sol | 2 +- src/lib/ConsumerLib.sol | 2 +- src/lib/DomainLib.sol | 2 +- src/lib/HashLib.sol | 2 +- src/lib/IdLib.sol | 2 +- src/lib/MetadataLib.sol | 2 +- src/lib/RegistrationLib.sol | 2 +- src/lib/TransferFunctionCastLib.sol | 2 +- src/lib/ValidityLib.sol | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/lib/ClaimHashFunctionCastLib.sol b/src/lib/ClaimHashFunctionCastLib.sol index e318de9..6ee3577 100644 --- a/src/lib/ClaimHashFunctionCastLib.sol +++ b/src/lib/ClaimHashFunctionCastLib.sol @@ -54,7 +54,7 @@ import { /** * @title ClaimHashFunctionCastLib - * @notice Libray contract implementing function casts used throughout the codebase, + * @notice Library contract implementing function casts used throughout the codebase, * particularly as part of processing claims. The input function operates on a * function that takes some argument that differs from what is currently available. * The output function modifies one or more argument types so that they match the diff --git a/src/lib/ClaimHashLib.sol b/src/lib/ClaimHashLib.sol index e5a36ab..2d08076 100644 --- a/src/lib/ClaimHashLib.sol +++ b/src/lib/ClaimHashLib.sol @@ -76,7 +76,7 @@ import { HashLib } from "./HashLib.sol"; /** * @title ClaimHashLib - * @notice Libray contract implementing logic for deriving hashes as part of processing + * @notice Library contract implementing logic for deriving hashes as part of processing * claims, allocated transfers, and withdrawals. */ library ClaimHashLib { diff --git a/src/lib/ClaimProcessorFunctionCastLib.sol b/src/lib/ClaimProcessorFunctionCastLib.sol index 55d5b4d..859da17 100644 --- a/src/lib/ClaimProcessorFunctionCastLib.sol +++ b/src/lib/ClaimProcessorFunctionCastLib.sol @@ -54,7 +54,7 @@ import { /** * @title ClaimProcessorFunctionCastLib - * @notice Libray contract implementing function casts used in ClaimProcessorLogic. + * @notice Library contract implementing function casts used in ClaimProcessorLogic. * The input function operates on a function that takes some argument that differs * from what is currently available. The output function modifies one or more * argument types so that they match the arguments that are being used to call the diff --git a/src/lib/ConsumerLib.sol b/src/lib/ConsumerLib.sol index 6d18526..ab0ad6c 100644 --- a/src/lib/ConsumerLib.sol +++ b/src/lib/ConsumerLib.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.27; /** * @title ConsumerLib - * @notice Libray contract implementing logic for consuming bitpacked nonces scoped to + * @notice Library contract implementing logic for consuming bitpacked nonces scoped to * specific accounts and for querying for the state of those nonces. Note that only the * allocator nonce scope is currently in use in The Compact. */ diff --git a/src/lib/DomainLib.sol b/src/lib/DomainLib.sol index 509f0ab..32d6626 100644 --- a/src/lib/DomainLib.sol +++ b/src/lib/DomainLib.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.27; /** * @title DomainLib - * @notice Libray contract implementing logic for deriving domain hashes. + * @notice Library contract implementing logic for deriving domain hashes. */ library DomainLib { /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`. diff --git a/src/lib/HashLib.sol b/src/lib/HashLib.sol index fde0eb3..7313fae 100644 --- a/src/lib/HashLib.sol +++ b/src/lib/HashLib.sol @@ -31,7 +31,7 @@ import { TransferFunctionCastLib } from "./TransferFunctionCastLib.sol"; /** * @title HashLib - * @notice Libray contract implementing logic for deriving hashes as part of processing + * @notice Library contract implementing logic for deriving hashes as part of processing * claims, allocated transfers, and withdrawals, including deriving typehashes when * witness data is utilized and qualification hashes when claims have been qualified by * the allocator. diff --git a/src/lib/IdLib.sol b/src/lib/IdLib.sol index 57905c1..83d2db8 100644 --- a/src/lib/IdLib.sol +++ b/src/lib/IdLib.sol @@ -13,7 +13,7 @@ import { EfficientHashLib } from "solady/utils/EfficientHashLib.sol"; /** * @title IdLib - * @notice Libray contract implementing logic for deriving IDs for allocators and + * @notice Library contract implementing logic for deriving IDs for allocators and * for resource locks, converting between various IDs, and for extracting details * related to those IDs. This includes logic for registering allocators and for * assigning them an allocator ID. diff --git a/src/lib/MetadataLib.sol b/src/lib/MetadataLib.sol index 074e937..f6baadd 100644 --- a/src/lib/MetadataLib.sol +++ b/src/lib/MetadataLib.sol @@ -11,7 +11,7 @@ import { MetadataReaderLib } from "solady/utils/MetadataReaderLib.sol"; /** * @title MetadataLib - * @notice Libray contract implementing logic for deriving and displaying + * @notice Library contract implementing logic for deriving and displaying * ERC6909 metadata as well as metadata specific to various underlying tokens. */ library MetadataLib { diff --git a/src/lib/RegistrationLib.sol b/src/lib/RegistrationLib.sol index 9b397f2..20f37fb 100644 --- a/src/lib/RegistrationLib.sol +++ b/src/lib/RegistrationLib.sol @@ -8,7 +8,7 @@ import { IdLib } from "./IdLib.sol"; /** * @title RegistrationLib - * @notice Libray contract implementing logic for registering compact claim hashes + * @notice Library contract implementing logic for registering compact claim hashes * and typehashes and querying for whether given claim hashes and typehashes have * been registered. */ diff --git a/src/lib/TransferFunctionCastLib.sol b/src/lib/TransferFunctionCastLib.sol index 4db7b1f..38e4277 100644 --- a/src/lib/TransferFunctionCastLib.sol +++ b/src/lib/TransferFunctionCastLib.sol @@ -7,7 +7,7 @@ import { TransferComponent, SplitByIdComponent } from "../types/Components.sol"; /** * @title TransferFunctionCastLib - * @notice Libray contract implementing function casts used in TransferLogic as well as + * @notice Library contract implementing function casts used in TransferLogic as well as * in HashLib. The input function operates on a function that takes some argument that * differs from what is currently available. The output function modifies one or more * argument types so that they match the arguments that are being used to call the diff --git a/src/lib/ValidityLib.sol b/src/lib/ValidityLib.sol index d88ec1e..6a765e5 100644 --- a/src/lib/ValidityLib.sol +++ b/src/lib/ValidityLib.sol @@ -11,7 +11,7 @@ import { SignatureCheckerLib } from "solady/utils/SignatureCheckerLib.sol"; /** * @title ValidityLib - * @notice Libray contract implementing logic for validating expirations, + * @notice Library contract implementing logic for validating expirations, * signatures, nonces (including consuming unused nonces), and token addresses. */ library ValidityLib {