diff --git a/src/TheCompact.sol b/src/TheCompact.sol index 344f358..000d274 100644 --- a/src/TheCompact.sol +++ b/src/TheCompact.sol @@ -2,6 +2,8 @@ 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"; @@ -154,11 +156,13 @@ 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; using IdLib for Lock; using IdLib for ResetPeriod; + using IdLib for CompactCategory; using SafeTransferLib for address; using FixedPointMathLib for uint256; using ConsumerLib for uint256; @@ -379,6 +383,179 @@ contract TheCompact is ITheCompact, ERC6909, Tstorish { _clearTstorish(_REENTRANCY_GUARD_SLOT); } + function depositAndRegister( + uint256 id, + uint256 amount, + uint256 nonce, + uint256 deadline, + address depositor, + bytes32 claimHash, + CompactCategory compactCategory, + string calldata witness, + bytes calldata signature + ) external returns (bool) { + _setTstorish(_REENTRANCY_GUARD_SLOT, 1); + id.toAllocatorId().mustHaveARegisteredAllocator(); + address token = id.toToken().excludingNative(); + + 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); + } + + string memory witnessTypestring = string.concat("Activation witness)", activationTypestring, "TokenPermissions(address token,uint256 amount)"); + + bytes32 witnessHash = keccak256(abi.encodePacked(keccak256(bytes(activationTypestring)), id, claimHash)); + + ISignatureTransfer.SignatureTransferDetails memory details = ISignatureTransfer.SignatureTransferDetails({ to: address(this), requestedAmount: amount }); + + ISignatureTransfer.PermitTransferFrom memory permitTransferFrom = + ISignatureTransfer.PermitTransferFrom({ permitted: ISignatureTransfer.TokenPermissions({ token: token, amount: amount }), nonce: nonce, deadline: deadline }); + + _PERMIT2.permitWitnessTransferFrom(permitTransferFrom, details, depositor, witnessHash, witnessTypestring, signature); + + uint256 tokenBalance = token.balanceOf(address(this)); + + assembly ("memory-safe") { + if iszero(lt(initialBalance, tokenBalance)) { + // revert InvalidDepositBalanceChange() + mstore(0, 0x426d8dcf) + revert(0x1c, 0x04) + } + } + + unchecked { + _deposit(depositor, id, tokenBalance - initialBalance); + } + + _registeredClaimHashes[depositor][claimHash] = keccak256(bytes(compactTypestring)); + + _clearTstorish(_REENTRANCY_GUARD_SLOT); + + return true; + } + + function depositAndRegister( + 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) { + _setTstorish(_REENTRANCY_GUARD_SLOT, 1); + + 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); + + 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("BatchActivation(uint256[] ids,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("BatchActivation(uint256[] ids,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("BatchActivation(uint256[] ids,MultichainCompact compact)", compactTypestring); + } + + ids = new uint256[](totalTokens); + + uint256 totalTokensLessInitialNative; + unchecked { + totalTokensLessInitialNative = totalTokens - firstUnderlyingTokenIsNative.asUint256(); + } + + if (firstUnderlyingTokenIsNative) { + _deposit(recipient, initialId, msg.value); + ids[0] = initialId; + } + + (ISignatureTransfer.SignatureTransferDetails[] memory details, ISignatureTransfer.TokenPermissions[] memory permittedTokens, uint256[] memory initialTokenBalances) = + _preparePermit2ArraysAndGetBalances(ids, totalTokensLessInitialNative, firstUnderlyingTokenIsNative, permitted, initialId); + + ISignatureTransfer.PermitBatchTransferFrom memory permitTransferFrom = ISignatureTransfer.PermitBatchTransferFrom({ permitted: permittedTokens, nonce: nonce, deadline: deadline }); + + string memory witnessTypestring = string.concat("BatchActivation witness)", activationTypestring, "TokenPermissions(address token,uint256 amount)"); + + bytes32 witnessHash = keccak256(abi.encodePacked(keccak256(bytes(activationTypestring)), keccak256(abi.encodePacked(ids)), claimHash)); + + _PERMIT2.permitWitnessTransferFrom(permitTransferFrom, details, depositor, witnessHash, witnessTypestring, signature); + + uint256 tokenBalance; + uint256 initialBalance; + uint256 errorBuffer; + unchecked { + for (uint256 i = 0; i < totalTokensLessInitialNative; ++i) { + tokenBalance = permittedTokens[i].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) + } + } + + _registeredClaimHashes[depositor][claimHash] = keccak256(bytes(compactTypestring)); + + _clearTstorish(_REENTRANCY_GUARD_SLOT); + } + function deposit( address depositor, ISignatureTransfer.TokenPermissions[] calldata permitted, @@ -412,7 +589,17 @@ contract TheCompact is ITheCompact, ERC6909, Tstorish { uint256 initialId = address(0).toIdIfRegistered(scope, resetPeriod, allocator); return _processBatchPermit2Deposits( - firstUnderlyingTokenIsNative, recipient, initialId, totalTokens, permitted, depositor, nonce, deadline, allocator.toPermit2DepositWitnessHash(resetPeriod, scope, recipient), signature + 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 ); } @@ -1768,6 +1955,7 @@ contract TheCompact is ITheCompact, ERC6909, Tstorish { uint256 nonce, uint256 deadline, bytes32 witness, + string memory witnessTypestring, bytes calldata signature ) internal returns (uint256[] memory ids) { _setTstorish(_REENTRANCY_GUARD_SLOT, 1); @@ -1789,14 +1977,7 @@ contract TheCompact is ITheCompact, ERC6909, Tstorish { ISignatureTransfer.PermitBatchTransferFrom memory permitTransferFrom = ISignatureTransfer.PermitBatchTransferFrom({ permitted: permittedTokens, nonce: nonce, deadline: deadline }); - _PERMIT2.permitWitnessTransferFrom( - permitTransferFrom, - details, - depositor, - witness, - "CompactDeposit witness)CompactDeposit(address allocator,uint8 resetPeriod,uint8 scope,address recipient)TokenPermissions(address token,uint256 amount)", - signature - ); + _PERMIT2.permitWitnessTransferFrom(permitTransferFrom, details, depositor, witness, witnessTypestring, signature); uint256 tokenBalance; uint256 initialBalance; diff --git a/src/lib/HashLib.sol b/src/lib/HashLib.sol index e093f96..dde3746 100644 --- a/src/lib/HashLib.sol +++ b/src/lib/HashLib.sol @@ -53,7 +53,15 @@ import { 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 + PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_SIX, + 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, + TOKEN_PERMISSIONS_TYPSTRING_FRAGMENT_ONE, + TOKEN_PERMISSIONS_TYPSTRING_FRAGMENT_TWO } from "../types/EIP712Types.sol"; import { @@ -922,13 +930,20 @@ library HashLib { } } - function toPermit2ActivatedCompactTypehash(ActivatedCompactCategory category, string calldata witness) internal pure returns (bytes32 typehash) { + function toPermit2DepositAndRegisterTypehashes(ActivatedCompactCategory category, string calldata compactWitnessTypestringFragment) + internal + pure + returns (bytes32 permit2Typehash, bytes32 activationTypehash, bytes32 compactTypehash) + { assembly ("memory-safe") { - function toTypehash(c, witnessOffset, witnessLength) -> t { + 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 @@ -937,7 +952,18 @@ library HashLib { 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) - t := mload(shl(5, c)) + 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 } @@ -948,6 +974,7 @@ library HashLib { 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) { @@ -955,7 +982,18 @@ library HashLib { 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) - t := mload(shl(5, c)) + 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 } @@ -967,6 +1005,7 @@ library HashLib { 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 @@ -997,14 +1036,26 @@ library HashLib { fragmentThreeStart := add(fragmentTwoStart, 0xb0) } - // 3. insert the supplied witness (must also include TokenPermissions) + // 3. insert the supplied compact witness calldatacopy(fragmentThreeStart, witnessOffset, witnessLength) - // 4. derive the typehash - t := keccak256(m, add(sub(fragmentThreeStart, m), 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)) } - typehash := toTypehash(category, witness.offset, witness.length) + permit2Typehash, activationTypehash, compactTypehash := toTypehash(category, compactWitnessTypestringFragment.offset, compactWitnessTypestringFragment.length) } } } diff --git a/src/lib/IdLib.sol b/src/lib/IdLib.sol index a4dff4f..016f4e4 100644 --- a/src/lib/IdLib.sol +++ b/src/lib/IdLib.sol @@ -7,6 +7,8 @@ import { Lock } from "../types/Lock.sol"; import { MetadataLib } from "./MetadataLib.sol"; import { EfficiencyLib } from "./EfficiencyLib.sol"; import { SignatureCheckerLib } from "solady/utils/SignatureCheckerLib.sol"; +import { CompactCategory } from "../types/CompactCategory.sol"; +import { ActivatedCompactCategory } from "../types/ActivatedCompactCategory.sol"; library IdLib { using IdLib for uint96; @@ -192,6 +194,12 @@ 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/CompactCategory.sol b/src/types/CompactCategory.sol new file mode 100644 index 0000000..f345f5e --- /dev/null +++ b/src/types/CompactCategory.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +enum CompactCategory { + Compact, + BatchCompact, + MultichainCompact +} diff --git a/src/types/EIP712Types.sol b/src/types/EIP712Types.sol index 346ca34..df3974b 100644 --- a/src/types/EIP712Types.sol +++ b/src/types/EIP712Types.sol @@ -124,21 +124,39 @@ bytes32 constant PERMIT2_DEPOSIT_WITNESS_FRAGMENT_HASH = 0xe055493563385cc588fff /// @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("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)TokenPermissions(address token,uint256 amount)"))`. +/// @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; @@ -169,7 +187,7 @@ bytes32 constant PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_FOUR // abi.decode(bytes("ss)BatchActivation(uint256[] ids"), (bytes32)) bytes32 constant PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_FIVE = 0x737329426174636841637469766174696f6e2875696e743235365b5d20696473; -// uint8(abi.decode(bytes("n(uint256 id,"), (bytes1))) +// uint8(abi.decode(bytes(","), (bytes1))) uint8 constant PERMIT2_BATCH_DEPOSIT_WITH_ACTIVATION_TYPESTRING_FRAGMENT_SIX = 0x2c; // abi.decode(bytes("Compact compact)Compact(address "), (bytes32)) @@ -213,3 +231,9 @@ bytes32 constant PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_FIVE // uint128(abi.decode(bytes("] idsAndAmounts,"), (bytes16))) uint128 constant PERMIT2_ACTIVATION_MULTICHAIN_COMPACT_TYPESTRING_FRAGMENT_SIX = 0x5d20696473416e64416d6f756e74732c; + +// abi.decode(bytes("TokenPermissions(address token,u"), (bytes32)) +bytes32 constant TOKEN_PERMISSIONS_TYPSTRING_FRAGMENT_ONE = 0x546f6b656e5065726d697373696f6e73286164647265737320746f6b656e2c75; + +// uint112(abi.decode(bytes("int256 amount)"), (bytes14))) +uint112 constant TOKEN_PERMISSIONS_TYPSTRING_FRAGMENT_TWO = 0x696e7432353620616d6f756e7429;