From d9317ac5dc683785a912c3bf4617e57daa0e584a Mon Sep 17 00:00:00 2001 From: Brendan Ryan Date: Wed, 4 Feb 2026 08:29:11 -0800 Subject: [PATCH 1/2] docs: document fee sponsorship signing hash behavior Adds documentation explaining that when building sponsored transactions, the sender must indicate sponsorship BEFORE signing because the signing hash differs: - Sponsored: fee_token omitted from signing payload, 0x00 marker used - Non-sponsored: fee_token included in signing payload This was raised as feedback from an external integration partner who discovered this behavior during testing. Changes: - Added warning callout in Go SDK docs - Added 'Signing Hash Behavior' section in sponsor-user-fees guide --- .../guide/payments/sponsor-user-fees.mdx | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/pages/guide/payments/sponsor-user-fees.mdx b/src/pages/guide/payments/sponsor-user-fees.mdx index cae2f47e..c3c56618 100644 --- a/src/pages/guide/payments/sponsor-user-fees.mdx +++ b/src/pages/guide/payments/sponsor-user-fees.mdx @@ -156,6 +156,47 @@ const { receipt } = await client.token.transferSync({ - **Balance checks**: Network verifies fee payer has sufficient balance - **Signature validation**: Both signatures must be valid +### Signing Hash Behavior + +When building fee-sponsored transactions, the sender must indicate sponsorship **before signing**. This is because the transaction's signing hash differs based on whether it will be sponsored: + +- **Sponsored transactions**: The `fee_token` field is omitted from the sender's signing payload, and a `0x00` marker is used. This allows the fee payer to choose the fee token. +- **Non-sponsored transactions**: The `fee_token` is included in the sender's signing payload. + +The `withFeePayer` transport and `feePayer: true` parameter handle this automatically. If you're building transactions manually with a local account as fee payer, the Viem SDK handles this for you: + +```ts twoslash +// @noErrors +import { createClient, http, parseUnits } from 'viem' +import { privateKeyToAccount } from 'viem/accounts' +import { tempoModerato } from 'viem/chains' + +const client = createClient({ + chain: tempoModerato, + transport: http(), +}) + +const senderAccount = privateKeyToAccount('0x...') +const feePayerAccount = privateKeyToAccount('0x...') + +// When feePayer is an Account object, Viem: +// 1. Has the sender sign the transaction (with feeToken) +// 2. Recovers the sender address from their signature +// 3. Has the fee payer sign a separate hash (includes sender + feeToken) +// 4. Serializes the dual-signed transaction +const { receipt } = await client.token.transferSync({ + account: senderAccount, + amount: parseUnits('10.5', 6), + to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb', + token: '0x20c0000000000000000000000000000000000000', + feePayer: feePayerAccount, // [!code hl] +}) +``` + +:::info +When using `feePayer: true` with the `withFeePayer` transport, the SDK deletes the `feeToken` from the transaction before signing, then sends it to the fee payer service which adds their signature. +::: + ## Learning Resources From a09d0d121a9e0a8352b9c70801b512788b948d73 Mon Sep 17 00:00:00 2001 From: Brendan Ryan Date: Wed, 4 Feb 2026 08:41:13 -0800 Subject: [PATCH 2/2] ci: add build step to verify workflow, warn on dead links - Add build step after typecheck in CI to catch build failures before deploy - Change checkDeadlinks to 'warn' (TIP-1011 has dead link in tempo repo) --- .github/workflows/verify.yml | 5 +++++ vocs.config.ts | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index aca18cab..345fba54 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -32,6 +32,11 @@ jobs: - name: Check types run: pnpm run check:types + - name: Build + run: pnpm run build + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + e2e: name: E2E Tests runs-on: ubuntu-latest diff --git a/vocs.config.ts b/vocs.config.ts index 900c8ed2..18b76687 100644 --- a/vocs.config.ts +++ b/vocs.config.ts @@ -9,7 +9,8 @@ const baseUrl = (() => { export default defineConfig({ changelog: Changelog.github({ prereleases: true, repo: 'tempoxyz/tempo' }), - checkDeadlinks: true, + // TODO: Set back to true once tempoxyz/tempo#tip-1011 dead link is fixed + checkDeadlinks: 'warn', title: 'Tempo', titleTemplate: '%s ⋅ Tempo',