UNPKG

ox

Version:

Ethereum Standard Library

267 lines (253 loc) 7.89 kB
import { describe, expect, test } from 'vp/test' import * as z_Transaction from '../Transaction.js' import * as z from 'zod/mini' const rpc = { accessList: [], blockHash: '0xc350d807505fb835650f0013632c5515592987ba169bbc6626d9fc54d91f0f0b', blockNumber: '0x12f296f', blockTimestamp: '0x66434e07', calls: [ { input: '0xdeadbeef', to: '0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad', value: '0x9b6e64a8ec60000', }, ], chainId: '0x1', feeToken: '0x20c0000000000000000000000000000000000000', from: '0x814e5e0e31016b9a7f138c76b7e7b2bb5c1ab6a6', gas: '0x43f5d', gasPrice: '0x2ca6ae494', hash: '0x353fdfc38a2f26115daadee9f5b8392ce62b84f410957967e2ed56b35338cdd0', maxFeePerGas: '0x2', maxPriorityFeePerGas: '0x1', nonce: '0x357', signature: { r: '0x635dc2033e60185bb36709c29c75d64ea51dfbd91c32ef4be198e4ceb169fb4d', s: '0x50c2667ac4c771072746acfdcf1f1483336dcca8bd2df47cd83175dbe60f0540', type: 'secp256k1', v: '0x0', yParity: '0x0', }, transactionIndex: '0x2', type: '0x76', } as const /** Mined shape as serialized by the tempo node (absent optionals are `null`). */ const nodeRpc = { accessList: [], aaAuthorizationList: [], blockHash: '0xa27e7b87e6f558014cb357e8361579de7f8bff8c2f39beb47e5cc75cd7bbba40', blockNumber: '0x5a', blockTimestamp: '0x6a4d7ca5', calls: [ { data: null, input: '0x5c559d2000000000000000000000000000000000000000000000000000000000abf52baf', to: '0xfdc0000000000000000000000000000000000000', value: '0x0', }, ], chainId: '0x539', feePayerSignature: null, feeToken: '0x20c0000000000000000000000000000000000000', from: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266', gas: '0x81fb2', gasPrice: '0x23c34600', hash: '0x76e9adc3b5f6262159d49582a64b8696ecf5864ac5237f72b5c0797ca380e9d4', keyAuthorization: null, maxFeePerGas: '0x2aea5400', maxPriorityFeePerGas: '0x0', nonce: '0x0', nonceKey: '0x0', signature: { r: '0xc5363149ebd9b247cd6948469677efbed1c58be3a79ec020ff767e41196b464', s: '0x701c441f1ce3ca8dd0bff969924db2c8817a7dec1ade02c39c79bd57c8d0089d', type: 'secp256k1', v: '0x0', yParity: '0x0', }, transactionIndex: '0x0', type: '0x76', validAfter: null, validBefore: null, } as const describe('Tempo', () => { test('decodes a tempo transaction', () => { const decoded = z.decode(z_Transaction.Tempo, rpc) expect(decoded).toMatchObject({ blockNumber: 19868015n, chainId: 1, feeToken: '0x20c0000000000000000000000000000000000000', from: '0x814e5e0e31016b9a7f138c76b7e7b2bb5c1ab6a6', gas: 278365n, maxFeePerGas: 2n, maxPriorityFeePerGas: 1n, nonce: 855n, transactionIndex: 2, type: 'tempo', }) expect(decoded.calls).toEqual([ { data: '0xdeadbeef', to: '0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad', value: 700000000000000000n, }, ]) }) test('round-trips via encode', () => { const decoded = z.decode(z_Transaction.Tempo, rpc) const encoded = z.encode(z_Transaction.Tempo, decoded) expect(encoded).toMatchObject({ blockNumber: '0x12f296f', chainId: '0x1', from: '0x814e5e0e31016b9a7f138c76b7e7b2bb5c1ab6a6', gas: '0x43f5d', maxFeePerGas: '0x2', type: '0x76', }) }) test('decodes a node transaction (null optionals)', () => { const decoded = z.decode(z_Transaction.Tempo, nodeRpc) expect(decoded).toMatchInlineSnapshot(` { "accessList": [], "blockHash": "0xa27e7b87e6f558014cb357e8361579de7f8bff8c2f39beb47e5cc75cd7bbba40", "blockNumber": 90n, "blockTimestamp": 1783463077n, "calls": [ { "data": "0x5c559d2000000000000000000000000000000000000000000000000000000000abf52baf", "to": "0xfdc0000000000000000000000000000000000000", "value": 0n, }, ], "chainId": 1337, "feeToken": "0x20c0000000000000000000000000000000000000", "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", "gas": 532402n, "gasPrice": 600000000n, "hash": "0x76e9adc3b5f6262159d49582a64b8696ecf5864ac5237f72b5c0797ca380e9d4", "maxFeePerGas": 720000000n, "maxPriorityFeePerGas": 0n, "nonce": 0n, "nonceKey": 0n, "signature": { "signature": { "r": "0x0c5363149ebd9b247cd6948469677efbed1c58be3a79ec020ff767e41196b464", "s": "0x701c441f1ce3ca8dd0bff969924db2c8817a7dec1ade02c39c79bd57c8d0089d", "yParity": 0, }, "type": "secp256k1", }, "transactionIndex": 0, "type": "tempo", } `) }) test('maps `aaAuthorizationList` to `authorizationList`', () => { const decoded = z.decode(z_Transaction.Tempo, { ...nodeRpc, aaAuthorizationList: [ { address: '0xfdc0000000000000000000000000000000000000', chainId: '0x539', nonce: '0x1', signature: { r: '0xc5363149ebd9b247cd6948469677efbed1c58be3a79ec020ff767e41196b464', s: '0x701c441f1ce3ca8dd0bff969924db2c8817a7dec1ade02c39c79bd57c8d0089d', type: 'secp256k1', yParity: '0x0', }, }, ], }) expect(decoded.type === 'tempo' && decoded.authorizationList) .toMatchInlineSnapshot(` [ { "address": "0xfdc0000000000000000000000000000000000000", "chainId": 1337, "nonce": 1n, "signature": { "signature": { "r": "0x0c5363149ebd9b247cd6948469677efbed1c58be3a79ec020ff767e41196b464", "s": "0x701c441f1ce3ca8dd0bff969924db2c8817a7dec1ade02c39c79bd57c8d0089d", "yParity": 0, }, "type": "secp256k1", }, }, ] `) const encoded = z.encode(z_Transaction.Tempo, decoded) expect( 'aaAuthorizationList' in encoded && encoded.aaAuthorizationList, ).toHaveLength(1) expect(encoded).not.toHaveProperty('authorizationList') }) }) describe('PendingTempo', () => { test('decodes a pending node transaction', () => { const decoded = z.decode(z_Transaction.PendingTempo, { ...nodeRpc, blockHash: null, blockNumber: null, blockTimestamp: undefined, gasPrice: '0x2aea5400', transactionIndex: null, }) expect(decoded).toMatchObject({ blockHash: null, blockNumber: null, gasPrice: 720000000n, transactionIndex: null, type: 'tempo', }) }) test('decodes via the `Pending` union', () => { const decoded = z.decode(z_Transaction.Pending, { ...nodeRpc, blockHash: null, blockNumber: null, blockTimestamp: undefined, transactionIndex: null, }) expect(decoded).toMatchObject({ type: 'tempo' }) }) }) describe('Transaction', () => { test('decodes a tempo transaction via the union', () => { const decoded = z.decode(z_Transaction.Transaction, rpc) expect(decoded).toMatchObject({ type: 'tempo' }) }) test('TempoToRpc accepts numberish encode inputs', () => { const decoded = z.decode(z_Transaction.Tempo, rpc) const strict = z.encode(z_Transaction.Tempo, decoded) expect( z.encode(z_Transaction.TempoToRpc, { ...decoded, chainId: 1, gas: 278365, maxFeePerGas: 2, transactionIndex: 2, }), ).toEqual(strict) expect( z.encode(z_Transaction.TempoToRpc, { ...decoded, chainId: '0x1', gas: '0x43f5d', maxFeePerGas: '0x2', }), ).toEqual(strict) }) test('rejects an invalid transaction', () => { expect( z.safeDecode(z_Transaction.Transaction, { type: '0x76' } as never) .success, ).toBe(false) }) })