UNPKG

ox

Version:

Ethereum Standard Library

308 lines 11.7 kB
import * as Hex from '../core/Hex.js'; import * as Quantity from '../core/internal/quantity.js'; import * as Signature from '../core/Signature.js'; import * as ox_TransactionRequest from '../core/TransactionRequest.js'; import * as AuthorizationTempo from './AuthorizationTempo.js'; import * as KeyAuthorization from './KeyAuthorization.js'; import * as SignatureEnvelope from './SignatureEnvelope.js'; import * as Transaction from './Transaction.js'; import * as TxEnvelopeTempo from './TxEnvelopeTempo.js'; /** * Converts a {@link ox#TransactionRequest.Rpc} to a {@link ox#TransactionRequest.TransactionRequest}. * * @example * ```ts twoslash * import { TransactionRequest } from 'ox/tempo' * * const request = TransactionRequest.fromRpc({ * calls: [ * { * data: '0xdeadbeef', * to: '0xcafebabecafebabecafebabecafebabecafebabe' * } * ], * feeToken: '0x20c0000000000000000000000000000000000000', * type: '0x76' * }) * ``` * * @param request - The RPC request to convert. * @returns A transaction request. */ export function fromRpc(request) { const { authorizationList: _, ...rest } = request; const request_ = ox_TransactionRequest.fromRpc(rest); if (typeof request.type !== 'undefined') request_.type = Transaction.fromRpcType[request.type] || request_.type; if (request.authorizationList) request_.authorizationList = AuthorizationTempo.fromRpcList(request.authorizationList); if (request.signature) request_.signature = SignatureEnvelope.fromRpc(request.signature); if (request.feePayerSignature) request_.feePayerSignature = Signature.fromRpc(request.feePayerSignature); if (request.calls) request_.calls = request.calls.map((call) => { const mapped = { to: call.to, data: call.data, }; if (call.value && call.value !== '0x') mapped.value = Hex.toBigInt(call.value); return mapped; }); if (typeof request.feeToken !== 'undefined') request_.feeToken = request.feeToken; if (request.keyAuthorization) request_.keyAuthorization = KeyAuthorization.fromRpc(request.keyAuthorization); if (typeof request.validBefore !== 'undefined') request_.validBefore = Hex.toNumber(request.validBefore); if (typeof request.validAfter !== 'undefined') request_.validAfter = Hex.toNumber(request.validAfter); if (typeof request.nonceKey !== 'undefined') request_.nonceKey = Hex.toBigInt(request.nonceKey); return request_; } /** * Converts a {@link ox#TransactionRequest.TransactionRequest} to a {@link ox#TransactionRequest.Rpc}. * * @see {@link https://docs.tempo.xyz/protocol/transactions} * * @example * ```ts twoslash * import { Value } from 'ox' * import { TransactionRequest } from 'ox/tempo' * * const request = TransactionRequest.toRpc({ * calls: [ * { * data: '0xdeadbeef', * to: '0xcafebabecafebabecafebabecafebabecafebabe' * } * ], * feeToken: '0x20c0000000000000000000000000000000000000' * }) * ``` * * @example * ### Using with a Provider * * You can use {@link ox#Provider.(from:function)} to instantiate an EIP-1193 Provider and * send a transaction to the Wallet using the `eth_sendTransaction` method. * * ```ts twoslash * // @noErrors * import 'ox/window' * import { Provider, Value } from 'ox' * import { TransactionRequest } from 'ox/tempo' * * const provider = Provider.from(window.ethereum!) * * const request = TransactionRequest.toRpc({ * calls: [ * { * data: '0xdeadbeef', * to: '0xcafebabecafebabecafebabecafebabecafebabe' * } * ], * feeToken: '0x20c0000000000000000000000000000000000000' * }) * * const hash = await provider.request({ * // [!code focus] * method: 'eth_sendTransaction', // [!code focus] * params: [request] // [!code focus] * }) // [!code focus] * ``` * * @param request - The request to convert. * @returns An RPC request. */ export function toRpc(request) { const request_rpc = ox_TransactionRequest.toRpc({ ...request, authorizationList: undefined, }); const tempo = typeof request.calls !== 'undefined' || typeof request.capabilities !== 'undefined' || typeof request.feePayer !== 'undefined' || typeof request.feeToken !== 'undefined' || typeof request.keyAuthorization !== 'undefined' || typeof request.keyData !== 'undefined' || typeof request.keyId !== 'undefined' || typeof request.keyType !== 'undefined' || typeof request.multisigInit !== 'undefined' || typeof request.multisigSignatureCount !== 'undefined' || typeof request.nonceKey !== 'undefined' || typeof request.validBefore !== 'undefined' || typeof request.validAfter !== 'undefined' || request.type === 'tempo'; if (request.authorizationList) request_rpc.authorizationList = AuthorizationTempo.toRpcList(request.authorizationList); if (request.signature) request_rpc.signature = SignatureEnvelope.toRpc(request.signature); if (request.feePayerSignature) request_rpc.feePayerSignature = Signature.toRpc(request.feePayerSignature); if (request.calls) request_rpc.calls = request.calls.map((call) => ({ to: call.to, value: call.value ? Quantity.fromNumberish(call.value) : '0x', data: call.data ?? '0x', })); else if (request.to || request.data || request.value || tempo) request_rpc.calls = [ { to: request.to || (tempo && (!request.data || request.data === '0x') ? '0x0000000000000000000000000000000000000000' : undefined), value: request.value ? Quantity.fromNumberish(request.value) : '0x', data: request.data ?? '0x', }, ]; if (typeof request.feeToken !== 'undefined' && !(request.feePayer === true && !request.feePayerSignature)) request_rpc.feeToken = request.feeToken; if (request.keyAuthorization) request_rpc.keyAuthorization = KeyAuthorization.toRpc(request.keyAuthorization); if (typeof request.capabilities !== 'undefined') request_rpc.capabilities = request.capabilities; if (typeof request.feePayer !== 'undefined') request_rpc.feePayer = request.feePayer; if (typeof request.keyData !== 'undefined') request_rpc.keyData = shimKeyData(request.keyData); if (typeof request.keyId !== 'undefined') request_rpc.keyId = request.keyId; if (typeof request.keyType !== 'undefined') request_rpc.keyType = request.keyType; if (typeof request.multisigInit !== 'undefined') request_rpc.multisigInit = request.multisigInit; if (typeof request.multisigSignatureCount !== 'undefined') request_rpc.multisigSignatureCount = request.multisigSignatureCount; if (typeof request.validBefore !== 'undefined') request_rpc.validBefore = Quantity.fromNumberish(request.validBefore); if (typeof request.validAfter !== 'undefined') request_rpc.validAfter = Quantity.fromNumberish(request.validAfter); const nonceKey = (() => { if (request.nonceKey === 'random') return Hex.random(24); if (request.nonceKey !== undefined) return Quantity.fromNumberish(request.nonceKey); return undefined; })(); if (nonceKey) request_rpc.nonceKey = nonceKey; if (tempo) { request_rpc.type = Transaction.toRpcType.tempo; delete request_rpc.data; delete request_rpc.input; delete request_rpc.to; delete request_rpc.value; } return request_rpc; } /** * Converts a Tempo {@link ox#TransactionRequest.TransactionRequest} to a {@link ox#TxEnvelopeTempo.TxEnvelopeTempo}. * * @example * ```ts twoslash * import { TransactionRequest } from 'ox/tempo' * * const envelope = TransactionRequest.toEnvelope({ * calls: [ * { * data: '0xdeadbeef', * to: '0xcafebabecafebabecafebabecafebabecafebabe' * } * ], * chainId: 1, * feeToken: '0x20c0000000000000000000000000000000000000', * maxFeePerGas: 1n * }) * ``` * * @param request - The transaction request to convert. * @param options - Options. * @returns A Tempo transaction envelope. */ export function toEnvelope(request, options = {}) { const calls = (() => { if (request.calls) return request.calls; const to = request.to || (!request.data || request.data === '0x' ? '0x0000000000000000000000000000000000000000' : undefined); return [ { ...(typeof to !== 'undefined' ? { to } : {}), ...(typeof request.data !== 'undefined' ? { data: request.data } : {}), ...(typeof request.value !== 'undefined' ? { value: request.value } : {}), }, ]; })(); const nonceKey = (() => { if (request.nonceKey === 'random') return Hex.toBigInt(Hex.random(24)); if (typeof request.nonceKey === 'bigint') return request.nonceKey; return undefined; })(); const input = { type: 'tempo', calls, chainId: request.chainId, ...(typeof request.accessList !== 'undefined' ? { accessList: request.accessList } : {}), ...(typeof request.authorizationList !== 'undefined' ? { authorizationList: request.authorizationList } : {}), ...(typeof request.feePayerSignature !== 'undefined' ? { feePayerSignature: request.feePayerSignature } : request.feePayer ? { feePayerSignature: null } : {}), ...(typeof request.feeToken !== 'undefined' ? { feeToken: request.feeToken } : {}), ...(typeof request.from !== 'undefined' ? { from: request.from } : {}), ...(typeof request.gas !== 'undefined' ? { gas: request.gas } : {}), ...(typeof request.keyAuthorization !== 'undefined' ? { keyAuthorization: request.keyAuthorization } : {}), ...(typeof request.maxFeePerGas !== 'undefined' ? { maxFeePerGas: request.maxFeePerGas } : {}), ...(typeof request.maxPriorityFeePerGas !== 'undefined' ? { maxPriorityFeePerGas: request.maxPriorityFeePerGas } : {}), ...(typeof request.nonce !== 'undefined' ? { nonce: request.nonce } : {}), ...(typeof nonceKey !== 'undefined' ? { nonceKey } : {}), ...(typeof request.signature !== 'undefined' ? { signature: request.signature } : {}), ...(typeof request.validAfter !== 'undefined' ? { validAfter: request.validAfter } : {}), ...(typeof request.validBefore !== 'undefined' ? { validBefore: request.validBefore } : {}), }; return TxEnvelopeTempo.from(input, options); } /** * Shims key data longer than 4 bytes into a 2-byte big-endian length hint. * The node's gas estimator only accepts 1, 2, or 4-byte key data as a * signature-size hint; anything else silently falls back to the default. * @internal */ function shimKeyData(data) { const byteLength = Hex.size(data); if (byteLength <= 4) return data; return Hex.fromNumber(byteLength, { size: 2 }); } //# sourceMappingURL=TransactionRequest.js.map