From 617acf88746589f31e4f111363173d5b70e42911 Mon Sep 17 00:00:00 2001 From: jxom <7336481+jxom@users.noreply.github.com> Date: Mon, 6 Jul 2026 14:57:24 +1000 Subject: [PATCH] fix: preserve sponsored fee token --- .changeset/polite-sponsors-pay.md | 5 +++ .../wallet/prepareTransactionRequest.test.ts | 34 +++++++++++++++++++ .../wallet/prepareTransactionRequest.ts | 16 +++++---- 3 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 .changeset/polite-sponsors-pay.md diff --git a/.changeset/polite-sponsors-pay.md b/.changeset/polite-sponsors-pay.md new file mode 100644 index 0000000000..b5b52d5efb --- /dev/null +++ b/.changeset/polite-sponsors-pay.md @@ -0,0 +1,5 @@ +--- +"viem": patch +--- + +`viem/tempo`: Preserved sponsor-returned `feeToken` values from `eth_fillTransaction` responses with `feePayerSignature`. diff --git a/src/actions/wallet/prepareTransactionRequest.test.ts b/src/actions/wallet/prepareTransactionRequest.test.ts index 1246be9ce3..43dac059cd 100644 --- a/src/actions/wallet/prepareTransactionRequest.test.ts +++ b/src/actions/wallet/prepareTransactionRequest.test.ts @@ -828,6 +828,40 @@ describe('without `eth_fillTransaction`', () => { `) }) + test('behavior: sponsor fill feeToken overrides prefilled feeToken', async () => { + const requestFeeToken = '0x20c0000000000000000000000000000000000001' + const sponsorFeeToken = '0x20c0000000000000000000000000000000000000' + const fillTransactionSpy = vi + .spyOn(fillTransaction, 'fillTransaction') + .mockResolvedValueOnce({ + transaction: { + feePayerSignature: { + r: '0x1', + s: '0x2', + yParity: 0, + }, + feeToken: sponsorFeeToken, + gas: 21000n, + }, + } as never) + + try { + const request = await prepareTransactionRequest(client, { + account: privateKeyToAccount(sourceAccount.privateKey), + feePayer: true, + feeToken: requestFeeToken, + parameters: ['gas'], + to: targetAccount.address, + value: parseEther('1'), + } as never) + + expect(request.feePayerSignature).toBeDefined() + expect(request.feeToken).toBe(sponsorFeeToken) + } finally { + fillTransactionSpy.mockRestore() + } + }) + test('behavior: chain default priority fee', async () => { await setup() diff --git a/src/actions/wallet/prepareTransactionRequest.ts b/src/actions/wallet/prepareTransactionRequest.ts index df5008855a..08a686934c 100644 --- a/src/actions/wallet/prepareTransactionRequest.ts +++ b/src/actions/wallet/prepareTransactionRequest.ts @@ -423,6 +423,15 @@ export async function prepareTransactionRequest< type, ...rest } = result.transaction + const feeToken = 'feeToken' in rest ? rest.feeToken : undefined + const hasFilledFeePayerSignature = + 'feePayerSignature' in rest && + rest.feePayerSignature !== null && + typeof rest.feePayerSignature !== 'undefined' + const shouldUseFilledFeeToken = + typeof feeToken !== 'undefined' && + feeToken !== null && + (!('feeToken' in request) || hasFilledFeePayerSignature) supportsFillTransaction.set(client.uid, true) return { ...request, @@ -461,12 +470,7 @@ export async function prepareTransactionRequest< rest.feePayerSignature !== null ? { feePayerSignature: rest.feePayerSignature } : {}), - ...('feeToken' in rest && - typeof rest.feeToken !== 'undefined' && - rest.feeToken !== null && - !('feeToken' in request) - ? { feeToken: rest.feeToken } - : {}), + ...(shouldUseFilledFeeToken ? { feeToken } : {}), ...(result.capabilities ? { _capabilities: result.capabilities } : {}),