Skip to content

Commit

Permalink
add split multichain
Browse files Browse the repository at this point in the history
  • Loading branch information
0age committed Oct 19, 2024
1 parent 941fd48 commit 8339afd
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 17 deletions.
61 changes: 45 additions & 16 deletions src/TheCompact.sol
Original file line number Diff line number Diff line change
Expand Up @@ -451,127 +451,143 @@ contract TheCompact is ITheCompact, ERC6909, Extsload {
}

function claimAndWithdraw(BatchClaim calldata claimPayload) external returns (bool) {
return _processBatchClaim(claimPayload, _release);
return _processBatchClaim(claimPayload, _withdraw);
}

function claim(QualifiedBatchClaim calldata claimPayload) external returns (bool) {
return _processQualifiedBatchClaim(claimPayload, _release);
}

function claimAndWithdraw(QualifiedBatchClaim calldata claimPayload) external returns (bool) {
return _processQualifiedBatchClaim(claimPayload, _release);
return _processQualifiedBatchClaim(claimPayload, _withdraw);
}

function claim(BatchClaimWithWitness calldata claimPayload) external returns (bool) {
return _processBatchClaimWithWitness(claimPayload, _release);
}

function claimAndWithdraw(BatchClaimWithWitness calldata claimPayload) external returns (bool) {
return _processBatchClaimWithWitness(claimPayload, _release);
return _processBatchClaimWithWitness(claimPayload, _withdraw);
}

function claim(QualifiedBatchClaimWithWitness calldata claimPayload) external returns (bool) {
return _processQualifiedBatchClaimWithWitness(claimPayload, _release);
}

function claimAndWithdraw(QualifiedBatchClaimWithWitness calldata claimPayload) external returns (bool) {
return _processQualifiedBatchClaimWithWitness(claimPayload, _release);
return _processQualifiedBatchClaimWithWitness(claimPayload, _withdraw);
}

function claim(SplitBatchClaim calldata claimPayload) external returns (bool) {
return _processSplitBatchClaim(claimPayload, _release);
}

function claimAndWithdraw(SplitBatchClaim calldata claimPayload) external returns (bool) {
return _processSplitBatchClaim(claimPayload, _release);
return _processSplitBatchClaim(claimPayload, _withdraw);
}

function claim(QualifiedSplitBatchClaim calldata claimPayload) external returns (bool) {
return _processQualifiedSplitBatchClaim(claimPayload, _release);
}

function claimAndWithdraw(QualifiedSplitBatchClaim calldata claimPayload) external returns (bool) {
return _processQualifiedSplitBatchClaim(claimPayload, _release);
return _processQualifiedSplitBatchClaim(claimPayload, _withdraw);
}

function claim(SplitBatchClaimWithWitness calldata claimPayload) external returns (bool) {
return _processSplitBatchClaimWithWitness(claimPayload, _release);
}

function claimAndWithdraw(SplitBatchClaimWithWitness calldata claimPayload) external returns (bool) {
return _processSplitBatchClaimWithWitness(claimPayload, _release);
return _processSplitBatchClaimWithWitness(claimPayload, _withdraw);
}

function claim(QualifiedSplitBatchClaimWithWitness calldata claimPayload) external returns (bool) {
return _processQualifiedSplitBatchClaimWithWitness(claimPayload, _release);
}

function claimAndWithdraw(QualifiedSplitBatchClaimWithWitness calldata claimPayload) external returns (bool) {
return _processQualifiedSplitBatchClaimWithWitness(claimPayload, _release);
return _processQualifiedSplitBatchClaimWithWitness(claimPayload, _withdraw);
}

function claim(MultichainClaim calldata claimPayload) external returns (bool) {
return _processMultichainClaim(claimPayload, _release);
}

function claimAndWithdraw(MultichainClaim calldata claimPayload) external returns (bool) {
return _processMultichainClaim(claimPayload, _release);
return _processMultichainClaim(claimPayload, _withdraw);
}

function claim(ExogenousMultichainClaim calldata claimPayload) external returns (bool) {
return _processExogenousMultichainClaim(claimPayload, _release);
}

function claimAndWithdraw(ExogenousMultichainClaim calldata claimPayload) external returns (bool) {
return _processExogenousMultichainClaim(claimPayload, _release);
return _processExogenousMultichainClaim(claimPayload, _withdraw);
}

function claim(QualifiedMultichainClaim calldata claimPayload) external returns (bool) {
return _processQualifiedMultichainClaim(claimPayload, _release);
}

function claimAndWithdraw(QualifiedMultichainClaim calldata claimPayload) external returns (bool) {
return _processQualifiedMultichainClaim(claimPayload, _release);
return _processQualifiedMultichainClaim(claimPayload, _withdraw);
}

function claim(ExogenousQualifiedMultichainClaim calldata claimPayload) external returns (bool) {
return _processExogenousQualifiedMultichainClaim(claimPayload, _release);
}

function claimAndWithdraw(ExogenousQualifiedMultichainClaim calldata claimPayload) external returns (bool) {
return _processExogenousQualifiedMultichainClaim(claimPayload, _release);
return _processExogenousQualifiedMultichainClaim(claimPayload, _withdraw);
}

function claim(MultichainClaimWithWitness calldata claimPayload) external returns (bool) {
return _processMultichainClaimWithWitness(claimPayload, _release);
}

function claimAndWithdraw(MultichainClaimWithWitness calldata claimPayload) external returns (bool) {
return _processMultichainClaimWithWitness(claimPayload, _release);
return _processMultichainClaimWithWitness(claimPayload, _withdraw);
}

function claim(ExogenousMultichainClaimWithWitness calldata claimPayload) external returns (bool) {
return _processExogenousMultichainClaimWithWitness(claimPayload, _release);
}

function claimAndWithdraw(ExogenousMultichainClaimWithWitness calldata claimPayload) external returns (bool) {
return _processExogenousMultichainClaimWithWitness(claimPayload, _release);
return _processExogenousMultichainClaimWithWitness(claimPayload, _withdraw);
}

function claim(QualifiedMultichainClaimWithWitness calldata claimPayload) external returns (bool) {
return _processQualifiedMultichainClaimWithWitness(claimPayload, _release);
}

function claimAndWithdraw(QualifiedMultichainClaimWithWitness calldata claimPayload) external returns (bool) {
return _processQualifiedMultichainClaimWithWitness(claimPayload, _release);
return _processQualifiedMultichainClaimWithWitness(claimPayload, _withdraw);
}

function claim(ExogenousQualifiedMultichainClaimWithWitness calldata claimPayload) external returns (bool) {
return _processExogenousQualifiedMultichainClaimWithWitness(claimPayload, _release);
}

function claimAndWithdraw(ExogenousQualifiedMultichainClaimWithWitness calldata claimPayload) external returns (bool) {
return _processExogenousQualifiedMultichainClaimWithWitness(claimPayload, _release);
return _processExogenousQualifiedMultichainClaimWithWitness(claimPayload, _withdraw);
}

function claim(SplitMultichainClaim calldata claimPayload) external returns (bool) {
return _processSplitMultichainClaim(claimPayload, _release);
}

function claimAndWithdraw(SplitMultichainClaim calldata claimPayload) external returns (bool) {
return _processSplitMultichainClaim(claimPayload, _withdraw);
}

function claim(ExogenousSplitMultichainClaim calldata claimPayload) external returns (bool) {
return _processExogenousSplitMultichainClaim(claimPayload, _release);
}

function claimAndWithdraw(ExogenousSplitMultichainClaim calldata claimPayload) external returns (bool) {
return _processExogenousSplitMultichainClaim(claimPayload, _withdraw);
}

function enableForcedWithdrawal(uint256 id) external returns (uint256 withdrawableAt) {
Expand Down Expand Up @@ -2280,6 +2296,10 @@ contract TheCompact is ITheCompact, ERC6909, Extsload {
return usingQualifiedMultichainClaimWithWitness(_processClaimWithQualification)(messageHash, qualificationMessageHash, claimPayload, 0x140, operation);
}

function _processSplitMultichainClaim(SplitMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) {
return usingSplitMultichainClaim(_processSimpleSplitClaim)(claimPayload.toMessageHash(), claimPayload, 0xc0, operation);
}

function _processExogenousMultichainClaim(ExogenousMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) {
return usingExogenousMultichainClaim(_processClaimWithSponsorDomain)(claimPayload.toMessageHash(), claimPayload, 0x100, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), operation);
}
Expand Down Expand Up @@ -2313,6 +2333,15 @@ contract TheCompact is ITheCompact, ERC6909, Extsload {
);
}

function _processExogenousSplitMultichainClaim(ExogenousSplitMultichainClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation)
internal
returns (bool)
{
return usingExogenousSplitMultichainClaim(_processSplitClaimWithSponsorDomain)(
claimPayload.toMessageHash(), claimPayload, 0x100, claimPayload.notarizedChainId.toNotarizedDomainSeparator(), operation
);
}

function _processSplitClaim(SplitClaim calldata claimPayload, function(address, address, uint256, uint256) internal returns (bool) operation) internal returns (bool) {
return usingSplitClaim(_processSimpleSplitClaim)(claimPayload.toMessageHash(), claimPayload, 0xa0, operation);
}
Expand Down
28 changes: 28 additions & 0 deletions src/lib/HashLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,20 @@ library HashLib {
}
}

function usingSplitMultichainClaim(function (MultichainClaim calldata, uint256, bytes32, bytes32) internal view returns (bytes32) fnIn)
internal
pure
returns (function (SplitMultichainClaim calldata, uint256, bytes32, bytes32) internal view returns (bytes32) fnOut)
{
assembly ("memory-safe") {
fnOut := fnIn
}
}

function toMessageHash(SplitMultichainClaim calldata claim) internal view returns (bytes32 messageHash) {
messageHash = usingSplitMultichainClaim(toMultichainClaimMessageHash)(claim, 0, ALLOCATION_TYPEHASH, MULTICHAIN_COMPACT_TYPEHASH);
}

function usingExogenousMultichainClaimWithWitness(function (ExogenousMultichainClaim calldata, uint256, bytes32, bytes32) internal view returns (bytes32) fnIn)
internal
pure
Expand All @@ -501,6 +515,16 @@ library HashLib {
}
}

function usingExogenousSplitMultichainClaim(function (ExogenousMultichainClaim calldata, uint256, bytes32, bytes32) internal view returns (bytes32) fnIn)
internal
pure
returns (function (ExogenousSplitMultichainClaim calldata, uint256, bytes32, bytes32) internal view returns (bytes32) fnOut)
{
assembly ("memory-safe") {
fnOut := fnIn
}
}

function usingExogenousMultichainClaimWithWitness(function (QualifiedClaim calldata, bytes32, uint256) internal pure returns (bytes32) fnIn)
internal
pure
Expand Down Expand Up @@ -680,6 +704,10 @@ library HashLib {
return toExogenousMultichainClaimMessageHash(claim, 0, ALLOCATION_TYPEHASH, MULTICHAIN_COMPACT_TYPEHASH);
}

function toMessageHash(ExogenousSplitMultichainClaim calldata claim) internal view returns (bytes32 messageHash) {
return usingExogenousSplitMultichainClaim(toExogenousMultichainClaimMessageHash)(claim, 0, ALLOCATION_TYPEHASH, MULTICHAIN_COMPACT_TYPEHASH);
}

function toMessageHash(ExogenousQualifiedMultichainClaim calldata claim) internal view returns (bytes32 messageHash, bytes32 qualificationMessageHash) {
messageHash = usingExogenousQualifiedMultichainClaim(toExogenousMultichainClaimMessageHash)(claim, 0x40, ALLOCATION_TYPEHASH, MULTICHAIN_COMPACT_TYPEHASH);
qualificationMessageHash = usingExogenousQualifiedMultichainClaim(toQualificationMessageHash)(claim, messageHash, 0);
Expand Down
128 changes: 127 additions & 1 deletion test/TheCompact.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,15 @@ import {
MultichainClaimWithWitness,
ExogenousMultichainClaimWithWitness,
QualifiedMultichainClaimWithWitness,
ExogenousQualifiedMultichainClaimWithWitness
ExogenousQualifiedMultichainClaimWithWitness,
SplitMultichainClaim,
ExogenousSplitMultichainClaim,
QualifiedSplitMultichainClaim,
ExogenousQualifiedSplitMultichainClaim,
SplitMultichainClaimWithWitness,
ExogenousSplitMultichainClaimWithWitness,
QualifiedSplitMultichainClaimWithWitness,
ExogenousQualifiedSplitMultichainClaimWithWitness
} from "../src/types/MultichainClaims.sol";

import { SplitComponent, TransferComponent, SplitByIdComponent, BatchClaimComponent, SplitBatchClaimComponent } from "../src/types/Components.sol";
Expand Down Expand Up @@ -2512,4 +2520,122 @@ contract TheCompactTest is Test {
vm.chainId(notarizedChainId);
assertEq(block.chainid, notarizedChainId);
}

function test_splitMultichainClaim() 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];

bytes32 allocationHashOne =
keccak256(abi.encode(keccak256("Allocation(address arbiter,uint256 chainId,uint256[2][] idsAndAmounts)"), arbiter, block.chainid, keccak256(abi.encodePacked(idsAndAmountsOne))));

bytes32 allocationHashTwo =
keccak256(abi.encode(keccak256("Allocation(address arbiter,uint256 chainId,uint256[2][] idsAndAmounts)"), arbiter, anotherChainId, keccak256(abi.encodePacked(idsAndAmountsTwo))));

bytes32 claimHash = keccak256(
abi.encode(
keccak256("MultichainCompact(address sponsor,uint256 nonce,uint256 expires,Allocation[] allocations)Allocation(address arbiter,uint256 chainId,uint256[2][] idsAndAmounts)"),
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;

SplitMultichainClaim memory claim = SplitMultichainClaim(allocatorSignature, sponsorSignature, swapper, nonce, expires, 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;

ExogenousSplitMultichainClaim memory anotherClaim =
ExogenousSplitMultichainClaim(exogenousAllocatorSignature, sponsorSignature, swapper, nonce, expires, 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);
}
}

0 comments on commit 8339afd

Please sign in to comment.