diff --git a/packages/ethereum/README.md b/packages/ethereum/README.md index b8d4449a..9c9a8d41 100644 --- a/packages/ethereum/README.md +++ b/packages/ethereum/README.md @@ -10,6 +10,7 @@ Ethereum JSON-RPC utilities for Oya kernel code. This package is a hardened kern - `createHttpConfig(options)`: validate explicit HTTP transport settings, re-exported from `@oyaprotocol/utils`. - `requestEthereumJsonRpc(options)`: send one JSON-RPC POST request with explicit config and injected `fetch`, returning the raw `result`, attempt count, id, and parsed response payload. +- `createTransactionPreparer(options)`: configure a reusable EIP-1559 preparer that fetches transaction fields and invokes a host signer, without broadcasting. - `ethSendRawTransaction(options)`: submit a signed raw transaction and return the transaction hash with attempt metadata. Callers may pass `transactionHash` when they already know the hash, allowing the wrapper to verify duplicate-style retry errors with `eth_getTransactionByHash`. - `ethGetTransactionReceipt(options)`: look up a transaction receipt, returning `{ receipt, attemptCount, response }`. The receipt is `null` when unavailable, including pending or unknown transactions. - `ethWaitForTransactionReceipt(options)`: poll for a receipt with an explicit overall deadline, poll interval, and optional cancellation signal. Returns `{ receipt, pollCount, attemptCount, response }` with a non-null receipt. @@ -39,11 +40,53 @@ Hosts own transaction signing, environment configuration, and RPC endpoint disco - `TransactionRequest`: readonly `to`, `data`, `value: bigint` (wei), and optional `signal`. It describes call intent; the host supplies the remaining transaction fields. - `SignedTransaction`: readonly signed `rawTransaction` and its `transactionHash`. +- `UnsignedTransaction`: readonly `to`, `data`, `value`, `type: 2`, `chainId: number` (positive safe integer), `nonce: number`, `gasLimit: bigint`, `maxFeePerGas: bigint`, and `maxPriorityFeePerGas: bigint`. The access list is empty. There is no embedded cancellation signal. +- `TransactionSigner`: a readonly `address` and `signTransaction(transaction, signal?)` method returning `SignedTransaction`, synchronously or asynchronously. The host implements signing and must preserve all supplied fields, use the advertised account, and return without broadcasting. - `TransactionPreparer`: a callback from `TransactionRequest` to `SignedTransaction`, synchronously or asynchronously, without broadcasting. - `TransactionStage`: `'prepare' | 'submit' | 'receipt' | 'verify'`. Verification means the operation's checks after receiving a receipt, such as execution status and expected events. Logger uses these shared types and always requests `value: 0n`. Other callers can use the same host preparation callback with a nonzero value. These names replace `LoggerTransactionRequest`, `PreparedLoggerTransaction`, `PrepareLoggerTransaction`, and `LogCidStage`; update type imports accordingly. +## Default Transaction Preparation + +`createTransactionPreparer(options)` in `src/transaction-preparer.ts` returns a `TransactionPreparer` compatible with `logCid` and the messages package's `publishAndLogSignedMessage`. The host supplies a `TransactionSigner`; no local wallet adapter, private-key handling, ethers, viem, or new dependency is included. + +```ts +import { createTransactionPreparer, logCid } from '@oyaprotocol/ethereum'; +import type { TransactionSigner } from '@oyaprotocol/ethereum'; + +declare const signer: TransactionSigner; // Implemented by the host's wallet/signing service. +const transactionPreparer = createTransactionPreparer({ + config: rpcConfig, + fetch: rpcFetch, + chainId: 1, // The operator's expected network; a positive safe integer. + signer, + gasLimitMarginPercent: 20, // Default: 20% above the estimate, rounded up. + baseFeeMultiplier: 2, // Default: 2 * base fee + suggested priority fee. + limits: { gasLimit: 200_000n, feePerGas: 30_000_000_000n }, // Illustrative operator-chosen caps. + timeoutMs: 30_000, // Default: overall preparation deadline, including signing. + id: 'prepare-42', // Optional; preparation RPCs default to ID 1. +}); + +const logging = await logCid(cid, { + config: rpcConfig, fetch: rpcFetch, loggerContract, + nodeAddress: signer.address, // Direct account call in this example. + transactionPreparer, timeoutMs: 60_000, pollIntervalMs: 1_000, signal, +}); +``` + +Construction validates and snapshots configuration without making RPC calls. `chainId` must be a `number` satisfying `Number.isSafeInteger(chainId) && chainId > 0`; bigint, string, fractional, nonpositive, and unsafe values are rejected. Update previous configurations such as `chainId: 1n` to `chainId: 1`. The signer receives the validated number and can use `BigInt(transaction.chainId)` if its wallet API requires bigint. + +Each invocation validates and snapshots the call, parses `eth_chainId` losslessly as bigint, and requires an exact match with `BigInt(chainId)`. Unsupported or mismatched RPC chain IDs reject before further RPC calls or signing; they are never rounded to a number. The preparer then reads `eth_getTransactionCount(address, "pending")`, obtains the pending block's base fee and gas limit, and reads `eth_maxPriorityFeePerGas`. It calls `eth_estimateGas` against pending state with the signing address, recipient, calldata, value, chain ID, nonce, and selected fees. Fee selection and gas estimation both use pending state, although that state can advance between separate RPC calls. These methods follow the [Ethereum execution API](https://github.com/ethereum/execution-apis/tree/main/src/eth); the fee fields follow [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559). + +The gas limit is `ceil(estimate * (100 + gasLimitMarginPercent) / 100)`. The maximum fee per gas is `baseFee * baseFeeMultiplier + suggestedPriorityFee`; the priority fee is the RPC suggestion. The multiplier and margin are policy choices, not protocol requirements. Arithmetic uses bigint, and fee values are in wei per gas. Nonces above `Number.MAX_SAFE_INTEGER` reject before conversion for the signer. Both optional `limits` fields are ceilings: the factory rejects a selected value above a ceiling instead of reducing the gas buffer or fee suggestion. Omitting them adds no operator ceiling; the buffered gas limit must still fit the pending block's gas limit. A configured gas cap must be positive; a fee cap of zero is permitted. Networks without EIP-1559 base-fee data, unsupported RPC methods, malformed quantities, estimation errors, and out-of-range values reject before signing. + +The signer receives a frozen transaction and a separate signal combining caller cancellation with the overall deadline. Each RPC read uses the existing transport timeout/retry policy. The whole preparation has no retries, and the signer is called at most once per invocation. Signer errors propagate; timeout/cancellation stops waiting even when the signer ignores its signal, and late results are discarded. The host should honor the signal where its signing API permits. Aborting cannot undo an external signing request already started. + +The returned result is a frozen snapshot. The factory checks byte formatting, the type-2 prefix, and that the supplied hash equals Keccak-256 of the returned bytes, using the existing `@noble/hashes` dependency. It does not decode the transaction or recover the signing account: the host signer remains responsible for a valid signature, the advertised account, and exact transaction fields. Only ordinary type-2 calls with an empty access list are supported; contract creation, legacy transactions, blobs, and smart-wallet execution wrapping require a custom preparer. A wallet API that only signs and broadcasts together cannot implement this signing contract. + +**The host coordinates nonces across the complete prepare/submit/receipt lifecycle for each account.** Serialize that lifecycle for the initial implementation, including other users of the account, and reconcile uncertain submissions before proceeding. The factory does not reserve, cache, or increment nonces and does not coordinate different processes. It refreshes chain values on every call; preparation alone cannot guarantee unique nonces before submission. Existing submission retries resend retained signed bytes rather than calling the preparer again. The factory's `id` applies to its read RPCs; Logger's optional `id` separately controls submission and receipt requests. + ## Transaction Receipts The host passes the hash returned by `ethSendRawTransaction(...)` to either receipt function, with the same explicit RPC config and injected fetch: @@ -145,7 +188,7 @@ const logging = await logCid(publication.cid, { // logging: { cid, transactionHash, receipt, event } ``` -`transactionPreparer` is a host-supplied `TransactionPreparer` function. It receives a frozen `{ to, data, value: 0n, signal? }` request describing the Logger call and returns `{ rawTransaction, transactionHash }`, synchronously or asynchronously. It must prepare and sign without broadcasting. The host supplies chain ID, nonce, fees, gas, and key or wallet access, and coordinates nonces across concurrent messages. It must return the correct hash for the signed transaction and preserve the requested call, including when routing through a contract wallet. The helper validates the returned hex shapes and checks the RPC's returned hash; it does not parse or independently verify the signed transaction. +`transactionPreparer` is a host-supplied `TransactionPreparer` function, which can be created with `createTransactionPreparer` above. It receives a frozen `{ to, data, value: 0n, signal? }` request describing the Logger call and returns `{ rawTransaction, transactionHash }`, synchronously or asynchronously. It must prepare and sign without broadcasting. The host selects the chain and preparation policy, supplies wallet access, and coordinates nonces across concurrent messages. It must return the correct hash for the signed transaction and preserve the requested call, including when routing through a contract wallet. The Logger helper validates the returned hex shapes and checks the RPC's returned hash; it does not parse or independently verify the signed transaction. The optional `id` accepts a nonempty string or a safe integer, including zero. It uses the existing RPC validation and defaults to `1` when omitted. The same ID is forwarded to submission, retries and recovery lookups, and every receipt poll. Invalid IDs reject before transaction preparation. This identifier is RPC metadata and is separate from the signed transaction's hash. diff --git a/packages/ethereum/dist/index.d.ts b/packages/ethereum/dist/index.d.ts index 3cd608c7..cdfa21f4 100644 --- a/packages/ethereum/dist/index.d.ts +++ b/packages/ethereum/dist/index.d.ts @@ -1,7 +1,9 @@ export { createHttpConfig, HttpStatusError } from '@oyaprotocol/utils'; export type { CreateHttpConfigOptions, HttpConfig, HttpFetchLike, HttpPostFetchLike, HttpPostFetchOptions, HttpStatusErrorOptions, HttpTextResponse, } from '@oyaprotocol/utils'; export { EthereumRawTransactionRecoveryError, ethSendRawTransaction, } from './transactions.js'; -export type { TransactionRequest, SignedTransaction, TransactionPreparer, TransactionStage, EthSendRawTransactionOptions, EthSendRawTransactionResult, } from './transactions.js'; +export type { TransactionRequest, SignedTransaction, UnsignedTransaction, TransactionSigner, TransactionPreparer, TransactionStage, EthSendRawTransactionOptions, EthSendRawTransactionResult, } from './transactions.js'; +export { createTransactionPreparer } from './transaction-preparer.js'; +export type { CreateTransactionPreparerOptions } from './transaction-preparer.js'; export { EthereumTransactionReceiptTimeoutError, ethGetTransactionReceipt, ethWaitForTransactionReceipt, } from './receipts.js'; export type { EthGetTransactionReceiptOptions, EthGetTransactionReceiptResult, EthWaitForTransactionReceiptOptions, EthWaitForTransactionReceiptResult, } from './receipts.js'; export type { EthereumReceiptLog, EthereumTransactionReceipt } from './receipt-utils.js'; diff --git a/packages/ethereum/dist/index.js b/packages/ethereum/dist/index.js index 714e6d4e..b6f1b50c 100644 --- a/packages/ethereum/dist/index.js +++ b/packages/ethereum/dist/index.js @@ -1,5 +1,6 @@ export { createHttpConfig, HttpStatusError } from '@oyaprotocol/utils'; export { EthereumRawTransactionRecoveryError, ethSendRawTransaction, } from './transactions.js'; +export { createTransactionPreparer } from './transaction-preparer.js'; export { EthereumTransactionReceiptTimeoutError, ethGetTransactionReceipt, ethWaitForTransactionReceipt, } from './receipts.js'; export { encodeLoggerCall, decodeLoggerEvent, hashLoggerCid, logCid, LogCidError } from './logger.js'; export { EthereumJsonRpcError, requestEthereumJsonRpc, } from './request-utils.js'; diff --git a/packages/ethereum/dist/index.js.map b/packages/ethereum/dist/index.js.map index af208883..65470407 100644 --- a/packages/ethereum/dist/index.js.map +++ b/packages/ethereum/dist/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAUvE,OAAO,EACH,mCAAmC,EACnC,qBAAqB,GACxB,MAAM,mBAAmB,CAAC;AAS3B,OAAO,EACH,sCAAsC,EACtC,wBAAwB,EACxB,4BAA4B,GAC/B,MAAM,eAAe,CAAC;AAQvB,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAKtG,OAAO,EACH,oBAAoB,EACpB,sBAAsB,GACzB,MAAM,oBAAoB,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAUvE,OAAO,EACH,mCAAmC,EACnC,qBAAqB,GACxB,MAAM,mBAAmB,CAAC;AAW3B,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAEtE,OAAO,EACH,sCAAsC,EACtC,wBAAwB,EACxB,4BAA4B,GAC/B,MAAM,eAAe,CAAC;AAQvB,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAKtG,OAAO,EACH,oBAAoB,EACpB,sBAAsB,GACzB,MAAM,oBAAoB,CAAC"} \ No newline at end of file diff --git a/packages/ethereum/dist/logger.js b/packages/ethereum/dist/logger.js index 61464c1f..f64a09c6 100644 --- a/packages/ethereum/dist/logger.js +++ b/packages/ethereum/dist/logger.js @@ -1,7 +1,7 @@ import { keccak_256 } from '@noble/hashes/sha3.js'; import { bytesToHex } from '@noble/hashes/utils.js'; -import { assertCanonicalCid, assertHexData, createHttpConfig, invokeWithAbort, isPlainObject, parseBytes, throwIfSignalAborted, } from '@oyaprotocol/utils'; -import { assertTimerMs, ethWaitForTransactionReceipt } from './receipts.js'; +import { assertCanonicalCid, assertHexData, assertTimerMs, createHttpConfig, invokeWithAbort, isPlainObject, parseBytes, throwIfSignalAborted, } from '@oyaprotocol/utils'; +import { ethWaitForTransactionReceipt } from './receipts.js'; import { normalizeJsonRpcId } from './request-utils.js'; import { ethSendRawTransaction } from './transactions.js'; // Verified against contracts/src/Logger.sol with forge inspect and cast keccak. diff --git a/packages/ethereum/dist/logger.js.map b/packages/ethereum/dist/logger.js.map index 4ae0172e..4e4a0104 100644 --- a/packages/ethereum/dist/logger.js.map +++ b/packages/ethereum/dist/logger.js.map @@ -1 +1 @@ -{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/ethereum/dist/receipt-utils.js b/packages/ethereum/dist/receipt-utils.js index ba565571..fb8c216f 100644 --- a/packages/ethereum/dist/receipt-utils.js +++ b/packages/ethereum/dist/receipt-utils.js @@ -1,10 +1,5 @@ import { isPlainObject, parseBytes } from '@oyaprotocol/utils'; -function parseQuantity(value, name) { - if (typeof value !== 'string' || !/^0x(?:0|[1-9a-fA-F][0-9a-fA-F]*)$/.test(value)) { - throw new Error(`${name} must be an Ethereum quantity hex string without leading zeros.`); - } - return BigInt(value); -} +import { parseQuantity } from './request-utils.js'; function assertMatchingHash(actual, expected, name) { if (actual.toLowerCase() !== expected.toLowerCase()) { throw new Error(`${name} did not match the expected hash.`); diff --git a/packages/ethereum/dist/receipt-utils.js.map b/packages/ethereum/dist/receipt-utils.js.map index db63e5fa..5b651a60 100644 --- a/packages/ethereum/dist/receipt-utils.js.map +++ b/packages/ethereum/dist/receipt-utils.js.map @@ -1 +1 @@ -{"version":3,"file":"receipt-utils.js","sourceRoot":"","sources":["../src/receipt-utils.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"receipt-utils.js","sourceRoot":"","sources":["../src/receipt-utils.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/ethereum/dist/receipts.d.ts b/packages/ethereum/dist/receipts.d.ts index e9ffa3c9..a0136e7f 100644 --- a/packages/ethereum/dist/receipts.d.ts +++ b/packages/ethereum/dist/receipts.d.ts @@ -30,8 +30,7 @@ declare class EthereumTransactionReceiptTimeoutError extends Error { readonly pollCount: number; constructor(transactionHash: string, timeoutMs: number, pollCount: number, options?: ErrorOptions); } -declare function assertTimerMs(value: unknown, name: string): number; declare function ethGetTransactionReceipt({ config, fetch, transactionHash, id, signal, }: EthGetTransactionReceiptOptions): Promise; declare function ethWaitForTransactionReceipt({ config, fetch, transactionHash, id, signal, timeoutMs, pollIntervalMs, }: EthWaitForTransactionReceiptOptions): Promise; -export { assertTimerMs, EthereumTransactionReceiptTimeoutError, ethGetTransactionReceipt, ethWaitForTransactionReceipt }; +export { EthereumTransactionReceiptTimeoutError, ethGetTransactionReceipt, ethWaitForTransactionReceipt }; export type { EthGetTransactionReceiptOptions, EthGetTransactionReceiptResult, EthWaitForTransactionReceiptOptions, EthWaitForTransactionReceiptResult, }; diff --git a/packages/ethereum/dist/receipts.js b/packages/ethereum/dist/receipts.js index bc7e21ca..3a8fd7bd 100644 --- a/packages/ethereum/dist/receipts.js +++ b/packages/ethereum/dist/receipts.js @@ -1,4 +1,4 @@ -import { assertBytes32HexString, assertPositiveInteger, combineAbortSignals, createTimeoutSignal, throwIfSignalAborted, waitForRetryDelay, } from '@oyaprotocol/utils'; +import { assertBytes32HexString, assertTimerMs, combineAbortSignals, createTimeoutSignal, throwIfSignalAborted, waitForRetryDelay, } from '@oyaprotocol/utils'; import { parseTransactionReceipt } from './receipt-utils.js'; import { requestEthereumJsonRpc } from './request-utils.js'; class EthereumTransactionReceiptTimeoutError extends Error { @@ -13,13 +13,6 @@ class EthereumTransactionReceiptTimeoutError extends Error { this.pollCount = pollCount; } } -function assertTimerMs(value, name) { - const duration = assertPositiveInteger(value, name); - if (duration > 2_147_483_647) { - throw new Error(`${name} must not exceed 2147483647 ms.`); - } - return duration; -} async function ethGetTransactionReceipt({ config, fetch, transactionHash, id, signal, }) { const validatedHash = assertBytes32HexString(transactionHash, 'transactionHash'); const result = await requestEthereumJsonRpc({ @@ -83,5 +76,5 @@ async function ethWaitForTransactionReceipt({ config, fetch, transactionHash, id timeout.cleanup?.(); } } -export { assertTimerMs, EthereumTransactionReceiptTimeoutError, ethGetTransactionReceipt, ethWaitForTransactionReceipt }; +export { EthereumTransactionReceiptTimeoutError, ethGetTransactionReceipt, ethWaitForTransactionReceipt }; //# sourceMappingURL=receipts.js.map \ No newline at end of file diff --git a/packages/ethereum/dist/receipts.js.map b/packages/ethereum/dist/receipts.js.map index a0fc4ce3..966b0e95 100644 --- a/packages/ethereum/dist/receipts.js.map +++ b/packages/ethereum/dist/receipts.js.map @@ -1 +1 @@ -{"version":3,"file":"receipts.js","sourceRoot":"","sources":["../src/receipts.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"receipts.js","sourceRoot":"","sources":["../src/receipts.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/ethereum/dist/request-utils.d.ts b/packages/ethereum/dist/request-utils.d.ts index 3b5195ee..5850dfa6 100644 --- a/packages/ethereum/dist/request-utils.d.ts +++ b/packages/ethereum/dist/request-utils.d.ts @@ -32,6 +32,8 @@ declare class EthereumJsonRpcError extends Error { constructor(error: JsonRpcErrorPayload, { method, response, attemptCount }: EthereumJsonRpcErrorOptions); } declare function normalizeJsonRpcId(id: unknown): string | number; +declare function parseQuantity(value: unknown, name: string): bigint; +declare function parseTransactionQuantity(value: unknown, name: string): bigint; declare function requestEthereumJsonRpcWithCustomRetryPolicy({ config, fetch, method, params, id, signal, }: RequestEthereumJsonRpcOptions, shouldRetryJsonRpcMethod: (method: string) => boolean): Promise>; declare function requestEthereumJsonRpc(options: RequestEthereumJsonRpcOptions): Promise>; -export { EthereumJsonRpcError, normalizeJsonRpcId, requestEthereumJsonRpc, requestEthereumJsonRpcWithCustomRetryPolicy, }; +export { EthereumJsonRpcError, normalizeJsonRpcId, parseQuantity, parseTransactionQuantity, requestEthereumJsonRpc, requestEthereumJsonRpcWithCustomRetryPolicy, }; diff --git a/packages/ethereum/dist/request-utils.js b/packages/ethereum/dist/request-utils.js index 1bcc652a..5b4bd2dc 100644 --- a/packages/ethereum/dist/request-utils.js +++ b/packages/ethereum/dist/request-utils.js @@ -102,6 +102,18 @@ function normalizeJsonRpcId(id) { } throw new Error('id must be a non-empty string or safe integer.'); } +function parseQuantity(value, name) { + if (typeof value !== 'string' || !/^0x(?:0|[1-9a-fA-F][0-9a-fA-F]*)$/.test(value)) { + throw new Error(`${name} must be an Ethereum quantity hex string without leading zeros.`); + } + return BigInt(value); +} +function parseTransactionQuantity(value, name) { + if (typeof value === 'string' && value.length > 66) { + throw new Error(`${name} must fit in 256 bits.`); + } + return parseQuantity(value, name); +} function buildJsonRpcBody({ id, method, params, }) { try { return JSON.stringify({ @@ -223,5 +235,5 @@ async function requestEthereumJsonRpcWithCustomRetryPolicy({ config, fetch, meth async function requestEthereumJsonRpc(options) { return await requestEthereumJsonRpcWithCustomRetryPolicy(options, shouldRetryMethod); } -export { EthereumJsonRpcError, normalizeJsonRpcId, requestEthereumJsonRpc, requestEthereumJsonRpcWithCustomRetryPolicy, }; +export { EthereumJsonRpcError, normalizeJsonRpcId, parseQuantity, parseTransactionQuantity, requestEthereumJsonRpc, requestEthereumJsonRpcWithCustomRetryPolicy, }; //# sourceMappingURL=request-utils.js.map \ No newline at end of file diff --git a/packages/ethereum/dist/request-utils.js.map b/packages/ethereum/dist/request-utils.js.map index e6c38ac7..85ff6942 100644 --- a/packages/ethereum/dist/request-utils.js.map +++ b/packages/ethereum/dist/request-utils.js.map @@ -1 +1 @@ -{"version":3,"file":"request-utils.js","sourceRoot":"","sources":["../src/request-utils.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"request-utils.js","sourceRoot":"","sources":["../src/request-utils.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/ethereum/dist/transaction-preparer.d.ts b/packages/ethereum/dist/transaction-preparer.d.ts new file mode 100644 index 00000000..c5aa9fd3 --- /dev/null +++ b/packages/ethereum/dist/transaction-preparer.d.ts @@ -0,0 +1,26 @@ +import type { HttpConfig, HttpPostFetchLike } from '@oyaprotocol/utils'; +import type { TransactionPreparer, TransactionSigner } from './transactions.js'; +interface CreateTransactionPreparerOptions { + config: HttpConfig; + fetch: HttpPostFetchLike; + /** Expected network ID; must be a positive safe integer. */ + chainId: number; + signer: TransactionSigner; + /** Whole percent added to the estimate, rounded up. Default: 20. */ + gasLimitMarginPercent?: number; + /** Integer multiplier for the pending block's base fee. Default: 2. */ + baseFeeMultiplier?: number; + /** Exceeding either optional ceiling rejects before signing. */ + limits?: { + gasLimit?: bigint; + feePerGas?: bigint; + }; + /** Overall preparation deadline, including signing. Default: 30,000 ms. */ + timeoutMs?: number; + /** JSON-RPC ID for preparation reads. Default: 1. */ + id?: string | number; +} +/** Prepare direct account calls; the host coordinates nonces through submission. */ +declare function createTransactionPreparer({ config, fetch, chainId, signer, gasLimitMarginPercent, baseFeeMultiplier, limits, timeoutMs, id, }: CreateTransactionPreparerOptions): TransactionPreparer; +export { createTransactionPreparer }; +export type { CreateTransactionPreparerOptions }; diff --git a/packages/ethereum/dist/transaction-preparer.js b/packages/ethereum/dist/transaction-preparer.js new file mode 100644 index 00000000..99d0332a --- /dev/null +++ b/packages/ethereum/dist/transaction-preparer.js @@ -0,0 +1,125 @@ +import { keccak_256 } from '@noble/hashes/sha3.js'; +import { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'; +import { assertTimerMs, assertUint256, createHttpConfig, isPlainObject, parseBytes, runWithRetry, throwIfSignalAborted, } from '@oyaprotocol/utils'; +import { normalizeJsonRpcId, parseTransactionQuantity, requestEthereumJsonRpc } from './request-utils.js'; +/** Prepare direct account calls; the host coordinates nonces through submission. */ +function createTransactionPreparer({ config, fetch, chainId, signer, gasLimitMarginPercent = 20, baseFeeMultiplier = 2, limits, timeoutMs = 30_000, id, }) { + const rpcConfig = createHttpConfig(config); + assertTimerMs(rpcConfig.timeoutMs, 'config.timeoutMs'); + const deadlineMs = assertTimerMs(timeoutMs, 'timeoutMs'); + if (!Number.isSafeInteger(chainId) || chainId < 1) { + throw new Error('chainId must be a positive safe integer.'); + } + const expectedChainId = BigInt(chainId); + const requestId = normalizeJsonRpcId(id); + if (typeof fetch !== 'function') { + throw new TypeError('fetch must be provided as a function.'); + } + if (signer == null || typeof signer.signTransaction !== 'function') { + throw new TypeError('signer.signTransaction must be provided as a function.'); + } + const signerAddress = parseBytes(signer.address, 'signer.address', 20); + const signTransaction = signer.signTransaction.bind(signer); + if (!Number.isSafeInteger(gasLimitMarginPercent) || gasLimitMarginPercent < 0) { + throw new Error('gasLimitMarginPercent must be a non-negative safe integer.'); + } + if (!Number.isSafeInteger(baseFeeMultiplier) || baseFeeMultiplier < 1) { + throw new Error('baseFeeMultiplier must be a positive safe integer.'); + } + if (limits !== undefined && !isPlainObject(limits)) { + throw new TypeError('limits must be a plain object.'); + } + const gasLimitCap = limits?.gasLimit === undefined + ? undefined : assertUint256(limits.gasLimit, 'limits.gasLimit'); + const feePerGasCap = limits?.feePerGas === undefined + ? undefined : assertUint256(limits.feePerGas, 'limits.feePerGas'); + if (gasLimitCap === 0n) { + throw new Error('limits.gasLimit must be positive.'); + } + return async ({ to, data, value, signal }) => { + const call = { + to: parseBytes(to, 'to', 20), + data: parseBytes(data, 'data'), + value: assertUint256(value, 'value'), + }; + const abortMessage = 'Transaction preparation was aborted by the caller.'; + return await runWithRetry({ + maxRetries: 0, retryDelayMs: 0, timeoutMs: deadlineMs, signal, + abortErrorMessage: abortMessage, + shouldRetry: () => false, + normalizeError: (error) => error instanceof Error + ? error : new Error('Transaction preparation failed.', { cause: error }), + run: async ({ signal: operationSignal }) => { + const rpc = async (method, params = []) => { + const response = await requestEthereumJsonRpc({ + config: rpcConfig, fetch, method, params, id: requestId, + ...(operationSignal === undefined ? {} : { signal: operationSignal }), + }); + return response.result; + }; + const actualChainId = parseTransactionQuantity(await rpc('eth_chainId'), 'eth_chainId result'); + if (actualChainId !== expectedChainId) { + throw new Error(`RPC chain ID ${actualChainId} did not match configured chainId ${expectedChainId}.`); + } + const nonce = parseTransactionQuantity(await rpc('eth_getTransactionCount', [signerAddress, 'pending']), 'eth_getTransactionCount result'); + if (nonce > BigInt(Number.MAX_SAFE_INTEGER)) { + throw new Error('Transaction nonce must fit in a safe integer.'); + } + const block = await rpc('eth_getBlockByNumber', ['pending', false]); + if (!isPlainObject(block) || block.baseFeePerGas === undefined || block.baseFeePerGas === null) { + throw new Error('Pending block must include baseFeePerGas for EIP-1559 transaction preparation.'); + } + const baseFee = parseTransactionQuantity(block.baseFeePerGas, 'block.baseFeePerGas'); + const blockGasLimit = parseTransactionQuantity(block.gasLimit, 'block.gasLimit'); + if (blockGasLimit === 0n) { + throw new Error('block.gasLimit must be positive.'); + } + const maxPriorityFeePerGas = parseTransactionQuantity(await rpc('eth_maxPriorityFeePerGas'), 'eth_maxPriorityFeePerGas result'); + const maxFeePerGas = assertUint256(baseFee * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas, 'maxFeePerGas'); + if (feePerGasCap !== undefined && maxFeePerGas > feePerGasCap) { + throw new Error('Calculated maxFeePerGas exceeds limits.feePerGas.'); + } + const estimate = parseTransactionQuantity(await rpc('eth_estimateGas', [{ + from: signerAddress, to: call.to, data: call.data, + value: `0x${call.value.toString(16)}`, + type: '0x2', chainId: `0x${expectedChainId.toString(16)}`, + nonce: `0x${nonce.toString(16)}`, + maxFeePerGas: `0x${maxFeePerGas.toString(16)}`, + maxPriorityFeePerGas: `0x${maxPriorityFeePerGas.toString(16)}`, + }, 'pending']), 'eth_estimateGas result'); + if (estimate === 0n) { + throw new Error('eth_estimateGas result must be positive.'); + } + const gasLimit = (estimate * (100n + BigInt(gasLimitMarginPercent)) + 99n) / 100n; + if (gasLimit > blockGasLimit) { + throw new Error('Buffered gas limit exceeds the pending block gas limit.'); + } + if (gasLimitCap !== undefined && gasLimit > gasLimitCap) { + throw new Error('Buffered gas limit exceeds limits.gasLimit.'); + } + const transaction = Object.freeze({ + ...call, type: 2, chainId, nonce: Number(nonce), + gasLimit, maxFeePerGas, maxPriorityFeePerGas, + }); + throwIfSignalAborted(operationSignal, abortMessage, operationSignal?.reason); + const signed = await signTransaction(transaction, operationSignal); + throwIfSignalAborted(operationSignal, abortMessage, operationSignal?.reason); + if (!isPlainObject(signed)) { + throw new TypeError('signer.signTransaction must return a plain object.'); + } + const rawTransaction = parseBytes(signed.rawTransaction, 'rawTransaction'); + const transactionHash = parseBytes(signed.transactionHash, 'transactionHash', 32); + if (!rawTransaction.startsWith('0x02') || rawTransaction.length <= 4) { + throw new Error('rawTransaction must contain a signed EIP-1559 type-2 transaction.'); + } + const computedHash = `0x${bytesToHex(keccak_256(hexToBytes(rawTransaction.slice(2))))}`; + if (computedHash !== transactionHash.toLowerCase()) { + throw new Error('transactionHash did not match the signed rawTransaction bytes.'); + } + return Object.freeze({ rawTransaction, transactionHash }); + }, + }); + }; +} +export { createTransactionPreparer }; +//# sourceMappingURL=transaction-preparer.js.map \ No newline at end of file diff --git a/packages/ethereum/dist/transaction-preparer.js.map b/packages/ethereum/dist/transaction-preparer.js.map new file mode 100644 index 00000000..932a0355 --- /dev/null +++ b/packages/ethereum/dist/transaction-preparer.js.map @@ -0,0 +1 @@ +{"version":3,"file":"transaction-preparer.js","sourceRoot":"","sources":["../src/transaction-preparer.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/ethereum/dist/transactions.d.ts b/packages/ethereum/dist/transactions.d.ts index 902776db..7dcfddf2 100644 --- a/packages/ethereum/dist/transactions.d.ts +++ b/packages/ethereum/dist/transactions.d.ts @@ -12,6 +12,23 @@ interface SignedTransaction { readonly rawTransaction: string; readonly transactionHash: string; } +/** Fully specified EIP-1559 call with an empty access list. */ +interface UnsignedTransaction extends Omit { + readonly type: 2; + /** Positive safe integer identifying the expected network. */ + readonly chainId: number; + /** Nonces outside the safe integer range are rejected before signing. */ + readonly nonce: number; + readonly gasLimit: bigint; + readonly maxFeePerGas: bigint; + readonly maxPriorityFeePerGas: bigint; +} +interface TransactionSigner { + /** Account signing the outer Ethereum transaction. */ + readonly address: string; + /** Preserve all supplied fields and sign without broadcasting. */ + signTransaction(transaction: Readonly, signal?: AbortSignal): SignedTransaction | PromiseLike; +} /** Prepare and sign the requested call without broadcasting it. */ type TransactionPreparer = (request: TransactionRequest) => SignedTransaction | PromiseLike; /** Verify covers operation-specific checks after receipt observation. */ @@ -45,4 +62,4 @@ declare class EthereumRawTransactionRecoveryError extends Error { } declare function ethSendRawTransaction({ config, fetch, rawTransaction, transactionHash, id, signal, }: EthSendRawTransactionOptions): Promise; export { EthereumRawTransactionRecoveryError, ethSendRawTransaction, }; -export type { TransactionRequest, SignedTransaction, TransactionPreparer, TransactionStage, EthSendRawTransactionOptions, EthSendRawTransactionResult, }; +export type { TransactionRequest, SignedTransaction, UnsignedTransaction, TransactionSigner, TransactionPreparer, TransactionStage, EthSendRawTransactionOptions, EthSendRawTransactionResult, }; diff --git a/packages/ethereum/dist/transactions.js.map b/packages/ethereum/dist/transactions.js.map index 78a22655..b952847a 100644 --- a/packages/ethereum/dist/transactions.js.map +++ b/packages/ethereum/dist/transactions.js.map @@ -1 +1 @@ -{"version":3,"file":"transactions.js","sourceRoot":"","sources":["../src/transactions.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"transactions.js","sourceRoot":"","sources":["../src/transactions.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/ethereum/src/index.ts b/packages/ethereum/src/index.ts index d84caa8d..3316d0da 100644 --- a/packages/ethereum/src/index.ts +++ b/packages/ethereum/src/index.ts @@ -15,11 +15,15 @@ export { export type { TransactionRequest, SignedTransaction, + UnsignedTransaction, + TransactionSigner, TransactionPreparer, TransactionStage, EthSendRawTransactionOptions, EthSendRawTransactionResult, } from './transactions.js'; +export { createTransactionPreparer } from './transaction-preparer.js'; +export type { CreateTransactionPreparerOptions } from './transaction-preparer.js'; export { EthereumTransactionReceiptTimeoutError, ethGetTransactionReceipt, diff --git a/packages/ethereum/src/logger.ts b/packages/ethereum/src/logger.ts index eaa8a2de..3b90631b 100644 --- a/packages/ethereum/src/logger.ts +++ b/packages/ethereum/src/logger.ts @@ -3,6 +3,7 @@ import { bytesToHex } from '@noble/hashes/utils.js'; import { assertCanonicalCid, assertHexData, + assertTimerMs, createHttpConfig, invokeWithAbort, isPlainObject, @@ -11,7 +12,7 @@ import { } from '@oyaprotocol/utils'; import type { EthereumReceiptLog, EthereumTransactionReceipt } from './receipt-utils.js'; -import { assertTimerMs, ethWaitForTransactionReceipt } from './receipts.js'; +import { ethWaitForTransactionReceipt } from './receipts.js'; import type { EthWaitForTransactionReceiptOptions } from './receipts.js'; import { normalizeJsonRpcId } from './request-utils.js'; import { ethSendRawTransaction } from './transactions.js'; diff --git a/packages/ethereum/src/receipt-utils.ts b/packages/ethereum/src/receipt-utils.ts index 3c5b8df9..8ce19bc5 100644 --- a/packages/ethereum/src/receipt-utils.ts +++ b/packages/ethereum/src/receipt-utils.ts @@ -1,4 +1,5 @@ import { isPlainObject, parseBytes } from '@oyaprotocol/utils'; +import { parseQuantity } from './request-utils.js'; interface EthereumReceiptLog { readonly address: string; @@ -34,13 +35,6 @@ interface EthereumTransactionReceipt { readonly blobGasPrice?: bigint; } -function parseQuantity(value: unknown, name: string): bigint { - if (typeof value !== 'string' || !/^0x(?:0|[1-9a-fA-F][0-9a-fA-F]*)$/.test(value)) { - throw new Error(`${name} must be an Ethereum quantity hex string without leading zeros.`); - } - return BigInt(value); -} - function assertMatchingHash(actual: string, expected: string, name: string): void { if (actual.toLowerCase() !== expected.toLowerCase()) { throw new Error(`${name} did not match the expected hash.`); diff --git a/packages/ethereum/src/receipts.ts b/packages/ethereum/src/receipts.ts index dc6bb4d3..a4c08c8e 100644 --- a/packages/ethereum/src/receipts.ts +++ b/packages/ethereum/src/receipts.ts @@ -1,6 +1,6 @@ import { assertBytes32HexString, - assertPositiveInteger, + assertTimerMs, combineAbortSignals, createTimeoutSignal, throwIfSignalAborted, @@ -54,14 +54,6 @@ class EthereumTransactionReceiptTimeoutError extends Error { } } -function assertTimerMs(value: unknown, name: string): number { - const duration = assertPositiveInteger(value, name); - if (duration > 2_147_483_647) { - throw new Error(`${name} must not exceed 2147483647 ms.`); - } - return duration; -} - async function ethGetTransactionReceipt({ config, fetch, @@ -139,7 +131,7 @@ async function ethWaitForTransactionReceipt({ } } -export { assertTimerMs, EthereumTransactionReceiptTimeoutError, ethGetTransactionReceipt, ethWaitForTransactionReceipt }; +export { EthereumTransactionReceiptTimeoutError, ethGetTransactionReceipt, ethWaitForTransactionReceipt }; export type { EthGetTransactionReceiptOptions, EthGetTransactionReceiptResult, diff --git a/packages/ethereum/src/request-utils.ts b/packages/ethereum/src/request-utils.ts index f4327b39..9ccb337b 100644 --- a/packages/ethereum/src/request-utils.ts +++ b/packages/ethereum/src/request-utils.ts @@ -150,6 +150,20 @@ function normalizeJsonRpcId(id: unknown): string | number { throw new Error('id must be a non-empty string or safe integer.'); } +function parseQuantity(value: unknown, name: string): bigint { + if (typeof value !== 'string' || !/^0x(?:0|[1-9a-fA-F][0-9a-fA-F]*)$/.test(value)) { + throw new Error(`${name} must be an Ethereum quantity hex string without leading zeros.`); + } + return BigInt(value); +} + +function parseTransactionQuantity(value: unknown, name: string): bigint { + if (typeof value === 'string' && value.length > 66) { + throw new Error(`${name} must fit in 256 bits.`); + } + return parseQuantity(value, name); +} + function buildJsonRpcBody({ id, method, @@ -316,6 +330,8 @@ async function requestEthereumJsonRpc( export { EthereumJsonRpcError, normalizeJsonRpcId, + parseQuantity, + parseTransactionQuantity, requestEthereumJsonRpc, requestEthereumJsonRpcWithCustomRetryPolicy, }; diff --git a/packages/ethereum/src/transaction-preparer.ts b/packages/ethereum/src/transaction-preparer.ts new file mode 100644 index 00000000..da59544a --- /dev/null +++ b/packages/ethereum/src/transaction-preparer.ts @@ -0,0 +1,167 @@ +import { keccak_256 } from '@noble/hashes/sha3.js'; +import { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'; +import { + assertTimerMs, + assertUint256, + createHttpConfig, + isPlainObject, + parseBytes, + runWithRetry, + throwIfSignalAborted, +} from '@oyaprotocol/utils'; +import type { HttpConfig, HttpPostFetchLike } from '@oyaprotocol/utils'; + +import { normalizeJsonRpcId, parseTransactionQuantity, requestEthereumJsonRpc } from './request-utils.js'; +import type { SignedTransaction, TransactionPreparer, TransactionSigner, UnsignedTransaction } from './transactions.js'; + +interface CreateTransactionPreparerOptions { + config: HttpConfig; + fetch: HttpPostFetchLike; + /** Expected network ID; must be a positive safe integer. */ + chainId: number; + signer: TransactionSigner; + /** Whole percent added to the estimate, rounded up. Default: 20. */ + gasLimitMarginPercent?: number; + /** Integer multiplier for the pending block's base fee. Default: 2. */ + baseFeeMultiplier?: number; + /** Exceeding either optional ceiling rejects before signing. */ + limits?: { gasLimit?: bigint; feePerGas?: bigint }; + /** Overall preparation deadline, including signing. Default: 30,000 ms. */ + timeoutMs?: number; + /** JSON-RPC ID for preparation reads. Default: 1. */ + id?: string | number; +} + +/** Prepare direct account calls; the host coordinates nonces through submission. */ +function createTransactionPreparer({ + config, fetch, chainId, signer, gasLimitMarginPercent = 20, + baseFeeMultiplier = 2, limits, timeoutMs = 30_000, id, +}: CreateTransactionPreparerOptions): TransactionPreparer { + const rpcConfig = createHttpConfig(config); + assertTimerMs(rpcConfig.timeoutMs, 'config.timeoutMs'); + const deadlineMs = assertTimerMs(timeoutMs, 'timeoutMs'); + if (!Number.isSafeInteger(chainId) || chainId < 1) { + throw new Error('chainId must be a positive safe integer.'); + } + const expectedChainId = BigInt(chainId); + const requestId = normalizeJsonRpcId(id); + if (typeof fetch !== 'function') { + throw new TypeError('fetch must be provided as a function.'); + } + if (signer == null || typeof signer.signTransaction !== 'function') { + throw new TypeError('signer.signTransaction must be provided as a function.'); + } + const signerAddress = parseBytes(signer.address, 'signer.address', 20); + const signTransaction = signer.signTransaction.bind(signer); + if (!Number.isSafeInteger(gasLimitMarginPercent) || gasLimitMarginPercent < 0) { + throw new Error('gasLimitMarginPercent must be a non-negative safe integer.'); + } + if (!Number.isSafeInteger(baseFeeMultiplier) || baseFeeMultiplier < 1) { + throw new Error('baseFeeMultiplier must be a positive safe integer.'); + } + if (limits !== undefined && !isPlainObject(limits)) { + throw new TypeError('limits must be a plain object.'); + } + const gasLimitCap = limits?.gasLimit === undefined + ? undefined : assertUint256(limits.gasLimit, 'limits.gasLimit'); + const feePerGasCap = limits?.feePerGas === undefined + ? undefined : assertUint256(limits.feePerGas, 'limits.feePerGas'); + if (gasLimitCap === 0n) { + throw new Error('limits.gasLimit must be positive.'); + } + + return async ({ to, data, value, signal }) => { + const call = { + to: parseBytes(to, 'to', 20), + data: parseBytes(data, 'data'), + value: assertUint256(value, 'value'), + }; + const abortMessage = 'Transaction preparation was aborted by the caller.'; + return await runWithRetry({ + maxRetries: 0, retryDelayMs: 0, timeoutMs: deadlineMs, signal, + abortErrorMessage: abortMessage, + shouldRetry: () => false, + normalizeError: (error) => error instanceof Error + ? error : new Error('Transaction preparation failed.', { cause: error }), + run: async ({ signal: operationSignal }) => { + const rpc = async (method: string, params: readonly unknown[] = []): Promise => { + const response = await requestEthereumJsonRpc({ + config: rpcConfig, fetch, method, params, id: requestId, + ...(operationSignal === undefined ? {} : { signal: operationSignal }), + }); + return response.result; + }; + const actualChainId = parseTransactionQuantity(await rpc('eth_chainId'), 'eth_chainId result'); + if (actualChainId !== expectedChainId) { + throw new Error(`RPC chain ID ${actualChainId} did not match configured chainId ${expectedChainId}.`); + } + const nonce = parseTransactionQuantity( + await rpc('eth_getTransactionCount', [signerAddress, 'pending']), + 'eth_getTransactionCount result', + ); + if (nonce > BigInt(Number.MAX_SAFE_INTEGER)) { + throw new Error('Transaction nonce must fit in a safe integer.'); + } + const block = await rpc('eth_getBlockByNumber', ['pending', false]); + if (!isPlainObject(block) || block.baseFeePerGas === undefined || block.baseFeePerGas === null) { + throw new Error('Pending block must include baseFeePerGas for EIP-1559 transaction preparation.'); + } + const baseFee = parseTransactionQuantity(block.baseFeePerGas, 'block.baseFeePerGas'); + const blockGasLimit = parseTransactionQuantity(block.gasLimit, 'block.gasLimit'); + if (blockGasLimit === 0n) { + throw new Error('block.gasLimit must be positive.'); + } + const maxPriorityFeePerGas = parseTransactionQuantity( + await rpc('eth_maxPriorityFeePerGas'), 'eth_maxPriorityFeePerGas result', + ); + const maxFeePerGas = assertUint256( + baseFee * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas, 'maxFeePerGas', + ); + if (feePerGasCap !== undefined && maxFeePerGas > feePerGasCap) { + throw new Error('Calculated maxFeePerGas exceeds limits.feePerGas.'); + } + const estimate = parseTransactionQuantity(await rpc('eth_estimateGas', [{ + from: signerAddress, to: call.to, data: call.data, + value: `0x${call.value.toString(16)}`, + type: '0x2', chainId: `0x${expectedChainId.toString(16)}`, + nonce: `0x${nonce.toString(16)}`, + maxFeePerGas: `0x${maxFeePerGas.toString(16)}`, + maxPriorityFeePerGas: `0x${maxPriorityFeePerGas.toString(16)}`, + }, 'pending']), 'eth_estimateGas result'); + if (estimate === 0n) { + throw new Error('eth_estimateGas result must be positive.'); + } + const gasLimit = (estimate * (100n + BigInt(gasLimitMarginPercent)) + 99n) / 100n; + if (gasLimit > blockGasLimit) { + throw new Error('Buffered gas limit exceeds the pending block gas limit.'); + } + if (gasLimitCap !== undefined && gasLimit > gasLimitCap) { + throw new Error('Buffered gas limit exceeds limits.gasLimit.'); + } + const transaction: Readonly = Object.freeze({ + ...call, type: 2, chainId, nonce: Number(nonce), + gasLimit, maxFeePerGas, maxPriorityFeePerGas, + }); + throwIfSignalAborted(operationSignal, abortMessage, operationSignal?.reason); + const signed = await signTransaction(transaction, operationSignal); + throwIfSignalAborted(operationSignal, abortMessage, operationSignal?.reason); + if (!isPlainObject(signed)) { + throw new TypeError('signer.signTransaction must return a plain object.'); + } + const rawTransaction = parseBytes(signed.rawTransaction, 'rawTransaction'); + const transactionHash = parseBytes(signed.transactionHash, 'transactionHash', 32); + if (!rawTransaction.startsWith('0x02') || rawTransaction.length <= 4) { + throw new Error('rawTransaction must contain a signed EIP-1559 type-2 transaction.'); + } + const computedHash = `0x${bytesToHex(keccak_256(hexToBytes(rawTransaction.slice(2))))}`; + if (computedHash !== transactionHash.toLowerCase()) { + throw new Error('transactionHash did not match the signed rawTransaction bytes.'); + } + return Object.freeze({ rawTransaction, transactionHash }); + }, + }); + }; +} + +export { createTransactionPreparer }; +export type { CreateTransactionPreparerOptions }; diff --git a/packages/ethereum/src/transactions.ts b/packages/ethereum/src/transactions.ts index b74932b7..f1e249e8 100644 --- a/packages/ethereum/src/transactions.ts +++ b/packages/ethereum/src/transactions.ts @@ -35,6 +35,28 @@ interface SignedTransaction { readonly transactionHash: string; } +/** Fully specified EIP-1559 call with an empty access list. */ +interface UnsignedTransaction extends Omit { + readonly type: 2; + /** Positive safe integer identifying the expected network. */ + readonly chainId: number; + /** Nonces outside the safe integer range are rejected before signing. */ + readonly nonce: number; + readonly gasLimit: bigint; + readonly maxFeePerGas: bigint; + readonly maxPriorityFeePerGas: bigint; +} + +interface TransactionSigner { + /** Account signing the outer Ethereum transaction. */ + readonly address: string; + /** Preserve all supplied fields and sign without broadcasting. */ + signTransaction( + transaction: Readonly, + signal?: AbortSignal, + ): SignedTransaction | PromiseLike; +} + /** Prepare and sign the requested call without broadcasting it. */ type TransactionPreparer = ( request: TransactionRequest @@ -277,6 +299,8 @@ export { export type { TransactionRequest, SignedTransaction, + UnsignedTransaction, + TransactionSigner, TransactionPreparer, TransactionStage, EthSendRawTransactionOptions, diff --git a/packages/ethereum/test/transaction-preparer-types.test.ts b/packages/ethereum/test/transaction-preparer-types.test.ts new file mode 100644 index 00000000..22ae5650 --- /dev/null +++ b/packages/ethereum/test/transaction-preparer-types.test.ts @@ -0,0 +1,45 @@ +import { createTransactionPreparer, logCid } from '@oyaprotocol/ethereum'; +import type { + CreateTransactionPreparerOptions, SignedTransaction, TransactionPreparer, + TransactionRequest, TransactionSigner, UnsignedTransaction, LogCidOptions, +} from '@oyaprotocol/ethereum'; + +declare const options: CreateTransactionPreparerOptions; +declare const signed: SignedTransaction; +declare const request: TransactionRequest; +declare const loggerOptions: LogCidOptions; + +const signer: TransactionSigner = { + address: '0x1111111111111111111111111111111111111111', + signTransaction(transaction, signal) { + const fields: readonly [2, number, number, bigint, bigint, bigint] = [ + transaction.type, transaction.chainId, transaction.nonce, transaction.gasLimit, + transaction.maxFeePerGas, transaction.maxPriorityFeePerGas, + ]; + const cancellation: AbortSignal | undefined = signal; + // @ts-expect-error Signing must preserve the supplied fields. + transaction.to = '0x'; + // @ts-expect-error Cancellation is passed separately from transaction fields. + transaction.signal; + void [fields, cancellation]; + return signed; + }, +}; +const asynchronousSigner: TransactionSigner = { ...signer, signTransaction: async () => signed }; +const preparer: TransactionPreparer = createTransactionPreparer({ + ...options, signer, chainId: 1, gasLimitMarginPercent: 20, baseFeeMultiplier: 2, + limits: { gasLimit: 100_000n, feePerGas: 30_000_000_000n }, timeoutMs: 30_000, id: 'prepare', +}); +const result: SignedTransaction = await preparer(request); +const logging = logCid('cid', { ...loggerOptions, transactionPreparer: preparer }); +declare const transaction: UnsignedTransaction; +const call: Omit = transaction; +// @ts-expect-error Public chain IDs use numbers, validated at runtime as positive safe integers. +createTransactionPreparer({ ...options, chainId: 1n }); +// @ts-expect-error Chain ID strings must be converted and validated before use. +createTransactionPreparer({ ...options, chainId: '1' }); +// @ts-expect-error A signing adapter must provide its address and signing method. +createTransactionPreparer({ ...options, signer: { address: signer.address } }); +// @ts-expect-error Fee limits are denominated in integer wei. +createTransactionPreparer({ ...options, limits: { feePerGas: 10 } }); +void [asynchronousSigner, result, logging, call]; diff --git a/packages/ethereum/test/transaction-preparer.test.js b/packages/ethereum/test/transaction-preparer.test.js new file mode 100644 index 00000000..5c91d372 --- /dev/null +++ b/packages/ethereum/test/transaction-preparer.test.js @@ -0,0 +1,410 @@ +import assert from 'node:assert/strict'; +import { setImmediate as nextTurn } from 'node:timers/promises'; +import test from 'node:test'; + +import { createHttpConfig, createTransactionPreparer, EthereumJsonRpcError, logCid } from '@oyaprotocol/ethereum'; +import { sample, loggerContract, node, createReceipt, response } from './fixtures/logger-transaction.js'; + +// Opaque test bytes, not a real signature. Hash independently checked with cast keccak 0x02abcd. +const rawTransaction = '0x02abcd'; +const transactionHash = '0xe3607eedbe2ea88ad1994e3ef901f3c7ed167a59ebb5ffe5e40321e468f49eb1'; +const signed = { rawTransaction, transactionHash }; +const request = { to: loggerContract, data: '0x1234', value: 7n }; + +function fixture(overrides = {}) { + const calls = []; + const signatures = []; + const results = { + eth_chainId: '0x1', + eth_getTransactionCount: '0x3', + eth_getBlockByNumber: { baseFeePerGas: '0x64', gasLimit: '0x1c9c380' }, + eth_maxPriorityFeePerGas: '0x2', + eth_estimateGas: '0x5209', // 21,001; the margin must round up. + }; + const options = { + config: createHttpConfig({ + url: 'https://rpc.example', headers: {}, timeoutMs: 1_000, maxRetries: 0, retryDelayMs: 0, + }), + fetch: async (_url, init) => { + const body = JSON.parse(init.body); + calls.push(body); + assert.ok(body.method in results, `Unexpected RPC method ${body.method}`); + return response(results[body.method], body.id); + }, + chainId: 1, + signer: { + address: node, + signTransaction(transaction, signal) { + assert.equal(this.address, node); + signatures.push({ transaction, signal }); + return signed; + }, + }, + ...overrides, + }; + return { options, results, calls, signatures }; +} + +test('the factory creates a frozen EIP-1559 transaction with current RPC values and no broadcast', async () => { + const { options, calls, signatures } = fixture(); + const prepare = createTransactionPreparer(options); + assert.equal(calls.length, 0); + const result = await prepare(request); + assert.deepEqual(result, signed); + assert.ok(Object.isFrozen(result)); + assert.equal(signatures.length, 1); + assert.ok(Object.isFrozen(signatures[0].transaction)); + assert.equal('signal' in signatures[0].transaction, false); + assert.deepEqual(signatures[0].transaction, { + ...request, type: 2, chainId: 1, nonce: 3, + gasLimit: 25_202n, maxFeePerGas: 202n, maxPriorityFeePerGas: 2n, + }); + assert.deepEqual(calls.map(({ method, params, id }) => ({ method, params, id })), [ + { method: 'eth_chainId', params: [], id: 1 }, + { method: 'eth_getTransactionCount', params: [node, 'pending'], id: 1 }, + { method: 'eth_getBlockByNumber', params: ['pending', false], id: 1 }, + { method: 'eth_maxPriorityFeePerGas', params: [], id: 1 }, + { method: 'eth_estimateGas', params: [{ + from: node, to: request.to, data: request.data, value: '0x7', + type: '0x2', chainId: '0x1', nonce: '0x3', + maxFeePerGas: '0xca', maxPriorityFeePerGas: '0x2', + }, 'pending'], id: 1 }, + ]); +}); + +test('fees and gas limits use the pending block when the base fee multiplier is one', async () => { + const { options, signatures } = fixture({ baseFeeMultiplier: 1 }); + const blocks = { + latest: { baseFeePerGas: '0x64', gasLimit: '0x6271' }, + pending: { baseFeePerGas: '0x6e', gasLimit: '0x6272' }, + }; + const blockTags = []; + const fetch = options.fetch; + options.fetch = async (url, init) => { + const { method, params, id } = JSON.parse(init.body); + if (method === 'eth_getBlockByNumber') { + blockTags.push(params[0]); + return response(blocks[params[0]], id); + } + if (method === 'eth_estimateGas') { + assert.equal(params[1], 'pending'); + if (BigInt(params[0].maxFeePerGas) < BigInt(blocks.pending.baseFeePerGas)) { + return { ok: true, text: async () => JSON.stringify({ + jsonrpc: '2.0', id, error: { code: -32000, message: 'max fee per gas less than block base fee' }, + }) }; + } + } + return fetch(url, init); + }; + const prepare = createTransactionPreparer(options); + await prepare(request); + assert.deepEqual(blockTags, ['pending']); + assert.equal(signatures[0].transaction.maxFeePerGas, 112n); + assert.equal(signatures[0].transaction.gasLimit, 25_202n); + + blocks.pending.gasLimit = '0x6271'; + await assert.rejects(prepare(request), /pending block gas limit/); + assert.equal(signatures.length, 1); +}); + +test('policies support exact ceilings, zero fees, empty calldata, and fresh nonces', async () => { + const { options, results, calls, signatures } = fixture({ + id: 'prepare-42', gasLimitMarginPercent: 0, baseFeeMultiplier: 3, + limits: { gasLimit: 21_001n, feePerGas: 302n }, + }); + const prepare = createTransactionPreparer(options); + await prepare({ ...request, data: '0x', value: 0n }); + assert.equal(signatures[0].transaction.maxFeePerGas, 302n); + assert.equal(signatures[0].transaction.gasLimit, 21_001n); + results.eth_getTransactionCount = '0x4'; + results.eth_getBlockByNumber.baseFeePerGas = '0x0'; + results.eth_maxPriorityFeePerGas = '0x0'; + await prepare(request); + assert.equal(signatures[1].transaction.nonce, 4); + assert.equal(signatures[1].transaction.maxFeePerGas, 0n); + assert.ok(calls.every(({ id }) => id === 'prepare-42')); + results.eth_chainId = '0x2'; + await assert.rejects(prepare(request), /did not match configured chainId/); + assert.equal(signatures.length, 2); +}); + +test('the largest safe chain ID is passed exactly to estimation and signing', async () => { + const { options, results, calls, signatures } = fixture({ chainId: Number.MAX_SAFE_INTEGER }); + results.eth_chainId = '0x1fffffffffffff'; + await createTransactionPreparer(options)(request); + assert.equal(signatures[0].transaction.chainId, Number.MAX_SAFE_INTEGER); + assert.equal(calls.find(({ method }) => method === 'eth_estimateGas').params[0].chainId, + '0x1fffffffffffff'); +}); + +test('unsupported configured chain IDs reject before RPC or signing', () => { + for (const chainId of [ + 0, -1, 1.5, Number.MAX_SAFE_INTEGER + 1, NaN, Infinity, -Infinity, + 1n, '1', '0x1', null, undefined, + ]) { + const { options, calls, signatures } = fixture({ chainId }); + assert.throws(() => createTransactionPreparer(options), /chainId must be a positive safe integer/); + assert.equal(calls.length, 0); + assert.equal(signatures.length, 0); + } +}); + +test('unsupported RPC chain IDs reject losslessly before further RPC calls or signing', async () => { + for (const [rpcChainId, exactChainId] of [ + ['0x0', '0'], + ['0x20000000000000', '9007199254740992'], + ['0x20000000000001', '9007199254740993'], + ['0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', + '115792089237316195423570985008687907853269984665640564039457584007913129639935'], + ]) { + const { options, results, calls, signatures } = fixture({ chainId: Number.MAX_SAFE_INTEGER }); + results.eth_chainId = rpcChainId; + await assert.rejects(createTransactionPreparer(options)(request), { + message: `RPC chain ID ${exactChainId} did not match configured chainId ${Number.MAX_SAFE_INTEGER}.`, + }); + assert.deepEqual(calls.map(({ method }) => method), ['eth_chainId']); + assert.equal(signatures.length, 0); + } +}); + +test('invalid factory configuration is rejected before RPC or signing', () => { + const invalid = [ + { signer: null }, { signer: { address: node } }, + { signer: { address: '0x1234', signTransaction() {} } }, { fetch: null }, + { id: '' }, { id: 1.5 }, { id: Number.MAX_SAFE_INTEGER + 1 }, + { gasLimitMarginPercent: -1 }, { gasLimitMarginPercent: 0.5 }, { gasLimitMarginPercent: Infinity }, + { baseFeeMultiplier: 0 }, { baseFeeMultiplier: 1.5 }, + { timeoutMs: 0 }, { timeoutMs: 2_147_483_648 }, + { limits: null }, { limits: [] }, { limits: { gasLimit: 0n } }, + { limits: { gasLimit: 1 } }, { limits: { feePerGas: -1n } }, + { limits: { feePerGas: 1n << 256n } }, + ]; + for (const overrides of invalid) { + const { options, calls, signatures } = fixture(overrides); + assert.throws(() => createTransactionPreparer(options)); + assert.equal(calls.length, 0); + assert.equal(signatures.length, 0); + } +}); + +test('invalid call intent is rejected before RPC or signing', async () => { + const { options, calls, signatures } = fixture(); + const prepare = createTransactionPreparer(options); + for (const changes of [ + { to: '0x' }, { to: ` ${node}` }, { data: '0x1' }, { data: '0xgg' }, + { value: 0 }, { value: -1n }, { value: 1n << 256n }, + ]) { + await assert.rejects(prepare({ ...request, ...changes })); + } + assert.equal(calls.length, 0); + assert.equal(signatures.length, 0); +}); + +test('malformed RPC results, unsupported fees, and unsafe quantities never reach the signer', async () => { + const cases = [ + ['eth_chainId', '0x2', /did not match configured chainId/], + ['eth_chainId', '0x01', /without leading zeros/], + ['eth_chainId', '0x' + 'f'.repeat(65), /256 bits/], + ['eth_getTransactionCount', '0x20000000000000', /safe integer/], + ['eth_getTransactionCount', '-0x1', /quantity/], + ['eth_getBlockByNumber', null, /baseFeePerGas/], + ['eth_getBlockByNumber', { gasLimit: '0x5208' }, /baseFeePerGas/], + ['eth_getBlockByNumber', { baseFeePerGas: '0x1', gasLimit: '0x0' }, /gasLimit/], + ['eth_getBlockByNumber', { baseFeePerGas: '0x01', gasLimit: '0x5208' }, /quantity/], + ['eth_maxPriorityFeePerGas', '0x00', /quantity/], + ['eth_maxPriorityFeePerGas', '0x' + 'f'.repeat(65), /256 bits/], + ['eth_maxPriorityFeePerGas', '0x' + 'f'.repeat(64), /maxFeePerGas/], + ['eth_estimateGas', '0x', /quantity/], + ['eth_estimateGas', 21_000, /quantity/], + ['eth_estimateGas', '0x0', /positive/], + ]; + for (const [method, result, expected] of cases) { + const { options, results, signatures } = fixture(); + results[method] = result; + await assert.rejects(createTransactionPreparer(options)(request), expected); + assert.equal(signatures.length, 0); + } +}); + +test('gas and fee ceilings reject before signing instead of reducing the selected values', async () => { + for (const [limits, expected] of [ + [{ gasLimit: 25_201n }, /limits.gasLimit/], + [{ feePerGas: 201n }, /limits.feePerGas/], + ]) { + const { options, signatures } = fixture({ limits }); + await assert.rejects(createTransactionPreparer(options)(request), expected); + assert.equal(signatures.length, 0); + } + const { options, results, signatures } = fixture(); + results.eth_getBlockByNumber.gasLimit = '0x5209'; + await assert.rejects(createTransactionPreparer(options)(request), /block gas limit/); + assert.equal(signatures.length, 0); +}); + +test('RPC transport retries are reused but execution reverts and signer failures are not retried', async () => { + const { options, signatures } = fixture(); + options.config = { ...options.config, maxRetries: 1 }; + const fetch = options.fetch; + let attempts = 0; + options.fetch = async (...args) => { + if (++attempts === 1) return { ok: false, status: 503, statusText: 'Unavailable', text: async () => '' }; + return fetch(...args); + }; + await createTransactionPreparer(options)(request); + assert.equal(attempts, 6); + assert.equal(signatures.length, 1); + + const failed = fixture(); + failed.options.config = { ...failed.options.config, maxRetries: 2 }; + const normalFetch = failed.options.fetch; + let estimates = 0; + failed.options.fetch = async (url, init) => { + const body = JSON.parse(init.body); + if (body.method !== 'eth_estimateGas') return normalFetch(url, init); + estimates++; + return { ok: true, text: async () => JSON.stringify({ + jsonrpc: '2.0', id: body.id, error: { code: 3, message: 'execution reverted' }, + }) }; + }; + await assert.rejects(createTransactionPreparer(failed.options)(request), EthereumJsonRpcError); + assert.equal(estimates, 1); + assert.equal(failed.signatures.length, 0); + + let signingAttempts = 0; + const cause = new Error('Signer unavailable'); + options.signer.signTransaction = async () => { signingAttempts++; throw cause; }; + await assert.rejects(createTransactionPreparer(options)(request), (error) => error === cause); + assert.equal(signingAttempts, 1); +}); + +test('configuration and call fields are snapshotted before asynchronous work', async () => { + const { options, signatures } = fixture({ limits: { gasLimit: 30_000n, feePerGas: 300n } }); + const started = Promise.withResolvers(); + const release = Promise.withResolvers(); + const fetch = options.fetch; + options.config = { ...options.config, headers: { Authorization: 'original' } }; + options.fetch = async (url, init) => { + assert.equal(url, 'https://rpc.example'); + assert.equal(init.headers.Authorization, 'original'); + started.resolve(); + await release.promise; + return fetch(url, init); + }; + const prepare = createTransactionPreparer(options); + options.chainId = 2; + options.config.url = 'https://changed.example'; + options.config.headers.Authorization = 'changed'; + options.limits.gasLimit = 1n; + options.limits.feePerGas = 1n; + options.signer.signTransaction = () => { throw new Error('Replaced signer'); }; + options.fetch = () => { throw new Error('Replaced transport'); }; + const mutableRequest = { ...request }; + const promise = prepare(mutableRequest); + await started.promise; + mutableRequest.to = node; + mutableRequest.data = '0x'; + mutableRequest.value = 99n; + release.resolve(); + await promise; + assert.equal(signatures[0].transaction.chainId, 1); + assert.equal(signatures[0].transaction.to, request.to); + assert.equal(signatures[0].transaction.data, request.data); + assert.equal(signatures[0].transaction.value, request.value); +}); + +test('pre-aborted requests perform no RPC or signing', async () => { + const { options, calls, signatures } = fixture(); + await assert.rejects(createTransactionPreparer(options)({ + ...request, signal: AbortSignal.abort('Cancelled'), + }), /aborted/); + assert.equal(calls.length, 0); + assert.equal(signatures.length, 0); +}); + +test('cancellation during an uncooperative RPC prevents later signing', async () => { + const { options, signatures } = fixture(); + const controller = new AbortController(); + const started = Promise.withResolvers(); + const release = Promise.withResolvers(); + let calls = 0; + options.fetch = async () => { calls++; started.resolve(); await release.promise; return response('0x1'); }; + const promise = createTransactionPreparer(options)({ ...request, signal: controller.signal }); + await started.promise; + controller.abort('Cancelled'); + await assert.rejects(promise, /aborted/); + release.resolve(); + await nextTurn(); + assert.equal(calls, 1); + assert.equal(signatures.length, 0); +}); + +for (const cancel of ['caller', 'deadline']) { + test(`${cancel} cancellation bounds an uncooperative signer and ignores its late result`, async () => { + const { options } = fixture({ timeoutMs: cancel === 'deadline' ? 30 : 1_000 }); + const controller = new AbortController(); + const started = Promise.withResolvers(); + const release = Promise.withResolvers(); + let signingSignal; + let attempts = 0; + options.signer.signTransaction = async (_transaction, signal) => { + attempts++; + signingSignal = signal; + started.resolve(); + return await release.promise; + }; + const promise = createTransactionPreparer(options)({ ...request, signal: controller.signal }); + await started.promise; + if (cancel === 'caller') controller.abort('Cancelled'); + await assert.rejects(promise, /aborted|timed out/); + assert.equal(signingSignal.aborted, true); + release.resolve(signed); + await nextTurn(); + assert.equal(attempts, 1); + }); +} + +test('signed results must have type-2 bytes and a matching hash', async () => { + for (const output of [ + null, {}, { ...signed, rawTransaction: '0x' }, { ...signed, rawTransaction: '0x02' }, + { ...signed, rawTransaction: '0x02abc' }, { ...signed, rawTransaction: '0x01abcd' }, + { ...signed, transactionHash: '0x1234' }, { ...signed, transactionHash: '0x' + 'ff'.repeat(32) }, + ]) { + const { options } = fixture(); + options.signer.signTransaction = () => output; + await assert.rejects(createTransactionPreparer(options)(request)); + } + const { options } = fixture(); + const output = { rawTransaction: '0x02ABCD', transactionHash: '0x' + transactionHash.slice(2).toUpperCase() }; + options.signer.signTransaction = async () => output; + const result = await createTransactionPreparer(options)(request); + output.rawTransaction = '0x02'; + assert.equal(result.rawTransaction, '0x02ABCD'); +}); + +test('the default preparer composes with Logger submission and event verification', async () => { + const { options, signatures, calls } = fixture(); + const prepare = createTransactionPreparer(options); + const loggingCalls = []; + const result = await logCid(sample.cid, { + config: options.config, loggerContract, nodeAddress: node, transactionPreparer: prepare, + timeoutMs: 1_000, pollIntervalMs: 1, + fetch: async (_url, init) => { + assert.equal(signatures.length, 1); + const body = JSON.parse(init.body); + loggingCalls.push(body.method); + if (body.method === 'eth_sendRawTransaction') { + assert.deepEqual(body.params, [rawTransaction]); + return response(transactionHash); + } + const receipt = createReceipt(); + return response({ ...receipt, transactionHash, logs: receipt.logs.map(log => ({ ...log, transactionHash })) }); + }, + }); + assert.equal(signatures[0].transaction.data, sample.calldata); + assert.equal(signatures[0].transaction.value, 0n); + assert.equal(signatures[0].transaction.to, loggerContract); + assert.equal(result.transactionHash, transactionHash); + assert.equal(result.event.node, node); + assert.equal(calls.length, 5); + assert.deepEqual(loggingCalls, ['eth_sendRawTransaction', 'eth_getTransactionReceipt']); +}); diff --git a/packages/utils/README.md b/packages/utils/README.md index 1352bd69..2ed37b2f 100644 --- a/packages/utils/README.md +++ b/packages/utils/README.md @@ -16,6 +16,7 @@ Small shared utilities for hardened Oya kernel packages. - `assertHexString(value, label)` - `assertPositiveInteger(value, label)` - `assertNonNegativeInteger(value, label)` +- `assertUint256(value, name)`: requires a bigint from `0n` through `(1n << 256n) - 1n`, returning the original value. - `assertHeadersObject(headers, label, options)` - `isPlainObject(value)` - `parseBytes(value, name, size?)`: validates `0x`-prefixed, byte-aligned hex, optionally requiring an exact byte count. Returns the original string without trimming; accepts `0x` when no size is required. @@ -37,6 +38,7 @@ Small shared utilities for hardened Oya kernel packages. ## Async Utilities +- `assertTimerMs(value, name)`: validates a positive integer duration up to 2,147,483,647 ms, avoiding timer overflow. - `AbortSignalHandle` - `RunWithRetryAttemptContext` - `RunWithRetryOptions` diff --git a/packages/utils/dist/async-utils.d.ts b/packages/utils/dist/async-utils.d.ts index 8c073f62..9ad8332d 100644 --- a/packages/utils/dist/async-utils.d.ts +++ b/packages/utils/dist/async-utils.d.ts @@ -16,6 +16,7 @@ interface RunWithRetryOptions { normalizeError(error: unknown): Error; run(context: RunWithRetryAttemptContext): Promise; } +declare function assertTimerMs(value: unknown, name: string): number; declare function createTimeoutSignal(timeoutMs: number): AbortSignalHandle; declare function combineAbortSignals(signals: Array): AbortSignalHandle; declare function invokeWithAbort(createPromise: () => Promise, signal: AbortSignal | undefined): Promise; @@ -26,5 +27,5 @@ declare function waitForRetryDelay({ retryDelayMs, signal, abortErrorMessage, }: abortErrorMessage: string; }): Promise; declare function runWithRetry({ maxRetries, retryDelayMs, timeoutMs, signal, abortErrorMessage, shouldRetry, normalizeError, run, }: RunWithRetryOptions): Promise; -export { combineAbortSignals, createTimeoutSignal, invokeWithAbort, runWithRetry, throwIfSignalAborted, waitForRetryDelay, }; +export { assertTimerMs, combineAbortSignals, createTimeoutSignal, invokeWithAbort, runWithRetry, throwIfSignalAborted, waitForRetryDelay, }; export type { AbortSignalHandle, RunWithRetryAttemptContext, RunWithRetryOptions, }; diff --git a/packages/utils/dist/async-utils.js b/packages/utils/dist/async-utils.js index c2f14429..a2ecb8fd 100644 --- a/packages/utils/dist/async-utils.js +++ b/packages/utils/dist/async-utils.js @@ -1,4 +1,11 @@ import { assertNonEmptyString, assertNonNegativeInteger, assertPositiveInteger, } from './validation-utils.js'; +function assertTimerMs(value, name) { + const duration = assertPositiveInteger(value, name); + if (duration > 2_147_483_647) { + throw new Error(`${name} must not exceed 2147483647 ms.`); + } + return duration; +} function createTimeoutSignal(timeoutMs) { const controller = new AbortController(); const timer = setTimeout(() => controller.abort(new Error('Request timed out.')), timeoutMs); @@ -175,5 +182,5 @@ async function runWithRetry({ maxRetries, retryDelayMs, timeoutMs, signal, abort } throw normalizeError(lastError); } -export { combineAbortSignals, createTimeoutSignal, invokeWithAbort, runWithRetry, throwIfSignalAborted, waitForRetryDelay, }; +export { assertTimerMs, combineAbortSignals, createTimeoutSignal, invokeWithAbort, runWithRetry, throwIfSignalAborted, waitForRetryDelay, }; //# sourceMappingURL=async-utils.js.map \ No newline at end of file diff --git a/packages/utils/dist/async-utils.js.map b/packages/utils/dist/async-utils.js.map index 6319baae..f85c128e 100644 --- a/packages/utils/dist/async-utils.js.map +++ b/packages/utils/dist/async-utils.js.map @@ -1 +1 @@ -{"version":3,"file":"async-utils.js","sourceRoot":"","sources":["../src/async-utils.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"async-utils.js","sourceRoot":"","sources":["../src/async-utils.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/utils/dist/index.d.ts b/packages/utils/dist/index.d.ts index 10b91d32..7157e855 100644 --- a/packages/utils/dist/index.d.ts +++ b/packages/utils/dist/index.d.ts @@ -1,6 +1,6 @@ export { assertCanonicalCid } from './cid-utils.js'; -export { combineAbortSignals, createTimeoutSignal, invokeWithAbort, runWithRetry, throwIfSignalAborted, waitForRetryDelay, } from './async-utils.js'; +export { assertTimerMs, combineAbortSignals, createTimeoutSignal, invokeWithAbort, runWithRetry, throwIfSignalAborted, waitForRetryDelay, } from './async-utils.js'; export type { AbortSignalHandle, RunWithRetryAttemptContext, RunWithRetryOptions, } from './async-utils.js'; export { HttpStatusError, RETRYABLE_HTTP_NETWORK_ERROR_CODES, createHttpConfig, hasRetryableNetworkErrorCode, readErrorStringChain, } from './http-utils.js'; export type { CreateHttpConfigOptions, HttpConfig, HttpFetchLike, HttpPostFetchLike, HttpPostFetchOptions, HttpStatusErrorOptions, HttpTextResponse, } from './http-utils.js'; -export { assertAsciiBytes, assertBytes32HexString, assertHeadersObject, assertHexData, assertHexString, assertNonEmptyString, assertNonNegativeInteger, assertPositiveInteger, isPlainObject, parseBytes, } from './validation-utils.js'; +export { assertAsciiBytes, assertBytes32HexString, assertHeadersObject, assertHexData, assertHexString, assertNonEmptyString, assertNonNegativeInteger, assertPositiveInteger, assertUint256, isPlainObject, parseBytes, } from './validation-utils.js'; diff --git a/packages/utils/dist/index.js b/packages/utils/dist/index.js index a9a55173..a085c458 100644 --- a/packages/utils/dist/index.js +++ b/packages/utils/dist/index.js @@ -1,5 +1,5 @@ export { assertCanonicalCid } from './cid-utils.js'; -export { combineAbortSignals, createTimeoutSignal, invokeWithAbort, runWithRetry, throwIfSignalAborted, waitForRetryDelay, } from './async-utils.js'; +export { assertTimerMs, combineAbortSignals, createTimeoutSignal, invokeWithAbort, runWithRetry, throwIfSignalAborted, waitForRetryDelay, } from './async-utils.js'; export { HttpStatusError, RETRYABLE_HTTP_NETWORK_ERROR_CODES, createHttpConfig, hasRetryableNetworkErrorCode, readErrorStringChain, } from './http-utils.js'; -export { assertAsciiBytes, assertBytes32HexString, assertHeadersObject, assertHexData, assertHexString, assertNonEmptyString, assertNonNegativeInteger, assertPositiveInteger, isPlainObject, parseBytes, } from './validation-utils.js'; +export { assertAsciiBytes, assertBytes32HexString, assertHeadersObject, assertHexData, assertHexString, assertNonEmptyString, assertNonNegativeInteger, assertPositiveInteger, assertUint256, isPlainObject, parseBytes, } from './validation-utils.js'; //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/utils/dist/index.js.map b/packages/utils/dist/index.js.map index a79ec810..29e19647 100644 --- a/packages/utils/dist/index.js.map +++ b/packages/utils/dist/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EACH,mBAAmB,EACnB,mBAAmB,EACnB,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,GACpB,MAAM,kBAAkB,CAAC;AAM1B,OAAO,EACH,eAAe,EACf,kCAAkC,EAClC,gBAAgB,EAChB,4BAA4B,EAC5B,oBAAoB,GACvB,MAAM,iBAAiB,CAAC;AAWzB,OAAO,EACH,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,oBAAoB,EACpB,wBAAwB,EACxB,qBAAqB,EACrB,aAAa,EACb,UAAU,GACb,MAAM,uBAAuB,CAAC"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EACH,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,GACpB,MAAM,kBAAkB,CAAC;AAM1B,OAAO,EACH,eAAe,EACf,kCAAkC,EAClC,gBAAgB,EAChB,4BAA4B,EAC5B,oBAAoB,GACvB,MAAM,iBAAiB,CAAC;AAWzB,OAAO,EACH,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,oBAAoB,EACpB,wBAAwB,EACxB,qBAAqB,EACrB,aAAa,EACb,aAAa,EACb,UAAU,GACb,MAAM,uBAAuB,CAAC"} \ No newline at end of file diff --git a/packages/utils/dist/validation-utils.d.ts b/packages/utils/dist/validation-utils.d.ts index 55d31847..f6e44d62 100644 --- a/packages/utils/dist/validation-utils.d.ts +++ b/packages/utils/dist/validation-utils.d.ts @@ -1,6 +1,7 @@ declare function assertNonEmptyString(value: unknown, label: string): string; declare function assertPositiveInteger(value: unknown, label: string): number; declare function assertNonNegativeInteger(value: unknown, label: string): number; +declare function assertUint256(value: unknown, name: string): bigint; declare function isPlainObject(value: unknown): value is Record; declare function assertHeadersObject(headers: unknown, label: string, options?: { disallowedNames?: string[]; @@ -10,4 +11,4 @@ declare function assertHexString(value: unknown, label: string): string; declare function assertHexData(value: unknown, label: string): string; declare function assertBytes32HexString(value: unknown, label: string): string; declare function parseBytes(value: unknown, name: string, size?: number): string; -export { assertAsciiBytes, assertBytes32HexString, assertHeadersObject, assertHexData, assertHexString, assertNonEmptyString, assertNonNegativeInteger, assertPositiveInteger, isPlainObject, parseBytes, }; +export { assertAsciiBytes, assertBytes32HexString, assertHeadersObject, assertHexData, assertHexString, assertNonEmptyString, assertNonNegativeInteger, assertPositiveInteger, assertUint256, isPlainObject, parseBytes, }; diff --git a/packages/utils/dist/validation-utils.js b/packages/utils/dist/validation-utils.js index f6a73879..53bd5ef4 100644 --- a/packages/utils/dist/validation-utils.js +++ b/packages/utils/dist/validation-utils.js @@ -1,3 +1,4 @@ +const UINT256_MAX = (1n << 256n) - 1n; function assertNonEmptyString(value, label) { if (typeof value !== 'string' || !value.trim()) { throw new Error(`${label} must be a non-empty string.`); @@ -16,6 +17,12 @@ function assertNonNegativeInteger(value, label) { } return value; } +function assertUint256(value, name) { + if (typeof value !== 'bigint' || value < 0n || value > UINT256_MAX) { + throw new Error(`${name} must be a non-negative bigint fitting in 256 bits.`); + } + return value; +} function isPlainObject(value) { if (value === null || typeof value !== 'object' || Array.isArray(value)) { return false; @@ -76,5 +83,5 @@ function parseBytes(value, name, size) { } return value; } -export { assertAsciiBytes, assertBytes32HexString, assertHeadersObject, assertHexData, assertHexString, assertNonEmptyString, assertNonNegativeInteger, assertPositiveInteger, isPlainObject, parseBytes, }; +export { assertAsciiBytes, assertBytes32HexString, assertHeadersObject, assertHexData, assertHexString, assertNonEmptyString, assertNonNegativeInteger, assertPositiveInteger, assertUint256, isPlainObject, parseBytes, }; //# sourceMappingURL=validation-utils.js.map \ No newline at end of file diff --git a/packages/utils/dist/validation-utils.js.map b/packages/utils/dist/validation-utils.js.map index d8f0df58..8ed664f0 100644 --- a/packages/utils/dist/validation-utils.js.map +++ b/packages/utils/dist/validation-utils.js.map @@ -1 +1 @@ -{"version":3,"file":"validation-utils.js","sourceRoot":"","sources":["../src/validation-utils.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"validation-utils.js","sourceRoot":"","sources":["../src/validation-utils.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,GAAG,CAAC,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;AAEtC,SAAS,oBAAoB,CAAC,KAAc,EAAE,KAAa;IACvD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,8BAA8B,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;AACxB,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAc,EAAE,KAAa;IACxD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,8BAA8B,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,SAAS,wBAAwB,CAAC,KAAc,EAAE,KAAa;IAC3D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,kCAAkC,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,SAAS,aAAa,CAAC,KAAc,EAAE,IAAY;IAC/C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,GAAG,EAAE,IAAI,KAAK,GAAG,WAAW,EAAE,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,qDAAqD,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACjC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACtE,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IAC/C,OAAO,SAAS,KAAK,MAAM,CAAC,SAAS,IAAI,SAAS,KAAK,IAAI,CAAC;AAChE,CAAC;AAED,SAAS,mBAAmB,CACxB,OAAgB,EAChB,KAAa,EACb,UAA0C,EAAE;IAE5C,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,0BAA0B,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,eAAe,GAAG,IAAI,GAAG,CAC3B,CAAC,OAAO,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CACpE,CAAC;IACF,MAAM,SAAS,GAA2B,EAAE,CAAC;IAC7C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACjD,IAAI,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,qBAAqB,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;QACvE,CAAC;QACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,IAAI,GAAG,oBAAoB,CAAC,CAAC;QACzD,CAAC;QACD,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAC3B,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AACpC,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAiB,EAAE,OAAe;IACxD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,IAAI,GAAG,IAAI,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC;IACL,CAAC;AACL,CAAC;AAED,SAAS,eAAe,CAAC,KAAc,EAAE,KAAa;IAClD,MAAM,SAAS,GAAG,oBAAoB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACrD,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,oCAAoC,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,SAAS,CAAC;AACrB,CAAC;AAED,SAAS,aAAa,CAAC,KAAc,EAAE,KAAa;IAChD,MAAM,SAAS,GAAG,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAChD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,2CAA2C,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,SAAS,CAAC;AACrB,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAc,EAAE,KAAa;IACzD,MAAM,SAAS,GAAG,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAChD,IAAI,SAAS,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,gCAAgC,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,SAAS,CAAC;AACrB,CAAC;AAED,SAAS,UAAU,CAAC,KAAc,EAAE,IAAY,EAAE,IAAa;IAC3D,IACI,OAAO,KAAK,KAAK,QAAQ;QACzB,CAAC,yBAAyB,CAAC,IAAI,CAAC,KAAK,CAAC;QACtC,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,EACvD,CAAC;QACC,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,YAAY,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,IAAI,OAAO,YAAY,CAAC,CAAC;IACzG,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,OAAO,EACH,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,oBAAoB,EACpB,wBAAwB,EACxB,qBAAqB,EACrB,aAAa,EACb,aAAa,EACb,UAAU,GACb,CAAC"} \ No newline at end of file diff --git a/packages/utils/src/async-utils.ts b/packages/utils/src/async-utils.ts index f1f0f39c..ca4d8baf 100644 --- a/packages/utils/src/async-utils.ts +++ b/packages/utils/src/async-utils.ts @@ -25,6 +25,14 @@ interface RunWithRetryOptions { run(context: RunWithRetryAttemptContext): Promise; } +function assertTimerMs(value: unknown, name: string): number { + const duration = assertPositiveInteger(value, name); + if (duration > 2_147_483_647) { + throw new Error(`${name} must not exceed 2147483647 ms.`); + } + return duration; +} + function createTimeoutSignal(timeoutMs: number): AbortSignalHandle { const controller = new AbortController(); const timer = setTimeout(() => controller.abort(new Error('Request timed out.')), timeoutMs); @@ -242,6 +250,7 @@ async function runWithRetry({ } export { + assertTimerMs, combineAbortSignals, createTimeoutSignal, invokeWithAbort, diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 3ccddd76..ce170655 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -1,5 +1,6 @@ export { assertCanonicalCid } from './cid-utils.js'; export { + assertTimerMs, combineAbortSignals, createTimeoutSignal, invokeWithAbort, @@ -38,6 +39,7 @@ export { assertNonEmptyString, assertNonNegativeInteger, assertPositiveInteger, + assertUint256, isPlainObject, parseBytes, } from './validation-utils.js'; diff --git a/packages/utils/src/validation-utils.ts b/packages/utils/src/validation-utils.ts index 7d00bc31..e4970cb0 100644 --- a/packages/utils/src/validation-utils.ts +++ b/packages/utils/src/validation-utils.ts @@ -1,3 +1,5 @@ +const UINT256_MAX = (1n << 256n) - 1n; + function assertNonEmptyString(value: unknown, label: string): string { if (typeof value !== 'string' || !value.trim()) { throw new Error(`${label} must be a non-empty string.`); @@ -19,6 +21,13 @@ function assertNonNegativeInteger(value: unknown, label: string): number { return value; } +function assertUint256(value: unknown, name: string): bigint { + if (typeof value !== 'bigint' || value < 0n || value > UINT256_MAX) { + throw new Error(`${name} must be a non-negative bigint fitting in 256 bits.`); + } + return value; +} + function isPlainObject(value: unknown): value is Record { if (value === null || typeof value !== 'object' || Array.isArray(value)) { return false; @@ -103,6 +112,7 @@ export { assertNonEmptyString, assertNonNegativeInteger, assertPositiveInteger, + assertUint256, isPlainObject, parseBytes, }; diff --git a/plans/default-transaction-preparer.md b/plans/default-transaction-preparer.md new file mode 100644 index 00000000..5a18b2cb --- /dev/null +++ b/plans/default-transaction-preparer.md @@ -0,0 +1,85 @@ +# Add a default transaction preparer with an injected signer + +This ExecPlan is maintained according to `PLANS.md`. + +## Purpose / Big Picture + +Nodes will be able to configure a reusable Ethereum transaction preparer once, provide their own signing implementation, and pass the returned callback to `logCid` or the existing publish-and-log handler. The package will obtain chain-dependent transaction fields without adding ethers, viem, a wallet adapter, private-key handling, or any new dependency. Mock RPC and signer tests will demonstrate preparation followed by existing Logger submission and receipt verification without using a real network or key. + +## Progress + +- [x] 2026-09-05 20:38Z: Read repository instructions and audited transaction, RPC, validation, cancellation, and Logger code. Checked Ethereum execution API and EIP-1559 specifications. +- [x] 2026-09-05 20:40Z: Implemented public types and the factory; reused quantity parsing, shared timer validation, RPC retries, and bounded async invocation. Initial build passed. +- [x] 2026-09-05 20:41Z: Added 14 passing runtime tests including Logger integration and uncooperative signer cancellation. Ethereum type tests passed. +- [x] 2026-09-05 20:44Z: Updated Ethereum/utils documentation, rebuilt tracked output, reviewed the implementation/declarations, and passed all 201 package runtime tests, Ethereum/messages type checks, package imports, and whitespace checks. Dependency metadata is unchanged. +- [x] 2026-09-05 21:06Z: Aligned the block fee/gas-limit lookup with pending gas estimation. Added a regression for differing latest/pending fees with multiplier 1, updated documentation/errors, rebuilt output, and passed all 137 Ethereum/messages runtime tests, both type suites, package import, and whitespace checks. +- [x] 2026-09-07 01:43Z: Audited public chain ID usage and changed factory/signing types to positive safe integer numbers while preserving bigint RPC parsing/comparison. Updated runtime/type coverage and documentation. +- [x] 2026-09-07 01:44Z: Rebuilt tracked output and reviewed the final diff. All 140 Ethereum/messages runtime tests, both type suites, package import, and whitespace checks passed for the chain ID change. +- [x] 2026-09-07 02:02Z: Moved `assertUint256` to shared validation utilities and `parseTransactionQuantity` to Ethereum request utilities without changing behavior. Rebuilt output; all 98 utils/Ethereum runtime tests, Ethereum type checks, both package imports, uint256 export boundary checks, and whitespace checks passed. + +## Surprises & Discoveries + +- `requestEthereumJsonRpc` already supports retries for all five required read methods; no new transport or retry implementation is needed. +- Canonical RPC quantity parsing originally lived in `receipt-utils.ts`; it now lives in `request-utils.ts`. Bounded timer validation originally lived in `receipts.ts`; it is now exported by `@oyaprotocol/utils` from `async-utils.ts`, following the user's requested relocation. +- A preparer cannot coordinate nonce reuse through submission because its callback finishes before broadcasting starts. An internal queue would not solve this lifecycle constraint. +- Reading latest-block fees while estimating pending state can underprice the estimate with multiplier 1. The regression reproduced `max fee per gas less than block base fee` before the fix; reading the pending block fixes that mismatch. Separate RPC calls can still observe advancing pending state. +- Public chain IDs only occur in the Ethereum factory and unsigned transaction interface. Keeping the existing bigint RPC comparison against the validated configured ID rejects unsupported RPC IDs without converting or rounding them; the signer receives the configured number. +- The two preparer-local validation helpers have no orchestration dependency. Their existing tests continue to cover them after relocation; the new public `assertUint256` export also passed direct boundary checks. + +## Decision Log + +- 2026-09-05 / Codex: Support type-2 (EIP-1559) transactions to an explicit address, with empty access list, initially. This matches the discussed default and avoids inventing support for wallet-specific execution, contract creation, blobs, or legacy fees. +- 2026-09-05 / Codex, updated 2026-09-07 after user approval: Require an expected positive safe integer `number` chain ID and a signer with an address and `signTransaction` method. This replaces the original bigint chain ID interface to simplify host configuration and wallet integrations for supported target chains. Reject invalid configuration before RPC work, preserve bigint RPC parsing and exact comparison against `BigInt(chainId)`, and pass the validated number to the signer. Amounts, gas limits, and fees remain bigint. Reuse existing `TransactionRequest`, `SignedTransaction`, and `TransactionPreparer`. Keep the new factory in `packages/ethereum/src/transaction-preparer.ts` and shared signing types in `transactions.ts`. +- 2026-09-05 / Codex, updated after user-approved review fix: Read chain ID, pending nonce, pending block base fee/gas limit, suggested priority fee, then estimate gas against pending state with the completed call/fee fields. Using pending for both the block lookup and estimate avoids the original latest/pending mismatch. Check chain ID on every invocation. Default maximum fee is twice the current base fee plus the suggested priority fee. Default gas margin is 20%, rounded up. Configurable integer base-fee multiplier and margin, optional gas/fee ceilings, and block gas limit checks reject before signing rather than silently reducing values. +- 2026-09-05 / Codex: A configurable 30-second overall preparation deadline and the per-call abort signal cover RPC work and signing. Reuse `runWithRetry` with zero outer retries; individual RPC reads retain their existing retry policy. Sign only once and discard late results after cancellation. The signer is trusted to preserve the requested transaction and account; validate returned byte shapes, type-2 prefix, and hash correspondence with existing noble Keccak, without adding transaction decoding or key recovery. +- 2026-09-05 / Codex: Do not reserve or increment nonces locally. Document serialization of the complete transaction lifecycle per account, including reconciliation of uncertain submissions, and the lack of coordination across processes. RPC IDs default to 1 and are configurable at factory creation; they are not signed fields. +- 2026-09-07 / Codex, requested by the user: Export generic `assertUint256` from `packages/utils/src/validation-utils.ts` through `@oyaprotocol/utils`. Keep `parseTransactionQuantity` beside `parseQuantity` in `packages/ethereum/src/request-utils.ts` as an internal Ethereum helper. Preserve their original validation and errors, including the length check before bigint parsing. + +## Outcomes & Retrospective + +The factory and signer interface are implemented with no new dependencies or concrete wallet adapter. Initial validation passed all 201 runtime tests across utils, IPFS, Ethereum, and messages, including 14 new factory tests. The pending-block follow-up passed all 137 Ethereum/messages runtime tests, including the now 15 factory tests, both type suites, package import, the build, and `git diff --check`. The regression demonstrates successful preparation with differing block fees and multiplier 1, and rejection against the pending block's gas limit before signing. The Logger integration test demonstrates preparation followed by one submission and the expected receipt/event verification. No live RPC, production key, deployment, or wallet adapter was used. The remaining operational responsibility is intentionally the host's signer implementation and coordination of the complete transaction lifecycle per account; no implementation work remains for this task. + +The chain ID follow-up changes public configuration and signing fields to `number`, with positive safe integer validation and lossless bigint RPC comparison. Tests cover the largest safe ID, rejected configuration values, and exact errors for unsupported RPC IDs through the uint256 maximum. Tracked output is rebuilt, all 140 Ethereum/messages runtime tests (including 18 factory tests) passed, and both type suites, package import, and whitespace checks passed. No work remains for this follow-up. + +The utility relocation is complete with unchanged runtime behavior and no new dependencies. The build, `node --test --test-reporter=dot packages/utils/test/*.test.js packages/ethereum/test/*.test.js` (98 tests), Ethereum type suite, utils/Ethereum package imports, uint256 export boundary checks, and `git diff --check` all passed. + +## Context and Orientation + +`packages/ethereum/src/transactions.ts` defines call intent (`to`, `data`, `value`, optional signal), a prepared signed result, and the existing callback accepted by Logger. `logger.ts` invokes that callback, submits bytes, waits for a receipt, and verifies an event. `request-utils.ts` performs JSON-RPC reads with bounded retries and response-envelope checks. `packages/utils/src/async-utils.ts` provides cancellation, deadlines, and retry composition. `packages/messages` composes IPFS publication with Logger; its API requires no change. Tracked `dist` files are rebuilt with TypeScript. Root and package `AGENTS.md` apply. + +An Ethereum nonce is an account's transaction sequence number. A gas limit bounds execution units, while fees are prices per unit in wei (integer native currency units). EIP-1559 transactions contain a maximum priority fee and maximum total fee per gas. The factory computes a policy suggestion and never broadcasts it. + +## Plan of Work + +First add `UnsignedTransaction`, `TransactionSigner`, and `CreateTransactionPreparerOptions` through the Ethereum package root. Move existing generic validation implementations without changing their behavior. Implement strict factory/request/RPC validation, snapshots of configuration and request fields, integer arithmetic, immutable signing input/output, and a single bounded signer invocation. Then test the new factory with injected RPC responses, synchronous/asynchronous fake signers, cancellation, mutated objects, and existing Logger orchestration. Finally explain configuration defaults, limits, supported wallet/transaction scope, and nonce ownership in the READMEs. + +## Concrete Steps + +All commands run from the repository root unless indicated: + + npm --prefix packages run build + node --test packages/ethereum/test/transaction-preparer.test.js + node --test --test-reporter=dot packages/utils/test/*.test.js packages/ipfs/test/*.test.js packages/ethereum/test/*.test.js packages/messages/test/*.test.js + packages/node_modules/.bin/tsc -p packages/ethereum/tsconfig.type-test.json + packages/node_modules/.bin/tsc -p packages/messages/tsconfig.type-test.json + git diff --check + +Smoke-import changed package roots with Node from `packages/`. Expect no missing exports, no TypeScript errors, and all mock tests passing. Inspect dependency metadata diff to verify no dependencies were added. + +## Validation and Acceptance + +Tests must prove exact default fields and RPC parameters (including pending nonce/state, request ID, fee fields and rounding), refreshed values across calls, configured overrides/caps, early rejection of invalid configuration, malformed or oversized quantities, unsupported fee data, chain mismatch and gas estimation errors. Chain ID tests must accept `Number.MAX_SAFE_INTEGER` exactly in estimation and signing, reject non-number/nonpositive/fractional/unsafe configuration before RPC work, and reject unsupported RPC IDs while preserving their exact values in errors and preventing further reads or signing. Cancellation before RPC, during RPC, and during an uncooperative signer must settle promptly, prevent later signing/submission, and preserve original objects. Retryable reads may retry, but signer failures never retry. Returned hashes must match signed bytes. A Logger integration test must show a completed signing request followed by one submission and the correct event verification. Type tests must establish public imports, callback compatibility, number chain IDs and nonces, bigint amount/gas/fee fields, immutability, and required signer methods. + +## Idempotence and Recovery + +Build and mock tests are repeatable and do not contact external services. Factory construction performs no RPC calls or signing. Each invocation reads current state and can request another signature, so the host should reuse retained signed bytes for submission retries rather than invoke the factory again. The factory has no nonce reservation, broadcast, persistence, wallet approval, or deployment side effects. Aborting a wait cannot undo a signer operation already started; late completion is ignored. Hosts must coordinate all users of the signing account and reconcile ambiguous submissions. + +## Artifacts and Notes + +Protocol references checked: https://eips.ethereum.org/EIPS/eip-1559 and the Ethereum execution API `src/eth/execute.yaml` / `src/eth/fee_market.yaml`. The relevant facts and chosen defaults are recorded above; external sources are not required to resume implementation. Runtime tests use opaque type-2 bytes and a matching hash to exercise orchestration, not real cryptographic signing. + +Independent fixture check: `cast keccak 0x02abcd` returned `0xe3607eedbe2ea88ad1994e3ef901f3c7ed167a59ebb5ffe5e40321e468f49eb1`. The full runtime command printed 201 passing test dots and exited zero; builds, both type-check commands, smoke imports, and whitespace checks also exited zero. New files are `transaction-preparer.ts`, its generated dist artifacts, the corresponding runtime/type tests, and this plan. Existing quantity parsing moved to `request-utils.ts`; existing timer validation moved to `@oyaprotocol/utils` and all callers use the shared definition. + +## Interfaces and Dependencies + +`createTransactionPreparer(options)` returns the existing `TransactionPreparer`. Options include `config`, `fetch`, `chainId: number` (positive safe integer), `signer`, optional `gasLimitMarginPercent` (20), `baseFeeMultiplier` (2), `limits: { gasLimit?: bigint; feePerGas?: bigint }`, `timeoutMs` (30000), and JSON-RPC `id` (1). `UnsignedTransaction` adds type 2, the validated number chain ID, a safe-integer nonce, gas limit and both fee fields to the existing call intent without its signal. RPC quantities remain bigint internally; host signer adapters can convert the validated numeric chain ID to bigint if needed by their wallet API. `TransactionSigner` exposes an address and a signing method accepting the unsigned transaction and optional abort signal, returning `SignedTransaction` synchronously or asynchronously. Existing `@noble/hashes` and `@oyaprotocol/utils` are sufficient; package metadata remains unchanged.