UNPKG

accounts

Version:

Tempo Accounts SDK

122 lines 5.17 kB
import {} from 'ox'; import { createClient, http, } from 'viem'; import { Transaction } from 'viem/tempo'; const defaultClients = new Map(); const clients = new WeakMap(); /** Resolves a viem Client for a given chain ID (cached). */ export function fromChainId(chainId, options) { const { chains, feePayer: feePayerOption, provider, store, transports } = options; const feePayerUrl = (() => { if (feePayerOption === false) return undefined; if (typeof feePayerOption === 'string') return normalizeFeePayerUrl(feePayerOption); if (feePayerOption?.url) return normalizeFeePayerUrl(feePayerOption.url); return undefined; })(); const precedence = (() => { if (typeof feePayerOption === 'object' && feePayerOption !== null) return feePayerOption.precedence ?? 'fee-payer-first'; return 'fee-payer-first'; })(); const id = chainId ?? store.getState().chainId; const key = `${id}:${provider ? 'p' : ''}:${feePayerOption === false ? 'no-fp' : (feePayerUrl ?? '')}:${precedence}`; // Scope the cache by `provider` (preferred) or `transports`, falling back // to a shared module-level map. The cache key only encodes a boolean for // `provider`, so without scoping, two providers sharing the same chainId // would hit each other's cached clients and route requests to the wrong // adapter via `providerTransport`. const scope = provider ?? transports; const cache = (() => { if (!scope) return defaultClients; let map = clients.get(scope); if (!map) { map = new Map(); clients.set(scope, map); } return map; })(); let client = cache.get(key); if (!client) { const chain = chains.find((c) => c.id === id) ?? chains[0]; const base = transports?.[id] ?? http(); const transport_base = provider ? providerTransport(provider, base) : base; const transport = feePayerUrl ? feePayerTransport(transport_base, feePayerUrl, precedence) : transport_base; client = createClient({ chain, transport, pollingInterval: 1000 }); cache.set(key, client); } return client; } /** * Creates a transport that routes requests through the provider, falling * back to the given base transport for methods the provider proxies to RPC. */ function providerTransport(provider, base) { return (params) => { const baseTransport = base(params); return { ...baseTransport, async request({ method, params: reqParams }) { return provider.request({ method, params: reqParams, }); }, }; }; } /** * Resolves a fee payer URL to an absolute URL string. Relative paths (e.g. * `/relay`) are resolved against `window.location.origin` when running in a * browser; on the server, relative paths are returned as-is. */ function normalizeFeePayerUrl(url) { if (url.startsWith('http://') || url.startsWith('https://')) return url; if (typeof window !== 'undefined') return new URL(url, window.location.origin).href; return url; } function feePayerTransport(base, url, precedence) { return (params) => { const baseTransport = base(params); const sponsor = http(url)(params); return { ...baseTransport, async request({ method, params: rpcParams }) { const args = rpcParams; if (precedence === 'fee-payer-first' && method === 'eth_fillTransaction') { const request = args?.[0]; if (request && typeof request === 'object' && 'feePayer' in request && (request.feePayer === true || typeof request.feePayer === 'string')) return sponsor.request({ method, params: [{ ...request, feePayer: true }], }); } if (method === 'eth_sendRawTransaction' || method === 'eth_sendRawTransactionSync') { const serialized = args?.[0]; if (typeof serialized === 'string' && (serialized.startsWith('0x76') || serialized.startsWith('0x78'))) { const deserialized = Transaction.deserialize(serialized); if ('feePayerSignature' in deserialized && deserialized.feePayerSignature === null) { const signed = await sponsor.request({ method: 'eth_signRawTransaction', params: [serialized], }); return await baseTransport.request({ method, params: [signed] }); } } } return await baseTransport.request({ method, params: rpcParams }); }, }; }; } //# sourceMappingURL=Client.js.map