Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
jxom committed Aug 21, 2023
1 parent 0be63c7 commit 3bf85d6
Show file tree
Hide file tree
Showing 7 changed files with 246 additions and 181 deletions.
2 changes: 1 addition & 1 deletion .changeset/cyan-bears-smoke.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
"viem": minor
---

Added `parseTransactionCelo` function for parsing serialized transactions that could be CIP42 tx or other serialized transaction types exported at viem/chains/utils
Added `parseTransactionCelo` to the `viem/chains/utils` entrypoint.
226 changes: 111 additions & 115 deletions src/chains/celo/parsers.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { expect, test } from 'vitest'

import { accounts } from '../../_test/constants.js'
import {
parseEther,
Expand All @@ -6,21 +8,15 @@ import {
serializeTransaction,
toRlp,
} from '../../index.js'

import {
type TransactionSerializableCIP42,
serializeTransactionCelo,
} from './serializers.js'

import { parseTransactionCelo } from './parsers.js'
import { describe, expect, test } from 'vitest'
import { serializeTransactionCelo } from './serializers.js'
import type { TransactionSerializableCIP42 } from './types.js'

describe('parseTransaction', () => {
test('should be able to parse a cip42 transaction', () => {
const signedTransaction =
'0x7cf84682a4ec80847735940084773594008094765de816845861e75a25fca122bb6898b8b1282a808094f39fd6e51aad88f6f4ce6ab8827279cfffb92266880de0b6b3a764000080c0'
test('should be able to parse a cip42 transaction', () => {
const signedTransaction =
'0x7cf84682a4ec80847735940084773594008094765de816845861e75a25fca122bb6898b8b1282a808094f39fd6e51aad88f6f4ce6ab8827279cfffb92266880de0b6b3a764000080c0'

expect(parseTransactionCelo(signedTransaction)).toMatchInlineSnapshot(`
expect(parseTransactionCelo(signedTransaction)).toMatchInlineSnapshot(`
{
"chainId": 42220,
"feeCurrency": "0x765de816845861e75a25fca122bb6898b8b1282a",
Expand All @@ -31,37 +27,37 @@ describe('parseTransaction', () => {
"value": 1000000000000000000n,
}
`)
})

const transaction = {
chainId: 1,
gas: 21001n,
maxFeePerGas: parseGwei('2'),
maxPriorityFeePerGas: parseGwei('2'),
to: accounts[3].address,
nonce: 785,
value: parseEther('1'),
}

test('should return same result as standard parser when not CIP42', () => {
const serialized = serializeTransaction(transaction)
})

expect(parseTransactionCelo(serialized)).toEqual(
parseTransaction_(serialized),
)
})
const transaction = {
chainId: 1,
gas: 21001n,
maxFeePerGas: parseGwei('2'),
maxPriorityFeePerGas: parseGwei('2'),
to: accounts[3].address,
nonce: 785,
value: parseEther('1'),
}

test('should return same result as standard parser when not CIP42', () => {
const serialized = serializeTransaction(transaction)

expect(parseTransactionCelo(serialized)).toEqual(
parseTransaction_(serialized),
)
})

test('should parse a CIP42 transaction with gatewayFee', () => {
const transactionWithGatewayFee = {
...transaction,
chainId: 42270,
gatewayFee: parseEther('0.1'),
gatewayFeeRecipient: accounts[1].address,
}
test('should parse a CIP42 transaction with gatewayFee', () => {
const transactionWithGatewayFee = {
...transaction,
chainId: 42270,
gatewayFee: parseEther('0.1'),
gatewayFeeRecipient: accounts[1].address,
}

const serialized = serializeTransactionCelo(transactionWithGatewayFee)
const serialized = serializeTransactionCelo(transactionWithGatewayFee)

expect(parseTransactionCelo(serialized)).toMatchInlineSnapshot(`
expect(parseTransactionCelo(serialized)).toMatchInlineSnapshot(`
{
"chainId": 42270,
"gas": 21001n,
Expand All @@ -75,27 +71,27 @@ describe('parseTransaction', () => {
"value": 1000000000000000000n,
}
`)
})

test('should parse a CIP42 transaction with access list', () => {
const transactionWithAccessList: TransactionSerializableCIP42 = {
feeCurrency: '0x765de816845861e75a25fca122bb6898b8b1282a',
...transaction,
chainId: 42270,
accessList: [
{
address: '0x0000000000000000000000000000000000000000',
storageKeys: [
'0x0000000000000000000000000000000000000000000000000000000000000001',
'0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe',
],
},
],
}

const serialized = serializeTransactionCelo(transactionWithAccessList)

expect(parseTransactionCelo(serialized)).toMatchInlineSnapshot(`
})

test('should parse a CIP42 transaction with access list', () => {
const transactionWithAccessList: TransactionSerializableCIP42 = {
feeCurrency: '0x765de816845861e75a25fca122bb6898b8b1282a',
...transaction,
chainId: 42270,
accessList: [
{
address: '0x0000000000000000000000000000000000000000',
storageKeys: [
'0x0000000000000000000000000000000000000000000000000000000000000001',
'0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe',
],
},
],
}

const serialized = serializeTransactionCelo(transactionWithAccessList)

expect(parseTransactionCelo(serialized)).toMatchInlineSnapshot(`
{
"accessList": [
{
Expand All @@ -117,19 +113,19 @@ describe('parseTransaction', () => {
"value": 1000000000000000000n,
}
`)
})
})

test('should parse a CIP42 transaction with data as 0x', () => {
const transactionWithData: TransactionSerializableCIP42 = {
feeCurrency: '0x765de816845861e75a25fca122bb6898b8b1282a',
...transaction,
chainId: 42270,
data: '0x',
}
test('should parse a CIP42 transaction with data as 0x', () => {
const transactionWithData: TransactionSerializableCIP42 = {
feeCurrency: '0x765de816845861e75a25fca122bb6898b8b1282a',
...transaction,
chainId: 42270,
data: '0x',
}

const serialized = serializeTransactionCelo(transactionWithData)
const serialized = serializeTransactionCelo(transactionWithData)

expect(parseTransactionCelo(serialized)).toMatchInlineSnapshot(`
expect(parseTransactionCelo(serialized)).toMatchInlineSnapshot(`
{
"chainId": 42270,
"feeCurrency": "0x765de816845861e75a25fca122bb6898b8b1282a",
Expand All @@ -142,18 +138,19 @@ describe('parseTransaction', () => {
"value": 1000000000000000000n,
}
`)
})
test('should parse a CIP42 transaction with data', () => {
const transactionWithData: TransactionSerializableCIP42 = {
...transaction,
feeCurrency: '0x765de816845861e75a25fca122bb6898b8b1282a',
chainId: 42270,
data: '0x1234',
}

const serialized = serializeTransactionCelo(transactionWithData)

expect(parseTransactionCelo(serialized)).toMatchInlineSnapshot(`
})

test('should parse a CIP42 transaction with data', () => {
const transactionWithData: TransactionSerializableCIP42 = {
...transaction,
feeCurrency: '0x765de816845861e75a25fca122bb6898b8b1282a',
chainId: 42270,
data: '0x1234',
}

const serialized = serializeTransactionCelo(transactionWithData)

expect(parseTransactionCelo(serialized)).toMatchInlineSnapshot(`
{
"chainId": 42270,
"data": "0x1234",
Expand All @@ -167,60 +164,59 @@ describe('parseTransaction', () => {
"value": 1000000000000000000n,
}
`)
})
})

test('invalid transaction (all missing)', () => {
expect(() =>
parseTransactionCelo(`0x7c${toRlp([]).slice(2)}`),
).toThrowErrorMatchingInlineSnapshot(`
test('invalid transaction (all missing)', () => {
expect(() =>
parseTransactionCelo(`0x7c${toRlp([]).slice(2)}`),
).toThrowErrorMatchingInlineSnapshot(`
"Invalid serialized transaction of type \\"cip42\\" was provided.
Serialized Transaction: \\"0x7cc0\\"
Missing Attributes: chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, gas, feeCurrency, to, gatewayFeeRecipient, gatewayFee, value, data, accessList
Version: viem@1.0.2"
`)
})
})

test('invalid transaction (some missing)', () => {
expect(() =>
parseTransactionCelo(`0x7c${toRlp(['0x0', '0x1']).slice(2)}`),
).toThrowErrorMatchingInlineSnapshot(`
test('invalid transaction (some missing)', () => {
expect(() =>
parseTransactionCelo(`0x7c${toRlp(['0x0', '0x1']).slice(2)}`),
).toThrowErrorMatchingInlineSnapshot(`
"Invalid serialized transaction of type \\"cip42\\" was provided.
Serialized Transaction: \\"0x7cc20001\\"
Missing Attributes: maxPriorityFeePerGas, maxFeePerGas, gas, feeCurrency, to, gatewayFeeRecipient, gatewayFee, value, data, accessList
Version: viem@1.0.2"
`)
})

test('invalid transaction (missing signature)', () => {
expect(() =>
parseTransactionCelo(
`0x7c${toRlp([
'0x',
'0x',
'0x',
'0x',
'0x',
'0x',
'0x',
'0x',
'0x',
'0x',
'0x',
'0x',
'0x',
]).slice(2)}`,
),
).toThrowErrorMatchingInlineSnapshot(`
})

test('invalid transaction (missing signature)', () => {
expect(() =>
parseTransactionCelo(
`0x7c${toRlp([
'0x',
'0x',
'0x',
'0x',
'0x',
'0x',
'0x',
'0x',
'0x',
'0x',
'0x',
'0x',
'0x',
]).slice(2)}`,
),
).toThrowErrorMatchingInlineSnapshot(`
"Invalid serialized transaction of type \\"cip42\\" was provided.
Serialized Transaction: \\"0x7ccd80808080808080808080808080\\"
Missing Attributes: r, s
Version: viem@1.0.2"
`)
})
})
60 changes: 33 additions & 27 deletions src/chains/celo/parsers.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,50 @@
import { InvalidSerializedTransactionError } from '../../errors/transaction.js'
import type { Hex } from '../../types/misc.js'
import { isHex } from '../../utils/data/isHex.js'
import { sliceHex } from '../../utils/data/slice.js'
import { hexToBigInt, hexToNumber } from '../../utils/encoding/fromHex.js'
import type { RecursiveArray } from '../../utils/encoding/toRlp.js'
import type { GetSerializedTransactionType } from '../../utils/transaction/getSerializedTransactionType.js'
import {
type Hex,
type TransactionSerialized,
hexToBigInt,
hexToNumber,
isHex,
parseTransaction,
sliceHex,
} from '../../index.js'
import {
type ParseTransactionReturnType,
parseAccessList,
parseTransaction,
toTransactionArray,
} from '../../utils/transaction/parseTransaction.js'
import {
type CeloTransactionSerializable,
type SerializedCIP42TransactionReturnType,
type TransactionSerializableCIP42,
assertTransactionCIP42,
} from './serializers.js'
import { assertTransactionCIP42 } from './serializers.js'
import type {
CeloTransactionSerialized,
CeloTransactionType,
TransactionSerializableCIP42,
TransactionSerializedCIP42,
} from './types.js'

import type { RecursiveArray } from '../../utils/encoding/toRlp.js'
export type ParseTransactionCeloReturnType<
TSerialized extends CeloTransactionSerialized = CeloTransactionSerialized,
TType extends CeloTransactionType = GetSerializedTransactionType<TSerialized>,
> = TSerialized extends TransactionSerializedCIP42
? TransactionSerializableCIP42
: ParseTransactionReturnType<TSerialized, TType>

export function parseTransactionCelo(
serializedTransaction:
| TransactionSerialized
| SerializedCIP42TransactionReturnType,
): CeloTransactionSerializable {
export function parseTransactionCelo<
TSerialized extends CeloTransactionSerialized,
>(
serializedTransaction: TSerialized,
): ParseTransactionCeloReturnType<TSerialized> {
const serializedType = sliceHex(serializedTransaction, 0, 1)

if (serializedType === '0x7c') {
if (serializedType === '0x7c')
return parseTransactionCIP42(
serializedTransaction as SerializedCIP42TransactionReturnType,
)
}
serializedTransaction as TransactionSerializedCIP42,
) as ParseTransactionCeloReturnType<TSerialized>

return parseTransaction(serializedTransaction)
return parseTransaction(
serializedTransaction,
) as ParseTransactionCeloReturnType<TSerialized>
}

function parseTransactionCIP42(
serializedTransaction: SerializedCIP42TransactionReturnType,
serializedTransaction: TransactionSerializedCIP42,
): TransactionSerializableCIP42 {
const transactionArray = toTransactionArray(serializedTransaction)

Expand Down
Loading

0 comments on commit 3bf85d6

Please sign in to comment.