Skip to content

Commit 2b2721f

Browse files
Update briefcase
Changes: M src/deployers/v2-core/UniswapV2FactoryDeployer.sol A src/protocols/uniswapx/v4/base/ReactorStructs.sol A src/protocols/uniswapx/v4/hooks/dca/DCAStructs.sol A src/protocols/uniswapx/v4/interfaces/IAuctionResolver.sol A src/protocols/uniswapx/v4/interfaces/IDCAHook.sol A src/protocols/uniswapx/v4/interfaces/IHook.sol A src/protocols/uniswapx/v4/interfaces/IReactor.sol
1 parent 41b823e commit 2b2721f

File tree

7 files changed

+392
-1
lines changed

7 files changed

+392
-1
lines changed

src/deployers/v2-core/UniswapV2FactoryDeployer.sol

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
pragma solidity ^0.8.0;
3+
4+
import {InputToken, OutputToken} from '../../base/ReactorStructs.sol';
5+
import {IAuctionResolver} from '../interfaces/IAuctionResolver.sol';
6+
import {IPostExecutionHook, IPreExecutionHook} from '../interfaces/IHook.sol';
7+
import {IReactor} from '../interfaces/IReactor.sol';
8+
9+
/// @dev generic order information
10+
/// should be included as the first field in any concrete order types
11+
struct OrderInfo {
12+
// The address of the reactor that this order is targeting
13+
// Note that this must be included in every order so the swapper
14+
// signature commits to the specific reactor that they trust to fill their order properly
15+
IReactor reactor;
16+
// The address of the user which created the order
17+
// Note that this must be included so that order hashes are unique by swapper
18+
address swapper;
19+
// The nonce of the order, allowing for signature replay protection and cancellation
20+
uint256 nonce;
21+
// The timestamp after which this order is no longer valid
22+
uint256 deadline;
23+
// Pre-execution hook contract
24+
IPreExecutionHook preExecutionHook;
25+
// Encoded pre-execution hook data
26+
bytes preExecutionHookData;
27+
// Post-execution hook contract
28+
IPostExecutionHook postExecutionHook;
29+
// Encoded post-execution hook data
30+
bytes postExecutionHookData;
31+
// Auction resolver contract
32+
IAuctionResolver auctionResolver;
33+
}
34+
35+
/// @dev generic concrete order that specifies exact tokens which need to be sent and received
36+
struct ResolvedOrder {
37+
OrderInfo info;
38+
InputToken input;
39+
OutputToken[] outputs;
40+
bytes sig;
41+
bytes32 hash; // The witness hash that includes resolver address and full order (what was signed)
42+
address auctionResolver;
43+
// Witness type string provided by resolver for Permit2 verification
44+
string witnessTypeString;
45+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
pragma solidity ^0.8.0;
3+
4+
import {IAllowanceTransfer} from '../../../../permit2/interfaces/IAllowanceTransfer.sol';
5+
6+
struct FeedInfo {
7+
bytes32 feedId;
8+
address feed_address;
9+
string feedType;
10+
}
11+
12+
struct DCAIntent {
13+
address swapper;
14+
uint256 nonce;
15+
uint256 chainId;
16+
address hookAddress; // DCA contract's address
17+
bool isExactIn; // EXACT_IN or EXACT_OUT
18+
address inputToken; // Token to sell
19+
address outputToken; // Token to buy
20+
address cosigner; // TEE address that authorizes executions
21+
uint256 minPeriod; // Minimum seconds between chunks
22+
uint256 maxPeriod; // Maximum seconds between chunks
23+
uint256 minChunkSize; // Min input or min output per chunk
24+
uint256 maxChunkSize; // Max input or max output per chunk
25+
uint256 minPrice; // Minimum price (output/input * 1e18)
26+
uint256 deadline; // Intent expiration timestamp
27+
OutputAllocation[] outputAllocations; // Distribution of output tokens
28+
PrivateIntent privateIntent; // Private execution parameters - included in EIP-712 signature but zeroed on-chain, only hash revealed
29+
}
30+
31+
struct PrivateIntent {
32+
uint256 totalAmount; // Total amount on the exact side (input for EXACT_IN, output for EXACT_OUT)
33+
uint256 exactFrequency;
34+
uint256 numChunks;
35+
bytes32 salt;
36+
FeedInfo[] oracleFeeds; // Array of possible oracle feeds
37+
}
38+
39+
struct OutputAllocation {
40+
address recipient; // 20 bytes
41+
uint16 basisPoints; // 2 bytes - Out of 10000 (100% = 10000), packed in same slot
42+
}
43+
44+
struct DCAOrderCosignerData {
45+
address swapper; // 20 bytes, slot 1
46+
uint96 nonce; // 12 bytes
47+
uint160 execAmount; // 20 bytes, slot 2
48+
uint96 orderNonce; // 12 bytes Unique execution chunk identifier
49+
uint160 limitAmount; // 20 bytes, slot 3 (12 bytes padding)
50+
// uint160 matches Permit2's transferFrom amount limit
51+
}
52+
53+
struct DCAExecutionState {
54+
uint128 executedChunks; // 16 bytes slot 1 (perfectly packed)
55+
uint120 lastExecutionTime; // 15 bytes
56+
bool cancelled; // 1 byte
57+
uint256 totalInputExecuted; // 32 bytes slot 2 - Cumulative input amount
58+
uint256 totalOutput; // 32 bytes slot 3 - Cumulative output amount
59+
}
60+
61+
struct PermitData {
62+
bool hasPermit; // Whether a permit signature is included
63+
IAllowanceTransfer.PermitSingle permitSingle; // The permit data (if hasPermit is true)
64+
bytes signature; // The permit signature (if hasPermit is true)
65+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
pragma solidity >=0.6.2;
3+
4+
import {SignedOrder} from '../../base/ReactorStructs.sol';
5+
import {ResolvedOrder} from '../base/ReactorStructs.sol';
6+
7+
/// @notice Interface for auction mechanism resolvers (for UnifiedReactor)
8+
interface IAuctionResolver {
9+
/// @notice Resolves a signed order into a resolved order based on auction rules
10+
/// @param signedOrder The signed order with auction-specific order data (resolver address already stripped)
11+
/// @return resolvedOrder The resolved order with final amounts
12+
function resolve(SignedOrder calldata signedOrder) external view returns (ResolvedOrder memory resolvedOrder);
13+
14+
/// @notice Get the Permit2 order type string for EIP-712 signature verification
15+
/// @return orderType The EIP-712 order type string for this resolver's orders
16+
function getPermit2OrderType() external pure returns (string memory);
17+
}
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
pragma solidity >=0.6.2;
3+
4+
import {DCAExecutionState} from '../hooks/dca/DCAStructs.sol';
5+
import {IPreExecutionHook} from './IHook.sol';
6+
7+
/// @title IDCAHook
8+
/// @notice Interface for the DCA (Dollar-Cost Averaging) hook contract
9+
/// @dev Extends IPreExecutionHook to enable periodic execution of DCA intents
10+
interface IDCAHook is IPreExecutionHook {
11+
/// @notice Thrown when attempting to cancel an already cancelled intent
12+
/// @param intentId The identifier of the intent that was already cancelled
13+
error IntentAlreadyCancelled(bytes32 intentId);
14+
15+
/// @notice Thrown when the swapper signature is invalid
16+
/// @param recoveredSigner The address recovered from the signature
17+
/// @param expectedSwapper The expected swapper address
18+
error InvalidSwapperSignature(address recoveredSigner, address expectedSwapper);
19+
20+
/// @notice Thrown when the cosigner signature is invalid
21+
/// @param recoveredCosigner The address recovered from the signature
22+
/// @param expectedCosigner The expected cosigner address
23+
error InvalidCosignerSignature(address recoveredCosigner, address expectedCosigner);
24+
25+
/// @notice Thrown when the cosigner data swapper doesn't match the intent swapper
26+
/// @param cosignerSwapper The swapper address in cosigner data
27+
/// @param intentSwapper The swapper address in the intent
28+
error CosignerSwapperMismatch(address cosignerSwapper, address intentSwapper);
29+
30+
/// @notice Thrown when the cosigner data nonce doesn't match the intent nonce
31+
/// @param cosignerNonce The nonce in cosigner data
32+
/// @param intentNonce The nonce in the intent
33+
error CosignerNonceMismatch(uint96 cosignerNonce, uint256 intentNonce);
34+
35+
/// @notice Thrown when output allocations array is empty
36+
error EmptyAllocations();
37+
38+
/// @notice Thrown when an output allocation has zero basis points
39+
error ZeroAllocation();
40+
41+
/// @notice Thrown when allocations don't sum to exactly 100% (10000 basis points)
42+
/// @param totalBasisPoints The actual sum of basis points
43+
error AllocationsNot100Percent(uint256 totalBasisPoints);
44+
45+
/// @notice Thrown when multiple allocations have the same recipient
46+
/// @param recipient The duplicate recipient address
47+
error DuplicateRecipient(address recipient);
48+
49+
/// @notice Thrown when the hook address doesn't match the expected hook
50+
/// @param providedHook The hook address provided in the intent
51+
/// @param expectedHook The expected hook address (this contract)
52+
error WrongHook(address providedHook, address expectedHook);
53+
54+
/// @notice Thrown when the chain ID doesn't match the current chain
55+
/// @param providedChainId The chain ID provided in the intent
56+
/// @param currentChainId The current blockchain's chain ID
57+
error WrongChain(uint256 providedChainId, uint256 currentChainId);
58+
59+
/// @notice Thrown when the swapper address doesn't match between intent and order
60+
/// @param orderSwapper The swapper address in the resolved order
61+
/// @param intentSwapper The swapper address in the intent
62+
error SwapperMismatch(address orderSwapper, address intentSwapper);
63+
64+
/// @notice Thrown when the input token doesn't match the intent
65+
/// @param orderInputToken The input token in the resolved order
66+
/// @param intentInputToken The input token in the intent
67+
error WrongInputToken(address orderInputToken, address intentInputToken);
68+
69+
/// @notice Thrown when an output token doesn't match the intent
70+
/// @param outputToken The output token in the resolved order
71+
/// @param expectedToken The expected output token from the intent
72+
error WrongOutputToken(address outputToken, address expectedToken);
73+
74+
/// @notice Thrown when chunk size is below minimum allowed
75+
/// @param amount The actual chunk size (input for EXACT_IN, output for EXACT_OUT)
76+
/// @param minChunkSize The minimum allowed chunk size
77+
error ChunkSizeBelowMin(uint256 amount, uint256 minChunkSize);
78+
79+
/// @notice Thrown when chunk size exceeds maximum allowed
80+
/// @param amount The actual chunk size (input for EXACT_IN, output for EXACT_OUT)
81+
/// @param maxChunkSize The maximum allowed chunk size
82+
error ChunkSizeAboveMax(uint256 amount, uint256 maxChunkSize);
83+
84+
/// @notice Thrown when input amount doesn't match execAmount (EXACT_IN)
85+
/// @param inputAmount The input amount in the order
86+
/// @param execAmount The expected exec amount from cosigner data
87+
error InputAmountMismatch(uint256 inputAmount, uint256 execAmount);
88+
89+
/// @notice Thrown when input amount is zero (EXACT_OUT)
90+
error ZeroInput();
91+
92+
/// @notice Thrown when input exceeds cosigner's limit (EXACT_OUT)
93+
/// @param inputAmount The actual input amount
94+
/// @param limitAmount The cosigner's limit amount
95+
error InputAboveLimit(uint256 inputAmount, uint256 limitAmount);
96+
97+
/// @notice Thrown when attempting to execute a cancelled intent
98+
/// @param intentId The identifier of the cancelled intent
99+
error IntentIsCancelled(bytes32 intentId);
100+
101+
/// @notice Thrown when the intent has expired
102+
/// @param currentTime The current block timestamp
103+
/// @param deadline The intent's deadline
104+
error IntentExpired(uint256 currentTime, uint256 deadline);
105+
106+
/// @notice Thrown when the order nonce doesn't match the expected nonce
107+
/// @param providedNonce The nonce provided in the cosigner data
108+
/// @param expectedNonce The expected next nonce for the intent
109+
error WrongChunkNonce(uint96 providedNonce, uint96 expectedNonce);
110+
111+
/// @notice Thrown when execution is attempted too soon after the last execution
112+
/// @param elapsed The time elapsed since last execution
113+
/// @param minPeriod The minimum required period between executions
114+
error TooSoon(uint256 elapsed, uint256 minPeriod);
115+
116+
/// @notice Thrown when execution is attempted too late after the last execution
117+
/// @param elapsed The time elapsed since last execution
118+
/// @param maxPeriod The maximum allowed period between executions
119+
error TooLate(uint256 elapsed, uint256 maxPeriod);
120+
121+
/// @notice Thrown when the execution price is below the minimum price floor
122+
/// @param executionPrice The actual execution price (scaled by 1e18)
123+
/// @param minPrice The minimum acceptable price (scaled by 1e18)
124+
error PriceBelowMin(uint256 executionPrice, uint256 minPrice);
125+
126+
/// @notice Thrown when output allocation doesn't match expected amount
127+
/// @param recipient The recipient address
128+
/// @param actual The actual amount allocated to the recipient
129+
/// @param expected The expected amount for the recipient
130+
error AllocationMismatch(address recipient, uint256 actual, uint256 expected);
131+
132+
/// @notice Thrown when total output is insufficient (EXACT_IN)
133+
/// @param totalOutput The total output amount produced
134+
/// @param limitAmount The minimum required output amount
135+
error InsufficientOutput(uint256 totalOutput, uint256 limitAmount);
136+
137+
/// @notice Thrown when total output doesn't match expected amount (EXACT_OUT)
138+
/// @param totalOutput The actual total output amount
139+
/// @param execAmount The expected exact output amount
140+
error WrongTotalOutput(uint256 totalOutput, uint256 execAmount);
141+
142+
/// @notice Emitted when an intent is cancelled
143+
/// @param intentId The unique identifier of the intent
144+
/// @param swapper The address of the swapper who cancelled the intent
145+
event IntentCancelled(bytes32 indexed intentId, address indexed swapper);
146+
147+
/// @notice Emitted when a DCA chunk is executing
148+
/// @param intentId The unique identifier of the intent
149+
/// @param execAmount The amount being executed (input for EXACT_IN, output for EXACT_OUT)
150+
/// @param limitAmount The limit amount (min output for EXACT_IN, max input for EXACT_OUT)
151+
/// @param totalInputExecuted Cumulative input amount after this execution
152+
/// @param totalOutput Cumulative output amount after this execution
153+
event ChunkExecuted(
154+
bytes32 indexed intentId,
155+
uint256 execAmount,
156+
uint256 limitAmount,
157+
uint256 totalInputExecuted,
158+
uint256 totalOutput
159+
);
160+
161+
/// @notice Cancel a single DCA intent
162+
/// @param nonce The nonce of the intent to cancel
163+
/// @dev Only callable by the intent owner (verified via msg.sender and nonce)
164+
function cancelIntent(uint256 nonce) external;
165+
166+
/// @notice Cancel multiple DCA intents in a single transaction
167+
/// @param nonces Array of intent nonces to cancel
168+
/// @dev Only callable by the intent owner for each intent (verified via msg.sender and nonces)
169+
function cancelIntents(uint256[] calldata nonces) external;
170+
171+
/// @notice Compute the unique identifier for an intent
172+
/// @param swapper The address of the swapper
173+
/// @param nonce The nonce of the intent
174+
/// @return intentId The computed intent identifier
175+
function computeIntentId(address swapper, uint256 nonce) external pure returns (bytes32);
176+
177+
/// @notice Get the execution state for a specific intent
178+
/// @param intentId The unique identifier of the intent
179+
/// @return state The execution state of the intent
180+
function getExecutionState(bytes32 intentId) external view returns (DCAExecutionState memory state);
181+
182+
/// @notice Check if an intent is currently active (not cancelled and within period/deadline)
183+
/// @dev Semantics:
184+
/// - Uninitialized intents (no executed chunks) are considered active unless cancelled or past deadline.
185+
/// - maxPeriod is enforced only after the first execution; before that, it is ignored.
186+
/// - A maxPeriod of 0 means no upper bound; a deadline of 0 means no deadline.
187+
/// @param intentId The unique identifier of the intent
188+
/// @param maxPeriod The maximum allowed seconds since last execution (0 = no upper bound)
189+
/// @param deadline The intent expiration timestamp (0 = no deadline)
190+
/// @return active True if the intent is active, false otherwise
191+
function isIntentActive(bytes32 intentId, uint256 maxPeriod, uint256 deadline) external view returns (bool active);
192+
193+
/// @notice Get the next expected nonce for an intent
194+
/// @param intentId The unique identifier of the intent
195+
/// @return nextNonce The next nonce that should be used for this intent
196+
function getNextNonce(bytes32 intentId) external view returns (uint96 nextNonce);
197+
198+
/// @notice Get comprehensive statistics for an intent
199+
/// @param intentId The unique identifier of the intent
200+
/// @return totalChunks Number of chunks executed
201+
/// @return totalInput Total input amount executed
202+
/// @return totalOutput Total output amount received
203+
/// @return lastExecutionTime Timestamp of last execution
204+
function getIntentStatistics(bytes32 intentId)
205+
external
206+
view
207+
returns (uint256 totalChunks, uint256 totalInput, uint256 totalOutput, uint256 lastExecutionTime);
208+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity >=0.6.2;
3+
4+
import {ResolvedOrder} from '../base/ReactorStructs.sol';
5+
6+
/// @notice Hook to be called before order execution, allowing state modifications
7+
interface IPreExecutionHook {
8+
/// @notice Called by the reactor before order execution for custom validation and state changes
9+
/// @param filler The filler of the order
10+
/// @param resolvedOrder The resolved order to fill
11+
function preExecutionHook(address filler, ResolvedOrder calldata resolvedOrder) external;
12+
}
13+
14+
/// @notice Hook to be called after transferring output tokens, enabling chained actions
15+
interface IPostExecutionHook {
16+
/// @notice Called by the reactor after order execution for chained actions
17+
/// @param filler The filler of the order
18+
/// @param resolvedOrder The resolved order that was filled
19+
function postExecutionHook(address filler, ResolvedOrder calldata resolvedOrder) external;
20+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
pragma solidity >=0.6.2;
3+
4+
import {SignedOrder} from '../../base/ReactorStructs.sol';
5+
6+
/// @notice Interface for order execution reactors
7+
interface IReactor {
8+
/// @notice thrown when an auction resolver is not set
9+
error EmptyAuctionResolver();
10+
/// @notice thrown when the order targets a different reactor
11+
error InvalidReactor();
12+
/// @notice thrown when the order's deadline has passed
13+
error DeadlinePassed();
14+
/// @notice thrown when a pre-execution hook is not set
15+
error MissingPreExecutionHook();
16+
/// @notice thrown when resolver addr encoded in SignedOrder doesn't match signed resolver in OrderInfo
17+
error ResolverMismatch();
18+
19+
/// @notice Execute a single order
20+
/// @param order The order definition and valid signature to execute
21+
function execute(SignedOrder calldata order) external payable;
22+
23+
/// @notice Execute a single order using the given callback data
24+
/// @param order The order definition and valid signature to execute
25+
/// @param callbackData The callbackData to pass to the callback
26+
function executeWithCallback(SignedOrder calldata order, bytes calldata callbackData) external payable;
27+
28+
/// @notice Execute the given orders at once
29+
/// @param orders The order definitions and valid signatures to execute
30+
function executeBatch(SignedOrder[] calldata orders) external payable;
31+
32+
/// @notice Execute the given orders at once using a callback with the given callback data
33+
/// @param orders The order definitions and valid signatures to execute
34+
/// @param callbackData The callbackData to pass to the callback
35+
function executeBatchWithCallback(SignedOrder[] calldata orders, bytes calldata callbackData) external payable;
36+
}

0 commit comments

Comments
 (0)