Skip to content

Commit 0ac955d

Browse files
authored
Merge pull request #6 from Uniswap/ERC7683Allocator
Erc7683 allocator
2 parents a2fb41b + 273e632 commit 0ac955d

File tree

8 files changed

+1798
-10
lines changed

8 files changed

+1798
-10
lines changed

.github/workflows/semgrep.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ on:
1111
jobs:
1212
semgrep:
1313
name: semgrep/ci
14-
runs-on: ubuntu-20.04
14+
runs-on: ubuntu-latest
1515
env:
1616
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
1717
container:

.github/workflows/test.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
- name: Install Foundry
2525
uses: foundry-rs/foundry-toolchain@v1
2626
with:
27-
version: nightly
27+
version: stable
2828

2929
- name: Run Forge build
3030
run: |

foundry.toml

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ libs = ["lib"]
55
optimizer = true
66
optimizer_runs = 999999
77
via_ir = true
8-
solc = "0.8.27"
8+
solc = "0.8.28"
99
verbosity = 2
1010
ffi = true
11+
evm_version = "cancun"
1112
fs_permissions = [
1213
{ access = "read-write", path = ".forge-snapshots"},
1314
{ access = "read", path = "script/" }
1415
]
15-
1616
remappings = [
1717
"forge-std=lib/forge-std/src",
1818
"@openzeppelin/contracts=lib/openzeppelin-contracts/contracts",
@@ -21,13 +21,15 @@ remappings = [
2121
"@solady=lib/solady/src",
2222
]
2323

24-
additional_compiler_profiles = [
25-
{ name = "test", via_ir = false }
26-
]
24+
[profile.ci]
25+
inherit = "default"
26+
optimizer_runs = 200 # Override optimizer runs to reduce the compact contract sizes
27+
bytecode_hash = 'none'
2728

28-
compilation_restrictions = [
29-
{ paths = "test/**", via_ir = false }
30-
]
29+
[profile.pr]
30+
inherit = "default"
31+
optimizer_runs = 200 # Override optimizer runs to reduce the compact contract sizes
32+
bytecode_hash = 'none'
3133

3234
[profile.default.fuzz]
3335
runs = 1000

src/allocators/ERC7683Allocator.sol

Lines changed: 365 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.27;
4+
5+
import {Compact} from '@uniswap/the-compact/types/EIP712Types.sol';
6+
7+
struct Claim {
8+
uint256 chainId; // Claim processing chain ID
9+
Compact compact;
10+
bytes sponsorSignature; // Authorization from the sponsor
11+
bytes allocatorSignature; // Authorization from the allocator
12+
}
13+
14+
struct Mandate {
15+
// uint256 chainId; // (implicit arg, included in EIP712 payload).
16+
// address tribunal; // (implicit arg, included in EIP712 payload).
17+
address recipient; // Recipient of filled tokens.
18+
uint256 expires; // Mandate expiration timestamp.
19+
address token; // Fill token (address(0) for native).
20+
uint256 minimumAmount; // Minimum fill amount.
21+
uint256 baselinePriorityFee; // Base fee threshold where scaling kicks in.
22+
uint256 scalingFactor; // Fee scaling multiplier (1e18 baseline).
23+
uint256[] decayCurve; // Block durations, fill increases, & claim decreases.
24+
bytes32 salt; // Replay protection parameter.
25+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.0;
4+
5+
/// @title IOriginSettler
6+
/// @notice Standard interface for settlement contracts on the origin chain
7+
interface IOriginSettler {
8+
/// @title GaslessCrossChainOrder CrossChainOrder type
9+
/// @notice Standard order struct to be signed by users, disseminated to fillers, and submitted to origin settler contracts
10+
struct GaslessCrossChainOrder {
11+
/// @dev The contract address that the order is meant to be settled by.
12+
/// Fillers send this order to this contract address on the origin chain
13+
address originSettler;
14+
/// @dev The address of the user who is initiating the swap,
15+
/// whose input tokens will be taken and escrowed
16+
address user;
17+
/// @dev Nonce to be used as replay protection for the order
18+
uint256 nonce;
19+
/// @dev The chainId of the origin chain
20+
uint256 originChainId;
21+
/// @dev The timestamp by which the order must be opened
22+
uint32 openDeadline;
23+
/// @dev The timestamp by which the order must be filled on the destination chain
24+
uint32 fillDeadline;
25+
/// @dev Type identifier for the order data. This is an EIP-712 typehash.
26+
bytes32 orderDataType;
27+
/// @dev Arbitrary implementation-specific data
28+
/// Can be used to define tokens, amounts, destination chains, fees, settlement parameters,
29+
/// or any other order-type specific information
30+
bytes orderData;
31+
}
32+
33+
/// @title OnchainCrossChainOrder CrossChainOrder type
34+
/// @notice Standard order struct for user-opened orders, where the user is the msg.sender.
35+
struct OnchainCrossChainOrder {
36+
/// @dev The timestamp by which the order must be filled on the destination chain
37+
uint32 fillDeadline;
38+
/// @dev Type identifier for the order data. This is an EIP-712 typehash.
39+
bytes32 orderDataType;
40+
/// @dev Arbitrary implementation-specific data
41+
/// Can be used to define tokens, amounts, destination chains, fees, settlement parameters,
42+
/// or any other order-type specific information
43+
bytes orderData;
44+
}
45+
/// @title ResolvedCrossChainOrder type
46+
/// @notice An implementation-generic representation of an order intended for filler consumption
47+
/// @dev Defines all requirements for filling an order by unbundling the implementation-specific orderData.
48+
/// @dev Intended to improve integration generalization by allowing fillers to compute the exact input and output information of any order
49+
50+
struct ResolvedCrossChainOrder {
51+
/// @dev The address of the user who is initiating the transfer
52+
address user;
53+
/// @dev The chainId of the origin chain
54+
uint256 originChainId;
55+
/// @dev The timestamp by which the order must be opened
56+
uint32 openDeadline;
57+
/// @dev The timestamp by which the order must be filled on the destination chain(s)
58+
uint32 fillDeadline;
59+
/// @dev The unique identifier for this order within this settlement system
60+
bytes32 orderId;
61+
/// @dev The max outputs that the filler will send. It's possible the actual amount depends on the state of the destination
62+
/// chain (destination dutch auction, for instance), so these outputs should be considered a cap on filler liabilities.
63+
Output[] maxSpent;
64+
/// @dev The minimum outputs that must be given to the filler as part of order settlement. Similar to maxSpent, it's possible
65+
/// that special order types may not be able to guarantee the exact amount at open time, so this should be considered
66+
/// a floor on filler receipts.
67+
Output[] minReceived;
68+
/// @dev Each instruction in this array is parameterizes a single leg of the fill. This provides the filler with the information
69+
/// necessary to perform the fill on the destination(s).
70+
FillInstruction[] fillInstructions;
71+
}
72+
73+
/// @notice Tokens that must be received for a valid order fulfillment
74+
struct Output {
75+
/// @dev The address of the ERC20 token on the destination chain
76+
/// @dev address(0) used as a sentinel for the native token
77+
bytes32 token;
78+
/// @dev The amount of the token to be sent
79+
uint256 amount;
80+
/// @dev The address to receive the output tokens
81+
bytes32 recipient;
82+
/// @dev The destination chain for this output
83+
uint256 chainId;
84+
}
85+
86+
/// @title FillInstruction type
87+
/// @notice Instructions to parameterize each leg of the fill
88+
/// @dev Provides all the origin-generated information required to produce a valid fill leg
89+
struct FillInstruction {
90+
/// @dev The contract address that the order is meant to be settled by
91+
uint256 destinationChainId;
92+
/// @dev The contract address that the order is meant to be filled on
93+
bytes32 destinationSettler;
94+
/// @dev The data generated on the origin chain needed by the destinationSettler to process the fill
95+
bytes originData;
96+
}
97+
98+
/// @notice Signals that an order has been opened
99+
/// @param orderId a unique order identifier within this settlement system
100+
/// @param resolvedOrder resolved order that would be returned by resolve if called instead of Open
101+
event Open(bytes32 indexed orderId, ResolvedCrossChainOrder resolvedOrder);
102+
103+
/// @notice Opens a gasless cross-chain order on behalf of a user.
104+
/// @dev To be called by the filler.
105+
/// @dev This method must emit the Open event
106+
/// @param order The GaslessCrossChainOrder definition
107+
/// @param signature The user's signature over the order
108+
/// @param originFillerData Any filler-defined data required by the settler
109+
function openFor(GaslessCrossChainOrder calldata order, bytes calldata signature, bytes calldata originFillerData)
110+
external;
111+
112+
/// @notice Opens a cross-chain order
113+
/// @dev To be called by the user
114+
/// @dev This method must emit the Open event
115+
/// @param order The OnchainCrossChainOrder definition
116+
function open(OnchainCrossChainOrder calldata order) external;
117+
118+
/// @notice Resolves a specific GaslessCrossChainOrder into a generic ResolvedCrossChainOrder
119+
/// @dev Intended to improve standardized integration of various order types and settlement contracts
120+
/// @param order The GaslessCrossChainOrder definition
121+
/// @param originFillerData Any filler-defined data required by the settler
122+
/// @return ResolvedCrossChainOrder hydrated order data including the inputs and outputs of the order
123+
function resolveFor(GaslessCrossChainOrder calldata order, bytes calldata originFillerData)
124+
external
125+
view
126+
returns (ResolvedCrossChainOrder memory);
127+
128+
/// @notice Resolves a specific OnchainCrossChainOrder into a generic ResolvedCrossChainOrder
129+
/// @dev Intended to improve standardized integration of various order types and settlement contracts
130+
/// @param order The OnchainCrossChainOrder definition
131+
/// @return ResolvedCrossChainOrder hydrated order data including the inputs and outputs of the order
132+
function resolve(OnchainCrossChainOrder calldata order) external view returns (ResolvedCrossChainOrder memory);
133+
}

src/interfaces/IERC7683Allocator.sol

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.27;
4+
5+
import {IOriginSettler} from './ERC7683/IOriginSettler.sol';
6+
7+
interface IERC7683Allocator is IOriginSettler {
8+
struct OrderData {
9+
// COMPACT
10+
address arbiter; // The account tasked with verifying and submitting the claim.
11+
address sponsor; // The account to source the tokens from.
12+
uint256 nonce; // A parameter to enforce replay protection, scoped to allocator.
13+
uint256 expires; // The time at which the claim expires.
14+
uint256 id; // The token ID of the ERC6909 token to allocate.
15+
uint256 amount; // The amount of ERC6909 tokens to allocate.
16+
// MANDATE
17+
uint256 chainId; // (implicit arg, included in EIP712 payload)
18+
address tribunal; // (implicit arg, included in EIP712 payload)
19+
address recipient; // Recipient of settled tokens
20+
// uint256 expires; // Mandate expiration timestamp
21+
address token; // Settlement token (address(0) for native)
22+
uint256 minimumAmount; // Minimum settlement amount
23+
uint256 baselinePriorityFee; // Base fee threshold where scaling kicks in
24+
uint256 scalingFactor; // Fee scaling multiplier (1e18 baseline)
25+
uint256[] decayCurve; // Block durations, fill increases, & claim decreases.
26+
bytes32 salt; // Replay protection parameter
27+
// ADDITIONAL INPUT
28+
uint256 targetBlock; // The block number at the target chain on which the PGA is executed / the reverse dutch auction starts.
29+
uint256 maximumBlocksAfterTarget; // Blocks after target block that are still fillable.
30+
}
31+
32+
struct OrderDataGasless {
33+
// COMPACT
34+
address arbiter; // The account tasked with verifying and submitting the claim.
35+
// address sponsor; // The account to source the tokens from.
36+
// uint256 nonce; // A parameter to enforce replay protection, scoped to allocator.
37+
// uint256 expires; // The time at which the claim expires.
38+
uint256 id; // The token ID of the ERC6909 token to allocate.
39+
uint256 amount; // The amount of ERC6909 tokens to allocate.
40+
// MANDATE
41+
uint256 chainId; // (implicit arg, included in EIP712 payload)
42+
address tribunal; // (implicit arg, included in EIP712 payload)
43+
address recipient; // Recipient of settled tokens
44+
// uint256 expires; // Mandate expiration timestamp
45+
address token; // Settlement token (address(0) for native)
46+
uint256 minimumAmount; // Minimum settlement amount
47+
uint256 baselinePriorityFee; // Base fee threshold where scaling kicks in
48+
uint256 scalingFactor; // Fee scaling multiplier (1e18 baseline)
49+
uint256[] decayCurve; // Block durations, fill increases, & claim decreases.
50+
bytes32 salt; // Replay protection parameter
51+
}
52+
53+
error InvalidOriginSettler(address originSettler, address expectedOriginSettler);
54+
error InvalidOrderDataType(bytes32 orderDataType, bytes32 expectedOrderDataType);
55+
error InvalidNonce(uint256 nonce);
56+
error NonceAlreadyInUse(uint256 nonce);
57+
error InvalidSignature(address signer, address expectedSigner);
58+
error InvalidRegistration(address sponsor, bytes32 claimHash);
59+
error InvalidSponsor(address sponsor, address expectedSponsor);
60+
61+
/// @inheritdoc IOriginSettler
62+
function openFor(GaslessCrossChainOrder calldata order, bytes calldata signature, bytes calldata originFillerData)
63+
external;
64+
65+
/// @inheritdoc IOriginSettler
66+
/// @dev Requires the user to have previously registered the claim hash on the compact
67+
function open(OnchainCrossChainOrder calldata order) external;
68+
69+
/// @inheritdoc IOriginSettler
70+
function resolveFor(GaslessCrossChainOrder calldata order, bytes calldata originFillerData)
71+
external
72+
view
73+
returns (ResolvedCrossChainOrder memory);
74+
75+
/// @inheritdoc IOriginSettler
76+
function resolve(OnchainCrossChainOrder calldata order) external view returns (ResolvedCrossChainOrder memory);
77+
78+
/// @notice Returns the type string of the compact including the witness
79+
function getCompactWitnessTypeString() external pure returns (string memory);
80+
81+
/// @notice Checks if a nonce is free to be used
82+
/// @dev The nonce is the most significant 96 bits. The least significant 160 bits must be the sponsor address
83+
function checkNonce(address sponsor_, uint256 nonce_) external view returns (bool nonceFree_);
84+
85+
/// @notice Creates the filler data for the open event to be used on the IDestinationSettler
86+
/// @param claimant_ The address claiming the origin tokens after a successful fill (typically the address of the filler)
87+
function createFillerData(address claimant_) external pure returns (bytes memory fillerData);
88+
}

0 commit comments

Comments
 (0)