Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/frame-rpc-fields.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ox": patch
---

Aligned frame RPC quantities, signature placeholders, and receipt gas totals with the execution API definitions.
13 changes: 7 additions & 6 deletions site/pages/guides/frame-transactions.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,10 @@ Use an explicit 32-byte `payload` only when the account expects a separate diges
## Convert RPC Data

[`TxEnvelopeEip8141.toRpc`](/api/TxEnvelopeEip8141/toRpc) converts `sender` to
`from`, frame `to` to `target`, `executionGas` to `executionGasLimit`,
`stateGas` to `stateGasLimit`, and signature `payload` to `msg`. RPC frame modes,
flags, and signature schemes are numbers, while gas and fee quantities are hex
strings.
`from`, frame `to` to `target`, and signature `payload` to `msg`. Frame gas fields
remain `executionGas` and `stateGas`. RPC frame modes, flags, signature schemes,
and gas and fee quantities are hex strings. Protocol signature placeholders omit
`signature`.

```ts twoslash
import { TxEnvelopeEip8141 } from 'ox'
Expand All @@ -135,8 +135,9 @@ const serialized = TxEnvelopeEip8141.serialize(restored)

Convert the transaction receipt with
`TransactionReceipt.fromRpc` to read the payer
and individual frame results. Each frame receipt exposes `gasUsed`, `stateGasUsed`,
`logs`, and a `status` of `'success'`, `'reverted'`, or `'skipped'`.
and individual frame results. Each frame receipt exposes `executionGasUsed`,
`stateGasUsed`, total `gasUsed`, `logs`, and a `status` of `'success'`, `'reverted'`,
or `'skipped'`.

```ts twoslash
import { Hex, RpcTransport, TransactionReceipt } from 'ox'
Expand Down
37 changes: 20 additions & 17 deletions src/core/Frame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ export type Rpc = {
/** Frame calldata. */
data: Hex.Hex
/** Execution gas budget. */
executionGasLimit: Hex.Hex
executionGas: Hex.Hex

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Update the guide for the renamed RPC frame fields

When users follow the RPC conversion guide, it still says executionGas becomes executionGasLimit, stateGas becomes stateGasLimit, and that modes, flags, and signature schemes are numbers (site/pages/guides/frame-transactions.md:118-122). This change now emits executionGas/stateGas and hex quantities for all three values, so manually constructed requests based on the guide will no longer match Frame.Rpc and may be rejected by the node; update that guide alongside these public RPC changes.

Useful? React with 👍 / 👎.

/** Approval scope and batching bits. */
flags: number
flags: Hex.Hex
/** Execution mode. */
mode: number
mode: Hex.Hex
/** State gas budget. */
stateGasLimit: Hex.Hex
stateGas: Hex.Hex
/** Target address; absent for the transaction sender. */
target?: Address.Address | null | undefined
/** Value transferred in wei. */
Expand Down Expand Up @@ -205,10 +205,10 @@ export declare namespace from {
*
* const frame = Frame.fromRpc({
* data: '0x',
* executionGasLimit: '0xc350',
* flags: 3,
* mode: 1,
* stateGasLimit: '0x0',
* executionGas: '0xc350',
* flags: '0x3',
* mode: '0x1',
* stateGas: '0x0',
* value: '0x0'
* })
* ```
Expand All @@ -219,17 +219,20 @@ export declare namespace from {
export function fromRpc(frame: Rpc): Frame {
return from({
data: frame.data,
executionGas: Hex.toBigInt(frame.executionGasLimit),
flags: frame.flags,
mode: frame.mode,
stateGas: Hex.toBigInt(frame.stateGasLimit),
executionGas: Hex.toBigInt(frame.executionGas),
flags: Hex.toNumber(frame.flags),
mode: Hex.toNumber(frame.mode),
stateGas: Hex.toBigInt(frame.stateGas),
...(frame.target == null ? {} : { to: frame.target }),
value: Hex.toBigInt(frame.value),
})
}

export declare namespace fromRpc {
type ErrorType = from.ErrorType | Hex.toBigInt.ErrorType
type ErrorType =
| from.ErrorType
| Hex.toBigInt.ErrorType
| Hex.toNumber.ErrorType
}

/**
Expand All @@ -252,10 +255,10 @@ export function toRpc(frame: toRpc.Input): Rpc {
const { flags: flags_ = 0, mode = 0 } = frame
return {
data: frame.data ?? '0x',
executionGasLimit: Quantity.fromNumberish(frame.executionGas ?? 0n),
flags: typeof flags_ === 'string' ? flags[flags_] : flags_,
mode: typeof mode === 'string' ? modes[mode] : mode,
stateGasLimit: Quantity.fromNumberish(frame.stateGas ?? 0n),
executionGas: Quantity.fromNumberish(frame.executionGas ?? 0n),
flags: Hex.fromNumber(typeof flags_ === 'string' ? flags[flags_] : flags_),
mode: Hex.fromNumber(typeof mode === 'string' ? modes[mode] : mode),
stateGas: Quantity.fromNumberish(frame.stateGas ?? 0n),
...(frame.to === undefined ? {} : { target: frame.to }),
value: Quantity.fromNumberish(frame.value ?? 0n),
}
Expand Down
34 changes: 21 additions & 13 deletions src/core/FrameReceipt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import type * as Log from './Log.js'
/** Receipt for one frame. Frame logs contain only address, data, and topics. */
export type FrameReceipt<bigintType = bigint> = {
/** Execution gas used before transaction-level refunds. */
executionGasUsed: bigintType
/** Total execution and state gas used. */
gasUsed: bigintType
/** Logs emitted by this frame. */
logs: readonly Pick<Log.Log, 'address' | 'data' | 'topics'>[]
Expand All @@ -17,6 +19,8 @@ export type FrameReceipt<bigintType = bigint> = {

/** JSON-RPC receipt for one frame. */
export type Rpc = {
/** Total execution and state gas used. */
gasUsed: Hex.Hex
/** Execution gas used. */
executionGasUsed: Hex.Hex
/** Logs emitted by this frame. */
Expand All @@ -30,21 +34,21 @@ export type Rpc = {
/** Frame execution status. */
export type Status = 'reverted' | 'skipped' | 'success'

/** Numeric JSON-RPC frame execution status. */
export type RpcStatus = 0 | 1 | 2
/** Hex JSON-RPC frame execution status. */
export type RpcStatus = '0x0' | '0x1' | '0x2'

/** RPC status to status mapping. */
export const fromRpcStatus = {
0: 'reverted',
1: 'success',
2: 'skipped',
'0x0': 'reverted',
'0x1': 'success',
'0x2': 'skipped',
} as const

/** Status to RPC status mapping. */
export const toRpcStatus = {
reverted: 0,
skipped: 2,
success: 1,
reverted: '0x0',
skipped: '0x2',
success: '0x1',
} as const

/**
Expand All @@ -58,9 +62,10 @@ export const toRpcStatus = {
*
* const receipt = FrameReceipt.fromRpc({
* executionGasUsed: '0x5208',
* gasUsed: '0x5208',
* logs: [],
* stateGasUsed: '0x0',
* status: 1
* status: '0x1'
* })
* ```
*
Expand All @@ -69,7 +74,8 @@ export const toRpcStatus = {
*/
export function fromRpc(receipt: Rpc): FrameReceipt {
return {
gasUsed: Hex.toBigInt(receipt.executionGasUsed),
executionGasUsed: Hex.toBigInt(receipt.executionGasUsed),
gasUsed: Hex.toBigInt(receipt.gasUsed),
logs: receipt.logs,
stateGasUsed: Hex.toBigInt(receipt.stateGasUsed),
status: fromRpcStatus[receipt.status],
Expand All @@ -91,19 +97,21 @@ export declare namespace fromRpc {
*
* const receipt = FrameReceipt.fromRpc({
* executionGasUsed: '0x5208',
* gasUsed: '0x5208',
* logs: [],
* stateGasUsed: '0x0',
* status: 1
* status: '0x1'
* })
* const rpc = FrameReceipt.toRpc(receipt)
* ```
*
* @param receipt - The frame receipt. Gas accepts hex, bigint, or number values.
* @returns The RPC frame receipt with hex gas and a numeric status.
* @returns The RPC frame receipt with hex gas and a hex status.
*/
export function toRpc(receipt: toRpc.Input): Rpc {
return {
executionGasUsed: Quantity.fromNumberish(receipt.gasUsed),
executionGasUsed: Quantity.fromNumberish(receipt.executionGasUsed),
gasUsed: Quantity.fromNumberish(receipt.gasUsed),
logs: receipt.logs,
stateGasUsed: Quantity.fromNumberish(receipt.stateGasUsed),
status: toRpcStatus[receipt.status],
Expand Down
27 changes: 17 additions & 10 deletions src/core/FrameSignature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@ export type FrameSignature = Arbitrary | Secp256k1 | P256
/** JSON-RPC representation of a frame signature. */
export type Rpc = {
/** Explicit digest, or empty bytes for the transaction signing hash. */
msg: Hex.Hex
msg?: Hex.Hex | undefined
/** Signature verification scheme. */
scheme: 0 | 1 | 2
scheme: '0x0' | '0x1' | '0x2'
/** Encoded signature bytes. */
signature: Hex.Hex
signature?: Hex.Hex | undefined
/** Signer address; absent for the transaction sender. */
signer?: Address.Address | null | undefined
}
Expand Down Expand Up @@ -351,7 +351,7 @@ export declare namespace from {
*
* const entry = FrameSignature.fromRpc({
* msg: '0x',
* scheme: 0,
* scheme: '0x0',
* signature: '0xdeadbeef'
* })
* ```
Expand All @@ -361,15 +361,20 @@ export declare namespace from {
*/
export function fromRpc(entry: Rpc): FrameSignature {
return fromTuple([
entry.scheme === 0 ? '0x' : Hex.fromNumber(entry.scheme, { size: 1 }),
entry.scheme === '0x0'
? '0x'
: Hex.fromNumber(Hex.toNumber(entry.scheme), { size: 1 }),
entry.signer ?? '0x',
entry.msg,
entry.signature,
entry.msg ?? '0x',
entry.signature ?? '0x',
])
}

export declare namespace fromRpc {
type ErrorType = fromTuple.ErrorType | Hex.fromNumber.ErrorType
type ErrorType =
| fromTuple.ErrorType
| Hex.fromNumber.ErrorType
| Hex.toNumber.ErrorType
}

/**
Expand All @@ -392,8 +397,10 @@ export function toRpc(entry: FrameSignature): Rpc {
const [scheme, signer, msg, signature] = toTuple(entry)
return {
msg,
scheme: (scheme === '0x' ? 0 : Hex.toNumber(scheme)) as Rpc['scheme'],
signature,
scheme: (scheme === '0x'
? '0x0'
: Hex.fromNumber(Hex.toNumber(scheme))) as Rpc['scheme'],
...(signature === '0x' && scheme !== '0x' ? {} : { signature }),
...(signer === '0x' ? {} : { signer }),
}
}
Expand Down
24 changes: 12 additions & 12 deletions src/core/_test/Frame.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,10 @@ describe('fromRpc', () => {
expect(
Frame.fromRpc({
data: '0xdeadbeef',
executionGasLimit: '0x20000000000001',
flags: 0,
mode: 2,
stateGasLimit: '0xc',
executionGas: '0x20000000000001',
flags: '0x0',
mode: '0x2',
stateGas: '0xc',
target: null,
value: '0x1',
}),
Expand All @@ -273,10 +273,10 @@ describe('toRpc', () => {
),
).toEqual({
data: '0x',
executionGasLimit: '0x0',
flags: 3,
mode: 1,
stateGasLimit: '0x0',
executionGas: '0x0',
flags: '0x3',
mode: '0x1',
stateGas: '0x0',
value: '0x0',
})
})
Expand All @@ -285,10 +285,10 @@ describe('toRpc', () => {
Frame.toRpc({ executionGas: '0xc350', stateGas: 12, value: 0n }),
).toEqual({
data: '0x',
executionGasLimit: '0xc350',
flags: 0,
mode: 0,
stateGasLimit: '0xc',
executionGas: '0xc350',
flags: '0x0',
mode: '0x0',
stateGas: '0xc',
value: '0x0',
})
})
Expand Down
24 changes: 15 additions & 9 deletions src/core/_test/FrameReceipt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ test('exports', () => {

describe('fromRpc', () => {
test.each([
[0, 'reverted'],
[1, 'success'],
[2, 'skipped'],
['0x0', 'reverted'],
['0x1', 'success'],
['0x2', 'skipped'],
] as const)('status %s', (status, expected) => {
expect(
FrameReceipt.fromRpc({
executionGasUsed: '0x20000000000001',
gasUsed: '0x20000000000003',
logs: [
{
address: '0x1111111111111111111111111111111111111111',
Expand All @@ -32,7 +33,8 @@ describe('fromRpc', () => {
status,
}),
).toEqual({
gasUsed: 9007199254740993n,
executionGasUsed: 9007199254740993n,
gasUsed: 9007199254740995n,
logs: [
{
address: '0x1111111111111111111111111111111111111111',
Expand All @@ -48,18 +50,20 @@ describe('fromRpc', () => {

describe('toRpc', () => {
test.each([
['reverted', 0],
['success', 1],
['skipped', 2],
['reverted', '0x0'],
['success', '0x1'],
['skipped', '0x2'],
] as const)('status %s', (status, expected) => {
const receipt = FrameReceipt.fromRpc({
executionGasUsed: '0x20000000000001',
gasUsed: '0x20000000000003',
logs: [],
stateGasUsed: '0x2',
status: expected,
})
expect(FrameReceipt.toRpc({ ...receipt, status })).toEqual({
executionGasUsed: '0x20000000000001',
gasUsed: '0x20000000000003',
logs: [],
stateGasUsed: '0x2',
status: expected,
Expand All @@ -69,17 +73,19 @@ describe('toRpc', () => {
test('numberish gas', () => {
expect(
FrameReceipt.toRpc({
gasUsed: '0x5208',
executionGasUsed: '0x5208',
gasUsed: '0x520a',
logs: [],
stateGasUsed: 2,
status: 'success',
}),
).toMatchInlineSnapshot(`
{
"executionGasUsed": "0x5208",
"gasUsed": "0x520a",
"logs": [],
"stateGasUsed": "0x2",
"status": 1,
"status": "0x1",
}
`)
})
Expand Down
Loading
Loading