From 9719d1289bb1eac880a287dbdc1ab72ca3305654 Mon Sep 17 00:00:00 2001 From: Kevin Pita Date: Wed, 22 Apr 2026 12:17:20 +0200 Subject: [PATCH 1/4] fix: correct allowance argument order in erc20 approve test --- modules/evm/test/precompiles/erc20/index.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/evm/test/precompiles/erc20/index.test.ts b/modules/evm/test/precompiles/erc20/index.test.ts index 43c7299..0fc7438 100644 --- a/modules/evm/test/precompiles/erc20/index.test.ts +++ b/modules/evm/test/precompiles/erc20/index.test.ts @@ -88,7 +88,7 @@ describe("ERC20", () => { describe("allowance", () => { it("should check that allowance is 0 after approve 0", async () => { await executeTx(contractAsUser.approve(ownerSigner.address, 0n)); - const allowance = await contractAsUser.allowance(ownerSigner.address, userSigner.address); + const allowance = await contractAsUser.allowance(userSigner.address, ownerSigner.address); expect(allowance).to.equal(0n); }); }); From c84a151cac19c9b9b4b5a61370b21c5bc43f3afe Mon Sep 17 00:00:00 2001 From: Kevin Pita Date: Wed, 22 Apr 2026 12:17:44 +0200 Subject: [PATCH 2/4] feat: remove single-owner tests from erc20 precompile --- .../evm/test/precompiles/erc20/index.test.ts | 44 +++---------------- .../test/precompiles/erc20/utils/helpers.ts | 9 ---- 2 files changed, 6 insertions(+), 47 deletions(-) diff --git a/modules/evm/test/precompiles/erc20/index.test.ts b/modules/evm/test/precompiles/erc20/index.test.ts index 0fc7438..bd7f90d 100644 --- a/modules/evm/test/precompiles/erc20/index.test.ts +++ b/modules/evm/test/precompiles/erc20/index.test.ts @@ -49,11 +49,6 @@ describe("ERC20", () => { const { erc20 } = moduleConfig.contracts; const chain = moduleConfig.chain; - /** - * The owner is the account that can mint and burn tokens. - * It is set in the genesis block. - */ - const { owner } = moduleConfig.contracts.erc20; // Notice: user is acting as a faucet, providing the owner with enough tokens // to cover transaction fees and execute mint, burn, and transferOwnership (just in localnet) tests. @@ -70,14 +65,6 @@ describe("ERC20", () => { burnAmount = toBigInt(erc20.burnAmount); }); - describe("owner", () => { - it("should return the correct owner", async () => { - const currentOwner = await contractAsOwner.owner(); - expect(currentOwner).to.equal(owner); - expect(currentOwner).to.equal(await contractAsUser.owner()); - }); - }); - describe("totalSupply", () => { it("should return a positive totalSupply", async () => { const totalSupply = await contractAsOwner.totalSupply(); @@ -119,7 +106,7 @@ describe("ERC20", () => { await executeTx(contractAsUser.transfer(ownerSigner.address, erc20.faucetFund)); }); afterEach(async () => { - await resetOwnerState(contractAsOwner, contractAsUser, ownerSigner, userSigner, chain.env); + await resetOwnerState(contractAsOwner, contractAsUser, ownerSigner, userSigner); }); it("should mint tokens to the user", async () => { @@ -167,7 +154,7 @@ describe("ERC20", () => { await executeTx(contractAsUser.transfer(ownerSigner.address, erc20.faucetFund)); }); afterEach(async () => { - await resetOwnerState(contractAsOwner, contractAsUser, ownerSigner, userSigner, chain.env); + await resetOwnerState(contractAsOwner, contractAsUser, ownerSigner, userSigner); }); it("should revert if sender is not owner", async () => { @@ -189,7 +176,7 @@ describe("ERC20", () => { await executeTx(contractAsUser.transfer(ownerSigner.address, erc20.faucetFund)); }); afterEach(async () => { - await resetOwnerState(contractAsOwner, contractAsUser, ownerSigner, userSigner, chain.env); + await resetOwnerState(contractAsOwner, contractAsUser, ownerSigner, userSigner); }); it("should revert if spender does not have allowance", async () => { @@ -214,31 +201,12 @@ describe("ERC20", () => { }); }); - describeOrSkip("transferOwnership", isChainEnvironment(["localnet"], chain as unknown as Chain), () => { - beforeEach(async () => { - await executeTx(contractAsUser.transfer(ownerSigner.address, erc20.faucetFund)); - }); - afterEach(async () => { - await resetOwnerState(contractAsOwner, contractAsUser, ownerSigner, userSigner, chain.env); - }); - - it("should revert if sender is not the owner", async () => { - await expectRevert(contractAsUser.transferOwnership(ownerSigner.address), ERC20Errors.SENDER_IS_NOT_OWNER); - }); - - it("should transfer ownership if sender is owner", async () => { - await executeTx(contractAsOwner.transferOwnership(userSigner.address)); - const newOwner = await contractAsOwner.owner(); - expect(newOwner).to.equal(userSigner.address); - }); - }); - describe("transfer", () => { beforeEach(async () => { await executeTx(contractAsUser.transfer(ownerSigner.address, erc20.faucetFund)); }); afterEach(async () => { - await resetOwnerState(contractAsOwner, contractAsUser, ownerSigner, userSigner, chain.env); + await resetOwnerState(contractAsOwner, contractAsUser, ownerSigner, userSigner); }); it("should successfully transfer tokens between accounts", async () => { @@ -271,7 +239,7 @@ describe("ERC20", () => { await executeTx(contractAsUser.transfer(ownerSigner.address, erc20.faucetFund)); }); afterEach(async () => { - await resetOwnerState(contractAsOwner, contractAsUser, ownerSigner, userSigner, chain.env); + await resetOwnerState(contractAsOwner, contractAsUser, ownerSigner, userSigner); }); it("should successfully transfer tokens using transferFrom", async () => { @@ -315,7 +283,7 @@ describe("ERC20", () => { await executeTx(contractAsUser.transfer(ownerSigner.address, erc20.faucetFund)); }); afterEach(async () => { - await resetOwnerState(contractAsOwner, contractAsUser, ownerSigner, userSigner, chain.env); + await resetOwnerState(contractAsOwner, contractAsUser, ownerSigner, userSigner); }); it("should set and reset the allowance correctly and emit Approval events", async () => { diff --git a/modules/evm/test/precompiles/erc20/utils/helpers.ts b/modules/evm/test/precompiles/erc20/utils/helpers.ts index fb67b3b..decf69f 100644 --- a/modules/evm/test/precompiles/erc20/utils/helpers.ts +++ b/modules/evm/test/precompiles/erc20/utils/helpers.ts @@ -28,19 +28,10 @@ export async function resetOwnerState( contractAsUser: Contract, ownerSigner: HardhatEthersSigner, userSigner: HardhatEthersSigner, - chainEvn: string, ): Promise { const ownerBalance: bigint = await contractAsOwner.balanceOf(ownerSigner.address); if (ownerBalance <= 0n) return; - if (chainEvn === "localnet") { - // Restore ownership if needed - const currentOwner = await contractAsOwner.owner(); - if (currentOwner !== ownerSigner.address) { - await executeTx(contractAsUser.transferOwnership(ownerSigner.address)); - } - } - // Approve the full balance. await executeTx(contractAsOwner.approve(userSigner.address, ownerBalance)); From 6cd47a24a23fd2742eb1dbee09e0a2d703536852 Mon Sep 17 00:00:00 2001 From: Kevin Pita Date: Thu, 23 Apr 2026 15:47:49 +0200 Subject: [PATCH 3/4] feat(cosmos): extract ethermint module and add gov/query helpers --- modules/cosmos/package.json | 5 + .../{ibc => ethermint}/account-parser.ts | 42 +- modules/cosmos/src/modules/ethermint/index.ts | 7 + .../src/modules/{ibc => ethermint}/parser.ts | 0 .../src/modules/{ibc => ethermint}/pubkey.ts | 0 .../modules/{ibc => ethermint}/secp256k1.ts | 0 .../src/modules/{ibc => ethermint}/signer.ts | 3 +- .../src/modules/ethermint/signing-client.ts | 110 ++++ .../signing-stargate-client.ts} | 0 modules/cosmos/src/modules/gov/gov.ts | 138 +++++ modules/cosmos/src/modules/gov/index.ts | 1 + modules/cosmos/src/modules/ibc/client.ts | 179 +----- modules/cosmos/src/modules/ibc/utils.ts | 2 +- modules/cosmos/src/modules/query/abci.ts | 35 ++ modules/cosmos/src/modules/query/index.ts | 1 + pnpm-lock.yaml | 538 ++++++++++++------ 16 files changed, 692 insertions(+), 369 deletions(-) rename modules/cosmos/src/modules/{ibc => ethermint}/account-parser.ts (57%) create mode 100644 modules/cosmos/src/modules/ethermint/index.ts rename modules/cosmos/src/modules/{ibc => ethermint}/parser.ts (100%) rename modules/cosmos/src/modules/{ibc => ethermint}/pubkey.ts (100%) rename modules/cosmos/src/modules/{ibc => ethermint}/secp256k1.ts (100%) rename modules/cosmos/src/modules/{ibc => ethermint}/signer.ts (99%) create mode 100644 modules/cosmos/src/modules/ethermint/signing-client.ts rename modules/cosmos/src/modules/{ibc/signingstartgateclient.ts => ethermint/signing-stargate-client.ts} (100%) create mode 100644 modules/cosmos/src/modules/gov/gov.ts create mode 100644 modules/cosmos/src/modules/gov/index.ts create mode 100644 modules/cosmos/src/modules/query/abci.ts create mode 100644 modules/cosmos/src/modules/query/index.ts diff --git a/modules/cosmos/package.json b/modules/cosmos/package.json index bb13b01..63e7587 100644 --- a/modules/cosmos/package.json +++ b/modules/cosmos/package.json @@ -3,6 +3,11 @@ "version": "1.0.0", "description": "", "main": "index.js", + "exports": { + "./gov": "./src/modules/gov/index.ts", + "./ethermint": "./src/modules/ethermint/index.ts", + "./query": "./src/modules/query/index.ts" + }, "scripts": { "lint": "eslint .", "test:mainnet": "cp configs/mainnet.module.config.json module.config.json && mocha", diff --git a/modules/cosmos/src/modules/ibc/account-parser.ts b/modules/cosmos/src/modules/ethermint/account-parser.ts similarity index 57% rename from modules/cosmos/src/modules/ibc/account-parser.ts rename to modules/cosmos/src/modules/ethermint/account-parser.ts index f308d25..9dfb2e3 100644 --- a/modules/cosmos/src/modules/ibc/account-parser.ts +++ b/modules/cosmos/src/modules/ethermint/account-parser.ts @@ -1,4 +1,5 @@ import { Account, accountFromAny } from "@cosmjs/stargate"; +import { BaseAccount } from "cosmjs-types/cosmos/auth/v1beta1/auth"; import { Any } from "cosmjs-types/google/protobuf/any"; import { parseEthAccount } from "./parser"; @@ -18,28 +19,31 @@ import { parseEthAccount } from "./parser"; * @throws Error if parsing fails for both EthAccount and standard account formats. */ export function ethermintAccountParser(input: Any): Account { - try { - // Handle EthAccount specifically - if (input.typeUrl === "/ethermint.types.v1.EthAccount") { - const ethAccount = parseEthAccount(input); - if (ethAccount?.baseAccount) { - return { - address: ethAccount.baseAccount.address, - accountNumber: Number(ethAccount.baseAccount.accountNumber), - sequence: Number(ethAccount.baseAccount.sequence), - pubkey: null, // EthAccount doesn't store pubkey in the account - } as Account; - } - // If EthAccount parsing fails, fall through to standard parsing + if (input.typeUrl === "/ethermint.types.v1.EthAccount") { + const ethAccount = parseEthAccount(input); + if (ethAccount?.baseAccount) { + return { + address: ethAccount.baseAccount.address, + accountNumber: Number(ethAccount.baseAccount.accountNumber), + sequence: Number(ethAccount.baseAccount.sequence), + pubkey: null, + } as Account; } + } - // For all other account types or if EthAccount parsing failed, use standard parsing - return accountFromAny(input); - } catch (error) { - console.error("Failed to parse account with ethermintAccountParser:", error); - // Final fallback to standard parsing, let it throw if it fails - return accountFromAny(input); + // BaseAccount may carry a non-cosmos pubkey (e.g. ethsecp256k1) that accountFromAny cannot decode. + // Decode fields directly and drop the pubkey to avoid the failure. + if (input.typeUrl === "/cosmos.auth.v1beta1.BaseAccount") { + const base = BaseAccount.decode(input.value); + return { + address: base.address, + accountNumber: Number(base.accountNumber), + sequence: Number(base.sequence), + pubkey: null, + } as Account; } + + return accountFromAny(input); } /** diff --git a/modules/cosmos/src/modules/ethermint/index.ts b/modules/cosmos/src/modules/ethermint/index.ts new file mode 100644 index 0000000..485c4b6 --- /dev/null +++ b/modules/cosmos/src/modules/ethermint/index.ts @@ -0,0 +1,7 @@ +export * from "./account-parser"; +export * from "./parser"; +export * from "./pubkey"; +export * from "./secp256k1"; +export * from "./signer"; +export * from "./signing-client"; +export * from "./signing-stargate-client"; diff --git a/modules/cosmos/src/modules/ibc/parser.ts b/modules/cosmos/src/modules/ethermint/parser.ts similarity index 100% rename from modules/cosmos/src/modules/ibc/parser.ts rename to modules/cosmos/src/modules/ethermint/parser.ts diff --git a/modules/cosmos/src/modules/ibc/pubkey.ts b/modules/cosmos/src/modules/ethermint/pubkey.ts similarity index 100% rename from modules/cosmos/src/modules/ibc/pubkey.ts rename to modules/cosmos/src/modules/ethermint/pubkey.ts diff --git a/modules/cosmos/src/modules/ibc/secp256k1.ts b/modules/cosmos/src/modules/ethermint/secp256k1.ts similarity index 100% rename from modules/cosmos/src/modules/ibc/secp256k1.ts rename to modules/cosmos/src/modules/ethermint/secp256k1.ts diff --git a/modules/cosmos/src/modules/ibc/signer.ts b/modules/cosmos/src/modules/ethermint/signer.ts similarity index 99% rename from modules/cosmos/src/modules/ibc/signer.ts rename to modules/cosmos/src/modules/ethermint/signer.ts index b9cf7fa..853c85f 100644 --- a/modules/cosmos/src/modules/ibc/signer.ts +++ b/modules/cosmos/src/modules/ethermint/signer.ts @@ -12,7 +12,6 @@ import { Random, Secp256k1, Secp256k1Keypair, - sha256, Slip10, Slip10Curve, stringToPath, @@ -281,7 +280,7 @@ export class DirectSecp256k1HdWallet implements OfflineDirectSigner { } const { privkey, pubkey } = account; const signBytes = makeSignBytes(signDoc); - const hashedMessage = sha256(signBytes); + const hashedMessage = keccak256(signBytes); const signature = await Secp256k1.createSignature(hashedMessage, privkey); const signatureBytes = new Uint8Array([...signature.r(32), ...signature.s(32)]); const stdSignature = encodeSecp256k1Signature(pubkey, signatureBytes, true); // true for Ethermint diff --git a/modules/cosmos/src/modules/ethermint/signing-client.ts b/modules/cosmos/src/modules/ethermint/signing-client.ts new file mode 100644 index 0000000..f067258 --- /dev/null +++ b/modules/cosmos/src/modules/ethermint/signing-client.ts @@ -0,0 +1,110 @@ +import { Account, HttpEndpoint, SigningStargateClientOptions, defaultRegistryTypes } from "@cosmjs/stargate"; +import { OfflineSigner, Registry } from "@cosmjs/proto-signing"; +import { CometClient, connectComet } from "@cosmjs/tendermint-rpc"; +import { createEthermintAccountParser, ethermintAccountParser } from "./account-parser"; +import { SigningStargateClient } from "./signing-stargate-client"; + +/** + * Create Ethermint-compatible registry with correct public key types. + * @returns Registry configured for Ethermint chains. + */ +function createEthermintRegistry(): Registry { + const registry = new Registry(defaultRegistryTypes); + + // Register Ethermint-specific amino types + registry.register("/ethermint.crypto.v1.ethsecp256k1.PubKey", {} as any); + registry.register("/ethermint.types.v1.EthAccount", {} as any); + + return registry; +} + +type EthermintClientCtor = new ( + cometClient: CometClient, + signer: OfflineSigner, + options: SigningStargateClientOptions, +) => T; + +/** + * Ethermint-aware signing client. Uses ethermint pubkey/account types and + * unwraps EthAccount on account queries. + */ +export class EthermintSigningClient extends SigningStargateClient { + /** + * Widens the parent's protected constructor to public so subclasses can be + * instantiated via `new this(...)` from the static factories below. + * @param cometClient The comet client. + * @param signer The signer. + * @param options The client options. + */ + constructor(cometClient: CometClient, signer: OfflineSigner, options: SigningStargateClientOptions) { + super(cometClient, signer, options); + } + + /** + * Get the account. + * @param searchAddress The address to search for. + * @returns The account, or null if not found. + */ + async getAccount(searchAddress: string): Promise { + try { + const accountAny = await this.forceGetQueryClient().auth.account(searchAddress); + if (!accountAny) { + return null; + } + return ethermintAccountParser(accountAny); + } catch (error) { + console.error("Failed to get account:", error); + return null; + } + } + + /** + * Run a raw ABCI query against the connected chain. + * @param path The ABCI query path (e.g. "/cosmos.gov.v1.Query/Proposal"). + * @param data The encoded request bytes. + * @returns The raw response value bytes. + */ + async queryAbci(path: string, data: Uint8Array): Promise { + const { value } = await this.forceGetQueryClient().queryAbci(path, data); + return value; + } + + /** + * Create a client with a signer. + * @param cometClient The comet client. + * @param signer The signer. + * @param options The options. + * @returns The client. + */ + static async createWithSigner( + this: EthermintClientCtor, + cometClient: CometClient, + signer: OfflineSigner, + options?: SigningStargateClientOptions, + ): Promise { + const defaultOptions: SigningStargateClientOptions = { + accountParser: createEthermintAccountParser(), + registry: createEthermintRegistry(), + aminoTypes: undefined, + ...options, + }; + return new this(cometClient, signer, defaultOptions); + } + + /** + * Connect with a signer. + * @param endpoint The endpoint. + * @param signer The signer. + * @param options The options. + * @returns The client. + */ + static async connectWithSigner( + this: EthermintClientCtor, + endpoint: string | HttpEndpoint, + signer: OfflineSigner, + options?: SigningStargateClientOptions, + ): Promise { + const cometClient = await connectComet(endpoint); + return EthermintSigningClient.createWithSigner.call(this, cometClient, signer, options) as Promise; + } +} diff --git a/modules/cosmos/src/modules/ibc/signingstartgateclient.ts b/modules/cosmos/src/modules/ethermint/signing-stargate-client.ts similarity index 100% rename from modules/cosmos/src/modules/ibc/signingstartgateclient.ts rename to modules/cosmos/src/modules/ethermint/signing-stargate-client.ts diff --git a/modules/cosmos/src/modules/gov/gov.ts b/modules/cosmos/src/modules/gov/gov.ts new file mode 100644 index 0000000..2152ed6 --- /dev/null +++ b/modules/cosmos/src/modules/gov/gov.ts @@ -0,0 +1,138 @@ +import { stringToPath } from "@cosmjs/crypto"; +import { MsgSubmitProposal, MsgSubmitProposalResponse, MsgVote } from "cosmjs-types/cosmos/gov/v1/tx"; +import { QueryProposalRequest, QueryProposalResponse } from "cosmjs-types/cosmos/gov/v1/query"; +import { ProposalStatus, VoteOption } from "cosmjs-types/cosmos/gov/v1/gov"; +import { Any } from "cosmjs-types/google/protobuf/any"; +import { DirectSecp256k1HdWallet, EthermintSigningClient } from "../ethermint"; + +export { ProposalStatus } from "cosmjs-types/cosmos/gov/v1/gov"; + +const ETHEREUM_HD_PATH = "m/44'/60'/0'/0/0"; +const SUBMIT_PROPOSAL_GAS = "500000"; +const VOTE_GAS = "200000"; +const PROPOSAL_POLL_INTERVAL_MS = 2_000; +const PROPOSAL_DEFAULT_TIMEOUT_MS = 30_000; + +export type SubmitAndVoteParams = { + rpcUrl: string; + mnemonic: string; + prefix: string; + denom: string; + message: Any; + title: string; + summary: string; + depositAmount: string; + timeoutMs?: number; +}; + +/** + * Sleep for the given duration. + * @param ms Duration in milliseconds. + */ +async function sleep(ms: number): Promise { + await new Promise((resolvePromise) => { + setTimeout(resolvePromise, ms); + }); +} + +/** + * Poll the chain until a proposal reaches a terminal status (>= PASSED). + * @param client Connected Ethermint signing client. + * @param proposalId Proposal identifier. + * @param timeoutMs Timeout in milliseconds. + * @returns The terminal proposal status code. + */ +async function waitForProposal(client: EthermintSigningClient, proposalId: bigint, timeoutMs: number): Promise { + const deadline = Date.now() + timeoutMs; + const request = QueryProposalRequest.encode(QueryProposalRequest.fromPartial({ proposalId })).finish(); + + while (Date.now() < deadline) { + const value = await client.queryAbci("/cosmos.gov.v1.Query/Proposal", request); + if (value.length > 0) { + const { proposal } = QueryProposalResponse.decode(value); + const status = proposal ? Number(proposal.status) : undefined; + if (typeof status === "number" && status >= ProposalStatus.PROPOSAL_STATUS_PASSED) { + return status; + } + } + + await sleep(PROPOSAL_POLL_INTERVAL_MS); + } + + throw new Error(`Proposal ${proposalId} did not reach terminal state within ${timeoutMs}ms`); +} + +/** + * Submit a single-message governance proposal, vote YES from the same sender, and wait for a terminal status. + * + * The `depositAmount` must be >= the chain's `min_deposit` (gov params), otherwise the proposal stays + * in deposit period and `waitForProposal` times out. + * @param params Submit-and-vote parameters. + * @returns Proposal id and terminal status. + */ +export async function submitAndVote(params: SubmitAndVoteParams): Promise<{ proposalId: string; status: number }> { + const { rpcUrl, mnemonic, prefix, denom, message, title, summary, depositAmount, timeoutMs = PROPOSAL_DEFAULT_TIMEOUT_MS } = params; + + const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { + prefix, + hdPaths: [stringToPath(ETHEREUM_HD_PATH)], + }); + const client = await EthermintSigningClient.connectWithSigner(rpcUrl, wallet); + + try { + const [{ address: sender }] = await wallet.getAccounts(); + + const submitResult = await client.signAndBroadcast( + sender, + [ + { + typeUrl: "/cosmos.gov.v1.MsgSubmitProposal", + value: MsgSubmitProposal.fromPartial({ + messages: [message], + initialDeposit: [{ denom, amount: depositAmount }], + proposer: sender, + metadata: "", + title, + summary, + }), + }, + ], + { amount: [{ denom, amount: "1" }], gas: SUBMIT_PROPOSAL_GAS }, + ); + if (submitResult.code !== 0) { + throw new Error(`Submit proposal failed: ${submitResult.rawLog ?? `code=${submitResult.code}`}`); + } + + const [msgResponse] = submitResult.msgResponses; + if (!msgResponse) { + throw new Error("MsgSubmitProposalResponse missing from submit result"); + } + const proposalId = MsgSubmitProposalResponse.decode(msgResponse.value).proposalId; + + const voteResult = await client.signAndBroadcast( + sender, + [ + { + typeUrl: "/cosmos.gov.v1.MsgVote", + value: MsgVote.fromPartial({ + proposalId, + voter: sender, + option: VoteOption.VOTE_OPTION_YES, + metadata: "", + }), + }, + ], + { amount: [{ denom, amount: "1" }], gas: VOTE_GAS }, + ); + if (voteResult.code !== 0) { + throw new Error(`Vote failed: ${voteResult.rawLog ?? `code=${voteResult.code}`}`); + } + + return { + proposalId: proposalId.toString(), + status: await waitForProposal(client, proposalId, timeoutMs), + }; + } finally { + client.disconnect(); + } +} diff --git a/modules/cosmos/src/modules/gov/index.ts b/modules/cosmos/src/modules/gov/index.ts new file mode 100644 index 0000000..bd07c9a --- /dev/null +++ b/modules/cosmos/src/modules/gov/index.ts @@ -0,0 +1 @@ +export * from "./gov"; diff --git a/modules/cosmos/src/modules/ibc/client.ts b/modules/cosmos/src/modules/ibc/client.ts index fd70bde..e9c8404 100644 --- a/modules/cosmos/src/modules/ibc/client.ts +++ b/modules/cosmos/src/modules/ibc/client.ts @@ -1,141 +1,10 @@ -import { - DeliverTxResponse, - StdFee, - SignerData, - HttpEndpoint, - SigningStargateClientOptions, - accountFromAny, - Account, - defaultRegistryTypes, -} from "@cosmjs/stargate"; +import { DeliverTxResponse, StdFee } from "@cosmjs/stargate"; import { Coin } from "cosmjs-types/cosmos/base/v1beta1/coin"; import { Height } from "cosmjs-types/ibc/core/client/v1/client"; import { MsgTransfer } from "cosmjs-types/ibc/applications/transfer/v1/tx"; -import { EncodeObject, OfflineSigner, Registry } from "@cosmjs/proto-signing"; -import { TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx"; -import { CometClient, connectComet } from "@cosmjs/tendermint-rpc"; -import { parseEthAccount } from "./parser"; -import { SigningStargateClient } from "./signingstartgateclient"; -import { Any } from "cosmjs-types/google/protobuf/any"; - -/** - * Create Ethermint-compatible registry with correct public key types. - * @returns Registry configured for Ethermint chains. - */ -function createEthermintRegistry(): Registry { - const registry = new Registry(defaultRegistryTypes); - - // Register Ethermint-specific amino types - registry.register("/ethermint.crypto.v1.ethsecp256k1.PubKey", {} as any); - registry.register("/ethermint.types.v1.EthAccount", {} as any); - - return registry; -} - -/** - * Custom account parser that extends accountFromAny to support EthAccount. - * @param input The Any message containing the account. - * @returns The parsed account. - * @throws Error if parsing fails. - */ -export function ethermintAccountParser(input: Any): Account { - try { - // First try standard Cosmos account parsing for non-EthAccount types - if (input.typeUrl !== "/ethermint.types.v1.EthAccount") { - return accountFromAny(input); - } - - // Handle EthAccount specifically - const ethAccount = parseEthAccount(input); - if (ethAccount?.baseAccount) { - return { - address: ethAccount.baseAccount.address, - accountNumber: Number(ethAccount.baseAccount.accountNumber), - sequence: Number(ethAccount.baseAccount.sequence), - pubkey: null, // EthAccount doesn't store pubkey in the account - } as Account; - } - - // If EthAccount parsing fails, try fallback to standard parsing - return accountFromAny(input); - } catch (error) { - console.error("Failed to parse account:", error); - // Final fallback to standard parsing, let it throw if it fails - return accountFromAny(input); - } -} - -/** - * Create an account parser configured for a specific address prefix. - * @returns A configured account parser function. - */ -export function createEthermintAccountParser() { - return (input: Any): Account => ethermintAccountParser(input); -} - -export class IBCEvmSignerClient extends SigningStargateClient { - constructor(cometClient: CometClient, signer: OfflineSigner, options: SigningStargateClientOptions) { - super(cometClient, signer, options); - } - - /** - * Get the account. - * @param searchAddress The address to search for. - * @returns The account. - */ - async getAccount(searchAddress: string): Promise { - try { - const accountAny = await this.forceGetQueryClient().auth.account(searchAddress); - - if (!accountAny) { - return null; - } - - // Use the custom account parser - return ethermintAccountParser(accountAny); - } catch (error) { - console.error("Failed to get account:", error); - return null; - } - } - - /** - * Create a client with a signer. - * @param cometClient The comet client. - * @param signer The signer. - * @param options The options. - * @returns The client. - */ - static async createWithSigner( - cometClient: CometClient, - signer: OfflineSigner, - options?: SigningStargateClientOptions, - ): Promise { - const defaultOptions: SigningStargateClientOptions = { - accountParser: createEthermintAccountParser(), // Use our custom account parser - registry: createEthermintRegistry(), - aminoTypes: undefined, // Use default amino types - ...options, - }; - return new IBCEvmSignerClient(cometClient, signer, defaultOptions); - } - - /** - * Connect with a signer. - * @param endpoint The endpoint. - * @param signer The signer. - * @param options The options. - * @returns The client. - */ - static async connectWithSigner( - endpoint: string | HttpEndpoint, - signer: OfflineSigner, - options?: SigningStargateClientOptions, - ): Promise { - const cometClient = await connectComet(endpoint); - return await IBCEvmSignerClient.createWithSigner(cometClient, signer, options); - } +import { EthermintSigningClient } from "../ethermint/signing-client"; +export class IBCEvmSignerClient extends EthermintSigningClient { /** * Send IBC tokens from one chain to another. * @param senderAddress The address of the sender. @@ -187,46 +56,4 @@ export class IBCEvmSignerClient extends SigningStargateClient { return this.signAndBroadcast(senderAddress, [transferMsg], fee, memo); } - - /** - * Sign and broadcast a transaction. - * @param signerAddress The address of the signer. - * @param messages The messages to sign and broadcast. - * @param fee The fee. - * @param memo The memo. - * @param timeoutHeight The timeout height. - * @returns The deliver tx response. - */ - async signAndBroadcast( - signerAddress: string, - messages: readonly EncodeObject[], - fee: StdFee, - memo: string = "", - timeoutHeight?: bigint, - ): Promise { - const txRaw = await this.sign(signerAddress, messages, fee, memo, undefined, timeoutHeight); - const txBytes = TxRaw.encode(txRaw).finish(); - return this.broadcastTx(txBytes, this.broadcastTimeoutMs, this.broadcastPollIntervalMs); - } - - /** - * Sign a transaction. - * @param signerAddress The address of the signer. - * @param messages The messages to sign. - * @param fee The fee. - * @param memo The memo. - * @param explicitSignerData Explicit signer data. - * @param timeoutHeight The timeout height. - * @returns The signed transaction. - */ - async sign( - signerAddress: string, - messages: readonly EncodeObject[], - fee: StdFee, - memo: string, - explicitSignerData?: SignerData, - timeoutHeight?: bigint, - ): Promise { - return super.sign(signerAddress, messages, fee, memo, explicitSignerData as any, timeoutHeight); - } } diff --git a/modules/cosmos/src/modules/ibc/utils.ts b/modules/cosmos/src/modules/ibc/utils.ts index dc59c29..c77db93 100644 --- a/modules/cosmos/src/modules/ibc/utils.ts +++ b/modules/cosmos/src/modules/ibc/utils.ts @@ -2,7 +2,7 @@ import { SigningStargateClient, StargateClient } from "@cosmjs/stargate"; import { IBCChain, IBCChainPair } from "./config"; import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing"; import { IBCEvmSignerClient } from "./client"; -import { DirectSecp256k1HdWallet as EvmDirectSecp256k1HdWallet } from "./signer"; +import { DirectSecp256k1HdWallet as EvmDirectSecp256k1HdWallet } from "../ethermint/signer"; import { makeCosmoshubPath } from "@cosmjs/amino"; import { stringToPath } from "@cosmjs/crypto"; diff --git a/modules/cosmos/src/modules/query/abci.ts b/modules/cosmos/src/modules/query/abci.ts new file mode 100644 index 0000000..0b59aab --- /dev/null +++ b/modules/cosmos/src/modules/query/abci.ts @@ -0,0 +1,35 @@ +import { connectComet } from "@cosmjs/tendermint-rpc"; + +/** + * Open a Comet RPC connection, run the callback, and disconnect. Use for + * batching multiple ABCI queries against the same connection. + * @param rpcUrl Comet RPC endpoint. + * @param fn Callback receiving a bound `(path, data)` query function. + * @returns The callback's return value. + */ +export async function withComet( + rpcUrl: string, + fn: (query: (path: string, data: Uint8Array) => Promise) => Promise, +): Promise { + const client = await connectComet(rpcUrl); + try { + return await fn(async (path, data) => { + const { value } = await client.abciQuery({ path, data }); + return value ?? new Uint8Array(); + }); + } finally { + client.disconnect(); + } +} + +/** + * Run a one-shot ABCI query against a Comet RPC endpoint. Opens a connection, + * issues the query, and disconnects. For repeated queries use `withComet`. + * @param rpcUrl Comet RPC endpoint. + * @param path ABCI query path (e.g. "/cosmos.gov.v1.Query/Proposal"). + * @param data Encoded request bytes. + * @returns Raw response value bytes (empty if the response had none). + */ +export async function abciQuery(rpcUrl: string, path: string, data: Uint8Array): Promise { + return withComet(rpcUrl, (query) => query(path, data)); +} diff --git a/modules/cosmos/src/modules/query/index.ts b/modules/cosmos/src/modules/query/index.ts new file mode 100644 index 0000000..c64cf40 --- /dev/null +++ b/modules/cosmos/src/modules/query/index.ts @@ -0,0 +1 @@ +export * from "./abci"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a0d389b..d12185d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,7 +22,7 @@ importers: version: 6.0.1 tsup: specifier: ^8.2.4 - version: 8.3.6(typescript@5.9.3) + version: 8.3.6(typescript@6.0.3) turbo: specifier: ^2.1.0 version: 2.4.2 @@ -162,10 +162,10 @@ importers: dependencies: '@nomicfoundation/hardhat-ethers': specifier: ^3.0.8 - version: 3.0.8(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)) + version: 3.0.8(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)) '@nomicfoundation/hardhat-toolbox': specifier: ^5.0.0 - version: 5.0.0(6qv3amog762zhvysfqmmoxayvu) + version: 5.0.0(7idygwlwsesd5erfftcdwsdmae) bignumber.js: specifier: ^9.1.2 version: 9.1.2 @@ -177,11 +177,17 @@ importers: version: 6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7) hardhat: specifier: ^2.22.18 - version: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7) + version: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7) devDependencies: + '@cosmjs/encoding': + specifier: ^0.33.1 + version: 0.33.1 '@firewatch/core': specifier: workspace:* version: link:../../packages/core + '@firewatch/cosmos': + specifier: workspace:* + version: link:../cosmos '@shared/eslint': specifier: workspace:* version: link:../../packages/shared/eslint @@ -200,6 +206,9 @@ importers: '@types/chai': specifier: ^5.0.1 version: 5.0.1 + cosmjs-types: + specifier: ^0.9.0 + version: 0.9.0 dotenv: specifier: ^16.4.7 version: 16.4.7 @@ -208,7 +217,7 @@ importers: dependencies: '@axelar-network/axelarjs-sdk': specifier: github:banasa44/axelarjs-sdk#chore/release-0.17.1 - version: https://codeload.github.com/banasa44/axelarjs-sdk/tar.gz/f55f46a6ae4d77477c87e2f4720a680bec7c5b34(bufferutil@4.0.5)(encoding@0.1.13)(typescript@5.9.3)(utf-8-validate@5.0.7) + version: https://codeload.github.com/banasa44/axelarjs-sdk/tar.gz/f55f46a6ae4d77477c87e2f4720a680bec7c5b34(bufferutil@4.0.5)(encoding@0.1.13)(typescript@6.0.3)(utf-8-validate@5.0.7) '@firewatch/core': specifier: workspace:* version: link:../core @@ -242,7 +251,7 @@ importers: version: link:../shared/xrpl '@swisstype/essential': specifier: ^0.1.1 - version: 0.1.2(typescript@5.9.3) + version: 0.1.2(typescript@6.0.3) '@tanstack/react-query': specifier: ^5.52.2 version: 5.66.7(react@19.0.0) @@ -257,13 +266,13 @@ importers: version: 6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7) jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)) + version: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@6.0.3)) ts-jest: specifier: ^29.2.5 - version: 29.2.5(@babel/core@7.26.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.9))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.2.5(@babel/core@7.26.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.9))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@6.0.3)))(typescript@6.0.3) typescript: specifier: latest - version: 5.9.3 + version: 6.0.3 xchain-sdk: specifier: workspace:* version: link:../xchain-sdk @@ -470,7 +479,7 @@ importers: version: link:../../shared/tsup typescript: specifier: latest - version: 5.9.3 + version: 6.0.3 packages/proto/evmos: dependencies: @@ -504,16 +513,16 @@ importers: version: link:../../shared/tsup typescript: specifier: latest - version: 5.9.3 + version: 6.0.3 packages/shared/eslint: devDependencies: '@typescript-eslint/eslint-plugin': specifier: ^8.3.0 - version: 8.24.1(@typescript-eslint/parser@8.24.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3) + version: 8.24.1(@typescript-eslint/parser@8.24.1(eslint@8.57.1)(typescript@6.0.3))(eslint@8.57.1)(typescript@6.0.3) '@typescript-eslint/parser': specifier: ^8.3.0 - version: 8.24.1(eslint@8.57.1)(typescript@5.9.3) + version: 8.24.1(eslint@8.57.1)(typescript@6.0.3) eslint: specifier: ^8.57.0 version: 8.57.1 @@ -525,7 +534,7 @@ importers: version: 3.8.2(eslint-plugin-import@2.29.1)(eslint@8.57.1) eslint-plugin-import: specifier: 2.29.1 - version: 2.29.1(@typescript-eslint/parser@8.24.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.8.2)(eslint@8.57.1) + version: 2.29.1(@typescript-eslint/parser@8.24.1(eslint@8.57.1)(typescript@6.0.3))(eslint-import-resolver-typescript@3.8.2)(eslint@8.57.1) eslint-plugin-jsdoc: specifier: ^50.2.2 version: 50.6.3(eslint@8.57.1) @@ -568,10 +577,10 @@ importers: version: 29.5.14 '@types/node': specifier: latest - version: 25.0.9 + version: 25.6.0 typescript: specifier: latest - version: 5.9.3 + version: 6.0.3 packages/shared/modules: devDependencies: @@ -586,7 +595,7 @@ importers: version: link:../tsup typescript: specifier: latest - version: 5.9.3 + version: 6.0.3 packages/shared/number: devDependencies: @@ -601,13 +610,13 @@ importers: version: link:../tsup '@types/node': specifier: latest - version: 25.0.9 + version: 25.6.0 bignumber.js: specifier: ^9.1.2 version: 9.1.2 typescript: specifier: latest - version: 5.9.3 + version: 6.0.3 packages/shared/tsconfig: {} @@ -621,13 +630,13 @@ importers: version: link:../tsconfig '@types/node': specifier: latest - version: 25.0.9 + version: 25.6.0 tsup: specifier: ^8.2.4 - version: 8.3.6(typescript@5.9.3) + version: 8.3.6(typescript@6.0.3) typescript: specifier: latest - version: 5.9.3 + version: 6.0.3 packages/shared/utils: devDependencies: @@ -645,16 +654,16 @@ importers: version: 29.5.14 '@types/node': specifier: latest - version: 25.0.9 + version: 25.6.0 '@types/validator': specifier: ^13.12.1 version: 13.12.2 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@25.0.9)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3)) + version: 29.7.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3)) typescript: specifier: latest - version: 5.9.3 + version: 6.0.3 validator: specifier: 13.12.0 version: 13.12.0 @@ -672,19 +681,19 @@ importers: version: link:../tsup '@swisstype/essential': specifier: ^0.1.1 - version: 0.1.2(typescript@5.9.3) + version: 0.1.2(typescript@6.0.3) '@types/jest': specifier: ^29.5.12 version: 29.5.14 '@types/node': specifier: latest - version: 25.0.9 + version: 25.6.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@25.0.9)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3)) + version: 29.7.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3)) typescript: specifier: latest - version: 5.9.3 + version: 6.0.3 xrpl: specifier: 3.0.0 version: 3.0.0(bufferutil@4.0.5)(encoding@0.1.13)(utf-8-validate@5.0.7) @@ -706,10 +715,10 @@ importers: version: link:../../core '@nomiclabs/hardhat-ethers': specifier: ^2.2.2 - version: 2.2.3(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)) + version: 2.2.3(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)) '@nomiclabs/hardhat-waffle': specifier: ^2.0.3 - version: 2.0.6(@nomiclabs/hardhat-ethers@2.2.3(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)))(@types/sinon-chai@3.2.12)(ethereum-waffle@4.0.10(@ensdomains/ens@0.4.5)(@ensdomains/resolver@0.2.4)(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.8.0(bufferutil@4.0.5)(utf-8-validate@5.0.7))(encoding@0.1.13)(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typescript@5.9.3))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)) + version: 2.0.6(@nomiclabs/hardhat-ethers@2.2.3(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)))(@types/sinon-chai@3.2.12)(ethereum-waffle@4.0.10(@ensdomains/ens@0.4.5)(@ensdomains/resolver@0.2.4)(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.8.0(bufferutil@4.0.5)(utf-8-validate@5.0.7))(encoding@0.1.13)(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typescript@6.0.3))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)) '@shared/eslint': specifier: workspace:* version: link:../../shared/eslint @@ -730,7 +739,7 @@ importers: version: 4.5.0 hardhat: specifier: ^2.12.7 - version: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7) + version: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7) packages/testing/mocha: dependencies: @@ -2676,8 +2685,8 @@ packages: '@types/node@24.10.14': resolution: {integrity: sha512-OowOUbD1lBCOFIPOZ8xnMIhgqA4sCutMiYOmPHL1PTLt5+y1XA+g2+yC9OOyz8p+deMZqPZLxfMjYIfrKsPeFg==} - '@types/node@25.0.9': - resolution: {integrity: sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw==} + '@types/node@25.6.0': + resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} '@types/node@8.10.66': resolution: {integrity: sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==} @@ -5082,29 +5091,31 @@ packages: glob@10.4.5: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@11.0.1: resolution: {integrity: sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==} engines: {node: 20 || >=22} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@5.0.15: resolution: {integrity: sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me glob@7.1.7: resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me glob@8.1.0: resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} engines: {node: '>=12'} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me global-modules@2.0.0: resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} @@ -7814,6 +7825,7 @@ packages: tar@4.4.19: resolution: {integrity: sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==} engines: {node: '>=4.5'} + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me test-exclude@6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} @@ -7822,6 +7834,7 @@ packages: test-value@2.1.0: resolution: {integrity: sha512-+1epbAxtKeXttkGFMTX9H42oqzOTufR1ceCF+GYA5aOmvaPq9wd4PUS8329fn2RRLGNeUkgRLnVpycjx8DsO2w==} engines: {node: '>=0.10.0'} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. testrpc@0.0.1: resolution: {integrity: sha512-afH1hO+SQ/VPlmaLUFj2636QMeDvPCeQMc/9RBMW0IfjNe9gFD9Ra3ShqYkB7py0do1ZcCna/9acHyzTJ+GcNA==} @@ -8155,6 +8168,11 @@ packages: engines: {node: '>=14.17'} hasBin: true + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} + engines: {node: '>=14.17'} + hasBin: true + typewise-core@1.2.0: resolution: {integrity: sha512-2SCC/WLzj2SbUwzFOzqMCkz5amXLlxtJqDKTICqg30x+2DZxcfZN2MvQZmGfXWKNWaKK9pBPsvkcwv8bF/gxKg==} @@ -8202,6 +8220,9 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + undici-types@7.19.2: + resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} + undici@5.28.5: resolution: {integrity: sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==} engines: {node: '>=14.0'} @@ -8703,11 +8724,11 @@ snapshots: optionalDependencies: graphql: 16.11.0 - '@0no-co/graphqlsp@1.12.16(graphql@16.11.0)(typescript@5.9.3)': + '@0no-co/graphqlsp@1.12.16(graphql@16.11.0)(typescript@6.0.3)': dependencies: - '@gql.tada/internal': 1.0.8(graphql@16.11.0)(typescript@5.9.3) + '@gql.tada/internal': 1.0.8(graphql@16.11.0)(typescript@6.0.3) graphql: 16.11.0 - typescript: 5.9.3 + typescript: 6.0.3 '@adraffy/ens-normalize@1.10.1': {} @@ -9065,7 +9086,7 @@ snapshots: '@axelar-network/axelar-gmp-sdk-solidity@5.10.0': {} - '@axelar-network/axelarjs-sdk@https://codeload.github.com/banasa44/axelarjs-sdk/tar.gz/f55f46a6ae4d77477c87e2f4720a680bec7c5b34(bufferutil@4.0.5)(encoding@0.1.13)(typescript@5.9.3)(utf-8-validate@5.0.7)': + '@axelar-network/axelarjs-sdk@https://codeload.github.com/banasa44/axelarjs-sdk/tar.gz/f55f46a6ae4d77477c87e2f4720a680bec7c5b34(bufferutil@4.0.5)(encoding@0.1.13)(typescript@6.0.3)(utf-8-validate@5.0.7)': dependencies: '@axelar-network/axelar-cgp-solidity': 6.4.0 '@axelar-network/axelarjs-types': 0.33.0 @@ -9074,7 +9095,7 @@ snapshots: '@ethersproject/abstract-provider': 5.8.0 '@ethersproject/networks': 5.8.0 '@ethersproject/providers': 5.8.0(bufferutil@4.0.5)(utf-8-validate@5.0.7) - '@mysten/sui': 1.29.1(typescript@5.9.3) + '@mysten/sui': 1.29.1(typescript@6.0.3) '@stellar/stellar-sdk': 13.3.0 '@types/uuid': 8.3.4 bech32: 2.0.0 @@ -9657,18 +9678,18 @@ snapshots: - typescript - utf-8-validate - '@ethereum-waffle/compiler@4.0.3(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.8.0(bufferutil@4.0.5)(utf-8-validate@5.0.7))(encoding@0.1.13)(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(solc@0.8.15)(typechain@8.3.2(typescript@5.9.3))(typescript@5.9.3)': + '@ethereum-waffle/compiler@4.0.3(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.8.0(bufferutil@4.0.5)(utf-8-validate@5.0.7))(encoding@0.1.13)(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(solc@0.8.15)(typechain@8.3.2(typescript@6.0.3))(typescript@6.0.3)': dependencies: '@resolver-engine/imports': 0.3.3 '@resolver-engine/imports-fs': 0.3.3 - '@typechain/ethers-v5': 10.2.1(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.8.0(bufferutil@4.0.5)(utf-8-validate@5.0.7))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@5.9.3))(typescript@5.9.3) + '@typechain/ethers-v5': 10.2.1(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.8.0(bufferutil@4.0.5)(utf-8-validate@5.0.7))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@6.0.3))(typescript@6.0.3) '@types/mkdirp': 0.5.2 '@types/node-fetch': 2.6.12 ethers: 6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7) mkdirp: 0.5.6 node-fetch: 2.7.0(encoding@0.1.13) solc: 0.8.15 - typechain: 8.3.2(typescript@5.9.3) + typechain: 8.3.2(typescript@6.0.3) transitivePeerDependencies: - '@ethersproject/abi' - '@ethersproject/providers' @@ -10280,18 +10301,18 @@ snapshots: optionalDependencies: '@trufflesuite/bigint-buffer': 1.1.9 - '@gql.tada/cli-utils@1.6.3(@0no-co/graphqlsp@1.12.16(graphql@16.11.0)(typescript@5.9.3))(graphql@16.11.0)(typescript@5.9.3)': + '@gql.tada/cli-utils@1.6.3(@0no-co/graphqlsp@1.12.16(graphql@16.11.0)(typescript@6.0.3))(graphql@16.11.0)(typescript@6.0.3)': dependencies: - '@0no-co/graphqlsp': 1.12.16(graphql@16.11.0)(typescript@5.9.3) - '@gql.tada/internal': 1.0.8(graphql@16.11.0)(typescript@5.9.3) + '@0no-co/graphqlsp': 1.12.16(graphql@16.11.0)(typescript@6.0.3) + '@gql.tada/internal': 1.0.8(graphql@16.11.0)(typescript@6.0.3) graphql: 16.11.0 - typescript: 5.9.3 + typescript: 6.0.3 - '@gql.tada/internal@1.0.8(graphql@16.11.0)(typescript@5.9.3)': + '@gql.tada/internal@1.0.8(graphql@16.11.0)(typescript@6.0.3)': dependencies: '@0no-co/graphql.web': 1.1.2(graphql@16.11.0) graphql: 16.11.0 - typescript: 5.9.3 + typescript: 6.0.3 '@graphql-typed-document-node/core@3.2.0(graphql@16.11.0)': dependencies: @@ -10372,7 +10393,42 @@ snapshots: - supports-color - ts-node - '@jest/core@29.7.0(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))': + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@20.19.25)(typescript@6.0.3))': + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.19.25 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@6.0.3)) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -10386,7 +10442,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3)) + jest-config: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -10568,7 +10624,7 @@ snapshots: '@mysten/utils': 0.0.0 '@scure/base': 1.2.4 - '@mysten/sui@1.29.1(typescript@5.9.3)': + '@mysten/sui@1.29.1(typescript@6.0.3)': dependencies: '@graphql-typed-document-node/core': 3.2.0(graphql@16.11.0) '@mysten/bcs': 1.6.1 @@ -10578,7 +10634,7 @@ snapshots: '@scure/base': 1.2.4 '@scure/bip32': 1.6.2 '@scure/bip39': 1.5.4 - gql.tada: 1.8.10(graphql@16.11.0)(typescript@5.9.3) + gql.tada: 1.8.10(graphql@16.11.0)(typescript@6.0.3) graphql: 16.11.0 poseidon-lite: 0.2.1 valibot: 0.36.0 @@ -10671,43 +10727,43 @@ snapshots: '@nomicfoundation/ethereumjs-rlp': 5.0.4 ethereum-cryptography: 0.1.3 - '@nomicfoundation/hardhat-chai-matchers@2.0.8(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)))(chai@4.5.0)(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7))': + '@nomicfoundation/hardhat-chai-matchers@2.0.8(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)))(chai@4.5.0)(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7))': dependencies: - '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)) + '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)) '@types/chai-as-promised': 7.1.8 chai: 4.5.0 chai-as-promised: 7.1.2(chai@4.5.0) deep-eql: 4.1.4 ethers: 6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7) - hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7) ordinal: 1.0.3 - '@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7))': + '@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7))': dependencies: debug: 4.4.0(supports-color@8.1.1) ethers: 6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7) - hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7) lodash.isequal: 4.5.0 transitivePeerDependencies: - supports-color - '@nomicfoundation/hardhat-ignition-ethers@0.15.9(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)))(@nomicfoundation/hardhat-ignition@0.15.9(@nomicfoundation/hardhat-verify@2.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)))(bufferutil@4.0.5)(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7))(utf-8-validate@5.0.7))(@nomicfoundation/ignition-core@0.15.9(bufferutil@4.0.5)(utf-8-validate@5.0.7))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7))': + '@nomicfoundation/hardhat-ignition-ethers@0.15.9(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)))(@nomicfoundation/hardhat-ignition@0.15.9(@nomicfoundation/hardhat-verify@2.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)))(bufferutil@4.0.5)(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7))(utf-8-validate@5.0.7))(@nomicfoundation/ignition-core@0.15.9(bufferutil@4.0.5)(utf-8-validate@5.0.7))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7))': dependencies: - '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)) - '@nomicfoundation/hardhat-ignition': 0.15.9(@nomicfoundation/hardhat-verify@2.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)))(bufferutil@4.0.5)(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7))(utf-8-validate@5.0.7) + '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)) + '@nomicfoundation/hardhat-ignition': 0.15.9(@nomicfoundation/hardhat-verify@2.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)))(bufferutil@4.0.5)(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7))(utf-8-validate@5.0.7) '@nomicfoundation/ignition-core': 0.15.9(bufferutil@4.0.5)(utf-8-validate@5.0.7) ethers: 6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7) - hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7) - '@nomicfoundation/hardhat-ignition@0.15.9(@nomicfoundation/hardhat-verify@2.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)))(bufferutil@4.0.5)(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7))(utf-8-validate@5.0.7)': + '@nomicfoundation/hardhat-ignition@0.15.9(@nomicfoundation/hardhat-verify@2.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)))(bufferutil@4.0.5)(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7))(utf-8-validate@5.0.7)': dependencies: - '@nomicfoundation/hardhat-verify': 2.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)) + '@nomicfoundation/hardhat-verify': 2.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)) '@nomicfoundation/ignition-core': 0.15.9(bufferutil@4.0.5)(utf-8-validate@5.0.7) '@nomicfoundation/ignition-ui': 0.15.9 chalk: 4.1.2 debug: 4.4.0(supports-color@8.1.1) fs-extra: 10.1.0 - hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7) json5: 2.2.3 prompts: 2.4.2 transitivePeerDependencies: @@ -10720,39 +10776,39 @@ snapshots: ethereumjs-util: 7.1.5 hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7) - '@nomicfoundation/hardhat-network-helpers@1.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7))': + '@nomicfoundation/hardhat-network-helpers@1.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7))': dependencies: ethereumjs-util: 7.1.5 - hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7) - '@nomicfoundation/hardhat-toolbox@5.0.0(6qv3amog762zhvysfqmmoxayvu)': + '@nomicfoundation/hardhat-toolbox@5.0.0(7idygwlwsesd5erfftcdwsdmae)': dependencies: - '@nomicfoundation/hardhat-chai-matchers': 2.0.8(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)))(chai@4.5.0)(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)) - '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)) - '@nomicfoundation/hardhat-ignition-ethers': 0.15.9(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)))(@nomicfoundation/hardhat-ignition@0.15.9(@nomicfoundation/hardhat-verify@2.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)))(bufferutil@4.0.5)(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7))(utf-8-validate@5.0.7))(@nomicfoundation/ignition-core@0.15.9(bufferutil@4.0.5)(utf-8-validate@5.0.7))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)) - '@nomicfoundation/hardhat-network-helpers': 1.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)) - '@nomicfoundation/hardhat-verify': 2.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)) - '@typechain/ethers-v6': 0.5.1(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@5.9.3))(typescript@5.9.3) - '@typechain/hardhat': 9.1.0(@typechain/ethers-v6@0.5.1(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@5.9.3))(typescript@5.9.3))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@5.9.3)) + '@nomicfoundation/hardhat-chai-matchers': 2.0.8(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)))(chai@4.5.0)(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)) + '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)) + '@nomicfoundation/hardhat-ignition-ethers': 0.15.9(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)))(@nomicfoundation/hardhat-ignition@0.15.9(@nomicfoundation/hardhat-verify@2.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)))(bufferutil@4.0.5)(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7))(utf-8-validate@5.0.7))(@nomicfoundation/ignition-core@0.15.9(bufferutil@4.0.5)(utf-8-validate@5.0.7))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)) + '@nomicfoundation/hardhat-network-helpers': 1.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)) + '@nomicfoundation/hardhat-verify': 2.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)) + '@typechain/ethers-v6': 0.5.1(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@6.0.3))(typescript@6.0.3) + '@typechain/hardhat': 9.1.0(@typechain/ethers-v6@0.5.1(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@6.0.3))(typescript@6.0.3))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@6.0.3)) '@types/chai': 5.0.1 '@types/mocha': 10.0.10 - '@types/node': 25.0.9 + '@types/node': 25.6.0 chai: 4.5.0 ethers: 6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7) - hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7) - hardhat-gas-reporter: 1.0.10(bufferutil@4.0.5)(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7))(utf-8-validate@5.0.7) - solidity-coverage: 0.8.14(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)) - ts-node: 10.9.2(@types/node@25.0.9)(typescript@5.9.3) - typechain: 8.3.2(typescript@5.9.3) - typescript: 5.9.3 + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7) + hardhat-gas-reporter: 1.0.10(bufferutil@4.0.5)(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7))(utf-8-validate@5.0.7) + solidity-coverage: 0.8.14(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)) + ts-node: 10.9.2(@types/node@25.6.0)(typescript@6.0.3) + typechain: 8.3.2(typescript@6.0.3) + typescript: 6.0.3 - '@nomicfoundation/hardhat-verify@2.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7))': + '@nomicfoundation/hardhat-verify@2.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7))': dependencies: '@ethersproject/abi': 5.7.0 '@ethersproject/address': 5.8.0 cbor: 8.1.0 debug: 4.4.0(supports-color@8.1.1) - hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7) lodash.clonedeep: 4.5.0 picocolors: 1.1.1 semver: 6.3.1 @@ -10815,10 +10871,10 @@ snapshots: ethers: 5.7.2(bufferutil@4.0.5)(utf-8-validate@5.0.7) hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7) - '@nomiclabs/hardhat-ethers@2.2.3(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7))': + '@nomiclabs/hardhat-ethers@2.2.3(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7))': dependencies: ethers: 6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7) - hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7) '@nomiclabs/hardhat-etherscan@3.1.8(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7))': dependencies: @@ -10845,13 +10901,13 @@ snapshots: ethers: 5.7.2(bufferutil@4.0.5)(utf-8-validate@5.0.7) hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7) - '@nomiclabs/hardhat-waffle@2.0.6(@nomiclabs/hardhat-ethers@2.2.3(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)))(@types/sinon-chai@3.2.12)(ethereum-waffle@4.0.10(@ensdomains/ens@0.4.5)(@ensdomains/resolver@0.2.4)(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.8.0(bufferutil@4.0.5)(utf-8-validate@5.0.7))(encoding@0.1.13)(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typescript@5.9.3))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7))': + '@nomiclabs/hardhat-waffle@2.0.6(@nomiclabs/hardhat-ethers@2.2.3(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)))(@types/sinon-chai@3.2.12)(ethereum-waffle@4.0.10(@ensdomains/ens@0.4.5)(@ensdomains/resolver@0.2.4)(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.8.0(bufferutil@4.0.5)(utf-8-validate@5.0.7))(encoding@0.1.13)(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typescript@6.0.3))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7))': dependencies: - '@nomiclabs/hardhat-ethers': 2.2.3(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)) + '@nomiclabs/hardhat-ethers': 2.2.3(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)) '@types/sinon-chai': 3.2.12 - ethereum-waffle: 4.0.10(@ensdomains/ens@0.4.5)(@ensdomains/resolver@0.2.4)(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.8.0(bufferutil@4.0.5)(utf-8-validate@5.0.7))(encoding@0.1.13)(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typescript@5.9.3) + ethereum-waffle: 4.0.10(@ensdomains/ens@0.4.5)(@ensdomains/resolver@0.2.4)(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.8.0(bufferutil@4.0.5)(utf-8-validate@5.0.7))(encoding@0.1.13)(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typescript@6.0.3) ethers: 6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7) - hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7) '@openzeppelin/contracts@4.9.6': {} @@ -11386,9 +11442,9 @@ snapshots: dependencies: typescript: 5.9.3 - '@swisstype/essential@0.1.2(typescript@5.9.3)': + '@swisstype/essential@0.1.2(typescript@6.0.3)': dependencies: - typescript: 5.9.3 + typescript: 6.0.3 '@swisstype/string@0.0.4(@swisstype/essential@0.0.5(typescript@5.9.3))(typescript@5.9.3)': dependencies: @@ -11425,15 +11481,15 @@ snapshots: '@tsconfig/node16@1.0.4': {} - '@typechain/ethers-v5@10.2.1(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.8.0(bufferutil@4.0.5)(utf-8-validate@5.0.7))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@5.9.3))(typescript@5.9.3)': + '@typechain/ethers-v5@10.2.1(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.8.0(bufferutil@4.0.5)(utf-8-validate@5.0.7))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@6.0.3))(typescript@6.0.3)': dependencies: '@ethersproject/abi': 5.7.0 '@ethersproject/providers': 5.8.0(bufferutil@4.0.5)(utf-8-validate@5.0.7) ethers: 6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7) lodash: 4.17.21 - ts-essentials: 7.0.3(typescript@5.9.3) - typechain: 8.3.2(typescript@5.9.3) - typescript: 5.9.3 + ts-essentials: 7.0.3(typescript@6.0.3) + typechain: 8.3.2(typescript@6.0.3) + typescript: 6.0.3 '@typechain/ethers-v5@11.1.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.5)(utf-8-validate@5.0.7))(ethers@5.7.2(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@5.9.3))(typescript@5.9.3)': dependencies: @@ -11450,13 +11506,13 @@ snapshots: ethers: 5.7.2(bufferutil@4.0.5)(utf-8-validate@5.0.7) typechain: 3.0.0(typescript@5.9.3) - '@typechain/ethers-v6@0.5.1(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@5.9.3))(typescript@5.9.3)': + '@typechain/ethers-v6@0.5.1(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@6.0.3))(typescript@6.0.3)': dependencies: ethers: 6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7) lodash: 4.17.21 - ts-essentials: 7.0.3(typescript@5.9.3) - typechain: 8.3.2(typescript@5.9.3) - typescript: 5.9.3 + ts-essentials: 7.0.3(typescript@6.0.3) + typechain: 8.3.2(typescript@6.0.3) + typescript: 6.0.3 '@typechain/hardhat@7.0.0(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.5)(utf-8-validate@5.0.7))(@typechain/ethers-v5@11.1.2(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2(bufferutil@4.0.5)(utf-8-validate@5.0.7))(ethers@5.7.2(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@5.9.3))(typescript@5.9.3))(ethers@5.7.2(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@5.9.3))': dependencies: @@ -11468,13 +11524,13 @@ snapshots: hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7) typechain: 8.3.2(typescript@5.9.3) - '@typechain/hardhat@9.1.0(@typechain/ethers-v6@0.5.1(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@5.9.3))(typescript@5.9.3))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@5.9.3))': + '@typechain/hardhat@9.1.0(@typechain/ethers-v6@0.5.1(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@6.0.3))(typescript@6.0.3))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@6.0.3))': dependencies: - '@typechain/ethers-v6': 0.5.1(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@5.9.3))(typescript@5.9.3) + '@typechain/ethers-v6': 0.5.1(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@6.0.3))(typescript@6.0.3) ethers: 6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7) fs-extra: 9.1.0 - hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7) - typechain: 8.3.2(typescript@5.9.3) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7) + typechain: 8.3.2(typescript@6.0.3) '@types/abstract-leveldown@7.2.5': {} @@ -11627,9 +11683,9 @@ snapshots: dependencies: undici-types: 7.16.0 - '@types/node@25.0.9': + '@types/node@25.6.0': dependencies: - undici-types: 7.16.0 + undici-types: 7.19.2 '@types/node@8.10.66': {} @@ -11706,20 +11762,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@8.24.1(@typescript-eslint/parser@8.24.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.24.1(@typescript-eslint/parser@8.24.1(eslint@8.57.1)(typescript@6.0.3))(eslint@8.57.1)(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.24.1(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/parser': 8.24.1(eslint@8.57.1)(typescript@6.0.3) '@typescript-eslint/scope-manager': 8.24.1 - '@typescript-eslint/type-utils': 8.24.1(eslint@8.57.1)(typescript@5.9.3) - '@typescript-eslint/utils': 8.24.1(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/type-utils': 8.24.1(eslint@8.57.1)(typescript@6.0.3) + '@typescript-eslint/utils': 8.24.1(eslint@8.57.1)(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.24.1 eslint: 8.57.1 graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 - ts-api-utils: 2.0.1(typescript@5.9.3) - typescript: 5.9.3 + ts-api-utils: 2.0.1(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -11736,15 +11792,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.24.1(eslint@8.57.1)(typescript@5.9.3)': + '@typescript-eslint/parser@8.24.1(eslint@8.57.1)(typescript@6.0.3)': dependencies: '@typescript-eslint/scope-manager': 8.24.1 '@typescript-eslint/types': 8.24.1 - '@typescript-eslint/typescript-estree': 8.24.1(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.24.1(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.24.1 debug: 4.4.0(supports-color@8.1.1) eslint: 8.57.1 - typescript: 5.9.3 + typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -11770,14 +11826,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.24.1(eslint@8.57.1)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.24.1(eslint@8.57.1)(typescript@6.0.3)': dependencies: - '@typescript-eslint/typescript-estree': 8.24.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.24.1(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.24.1(typescript@6.0.3) + '@typescript-eslint/utils': 8.24.1(eslint@8.57.1)(typescript@6.0.3) debug: 4.4.0(supports-color@8.1.1) eslint: 8.57.1 - ts-api-utils: 2.0.1(typescript@5.9.3) - typescript: 5.9.3 + ts-api-utils: 2.0.1(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -11800,7 +11856,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.24.1(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.24.1(typescript@6.0.3)': dependencies: '@typescript-eslint/types': 8.24.1 '@typescript-eslint/visitor-keys': 8.24.1 @@ -11809,8 +11865,8 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.5 semver: 7.7.1 - ts-api-utils: 2.0.1(typescript@5.9.3) - typescript: 5.9.3 + ts-api-utils: 2.0.1(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -11828,14 +11884,14 @@ snapshots: - supports-color - typescript - '@typescript-eslint/utils@8.24.1(eslint@8.57.1)(typescript@5.9.3)': + '@typescript-eslint/utils@8.24.1(eslint@8.57.1)(typescript@6.0.3)': dependencies: '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) '@typescript-eslint/scope-manager': 8.24.1 '@typescript-eslint/types': 8.24.1 - '@typescript-eslint/typescript-estree': 8.24.1(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.24.1(typescript@6.0.3) eslint: 8.57.1 - typescript: 5.9.3 + typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -13358,13 +13414,28 @@ snapshots: - supports-color - ts-node - create-jest@29.7.0(@types/node@25.0.9)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3)): + create-jest@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@6.0.3)): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@6.0.3)) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + create-jest@29.7.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@25.0.9)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3)) + jest-config: 29.7.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -13943,7 +14014,7 @@ snapshots: stable-hash: 0.0.4 tinyglobby: 0.2.11 optionalDependencies: - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@8.24.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.8.2)(eslint@8.57.1) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@8.24.1(eslint@8.57.1)(typescript@6.0.3))(eslint-import-resolver-typescript@3.8.2)(eslint@8.57.1) transitivePeerDependencies: - supports-color @@ -13957,11 +14028,11 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.24.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.2(eslint-plugin-import@2.29.1)(eslint@8.57.1))(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.24.1(eslint@8.57.1)(typescript@6.0.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.2(eslint-plugin-import@2.29.1)(eslint@8.57.1))(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.24.1(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/parser': 8.24.1(eslint@8.57.1)(typescript@6.0.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.8.2(eslint-plugin-import@2.29.1)(eslint@8.57.1) @@ -14008,7 +14079,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@8.24.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-typescript@3.8.2)(eslint@8.57.1): + eslint-plugin-import@2.29.1(@typescript-eslint/parser@8.24.1(eslint@8.57.1)(typescript@6.0.3))(eslint-import-resolver-typescript@3.8.2)(eslint@8.57.1): dependencies: array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 @@ -14018,7 +14089,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.24.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.2(eslint-plugin-import@2.29.1)(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.24.1(eslint@8.57.1)(typescript@6.0.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.2(eslint-plugin-import@2.29.1)(eslint@8.57.1))(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -14029,7 +14100,7 @@ snapshots: semver: 6.3.1 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.24.1(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/parser': 8.24.1(eslint@8.57.1)(typescript@6.0.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -14402,15 +14473,15 @@ snapshots: - typescript - utf-8-validate - ethereum-waffle@4.0.10(@ensdomains/ens@0.4.5)(@ensdomains/resolver@0.2.4)(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.8.0(bufferutil@4.0.5)(utf-8-validate@5.0.7))(encoding@0.1.13)(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typescript@5.9.3): + ethereum-waffle@4.0.10(@ensdomains/ens@0.4.5)(@ensdomains/resolver@0.2.4)(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.8.0(bufferutil@4.0.5)(utf-8-validate@5.0.7))(encoding@0.1.13)(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typescript@6.0.3): dependencies: '@ethereum-waffle/chai': 4.0.10(@ensdomains/ens@0.4.5)(@ensdomains/resolver@0.2.4)(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7)) - '@ethereum-waffle/compiler': 4.0.3(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.8.0(bufferutil@4.0.5)(utf-8-validate@5.0.7))(encoding@0.1.13)(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(solc@0.8.15)(typechain@8.3.2(typescript@5.9.3))(typescript@5.9.3) + '@ethereum-waffle/compiler': 4.0.3(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.8.0(bufferutil@4.0.5)(utf-8-validate@5.0.7))(encoding@0.1.13)(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(solc@0.8.15)(typechain@8.3.2(typescript@6.0.3))(typescript@6.0.3) '@ethereum-waffle/mock-contract': 4.0.4(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7)) '@ethereum-waffle/provider': 4.0.5(@ensdomains/ens@0.4.5)(@ensdomains/resolver@0.2.4)(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7)) ethers: 6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7) solc: 0.8.15 - typechain: 8.3.2(typescript@5.9.3) + typechain: 8.3.2(typescript@6.0.3) transitivePeerDependencies: - '@ensdomains/ens' - '@ensdomains/resolver' @@ -15267,13 +15338,13 @@ snapshots: url-parse-lax: 3.0.0 optional: true - gql.tada@1.8.10(graphql@16.11.0)(typescript@5.9.3): + gql.tada@1.8.10(graphql@16.11.0)(typescript@6.0.3): dependencies: '@0no-co/graphql.web': 1.1.2(graphql@16.11.0) - '@0no-co/graphqlsp': 1.12.16(graphql@16.11.0)(typescript@5.9.3) - '@gql.tada/cli-utils': 1.6.3(@0no-co/graphqlsp@1.12.16(graphql@16.11.0)(typescript@5.9.3))(graphql@16.11.0)(typescript@5.9.3) - '@gql.tada/internal': 1.0.8(graphql@16.11.0)(typescript@5.9.3) - typescript: 5.9.3 + '@0no-co/graphqlsp': 1.12.16(graphql@16.11.0)(typescript@6.0.3) + '@gql.tada/cli-utils': 1.6.3(@0no-co/graphqlsp@1.12.16(graphql@16.11.0)(typescript@6.0.3))(graphql@16.11.0)(typescript@6.0.3) + '@gql.tada/internal': 1.0.8(graphql@16.11.0)(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - '@gql.tada/svelte-support' - '@gql.tada/vue-support' @@ -15301,11 +15372,11 @@ snapshots: ajv: 6.12.6 har-schema: 2.0.0 - hardhat-gas-reporter@1.0.10(bufferutil@4.0.5)(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7))(utf-8-validate@5.0.7): + hardhat-gas-reporter@1.0.10(bufferutil@4.0.5)(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7))(utf-8-validate@5.0.7): dependencies: array-uniq: 1.0.3 eth-gas-reporter: 0.2.27(bufferutil@4.0.5)(utf-8-validate@5.0.7) - hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7) sha1: 1.1.1 transitivePeerDependencies: - '@codechecks/client' @@ -15368,7 +15439,7 @@ snapshots: - supports-color - utf-8-validate - hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7): + hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7): dependencies: '@ethersproject/abi': 5.7.0 '@metamask/eth-sig-util': 4.0.1 @@ -15415,8 +15486,8 @@ snapshots: uuid: 8.3.2 ws: 7.5.10(bufferutil@4.0.5)(utf-8-validate@5.0.7) optionalDependencies: - ts-node: 10.9.2(@types/node@25.0.9)(typescript@5.9.3) - typescript: 5.9.3 + ts-node: 10.9.2(@types/node@25.6.0)(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - bufferutil - c-kzg @@ -15982,16 +16053,35 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@25.0.9)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3)): + jest-cli@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@6.0.3)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.19.25)(typescript@6.0.3)) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@6.0.3)) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@6.0.3)) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + jest-cli@29.7.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@25.0.9)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3)) + create-jest: 29.7.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@25.0.9)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3)) + jest-config: 29.7.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -16032,7 +16122,38 @@ snapshots: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3)): + jest-config@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@6.0.3)): + dependencies: + '@babel/core': 7.26.9 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.26.9) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 20.19.25 + ts-node: 10.9.2(@types/node@20.19.25)(typescript@6.0.3) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-config@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3)): dependencies: '@babel/core': 7.26.9 '@jest/test-sequencer': 29.7.0 @@ -16058,12 +16179,12 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 20.19.25 - ts-node: 10.9.2(@types/node@25.0.9)(typescript@5.9.3) + ts-node: 10.9.2(@types/node@25.6.0)(typescript@6.0.3) transitivePeerDependencies: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@25.0.9)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3)): + jest-config@29.7.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3)): dependencies: '@babel/core': 7.26.9 '@jest/test-sequencer': 29.7.0 @@ -16088,8 +16209,8 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 25.0.9 - ts-node: 10.9.2(@types/node@25.0.9)(typescript@5.9.3) + '@types/node': 25.6.0 + ts-node: 10.9.2(@types/node@25.6.0)(typescript@6.0.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -16321,12 +16442,24 @@ snapshots: - supports-color - ts-node - jest@29.7.0(@types/node@25.0.9)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3)): + jest@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@6.0.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.19.25)(typescript@6.0.3)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@25.0.9)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3)) + jest-cli: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@6.0.3)) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + jest@29.7.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3)) + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@25.6.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -18404,7 +18537,7 @@ snapshots: shelljs: 0.8.5 web3-utils: 1.10.4 - solidity-coverage@0.8.14(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7)): + solidity-coverage@0.8.14(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7)): dependencies: '@ethersproject/abi': 5.7.0 '@solidity-parser/parser': 0.19.0 @@ -18415,7 +18548,7 @@ snapshots: ghost-testrpc: 0.0.2 global-modules: 2.0.0 globby: 10.0.2 - hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3))(typescript@5.9.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3))(typescript@6.0.3)(utf-8-validate@5.0.7) jsonschema: 1.5.0 lodash: 4.17.21 mocha: 10.8.2 @@ -18903,9 +19036,9 @@ snapshots: dependencies: typescript: 5.9.3 - ts-api-utils@2.0.1(typescript@5.9.3): + ts-api-utils@2.0.1(typescript@6.0.3): dependencies: - typescript: 5.9.3 + typescript: 6.0.3 ts-command-line-args@2.5.1: dependencies: @@ -18924,6 +19057,10 @@ snapshots: dependencies: typescript: 5.9.3 + ts-essentials@7.0.3(typescript@6.0.3): + dependencies: + typescript: 6.0.3 + ts-generator@0.1.1: dependencies: '@types/mkdirp': 0.5.2 @@ -18958,6 +19095,26 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.26.9) esbuild: 0.24.2 + ts-jest@29.2.5(@babel/core@7.26.9)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.9))(esbuild@0.24.2)(jest@29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@6.0.3)))(typescript@6.0.3): + dependencies: + bs-logger: 0.2.6 + ejs: 3.1.10 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@6.0.3)) + jest-util: 29.7.0 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.7.1 + typescript: 6.0.3 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.26.9 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.26.9) + esbuild: 0.24.2 + ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -18976,21 +19133,40 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3): + ts-node@10.9.2(@types/node@20.19.25)(typescript@6.0.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 25.0.9 + '@types/node': 20.19.25 acorn: 8.14.0 acorn-walk: 8.3.4 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.9.3 + typescript: 6.0.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optional: true + + ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 25.6.0 + acorn: 8.14.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 6.0.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 @@ -19009,7 +19185,7 @@ snapshots: tsort@0.0.1: {} - tsup@8.3.6(typescript@5.9.3): + tsup@8.3.6(typescript@6.0.3): dependencies: bundle-require: 5.1.0(esbuild@0.24.2) cac: 6.7.14 @@ -19028,7 +19204,7 @@ snapshots: tinyglobby: 0.2.11 tree-kill: 1.2.2 optionalDependencies: - typescript: 5.9.3 + typescript: 6.0.3 transitivePeerDependencies: - jiti - supports-color @@ -19127,6 +19303,22 @@ snapshots: transitivePeerDependencies: - supports-color + typechain@8.3.2(typescript@6.0.3): + dependencies: + '@types/prettier': 2.7.3 + debug: 4.4.0(supports-color@8.1.1) + fs-extra: 7.0.1 + glob: 7.1.7 + js-sha3: 0.8.0 + lodash: 4.17.21 + mkdirp: 1.0.4 + prettier: 2.8.8 + ts-command-line-args: 2.5.1 + ts-essentials: 7.0.3(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.3 @@ -19170,6 +19362,8 @@ snapshots: typescript@5.9.3: {} + typescript@6.0.3: {} + typewise-core@1.2.0: {} typewise@1.0.3: @@ -19208,6 +19402,8 @@ snapshots: undici-types@7.16.0: {} + undici-types@7.19.2: {} + undici@5.28.5: dependencies: '@fastify/busboy': 2.1.1 From 901780bae5d0ae56acc032576a6c9f2de41abdab Mon Sep 17 00:00:00 2001 From: Kevin Pita Date: Thu, 23 Apr 2026 17:22:22 +0200 Subject: [PATCH 4/4] test(evm): add erc20 multi-minter governance tests --- .../evm/configs/localnet.module.config.json | 13 +- modules/evm/package.json | 3 + .../evm/test/precompiles/erc20/index.test.ts | 3 +- .../precompiles/erc20/multi-minter.test.ts | 207 ++++++++++++++++++ .../test/precompiles/erc20/utils/cosmos.ts | 115 ++++++++++ .../test/precompiles/erc20/utils/helpers.ts | 45 +++- .../test/precompiles/erc20/utils/minters.ts | 92 ++++++++ .../evm/test/precompiles/erc20/utils/proto.ts | 157 +++++++++++++ modules/evm/tsconfig.json | 6 +- 9 files changed, 623 insertions(+), 18 deletions(-) create mode 100644 modules/evm/test/precompiles/erc20/multi-minter.test.ts create mode 100644 modules/evm/test/precompiles/erc20/utils/cosmos.ts create mode 100644 modules/evm/test/precompiles/erc20/utils/minters.ts create mode 100644 modules/evm/test/precompiles/erc20/utils/proto.ts diff --git a/modules/evm/configs/localnet.module.config.json b/modules/evm/configs/localnet.module.config.json index 8192c94..ae9b7e6 100644 --- a/modules/evm/configs/localnet.module.config.json +++ b/modules/evm/configs/localnet.module.config.json @@ -25,8 +25,6 @@ "function burn(uint256 amount) external", "function burn(address account, uint256 amount) external", "function burnFrom(address account, uint256 amount) external", - "function transferOwnership(address newOwner) external", - "function owner() external view returns (address)", "function totalSupply() external view returns (uint256)", "function name() external view returns (string)", "function symbol() external view returns (string)", @@ -72,10 +70,17 @@ } ] }, + "cosmos": { + "rpcUrl": "http://localhost:26657", + "mnemonic": "birth rebuild refuse area aisle language bullet pride place clutch paddle drama", + "denom": "axrp", + "prefix": "ethm", + "govModuleAddress": "ethm10d07y265gmmuvt4z0w9aw880jnsr700jpva843" + }, "chain": { "id": "xrplevm_localnet", "name": "xrplevm_localnet", - "chainId": 100, + "chainId": 1449999, "env": "localnet", "type": "evm", "symbol": "XRP", @@ -83,4 +88,4 @@ "address": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" } } -} \ No newline at end of file +} diff --git a/modules/evm/package.json b/modules/evm/package.json index 4714919..ec63b3d 100644 --- a/modules/evm/package.json +++ b/modules/evm/package.json @@ -26,7 +26,10 @@ "@testing/mocha": "workspace:*", "@testing/hardhat": "workspace:*", "@firewatch/core": "workspace:*", + "@firewatch/cosmos": "workspace:*", + "@cosmjs/encoding": "^0.33.1", "@types/chai": "^5.0.1", + "cosmjs-types": "^0.9.0", "dotenv": "^16.4.7" } } diff --git a/modules/evm/test/precompiles/erc20/index.test.ts b/modules/evm/test/precompiles/erc20/index.test.ts index bd7f90d..4e46837 100644 --- a/modules/evm/test/precompiles/erc20/index.test.ts +++ b/modules/evm/test/precompiles/erc20/index.test.ts @@ -25,7 +25,6 @@ import { describeOrSkip } from "@testing/mocha/utils"; * - transferFrom(owner, to, amount) — the spender exercises the allowance, moving tokens from owner to to * Token exchange functionalities: * - transfer(to, amount) — the owner transfers tokens to another account - * - transferOwnership(newOwner) — the owner transfers ownership to a new account * Token query functionalities: * - balanceOf(account) — returns the balance of an account * Token creation/destruction functionalities: @@ -51,7 +50,7 @@ describe("ERC20", () => { const chain = moduleConfig.chain; // Notice: user is acting as a faucet, providing the owner with enough tokens - // to cover transaction fees and execute mint, burn, and transferOwnership (just in localnet) tests. + // to cover transaction fees and execute mint and burn tests. before(async () => { abi = erc20.abi; contractInterface = new Interface(erc20.abi); diff --git a/modules/evm/test/precompiles/erc20/multi-minter.test.ts b/modules/evm/test/precompiles/erc20/multi-minter.test.ts new file mode 100644 index 0000000..fadf6e7 --- /dev/null +++ b/modules/evm/test/precompiles/erc20/multi-minter.test.ts @@ -0,0 +1,207 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import { Contract, toBigInt } from "ethers"; +import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; +import { executeTx, expectRevert } from "@testing/hardhat/utils"; +import { describeOrSkip } from "@testing/mocha/utils"; +import { isChainEnvironment } from "@testing/mocha/assertions"; +import { ERC20Errors } from "../../../src/precompiles/erc20/errors/errors"; +import moduleConfig from "../../../module.config.json"; +import { Chain } from "@firewatch/core/chain"; +import { ProposalStatus } from "@firewatch/cosmos/gov"; +import { CosmosConfig, expectOwnerAddresses, expectTokenPairOwnerAddresses, getCosmosConfig, hexToBech32 } from "./utils/cosmos"; +import { addMinter, ensureOwnerOnlyMinter, removeMinter } from "./utils/minters"; +import { expectMinterCanMintAndBurn, resetOwnerState } from "./utils/helpers"; + +// Fixed hex for a "bob" address used only to exercise 3-minter set membership via +// governance add/remove. No signer is derived from it - it never submits EVM txs. +const BOB_HEX = "0x1234567890123456789012345678901234567890"; +const UNREGISTERED_DENOM = "nonexistenttoken"; + +describeOrSkip("ERC20 Multi-Minter", isChainEnvironment(["localnet"], moduleConfig.chain as unknown as Chain), () => { + let ownerSigner: HardhatEthersSigner; + let aliceSigner: HardhatEthersSigner; + let contractAsOwner: Contract; + let contractAsAlice: Contract; + + let ownerBech32: string; + let aliceBech32: string; + let bobBech32: string; + let cosmosConfig: CosmosConfig; + + const { erc20 } = moduleConfig.contracts; + const tokenAmount = toBigInt(erc20.amount); + + before(async () => { + [ownerSigner, aliceSigner] = await ethers.getSigners(); + + contractAsOwner = new ethers.Contract(erc20.contractAddress, erc20.abi, ownerSigner); + contractAsAlice = new ethers.Contract(erc20.contractAddress, erc20.abi, aliceSigner); + cosmosConfig = getCosmosConfig(moduleConfig); + ownerBech32 = hexToBech32(cosmosConfig.prefix, ownerSigner.address); + aliceBech32 = hexToBech32(cosmosConfig.prefix, aliceSigner.address); + bobBech32 = hexToBech32(cosmosConfig.prefix, BOB_HEX); + }); + + // Baseline assumes chain genesis registers the erc20 pair with `ownerBech32` (derived + // from hardhat signer[0] via ethermint-style bech32) as the sole minter. If the genesis + // owner changes, the baseline assertion inside ensureOwnerOnlyMinter breaks. + beforeEach(async () => { + await ensureOwnerOnlyMinter(cosmosConfig, erc20.contractAddress, ownerBech32); + }); + + afterEach(async () => { + await resetOwnerState(contractAsOwner, contractAsAlice, ownerSigner, aliceSigner); + }); + + after(async () => { + await ensureOwnerOnlyMinter(cosmosConfig, erc20.contractAddress, ownerBech32); + }); + + describe("Add minter", () => { + it("should add alice by denom, update both queries, and keep owner authorized", async () => { + const { status } = await addMinter(cosmosConfig, cosmosConfig.denom, aliceBech32); + + expect(status).to.equal(ProposalStatus.PROPOSAL_STATUS_PASSED); + await expectOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ownerBech32, aliceBech32]); + + // Alice acts as faucet so the owner can cover gas for its own mint/burn. + await executeTx(contractAsAlice.transfer(ownerSigner.address, erc20.faucetFund)); + await expectMinterCanMintAndBurn(contractAsOwner, contractAsAlice, aliceSigner.address, tokenAmount); + }); + + it("should add alice by contract address, update both queries, and authorize alice", async () => { + const { status } = await addMinter(cosmosConfig, erc20.contractAddress, aliceBech32); + + expect(status).to.equal(ProposalStatus.PROPOSAL_STATUS_PASSED); + await expectOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ownerBech32, aliceBech32]); + await expectMinterCanMintAndBurn(contractAsAlice, contractAsOwner, ownerSigner.address, tokenAmount); + }); + }); + + describe("Remove minter", () => { + it("should remove alice by denom, update both queries, and revoke alice access", async () => { + const { status: addStatus } = await addMinter(cosmosConfig, cosmosConfig.denom, aliceBech32); + + expect(addStatus).to.equal(ProposalStatus.PROPOSAL_STATUS_PASSED); + await expectOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ownerBech32, aliceBech32]); + + const { status: removeStatus } = await removeMinter(cosmosConfig, cosmosConfig.denom, aliceBech32); + + expect(removeStatus).to.equal(ProposalStatus.PROPOSAL_STATUS_PASSED); + await expectOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ownerBech32]); + await expectRevert(contractAsAlice.mint(aliceSigner.address, tokenAmount), ERC20Errors.MINTER_IS_NOT_OWNER); + await expectRevert(contractAsAlice["burn(address,uint256)"](aliceSigner.address, tokenAmount), ERC20Errors.SENDER_IS_NOT_OWNER); + }); + + it("should remove alice by contract address, update both queries, and revoke alice access", async () => { + const { status: addStatus } = await addMinter(cosmosConfig, erc20.contractAddress, aliceBech32); + + expect(addStatus).to.equal(ProposalStatus.PROPOSAL_STATUS_PASSED); + await expectOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ownerBech32, aliceBech32]); + + const { status: removeStatus } = await removeMinter(cosmosConfig, erc20.contractAddress, aliceBech32); + + expect(removeStatus).to.equal(ProposalStatus.PROPOSAL_STATUS_PASSED); + await expectOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ownerBech32]); + await expectRevert(contractAsAlice.mint(aliceSigner.address, tokenAmount), ERC20Errors.MINTER_IS_NOT_OWNER); + await expectRevert(contractAsAlice["burn(address,uint256)"](aliceSigner.address, tokenAmount), ERC20Errors.SENDER_IS_NOT_OWNER); + }); + }); + + describe("Cycles", () => { + it("should re-authorize alice after a full add-remove-add cycle", async () => { + const { status: firstAddStatus } = await addMinter(cosmosConfig, cosmosConfig.denom, aliceBech32); + expect(firstAddStatus).to.equal(ProposalStatus.PROPOSAL_STATUS_PASSED); + await expectOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ownerBech32, aliceBech32]); + + const { status: removeStatus } = await removeMinter(cosmosConfig, cosmosConfig.denom, aliceBech32); + expect(removeStatus).to.equal(ProposalStatus.PROPOSAL_STATUS_PASSED); + await expectOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ownerBech32]); + await expectRevert(contractAsAlice.mint(aliceSigner.address, tokenAmount), ERC20Errors.MINTER_IS_NOT_OWNER); + await expectRevert(contractAsAlice["burn(address,uint256)"](aliceSigner.address, tokenAmount), ERC20Errors.SENDER_IS_NOT_OWNER); + + const { status: secondAddStatus } = await addMinter(cosmosConfig, erc20.contractAddress, aliceBech32); + expect(secondAddStatus).to.equal(ProposalStatus.PROPOSAL_STATUS_PASSED); + await expectOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ownerBech32, aliceBech32]); + await expectMinterCanMintAndBurn(contractAsAlice, contractAsOwner, ownerSigner.address, tokenAmount); + }); + + it("should support 3 minters and revoke them individually", async () => { + const { status: addAliceStatus } = await addMinter(cosmosConfig, cosmosConfig.denom, aliceBech32); + expect(addAliceStatus).to.equal(ProposalStatus.PROPOSAL_STATUS_PASSED); + + const { status: addBobStatus } = await addMinter(cosmosConfig, erc20.contractAddress, bobBech32); + expect(addBobStatus).to.equal(ProposalStatus.PROPOSAL_STATUS_PASSED); + + await expectOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ + ownerBech32, + aliceBech32, + bobBech32, + ]); + await expectMinterCanMintAndBurn(contractAsAlice, contractAsOwner, ownerSigner.address, tokenAmount); + + const { status: removeBobStatus } = await removeMinter(cosmosConfig, cosmosConfig.denom, bobBech32); + expect(removeBobStatus).to.equal(ProposalStatus.PROPOSAL_STATUS_PASSED); + await expectOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ownerBech32, aliceBech32]); + + const { status: removeAliceStatus } = await removeMinter(cosmosConfig, erc20.contractAddress, aliceBech32); + expect(removeAliceStatus).to.equal(ProposalStatus.PROPOSAL_STATUS_PASSED); + await expectOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ownerBech32]); + }); + }); + + describe("Backwards compatibility", () => { + it("should populate deprecated owner_address field on TokenPair with the first minter", async () => { + await expectTokenPairOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ownerBech32]); + + const { status: addStatus } = await addMinter(cosmosConfig, cosmosConfig.denom, aliceBech32); + expect(addStatus).to.equal(ProposalStatus.PROPOSAL_STATUS_PASSED); + await expectTokenPairOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ownerBech32, aliceBech32]); + + const { status: removeStatus } = await removeMinter(cosmosConfig, cosmosConfig.denom, aliceBech32); + expect(removeStatus).to.equal(ProposalStatus.PROPOSAL_STATUS_PASSED); + await expectTokenPairOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ownerBech32]); + }); + }); + + describe("Error cases", () => { + it("should fail to add ownerSigner as minter when it already exists and keep the owner set unchanged", async () => { + const { status } = await addMinter(cosmosConfig, erc20.contractAddress, ownerBech32); + + expect(status).to.equal(ProposalStatus.PROPOSAL_STATUS_FAILED); + await expectOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ownerBech32]); + }); + + it("should fail to re-add alice through a different token identifier", async () => { + const { status: addStatus } = await addMinter(cosmosConfig, cosmosConfig.denom, aliceBech32); + expect(addStatus).to.equal(ProposalStatus.PROPOSAL_STATUS_PASSED); + await expectOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ownerBech32, aliceBech32]); + + const { status: duplicateStatus } = await addMinter(cosmosConfig, erc20.contractAddress, aliceBech32); + expect(duplicateStatus).to.equal(ProposalStatus.PROPOSAL_STATUS_FAILED); + await expectOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ownerBech32, aliceBech32]); + }); + + it("should fail to remove ownerSigner as the last minter and keep the owner set unchanged", async () => { + const { status } = await removeMinter(cosmosConfig, cosmosConfig.denom, ownerBech32); + + expect(status).to.equal(ProposalStatus.PROPOSAL_STATUS_FAILED); + await expectOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ownerBech32]); + }); + + it("should fail to remove a non-existent minter and keep the owner set unchanged", async () => { + const { status } = await removeMinter(cosmosConfig, erc20.contractAddress, aliceBech32); + + expect(status).to.equal(ProposalStatus.PROPOSAL_STATUS_FAILED); + await expectOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ownerBech32]); + }); + + it("should fail to add a minter to an unregistered token and keep the owner set unchanged", async () => { + const { status } = await addMinter(cosmosConfig, UNREGISTERED_DENOM, aliceBech32); + + expect(status).to.equal(ProposalStatus.PROPOSAL_STATUS_FAILED); + await expectOwnerAddresses(cosmosConfig.rpcUrl, erc20.contractAddress, cosmosConfig.denom, [ownerBech32]); + }); + }); +}); diff --git a/modules/evm/test/precompiles/erc20/utils/cosmos.ts b/modules/evm/test/precompiles/erc20/utils/cosmos.ts new file mode 100644 index 0000000..87fa438 --- /dev/null +++ b/modules/evm/test/precompiles/erc20/utils/cosmos.ts @@ -0,0 +1,115 @@ +import { expect } from "chai"; +import { toBech32, fromHex } from "@cosmjs/encoding"; +import { abciQuery } from "@firewatch/cosmos/query"; +import { QueryOwnerAddressesRequest, QueryOwnerAddressesResponse, QueryTokenPairRequest, QueryTokenPairResponse, TokenPair } from "./proto"; + +export type CosmosConfig = { + rpcUrl: string; + mnemonic: string; + denom: string; + prefix: string; + govModuleAddress: string; +}; + +/** + * Extract the cosmos section from a module config. + * @param moduleConfig Imported module.config.json. + * @returns Cosmos config. + */ +export function getCosmosConfig(moduleConfig: { cosmos: CosmosConfig }): CosmosConfig { + return moduleConfig.cosmos; +} + +/** + * Convert a 0x-prefixed hex address to bech32. + * @param prefix Bech32 HRP. + * @param hex Hex address with or without `0x` prefix. + * @returns Bech32-encoded address. + */ +export function hexToBech32(prefix: string, hex: string): string { + const stripped = hex.startsWith("0x") ? hex.slice(2) : hex; + return toBech32(prefix, fromHex(stripped)); +} + +/** + * Query authorized minters for a token pair. + * @param rpcUrl Comet RPC endpoint. + * @param token ERC-20 contract address or cosmos denom. + * @returns Bech32 minter addresses, empty array if none or pair unknown. + */ +export async function queryOwnerAddresses(rpcUrl: string, token: string): Promise { + const value = await abciQuery( + rpcUrl, + "/cosmos.evm.erc20.v1.Query/OwnerAddresses", + QueryOwnerAddressesRequest.encode({ contractAddress: token }).finish(), + ); + if (value.length === 0) { + return []; + } + + return QueryOwnerAddressesResponse.decode(value).ownerAddresses; +} + +/** + * Query token pair metadata. + * @param rpcUrl Comet RPC endpoint. + * @param token ERC-20 contract address or cosmos denom. + * @returns Decoded TokenPair. + * @throws If pair is not registered. + */ +export async function queryTokenPair(rpcUrl: string, token: string): Promise { + const value = await abciQuery(rpcUrl, "/cosmos.evm.erc20.v1.Query/TokenPair", QueryTokenPairRequest.encode({ token }).finish()); + if (value.length === 0) { + throw new Error(`TokenPair not found for token '${token}'`); + } + + const { tokenPair } = QueryTokenPairResponse.decode(value); + if (!tokenPair) { + throw new Error(`TokenPair missing in response for token '${token}'`); + } + + return tokenPair; +} + +/** + * Assert both contract-address and denom queries return the same ordered minter set. + * @param rpcUrl Comet RPC endpoint. + * @param contractAddress ERC-20 contract address. + * @param denom Cosmos denom for the same token pair. + * @param expected Expected bech32 minters in order. + */ +export async function expectOwnerAddresses(rpcUrl: string, contractAddress: string, denom: string, expected: string[]): Promise { + const ownersByContract = await queryOwnerAddresses(rpcUrl, contractAddress); + const ownersByDenom = await queryOwnerAddresses(rpcUrl, denom); + + expect(ownersByContract).to.have.ordered.members(expected); + expect(ownersByDenom).to.have.ordered.members(expected); +} + +/** + * Assert TokenPair queries by contract and denom return `ownerAddresses` in the expected order, + * and that deprecated `ownerAddress` matches `ownerAddresses[0]` (empty string if none). + * + * Ordered: deprecated `ownerAddress` is defined as `ownerAddresses[0]`, so a keeper re-order + * would pass set-equality while `ownerAddress` silently points at a different minter. + * @param rpcUrl Comet RPC endpoint. + * @param contractAddress ERC-20 contract address. + * @param denom Cosmos denom for the same token pair. + * @param expected Expected bech32 minters in order. + */ +export async function expectTokenPairOwnerAddresses( + rpcUrl: string, + contractAddress: string, + denom: string, + expected: string[], +): Promise { + const pairByContract = await queryTokenPair(rpcUrl, contractAddress); + const pairByDenom = await queryTokenPair(rpcUrl, denom); + + expect(pairByContract.ownerAddresses).to.have.ordered.members(expected); + expect(pairByDenom.ownerAddresses).to.have.ordered.members(expected); + + const expectedDeprecated = expected.length > 0 ? expected[0] : ""; + expect(pairByContract.ownerAddress).to.equal(expectedDeprecated); + expect(pairByDenom.ownerAddress).to.equal(expectedDeprecated); +} diff --git a/modules/evm/test/precompiles/erc20/utils/helpers.ts b/modules/evm/test/precompiles/erc20/utils/helpers.ts index decf69f..a996a46 100644 --- a/modules/evm/test/precompiles/erc20/utils/helpers.ts +++ b/modules/evm/test/precompiles/erc20/utils/helpers.ts @@ -5,23 +5,19 @@ import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; import { executeTx } from "@testing/hardhat/utils"; /** - * Resets the owner's contract state. Transferring tokens back to "faucet account". - * For "localnet", restores ownership if needed. - * 1. Check owner balance — if the owner has no tokens, nothing to clean up, return early - * 2. Restore ownership (localnet only) — if a test transferred ownership away from the owner (e.g. - * the transferOwnership tests), it transfers it back. - * 3. Approve full balance — the owner approves the user to spend their entire token balance. After - * this tx, the owner's balance is slightly less (gas cost deducted). - * 4. Query actual remaining balance — instead of estimating gas, it reads the real post-approve + * Resets the owner's contract state by transferring tokens back to the "faucet account". + * 1. Check owner balance, if the owner has no tokens, nothing to clean up, return early. + * 2. Approve full balance, the owner approves the user to spend their entire token balance. + * After this tx, the owner's balance is slightly less (gas cost deducted). + * 3. Query actual remaining balance, instead of estimating gas, it reads the real post-approve * balance. This is the exact amount safe to transfer. - * 5. Transfer back to user — the user calls transferFrom to pull all remaining tokens from the + * 4. Transfer back to user, the user calls transferFrom to pull all remaining tokens from the * owner back to themselves (acting as the "faucet"). - * 6. Assert owner balance is 0 — verifies the cleanup work + * 5. Assert owner balance is 0, verifies the cleanup work. * @param contractAsOwner Contract instance connected with the owner signer. * @param contractAsUser Contract instance connected with the user signer. * @param ownerSigner Owner signer. * @param userSigner User signer. - * @param chainEvn Network environment. */ export async function resetOwnerState( contractAsOwner: Contract, @@ -45,6 +41,33 @@ export async function resetOwnerState( expect(ownerBalanceAfter).to.equal(0n); } +/** + * Runs a mint/burn round-trip signed by `minterContract` against `recipient` and asserts + * the recipient balance returns to its starting value. + * @param minterContract Contract instance connected with the minter signer. + * @param recipientContract Contract instance connected with a signer that can read balances. + * @param recipient Address receiving the mint and then losing it to burn. + * @param amount Amount to mint and burn. + */ +export async function expectMinterCanMintAndBurn( + minterContract: Contract, + recipientContract: Contract, + recipient: string, + amount: bigint, +): Promise { + const recipientBeforeBalance: bigint = await recipientContract.balanceOf(recipient); + + await executeTx(minterContract.mint(recipient, amount)); + + const recipientAfterMintBalance: bigint = await recipientContract.balanceOf(recipient); + expect(recipientAfterMintBalance).to.equal(recipientBeforeBalance + amount); + + await executeTx(minterContract["burn(address,uint256)"](recipient, amount)); + + const recipientAfterBurnBalance: bigint = await recipientContract.balanceOf(recipient); + expect(recipientAfterBurnBalance).to.equal(recipientBeforeBalance); +} + /** * Asserts that a Transfer event was emitted with the expected parameters. * @param receipt The transaction receipt containing logs. diff --git a/modules/evm/test/precompiles/erc20/utils/minters.ts b/modules/evm/test/precompiles/erc20/utils/minters.ts new file mode 100644 index 0000000..d90f7fb --- /dev/null +++ b/modules/evm/test/precompiles/erc20/utils/minters.ts @@ -0,0 +1,92 @@ +import { expect } from "chai"; +import { Any } from "cosmjs-types/google/protobuf/any"; +import { ProposalStatus, submitAndVote } from "@firewatch/cosmos/gov"; +import { CosmosConfig, expectOwnerAddresses, queryOwnerAddresses } from "./cosmos"; +import { MsgAddMinter, MsgRemoveMinter } from "./proto"; + +export type ProposalOptions = { + timeoutMs?: number; +}; + +/** + * Add a minter to the token pair via a governance proposal. + * @param config Cosmos runtime configuration. + * @param token ERC-20 contract address or cosmos denom identifying the token pair. + * @param minterAddress Bech32 address to authorize. + * @param options Optional proposal overrides (e.g. `timeoutMs`). + * @returns Proposal id and terminal status. + */ +export async function addMinter( + config: CosmosConfig, + token: string, + minterAddress: string, + options: ProposalOptions = {}, +): Promise<{ proposalId: string; status: number }> { + return submitAndVote({ + rpcUrl: config.rpcUrl, + mnemonic: config.mnemonic, + prefix: config.prefix, + denom: config.denom, + message: Any.fromPartial({ + typeUrl: MsgAddMinter.typeUrl, + value: MsgAddMinter.encode({ authority: config.govModuleAddress, token, minterAddress }).finish(), + }), + title: "Add Minter", + summary: `Add ${minterAddress} as minter for ${token}`, + depositAmount: "1", + timeoutMs: options.timeoutMs, + }); +} + +/** + * Remove a minter from the token pair via a governance proposal. + * @param config Cosmos runtime configuration. + * @param token ERC-20 contract address or cosmos denom identifying the token pair. + * @param minterAddress Bech32 address to revoke. + * @param options Optional proposal overrides (e.g. `timeoutMs`). + * @returns Proposal id and terminal status. + */ +export async function removeMinter( + config: CosmosConfig, + token: string, + minterAddress: string, + options: ProposalOptions = {}, +): Promise<{ proposalId: string; status: number }> { + return submitAndVote({ + rpcUrl: config.rpcUrl, + mnemonic: config.mnemonic, + prefix: config.prefix, + denom: config.denom, + message: Any.fromPartial({ + typeUrl: MsgRemoveMinter.typeUrl, + value: MsgRemoveMinter.encode({ authority: config.govModuleAddress, token, minterAddress }).finish(), + }), + title: "Remove Minter", + summary: `Remove ${minterAddress} as minter for ${token}`, + depositAmount: "1", + timeoutMs: options.timeoutMs, + }); +} + +/** + * Removes every authorized minter except `ownerBech32` via governance, then asserts the + * owner is the sole minter registered under both the denom and the contract-address queries. + * Used as a baseline between tests to isolate minter-set assertions. + * @param config Cosmos runtime configuration. + * @param contractAddress ERC-20 contract address of the token pair. + * @param ownerBech32 Bech32 address of the genesis minter that must remain authorized. + */ +export async function ensureOwnerOnlyMinter(config: CosmosConfig, contractAddress: string, ownerBech32: string): Promise { + const [ownersByDenom, ownersByContract] = await Promise.all([ + queryOwnerAddresses(config.rpcUrl, config.denom), + queryOwnerAddresses(config.rpcUrl, contractAddress), + ]); + const rogueOwners = Array.from(new Set([...ownersByDenom, ...ownersByContract])).filter((address) => address !== ownerBech32); + + for (const rogue of rogueOwners) { + const { status } = await removeMinter(config, config.denom, rogue); + expect(status, `cleanup removeMinter(${rogue})`).to.equal(ProposalStatus.PROPOSAL_STATUS_PASSED); + } + + await expectOwnerAddresses(config.rpcUrl, contractAddress, config.denom, [ownerBech32]); +} diff --git a/modules/evm/test/precompiles/erc20/utils/proto.ts b/modules/evm/test/precompiles/erc20/utils/proto.ts new file mode 100644 index 0000000..8f3d6d1 --- /dev/null +++ b/modules/evm/test/precompiles/erc20/utils/proto.ts @@ -0,0 +1,157 @@ +// Hand-rolled encoders/decoders for cosmos.evm.erc20.v1 messages used by the multi-minter tests. +// Upstream proto: https://github.com/cosmos/evm/blob/main/proto/cosmos/evm/erc20/v1/tx.proto +// and .../query.proto. Keep field numbers/types in sync if the upstream proto changes. +import { BinaryReader, BinaryWriter } from "cosmjs-types/binary"; + +export interface MsgAddMinter { + authority: string; + token: string; + minterAddress: string; +} + +export const MsgAddMinter = { + typeUrl: "/cosmos.evm.erc20.v1.MsgAddMinter", + encode(message: MsgAddMinter, writer: BinaryWriter = BinaryWriter.create()): BinaryWriter { + if (message.authority !== "") writer.uint32(10).string(message.authority); + if (message.token !== "") writer.uint32(18).string(message.token); + if (message.minterAddress !== "") writer.uint32(26).string(message.minterAddress); + return writer; + }, +}; + +export interface MsgRemoveMinter { + authority: string; + token: string; + minterAddress: string; +} + +export const MsgRemoveMinter = { + typeUrl: "/cosmos.evm.erc20.v1.MsgRemoveMinter", + encode(message: MsgRemoveMinter, writer: BinaryWriter = BinaryWriter.create()): BinaryWriter { + if (message.authority !== "") writer.uint32(10).string(message.authority); + if (message.token !== "") writer.uint32(18).string(message.token); + if (message.minterAddress !== "") writer.uint32(26).string(message.minterAddress); + return writer; + }, +}; + +export interface TokenPair { + erc20Address: string; + denom: string; + enabled: boolean; + contractOwner: number; + ownerAddress: string; + ownerAddresses: string[]; +} + +export const TokenPair = { + decode(input: BinaryReader | Uint8Array, length?: number): TokenPair { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message: TokenPair = { + erc20Address: "", + denom: "", + enabled: false, + contractOwner: 0, + ownerAddress: "", + ownerAddresses: [], + }; + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.erc20Address = reader.string(); + break; + case 2: + message.denom = reader.string(); + break; + case 3: + message.enabled = reader.bool(); + break; + case 4: + message.contractOwner = reader.int32(); + break; + case 5: + message.ownerAddress = reader.string(); + break; + case 6: + message.ownerAddresses.push(reader.string()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }, +}; + +export interface QueryTokenPairRequest { + token: string; +} + +export const QueryTokenPairRequest = { + encode(message: QueryTokenPairRequest, writer: BinaryWriter = BinaryWriter.create()): BinaryWriter { + if (message.token !== "") writer.uint32(10).string(message.token); + return writer; + }, +}; + +export interface QueryTokenPairResponse { + tokenPair: TokenPair | undefined; +} + +export const QueryTokenPairResponse = { + decode(input: BinaryReader | Uint8Array, length?: number): QueryTokenPairResponse { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message: QueryTokenPairResponse = { tokenPair: undefined }; + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.tokenPair = TokenPair.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }, +}; + +export interface QueryOwnerAddressesRequest { + contractAddress: string; +} + +export const QueryOwnerAddressesRequest = { + encode(message: QueryOwnerAddressesRequest, writer: BinaryWriter = BinaryWriter.create()): BinaryWriter { + if (message.contractAddress !== "") writer.uint32(10).string(message.contractAddress); + return writer; + }, +}; + +export interface QueryOwnerAddressesResponse { + ownerAddresses: string[]; +} + +export const QueryOwnerAddressesResponse = { + decode(input: BinaryReader | Uint8Array, length?: number): QueryOwnerAddressesResponse { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message: QueryOwnerAddressesResponse = { ownerAddresses: [] }; + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.ownerAddresses.push(reader.string()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }, +}; diff --git a/modules/evm/tsconfig.json b/modules/evm/tsconfig.json index 969c789..3b43e93 100644 --- a/modules/evm/tsconfig.json +++ b/modules/evm/tsconfig.json @@ -1,3 +1,7 @@ { - "extends": "@shared/tsconfig/package" + "extends": "@shared/tsconfig/package", + "compilerOptions": { + "declaration": false, + "rootDir": "../.." + } }