From 1ab6d08cf56182a2336ce8eb4b43f94cb8a9862d Mon Sep 17 00:00:00 2001 From: 0age <37939117+0age@users.noreply.github.com> Date: Wed, 30 Oct 2024 23:54:15 -0700 Subject: [PATCH] Break out Permit2 logic and organize claim processor logic --- src/lib/ClaimProcessorLogic.sol | 1017 ++++++++++++++-------------- src/lib/DepositLogic.sol | 551 +-------------- src/lib/DepositViaPermit2Logic.sol | 546 +++++++++++++++ src/lib/WithdrawalLogic.sol | 4 +- 4 files changed, 1073 insertions(+), 1045 deletions(-) create mode 100644 src/lib/DepositViaPermit2Logic.sol diff --git a/src/lib/ClaimProcessorLogic.sol b/src/lib/ClaimProcessorLogic.sol index e6cbafd..e896e2b 100644 --- a/src/lib/ClaimProcessorLogic.sol +++ b/src/lib/ClaimProcessorLogic.sol @@ -130,333 +130,100 @@ contract ClaimProcessorLogic is WithdrawalLogic { /// @dev `keccak256(bytes("Claim(address,address,address,bytes32)"))`. uint256 private constant _CLAIM_EVENT_SIGNATURE = 0x770c32a2314b700d6239ee35ba23a9690f2fceb93a55d8c753e953059b3b18d4; - function _processSimpleClaim(bytes32 messageHash, uint256 calldataPointer, uint256 offsetToId, bytes32 typehash, function(address, address, uint256, uint256) internal returns (bool) operation) - internal - returns (bool) - { - return _processClaimWithQualificationAndSponsorDomain(messageHash, messageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, operation); - } - - function _processSimpleSplitClaim( - bytes32 messageHash, - uint256 calldataPointer, - uint256 offsetToId, - bytes32 typehash, - function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { - return _processSplitClaimWithQualificationAndSponsorDomain(messageHash, messageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, operation); - } - - function _processSimpleBatchClaim( - bytes32 messageHash, - uint256 calldataPointer, - uint256 offsetToId, - bytes32 typehash, - function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { - return _processBatchClaimWithQualificationAndSponsorDomain(messageHash, messageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, operation); - } - - function _processBatchClaimWithQualification( - bytes32 messageHash, - bytes32 qualificationMessageHash, - uint256 calldataPointer, - uint256 offsetToId, - bytes32 typehash, - function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { - return _processBatchClaimWithQualificationAndSponsorDomain(messageHash, qualificationMessageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, operation); - } - - function _processSimpleSplitBatchClaim( - bytes32 messageHash, - uint256 calldataPointer, - uint256 offsetToId, - bytes32 typehash, - function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { - return _processSplitBatchClaimWithQualificationAndSponsorDomain(messageHash, messageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, operation); + ///// 1. Claims ///// + function _processBasicClaim(BasicClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + return _processSimpleClaim.usingBasicClaim()(claimPayload.toMessageHash(), claimPayload, uint256(0xa0).asStubborn(), _typehashes(uint256(0).asStubborn()), operation); } - function _processSplitBatchClaimWithQualification( - bytes32 messageHash, - bytes32 qualificationMessageHash, - uint256 calldataPointer, - uint256 offsetToId, - bytes32 typehash, - function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { - return _processSplitBatchClaimWithQualificationAndSponsorDomain(messageHash, qualificationMessageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, operation); + function _processQualifiedClaim(QualifiedClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHash(); + return _processClaimWithQualification.usingQualifiedClaim()(messageHash, qualificationMessageHash, claimPayload, 0xe0, _typehashes(uint256(0).asStubborn()), operation); } - function _processClaimWithSponsorDomain( - bytes32 messageHash, - uint256 calldataPointer, - uint256 offsetToId, - bytes32 sponsorDomain, - bytes32 typehash, - function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { - return _processClaimWithQualificationAndSponsorDomain(messageHash, messageHash, calldataPointer, offsetToId, sponsorDomain, typehash, operation); + function _processClaimWithWitness(ClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHash(); + return _processSimpleClaim.usingClaimWithWitness()(messageHash, claimPayload, 0xe0, typehash, operation); } - function _processClaimWithQualification( - bytes32 messageHash, - bytes32 qualificationMessageHash, - uint256 calldataPointer, - uint256 offsetToId, - bytes32 typehash, - function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { - return _processClaimWithQualificationAndSponsorDomain(messageHash, qualificationMessageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, 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.toMessageHash(); + return _processClaimWithQualification.usingQualifiedClaimWithWitness()(messageHash, qualificationMessageHash, claimPayload, 0x120, typehash, operation); } - function _processSplitClaimWithQualification( - bytes32 messageHash, - bytes32 qualificationMessageHash, - uint256 calldataPointer, - uint256 offsetToId, - bytes32 typehash, - function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { - return _processSplitClaimWithQualificationAndSponsorDomain(messageHash, qualificationMessageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, operation); + function _processSplitClaim(SplitClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + return _processSimpleSplitClaim.usingSplitClaim()(claimPayload.toMessageHash(), claimPayload, 0xa0, _typehashes(uint256(0).asStubborn()), operation); } - function _processSplitClaimWithSponsorDomain( - bytes32 messageHash, - uint256 calldataPointer, - uint256 offsetToId, - bytes32 sponsorDomain, - bytes32 typehash, - function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { - return _processSplitClaimWithQualificationAndSponsorDomain(messageHash, messageHash, calldataPointer, offsetToId, sponsorDomain, typehash, operation); + function _processQualifiedSplitClaim(QualifiedSplitClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHash(); + return _processSplitClaimWithQualification.usingQualifiedSplitClaim()(messageHash, qualificationMessageHash, claimPayload, 0xe0, _typehashes(uint256(0).asStubborn()), operation); } - function _processBatchClaimWithSponsorDomain( - bytes32 messageHash, - uint256 calldataPointer, - uint256 offsetToId, - bytes32 sponsorDomain, - bytes32 typehash, - function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { - return _processBatchClaimWithQualificationAndSponsorDomain(messageHash, messageHash, calldataPointer, offsetToId, sponsorDomain, typehash, operation); + function _processSplitClaimWithWitness(SplitClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHash(); + return _processSimpleSplitClaim.usingSplitClaimWithWitness()(messageHash, claimPayload, 0xe0, typehash, operation); } - function _processSplitBatchClaimWithSponsorDomain( - bytes32 messageHash, - uint256 calldataPointer, - uint256 offsetToId, - bytes32 sponsorDomain, - bytes32 typehash, - function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { - return _processSplitBatchClaimWithQualificationAndSponsorDomain(messageHash, messageHash, calldataPointer, offsetToId, sponsorDomain, typehash, 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.toMessageHash(); + return _processSplitClaimWithQualification.usingQualifiedSplitClaimWithWitness()(messageHash, qualificationMessageHash, claimPayload, 0x120, typehash, operation); } - function _processClaimWithQualificationAndSponsorDomain( - bytes32 messageHash, - bytes32 qualificationMessageHash, - uint256 calldataPointer, - uint256 offsetToId, - bytes32 sponsorDomainSeparator, - bytes32 typehash, - function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { - uint256 id; - uint256 allocatedAmount; - address claimant; - uint256 amount; - - assembly ("memory-safe") { - let calldataPointerWithOffset := add(calldataPointer, offsetToId) - id := calldataload(calldataPointerWithOffset) - allocatedAmount := calldataload(add(calldataPointerWithOffset, 0x20)) - claimant := shr(96, shl(96, calldataload(add(calldataPointerWithOffset, 0x40)))) - amount := calldataload(add(calldataPointerWithOffset, 0x60)) - } - - _ensureValidScope(sponsorDomainSeparator, id); - - amount.withinAllocated(allocatedAmount); - - return operation(_validate(id.toAllocatorId(), messageHash, qualificationMessageHash, calldataPointer, sponsorDomainSeparator, typehash), claimant, id, amount); + ///// 2. Batch Claims ///// + function _processBatchClaim(BatchClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + return _processSimpleBatchClaim.usingBatchClaim()(claimPayload.toMessageHash(), claimPayload, 0xa0, _typehashes(uint256(1).asStubborn()), operation); } - function _processSplitClaimWithQualificationAndSponsorDomain( - bytes32 messageHash, - bytes32 qualificationMessageHash, - uint256 calldataPointer, - uint256 offsetToId, - bytes32 sponsorDomainSeparator, - bytes32 typehash, - function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { - uint256 id; - uint256 allocatedAmount; - SplitComponent[] calldata claimants; - - assembly ("memory-safe") { - let calldataPointerWithOffset := add(calldataPointer, offsetToId) - id := calldataload(calldataPointerWithOffset) - allocatedAmount := calldataload(add(calldataPointerWithOffset, 0x20)) - - let claimantsPtr := add(calldataPointer, calldataload(add(calldataPointerWithOffset, 0x40))) - claimants.offset := add(0x20, claimantsPtr) - claimants.length := calldataload(claimantsPtr) - } - - address sponsor = _validate(id.toAllocatorId(), messageHash, qualificationMessageHash, calldataPointer, sponsorDomainSeparator, typehash); - - _ensureValidScope(sponsorDomainSeparator, id); - - return _verifyAndProcessSplitComponents(sponsor, id, allocatedAmount, claimants, operation); + function _processQualifiedBatchClaim(QualifiedBatchClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHash(); + return _processBatchClaimWithQualification.usingQualifiedBatchClaim()(messageHash, qualificationMessageHash, claimPayload, 0xe0, _typehashes(uint256(1).asStubborn()), operation); } - function _processBatchClaimWithQualificationAndSponsorDomain( - bytes32 messageHash, - bytes32 qualificationMessageHash, - uint256 calldataPointer, - uint256 offsetToId, - bytes32 sponsorDomainSeparator, - bytes32 typehash, - function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { - BatchClaimComponent[] calldata claims; - address claimant; - assembly ("memory-safe") { - let calldataPointerWithOffset := add(calldataPointer, offsetToId) - let claimsPtr := add(calldataPointer, calldataload(calldataPointerWithOffset)) - claims.offset := add(0x20, claimsPtr) - claims.length := calldataload(claimsPtr) - - claimant := calldataload(add(calldataPointerWithOffset, 0x20)) - } - - uint96 firstAllocatorId = claims[0].id.toAllocatorId(); - - address sponsor = _validate(firstAllocatorId, messageHash, qualificationMessageHash, calldataPointer, sponsorDomainSeparator, typehash); - - uint256 totalClaims = claims.length; - - assembly ("memory-safe") { - if iszero(totalClaims) { - // revert InvalidBatchAllocation() - mstore(0, 0x3a03d3bb) - revert(0x1c, 0x04) - } - } - - // TODO: 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 = (component.allocatedAmount < amount).or((sponsorDomainSeparator != bytes32(0)).and(id.toScope() == Scope.ChainSpecific)).asUint256(); - - operation(sponsor, claimant, id, amount); - - unchecked { - for (uint256 i = 1; i < totalClaims; ++i) { - component = claims[i]; - id = component.id; - amount = component.amount; - errorBuffer |= - (id.toAllocatorId() != firstAllocatorId).or(component.allocatedAmount < amount).or((sponsorDomainSeparator != bytes32(0)).and(id.toScope() == Scope.ChainSpecific)).asUint256(); - - operation(sponsor, claimant, id, amount); - } - - if (errorBuffer.asBool()) { - for (uint256 i = 0; i < totalClaims; ++i) { - component = claims[i]; - component.amount.withinAllocated(component.allocatedAmount); - id = component.id; - _ensureValidScope(sponsorDomainSeparator, component.id); - } - - assembly ("memory-safe") { - // revert InvalidBatchAllocation() - mstore(0, 0x3a03d3bb) - revert(0x1c, 0x04) - } - } - } - - return true; + function _processBatchClaimWithWitness(BatchClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHash(); + return _processSimpleBatchClaim.usingBatchClaimWithWitness()(messageHash, claimPayload, 0xe0, typehash, operation); } - function _processSplitBatchClaimWithQualificationAndSponsorDomain( - bytes32 messageHash, - bytes32 qualificationMessageHash, - uint256 calldataPointer, - uint256 offsetToId, - bytes32 sponsorDomainSeparator, - bytes32 typehash, - function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { - SplitBatchClaimComponent[] calldata claims; - assembly ("memory-safe") { - let claimsPtr := add(calldataPointer, calldataload(add(calldataPointer, offsetToId))) - claims.offset := add(0x20, claimsPtr) - claims.length := calldataload(claimsPtr) - } - - uint96 firstAllocatorId = claims[0].id.toAllocatorId(); - - address sponsor = _validate(firstAllocatorId, messageHash, qualificationMessageHash, calldataPointer, sponsorDomainSeparator, typehash); - - uint256 totalClaims = claims.length; - uint256 errorBuffer = (totalClaims == 0).asUint256(); - uint256 id; - - unchecked { - for (uint256 i = 0; i < totalClaims; ++i) { - SplitBatchClaimComponent calldata claimComponent = claims[i]; - id = claimComponent.id; - errorBuffer |= (id.toAllocatorId() != firstAllocatorId).or((sponsorDomainSeparator != bytes32(0)).and(id.toScope() == Scope.ChainSpecific)).asUint256(); - - _verifyAndProcessSplitComponents(sponsor, id, claimComponent.allocatedAmount, claimComponent.portions, operation); - } - - if (errorBuffer.asBool()) { - for (uint256 i = 0; i < totalClaims; ++i) { - _ensureValidScope(sponsorDomainSeparator, claims[i].id); - } - - assembly ("memory-safe") { - // revert InvalidBatchAllocation() - mstore(0, 0x3a03d3bb) - revert(0x1c, 0x04) - } - } - } - - return true; + function _processQualifiedBatchClaimWithWitness(QualifiedBatchClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHash(); + return _processBatchClaimWithQualification.usingQualifiedBatchClaimWithWitness()(messageHash, qualificationMessageHash, claimPayload, 0x120, typehash, operation); } - function _processBasicClaim(BasicClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { - return _processSimpleClaim.usingBasicClaim()(claimPayload.toMessageHash(), claimPayload, uint256(0xa0).asStubborn(), _typehashes(uint256(0).asStubborn()), operation); + function _processSplitBatchClaim(SplitBatchClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + return _processSimpleSplitBatchClaim.usingSplitBatchClaim()(claimPayload.toMessageHash(), claimPayload, 0xa0, _typehashes(uint256(1).asStubborn()), operation); } - function _processQualifiedClaim(QualifiedClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + function _processQualifiedSplitBatchClaim(QualifiedSplitBatchClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHash(); - return _processClaimWithQualification.usingQualifiedClaim()(messageHash, qualificationMessageHash, claimPayload, 0xe0, _typehashes(uint256(0).asStubborn()), operation); + return _processSplitBatchClaimWithQualification.usingQualifiedSplitBatchClaim()(messageHash, qualificationMessageHash, claimPayload, 0xe0, _typehashes(uint256(1).asStubborn()), operation); } - function _processClaimWithWitness(ClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + function _processSplitBatchClaimWithWitness(SplitBatchClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHash(); - return _processSimpleClaim.usingClaimWithWitness()(messageHash, claimPayload, 0xe0, typehash, operation); + return _processSimpleSplitBatchClaim.usingSplitBatchClaimWithWitness()(messageHash, claimPayload, 0xe0, typehash, operation); } - function _processQualifiedClaimWithWitness(QualifiedClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) 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.toMessageHash(); - return _processClaimWithQualification.usingQualifiedClaimWithWitness()(messageHash, qualificationMessageHash, claimPayload, 0x120, typehash, operation); + return _processSplitBatchClaimWithQualification.usingQualifiedSplitBatchClaimWithWitness()(messageHash, qualificationMessageHash, claimPayload, 0x120, typehash, operation); } + ///// 3. Multichain Claims ///// function _processMultichainClaim(MultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { return _processSimpleClaim.usingMultichainClaim()(claimPayload.toMessageHash(), claimPayload, 0xc0, _typehashes(uint256(2).asStubborn()), operation); } @@ -482,6 +249,70 @@ contract ClaimProcessorLogic is WithdrawalLogic { return _processClaimWithQualification.usingQualifiedMultichainClaimWithWitness()(messageHash, qualificationMessageHash, claimPayload, 0x140, typehash, operation); } + function _processSplitMultichainClaim(SplitMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + return _processSimpleSplitClaim.usingSplitMultichainClaim()(claimPayload.toMessageHash(), claimPayload, 0xc0, _typehashes(uint256(2).asStubborn()), operation); + } + + function _processQualifiedSplitMultichainClaim(QualifiedSplitMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHash(); + return _processSplitClaimWithQualification.usingQualifiedSplitMultichainClaim()(messageHash, qualificationMessageHash, claimPayload, 0x100, _typehashes(uint256(2).asStubborn()), operation); + } + + function _processSplitMultichainClaimWithWitness(SplitMultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHash(); + return _processSimpleSplitClaim.usingSplitMultichainClaimWithWitness()(messageHash, claimPayload, 0x100, typehash, 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.toMessageHash(); + return _processSplitClaimWithQualification.usingQualifiedSplitMultichainClaimWithWitness()(messageHash, qualificationMessageHash, claimPayload, 0x140, typehash, operation); + } + + ///// 4. Batch Multichain Claims ///// + function _processBatchMultichainClaim(BatchMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + return _processSimpleBatchClaim.usingBatchMultichainClaim()(claimPayload.toMessageHash(), claimPayload, 0xc0, _typehashes(uint256(2).asStubborn()), operation); + } + + function _processQualifiedBatchMultichainClaim(QualifiedBatchMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHash(); + return _processBatchClaimWithQualification.usingQualifiedBatchMultichainClaim()(messageHash, qualificationMessageHash, claimPayload, 0x100, _typehashes(uint256(2).asStubborn()), operation); + } + + function _processBatchMultichainClaimWithWitness(BatchMultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHash(); + return _processSimpleBatchClaim.usingBatchMultichainClaimWithWitness()(messageHash, claimPayload, 0x100, typehash, 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.toMessageHash(); + return _processBatchClaimWithQualification.usingQualifiedBatchMultichainClaimWithWitness()(messageHash, qualificationMessageHash, claimPayload, 0x140, typehash, operation); + } + + function _processSplitBatchMultichainClaim(SplitBatchMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + return _processSimpleSplitBatchClaim.usingSplitBatchMultichainClaim()(claimPayload.toMessageHash(), claimPayload, 0xc0, _typehashes(uint256(2).asStubborn()), operation); + } + function _processQualifiedSplitBatchMultichainClaim(QualifiedSplitBatchMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) @@ -508,60 +339,89 @@ contract ClaimProcessorLogic is WithdrawalLogic { return _processSplitBatchClaimWithQualification.usingQualifiedSplitBatchMultichainClaimWithWitness()(messageHash, qualificationMessageHash, claimPayload, 0x140, typehash, operation); } - function _processSplitMultichainClaim(SplitMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { - return _processSimpleSplitClaim.usingSplitMultichainClaim()(claimPayload.toMessageHash(), claimPayload, 0xc0, _typehashes(uint256(2).asStubborn()), operation); + ///// 5. Exogenous Multichain Claims ///// + function _processExogenousMultichainClaim(ExogenousMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + return _processClaimWithSponsorDomain.usingExogenousMultichainClaim()( + claimPayload.toMessageHash(), claimPayload, 0x100, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), _typehashes(uint256(2).asStubborn()), operation + ); } - function _processQualifiedSplitMultichainClaim(QualifiedSplitMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + function _processExogenousQualifiedMultichainClaim(ExogenousQualifiedMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHash(); - return _processSplitClaimWithQualification.usingQualifiedSplitMultichainClaim()(messageHash, qualificationMessageHash, claimPayload, 0x100, _typehashes(uint256(2).asStubborn()), operation); + return _processClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedMultichainClaim()( + messageHash, qualificationMessageHash, claimPayload, 0x140, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), _typehashes(uint256(2).asStubborn()), operation + ); } - function _processSplitMultichainClaimWithWitness(SplitMultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + function _processExogenousMultichainClaimWithWitness(ExogenousMultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHash(); - return _processSimpleSplitClaim.usingSplitMultichainClaimWithWitness()(messageHash, claimPayload, 0x100, typehash, operation); + return + _processClaimWithSponsorDomain.usingExogenousMultichainClaimWithWitness()(messageHash, claimPayload, 0x140, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), typehash, operation); } - function _processQualifiedSplitMultichainClaimWithWitness( - QualifiedSplitMultichainClaimWithWitness calldata claimPayload, + function _processExogenousQualifiedMultichainClaimWithWitness( + ExogenousQualifiedMultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation ) internal returns (bool) { (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHash(); - return _processSplitClaimWithQualification.usingQualifiedSplitMultichainClaimWithWitness()(messageHash, qualificationMessageHash, claimPayload, 0x140, typehash, operation); - } - - function _processBatchMultichainClaim(BatchMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { - return _processSimpleBatchClaim.usingBatchMultichainClaim()(claimPayload.toMessageHash(), claimPayload, 0xc0, _typehashes(uint256(2).asStubborn()), operation); + return _processClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedMultichainClaimWithWitness()( + messageHash, qualificationMessageHash, claimPayload, 0x180, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), typehash, operation + ); } - function _processQualifiedBatchMultichainClaim(QualifiedBatchMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + function _processExogenousSplitMultichainClaim(ExogenousSplitMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { + return _processSplitClaimWithSponsorDomain.usingExogenousSplitMultichainClaim()( + claimPayload.toMessageHash(), claimPayload, 0x100, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), _typehashes(uint256(2).asStubborn()), operation + ); + } + + function _processExogenousQualifiedSplitMultichainClaim( + ExogenousQualifiedSplitMultichainClaim calldata claimPayload, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHash(); - return _processBatchClaimWithQualification.usingQualifiedBatchMultichainClaim()(messageHash, qualificationMessageHash, claimPayload, 0x100, _typehashes(uint256(2).asStubborn()), operation); + return _processSplitClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedSplitMultichainClaim()( + messageHash, qualificationMessageHash, claimPayload, 0x140, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), _typehashes(uint256(2).asStubborn()), operation + ); } - function _processBatchMultichainClaimWithWitness(BatchMultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) - internal - returns (bool) - { + function _processExogenousSplitMultichainClaimWithWitness( + ExogenousSplitMultichainClaimWithWitness calldata claimPayload, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHash(); - return _processSimpleBatchClaim.usingBatchMultichainClaimWithWitness()(messageHash, claimPayload, 0x100, typehash, operation); + return _processSplitClaimWithSponsorDomain.usingExogenousSplitMultichainClaimWithWitness()( + messageHash, claimPayload, 0x140, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), typehash, operation + ); } - function _processQualifiedBatchMultichainClaimWithWitness( - QualifiedBatchMultichainClaimWithWitness calldata claimPayload, + function _processExogenousQualifiedSplitMultichainClaimWithWitness( + ExogenousQualifiedSplitMultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation ) internal returns (bool) { (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHash(); - return _processBatchClaimWithQualification.usingQualifiedBatchMultichainClaimWithWitness()(messageHash, qualificationMessageHash, claimPayload, 0x140, typehash, operation); + return _processSplitClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedSplitMultichainClaimWithWitness()( + messageHash, qualificationMessageHash, claimPayload, 0x180, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), typehash, operation + ); + } + + ///// 6. Exogenous Batch Multichain Claims ///// + function _processExogenousBatchMultichainClaim(ExogenousBatchMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + return _processBatchClaimWithSponsorDomain.usingExogenousBatchMultichainClaim()( + claimPayload.toMessageHash(), claimPayload, 0x100, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), _typehashes(uint256(2).asStubborn()), operation + ); } function _processExogenousQualifiedBatchMultichainClaim( @@ -594,202 +454,389 @@ contract ClaimProcessorLogic is WithdrawalLogic { ); } - function _processExogenousMultichainClaim(ExogenousMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { - return _processClaimWithSponsorDomain.usingExogenousMultichainClaim()( - claimPayload.toMessageHash(), claimPayload, 0x100, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), _typehashes(uint256(2).asStubborn()), operation - ); - } - - function _processSplitBatchMultichainClaim(SplitBatchMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) - internal - returns (bool) - { - return _processSimpleSplitBatchClaim.usingSplitBatchMultichainClaim()(claimPayload.toMessageHash(), claimPayload, 0xc0, _typehashes(uint256(2).asStubborn()), operation); - } - - function _processExogenousMultichainClaimWithWitness(ExogenousMultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + function _processExogenousSplitBatchMultichainClaim(ExogenousSplitBatchMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { - (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHash(); - return - _processClaimWithSponsorDomain.usingExogenousMultichainClaimWithWitness()(messageHash, claimPayload, 0x140, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), typehash, operation); + return _processSplitBatchClaimWithSponsorDomain.usingExogenousSplitBatchMultichainClaim()( + claimPayload.toMessageHash(), claimPayload, 0x100, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), _typehashes(uint256(2).asStubborn()), operation + ); } - function _processExogenousQualifiedMultichainClaim(ExogenousQualifiedMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) - internal - returns (bool) - { + function _processExogenousQualifiedSplitBatchMultichainClaim( + ExogenousQualifiedSplitBatchMultichainClaim calldata claimPayload, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHash(); - return _processClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedMultichainClaim()( + return _processSplitBatchClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedSplitBatchMultichainClaim()( messageHash, qualificationMessageHash, claimPayload, 0x140, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), _typehashes(uint256(2).asStubborn()), operation ); } - function _processExogenousQualifiedSplitMultichainClaim( - ExogenousQualifiedSplitMultichainClaim calldata claimPayload, + function _processExogenousSplitBatchMultichainClaimWithWitness( + ExogenousSplitBatchMultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation ) internal returns (bool) { - (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHash(); - return _processSplitClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedSplitMultichainClaim()( - messageHash, qualificationMessageHash, claimPayload, 0x140, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), _typehashes(uint256(2).asStubborn()), operation + (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHash(); + return _processSplitBatchClaimWithSponsorDomain.usingExogenousSplitBatchMultichainClaimWithWitness()( + messageHash, claimPayload, 0x140, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), typehash, operation ); } - function _processExogenousQualifiedMultichainClaimWithWitness( - ExogenousQualifiedMultichainClaimWithWitness calldata claimPayload, + function _processExogenousQualifiedSplitBatchMultichainClaimWithWitness( + ExogenousQualifiedSplitBatchMultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation ) internal returns (bool) { (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHash(); - return _processClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedMultichainClaimWithWitness()( + return _processSplitBatchClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedSplitBatchMultichainClaimWithWitness()( messageHash, qualificationMessageHash, claimPayload, 0x180, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), typehash, operation ); } - function _processExogenousSplitMultichainClaim(ExogenousSplitMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) - internal + ///// 7. Private Helpers ///// + function _validate(uint96 allocatorId, bytes32 messageHash, bytes32 qualificationMessageHash, uint256 calldataPointer, bytes32 sponsorDomainSeparator, bytes32 typehash) + private + returns (address sponsor) + { + bytes calldata allocatorSignature; + bytes calldata sponsorSignature; + uint256 nonce; + uint256 expires; + + assembly ("memory-safe") { + let allocatorSignaturePtr := add(calldataPointer, calldataload(calldataPointer)) + allocatorSignature.offset := add(0x20, allocatorSignaturePtr) + allocatorSignature.length := calldataload(allocatorSignaturePtr) + + let sponsorSignaturePtr := add(calldataPointer, calldataload(add(calldataPointer, 0x20))) + sponsorSignature.offset := add(0x20, sponsorSignaturePtr) + sponsorSignature.length := calldataload(sponsorSignaturePtr) + + sponsor := shr(96, shl(96, calldataload(add(calldataPointer, 0x40)))) + nonce := calldataload(add(calldataPointer, 0x60)) + expires := calldataload(add(calldataPointer, 0x80)) + } + + expires.later(); + + address allocator = allocatorId.fromRegisteredAllocatorIdWithConsumed(nonce); + + bytes32 domainSeparator = _domainSeparator(); + assembly ("memory-safe") { + sponsorDomainSeparator := add(sponsorDomainSeparator, mul(iszero(sponsorDomainSeparator), domainSeparator)) + } + + if ((sponsorDomainSeparator != domainSeparator).or(sponsorSignature.length != 0) || _hasNoActiveRegistration(sponsor, messageHash, typehash)) { + messageHash.signedBy(sponsor, sponsorSignature, sponsorDomainSeparator); + } + qualificationMessageHash.signedBy(allocator, allocatorSignature, domainSeparator); + + _emitClaim(sponsor, messageHash, allocator); + } + + function _processSimpleClaim(bytes32 messageHash, uint256 calldataPointer, uint256 offsetToId, bytes32 typehash, function(address, address, uint256, uint256) internal returns (bool) operation) + private returns (bool) { - return _processSplitClaimWithSponsorDomain.usingExogenousSplitMultichainClaim()( - claimPayload.toMessageHash(), claimPayload, 0x100, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), _typehashes(uint256(2).asStubborn()), operation - ); + return _processClaimWithQualificationAndSponsorDomain(messageHash, messageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, operation); + } + + function _processSimpleSplitClaim( + bytes32 messageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 typehash, + function(address, address, uint256, uint256) internal returns (bool) operation + ) private returns (bool) { + return _processSplitClaimWithQualificationAndSponsorDomain(messageHash, messageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, operation); + } + + function _processSimpleBatchClaim( + bytes32 messageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 typehash, + function(address, address, uint256, uint256) internal returns (bool) operation + ) private returns (bool) { + return _processBatchClaimWithQualificationAndSponsorDomain(messageHash, messageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, operation); + } + + function _processBatchClaimWithQualification( + bytes32 messageHash, + bytes32 qualificationMessageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 typehash, + function(address, address, uint256, uint256) internal returns (bool) operation + ) private returns (bool) { + return _processBatchClaimWithQualificationAndSponsorDomain(messageHash, qualificationMessageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, operation); + } + + function _processSimpleSplitBatchClaim( + bytes32 messageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 typehash, + function(address, address, uint256, uint256) internal returns (bool) operation + ) private returns (bool) { + return _processSplitBatchClaimWithQualificationAndSponsorDomain(messageHash, messageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, operation); + } + + function _processSplitBatchClaimWithQualification( + bytes32 messageHash, + bytes32 qualificationMessageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 typehash, + function(address, address, uint256, uint256) internal returns (bool) operation + ) private returns (bool) { + return _processSplitBatchClaimWithQualificationAndSponsorDomain(messageHash, qualificationMessageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, operation); + } + + function _processClaimWithSponsorDomain( + bytes32 messageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 sponsorDomain, + bytes32 typehash, + function(address, address, uint256, uint256) internal returns (bool) operation + ) private returns (bool) { + return _processClaimWithQualificationAndSponsorDomain(messageHash, messageHash, calldataPointer, offsetToId, sponsorDomain, typehash, operation); + } + + function _processClaimWithQualification( + bytes32 messageHash, + bytes32 qualificationMessageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 typehash, + function(address, address, uint256, uint256) internal returns (bool) operation + ) private returns (bool) { + return _processClaimWithQualificationAndSponsorDomain(messageHash, qualificationMessageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, operation); + } + + function _processSplitClaimWithQualification( + bytes32 messageHash, + bytes32 qualificationMessageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 typehash, + function(address, address, uint256, uint256) internal returns (bool) operation + ) private returns (bool) { + return _processSplitClaimWithQualificationAndSponsorDomain(messageHash, qualificationMessageHash, calldataPointer, offsetToId, bytes32(0).asStubborn(), typehash, operation); + } + + function _processSplitClaimWithSponsorDomain( + bytes32 messageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 sponsorDomain, + bytes32 typehash, + function(address, address, uint256, uint256) internal returns (bool) operation + ) private returns (bool) { + return _processSplitClaimWithQualificationAndSponsorDomain(messageHash, messageHash, calldataPointer, offsetToId, sponsorDomain, typehash, operation); + } + + function _processBatchClaimWithSponsorDomain( + bytes32 messageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 sponsorDomain, + bytes32 typehash, + function(address, address, uint256, uint256) internal returns (bool) operation + ) private returns (bool) { + return _processBatchClaimWithQualificationAndSponsorDomain(messageHash, messageHash, calldataPointer, offsetToId, sponsorDomain, typehash, operation); + } + + function _processSplitBatchClaimWithSponsorDomain( + bytes32 messageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 sponsorDomain, + bytes32 typehash, + function(address, address, uint256, uint256) internal returns (bool) operation + ) private returns (bool) { + return _processSplitBatchClaimWithQualificationAndSponsorDomain(messageHash, messageHash, calldataPointer, offsetToId, sponsorDomain, typehash, operation); + } + + function _processClaimWithQualificationAndSponsorDomain( + bytes32 messageHash, + bytes32 qualificationMessageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 sponsorDomainSeparator, + bytes32 typehash, + function(address, address, uint256, uint256) internal returns (bool) operation + ) private returns (bool) { + uint256 id; + uint256 allocatedAmount; + address claimant; + uint256 amount; + + assembly ("memory-safe") { + let calldataPointerWithOffset := add(calldataPointer, offsetToId) + id := calldataload(calldataPointerWithOffset) + allocatedAmount := calldataload(add(calldataPointerWithOffset, 0x20)) + claimant := shr(96, shl(96, calldataload(add(calldataPointerWithOffset, 0x40)))) + amount := calldataload(add(calldataPointerWithOffset, 0x60)) + } + + _ensureValidScope(sponsorDomainSeparator, id); + + amount.withinAllocated(allocatedAmount); + + return operation(_validate(id.toAllocatorId(), messageHash, qualificationMessageHash, calldataPointer, sponsorDomainSeparator, typehash), claimant, id, amount); } - function _processExogenousSplitMultichainClaimWithWitness( - ExogenousSplitMultichainClaimWithWitness calldata claimPayload, - function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { - (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHash(); - return _processSplitClaimWithSponsorDomain.usingExogenousSplitMultichainClaimWithWitness()( - messageHash, claimPayload, 0x140, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), typehash, operation - ); + function _processSplitClaimWithQualificationAndSponsorDomain( + bytes32 messageHash, + bytes32 qualificationMessageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 sponsorDomainSeparator, + bytes32 typehash, + function(address, address, uint256, uint256) internal returns (bool) operation + ) private returns (bool) { + uint256 id; + uint256 allocatedAmount; + SplitComponent[] calldata claimants; + + assembly ("memory-safe") { + let calldataPointerWithOffset := add(calldataPointer, offsetToId) + id := calldataload(calldataPointerWithOffset) + allocatedAmount := calldataload(add(calldataPointerWithOffset, 0x20)) + + let claimantsPtr := add(calldataPointer, calldataload(add(calldataPointerWithOffset, 0x40))) + claimants.offset := add(0x20, claimantsPtr) + claimants.length := calldataload(claimantsPtr) + } + + address sponsor = _validate(id.toAllocatorId(), messageHash, qualificationMessageHash, calldataPointer, sponsorDomainSeparator, typehash); + + _ensureValidScope(sponsorDomainSeparator, id); + + return _verifyAndProcessSplitComponents(sponsor, id, allocatedAmount, claimants, operation); } - function _processExogenousQualifiedSplitMultichainClaimWithWitness( - ExogenousQualifiedSplitMultichainClaimWithWitness calldata claimPayload, + function _processBatchClaimWithQualificationAndSponsorDomain( + bytes32 messageHash, + bytes32 qualificationMessageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 sponsorDomainSeparator, + bytes32 typehash, function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { - (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHash(); - return _processSplitClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedSplitMultichainClaimWithWitness()( - messageHash, qualificationMessageHash, claimPayload, 0x180, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), typehash, operation - ); - } + ) private returns (bool) { + BatchClaimComponent[] calldata claims; + address claimant; + assembly ("memory-safe") { + let calldataPointerWithOffset := add(calldataPointer, offsetToId) + let claimsPtr := add(calldataPointer, calldataload(calldataPointerWithOffset)) + claims.offset := add(0x20, claimsPtr) + claims.length := calldataload(claimsPtr) - function _processExogenousBatchMultichainClaim(ExogenousBatchMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) - internal - returns (bool) - { - return _processBatchClaimWithSponsorDomain.usingExogenousBatchMultichainClaim()( - claimPayload.toMessageHash(), claimPayload, 0x100, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), _typehashes(uint256(2).asStubborn()), operation - ); - } + claimant := calldataload(add(calldataPointerWithOffset, 0x20)) + } - function _processExogenousSplitBatchMultichainClaim(ExogenousSplitBatchMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) - internal - returns (bool) - { - return _processSplitBatchClaimWithSponsorDomain.usingExogenousSplitBatchMultichainClaim()( - claimPayload.toMessageHash(), claimPayload, 0x100, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), _typehashes(uint256(2).asStubborn()), operation - ); - } + uint96 firstAllocatorId = claims[0].id.toAllocatorId(); - function _processExogenousQualifiedSplitBatchMultichainClaim( - ExogenousQualifiedSplitBatchMultichainClaim calldata claimPayload, - function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { - (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHash(); - return _processSplitBatchClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedSplitBatchMultichainClaim()( - messageHash, qualificationMessageHash, claimPayload, 0x140, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), _typehashes(uint256(2).asStubborn()), operation - ); - } + address sponsor = _validate(firstAllocatorId, messageHash, qualificationMessageHash, calldataPointer, sponsorDomainSeparator, typehash); - function _processExogenousSplitBatchMultichainClaimWithWitness( - ExogenousSplitBatchMultichainClaimWithWitness calldata claimPayload, - function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { - (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHash(); - return _processSplitBatchClaimWithSponsorDomain.usingExogenousSplitBatchMultichainClaimWithWitness()( - messageHash, claimPayload, 0x140, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), typehash, operation - ); - } + uint256 totalClaims = claims.length; - function _processExogenousQualifiedSplitBatchMultichainClaimWithWitness( - ExogenousQualifiedSplitBatchMultichainClaimWithWitness calldata claimPayload, - function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { - (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHash(); - return _processSplitBatchClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedSplitBatchMultichainClaimWithWitness()( - messageHash, qualificationMessageHash, claimPayload, 0x180, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), typehash, operation - ); - } + assembly ("memory-safe") { + if iszero(totalClaims) { + // revert InvalidBatchAllocation() + mstore(0, 0x3a03d3bb) + revert(0x1c, 0x04) + } + } - function _processSplitClaim(SplitClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { - return _processSimpleSplitClaim.usingSplitClaim()(claimPayload.toMessageHash(), claimPayload, 0xa0, _typehashes(uint256(0).asStubborn()), operation); - } + // 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 = (component.allocatedAmount < amount).or((sponsorDomainSeparator != bytes32(0)).and(id.toScope() == Scope.ChainSpecific)).asUint256(); - function _processQualifiedSplitClaim(QualifiedSplitClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { - (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHash(); - return _processSplitClaimWithQualification.usingQualifiedSplitClaim()(messageHash, qualificationMessageHash, claimPayload, 0xe0, _typehashes(uint256(0).asStubborn()), operation); - } + operation(sponsor, claimant, id, amount); - function _processSplitClaimWithWitness(SplitClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { - (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHash(); - return _processSimpleSplitClaim.usingSplitClaimWithWitness()(messageHash, claimPayload, 0xe0, typehash, operation); - } + unchecked { + for (uint256 i = 1; i < totalClaims; ++i) { + component = claims[i]; + id = component.id; + amount = component.amount; + errorBuffer |= + (id.toAllocatorId() != firstAllocatorId).or(component.allocatedAmount < amount).or((sponsorDomainSeparator != bytes32(0)).and(id.toScope() == Scope.ChainSpecific)).asUint256(); - function _processQualifiedSplitClaimWithWitness(QualifiedSplitClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) - internal - returns (bool) - { - (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHash(); - return _processSplitClaimWithQualification.usingQualifiedSplitClaimWithWitness()(messageHash, qualificationMessageHash, claimPayload, 0x120, typehash, operation); - } + operation(sponsor, claimant, id, amount); + } - function _processBatchClaim(BatchClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { - return _processSimpleBatchClaim.usingBatchClaim()(claimPayload.toMessageHash(), claimPayload, 0xa0, _typehashes(uint256(1).asStubborn()), operation); - } + if (errorBuffer.asBool()) { + for (uint256 i = 0; i < totalClaims; ++i) { + component = claims[i]; + component.amount.withinAllocated(component.allocatedAmount); + id = component.id; + _ensureValidScope(sponsorDomainSeparator, component.id); + } - function _processSplitBatchClaim(SplitBatchClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { - return _processSimpleSplitBatchClaim.usingSplitBatchClaim()(claimPayload.toMessageHash(), claimPayload, 0xa0, _typehashes(uint256(1).asStubborn()), operation); - } + assembly ("memory-safe") { + // revert InvalidBatchAllocation() + mstore(0, 0x3a03d3bb) + revert(0x1c, 0x04) + } + } + } - function _processQualifiedSplitBatchClaim(QualifiedSplitBatchClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { - (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHash(); - return _processSplitBatchClaimWithQualification.usingQualifiedSplitBatchClaim()(messageHash, qualificationMessageHash, claimPayload, 0xe0, _typehashes(uint256(1).asStubborn()), operation); + return true; } - function _processQualifiedSplitBatchClaimWithWitness(QualifiedSplitBatchClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) - internal - returns (bool) - { - (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHash(); - return _processSplitBatchClaimWithQualification.usingQualifiedSplitBatchClaimWithWitness()(messageHash, qualificationMessageHash, claimPayload, 0x120, typehash, operation); - } + function _processSplitBatchClaimWithQualificationAndSponsorDomain( + bytes32 messageHash, + bytes32 qualificationMessageHash, + uint256 calldataPointer, + uint256 offsetToId, + bytes32 sponsorDomainSeparator, + bytes32 typehash, + function(address, address, uint256, uint256) internal returns (bool) operation + ) private returns (bool) { + SplitBatchClaimComponent[] calldata claims; + assembly ("memory-safe") { + let claimsPtr := add(calldataPointer, calldataload(add(calldataPointer, offsetToId))) + claims.offset := add(0x20, claimsPtr) + claims.length := calldataload(claimsPtr) + } - function _processSplitBatchClaimWithWitness(SplitBatchClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) - internal - returns (bool) - { - (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHash(); - return _processSimpleSplitBatchClaim.usingSplitBatchClaimWithWitness()(messageHash, claimPayload, 0xe0, typehash, operation); - } + uint96 firstAllocatorId = claims[0].id.toAllocatorId(); - function _processQualifiedBatchClaim(QualifiedBatchClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { - (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHash(); - return _processBatchClaimWithQualification.usingQualifiedBatchClaim()(messageHash, qualificationMessageHash, claimPayload, 0xe0, _typehashes(uint256(1).asStubborn()), operation); - } + address sponsor = _validate(firstAllocatorId, messageHash, qualificationMessageHash, calldataPointer, sponsorDomainSeparator, typehash); - function _processBatchClaimWithWitness(BatchClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) { - (bytes32 messageHash, bytes32 typehash) = claimPayload.toMessageHash(); - return _processSimpleBatchClaim.usingBatchClaimWithWitness()(messageHash, claimPayload, 0xe0, typehash, operation); - } + uint256 totalClaims = claims.length; + uint256 errorBuffer = (totalClaims == 0).asUint256(); + uint256 id; - function _processQualifiedBatchClaimWithWitness(QualifiedBatchClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) - internal - returns (bool) - { - (bytes32 messageHash, bytes32 qualificationMessageHash, bytes32 typehash) = claimPayload.toMessageHash(); - return _processBatchClaimWithQualification.usingQualifiedBatchClaimWithWitness()(messageHash, qualificationMessageHash, claimPayload, 0x120, typehash, operation); + unchecked { + for (uint256 i = 0; i < totalClaims; ++i) { + SplitBatchClaimComponent calldata claimComponent = claims[i]; + id = claimComponent.id; + errorBuffer |= (id.toAllocatorId() != firstAllocatorId).or((sponsorDomainSeparator != bytes32(0)).and(id.toScope() == Scope.ChainSpecific)).asUint256(); + + _verifyAndProcessSplitComponents(sponsor, id, claimComponent.allocatedAmount, claimComponent.portions, operation); + } + + if (errorBuffer.asBool()) { + for (uint256 i = 0; i < totalClaims; ++i) { + _ensureValidScope(sponsorDomainSeparator, claims[i].id); + } + + assembly ("memory-safe") { + // revert InvalidBatchAllocation() + mstore(0, 0x3a03d3bb) + revert(0x1c, 0x04) + } + } + } + + return true; } function _verifyAndProcessSplitComponents( @@ -798,7 +845,7 @@ contract ClaimProcessorLogic is WithdrawalLogic { uint256 allocatedAmount, SplitComponent[] calldata claimants, function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { + ) private returns (bool) { uint256 totalClaims = claimants.length; uint256 spentAmount = 0; uint256 errorBuffer = (totalClaims == 0).asUint256(); @@ -830,51 +877,11 @@ contract ClaimProcessorLogic is WithdrawalLogic { return true; } - function _validate(uint96 allocatorId, bytes32 messageHash, bytes32 qualificationMessageHash, uint256 calldataPointer, bytes32 sponsorDomainSeparator, bytes32 typehash) - internal - returns (address sponsor) - { - bytes calldata allocatorSignature; - bytes calldata sponsorSignature; - uint256 nonce; - uint256 expires; - - assembly ("memory-safe") { - let allocatorSignaturePtr := add(calldataPointer, calldataload(calldataPointer)) - allocatorSignature.offset := add(0x20, allocatorSignaturePtr) - allocatorSignature.length := calldataload(allocatorSignaturePtr) - - let sponsorSignaturePtr := add(calldataPointer, calldataload(add(calldataPointer, 0x20))) - sponsorSignature.offset := add(0x20, sponsorSignaturePtr) - sponsorSignature.length := calldataload(sponsorSignaturePtr) - - sponsor := shr(96, shl(96, calldataload(add(calldataPointer, 0x40)))) - nonce := calldataload(add(calldataPointer, 0x60)) - expires := calldataload(add(calldataPointer, 0x80)) - } - - expires.later(); - - address allocator = allocatorId.fromRegisteredAllocatorIdWithConsumed(nonce); - - bytes32 domainSeparator = _domainSeparator(); - assembly ("memory-safe") { - sponsorDomainSeparator := add(sponsorDomainSeparator, mul(iszero(sponsorDomainSeparator), domainSeparator)) - } - - if ((sponsorDomainSeparator != domainSeparator).or(sponsorSignature.length != 0) || _hasNoActiveRegistration(sponsor, messageHash, typehash)) { - messageHash.signedBy(sponsor, sponsorSignature, sponsorDomainSeparator); - } - qualificationMessageHash.signedBy(allocator, allocatorSignature, domainSeparator); - - _emitClaim(sponsor, messageHash, allocator); - } - - function _hasNoActiveRegistration(address sponsor, bytes32 claimHash, bytes32 typehash) internal view returns (bool) { + function _hasNoActiveRegistration(address sponsor, bytes32 claimHash, bytes32 typehash) private view returns (bool) { return _getRegistrationStatus(sponsor, claimHash, typehash) <= block.timestamp; } - function _ensureValidScope(bytes32 sponsorDomainSeparator, uint256 id) internal pure { + function _ensureValidScope(bytes32 sponsorDomainSeparator, uint256 id) private pure { assembly ("memory-safe") { if iszero(or(iszero(sponsorDomainSeparator), iszero(shr(255, id)))) { // revert InvalidScope(id) @@ -885,7 +892,7 @@ contract ClaimProcessorLogic is WithdrawalLogic { } } - function _typehashes(uint256 i) internal pure returns (bytes32 typehash) { + function _typehashes(uint256 i) private pure returns (bytes32 typehash) { assembly ("memory-safe") { let m := mload(0x40) mstore(0, COMPACT_TYPEHASH) diff --git a/src/lib/DepositLogic.sol b/src/lib/DepositLogic.sol index bcae969..7ca9963 100644 --- a/src/lib/DepositLogic.sol +++ b/src/lib/DepositLogic.sol @@ -1,44 +1,6 @@ // 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"; import { ResetPeriod } from "../types/ResetPeriod.sol"; import { Scope } from "../types/Scope.sol"; @@ -55,17 +17,10 @@ contract DepositLogic is TransferLogic, RegistrationLogic { using IdLib for uint96; using IdLib for uint256; using IdLib for address; - using IdLib for ResetPeriod; using EfficiencyLib for bool; - using EfficiencyLib for uint256; using ValidityLib for address; using SafeTransferLib for address; - uint32 private constant _PERMIT_WITNESS_TRANSFER_FROM_SELECTOR = 0x137c29fe; - uint32 private constant _BATCH_PERMIT_WITNESS_TRANSFER_FROM_SELECTOR = 0xfe8ec1a7; - - address private constant _PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3; - uint256 private constant _ERC6909_MASTER_SLOT_SEED = 0xedcaa89a82293940; /// @dev `keccak256(bytes("Transfer(address,address,address,uint256,uint256)"))`. @@ -125,186 +80,12 @@ contract DepositLogic is TransferLogic, RegistrationLogic { _clearReentrancyGuard(); } - function _depositViaPermit2(address token, address recipient, bytes calldata signature) internal returns (uint256) { - bytes32 witness = _deriveCompactDepositWitnessHash(uint256(0xa4).asStubborn()); - - (uint256 id, uint256 initialBalance, uint256 m, uint256 typestringMemoryLocation) = _setReentrancyLockAndStartPreparingPermit2Call(token); - - _insertCompactDepositTypestringAt(typestringMemoryLocation); - - assembly ("memory-safe") { - mstore(add(m, 0x100), witness) - } - - _writeSignatureAndPerformPermit2Call(m, uint256(0x140).asStubborn(), uint256(0x200).asStubborn(), signature); - - _checkBalanceAndDeposit(token, recipient, id, initialBalance); - - _clearReentrancyGuard(); - - return id; - } - - function _depositAndRegisterViaPermit2( - address token, - address depositor, // also recipient - ResetPeriod resetPeriod, - bytes32 claimHash, - CompactCategory compactCategory, - string calldata witness, - bytes calldata signature - ) internal returns (uint256) { - (uint256 id, uint256 initialBalance, uint256 m, uint256 typestringMemoryLocation) = _setReentrancyLockAndStartPreparingPermit2Call(token); - - (bytes32 activationTypehash, bytes32 compactTypehash) = _writeWitnessAndGetTypehashes(typestringMemoryLocation, compactCategory, witness, bool(false).asStubborn()); - - _deriveAndWriteWitnessHash(activationTypehash, id, claimHash, m, 0x100); - - uint256 signatureOffsetValue; - assembly ("memory-safe") { - signatureOffsetValue := and(add(mload(add(m, 0x160)), 0x17f), not(0x1f)) - } - - _writeSignatureAndPerformPermit2Call(m, uint256(0x140).asStubborn(), signatureOffsetValue, signature); - - _checkBalanceAndDeposit(token, depositor, id, initialBalance); - - _register(depositor, claimHash, compactTypehash, resetPeriod.toSeconds()); - - _clearReentrancyGuard(); - - return id; - } - - function _depositBatchViaPermit2(ISignatureTransfer.TokenPermissions[] calldata permitted, address recipient, bytes calldata signature) internal returns (uint256[] memory) { - (uint256 totalTokensLessInitialNative, bool firstUnderlyingTokenIsNative, uint256[] memory ids, uint256[] memory initialTokenBalances) = - _preprocessAndPerformInitialNativeDeposit(permitted, recipient); - - bytes32 witness = _deriveCompactDepositWitnessHash(uint256(0x84).asStubborn()); - - (uint256 m, uint256 typestringMemoryLocation) = _beginPreparingBatchDepositPermit2Calldata(totalTokensLessInitialNative, firstUnderlyingTokenIsNative); - - unchecked { - _insertCompactDepositTypestringAt(typestringMemoryLocation); - } - - uint256 signatureOffsetValue; - assembly ("memory-safe") { - mstore(add(m, 0x80), witness) - signatureOffsetValue := add(0x220, shl(7, totalTokensLessInitialNative)) - } - - _writeSignatureAndPerformPermit2Call(m, uint256(0xc0).asStubborn(), signatureOffsetValue, signature); - - _verifyBalancesAndPerformDeposits(ids, permitted, initialTokenBalances, recipient, firstUnderlyingTokenIsNative); - - return ids; - } - - function _depositBatchAndRegisterViaPermit2( - address depositor, - ISignatureTransfer.TokenPermissions[] calldata permitted, - ResetPeriod resetPeriod, - bytes32 claimHash, - CompactCategory compactCategory, - string calldata witness, - bytes calldata signature - ) internal returns (uint256[] memory) { - (uint256 totalTokensLessInitialNative, bool firstUnderlyingTokenIsNative, uint256[] memory ids, uint256[] memory initialTokenBalances) = - _preprocessAndPerformInitialNativeDeposit(permitted, depositor); - - uint256 idsHash; - assembly ("memory-safe") { - idsHash := keccak256(add(ids, 0x20), shl(5, add(totalTokensLessInitialNative, firstUnderlyingTokenIsNative))) - } - - (uint256 m, uint256 typestringMemoryLocation) = _beginPreparingBatchDepositPermit2Calldata(totalTokensLessInitialNative, firstUnderlyingTokenIsNative); - - (bytes32 activationTypehash, bytes32 compactTypehash) = _writeWitnessAndGetTypehashes(typestringMemoryLocation, compactCategory, witness, bool(true).asStubborn()); - - _deriveAndWriteWitnessHash(activationTypehash, idsHash, claimHash, m, 0x80); - - uint256 signatureOffsetValue; - assembly ("memory-safe") { - let witnessLength := witness.length - let totalWitnessMemoryOffset := and(add(add(0xf3, add(witnessLength, iszero(iszero(witnessLength)))), add(mul(eq(compactCategory, 1), 0x0b), shl(6, eq(compactCategory, 2)))), not(0x1f)) - signatureOffsetValue := add(add(0x180, shl(7, totalTokensLessInitialNative)), totalWitnessMemoryOffset) - } - - _writeSignatureAndPerformPermit2Call(m, uint256(0xc0).asStubborn(), signatureOffsetValue, signature); - - _verifyBalancesAndPerformDeposits(ids, permitted, initialTokenBalances, depositor, firstUnderlyingTokenIsNative); - - _register(depositor, claimHash, compactTypehash, resetPeriod.toSeconds()); - - return ids; - } - - function _verifyBalancesAndPerformDeposits( - uint256[] memory ids, - ISignatureTransfer.TokenPermissions[] calldata permittedTokens, - uint256[] memory initialTokenBalances, - address recipient, - bool firstUnderlyingTokenIsNative - ) internal { - uint256 tokenBalance; - uint256 initialBalance; - uint256 errorBuffer; - uint256 totalTokensLessInitialNative = initialTokenBalances.length; - - unchecked { - for (uint256 i = 0; i < totalTokensLessInitialNative; ++i) { - tokenBalance = permittedTokens[i + firstUnderlyingTokenIsNative.asUint256()].token.balanceOf(address(this)); - initialBalance = initialTokenBalances[i]; - errorBuffer |= (initialBalance >= tokenBalance).asUint256(); - - _deposit(recipient, ids[i + firstUnderlyingTokenIsNative.asUint256()], tokenBalance - initialBalance); - } - } - - assembly ("memory-safe") { - if errorBuffer { - // revert InvalidDepositBalanceChange() - mstore(0, 0x426d8dcf) - revert(0x1c, 0x04) - } - } - - _clearReentrancyGuard(); - } - function _performBasicERC20Deposit(address token, address allocator, uint256 amount) internal returns (uint256 id) { id = token.excludingNative().toIdIfRegistered(Scope.Multichain, ResetPeriod.TenMinutes, allocator); _transferAndDepositWithReentrancyGuard(token, msg.sender, id, amount); } - function _writeSignatureAndPerformPermit2Call(uint256 m, uint256 signatureOffsetLocation, uint256 signatureOffsetValue, bytes calldata signature) internal { - bool isPermit2Deployed = _isPermit2Deployed(); - assembly ("memory-safe") { - mstore(add(m, signatureOffsetLocation), signatureOffsetValue) // signature offset - - let signatureLength := signature.length - let signatureMemoryOffset := add(m, add(0x20, signatureOffsetValue)) - - mstore(signatureMemoryOffset, signatureLength) - calldatacopy(add(signatureMemoryOffset, 0x20), signature.offset, signatureLength) - - 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) - } - } - } - function _performCustomNativeTokenDeposit(address allocator, ResetPeriod resetPeriod, Scope scope, address recipient) internal returns (uint256 id) { id = address(0).toIdIfRegistered(scope, resetPeriod, allocator); @@ -317,148 +98,6 @@ contract DepositLogic is TransferLogic, RegistrationLogic { _transferAndDepositWithReentrancyGuard(token, recipient, id, amount); } - function _preprocessAndPerformInitialNativeDeposit(ISignatureTransfer.TokenPermissions[] calldata permitted, address recipient) - internal - returns (uint256 totalTokensLessInitialNative, bool firstUnderlyingTokenIsNative, uint256[] memory ids, uint256[] memory initialTokenBalances) - { - _setReentrancyGuard(); - - uint256 totalTokens = permitted.length; - address allocator; - ResetPeriod resetPeriod; - Scope scope; - assembly ("memory-safe") { - let permittedOffset := permitted.offset - 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) - } - - // NOTE: these may need to be sanitized if toIdIfRegistered doesn't already handle for it - allocator := calldataload(0x84) - resetPeriod := calldataload(0xa4) - scope := calldataload(0xc4) - } - - uint256 initialId = address(0).toIdIfRegistered(scope, resetPeriod, allocator); - ids = new uint256[](totalTokens); - if (firstUnderlyingTokenIsNative) { - _deposit(recipient, initialId, msg.value); - ids[0] = initialId; - } - - unchecked { - totalTokensLessInitialNative = totalTokens - firstUnderlyingTokenIsNative.asUint256(); - } - - initialTokenBalances = _prepareIdsAndGetBalances(ids, totalTokensLessInitialNative, firstUnderlyingTokenIsNative, permitted, initialId); - } - - function _setReentrancyLockAndStartPreparingPermit2Call(address token) internal returns (uint256 id, uint256 initialBalance, uint256 m, uint256 typestringMemoryLocation) { - _setReentrancyGuard(); - - address allocator; - ResetPeriod resetPeriod; - Scope scope; - assembly ("memory-safe") { - allocator := calldataload(0xa4) - resetPeriod := calldataload(0xc4) - scope := calldataload(0xe4) - } - - id = token.excludingNative().toIdIfRegistered(scope, resetPeriod, allocator); - - initialBalance = token.balanceOf(address(this)); - - assembly ("memory-safe") { - m := mload(0x40) // Grab the free memory pointer; memory will be left dirtied. - - 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) - typestringMemoryLocation := add(m, 0x160) - - // TODO: 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). - } - } - - function _beginPreparingBatchDepositPermit2Calldata(uint256 totalTokensLessInitialNative, bool firstUnderlyingTokenIsNative) internal view returns (uint256 m, uint256 typestringMemoryLocation) { - assembly ("memory-safe") { - m := mload(0x40) // Grab the free memory pointer; memory will be left dirtied. - - let tokenChunk := shl(6, totalTokensLessInitialNative) - let twoTokenChunks := shl(1, tokenChunk) - - let permittedCalldataLocation := add(add(0x24, calldataload(0x24)), shl(6, firstUnderlyingTokenIsNative)) - - 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 - // 0x80 => witnessHash - mstore(add(m, 0xa0), add(0x160, twoTokenChunks)) // witness offset - // 0xc0 => signatureOffset - 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 - - calldatacopy(add(m, 0x160), permittedCalldataLocation, tokenChunk) // permitted data - - let detailsOffset := add(add(m, 0x160), tokenChunk) - mstore(detailsOffset, totalTokensLessInitialNative) // details.length - - // details data - let starting := add(detailsOffset, 0x20) - let next := add(detailsOffset, 0x40) - let end := shl(6, totalTokensLessInitialNative) - for { let i := 0 } lt(i, end) { i := add(i, 0x40) } { - mstore(add(starting, i), address()) - mstore(add(next, i), calldataload(add(permittedCalldataLocation, add(0x20, i)))) - } - - typestringMemoryLocation := add(m, add(0x180, twoTokenChunks)) - - // TODO: 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). - } - } - - /// @dev Transfers `amount` of `token` and mints the resulting balance change of `id` to `to`. - /// Emits a {Transfer} event. - function _transferAndDeposit(address token, address to, uint256 id, uint256 amount) internal { - uint256 initialBalance = token.balanceOf(address(this)); - - token.safeTransferFrom(msg.sender, address(this), amount); - - _checkBalanceAndDeposit(token, to, id, initialBalance); - } - - /// @dev Transfers `amount` of `token` and mints the resulting balance change of `id` to `to`. - /// Emits a {Transfer} event. - function _transferAndDepositWithReentrancyGuard(address token, address to, uint256 id, uint256 amount) internal { - _setReentrancyGuard(); - - _transferAndDeposit(token, to, id, amount); - - _clearReentrancyGuard(); - } - /// @dev Retrieves a token balance, compares against `initialBalance`, and mints the resulting balance /// change of `id` to `to`. Emits a {Transfer} event. function _checkBalanceAndDeposit(address token, address to, uint256 id, uint256 initialBalance) internal { @@ -477,66 +116,6 @@ contract DepositLogic is TransferLogic, RegistrationLogic { } } - // NOTE: all tokens must be supplied in ascending order and cannot be duplicated. - function _prepareIdsAndGetBalances( - uint256[] memory ids, - uint256 totalTokensLessInitialNative, - bool firstUnderlyingTokenIsNative, - ISignatureTransfer.TokenPermissions[] calldata permitted, - uint256 id - ) internal view returns (uint256[] memory tokenBalances) { - unchecked { - tokenBalances = new uint256[](totalTokensLessInitialNative); - - address token; - uint256 candidateId; - uint256 errorBuffer; - - for (uint256 i = 0; i < totalTokensLessInitialNative; ++i) { - token = permitted[i + firstUnderlyingTokenIsNative.asUint256()].token; - candidateId = id.withReplacedToken(token); - errorBuffer |= (candidateId <= id).asUint256(); - id = candidateId; - - ids[i + firstUnderlyingTokenIsNative.asUint256()] = id; - - tokenBalances[i] = token.balanceOf(address(this)); - } - - assembly ("memory-safe") { - if errorBuffer { - // revert InvalidDepositTokenOrdering() - mstore(0, 0x0f2f1e51) - revert(0x1c, 0x04) - } - } - } - } - - function _deriveCompactDepositWitnessHash(uint256 calldataOffset) internal pure returns (bytes32 witnessHash) { - assembly ("memory-safe") { - let m := mload(0x40) // Grab the free memory pointer; memory will be left dirtied. - - // 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. - mstore(m, PERMIT2_DEPOSIT_WITNESS_FRAGMENT_HASH) - calldatacopy(add(m, 0x20), calldataOffset, 0x80) // allocator, resetPeriod, scope, recipient - witnessHash := keccak256(m, 0xa0) - } - } - - function _insertCompactDepositTypestringAt(uint256 memoryLocation) internal pure { - assembly ("memory-safe") { - mstore(memoryLocation, 0x96) - 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) - } - } - /// @dev Mints `amount` of token `id` to `to` without checking transfer hooks. /// Emits a {Transfer} event. function _deposit(address to, uint256 id, uint256 amount) internal { @@ -565,127 +144,23 @@ contract DepositLogic is TransferLogic, RegistrationLogic { } } - function _writeWitnessAndGetTypehashes(uint256 memoryLocation, CompactCategory category, string calldata witness, bool usingBatch) - internal - pure - returns (bytes32 activationTypehash, bytes32 compactTypehash) - { - assembly ("memory-safe") { - function writeWitnessAndGetTypehashes(memLocation, c, witnessOffset, witnessLength, usesBatch) -> derivedActivationTypehash, derivedCompactTypehash { - let memoryOffset := add(memLocation, 0x20) - - let activationStart - let categorySpecificStart - if iszero(usesBatch) { - // 1a. prepare initial Activation witness string at offset - mstore(add(memoryOffset, 0x09), PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO) - mstore(memoryOffset, PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE) - - activationStart := add(memoryOffset, 0x13) - categorySpecificStart := add(memoryOffset, 0x29) - } - - if iszero(activationStart) { - // 1b. prepare initial BatchActivation witness string at offset - mstore(add(memoryOffset, 0x16), PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO) - mstore(memoryOffset, PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE) - - activationStart := add(memoryOffset, 0x18) - categorySpecificStart := add(memoryOffset, 0x36) - } - - // 2. prepare activation witness string at offset - let categorySpecificEnd - if iszero(c) { - 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) - categorySpecificEnd := add(categorySpecificStart, 0x70) - categorySpecificStart := add(categorySpecificStart, 0x10) - } - - if iszero(sub(c, 1)) { - 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) - categorySpecificEnd := add(categorySpecificStart, 0x7b) - categorySpecificStart := add(categorySpecificStart, 0x15) - } - - if iszero(categorySpecificEnd) { - 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) - categorySpecificEnd := add(categorySpecificStart, 0x90) - categorySpecificStart := add(categorySpecificStart, 0x1a) - } - - // 3. handle no-witness cases - if iszero(witnessLength) { - let indexWords := shl(5, c) - - mstore(add(categorySpecificEnd, 0x0e), TOKEN_PERMISSIONS_TYPESTRING_FRAGMENT_TWO) - mstore(sub(categorySpecificEnd, 1), TOKEN_PERMISSIONS_TYPESTRING_FRAGMENT_ONE) - mstore(memLocation, sub(add(categorySpecificEnd, 0x2e), memoryOffset)) - - let m := mload(0x40) - - if iszero(usesBatch) { - mstore(0, COMPACT_ACTIVATION_TYPEHASH) - mstore(0x20, BATCH_COMPACT_ACTIVATION_TYPEHASH) - mstore(0x40, MULTICHAIN_COMPACT_ACTIVATION_TYPEHASH) - derivedActivationTypehash := mload(indexWords) - } - - if iszero(derivedActivationTypehash) { - mstore(0, COMPACT_BATCH_ACTIVATION_TYPEHASH) - mstore(0x20, BATCH_COMPACT_BATCH_ACTIVATION_TYPEHASH) - mstore(0x40, MULTICHAIN_COMPACT_BATCH_ACTIVATION_TYPEHASH) - derivedActivationTypehash := mload(indexWords) - } - - mstore(0, COMPACT_TYPEHASH) - mstore(0x20, BATCH_COMPACT_TYPEHASH) - mstore(0x40, MULTICHAIN_COMPACT_TYPEHASH) - derivedCompactTypehash := mload(indexWords) - - mstore(0x40, m) - leave - } - - // 4. insert the supplied compact witness - calldatacopy(categorySpecificEnd, witnessOffset, witnessLength) + /// @dev Transfers `amount` of `token` and mints the resulting balance change of `id` to `to`. + /// Emits a {Transfer} event. + function _transferAndDeposit(address token, address to, uint256 id, uint256 amount) private { + uint256 initialBalance = token.balanceOf(address(this)); - // 5. insert tokenPermissions - let tokenPermissionsFragmentStart := add(categorySpecificEnd, witnessLength) - mstore(add(tokenPermissionsFragmentStart, 0x0e), TOKEN_PERMISSIONS_TYPESTRING_FRAGMENT_TWO) - mstore(sub(tokenPermissionsFragmentStart, 1), TOKEN_PERMISSIONS_TYPESTRING_FRAGMENT_ONE) - mstore(memLocation, sub(add(tokenPermissionsFragmentStart, 0x2e), memoryOffset)) + token.safeTransferFrom(msg.sender, address(this), amount); - // 6. derive the activation typehash - derivedActivationTypehash := keccak256(activationStart, sub(tokenPermissionsFragmentStart, activationStart)) + _checkBalanceAndDeposit(token, to, id, initialBalance); + } - // 7. derive the compact typehash - derivedCompactTypehash := keccak256(categorySpecificStart, sub(tokenPermissionsFragmentStart, categorySpecificStart)) - } + /// @dev Transfers `amount` of `token` and mints the resulting balance change of `id` to `to`. + /// Emits a {Transfer} event. + function _transferAndDepositWithReentrancyGuard(address token, address to, uint256 id, uint256 amount) private { + _setReentrancyGuard(); - activationTypehash, compactTypehash := writeWitnessAndGetTypehashes(memoryLocation, category, witness.offset, witness.length, usingBatch) - } - } + _transferAndDeposit(token, to, id, amount); - function _deriveAndWriteWitnessHash(bytes32 activationTypehash, uint256 idOrIdsHash, bytes32 claimHash, uint256 memoryPointer, uint256 offset) internal pure { - assembly ("memory-safe") { - let m := mload(0x40) - mstore(0, activationTypehash) - mstore(0x20, idOrIdsHash) - mstore(0x40, claimHash) - mstore(add(memoryPointer, offset), keccak256(0, 0x60)) - mstore(0x40, m) - } + _clearReentrancyGuard(); } } diff --git a/src/lib/DepositViaPermit2Logic.sol b/src/lib/DepositViaPermit2Logic.sol new file mode 100644 index 0000000..f8bfe08 --- /dev/null +++ b/src/lib/DepositViaPermit2Logic.sol @@ -0,0 +1,546 @@ +// 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"; +import { ResetPeriod } from "../types/ResetPeriod.sol"; +import { Scope } from "../types/Scope.sol"; + +import { DepositLogic } from "./DepositLogic.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"; + +contract DepositViaPermit2Logic is DepositLogic { + using IdLib for uint256; + using IdLib for address; + using IdLib for ResetPeriod; + using EfficiencyLib for bool; + using EfficiencyLib for uint256; + using ValidityLib for address; + using SafeTransferLib for address; + + uint32 private constant _PERMIT_WITNESS_TRANSFER_FROM_SELECTOR = 0x137c29fe; + uint32 private constant _BATCH_PERMIT_WITNESS_TRANSFER_FROM_SELECTOR = 0xfe8ec1a7; + + address private constant _PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3; + + function _depositViaPermit2(address token, address recipient, bytes calldata signature) internal returns (uint256) { + bytes32 witness = _deriveCompactDepositWitnessHash(uint256(0xa4).asStubborn()); + + (uint256 id, uint256 initialBalance, uint256 m, uint256 typestringMemoryLocation) = _setReentrancyLockAndStartPreparingPermit2Call(token); + + _insertCompactDepositTypestringAt(typestringMemoryLocation); + + assembly ("memory-safe") { + mstore(add(m, 0x100), witness) + } + + _writeSignatureAndPerformPermit2Call(m, uint256(0x140).asStubborn(), uint256(0x200).asStubborn(), signature); + + _checkBalanceAndDeposit(token, recipient, id, initialBalance); + + _clearReentrancyGuard(); + + return id; + } + + function _depositAndRegisterViaPermit2( + address token, + address depositor, // also recipient + ResetPeriod resetPeriod, + bytes32 claimHash, + CompactCategory compactCategory, + string calldata witness, + bytes calldata signature + ) internal returns (uint256) { + (uint256 id, uint256 initialBalance, uint256 m, uint256 typestringMemoryLocation) = _setReentrancyLockAndStartPreparingPermit2Call(token); + + (bytes32 activationTypehash, bytes32 compactTypehash) = _writeWitnessAndGetTypehashes(typestringMemoryLocation, compactCategory, witness, bool(false).asStubborn()); + + _deriveAndWriteWitnessHash(activationTypehash, id, claimHash, m, 0x100); + + uint256 signatureOffsetValue; + assembly ("memory-safe") { + signatureOffsetValue := and(add(mload(add(m, 0x160)), 0x17f), not(0x1f)) + } + + _writeSignatureAndPerformPermit2Call(m, uint256(0x140).asStubborn(), signatureOffsetValue, signature); + + _checkBalanceAndDeposit(token, depositor, id, initialBalance); + + _register(depositor, claimHash, compactTypehash, resetPeriod.toSeconds()); + + _clearReentrancyGuard(); + + return id; + } + + function _depositBatchViaPermit2(ISignatureTransfer.TokenPermissions[] calldata permitted, address recipient, bytes calldata signature) internal returns (uint256[] memory) { + (uint256 totalTokensLessInitialNative, bool firstUnderlyingTokenIsNative, uint256[] memory ids, uint256[] memory initialTokenBalances) = + _preprocessAndPerformInitialNativeDeposit(permitted, recipient); + + bytes32 witness = _deriveCompactDepositWitnessHash(uint256(0x84).asStubborn()); + + (uint256 m, uint256 typestringMemoryLocation) = _beginPreparingBatchDepositPermit2Calldata(totalTokensLessInitialNative, firstUnderlyingTokenIsNative); + + unchecked { + _insertCompactDepositTypestringAt(typestringMemoryLocation); + } + + uint256 signatureOffsetValue; + assembly ("memory-safe") { + mstore(add(m, 0x80), witness) + signatureOffsetValue := add(0x220, shl(7, totalTokensLessInitialNative)) + } + + _writeSignatureAndPerformPermit2Call(m, uint256(0xc0).asStubborn(), signatureOffsetValue, signature); + + _verifyBalancesAndPerformDeposits(ids, permitted, initialTokenBalances, recipient, firstUnderlyingTokenIsNative); + + return ids; + } + + function _depositBatchAndRegisterViaPermit2( + address depositor, + ISignatureTransfer.TokenPermissions[] calldata permitted, + ResetPeriod resetPeriod, + bytes32 claimHash, + CompactCategory compactCategory, + string calldata witness, + bytes calldata signature + ) internal returns (uint256[] memory) { + (uint256 totalTokensLessInitialNative, bool firstUnderlyingTokenIsNative, uint256[] memory ids, uint256[] memory initialTokenBalances) = + _preprocessAndPerformInitialNativeDeposit(permitted, depositor); + + uint256 idsHash; + assembly ("memory-safe") { + idsHash := keccak256(add(ids, 0x20), shl(5, add(totalTokensLessInitialNative, firstUnderlyingTokenIsNative))) + } + + (uint256 m, uint256 typestringMemoryLocation) = _beginPreparingBatchDepositPermit2Calldata(totalTokensLessInitialNative, firstUnderlyingTokenIsNative); + + (bytes32 activationTypehash, bytes32 compactTypehash) = _writeWitnessAndGetTypehashes(typestringMemoryLocation, compactCategory, witness, bool(true).asStubborn()); + + _deriveAndWriteWitnessHash(activationTypehash, idsHash, claimHash, m, 0x80); + + uint256 signatureOffsetValue; + assembly ("memory-safe") { + let witnessLength := witness.length + let totalWitnessMemoryOffset := and(add(add(0xf3, add(witnessLength, iszero(iszero(witnessLength)))), add(mul(eq(compactCategory, 1), 0x0b), shl(6, eq(compactCategory, 2)))), not(0x1f)) + signatureOffsetValue := add(add(0x180, shl(7, totalTokensLessInitialNative)), totalWitnessMemoryOffset) + } + + _writeSignatureAndPerformPermit2Call(m, uint256(0xc0).asStubborn(), signatureOffsetValue, signature); + + _verifyBalancesAndPerformDeposits(ids, permitted, initialTokenBalances, depositor, firstUnderlyingTokenIsNative); + + _register(depositor, claimHash, compactTypehash, resetPeriod.toSeconds()); + + return ids; + } + + function _preprocessAndPerformInitialNativeDeposit(ISignatureTransfer.TokenPermissions[] calldata permitted, address recipient) + private + returns (uint256 totalTokensLessInitialNative, bool firstUnderlyingTokenIsNative, uint256[] memory ids, uint256[] memory initialTokenBalances) + { + _setReentrancyGuard(); + + uint256 totalTokens = permitted.length; + address allocator; + ResetPeriod resetPeriod; + Scope scope; + assembly ("memory-safe") { + let permittedOffset := permitted.offset + 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) + } + + // NOTE: these may need to be sanitized if toIdIfRegistered doesn't already handle for it + allocator := calldataload(0x84) + resetPeriod := calldataload(0xa4) + scope := calldataload(0xc4) + } + + uint256 initialId = address(0).toIdIfRegistered(scope, resetPeriod, allocator); + ids = new uint256[](totalTokens); + if (firstUnderlyingTokenIsNative) { + _deposit(recipient, initialId, msg.value); + ids[0] = initialId; + } + + unchecked { + totalTokensLessInitialNative = totalTokens - firstUnderlyingTokenIsNative.asUint256(); + } + + initialTokenBalances = _prepareIdsAndGetBalances(ids, totalTokensLessInitialNative, firstUnderlyingTokenIsNative, permitted, initialId); + } + + function _setReentrancyLockAndStartPreparingPermit2Call(address token) private returns (uint256 id, uint256 initialBalance, uint256 m, uint256 typestringMemoryLocation) { + _setReentrancyGuard(); + + address allocator; + ResetPeriod resetPeriod; + Scope scope; + assembly ("memory-safe") { + allocator := calldataload(0xa4) + resetPeriod := calldataload(0xc4) + scope := calldataload(0xe4) + } + + id = token.excludingNative().toIdIfRegistered(scope, resetPeriod, allocator); + + initialBalance = token.balanceOf(address(this)); + + assembly ("memory-safe") { + m := mload(0x40) // Grab the free memory pointer; memory will be left dirtied. + + 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) + 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). + } + } + + function _writeSignatureAndPerformPermit2Call(uint256 m, uint256 signatureOffsetLocation, uint256 signatureOffsetValue, bytes calldata signature) private { + bool isPermit2Deployed = _isPermit2Deployed(); + assembly ("memory-safe") { + mstore(add(m, signatureOffsetLocation), signatureOffsetValue) // signature offset + + let signatureLength := signature.length + let signatureMemoryOffset := add(m, add(0x20, signatureOffsetValue)) + + mstore(signatureMemoryOffset, signatureLength) + calldatacopy(add(signatureMemoryOffset, 0x20), signature.offset, signatureLength) + + 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) + } + } + } + + function _verifyBalancesAndPerformDeposits( + uint256[] memory ids, + ISignatureTransfer.TokenPermissions[] calldata permittedTokens, + uint256[] memory initialTokenBalances, + address recipient, + bool firstUnderlyingTokenIsNative + ) private { + uint256 tokenBalance; + uint256 initialBalance; + uint256 errorBuffer; + uint256 totalTokensLessInitialNative = initialTokenBalances.length; + + unchecked { + for (uint256 i = 0; i < totalTokensLessInitialNative; ++i) { + tokenBalance = permittedTokens[i + firstUnderlyingTokenIsNative.asUint256()].token.balanceOf(address(this)); + initialBalance = initialTokenBalances[i]; + errorBuffer |= (initialBalance >= tokenBalance).asUint256(); + + _deposit(recipient, ids[i + firstUnderlyingTokenIsNative.asUint256()], tokenBalance - initialBalance); + } + } + + assembly ("memory-safe") { + if errorBuffer { + // revert InvalidDepositBalanceChange() + mstore(0, 0x426d8dcf) + revert(0x1c, 0x04) + } + } + + _clearReentrancyGuard(); + } + + // NOTE: all tokens must be supplied in ascending order and cannot be duplicated. + function _prepareIdsAndGetBalances( + uint256[] memory ids, + uint256 totalTokensLessInitialNative, + bool firstUnderlyingTokenIsNative, + ISignatureTransfer.TokenPermissions[] calldata permitted, + uint256 id + ) private view returns (uint256[] memory tokenBalances) { + unchecked { + tokenBalances = new uint256[](totalTokensLessInitialNative); + + address token; + uint256 candidateId; + uint256 errorBuffer; + + for (uint256 i = 0; i < totalTokensLessInitialNative; ++i) { + token = permitted[i + firstUnderlyingTokenIsNative.asUint256()].token; + candidateId = id.withReplacedToken(token); + errorBuffer |= (candidateId <= id).asUint256(); + id = candidateId; + + ids[i + firstUnderlyingTokenIsNative.asUint256()] = id; + + tokenBalances[i] = token.balanceOf(address(this)); + } + + assembly ("memory-safe") { + if errorBuffer { + // revert InvalidDepositTokenOrdering() + mstore(0, 0x0f2f1e51) + revert(0x1c, 0x04) + } + } + } + } + + function _beginPreparingBatchDepositPermit2Calldata(uint256 totalTokensLessInitialNative, bool firstUnderlyingTokenIsNative) private view returns (uint256 m, uint256 typestringMemoryLocation) { + assembly ("memory-safe") { + m := mload(0x40) // Grab the free memory pointer; memory will be left dirtied. + + let tokenChunk := shl(6, totalTokensLessInitialNative) + let twoTokenChunks := shl(1, tokenChunk) + + let permittedCalldataLocation := add(add(0x24, calldataload(0x24)), shl(6, firstUnderlyingTokenIsNative)) + + 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 + // 0x80 => witnessHash + mstore(add(m, 0xa0), add(0x160, twoTokenChunks)) // witness offset + // 0xc0 => signatureOffset + 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 + + calldatacopy(add(m, 0x160), permittedCalldataLocation, tokenChunk) // permitted data + + let detailsOffset := add(add(m, 0x160), tokenChunk) + mstore(detailsOffset, totalTokensLessInitialNative) // details.length + + // details data + let starting := add(detailsOffset, 0x20) + let next := add(detailsOffset, 0x40) + let end := shl(6, totalTokensLessInitialNative) + for { let i := 0 } lt(i, end) { i := add(i, 0x40) } { + mstore(add(starting, i), address()) + mstore(add(next, i), calldataload(add(permittedCalldataLocation, add(0x20, i)))) + } + + 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). + } + } + + function _writeWitnessAndGetTypehashes(uint256 memoryLocation, CompactCategory category, string calldata witness, bool usingBatch) + private + pure + returns (bytes32 activationTypehash, bytes32 compactTypehash) + { + assembly ("memory-safe") { + function writeWitnessAndGetTypehashes(memLocation, c, witnessOffset, witnessLength, usesBatch) -> derivedActivationTypehash, derivedCompactTypehash { + let memoryOffset := add(memLocation, 0x20) + + let activationStart + let categorySpecificStart + if iszero(usesBatch) { + // 1a. prepare initial Activation witness string at offset + mstore(add(memoryOffset, 0x09), PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO) + mstore(memoryOffset, PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE) + + activationStart := add(memoryOffset, 0x13) + categorySpecificStart := add(memoryOffset, 0x29) + } + + if iszero(activationStart) { + // 1b. prepare initial BatchActivation witness string at offset + mstore(add(memoryOffset, 0x16), PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO) + mstore(memoryOffset, PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE) + + activationStart := add(memoryOffset, 0x18) + categorySpecificStart := add(memoryOffset, 0x36) + } + + // 2. prepare activation witness string at offset + let categorySpecificEnd + if iszero(c) { + 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) + categorySpecificEnd := add(categorySpecificStart, 0x70) + categorySpecificStart := add(categorySpecificStart, 0x10) + } + + if iszero(sub(c, 1)) { + 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) + categorySpecificEnd := add(categorySpecificStart, 0x7b) + categorySpecificStart := add(categorySpecificStart, 0x15) + } + + if iszero(categorySpecificEnd) { + 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) + categorySpecificEnd := add(categorySpecificStart, 0x90) + categorySpecificStart := add(categorySpecificStart, 0x1a) + } + + // 3. handle no-witness cases + if iszero(witnessLength) { + let indexWords := shl(5, c) + + mstore(add(categorySpecificEnd, 0x0e), TOKEN_PERMISSIONS_TYPESTRING_FRAGMENT_TWO) + mstore(sub(categorySpecificEnd, 1), TOKEN_PERMISSIONS_TYPESTRING_FRAGMENT_ONE) + mstore(memLocation, sub(add(categorySpecificEnd, 0x2e), memoryOffset)) + + let m := mload(0x40) + + if iszero(usesBatch) { + mstore(0, COMPACT_ACTIVATION_TYPEHASH) + mstore(0x20, BATCH_COMPACT_ACTIVATION_TYPEHASH) + mstore(0x40, MULTICHAIN_COMPACT_ACTIVATION_TYPEHASH) + derivedActivationTypehash := mload(indexWords) + } + + if iszero(derivedActivationTypehash) { + mstore(0, COMPACT_BATCH_ACTIVATION_TYPEHASH) + mstore(0x20, BATCH_COMPACT_BATCH_ACTIVATION_TYPEHASH) + mstore(0x40, MULTICHAIN_COMPACT_BATCH_ACTIVATION_TYPEHASH) + derivedActivationTypehash := mload(indexWords) + } + + mstore(0, COMPACT_TYPEHASH) + mstore(0x20, BATCH_COMPACT_TYPEHASH) + mstore(0x40, MULTICHAIN_COMPACT_TYPEHASH) + derivedCompactTypehash := mload(indexWords) + + mstore(0x40, m) + leave + } + + // 4. insert the supplied compact witness + calldatacopy(categorySpecificEnd, witnessOffset, witnessLength) + + // 5. insert tokenPermissions + let tokenPermissionsFragmentStart := add(categorySpecificEnd, witnessLength) + mstore(add(tokenPermissionsFragmentStart, 0x0e), TOKEN_PERMISSIONS_TYPESTRING_FRAGMENT_TWO) + mstore(sub(tokenPermissionsFragmentStart, 1), TOKEN_PERMISSIONS_TYPESTRING_FRAGMENT_ONE) + mstore(memLocation, sub(add(tokenPermissionsFragmentStart, 0x2e), memoryOffset)) + + // 6. derive the activation typehash + derivedActivationTypehash := keccak256(activationStart, sub(tokenPermissionsFragmentStart, activationStart)) + + // 7. derive the compact typehash + derivedCompactTypehash := keccak256(categorySpecificStart, sub(tokenPermissionsFragmentStart, categorySpecificStart)) + } + + activationTypehash, compactTypehash := writeWitnessAndGetTypehashes(memoryLocation, category, witness.offset, witness.length, usingBatch) + } + } + + function _deriveAndWriteWitnessHash(bytes32 activationTypehash, uint256 idOrIdsHash, bytes32 claimHash, uint256 memoryPointer, uint256 offset) private pure { + assembly ("memory-safe") { + let m := mload(0x40) + mstore(0, activationTypehash) + mstore(0x20, idOrIdsHash) + mstore(0x40, claimHash) + mstore(add(memoryPointer, offset), keccak256(0, 0x60)) + mstore(0x40, m) + } + } + + function _deriveCompactDepositWitnessHash(uint256 calldataOffset) private pure returns (bytes32 witnessHash) { + assembly ("memory-safe") { + let m := mload(0x40) // Grab the free memory pointer; memory will be left dirtied. + + // 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. + mstore(m, PERMIT2_DEPOSIT_WITNESS_FRAGMENT_HASH) + calldatacopy(add(m, 0x20), calldataOffset, 0x80) // allocator, resetPeriod, scope, recipient + witnessHash := keccak256(m, 0xa0) + } + } + + function _insertCompactDepositTypestringAt(uint256 memoryLocation) private pure { + assembly ("memory-safe") { + mstore(memoryLocation, 0x96) + 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/WithdrawalLogic.sol b/src/lib/WithdrawalLogic.sol index 9c9b7ab..ef75a69 100644 --- a/src/lib/WithdrawalLogic.sol +++ b/src/lib/WithdrawalLogic.sol @@ -4,12 +4,12 @@ pragma solidity ^0.8.27; import { ForcedWithdrawalStatus } from "../types/ForcedWithdrawalStatus.sol"; import { ResetPeriod } from "../types/ResetPeriod.sol"; -import { DepositLogic } from "./DepositLogic.sol"; +import { DepositViaPermit2Logic } from "./DepositViaPermit2Logic.sol"; import { EfficiencyLib } from "./EfficiencyLib.sol"; import { IdLib } from "./IdLib.sol"; import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol"; -contract WithdrawalLogic is DepositLogic { +contract WithdrawalLogic is DepositViaPermit2Logic { using IdLib for uint256; using IdLib for ResetPeriod; using SafeTransferLib for address;