-
-
Notifications
You must be signed in to change notification settings - Fork 935
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add parseTransactionCelo for parsing out serialized transaction types specific to celo chain. * refactor --------- Co-authored-by: Aaron <aaron.deruvo@clabs.co> Co-authored-by: moxey.eth <jakemoxey@gmail.com>
- Loading branch information
1 parent
ed96577
commit 7981fa9
Showing
8 changed files
with
462 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"viem": minor | ||
--- | ||
|
||
Added `parseTransactionCelo` to the `viem/chains/utils` entrypoint. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
import { expect, test } from 'vitest' | ||
|
||
import { accounts } from '../../_test/constants.js' | ||
import { | ||
parseEther, | ||
parseGwei, | ||
parseTransaction as parseTransaction_, | ||
serializeTransaction, | ||
toRlp, | ||
} from '../../index.js' | ||
import { parseTransactionCelo } from './parsers.js' | ||
import { serializeTransactionCelo } from './serializers.js' | ||
import type { TransactionSerializableCIP42 } from './types.js' | ||
|
||
test('should be able to parse a cip42 transaction', () => { | ||
const signedTransaction = | ||
'0x7cf84682a4ec80847735940084773594008094765de816845861e75a25fca122bb6898b8b1282a808094f39fd6e51aad88f6f4ce6ab8827279cfffb92266880de0b6b3a764000080c0' | ||
|
||
expect(parseTransactionCelo(signedTransaction)).toMatchInlineSnapshot(` | ||
{ | ||
"chainId": 42220, | ||
"feeCurrency": "0x765de816845861e75a25fca122bb6898b8b1282a", | ||
"maxFeePerGas": 2000000000n, | ||
"maxPriorityFeePerGas": 2000000000n, | ||
"to": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", | ||
"type": "cip42", | ||
"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), | ||
) | ||
}) | ||
|
||
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) | ||
|
||
expect(parseTransactionCelo(serialized)).toMatchInlineSnapshot(` | ||
{ | ||
"chainId": 42270, | ||
"gas": 21001n, | ||
"gatewayFee": 100000000000000000n, | ||
"gatewayFeeRecipient": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", | ||
"maxFeePerGas": 2000000000n, | ||
"maxPriorityFeePerGas": 2000000000n, | ||
"nonce": 785, | ||
"to": "0x90f79bf6eb2c4f870365e785982e1f101e93b906", | ||
"type": "cip42", | ||
"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(` | ||
{ | ||
"accessList": [ | ||
{ | ||
"address": "0x0000000000000000000000000000000000000000", | ||
"storageKeys": [ | ||
"0x0000000000000000000000000000000000000000000000000000000000000001", | ||
"0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe", | ||
], | ||
}, | ||
], | ||
"chainId": 42270, | ||
"feeCurrency": "0x765de816845861e75a25fca122bb6898b8b1282a", | ||
"gas": 21001n, | ||
"maxFeePerGas": 2000000000n, | ||
"maxPriorityFeePerGas": 2000000000n, | ||
"nonce": 785, | ||
"to": "0x90f79bf6eb2c4f870365e785982e1f101e93b906", | ||
"type": "cip42", | ||
"value": 1000000000000000000n, | ||
} | ||
`) | ||
}) | ||
|
||
test('should parse a CIP42 transaction with data as 0x', () => { | ||
const transactionWithData: TransactionSerializableCIP42 = { | ||
feeCurrency: '0x765de816845861e75a25fca122bb6898b8b1282a', | ||
...transaction, | ||
chainId: 42270, | ||
data: '0x', | ||
} | ||
|
||
const serialized = serializeTransactionCelo(transactionWithData) | ||
|
||
expect(parseTransactionCelo(serialized)).toMatchInlineSnapshot(` | ||
{ | ||
"chainId": 42270, | ||
"feeCurrency": "0x765de816845861e75a25fca122bb6898b8b1282a", | ||
"gas": 21001n, | ||
"maxFeePerGas": 2000000000n, | ||
"maxPriorityFeePerGas": 2000000000n, | ||
"nonce": 785, | ||
"to": "0x90f79bf6eb2c4f870365e785982e1f101e93b906", | ||
"type": "cip42", | ||
"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(` | ||
{ | ||
"chainId": 42270, | ||
"data": "0x1234", | ||
"feeCurrency": "0x765de816845861e75a25fca122bb6898b8b1282a", | ||
"gas": 21001n, | ||
"maxFeePerGas": 2000000000n, | ||
"maxPriorityFeePerGas": 2000000000n, | ||
"nonce": 785, | ||
"to": "0x90f79bf6eb2c4f870365e785982e1f101e93b906", | ||
"type": "cip42", | ||
"value": 1000000000000000000n, | ||
} | ||
`) | ||
}) | ||
|
||
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(` | ||
"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(` | ||
"Invalid serialized transaction of type \\"cip42\\" was provided. | ||
Serialized Transaction: \\"0x7ccd80808080808080808080808080\\" | ||
Missing Attributes: r, s | ||
Version: viem@1.0.2" | ||
`) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
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 ParseTransactionReturnType, | ||
parseAccessList, | ||
parseTransaction, | ||
toTransactionArray, | ||
} from '../../utils/transaction/parseTransaction.js' | ||
import { assertTransactionCIP42 } from './serializers.js' | ||
import type { | ||
CeloTransactionSerialized, | ||
CeloTransactionType, | ||
TransactionSerializableCIP42, | ||
TransactionSerializedCIP42, | ||
} from './types.js' | ||
|
||
export type ParseTransactionCeloReturnType< | ||
TSerialized extends CeloTransactionSerialized = CeloTransactionSerialized, | ||
TType extends CeloTransactionType = GetSerializedTransactionType<TSerialized>, | ||
> = TSerialized extends TransactionSerializedCIP42 | ||
? TransactionSerializableCIP42 | ||
: ParseTransactionReturnType<TSerialized, TType> | ||
|
||
export function parseTransactionCelo< | ||
TSerialized extends CeloTransactionSerialized, | ||
>( | ||
serializedTransaction: TSerialized, | ||
): ParseTransactionCeloReturnType<TSerialized> { | ||
const serializedType = sliceHex(serializedTransaction, 0, 1) | ||
|
||
if (serializedType === '0x7c') | ||
return parseTransactionCIP42( | ||
serializedTransaction as TransactionSerializedCIP42, | ||
) as ParseTransactionCeloReturnType<TSerialized> | ||
|
||
return parseTransaction( | ||
serializedTransaction, | ||
) as ParseTransactionCeloReturnType<TSerialized> | ||
} | ||
|
||
function parseTransactionCIP42( | ||
serializedTransaction: TransactionSerializedCIP42, | ||
): TransactionSerializableCIP42 { | ||
const transactionArray = toTransactionArray(serializedTransaction) | ||
|
||
const [ | ||
chainId, | ||
nonce, | ||
maxPriorityFeePerGas, | ||
maxFeePerGas, | ||
gas, | ||
feeCurrency, | ||
gatewayFeeRecipient, | ||
gatewayFee, | ||
to, | ||
value, | ||
data, | ||
accessList, | ||
v, | ||
r, | ||
s, | ||
] = transactionArray | ||
|
||
if (transactionArray.length !== 15 && transactionArray.length !== 12) { | ||
throw new InvalidSerializedTransactionError({ | ||
attributes: { | ||
chainId, | ||
nonce, | ||
maxPriorityFeePerGas, | ||
maxFeePerGas, | ||
gas, | ||
feeCurrency, | ||
to, | ||
gatewayFeeRecipient, | ||
gatewayFee, | ||
value, | ||
data, | ||
accessList, | ||
...(transactionArray.length > 12 | ||
? { | ||
v, | ||
r, | ||
s, | ||
} | ||
: {}), | ||
}, | ||
serializedTransaction, | ||
type: 'cip42', | ||
}) | ||
} | ||
|
||
const transaction: Partial<TransactionSerializableCIP42> = { | ||
chainId: hexToNumber(chainId as Hex), | ||
type: 'cip42', | ||
} | ||
|
||
if (isHex(to) && to !== '0x') transaction.to = to | ||
if (isHex(gas) && gas !== '0x') transaction.gas = hexToBigInt(gas) | ||
if (isHex(data) && data !== '0x') transaction.data = data | ||
if (isHex(nonce) && nonce !== '0x') transaction.nonce = hexToNumber(nonce) | ||
if (isHex(value) && value !== '0x') transaction.value = hexToBigInt(value) | ||
if (isHex(feeCurrency) && feeCurrency !== '0x') | ||
transaction.feeCurrency = feeCurrency | ||
if (isHex(gatewayFeeRecipient) && gatewayFeeRecipient !== '0x') | ||
transaction.gatewayFeeRecipient = gatewayFeeRecipient | ||
if (isHex(gatewayFee) && gatewayFee !== '0x') | ||
transaction.gatewayFee = hexToBigInt(gatewayFee) | ||
if (isHex(maxFeePerGas) && maxFeePerGas !== '0x') | ||
transaction.maxFeePerGas = hexToBigInt(maxFeePerGas) | ||
if (isHex(maxPriorityFeePerGas) && maxPriorityFeePerGas !== '0x') | ||
transaction.maxPriorityFeePerGas = hexToBigInt(maxPriorityFeePerGas) | ||
if (accessList.length !== 0 && accessList !== '0x') | ||
transaction.accessList = parseAccessList(accessList as RecursiveArray<Hex>) | ||
|
||
assertTransactionCIP42(transaction as TransactionSerializableCIP42) | ||
|
||
return transaction as TransactionSerializableCIP42 | ||
} |
Oops, something went wrong.
7981fa9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
viem – ./
viem.vercel.app
viem-site.vercel.app
www.viem.sh
viem-wagmi-dev.vercel.app
viem-git-main-wagmi-dev.vercel.app
viem.sh