From 58cd162bbdfafd383c1b36682355c9ae58451c0c Mon Sep 17 00:00:00 2001 From: Georgios Konstantopoulos Date: Fri, 30 Jan 2026 15:19:22 +0000 Subject: [PATCH 1/2] docs(foundry): add Tempo and T1 Foundry features Tempo Features (T0+): - Sponsored transactions (--sponsor-signature, --print-sponsor-hash) - Batch transactions (cast batch-mktx, cast batch-send, forge script --batch) - Atomic execution, single CREATE first, value must be 0, silent failures T1 Features: - 2D nonces (--nonce-key) for parallel tx submission - Expiring nonces (--expiring-nonce, --valid-before, --valid-after) - Access keys (--access-key, --root-account) for delegated signing Examples adapted from tempo-foundry tempo-check.sh Co-authored-by: George Amp-Thread-ID: https://ampcode.com/threads/T-019c0f64-ce8e-771c-af58-358a84c3d13c Co-authored-by: Amp --- src/pages/sdk/foundry/index.mdx | 153 ++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) diff --git a/src/pages/sdk/foundry/index.mdx b/src/pages/sdk/foundry/index.mdx index 1c28c96b..aae3d8be 100644 --- a/src/pages/sdk/foundry/index.mdx +++ b/src/pages/sdk/foundry/index.mdx @@ -175,6 +175,159 @@ cast run \ --rpc-url $TEMPO_RPC_URL ``` +## Tempo Features + +The following Tempo-specific features are now supported in the Foundry fork. + +### Sponsored Transactions + +Sponsored transactions allow a separate account to pay gas fees on behalf of the sender. + +```bash +# Step 1: Get the fee payer signature hash +FEE_PAYER_HASH=$(cast mktx 'increment()' \ + --rpc-url $TEMPO_RPC_URL \ + --private-key $SENDER_KEY \ + --print-sponsor-hash) + +# Step 2: Sponsor signs the hash +SPONSOR_SIG=$(cast wallet sign --private-key $SPONSOR_KEY "$FEE_PAYER_HASH" --no-hash) + +# Step 3: Send with sponsor signature +cast send 'increment()' \ + --rpc-url $TEMPO_RPC_URL \ + --private-key $SENDER_KEY \ + --sponsor-signature "$SPONSOR_SIG" +``` + +### Batch Transactions + +Batch transactions execute multiple calls atomically in a single type 0x76 transaction. All calls succeed or all revert. + +#### Using `cast batch-mktx` and `cast batch-send` + +```bash +# Create a batch transaction (dry-run) +cast batch-mktx \ + --call "::increment()" \ + --call "::setNumber(uint256):500" \ + --rpc-url $TEMPO_RPC_URL \ + --private-key $PRIVATE_KEY + +# Send a batch transaction +cast batch-send \ + --call "::increment()" \ + --call "::increment()" \ + --rpc-url $TEMPO_RPC_URL \ + --private-key $PRIVATE_KEY + +# Batch with pre-encoded calldata +ENCODED=$(cast calldata "setNumber(uint256)" 200) +cast batch-send \ + --call "::$ENCODED" \ + --call "::setNumber(uint256):101" \ + --rpc-url $TEMPO_RPC_URL \ + --private-key $PRIVATE_KEY +``` + +#### Using `forge script --batch` + +Deploy and call contracts atomically in a single transaction: + +```bash +forge script script/Deploy.s.sol \ + --broadcast --batch \ + --rpc-url $TEMPO_RPC_URL \ + --private-key $PRIVATE_KEY +``` + +All broadcast calls in the script are batched into a single atomic transaction. + +#### Batch Transaction Rules + +:::warning +Batch transactions have specific constraints: + +1. **Atomic execution**: If any call in the batch reverts, the entire batch reverts. No state changes from earlier calls persist. + +2. **Single CREATE allowed**: A batch may contain at most one contract deployment (CREATE opcode). + +3. **CREATE must be first**: If deploying a contract in a batch, the deployment must be the first operation. Subsequent calls can interact with the newly deployed contract. + +4. **Value must be zero**: Since Tempo has no native token, the `value` field for each call must be 0. + +5. **Silent failures**: Calling a non-existent function on a contract without a fallback does not revert - it succeeds silently with empty return data. Ensure your target contracts explicitly revert on invalid calls if you need strict failure handling. +::: + +## T1 Features + +The following features require the Tempo T1 hardfork. + +### 2D Nonces + +2D nonces allow parallel transaction submission by using separate nonce sequences per `nonce-key`. Each key maintains its own nonce counter starting at 0. + +```bash +# Create transaction with nonce-key 1 (starts at nonce 0) +cast mktx 'increment()' \ + --rpc-url $TEMPO_RPC_URL \ + --private-key $PRIVATE_KEY \ + --nonce 0 --nonce-key 1 + +# Send transaction with nonce-key 2 (independent sequence) +cast send 'increment()' \ + --rpc-url $TEMPO_RPC_URL \ + --private-key $PRIVATE_KEY \ + --nonce 0 --nonce-key 2 +``` + +### Expiring Nonces + +Expiring nonces allow transactions to be valid only within a time window (max 30 seconds). Useful for time-sensitive operations. + +```bash +# Transaction valid for next 25 seconds +VALID_BEFORE=$(($(date +%s) + 25)) +cast send 'increment()' \ + --rpc-url $TEMPO_RPC_URL \ + --private-key $PRIVATE_KEY \ + --expiring-nonce --valid-before $VALID_BEFORE + +# Transaction valid between two timestamps +VALID_AFTER=$(($(date +%s) + 5)) +VALID_BEFORE=$(($(date +%s) + 25)) +cast mktx 'increment()' \ + --rpc-url $TEMPO_RPC_URL \ + --private-key $PRIVATE_KEY \ + --expiring-nonce --valid-before $VALID_BEFORE --valid-after $VALID_AFTER +``` + +### Access Keys + +Access keys enable delegated signing, where an authorized key can sign transactions on behalf of a root account. + +```bash +# First, authorize an access key on-chain via the Account Keychain precompile +# SignatureType: 0 = Secp256k1, Expiry: Unix timestamp, enforceLimits: false +cast send 0xAAAAAAAA00000000000000000000000000000000 \ + 'authorizeKey(address,uint8,uint64,bool,(address,uint256)[])' \ + $ACCESS_KEY_ADDR 0 1893456000 false "[]" \ + --rpc-url $TEMPO_RPC_URL \ + --private-key $ROOT_PRIVATE_KEY + +# Create transaction signed by access key +cast mktx 'increment()' \ + --rpc-url $TEMPO_RPC_URL \ + --access-key $ACCESS_KEY_PRIVATE_KEY \ + --root-account $ROOT_ADDRESS + +# Send transaction using access key +cast send 'increment()' \ + --rpc-url $TEMPO_RPC_URL \ + --access-key $ACCESS_KEY_PRIVATE_KEY \ + --root-account $ROOT_ADDRESS +``` + ### Limitations Ledger and Trezor wallets are not yet compatible with the `--fee-token` option. From 7e7c122519c617801e628b3b3c48edb4ea196fe2 Mon Sep 17 00:00:00 2001 From: Georgios Konstantopoulos Date: Fri, 30 Jan 2026 15:25:21 +0000 Subject: [PATCH 2/2] docs(foundry): integrate new features into existing structure Add examples to existing sections without new paragraphs: - forge: --batch flag for atomic multi-call scripts - cast: batch-send, sponsored tx, 2D nonces, expiring nonces, access keys Batch transaction rules added as warning callout under forge section. Amp-Thread-ID: https://ampcode.com/threads/T-019c0f64-ce8e-771c-af58-358a84c3d13c Co-authored-by: Amp --- src/pages/sdk/foundry/index.mdx | 152 +++++++------------------------- 1 file changed, 34 insertions(+), 118 deletions(-) diff --git a/src/pages/sdk/foundry/index.mdx b/src/pages/sdk/foundry/index.mdx index aae3d8be..dd8de308 100644 --- a/src/pages/sdk/foundry/index.mdx +++ b/src/pages/sdk/foundry/index.mdx @@ -130,10 +130,24 @@ forge script script/Mail.s.sol \ --sender \ --broadcast \ --verify + +# Batch multiple calls into a single atomic transaction +forge script script/Deploy.s.sol \ + --broadcast --batch \ + --rpc-url $TEMPO_RPC_URL \ + --private-key $PRIVATE_KEY ``` For more verification options including verifying existing contracts and API verification, see [Contract Verification](/quickstart/verify-contracts). +:::warning[Batch Transaction Rules] +- **Atomic execution**: If any call reverts, the entire batch reverts +- **Single CREATE allowed**: At most one contract deployment per batch +- **CREATE must be first**: Deployment must be the first operation +- **Value must be zero**: Since Tempo has no native token, value must be 0 +- **Silent failures**: Calling a non-existent function without a fallback succeeds silently +::: + ### Interact & debug with `cast` ```bash @@ -173,155 +187,57 @@ cast send \ # Replay a transaction by hash: cast run \ --rpc-url $TEMPO_RPC_URL -``` - -## Tempo Features - -The following Tempo-specific features are now supported in the Foundry fork. - -### Sponsored Transactions - -Sponsored transactions allow a separate account to pay gas fees on behalf of the sender. -```bash -# Step 1: Get the fee payer signature hash -FEE_PAYER_HASH=$(cast mktx 'increment()' \ - --rpc-url $TEMPO_RPC_URL \ - --private-key $SENDER_KEY \ - --print-sponsor-hash) - -# Step 2: Sponsor signs the hash -SPONSOR_SIG=$(cast wallet sign --private-key $SPONSOR_KEY "$FEE_PAYER_HASH" --no-hash) - -# Step 3: Send with sponsor signature -cast send 'increment()' \ - --rpc-url $TEMPO_RPC_URL \ - --private-key $SENDER_KEY \ - --sponsor-signature "$SPONSOR_SIG" -``` - -### Batch Transactions - -Batch transactions execute multiple calls atomically in a single type 0x76 transaction. All calls succeed or all revert. - -#### Using `cast batch-mktx` and `cast batch-send` - -```bash -# Create a batch transaction (dry-run) -cast batch-mktx \ - --call "::increment()" \ - --call "::setNumber(uint256):500" \ - --rpc-url $TEMPO_RPC_URL \ - --private-key $PRIVATE_KEY - -# Send a batch transaction +# Send a batch transaction with multiple calls: cast batch-send \ --call "::increment()" \ - --call "::increment()" \ + --call "::setNumber(uint256):500" \ --rpc-url $TEMPO_RPC_URL \ --private-key $PRIVATE_KEY -# Batch with pre-encoded calldata +# Batch with pre-encoded calldata: ENCODED=$(cast calldata "setNumber(uint256)" 200) cast batch-send \ --call "::$ENCODED" \ --call "::setNumber(uint256):101" \ --rpc-url $TEMPO_RPC_URL \ --private-key $PRIVATE_KEY -``` - -#### Using `forge script --batch` -Deploy and call contracts atomically in a single transaction: - -```bash -forge script script/Deploy.s.sol \ - --broadcast --batch \ +# Sponsored transaction (gasless for sender): +# Step 1: Get the fee payer signature hash +FEE_PAYER_HASH=$(cast mktx 'increment()' \ --rpc-url $TEMPO_RPC_URL \ - --private-key $PRIVATE_KEY -``` - -All broadcast calls in the script are batched into a single atomic transaction. - -#### Batch Transaction Rules - -:::warning -Batch transactions have specific constraints: - -1. **Atomic execution**: If any call in the batch reverts, the entire batch reverts. No state changes from earlier calls persist. - -2. **Single CREATE allowed**: A batch may contain at most one contract deployment (CREATE opcode). - -3. **CREATE must be first**: If deploying a contract in a batch, the deployment must be the first operation. Subsequent calls can interact with the newly deployed contract. - -4. **Value must be zero**: Since Tempo has no native token, the `value` field for each call must be 0. - -5. **Silent failures**: Calling a non-existent function on a contract without a fallback does not revert - it succeeds silently with empty return data. Ensure your target contracts explicitly revert on invalid calls if you need strict failure handling. -::: - -## T1 Features - -The following features require the Tempo T1 hardfork. - -### 2D Nonces - -2D nonces allow parallel transaction submission by using separate nonce sequences per `nonce-key`. Each key maintains its own nonce counter starting at 0. - -```bash -# Create transaction with nonce-key 1 (starts at nonce 0) -cast mktx 'increment()' \ + --private-key $SENDER_KEY \ + --print-sponsor-hash) +# Step 2: Sponsor signs the hash +SPONSOR_SIG=$(cast wallet sign --private-key $SPONSOR_KEY "$FEE_PAYER_HASH" --no-hash) +# Step 3: Send with sponsor signature +cast send 'increment()' \ --rpc-url $TEMPO_RPC_URL \ - --private-key $PRIVATE_KEY \ - --nonce 0 --nonce-key 1 + --private-key $SENDER_KEY \ + --sponsor-signature "$SPONSOR_SIG" -# Send transaction with nonce-key 2 (independent sequence) +# Send with 2D nonce (parallel tx submission): cast send 'increment()' \ --rpc-url $TEMPO_RPC_URL \ --private-key $PRIVATE_KEY \ - --nonce 0 --nonce-key 2 -``` - -### Expiring Nonces - -Expiring nonces allow transactions to be valid only within a time window (max 30 seconds). Useful for time-sensitive operations. + --nonce 0 --nonce-key 1 -```bash -# Transaction valid for next 25 seconds +# Send with expiring nonce (time-bounded tx, max 30s): VALID_BEFORE=$(($(date +%s) + 25)) cast send 'increment()' \ --rpc-url $TEMPO_RPC_URL \ --private-key $PRIVATE_KEY \ --expiring-nonce --valid-before $VALID_BEFORE -# Transaction valid between two timestamps -VALID_AFTER=$(($(date +%s) + 5)) -VALID_BEFORE=$(($(date +%s) + 25)) -cast mktx 'increment()' \ - --rpc-url $TEMPO_RPC_URL \ - --private-key $PRIVATE_KEY \ - --expiring-nonce --valid-before $VALID_BEFORE --valid-after $VALID_AFTER -``` - -### Access Keys - -Access keys enable delegated signing, where an authorized key can sign transactions on behalf of a root account. - -```bash -# First, authorize an access key on-chain via the Account Keychain precompile -# SignatureType: 0 = Secp256k1, Expiry: Unix timestamp, enforceLimits: false +# Send with access key (delegated signing): +# First authorize the key via Account Keychain precompile cast send 0xAAAAAAAA00000000000000000000000000000000 \ 'authorizeKey(address,uint8,uint64,bool,(address,uint256)[])' \ $ACCESS_KEY_ADDR 0 1893456000 false "[]" \ --rpc-url $TEMPO_RPC_URL \ --private-key $ROOT_PRIVATE_KEY - -# Create transaction signed by access key -cast mktx 'increment()' \ - --rpc-url $TEMPO_RPC_URL \ - --access-key $ACCESS_KEY_PRIVATE_KEY \ - --root-account $ROOT_ADDRESS - -# Send transaction using access key +# Then send using the access key cast send 'increment()' \ --rpc-url $TEMPO_RPC_URL \ --access-key $ACCESS_KEY_PRIVATE_KEY \