From 6fb7a27fe190b4a542539310ec70ca55fa052196 Mon Sep 17 00:00:00 2001 From: 0age <37939117+0age@users.noreply.github.com> Date: Sat, 19 Oct 2024 15:39:20 -0700 Subject: [PATCH] finish all the split claim types --- src/TheCompact.sol | 66 +++++++++ src/lib/HashLib.sol | 183 ++++++++++++++++++++++++- test/TheCompact.t.sol | 304 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 552 insertions(+), 1 deletion(-) diff --git a/src/TheCompact.sol b/src/TheCompact.sol index 138bd96..a4d1767 100644 --- a/src/TheCompact.sol +++ b/src/TheCompact.sol @@ -627,6 +627,38 @@ contract TheCompact is ITheCompact, ERC6909, Extsload { return _processExogenousQualifiedSplitMultichainClaim(claimPayload, _withdraw); } + function claim(SplitMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processSplitMultichainClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(SplitMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processSplitMultichainClaimWithWitness(claimPayload, _withdraw); + } + + function claim(ExogenousSplitMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processExogenousSplitMultichainClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(ExogenousSplitMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processExogenousSplitMultichainClaimWithWitness(claimPayload, _withdraw); + } + + function claim(QualifiedSplitMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processQualifiedSplitMultichainClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(QualifiedSplitMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processQualifiedSplitMultichainClaimWithWitness(claimPayload, _withdraw); + } + + function claim(ExogenousQualifiedSplitMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processExogenousQualifiedSplitMultichainClaimWithWitness(claimPayload, _release); + } + + function claimAndWithdraw(ExogenousQualifiedSplitMultichainClaimWithWitness calldata claimPayload) external returns (bool) { + return _processExogenousQualifiedSplitMultichainClaimWithWitness(claimPayload, _withdraw); + } + function claim(BatchMultichainClaim calldata claimPayload) external returns (bool) { return _processBatchMultichainClaim(claimPayload, _release); } @@ -1243,6 +1275,21 @@ contract TheCompact is ITheCompact, ERC6909, Extsload { return _processSplitClaimWithQualification.usingQualifiedSplitMultichainClaim()(messageHash, qualificationMessageHash, claimPayload, 0x100, operation); } + function _processSplitMultichainClaimWithWitness(SplitMultichainClaimWithWitness calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) + internal + returns (bool) + { + return _processSimpleSplitClaim.usingSplitMultichainClaimWithWitness()(claimPayload.toMessageHash(), claimPayload, 0x100, operation); + } + + function _processQualifiedSplitMultichainClaimWithWitness( + QualifiedSplitMultichainClaimWithWitness calldata claimPayload, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHash(); + return _processSplitClaimWithQualification.usingQualifiedSplitMultichainClaimWithWitness()(messageHash, qualificationMessageHash, claimPayload, 0x140, 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, operation); } @@ -1306,6 +1353,25 @@ contract TheCompact is ITheCompact, ERC6909, Extsload { ); } + function _processExogenousSplitMultichainClaimWithWitness( + ExogenousSplitMultichainClaimWithWitness calldata claimPayload, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + return _processSplitClaimWithSponsorDomain.usingExogenousSplitMultichainClaimWithWitness()( + claimPayload.toMessageHash(), claimPayload, 0x140, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), operation + ); + } + + function _processExogenousQualifiedSplitMultichainClaimWithWitness( + ExogenousQualifiedSplitMultichainClaimWithWitness calldata claimPayload, + function(address, address, uint256, uint256) internal returns (bool) operation + ) internal returns (bool) { + (bytes32 messageHash, bytes32 qualificationMessageHash) = claimPayload.toMessageHash(); + return _processSplitClaimWithQualificationAndSponsorDomain.usingExogenousQualifiedSplitMultichainClaimWithWitness()( + messageHash, qualificationMessageHash, claimPayload, 0x180, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), operation + ); + } + function _processExogenousBatchMultichainClaim(ExogenousBatchMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) diff --git a/src/lib/HashLib.sol b/src/lib/HashLib.sol index 25d0c23..fbd59f1 100644 --- a/src/lib/HashLib.sol +++ b/src/lib/HashLib.sol @@ -591,6 +591,16 @@ library HashLib { } } + function usingQualifiedSplitMultichainClaimWithWitness(function (MultichainClaim calldata, uint256, bytes32, bytes32, bytes32) internal view returns (bytes32) fnIn) + internal + pure + returns (function (QualifiedSplitMultichainClaimWithWitness calldata, uint256, bytes32, bytes32, bytes32) internal view returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + function usingQualifiedMultichainClaimWithWitness(function (MultichainClaim calldata, uint256) internal pure returns (bytes32) fnIn) internal pure @@ -601,6 +611,16 @@ library HashLib { } } + function usingQualifiedSplitMultichainClaimWithWitness(function (MultichainClaim calldata, uint256) internal pure returns (bytes32) fnIn) + internal + pure + returns (function (QualifiedSplitMultichainClaimWithWitness calldata, uint256) internal pure returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + function usingQualifiedSplitMultichainClaim(function (MultichainClaim calldata, uint256) internal pure returns (bytes32) fnIn) internal pure @@ -631,6 +651,16 @@ library HashLib { } } + function usingExogenousQualifiedSplitMultichainClaimWithWitness(function (MultichainClaim calldata, uint256) internal pure returns (bytes32) fnIn) + internal + pure + returns (function (ExogenousQualifiedSplitMultichainClaimWithWitness calldata, uint256) internal pure returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + function usingQualifiedMultichainClaimWithWitness(function (QualifiedClaim calldata, bytes32, uint256) internal pure returns (bytes32) fnIn) internal pure @@ -641,6 +671,16 @@ library HashLib { } } + function usingQualifiedSplitMultichainClaimWithWitness(function (QualifiedClaim calldata, bytes32, uint256) internal pure returns (bytes32) fnIn) + internal + pure + returns (function (QualifiedSplitMultichainClaimWithWitness calldata, bytes32, uint256) internal pure returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + function usingQualifiedSplitBatchMultichainClaimWithWitness(function (QualifiedClaim calldata, bytes32, uint256) internal pure returns (bytes32) fnIn) internal pure @@ -785,6 +825,16 @@ library HashLib { } } + function usingExogenousSplitMultichainClaimWithWitness(function (ExogenousMultichainClaim calldata, uint256, bytes32, bytes32, bytes32) internal view returns (bytes32) fnIn) + internal + pure + returns (function (ExogenousSplitMultichainClaimWithWitness calldata, uint256, bytes32, bytes32, bytes32) internal view returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + function usingExogenousQualifiedMultichainClaimWithWitness(function (ExogenousMultichainClaim calldata, uint256, bytes32, bytes32, bytes32) internal view returns (bytes32) fnIn) internal pure @@ -795,6 +845,16 @@ library HashLib { } } + function usingExogenousQualifiedSplitMultichainClaimWithWitness(function (ExogenousMultichainClaim calldata, uint256, bytes32, bytes32, bytes32) internal view returns (bytes32) fnIn) + internal + pure + returns (function (ExogenousQualifiedSplitMultichainClaimWithWitness calldata, uint256, bytes32, bytes32, bytes32) internal view returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + function usingExogenousSplitMultichainClaim(function (ExogenousMultichainClaim calldata, uint256, bytes32, bytes32, bytes32) internal view returns (bytes32) fnIn) internal pure @@ -845,6 +905,16 @@ library HashLib { } } + function usingExogenousSplitMultichainClaimWithWitness(function (QualifiedClaim calldata, bytes32, uint256) internal pure returns (bytes32) fnIn) + internal + pure + returns (function (ExogenousSplitMultichainClaimWithWitness calldata, bytes32, uint256) internal pure returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + function usingMultichainClaimWithWitness(function (MultichainClaim calldata, uint256, bytes32, bytes32, bytes32) internal view returns (bytes32) fnIn) internal pure @@ -855,6 +925,16 @@ library HashLib { } } + function usingSplitMultichainClaimWithWitness(function (MultichainClaim calldata, uint256, bytes32, bytes32, bytes32) internal view returns (bytes32) fnIn) + internal + pure + returns (function (SplitMultichainClaimWithWitness calldata, uint256, bytes32, bytes32, bytes32) internal view returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + function usingMultichainClaimWithWitness(function (MultichainClaim calldata, uint256) internal pure returns (bytes32) fnIn) internal pure @@ -865,6 +945,26 @@ library HashLib { } } + function usingSplitMultichainClaimWithWitness(function (MultichainClaim calldata, uint256) internal pure returns (bytes32) fnIn) + internal + pure + returns (function (SplitMultichainClaimWithWitness calldata, uint256) internal pure returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + + function usingSplitMultichainClaimWithWitness(function (MultichainClaimWithWitness calldata) internal pure returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (SplitMultichainClaimWithWitness calldata) internal pure returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + function usingExogenousMultichainClaimWithWitness(function (MultichainClaim calldata, uint256) internal pure returns (bytes32) fnIn) internal pure @@ -875,6 +975,16 @@ library HashLib { } } + function usingExogenousSplitMultichainClaimWithWitness(function (MultichainClaim calldata, uint256) internal pure returns (bytes32) fnIn) + internal + pure + returns (function (ExogenousSplitMultichainClaimWithWitness calldata, uint256) internal pure returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + function usingExogenousMultichainClaim(function (MultichainClaim calldata, uint256) internal pure returns (bytes32) fnIn) internal pure @@ -892,6 +1002,13 @@ library HashLib { ); } + function toMessageHash(SplitMultichainClaimWithWitness calldata claim) internal view returns (bytes32 messageHash) { + (bytes32 allocationTypehash, bytes32 multichainCompactTypehash) = usingSplitMultichainClaimWithWitness(getMultichainTypehashes)(claim); + messageHash = usingSplitMultichainClaimWithWitness(toMultichainClaimMessageHash)( + claim, 0x40, allocationTypehash, multichainCompactTypehash, usingSplitMultichainClaimWithWitness(deriveIdsAndAmountsHash)(claim, 0x40) + ); + } + function toMessageHash(ExogenousMultichainClaimWithWitness calldata claim) internal view returns (bytes32 messageHash) { (bytes32 allocationTypehash, bytes32 multichainCompactTypehash) = usingExogenousMultichainClaimWithWitness(getMultichainTypehashes)(claim); messageHash = usingExogenousMultichainClaimWithWitness(toExogenousMultichainClaimMessageHash)( @@ -899,6 +1016,13 @@ library HashLib { ); } + function toMessageHash(ExogenousSplitMultichainClaimWithWitness calldata claim) internal view returns (bytes32 messageHash) { + (bytes32 allocationTypehash, bytes32 multichainCompactTypehash) = usingExogenousSplitMultichainClaimWithWitness(getMultichainTypehashes)(claim); + messageHash = usingExogenousSplitMultichainClaimWithWitness(toExogenousMultichainClaimMessageHash)( + claim, 0x40, allocationTypehash, multichainCompactTypehash, usingExogenousSplitMultichainClaimWithWitness(deriveIdsAndAmountsHash)(claim, 0x80) + ); + } + function toMessageHash(QualifiedMultichainClaimWithWitness calldata claim) internal view returns (bytes32 messageHash, bytes32 qualificationMessageHash) { (bytes32 allocationTypehash, bytes32 multichainCompactTypehash) = usingQualifiedMultichainClaimWithWitness(getMultichainTypehashes)(claim); @@ -908,6 +1032,15 @@ library HashLib { qualificationMessageHash = usingQualifiedMultichainClaimWithWitness(toQualificationMessageHash)(claim, messageHash, 0x40); } + function toMessageHash(QualifiedSplitMultichainClaimWithWitness calldata claim) internal view returns (bytes32 messageHash, bytes32 qualificationMessageHash) { + (bytes32 allocationTypehash, bytes32 multichainCompactTypehash) = usingQualifiedSplitMultichainClaimWithWitness(getMultichainTypehashes)(claim); + + messageHash = usingQualifiedSplitMultichainClaimWithWitness(toMultichainClaimMessageHash)( + claim, 0x80, allocationTypehash, multichainCompactTypehash, usingQualifiedSplitMultichainClaimWithWitness(deriveIdsAndAmountsHash)(claim, 0x80) + ); + qualificationMessageHash = usingQualifiedSplitMultichainClaimWithWitness(toQualificationMessageHash)(claim, messageHash, 0x40); + } + function toMessageHash(QualifiedSplitMultichainClaim calldata claim) internal view returns (bytes32 messageHash, bytes32 qualificationMessageHash) { messageHash = usingQualifiedSplitMultichainClaim(toMultichainClaimMessageHash)( claim, 0x40, ALLOCATION_TYPEHASH, MULTICHAIN_COMPACT_TYPEHASH, usingQualifiedSplitMultichainClaim(deriveIdsAndAmountsHash)(claim, 0x40) @@ -962,6 +1095,16 @@ library HashLib { } } + function usingExogenousQualifiedSplitMultichainClaimWithWitness(function(QualifiedClaim calldata, bytes32, uint256) internal pure returns (bytes32) fnIn) + internal + pure + returns (function(ExogenousQualifiedSplitMultichainClaimWithWitness calldata, bytes32, uint256) internal pure returns (bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + function usingExogenousMultichainClaimWithWitness(function (MultichainClaimWithWitness calldata) internal pure returns (bytes32, bytes32) fnIn) internal pure @@ -972,6 +1115,16 @@ library HashLib { } } + function usingExogenousSplitMultichainClaimWithWitness(function (MultichainClaimWithWitness calldata) internal pure returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (ExogenousSplitMultichainClaimWithWitness calldata) internal pure returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + function usingExogenousQualifiedMultichainClaimWithWitness(function (MultichainClaimWithWitness calldata) internal pure returns (bytes32, bytes32) fnIn) internal pure @@ -982,6 +1135,16 @@ library HashLib { } } + function usingExogenousQualifiedSplitMultichainClaimWithWitness(function (MultichainClaimWithWitness calldata) internal pure returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (ExogenousQualifiedSplitMultichainClaimWithWitness calldata) internal pure returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + function usingQualifiedMultichainClaimWithWitness(function (MultichainClaimWithWitness calldata) internal pure returns (bytes32, bytes32) fnIn) internal pure @@ -992,6 +1155,16 @@ library HashLib { } } + function usingQualifiedSplitMultichainClaimWithWitness(function (MultichainClaimWithWitness calldata) internal pure returns (bytes32, bytes32) fnIn) + internal + pure + returns (function (QualifiedSplitMultichainClaimWithWitness calldata) internal pure returns (bytes32, bytes32) fnOut) + { + assembly ("memory-safe") { + fnOut := fnIn + } + } + function usingQualifiedSplitBatchMultichainClaimWithWitness(function (MultichainClaimWithWitness calldata) internal pure returns (bytes32, bytes32) fnIn) internal pure @@ -1118,13 +1291,21 @@ library HashLib { } function toMessageHash(ExogenousQualifiedSplitMultichainClaim calldata claim) internal view returns (bytes32 messageHash, bytes32 qualificationMessageHash) { - bytes32 idsAndAmountsHash = usingExogenousQualifiedSplitMultichainClaim(deriveIdsAndAmountsHash)(claim, 0x80); messageHash = usingExogenousQualifiedSplitMultichainClaim(toExogenousMultichainClaimMessageHash)( claim, 0x40, ALLOCATION_TYPEHASH, MULTICHAIN_COMPACT_TYPEHASH, usingExogenousQualifiedSplitMultichainClaim(deriveIdsAndAmountsHash)(claim, 0x80) ); qualificationMessageHash = usingExogenousQualifiedSplitMultichainClaim(toQualificationMessageHash)(claim, messageHash, 0); } + function toMessageHash(ExogenousQualifiedSplitMultichainClaimWithWitness calldata claim) internal view returns (bytes32 messageHash, bytes32 qualificationMessageHash) { + (bytes32 allocationTypehash, bytes32 multichainCompactTypehash) = usingExogenousQualifiedSplitMultichainClaimWithWitness(getMultichainTypehashes)(claim); + + messageHash = usingExogenousQualifiedSplitMultichainClaimWithWitness(toExogenousMultichainClaimMessageHash)( + claim, 0x80, allocationTypehash, multichainCompactTypehash, usingExogenousQualifiedSplitMultichainClaimWithWitness(deriveIdsAndAmountsHash)(claim, 0xc0) + ); + qualificationMessageHash = usingExogenousQualifiedSplitMultichainClaimWithWitness(toQualificationMessageHash)(claim, messageHash, 0x40); + } + function toMessageHash(ExogenousQualifiedSplitBatchMultichainClaimWithWitness calldata claim) internal view returns (bytes32 messageHash, bytes32 qualificationMessageHash) { (bytes32 allocationTypehash, bytes32 multichainCompactTypehash) = usingExogenousQualifiedSplitBatchMultichainClaimWithWitness(getMultichainTypehashes)(claim); diff --git a/test/TheCompact.t.sol b/test/TheCompact.t.sol index cea1175..01b14d8 100644 --- a/test/TheCompact.t.sol +++ b/test/TheCompact.t.sol @@ -2799,6 +2799,310 @@ contract TheCompactTest is Test { assertEq(block.chainid, notarizedChainId); } + function test_splitMultichainClaimWithWitness() public { + ResetPeriod resetPeriod = ResetPeriod.TenMinutes; + Scope scope = Scope.Multichain; + uint256 amount = 1e18; + uint256 anotherAmount = 1e18; + uint256 nonce = 0; + uint256 expires = block.timestamp + 1000; + address arbiter = 0x2222222222222222222222222222222222222222; + uint256 anotherChainId = 7171717; + + address recipientOne = 0x1111111111111111111111111111111111111111; + address recipientTwo = 0x3333333333333333333333333333333333333333; + uint256 amountOne = 4e17; + uint256 amountTwo = 6e17; + + vm.prank(allocator); + theCompact.__register(allocator, ""); + + vm.startPrank(swapper); + uint256 id = theCompact.deposit{ value: amount }(allocator, resetPeriod, scope, swapper); + uint256 anotherId = theCompact.deposit(address(token), allocator, ResetPeriod.TenMinutes, Scope.Multichain, anotherAmount, swapper); + vm.stopPrank(); + + assertEq(theCompact.balanceOf(swapper, id), amount); + assertEq(theCompact.balanceOf(swapper, anotherId), anotherAmount); + + uint256[2][] memory idsAndAmountsOne = new uint256[2][](1); + idsAndAmountsOne[0] = [id, amount]; + + uint256[2][] memory idsAndAmountsTwo = new uint256[2][](1); + idsAndAmountsTwo[0] = [anotherId, anotherAmount]; + + string memory witnessTypestring = "Witness witness)Witness(uint256 witnessArgument)"; + uint256 witnessArgument = 234; + bytes32 witness = keccak256(abi.encode(witnessArgument)); + + bytes32 allocationHashOne = keccak256( + abi.encode( + keccak256("Allocation(address arbiter,uint256 chainId,uint256[2][] idsAndAmounts,Witness witness)Witness(uint256 witnessArgument)"), + arbiter, + block.chainid, + keccak256(abi.encodePacked(idsAndAmountsOne)), + witness + ) + ); + + bytes32 allocationHashTwo = keccak256( + abi.encode( + keccak256("Allocation(address arbiter,uint256 chainId,uint256[2][] idsAndAmounts,Witness witness)Witness(uint256 witnessArgument)"), + arbiter, + anotherChainId, + keccak256(abi.encodePacked(idsAndAmountsTwo)), + witness + ) + ); + + bytes32 claimHash = keccak256( + abi.encode( + keccak256( + "MultichainCompact(address sponsor,uint256 nonce,uint256 expires,Allocation[] allocations)Allocation(address arbiter,uint256 chainId,uint256[2][] idsAndAmounts,Witness witness)Witness(uint256 witnessArgument)" + ), + swapper, + nonce, + expires, + keccak256(abi.encodePacked(allocationHashOne, allocationHashTwo)) + ) + ); + + bytes32 initialDomainSeparator = theCompact.DOMAIN_SEPARATOR(); + + bytes32 digest = keccak256(abi.encodePacked(bytes2(0x1901), initialDomainSeparator, claimHash)); + + (bytes32 r, bytes32 vs) = vm.signCompact(swapperPrivateKey, digest); + bytes memory sponsorSignature = abi.encodePacked(r, vs); + + (r, vs) = vm.signCompact(allocatorPrivateKey, digest); + bytes memory allocatorSignature = abi.encodePacked(r, vs); + + bytes32[] memory additionalChains = new bytes32[](1); + additionalChains[0] = allocationHashTwo; + + SplitComponent memory splitOne = SplitComponent({ claimant: recipientOne, amount: amountOne }); + + SplitComponent memory splitTwo = SplitComponent({ claimant: recipientTwo, amount: amountTwo }); + + SplitComponent[] memory recipients = new SplitComponent[](2); + recipients[0] = splitOne; + recipients[1] = splitTwo; + + SplitMultichainClaimWithWitness memory claim = + SplitMultichainClaimWithWitness(allocatorSignature, sponsorSignature, swapper, nonce, expires, witness, witnessTypestring, additionalChains, id, amount, recipients); + + uint256 snapshotId = vm.snapshot(); + vm.prank(arbiter); + (bool status) = theCompact.claim(claim); + assert(status); + + assertEq(address(theCompact).balance, amount); + assertEq(recipientOne.balance, 0); + assertEq(recipientTwo.balance, 0); + assertEq(theCompact.balanceOf(recipientOne, id), amountOne); + assertEq(theCompact.balanceOf(recipientTwo, id), amountTwo); + vm.revertToAndDelete(snapshotId); + + // change to "new chain" (this hack is so the original one gets stored) + uint256 notarizedChainId = abi.decode(abi.encode(block.chainid), (uint256)); + assert(notarizedChainId != anotherChainId); + vm.chainId(anotherChainId); + assertEq(block.chainid, anotherChainId); + assert(notarizedChainId != anotherChainId); + + bytes32 anotherDomainSeparator = theCompact.DOMAIN_SEPARATOR(); + + assert(initialDomainSeparator != anotherDomainSeparator); + + digest = keccak256(abi.encodePacked(bytes2(0x1901), anotherDomainSeparator, claimHash)); + + (r, vs) = vm.signCompact(allocatorPrivateKey, digest); + bytes memory exogenousAllocatorSignature = abi.encodePacked(r, vs); + + additionalChains[0] = allocationHashOne; + uint256 chainIndex = 0; + + ExogenousSplitMultichainClaimWithWitness memory anotherClaim = ExogenousSplitMultichainClaimWithWitness( + exogenousAllocatorSignature, sponsorSignature, swapper, nonce, expires, witness, witnessTypestring, additionalChains, chainIndex, notarizedChainId, anotherId, anotherAmount, recipients + ); + + vm.prank(arbiter); + (bool exogenousStatus) = theCompact.claim(anotherClaim); + assert(exogenousStatus); + + assertEq(theCompact.balanceOf(swapper, anotherId), 0); + assertEq(theCompact.balanceOf(recipientOne, anotherId), amountOne); + assertEq(theCompact.balanceOf(recipientTwo, anotherId), amountTwo); + + // change back + vm.chainId(notarizedChainId); + assertEq(block.chainid, notarizedChainId); + } + + function test_qualifiedSplitMultichainClaimWithWitness() public { + ResetPeriod resetPeriod = ResetPeriod.TenMinutes; + Scope scope = Scope.Multichain; + uint256 amount = 1e18; + uint256 anotherAmount = 1e18; + uint256 nonce = 0; + uint256 expires = block.timestamp + 1000; + address arbiter = 0x2222222222222222222222222222222222222222; + uint256 anotherChainId = 7171717; + + address recipientOne = 0x1111111111111111111111111111111111111111; + address recipientTwo = 0x3333333333333333333333333333333333333333; + uint256 amountOne = 4e17; + uint256 amountTwo = 6e17; + + vm.prank(allocator); + theCompact.__register(allocator, ""); + + vm.startPrank(swapper); + uint256 id = theCompact.deposit{ value: amount }(allocator, resetPeriod, scope, swapper); + uint256 anotherId = theCompact.deposit(address(token), allocator, ResetPeriod.TenMinutes, Scope.Multichain, anotherAmount, swapper); + vm.stopPrank(); + + assertEq(theCompact.balanceOf(swapper, id), amount); + assertEq(theCompact.balanceOf(swapper, anotherId), anotherAmount); + + uint256[2][] memory idsAndAmountsOne = new uint256[2][](1); + idsAndAmountsOne[0] = [id, amount]; + + uint256[2][] memory idsAndAmountsTwo = new uint256[2][](1); + idsAndAmountsTwo[0] = [anotherId, anotherAmount]; + + string memory witnessTypestring = "Witness witness)Witness(uint256 witnessArgument)"; + uint256 witnessArgument = 234; + bytes32 witness = keccak256(abi.encode(witnessArgument)); + + bytes32 allocationHashOne = keccak256( + abi.encode( + keccak256("Allocation(address arbiter,uint256 chainId,uint256[2][] idsAndAmounts,Witness witness)Witness(uint256 witnessArgument)"), + arbiter, + block.chainid, + keccak256(abi.encodePacked(idsAndAmountsOne)), + witness + ) + ); + + bytes32 allocationHashTwo = keccak256( + abi.encode( + keccak256("Allocation(address arbiter,uint256 chainId,uint256[2][] idsAndAmounts,Witness witness)Witness(uint256 witnessArgument)"), + arbiter, + anotherChainId, + keccak256(abi.encodePacked(idsAndAmountsTwo)), + witness + ) + ); + + bytes32 claimHash = keccak256( + abi.encode( + keccak256( + "MultichainCompact(address sponsor,uint256 nonce,uint256 expires,Allocation[] allocations)Allocation(address arbiter,uint256 chainId,uint256[2][] idsAndAmounts,Witness witness)Witness(uint256 witnessArgument)" + ), + swapper, + nonce, + expires, + keccak256(abi.encodePacked(allocationHashOne, allocationHashTwo)) + ) + ); + + bytes32 initialDomainSeparator = theCompact.DOMAIN_SEPARATOR(); + + bytes32 digest = keccak256(abi.encodePacked(bytes2(0x1901), initialDomainSeparator, claimHash)); + + (bytes32 r, bytes32 vs) = vm.signCompact(swapperPrivateKey, digest); + bytes memory sponsorSignature = abi.encodePacked(r, vs); + + bytes32 qualificationTypehash = keccak256("ExampleQualifiedClaim(bytes32 claimHash,uint256 qualifiedClaimArgument)"); + + uint256 qualifiedClaimArgument = 123; + bytes memory qualificationPayload = abi.encode(qualifiedClaimArgument); + + bytes32 qualifiedClaimHash = keccak256(abi.encode(qualificationTypehash, claimHash, qualifiedClaimArgument)); + + digest = keccak256(abi.encodePacked(bytes2(0x1901), initialDomainSeparator, qualifiedClaimHash)); + + (r, vs) = vm.signCompact(allocatorPrivateKey, digest); + bytes memory allocatorSignature = abi.encodePacked(r, vs); + + bytes32[] memory additionalChains = new bytes32[](1); + additionalChains[0] = allocationHashTwo; + + SplitComponent memory splitOne = SplitComponent({ claimant: recipientOne, amount: amountOne }); + + SplitComponent memory splitTwo = SplitComponent({ claimant: recipientTwo, amount: amountTwo }); + + SplitComponent[] memory recipients = new SplitComponent[](2); + recipients[0] = splitOne; + recipients[1] = splitTwo; + + QualifiedSplitMultichainClaimWithWitness memory claim = QualifiedSplitMultichainClaimWithWitness( + allocatorSignature, sponsorSignature, swapper, nonce, expires, witness, witnessTypestring, qualificationTypehash, qualificationPayload, additionalChains, id, amount, recipients + ); + + uint256 snapshotId = vm.snapshot(); + vm.prank(arbiter); + (bool status) = theCompact.claim(claim); + assert(status); + + assertEq(address(theCompact).balance, amount); + assertEq(recipientOne.balance, 0); + assertEq(recipientTwo.balance, 0); + assertEq(theCompact.balanceOf(recipientOne, id), amountOne); + assertEq(theCompact.balanceOf(recipientTwo, id), amountTwo); + vm.revertToAndDelete(snapshotId); + + // change to "new chain" (this hack is so the original one gets stored) + uint256 notarizedChainId = abi.decode(abi.encode(block.chainid), (uint256)); + assert(notarizedChainId != anotherChainId); + vm.chainId(anotherChainId); + assertEq(block.chainid, anotherChainId); + assert(notarizedChainId != anotherChainId); + + bytes32 anotherDomainSeparator = theCompact.DOMAIN_SEPARATOR(); + + assert(initialDomainSeparator != anotherDomainSeparator); + + digest = keccak256(abi.encodePacked(bytes2(0x1901), anotherDomainSeparator, qualifiedClaimHash)); + + (r, vs) = vm.signCompact(allocatorPrivateKey, digest); + bytes memory exogenousAllocatorSignature = abi.encodePacked(r, vs); + + additionalChains[0] = allocationHashOne; + uint256 chainIndex = 0; + + ExogenousQualifiedSplitMultichainClaimWithWitness memory anotherClaim = ExogenousQualifiedSplitMultichainClaimWithWitness( + exogenousAllocatorSignature, + sponsorSignature, + swapper, + nonce, + expires, + witness, + witnessTypestring, + qualificationTypehash, + qualificationPayload, + additionalChains, + chainIndex, + notarizedChainId, + anotherId, + anotherAmount, + recipients + ); + + vm.prank(arbiter); + (bool exogenousStatus) = theCompact.claim(anotherClaim); + assert(exogenousStatus); + + assertEq(theCompact.balanceOf(swapper, anotherId), 0); + assertEq(theCompact.balanceOf(recipientOne, anotherId), amountOne); + assertEq(theCompact.balanceOf(recipientTwo, anotherId), amountTwo); + + // change back + vm.chainId(notarizedChainId); + assertEq(block.chainid, notarizedChainId); + } + function test_batchMultichainClaim() public { uint256 amount = 1e18; uint256 anotherAmount = 1e18;