UNPKG

accounts

Version:

Tempo Accounts SDK

103 lines 4.66 kB
import { RpcResponse, Signature } from 'ox'; import { TxEnvelopeTempo } from 'ox/tempo'; import { Transaction } from 'viem/tempo'; import * as Utils from './utils.js'; /** Returns sponsor metadata for `eth_fillTransaction` responses. */ export function getSponsor(options) { const { account, name, url } = options; return { address: account.address, ...(name ? { name } : {}), ...(url ? { url } : {}), }; } /** Returns whether the fee payer approves a filled transaction. */ export async function shouldSponsor(options) { const { sender, transaction, validate } = options; if (!validate) return true; return await validate({ ...transaction, from: sender, }); } /** Returns whether a raw Tempo transaction is explicitly requesting sponsorship. */ export function requestsRawSponsorship(serialized) { if (!Utils.isSerializedTempoTransaction(serialized)) return false; const transaction = Transaction.deserialize(serialized); return 'feePayerSignature' in transaction && transaction.feePayerSignature === null; } /** Returns `true` when a fill request already has the fields needed for sponsorship signing. */ export function isPreparedTransaction(value) { return (typeof value.from === 'string' && typeof Utils.resolveChainId(value.chainId) === 'number' && typeof value.gas !== 'undefined' && typeof value.nonce !== 'undefined' && (typeof value.maxFeePerGas !== 'undefined' || typeof value.gasPrice !== 'undefined')); } /** Signs a filled transaction as the fee payer. */ export async function sign(options) { const { account, transaction, sender } = options; const from = transaction.from ?? sender; const { signature: _, ...withoutSenderSig } = transaction; const prepared = { ...withoutSenderSig, from }; if (!prepared.from) throw new RpcResponse.InvalidParamsError({ message: 'Transaction sender must be provided before fee payer signing.', }); if (!account.sign) throw new Error('Fee payer account cannot sign transactions.'); const feePayerSignature = Signature.from(await account.sign({ hash: TxEnvelopeTempo.getFeePayerSignPayload(TxEnvelopeTempo.from(prepared), { sender: prepared.from, }), })); return { ...prepared, feePayerSignature }; } /** Handles `eth_signRawTransaction` and broadcast methods for sponsored Tempo transactions. */ export async function handleRawTransaction(options) { const { account, feeToken: sponsorFeeToken, getClient, method, request, validate } = options; const serialized = request.params?.[0]; if (!Utils.isSerializedTempoTransaction(serialized)) throw new RpcResponse.InvalidParamsError({ message: 'Only Tempo (0x76/0x78) transactions are supported.', }); const transaction = Transaction.deserialize(serialized); // Prefer sender recovered from raw envelope; multisig finalize path supplies fallback sender. const sender = transaction.from ?? options.sender; // Sponsorship only applies after sender has signed original transaction. if (!transaction.signature || !sender) throw new RpcResponse.InvalidParamsError({ message: 'Transaction must be signed by the sender before fee payer signing.', }); if (!account.sign) throw new Error('Fee payer account cannot sign transactions.'); const client = getClient(transaction.chainId); const feeToken_chain = client.chain?.feeToken; const feeToken = transaction.feeToken ?? sponsorFeeToken ?? (await options.getFeeToken?.(transaction.chainId)) ?? feeToken_chain; const transaction_sponsored = feeToken ? { ...transaction, feeToken } : transaction; if (validate && !(await validate(transaction_sponsored))) throw new RpcResponse.InvalidParamsError({ message: 'Sponsorship rejected.', }); const envelope = TxEnvelopeTempo.from(transaction_sponsored); const feePayerSignature = Signature.from(await account.sign({ hash: TxEnvelopeTempo.getFeePayerSignPayload(envelope, { sender }), })); const serializedTransaction = TxEnvelopeTempo.serialize(envelope, { feePayerSignature, signature: transaction.signature, }); // Raw-sign requests stop after fee-payer signature is added; send methods broadcast it. if (method === 'eth_signRawTransaction') return serializedTransaction; return await client.request({ method: method, params: [serializedTransaction], }); } //# sourceMappingURL=sponsorship.js.map