diff --git a/foundry.toml b/foundry.toml index 6c27aae..d9e7d95 100644 --- a/foundry.toml +++ b/foundry.toml @@ -3,7 +3,7 @@ solc = '0.8.28' evm_version='cancun' via_ir = true # optimizer_runs = 4_294_967_295 -optimizer_runs = 9 +optimizer_runs = 200 bytecode_hash = 'none' src = "src" out = "out" diff --git a/snapshots/TheCompactTest.json b/snapshots/TheCompactTest.json index 86584af..bfa3da6 100644 --- a/snapshots/TheCompactTest.json +++ b/snapshots/TheCompactTest.json @@ -1,34 +1,33 @@ { - "basicTransfer": "57220", - "basicWithdrawal": "60350", - "batchClaim": "112331", - "batchClaimWithWitness": "112988", - "batchTransfer": "82936", - "batchWithdrawal": "101303", - "claim": "60821", - "claimAndWithdraw": "73704", - "claimWithWitness": "60004", - "depositBatchSingleERC20": "67765", - "depositBatchViaPermit2SingleERC20": "107820", - "depositERC20AndURI": "67076", - "depositERC20Basic": "67081", - "depositERC20ViaPermit2AndURI": "98237", - "depositETHAndURI": "26774", - "depositETHBasic": "28237", - "qualifiedBatchClaim": "113658", - "qualifiedBatchClaimWithWitness": "113117", - "qualifiedClaim": "60719", - "qualifiedClaimWithWitness": "59407", - "qualifiedSplitBatchClaim": "141263", - "qualifiedSplitBatchClaimWithWitness": "141228", - "qualifiedSplitClaim": "86947", - "qualifiedSplitClaimWithWitness": "87358", - "splitBatchClaim": "140743", - "splitBatchClaimWithWitness": "140674", - "splitBatchTransfer": "113646", - "splitBatchWithdrawal": "142938", - "splitClaim": "86873", - "splitClaimWithWitness": "86452", - "splitTransfer": "83176", - "splitWithdrawal": "94106" + "basicTransfer": "57231", + "basicWithdrawal": "60321", + "batchClaim": "112342", + "batchClaimWithWitness": "112999", + "batchTransfer": "82862", + "batchWithdrawal": "101233", + "claim": "60835", + "claimAndWithdraw": "73718", + "claimWithWitness": "59909", + "depositBatchSingleERC20": "67728", + "depositERC20AndURI": "67021", + "depositERC20Basic": "67026", + "depositERC20ViaPermit2AndURI": "98015", + "depositETHAndURI": "26694", + "depositETHBasic": "28186", + "qualifiedBatchClaim": "113669", + "qualifiedBatchClaimWithWitness": "113128", + "qualifiedClaim": "60733", + "qualifiedClaimWithWitness": "59312", + "qualifiedSplitBatchClaim": "141215", + "qualifiedSplitBatchClaimWithWitness": "141180", + "qualifiedSplitClaim": "86961", + "qualifiedSplitClaimWithWitness": "87256", + "splitBatchClaim": "140724", + "splitBatchClaimWithWitness": "140655", + "splitBatchTransfer": "113519", + "splitBatchWithdrawal": "142771", + "splitClaim": "86887", + "splitClaimWithWitness": "86379", + "splitTransfer": "83187", + "splitWithdrawal": "94053" } \ No newline at end of file diff --git a/src/TheCompact.sol b/src/TheCompact.sol index 000d274..59155e3 100644 --- a/src/TheCompact.sol +++ b/src/TheCompact.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.27; import { ITheCompact } from "./interfaces/ITheCompact.sol"; import { CompactCategory } from "./types/CompactCategory.sol"; -import { ActivatedCompactCategory } from "./types/ActivatedCompactCategory.sol"; import { Lock } from "./types/Lock.sol"; import { Scope } from "./types/Scope.sol"; import { ResetPeriod } from "./types/ResetPeriod.sol"; @@ -85,7 +84,33 @@ import { ExogenousQualifiedSplitBatchMultichainClaimWithWitness } from "./types/BatchMultichainClaims.sol"; -import { COMPACT_TYPEHASH, BATCH_COMPACT_TYPEHASH, MULTICHAIN_COMPACT_TYPEHASH, PERMIT2_DEPOSIT_WITNESS_FRAGMENT_HASH } from "./types/EIP712Types.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, + TOKEN_PERMISSIONS_TYPSTRING_FRAGMENT_ONE, + TOKEN_PERMISSIONS_TYPSTRING_FRAGMENT_TWO, + COMPACT_ACTIVATION_TYPEHASH, + BATCH_COMPACT_ACTIVATION_TYPEHASH, + MULTICHAIN_COMPACT_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 +} from "./types/EIP712Types.sol"; import { SplitComponent, TransferComponent, SplitByIdComponent, BatchClaimComponent, SplitBatchClaimComponent } from "./types/Components.sol"; @@ -156,7 +181,6 @@ contract TheCompact is ITheCompact, ERC6909, Tstorish { using HashLib for ExogenousSplitBatchMultichainClaimWithWitness; using HashLib for ExogenousQualifiedSplitBatchMultichainClaim; using HashLib for ExogenousQualifiedSplitBatchMultichainClaimWithWitness; - using HashLib for ActivatedCompactCategory; using IdLib for uint96; using IdLib for uint256; using IdLib for address; @@ -208,11 +232,13 @@ contract TheCompact is ITheCompact, ERC6909, Tstorish { uint256 private immutable _INITIAL_CHAIN_ID; bytes32 private immutable _INITIAL_DOMAIN_SEPARATOR; MetadataRenderer private immutable _METADATA_RENDERER; + bool private immutable _PERMIT2_INITIALLY_DEPLOYED; constructor() { _INITIAL_CHAIN_ID = block.chainid; _INITIAL_DOMAIN_SEPARATOR = block.chainid.toNotarizedDomainSeparator(); _METADATA_RENDERER = new MetadataRenderer(); + _PERMIT2_INITIALLY_DEPLOYED = _checkPermit2Deployment(); } function deposit(address allocator) external payable returns (uint256 id) { @@ -253,56 +279,6 @@ contract TheCompact is ITheCompact, ERC6909, Tstorish { return _processBatchDeposit(idsAndAmounts, msg.sender); } - function _processBatchDeposit(uint256[2][] calldata idsAndAmounts, address recipient) internal returns (bool) { - _setTstorish(_REENTRANCY_GUARD_SLOT, 1); - uint256 totalIds = idsAndAmounts.length; - bool firstUnderlyingTokenIsNative; - uint256 id; - - assembly ("memory-safe") { - let idsAndAmountsOffset := idsAndAmounts.offset - id := calldataload(idsAndAmountsOffset) - firstUnderlyingTokenIsNative := iszero(shr(96, shl(96, id))) - // Revert if: - // * the array is empty - // * the callvalue is zero but the first token is native - // * the callvalue is nonzero but the first token is non-native - // * the first token is non-native and the callvalue doesn't equal the first amount - if or(iszero(totalIds), or(eq(firstUnderlyingTokenIsNative, iszero(callvalue())), and(firstUnderlyingTokenIsNative, iszero(eq(callvalue(), calldataload(add(idsAndAmountsOffset, 0x20))))))) - { - // revert InvalidBatchDepositStructure() - mstore(0, 0xca0fc08e) - revert(0x1c, 0x04) - } - } - - uint96 currentAllocatorId = id.toRegisteredAllocatorId(); - - if (firstUnderlyingTokenIsNative) { - _deposit(recipient, id, msg.value); - } - - unchecked { - for (uint256 i = firstUnderlyingTokenIsNative.asUint256(); i < totalIds; ++i) { - uint256[2] calldata idAndAmount = idsAndAmounts[i]; - id = idAndAmount[0]; - uint256 amount = idAndAmount[1]; - - uint96 newAllocatorId = id.toAllocatorId(); - if (newAllocatorId != currentAllocatorId) { - newAllocatorId.mustHaveARegisteredAllocator(); - currentAllocatorId = newAllocatorId; - } - - _transferAndDeposit(id.toToken(), recipient, id, amount); - } - } - - _clearTstorish(_REENTRANCY_GUARD_SLOT); - - return true; - } - function deposit( address token, uint256, // amount @@ -384,51 +360,150 @@ contract TheCompact is ITheCompact, ERC6909, Tstorish { } function depositAndRegister( - uint256 id, - uint256 amount, - uint256 nonce, - uint256 deadline, - address depositor, + address token, + uint256, // amount + uint256, // nonce + uint256, // deadline + address depositor, // also recipient + address allocator, + ResetPeriod resetPeriod, + Scope scope, bytes32 claimHash, CompactCategory compactCategory, string calldata witness, bytes calldata signature - ) external returns (bool) { + ) external returns (uint256 id) { _setTstorish(_REENTRANCY_GUARD_SLOT, 1); - id.toAllocatorId().mustHaveARegisteredAllocator(); - address token = id.toToken().excludingNative(); + id = token.excludingNative().toIdIfRegistered(scope, resetPeriod, allocator); + + address permit2 = address(_PERMIT2); uint256 initialBalance = token.balanceOf(address(this)); - string memory activationTypestring; - string memory compactTypestring; - if (compactCategory == CompactCategory.Compact) { - compactTypestring = string.concat("Compact(address arbiter,address sponsor,uint256 nonce,uint256 expires,uint256 id,uint256 amount", bytes(witness).length != 0 ? "," : "", witness, ")"); - activationTypestring = string.concat("Activation(uint256 id,Compact compact)", compactTypestring); - } else if (compactCategory == CompactCategory.BatchCompact) { - compactTypestring = - string.concat("BatchCompact(address arbiter,address sponsor,uint256 nonce,uint256 expires,uint256[2][] idsAndAmounts", bytes(witness).length != 0 ? "," : "", witness, ")"); - activationTypestring = string.concat("Activation(uint256 id,BatchCompact compact)", compactTypestring); - } else { - compactTypestring = string.concat( - "MultichainCompact(address sponsor,uint256 nonce,uint256 expires,Segment[] segments)Segment(address arbiter,uint256 chainId,uint256[2][] idsAndAmounts", - bytes(witness).length != 0 ? "," : "", - witness, - ")" - ); - activationTypestring = string.concat("Activation(uint256 id,MultichainCompact compact)", compactTypestring); - } + bool isPermit2Deployed = _isPermit2Deployed(); - string memory witnessTypestring = string.concat("Activation witness)", activationTypestring, "TokenPermissions(address token,uint256 amount)"); + bytes32 compactTypehash; - bytes32 witnessHash = keccak256(abi.encodePacked(keccak256(bytes(activationTypestring)), id, claimHash)); + assembly ("memory-safe") { + function writeWitnessAndGetTypehashes(memoryLocation, c, witnessOffset, witnessLength) -> derivedActivationTypehash, derivedCompactTypehash { + let memoryOffset := add(memoryLocation, 0x20) + // 1. prepare initial witness string at offset + mstore(add(memoryOffset, 0x09), PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO) + mstore(memoryOffset, PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE) + let activationStart := add(memoryOffset, 0x13) + let categorySpecificStart := add(memoryOffset, 0x29) + 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) + } - ISignatureTransfer.SignatureTransferDetails memory details = ISignatureTransfer.SignatureTransferDetails({ to: address(this), requestedAmount: amount }); + 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) + } - ISignatureTransfer.PermitTransferFrom memory permitTransferFrom = - ISignatureTransfer.PermitTransferFrom({ permitted: ISignatureTransfer.TokenPermissions({ token: token, amount: amount }), nonce: nonce, deadline: deadline }); + 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) + } - _PERMIT2.permitWitnessTransferFrom(permitTransferFrom, details, depositor, witnessHash, witnessTypestring, signature); + // 2. handle no-witness cases + if iszero(witnessLength) { + let indexWords := shl(5, c) + + mstore(add(categorySpecificEnd, 0x0e), TOKEN_PERMISSIONS_TYPSTRING_FRAGMENT_TWO) + mstore(sub(categorySpecificEnd, 1), TOKEN_PERMISSIONS_TYPSTRING_FRAGMENT_ONE) + mstore(memoryLocation, sub(add(categorySpecificEnd, 0x2e), memoryOffset)) + + let m := mload(0x40) + + mstore(0, COMPACT_ACTIVATION_TYPEHASH) + mstore(0x20, BATCH_COMPACT_ACTIVATION_TYPEHASH) + mstore(0x40, MULTICHAIN_COMPACT_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 + } + + // 3. insert the supplied compact witness + calldatacopy(categorySpecificEnd, witnessOffset, witnessLength) + + // 4. insert tokenPermissions + let tokenPermissionsFragmentStart := add(categorySpecificEnd, witnessLength) + mstore(add(tokenPermissionsFragmentStart, 0x0f), TOKEN_PERMISSIONS_TYPSTRING_FRAGMENT_TWO) + mstore(tokenPermissionsFragmentStart, TOKEN_PERMISSIONS_TYPSTRING_FRAGMENT_ONE) + mstore(memoryLocation, sub(add(tokenPermissionsFragmentStart, 0x2f), memoryOffset)) + + categorySpecificEnd := add(tokenPermissionsFragmentStart, 1) + + // 5. derive the activation typehash + derivedActivationTypehash := keccak256(activationStart, sub(categorySpecificEnd, activationStart)) + + // 6. derive the compact typehash + derivedCompactTypehash := keccak256(categorySpecificStart, sub(categorySpecificEnd, categorySpecificStart)) + } + + let m := mload(0x40) // Grab the free memory pointer; memory will be left dirtied. + + let signatureLength := signature.length + let dataStart := add(m, 0x1c) + + 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) + + let permit2WitnessOffset := add(m, 0x160) + let activationTypehash + activationTypehash, compactTypehash := writeWitnessAndGetTypehashes(permit2WitnessOffset, compactCategory, witness.offset, witness.length) + let signatureOffset := and(add(mload(permit2WitnessOffset), 0x5f), not(0x1f)) + mstore(add(m, 0x140), signatureOffset) + signatureOffset := add(m, add(signatureOffset, 0x20)) + + mstore(0, activationTypehash) + mstore(0x20, id) + mstore(0x40, claimHash) + mstore(add(m, 0x100), keccak256(0, 0x60)) + mstore(0x40, m) + + mstore(signatureOffset, signatureLength) + calldatacopy(add(signatureOffset, 0x20), signature.offset, signatureLength) + + if iszero(and(isPermit2Deployed, call(gas(), permit2, 0, add(m, 0x1c), add(0x24, add(signatureOffset, 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()) + } + + // TODO: add proper revert on no data + revert(0, 0) + } + } uint256 tokenBalance = token.balanceOf(address(this)); @@ -444,11 +519,57 @@ contract TheCompact is ITheCompact, ERC6909, Tstorish { _deposit(depositor, id, tokenBalance - initialBalance); } - _registeredClaimHashes[depositor][claimHash] = keccak256(bytes(compactTypestring)); + _registeredClaimHashes[depositor][claimHash] = compactTypehash; _clearTstorish(_REENTRANCY_GUARD_SLOT); + } - return true; + /* TODO: put these two batch deposit methods back in after finding some room for them + function deposit( + address depositor, + ISignatureTransfer.TokenPermissions[] calldata permitted, + address allocator, + ResetPeriod resetPeriod, + Scope scope, + address recipient, + uint256 nonce, + uint256 deadline, + bytes calldata signature + ) external payable returns (uint256[] memory) { + uint256 totalTokens = permitted.length; + bool firstUnderlyingTokenIsNative; + assembly ("memory-safe") { + let permittedOffset := permitted.offset + firstUnderlyingTokenIsNative := iszero(shr(96, shl(96, add(permittedOffset, 0x20)))) + + // 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, 0x40))))))) + { + // revert InvalidBatchDepositStructure() + mstore(0, 0xca0fc08e) + revert(0x1c, 0x04) + } + } + + uint256 initialId = address(0).toIdIfRegistered(scope, resetPeriod, allocator); + + return _processBatchPermit2Deposits( + firstUnderlyingTokenIsNative, + recipient, + initialId, + totalTokens, + permitted, + depositor, + nonce, + deadline, + allocator.toPermit2DepositWitnessHash(resetPeriod, scope, recipient), + "CompactDeposit witness)CompactDeposit(address allocator,uint8 resetPeriod,uint8 scope,address recipient)TokenPermissions(address token,uint256 amount)", + signature + ); } function depositAndRegister( @@ -555,53 +676,7 @@ contract TheCompact is ITheCompact, ERC6909, Tstorish { _clearTstorish(_REENTRANCY_GUARD_SLOT); } - - function deposit( - address depositor, - ISignatureTransfer.TokenPermissions[] calldata permitted, - address allocator, - ResetPeriod resetPeriod, - Scope scope, - address recipient, - uint256 nonce, - uint256 deadline, - bytes calldata signature - ) external payable returns (uint256[] memory) { - uint256 totalTokens = permitted.length; - bool firstUnderlyingTokenIsNative; - assembly ("memory-safe") { - let permittedOffset := permitted.offset - firstUnderlyingTokenIsNative := iszero(shr(96, shl(96, add(permittedOffset, 0x20)))) - - // 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, 0x40))))))) - { - // revert InvalidBatchDepositStructure() - mstore(0, 0xca0fc08e) - revert(0x1c, 0x04) - } - } - - uint256 initialId = address(0).toIdIfRegistered(scope, resetPeriod, allocator); - - return _processBatchPermit2Deposits( - firstUnderlyingTokenIsNative, - recipient, - initialId, - totalTokens, - permitted, - depositor, - nonce, - deadline, - allocator.toPermit2DepositWitnessHash(resetPeriod, scope, recipient), - "CompactDeposit witness)CompactDeposit(address allocator,uint8 resetPeriod,uint8 scope,address recipient)TokenPermissions(address token,uint256 amount)", - signature - ); - } + */ function allocatedTransfer(BasicTransfer calldata transfer) external returns (bool) { return _processBasicTransfer(transfer, _release); @@ -1160,6 +1235,56 @@ contract TheCompact is ITheCompact, ERC6909, Tstorish { } } + function _processBatchDeposit(uint256[2][] calldata idsAndAmounts, address recipient) internal returns (bool) { + _setTstorish(_REENTRANCY_GUARD_SLOT, 1); + uint256 totalIds = idsAndAmounts.length; + bool firstUnderlyingTokenIsNative; + uint256 id; + + assembly ("memory-safe") { + let idsAndAmountsOffset := idsAndAmounts.offset + id := calldataload(idsAndAmountsOffset) + firstUnderlyingTokenIsNative := iszero(shr(96, shl(96, id))) + // Revert if: + // * the array is empty + // * the callvalue is zero but the first token is native + // * the callvalue is nonzero but the first token is non-native + // * the first token is non-native and the callvalue doesn't equal the first amount + if or(iszero(totalIds), or(eq(firstUnderlyingTokenIsNative, iszero(callvalue())), and(firstUnderlyingTokenIsNative, iszero(eq(callvalue(), calldataload(add(idsAndAmountsOffset, 0x20))))))) + { + // revert InvalidBatchDepositStructure() + mstore(0, 0xca0fc08e) + revert(0x1c, 0x04) + } + } + + uint96 currentAllocatorId = id.toRegisteredAllocatorId(); + + if (firstUnderlyingTokenIsNative) { + _deposit(recipient, id, msg.value); + } + + unchecked { + for (uint256 i = firstUnderlyingTokenIsNative.asUint256(); i < totalIds; ++i) { + uint256[2] calldata idAndAmount = idsAndAmounts[i]; + id = idAndAmount[0]; + uint256 amount = idAndAmount[1]; + + uint96 newAllocatorId = id.toAllocatorId(); + if (newAllocatorId != currentAllocatorId) { + newAllocatorId.mustHaveARegisteredAllocator(); + currentAllocatorId = newAllocatorId; + } + + _transferAndDeposit(id.toToken(), recipient, id, amount); + } + } + + _clearTstorish(_REENTRANCY_GUARD_SLOT); + + return true; + } + function _notExpiredAndSignedByAllocator(bytes32 messageHash, address allocator, BasicTransfer calldata transferPayload) internal { transferPayload.expires.later(); @@ -2003,14 +2128,6 @@ contract TheCompact is ITheCompact, ERC6909, Tstorish { _clearTstorish(_REENTRANCY_GUARD_SLOT); } - function _verifyAndProcessBatchComponents( - uint96 allocatorId, - address sponsor, - address claimant, - BatchClaimComponent[] calldata claims, - function(address, address, uint256, uint256) internal returns (bool) operation - ) internal returns (bool) { } - function _verifyAndProcessSplitComponents( address sponsor, uint256 id, @@ -2294,4 +2411,19 @@ contract TheCompact is ITheCompact, ERC6909, Tstorish { } } } + + function _isPermit2Deployed() internal view returns (bool) { + if (_PERMIT2_INITIALLY_DEPLOYED) { + return true; + } + + return _checkPermit2Deployment(); + } + + function _checkPermit2Deployment() internal view returns (bool permit2Deployed) { + address permit2 = address(_PERMIT2); + assembly ("memory-safe") { + permit2Deployed := iszero(iszero(extcodesize(permit2))) + } + } } diff --git a/src/interfaces/ITheCompact.sol b/src/interfaces/ITheCompact.sol index 20d0401..f7f99ed 100644 --- a/src/interfaces/ITheCompact.sol +++ b/src/interfaces/ITheCompact.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.27; import { ForcedWithdrawalStatus } from "../types/ForcedWithdrawalStatus.sol"; import { ResetPeriod } from "../types/ResetPeriod.sol"; import { Scope } from "../types/Scope.sol"; +import { CompactCategory } from "../types/CompactCategory.sol"; import { ISignatureTransfer } from "permit2/src/interfaces/ISignatureTransfer.sol"; import { BasicTransfer, @@ -120,17 +121,20 @@ interface ITheCompact { bytes calldata signature ) external returns (uint256 id); - function deposit( + function depositAndRegister( + address token, + uint256 amount, + uint256 nonce, + uint256 deadline, address depositor, - ISignatureTransfer.TokenPermissions[] calldata permitted, address allocator, ResetPeriod resetPeriod, Scope scope, - address recipient, - uint256 nonce, - uint256 deadline, + bytes32 claimHash, + CompactCategory compactCategory, + string calldata witness, bytes calldata signature - ) external payable returns (uint256[] memory ids); + ) external returns (uint256 id); function allocatedTransfer(BasicTransfer calldata transfer) external returns (bool); diff --git a/src/lib/HashLib.sol b/src/lib/HashLib.sol index dde3746..73cfa7b 100644 --- a/src/lib/HashLib.sol +++ b/src/lib/HashLib.sol @@ -22,24 +22,6 @@ import { MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_THREE, MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_FOUR, MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_FIVE, - PERMIT2_DEPOSIT_WITNESS_FRAGMENT_HASH, - PERMIT2_DEPOSIT_WITH_COMPACT_ACTIVATION_TYPEHASH, - PERMIT2_DEPOSIT_WITH_BATCH_COMPACT_ACTIVATION_TYPEHASH, - PERMIT2_DEPOSIT_WITH_MULTICHAIN_COMPACT_ACTIVATION_TYPEHASH, - PERMIT2_BATCH_DEPOSIT_WITH_COMPACT_ACTIVATION_TYPEHASH, - PERMIT2_BATCH_DEPOSIT_WITH_BATCH_COMPACT_ACTIVATION_TYPEHASH, - PERMIT2_BATCH_DEPOSIT_WITH_MULTICHAIN_COMPACT_ACTIVATION_TYPEHASH, - PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE, - PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO, - PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_THREE, - PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_FOUR, - PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_FIVE, - PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE, - PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO, - PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_THREE, - PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_FOUR, - PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_FIVE, - PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_SIX, PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_ONE, PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_TWO, PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_THREE, @@ -61,7 +43,8 @@ import { BATCH_COMPACT_BATCH_ACTIVATION_TYPEHASH, MULTICHAIN_COMPACT_BATCH_ACTIVATION_TYPEHASH, TOKEN_PERMISSIONS_TYPSTRING_FRAGMENT_ONE, - TOKEN_PERMISSIONS_TYPSTRING_FRAGMENT_TWO + TOKEN_PERMISSIONS_TYPSTRING_FRAGMENT_TWO, + PERMIT2_DEPOSIT_WITNESS_FRAGMENT_HASH } from "../types/EIP712Types.sol"; import { @@ -130,7 +113,6 @@ import { import { TransferComponent, SplitComponent, SplitByIdComponent, BatchClaimComponent, SplitBatchClaimComponent } from "../types/Components.sol"; -import { ActivatedCompactCategory } from "../types/ActivatedCompactCategory.sol"; import { ResetPeriod } from "../types/ResetPeriod.sol"; import { Scope } from "../types/Scope.sol"; @@ -929,133 +911,4 @@ library HashLib { messageHash := keccak256(m, 0xa0) } } - - function toPermit2DepositAndRegisterTypehashes(ActivatedCompactCategory category, string calldata compactWitnessTypestringFragment) - internal - pure - returns (bytes32 permit2Typehash, bytes32 activationTypehash, bytes32 compactTypehash) - { - assembly ("memory-safe") { - function toTypehash(c, witnessOffset, witnessLength) -> p, a, t { - let m := mload(0x40) // Grab the free memory pointer; memory will be left dirtied - - let isBatch := gt(c, 2) - c := sub(c, mul(isBatch, 3)) - let indexWords := shl(5, c) - - let activationStart - - // 1. handle no-witness cases or prepare first witness fragment based on deposit vs batch deposit - let fragmentTwoStart - if iszero(isBatch) { - if iszero(witnessLength) { - mstore(0, PERMIT2_DEPOSIT_WITH_COMPACT_ACTIVATION_TYPEHASH) - mstore(0x20, PERMIT2_DEPOSIT_WITH_BATCH_COMPACT_ACTIVATION_TYPEHASH) - mstore(0x40, PERMIT2_DEPOSIT_WITH_MULTICHAIN_COMPACT_ACTIVATION_TYPEHASH) - p := mload(indexWords) - - mstore(0, COMPACT_ACTIVATION_TYPEHASH) - mstore(0x20, BATCH_COMPACT_ACTIVATION_TYPEHASH) - mstore(0x40, MULTICHAIN_COMPACT_ACTIVATION_TYPEHASH) - a := mload(indexWords) - - mstore(0, COMPACT_TYPEHASH) - mstore(0x20, BATCH_COMPACT_TYPEHASH) - mstore(0x40, MULTICHAIN_COMPACT_TYPEHASH) - t := mload(indexWords) - - mstore(0x40, m) - leave - } - - mstore(m, PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE) - mstore(add(m, 0x20), PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO) - mstore(add(m, 0x40), PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_THREE) - mstore(add(m, 0x6d), PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_FIVE) - mstore(add(m, 0x60), PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_FOUR) - fragmentTwoStart := add(m, 0x8d) - activationStart := add(m, 0x77) - } - - if iszero(fragmentTwoStart) { - if iszero(witnessLength) { - mstore(0, PERMIT2_BATCH_DEPOSIT_WITH_COMPACT_ACTIVATION_TYPEHASH) - mstore(0x20, PERMIT2_BATCH_DEPOSIT_WITH_BATCH_COMPACT_ACTIVATION_TYPEHASH) - mstore(0x40, PERMIT2_BATCH_DEPOSIT_WITH_MULTICHAIN_COMPACT_ACTIVATION_TYPEHASH) - p := mload(indexWords) - - mstore(0, COMPACT_BATCH_ACTIVATION_TYPEHASH) - mstore(0x20, BATCH_COMPACT_BATCH_ACTIVATION_TYPEHASH) - mstore(0x40, MULTICHAIN_COMPACT_BATCH_ACTIVATION_TYPEHASH) - a := mload(indexWords) - - mstore(0, COMPACT_TYPEHASH) - mstore(0x20, BATCH_COMPACT_TYPEHASH) - mstore(0x40, MULTICHAIN_COMPACT_TYPEHASH) - t := mload(indexWords) - - mstore(0x40, m) - leave - } - - mstore(m, PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE) - mstore(add(m, 0x20), PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO) - mstore(add(m, 0x40), PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_THREE) - mstore(add(m, 0x60), PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_FOUR) - mstore(add(m, 0x80), PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_FIVE) - mstore8(add(m, 0xa0), PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_SIX) - fragmentTwoStart := add(m, 0xa1) - activationStart := add(m, 0x83) - } - - // 2. prepare second witness fragment based on compact category - let fragmentThreeStart - if iszero(c) { - mstore(fragmentTwoStart, PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_ONE) - mstore(add(fragmentTwoStart, 0x20), PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_TWO) - mstore(add(fragmentTwoStart, 0x50), PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_FOUR) - mstore(add(fragmentTwoStart, 0x40), PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_THREE) - fragmentThreeStart := add(fragmentTwoStart, 0x70) - } - - if iszero(sub(c, 1)) { - mstore(fragmentTwoStart, PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_ONE) - mstore(add(fragmentTwoStart, 0x20), PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_TWO) - mstore(add(fragmentTwoStart, 0x5b), PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_FOUR) - mstore(add(fragmentTwoStart, 0x40), PERMIT2_ACTIVATION_BATCH_COMPACT_TYPESTRING_FRAGMENT_THREE) - fragmentThreeStart := add(fragmentTwoStart, 0x7b) - } - - if iszero(fragmentThreeStart) { - mstore(fragmentTwoStart, PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_ONE) - mstore(add(fragmentTwoStart, 0x20), PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_TWO) - mstore(add(fragmentTwoStart, 0x40), PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_THREE) - mstore(add(fragmentTwoStart, 0x60), PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_FOUR) - mstore(add(fragmentTwoStart, 0x90), PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_SIX) - mstore(add(fragmentTwoStart, 0x80), PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_FIVE) - fragmentThreeStart := add(fragmentTwoStart, 0xb0) - } - - // 3. insert the supplied compact witness - calldatacopy(fragmentThreeStart, witnessOffset, witnessLength) - - // 4. insert tokenPermissions - let tokenPermissionsFragmentStart := add(fragmentThreeStart, witnessLength) - mstore(add(tokenPermissionsFragmentStart, 0x0e), TOKEN_PERMISSIONS_TYPSTRING_FRAGMENT_TWO) - mstore(tokenPermissionsFragmentStart, TOKEN_PERMISSIONS_TYPSTRING_FRAGMENT_ONE) - - // 5. derive the permit2 typehash - let totalPayloadSizeWithoutTokenPermissions := sub(tokenPermissionsFragmentStart, m) - p := keccak256(m, add(totalPayloadSizeWithoutTokenPermissions, 0x2e)) - - // 6. derive the activation typehash - a := keccak256(activationStart, sub(totalPayloadSizeWithoutTokenPermissions, activationStart)) - - // 7. derive the compact typehash - t := keccak256(fragmentTwoStart, sub(totalPayloadSizeWithoutTokenPermissions, fragmentTwoStart)) - } - - permit2Typehash, activationTypehash, compactTypehash := toTypehash(category, compactWitnessTypestringFragment.offset, compactWitnessTypestringFragment.length) - } - } } diff --git a/src/lib/IdLib.sol b/src/lib/IdLib.sol index 016f4e4..ddc3ef0 100644 --- a/src/lib/IdLib.sol +++ b/src/lib/IdLib.sol @@ -8,7 +8,6 @@ import { MetadataLib } from "./MetadataLib.sol"; import { EfficiencyLib } from "./EfficiencyLib.sol"; import { SignatureCheckerLib } from "solady/utils/SignatureCheckerLib.sol"; import { CompactCategory } from "../types/CompactCategory.sol"; -import { ActivatedCompactCategory } from "../types/ActivatedCompactCategory.sol"; library IdLib { using IdLib for uint96; @@ -194,12 +193,6 @@ library IdLib { return (msg.sender == allocator).or(allocator.code.length > 0).or(proof.length == 86 && (proof[0] == 0xff).and(allocator == address(uint160(uint256(keccak256(proof)))))); } - function toActivated(CompactCategory category, bool batch) internal pure returns (ActivatedCompactCategory activatedCategory) { - assembly ("memory-safe") { - activatedCategory := add(category, mul(batch, 3)) - } - } - function register(address allocator) internal returns (uint96 allocatorId) { allocatorId = allocator.usingAllocatorId(); diff --git a/src/types/ActivatedCompactCategory.sol b/src/types/ActivatedCompactCategory.sol deleted file mode 100644 index 54ecefa..0000000 --- a/src/types/ActivatedCompactCategory.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.27; - -enum ActivatedCompactCategory { - Compact, - BatchCompact, - MultichainCompact, - BatchDepositCompact, - BatchDepositBatchCompact, - BatchDepositMultichainCompact -} diff --git a/src/types/EIP712Types.sol b/src/types/EIP712Types.sol index df3974b..dc40908 100644 --- a/src/types/EIP712Types.sol +++ b/src/types/EIP712Types.sol @@ -121,74 +121,35 @@ bytes32 constant EMISSARY_ASSIGNMENT_TYPEHASH = 0x5ca9a66b8bbf0d2316e90dfa3df465 /// @dev `keccak256(bytes("CompactDeposit(address allocator,uint8 resetPeriod,uint8 scope,address recipient)"))`. bytes32 constant PERMIT2_DEPOSIT_WITNESS_FRAGMENT_HASH = 0xe055493563385cc588fffacbffe2dab023fef807baa449530431169b0eeb5b69; -/// @dev `keccak256(bytes("PermitWitnessTransferFrom(TokenPermissions permitted,address spender,uint256 nonce,uint256 deadline,Activation witness)Activation(uint256 id,Compact compact)Compact(address arbiter,address sponsor,uint256 nonce,uint256 expires,uint256 id,uint256 amount)TokenPermissions(address token,uint256 amount)"))`. -bytes32 constant PERMIT2_DEPOSIT_WITH_COMPACT_ACTIVATION_TYPEHASH = 0xf653f659d3a9d0c2d3b3e901b5f71b67ad949a927c0c27b41dcdf4ecddd9b489; - /// @dev `keccak256(bytes("Activation(uint256 id,Compact compact)Compact(address arbiter,address sponsor,uint256 nonce,uint256 expires,uint256 id,uint256 amount)"))`. bytes32 constant COMPACT_ACTIVATION_TYPEHASH = 0x2bf981c42c7f423b06fa49ba996d2930887e2f1f53d9a26b8c7423ac1cf83e61; -/// @dev `keccak256(bytes("PermitWitnessTransferFrom(TokenPermissions permitted,address spender,uint256 nonce,uint256 deadline,Activation witness)Activation(uint256 id,BatchCompact compact)BatchCompact(address arbiter,address sponsor,uint256 nonce,uint256 expires,uint256[2][] idsAndAmounts)TokenPermissions(address token,uint256 amount)"))`. -bytes32 constant PERMIT2_DEPOSIT_WITH_BATCH_COMPACT_ACTIVATION_TYPEHASH = 0x17513dd8a454440fed0be792cc9b0b440ce3fc8ee96c1b1b1a836d2846eb6756; - /// @dev `keccak256(bytes("Activation(uint256 id,BatchCompact compact)BatchCompact(address arbiter,address sponsor,uint256 nonce,uint256 expires,uint256[2][] idsAndAmounts)"))`. bytes32 constant BATCH_COMPACT_ACTIVATION_TYPEHASH = 0xd14445d78213a5acddfa89171b0199de521c3b36738b835264cae18f5a53dbf3; -/// @dev `keccak256(bytes("PermitWitnessTransferFrom(TokenPermissions permitted,address spender,uint256 nonce,uint256 deadline,Activation witness)Activation(uint256 id,MultichainCompact compact)MultichainCompact(address sponsor,uint256 nonce,uint256 expires,Segment[] segments)Segment(address arbiter,uint256 chainId,uint256[2][] idsAndAmounts)TokenPermissions(address token,uint256 amount)"))`. -bytes32 constant PERMIT2_DEPOSIT_WITH_MULTICHAIN_COMPACT_ACTIVATION_TYPEHASH = 0x6a707dd548c9a14542ee33ebe7c7bedffc0f1a3bc827c73459e910b3b7f7ebe1; - /// @dev `keccak256(bytes("Activation(uint256 id,MultichainCompact compact)MultichainCompact(address sponsor,uint256 nonce,uint256 expires,Segment[] segments)Segment(address arbiter,uint256 chainId,uint256[2][] idsAndAmounts)"))`. bytes32 constant MULTICHAIN_COMPACT_ACTIVATION_TYPEHASH = 0x329b3c527a3c74b8cabc51c304669d1866b87352cafdf440ef2becd6dc261d1e; -/// @dev `keccak256(bytes("PermitBatchWitnessTransferFrom(TokenPermissions[] permitted,address spender,uint256 nonce,uint256 deadline,BatchActivation witness)BatchActivation(uint256[] ids,Compact compact)Compact(address arbiter,address sponsor,uint256 nonce,uint256 expires,uint256 id,uint256 amount)TokenPermissions(address token,uint256 amount)"))`. -bytes32 constant PERMIT2_BATCH_DEPOSIT_WITH_COMPACT_ACTIVATION_TYPEHASH = 0xc57615aa5f4f1313fa11445825d867465f56dfccd036e04265bfe0dd050822fd; - /// @dev `keccak256(bytes("BatchActivation(uint256[] ids,Compact compact)Compact(address arbiter,address sponsor,uint256 nonce,uint256 expires,uint256 id,uint256 amount)"))`. bytes32 constant COMPACT_BATCH_ACTIVATION_TYPEHASH = 0x45012d42fad8c9e937cff5a2d750ee18713dd45aadcd718660d5523056618d99; -/// @dev `keccak256(bytes("PermitBatchWitnessTransferFrom(TokenPermissions[] permitted,address spender,uint256 nonce,uint256 deadline,BatchActivation witness)BatchActivation(uint256[] ids,BatchCompact compact)BatchCompact(address arbiter,address sponsor,uint256 nonce,uint256 expires,uint256[2][] idsAndAmounts)TokenPermissions(address token,uint256 amount)"))`. -bytes32 constant PERMIT2_BATCH_DEPOSIT_WITH_BATCH_COMPACT_ACTIVATION_TYPEHASH = 0x95e426a66b0811209294f67c0bf2ae0aab045490466d04cd6bf18cb70295c0ad; - /// @dev `keccak256(bytes("BatchActivation(uint256[] ids,BatchCompact compact)BatchCompact(address arbiter,address sponsor,uint256 nonce,uint256 expires,uint256[2][] idsAndAmounts)"))`. bytes32 constant BATCH_COMPACT_BATCH_ACTIVATION_TYPEHASH = 0xc2e16a823b8cdddfdf889991d7a461f0a19faf1f8e608f1c164495a52151cc3e; -/// @dev `keccak256(bytes("PermitBatchWitnessTransferFrom(TokenPermissions[] permitted,address spender,uint256 nonce,uint256 deadline,BatchActivation witness)BatchActivation(uint256[] ids,MultichainCompact compact)MultichainCompact(address sponsor,uint256 nonce,uint256 expires,Segment[] segments)Segment(address arbiter,uint256 chainId,uint256[2][] idsAndAmounts)"))`. -bytes32 constant PERMIT2_BATCH_DEPOSIT_WITH_MULTICHAIN_COMPACT_ACTIVATION_TYPEHASH = 0x142f91d42a44f5b5264d0eac9eddd2080a6c1649a31d76457dcc0ff612ff69d6; - /// @dev `keccak256(bytes("BatchActivation(uint256[] ids,MultichainCompact compact)MultichainCompact(address sponsor,uint256 nonce,uint256 expires,Segment[] segments)Segment(address arbiter,uint256 chainId,uint256[2][] idsAndAmounts)"))`. bytes32 constant MULTICHAIN_COMPACT_BATCH_ACTIVATION_TYPEHASH = 0xd2f6ad391328936f118250f231e63c7e639f9756a9ebf972d81763870a772d87; -// abi.decode(bytes("PermitWitnessTransferFrom(TokenP"), (bytes32)) -bytes32 constant PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE = 0x5065726d69745769746e6573735472616e7366657246726f6d28546f6b656e50; - -// abi.decode(bytes("ermissions permitted,address spe"), (bytes32)) -bytes32 constant PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO = 0x65726d697373696f6e73207065726d69747465642c6164647265737320737065; - -// abi.decode(bytes("nder,uint256 nonce,uint256 deadl"), (bytes32)) -bytes32 constant PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_THREE = 0x6e6465722c75696e74323536206e6f6e63652c75696e7432353620646561646c; - -// abi.decode(bytes("ine,Activation witness)Activatio"), (bytes32)) -bytes32 constant PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_FOUR = 0x696e652c41637469766174696f6e207769746e6573732941637469766174696f; - -// uint104(abi.decode(bytes("n(uint256 id,"), (bytes13))) -uint104 constant PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_FIVE = 0x6e2875696e743235362069642c; - -// abi.decode(bytes("PermitBatchWitnessTransferFrom(T"), (bytes32)) -bytes32 constant PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE = 0x5065726d697442617463685769746e6573735472616e7366657246726f6d2854; - -// abi.decode(bytes("okenPermissions[] permitted,addr"), (bytes32)) -bytes32 constant PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO = 0x6f6b656e5065726d697373696f6e735b5d207065726d69747465642c61646472; - -// abi.decode(bytes("ess spender,uint256 nonce,uint25"), (bytes32)) -bytes32 constant PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_THREE = 0x657373207370656e6465722c75696e74323536206e6f6e63652c75696e743235; +// abi.decode(bytes("Activation witness)Activation(ui"), (bytes32)) +bytes32 constant PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE = 0x41637469766174696f6e207769746e6573732941637469766174696f6e287569; -// abi.decode(bytes("6 deadline,BatchActivation witne"), (bytes32)) -bytes32 constant PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_FOUR = 0x3620646561646c696e652c426174636841637469766174696f6e207769746e65; +// uint72(abi.decode(bytes("nt256 id,"), (bytes9))) +uint72 constant PERMIT2_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO = 0x6e743235362069642c; -// abi.decode(bytes("ss)BatchActivation(uint256[] ids"), (bytes32)) -bytes32 constant PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_FIVE = 0x737329426174636841637469766174696f6e2875696e743235365b5d20696473; +// abi.decode(bytes("BatchActivation witness)BatchAct"), (bytes32)) +bytes32 constant PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_ONE = 0x426174636841637469766174696f6e207769746e657373294261746368416374; -// uint8(abi.decode(bytes(","), (bytes1))) -uint8 constant PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_SIX = 0x2c; +// uint176(abi.decode(bytes("ivation(uint256[] ids,"), (bytes22))) +uint176 constant PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_TWO = 0x69766174696f6e2875696e743235365b5d206964732c; // abi.decode(bytes("Compact compact)Compact(address "), (bytes32)) bytes32 constant PERMIT2_ACTIVATION_COMPACT_TYPESTRING_FRAGMENT_ONE = 0x436f6d7061637420636f6d7061637429436f6d70616374286164647265737320; diff --git a/test/TheCompact.t.sol b/test/TheCompact.t.sol index 4d266dd..8dc9186 100644 --- a/test/TheCompact.t.sol +++ b/test/TheCompact.t.sol @@ -341,6 +341,7 @@ contract TheCompactTest is Test { assert(bytes(theCompact.tokenURI(id)).length > 0); } + /* TODO: add this test back once there's room for batch permit2 deposits again function test_depositBatchViaPermit2SingleERC20() public { address recipient = 0x1111111111111111111111111111111111111111; ResetPeriod resetPeriod = ResetPeriod.TenMinutes; @@ -397,6 +398,7 @@ contract TheCompactTest is Test { assertEq(theCompact.balanceOf(recipient, ids[0]), amount); assert(bytes(theCompact.tokenURI(ids[0])).length > 0); } + */ function test_basicTransfer() public { ResetPeriod resetPeriod = ResetPeriod.TenMinutes;