Skip to content

Commit

Permalink
verify allocator signature in transfer
Browse files Browse the repository at this point in the history
  • Loading branch information
vimageDE committed Jan 30, 2025
1 parent c64a4c9 commit 251653d
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 7 deletions.
8 changes: 4 additions & 4 deletions src/core/TheCompactCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ contract TheCompactCore is ERC6909, Deposit {

function allocatedTransfer(ITheCompactCore.Transfer calldata transfer_, bytes calldata allocatorSignature) external returns (bool) {
address allocator = _checkNonce(transfer_.recipients[0].id, transfer_.nonce);
uint256 length = _ensureBatchAttested(msg.sender, transfer_, allocatorSignature);
uint256 length = _ensureBatchAttested(msg.sender, msg.sender, transfer_, allocatorSignature);
// The allocator has successfully attested to the withdrawal. If the nonce is not 0, it must be consumed
if(transfer_.nonce != 0) {
// If the nonce is 0, it must be an on chain allocator that does not require a nonce to attest.
Expand All @@ -137,7 +137,7 @@ contract TheCompactCore is ERC6909, Deposit {

function allocatedTransferFrom(ITheCompactCore.DelegatedTransfer calldata delegatedTransfer, bytes calldata allocatorSignature) external returns (bool) {
address allocator = _checkNonce(delegatedTransfer.transfer.recipients[0].id, delegatedTransfer.transfer.nonce);
uint256 length = _ensureBatchAttested(msg.sender, delegatedTransfer.transfer, allocatorSignature);
uint256 length = _ensureBatchAttested(msg.sender, delegatedTransfer.from, delegatedTransfer.transfer, allocatorSignature);
// The allocator has successfully attested to the withdrawal. If the nonce is not 0, it must be consumed
if(delegatedTransfer.transfer.nonce != 0) {
// If the nonce is 0, it must be an on chain allocator that does not require a nonce to attest.
Expand All @@ -152,7 +152,7 @@ contract TheCompactCore is ERC6909, Deposit {

function withdrawal(ITheCompactCore.Transfer calldata withdrawal_, bytes calldata allocatorSignature) external returns (bool) {
address allocator = _checkNonce(withdrawal_.recipients[0].id, withdrawal_.nonce);
uint256 length = _ensureBatchAttested(msg.sender, withdrawal_, allocatorSignature);
uint256 length = _ensureBatchAttested(msg.sender, msg.sender, withdrawal_, allocatorSignature);
// The allocator has successfully attested to the withdrawal. If the nonce is not 0, it must be consumed
if(withdrawal_.nonce != 0) {
// If the nonce is 0, it must be an on chain allocator that does not require a nonce to attest.
Expand All @@ -168,7 +168,7 @@ contract TheCompactCore is ERC6909, Deposit {

function withdrawalFrom(ITheCompactCore.DelegatedTransfer calldata delegatedWithdrawal, bytes calldata allocatorSignature) external returns (bool) {
address allocator = _checkNonce(delegatedWithdrawal.transfer.recipients[0].id, delegatedWithdrawal.transfer.nonce);
uint256 length = _ensureBatchAttested(msg.sender, delegatedWithdrawal.transfer, allocatorSignature);
uint256 length = _ensureBatchAttested(msg.sender, delegatedWithdrawal.from, delegatedWithdrawal.transfer, allocatorSignature);
// The allocator has successfully attested to the withdrawal. If the nonce is not 0, it must be consumed
if(delegatedWithdrawal.transfer.nonce != 0) {
// If the nonce is 0, it must be an on chain allocator that does not require a nonce to attest.
Expand Down
33 changes: 30 additions & 3 deletions src/core/lib/Deposit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ contract Deposit {
// keccak256("Compact(address arbiter,address sponsor,uint256 nonce,uint256 expires,Allocation[] inputs)EnhancedCompact(Compact compact,uint256 chainId)MultiChainCompact(EnhancedCompact[])")
bytes32 private constant _MULTICHAIN_COMPACT_TYPEHASH = 0x4527c6867b5e06d14c0c8048cabe293f468c8ce4d78c2cdbaf193934751a96f0;

// keccak256("Transfer(address from,address[] to,uint256[] id,uint256[] amount,uint256 nonce,uint256 expires)")
bytes32 private constant _TRANSFER_TYPEHASH = 0x6d44c9455c8398fa551f6b1e552d67be7e70cf294bbb32590a4baf18180519e6;

// keccak256("Permit(address owner,address spender,uint256 id,uint256 value,uint256 nonce,uint256 deadline)")
bytes32 private constant _PERMIT_TYPEHASH = 0x41b82e2b5a0c36576b0cbe551120f192388f4a0e73168b730f27a8a467e1f79f;

Expand Down Expand Up @@ -282,6 +285,7 @@ contract Deposit {
return _permit2Nonces[owner];
}

// @dev Since there is no nonce, a single attestation can only be verified by an on chain allocator.
function _ensureAttested(address from, address to, uint256 id, uint256 amount) internal {
// Derive the allocator address from the supplied id.
address allocator = IdLib.toAllocator(id);
Expand All @@ -291,7 +295,7 @@ contract Deposit {
}
}

function _ensureBatchAttested(address caller, ITheCompactCore.Transfer calldata transfer, bytes calldata allocatorSignature) internal returns (uint256 length) {
function _ensureBatchAttested(address caller, address from, ITheCompactCore.Transfer calldata transfer, bytes calldata allocatorSignature) internal returns (uint256 length) {
address expectedAllocator = IdLib.toAllocator(transfer.recipients[0].id);
// Ensure the allocator attests the transfers.
length = transfer.recipients.length;
Expand All @@ -308,8 +312,11 @@ contract Deposit {
amount[i] = transfer.recipients[i].amount;
}

if( IAllocator(expectedAllocator).attest(caller, caller, to, id, amount, transfer.nonce, transfer.expires, allocatorSignature) != _ATTEST_BATCH_SELECTOR) {
revert Errors.AllocatorDenied(expectedAllocator);
bytes32 digest = _transferDigest(from, to, id, amount, transfer.nonce, transfer.expires);
if(!SignatureCheckerLib.isValidSignatureNowCalldata(expectedAllocator, digest, allocatorSignature)) {
if( IAllocator(expectedAllocator).attest(caller, from, to, id, amount, transfer.nonce, transfer.expires, allocatorSignature) != _ATTEST_BATCH_SELECTOR) {
revert Errors.AllocatorDenied(expectedAllocator);
}
}
}

Expand Down Expand Up @@ -432,6 +439,26 @@ contract Deposit {
);
}

function _transferDigest(address from, address[] memory to, uint256[] memory id, uint256[] memory amount, uint256 nonce, uint256 expires) internal view returns (bytes32) {
return keccak256(
abi.encodePacked(
bytes2(0x1901),
_DOMAIN_SEPARATOR,
keccak256(
abi.encode(
_TRANSFER_TYPEHASH,
from,
to,
id,
amount,
nonce,
expires
)
)
)
);
}

function _computePermitHash(address owner, address spender, uint256 id, uint256 value, uint256 nonce, uint256 deadline) internal view returns (bytes32) {
return keccak256(
abi.encodePacked(
Expand Down

0 comments on commit 251653d

Please sign in to comment.