From 46e84c33d787f3690f75418ca3a44ee5f28be3f4 Mon Sep 17 00:00:00 2001 From: TucksonDev Date: Thu, 24 Oct 2024 20:17:09 +0100 Subject: [PATCH 01/15] Add how to use timeboost --- .../how-to-use-timeboost.mdx | 371 ++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100644 arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx diff --git a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx new file mode 100644 index 000000000..791d08ed0 --- /dev/null +++ b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx @@ -0,0 +1,371 @@ +--- +title: 'How to use Timeboost' +description: Learn how to use timeboost +author: jose-franco +content_type: how-to +--- + +Timeboost is a new transaction ordering policy for Arbitrum chains where any participant can bid for the right to access an express lane on the sequencer for faster transaction inclusion. + +In this how-to, you'll learn how to bid for the right to use the express lane, how to submit transactions to it, and how to transfer that right to someone else. To learn more about Timeboost, refer to the gentle introduction. + +This how-to assumes that you're familiar with: + +- [How Timeboost works](#) +- [viem](https://viem.sh/), since the snippets of code present in the how-to use this library + +## How to submit bids for the right to be the express lane controller + +To use the express lane for faster transaction inclusion, we must win an auction for the right to be the express lane controller for a specific round. + +::::info + +Remember that, by default, each round lasts 60 seconds, and the auction for a specific round closes 15 seconds before the round starts. These default values can be configured in a chain with the `roundDurationSeconds` and `auctionClosingSeconds` parameters respectively. + +:::: + +Auctions are held in an auction contract, and bids are submitted to an autonomous auctioneer, that also communicates with the contract. Let's take a look at the process of submitting bids and finding out the winner of an auction. + +### Step 0: pre-requirements + +To run the following steps, we'll need this information: + +- Address of the auction contract +- Endpoint of the autonomous auctioneer + +### Step 1: deposit funds into the auction contract + +Before bidding on an auction, we need to deposit funds in the auction contract. These funds are deposited in the form of the ERC-20 token used to bid, also known as, the `bidding token`. We will be able to bid for an amount that is equal to or less than the tokens we have deposited in the auction contract. + +To see the amount of tokens we have deposited in the auction contract, we can call the function `balanceOf` in the auction contract: + +```tsx +const depositedBalance = await publicClient.readContract({ + address: auctionContractAddress, + abi: auctionContractAbi, + functionName: 'balanceOf', + args: [address], +}); +console.log(`Current balance of ${address} in auction contract: ${depositedBalance}`); +``` + +If we want to deposit more funds to the auction contract, we first need to know what the bidding token is. To obtain the address of the bidding token, we can call the function `biddingToken` in the auction contract: + +```tsx +const biddingTokenContractAddress = await publicClient.readContract({ + address: auctionContractAddress, + abi: auctionContractAbi, + functionName: 'biddingToken', +}); +console.log(`biddingToken: ${biddingTokenContractAddress}`); +``` + + + +Once we know what the bidding token is, we can deposit funds to the auction contract by calling the function `deposit` of the contract, after having it approved as spender of the amount we want to deposit: + +```tsx +// Approving spending tokens +const approveHash = await walletClient.writeContract({ + account, + address: biddingTokenContractAddress, + abi: parseAbi(['function approve(address,uint256)']), + functionName: 'approve', + args: [auctionContract, amountToDeposit], +}); +console.log(`Approve transaction sent: ${approveHash}`); + +// Making the deposit +const depositHash = await walletClient.writeContract({ + account, + address: auctionContractAddress, + abi: auctionContractAbi, + functionName: 'deposit', + args: [amountToDeposit], +}); +console.log(`Deposit transaction sent: ${depositHash}`); +``` + +### Step 2: submit bids + +Once we have deposited funds into the auction contract, we can start submitting bids for the current auction round. + +We can obtain the current round by calling the function `currentRound` in the auction contract: + +```tsx +const currentRound = await publicClient.readContract({ + address: auctionContractAddress, + abi: auctionContractAbi, + functionName: 'currentRound', +}); +console.log(`Current round: ${currentRound}`); +``` + +This is the current round that's running. And, at the same time, the auction for the next round might be open. For example, if `currentRound` is 10, that means that the auction for round 11 is happening right now. To check whether or not that auction is open, we can call the function `isAuctionRoundClosed` of the auction contract: + +```tsx +let currentAuctionRoundIsClosed = await publicClient.readContract({ + address: auctionContractAddress, + abi: auctionContractAbi, + functionName: 'isAuctionRoundClosed', +}); +``` + + + +Once we know what is the current round we can bid for (`currentRound + 1`) and we have verified that the auction is still open (`!currentAuctionRoundIsClosed`), we can submit a bid. + +Bids are submitted to the autonomous auctioneer endpoint. We need to send a `auctioneer_submitBid` request with the following information: + +- chain id +- address of the express lane controller candidate (for example, our address if we want to be the express lane controller) +- address of the auction contract +- round we are bidding for (in our example, `currentRound + 1`) +- amount in wei of the deposit ERC-20 token to bid +- signature (explained below) + +Let's see an example of a call to this RPC method: + +```tsx +const currentAuctionRound = currentRound + 1; +const hexChainId: `0x${string}` = `0x${Number(publicClient.chain.id).toString(16)}`; + +const res = await fetch(, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + jsonrpc: '2.0', + id: 'submit-bid', + method: 'auctioneer_submitBid', + params: [ + { + chainId: hexChainId, + expressLaneController: address, + auctionContractAddress: auctionContractAddress, + round: `0x${currentAuctionRound.toString(16)}`, + amount: `0x${Number(amountToBid).toString(16)}`, + signature: signature, + }, + ], + }), +}); +``` + +The signature that needs to be sent is an Ethereum signature over the bytes encoding of the following information: + +- Hash of `keccak256("TIMEBOOST_BID")` +- Chain id in hexadecimal, padded to 32 bytes +- Auction contract address +- Auction round number in hexadecimal, padded to 8 bytes +- Amount to bid in hexadecimal, padded to 32 bytes +- Address of the express lane controller candidate + +Here's an example to produce that signature: + +```tsx +const currentAuctionRound = currentRound + 1; +const hexChainId: `0x${string}` = `0x${Number(publicClient.chain.id).toString(16)}`; + +const signatureData = concat([ + keccak256(toHex('TIMEBOOST_BID')), + pad(hexChainId), + auctionContractAddress, + toHex(numberToBytes(currentAuctionRound, { size: 8 })), + toHex(numberToBytes(amountToBid, { size: 32 })), + address, +]); +const signature = await account.signMessage({ + message: { raw: signatureData }, +}); +``` + +::::info + +You can also call the function `getBidBytes` in the auction contract to obtain the `signatureData` , specifying the `round`, `amountToBid` and `address`. + +:::: + +When sending the request, the autonomous auctioneer will return an empty result with an HTTP status `200` if it received the request correctly. If the result returned contains an error message, it'll mean that something went wrong. Following are some of the error messages that can help us understand what's happening: + +| Error | Description | +| ----------------------- | ----------------------------------------------------------------------------------------------------------- | +| `MALFORMED_DATA` | wrong input data, failed to deserialize, missing certain fields, etc. | +| `NOT_DEPOSITOR` | the address is not an active depositor in the auction contract | +| `WRONG_CHAIN_ID` | wrong chain id for the target chain | +| `WRONG_SIGNATURE` | signature failed to verify | +| `BAD_ROUND_NUMBER` | incorrect round, such as one from the past | +| `RESERVE_PRICE_NOT_MET` | bid amount does not meet the minimum required reserve price on-chain | +| `INSUFFICIENT_BALANCE` | the bid amount specified in the request is higher than the deposit balance of the depositor in the contract | + +### Step 3: find out the winner of the auction + +After the auction closes, and before the round starts, the autonomous auctioneer will call the auction contract with the two highest bids received, so the contract can declare the winner and subtract the second-highest bid from the winner's deposited funds. After this, the contract will emit an event with the new express lane controller address. + +We can use this event to determine whether or not we've won the auction. The event signature is: + +```solidity +event SetExpressLaneController( + uint64 round, + address indexed previousExpressLaneController, + address indexed newExpressLaneController, + address indexed transferor, + uint64 startTimestamp, + uint64 endTimestamp +); +``` + +Here's an example to get the log from the auction contract to determine the new express lane controller: + +```tsx +const fromBlock = +const logs = await publicClient.getLogs({ + address: auctionContractAddress, + event: auctionContractAbi.filter((abiEntry) => abiEntry.name === 'SetExpressLaneController')[0], + fromBlock, +}); + +const newExpressLaneController = logs[0].args.newExpressLaneController; +console.log(`New express lane controller: ${newExpressLaneController}`); +``` + +If you won the auction, congratulations! You are the express lane controller for the next round, which, by default, will start 15 seconds after the auction closed. The following section explains how we can submit a transaction to the express lane. + +## How to submit transactions to the express lane + +Transactions that are sent to the express lane are immediately sequenced by the sequencer, while regular transactions are delayed 200ms by default. However, only the express lane controller can send transactions to the express lane. The previous section explained how to participate in the auction to be the express lane controller for a given round. + +The express lane is handled by the sequencer, so transactions are sent to the sequencer endpoint. We need to send a `timeboost_sendExpressLaneTransaction` request with the following information: + +- chain id +- current round (following the example above, `currentRound`) +- address of the auction contract +- sequence number: a per-round nonce of express lane submissions, which is reset to 0 at the beginning of each round +- RLP encoded transaction payload +- conditional options for Arbitrum transactions ([source](https://github.com/OffchainLabs/go-ethereum/blob/48de2030c7a6fa8689bc0a0212ebca2a0c73e3ad/arbitrum_types/txoptions.go#L71)) +- signature (explained below) + +Let's see an example of a call to this RPC method: + +```tsx +const hexChainId: `0x${string}` = `0x${Number(publicClient.chain.id).toString(16)}`; + +const transaction = await walletClient.prepareTransactionRequest(...); +const serializedTransaction = await walletClient.signTransaction(transaction); + +const res = await fetch(, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + jsonrpc: '2.0', + id: 'express-lane-tx', + method: 'timeboost_sendExpressLaneTransaction', + params: [ + { + chainId: hexChainId, + round: `0x${currentRound.toString(16)}`, + auctionContractAddress: auctionContractAddress, + sequence: `0x${sequenceNumber.toString(16)}`, + transaction: serializedTransaction, + options: {}, + signature: signature, + }, + ], + }), +}); +``` + +The signature that needs to be sent is an Ethereum signature over the bytes encoding of the following information: + +- Hash of `keccak256("TIMEBOOST_BID")` +- Chain id in hexadecimal, padded to 32 bytes +- Auction contract address +- Round number in hexadecimal, padded to 8 bytes +- Sequence number in hexadecimal, padded to 8 bytes +- Serialized transaction + +Here's an example to produce that signature: + +```tsx +const hexChainId: `0x${string}` = `0x${Number(publicClient.chain.id).toString(16)}`; + +const transaction = await walletClient.prepareTransactionRequest(...); +const serializedTransaction = await walletClient.signTransaction(transaction); + +const signatureData = concat([ + keccak256(toHex('TIMEBOOST_BID')), + pad(hexChainId), + auctionContract, + toHex(numberToBytes(currentRound, { size: 8 })), + toHex(numberToBytes(sequenceNumber, { size: 8 })), + serializedTransaction, +]); +const signature = await account.signMessage({ + message: { raw: signatureData }, +}); +``` + +When sending the request, the sequencer will return an empty result with an HTTP status `200` if it received the request correctly. If the result returned contains an error message, it'll mean that something went wrong. Following are some of the error messages that can help us understand what's happening: + +| Error | Description | +| ----------------------------- | --------------------------------------------------------------------- | +| `MALFORMED_DATA` | wrong input data, failed to deserialize, missing certain fields, etc. | +| `WRONG_CHAIN_ID` | wrong chain id for the target chain | +| `WRONG_SIGNATURE` | signature failed to verify | +| `BAD_ROUND_NUMBER` | incorrect round, such as one from the past | +| `NOT_EXPRESS_LANE_CONTROLLER` | the sender is not the express lane controller | +| `NO_ONCHAIN_CONTROLLER` | there is no defined, on-chain express lane controller for the round | + +::::info What happens if you're not the express lane controller? + +If you are not the express lane controller and you try to submit a transaction to the express lane, the sequencer will respond with the error `NOT_EXPRESS_LANE_CONTROLLER` or `NO_ONCHAIN_CONTROLLER`. + +:::: + +## How to transfer the right to use the express lane to someone else + +If you are the express lane controller, you also have the right to transfer the right to use the express lane to someone else. + +To do that, you can call the function `transferExpressLaneController` in the auction contract: + +```tsx +const transferELCTransaction = await walletClient.writeContract({ + currentELCAccount, + address: auctionContractAddress, + abi: auctionContractAbi, + functionName: 'transferExpressLaneController', + args: [currentRound, newELCAddress], +}); +console.log(`Transfer EL controller transaction hash: ${transferELCTransaction}`); +``` + +From that moment, the previous express lane controller will not be able to send new transactions to the express lane. + +### Setting a transferor account + +A `transferor` is an address that has the right to transfer express lane controller rights on behalf an express lane controller. We can set a transferor for our account using the auction contract. Additionally, we can choose to fix that transferor account until a specific round, to guarantee to other parties that we will not change the transferor until the specified round finishes. + +To set a transferor, we can call the function `setTransferor` in the auction contract: + +```tsx +// Fixing the transferor for 10 rounds +const fixedUntilRound = currentRound + 10n; + +const setTransferorTransaction = await walletClient.writeContract({ + currentELCAccount, + address: auctionContractAddress, + abi: auctionContractAbi, + functionName: 'setTransferor', + args: [ + { + addr: transferorAddress, + fixedUntilRound: fixedUntilRound, + }, + ], +}); +console.log(`Set transferor transaction hash: ${setTransferorTransaction}`); +``` + +From that moment on (until the transferor is changed or disabled), the transferor will be able to call `transferExpressLaneController` while the express lane controller is `currentELCAccount` to transfer the rights to use the express lane to a different account. From c21d044d41ebfcc0d929a896f3e64c8bd55b1549 Mon Sep 17 00:00:00 2001 From: TucksonDev Date: Fri, 25 Oct 2024 12:38:51 +0100 Subject: [PATCH 02/15] Add how to withdraw funds --- .../how-to-use-timeboost.mdx | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx index 791d08ed0..2b29adccb 100644 --- a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx +++ b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx @@ -369,3 +369,43 @@ console.log(`Set transferor transaction hash: ${setTransferorTransaction}`); ``` From that moment on (until the transferor is changed or disabled), the transferor will be able to call `transferExpressLaneController` while the express lane controller is `currentELCAccount` to transfer the rights to use the express lane to a different account. + +## How to withdraw funds deposited in the auction contract + +Funds are deposited in the auction contract to have the right the bid in auctions. These funds can be withdrawn through a two-step process: initiate withdrawal, wait for two rounds, finalize withdrawal. + +To initiate a withdrawal, we can call the function `initiateWithdrawal` in the auction contract: + +```tsx +const initWithdrawalTransaction = await walletClient.writeContract({ + account, + address: auctionContractAddress, + abi: auctionContractAbi, + functionName: 'initiateWithdrawal', +}); +console.log(`Initiate withdrawal transaction sent: ${initWithdrawalTransaction}`); +``` + +This transaction will initiate a withdrawal of all funds deposited by the sender account. When executing it, the contract will emit a `WithdrawalInitiated` event, with the following structure: + +```solidity +event WithdrawalInitiated( + address indexed account, + uint256 withdrawalAmount, + uint256 roundWithdrawable +); +``` + +In this event, `account` refers to the address whose funds are being withdrawn, `withdrawalAmount` refers to the amount being withdrawn from the contract, and `roundWithdrawable` refers to the round at which the withdrawal can be finalized. + +After two rounds have passed, we can call the method `finalizeWithdrawal` in the auction contract to finalize the withdrawal: + +```tsx +const finalizeWithdrawalTransaction = await walletClient.writeContract({ + account, + address: auctionContractAddress, + abi: auctionContractAbi, + functionName: 'finalizeWithdrawal', +}); +console.log(`Finalize withdrawal transaction sent: ${finalizeWithdrawalTransaction}`); +``` From 85ec45729d5255f643ebcae26b19949e66a4efd5 Mon Sep 17 00:00:00 2001 From: TucksonDev Date: Tue, 29 Oct 2024 11:31:34 +0000 Subject: [PATCH 03/15] Add note about transactions signed by third parties --- .../build-decentralized-apps/how-to-use-timeboost.mdx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx index 2b29adccb..cc69df2fb 100644 --- a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx +++ b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx @@ -244,9 +244,15 @@ The express lane is handled by the sequencer, so transactions are sent to the se - address of the auction contract - sequence number: a per-round nonce of express lane submissions, which is reset to 0 at the beginning of each round - RLP encoded transaction payload -- conditional options for Arbitrum transactions ([source](https://github.com/OffchainLabs/go-ethereum/blob/48de2030c7a6fa8689bc0a0212ebca2a0c73e3ad/arbitrum_types/txoptions.go#L71)) +- conditional options for Arbitrum transactions ([more information](https://github.com/OffchainLabs/go-ethereum/blob/48de2030c7a6fa8689bc0a0212ebca2a0c73e3ad/arbitrum_types/txoptions.go#L71)) - signature (explained below) +::::info Transactions signed by third parties + +Notice that, while the express lane controller needs to sign the `timeboost_sendExpressLaneTransaction` request, the actual transaction to be executed can be signed by any party. In other terms, the express lane controller can receive transactions signed by other parties and send them to the express lane. + +:::: + Let's see an example of a call to this RPC method: ```tsx From 66831281bb5586a96e0c09134d5ae7ef0f6ca433 Mon Sep 17 00:00:00 2001 From: TucksonDev Date: Tue, 29 Oct 2024 11:47:13 +0000 Subject: [PATCH 04/15] Update text about timeboost-ing 3rd party transactions --- .../build-decentralized-apps/how-to-use-timeboost.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx index cc69df2fb..8c56c68ac 100644 --- a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx +++ b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx @@ -247,9 +247,9 @@ The express lane is handled by the sequencer, so transactions are sent to the se - conditional options for Arbitrum transactions ([more information](https://github.com/OffchainLabs/go-ethereum/blob/48de2030c7a6fa8689bc0a0212ebca2a0c73e3ad/arbitrum_types/txoptions.go#L71)) - signature (explained below) -::::info Transactions signed by third parties +::::info Timeboost-ing third party transactions -Notice that, while the express lane controller needs to sign the `timeboost_sendExpressLaneTransaction` request, the actual transaction to be executed can be signed by any party. In other terms, the express lane controller can receive transactions signed by other parties and send them to the express lane. +Notice that, while the express lane controller needs to sign the `timeboost_sendExpressLaneTransaction` request, the actual transaction to be executed can be signed by any party. In other words, the express lane controller can receive transactions signed by other parties and sign them to apply the time advantage offered by the express lane to those transactions. :::: From c9442b16e0a4c492f1596122e6e4c4db9d94da79 Mon Sep 17 00:00:00 2001 From: TucksonDev Date: Thu, 21 Nov 2024 18:07:08 +0000 Subject: [PATCH 05/15] Add how to identify timeboosted transactions --- .../build-decentralized-apps/how-to-use-timeboost.mdx | 8 ++++++++ .../sequencer/02-read-sequencer-feed.mdx | 1 + 2 files changed, 9 insertions(+) diff --git a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx index 8c56c68ac..72267d559 100644 --- a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx +++ b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx @@ -415,3 +415,11 @@ const finalizeWithdrawalTransaction = await walletClient.writeContract({ }); console.log(`Finalize withdrawal transaction sent: ${finalizeWithdrawalTransaction}`); ``` + +## How to identify timeboosted transactions + +Transactions that have been sent to the express lane by the express lane controller, and that have been executed (regardless of them being successful or having reverted), can be identified by looking at their receipts, or the message broadcasted by the sequencer feed. + +Transaction receipts include now a new field `timeboosted`, which will be `true` for timeboosted transactions, and `false` for regular non-timeboosted transactions. + +In the sequencer feed, the `BroadcastFeedMessage` struct now contains a `blockMetadata` field that represents whether a particular transaction in the block was timeboosted or not. The field blockMetadata is an array of bytes and it starts with a byte representing the version (`0`), followed by `ceil(N/8)` number of bytes where `N` is the number of transactions in the block. If a particular transaction was timeboosted, the bit representing its position in the block will be set to `1`, while the rest will be set to `0`. For example, if the `blockMetadata` of a particular message, viewed as bits is `00000000 01100000`, then the 2nd and 3rd transactions in that block were timeboosted. diff --git a/arbitrum-docs/run-arbitrum-node/sequencer/02-read-sequencer-feed.mdx b/arbitrum-docs/run-arbitrum-node/sequencer/02-read-sequencer-feed.mdx index aa3b9b756..b4b62bb66 100644 --- a/arbitrum-docs/run-arbitrum-node/sequencer/02-read-sequencer-feed.mdx +++ b/arbitrum-docs/run-arbitrum-node/sequencer/02-read-sequencer-feed.mdx @@ -59,6 +59,7 @@ type BroadcastFeedMessage struct { SequenceNumber arbutil.MessageIndex `json:"sequenceNumber"` Message arbstate.MessageWithMetadata `json:"message"` Signature []byte `json:"signature"` + BlockMetadata arbostypes.BlockMetadata `json:"blockMetadata"` } ``` From ccb777057ae4037b6192319d93608ce333f59508 Mon Sep 17 00:00:00 2001 From: TucksonDev Date: Mon, 25 Nov 2024 17:32:32 +0000 Subject: [PATCH 06/15] Include feedback --- .../how-to-use-timeboost.mdx | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx index 72267d559..a2935be0a 100644 --- a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx +++ b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx @@ -5,9 +5,9 @@ author: jose-franco content_type: how-to --- -Timeboost is a new transaction ordering policy for Arbitrum chains where any participant can bid for the right to access an express lane on the sequencer for faster transaction inclusion. +Timeboost is a new transaction ordering policy for Arbitrum chains. With Timeboost, anyone can bid for the right to access an express lane on the sequencer for faster transaction inclusion. -In this how-to, you'll learn how to bid for the right to use the express lane, how to submit transactions to it, and how to transfer that right to someone else. To learn more about Timeboost, refer to the gentle introduction. +In this how-to, you'll learn how to bid for the right to use the express lane, how to submit transactions through the express lane, and how to transfer that express lane rights to someone else. To learn more about Timeboost, refer to the [gentle introduction](#). This how-to assumes that you're familiar with: @@ -16,19 +16,19 @@ This how-to assumes that you're familiar with: ## How to submit bids for the right to be the express lane controller -To use the express lane for faster transaction inclusion, we must win an auction for the right to be the express lane controller for a specific round. +To use the express lane for faster transaction inclusion, you must win an auction for the right to be the express lane controller for a specific round. ::::info -Remember that, by default, each round lasts 60 seconds, and the auction for a specific round closes 15 seconds before the round starts. These default values can be configured in a chain with the `roundDurationSeconds` and `auctionClosingSeconds` parameters respectively. +Remember that, by default, each round lasts 60 seconds, and the auction for a specific round closes 15 seconds before the round starts. These default values can be configured on a chain using the `roundDurationSeconds` and `auctionClosingSeconds` parameters, respectively. :::: Auctions are held in an auction contract, and bids are submitted to an autonomous auctioneer, that also communicates with the contract. Let's take a look at the process of submitting bids and finding out the winner of an auction. -### Step 0: pre-requirements +### Step 0: gather required information -To run the following steps, we'll need this information: +Before we begin, make sure you have: - Address of the auction contract - Endpoint of the autonomous auctioneer @@ -44,9 +44,9 @@ const depositedBalance = await publicClient.readContract({ address: auctionContractAddress, abi: auctionContractAbi, functionName: 'balanceOf', - args: [address], + args: [userAddress], }); -console.log(`Current balance of ${address} in auction contract: ${depositedBalance}`); +console.log(`Current balance of ${userAddress} in auction contract: ${depositedBalance}`); ``` If we want to deposit more funds to the auction contract, we first need to know what the bidding token is. To obtain the address of the bidding token, we can call the function `biddingToken` in the auction contract: @@ -112,8 +112,9 @@ let currentAuctionRoundIsClosed = await publicClient.readContract({ ``` Once we know what is the current round we can bid for (`currentRound + 1`) and we have verified that the auction is still open (`!currentAuctionRoundIsClosed`), we can submit a bid. @@ -127,6 +128,12 @@ Bids are submitted to the autonomous auctioneer endpoint. We need to send a `auc - amount in wei of the deposit ERC-20 token to bid - signature (explained below) +::::info Minimum reserve price + +The amount to bid must be above the minimum reserve price at the moment you are bidding. This parameter is configurable per chain. You can obtain the minimum reserve price by calling the method `minReservePrice()(uint256)` in the auction contract. + +:::: + Let's see an example of a call to this RPC method: ```tsx @@ -143,7 +150,7 @@ const res = await fetch(, { params: [ { chainId: hexChainId, - expressLaneController: address, + expressLaneController: userAddress, auctionContractAddress: auctionContractAddress, round: `0x${currentAuctionRound.toString(16)}`, amount: `0x${Number(amountToBid).toString(16)}`, @@ -175,7 +182,7 @@ const signatureData = concat([ auctionContractAddress, toHex(numberToBytes(currentAuctionRound, { size: 8 })), toHex(numberToBytes(amountToBid, { size: 32 })), - address, + userAddress, ]); const signature = await account.signMessage({ message: { raw: signatureData }, @@ -184,7 +191,7 @@ const signature = await account.signMessage({ ::::info -You can also call the function `getBidBytes` in the auction contract to obtain the `signatureData` , specifying the `round`, `amountToBid` and `address`. +You can also call the function `getBidBytes` in the auction contract to obtain the `signatureData` , specifying the `round`, `amountToBid` and `userAddress`. :::: @@ -351,7 +358,9 @@ From that moment, the previous express lane controller will not be able to send ### Setting a transferor account -A `transferor` is an address that has the right to transfer express lane controller rights on behalf an express lane controller. We can set a transferor for our account using the auction contract. Additionally, we can choose to fix that transferor account until a specific round, to guarantee to other parties that we will not change the transferor until the specified round finishes. +A `transferor` is an address that has the right to transfer express lane controller rights on behalf an express lane controller. The reason to include this function (setTransferor) is so the express lane controller has a way to nominate an address that can transfer rights to anyone they see fit, in order to improve the reselling rights user experience. + +We can set a transferor for our account using the auction contract. Additionally, we can choose to fix that transferor account until a specific round, to guarantee to other parties that we will not change the transferor until the specified round finishes. To set a transferor, we can call the function `setTransferor` in the auction contract: From 1b07501b50a3f01e76d3023255e543b48013497a Mon Sep 17 00:00:00 2001 From: TucksonDev Date: Fri, 29 Nov 2024 14:32:22 +0000 Subject: [PATCH 07/15] Update bid submission to use EIP-712 --- .../how-to-use-timeboost.mdx | 50 +++++++++++-------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx index a2935be0a..20726bde1 100644 --- a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx +++ b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx @@ -161,37 +161,47 @@ const res = await fetch(, { }); ``` -The signature that needs to be sent is an Ethereum signature over the bytes encoding of the following information: +The signature that needs to be sent is an [EIP-712](https://eips.ethereum.org/EIPS/eip-712) signature over the following typed structure data: -- Hash of `keccak256("TIMEBOOST_BID")` -- Chain id in hexadecimal, padded to 32 bytes -- Auction contract address -- Auction round number in hexadecimal, padded to 8 bytes -- Amount to bid in hexadecimal, padded to 32 bytes -- Address of the express lane controller candidate +- Domain: `Bid(uint64 round,address expressLaneController,uint256 amount)` +- `round`: auction round number +- `expressLaneController`: address of the express lane controller candidate +- `amount`: amount to bid -Here's an example to produce that signature: +Here's an example to produce that signature with viem: ```tsx const currentAuctionRound = currentRound + 1; -const hexChainId: `0x${string}` = `0x${Number(publicClient.chain.id).toString(16)}`; -const signatureData = concat([ - keccak256(toHex('TIMEBOOST_BID')), - pad(hexChainId), - auctionContractAddress, - toHex(numberToBytes(currentAuctionRound, { size: 8 })), - toHex(numberToBytes(amountToBid, { size: 32 })), - userAddress, -]); -const signature = await account.signMessage({ - message: { raw: signatureData }, +const signatureData = hashTypedData({ + domain: { + name: 'ExpressLaneAuction', + version: '1', + chainId: Number(publicClient.chain.id), + verifyingContract: auctionContractAddress, + }, + types: { + Bid: [ + { name: 'round', type: 'uint64' }, + { name: 'expressLaneController', type: 'address' }, + { name: 'amount', type: 'uint256' }, + ], + }, + primaryType: 'Bid', + message: { + round: currentAuctionRound, + expressLaneController: userAddress, + amount: amountToBid, + }, +}); +const signature = await account.sign({ + hash: signatureData, }); ``` ::::info -You can also call the function `getBidBytes` in the auction contract to obtain the `signatureData` , specifying the `round`, `amountToBid` and `userAddress`. +You can also call the function `getBidHash` in the auction contract to obtain the `signatureData`, specifying the `round`, `userAddress` and `amountToBid`. :::: From 49f40d14abb01e73a20a400d9657e2ce88e7f295 Mon Sep 17 00:00:00 2001 From: TucksonDev Date: Mon, 9 Dec 2024 16:32:05 +0000 Subject: [PATCH 08/15] Add example of receipt of a timeboosted transaction --- .../how-to-use-timeboost.mdx | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx index 20726bde1..5c420477b 100644 --- a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx +++ b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx @@ -439,6 +439,29 @@ console.log(`Finalize withdrawal transaction sent: ${finalizeWithdrawalTransacti Transactions that have been sent to the express lane by the express lane controller, and that have been executed (regardless of them being successful or having reverted), can be identified by looking at their receipts, or the message broadcasted by the sequencer feed. -Transaction receipts include now a new field `timeboosted`, which will be `true` for timeboosted transactions, and `false` for regular non-timeboosted transactions. +Transaction receipts include now a new field `timeboosted`, which will be `true` for timeboosted transactions, and `false` for regular non-timeboosted transactions. For example: + +```shell +blockHash 0x56325449149b362d4ace3267681c3c90823f1e5c26ccc4df4386be023f563eb6 +blockNumber 105169374 +contractAddress +cumulativeGasUsed 58213 +effectiveGasPrice 100000000 +from 0x193cA786e7C7CC67B6227391d739E41C43AF285f +gasUsed 58213 +logs [] +logsBloom 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +root +status 1 (success) +transactionHash 0x62ea458ad2bb408fab57d1a31aa282fe3324b2711e0d73f4777db6e34bc1bef5 +transactionIndex 1 +type 2 +blobGasPrice +blobGasUsed +to 0x0000000000000000000000000000000000000001 +gasUsedForL1 "0x85a5" +l1BlockNumber "0x6e8b49" +timeboosted true +``` In the sequencer feed, the `BroadcastFeedMessage` struct now contains a `blockMetadata` field that represents whether a particular transaction in the block was timeboosted or not. The field blockMetadata is an array of bytes and it starts with a byte representing the version (`0`), followed by `ceil(N/8)` number of bytes where `N` is the number of transactions in the block. If a particular transaction was timeboosted, the bit representing its position in the block will be set to `1`, while the rest will be set to `0`. For example, if the `blockMetadata` of a particular message, viewed as bits is `00000000 01100000`, then the 2nd and 3rd transactions in that block were timeboosted. From 399f9f8a67da209762e13d47df4e0abb8cad58b3 Mon Sep 17 00:00:00 2001 From: TucksonDev Date: Tue, 17 Dec 2024 17:12:55 +0000 Subject: [PATCH 09/15] Add links to the gentle introduction --- .../build-decentralized-apps/how-to-use-timeboost.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx index 5c420477b..8d883bab3 100644 --- a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx +++ b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx @@ -7,11 +7,11 @@ content_type: how-to Timeboost is a new transaction ordering policy for Arbitrum chains. With Timeboost, anyone can bid for the right to access an express lane on the sequencer for faster transaction inclusion. -In this how-to, you'll learn how to bid for the right to use the express lane, how to submit transactions through the express lane, and how to transfer that express lane rights to someone else. To learn more about Timeboost, refer to the [gentle introduction](#). +In this how-to, you'll learn how to bid for the right to use the express lane, how to submit transactions through the express lane, and how to transfer that express lane rights to someone else. To learn more about Timeboost, refer to the [gentle introduction](/how-arbitrum-works/timeboost/gentle-introduction.mdx). This how-to assumes that you're familiar with: -- [How Timeboost works](#) +- [How Timeboost works](/how-arbitrum-works/timeboost/gentle-introduction.mdx) - [viem](https://viem.sh/), since the snippets of code present in the how-to use this library ## How to submit bids for the right to be the express lane controller From c5c14d7ec9f7b4e7b8c03aca20e1c945f27b4fc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Blanchemain?= Date: Wed, 18 Dec 2024 10:14:05 -0800 Subject: [PATCH 10/15] feat: add banner about eth_sendRawTransactionConditional not being supported --- .../build-decentralized-apps/how-to-use-timeboost.mdx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx index 8d883bab3..f2576de05 100644 --- a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx +++ b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx @@ -270,6 +270,12 @@ Notice that, while the express lane controller needs to sign the `timeboost_send :::: +::::info Support for `eth_sendRawTransactionConditional` + +Timeboost doesn't currently support the `eth_sendRawTransactionConditional` method. + +:::: + Let's see an example of a call to this RPC method: ```tsx From 8c317cac2dca0266ad1b19afe3caea4205263028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Blanchemain?= Date: Wed, 18 Dec 2024 10:21:30 -0800 Subject: [PATCH 11/15] feat: add article to tmp location --- website/sidebars.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/website/sidebars.js b/website/sidebars.js index b77f15bcc..7212ed06f 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -54,6 +54,11 @@ const sidebars = { label: 'Cross-chain messaging', id: 'build-decentralized-apps/cross-chain-messaging', }, + { + type: 'doc', + label: 'Using Timeboost', + id: 'build-decentralized-apps/how-to-use-timeboost', + }, { type: 'category', label: 'Arbitrum vs Ethereum', From 722b68b3ae0b0593144b9c4e90085bff5518c22b Mon Sep 17 00:00:00 2001 From: TucksonDev Date: Thu, 19 Dec 2024 13:33:33 +0000 Subject: [PATCH 12/15] Update transferor text --- arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx index f2576de05..6db07f169 100644 --- a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx +++ b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx @@ -374,7 +374,7 @@ From that moment, the previous express lane controller will not be able to send ### Setting a transferor account -A `transferor` is an address that has the right to transfer express lane controller rights on behalf an express lane controller. The reason to include this function (setTransferor) is so the express lane controller has a way to nominate an address that can transfer rights to anyone they see fit, in order to improve the reselling rights user experience. +A `transferor` is an address that has the right to transfer express lane controller rights on behalf of the express lane controller. This function (`setTransferor`) was added to ensure that the express lane controller has a way of nominating an address that can transfer rights to anyone they see fit, in order to improve the user experience of reselling/transferring the control of the express lane. We can set a transferor for our account using the auction contract. Additionally, we can choose to fix that transferor account until a specific round, to guarantee to other parties that we will not change the transferor until the specified round finishes. From 89a73a388d2f1baaee0e0149bf10f6547f1f57e6 Mon Sep 17 00:00:00 2001 From: TucksonDev Date: Tue, 24 Dec 2024 12:22:00 +0000 Subject: [PATCH 13/15] Address editorial review comments --- .../how-to-use-timeboost.mdx | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx index 6db07f169..597b607e2 100644 --- a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx +++ b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx @@ -7,9 +7,9 @@ content_type: how-to Timeboost is a new transaction ordering policy for Arbitrum chains. With Timeboost, anyone can bid for the right to access an express lane on the sequencer for faster transaction inclusion. -In this how-to, you'll learn how to bid for the right to use the express lane, how to submit transactions through the express lane, and how to transfer that express lane rights to someone else. To learn more about Timeboost, refer to the [gentle introduction](/how-arbitrum-works/timeboost/gentle-introduction.mdx). +In this how-to, you'll learn how to bid for the right to use the express lane, submit transactions through the express lane, and transfer express lane rights to someone else. To learn more about Timeboost, refer to the [gentle introduction](/how-arbitrum-works/timeboost/gentle-introduction.mdx). -This how-to assumes that you're familiar with: +This how-to assumes that you're familiar with the following: - [How Timeboost works](/how-arbitrum-works/timeboost/gentle-introduction.mdx) - [viem](https://viem.sh/), since the snippets of code present in the how-to use this library @@ -20,11 +20,11 @@ To use the express lane for faster transaction inclusion, you must win an auctio ::::info -Remember that, by default, each round lasts 60 seconds, and the auction for a specific round closes 15 seconds before the round starts. These default values can be configured on a chain using the `roundDurationSeconds` and `auctionClosingSeconds` parameters, respectively. +Remember that, by default, each round lasts 60 seconds, and the auction for a specific round closes 15 seconds before the round starts. These default values can be configured on a chain using the `roundDurationSeconds` and `auctionClosingSeconds` parameters. :::: -Auctions are held in an auction contract, and bids are submitted to an autonomous auctioneer, that also communicates with the contract. Let's take a look at the process of submitting bids and finding out the winner of an auction. +Auctions are in an auction contract, and bids get submitted to an autonomous auctioneer who communicates with the contract. Let's look at the process of submitting bids and finding out the winner of an auction. ### Step 0: gather required information @@ -35,7 +35,7 @@ Before we begin, make sure you have: ### Step 1: deposit funds into the auction contract -Before bidding on an auction, we need to deposit funds in the auction contract. These funds are deposited in the form of the ERC-20 token used to bid, also known as, the `bidding token`. We will be able to bid for an amount that is equal to or less than the tokens we have deposited in the auction contract. +Before bidding on an auction, we need to deposit funds in the auction contract. These deposited funds are the ERC-20 token used to bid, also known as the `bidding token`. We will be able to bid for an amount that is equal to or less than the tokens we have deposited in the auction contract. To see the amount of tokens we have deposited in the auction contract, we can call the function `balanceOf` in the auction contract: @@ -62,7 +62,7 @@ console.log(`biddingToken: ${biddingTokenContractAddress}`); -Once we know what the bidding token is, we can deposit funds to the auction contract by calling the function `deposit` of the contract, after having it approved as spender of the amount we want to deposit: +Once we know what the bidding token is, we can deposit funds to the auction contract by calling the function `deposit` of the contract after having it approved as spender of the amount we want to deposit: ```tsx // Approving spending tokens @@ -88,7 +88,7 @@ console.log(`Deposit transaction sent: ${depositHash}`); ### Step 2: submit bids -Once we have deposited funds into the auction contract, we can start submitting bids for the current auction round. +Once we have deposited funds into the auction contract, we can submit bids for the current auction round. We can obtain the current round by calling the function `currentRound` in the auction contract: @@ -101,7 +101,7 @@ const currentRound = await publicClient.readContract({ console.log(`Current round: ${currentRound}`); ``` -This is the current round that's running. And, at the same time, the auction for the next round might be open. For example, if `currentRound` is 10, that means that the auction for round 11 is happening right now. To check whether or not that auction is open, we can call the function `isAuctionRoundClosed` of the auction contract: +The above shows the current round that's running. At the same time, the auction for the next round might be open. For example, if the `currentRound` is 10, the auction for round 11 is happening right now. To check whether or not that auction is open, we can call the function `isAuctionRoundClosed` of the auction contract: ```tsx let currentAuctionRoundIsClosed = await publicClient.readContract({ @@ -112,9 +112,8 @@ let currentAuctionRoundIsClosed = await publicClient.readContract({ ``` Once we know what is the current round we can bid for (`currentRound + 1`) and we have verified that the auction is still open (`!currentAuctionRoundIsClosed`), we can submit a bid. @@ -205,7 +204,7 @@ You can also call the function `getBidHash` in the auction contract to obtain th :::: -When sending the request, the autonomous auctioneer will return an empty result with an HTTP status `200` if it received the request correctly. If the result returned contains an error message, it'll mean that something went wrong. Following are some of the error messages that can help us understand what's happening: +When sending the request, the autonomous auctioneer will return an empty result with an HTTP status `200` if received correctly. If the result returned contains an error message, it means that something went wrong. Following are some of the error messages that can help us understand what's happening: | Error | Description | | ----------------------- | ----------------------------------------------------------------------------------------------------------- | @@ -219,7 +218,7 @@ When sending the request, the autonomous auctioneer will return an empty result ### Step 3: find out the winner of the auction -After the auction closes, and before the round starts, the autonomous auctioneer will call the auction contract with the two highest bids received, so the contract can declare the winner and subtract the second-highest bid from the winner's deposited funds. After this, the contract will emit an event with the new express lane controller address. +After the auction closes, and before the round starts the autonomous auctioneer will call the auction contract with the two highest bids received so the contract can declare the winner and subtract the second-highest bid from the winner's deposited funds. After this, the contract will emit an event with the new express lane controller address. We can use this event to determine whether or not we've won the auction. The event signature is: @@ -248,11 +247,11 @@ const newExpressLaneController = logs[0].args.newExpressLaneController; console.log(`New express lane controller: ${newExpressLaneController}`); ``` -If you won the auction, congratulations! You are the express lane controller for the next round, which, by default, will start 15 seconds after the auction closed. The following section explains how we can submit a transaction to the express lane. +If you won the auction, congratulations! You are the express lane controller for the next round, which, by default, will start 15 seconds after the auction closes. The following section explains how we can submit a transaction to the express lane. ## How to submit transactions to the express lane -Transactions that are sent to the express lane are immediately sequenced by the sequencer, while regular transactions are delayed 200ms by default. However, only the express lane controller can send transactions to the express lane. The previous section explained how to participate in the auction to be the express lane controller for a given round. +The sequencer immediately sequences transactions sent to the express lane, while regular transactions are delayed 200ms by default. However, only the express lane controller can send transactions to the express lane. The previous section explained how to participate in the auction as the express lane controller for a given round. The express lane is handled by the sequencer, so transactions are sent to the sequencer endpoint. We need to send a `timeboost_sendExpressLaneTransaction` request with the following information: @@ -266,7 +265,7 @@ The express lane is handled by the sequencer, so transactions are sent to the se ::::info Timeboost-ing third party transactions -Notice that, while the express lane controller needs to sign the `timeboost_sendExpressLaneTransaction` request, the actual transaction to be executed can be signed by any party. In other words, the express lane controller can receive transactions signed by other parties and sign them to apply the time advantage offered by the express lane to those transactions. +Notice that while the express lane controller must sign the `timeboost_sendExpressLaneTransaction` request, the actual transaction to be executed can be signed by any party. In other words, the express lane controller can receive transactions signed by other parties and sign them to apply the time advantage offered by the express lane to those transactions. :::: @@ -336,7 +335,7 @@ const signature = await account.signMessage({ }); ``` -When sending the request, the sequencer will return an empty result with an HTTP status `200` if it received the request correctly. If the result returned contains an error message, it'll mean that something went wrong. Following are some of the error messages that can help us understand what's happening: +When sending the request, the sequencer will return an empty result with an HTTP status `200` if it received it correctly. If the result returned contains an error message, something went wrong. Following are some of the error messages that can help us understand what's happening: | Error | Description | | ----------------------------- | --------------------------------------------------------------------- | @@ -374,9 +373,9 @@ From that moment, the previous express lane controller will not be able to send ### Setting a transferor account -A `transferor` is an address that has the right to transfer express lane controller rights on behalf of the express lane controller. This function (`setTransferor`) was added to ensure that the express lane controller has a way of nominating an address that can transfer rights to anyone they see fit, in order to improve the user experience of reselling/transferring the control of the express lane. +A `transferor` is an address with the right to transfer express lane controller rights on behalf of the express lane controller. This function (`setTransferor`) ensures that the express lane controller has a way of nominating an address that can transfer rights to anyone they see fit to improve the user experience of reselling/transferring the control of the express lane. -We can set a transferor for our account using the auction contract. Additionally, we can choose to fix that transferor account until a specific round, to guarantee to other parties that we will not change the transferor until the specified round finishes. +We can set a transferor for our account using the auction contract. Additionally, we can fix that transferor account until a specific round to guarantee other parties that we will not change the transferor until the specified round finishes. To set a transferor, we can call the function `setTransferor` in the auction contract: @@ -403,7 +402,7 @@ From that moment on (until the transferor is changed or disabled), the transfero ## How to withdraw funds deposited in the auction contract -Funds are deposited in the auction contract to have the right the bid in auctions. These funds can be withdrawn through a two-step process: initiate withdrawal, wait for two rounds, finalize withdrawal. +Funds are deposited in the auction contract to have the right to bid in auctions. Withdrawing funds is possible through two steps: initiate withdrawal, wait for two rounds, and finalize withdrawal. To initiate a withdrawal, we can call the function `initiateWithdrawal` in the auction contract: @@ -443,7 +442,7 @@ console.log(`Finalize withdrawal transaction sent: ${finalizeWithdrawalTransacti ## How to identify timeboosted transactions -Transactions that have been sent to the express lane by the express lane controller, and that have been executed (regardless of them being successful or having reverted), can be identified by looking at their receipts, or the message broadcasted by the sequencer feed. +Transactions sent to the express lane by the express lane controller and that have been executed (regardless of them being successful or having reverted) can be identified by looking at their receipts or the message broadcasted by the sequencer feed. Transaction receipts include now a new field `timeboosted`, which will be `true` for timeboosted transactions, and `false` for regular non-timeboosted transactions. For example: From 3bd55da5fc1f14fccade18c15e2180260cf4965c Mon Sep 17 00:00:00 2001 From: TucksonDev Date: Tue, 24 Dec 2024 12:52:11 +0000 Subject: [PATCH 14/15] Smol clarification --- arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx index 597b607e2..6d9e5e7cd 100644 --- a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx +++ b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx @@ -24,7 +24,7 @@ Remember that, by default, each round lasts 60 seconds, and the auction for a sp :::: -Auctions are in an auction contract, and bids get submitted to an autonomous auctioneer who communicates with the contract. Let's look at the process of submitting bids and finding out the winner of an auction. +Auctions are held in an auction contract, and bids get submitted to an autonomous auctioneer who communicates with the contract. Let's look at the process of submitting bids and finding out the winner of an auction. ### Step 0: gather required information From fb4811d237b56016969076c61e7b1c661276c0b9 Mon Sep 17 00:00:00 2001 From: TucksonDev Date: Tue, 24 Dec 2024 13:03:19 +0000 Subject: [PATCH 15/15] More smol changes --- .../build-decentralized-apps/how-to-use-timeboost.mdx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx index 6d9e5e7cd..6143762f0 100644 --- a/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx +++ b/arbitrum-docs/build-decentralized-apps/how-to-use-timeboost.mdx @@ -35,7 +35,7 @@ Before we begin, make sure you have: ### Step 1: deposit funds into the auction contract -Before bidding on an auction, we need to deposit funds in the auction contract. These deposited funds are the ERC-20 token used to bid, also known as the `bidding token`. We will be able to bid for an amount that is equal to or less than the tokens we have deposited in the auction contract. +Before bidding on an auction, we need to deposit funds in the auction contract. These funds are deposited in the form of the ERC-20 token used to bid, also known as the `bidding token`. We will be able to bid for an amount that is equal to or less than the tokens we have deposited in the auction contract. To see the amount of tokens we have deposited in the auction contract, we can call the function `balanceOf` in the auction contract: @@ -60,7 +60,11 @@ const biddingTokenContractAddress = await publicClient.readContract({ console.log(`biddingToken: ${biddingTokenContractAddress}`); ``` - +::::info Bidding token in Arbitrum chains + +On Arbitrum One and Arbitrum Nova, the bidding token is WETH. + +:::: Once we know what the bidding token is, we can deposit funds to the auction contract by calling the function `deposit` of the contract after having it approved as spender of the amount we want to deposit: @@ -218,7 +222,7 @@ When sending the request, the autonomous auctioneer will return an empty result ### Step 3: find out the winner of the auction -After the auction closes, and before the round starts the autonomous auctioneer will call the auction contract with the two highest bids received so the contract can declare the winner and subtract the second-highest bid from the winner's deposited funds. After this, the contract will emit an event with the new express lane controller address. +After the auction closes and before the round starts, the autonomous auctioneer will call the auction contract with the two highest bids received so the contract can declare the winner and subtract the second-highest bid from the winner's deposited funds. After this, the contract will emit an event with the new express lane controller address. We can use this event to determine whether or not we've won the auction. The event signature is: