Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

protect: Add "Nonce Management" page to document eth_getTransactionCount behavior. #573

Merged
merged 5 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions docs/flashbots-protect/nonce-management.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---
title: Nonce Management
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

Normally, a wallet can call `eth_getTransactionCount` to get the next nonce to use for a transaction.
However, since transactions sent to Flashbots Protect are potentially sensitive, even exposing the incremented nonce can leak information about the user's activity.

As such, transactions sent to Flashbots Protect are only included in the `eth_getTransactionCount` results when querying the `"pending"` nonce, and only if the request is signed by the user's private key.

This is done by sending a JSON-RPC request to the Flashbots Protect RPC endpoint with the following parameters:

```json
{
"jsonrpc": "2.0",
"method": "eth_getTransactionCount",
"params": [
"0xYOUR_ADDRESS",
"pending"
],
"id": 1
}
```

The request is signed and the signature is included in the `X-Flashbots-Signature` header. Without such a signature, the returned nonce will only include transactions sent to the public mempool.
ryanschneider marked this conversation as resolved.
Show resolved Hide resolved

### Authentication

To authenticate your request, sign the payload and include the signed payload in the `X-Flashbots-Signature` header of your request.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to (instead, or in addition) link directly to the authentication section in our API docs https://docs.flashbots.net/flashbots-auction/advanced/rpc-endpoint#authentication.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about that, but that section is relay-specific so includes some wording such as:

Any valid ECDSA-secp256k1 key, like an arbitrary Ethereum key, can be used to sign the payload. The address associated with this key will be used by Flashbots to keep track of your reputation over time and provide user statistics. You can change the key you use at any time.

That conflicts with the usage here.

```curl
curl -X POST -H "Content-Type: application/json" -H "X-Flashbots-Signature: <public key address>:<signature>" --data '{"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0xYOUR_ADDRESS","pending"],"id":1}' https://rpc.flashbots.net
```

The private key of the address your want to query must be used to sign the payload.

The signature is calculated by taking the [EIP-191](https://eips.ethereum.org/EIPS/eip-191) hash of the json body encoded as UTF-8 bytes. Here's an example using ethers.js:

<Tabs
defaultValue="ethers.js"
values={[
{ label: 'ethers.js', value: 'ethers.js', },
{ label: 'web3.py', value: 'web3.py' },
{ label: 'go', value: 'go' },
]}
>
<TabItem value="ethers.js">

```ts
import {Wallet, utils} from 'ethers';

const privateKey = '0x1234';
const wallet = new Wallet(privateKey);
const body =
'{"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0xYOUR_ADDRESS","pending"],"id":1}';
const signature = wallet.address + ':' + wallet.signMessage(utils.id(body));
```

</TabItem>
<TabItem value="web3.py">

```py
from web3 import Web3
from eth_account import Account, messages

body = '{"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0xYOUR_ADDRESS","pending"],"id":1}'
message = messages.encode_defunct(text=Web3.keccak(text=body).hex())
signature = Account.from_key(private_key).address + ':' + Account.sign_message(message, private_key).signature.hex()
```

</TabItem>
<TabItem value="go">

```go
body := `{"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0xYOUR_ADDRESS","pending"],"id":1}`
hashedBody := crypto.Keccak256Hash([]byte(body)).Hex()
sig, err := crypto.Sign(accounts.TextHash([]byte(hashedBody)), privKey)
signature := crypto.PubkeyToAddress(privKey.PublicKey).Hex() + ":" + hexutil.Encode(sig)
```

</TabItem>
</Tabs>

1 change: 1 addition & 0 deletions docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ module.exports = {
'flashbots-protect/mev-share',
'flashbots-protect/gas-fee-refunds',
'flashbots-protect/cancellations',
'flashbots-protect/nonce-management',
'flashbots-protect/stuck_transactions',
'flashbots-protect/large-transactions',
{
Expand Down
Loading