ox
Version:
Ethereum Standard Library
231 lines (221 loc) • 6.04 kB
text/typescript
import { describe, expect, test } from 'vp/test'
import * as z_Transaction from '../Transaction.js'
import * as z from 'zod/mini'
const address = '0x0000000000000000000000000000000000000000'
const hash = `0x${'11'.repeat(32)}` as const
const r = `0x${'22'.repeat(32)}` as const
const s = `0x${'33'.repeat(32)}` as const
const baseRpc = {
blockHash: hash,
blockNumber: '0x1',
chainId: '0x1',
from: address,
gas: '0x5208',
hash,
input: '0xdeadbeef',
nonce: '0x2',
r,
s,
to: address,
transactionIndex: '0x0',
value: '0x3',
yParity: '0x1',
} as const
const base = {
blockHash: hash,
blockNumber: 1n,
chainId: 1,
from: address,
gas: 21000n,
hash,
input: '0xdeadbeef',
nonce: 2n,
r,
s,
to: address,
transactionIndex: 0,
value: 3n,
yParity: 1,
} as const
describe('Transaction', () => {
test('decodes and encodes EIP-1559 transactions', () => {
expect(
z.decode(z_Transaction.Transaction, {
...baseRpc,
accessList: [],
gasPrice: '0x4',
maxFeePerGas: '0x5',
maxPriorityFeePerGas: '0x6',
type: '0x2',
}),
).toMatchInlineSnapshot(`
{
"accessList": [],
"blockHash": "0x1111111111111111111111111111111111111111111111111111111111111111",
"blockNumber": 1n,
"chainId": 1,
"from": "0x0000000000000000000000000000000000000000",
"gas": 21000n,
"gasPrice": 4n,
"hash": "0x1111111111111111111111111111111111111111111111111111111111111111",
"input": "0xdeadbeef",
"maxFeePerGas": 5n,
"maxPriorityFeePerGas": 6n,
"nonce": 2n,
"r": "0x2222222222222222222222222222222222222222222222222222222222222222",
"s": "0x3333333333333333333333333333333333333333333333333333333333333333",
"to": "0x0000000000000000000000000000000000000000",
"transactionIndex": 0,
"type": "eip1559",
"value": 3n,
"yParity": 1,
}
`)
expect(
z.encode(z_Transaction.Transaction, {
...base,
accessList: [],
gasPrice: 4n,
maxFeePerGas: 5n,
maxPriorityFeePerGas: 6n,
type: 'eip1559',
}),
).toMatchInlineSnapshot(`
{
"accessList": [],
"blockHash": "0x1111111111111111111111111111111111111111111111111111111111111111",
"blockNumber": "0x1",
"chainId": "0x1",
"from": "0x0000000000000000000000000000000000000000",
"gas": "0x5208",
"gasPrice": "0x4",
"hash": "0x1111111111111111111111111111111111111111111111111111111111111111",
"input": "0xdeadbeef",
"maxFeePerGas": "0x5",
"maxPriorityFeePerGas": "0x6",
"nonce": "0x2",
"r": "0x2222222222222222222222222222222222222222222222222222222222222222",
"s": "0x3333333333333333333333333333333333333333333333333333333333333333",
"to": "0x0000000000000000000000000000000000000000",
"transactionIndex": "0x0",
"type": "0x2",
"value": "0x3",
"yParity": "0x1",
}
`)
})
test('TransactionToRpc accepts numberish encode inputs', () => {
const decoded = {
...base,
accessList: [],
gasPrice: 4n,
maxFeePerGas: 5n,
maxPriorityFeePerGas: 6n,
type: 'eip1559',
} as const
const expected = z.encode(z_Transaction.Transaction, decoded)
expect(
z.encode(z_Transaction.TransactionToRpc, {
...decoded,
blockNumber: 1,
gas: 21000,
maxFeePerGas: 5,
value: 3,
}),
).toEqual(expected)
expect(
z.encode(z_Transaction.TransactionToRpc, {
...decoded,
blockNumber: '0x1',
gas: '0x5208',
maxFeePerGas: '0x5',
}),
).toEqual(expected)
})
test('decodes legacy and pending transactions', () => {
expect(
z.decode(z_Transaction.Legacy, {
...baseRpc,
chainId: '0x1',
gasPrice: '0x4',
type: '0x0',
v: '0x1b',
}),
).toMatchObject({ chainId: 1, gasPrice: 4n, type: 'legacy', v: 27 })
expect(
z.decode(z_Transaction.Pending, {
...baseRpc,
blockHash: null,
blockNumber: null,
gasPrice: '0x4',
transactionIndex: null,
type: '0x0',
v: '0x1b',
}),
).toMatchObject({
blockHash: null,
blockNumber: null,
transactionIndex: null,
type: 'legacy',
})
})
test('decodes other transaction variants', () => {
expect(
z.decode(z_Transaction.Eip2930, {
...baseRpc,
accessList: [],
gasPrice: '0x4',
type: '0x1',
}),
).toMatchObject({ gasPrice: 4n, type: 'eip2930' })
expect(
z.decode(z_Transaction.Eip4844, {
...baseRpc,
accessList: [],
blobVersionedHashes: [hash],
maxFeePerBlobGas: '0x4',
maxFeePerGas: '0x5',
maxPriorityFeePerGas: '0x6',
type: '0x3',
}),
).toMatchObject({ maxFeePerBlobGas: 4n, type: 'eip4844' })
expect(
z.decode(z_Transaction.Eip7702, {
...baseRpc,
accessList: [],
authorizationList: [
{ address, chainId: '0x1', nonce: '0x2', r, s, yParity: '0x1' },
],
maxFeePerGas: '0x5',
maxPriorityFeePerGas: '0x6',
type: '0x4',
}),
).toMatchObject({
authorizationList: [{ chainId: 1, nonce: 2n }],
type: 'eip7702',
})
expect(
z.decode(z_Transaction.Unknown, {
...baseRpc,
type: '0x99',
}),
).toMatchObject({ type: '0x99' })
})
test('rejects invalid variants', () => {
expect(
z.safeDecode(z_Transaction.Eip1559, {
...baseRpc,
accessList: [],
maxFeePerGas: '0x5',
maxPriorityFeePerGas: '0x6',
type: '0x1',
} as never).success,
).toBe(false)
expect(
z.safeDecode(z_Transaction.Transaction, {
...baseRpc,
type: '0x2',
} as never).success,
).toBe(false)
})
})