From 3db26e09ea91bd03eb6f1e9e3ffe4f41c9b567e7 Mon Sep 17 00:00:00 2001 From: ChrisD <18092467+ChristopherDedominici@users.noreply.github.com> Date: Thu, 5 Dec 2024 17:01:29 +0100 Subject: [PATCH 1/4] add logic to handle txs to the null address --- pnpm-lock.yaml | 49 ++++++++++++---- v-next/hardhat-errors/src/descriptors.ts | 9 ++- v-next/hardhat/package.json | 2 +- .../handlers/accounts/local-accounts.ts | 23 +++++--- .../handlers/accounts/local-accounts.ts | 56 +++++++++++++++++++ 5 files changed, 117 insertions(+), 22 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 90927f344a..521e1c18d8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1513,8 +1513,8 @@ importers: specifier: ^2.2.1 version: 2.2.1 micro-eth-signer: - specifier: ^0.12.0 - version: 0.12.0 + specifier: ^0.13.0 + version: 0.13.0 p-map: specifier: ^7.0.2 version: 7.0.2 @@ -3070,6 +3070,10 @@ packages: resolution: {integrity: sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ==} engines: {node: ^14.21.3 || >=16} + '@noble/curves@1.7.0': + resolution: {integrity: sha512-UTMhXK9SeDhFJVrHeUJ5uZlI6ajXg10O6Ddocf9S6GjbSBVZsJo88HzKwXznNfGpMTRDyJkqMjNDPYgf0qFWnw==} + engines: {node: ^14.21.3 || >=16} + '@noble/hashes@1.2.0': resolution: {integrity: sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==} @@ -3085,6 +3089,14 @@ packages: resolution: {integrity: sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==} engines: {node: ^14.21.3 || >=16} + '@noble/hashes@1.6.0': + resolution: {integrity: sha512-YUULf0Uk4/mAA89w+k3+yUYh6NrEvxZa5T6SY3wlMvE2chHkxFUUIDI8/XW1QSC357iA5pSnqt7XEhvFOqmDyQ==} + engines: {node: ^14.21.3 || >=16} + + '@noble/hashes@1.6.1': + resolution: {integrity: sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w==} + engines: {node: ^14.21.3 || >=16} + '@noble/secp256k1@1.7.1': resolution: {integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==} @@ -3242,6 +3254,9 @@ packages: '@scure/base@1.1.9': resolution: {integrity: sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==} + '@scure/base@1.2.1': + resolution: {integrity: sha512-DGmGtC8Tt63J5GfHgfl5CuAXh96VF/LD8K9Hr/Gv0J2lAoRGlPOMpqMpMbCTOoOJMZCk2Xt+DskdDyn6dEFdzQ==} + '@scure/bip32@1.1.5': resolution: {integrity: sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==} @@ -5488,14 +5503,14 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - micro-eth-signer@0.12.0: - resolution: {integrity: sha512-zHKuqXthGRvPjs0lQRSBnDN8E1Ndi09vqAdr7pJctE6wFkkkoHwjqp8RpD/dED2CDN8MoL3g5L/UopXZBNEbBw==} + micro-eth-signer@0.13.0: + resolution: {integrity: sha512-cPLq4nx9bd8Je1uFX97DvGEGMWYVymdB6rfvoi85q81FCMIEdJfC8OcGdMj6m0f/oktmti6FNGl8G1ANX+HnCw==} micro-ftch@0.3.1: resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} - micro-packed@0.6.3: - resolution: {integrity: sha512-VmVkyc7lIzAq/XCPFuLc/CwQ7Ehs5XDK3IwqsZHiBIDttAI9Gs7go6Lv4lNRuAIKrGKcRTtthFKUNyHS0S4wJQ==} + micro-packed@0.7.0: + resolution: {integrity: sha512-GJB99Ox8AI3C2Xr9DFalmHjYaJTUwh6w18jqnOKJEU9fpR9uZaRGCE8xjSS4b9yH2KDmW2BdPR8BylzfYVBIdg==} micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} @@ -7788,6 +7803,10 @@ snapshots: dependencies: '@noble/hashes': 1.5.0 + '@noble/curves@1.7.0': + dependencies: + '@noble/hashes': 1.6.0 + '@noble/hashes@1.2.0': {} '@noble/hashes@1.3.2': {} @@ -7796,6 +7815,10 @@ snapshots: '@noble/hashes@1.5.0': {} + '@noble/hashes@1.6.0': {} + + '@noble/hashes@1.6.1': {} + '@noble/secp256k1@1.7.1': {} '@nodelib/fs.scandir@2.1.5': @@ -7966,6 +7989,8 @@ snapshots: '@scure/base@1.1.9': {} + '@scure/base@1.2.1': {} + '@scure/bip32@1.1.5': dependencies: '@noble/hashes': 1.2.0 @@ -10609,17 +10634,17 @@ snapshots: merge2@1.4.1: {} - micro-eth-signer@0.12.0: + micro-eth-signer@0.13.0: dependencies: - '@noble/curves': 1.6.0 - '@noble/hashes': 1.5.0 - micro-packed: 0.6.3 + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 + micro-packed: 0.7.0 micro-ftch@0.3.1: {} - micro-packed@0.6.3: + micro-packed@0.7.0: dependencies: - '@scure/base': 1.1.9 + '@scure/base': 1.2.1 micromatch@4.0.8: dependencies: diff --git a/v-next/hardhat-errors/src/descriptors.ts b/v-next/hardhat-errors/src/descriptors.ts index 8901fa0e1d..36b41a4ca2 100644 --- a/v-next/hardhat-errors/src/descriptors.ts +++ b/v-next/hardhat-errors/src/descriptors.ts @@ -135,7 +135,7 @@ Please double check whether you have multiple versions of the same plugin instal ENV_VAR_NOT_FOUND: { number: 7, messageTemplate: `Configuration Variable '{name}' not found. - + You can define it using a plugin like hardhat-keystore, or set it as an environment variable.`, websiteTitle: "Configuration variable not found", websiteDescription: `A configuration variable was expected to be set as an environment variable, but it wasn't.`, @@ -678,6 +678,13 @@ Try using another mnemonic or deriving less keys.`, websiteTitle: "Invalid network type", websiteDescription: `The network manager only supports the network types 'http' and 'edr'.`, }, + DATA_FIELD_CANNOT_BE_NULL_WITH_NULL_ADDRESS: { + number: 721, + messageTemplate: `The "to" field is undefined, and the "data" field is also undefined; however, a transaction to the null address cannot have an undefined "data" field.`, + websiteTitle: "Transaction to null address cannot have undefined data", + websiteDescription: + "The transaction to the null address cannot have undefined data", + }, }, KEYSTORE: { INVALID_KEYSTORE_FILE_FORMAT: { diff --git a/v-next/hardhat/package.json b/v-next/hardhat/package.json index aa7df3401b..a6c8d29923 100644 --- a/v-next/hardhat/package.json +++ b/v-next/hardhat/package.json @@ -94,7 +94,7 @@ "debug": "^4.1.1", "enquirer": "^2.3.0", "ethereum-cryptography": "^2.2.1", - "micro-eth-signer": "^0.12.0", + "micro-eth-signer": "^0.13.0", "p-map": "^7.0.2", "semver": "^7.6.3", "solc": "^0.8.27", diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts index 3c210d708e..c42a8aecf0 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts @@ -276,15 +276,22 @@ export class LocalAccountsHandler extends ChainId implements RequestHandler { }; }); - // TODO: Fix after the alpha release - assertHardhatInvariant( - txData.to !== undefined, - "The alpha version doesn't support deploying contracts with local accounts yet", - ); + if (txData.to === undefined && txData.data === undefined) { + throw new HardhatError( + HardhatError.ERRORS.NETWORK.DATA_FIELD_CANNOT_BE_NULL_WITH_NULL_ADDRESS, + ); + } - const checksummedAddress = addr.addChecksum( - bytesToHexString(txData.to).toLowerCase(), - ); + let checksummedAddress; + if (txData.to === undefined) { + // This scenario arises during contract deployment. The npm package "micro-eth-signer" does not support + // null or undefined addresses. Therefore, these values must be converted to "0x", the expected format. + checksummedAddress = "0x"; + } else { + checksummedAddress = addr.addChecksum( + bytesToHexString(txData.to).toLowerCase(), + ); + } assertHardhatInvariant( txData.nonce !== undefined, diff --git a/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts b/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts index 8d1b10fb0b..90c4c81d83 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts @@ -451,6 +451,62 @@ describe("LocalAccountsHandler", () => { }); describe("modifyRequest", () => { + describe("sending transactions to the null address", () => { + it("should succeed when the data field is not empty", async () => { + const tx = { + // null address: the "to" field is not required + from: "0xb5bc06d4548a3ac17d72b372ae1e416bf65b8ead", + gas: numberToHexString(30000), + nonce: numberToHexString(0), + value: numberToHexString(1), + chainId: numberToHexString(MOCK_PROVIDER_CHAIN_ID), + maxFeePerGas: numberToHexString(12), + maxPriorityFeePerGas: numberToHexString(2), + data: "0x01", + }; + + const jsonRpcRequest = getJsonRpcRequest(1, "eth_sendTransaction", [ + tx, + ]); + + await localAccountsHandler.handle(jsonRpcRequest); + + assert.ok( + Array.isArray(jsonRpcRequest.params), + "params should be an array", + ); + + const rawTransaction = hexStringToBytes(jsonRpcRequest.params[0]); + // The tx type is encoded in the first byte, and it must be the EIP-1559 one + assert.equal(rawTransaction[0], 2); + }); + + it("should throw when the data field is undefined", async () => { + const tx = { + // null address: the "to" field is not required. + // Also, in this test scenario, the "data" field is omitted + from: "0xb5bc06d4548a3ac17d72b372ae1e416bf65b8ead", + gas: numberToHexString(30000), + nonce: numberToHexString(0), + value: numberToHexString(1), + chainId: numberToHexString(MOCK_PROVIDER_CHAIN_ID), + maxFeePerGas: numberToHexString(12), + maxPriorityFeePerGas: numberToHexString(2), + }; + + const jsonRpcRequest = getJsonRpcRequest(1, "eth_sendTransaction", [ + tx, + ]); + + assertRejectsWithHardhatError( + () => localAccountsHandler.handle(jsonRpcRequest), + HardhatError.ERRORS.NETWORK + .DATA_FIELD_CANNOT_BE_NULL_WITH_NULL_ADDRESS, + {}, + ); + }); + }); + it("should, given two identical tx, return the same raw transaction", async () => { const jsonRpcRequest = getJsonRpcRequest(1, "eth_sendTransaction", [ { From 5d54b2ee31e3eb8ffb09e37c4c457566074f0b16 Mon Sep 17 00:00:00 2001 From: ChrisD <18092467+ChristopherDedominici@users.noreply.github.com> Date: Thu, 5 Dec 2024 19:18:31 +0100 Subject: [PATCH 2/4] fix comment --- .../request-handlers/handlers/accounts/local-accounts.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts index c42a8aecf0..4451f4d8d9 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts @@ -285,7 +285,7 @@ export class LocalAccountsHandler extends ChainId implements RequestHandler { let checksummedAddress; if (txData.to === undefined) { // This scenario arises during contract deployment. The npm package "micro-eth-signer" does not support - // null or undefined addresses. Therefore, these values must be converted to "0x", the expected format. + // undefined addresses. Therefore, these values must be converted to "0x", the expected format. checksummedAddress = "0x"; } else { checksummedAddress = addr.addChecksum( From d08c6e08e410bcbec71e5c4cd7a3bce8869d3142 Mon Sep 17 00:00:00 2001 From: ChrisD <18092467+ChristopherDedominici@users.noreply.github.com> Date: Thu, 5 Dec 2024 21:00:20 +0100 Subject: [PATCH 3/4] handle the "to" field with a null value as the undefined case --- .../handlers/accounts/local-accounts.ts | 9 +- .../network-manager/rpc/types/address.ts | 1 + .../handlers/accounts/local-accounts.ts | 110 +++++++++--------- 3 files changed, 64 insertions(+), 56 deletions(-) diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts index 4451f4d8d9..baeabdaa70 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts @@ -276,16 +276,19 @@ export class LocalAccountsHandler extends ChainId implements RequestHandler { }; }); - if (txData.to === undefined && txData.data === undefined) { + if ( + (txData.to === undefined || txData.to === null) && + txData.data === undefined + ) { throw new HardhatError( HardhatError.ERRORS.NETWORK.DATA_FIELD_CANNOT_BE_NULL_WITH_NULL_ADDRESS, ); } let checksummedAddress; - if (txData.to === undefined) { + if (txData.to === undefined || txData.to === null) { // This scenario arises during contract deployment. The npm package "micro-eth-signer" does not support - // undefined addresses. Therefore, these values must be converted to "0x", the expected format. + // null or undefined addresses. Therefore, these values must be converted to "0x", the expected format. checksummedAddress = "0x"; } else { checksummedAddress = addr.addChecksum( diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/rpc/types/address.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/rpc/types/address.ts index 19e04e592f..9627975f25 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/rpc/types/address.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/rpc/types/address.ts @@ -14,6 +14,7 @@ export const rpcAddress: ZodType = conditionalUnionType( z.instanceof(Uint8Array), ], [isAddress, z.string()], + [(data) => data === null, z.null()], ], "Expected a Buffer with correct length or a valid RPC address string", ).transform((v) => (typeof v === "string" ? hexStringToBytes(v) : v)); diff --git a/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts b/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts index 90c4c81d83..f35bb6edfd 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/network-manager/request-handlers/handlers/accounts/local-accounts.ts @@ -452,59 +452,63 @@ describe("LocalAccountsHandler", () => { describe("modifyRequest", () => { describe("sending transactions to the null address", () => { - it("should succeed when the data field is not empty", async () => { - const tx = { - // null address: the "to" field is not required - from: "0xb5bc06d4548a3ac17d72b372ae1e416bf65b8ead", - gas: numberToHexString(30000), - nonce: numberToHexString(0), - value: numberToHexString(1), - chainId: numberToHexString(MOCK_PROVIDER_CHAIN_ID), - maxFeePerGas: numberToHexString(12), - maxPriorityFeePerGas: numberToHexString(2), - data: "0x01", - }; - - const jsonRpcRequest = getJsonRpcRequest(1, "eth_sendTransaction", [ - tx, - ]); - - await localAccountsHandler.handle(jsonRpcRequest); - - assert.ok( - Array.isArray(jsonRpcRequest.params), - "params should be an array", - ); - - const rawTransaction = hexStringToBytes(jsonRpcRequest.params[0]); - // The tx type is encoded in the first byte, and it must be the EIP-1559 one - assert.equal(rawTransaction[0], 2); - }); - - it("should throw when the data field is undefined", async () => { - const tx = { - // null address: the "to" field is not required. - // Also, in this test scenario, the "data" field is omitted - from: "0xb5bc06d4548a3ac17d72b372ae1e416bf65b8ead", - gas: numberToHexString(30000), - nonce: numberToHexString(0), - value: numberToHexString(1), - chainId: numberToHexString(MOCK_PROVIDER_CHAIN_ID), - maxFeePerGas: numberToHexString(12), - maxPriorityFeePerGas: numberToHexString(2), - }; - - const jsonRpcRequest = getJsonRpcRequest(1, "eth_sendTransaction", [ - tx, - ]); - - assertRejectsWithHardhatError( - () => localAccountsHandler.handle(jsonRpcRequest), - HardhatError.ERRORS.NETWORK - .DATA_FIELD_CANNOT_BE_NULL_WITH_NULL_ADDRESS, - {}, - ); - }); + const testCases = [null, undefined]; + + for (const testCase of testCases) { + it(`should succeed when the data field is not empty and the "to" field is ${testCase}`, async () => { + const tx = { + to: testCase, + from: "0xb5bc06d4548a3ac17d72b372ae1e416bf65b8ead", + gas: numberToHexString(30000), + nonce: numberToHexString(0), + value: numberToHexString(1), + chainId: numberToHexString(MOCK_PROVIDER_CHAIN_ID), + maxFeePerGas: numberToHexString(12), + maxPriorityFeePerGas: numberToHexString(2), + data: "0x01", + }; + + const jsonRpcRequest = getJsonRpcRequest(1, "eth_sendTransaction", [ + tx, + ]); + + await localAccountsHandler.handle(jsonRpcRequest); + + assert.ok( + Array.isArray(jsonRpcRequest.params), + "params should be an array", + ); + + const rawTransaction = hexStringToBytes(jsonRpcRequest.params[0]); + // The tx type is encoded in the first byte, and it must be the EIP-1559 one + assert.equal(rawTransaction[0], 2); + }); + + it(`should throw when the data field is undefined and the "to" field is ${testCase}`, async () => { + const tx = { + to: testCase, + // In this test scenario, the "data" field is omitted + from: "0xb5bc06d4548a3ac17d72b372ae1e416bf65b8ead", + gas: numberToHexString(30000), + nonce: numberToHexString(0), + value: numberToHexString(1), + chainId: numberToHexString(MOCK_PROVIDER_CHAIN_ID), + maxFeePerGas: numberToHexString(12), + maxPriorityFeePerGas: numberToHexString(2), + }; + + const jsonRpcRequest = getJsonRpcRequest(1, "eth_sendTransaction", [ + tx, + ]); + + assertRejectsWithHardhatError( + () => localAccountsHandler.handle(jsonRpcRequest), + HardhatError.ERRORS.NETWORK + .DATA_FIELD_CANNOT_BE_NULL_WITH_NULL_ADDRESS, + {}, + ); + }); + } }); it("should, given two identical tx, return the same raw transaction", async () => { From 756248a4fd0b0e3fdeb3e290e161f0697d71bb19 Mon Sep 17 00:00:00 2001 From: ChrisD <18092467+ChristopherDedominici@users.noreply.github.com> Date: Fri, 6 Dec 2024 11:20:02 +0100 Subject: [PATCH 4/4] allow null address only for the "to" field --- .../builtin-plugins/network-manager/rpc/types/address.ts | 7 ++++++- .../network-manager/rpc/types/tx-request.ts | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/rpc/types/address.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/rpc/types/address.ts index 9627975f25..dcdd5bf600 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/rpc/types/address.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/rpc/types/address.ts @@ -14,7 +14,12 @@ export const rpcAddress: ZodType = conditionalUnionType( z.instanceof(Uint8Array), ], [isAddress, z.string()], - [(data) => data === null, z.null()], ], "Expected a Buffer with correct length or a valid RPC address string", ).transform((v) => (typeof v === "string" ? hexStringToBytes(v) : v)); + +export const nullableRpcAddress: ZodType = rpcAddress + .or(z.null()) + .describe( + "Expected a Buffer with correct length, a valid RPC address string, or the null value", + ); diff --git a/v-next/hardhat/src/internal/builtin-plugins/network-manager/rpc/types/tx-request.ts b/v-next/hardhat/src/internal/builtin-plugins/network-manager/rpc/types/tx-request.ts index b47607ef53..1eb4aba48a 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/network-manager/rpc/types/tx-request.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/network-manager/rpc/types/tx-request.ts @@ -3,7 +3,7 @@ import type { ZodType } from "zod"; import { z } from "zod"; import { rpcAccessList } from "./access-list.js"; -import { rpcAddress } from "./address.js"; +import { nullableRpcAddress, rpcAddress } from "./address.js"; import { rpcData } from "./data.js"; import { rpcHash } from "./hash.js"; import { rpcQuantity } from "./quantity.js"; @@ -12,7 +12,7 @@ const optional = >(schema: T) => schema.optional(); export interface RpcTransactionRequest { from: Uint8Array; - to?: Uint8Array; + to?: Uint8Array | null; gas?: bigint; gasPrice?: bigint; value?: bigint; @@ -28,7 +28,7 @@ export interface RpcTransactionRequest { export const rpcTransactionRequest: ZodType = z.object({ from: rpcAddress, - to: optional(rpcAddress), + to: optional(nullableRpcAddress), gas: optional(rpcQuantity), gasPrice: optional(rpcQuantity), value: optional(rpcQuantity),