Skip to content

Commit

Permalink
feat(SpokePool): Add depositExclusive() function to support exclusive…
Browse files Browse the repository at this point in the history
… order routing (#514)

* feat(SpokePool): Add depositExclusive() function to support exclusive order routing

We want to support a user flow where a depositor can be paired off-chain with an `exclusiveRelayer` and give them a very short exclusivity window (think ~2-4 seconds) but we don't want the depositor to have to consider the latency between their deposit txn being submitted to the mempool and when it is mined. Instead, good depositor UX essentially requires that an offset can be specified so that a depositor can specify the amout of exclusivity the filler can get after a deposit is mined.

* forge
  • Loading branch information
nicholaspai authored Jun 13, 2024
1 parent 9402371 commit c14a801
Show file tree
Hide file tree
Showing 10 changed files with 277 additions and 173 deletions.
67 changes: 67 additions & 0 deletions contracts/SpokePool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,73 @@ abstract contract SpokePool is
);
}

/**
* @notice Submits deposit and sets exclusivityDeadline to current time plus some offset. This function is
* designed to be called by users who want to set an exclusive relayer for some amount of time after their deposit
* transaction is mined.
* @notice If exclusivtyDeadlineOffset > 0, then exclusiveRelayer must be set to a valid address, which is a
* requirement imposed by depositV3().
* @param depositor The account credited with the deposit who can request to "speed up" this deposit by modifying
* the output amount, recipient, and message.
* @param recipient The account receiving funds on the destination chain. Can be an EOA or a contract. If
* the output token is the wrapped native token for the chain, then the recipient will receive native token if
* an EOA or wrapped native token if a contract.
* @param inputToken The token pulled from the caller's account and locked into this contract to
* initiate the deposit. The equivalent of this token on the relayer's repayment chain of choice will be sent
* as a refund. If this is equal to the wrapped native token then the caller can optionally pass in native token as
* msg.value, as long as msg.value = inputTokenAmount.
* @param outputToken The token that the relayer will send to the recipient on the destination chain. Must be an
* ERC20.
* @param inputAmount The amount of input tokens to pull from the caller's account and lock into this contract.
* This amount will be sent to the relayer on their repayment chain of choice as a refund following an optimistic
* challenge window in the HubPool, plus a system fee.
* @param outputAmount The amount of output tokens that the relayer will send to the recipient on the destination.
* @param destinationChainId The destination chain identifier. Must be enabled along with the input token
* as a valid deposit route from this spoke pool or this transaction will revert.
* @param exclusiveRelayer The relayer that will be exclusively allowed to fill this deposit before the
* exclusivity deadline timestamp.
* @param quoteTimestamp The HubPool timestamp that is used to determine the system fee paid by the depositor.
* This must be set to some time between [currentTime - depositQuoteTimeBuffer, currentTime]
* where currentTime is block.timestamp on this chain or this transaction will revert.
* @param fillDeadline The deadline for the relayer to fill the deposit. After this destination chain timestamp,
* the fill will revert on the destination chain. Must be set between [currentTime, currentTime + fillDeadlineBuffer]
* where currentTime is block.timestamp on this chain or this transaction will revert.
* @param exclusivityDeadlineOffset Added to the current time to set the exclusive reayer deadline,
* which is the deadline for the exclusiveRelayer to fill the deposit. After this destination chain timestamp,
* anyone can fill the deposit.
* @param message The message to send to the recipient on the destination chain if the recipient is a contract.
* If the message is not empty, the recipient contract must implement handleV3AcrossMessage() or the fill will revert.
*/
function depositExclusive(
address depositor,
address recipient,
address inputToken,
address outputToken,
uint256 inputAmount,
uint256 outputAmount,
uint256 destinationChainId,
address exclusiveRelayer,
uint32 quoteTimestamp,
uint32 fillDeadline,
uint32 exclusivityDeadlineOffset,
bytes calldata message
) public payable {
depositV3(
depositor,
recipient,
inputToken,
outputToken,
inputAmount,
outputAmount,
destinationChainId,
exclusiveRelayer,
quoteTimestamp,
fillDeadline,
uint32(getCurrentTime()) + exclusivityDeadlineOffset,
message
);
}

/**
* @notice Depositor can use this function to signal to relayer to use updated output amount, recipient,
* and/or message.
Expand Down
40 changes: 20 additions & 20 deletions storage-layouts/Arbitrum_SpokePool.json
Original file line number Diff line number Diff line change
@@ -1,79 +1,79 @@
{
"storage": [
{
"astId": 65577,
"astId": 65627,
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
"label": "_initialized",
"offset": 0,
"slot": "0",
"type": "t_uint8"
},
{
"astId": 65580,
"astId": 65630,
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
"label": "_initializing",
"offset": 1,
"slot": "0",
"type": "t_bool"
},
{
"astId": 65559,
"astId": 65609,
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
"label": "__gap",
"offset": 0,
"slot": "1",
"type": "t_array(t_uint256)50_storage"
},
{
"astId": 65875,
"astId": 65925,
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
"label": "__gap",
"offset": 0,
"slot": "51",
"type": "t_array(t_uint256)50_storage"
},
{
"astId": 65891,
"astId": 65941,
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
"label": "_status",
"offset": 0,
"slot": "101",
"type": "t_uint256"
},
{
"astId": 65960,
"astId": 66010,
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
"label": "__gap",
"offset": 0,
"slot": "102",
"type": "t_array(t_uint256)49_storage"
},
{
"astId": 17991,
"astId": 18041,
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
"label": "__gap",
"offset": 0,
"slot": "151",
"type": "t_array(t_uint256)1000_storage"
},
{
"astId": 17723,
"astId": 17773,
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
"label": "_HASHED_NAME",
"offset": 0,
"slot": "1151",
"type": "t_bytes32"
},
{
"astId": 17725,
"astId": 17775,
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
"label": "_HASHED_VERSION",
"offset": 0,
"slot": "1152",
"type": "t_bytes32"
},
{
"astId": 17824,
"astId": 17874,
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
"label": "__gap",
"offset": 0,
Expand Down Expand Up @@ -102,7 +102,7 @@
"label": "DEPRECATED_wrappedNativeToken",
"offset": 0,
"slot": "2155",
"type": "t_contract(WETH9Interface)13461"
"type": "t_contract(WETH9Interface)13511"
},
{
"astId": 5945,
Expand Down Expand Up @@ -142,7 +142,7 @@
"label": "rootBundles",
"offset": 0,
"slot": "2156",
"type": "t_array(t_struct(RootBundle)14038_storage)dyn_storage"
"type": "t_array(t_struct(RootBundle)14088_storage)dyn_storage"
},
{
"astId": 5961,
Expand Down Expand Up @@ -193,7 +193,7 @@
"type": "t_mapping(t_bytes32,t_uint256)"
},
{
"astId": 7882,
"astId": 7932,
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
"label": "__gap",
"offset": 0,
Expand Down Expand Up @@ -223,11 +223,11 @@
"label": "address",
"numberOfBytes": "20"
},
"t_array(t_struct(RootBundle)14038_storage)dyn_storage": {
"t_array(t_struct(RootBundle)14088_storage)dyn_storage": {
"encoding": "dynamic_array",
"label": "struct SpokePoolInterface.RootBundle[]",
"numberOfBytes": "32",
"base": "t_struct(RootBundle)14038_storage"
"base": "t_struct(RootBundle)14088_storage"
},
"t_array(t_uint256)1000_storage": {
"encoding": "inplace",
Expand Down Expand Up @@ -263,7 +263,7 @@
"label": "bytes32",
"numberOfBytes": "32"
},
"t_contract(WETH9Interface)13461": {
"t_contract(WETH9Interface)13511": {
"encoding": "inplace",
"label": "contract WETH9Interface",
"numberOfBytes": "20"
Expand Down Expand Up @@ -310,29 +310,29 @@
"numberOfBytes": "32",
"value": "t_uint256"
},
"t_struct(RootBundle)14038_storage": {
"t_struct(RootBundle)14088_storage": {
"encoding": "inplace",
"label": "struct SpokePoolInterface.RootBundle",
"numberOfBytes": "96",
"members": [
{
"astId": 14031,
"astId": 14081,
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
"label": "slowRelayRoot",
"offset": 0,
"slot": "0",
"type": "t_bytes32"
},
{
"astId": 14033,
"astId": 14083,
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
"label": "relayerRefundRoot",
"offset": 0,
"slot": "1",
"type": "t_bytes32"
},
{
"astId": 14037,
"astId": 14087,
"contract": "contracts/Arbitrum_SpokePool.sol:Arbitrum_SpokePool",
"label": "claimedBitmap",
"offset": 0,
Expand Down
Loading

0 comments on commit c14a801

Please sign in to comment.