UNPKG

accounts

Version:

Tempo Accounts SDK

96 lines 4.09 kB
import { RpcResponse, Signature } from 'ox'; import { TxEnvelopeTempo } from 'ox/tempo'; import { signTransaction } from 'viem/actions'; 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 (!serialized.startsWith('0x76') && !serialized.startsWith('0x78')) 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, getClient, method, request, validate } = options; const serialized = request.params?.[0]; if (!serialized?.startsWith('0x76') && !serialized?.startsWith('0x78')) throw new RpcResponse.InvalidParamsError({ message: 'Only Tempo (0x76/0x78) transactions are supported.', }); const transaction = Transaction.deserialize(serialized); if (!transaction.signature || !transaction.from) throw new RpcResponse.InvalidParamsError({ message: 'Transaction must be signed by the sender before fee payer signing.', }); if (validate && !(await validate(transaction))) throw new RpcResponse.InvalidParamsError({ message: 'Sponsorship rejected.', }); const client = getClient(transaction.chainId); const serializedTransaction = toSerializedTransaction(await signTransaction(client, { ...transaction, account, feePayer: account, })); if (method === 'eth_signRawTransaction') return serializedTransaction; return await client.request({ method: method, params: [serializedTransaction], }); } function toSerializedTransaction(value) { if (typeof value === 'string') return value; if (value && typeof value === 'object' && 'raw' in value && typeof value.raw === 'string') return value.raw; throw new Error('Expected a serialized transaction result.'); } //# sourceMappingURL=sponsorship.js.map