Skip to content

Commit

Permalink
Merge pull request #20 from Uniswap/more-libs
Browse files Browse the repository at this point in the history
create more libs
  • Loading branch information
0age authored Nov 3, 2024
2 parents 2b18148 + d14408c commit 4689e81
Show file tree
Hide file tree
Showing 11 changed files with 642 additions and 428 deletions.
54 changes: 27 additions & 27 deletions snapshots/TheCompactTest.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
{
"basicTransfer": "56850",
"basicWithdrawal": "59816",
"batchClaim": "111810",
"batchClaimRegisteredWithDeposit": "111810",
"batchClaimRegisteredWithDepositWithWitness": "112675",
"batchClaimWithWitness": "112669",
"basicTransfer": "56867",
"basicWithdrawal": "59810",
"batchClaim": "112477",
"batchClaimRegisteredWithDeposit": "112477",
"batchClaimRegisteredWithDepositWithWitness": "113236",
"batchClaimWithWitness": "113230",
"batchDepositAndRegisterViaPermit2": "221877",
"batchDepositAndRegisterWithWitnessViaPermit2": "221855",
"batchTransfer": "81520",
"batchWithdrawal": "99951",
"claim": "56817",
"claimAndWithdraw": "73116",
"claimWithWitness": "59462",
"batchTransfer": "81344",
"batchWithdrawal": "99729",
"claim": "56982",
"claimAndWithdraw": "73258",
"claimWithWitness": "59479",
"depositAndRegisterViaPermit2": "124247",
"depositBatchSingleERC20": "67868",
"depositBatchSingleNative": "28171",
Expand All @@ -22,21 +22,21 @@
"depositERC20ViaPermit2AndURI": "98289",
"depositETHAndURI": "26754",
"depositETHBasic": "28391",
"qualifiedBatchClaim": "113348",
"qualifiedBatchClaimWithWitness": "112885",
"qualifiedClaim": "60238",
"qualifiedClaimWithWitness": "58927",
"qualifiedSplitBatchClaim": "140922",
"qualifiedSplitBatchClaimWithWitness": "140987",
"qualifiedSplitClaim": "86554",
"qualifiedSplitClaimWithWitness": "87031",
"qualifiedBatchClaim": "114099",
"qualifiedBatchClaimWithWitness": "113637",
"qualifiedClaim": "60414",
"qualifiedClaimWithWitness": "59106",
"qualifiedSplitBatchClaim": "141456",
"qualifiedSplitBatchClaimWithWitness": "141522",
"qualifiedSplitClaim": "86977",
"qualifiedSplitClaimWithWitness": "87452",
"register": "25379",
"splitBatchClaim": "140264",
"splitBatchClaimWithWitness": "140331",
"splitBatchTransfer": "110587",
"splitBatchWithdrawal": "139819",
"splitClaim": "86275",
"splitClaimWithWitness": "85936",
"splitTransfer": "82732",
"splitWithdrawal": "93702"
"splitBatchClaim": "140758",
"splitBatchClaimWithWitness": "140719",
"splitBatchTransfer": "110582",
"splitBatchWithdrawal": "139745",
"splitClaim": "86751",
"splitClaimWithWitness": "86232",
"splitTransfer": "82438",
"splitWithdrawal": "93362"
}
2 changes: 1 addition & 1 deletion src/lib/ClaimHashLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ import {
ExogenousQualifiedSplitBatchMultichainClaimWithWitness
} from "../types/BatchMultichainClaims.sol";

import { TransferComponent, SplitComponent, SplitByIdComponent, BatchClaimComponent, SplitBatchClaimComponent } from "../types/Components.sol";
import { BatchClaimComponent, SplitBatchClaimComponent } from "../types/Components.sol";

import { ResetPeriod } from "../types/ResetPeriod.sol";
import { Scope } from "../types/Scope.sol";
Expand Down
231 changes: 7 additions & 224 deletions src/lib/ClaimProcessorLib.sol
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import { COMPACT_TYPEHASH, BATCH_COMPACT_TYPEHASH, MULTICHAIN_COMPACT_TYPEHASH } from "../types/EIP712Types.sol";
import { SplitComponent, BatchClaimComponent, SplitBatchClaimComponent } from "../types/Components.sol";

import { ComponentLib } from "./ComponentLib.sol";
import { EfficiencyLib } from "./EfficiencyLib.sol";
import { EventLib } from "./EventLib.sol";
import { HashLib } from "./HashLib.sol";
import { IdLib } from "./IdLib.sol";
import { RegistrationLib } from "./RegistrationLib.sol";
import { ValidityLib } from "./ValidityLib.sol";
Expand All @@ -20,13 +19,14 @@ import { ValidityLib } from "./ValidityLib.sol";
* any changes.
*/
library ClaimProcessorLib {
using ComponentLib for bytes32;
using ClaimProcessorLib for uint256;
using ClaimProcessorLib for bytes32;
using ClaimProcessorLib for SplitComponent[];
using EfficiencyLib for bool;
using EfficiencyLib for uint256;
using EfficiencyLib for bytes32;
using EventLib for address;
using HashLib for uint256;
using IdLib for uint256;
using ValidityLib for uint256;
using ValidityLib for uint96;
Expand Down Expand Up @@ -177,33 +177,7 @@ library ClaimProcessorLib {
bytes32 domainSeparator,
function(address, address, uint256, uint256) internal returns (bool) operation
) internal returns (bool) {
// Declare variables for parameters that will be extracted from calldata.
uint256 id;
uint256 allocatedAmount;
SplitComponent[] calldata components;

assembly ("memory-safe") {
// Calculate pointer to claim parameters using provided offset.
let calldataPointerWithOffset := add(calldataPointer, offsetToId)

// Extract resource lock id and allocated amount.
id := calldataload(calldataPointerWithOffset)
allocatedAmount := calldataload(add(calldataPointerWithOffset, 0x20))

// Extract array of split components containing claimant addresses and amounts.
let componentsPtr := add(calldataPointer, calldataload(add(calldataPointerWithOffset, 0x40)))
components.offset := add(0x20, componentsPtr)
components.length := calldataload(componentsPtr)
}

// Validate the claim and extract the sponsor address.
address sponsor = messageHash.validate(id.toAllocatorId(), qualificationMessageHash, calldataPointer, domainSeparator, sponsorDomainSeparator, typehash);

// Verify the resource lock scope is compatible with the provided domain separator.
sponsorDomainSeparator.ensureValidScope(id);

// Process each split component, verifying total amount and executing operations.
return components.verifyAndProcessSplitComponents(sponsor, id, allocatedAmount, operation);
return messageHash.processClaimWithSplitComponents(qualificationMessageHash, calldataPointer, offsetToId, sponsorDomainSeparator, typehash, domainSeparator, operation, validate);
}

/**
Expand Down Expand Up @@ -232,76 +206,7 @@ library ClaimProcessorLib {
bytes32 domainSeparator,
function(address, address, uint256, uint256) internal returns (bool) operation
) internal returns (bool) {
// Declare variables for parameters that will be extracted from calldata.
BatchClaimComponent[] calldata claims;
address claimant;

assembly ("memory-safe") {
// Calculate pointer to claim parameters using provided offset.
let calldataPointerWithOffset := add(calldataPointer, offsetToId)

// Extract array of batch claim components and claimant address.
let claimsPtr := add(calldataPointer, calldataload(calldataPointerWithOffset))
claims.offset := add(0x20, claimsPtr)
claims.length := calldataload(claimsPtr)
claimant := calldataload(add(calldataPointerWithOffset, 0x20))
}

// Extract allocator id from first claim for validation.
uint96 firstAllocatorId = claims[0].id.toAllocatorId();

// Validate the claim and extract the sponsor address.
address sponsor = messageHash.validate(firstAllocatorId, qualificationMessageHash, calldataPointer, domainSeparator, sponsorDomainSeparator, typehash);

// Revert if the batch is empty.
uint256 totalClaims = claims.length;
assembly ("memory-safe") {
if iszero(totalClaims) {
// revert InvalidBatchAllocation()
mstore(0, 0x3a03d3bb)
revert(0x1c, 0x04)
}
}

// Process first claim and initialize error tracking.
// NOTE: many of the bounds checks on these array accesses can be skipped as an optimization
BatchClaimComponent calldata component = claims[0];
uint256 id = component.id;
uint256 amount = component.amount;
uint256 errorBuffer = component.allocatedAmount.allocationExceededOrScopeNotMultichain(amount, id, sponsorDomainSeparator).asUint256();

// Execute transfer or withdrawal for first claim.
operation(sponsor, claimant, id, amount);

unchecked {
// Process remaining claims while accumulating potential errors.
for (uint256 i = 1; i < totalClaims; ++i) {
component = claims[i];
id = component.id;
amount = component.amount;
errorBuffer |= (id.toAllocatorId() != firstAllocatorId).or(component.allocatedAmount.allocationExceededOrScopeNotMultichain(amount, id, sponsorDomainSeparator)).asUint256();

operation(sponsor, claimant, id, amount);
}

// If any errors occurred, identify specific failures and revert.
if (errorBuffer.asBool()) {
for (uint256 i = 0; i < totalClaims; ++i) {
component = claims[i];
component.amount.withinAllocated(component.allocatedAmount);
id = component.id;
sponsorDomainSeparator.ensureValidScope(component.id);
}

assembly ("memory-safe") {
// revert InvalidBatchAllocation()
mstore(0, 0x3a03d3bb)
revert(0x1c, 0x04)
}
}
}

return true;
return messageHash.processClaimWithBatchComponents(qualificationMessageHash, calldataPointer, offsetToId, sponsorDomainSeparator, typehash, domainSeparator, operation, validate);
}

/**
Expand Down Expand Up @@ -330,108 +235,7 @@ library ClaimProcessorLib {
bytes32 domainSeparator,
function(address, address, uint256, uint256) internal returns (bool) operation
) internal returns (bool) {
// Declare variable for SplitBatchClaimComponent array that will be extracted from calldata.
SplitBatchClaimComponent[] calldata claims;

assembly ("memory-safe") {
// Extract array of split batch claim components.
let claimsPtr := add(calldataPointer, calldataload(add(calldataPointer, offsetToId)))
claims.offset := add(0x20, claimsPtr)
claims.length := calldataload(claimsPtr)
}

// Extract allocator id from first claim for validation.
uint96 firstAllocatorId = claims[0].id.toAllocatorId();

// Validate the claim and extract the sponsor address.
address sponsor = messageHash.validate(firstAllocatorId, qualificationMessageHash, calldataPointer, domainSeparator, sponsorDomainSeparator, typehash);

// Initialize tracking variables.
uint256 totalClaims = claims.length;
uint256 errorBuffer = (totalClaims == 0).asUint256();
uint256 id;

unchecked {
// Process each claim component while accumulating potential errors.
for (uint256 i = 0; i < totalClaims; ++i) {
SplitBatchClaimComponent calldata claimComponent = claims[i];
id = claimComponent.id;
errorBuffer |= (id.toAllocatorId() != firstAllocatorId).or(id.scopeNotMultichain(sponsorDomainSeparator)).asUint256();

// Process each split component, verifying total amount and executing operations.
claimComponent.portions.verifyAndProcessSplitComponents(sponsor, id, claimComponent.allocatedAmount, operation);
}

// If any errors occurred, identify specific scope failures and revert.
if (errorBuffer.asBool()) {
for (uint256 i = 0; i < totalClaims; ++i) {
sponsorDomainSeparator.ensureValidScope(claims[i].id);
}

assembly ("memory-safe") {
// revert InvalidBatchAllocation()
mstore(0, 0x3a03d3bb)
revert(0x1c, 0x04)
}
}
}

return true;
}

/**
* @notice Internal function for verifying and processing split components. Ensures that the
* sum of split amounts doesn't exceed the allocated amount, checks for arithmetic overflow,
* and executes the specified operation for each split recipient. Reverts if the total
* claimed amount exceeds the allocation or if arithmetic overflow occurs during summation.
* @param claimants Array of split components specifying recipients and their amounts.
* @param sponsor The address of the claim sponsor.
* @param id The ERC6909 token identifier of the resource lock.
* @param allocatedAmount The total amount allocated for this claim.
* @param operation Function pointer to either _release or _withdraw for executing the claim.
* @return Whether all split components were successfully processed.
*/
function verifyAndProcessSplitComponents(
SplitComponent[] calldata claimants,
address sponsor,
uint256 id,
uint256 allocatedAmount,
function(address, address, uint256, uint256) internal returns (bool) operation
) internal returns (bool) {
// Initialize tracking variables.
uint256 totalClaims = claimants.length;
uint256 spentAmount = 0;
uint256 errorBuffer = (totalClaims == 0).asUint256();

unchecked {
// Process each split component while tracking total amount and checking for overflow.
for (uint256 i = 0; i < totalClaims; ++i) {
SplitComponent calldata component = claimants[i];
uint256 amount = component.amount;

// Track total amount claimed, checking for overflow.
uint256 updatedSpentAmount = amount + spentAmount;
errorBuffer |= (updatedSpentAmount < spentAmount).asUint256();
spentAmount = updatedSpentAmount;

// Execute transfer or withdrawal for the split component.
operation(sponsor, component.claimant, id, amount);
}
}

// Revert if an overflow occurred or if total claimed amount exceeds allocation.
errorBuffer |= (allocatedAmount < spentAmount).asUint256();
assembly ("memory-safe") {
if errorBuffer {
// revert AllocatedAmountExceeded(allocatedAmount, amount);
mstore(0, 0x3078b2f6)
mstore(0x20, allocatedAmount)
mstore(0x40, spentAmount)
revert(0x1c, 0x44)
}
}

return true;
return messageHash.processClaimWithSplitBatchComponents(qualificationMessageHash, calldataPointer, offsetToId, sponsorDomainSeparator, typehash, domainSeparator, operation, validate);
}

/**
Expand Down Expand Up @@ -739,25 +543,4 @@ library ClaimProcessorLib {
) internal returns (bool) {
return messageHash.processSplitBatchClaimWithQualificationAndSponsorDomain(messageHash, calldataPointer, offsetToId, sponsorDomain, typehash, domainSeparator, operation);
}

/**
* @notice Internal pure function for retrieving EIP-712 typehashes where no witness data is
* provided, returning the corresponding typehash based on the index provided. The available
* typehashes are:
* - 0: COMPACT_TYPEHASH
* - 1: BATCH_COMPACT_TYPEHASH
* - 2: MULTICHAIN_COMPACT_TYPEHASH
* @param i The index of the EIP-712 typehash to retrieve.
* @return typehash The corresponding EIP-712 typehash.
*/
function typehashes(uint256 i) internal pure returns (bytes32 typehash) {
assembly ("memory-safe") {
let m := mload(0x40)
mstore(0, COMPACT_TYPEHASH)
mstore(0x20, BATCH_COMPACT_TYPEHASH)
mstore(0x40, MULTICHAIN_COMPACT_TYPEHASH)
typehash := mload(shl(5, i))
mstore(0x40, m)
}
}
}
6 changes: 4 additions & 2 deletions src/lib/ClaimProcessorLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@ import {

import { ClaimHashLib } from "./ClaimHashLib.sol";
import { ClaimProcessorLib } from "./ClaimProcessorLib.sol";
import { DomainLib } from "./DomainLib.sol";
import { HashLib } from "./HashLib.sol";
import { EfficiencyLib } from "./EfficiencyLib.sol";
import { FunctionCastLib } from "./FunctionCastLib.sol";
import { HashLib } from "./HashLib.sol";
import { SharedLogic } from "./SharedLogic.sol";
import { ValidityLib } from "./ValidityLib.sol";

Expand Down Expand Up @@ -117,12 +118,13 @@ contract ClaimProcessorLogic is SharedLogic {
using ClaimHashLib for ExogenousQualifiedSplitBatchMultichainClaim;
using ClaimHashLib for ExogenousQualifiedSplitBatchMultichainClaimWithWitness;
using ClaimProcessorLib for uint256;
using DomainLib for uint256;
using HashLib for uint256;
using EfficiencyLib for uint256;
using FunctionCastLib for function(bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool);
using FunctionCastLib for function(bytes32, uint256, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool);
using FunctionCastLib for function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool);
using FunctionCastLib for function(bytes32, bytes32, uint256, uint256, bytes32, bytes32, bytes32, function(address, address, uint256, uint256) internal returns (bool)) internal returns (bool);
using HashLib for uint256;
using ValidityLib for uint96;
using ValidityLib for uint256;
using ValidityLib for bytes32;
Expand Down
Loading

0 comments on commit 4689e81

Please sign in to comment.