From 65a3e60f3c624c0251f45b53da772588c602b1bb Mon Sep 17 00:00:00 2001 From: Leszek Stachowski Date: Fri, 26 Apr 2024 10:52:02 +0200 Subject: [PATCH 01/19] Remove CIP-42 support (#16) --- .changeset/rude-vans-decide.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/rude-vans-decide.md diff --git a/.changeset/rude-vans-decide.md b/.changeset/rude-vans-decide.md new file mode 100644 index 0000000000..1e6ec80750 --- /dev/null +++ b/.changeset/rude-vans-decide.md @@ -0,0 +1,7 @@ +--- +"viem": minor +--- + +Removed CIP-42 support. + +Any transactions with feeCurrency field will be treated as CIP-64. From bf606a5760f3e60eb450a233c63326e146572d86 Mon Sep 17 00:00:00 2001 From: Leszek Stachowski Date: Thu, 18 Apr 2024 16:35:35 +0200 Subject: [PATCH 02/19] CIP-66 support --- src/celo/formatters.test.ts | 68 +++++++++++- src/celo/formatters.ts | 13 ++- src/celo/index.ts | 6 + src/celo/parsers.test.ts | 130 +++++++++++++++++++++- src/celo/parsers.ts | 83 ++++++++++++++ src/celo/serializers.test.ts | 206 +++++++++++++++++++++++++++++++++++ src/celo/serializers.ts | 76 ++++++++++++- src/celo/types.ts | 81 +++++++++++++- src/celo/utils.ts | 15 +++ 9 files changed, 664 insertions(+), 14 deletions(-) diff --git a/src/celo/formatters.test.ts b/src/celo/formatters.test.ts index d7f5f2389c..683bd1eb87 100644 --- a/src/celo/formatters.test.ts +++ b/src/celo/formatters.test.ts @@ -1,5 +1,6 @@ import { describe, expect, test } from 'vitest' +import type { TransactionLegacy } from '~viem/index.js' import { getBlock } from '../actions/public/getBlock.js' import { getTransaction } from '../actions/public/getTransaction.js' import { celo } from '../chains/index.js' @@ -243,7 +244,7 @@ describe('block', () => { }) const { extraData: _extraData, transactions, ...rest } = block - expect(transactions[0]).toMatchInlineSnapshot(` + expect(transactions[0] as TransactionLegacy).toMatchInlineSnapshot(` { "blockHash": "0xac8c9bc3b84e103dc321bbe83b670e425ff68bfc9a333a4f1b1b204ad11c583d", "blockNumber": 16645775n, @@ -307,6 +308,7 @@ describe('transaction', () => { blockNumber: '0x1', chainId: '0x1', feeCurrency: null, + maxFeeInFeeCurrency: null, from: '0xa152f8bb749c55e9943a3a0a3111d18ee2b3f94e', gas: '0x2', gasPrice: undefined, @@ -341,6 +343,7 @@ describe('transaction', () => { "gatewayFeeRecipient": null, "hash": "0xa4b1f606b66105fa45cb5db23d2f6597075701e7f0e2367f4e6a39d17a8cf98b", "input": "0x23b872dd000000000000000000000000a00f99bc38b1ecda1fd70eaa1cd31d576a9f46b0000000000000000000000000f16e9b0d03470827a95cdfd0cb8a8a3b46969b910000000000000000000000000000000000000000000000000000002b3b6fb3d0", + "maxFeeInFeeCurrency": null, "maxFeePerGas": 4n, "maxPriorityFeePerGas": 5n, "nonce": 6, @@ -364,6 +367,7 @@ describe('transaction', () => { blockNumber: '0x1', chainId: '0x1', feeCurrency: null, + maxFeeInFeeCurrency: null, from: '0xa152f8bb749c55e9943a3a0a3111d18ee2b3f94e', gas: '0x2', gasPrice: undefined, @@ -398,6 +402,7 @@ describe('transaction', () => { "gatewayFeeRecipient": null, "hash": "0xa4b1f606b66105fa45cb5db23d2f6597075701e7f0e2367f4e6a39d17a8cf98b", "input": "0x23b872dd000000000000000000000000a00f99bc38b1ecda1fd70eaa1cd31d576a9f46b0000000000000000000000000f16e9b0d03470827a95cdfd0cb8a8a3b46969b910000000000000000000000000000000000000000000000000000002b3b6fb3d0", + "maxFeeInFeeCurrency": null, "maxFeePerGas": 4n, "maxPriorityFeePerGas": 5n, "nonce": 6, @@ -413,6 +418,7 @@ describe('transaction', () => { } `) + // CIP-42 expect( transaction.format({ accessList: [], @@ -471,6 +477,7 @@ describe('transaction', () => { } `) + // CIP-64 expect( transaction.format({ accessList: [], @@ -524,6 +531,63 @@ describe('transaction', () => { "yParity": 1, } `) + + // CIP-66 + expect( + transaction.format({ + accessList: [], + blockHash: + '0x89644bbd5c8d682a2e9611170e6c1f02573d866d286f006cbf517eec7254ec2d', + blockNumber: '0x1', + chainId: '0x1', + feeCurrency: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', + maxFeeInFeeCurrency: '0x12345', + from: '0xa152f8bb749c55e9943a3a0a3111d18ee2b3f94e', + gas: '0x2', + gasPrice: undefined, + hash: '0xa4b1f606b66105fa45cb5db23d2f6597075701e7f0e2367f4e6a39d17a8cf98b', + input: + '0x23b872dd000000000000000000000000a00f99bc38b1ecda1fd70eaa1cd31d576a9f46b0000000000000000000000000f16e9b0d03470827a95cdfd0cb8a8a3b46969b910000000000000000000000000000000000000000000000000000002b3b6fb3d0', + maxFeePerGas: '0x4', + maxPriorityFeePerGas: '0x5', + nonce: '0x6', + r: '0x5e49a7bd0534c6b6d3bbe581659424d3747f920d40ce56e48d26e5d94aac32ca', + s: '0x1746abe27b7c4f00bda1ec714ac1f7083e9025b6ca3b2248e439a173e4ab55e0', + to: '0x15d4c048f83bd7e37d49ea4c83a07267ec4203da', + transactionIndex: '0x7', + type: '0x7a', + v: '0x1', + value: '0x0', + yParity: '0x1', + }), + ).toMatchInlineSnapshot(` + { + "accessList": [], + "blockHash": "0x89644bbd5c8d682a2e9611170e6c1f02573d866d286f006cbf517eec7254ec2d", + "blockNumber": 1n, + "chainId": 1, + "feeCurrency": "0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9", + "from": "0xa152f8bb749c55e9943a3a0a3111d18ee2b3f94e", + "gas": 2n, + "gasPrice": undefined, + "hash": "0xa4b1f606b66105fa45cb5db23d2f6597075701e7f0e2367f4e6a39d17a8cf98b", + "input": "0x23b872dd000000000000000000000000a00f99bc38b1ecda1fd70eaa1cd31d576a9f46b0000000000000000000000000f16e9b0d03470827a95cdfd0cb8a8a3b46969b910000000000000000000000000000000000000000000000000000002b3b6fb3d0", + "maxFeeInFeeCurrency": "0x12345", + "maxFeePerBlobGas": undefined, + "maxFeePerGas": 4n, + "maxPriorityFeePerGas": 5n, + "nonce": 6, + "r": "0x5e49a7bd0534c6b6d3bbe581659424d3747f920d40ce56e48d26e5d94aac32ca", + "s": "0x1746abe27b7c4f00bda1ec714ac1f7083e9025b6ca3b2248e439a173e4ab55e0", + "to": "0x15d4c048f83bd7e37d49ea4c83a07267ec4203da", + "transactionIndex": 7, + "type": "cip66", + "typeHex": "0x7a", + "v": 1n, + "value": 0n, + "yParity": 1, + } + `) }) test('action', async () => { @@ -537,7 +601,7 @@ describe('transaction', () => { index: 0, }) - expect(transaction).toMatchInlineSnapshot(` + expect(transaction as TransactionLegacy).toMatchInlineSnapshot(` { "blockHash": "0x740371d30b3cee9d687f72e3409ba6447eceda7de86bc38b0fa84493114b510b", "blockNumber": 16628100n, diff --git a/src/celo/formatters.ts b/src/celo/formatters.ts index 6f7defe996..3c55298c04 100644 --- a/src/celo/formatters.ts +++ b/src/celo/formatters.ts @@ -15,7 +15,7 @@ import type { CeloTransaction, CeloTransactionRequest, } from './types.js' -import { isCIP64 } from './utils.js' +import { isCIP64, isCIP66 } from './utils.js' export const formatters = { block: /*#__PURE__*/ defineBlock({ @@ -52,8 +52,11 @@ export const formatters = { format(args: CeloRpcTransaction): CeloTransaction { const transaction = { feeCurrency: args.feeCurrency } as CeloTransaction - if (args.type === '0x7b') transaction.type = 'cip64' - else { + if (args.type === '0x7a') { + transaction.type = 'cip66' + } else if (args.type === '0x7b') { + transaction.type = 'cip64' + } else { if (args.type === '0x7c') transaction.type = 'cip42' transaction.gatewayFee = args.gatewayFee @@ -72,7 +75,9 @@ export const formatters = { feeCurrency: args.feeCurrency, } as CeloRpcTransactionRequest - if (isCIP64(args)) { + if (isCIP66(args)) { + request.type = '0x7a' + } else if (isCIP64(args)) { request.type = '0x7b' } diff --git a/src/celo/index.ts b/src/celo/index.ts index c84b14c64d..289d70aefb 100644 --- a/src/celo/index.ts +++ b/src/celo/index.ts @@ -19,12 +19,18 @@ export type { CeloTransactionType, RpcTransactionCIP42, RpcTransactionCIP64, + RpcTransactionCIP66, RpcTransactionRequestCIP64, + RpcTransactionRequestCIP66, TransactionCIP42, TransactionCIP64, + TransactionCIP66, TransactionRequestCIP64, + TransactionRequestCIP66, TransactionSerializableCIP42, TransactionSerializableCIP64, + TransactionSerializableCIP66, TransactionSerializedCIP42, TransactionSerializedCIP64, + TransactionSerializedCIP66, } from './types.js' diff --git a/src/celo/parsers.test.ts b/src/celo/parsers.test.ts index c9f48cbe3e..6dc0dc6494 100644 --- a/src/celo/parsers.test.ts +++ b/src/celo/parsers.test.ts @@ -10,7 +10,10 @@ import { } from '../index.js' import { parseTransaction } from './parsers.js' import { serializeTransaction } from './serializers.js' -import type { TransactionSerializableCIP64 } from './types.js' +import type { + TransactionSerializableCIP64, + TransactionSerializableCIP66, +} from './types.js' test('should be able to parse a cip42 transaction', () => { const signedTransaction = @@ -371,3 +374,128 @@ describe('should throw an error for invalid cip64 transactions', () => { `) }) }) + +describe('should parse a CIP66 transaction', () => { + const transactionCip66 = { + ...transaction, + feeCurrency: '0x765de816845861e75a25fca122bb6898b8b1282a', + maxFeeInFeeCurrency: 12345n, + chainId: 42270, + type: 'cip66', + } as TransactionSerializableCIP66 + + test('when type is not specified, but the fields match CIP66', () => { + const transactionWithoutType = { + ...transaction, + feeCurrency: '0x765de816845861e75a25fca122bb6898b8b1282a', + maxFeeInFeeCurrency: 12345n, + type: 'cip66', + chainId: 42270, + } as TransactionSerializableCIP66 + + const serialized = serializeTransaction(transactionWithoutType) + + expect(parseTransaction(serialized)).toMatchInlineSnapshot(` + { + "chainId": 42270, + "feeCurrency": "0x765de816845861e75a25fca122bb6898b8b1282a", + "gas": 21001n, + "maxFeeInFeeCurrency": 12345n, + "maxFeePerGas": 2000000000n, + "maxPriorityFeePerGas": 2000000000n, + "nonce": 785, + "to": "0x90f79bf6eb2c4f870365e785982e1f101e93b906", + "type": "cip66", + "value": 1000000000000000000n, + } + `) + }) + + test('with access list', () => { + const transactionWithAccessList: TransactionSerializableCIP66 = { + ...transactionCip66, + accessList: [ + { + address: '0x0000000000000000000000000000000000000000', + storageKeys: [ + '0x0000000000000000000000000000000000000000000000000000000000000001', + '0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe', + ], + }, + ], + } + + const serialized = serializeTransaction(transactionWithAccessList) + + expect(parseTransaction(serialized)).toMatchInlineSnapshot(` + { + "accessList": [ + { + "address": "0x0000000000000000000000000000000000000000", + "storageKeys": [ + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe", + ], + }, + ], + "chainId": 42270, + "feeCurrency": "0x765de816845861e75a25fca122bb6898b8b1282a", + "gas": 21001n, + "maxFeeInFeeCurrency": 12345n, + "maxFeePerGas": 2000000000n, + "maxPriorityFeePerGas": 2000000000n, + "nonce": 785, + "to": "0x90f79bf6eb2c4f870365e785982e1f101e93b906", + "type": "cip66", + "value": 1000000000000000000n, + } + `) + }) + test('with data as 0x', () => { + const transactionWithData: TransactionSerializableCIP66 = { + ...transactionCip66, + data: '0x', + } + + const serialized = serializeTransaction(transactionWithData) + + expect(parseTransaction(serialized)).toMatchInlineSnapshot(` + { + "chainId": 42270, + "feeCurrency": "0x765de816845861e75a25fca122bb6898b8b1282a", + "gas": 21001n, + "maxFeeInFeeCurrency": 12345n, + "maxFeePerGas": 2000000000n, + "maxPriorityFeePerGas": 2000000000n, + "nonce": 785, + "to": "0x90f79bf6eb2c4f870365e785982e1f101e93b906", + "type": "cip66", + "value": 1000000000000000000n, + } + `) + }) + test('with data', () => { + const transactionWithData: TransactionSerializableCIP66 = { + ...transactionCip66, + data: '0x1234', + } + + const serialized = serializeTransaction(transactionWithData) + + expect(parseTransaction(serialized)).toMatchInlineSnapshot(` + { + "chainId": 42270, + "data": "0x1234", + "feeCurrency": "0x765de816845861e75a25fca122bb6898b8b1282a", + "gas": 21001n, + "maxFeeInFeeCurrency": 12345n, + "maxFeePerGas": 2000000000n, + "maxPriorityFeePerGas": 2000000000n, + "nonce": 785, + "to": "0x90f79bf6eb2c4f870365e785982e1f101e93b906", + "type": "cip66", + "value": 1000000000000000000n, + } + `) + }) +}) diff --git a/src/celo/parsers.ts b/src/celo/parsers.ts index a94b8ab4fb..81d19270ca 100644 --- a/src/celo/parsers.ts +++ b/src/celo/parsers.ts @@ -15,14 +15,17 @@ import { import { assertTransactionCIP42, assertTransactionCIP64, + assertTransactionCIP66, } from './serializers.js' import type { CeloTransactionSerialized, CeloTransactionType, TransactionSerializableCIP42, TransactionSerializableCIP64, + TransactionSerializableCIP66, TransactionSerializedCIP42, TransactionSerializedCIP64, + TransactionSerializedCIP66, } from './types.js' export type ParseTransactionReturnType< @@ -47,6 +50,11 @@ export function parseTransaction( serializedTransaction as TransactionSerializedCIP64, ) as ParseTransactionReturnType + if (serializedType === '0x7a') + return parseTransactionCIP66( + serializedTransaction as TransactionSerializedCIP66, + ) as ParseTransactionReturnType + return parseTransaction_( serializedTransaction, ) as ParseTransactionReturnType @@ -201,3 +209,78 @@ function parseTransactionCIP64( return transaction as TransactionSerializableCIP64 } + +function parseTransactionCIP66( + serializedTransaction: TransactionSerializedCIP66, +): TransactionSerializableCIP66 { + const transactionArray = toTransactionArray(serializedTransaction) + + const [ + chainId, + nonce, + maxPriorityFeePerGas, + maxFeePerGas, + gas, + to, + value, + data, + accessList, + feeCurrency, + maxFeeInFeeCurrency, + v, + r, + s, + ] = transactionArray + + if (transactionArray.length !== 14 && transactionArray.length !== 11) { + throw new InvalidSerializedTransactionError({ + attributes: { + chainId, + nonce, + maxPriorityFeePerGas, + maxFeePerGas, + gas, + to, + value, + data, + accessList, + feeCurrency, + maxFeeInFeeCurrency, + ...(transactionArray.length > 11 + ? { + v, + r, + s, + } + : {}), + }, + serializedTransaction, + type: 'cip66', + }) + } + + const transaction: ExactPartial = { + chainId: hexToNumber(chainId as Hex), + type: 'cip66', + } + + 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(maxFeeInFeeCurrency) && maxFeeInFeeCurrency !== '0x') + transaction.maxFeeInFeeCurrency = hexToBigInt(maxFeeInFeeCurrency) + 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) + + assertTransactionCIP66(transaction as TransactionSerializableCIP66) + + return transaction as TransactionSerializableCIP66 +} diff --git a/src/celo/serializers.test.ts b/src/celo/serializers.test.ts index 16a6d9df9c..9677f38f76 100644 --- a/src/celo/serializers.test.ts +++ b/src/celo/serializers.test.ts @@ -16,6 +16,7 @@ import { serializeTransaction } from './serializers.js' import type { TransactionSerializableCIP42, TransactionSerializableCIP64, + TransactionSerializableCIP66, } from './types.js' const commonBaseTx = { @@ -40,6 +41,13 @@ const baseCip64 = { maxPriorityFeePerGas: parseGwei('2'), } as TransactionSerializableCIP64 +const baseCip66 = { + ...commonBaseTx, + maxFeePerGas: parseGwei('2'), + maxPriorityFeePerGas: parseGwei('2'), + maxFeeInFeeCurrency: parseGwei('12345'), +} as TransactionSerializableCIP66 + describe('cip64', () => { test('should be able to serialize a cip64 transaction', () => { // sanity checks the serialized value, but then rely on the parser @@ -236,6 +244,204 @@ describe('cip64', () => { }) }) +describe('cip66', () => { + test('should be able to serialize a cip66 transaction', () => { + const serialized = serializeTransaction(baseCip66) + const reparsed = parseTransaction(serialized) + const reserialized = serializeTransaction(reparsed) + expect(serialized).toEqual( + '0x7af84b82a4ec01847735940084773594008094f39fd6e51aad88f6f4ce6ab8827279cfffb92266880de0b6b3a764000080c094765de816845861e75a25fca122bb6898b8b1282a860b3a4b56fa00', + ) + expect(reparsed).toEqual({ ...baseCip66, type: 'cip66' }) + expect(serialized).toEqual(reserialized) + }) + + test('args: accessList', () => { + const transaction: TransactionSerializableCIP66 = { + ...baseCip66, + accessList: [ + { + address: '0x0000000000000000000000000000000000000000', + storageKeys: [ + '0x0000000000000000000000000000000000000000000000000000000000000001', + '0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe', + ], + }, + ], + } + + expect(parseTransaction(serializeTransaction(transaction))).toEqual({ + ...transaction, + type: 'cip66', + }) + }) + + test('args: data', () => { + const transaction: TransactionSerializableCIP66 = { + ...baseCip66, + data: '0x1234', + } + expect(parseTransaction(serializeTransaction(transaction))).toEqual({ + ...transaction, + type: 'cip66', + }) + }) + + test('args: gas', () => { + const transaction: TransactionSerializableCIP66 = { + ...baseCip66, + gas: 69420n, + } + expect(parseTransaction(serializeTransaction(transaction))).toEqual({ + ...transaction, + type: 'cip66', + }) + }) + + test('args: gas (absent)', () => { + const transaction: TransactionSerializableCIP66 = { + ...baseCip66, + gas: undefined, + } + expect(parseTransaction(serializeTransaction(transaction))).toEqual({ + ...transaction, + type: 'cip66', + }) + }) + + test('args: maxFeePerGas (absent)', () => { + const transaction: TransactionSerializableCIP66 = { + ...baseCip66, + type: 'cip66', + maxFeePerGas: undefined, + } + expect(parseTransaction(serializeTransaction(transaction))).toEqual({ + ...transaction, + type: 'cip66', + }) + }) + + test('args: maxPriorityFeePerGas (absent)', () => { + const transaction: TransactionSerializableCIP66 = { + ...baseCip66, + type: 'cip66', + maxPriorityFeePerGas: undefined, + } + expect(parseTransaction(serializeTransaction(transaction))).toEqual({ + ...transaction, + type: 'cip66', + }) + }) + + test('args: nonce (absent)', () => { + const transaction: TransactionSerializableCIP66 = { + ...baseCip66, + nonce: undefined, + } + expect(parseTransaction(serializeTransaction(transaction))).toEqual({ + ...transaction, + type: 'cip66', + }) + }) + + test('args: to (absent)', () => { + const transaction: TransactionSerializableCIP66 = { + ...baseCip66, + to: undefined, + } + expect(parseTransaction(serializeTransaction(transaction))).toEqual({ + ...transaction, + type: 'cip66', + }) + }) + + test('args: value (absent)', () => { + const transaction: TransactionSerializableCIP66 = { + ...baseCip66, + value: undefined, + } + expect(parseTransaction(serializeTransaction(transaction))).toEqual({ + ...transaction, + type: 'cip66', + }) + }) + + test('type is undefined but has cip66 fields (feeCurrency, but not gateway*)', () => { + const transaction: TransactionSerializableCIP66 = { + ...baseCip66, + feeCurrency: '0xd8763cba276a3738e6de85b4b3bf5fded6d6ca73', + type: undefined, + } + expect(parseTransaction(serializeTransaction(transaction))).toEqual({ + ...transaction, + type: 'cip66', + }) + }) + + test('signed', async () => { + const signed = await signTransaction({ + privateKey: accounts[0].privateKey, + transaction: baseCip66, + serializer: serializeTransaction, + }) + + console.log('SIGNED:', signed) + + const serialized = + '0x7af88e82a4ec01847735940084773594008094f39fd6e51aad88f6f4ce6ab8827279cfffb92266880de0b6b3a764000080c094765de816845861e75a25fca122bb6898b8b1282a860b3a4b56fa0001a0f376d59efea3eb24397b74303b6225aeb6d32ca57f2854c4454c49c779cd68dda0214b12ee3d68b7aec1dc43ee5e668bd76ba3a805350e8ae9ca54a381ac9871e8' + expect(signed).toEqual(serialized) + expect(parseTransaction(signed)).toEqual({ + ...baseCip66, + type: 'cip66', + }) + }) + + test('signature', () => { + const tx1 = + '0x7af88e82a4ec01847735940084773594008094f39fd6e51aad88f6f4ce6ab8827279cfffb92266880de0b6b3a764000080c094765de816845861e75a25fca122bb6898b8b1282a860b3a4b56fa0001a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fea060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe' + const tx2 = + '0x7af88e82a4ec01847735940084773594008094f39fd6e51aad88f6f4ce6ab8827279cfffb92266880de0b6b3a764000080c094765de816845861e75a25fca122bb6898b8b1282a860b3a4b56fa0080a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fea060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe' + + expect( + serializeTransaction( + baseCip66, + + { + r: '0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe', + s: '0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe', + yParity: 1, + }, + ), + ).toEqual(tx1) + expect( + serializeTransaction( + baseCip66, + + { + r: '0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe', + s: '0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe', + yParity: 0, + }, + ), + ).toEqual(tx2) + expect(parseTransaction(tx1)).toEqual(parseTransaction(tx2)) + expect(parseTransaction(tx1)).toEqual({ ...baseCip66, type: 'cip66' }) + }) + + test('CIP-42 transaction that has all CIP-64 fields and CIP-64 takes precedence', () => { + const transaction: TransactionSerializableCIP42 = { + ...baseCip42, + gatewayFeeRecipient: undefined, + gatewayFee: undefined, + type: 'cip42', + } + expect(parseTransaction(serializeTransaction(transaction as any))).toEqual({ + ...transaction, + type: 'cip64', + }) + }) +}) + describe('invalid params specific to CIP-64', () => { test('transaction looks like cip64 but does not have a value for feeCurrency', () => { const transaction: TransactionSerializableCIP64 = { diff --git a/src/celo/serializers.ts b/src/celo/serializers.ts index 243403557b..9e6ac93036 100644 --- a/src/celo/serializers.ts +++ b/src/celo/serializers.ts @@ -17,16 +17,23 @@ import type { CeloTransactionSerializable, TransactionSerializableCIP42, TransactionSerializableCIP64, + TransactionSerializableCIP66, TransactionSerializedCIP64, + TransactionSerializedCIP66, } from './types.js' -import { isCIP64, isEmpty, isPresent } from './utils.js' +import { isCIP64, isCIP66, isEmpty, isPresent } from './utils.js' export function serializeTransaction( transaction: CeloTransactionSerializable, signature?: Signature | undefined, ) { - if (isCIP64(transaction)) + if (isCIP66(transaction)) { + return serializeTransactionCIP66(transaction, signature) + } + + if (isCIP64(transaction)) { return serializeTransactionCIP64(transaction, signature) + } return serializeTransaction_(transaction, signature) } @@ -39,6 +46,7 @@ export const serializers = { // Serializers export type SerializeTransactionCIP64ReturnType = TransactionSerializedCIP64 +export type SerializeTransactionCIP66ReturnType = TransactionSerializedCIP66 function serializeTransactionCIP64( transaction: TransactionSerializableCIP64, @@ -78,6 +86,47 @@ function serializeTransactionCIP64( ]) as SerializeTransactionCIP64ReturnType } +function serializeTransactionCIP66( + transaction: TransactionSerializableCIP66, + signature?: Signature | undefined, +): SerializeTransactionCIP66ReturnType { + assertTransactionCIP66(transaction) + + const { + chainId, + gas, + nonce, + to, + value, + maxFeePerGas, + maxPriorityFeePerGas, + accessList, + feeCurrency, + maxFeeInFeeCurrency, + data, + } = transaction + + const serializedTransaction = [ + toHex(chainId), + nonce ? toHex(nonce) : '0x', + maxPriorityFeePerGas ? toHex(maxPriorityFeePerGas) : '0x', + maxFeePerGas ? toHex(maxFeePerGas) : '0x', + gas ? toHex(gas) : '0x', + to ?? '0x', + value ? toHex(value) : '0x', + data ?? '0x', + serializeAccessList(accessList), + feeCurrency!, + toHex(maxFeeInFeeCurrency!), + ...toYParitySignatureArray(transaction, signature), + ] + + return concatHex([ + '0x7a', + toRlp(serializedTransaction), + ]) as SerializeTransactionCIP66ReturnType +} + // maxFeePerGas must be less than 2^256 - 1 const MAX_MAX_FEE_PER_GAS = 2n ** 256n - 1n @@ -137,8 +186,11 @@ export function assertTransactionCIP42( } } +type CIP_64_OR_CIP_66 = 'CIP-64' | 'CIP-66' + export function assertTransactionCIP64( transaction: TransactionSerializableCIP64, + type: CIP_64_OR_CIP_66 = 'CIP-64', ) { const { chainId, @@ -154,7 +206,7 @@ export function assertTransactionCIP64( if (gasPrice) throw new BaseError( - '`gasPrice` is not a valid CIP-64 Transaction attribute.', + `\`gasPrice\` is not a valid ${type} Transaction attribute.`, ) if (isPresent(maxFeePerGas) && maxFeePerGas > MAX_MAX_FEE_PER_GAS) @@ -168,13 +220,27 @@ export function assertTransactionCIP64( if (isPresent(feeCurrency) && !isAddress(feeCurrency)) { throw new BaseError( - '`feeCurrency` MUST be a token address for CIP-64 transactions.', + `\`feeCurrency\` MUST be a token address for ${type} transactions.`, ) } if (isEmpty(feeCurrency)) { throw new BaseError( - '`feeCurrency` must be provided for CIP-64 transactions.', + `\`feeCurrency\` must be provided for ${type} transactions.`, + ) + } +} + +export function assertTransactionCIP66( + transaction: TransactionSerializableCIP66, +) { + assertTransactionCIP64(transaction as TransactionSerializableCIP64, 'CIP-66') + + const { maxFeeInFeeCurrency } = transaction + + if (isEmpty(maxFeeInFeeCurrency)) { + throw new BaseError( + '`maxFeeInFeeCurrency` must be provided for CIP-66 transactions.', ) } } diff --git a/src/celo/types.ts b/src/celo/types.ts index a57cc7afd1..39174d736e 100644 --- a/src/celo/types.ts +++ b/src/celo/types.ts @@ -73,22 +73,28 @@ export type CeloRpcTransaction = | RpcTransaction | RpcTransactionCIP42 | RpcTransactionCIP64 + | RpcTransactionCIP66 export type CeloRpcTransactionRequest = | RpcTransactionRequest | RpcTransactionRequestCIP64 + | RpcTransactionRequestCIP66 export type CeloTransaction = | Transaction | TransactionCIP42 | TransactionCIP64 + | TransactionCIP66 export type CeloTransactionRequest = | TransactionRequest | TransactionRequestCIP64 + | TransactionRequestCIP66 export type CeloTransactionSerializable = OneOf< - TransactionSerializable | TransactionSerializableCIP64 + | TransactionSerializable + | TransactionSerializableCIP64 + | TransactionSerializableCIP66 > export type CeloTransactionSerialized< @@ -97,18 +103,21 @@ export type CeloTransactionSerialized< | TransactionSerialized | TransactionSerializedCIP42 | TransactionSerializedCIP64 + | TransactionSerializedCIP66 -export type CeloTransactionType = TransactionType | 'cip42' | 'cip64' +export type CeloTransactionType = TransactionType | 'cip42' | 'cip64' | 'cip66' type RpcTransaction = RpcTransaction_ & { feeCurrency: Address | null + maxFeeInFeeCurrency: bigint | null gatewayFee: Hex | null gatewayFeeRecipient: Address | null } type RpcTransactionRequest = RpcTransactionRequest_ & { feeCurrency?: Address | undefined + maxFeeInFeeCurrency?: bigint | null } export type RpcTransactionCIP42 = Omit< @@ -117,6 +126,7 @@ export type RpcTransactionCIP42 = Omit< > & FeeValuesEIP1559 & { feeCurrency: Address | null + maxFeeInFeeCurrency?: undefined gatewayFee: Hex | null gatewayFeeRecipient: Address | null type: '0x7c' @@ -128,11 +138,24 @@ export type RpcTransactionCIP64 = Omit< > & FeeValuesEIP1559 & { feeCurrency: Address | null + maxFeeInFeeCurrency?: undefined gatewayFee?: undefined gatewayFeeRecipient?: undefined type: '0x7b' } +export type RpcTransactionCIP66 = Omit< + TransactionBase, + 'typeHex' +> & + FeeValuesEIP1559 & { + feeCurrency: Address | null + maxFeeInFeeCurrency: Quantity | null + gatewayFee?: undefined + gatewayFeeRecipient?: undefined + type: '0x7a' + } + export type RpcTransactionRequestCIP64 = TransactionRequestBase< Quantity, Index @@ -140,9 +163,21 @@ export type RpcTransactionRequestCIP64 = TransactionRequestBase< ExactPartial> & { accessList?: AccessList | undefined feeCurrency?: Address | undefined + maxFeeInFeeCurrency?: undefined type?: '0x7b' | undefined } +export type RpcTransactionRequestCIP66 = TransactionRequestBase< + Quantity, + Index +> & + ExactPartial> & { + accessList?: AccessList | undefined + feeCurrency?: Address | undefined + maxFeeInFeeCurrency?: Quantity | undefined + type?: '0x7a' | undefined + } + type Transaction = Transaction_< bigint, number, @@ -171,17 +206,40 @@ export type TransactionCIP64 = type: 'cip64' } +export type TransactionCIP66 = + TransactionBase & + FeeValuesEIP1559 & { + feeCurrency: Address | null + maxFeeInFeeCurrency: bigint | null + gatewayFee?: undefined + gatewayFeeRecipient?: undefined + type: 'cip66' + } + type TransactionRequest = TransactionRequest_ & { feeCurrency?: Address | undefined + maxFeeInFeeCurrency?: bigint | undefined } export type TransactionRequestCIP64 = TransactionRequestBase & ExactPartial & { accessList?: AccessList | undefined feeCurrency?: Address | undefined + maxFeeInFeeCurrency?: undefined type?: 'cip64' | undefined } +export type TransactionRequestCIP66 = + TransactionRequestBase & + ExactPartial & { + accessList?: AccessList | undefined + feeCurrency?: Address | undefined + maxFeeInFeeCurrency?: TQuantity | undefined + gatewayFee?: undefined + gatewayFeeRecipient?: undefined + type?: 'cip66' | undefined + } + export type TransactionSerializableCIP42< TQuantity = bigint, TIndex = number, @@ -189,6 +247,7 @@ export type TransactionSerializableCIP42< ExactPartial> & { accessList?: AccessList | undefined feeCurrency?: Address | undefined + maxFeeInFeeCurrency?: undefined gatewayFeeRecipient?: Address | undefined gatewayFee?: TQuantity | undefined chainId: number @@ -202,9 +261,27 @@ export type TransactionSerializableCIP64< ExactPartial> & { accessList?: AccessList | undefined feeCurrency?: Address | undefined + maxFeeInFeeCurrency?: undefined + gatewayFee?: undefined + gatewayFeeRecipient?: undefined chainId: number type?: 'cip64' | undefined } +export type TransactionSerializableCIP66< + TQuantity = bigint, + TIndex = number, +> = TransactionSerializableBase & + ExactPartial> & { + accessList?: AccessList | undefined + feeCurrency?: Address | undefined + maxFeeInFeeCurrency?: TQuantity | undefined + gatewayFee?: undefined + gatewayFeeRecipient?: undefined + chainId: number + type?: 'cip66' | undefined + } + export type TransactionSerializedCIP42 = `0x7c${string}` export type TransactionSerializedCIP64 = `0x7b${string}` +export type TransactionSerializedCIP66 = `0x7a${string}` diff --git a/src/celo/utils.ts b/src/celo/utils.ts index d16552b7a0..1e515beeb5 100644 --- a/src/celo/utils.ts +++ b/src/celo/utils.ts @@ -4,6 +4,7 @@ import type { CeloTransactionRequest, CeloTransactionSerializable, TransactionSerializableCIP64, + TransactionSerializableCIP66, } from './types.js' export function isEmpty( @@ -56,3 +57,17 @@ export function isCIP64( return isEIP1559(transaction) && isPresent(transaction.feeCurrency) } + +export function isCIP66( + transaction: CeloTransactionSerializable | CeloTransactionRequest, +): transaction is TransactionSerializableCIP66 { + if (transaction.type === 'cip66') { + return true + } + + return ( + isEIP1559(transaction) && + isPresent(transaction.feeCurrency) && + isPresent(transaction.maxFeeInFeeCurrency) + ) +} From 7f1521409cb0ea42171951f1c8861ed3dab0ccfd Mon Sep 17 00:00:00 2001 From: Leszek Stachowski Date: Thu, 18 Apr 2024 16:37:30 +0200 Subject: [PATCH 03/19] add changeset --- .changeset/nasty-mayflies-search.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/nasty-mayflies-search.md diff --git a/.changeset/nasty-mayflies-search.md b/.changeset/nasty-mayflies-search.md new file mode 100644 index 0000000000..1301185faa --- /dev/null +++ b/.changeset/nasty-mayflies-search.md @@ -0,0 +1,7 @@ +--- +"viem": minor +--- + +Add CIP-66 support for Celo + +https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0066.md From 0d9f5cdc7e8e80bd48058d94aeacb0c68c27bd73 Mon Sep 17 00:00:00 2001 From: Leszek Stachowski Date: Fri, 19 Apr 2024 14:35:06 +0200 Subject: [PATCH 04/19] solve autocomplete issue --- src/celo/formatters.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/celo/formatters.ts b/src/celo/formatters.ts index 3c55298c04..84a754635a 100644 --- a/src/celo/formatters.ts +++ b/src/celo/formatters.ts @@ -77,6 +77,7 @@ export const formatters = { if (isCIP66(args)) { request.type = '0x7a' + request.maxFeeInFeeCurrency = args.maxFeeInFeeCurrency } else if (isCIP64(args)) { request.type = '0x7b' } From 54a44c8f72145d93c72df7e1ceaab1981d556804 Mon Sep 17 00:00:00 2001 From: Leszek Stachowski Date: Mon, 22 Apr 2024 12:54:32 +0200 Subject: [PATCH 05/19] fix snapshots, fix types, rename type --- src/celo/formatters.test.ts | 11 +++++++---- src/celo/formatters.ts | 3 +++ src/celo/serializers.ts | 4 ++-- src/celo/types.ts | 7 +++++-- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/celo/formatters.test.ts b/src/celo/formatters.test.ts index 683bd1eb87..8c781df949 100644 --- a/src/celo/formatters.test.ts +++ b/src/celo/formatters.test.ts @@ -1,6 +1,5 @@ import { describe, expect, test } from 'vitest' -import type { TransactionLegacy } from '~viem/index.js' import { getBlock } from '../actions/public/getBlock.js' import { getTransaction } from '../actions/public/getTransaction.js' import { celo } from '../chains/index.js' @@ -105,6 +104,7 @@ describe('block', () => { blockNumber: '0x1', chainId: '0x1', feeCurrency: null, + maxFeeInFeeCurrency: null, from: '0x045d685d23e8aa34dc408a66fb408f20dc84d785', gas: '0x69420', maxFeePerGas: '0x0', @@ -130,6 +130,7 @@ describe('block', () => { blockNumber: '0x1', chainId: '0x1', feeCurrency: null, + maxFeeInFeeCurrency: null, from: '0x045d685d23e8aa34dc408a66fb408f20dc84d785', gas: '0x69420', maxFeePerGas: '0x0', @@ -187,6 +188,7 @@ describe('block', () => { "gatewayFeeRecipient": null, "hash": "0x487efb864b308ee85afd7ed5954e968457cfe84e71726114b0a44f31fb876e85", "input": "0x389ec778", + "maxFeeInFeeCurrency": null, "maxFeePerGas": 0n, "maxPriorityFeePerGas": 0n, "nonce": 1, @@ -213,6 +215,7 @@ describe('block', () => { "gatewayFeeRecipient": null, "hash": "0x487efb864b308ee85afd7ed5954e968457cfe84e71726114b0a44f31fb876e85", "input": "0x389ec778", + "maxFeeInFeeCurrency": null, "maxFeePerGas": 0n, "maxPriorityFeePerGas": 0n, "nonce": 1, @@ -244,7 +247,7 @@ describe('block', () => { }) const { extraData: _extraData, transactions, ...rest } = block - expect(transactions[0] as TransactionLegacy).toMatchInlineSnapshot(` + expect(transactions[0]).toMatchInlineSnapshot(` { "blockHash": "0xac8c9bc3b84e103dc321bbe83b670e425ff68bfc9a333a4f1b1b204ad11c583d", "blockNumber": 16645775n, @@ -572,7 +575,7 @@ describe('transaction', () => { "gasPrice": undefined, "hash": "0xa4b1f606b66105fa45cb5db23d2f6597075701e7f0e2367f4e6a39d17a8cf98b", "input": "0x23b872dd000000000000000000000000a00f99bc38b1ecda1fd70eaa1cd31d576a9f46b0000000000000000000000000f16e9b0d03470827a95cdfd0cb8a8a3b46969b910000000000000000000000000000000000000000000000000000002b3b6fb3d0", - "maxFeeInFeeCurrency": "0x12345", + "maxFeeInFeeCurrency": 74565n, "maxFeePerBlobGas": undefined, "maxFeePerGas": 4n, "maxPriorityFeePerGas": 5n, @@ -601,7 +604,7 @@ describe('transaction', () => { index: 0, }) - expect(transaction as TransactionLegacy).toMatchInlineSnapshot(` + expect(transaction).toMatchInlineSnapshot(` { "blockHash": "0x740371d30b3cee9d687f72e3409ba6447eceda7de86bc38b0fa84493114b510b", "blockNumber": 16628100n, diff --git a/src/celo/formatters.ts b/src/celo/formatters.ts index 84a754635a..7d366ba5a5 100644 --- a/src/celo/formatters.ts +++ b/src/celo/formatters.ts @@ -54,6 +54,9 @@ export const formatters = { if (args.type === '0x7a') { transaction.type = 'cip66' + transaction.maxFeeInFeeCurrency = args.maxFeeInFeeCurrency + ? hexToBigInt(args.maxFeeInFeeCurrency) + : null } else if (args.type === '0x7b') { transaction.type = 'cip64' } else { diff --git a/src/celo/serializers.ts b/src/celo/serializers.ts index 9e6ac93036..05d959006a 100644 --- a/src/celo/serializers.ts +++ b/src/celo/serializers.ts @@ -186,11 +186,11 @@ export function assertTransactionCIP42( } } -type CIP_64_OR_CIP_66 = 'CIP-64' | 'CIP-66' +type Cip64OrCip66 = 'CIP-64' | 'CIP-66' export function assertTransactionCIP64( transaction: TransactionSerializableCIP64, - type: CIP_64_OR_CIP_66 = 'CIP-64', + type: Cip64OrCip66 = 'CIP-64', ) { const { chainId, diff --git a/src/celo/types.ts b/src/celo/types.ts index 39174d736e..705c86d47a 100644 --- a/src/celo/types.ts +++ b/src/celo/types.ts @@ -184,14 +184,16 @@ type Transaction = Transaction_< TPending > & { feeCurrency: Address | null - gatewayFee?: undefined - gatewayFeeRecipient?: undefined + maxFeeInFeeCurrency: bigint | null + gatewayFee: bigint | null + gatewayFeeRecipient: Address | null } export type TransactionCIP42 = TransactionBase & FeeValuesEIP1559 & { feeCurrency: Address | null + maxFeeInFeeCurrency?: undefined gatewayFee: bigint | null gatewayFeeRecipient: Address | null type: 'cip42' @@ -201,6 +203,7 @@ export type TransactionCIP64 = TransactionBase & FeeValuesEIP1559 & { feeCurrency: Address | null + maxFeeInFeeCurrency?: undefined gatewayFee?: undefined gatewayFeeRecipient?: undefined type: 'cip64' From d2e6707fef7429df9e54469a402d53a46d31594a Mon Sep 17 00:00:00 2001 From: Leszek Stachowski Date: Mon, 22 Apr 2024 15:54:14 +0200 Subject: [PATCH 06/19] add more test cases --- src/celo/sendTransaction.test.ts | 19 ++++++++ src/celo/serializers.test.ts | 83 ++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/src/celo/sendTransaction.test.ts b/src/celo/sendTransaction.test.ts index 0493efa1dd..dea81c1e89 100644 --- a/src/celo/sendTransaction.test.ts +++ b/src/celo/sendTransaction.test.ts @@ -86,6 +86,25 @@ describe('sendTransaction()', () => { }) }) + test('provides valid transaction params to sign for eth_sendRawTransaction (local account) for CIP-66', async () => { + const hash = await client.sendTransaction({ + value: 1n, + to: toAddress, + feeCurrency: feeCurrencyAddress, + maxFeeInFeeCurrency: 456n, + maxFeePerGas: 123n, + maxPriorityFeePerGas: 123n, + }) + + expect(hash).toEqual(transactionHash) + expect(transportRequestMock).toHaveBeenLastCalledWith({ + method: 'eth_sendRawTransaction', + params: [ + '0x7af87a82a4ec807b7b0194f39fd6e51aad88f6f4ce6ab8827279cfffb922660180c0940000000000000000000000000000000000000fee8201c801a01d21ed1dccd708f1e3aad4f26fa800e726eb3558d93360429b8b4241dcb10761a01231898e1d598ae8f58b53b7c032d7710a4b24c0921c63a749c2f03d52848a39', + ], + }) + }) + test('provides valid transaction params to sign for eth_sendRawTransaction (local account) for CIP-42 - sending as CIP-64', async () => { const hash = await client.sendTransaction({ value: 1n, diff --git a/src/celo/serializers.test.ts b/src/celo/serializers.test.ts index 9677f38f76..5d14807bfe 100644 --- a/src/celo/serializers.test.ts +++ b/src/celo/serializers.test.ts @@ -455,6 +455,19 @@ describe('invalid params specific to CIP-64', () => { }) }) +describe('invalid params specific to CIP-66', () => { + test('transaction looks like cip66 but does not have a value for feeCurrency', () => { + const transaction: TransactionSerializableCIP66 = { + ...baseCip66, + type: 'cip66', + feeCurrency: undefined, + } + expect(() => serializeTransaction(transaction)).toThrowError( + '`feeCurrency` must be provided for CIP-66 transactions.', + ) + }) +}) + describe('Common invalid params (for CIP-64)', () => { test('invalid to', () => { const transaction: TransactionSerializableCIP64 = { @@ -525,6 +538,76 @@ describe('Common invalid params (for CIP-64)', () => { }) }) +describe('Common invalid params (for CIP-66)', () => { + test('invalid to', () => { + const transaction: TransactionSerializableCIP66 = { + ...baseCip66, + to: '0xdeadbeef', + } + expect(() => serializeTransaction(transaction)).toThrowError( + InvalidAddressError, + ) + }) + + test('maxPriorityFeePerGas is higher than maxPriorityFee', () => { + const transaction: TransactionSerializableCIP66 = { + ...baseCip66, + maxPriorityFeePerGas: parseGwei('5000000000'), + maxFeePerGas: parseGwei('1'), + } + expect(() => serializeTransaction(transaction)).toThrowError( + TipAboveFeeCapError, + ) + }) + + test('maxFeePerGas is too high', () => { + const transaction: TransactionSerializableCIP66 = { + ...baseCip66, + maxPriorityFeePerGas: parseGwei('5000000000'), + maxFeePerGas: + 115792089237316195423570985008687907853269984665640564039457584007913129639938n, + } + expect(() => serializeTransaction(transaction)).toThrowError( + FeeCapTooHighError, + ) + }) + + test('feeCurrency is not an address', () => { + const transaction: TransactionSerializableCIP66 = { + ...baseCip66, + // @ts-expect-error + feeCurrency: 'CUSD', + } + + expect(() => serializeTransaction(transaction)).toThrowError( + '`feeCurrency` MUST be a token address for CIP-66 transactions.', + ) + }) + + test('gasPrice is defined', () => { + const transaction: TransactionSerializableCIP66 = { + ...baseCip66, + // @ts-expect-error + gasPrice: BigInt(1), + } + + expect(() => serializeTransaction(transaction)).toThrowError( + '`gasPrice` is not a valid CIP-66 Transaction attribute.', + ) + }) + + test('chainID is invalid', () => { + const transaction: TransactionSerializableCIP66 = { + ...baseCip66, + chainId: -1, + } + + expect(() => serializeTransaction(transaction)).toThrowError( + `Chain ID "${-1}" is invalid.`, + ) + }) +}) + describe('not cip42', () => { const transaction: TransactionSerializableEIP1559 = { to: accounts[0].address, From 7b1c718c308223fcc21f722b1c458ec59bbef476 Mon Sep 17 00:00:00 2001 From: Leszek Stachowski Date: Fri, 26 Apr 2024 12:30:06 +0200 Subject: [PATCH 07/19] Update .changeset/nasty-mayflies-search.md Co-authored-by: Arthur Gousset <46296830+arthurgousset@users.noreply.github.com> --- .changeset/nasty-mayflies-search.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/nasty-mayflies-search.md b/.changeset/nasty-mayflies-search.md index 1301185faa..f33cd7fa62 100644 --- a/.changeset/nasty-mayflies-search.md +++ b/.changeset/nasty-mayflies-search.md @@ -2,6 +2,6 @@ "viem": minor --- -Add CIP-66 support for Celo +Adds support for "[CIP-66: New Transaction Type: Celo Denominated Fees](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0066.md)" on Celo https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0066.md From 26fba997c17a4926de411969a603b461f158ed08 Mon Sep 17 00:00:00 2001 From: Leszek Stachowski Date: Fri, 26 Apr 2024 12:30:24 +0200 Subject: [PATCH 08/19] Update .changeset/nasty-mayflies-search.md Co-authored-by: Arthur Gousset <46296830+arthurgousset@users.noreply.github.com> --- .changeset/nasty-mayflies-search.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.changeset/nasty-mayflies-search.md b/.changeset/nasty-mayflies-search.md index f33cd7fa62..38e371e261 100644 --- a/.changeset/nasty-mayflies-search.md +++ b/.changeset/nasty-mayflies-search.md @@ -4,4 +4,3 @@ Adds support for "[CIP-66: New Transaction Type: Celo Denominated Fees](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0066.md)" on Celo -https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0066.md From 498074da93bd544c4567fe93991197a082d21da3 Mon Sep 17 00:00:00 2001 From: Leszek Stachowski Date: Fri, 26 Apr 2024 12:45:12 +0200 Subject: [PATCH 09/19] CR fix: numberToHex + unit test --- src/celo/formatters.test.ts | 51 +++++++++++++++++++++++++++++++++++++ src/celo/formatters.ts | 5 +++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/celo/formatters.test.ts b/src/celo/formatters.test.ts index 8c781df949..3cad488f41 100644 --- a/src/celo/formatters.test.ts +++ b/src/celo/formatters.test.ts @@ -765,6 +765,7 @@ describe('transactionRequest', () => { } `) }) + test('formatter cip64', () => { expect( transactionRequest.format({ @@ -810,4 +811,54 @@ describe('transactionRequest', () => { } `) }) + + test('formatter cip66', () => { + expect( + transactionRequest.format({ + feeCurrency: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', + maxFeeInFeeCurrency: 123n, + from: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', + gas: 1n, + maxFeePerGas: 2n, + maxPriorityFeePerGas: 1n, + nonce: 1, + value: 1n, + }), + ).toMatchInlineSnapshot(` + { + "feeCurrency": "0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9", + "from": "0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9", + "gas": "0x1", + "maxFeeInFeeCurrency": "0x7b", + "maxFeePerGas": "0x2", + "maxPriorityFeePerGas": "0x1", + "nonce": "0x1", + "type": "0x7a", + "value": "0x1", + } + `) + + expect( + transactionRequest.format({ + from: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', + to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', // Recipient (illustrative address) + value: 1n, + feeCurrency: '0x874069Fa1Eb16D44d622F2e0Ca25eeA172369bC1', // cUSD fee currency + maxFeeInFeeCurrency: 123n, + maxFeePerGas: 2n, // Special field for dynamic fee transaction type (EIP-1559) + maxPriorityFeePerGas: 2n, // Special field for dynamic fee transaction type (EIP-1559) + }), + ).toMatchInlineSnapshot(` + { + "feeCurrency": "0x874069Fa1Eb16D44d622F2e0Ca25eeA172369bC1", + "from": "0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9", + "maxFeeInFeeCurrency": "0x7b", + "maxFeePerGas": "0x2", + "maxPriorityFeePerGas": "0x2", + "to": "0x70997970c51812dc3a010c7d01b50e0d17dc79c8", + "type": "0x7a", + "value": "0x1", + } + `) + }) }) diff --git a/src/celo/formatters.ts b/src/celo/formatters.ts index 7d366ba5a5..37ae552174 100644 --- a/src/celo/formatters.ts +++ b/src/celo/formatters.ts @@ -80,7 +80,10 @@ export const formatters = { if (isCIP66(args)) { request.type = '0x7a' - request.maxFeeInFeeCurrency = args.maxFeeInFeeCurrency + request.maxFeeInFeeCurrency = + typeof args.maxFeeInFeeCurrency !== 'undefined' + ? numberToHex(args.maxFeeInFeeCurrency) + : undefined } else if (isCIP64(args)) { request.type = '0x7b' } From 400a593d5ada641edadf546de34d6a4f324e95bb Mon Sep 17 00:00:00 2001 From: Leszek Stachowski Date: Fri, 26 Apr 2024 13:00:09 +0200 Subject: [PATCH 10/19] introduce EMPTY_HEX_VALUE --- src/celo/formatters.test-d.ts | 25 ++++++------- src/celo/formatters.ts | 1 + src/celo/parsers.test.ts | 53 +++++++++++++-------------- src/celo/parsers.ts | 67 +++++++++++++++++++---------------- src/celo/serializers.ts | 36 +++++++++++-------- src/celo/utils.test.ts | 12 +++++-- src/celo/utils.ts | 4 ++- 7 files changed, 111 insertions(+), 87 deletions(-) diff --git a/src/celo/formatters.test-d.ts b/src/celo/formatters.test-d.ts index f64c40606c..081a1adb27 100644 --- a/src/celo/formatters.test-d.ts +++ b/src/celo/formatters.test-d.ts @@ -14,6 +14,7 @@ import type { RpcBlock } from '../types/rpc.js' import type { TransactionRequest } from '../types/transaction.js' import type { Assign, ExactPartial } from '../types/utils.js' import { formatters } from './formatters.js' +import { EMPTY_HEX_VALUE } from './utils.js' import type { CeloBlockOverrides, CeloRpcTransaction, @@ -151,15 +152,15 @@ describe('smoke', () => { test('transactionRequest (prepareTransactionRequest)', async () => { const client = createWalletClient({ - account: '0x', + account: EMPTY_HEX_VALUE, chain: celo, transport: http(), }) prepareTransactionRequest(client, { - feeCurrency: '0x', + feeCurrency: EMPTY_HEX_VALUE, gatewayFee: 0n, - gatewayFeeRecipient: '0x', + gatewayFeeRecipient: EMPTY_HEX_VALUE, }) // @ts-expect-error `gasPrice` is not defined @@ -172,43 +173,43 @@ describe('smoke', () => { test('transactionRequest (sendTransaction)', async () => { const client = createWalletClient({ - account: '0x', + account: EMPTY_HEX_VALUE, chain: celo, transport: http(), }) sendTransaction(client, { - feeCurrency: '0x', + feeCurrency: EMPTY_HEX_VALUE, gatewayFee: 0n, - gatewayFeeRecipient: '0x', + gatewayFeeRecipient: EMPTY_HEX_VALUE, }) }) test('transactionRequest (signTransaction)', async () => { const client = createWalletClient({ - account: '0x', + account: EMPTY_HEX_VALUE, chain: celo, transport: http(), }) signTransaction(client, { - feeCurrency: '0x', + feeCurrency: EMPTY_HEX_VALUE, gatewayFee: 0n, - gatewayFeeRecipient: '0x', + gatewayFeeRecipient: EMPTY_HEX_VALUE, }) }) test('transactionRequest (chain on action)', async () => { const client = createWalletClient({ - account: '0x', + account: EMPTY_HEX_VALUE, transport: http(), }) sendTransaction(client, { chain: celo, - feeCurrency: '0x', + feeCurrency: EMPTY_HEX_VALUE, gatewayFee: 0n, - gatewayFeeRecipient: '0x', + gatewayFeeRecipient: EMPTY_HEX_VALUE, }) }) }) diff --git a/src/celo/formatters.ts b/src/celo/formatters.ts index 37ae552174..ad7d9b0900 100644 --- a/src/celo/formatters.ts +++ b/src/celo/formatters.ts @@ -2,6 +2,7 @@ import type { ChainFormatters } from '../types/chain.js' import type { Hash } from '../types/misc.js' import type { RpcTransaction } from '../types/rpc.js' import { hexToBigInt } from '../utils/encoding/fromHex.js' +import { numberToHex } from '../utils/encoding/toHex.js' import { defineBlock } from '../utils/formatters/block.js' import { defineTransaction, diff --git a/src/celo/parsers.test.ts b/src/celo/parsers.test.ts index 6dc0dc6494..f416f67b70 100644 --- a/src/celo/parsers.test.ts +++ b/src/celo/parsers.test.ts @@ -14,6 +14,7 @@ import type { TransactionSerializableCIP64, TransactionSerializableCIP66, } from './types.js' +import { EMPTY_HEX_VALUE } from './utils.js' test('should be able to parse a cip42 transaction', () => { const signedTransaction = @@ -175,19 +176,19 @@ describe('should throw an error for invalid cip42 transactions', () => { expect(() => parseTransaction( `0x7c${toRlp([ - '0x', - '0x', - '0x', - '0x', - '0x', - '0x', - '0x', - '0x', - '0x', - '0x', - '0x', - '0x', - '0x', + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, ]).slice(2)}`, ), ).toThrowErrorMatchingInlineSnapshot(` @@ -276,7 +277,7 @@ describe('should parse a CIP64 transaction', () => { test('with data as 0x', () => { const transactionWithData: TransactionSerializableCIP64 = { ...transactionCip64, - data: '0x', + data: EMPTY_HEX_VALUE, } const serialized = serializeTransaction(transactionWithData) @@ -351,17 +352,17 @@ describe('should throw an error for invalid cip64 transactions', () => { expect(() => parseTransaction( `0x7b${toRlp([ - '0x', - '0x', - '0x', - '0x', - '0x', - '0x', - '0x', - '0x', - '0x', - '0x', - '0x', + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, + EMPTY_HEX_VALUE, ]).slice(2)}`, ), ).toThrowErrorMatchingInlineSnapshot(` @@ -454,7 +455,7 @@ describe('should parse a CIP66 transaction', () => { test('with data as 0x', () => { const transactionWithData: TransactionSerializableCIP66 = { ...transactionCip66, - data: '0x', + data: EMPTY_HEX_VALUE, } const serialized = serializeTransaction(transactionWithData) diff --git a/src/celo/parsers.ts b/src/celo/parsers.ts index 81d19270ca..1c1dd6a19c 100644 --- a/src/celo/parsers.ts +++ b/src/celo/parsers.ts @@ -27,6 +27,7 @@ import type { TransactionSerializedCIP64, TransactionSerializedCIP66, } from './types.js' +import { EMPTY_HEX_VALUE } from './utils.js' export type ParseTransactionReturnType< TSerialized extends CeloTransactionSerialized = CeloTransactionSerialized, @@ -116,22 +117,24 @@ function parseTransactionCIP42( 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') + if (isHex(to) && to !== EMPTY_HEX_VALUE) transaction.to = to + if (isHex(gas) && gas !== EMPTY_HEX_VALUE) transaction.gas = hexToBigInt(gas) + if (isHex(data) && data !== EMPTY_HEX_VALUE) transaction.data = data + if (isHex(nonce) && nonce !== EMPTY_HEX_VALUE) + transaction.nonce = hexToNumber(nonce) + if (isHex(value) && value !== EMPTY_HEX_VALUE) + transaction.value = hexToBigInt(value) + if (isHex(feeCurrency) && feeCurrency !== EMPTY_HEX_VALUE) transaction.feeCurrency = feeCurrency - if (isHex(gatewayFeeRecipient) && gatewayFeeRecipient !== '0x') + if (isHex(gatewayFeeRecipient) && gatewayFeeRecipient !== EMPTY_HEX_VALUE) transaction.gatewayFeeRecipient = gatewayFeeRecipient - if (isHex(gatewayFee) && gatewayFee !== '0x') + if (isHex(gatewayFee) && gatewayFee !== EMPTY_HEX_VALUE) transaction.gatewayFee = hexToBigInt(gatewayFee) - if (isHex(maxFeePerGas) && maxFeePerGas !== '0x') + if (isHex(maxFeePerGas) && maxFeePerGas !== EMPTY_HEX_VALUE) transaction.maxFeePerGas = hexToBigInt(maxFeePerGas) - if (isHex(maxPriorityFeePerGas) && maxPriorityFeePerGas !== '0x') + if (isHex(maxPriorityFeePerGas) && maxPriorityFeePerGas !== EMPTY_HEX_VALUE) transaction.maxPriorityFeePerGas = hexToBigInt(maxPriorityFeePerGas) - if (accessList.length !== 0 && accessList !== '0x') + if (accessList.length !== 0 && accessList !== EMPTY_HEX_VALUE) transaction.accessList = parseAccessList(accessList as RecursiveArray) assertTransactionCIP42(transaction as TransactionSerializableCIP42) @@ -191,18 +194,20 @@ function parseTransactionCIP64( type: 'cip64', } - 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') + if (isHex(to) && to !== EMPTY_HEX_VALUE) transaction.to = to + if (isHex(gas) && gas !== EMPTY_HEX_VALUE) transaction.gas = hexToBigInt(gas) + if (isHex(data) && data !== EMPTY_HEX_VALUE) transaction.data = data + if (isHex(nonce) && nonce !== EMPTY_HEX_VALUE) + transaction.nonce = hexToNumber(nonce) + if (isHex(value) && value !== EMPTY_HEX_VALUE) + transaction.value = hexToBigInt(value) + if (isHex(feeCurrency) && feeCurrency !== EMPTY_HEX_VALUE) transaction.feeCurrency = feeCurrency - if (isHex(maxFeePerGas) && maxFeePerGas !== '0x') + if (isHex(maxFeePerGas) && maxFeePerGas !== EMPTY_HEX_VALUE) transaction.maxFeePerGas = hexToBigInt(maxFeePerGas) - if (isHex(maxPriorityFeePerGas) && maxPriorityFeePerGas !== '0x') + if (isHex(maxPriorityFeePerGas) && maxPriorityFeePerGas !== EMPTY_HEX_VALUE) transaction.maxPriorityFeePerGas = hexToBigInt(maxPriorityFeePerGas) - if (accessList.length !== 0 && accessList !== '0x') + if (accessList.length !== 0 && accessList !== EMPTY_HEX_VALUE) transaction.accessList = parseAccessList(accessList as RecursiveArray) assertTransactionCIP64(transaction as TransactionSerializableCIP64) @@ -264,20 +269,22 @@ function parseTransactionCIP66( type: 'cip66', } - 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') + if (isHex(to) && to !== EMPTY_HEX_VALUE) transaction.to = to + if (isHex(gas) && gas !== EMPTY_HEX_VALUE) transaction.gas = hexToBigInt(gas) + if (isHex(data) && data !== EMPTY_HEX_VALUE) transaction.data = data + if (isHex(nonce) && nonce !== EMPTY_HEX_VALUE) + transaction.nonce = hexToNumber(nonce) + if (isHex(value) && value !== EMPTY_HEX_VALUE) + transaction.value = hexToBigInt(value) + if (isHex(feeCurrency) && feeCurrency !== EMPTY_HEX_VALUE) transaction.feeCurrency = feeCurrency - if (isHex(maxFeeInFeeCurrency) && maxFeeInFeeCurrency !== '0x') + if (isHex(maxFeeInFeeCurrency) && maxFeeInFeeCurrency !== EMPTY_HEX_VALUE) transaction.maxFeeInFeeCurrency = hexToBigInt(maxFeeInFeeCurrency) - if (isHex(maxFeePerGas) && maxFeePerGas !== '0x') + if (isHex(maxFeePerGas) && maxFeePerGas !== EMPTY_HEX_VALUE) transaction.maxFeePerGas = hexToBigInt(maxFeePerGas) - if (isHex(maxPriorityFeePerGas) && maxPriorityFeePerGas !== '0x') + if (isHex(maxPriorityFeePerGas) && maxPriorityFeePerGas !== EMPTY_HEX_VALUE) transaction.maxPriorityFeePerGas = hexToBigInt(maxPriorityFeePerGas) - if (accessList.length !== 0 && accessList !== '0x') + if (accessList.length !== 0 && accessList !== EMPTY_HEX_VALUE) transaction.accessList = parseAccessList(accessList as RecursiveArray) assertTransactionCIP66(transaction as TransactionSerializableCIP66) diff --git a/src/celo/serializers.ts b/src/celo/serializers.ts index 05d959006a..8fbfdecd92 100644 --- a/src/celo/serializers.ts +++ b/src/celo/serializers.ts @@ -21,7 +21,13 @@ import type { TransactionSerializedCIP64, TransactionSerializedCIP66, } from './types.js' -import { isCIP64, isCIP66, isEmpty, isPresent } from './utils.js' +import { + EMPTY_HEX_VALUE, + isCIP64, + isCIP66, + isEmpty, + isPresent, +} from './utils.js' export function serializeTransaction( transaction: CeloTransactionSerializable, @@ -68,13 +74,13 @@ function serializeTransactionCIP64( const serializedTransaction = [ toHex(chainId), - nonce ? toHex(nonce) : '0x', - maxPriorityFeePerGas ? toHex(maxPriorityFeePerGas) : '0x', - maxFeePerGas ? toHex(maxFeePerGas) : '0x', - gas ? toHex(gas) : '0x', - to ?? '0x', - value ? toHex(value) : '0x', - data ?? '0x', + nonce ? toHex(nonce) : EMPTY_HEX_VALUE, + maxPriorityFeePerGas ? toHex(maxPriorityFeePerGas) : EMPTY_HEX_VALUE, + maxFeePerGas ? toHex(maxFeePerGas) : EMPTY_HEX_VALUE, + gas ? toHex(gas) : EMPTY_HEX_VALUE, + to ?? EMPTY_HEX_VALUE, + value ? toHex(value) : EMPTY_HEX_VALUE, + data ?? EMPTY_HEX_VALUE, serializeAccessList(accessList), feeCurrency!, ...toYParitySignatureArray(transaction, signature), @@ -108,13 +114,13 @@ function serializeTransactionCIP66( const serializedTransaction = [ toHex(chainId), - nonce ? toHex(nonce) : '0x', - maxPriorityFeePerGas ? toHex(maxPriorityFeePerGas) : '0x', - maxFeePerGas ? toHex(maxFeePerGas) : '0x', - gas ? toHex(gas) : '0x', - to ?? '0x', - value ? toHex(value) : '0x', - data ?? '0x', + nonce ? toHex(nonce) : EMPTY_HEX_VALUE, + maxPriorityFeePerGas ? toHex(maxPriorityFeePerGas) : EMPTY_HEX_VALUE, + maxFeePerGas ? toHex(maxFeePerGas) : EMPTY_HEX_VALUE, + gas ? toHex(gas) : EMPTY_HEX_VALUE, + to ?? EMPTY_HEX_VALUE, + value ? toHex(value) : EMPTY_HEX_VALUE, + data ?? EMPTY_HEX_VALUE, serializeAccessList(accessList), feeCurrency!, toHex(maxFeeInFeeCurrency!), diff --git a/src/celo/utils.test.ts b/src/celo/utils.test.ts index 9f29b2254d..7ac385610b 100644 --- a/src/celo/utils.test.ts +++ b/src/celo/utils.test.ts @@ -1,13 +1,19 @@ import { randomBytes } from 'node:crypto' import type { Address } from 'abitype' import { beforeEach, describe, expect, test } from 'vitest' -import { isCIP64, isEIP1559, isEmpty, isPresent } from './utils.js' +import { + EMPTY_HEX_VALUE, + isCIP64, + isEIP1559, + isEmpty, + isPresent, +} from './utils.js' let mockAddress: Address const emptyValues: any[] = [ '0x000000', - '0x', + EMPTY_HEX_VALUE, 0n, 0, 0, @@ -176,7 +182,7 @@ describe('isCIP64', () => { expect( isCIP64({ - feeCurrency: '0x', + feeCurrency: EMPTY_HEX_VALUE, maxFeePerGas: 123n, maxPriorityFeePerGas: 456n, from: mockAddress, diff --git a/src/celo/utils.ts b/src/celo/utils.ts index 1e515beeb5..757c0a3446 100644 --- a/src/celo/utils.ts +++ b/src/celo/utils.ts @@ -18,7 +18,7 @@ export function isEmpty( value === '0' || value === '' || (typeof value === 'string' && - (trim(value as Address).toLowerCase() === '0x' || + (trim(value as Address).toLowerCase() === EMPTY_HEX_VALUE || trim(value as Address).toLowerCase() === '0x00')) ) } @@ -71,3 +71,5 @@ export function isCIP66( isPresent(transaction.maxFeeInFeeCurrency) ) } + +export const EMPTY_HEX_VALUE = '0x' From 34d162bdfddbd23684ba1207853949ef70db8825 Mon Sep 17 00:00:00 2001 From: Aaron DeRuvo Date: Wed, 29 May 2024 11:26:06 +0200 Subject: [PATCH 11/19] cleanup --- .changeset/rude-vans-decide.md | 7 ------- bun.lockb | Bin 564972 -> 564972 bytes src/celo/formatters.test-d.ts | 2 +- src/celo/serializers.test.ts | 2 -- 4 files changed, 1 insertion(+), 10 deletions(-) delete mode 100644 .changeset/rude-vans-decide.md diff --git a/.changeset/rude-vans-decide.md b/.changeset/rude-vans-decide.md deleted file mode 100644 index 1e6ec80750..0000000000 --- a/.changeset/rude-vans-decide.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"viem": minor ---- - -Removed CIP-42 support. - -Any transactions with feeCurrency field will be treated as CIP-64. diff --git a/bun.lockb b/bun.lockb index 45d2448f544145c0b842a06b2c9a3757a003d619..751dd62e2576eb9ad4974d13dd902ff0b0a67fe3 100755 GIT binary patch delta 9811 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 delta 9810 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 { expectTypeOf(formatters.block.format).parameter(0).toEqualTypeOf< diff --git a/src/celo/serializers.test.ts b/src/celo/serializers.test.ts index 5d14807bfe..e437025196 100644 --- a/src/celo/serializers.test.ts +++ b/src/celo/serializers.test.ts @@ -385,8 +385,6 @@ describe('cip66', () => { serializer: serializeTransaction, }) - console.log('SIGNED:', signed) - const serialized = '0x7af88e82a4ec01847735940084773594008094f39fd6e51aad88f6f4ce6ab8827279cfffb92266880de0b6b3a764000080c094765de816845861e75a25fca122bb6898b8b1282a860b3a4b56fa0001a0f376d59efea3eb24397b74303b6225aeb6d32ca57f2854c4454c49c779cd68dda0214b12ee3d68b7aec1dc43ee5e668bd76ba3a805350e8ae9ca54a381ac9871e8' expect(signed).toEqual(serialized) From 18bc2c47fa12ee31f0e57b99f61023e4e747faf3 Mon Sep 17 00:00:00 2001 From: aaronmgdr Date: Wed, 29 May 2024 09:27:37 +0000 Subject: [PATCH 12/19] chore: format --- bun.lockb | Bin 564972 -> 564972 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bun.lockb b/bun.lockb index 751dd62e2576eb9ad4974d13dd902ff0b0a67fe3..45d2448f544145c0b842a06b2c9a3757a003d619 100755 GIT binary patch delta 9810 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 From 67bbc510c43be8e72650f548648ba903c0141f7d Mon Sep 17 00:00:00 2001 From: Aaron DeRuvo Date: Wed, 5 Jun 2024 11:15:04 +0200 Subject: [PATCH 13/19] add test from blockchain, handle empty values better for cip66, adjust places where we are ignoring on purpose --- src/celo/formatters.test-d.ts | 2 +- src/celo/formatters.test.ts | 23 ++++++++++------------- src/celo/formatters.ts | 10 +++++++++- src/celo/parsers.test.ts | 20 ++++++++++++++++++++ src/celo/parsers.ts | 9 +++++---- src/celo/types.ts | 12 ++++++------ 6 files changed, 51 insertions(+), 25 deletions(-) diff --git a/src/celo/formatters.test-d.ts b/src/celo/formatters.test-d.ts index 5f99728e65..3eb2f358e7 100644 --- a/src/celo/formatters.test-d.ts +++ b/src/celo/formatters.test-d.ts @@ -146,7 +146,7 @@ describe('smoke', () => { `0x${string}` | null | undefined >() expectTypeOf(transaction.type).toEqualTypeOf< - 'legacy' | 'eip2930' | 'eip1559' | 'eip4844' | 'cip42' | 'cip64' + 'legacy' | 'eip2930' | 'eip1559' | 'eip4844' | 'cip42' | 'cip64' | 'cip66' >() }) diff --git a/src/celo/formatters.test.ts b/src/celo/formatters.test.ts index 3cad488f41..05d00be2a3 100644 --- a/src/celo/formatters.test.ts +++ b/src/celo/formatters.test.ts @@ -104,7 +104,6 @@ describe('block', () => { blockNumber: '0x1', chainId: '0x1', feeCurrency: null, - maxFeeInFeeCurrency: null, from: '0x045d685d23e8aa34dc408a66fb408f20dc84d785', gas: '0x69420', maxFeePerGas: '0x0', @@ -130,7 +129,7 @@ describe('block', () => { blockNumber: '0x1', chainId: '0x1', feeCurrency: null, - maxFeeInFeeCurrency: null, + maxFeeInFeeCurrency: undefined, from: '0x045d685d23e8aa34dc408a66fb408f20dc84d785', gas: '0x69420', maxFeePerGas: '0x0', @@ -188,7 +187,6 @@ describe('block', () => { "gatewayFeeRecipient": null, "hash": "0x487efb864b308ee85afd7ed5954e968457cfe84e71726114b0a44f31fb876e85", "input": "0x389ec778", - "maxFeeInFeeCurrency": null, "maxFeePerGas": 0n, "maxPriorityFeePerGas": 0n, "nonce": 1, @@ -215,7 +213,7 @@ describe('block', () => { "gatewayFeeRecipient": null, "hash": "0x487efb864b308ee85afd7ed5954e968457cfe84e71726114b0a44f31fb876e85", "input": "0x389ec778", - "maxFeeInFeeCurrency": null, + "maxFeeInFeeCurrency": undefined, "maxFeePerGas": 0n, "maxPriorityFeePerGas": 0n, "nonce": 1, @@ -311,7 +309,7 @@ describe('transaction', () => { blockNumber: '0x1', chainId: '0x1', feeCurrency: null, - maxFeeInFeeCurrency: null, + maxFeeInFeeCurrency: undefined, from: '0xa152f8bb749c55e9943a3a0a3111d18ee2b3f94e', gas: '0x2', gasPrice: undefined, @@ -346,7 +344,7 @@ describe('transaction', () => { "gatewayFeeRecipient": null, "hash": "0xa4b1f606b66105fa45cb5db23d2f6597075701e7f0e2367f4e6a39d17a8cf98b", "input": "0x23b872dd000000000000000000000000a00f99bc38b1ecda1fd70eaa1cd31d576a9f46b0000000000000000000000000f16e9b0d03470827a95cdfd0cb8a8a3b46969b910000000000000000000000000000000000000000000000000000002b3b6fb3d0", - "maxFeeInFeeCurrency": null, + "maxFeeInFeeCurrency": undefined, "maxFeePerGas": 4n, "maxPriorityFeePerGas": 5n, "nonce": 6, @@ -370,7 +368,6 @@ describe('transaction', () => { blockNumber: '0x1', chainId: '0x1', feeCurrency: null, - maxFeeInFeeCurrency: null, from: '0xa152f8bb749c55e9943a3a0a3111d18ee2b3f94e', gas: '0x2', gasPrice: undefined, @@ -405,7 +402,6 @@ describe('transaction', () => { "gatewayFeeRecipient": null, "hash": "0xa4b1f606b66105fa45cb5db23d2f6597075701e7f0e2367f4e6a39d17a8cf98b", "input": "0x23b872dd000000000000000000000000a00f99bc38b1ecda1fd70eaa1cd31d576a9f46b0000000000000000000000000f16e9b0d03470827a95cdfd0cb8a8a3b46969b910000000000000000000000000000000000000000000000000000002b3b6fb3d0", - "maxFeeInFeeCurrency": null, "maxFeePerGas": 4n, "maxPriorityFeePerGas": 5n, "nonce": 6, @@ -637,11 +633,11 @@ describe('transactionRequest', () => { test('formatter CIP-42 (removed, should produce CIP-64 when feeCurrency specified, EIP-1559 otherwise)', () => { expect( + // @ts-expect-error transactionRequest.format({ feeCurrency: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', from: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', gas: 1n, - // @ts-ignore gatewayFee: 4n, gatewayFeeRecipient: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', maxFeePerGas: 2n, @@ -663,11 +659,11 @@ describe('transactionRequest', () => { `) expect( + // @ts-expect-error transactionRequest.format({ feeCurrency: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', from: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', gas: 1n, - // @ts-ignore gatewayFeeRecipient: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', maxFeePerGas: 2n, maxPriorityFeePerGas: 1n, @@ -688,11 +684,12 @@ describe('transactionRequest', () => { `) expect( + // @ts-expect-error + transactionRequest.format({ feeCurrency: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', from: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', gas: 1n, - // @ts-ignore gatewayFee: 4n, gatewayFeeRecipient: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', maxFeePerGas: 2n, @@ -714,11 +711,11 @@ describe('transactionRequest', () => { `) expect( + // @ts-expect-error transactionRequest.format({ feeCurrency: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', from: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', gas: 1n, - // @ts-ignore gatewayFee: 4n, gatewayFeeRecipient: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', maxFeePerGas: 2n, @@ -740,11 +737,11 @@ describe('transactionRequest', () => { `) expect( + // @ts-expect-error transactionRequest.format({ feeCurrency: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', from: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', gas: 1n, - // @ts-ignore gatewayFee: 4n, gatewayFeeRecipient: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', maxFeePerGas: 2n, diff --git a/src/celo/formatters.ts b/src/celo/formatters.ts index ad7d9b0900..43915699d1 100644 --- a/src/celo/formatters.ts +++ b/src/celo/formatters.ts @@ -32,6 +32,14 @@ export const formatters = { if (typeof transaction === 'string') return transaction return { ...formatTransaction(transaction as RpcTransaction), + ...(transaction.maxFeeInFeeCurrency + ? { + maxFeeInFeeCurrency: + typeof transaction.maxFeeInFeeCurrency === 'string' + ? hexToBigInt(transaction.maxFeeInFeeCurrency) + : transaction.maxFeeInFeeCurrency, + } + : {}), feeCurrency: transaction.feeCurrency, ...(transaction.type !== '0x7b' ? { @@ -57,7 +65,7 @@ export const formatters = { transaction.type = 'cip66' transaction.maxFeeInFeeCurrency = args.maxFeeInFeeCurrency ? hexToBigInt(args.maxFeeInFeeCurrency) - : null + : undefined } else if (args.type === '0x7b') { transaction.type = 'cip64' } else { diff --git a/src/celo/parsers.test.ts b/src/celo/parsers.test.ts index f416f67b70..da6daea263 100644 --- a/src/celo/parsers.test.ts +++ b/src/celo/parsers.test.ts @@ -499,4 +499,24 @@ describe('should parse a CIP66 transaction', () => { } `) }) + + test('using example from blockchain repo', () => { + // created by celo blockchain client + const transaction = + '0x7af8ce82a4ec01843b9aca00850342770c0083030d409443d72ff17701b2da814620735c39c620ce0ea4a180b844a9059cbb000000000000000000000000bd8be21f6883569ad7d15cc55c87137fcef308c300000000000000000000000000000000000000000000000001605eba271024d6c094765de816845861e75a25fca122bb6898b8b1282a8501a13b860080a02a015905a494549d8a1da26ce769309963e43f407936bbce1ea8276072b08416a072fd12d24c44bc79648bd88f4d8c158f2f0778694557868b3dc7d80e3aa6b539' + expect(parseTransaction(transaction)).toMatchInlineSnapshot(` + { + "chainId": 42220, + "data": "0xa9059cbb000000000000000000000000bd8be21f6883569ad7d15cc55c87137fcef308c300000000000000000000000000000000000000000000000001605eba271024d6", + "feeCurrency": "0x765de816845861e75a25fca122bb6898b8b1282a", + "gas": 200000n, + "maxFeeInFeeCurrency": 7000000000n, + "maxFeePerGas": 14000000000n, + "maxPriorityFeePerGas": 1000000000n, + "nonce": 1, + "to": "0x43d72ff17701b2da814620735c39c620ce0ea4a1", + "type": "cip66", + } + `) + }) }) diff --git a/src/celo/parsers.ts b/src/celo/parsers.ts index 1c1dd6a19c..128a4103ae 100644 --- a/src/celo/parsers.ts +++ b/src/celo/parsers.ts @@ -276,10 +276,6 @@ function parseTransactionCIP66( transaction.nonce = hexToNumber(nonce) if (isHex(value) && value !== EMPTY_HEX_VALUE) transaction.value = hexToBigInt(value) - if (isHex(feeCurrency) && feeCurrency !== EMPTY_HEX_VALUE) - transaction.feeCurrency = feeCurrency - if (isHex(maxFeeInFeeCurrency) && maxFeeInFeeCurrency !== EMPTY_HEX_VALUE) - transaction.maxFeeInFeeCurrency = hexToBigInt(maxFeeInFeeCurrency) if (isHex(maxFeePerGas) && maxFeePerGas !== EMPTY_HEX_VALUE) transaction.maxFeePerGas = hexToBigInt(maxFeePerGas) if (isHex(maxPriorityFeePerGas) && maxPriorityFeePerGas !== EMPTY_HEX_VALUE) @@ -287,6 +283,11 @@ function parseTransactionCIP66( if (accessList.length !== 0 && accessList !== EMPTY_HEX_VALUE) transaction.accessList = parseAccessList(accessList as RecursiveArray) + if (isHex(feeCurrency) && feeCurrency !== EMPTY_HEX_VALUE) + transaction.feeCurrency = feeCurrency + if (isHex(maxFeeInFeeCurrency) && maxFeeInFeeCurrency !== EMPTY_HEX_VALUE) + transaction.maxFeeInFeeCurrency = hexToBigInt(maxFeeInFeeCurrency) + assertTransactionCIP66(transaction as TransactionSerializableCIP66) return transaction as TransactionSerializableCIP66 diff --git a/src/celo/types.ts b/src/celo/types.ts index 705c86d47a..5effba5025 100644 --- a/src/celo/types.ts +++ b/src/celo/types.ts @@ -110,7 +110,7 @@ export type CeloTransactionType = TransactionType | 'cip42' | 'cip64' | 'cip66' type RpcTransaction = RpcTransaction_ & { feeCurrency: Address | null - maxFeeInFeeCurrency: bigint | null + maxFeeInFeeCurrency?: bigint | undefined gatewayFee: Hex | null gatewayFeeRecipient: Address | null } @@ -149,8 +149,8 @@ export type RpcTransactionCIP66 = Omit< 'typeHex' > & FeeValuesEIP1559 & { - feeCurrency: Address | null - maxFeeInFeeCurrency: Quantity | null + feeCurrency: Address + maxFeeInFeeCurrency: Quantity gatewayFee?: undefined gatewayFeeRecipient?: undefined type: '0x7a' @@ -184,7 +184,7 @@ type Transaction = Transaction_< TPending > & { feeCurrency: Address | null - maxFeeInFeeCurrency: bigint | null + maxFeeInFeeCurrency: bigint | undefined gatewayFee: bigint | null gatewayFeeRecipient: Address | null } @@ -212,8 +212,8 @@ export type TransactionCIP64 = export type TransactionCIP66 = TransactionBase & FeeValuesEIP1559 & { - feeCurrency: Address | null - maxFeeInFeeCurrency: bigint | null + feeCurrency: Address + maxFeeInFeeCurrency: bigint gatewayFee?: undefined gatewayFeeRecipient?: undefined type: 'cip66' From 0bdfda4cc601b826ae872c3b3156232d2690079c Mon Sep 17 00:00:00 2001 From: Aaron DeRuvo Date: Wed, 12 Jun 2024 12:52:32 +0300 Subject: [PATCH 14/19] formatting --- src/celo/types.ts | 72 ++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/src/celo/types.ts b/src/celo/types.ts index 2dd920e694..24c0691873 100644 --- a/src/celo/types.ts +++ b/src/celo/types.ts @@ -87,7 +87,6 @@ export type CeloTransaction = | TransactionCIP64 | TransactionCIP66 - export type CeloTransactionRequest = | TransactionRequest | TransactionRequestCIP64 @@ -159,24 +158,22 @@ export type RpcTransactionCIP66 = Omit< export type RpcTransactionRequestCIP64 = TransactionRequestBase< Quantity, Index -> & - { - accessList?: AccessList | undefined - feeCurrency?: Address | undefined - maxFeeInFeeCurrency?: undefined - type?: '0x7b' | undefined - } & ExactPartial> +> & { + accessList?: AccessList | undefined + feeCurrency?: Address | undefined + maxFeeInFeeCurrency?: undefined + type?: '0x7b' | undefined +} & ExactPartial> export type RpcTransactionRequestCIP66 = TransactionRequestBase< Quantity, Index -> & - { - accessList?: AccessList | undefined - feeCurrency?: Address | undefined - maxFeeInFeeCurrency?: Quantity | undefined - type?: '0x7a' | undefined - } & ExactPartial> +> & { + accessList?: AccessList | undefined + feeCurrency?: Address | undefined + maxFeeInFeeCurrency?: Quantity | undefined + type?: '0x7a' | undefined +} & ExactPartial> type Transaction = core_Transaction< bigint, @@ -190,34 +187,31 @@ type Transaction = core_Transaction< } export type TransactionCIP42 = - TransactionBase & - { - feeCurrency: Address | null - maxFeeInFeeCurrency?: undefined - gatewayFee: bigint | null - gatewayFeeRecipient: Address | null - type: 'cip42' - } & FeeValuesEIP1559 + TransactionBase & { + feeCurrency: Address | null + maxFeeInFeeCurrency?: undefined + gatewayFee: bigint | null + gatewayFeeRecipient: Address | null + type: 'cip42' + } & FeeValuesEIP1559 export type TransactionCIP64 = - TransactionBase & - { - feeCurrency: Address | null - maxFeeInFeeCurrency?: undefined - gatewayFee?: undefined - gatewayFeeRecipient?: undefined - type: 'cip64' - } & FeeValuesEIP1559 + TransactionBase & { + feeCurrency: Address | null + maxFeeInFeeCurrency?: undefined + gatewayFee?: undefined + gatewayFeeRecipient?: undefined + type: 'cip64' + } & FeeValuesEIP1559 export type TransactionCIP66 = - TransactionBase & - { - feeCurrency: Address - maxFeeInFeeCurrency: bigint - gatewayFee?: undefined - gatewayFeeRecipient?: undefined - type: 'cip66' - } & FeeValuesEIP1559 + TransactionBase & { + feeCurrency: Address + maxFeeInFeeCurrency: bigint + gatewayFee?: undefined + gatewayFeeRecipient?: undefined + type: 'cip66' + } & FeeValuesEIP1559 type TransactionRequest = core_TransactionRequest & { feeCurrency?: Address | undefined From 8be3350484d331960b8b84dcc98bc3404c8c8ef2 Mon Sep 17 00:00:00 2001 From: Aaron DeRuvo Date: Wed, 12 Jun 2024 14:32:12 +0300 Subject: [PATCH 15/19] add missing public export --- src/celo/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/celo/index.ts b/src/celo/index.ts index 957be7eb4b..5a1b6b0ab8 100644 --- a/src/celo/index.ts +++ b/src/celo/index.ts @@ -5,6 +5,7 @@ export { type ParseTransactionReturnType, parseTransaction } from './parsers.js' export { type SerializeTransactionCIP64ReturnType, + type SerializeTransactionCIP66ReturnType, serializeTransaction, } from './serializers.js' From ae58159a594b4ea6e46e66f25e6dd782ab312f9b Mon Sep 17 00:00:00 2001 From: Aaron DeRuvo Date: Wed, 12 Jun 2024 14:46:59 +0300 Subject: [PATCH 16/19] update types --- src/celo/formatters.test-d.ts | 3 +-- src/types/chain.test-d.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/celo/formatters.test-d.ts b/src/celo/formatters.test-d.ts index 529e117ed9..1f3681bb87 100644 --- a/src/celo/formatters.test-d.ts +++ b/src/celo/formatters.test-d.ts @@ -159,8 +159,7 @@ describe('smoke', () => { prepareTransactionRequest(client, { feeCurrency: EMPTY_HEX_VALUE, - gatewayFee: 0n, - gatewayFeeRecipient: EMPTY_HEX_VALUE, + maxFeeInFeeCurrency: 2000000000n, }) // @ts-expect-error `gasPrice` is not defined diff --git a/src/types/chain.test-d.ts b/src/types/chain.test-d.ts index 5345e9f761..06e9f98bd1 100644 --- a/src/types/chain.test-d.ts +++ b/src/types/chain.test-d.ts @@ -54,7 +54,7 @@ test('ExtractChainFormatterParameters', () => { TransactionRequest > expectTypeOf().toEqualTypeOf< - 'legacy' | 'eip2930' | 'eip1559' | 'eip4844' | 'cip64' | undefined + 'legacy' | 'eip2930' | 'eip1559' | 'eip4844' | 'cip64' | 'cip66' | undefined >() expectTypeOf().toEqualTypeOf< `0x${string}` | undefined From 959e28bb9ed413b7393b72bb522ad6f95f333f21 Mon Sep 17 00:00:00 2001 From: Aaron DeRuvo Date: Wed, 12 Jun 2024 15:01:38 +0300 Subject: [PATCH 17/19] add notes about cip66 in changeset --- .changeset/nasty-mayflies-search.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/nasty-mayflies-search.md b/.changeset/nasty-mayflies-search.md index 38e371e261..0f491ff70b 100644 --- a/.changeset/nasty-mayflies-search.md +++ b/.changeset/nasty-mayflies-search.md @@ -2,5 +2,5 @@ "viem": minor --- -Adds support for "[CIP-66: New Transaction Type: Celo Denominated Fees](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0066.md)" on Celo +Adds support for "[CIP-66: New Transaction Type: Celo Denominated Fees](https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0066.md)" on Celo. Note that this transaction type is only supported on Cel2 and can be created by adding the additional maxFeeInFeeCurrency field to your transaction params. From 8d7310000041622e70b5b8ae650e8e5ed93ad241 Mon Sep 17 00:00:00 2001 From: shazarre Date: Thu, 4 Jul 2024 14:42:48 +0000 Subject: [PATCH 18/19] chore: format --- src/celo/types.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/celo/types.ts b/src/celo/types.ts index 6bcb4d7a9a..5d8341a7e6 100644 --- a/src/celo/types.ts +++ b/src/celo/types.ts @@ -7,19 +7,19 @@ import type { Index, Quantity, RpcBlock, + TransactionType, RpcTransaction as core_RpcTransaction, RpcTransactionRequest as core_RpcTransactionRequest, - TransactionType, } from '../types/rpc.js' import type { AccessList, - Transaction as core_Transaction, TransactionBase, - TransactionRequest as core_TransactionRequest, TransactionRequestBase, TransactionSerializable, TransactionSerializableBase, TransactionSerialized, + Transaction as core_Transaction, + TransactionRequest as core_TransactionRequest, } from '../types/transaction.js' import type { Assign, ExactPartial, OneOf } from '../types/utils.js' From 6c4331dacda394b0d4f66c6ca8697afd0fb9c3b3 Mon Sep 17 00:00:00 2001 From: Leszek Stachowski Date: Thu, 4 Jul 2024 16:51:14 +0200 Subject: [PATCH 19/19] format and update snapshots --- src/celo/formatters.test.ts | 22 ++++++++++++++-------- src/celo/types.ts | 6 +++--- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/celo/formatters.test.ts b/src/celo/formatters.test.ts index 51accb59f0..7ae0042d67 100644 --- a/src/celo/formatters.test.ts +++ b/src/celo/formatters.test.ts @@ -591,6 +591,7 @@ describe('transaction', () => { yParity: '0x1', }), ).toMatchInlineSnapshot(` + { "accessList": [], "blockHash": "0x89644bbd5c8d682a2e9611170e6c1f02573d866d286f006cbf517eec7254ec2d", "blockNumber": 1n, @@ -613,9 +614,10 @@ describe('transaction', () => { "type": "cip66", "typeHex": "0x7a", "v": 1n, - "value": 0n, - yParity: '1', - `) + "value": 0n, + "yParity": 1, + } + `) expect( transaction.format({ @@ -715,12 +717,13 @@ describe('transactionRequest', () => { test('formatter CIP-42 (removed, should produce CIP-64 when feeCurrency specified, EIP-1559 otherwise)', () => { expect( - // @ts-expect-error transactionRequest.format({ feeCurrency: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', from: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', gas: 1n, + // @ts-ignore gatewayFee: 4n, + // @ts-ignore gatewayFeeRecipient: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', maxFeePerGas: 2n, maxPriorityFeePerGas: 1n, @@ -741,11 +744,11 @@ describe('transactionRequest', () => { `) expect( - // @ts-expect-error transactionRequest.format({ feeCurrency: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', from: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', gas: 1n, + // @ts-ignore gatewayFeeRecipient: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', maxFeePerGas: 2n, maxPriorityFeePerGas: 1n, @@ -766,12 +769,13 @@ describe('transactionRequest', () => { `) expect( - // @ts-expect-error transactionRequest.format({ feeCurrency: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', from: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', gas: 1n, + // @ts-ignore gatewayFee: 4n, + // @ts-ignore gatewayFeeRecipient: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', maxFeePerGas: 2n, maxPriorityFeePerGas: 1n, @@ -792,12 +796,13 @@ describe('transactionRequest', () => { `) expect( - // @ts-expect-error transactionRequest.format({ feeCurrency: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', from: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', gas: 1n, + // @ts-ignore gatewayFee: 4n, + // @ts-ignore gatewayFeeRecipient: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', maxFeePerGas: 2n, maxPriorityFeePerGas: 1n, @@ -818,12 +823,13 @@ describe('transactionRequest', () => { `) expect( - // @ts-expect-error transactionRequest.format({ feeCurrency: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', from: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', gas: 1n, + // @ts-ignore gatewayFee: 4n, + // @ts-ignore gatewayFeeRecipient: '0x0f16e9b0d03470827a95cdfd0cb8a8a3b46969b9', maxFeePerGas: 2n, maxPriorityFeePerGas: 4n, diff --git a/src/celo/types.ts b/src/celo/types.ts index 6bcb4d7a9a..5d8341a7e6 100644 --- a/src/celo/types.ts +++ b/src/celo/types.ts @@ -7,19 +7,19 @@ import type { Index, Quantity, RpcBlock, + TransactionType, RpcTransaction as core_RpcTransaction, RpcTransactionRequest as core_RpcTransactionRequest, - TransactionType, } from '../types/rpc.js' import type { AccessList, - Transaction as core_Transaction, TransactionBase, - TransactionRequest as core_TransactionRequest, TransactionRequestBase, TransactionSerializable, TransactionSerializableBase, TransactionSerialized, + Transaction as core_Transaction, + TransactionRequest as core_TransactionRequest, } from '../types/transaction.js' import type { Assign, ExactPartial, OneOf } from '../types/utils.js'