From c24154f9c333e25ec2eeda404daa105e0fd1ef17 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Wed, 2 Jul 2025 19:32:04 +0200 Subject: [PATCH 1/3] feat(cosmos): adaptint `@cosmjs` to support `EthAccount` --- modules/cosmos/.mocharc.json | 2 +- .../cosmos/configs/testnet.module.config.json | 41 ++ modules/cosmos/module.config.json | 41 ++ modules/cosmos/package.json | 9 +- .../cosmos/src/modules/ibc/account-parser.ts | 61 +++ modules/cosmos/src/modules/ibc/client.ts | 232 ++++++++++ modules/cosmos/src/modules/ibc/config.ts | 32 ++ modules/cosmos/src/modules/ibc/parser.ts | 208 +++++++++ modules/cosmos/src/modules/ibc/pubkey.ts | 52 +++ modules/cosmos/src/modules/ibc/secp256k1.ts | 38 ++ modules/cosmos/src/modules/ibc/signer.ts | 364 ++++++++++++++++ .../src/modules/ibc/signingstartgateclient.ts | 411 ++++++++++++++++++ modules/cosmos/src/modules/ibc/utils.ts | 92 ++++ modules/cosmos/test/modules/ibc/index.test.ts | 132 ++++++ pnpm-lock.yaml | 404 +++++++---------- 15 files changed, 1870 insertions(+), 249 deletions(-) create mode 100644 modules/cosmos/src/modules/ibc/account-parser.ts create mode 100644 modules/cosmos/src/modules/ibc/client.ts create mode 100644 modules/cosmos/src/modules/ibc/config.ts create mode 100644 modules/cosmos/src/modules/ibc/parser.ts create mode 100644 modules/cosmos/src/modules/ibc/pubkey.ts create mode 100644 modules/cosmos/src/modules/ibc/secp256k1.ts create mode 100644 modules/cosmos/src/modules/ibc/signer.ts create mode 100644 modules/cosmos/src/modules/ibc/signingstartgateclient.ts create mode 100644 modules/cosmos/src/modules/ibc/utils.ts create mode 100644 modules/cosmos/test/modules/ibc/index.test.ts diff --git a/modules/cosmos/.mocharc.json b/modules/cosmos/.mocharc.json index 4a80d02..88cbff7 100644 --- a/modules/cosmos/.mocharc.json +++ b/modules/cosmos/.mocharc.json @@ -1,5 +1,5 @@ { "require": ["ts-node/register"], "spec": "test/**/*.test.ts", - "timeout": 15000 + "timeout": 1000000 } diff --git a/modules/cosmos/configs/testnet.module.config.json b/modules/cosmos/configs/testnet.module.config.json index e733641..f628f86 100644 --- a/modules/cosmos/configs/testnet.module.config.json +++ b/modules/cosmos/configs/testnet.module.config.json @@ -23,5 +23,46 @@ }, "bank": { "account": "ethm1dakgyqjulg29m5fmv992g2y66m9g2mjn6hahwg" + }, + "ibc": { + "chains": [ + { + "dstChain": { + "account": { + "mnemonic": "harsh harsh mean pool tell oval cancel deal unit strategy deny pool", + "address": "ethm1dny09udcpxg2j6440fuk2m6wajz6249tgu2znt" + }, + "evm": true, + "chainId": "xrplevm_1449000-1", + "rpcUrl": "http://cosmos.testnet.xrplevm.org:26657", + "prefix": "ethm", + "denom": "axrp", + "amount": "5000", + "channel": "channel-2", + "gas": { + "amount": "40000000000000000", + "gas": "200000" + } + }, + "srcChain": { + "account": { + "mnemonic": "harsh harsh mean pool tell oval cancel deal unit strategy deny pool", + "address": "cosmos1dakgyqjulg29m5fmv992g2y66m9g2mjn6hahwg" + }, + "evm": false, + "chainId": "osmo-test-5", + "rpcUrl": "https://rpc.testnet.osmosis.zone", + "prefix": "osmo", + "denom": "uosmo", + "amount": "5000", + "gas": { + "amount": "200000", + "gas": "200000" + }, + "channel": "channel-10361" + }, + "port": "transfer" + } + ] } } diff --git a/modules/cosmos/module.config.json b/modules/cosmos/module.config.json index e733641..f628f86 100644 --- a/modules/cosmos/module.config.json +++ b/modules/cosmos/module.config.json @@ -23,5 +23,46 @@ }, "bank": { "account": "ethm1dakgyqjulg29m5fmv992g2y66m9g2mjn6hahwg" + }, + "ibc": { + "chains": [ + { + "dstChain": { + "account": { + "mnemonic": "harsh harsh mean pool tell oval cancel deal unit strategy deny pool", + "address": "ethm1dny09udcpxg2j6440fuk2m6wajz6249tgu2znt" + }, + "evm": true, + "chainId": "xrplevm_1449000-1", + "rpcUrl": "http://cosmos.testnet.xrplevm.org:26657", + "prefix": "ethm", + "denom": "axrp", + "amount": "5000", + "channel": "channel-2", + "gas": { + "amount": "40000000000000000", + "gas": "200000" + } + }, + "srcChain": { + "account": { + "mnemonic": "harsh harsh mean pool tell oval cancel deal unit strategy deny pool", + "address": "cosmos1dakgyqjulg29m5fmv992g2y66m9g2mjn6hahwg" + }, + "evm": false, + "chainId": "osmo-test-5", + "rpcUrl": "https://rpc.testnet.osmosis.zone", + "prefix": "osmo", + "denom": "uosmo", + "amount": "5000", + "gas": { + "amount": "200000", + "gas": "200000" + }, + "channel": "channel-10361" + }, + "port": "transfer" + } + ] } } diff --git a/modules/cosmos/package.json b/modules/cosmos/package.json index 2a52731..2e78700 100644 --- a/modules/cosmos/package.json +++ b/modules/cosmos/package.json @@ -12,9 +12,14 @@ }, "license": "ISC", "dependencies": { + "@cosmjs/amino": "^0.33.1", + "@cosmjs/crypto": "^0.33.1", "@cosmjs/encoding": "^0.33.1", + "@cosmjs/math": "^0.33.1", + "@cosmjs/proto-signing": "^0.33.1", "@cosmjs/stargate": "^0.33.0", "@cosmjs/tendermint-rpc": "^0.33.1", + "@cosmjs/utils": "^0.33.1", "@types/chai": "^5.0.1", "cosmjs-types": "^0.9.0", "mocha": "^11.1.0" @@ -23,7 +28,9 @@ "@firewatch/core": "workspace:*", "@shared/eslint": "workspace:*", "@shared/tsconfig": "workspace:*", + "@shared/utils": "workspace:*", "@testing/mocha": "workspace:*", - "@types/mocha": "^10.0.10" + "@types/mocha": "^10.0.10", + "@types/node": "^24.0.10" } } diff --git a/modules/cosmos/src/modules/ibc/account-parser.ts b/modules/cosmos/src/modules/ibc/account-parser.ts new file mode 100644 index 0000000..f308d25 --- /dev/null +++ b/modules/cosmos/src/modules/ibc/account-parser.ts @@ -0,0 +1,61 @@ +import { Account, accountFromAny } from "@cosmjs/stargate"; +import { Any } from "cosmjs-types/google/protobuf/any"; +import { parseEthAccount } from "./parser"; + +/** + * Custom account parser that extends accountFromAny to support EthAccount format. + * This parser handles both standard Cosmos accounts and Ethermint EthAccount types. + * + * Supports the EthAccount format as defined in ethermint.types.v1: + * ```proto + * message EthAccount { + * cosmos.auth.v1beta1.BaseAccount base_account = 1; + * string code_hash = 2; + * } + * ``` + * @param input The Any message containing the account. + * @returns The parsed account. + * @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 + } + + // 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); + } +} + +/** + * Check if an account type URL represents an EthAccount. + * @param typeUrl The type URL to check. + * @returns True if the type URL is for an EthAccount. + */ +export function isEthAccount(typeUrl: string): boolean { + return typeUrl === "/ethermint.types.v1.EthAccount"; +} + +/** + * Create an account parser specifically for Ethermint/Evmos chains. + * This is a factory function that returns a configured account parser. + * @returns The account parser function. + */ +export function createEthermintAccountParser() { + return (input: Any): Account => ethermintAccountParser(input); +} diff --git a/modules/cosmos/src/modules/ibc/client.ts b/modules/cosmos/src/modules/ibc/client.ts new file mode 100644 index 0000000..fd70bde --- /dev/null +++ b/modules/cosmos/src/modules/ibc/client.ts @@ -0,0 +1,232 @@ +import { + DeliverTxResponse, + StdFee, + SignerData, + HttpEndpoint, + SigningStargateClientOptions, + accountFromAny, + Account, + defaultRegistryTypes, +} 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); + } + + /** + * Send IBC tokens from one chain to another. + * @param senderAddress The address of the sender. + * @param recipientAddress The address of the recipient. + * @param transferAmount The amount of tokens to transfer. + * @param sourcePort The source port. + * @param sourceChannel The source channel. + * @param timeoutHeight The timeout height. + * @param timeoutTimestamp The timeout timestamp (in milliseconds if number, or nanoseconds if bigint). + * @param fee The fee. + * @param memo The memo. + * @returns The deliver tx response. + */ + async sendIbcTokens( + senderAddress: string, + recipientAddress: string, + transferAmount: Coin, + sourcePort: string, + sourceChannel: string, + timeoutHeight: Height | undefined, + timeoutTimestamp: number | bigint | undefined, + fee: StdFee, + memo?: string, + ): Promise { + let timeoutTimestampNanos: bigint | undefined; + + if (timeoutTimestamp !== undefined) { + if (typeof timeoutTimestamp === "bigint") { + // Already in nanoseconds (from calculateTimeoutTimestamp utility) + timeoutTimestampNanos = timeoutTimestamp; + } else { + // Convert from milliseconds to nanoseconds + timeoutTimestampNanos = BigInt(timeoutTimestamp) * BigInt(1000000); + } + } + + const transferMsg = { + typeUrl: "/ibc.applications.transfer.v1.MsgTransfer", + value: MsgTransfer.fromPartial({ + sourcePort: sourcePort, + sourceChannel: sourceChannel, + sender: senderAddress, + receiver: recipientAddress, + token: transferAmount, + timeoutHeight: timeoutHeight, + timeoutTimestamp: timeoutTimestampNanos, + }), + }; + + 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/config.ts b/modules/cosmos/src/modules/ibc/config.ts new file mode 100644 index 0000000..74856ab --- /dev/null +++ b/modules/cosmos/src/modules/ibc/config.ts @@ -0,0 +1,32 @@ +export interface IBCAccount { + mnemonic: string; + address: string; +} + +export interface IBCGas { + amount: string; + gas: string; +} + +export interface IBCChain { + account: IBCAccount; + evm: boolean; + chainId: string; + rpcUrl: string; + prefix: string; + denom: string; + amount: string; + gas: IBCGas; + channel: string; +} + +export interface IBCChainPair { + srcChain: IBCChain; + dstChain: IBCChain; + port: string; + roundtrip?: boolean; +} + +export interface IBCModuleConfig { + chains: IBCChainPair[]; +} diff --git a/modules/cosmos/src/modules/ibc/parser.ts b/modules/cosmos/src/modules/ibc/parser.ts new file mode 100644 index 0000000..6bd23f4 --- /dev/null +++ b/modules/cosmos/src/modules/ibc/parser.ts @@ -0,0 +1,208 @@ +import { BaseAccount } from "cosmjs-types/cosmos/auth/v1beta1/auth"; +import { Any } from "cosmjs-types/google/protobuf/any"; + +/** + * EthAccount message structure from ethermint.types.v1. + */ +export interface EthAccount { + baseAccount?: BaseAccount; + codeHash: string; +} + +/** + * Parse EthAccount from protobuf Any message. + * @param accountAny The Any message containing EthAccount. + * @returns Parsed EthAccount or null if parsing fails. + */ +export function parseEthAccount(accountAny: Any): EthAccount | null { + try { + if (accountAny.typeUrl !== "/ethermint.types.v1.EthAccount") { + return null; + } + + const reader = new Uint8Array(accountAny.value); + let position = 0; + + let baseAccount: BaseAccount | undefined; + let codeHash = ""; + + while (position < reader.length) { + const tag = reader[position++]; + const fieldNumber = tag >> 3; + const wireType = tag & 0x07; + + switch (fieldNumber) { + case 1: // base_account + if (wireType === 2) { + // Length-delimited + const length = readVarint(reader, position); + position = skipVarint(reader, position); + const baseAccountBytes = reader.slice(position, position + length); + position += length; + + // Parse BaseAccount with custom parser + baseAccount = parseBaseAccount(baseAccountBytes); + } + break; + case 2: // code_hash + if (wireType === 2) { + // Length-delimited + const length = readVarint(reader, position); + position = skipVarint(reader, position); + const codeHashBytes = reader.slice(position, position + length); + position += length; + codeHash = new TextDecoder().decode(codeHashBytes); + } + break; + default: + // Skip unknown fields + if (wireType === 0) { + // Varint + position = skipVarint(reader, position); + } else if (wireType === 2) { + // Length-delimited + const length = readVarint(reader, position); + position = skipVarint(reader, position); + position += length; + } else { + // For other wire types, try to skip safely + console.warn(`Unknown wire type ${wireType} for field ${fieldNumber}, skipping`); + break; + } + break; + } + } + + return { baseAccount, codeHash }; + } catch (error) { + console.error("Failed to parse EthAccount:", error); + return null; + } +} + +/** + * Parse BaseAccount from protobuf bytes. + * @param bytes The protobuf bytes. + * @returns Parsed BaseAccount. + */ +function parseBaseAccount(bytes: Uint8Array): BaseAccount { + let position = 0; + let address = ""; + let accountNumber = 0n; + let sequence = 0n; + const pubKey: any = null; + + while (position < bytes.length) { + if (position >= bytes.length) break; + + const tag = bytes[position++]; + const fieldNumber = tag >> 3; + const wireType = tag & 0x07; + + switch (fieldNumber) { + case 1: // address + if (wireType === 2) { + const length = readVarint(bytes, position); + position = skipVarint(bytes, position); + + // Address is stored as bech32 string in BaseAccount + const addressBytes = bytes.slice(position, position + length); + address = new TextDecoder().decode(addressBytes); + position += length; + } + break; + case 2: // pub_key + if (wireType === 2) { + const length = readVarint(bytes, position); + position = skipVarint(bytes, position); + // Skip pubkey for now - it's complex to parse + position += length; + } + break; + case 3: // account_number + if (wireType === 0) { + accountNumber = BigInt(readVarint64(bytes, position)); + position = skipVarint(bytes, position); + } + break; + case 4: // sequence + if (wireType === 0) { + sequence = BigInt(readVarint64(bytes, position)); + position = skipVarint(bytes, position); + } + break; + default: + // Skip unknown fields safely + if (wireType === 0) { + position = skipVarint(bytes, position); + } else if (wireType === 2) { + const length = readVarint(bytes, position); + position = skipVarint(bytes, position); + position += length; + } else { + // For other wire types, just skip one byte to avoid infinite loop + console.warn(`Unknown wire type ${wireType} for field ${fieldNumber} in BaseAccount`); + position++; + } + break; + } + } + + return { + address, + pubKey, + accountNumber, + sequence, + } as BaseAccount; +} + +/** + * Read varint from bytes (32-bit). + * @param bytes The bytes array. + * @param position The starting position. + * @returns The varint value. + */ +function readVarint(bytes: Uint8Array, position: number): number { + let result = 0; + let shift = 0; + while (position < bytes.length && shift < 32) { + const byte = bytes[position]; + result |= (byte & 0x7f) << shift; + if ((byte & 0x80) === 0) break; + shift += 7; + position++; + } + return result; +} + +/** + * Read varint from bytes (64-bit). + * @param bytes The bytes array. + * @param position The starting position. + * @returns The varint value. + */ +function readVarint64(bytes: Uint8Array, position: number): number { + let result = 0; + let shift = 0; + while (position < bytes.length && shift < 64) { + const byte = bytes[position]; + result += (byte & 0x7f) * Math.pow(2, shift); + if ((byte & 0x80) === 0) break; + shift += 7; + position++; + } + return result; +} + +/** + * Skip varint and return the new position. + * @param bytes The bytes array. + * @param position The starting position. + * @returns The position after the varint. + */ +function skipVarint(bytes: Uint8Array, position: number): number { + while (position < bytes.length && (bytes[position] & 0x80) !== 0) { + position++; + } + return position < bytes.length ? position + 1 : position; +} diff --git a/modules/cosmos/src/modules/ibc/pubkey.ts b/modules/cosmos/src/modules/ibc/pubkey.ts new file mode 100644 index 0000000..b65431a --- /dev/null +++ b/modules/cosmos/src/modules/ibc/pubkey.ts @@ -0,0 +1,52 @@ +/* eslint-disable jsdoc/require-jsdoc */ +/* eslint-disable @typescript-eslint/naming-convention */ +import { isEd25519Pubkey, isMultisigThresholdPubkey, isSecp256k1Pubkey, Pubkey } from "@cosmjs/amino"; +import { fromBase64 } from "@cosmjs/encoding"; +import { Uint53 } from "@cosmjs/math"; +import { PubKey as CosmosCryptoEd25519Pubkey } from "cosmjs-types/cosmos/crypto/ed25519/keys"; +import { LegacyAminoPubKey } from "cosmjs-types/cosmos/crypto/multisig/keys"; +import { PubKey as CosmosCryptoSecp256k1Pubkey } from "cosmjs-types/cosmos/crypto/secp256k1/keys"; +import { Any } from "cosmjs-types/google/protobuf/any"; + +const isEvm256k1Pubkey = (pubkey: Pubkey): boolean => { + return pubkey.type === "ethermint.crypto.v1.ethsecp256k1.PubKey"; +}; + +export function encodePubkey(pubkey: Pubkey): Any { + if (isSecp256k1Pubkey(pubkey)) { + const pubkeyProto = CosmosCryptoSecp256k1Pubkey.fromPartial({ + key: fromBase64(pubkey.value), + }); + return Any.fromPartial({ + typeUrl: "/cosmos.crypto.secp256k1.PubKey", + value: Uint8Array.from(CosmosCryptoSecp256k1Pubkey.encode(pubkeyProto).finish()), + }); + } else if (isEvm256k1Pubkey(pubkey)) { + const pubkeyProto = CosmosCryptoSecp256k1Pubkey.fromPartial({ + key: fromBase64(pubkey.value), + }); + return Any.fromPartial({ + typeUrl: "/ethermint.crypto.v1.ethsecp256k1.PubKey", + value: Uint8Array.from(CosmosCryptoSecp256k1Pubkey.encode(pubkeyProto).finish()), + }); + } else if (isEd25519Pubkey(pubkey)) { + const pubkeyProto = CosmosCryptoEd25519Pubkey.fromPartial({ + key: fromBase64(pubkey.value), + }); + return Any.fromPartial({ + typeUrl: "/cosmos.crypto.ed25519.PubKey", + value: Uint8Array.from(CosmosCryptoEd25519Pubkey.encode(pubkeyProto).finish()), + }); + } else if (isMultisigThresholdPubkey(pubkey)) { + const pubkeyProto = LegacyAminoPubKey.fromPartial({ + threshold: Uint53.fromString(pubkey.value.threshold).toNumber(), + publicKeys: pubkey.value.pubkeys.map(encodePubkey), + }); + return Any.fromPartial({ + typeUrl: "/cosmos.crypto.multisig.LegacyAminoPubKey", + value: Uint8Array.from(LegacyAminoPubKey.encode(pubkeyProto).finish()), + }); + } else { + throw new Error(`Pubkey type ${pubkey.type} not recognized`); + } +} diff --git a/modules/cosmos/src/modules/ibc/secp256k1.ts b/modules/cosmos/src/modules/ibc/secp256k1.ts new file mode 100644 index 0000000..da2d910 --- /dev/null +++ b/modules/cosmos/src/modules/ibc/secp256k1.ts @@ -0,0 +1,38 @@ +import { StdSignature } from "@cosmjs/amino"; +import { toBase64 } from "@cosmjs/encoding"; + +/** + * Takes a binary pubkey and signature to create a signature object. + * @param pubkey A compressed secp256k1 public key. + * @param signature A 64 byte fixed length representation of secp256k1 signature components r and s. + * @param isEthermint Whether to use Ethermint pubkey type or standard Cosmos pubkey type. + * @returns A StdSignature containing the encoded public key and base64 signature. + */ +export function encodeSecp256k1Signature(pubkey: Uint8Array, signature: Uint8Array, isEthermint = false): StdSignature { + if (signature.length !== 64) { + throw new Error( + "Signature must be 64 bytes long. Cosmos SDK uses a 2x32 byte fixed length encoding for the secp256k1 signature integers r and s.", + ); + } + + return { + pub_key: encodeSecp256k1Pubkey(pubkey, isEthermint), + signature: toBase64(signature), + }; +} + +/** + * Takes a Secp256k1 public key as raw bytes and returns the Amino JSON representation of it (the type/value wrapper object). + * @param pubkey A compressed secp256k1 public key. + * @param isEthermint Whether to use Ethermint pubkey type or standard Cosmos pubkey type. + * @returns A Secp256k1Pubkey containing the encoded public key. + */ +export function encodeSecp256k1Pubkey(pubkey: Uint8Array, isEthermint = false) { + if (pubkey.length !== 33 || (pubkey[0] !== 0x02 && pubkey[0] !== 0x03)) { + throw new Error("Public key must be compressed secp256k1, i.e. 33 bytes starting with 0x02 or 0x03"); + } + return { + type: isEthermint ? "ethermint.crypto.v1.ethsecp256k1.PubKey" : "cosmos.crypto.secp256k1.PubKey", + value: toBase64(pubkey), + }; +} diff --git a/modules/cosmos/src/modules/ibc/signer.ts b/modules/cosmos/src/modules/ibc/signer.ts new file mode 100644 index 0000000..b9cf7fa --- /dev/null +++ b/modules/cosmos/src/modules/ibc/signer.ts @@ -0,0 +1,364 @@ +/* eslint-disable jsdoc/check-param-names */ +/* eslint-disable jsdoc/require-param */ +/* eslint-disable jsdoc/tag-lines */ +/* eslint-disable jsdoc/require-returns */ +/* eslint-disable jsdoc/require-jsdoc */ +import { makeCosmoshubPath } from "@cosmjs/amino"; +import { + Bip39, + EnglishMnemonic, + HdPath, + pathToString, + Random, + Secp256k1, + Secp256k1Keypair, + sha256, + Slip10, + Slip10Curve, + stringToPath, + keccak256, +} from "@cosmjs/crypto"; +import { fromBase64, fromUtf8, toBase64, toBech32, toUtf8 } from "@cosmjs/encoding"; +import { AccountData, DirectSignResponse, KdfConfiguration, makeSignBytes, OfflineDirectSigner } from "@cosmjs/proto-signing"; +import { decrypt, encrypt, EncryptionConfiguration, executeKdf, supportedAlgorithms } from "@cosmjs/proto-signing/build/wallet"; +import { assert, isNonNullObject } from "@cosmjs/utils"; +import { SignDoc } from "cosmjs-types/cosmos/tx/v1beta1/tx"; +import { encodeSecp256k1Signature } from "./secp256k1"; + +interface AccountDataWithPrivkey extends AccountData { + readonly privkey: Uint8Array; +} + +const serializationTypeV1 = "directsecp256k1hdwallet-v1"; + +/** + * A KDF configuration that is not very strong but can be used on the main thread. + * It takes about 1 second in Node.js 16.0.0 and should have similar runtimes in other modern Wasm hosts. + */ +const basicPasswordHashingOptions: KdfConfiguration = { + algorithm: "argon2id", + params: { + outputLength: 32, + opsLimit: 24, + memLimitKib: 12 * 1024, + }, +}; + +/** + * This interface describes a JSON object holding the encrypted wallet and the meta data. + * All fields in here must be JSON types. + */ +export interface DirectSecp256k1HdWalletSerialization { + /** A format+version identifier for this serialization format */ + readonly type: string; + /** Information about the key derivation function (i.e. password to encryption key) */ + readonly kdf: KdfConfiguration; + /** Information about the symmetric encryption */ + readonly encryption: EncryptionConfiguration; + /** An instance of Secp256k1HdWalletData, which is stringified, encrypted and base64 encoded. */ + readonly data: string; +} + +/** + * Derivation information required to derive a keypair and an address from a mnemonic. + */ +interface Secp256k1Derivation { + readonly hdPath: HdPath; + readonly prefix: string; +} + +/** + * Derivation information required to derive a keypair and an address from a mnemonic. + * All fields in here must be JSON types. + */ +interface DerivationInfoJson { + readonly hdPath: string; + readonly prefix: string; +} + +function isDerivationJson(thing: unknown): thing is DerivationInfoJson { + if (!isNonNullObject(thing)) return false; + if (typeof (thing as DerivationInfoJson).hdPath !== "string") return false; + if (typeof (thing as DerivationInfoJson).prefix !== "string") return false; + return true; +} + +/** + * The data of a wallet serialization that is encrypted. + * All fields in here must be JSON types. + */ +interface DirectSecp256k1HdWalletData { + readonly mnemonic: string; + readonly accounts: readonly DerivationInfoJson[]; +} + +function extractKdfConfigurationV1(doc: any): KdfConfiguration { + return doc.kdf; +} + +export function extractKdfConfiguration(serialization: string): KdfConfiguration { + const root = JSON.parse(serialization); + if (!isNonNullObject(root)) throw new Error("Root document is not an object."); + + switch ((root as any).type) { + case serializationTypeV1: + return extractKdfConfigurationV1(root); + default: + throw new Error("Unsupported serialization type"); + } +} + +export interface DirectSecp256k1HdWalletOptions { + /** The password to use when deriving a BIP39 seed from a mnemonic. */ + readonly bip39Password: string; + /** The BIP-32/SLIP-10 derivation paths. Defaults to the Cosmos Hub/ATOM path `m/44'/118'/0'/0/0`. */ + readonly hdPaths: readonly HdPath[]; + /** The bech32 address prefix (human readable part). Defaults to "cosmos". */ + readonly prefix: string; +} + +interface DirectSecp256k1HdWalletConstructorOptions extends Partial { + readonly seed: Uint8Array; +} + +const defaultOptions: DirectSecp256k1HdWalletOptions = { + bip39Password: "", + hdPaths: [makeCosmoshubPath(0)], + prefix: "cosmos", +}; + +/** + * Derive Ethereum-style address from secp256k1 public key for Ethermint chains. + * @param pubkey A compressed secp256k1 public key. + * @returns The raw address bytes (20 bytes). + */ +function ethermintPubkeyToRawAddress(pubkey: Uint8Array): Uint8Array { + if (pubkey.length !== 33) { + throw new Error("Public key must be compressed secp256k1 (33 bytes)"); + } + + // Convert compressed pubkey to uncompressed + const uncompressed = Secp256k1.uncompressPubkey(pubkey); + + // Remove the 0x04 prefix byte, keep only the 64-byte coordinates + const pubkeyWithoutPrefix = uncompressed.slice(1); + + // Apply keccak256 hash and take the last 20 bytes for Ethereum address + const hash = keccak256(pubkeyWithoutPrefix); + return hash.slice(-20); +} + +/** A wallet for protobuf based signing using SIGN_MODE_DIRECT */ +export class DirectSecp256k1HdWallet implements OfflineDirectSigner { + /** + * Restores a wallet from the given BIP39 mnemonic. + * + * @param mnemonic Any valid English mnemonic. + * @param options An optional `DirectSecp256k1HdWalletOptions` object optionally containing a bip39Password, hdPaths, and prefix. + */ + static async fromMnemonic(mnemonic: string, options: Partial = {}): Promise { + const mnemonicChecked = new EnglishMnemonic(mnemonic); + const seed = await Bip39.mnemonicToSeed(mnemonicChecked, options.bip39Password); + return new DirectSecp256k1HdWallet(mnemonicChecked, { + ...options, + seed: seed, + }); + } + + /** + * Generates a new wallet with a BIP39 mnemonic of the given length. + * + * @param length The number of words in the mnemonic (12, 15, 18, 21 or 24). + * @param options An optional `DirectSecp256k1HdWalletOptions` object optionally containing a bip39Password, hdPaths, and prefix. + */ + static async generate( + length: 12 | 15 | 18 | 21 | 24 = 12, + options: Partial = {}, + ): Promise { + const entropyLength = 4 * Math.floor((11 * length) / 33); + const entropy = Random.getBytes(entropyLength); + const mnemonic = Bip39.encode(entropy); + return DirectSecp256k1HdWallet.fromMnemonic(mnemonic.toString(), options); + } + + /** + * Restores a wallet from an encrypted serialization. + * + * @param password The user provided password used to generate an encryption key via a KDF. + * This is not normalized internally (see "Unicode normalization" to learn more). + */ + static async deserialize(serialization: string, password: string): Promise { + const root = JSON.parse(serialization); + if (!isNonNullObject(root)) throw new Error("Root document is not an object."); + switch ((root as any).type) { + case serializationTypeV1: + return DirectSecp256k1HdWallet.deserializeTypeV1(serialization, password); + default: + throw new Error("Unsupported serialization type"); + } + } + /** + * Restores a wallet from an encrypted serialization. + * + * This is an advanced alternative to calling `deserialize(serialization, password)` directly, which allows + * you to offload the KDF execution to a non-UI thread (e.g. in a WebWorker). + * + * The caller is responsible for ensuring the key was derived with the given KDF configuration. This can be + * done using `extractKdfConfiguration(serialization)` and `executeKdf(password, kdfConfiguration)` from this package. + */ + static async deserializeWithEncryptionKey(serialization: string, encryptionKey: Uint8Array): Promise { + const root = JSON.parse(serialization); + if (!isNonNullObject(root)) throw new Error("Root document is not an object."); + const untypedRoot: any = root; + switch (untypedRoot.type) { + case serializationTypeV1: { + const decryptedBytes = await decrypt(fromBase64(untypedRoot.data), encryptionKey, untypedRoot.encryption); + const decryptedDocument = JSON.parse(fromUtf8(decryptedBytes)); + const { mnemonic, accounts } = decryptedDocument; + assert(typeof mnemonic === "string"); + if (!Array.isArray(accounts)) throw new Error("Property 'accounts' is not an array"); + if (!accounts.every((account) => isDerivationJson(account))) { + throw new Error("Account is not in the correct format."); + } + const firstPrefix = accounts[0].prefix; + if (!accounts.every(({ prefix }) => prefix === firstPrefix)) { + throw new Error("Accounts do not all have the same prefix"); + } + const hdPaths = accounts.map(({ hdPath }) => stringToPath(hdPath)); + return DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { + hdPaths: hdPaths, + prefix: firstPrefix, + }); + } + default: + throw new Error("Unsupported serialization type"); + } + } + + private static async deserializeTypeV1(serialization: string, password: string): Promise { + const root = JSON.parse(serialization); + if (!isNonNullObject(root)) throw new Error("Root document is not an object."); + const encryptionKey = await executeKdf(password, (root as any).kdf); + return DirectSecp256k1HdWallet.deserializeWithEncryptionKey(serialization, encryptionKey); + } + + /** Base secret */ + private readonly secret: EnglishMnemonic; + /** BIP39 seed */ + private readonly seed: Uint8Array; + /** Derivation instructions */ + private readonly accounts: readonly Secp256k1Derivation[]; + + protected constructor(mnemonic: EnglishMnemonic, options: DirectSecp256k1HdWalletConstructorOptions) { + const prefix = options.prefix ?? defaultOptions.prefix; + const hdPaths = options.hdPaths ?? defaultOptions.hdPaths; + this.secret = mnemonic; + this.seed = options.seed; + this.accounts = hdPaths.map((hdPath) => ({ + hdPath: hdPath, + prefix: prefix, + })); + } + + get mnemonic(): string { + return this.secret.toString(); + } + + async getAccounts(): Promise { + const accountsWithPrivkeys = await this.getAccountsWithPrivkeys(); + return accountsWithPrivkeys.map(({ algo, pubkey, address }) => ({ + algo: algo, + pubkey: pubkey, + address: address, + })); + } + + async signDirect(signerAddress: string, signDoc: SignDoc): Promise { + const accounts = await this.getAccountsWithPrivkeys(); + const account = accounts.find(({ address }) => address === signerAddress); + if (account === undefined) { + throw new Error(`Address ${signerAddress} not found in wallet`); + } + const { privkey, pubkey } = account; + const signBytes = makeSignBytes(signDoc); + const hashedMessage = sha256(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 + return { + signed: signDoc, + signature: stdSignature, + }; + } + + /** + * Generates an encrypted serialization of this wallet. + * + * @param password The user provided password used to generate an encryption key via a KDF. + * This is not normalized internally (see "Unicode normalization" to learn more). + */ + async serialize(password: string): Promise { + const kdfConfiguration = basicPasswordHashingOptions; + const encryptionKey = await executeKdf(password, kdfConfiguration); + return this.serializeWithEncryptionKey(encryptionKey, kdfConfiguration); + } + + /** + * Generates an encrypted serialization of this wallet. + * + * This is an advanced alternative to calling `serialize(password)` directly, which allows you to + * offload the KDF execution to a non-UI thread (e.g. in a WebWorker). + * + * The caller is responsible for ensuring the key was derived with the given KDF options. If this + * is not the case, the wallet cannot be restored with the original password. + */ + async serializeWithEncryptionKey(encryptionKey: Uint8Array, kdfConfiguration: KdfConfiguration): Promise { + const dataToEncrypt: DirectSecp256k1HdWalletData = { + mnemonic: this.mnemonic, + accounts: this.accounts.map(({ hdPath, prefix }) => ({ + hdPath: pathToString(hdPath), + prefix: prefix, + })), + }; + const dataToEncryptRaw = toUtf8(JSON.stringify(dataToEncrypt)); + + const encryptionConfiguration: EncryptionConfiguration = { + algorithm: supportedAlgorithms.xchacha20poly1305Ietf, + }; + const encryptedData = await encrypt(dataToEncryptRaw, encryptionKey, encryptionConfiguration); + + const out: DirectSecp256k1HdWalletSerialization = { + type: serializationTypeV1, + kdf: kdfConfiguration, + encryption: encryptionConfiguration, + data: toBase64(encryptedData), + }; + return JSON.stringify(out); + } + + private async getKeyPair(hdPath: HdPath): Promise { + const { privkey } = Slip10.derivePath(Slip10Curve.Secp256k1, this.seed, hdPath); + const { pubkey } = await Secp256k1.makeKeypair(privkey); + return { + privkey: privkey, + pubkey: Secp256k1.compressPubkey(pubkey), + }; + } + + private async getAccountsWithPrivkeys(): Promise { + return Promise.all( + this.accounts.map(async ({ hdPath, prefix }) => { + const { privkey, pubkey } = await this.getKeyPair(hdPath); + // Use Ethereum-style address derivation for Ethermint chains + const addressBytes = ethermintPubkeyToRawAddress(pubkey); + const address = toBech32(prefix, addressBytes); + return { + algo: "secp256k1" as const, + privkey: privkey, + pubkey: pubkey, + address: address, + }; + }), + ); + } +} diff --git a/modules/cosmos/src/modules/ibc/signingstartgateclient.ts b/modules/cosmos/src/modules/ibc/signingstartgateclient.ts new file mode 100644 index 0000000..e7d342b --- /dev/null +++ b/modules/cosmos/src/modules/ibc/signingstartgateclient.ts @@ -0,0 +1,411 @@ +/* eslint-disable jsdoc/require-returns */ +/* eslint-disable jsdoc/require-jsdoc */ +import { makeSignDoc as makeSignDocAmino, StdFee } from "@cosmjs/amino"; +import { fromBase64 } from "@cosmjs/encoding"; +import { Int53, Uint53 } from "@cosmjs/math"; +import { + EncodeObject, + GeneratedType, + isOfflineDirectSigner, + makeAuthInfoBytes, + makeSignDoc, + OfflineSigner, + Registry, + TxBodyEncodeObject, +} from "@cosmjs/proto-signing"; +import { + StargateClientOptions, + AminoTypes, + GasPrice, + AminoConverters, + createAuthzAminoConverters, + createBankAminoConverters, + createDistributionAminoConverters, + createGovAminoConverters, + createStakingAminoConverters, + createIbcAminoConverters, + createFeegrantAminoConverters, + createVestingAminoConverters, + StargateClient, + DeliverTxResponse, + MsgSendEncodeObject, + MsgDelegateEncodeObject, + MsgUndelegateEncodeObject, + MsgWithdrawDelegatorRewardEncodeObject, + MsgTransferEncodeObject, + calculateFee, +} from "@cosmjs/stargate"; +import { + authzTypes, + bankTypes, + distributionTypes, + feegrantTypes, + govTypes, + groupTypes, + stakingTypes, + ibcTypes, + vestingTypes, +} from "@cosmjs/stargate/build/modules"; +import { CometClient, connectComet, HttpEndpoint } from "@cosmjs/tendermint-rpc"; +import { assert, assertDefined } from "@cosmjs/utils"; +import { Coin } from "cosmjs-types/cosmos/base/v1beta1/coin"; +import { MsgWithdrawDelegatorReward } from "cosmjs-types/cosmos/distribution/v1beta1/tx"; +import { MsgDelegate, MsgUndelegate } from "cosmjs-types/cosmos/staking/v1beta1/tx"; +import { SignMode } from "cosmjs-types/cosmos/tx/signing/v1beta1/signing"; +import { TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx"; +import { MsgTransfer } from "cosmjs-types/ibc/applications/transfer/v1/tx"; +import { Height } from "cosmjs-types/ibc/core/client/v1/client"; +import { encodeSecp256k1Pubkey } from "./secp256k1"; +import { encodePubkey } from "./pubkey"; + +export const defaultRegistryTypes: ReadonlyArray<[string, GeneratedType]> = [ + ["/cosmos.base.v1beta1.Coin", Coin], + ...authzTypes, + ...bankTypes, + ...distributionTypes, + ...feegrantTypes, + ...govTypes, + ...groupTypes, + ...stakingTypes, + ...ibcTypes, + ...vestingTypes, +]; + +/** + * Signing information for a single signer that is not included in the transaction. + * @see https://github.com/cosmos/cosmos-sdk/blob/v0.42.2/x/auth/signing/sign_mode_handler.go#L23-L37 + */ +export interface SignerData { + readonly accountNumber: number; + readonly sequence: number; + readonly chainId: string; +} + +/** Use for testing only */ +export interface PrivateSigningStargateClient { + readonly registry: Registry; +} + +export interface SigningStargateClientOptions extends StargateClientOptions { + readonly registry?: Registry; + readonly aminoTypes?: AminoTypes; + readonly broadcastTimeoutMs?: number; + readonly broadcastPollIntervalMs?: number; + readonly gasPrice?: GasPrice; +} + +export function createDefaultAminoConverters(): AminoConverters { + return { + ...createAuthzAminoConverters(), + ...createBankAminoConverters(), + ...createDistributionAminoConverters(), + ...createGovAminoConverters(), + ...createStakingAminoConverters(), + ...createIbcAminoConverters(), + ...createFeegrantAminoConverters(), + ...createVestingAminoConverters(), + }; +} + +export class SigningStargateClient extends StargateClient { + readonly registry: Registry; + readonly broadcastTimeoutMs: number | undefined; + readonly broadcastPollIntervalMs: number | undefined; + + private readonly signer: OfflineSigner; + private readonly aminoTypes: AminoTypes; + private readonly gasPrice: GasPrice | undefined; + // Starting with Cosmos SDK 0.47, we see many cases in which 1.3 is not enough anymore + // E.g. https://github.com/cosmos/cosmos-sdk/issues/16020 + private readonly defaultGasMultiplier = 1.4; + + static async connectWithSigner( + endpoint: string | HttpEndpoint, + signer: OfflineSigner, + options: SigningStargateClientOptions = {}, + ): Promise { + const cometClient = await connectComet(endpoint); + return SigningStargateClient.createWithSigner(cometClient, signer, options); + } + + static async createWithSigner( + cometClient: CometClient, + signer: OfflineSigner, + options: SigningStargateClientOptions = {}, + ): Promise { + return new SigningStargateClient(cometClient, signer, options); + } + + static async offline(signer: OfflineSigner, options: SigningStargateClientOptions = {}): Promise { + return new SigningStargateClient(undefined, signer, options); + } + + protected constructor(cometClient: CometClient | undefined, signer: OfflineSigner, options: SigningStargateClientOptions) { + super(cometClient, options); + const { registry = new Registry(defaultRegistryTypes), aminoTypes = new AminoTypes(createDefaultAminoConverters()) } = options; + this.registry = registry; + this.aminoTypes = aminoTypes; + this.signer = signer; + this.broadcastTimeoutMs = options.broadcastTimeoutMs; + this.broadcastPollIntervalMs = options.broadcastPollIntervalMs; + this.gasPrice = options.gasPrice; + } + + async simulate(signerAddress: string, messages: readonly EncodeObject[], memo: string | undefined): Promise { + const anyMsgs = messages.map((m) => this.registry.encodeAsAny(m)); + const accountFromSigner = (await this.signer.getAccounts()).find((account) => account.address === signerAddress); + if (!accountFromSigner) { + throw new Error("Failed to retrieve account from signer"); + } + const pubkey = encodeSecp256k1Pubkey(accountFromSigner.pubkey, true); // true for Ethermint + const { sequence } = await this.getSequence(signerAddress); + const { gasInfo } = await this.forceGetQueryClient().tx.simulate(anyMsgs, memo, pubkey, sequence); + assertDefined(gasInfo); + return Uint53.fromString(gasInfo.gasUsed.toString()).toNumber(); + } + + async sendTokens( + senderAddress: string, + recipientAddress: string, + amount: readonly Coin[], + fee: StdFee | "auto" | number, + memo = "", + ): Promise { + const sendMsg: MsgSendEncodeObject = { + typeUrl: "/cosmos.bank.v1beta1.MsgSend", + value: { + fromAddress: senderAddress, + toAddress: recipientAddress, + amount: [...amount], + }, + }; + return this.signAndBroadcast(senderAddress, [sendMsg], fee, memo); + } + + async delegateTokens( + delegatorAddress: string, + validatorAddress: string, + amount: Coin, + fee: StdFee | "auto" | number, + memo = "", + ): Promise { + const delegateMsg: MsgDelegateEncodeObject = { + typeUrl: "/cosmos.staking.v1beta1.MsgDelegate", + value: MsgDelegate.fromPartial({ + delegatorAddress: delegatorAddress, + validatorAddress: validatorAddress, + amount: amount, + }), + }; + return this.signAndBroadcast(delegatorAddress, [delegateMsg], fee, memo); + } + + async undelegateTokens( + delegatorAddress: string, + validatorAddress: string, + amount: Coin, + fee: StdFee | "auto" | number, + memo = "", + ): Promise { + const undelegateMsg: MsgUndelegateEncodeObject = { + typeUrl: "/cosmos.staking.v1beta1.MsgUndelegate", + value: MsgUndelegate.fromPartial({ + delegatorAddress: delegatorAddress, + validatorAddress: validatorAddress, + amount: amount, + }), + }; + return this.signAndBroadcast(delegatorAddress, [undelegateMsg], fee, memo); + } + + async withdrawRewards( + delegatorAddress: string, + validatorAddress: string, + fee: StdFee | "auto" | number, + memo = "", + ): Promise { + const withdrawMsg: MsgWithdrawDelegatorRewardEncodeObject = { + typeUrl: "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward", + value: MsgWithdrawDelegatorReward.fromPartial({ + delegatorAddress: delegatorAddress, + validatorAddress: validatorAddress, + }), + }; + return this.signAndBroadcast(delegatorAddress, [withdrawMsg], fee, memo); + } + + async sendIbcTokens( + senderAddress: string, + recipientAddress: string, + transferAmount: Coin, + sourcePort: string, + sourceChannel: string, + timeoutHeight: Height | undefined, + /** timeout in seconds */ + timeoutTimestamp: number | undefined, + fee: StdFee | "auto" | number, + memo = "", + ): Promise { + const timeoutTimestampNanoseconds = timeoutTimestamp ? BigInt(timeoutTimestamp) * BigInt(1_000_000_000) : undefined; + const transferMsg: MsgTransferEncodeObject = { + typeUrl: "/ibc.applications.transfer.v1.MsgTransfer", + value: MsgTransfer.fromPartial({ + sourcePort: sourcePort, + sourceChannel: sourceChannel, + sender: senderAddress, + receiver: recipientAddress, + token: transferAmount, + timeoutHeight: timeoutHeight, + timeoutTimestamp: timeoutTimestampNanoseconds, + }), + }; + return this.signAndBroadcast(senderAddress, [transferMsg], fee, memo); + } + + async signAndBroadcast( + signerAddress: string, + messages: readonly EncodeObject[], + fee: StdFee | "auto" | number, + memo = "", + timeoutHeight?: bigint, + ): Promise { + let usedFee: StdFee; + if (fee == "auto" || typeof fee === "number") { + assertDefined(this.gasPrice, "Gas price must be set in the client options when auto gas is used."); + const gasEstimation = await this.simulate(signerAddress, messages, memo); + const multiplier = typeof fee === "number" ? fee : this.defaultGasMultiplier; + usedFee = calculateFee(Math.round(gasEstimation * multiplier), this.gasPrice); + } else { + usedFee = fee; + } + const txRaw = await this.sign(signerAddress, messages, usedFee, memo, undefined, timeoutHeight); + const txBytes = TxRaw.encode(txRaw).finish(); + return this.broadcastTx(txBytes, this.broadcastTimeoutMs, this.broadcastPollIntervalMs); + } + + async signAndBroadcastSync( + signerAddress: string, + messages: readonly EncodeObject[], + fee: StdFee | "auto" | number, + memo = "", + timeoutHeight?: bigint, + ): Promise { + let usedFee: StdFee; + if (fee == "auto" || typeof fee === "number") { + assertDefined(this.gasPrice, "Gas price must be set in the client options when auto gas is used."); + const gasEstimation = await this.simulate(signerAddress, messages, memo); + const multiplier = typeof fee === "number" ? fee : this.defaultGasMultiplier; + usedFee = calculateFee(Math.round(gasEstimation * multiplier), this.gasPrice); + } else { + usedFee = fee; + } + const txRaw = await this.sign(signerAddress, messages, usedFee, memo, undefined, timeoutHeight); + const txBytes = TxRaw.encode(txRaw).finish(); + return this.broadcastTxSync(txBytes); + } + + async sign( + signerAddress: string, + messages: readonly EncodeObject[], + fee: StdFee, + memo: string, + explicitSignerData?: SignerData, + timeoutHeight?: bigint, + ): Promise { + let signerData: SignerData; + if (explicitSignerData) { + signerData = explicitSignerData; + } else { + const { accountNumber, sequence } = await this.getSequence(signerAddress); + const chainId = await this.getChainId(); + signerData = { + accountNumber: accountNumber, + sequence: sequence, + chainId: chainId, + }; + } + + return isOfflineDirectSigner(this.signer) + ? this.signDirect(signerAddress, messages, fee, memo, signerData, timeoutHeight) + : this.signAmino(signerAddress, messages, fee, memo, signerData, timeoutHeight); + } + + private async signAmino( + signerAddress: string, + messages: readonly EncodeObject[], + fee: StdFee, + memo: string, + { accountNumber, sequence, chainId }: SignerData, + timeoutHeight?: bigint, + ): Promise { + assert(!isOfflineDirectSigner(this.signer)); + const accountFromSigner = (await this.signer.getAccounts()).find((account) => account.address === signerAddress); + if (!accountFromSigner) { + throw new Error("Failed to retrieve account from signer"); + } + const pubkey = encodePubkey(encodeSecp256k1Pubkey(accountFromSigner.pubkey, true)); // true for Ethermint + const signMode = SignMode.SIGN_MODE_LEGACY_AMINO_JSON; + const msgs = messages.map((msg) => this.aminoTypes.toAmino(msg)); + const signDoc = makeSignDocAmino(msgs, fee, chainId, memo, accountNumber, sequence, timeoutHeight); + const { signature, signed } = await this.signer.signAmino(signerAddress, signDoc); + const signedTxBody = { + messages: signed.msgs.map((msg) => this.aminoTypes.fromAmino(msg)), + memo: signed.memo, + timeoutHeight: timeoutHeight, + }; + const signedTxBodyEncodeObject: TxBodyEncodeObject = { + typeUrl: "/cosmos.tx.v1beta1.TxBody", + value: signedTxBody, + }; + const signedTxBodyBytes = this.registry.encode(signedTxBodyEncodeObject); + const signedGasLimit = Int53.fromString(signed.fee.gas).toNumber(); + const signedSequence = Int53.fromString(signed.sequence).toNumber(); + const signedAuthInfoBytes = makeAuthInfoBytes( + [{ pubkey, sequence: signedSequence }], + signed.fee.amount, + signedGasLimit, + signed.fee.granter, + signed.fee.payer, + signMode, + ); + return TxRaw.fromPartial({ + bodyBytes: signedTxBodyBytes, + authInfoBytes: signedAuthInfoBytes, + signatures: [fromBase64(signature.signature)], + }); + } + + private async signDirect( + signerAddress: string, + messages: readonly EncodeObject[], + fee: StdFee, + memo: string, + { accountNumber, sequence, chainId }: SignerData, + timeoutHeight?: bigint, + ): Promise { + assert(isOfflineDirectSigner(this.signer)); + const accountFromSigner = (await this.signer.getAccounts()).find((account) => account.address === signerAddress); + if (!accountFromSigner) { + throw new Error("Failed to retrieve account from signer"); + } + const pubkey = encodePubkey(encodeSecp256k1Pubkey(accountFromSigner.pubkey, true)); // true for Ethermint + const txBodyEncodeObject: TxBodyEncodeObject = { + typeUrl: "/cosmos.tx.v1beta1.TxBody", + value: { + messages: messages, + memo: memo, + timeoutHeight: timeoutHeight, + }, + }; + const txBodyBytes = this.registry.encode(txBodyEncodeObject); + const gasLimit = Int53.fromString(fee.gas).toNumber(); + const authInfoBytes = makeAuthInfoBytes([{ pubkey, sequence }], fee.amount, gasLimit, fee.granter, fee.payer); + const signDoc = makeSignDoc(txBodyBytes, authInfoBytes, chainId, accountNumber); + const { signature, signed } = await this.signer.signDirect(signerAddress, signDoc); + return TxRaw.fromPartial({ + bodyBytes: signed.bodyBytes, + authInfoBytes: signed.authInfoBytes, + signatures: [fromBase64(signature.signature)], + }); + } +} diff --git a/modules/cosmos/src/modules/ibc/utils.ts b/modules/cosmos/src/modules/ibc/utils.ts new file mode 100644 index 0000000..dc59c29 --- /dev/null +++ b/modules/cosmos/src/modules/ibc/utils.ts @@ -0,0 +1,92 @@ +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 { makeCosmoshubPath } from "@cosmjs/amino"; +import { stringToPath } from "@cosmjs/crypto"; + +/** + * Format the test name for IBC transfer. + * @param chainPair The chain pair configuration. + * @returns The formatted test name. + */ +export function formatIBCTestname(chainPair: IBCChainPair): string { + const direction = chainPair.roundtrip ? "<->" : "->"; + return `${chainPair.srcChain.chainId} ${direction} ${chainPair.dstChain.chainId}`; +} + +/** + * Extract the packet sequence from the logs. + * @param events The events to extract the packet sequence from. + * @returns The packet sequence. + */ +export function extractPacketSequenceFromLogs(events: readonly any[]): string | undefined { + const event = events.find((event) => event.type === "send_packet"); + const attr = event?.attributes.find((attr: any) => attr.key === "packet_sequence"); + return attr?.value; +} + +/** + * Verify the IBC packet acknowledgement. + * @param client The client. + * @param channelId The channel ID. + * @param sequence The packet sequence. + * @returns True if the packet was received, false otherwise. + */ +export async function verifyIbcPacketAcknowledgement(client: StargateClient, channelId: string, sequence: string) { + const searchKey = `recv_packet.packet_sequence='${sequence}' AND recv_packet.packet_dst_channel='${channelId}'`; + + const results = await client.searchTx(searchKey); + + return results.length > 0; +} + +/** + * Load the IBC chain client and sender. + * @param chain The chain configuration. + * @returns The client and sender. + */ +export async function loadIbcChain(chain: IBCChain) { + const wallet = chain.evm + ? await EvmDirectSecp256k1HdWallet.fromMnemonic(chain.account.mnemonic, { + prefix: chain.prefix, + hdPaths: [stringToPath("m/44'/60'/0'/0/0")], // Ethereum derivation path + }) + : await DirectSecp256k1HdWallet.fromMnemonic(chain.account.mnemonic, { + prefix: chain.prefix, + hdPaths: [makeCosmoshubPath(0)], // Standard Cosmos derivation path + }); + const client = chain.evm + ? await IBCEvmSignerClient.connectWithSigner(chain.rpcUrl, wallet) + : await SigningStargateClient.connectWithSigner(chain.rpcUrl, wallet); + + const accounts = await wallet.getAccounts(); + const sender = accounts[0].address; + + return { client, sender, accounts }; +} + +/** + * Calculate timeout height for IBC transfer. + * @param client The destination chain client. + * @param heightBuffer The number of blocks to add as buffer (default: 1000). + * @returns The timeout height object. + */ +export async function calculateTimeoutHeight(client: StargateClient, heightBuffer: number = 1000) { + const currentHeight = await client.getHeight(); + return { + revisionNumber: 1, + revisionHeight: currentHeight + heightBuffer, + }; +} + +/** + * Calculate timeout timestamp for IBC transfer. + * @param timeoutMinutes The number of minutes from now for timeout (default: 10). + * @returns The timeout timestamp in nanoseconds. + */ +export function calculateTimeoutTimestamp(timeoutMinutes: number = 10): bigint { + const timeoutMs = Date.now() + timeoutMinutes * 60 * 1000; + return BigInt(timeoutMs) * BigInt(1000000); // Convert to nanoseconds +} diff --git a/modules/cosmos/test/modules/ibc/index.test.ts b/modules/cosmos/test/modules/ibc/index.test.ts new file mode 100644 index 0000000..0ef7edc --- /dev/null +++ b/modules/cosmos/test/modules/ibc/index.test.ts @@ -0,0 +1,132 @@ +import { coins } from "@cosmjs/proto-signing"; +import { assertIsDeliverTxSuccess } from "@cosmjs/stargate"; +import config from "../../../module.config.json"; +import { + extractPacketSequenceFromLogs, + formatIBCTestname, + loadIbcChain, + verifyIbcPacketAcknowledgement, + calculateTimeoutHeight, + calculateTimeoutTimestamp, +} from "../../../src/modules/ibc/utils"; +import { expect } from "chai"; +import { polling } from "@shared/utils"; +import { describeOrSkip } from "@testing/mocha/utils"; +import { isChainEnvironment, isChainType } from "@testing/mocha/assertions"; +import { Chain } from "@firewatch/core/chain"; + +describeOrSkip( + "IBCModule", + () => { + return ( + isChainType(["cosmos"], config.network as unknown as Chain) && + isChainEnvironment(["testnet", "mainnet"], config.network as unknown as Chain) + ); + }, + () => { + const { ibc: ibcConfig } = config; + + for (const chainPair of ibcConfig.chains) { + describe(formatIBCTestname(chainPair), () => { + const { srcChain, dstChain } = chainPair; + + let srcClient: any; + let srcSender: string; + let dstClient: any; + let dstSender: string; + + before(async () => { + const srcChainData = await loadIbcChain(srcChain); + const dstChainData = await loadIbcChain(dstChain); + + srcClient = srcChainData.client; + srcSender = srcChainData.sender; + dstClient = dstChainData.client; + dstSender = dstChainData.sender; + + console.log("srcSender", srcSender); + console.log("dstSender", dstSender); + }); + + it(`should transfer ${srcChain.amount} ${srcChain.denom} from ${srcChain.chainId} to ${dstChain.chainId}`, async () => { + // Calculate dynamic timeout height and timestamp + const timeoutHeight = await calculateTimeoutHeight(dstClient, 1000); + const timeoutTimestamp = calculateTimeoutTimestamp(10); // 10 minutes + + const result = await srcClient.sendIbcTokens( + srcSender, + dstSender, + { + denom: srcChain.denom, + amount: srcChain.amount, + }, + "transfer", + srcChain.channel, + timeoutHeight, + timeoutTimestamp, + { + amount: coins(srcChain.gas.amount, srcChain.denom), + gas: srcChain.gas.gas, + }, + ); + + assertIsDeliverTxSuccess(result); + + const txDetails = await srcClient.getTx(result.transactionHash); + const sequence = extractPacketSequenceFromLogs(txDetails.events); + + expect(sequence).to.not.equal(undefined); + + const isPacketReceived = await polling( + async () => await verifyIbcPacketAcknowledgement(dstClient, dstChain.channel, sequence!), + (res) => !res, + { + delay: 10000, + maxIterations: 12, + }, + ); + expect(isPacketReceived).to.equal(true); + }); + + it(`should transfer ${dstChain.amount} ${dstChain.denom} from ${dstChain.chainId} to ${srcChain.chainId}`, async () => { + const timeoutHeight = await calculateTimeoutHeight(srcClient, 1000); + const timeoutTimestamp = calculateTimeoutTimestamp(10); // 10 minutes + + const result = await dstClient.sendIbcTokens( + dstSender, + srcSender, + { + denom: dstChain.denom, + amount: dstChain.amount, + }, + "transfer", + dstChain.channel, + timeoutHeight, + timeoutTimestamp, + { + amount: coins(dstChain.gas.amount, dstChain.denom), + gas: dstChain.gas.gas, + }, + ); + + assertIsDeliverTxSuccess(result); + + const txDetails = await dstClient.getTx(result.transactionHash); + const sequence = extractPacketSequenceFromLogs(txDetails.events); + + expect(sequence).to.not.equal(undefined); + + const isPacketReceived = await polling( + async () => await verifyIbcPacketAcknowledgement(srcClient, srcChain.channel, sequence!), + (res) => !res, + { + delay: 10000, + maxIterations: 12, + }, + ); + expect(isPacketReceived).to.equal(true); + }); + }); + } + }, +); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d5ba371..ca9ce07 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -93,15 +93,30 @@ importers: modules/cosmos: dependencies: + '@cosmjs/amino': + specifier: ^0.33.1 + version: 0.33.1 + '@cosmjs/crypto': + specifier: ^0.33.1 + version: 0.33.1 '@cosmjs/encoding': specifier: ^0.33.1 version: 0.33.1 + '@cosmjs/math': + specifier: ^0.33.1 + version: 0.33.1 + '@cosmjs/proto-signing': + specifier: ^0.33.1 + version: 0.33.1 '@cosmjs/stargate': specifier: ^0.33.0 version: 0.33.0(bufferutil@4.0.5)(utf-8-validate@5.0.7) '@cosmjs/tendermint-rpc': specifier: ^0.33.1 version: 0.33.1(bufferutil@4.0.5)(utf-8-validate@5.0.7) + '@cosmjs/utils': + specifier: ^0.33.1 + version: 0.33.1 '@types/chai': specifier: ^5.0.1 version: 5.0.1 @@ -121,21 +136,27 @@ importers: '@shared/tsconfig': specifier: workspace:* version: link:../../packages/shared/tsconfig + '@shared/utils': + specifier: workspace:* + version: link:../../packages/shared/utils '@testing/mocha': specifier: workspace:* version: link:../../packages/testing/mocha '@types/mocha': specifier: ^10.0.10 version: 10.0.10 + '@types/node': + specifier: ^24.0.10 + version: 24.0.10 modules/evm: 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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7)) '@nomicfoundation/hardhat-toolbox': specifier: ^5.0.0 - version: 5.0.0(5rgkbdcfgwydeecayhmawagj2a) + version: 5.0.0(tmi2zvp4rmzs6gbbp2lln5p26u) bignumber.js: specifier: ^9.1.2 version: 9.1.2 @@ -147,7 +168,7 @@ 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@22.15.27)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) + version: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) devDependencies: '@firewatch/core': specifier: workspace:* @@ -224,16 +245,16 @@ 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@22.15.19)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3)) + version: 29.7.0(@types/node@24.0.10)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.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@22.15.19)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3)))(typescript@5.8.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@24.0.10)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3)))(typescript@5.8.3) typescript: specifier: latest version: 5.8.3 xchain-sdk: specifier: ^1.2.2 - version: 1.2.5(bufferutil@4.0.5)(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7))(utf-8-validate@5.0.7) + version: 1.2.5(bufferutil@4.0.5)(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7))(utf-8-validate@5.0.7) xrpl: specifier: 3.0.0 version: 3.0.0(bufferutil@4.0.5)(utf-8-validate@5.0.7) @@ -361,7 +382,7 @@ importers: version: 29.5.14 '@types/node': specifier: latest - version: 22.15.19 + version: 24.0.10 typescript: specifier: latest version: 5.8.3 @@ -394,7 +415,7 @@ importers: version: link:../tsup '@types/node': specifier: latest - version: 22.15.19 + version: 24.0.10 bignumber.js: specifier: ^9.1.2 version: 9.1.2 @@ -414,7 +435,7 @@ importers: version: link:../tsconfig '@types/node': specifier: latest - version: 22.15.19 + version: 24.0.10 tsup: specifier: ^8.2.4 version: 8.3.6(typescript@5.8.3) @@ -438,13 +459,13 @@ importers: version: 29.5.14 '@types/node': specifier: latest - version: 22.15.19 + version: 24.0.10 '@types/validator': specifier: ^13.12.1 version: 13.12.2 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@22.15.19)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3)) + version: 29.7.0(@types/node@24.0.10)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3)) typescript: specifier: latest version: 5.8.3 @@ -471,10 +492,10 @@ importers: version: 29.5.14 '@types/node': specifier: latest - version: 22.15.19 + version: 24.0.10 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@22.15.19)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3)) + version: 29.7.0(@types/node@24.0.10)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3)) typescript: specifier: latest version: 5.8.3 @@ -499,10 +520,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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7)) '@shared/eslint': specifier: workspace:* version: link:../../shared/eslint @@ -523,7 +544,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@22.15.27)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) + version: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) packages/testing/mocha: dependencies: @@ -871,15 +892,12 @@ packages: '@cosmjs/amino@0.31.3': resolution: {integrity: sha512-36emtUq895sPRX8PTSOnG+lhJDCVyIcE0Tr5ct59sUbgQiI14y43vj/4WAlJ/utSOxy+Zhj9wxcs4AZfu0BHsw==} - '@cosmjs/amino@0.33.0': - resolution: {integrity: sha512-a4qnWGzuM2IrlkDTFQmU7bDd+wNIzyvfcRIZ43i00ZHvTEtrCcWopT94rIv/Zy6fdgkhQ3HWrsGVlIPDT/ibRw==} + '@cosmjs/amino@0.33.1': + resolution: {integrity: sha512-WfWiBf2EbIWpwKG9AOcsIIkR717SY+JdlXM/SL/bI66BdrhniAF+/ZNis9Vo9HF6lP2UU5XrSmFA4snAvEgdrg==} '@cosmjs/crypto@0.31.3': resolution: {integrity: sha512-vRbvM9ZKR2017TO73dtJ50KxoGcFzKtKI7C8iO302BQ5p+DuB+AirUg1952UpSoLfv5ki9O416MFANNg8UN/EQ==} - '@cosmjs/crypto@0.33.0': - resolution: {integrity: sha512-kkt06t+cFW2XRGDGUZ0cVf5yoQ2OhZnubwbYbz3QXdyhf1qOXYVPRThfFPsko7dssr+e8Yy4OJKlh5SLA8DXTQ==} - '@cosmjs/crypto@0.33.1': resolution: {integrity: sha512-U4kGIj/SNBzlb2FGgA0sMR0MapVgJUg8N+oIAiN5+vl4GZ3aefmoL1RDyTrFS/7HrB+M+MtHsxC0tvEu4ic/zA==} @@ -901,17 +919,14 @@ packages: '@cosmjs/math@0.31.3': resolution: {integrity: sha512-kZ2C6glA5HDb9hLz1WrftAjqdTBb3fWQsRR+Us2HsjAYdeE6M3VdXMsYCP5M3yiihal1WDwAY2U7HmfJw7Uh4A==} - '@cosmjs/math@0.33.0': - resolution: {integrity: sha512-B2uOgM12iuIhJWzGuAxGwO6zO+cI8Q4z7mVu7HgFrGJJTM1HtPTYgb55oMOuUN0OZ352MEEm5uAt8sA9jZQqbA==} - '@cosmjs/math@0.33.1': resolution: {integrity: sha512-ytGkWdKFCPiiBU5eqjHNd59djPpIsOjbr2CkNjlnI1Zmdj+HDkSoD9MUGpz9/RJvRir5IvsXqdE05x8EtoQkJA==} '@cosmjs/proto-signing@0.31.3': resolution: {integrity: sha512-24+10/cGl6lLS4VCrGTCJeDRPQTn1K5JfknzXzDIHOx8THR31JxA7/HV5eWGHqWgAbudA7ccdSvEK08lEHHtLA==} - '@cosmjs/proto-signing@0.33.0': - resolution: {integrity: sha512-UHA92d/Siy3wnce/xhU4iagKrs6r8Ruacc0qeHj3mNrtuUH8f70cD7lzzClzI7wvRLcPprOY0YTeEzqGbPeBFw==} + '@cosmjs/proto-signing@0.33.1': + resolution: {integrity: sha512-Sv4W+MxX+0LVnd+2rU4Fw1HRsmMwSVSYULj7pRkij3wnPwUlTVoJjmKFgKz13ooIlfzPrz/dnNjGp/xnmXChFQ==} '@cosmjs/socket@0.31.3': resolution: {integrity: sha512-aqrDGGi7os/hsz5p++avI4L0ZushJ+ItnzbqA7C6hamFSCJwgOkXaOUs+K9hXZdX4rhY7rXO4PH9IH8q09JkTw==} @@ -946,9 +961,6 @@ packages: '@cosmjs/utils@0.31.3': resolution: {integrity: sha512-VBhAgzrrYdIe0O5IbKRqwszbQa7ZyQLx9nEQuHQ3HUplQW7P44COG/ye2n6AzCudtqxmwdX7nyX8ta1J07GoqA==} - '@cosmjs/utils@0.33.0': - resolution: {integrity: sha512-Y6glwHNlNjcOgwPg8YmNr1PSrNm307EhJVytFt8HmA/G7MRcIA+jIzCL0VlOrWGU4TrAOXvshM+oJZbTIldFRA==} - '@cosmjs/utils@0.33.1': resolution: {integrity: sha512-UnLHDY6KMmC+UXf3Ufyh+onE19xzEXjT4VZ504Acmk4PXxqyvG4cCPprlKUFnGUX7f0z8Or9MAOHXBx41uHBcg==} @@ -2291,15 +2303,12 @@ packages: '@types/node@22.13.4': resolution: {integrity: sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==} - '@types/node@22.15.19': - resolution: {integrity: sha512-3vMNr4TzNQyjHcRZadojpRaD9Ofr6LsonZAoQ+HMUa/9ORTPoxVIw0e0mpqWpdjj8xybyCM+oKOUH2vwFu/oEw==} - - '@types/node@22.15.27': - resolution: {integrity: sha512-5fF+eu5mwihV2BeVtX5vijhdaZOfkQTATrePEaXTcKqI16LhJ7gi2/Vhd9OZM0UojcdmiOCVg5rrax+i1MdoQQ==} - '@types/node@22.7.5': resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} + '@types/node@24.0.10': + resolution: {integrity: sha512-ENHwaH+JIRTDIEEbDK6QSQntAYGtbvdDXnMXnZaZ6k13Du1dPMmprkEHIL7ok2Wl2aZevetwTAb5S+7yIF+enA==} + '@types/node@8.10.66': resolution: {integrity: sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==} @@ -5984,8 +5993,8 @@ packages: undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici-types@7.8.0: + resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==} undici@5.28.5: resolution: {integrity: sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==} @@ -6886,12 +6895,12 @@ snapshots: '@cosmjs/math': 0.31.3 '@cosmjs/utils': 0.31.3 - '@cosmjs/amino@0.33.0': + '@cosmjs/amino@0.33.1': dependencies: - '@cosmjs/crypto': 0.33.0 + '@cosmjs/crypto': 0.33.1 '@cosmjs/encoding': 0.33.1 - '@cosmjs/math': 0.33.0 - '@cosmjs/utils': 0.33.0 + '@cosmjs/math': 0.33.1 + '@cosmjs/utils': 0.33.1 '@cosmjs/crypto@0.31.3': dependencies: @@ -6903,16 +6912,6 @@ snapshots: elliptic: 6.6.1 libsodium-wrappers-sumo: 0.7.15 - '@cosmjs/crypto@0.33.0': - dependencies: - '@cosmjs/encoding': 0.33.1 - '@cosmjs/math': 0.33.0 - '@cosmjs/utils': 0.33.0 - '@noble/hashes': 1.7.1 - bn.js: 5.2.1 - elliptic: 6.6.1 - libsodium-wrappers-sumo: 0.7.15 - '@cosmjs/crypto@0.33.1': dependencies: '@cosmjs/encoding': 0.33.1 @@ -6954,10 +6953,6 @@ snapshots: dependencies: bn.js: 5.2.1 - '@cosmjs/math@0.33.0': - dependencies: - bn.js: 5.2.1 - '@cosmjs/math@0.33.1': dependencies: bn.js: 5.2.1 @@ -6972,13 +6967,13 @@ snapshots: cosmjs-types: 0.8.0 long: 4.0.0 - '@cosmjs/proto-signing@0.33.0': + '@cosmjs/proto-signing@0.33.1': dependencies: - '@cosmjs/amino': 0.33.0 - '@cosmjs/crypto': 0.33.0 + '@cosmjs/amino': 0.33.1 + '@cosmjs/crypto': 0.33.1 '@cosmjs/encoding': 0.33.1 - '@cosmjs/math': 0.33.0 - '@cosmjs/utils': 0.33.0 + '@cosmjs/math': 0.33.1 + '@cosmjs/utils': 0.33.1 cosmjs-types: 0.9.0 '@cosmjs/socket@0.31.3(bufferutil@4.0.5)(utf-8-validate@5.0.7)': @@ -7022,13 +7017,13 @@ snapshots: '@cosmjs/stargate@0.33.0(bufferutil@4.0.5)(utf-8-validate@5.0.7)': dependencies: - '@cosmjs/amino': 0.33.0 + '@cosmjs/amino': 0.33.1 '@cosmjs/encoding': 0.33.1 - '@cosmjs/math': 0.33.0 - '@cosmjs/proto-signing': 0.33.0 + '@cosmjs/math': 0.33.1 + '@cosmjs/proto-signing': 0.33.1 '@cosmjs/stream': 0.33.0 '@cosmjs/tendermint-rpc': 0.33.1(bufferutil@4.0.5)(utf-8-validate@5.0.7) - '@cosmjs/utils': 0.33.0 + '@cosmjs/utils': 0.33.1 cosmjs-types: 0.9.0 transitivePeerDependencies: - bufferutil @@ -7087,8 +7082,6 @@ snapshots: '@cosmjs/utils@0.31.3': {} - '@cosmjs/utils@0.33.0': {} - '@cosmjs/utils@0.33.1': {} '@cspotcode/source-map-support@0.8.1': @@ -7851,27 +7844,27 @@ snapshots: '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 - '@types/node': 22.15.19 + '@types/node': 24.0.10 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3))': + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.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': 22.15.19 + '@types/node': 24.0.10 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@22.15.19)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3)) + jest-config: 29.7.0(@types/node@24.0.10)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -7896,7 +7889,7 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.15.19 + '@types/node': 24.0.10 jest-mock: 29.7.0 '@jest/expect-utils@29.7.0': @@ -7914,7 +7907,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 22.15.19 + '@types/node': 24.0.10 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -7936,7 +7929,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.25 - '@types/node': 22.15.19 + '@types/node': 24.0.10 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -8006,7 +7999,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 22.15.19 + '@types/node': 24.0.10 '@types/yargs': 17.0.33 chalk: 4.1.2 @@ -8148,43 +8141,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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) json5: 2.2.3 prompts: 2.4.2 transitivePeerDependencies: @@ -8192,44 +8185,39 @@ snapshots: - supports-color - utf-8-validate - '@nomicfoundation/hardhat-network-helpers@1.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3))(typescript@5.8.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@22.15.19)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) - '@nomicfoundation/hardhat-toolbox@5.0.0(5rgkbdcfgwydeecayhmawagj2a)': + '@nomicfoundation/hardhat-toolbox@5.0.0(tmi2zvp4rmzs6gbbp2lln5p26u)': 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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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.8.3))(typescript@5.8.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.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@5.8.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.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@5.8.3)) '@types/chai': 5.0.1 '@types/mocha': 10.0.10 - '@types/node': 22.15.27 + '@types/node': 24.0.10 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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7)) - ts-node: 10.9.2(@types/node@22.15.27)(typescript@5.8.3) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7)) + ts-node: 10.9.2(@types/node@24.0.10)(typescript@5.8.3) typechain: 8.3.2(typescript@5.8.3) typescript: 5.8.3 - '@nomicfoundation/hardhat-verify@2.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@22.15.27)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) lodash.clonedeep: 4.5.0 picocolors: 1.1.1 semver: 6.3.1 @@ -8287,22 +8275,22 @@ snapshots: '@nomicfoundation/solidity-analyzer-linux-x64-musl': 0.1.2 '@nomicfoundation/solidity-analyzer-win32-x64-msvc': 0.1.2 - '@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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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))(ethers@6.13.5(bufferutil@4.0.5)(utf-8-validate@5.0.7))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) - '@peersyst/xrp-evm-contracts@2.1.1(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7))': + '@peersyst/xrp-evm-contracts@2.1.1(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7))': dependencies: - '@nomicfoundation/hardhat-network-helpers': 1.0.12(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7)) transitivePeerDependencies: - hardhat @@ -8863,12 +8851,12 @@ snapshots: typechain: 8.3.2(typescript@5.8.3) typescript: 5.8.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.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@5.8.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.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7))(typechain@8.3.2(typescript@5.8.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.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) typechain: 8.3.2(typescript@5.8.3) '@types/abstract-leveldown@7.2.5': {} @@ -8896,11 +8884,11 @@ snapshots: '@types/bn.js@4.11.6': dependencies: - '@types/node': 22.15.19 + '@types/node': 24.0.10 '@types/bn.js@5.1.6': dependencies: - '@types/node': 22.15.19 + '@types/node': 24.0.10 '@types/chai-as-promised@7.1.8': dependencies: @@ -8912,7 +8900,7 @@ snapshots: '@types/concat-stream@1.6.1': dependencies: - '@types/node': 22.15.27 + '@types/node': 24.0.10 '@types/deep-eql@4.0.2': {} @@ -8920,16 +8908,16 @@ snapshots: '@types/form-data@0.0.33': dependencies: - '@types/node': 22.15.27 + '@types/node': 24.0.10 '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 22.15.27 + '@types/node': 24.0.10 '@types/graceful-fs@4.1.9': dependencies: - '@types/node': 22.15.19 + '@types/node': 24.0.10 '@types/istanbul-lib-coverage@2.0.6': {} @@ -8954,7 +8942,7 @@ snapshots: dependencies: '@types/abstract-leveldown': 7.2.5 '@types/level-errors': 3.0.2 - '@types/node': 22.15.27 + '@types/node': 24.0.10 '@types/long@4.0.2': {} @@ -8964,13 +8952,13 @@ snapshots: '@types/mkdirp@0.5.2': dependencies: - '@types/node': 22.15.27 + '@types/node': 24.0.10 '@types/mocha@10.0.10': {} '@types/node-fetch@2.6.12': dependencies: - '@types/node': 22.15.27 + '@types/node': 24.0.10 form-data: 4.0.2 '@types/node@10.17.60': {} @@ -8981,23 +8969,19 @@ snapshots: dependencies: undici-types: 6.20.0 - '@types/node@22.15.19': - dependencies: - undici-types: 6.21.0 - - '@types/node@22.15.27': - dependencies: - undici-types: 6.21.0 - '@types/node@22.7.5': dependencies: undici-types: 6.19.8 + '@types/node@24.0.10': + dependencies: + undici-types: 7.8.0 + '@types/node@8.10.66': {} '@types/pbkdf2@3.1.2': dependencies: - '@types/node': 22.15.19 + '@types/node': 24.0.10 '@types/prettier@2.7.3': {} @@ -9005,7 +8989,7 @@ snapshots: '@types/secp256k1@4.0.6': dependencies: - '@types/node': 22.15.19 + '@types/node': 24.0.10 '@types/sinon-chai@3.2.12': dependencies: @@ -9820,13 +9804,13 @@ snapshots: safe-buffer: 5.2.1 sha.js: 2.4.11 - create-jest@29.7.0(@types/node@22.15.19)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3)): + create-jest@29.7.0(@types/node@24.0.10)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.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@22.15.19)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3)) + jest-config: 29.7.0(@types/node@24.0.10)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -10224,7 +10208,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.24.1(eslint@8.57.1)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.2)(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.24.1(eslint@8.57.1)(typescript@5.8.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: @@ -10245,7 +10229,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.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.2)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.24.1(eslint@8.57.1)(typescript@5.8.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 @@ -10957,11 +10941,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@22.15.27)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.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@22.15.27)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) sha1: 1.1.1 transitivePeerDependencies: - '@codechecks/client' @@ -10969,62 +10953,7 @@ snapshots: - debug - utf-8-validate - hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7): - dependencies: - '@ethersproject/abi': 5.7.0 - '@metamask/eth-sig-util': 4.0.1 - '@nomicfoundation/edr': 0.7.0 - '@nomicfoundation/ethereumjs-common': 4.0.4 - '@nomicfoundation/ethereumjs-tx': 5.0.4 - '@nomicfoundation/ethereumjs-util': 9.0.4 - '@nomicfoundation/solidity-analyzer': 0.1.2 - '@sentry/node': 5.30.0 - '@types/bn.js': 5.1.6 - '@types/lru-cache': 5.1.1 - adm-zip: 0.4.16 - aggregate-error: 3.1.0 - ansi-escapes: 4.3.2 - boxen: 5.1.2 - chokidar: 4.0.3 - ci-info: 2.0.0 - debug: 4.4.0(supports-color@8.1.1) - enquirer: 2.4.1 - env-paths: 2.2.1 - ethereum-cryptography: 1.2.0 - ethereumjs-abi: 0.6.8 - find-up: 5.0.0 - fp-ts: 1.19.3 - fs-extra: 7.0.1 - immutable: 4.3.7 - io-ts: 1.10.4 - json-stream-stringify: 3.1.6 - keccak: 3.0.4 - lodash: 4.17.21 - mnemonist: 0.38.5 - mocha: 10.8.2 - p-map: 4.0.0 - picocolors: 1.1.1 - raw-body: 2.5.2 - resolve: 1.17.0 - semver: 6.3.1 - solc: 0.8.26(debug@4.4.0) - source-map-support: 0.5.21 - stacktrace-parser: 0.1.11 - tinyglobby: 0.2.11 - tsort: 0.0.1 - undici: 5.28.5 - 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@22.15.19)(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - bufferutil - - c-kzg - - supports-color - - utf-8-validate - - hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@22.15.27)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7): + hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7): dependencies: '@ethersproject/abi': 5.7.0 '@metamask/eth-sig-util': 4.0.1 @@ -11071,7 +11000,7 @@ 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@22.15.27)(typescript@5.8.3) + ts-node: 10.9.2(@types/node@24.0.10)(typescript@5.8.3) typescript: 5.8.3 transitivePeerDependencies: - bufferutil @@ -11461,7 +11390,7 @@ snapshots: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.15.19 + '@types/node': 24.0.10 chalk: 4.1.2 co: 4.6.0 dedent: 1.5.3 @@ -11481,16 +11410,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@22.15.19)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3)): + jest-cli@29.7.0(@types/node@24.0.10)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@22.15.19)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3)) + create-jest: 29.7.0(@types/node@24.0.10)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@22.15.19)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3)) + jest-config: 29.7.0(@types/node@24.0.10)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -11500,7 +11429,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@22.15.19)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3)): + jest-config@29.7.0(@types/node@24.0.10)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3)): dependencies: '@babel/core': 7.26.9 '@jest/test-sequencer': 29.7.0 @@ -11525,8 +11454,8 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 22.15.19 - ts-node: 10.9.2(@types/node@22.15.19)(typescript@5.8.3) + '@types/node': 24.0.10 + ts-node: 10.9.2(@types/node@24.0.10)(typescript@5.8.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -11555,7 +11484,7 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.15.19 + '@types/node': 24.0.10 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -11565,7 +11494,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 22.15.19 + '@types/node': 24.0.10 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -11604,7 +11533,7 @@ snapshots: jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 22.15.19 + '@types/node': 24.0.10 jest-util: 29.7.0 jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): @@ -11639,7 +11568,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.15.19 + '@types/node': 24.0.10 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -11667,7 +11596,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.15.19 + '@types/node': 24.0.10 chalk: 4.1.2 cjs-module-lexer: 1.4.3 collect-v8-coverage: 1.0.2 @@ -11713,7 +11642,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 22.15.19 + '@types/node': 24.0.10 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -11732,7 +11661,7 @@ snapshots: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.15.19 + '@types/node': 24.0.10 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -11741,17 +11670,17 @@ snapshots: jest-worker@29.7.0: dependencies: - '@types/node': 22.15.19 + '@types/node': 24.0.10 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@22.15.19)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3)): + jest@29.7.0(@types/node@24.0.10)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@22.15.19)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3)) + jest-cli: 29.7.0(@types/node@24.0.10)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -12486,7 +12415,7 @@ snapshots: '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 '@types/long': 4.0.2 - '@types/node': 22.15.27 + '@types/node': 24.0.10 long: 4.0.0 protobufjs@7.5.3: @@ -12501,7 +12430,7 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 22.15.27 + '@types/node': 24.0.10 long: 5.3.2 proxy-from-env@1.1.0: {} @@ -12989,7 +12918,7 @@ snapshots: transitivePeerDependencies: - debug - solidity-coverage@0.8.14(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@22.15.27)(typescript@5.8.3))(typescript@5.8.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@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7)): dependencies: '@ethersproject/abi': 5.7.0 '@solidity-parser/parser': 0.19.0 @@ -13000,7 +12929,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@22.15.27)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) + hardhat: 2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7) jsonschema: 1.5.0 lodash: 4.17.21 mocha: 10.8.2 @@ -13355,12 +13284,12 @@ snapshots: ts-interface-checker@0.1.13: {} - 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@22.15.19)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3)))(typescript@5.8.3): + 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@24.0.10)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3)))(typescript@5.8.3): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@22.15.19)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3)) + jest: 29.7.0(@types/node@24.0.10)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -13375,33 +13304,14 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.26.9) esbuild: 0.24.2 - ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.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': 22.15.19 - 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.8.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - optional: true - - ts-node@10.9.2(@types/node@22.15.27)(typescript@5.8.3): + ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.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': 22.15.27 + '@types/node': 24.0.10 acorn: 8.14.0 acorn-walk: 8.3.4 arg: 4.1.3 @@ -13579,7 +13489,7 @@ snapshots: undici-types@6.20.0: {} - undici-types@6.21.0: {} + undici-types@7.8.0: {} undici@5.28.5: dependencies: @@ -13789,9 +13699,9 @@ snapshots: bufferutil: 4.0.5 utf-8-validate: 5.0.7 - xchain-sdk@1.2.5(bufferutil@4.0.5)(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7))(utf-8-validate@5.0.7): + xchain-sdk@1.2.5(bufferutil@4.0.5)(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7))(utf-8-validate@5.0.7): dependencies: - '@peersyst/xrp-evm-contracts': 2.1.1(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@22.15.19)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7)) + '@peersyst/xrp-evm-contracts': 2.1.1(hardhat@2.22.18(bufferutil@4.0.5)(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3))(typescript@5.8.3)(utf-8-validate@5.0.7)) bignumber.js: 9.3.0 ethers: 5.7.2(bufferutil@4.0.5)(utf-8-validate@5.0.7) ripple-address-codec: 5.0.0(bufferutil@4.0.5)(utf-8-validate@5.0.7) From 622e4eaa78e0598214e46c1f6a66f7db24f885f0 Mon Sep 17 00:00:00 2001 From: GuillemGarciaDev Date: Thu, 3 Jul 2025 15:28:31 +0200 Subject: [PATCH 2/3] feat(cosmos): template mainnet config --- .../cosmos/configs/mainnet.module.config.json | 43 +++++++++ .../cosmos/configs/testnet.module.config.json | 6 +- modules/cosmos/module.config.json | 6 +- modules/cosmos/src/modules/ibc/config.ts | 5 +- modules/cosmos/test/modules/ibc/index.test.ts | 93 ++++++++++--------- 5 files changed, 104 insertions(+), 49 deletions(-) diff --git a/modules/cosmos/configs/mainnet.module.config.json b/modules/cosmos/configs/mainnet.module.config.json index 8fc2c10..e035b2b 100644 --- a/modules/cosmos/configs/mainnet.module.config.json +++ b/modules/cosmos/configs/mainnet.module.config.json @@ -23,5 +23,48 @@ }, "bank": { "account": "ethm1dakgyqjulg29m5fmv992g2y66m9g2mjn6hahwg" + }, + "ibc": { + "chains": [ + { + "dstChain": { + "account": { + "mnemonic": "" + }, + "evm": true, + "chainId": "xrplevm_1440000-1", + "rpcUrl": "http://cosmos-rpc.xrplevm.org:26657", + "prefix": "ethm", + "denom": "axrp", + "amount": "5000", + "channel": "", + "gas": { + "amount": "40000000000000000", + "gas": "200000" + } + }, + "srcChain": { + "account": { + "mnemonic": "" + }, + "evm": false, + "chainId": "osmo-mainnet-1", + "rpcUrl": "https://rpc.osmosis.zone", + "prefix": "osmo", + "denom": "uosmo", + "amount": "5000", + "gas": { + "amount": "200000", + "gas": "200000" + }, + "channel": "" + }, + "port": "transfer" + } + ], + "heightBuffer": 1000, + "timeoutMinutes": 10, + "maxIterations": 12, + "delay": 10000 } } diff --git a/modules/cosmos/configs/testnet.module.config.json b/modules/cosmos/configs/testnet.module.config.json index f628f86..8bd3bb9 100644 --- a/modules/cosmos/configs/testnet.module.config.json +++ b/modules/cosmos/configs/testnet.module.config.json @@ -63,6 +63,10 @@ }, "port": "transfer" } - ] + ], + "heightBuffer": 1000, + "timeoutMinutes": 10, + "maxIterations": 12, + "delay": 10000 } } diff --git a/modules/cosmos/module.config.json b/modules/cosmos/module.config.json index f628f86..8bd3bb9 100644 --- a/modules/cosmos/module.config.json +++ b/modules/cosmos/module.config.json @@ -63,6 +63,10 @@ }, "port": "transfer" } - ] + ], + "heightBuffer": 1000, + "timeoutMinutes": 10, + "maxIterations": 12, + "delay": 10000 } } diff --git a/modules/cosmos/src/modules/ibc/config.ts b/modules/cosmos/src/modules/ibc/config.ts index 74856ab..cdc42f6 100644 --- a/modules/cosmos/src/modules/ibc/config.ts +++ b/modules/cosmos/src/modules/ibc/config.ts @@ -1,6 +1,5 @@ export interface IBCAccount { mnemonic: string; - address: string; } export interface IBCGas { @@ -29,4 +28,8 @@ export interface IBCChainPair { export interface IBCModuleConfig { chains: IBCChainPair[]; + heightBuffer: number; + timeoutMinutes: number; + maxIterations: number; + delay: number; } diff --git a/modules/cosmos/test/modules/ibc/index.test.ts b/modules/cosmos/test/modules/ibc/index.test.ts index 0ef7edc..795e033 100644 --- a/modules/cosmos/test/modules/ibc/index.test.ts +++ b/modules/cosmos/test/modules/ibc/index.test.ts @@ -11,7 +11,7 @@ import { } from "../../../src/modules/ibc/utils"; import { expect } from "chai"; import { polling } from "@shared/utils"; -import { describeOrSkip } from "@testing/mocha/utils"; +import { describeOrSkip, itOrSkip } from "@testing/mocha/utils"; import { isChainEnvironment, isChainType } from "@testing/mocha/assertions"; import { Chain } from "@firewatch/core/chain"; @@ -43,15 +43,12 @@ describeOrSkip( srcSender = srcChainData.sender; dstClient = dstChainData.client; dstSender = dstChainData.sender; - - console.log("srcSender", srcSender); - console.log("dstSender", dstSender); }); it(`should transfer ${srcChain.amount} ${srcChain.denom} from ${srcChain.chainId} to ${dstChain.chainId}`, async () => { // Calculate dynamic timeout height and timestamp - const timeoutHeight = await calculateTimeoutHeight(dstClient, 1000); - const timeoutTimestamp = calculateTimeoutTimestamp(10); // 10 minutes + const timeoutHeight = await calculateTimeoutHeight(dstClient, ibcConfig.heightBuffer); + const timeoutTimestamp = calculateTimeoutTimestamp(ibcConfig.timeoutMinutes); // 10 minutes const result = await srcClient.sendIbcTokens( srcSender, @@ -81,51 +78,55 @@ describeOrSkip( async () => await verifyIbcPacketAcknowledgement(dstClient, dstChain.channel, sequence!), (res) => !res, { - delay: 10000, - maxIterations: 12, + delay: ibcConfig.delay, + maxIterations: ibcConfig.maxIterations, }, ); expect(isPacketReceived).to.equal(true); }); - it(`should transfer ${dstChain.amount} ${dstChain.denom} from ${dstChain.chainId} to ${srcChain.chainId}`, async () => { - const timeoutHeight = await calculateTimeoutHeight(srcClient, 1000); - const timeoutTimestamp = calculateTimeoutTimestamp(10); // 10 minutes - - const result = await dstClient.sendIbcTokens( - dstSender, - srcSender, - { - denom: dstChain.denom, - amount: dstChain.amount, - }, - "transfer", - dstChain.channel, - timeoutHeight, - timeoutTimestamp, - { - amount: coins(dstChain.gas.amount, dstChain.denom), - gas: dstChain.gas.gas, - }, - ); - - assertIsDeliverTxSuccess(result); - - const txDetails = await dstClient.getTx(result.transactionHash); - const sequence = extractPacketSequenceFromLogs(txDetails.events); - - expect(sequence).to.not.equal(undefined); - - const isPacketReceived = await polling( - async () => await verifyIbcPacketAcknowledgement(srcClient, srcChain.channel, sequence!), - (res) => !res, - { - delay: 10000, - maxIterations: 12, - }, - ); - expect(isPacketReceived).to.equal(true); - }); + itOrSkip( + `should transfer ${dstChain.amount} ${dstChain.denom} from ${dstChain.chainId} to ${srcChain.chainId}`, + !dstChain.evm, + async () => { + const timeoutHeight = await calculateTimeoutHeight(srcClient, ibcConfig.heightBuffer); + const timeoutTimestamp = calculateTimeoutTimestamp(ibcConfig.timeoutMinutes); // 10 minutes + + const result = await dstClient.sendIbcTokens( + dstSender, + srcSender, + { + denom: dstChain.denom, + amount: dstChain.amount, + }, + "transfer", + dstChain.channel, + timeoutHeight, + timeoutTimestamp, + { + amount: coins(dstChain.gas.amount, dstChain.denom), + gas: dstChain.gas.gas, + }, + ); + + assertIsDeliverTxSuccess(result); + + const txDetails = await dstClient.getTx(result.transactionHash); + const sequence = extractPacketSequenceFromLogs(txDetails.events); + + expect(sequence).to.not.equal(undefined); + + const isPacketReceived = await polling( + async () => await verifyIbcPacketAcknowledgement(srcClient, srcChain.channel, sequence!), + (res) => !res, + { + delay: ibcConfig.delay, + maxIterations: ibcConfig.maxIterations, + }, + ); + expect(isPacketReceived).to.equal(true); + }, + ); }); } }, From ea7cc43359dbc3a0e7cff7fda3357ad76c19ebb3 Mon Sep 17 00:00:00 2001 From: AdriaCarrera Date: Thu, 26 Feb 2026 15:09:10 +0100 Subject: [PATCH 3/3] feat: update Cosmos network configurations and dependencies - Updated RPC URLs to use secure HTTPS endpoints across all environments. - Added IBC module and configuration for chain interoperability. - Revised EVM configurations with proper `evmDenom`, active precompiles, and enhanced fee market parameters. - Introduced Cosmos SDK v0.33.1 dependencies for compatibility improvements. - Included devnet configurations and adjusted test cases for mainnet, testnet, and devnet execution. - Made adjustments in `pnpm-lock.yaml` for upgraded dependencies and package resolution. --- .../cosmos/configs/devnet.module.config.json | 86 +++++++--- .../cosmos/configs/mainnet.module.config.json | 35 ++-- .../cosmos/configs/testnet.module.config.json | 35 ++-- modules/cosmos/module.config.json | 41 ++--- modules/cosmos/test/modules/evm/index.test.ts | 4 +- .../test/modules/feemarket/index.test.ts | 4 +- modules/cosmos/test/modules/ibc/index.test.ts | 6 +- pnpm-lock.yaml | 149 ++++++++---------- 8 files changed, 206 insertions(+), 154 deletions(-) diff --git a/modules/cosmos/configs/devnet.module.config.json b/modules/cosmos/configs/devnet.module.config.json index bb8e41c..fb66e12 100644 --- a/modules/cosmos/configs/devnet.module.config.json +++ b/modules/cosmos/configs/devnet.module.config.json @@ -11,7 +11,7 @@ "decimals": 18 }, "urls": { - "rpc": "http://cosmos.devnet.xrplevm.org:26657" + "rpc": "https://cosmos-rpc.devnet.xrplevm.org" } }, "slashing": { @@ -24,6 +24,51 @@ "bank": { "account": "ethm1dakgyqjulg29m5fmv992g2y66m9g2mjn6hahwg" }, + "ibc": { + "chains": [ + { + "dstChain": { + "account": { + "mnemonic": "harsh harsh mean pool tell oval cancel deal unit strategy deny pool", + "address": "ethm1dny09udcpxg2j6440fuk2m6wajz6249tgu2znt" + }, + "evm": true, + "chainId": "xrplevm_1449000-1", + "rpcUrl": "https://cosmos-rpc.testnet.xrplevm.org", + "prefix": "ethm", + "denom": "axrp", + "amount": "5000", + "channel": "channel-2", + "gas": { + "amount": "40000000000000000", + "gas": "200000" + } + }, + "srcChain": { + "account": { + "mnemonic": "harsh harsh mean pool tell oval cancel deal unit strategy deny pool", + "address": "cosmos1dakgyqjulg29m5fmv992g2y66m9g2mjn6hahwg" + }, + "evm": false, + "chainId": "osmo-test-5", + "rpcUrl": "https://rpc.testnet.osmosis.zone", + "prefix": "osmo", + "denom": "uosmo", + "amount": "5000", + "gas": { + "amount": "200000", + "gas": "200000" + }, + "channel": "channel-10361" + }, + "port": "transfer" + } + ], + "heightBuffer": 1000, + "timeoutMinutes": 10, + "maxIterations": 12, + "delay": 10000 + }, "evm": { "v1": { "accounts": [ @@ -65,15 +110,15 @@ }, "v2": { "accounts": [{ - "address": "", - "code": "", - "codeHash": "" + "address": "0xe432150cce91c13a887f7D836923d5597adD8E31", + "code": null, + "codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" }], "params": { - "evmDenom": "", - "allowUnprotectedTxs": false, - "extraEips": [], + "evmDenom": "axrp", + "allowUnprotectedTxs": true, "evmChannels": [], + "extraEips": [], "accessControl": { "create": { "accessType": 0, @@ -84,7 +129,12 @@ "accessControlList": [] } }, - "activeStaticPrecompiles": [] + "activeStaticPrecompiles": [ + "0x0000000000000000000000000000000000000100", + "0x0000000000000000000000000000000000000400", + "0x0000000000000000000000000000000000000804", + "0x0000000000000000000000000000000000000805" + ] } } }, @@ -95,23 +145,23 @@ "baseFeeChangeDenominator": 8, "elasticityMultiplier": 4, "enableHeight": 0, - "baseFee": "800000000000", - "minGasPrice": "800000000000000000000000000000", + "baseFee": "200000000000", + "minGasPrice": "200000000000000000000000000000", "minGasMultiplier": "500000000000000000" }, - "baseFee": "800000000000" + "baseFee": "200000000000" }, "v2": { "params": { "noBaseFee": false, - "baseFeeChangeDenominator": 1, - "elasticityMultiplier": 1, - "enableHeight": "", - "baseFee": "", - "minGasPrice": "", - "minGasMultiplier": "" + "baseFeeChangeDenominator": 8, + "elasticityMultiplier": 4, + "enableHeight": 0, + "baseFee": "200000000000000000000000000000", + "minGasPrice": "200000000000000000000000000000", + "minGasMultiplier": "500000000000000000" }, - "baseFee": "" + "baseFee": "200000000000000000000000000000" } } } diff --git a/modules/cosmos/configs/mainnet.module.config.json b/modules/cosmos/configs/mainnet.module.config.json index 1bd7116..d5fe0d0 100644 --- a/modules/cosmos/configs/mainnet.module.config.json +++ b/modules/cosmos/configs/mainnet.module.config.json @@ -33,7 +33,7 @@ }, "evm": true, "chainId": "xrplevm_1440000-1", - "rpcUrl": "http://cosmos-rpc.xrplevm.org:26657", + "rpcUrl": "https://cosmos-rpc.xrplevm.org", "prefix": "ethm", "denom": "axrp", "amount": "5000", @@ -108,15 +108,15 @@ }, "v2": { "accounts": [{ - "address": "", - "code": "", - "codeHash": "" + "address": "0xe432150cce91c13a887f7D836923d5597adD8E31", + "code": "6080604052600436106100385760003560e01c80633e35487c146100915780635c60da1b146100d85780639ded06df1461012c5761003f565b3661003f57005b60006100697f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b90503660008037600080366000845af43d6000803e80801561008a573d6000f35b3d6000fd5b005b34801561009d57600080fd5b506100c57fd10cce6f0e3f6dc9eb8280c32952dc6e4759d0519c550c55d0f8747d13a64bfd81565b6040519081526020015b60405180910390f35b3480156100e457600080fd5b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100cf565b34801561013857600080fd5b5061008f61014736600461014b565b5050565b6000806020838503121561015e57600080fd5b823567ffffffffffffffff8082111561017657600080fd5b818501915085601f83011261018a57600080fd5b81358181111561019957600080fd5b8660208285010111156101ab57600080fd5b6020929092019691955090935050505056fea264697066735822122048cf09e223a1bd27520b20e79507d7de6a036b11d95e1368da36c89f0c67f6a764736f6c63430008170033", + "codeHash": "0xb517e33d0b0a195c9689f81879dc551f8cc0d09ace8e2ed2a9377208527ede18" }], "params": { - "evmDenom": "", - "allowUnprotectedTxs": false, + "evmDenom": "axrp", + "allowUnprotectedTxs": true, "evmChannels": [], - "extraEips": [], + "extraEips": ["3855"], "accessControl": { "create": { "accessType": 0, @@ -127,7 +127,12 @@ "accessControlList": [] } }, - "activeStaticPrecompiles": [] + "activeStaticPrecompiles": [ + "0x0000000000000000000000000000000000000100", + "0x0000000000000000000000000000000000000400", + "0x0000000000000000000000000000000000000804", + "0x0000000000000000000000000000000000000805" + ] } } }, @@ -147,14 +152,14 @@ "v2": { "params": { "noBaseFee": false, - "baseFeeChangeDenominator": 1, - "elasticityMultiplier": 1, - "enableHeight": "", - "baseFee": "", - "minGasPrice": "", - "minGasMultiplier": "" + "baseFeeChangeDenominator": 8, + "elasticityMultiplier": 4, + "enableHeight": 0, + "baseFee": "100000000000000000000000000000", + "minGasPrice": "100000000000000000000000000000", + "minGasMultiplier": "500000000000000000" }, - "baseFee": "" + "baseFee": "100000000000000000000000000000" } } } diff --git a/modules/cosmos/configs/testnet.module.config.json b/modules/cosmos/configs/testnet.module.config.json index f9af475..674a300 100644 --- a/modules/cosmos/configs/testnet.module.config.json +++ b/modules/cosmos/configs/testnet.module.config.json @@ -11,7 +11,7 @@ "decimals": 18 }, "urls": { - "rpc": "http://cosmos.testnet.xrplevm.org:26657" + "rpc": "https://cosmos-rpc.testnet.xrplevm.org" } }, "slashing": { @@ -34,7 +34,7 @@ }, "evm": true, "chainId": "xrplevm_1449000-1", - "rpcUrl": "http://cosmos.testnet.xrplevm.org:26657", + "rpcUrl": "https://cosmos-rpc.testnet.xrplevm.org", "prefix": "ethm", "denom": "axrp", "amount": "5000", @@ -110,15 +110,15 @@ }, "v2": { "accounts": [{ - "address": "", - "code": "", - "codeHash": "" + "address": "0xe432150cce91c13a887f7D836923d5597adD8E31", + "code": "6080604052600436106100385760003560e01c80633e35487c146100915780635c60da1b146100d85780639ded06df1461012c5761003f565b3661003f57005b60006100697f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b90503660008037600080366000845af43d6000803e80801561008a573d6000f35b3d6000fd5b005b34801561009d57600080fd5b506100c57fd10cce6f0e3f6dc9eb8280c32952dc6e4759d0519c550c55d0f8747d13a64bfd81565b6040519081526020015b60405180910390f35b3480156100e457600080fd5b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100cf565b34801561013857600080fd5b5061008f61014736600461014b565b5050565b6000806020838503121561015e57600080fd5b823567ffffffffffffffff8082111561017657600080fd5b818501915085601f83011261018a57600080fd5b81358181111561019957600080fd5b8660208285010111156101ab57600080fd5b6020929092019691955090935050505056fea264697066735822122048cf09e223a1bd27520b20e79507d7de6a036b11d95e1368da36c89f0c67f6a764736f6c63430008170033", + "codeHash": "0xb517e33d0b0a195c9689f81879dc551f8cc0d09ace8e2ed2a9377208527ede18" }], "params": { - "evmDenom": "", + "evmDenom": "axrp", "allowUnprotectedTxs": false, "evmChannels": [], - "extraEips": [], + "extraEips": ["3855"], "accessControl": { "create": { "accessType": 0, @@ -129,7 +129,12 @@ "accessControlList": [] } }, - "activeStaticPrecompiles": [] + "activeStaticPrecompiles": [ + "0x0000000000000000000000000000000000000100", + "0x0000000000000000000000000000000000000400", + "0x0000000000000000000000000000000000000804", + "0x0000000000000000000000000000000000000805" + ] } } }, @@ -149,14 +154,14 @@ "v2": { "params": { "noBaseFee": false, - "baseFeeChangeDenominator": 1, - "elasticityMultiplier": 1, - "enableHeight": "", - "baseFee": "", - "minGasPrice": "", - "minGasMultiplier": "" + "baseFeeChangeDenominator": 8, + "elasticityMultiplier": 4, + "enableHeight": 0, + "baseFee": "200000000000000000000000000000", + "minGasPrice": "200000000000000000000000000000", + "minGasMultiplier": "500000000000000000" }, - "baseFee": "" + "baseFee": "200000000000000000000000000000" } } } diff --git a/modules/cosmos/module.config.json b/modules/cosmos/module.config.json index ab5884e..fb66e12 100644 --- a/modules/cosmos/module.config.json +++ b/modules/cosmos/module.config.json @@ -1,9 +1,9 @@ { "network": { - "id": "xrplevm_mainnet", - "name": "xrplevm_mainnet", + "id": "xrplevm_devnet", + "name": "xrplevm_devnet", "symbol": "XRP", - "env": "mainnet", + "env": "devnet", "type": "cosmos", "nativeToken": { "name": "XRP", @@ -11,7 +11,7 @@ "decimals": 18 }, "urls": { - "rpc": "https://cosmos-rpc.xrplevm.org" + "rpc": "https://cosmos-rpc.devnet.xrplevm.org" } }, "slashing": { @@ -34,7 +34,7 @@ }, "evm": true, "chainId": "xrplevm_1449000-1", - "rpcUrl": "http://cosmos.testnet.xrplevm.org:26657", + "rpcUrl": "https://cosmos-rpc.testnet.xrplevm.org", "prefix": "ethm", "denom": "axrp", "amount": "5000", @@ -110,13 +110,13 @@ }, "v2": { "accounts": [{ - "address": "", - "code": "", - "codeHash": "" + "address": "0xe432150cce91c13a887f7D836923d5597adD8E31", + "code": null, + "codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" }], "params": { - "evmDenom": "", - "allowUnprotectedTxs": false, + "evmDenom": "axrp", + "allowUnprotectedTxs": true, "evmChannels": [], "extraEips": [], "accessControl": { @@ -129,7 +129,12 @@ "accessControlList": [] } }, - "activeStaticPrecompiles": [] + "activeStaticPrecompiles": [ + "0x0000000000000000000000000000000000000100", + "0x0000000000000000000000000000000000000400", + "0x0000000000000000000000000000000000000804", + "0x0000000000000000000000000000000000000805" + ] } } }, @@ -149,14 +154,14 @@ "v2": { "params": { "noBaseFee": false, - "baseFeeChangeDenominator": 1, - "elasticityMultiplier": 1, - "enableHeight": "", - "baseFee": "", - "minGasPrice": "", - "minGasMultiplier": "" + "baseFeeChangeDenominator": 8, + "elasticityMultiplier": 4, + "enableHeight": 0, + "baseFee": "200000000000000000000000000000", + "minGasPrice": "200000000000000000000000000000", + "minGasMultiplier": "500000000000000000" }, - "baseFee": "" + "baseFee": "200000000000000000000000000000" } } } diff --git a/modules/cosmos/test/modules/evm/index.test.ts b/modules/cosmos/test/modules/evm/index.test.ts index 4e1500d..03c99c1 100644 --- a/modules/cosmos/test/modules/evm/index.test.ts +++ b/modules/cosmos/test/modules/evm/index.test.ts @@ -17,7 +17,7 @@ describeOrSkip( () => { describeOrSkip( "v1 (evmos)", - () => isChainEnvironment(["devnet", "testnet", "mainnet"], moduleConfig.network as unknown as Chain), + () => isChainEnvironment([], moduleConfig.network as unknown as Chain), () => { let evmClientV1: EvmClientV1; const { @@ -85,7 +85,7 @@ describeOrSkip( describeOrSkip( "v2 (cosmos/evm)", - () => isChainEnvironment(["localnet"], moduleConfig.network as unknown as Chain), + () => isChainEnvironment(["mainnet", "testnet", "devnet", "localnet"], moduleConfig.network as unknown as Chain), () => { let evmClientV2: EvmClientV2; const { diff --git a/modules/cosmos/test/modules/feemarket/index.test.ts b/modules/cosmos/test/modules/feemarket/index.test.ts index 4967a35..5d27a8f 100644 --- a/modules/cosmos/test/modules/feemarket/index.test.ts +++ b/modules/cosmos/test/modules/feemarket/index.test.ts @@ -19,7 +19,7 @@ describeOrSkip( () => { describeOrSkip( "v1 (evmos)", - () => isChainEnvironment(["devnet", "testnet", "mainnet"], moduleConfig.network as unknown as Chain), + () => isChainEnvironment([], moduleConfig.network as unknown as Chain), () => { let feemarketClientV1: FeemarketClientV1; let params: QueryParamsResponseV1; @@ -86,7 +86,7 @@ describeOrSkip( describeOrSkip( "v2 (cosmos/evm)", - () => isChainEnvironment(["localnet"], moduleConfig.network as unknown as Chain), + () => isChainEnvironment(["mainnet", "testnet", "devnet", "localnet"], moduleConfig.network as unknown as Chain), () => { let feemarketClientV2: FeemarketClientV2; let params: QueryParamsResponse; diff --git a/modules/cosmos/test/modules/ibc/index.test.ts b/modules/cosmos/test/modules/ibc/index.test.ts index 795e033..e48a099 100644 --- a/modules/cosmos/test/modules/ibc/index.test.ts +++ b/modules/cosmos/test/modules/ibc/index.test.ts @@ -15,13 +15,11 @@ import { describeOrSkip, itOrSkip } from "@testing/mocha/utils"; import { isChainEnvironment, isChainType } from "@testing/mocha/assertions"; import { Chain } from "@firewatch/core/chain"; +// TODO: Fix this tests to be executed in mainnet and testnet describeOrSkip( "IBCModule", () => { - return ( - isChainType(["cosmos"], config.network as unknown as Chain) && - isChainEnvironment(["testnet", "mainnet"], config.network as unknown as Chain) - ); + return isChainType(["cosmos"], config.network as unknown as Chain) && isChainEnvironment([], config.network as unknown as Chain); }, () => { const { ibc: ibcConfig } = config; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 48c0018..a0d389b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -93,15 +93,30 @@ importers: modules/cosmos: dependencies: + '@cosmjs/amino': + specifier: ^0.33.1 + version: 0.33.1 + '@cosmjs/crypto': + specifier: ^0.33.1 + version: 0.33.1 '@cosmjs/encoding': specifier: ^0.33.1 version: 0.33.1 + '@cosmjs/math': + specifier: ^0.33.1 + version: 0.33.1 + '@cosmjs/proto-signing': + specifier: ^0.33.1 + version: 0.33.1 '@cosmjs/stargate': specifier: ^0.33.0 version: 0.33.0(bufferutil@4.0.5)(utf-8-validate@5.0.7) '@cosmjs/tendermint-rpc': specifier: ^0.33.1 version: 0.33.1(bufferutil@4.0.5)(utf-8-validate@5.0.7) + '@cosmjs/utils': + specifier: ^0.33.1 + version: 0.33.1 '@firewatch/proto-evm': specifier: workspace:* version: link:../../packages/proto/evm @@ -130,12 +145,18 @@ importers: '@shared/tsconfig': specifier: workspace:* version: link:../../packages/shared/tsconfig + '@shared/utils': + specifier: workspace:* + version: link:../../packages/shared/utils '@testing/mocha': specifier: workspace:* version: link:../../packages/testing/mocha '@types/mocha': specifier: ^10.0.10 version: 10.0.10 + '@types/node': + specifier: ^24.0.10 + version: 24.10.14 modules/evm: dependencies: @@ -236,10 +257,10 @@ 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@25.0.9)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3)) + version: 29.7.0(@types/node@20.19.25)(ts-node@10.9.2(@types/node@20.19.25)(typescript@5.9.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@25.0.9)(ts-node@10.9.2(@types/node@25.0.9)(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@5.9.3)))(typescript@5.9.3) typescript: specifier: latest version: 5.9.3 @@ -1103,17 +1124,13 @@ packages: '@cosmjs/amino@0.31.3': resolution: {integrity: sha512-36emtUq895sPRX8PTSOnG+lhJDCVyIcE0Tr5ct59sUbgQiI14y43vj/4WAlJ/utSOxy+Zhj9wxcs4AZfu0BHsw==} - '@cosmjs/amino@0.33.0': - resolution: {integrity: sha512-a4qnWGzuM2IrlkDTFQmU7bDd+wNIzyvfcRIZ43i00ZHvTEtrCcWopT94rIv/Zy6fdgkhQ3HWrsGVlIPDT/ibRw==} + '@cosmjs/amino@0.33.1': + resolution: {integrity: sha512-WfWiBf2EbIWpwKG9AOcsIIkR717SY+JdlXM/SL/bI66BdrhniAF+/ZNis9Vo9HF6lP2UU5XrSmFA4snAvEgdrg==} '@cosmjs/crypto@0.31.3': resolution: {integrity: sha512-vRbvM9ZKR2017TO73dtJ50KxoGcFzKtKI7C8iO302BQ5p+DuB+AirUg1952UpSoLfv5ki9O416MFANNg8UN/EQ==} deprecated: This uses elliptic for cryptographic operations, which contains several security-relevant bugs. To what degree this affects your application is something you need to carefully investigate. See https://github.com/cosmos/cosmjs/issues/1708 for further pointers. Starting with version 0.34.0 the cryptographic library has been replaced. However, private keys might still be at risk. - '@cosmjs/crypto@0.33.0': - resolution: {integrity: sha512-kkt06t+cFW2XRGDGUZ0cVf5yoQ2OhZnubwbYbz3QXdyhf1qOXYVPRThfFPsko7dssr+e8Yy4OJKlh5SLA8DXTQ==} - deprecated: This uses elliptic for cryptographic operations, which contains several security-relevant bugs. To what degree this affects your application is something you need to carefully investigate. See https://github.com/cosmos/cosmjs/issues/1708 for further pointers. Starting with version 0.34.0 the cryptographic library has been replaced. However, private keys might still be at risk. - '@cosmjs/crypto@0.33.1': resolution: {integrity: sha512-U4kGIj/SNBzlb2FGgA0sMR0MapVgJUg8N+oIAiN5+vl4GZ3aefmoL1RDyTrFS/7HrB+M+MtHsxC0tvEu4ic/zA==} deprecated: This uses elliptic for cryptographic operations, which contains several security-relevant bugs. To what degree this affects your application is something you need to carefully investigate. See https://github.com/cosmos/cosmjs/issues/1708 for further pointers. Starting with version 0.34.0 the cryptographic library has been replaced. However, private keys might still be at risk. @@ -1136,9 +1153,6 @@ packages: '@cosmjs/math@0.31.3': resolution: {integrity: sha512-kZ2C6glA5HDb9hLz1WrftAjqdTBb3fWQsRR+Us2HsjAYdeE6M3VdXMsYCP5M3yiihal1WDwAY2U7HmfJw7Uh4A==} - '@cosmjs/math@0.33.0': - resolution: {integrity: sha512-B2uOgM12iuIhJWzGuAxGwO6zO+cI8Q4z7mVu7HgFrGJJTM1HtPTYgb55oMOuUN0OZ352MEEm5uAt8sA9jZQqbA==} - '@cosmjs/math@0.33.1': resolution: {integrity: sha512-ytGkWdKFCPiiBU5eqjHNd59djPpIsOjbr2CkNjlnI1Zmdj+HDkSoD9MUGpz9/RJvRir5IvsXqdE05x8EtoQkJA==} @@ -1148,6 +1162,9 @@ packages: '@cosmjs/proto-signing@0.33.0': resolution: {integrity: sha512-UHA92d/Siy3wnce/xhU4iagKrs6r8Ruacc0qeHj3mNrtuUH8f70cD7lzzClzI7wvRLcPprOY0YTeEzqGbPeBFw==} + '@cosmjs/proto-signing@0.33.1': + resolution: {integrity: sha512-Sv4W+MxX+0LVnd+2rU4Fw1HRsmMwSVSYULj7pRkij3wnPwUlTVoJjmKFgKz13ooIlfzPrz/dnNjGp/xnmXChFQ==} + '@cosmjs/socket@0.31.3': resolution: {integrity: sha512-aqrDGGi7os/hsz5p++avI4L0ZushJ+ItnzbqA7C6hamFSCJwgOkXaOUs+K9hXZdX4rhY7rXO4PH9IH8q09JkTw==} @@ -1181,9 +1198,6 @@ packages: '@cosmjs/utils@0.31.3': resolution: {integrity: sha512-VBhAgzrrYdIe0O5IbKRqwszbQa7ZyQLx9nEQuHQ3HUplQW7P44COG/ye2n6AzCudtqxmwdX7nyX8ta1J07GoqA==} - '@cosmjs/utils@0.33.0': - resolution: {integrity: sha512-Y6glwHNlNjcOgwPg8YmNr1PSrNm307EhJVytFt8HmA/G7MRcIA+jIzCL0VlOrWGU4TrAOXvshM+oJZbTIldFRA==} - '@cosmjs/utils@0.33.1': resolution: {integrity: sha512-UnLHDY6KMmC+UXf3Ufyh+onE19xzEXjT4VZ504Acmk4PXxqyvG4cCPprlKUFnGUX7f0z8Or9MAOHXBx41uHBcg==} @@ -2659,6 +2673,9 @@ packages: '@types/node@22.7.5': resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} + '@types/node@24.10.14': + resolution: {integrity: sha512-OowOUbD1lBCOFIPOZ8xnMIhgqA4sCutMiYOmPHL1PTLt5+y1XA+g2+yC9OOyz8p+deMZqPZLxfMjYIfrKsPeFg==} + '@types/node@25.0.9': resolution: {integrity: sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw==} @@ -3436,9 +3453,6 @@ packages: bn.js@4.12.1: resolution: {integrity: sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==} - bn.js@5.2.1: - resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} - bn.js@5.2.2: resolution: {integrity: sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==} @@ -4621,8 +4635,8 @@ packages: resolution: {integrity: sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==} deprecated: This library has been deprecated and usage is discouraged. - ethereumjs-abi@git+https://git@github.com:ethereumjs/ethereumjs-abi.git#ee3994657fa7a427238e6ba92a84d0b529bbcde0: - resolution: {commit: ee3994657fa7a427238e6ba92a84d0b529bbcde0, repo: git@github.com:ethereumjs/ethereumjs-abi.git, type: git} + ethereumjs-abi@https://codeload.github.com/ethereumjs/ethereumjs-abi/tar.gz/ee3994657fa7a427238e6ba92a84d0b529bbcde0: + resolution: {tarball: https://codeload.github.com/ethereumjs/ethereumjs-abi/tar.gz/ee3994657fa7a427238e6ba92a84d0b529bbcde0} version: 0.6.8 ethereumjs-account@2.0.5: @@ -9286,12 +9300,12 @@ snapshots: '@cosmjs/math': 0.31.3 '@cosmjs/utils': 0.31.3 - '@cosmjs/amino@0.33.0': + '@cosmjs/amino@0.33.1': dependencies: - '@cosmjs/crypto': 0.33.0 + '@cosmjs/crypto': 0.33.1 '@cosmjs/encoding': 0.33.1 - '@cosmjs/math': 0.33.0 - '@cosmjs/utils': 0.33.0 + '@cosmjs/math': 0.33.1 + '@cosmjs/utils': 0.33.1 '@cosmjs/crypto@0.31.3': dependencies: @@ -9299,17 +9313,7 @@ snapshots: '@cosmjs/math': 0.31.3 '@cosmjs/utils': 0.31.3 '@noble/hashes': 1.7.1 - bn.js: 5.2.1 - elliptic: 6.6.1 - libsodium-wrappers-sumo: 0.7.15 - - '@cosmjs/crypto@0.33.0': - dependencies: - '@cosmjs/encoding': 0.33.1 - '@cosmjs/math': 0.33.0 - '@cosmjs/utils': 0.33.0 - '@noble/hashes': 1.7.1 - bn.js: 5.2.1 + bn.js: 5.2.2 elliptic: 6.6.1 libsodium-wrappers-sumo: 0.7.15 @@ -9319,7 +9323,7 @@ snapshots: '@cosmjs/math': 0.33.1 '@cosmjs/utils': 0.33.1 '@noble/hashes': 1.7.1 - bn.js: 5.2.1 + bn.js: 5.2.2 elliptic: 6.6.1 libsodium-wrappers-sumo: 0.7.15 @@ -9352,15 +9356,11 @@ snapshots: '@cosmjs/math@0.31.3': dependencies: - bn.js: 5.2.1 - - '@cosmjs/math@0.33.0': - dependencies: - bn.js: 5.2.1 + bn.js: 5.2.2 '@cosmjs/math@0.33.1': dependencies: - bn.js: 5.2.1 + bn.js: 5.2.2 '@cosmjs/proto-signing@0.31.3': dependencies: @@ -9374,7 +9374,16 @@ snapshots: '@cosmjs/proto-signing@0.33.0': dependencies: - '@cosmjs/amino': 0.33.0 + '@cosmjs/amino': 0.33.1 + '@cosmjs/crypto': 0.33.1 + '@cosmjs/encoding': 0.33.1 + '@cosmjs/math': 0.33.1 + '@cosmjs/utils': 0.33.1 + cosmjs-types: 0.9.0 + + '@cosmjs/proto-signing@0.33.1': + dependencies: + '@cosmjs/amino': 0.33.1 '@cosmjs/crypto': 0.33.1 '@cosmjs/encoding': 0.33.1 '@cosmjs/math': 0.33.1 @@ -9422,13 +9431,13 @@ snapshots: '@cosmjs/stargate@0.33.0(bufferutil@4.0.5)(utf-8-validate@5.0.7)': dependencies: - '@cosmjs/amino': 0.33.0 + '@cosmjs/amino': 0.33.1 '@cosmjs/encoding': 0.33.1 - '@cosmjs/math': 0.33.0 - '@cosmjs/proto-signing': 0.33.0 + '@cosmjs/math': 0.33.1 + '@cosmjs/proto-signing': 0.33.1 '@cosmjs/stream': 0.33.0 '@cosmjs/tendermint-rpc': 0.33.1(bufferutil@4.0.5)(utf-8-validate@5.0.7) - '@cosmjs/utils': 0.33.0 + '@cosmjs/utils': 0.33.1 cosmjs-types: 0.9.0 transitivePeerDependencies: - bufferutil @@ -9487,8 +9496,6 @@ snapshots: '@cosmjs/utils@0.31.3': {} - '@cosmjs/utils@0.33.0': {} - '@cosmjs/utils@0.33.1': {} '@cspotcode/source-map-support@0.8.1': @@ -9901,13 +9908,13 @@ snapshots: dependencies: '@ethersproject/bytes': 5.8.0 '@ethersproject/logger': 5.8.0 - bn.js: 5.2.1 + bn.js: 5.2.2 '@ethersproject/bignumber@5.8.0': dependencies: '@ethersproject/bytes': 5.8.0 '@ethersproject/logger': 5.8.0 - bn.js: 5.2.1 + bn.js: 5.2.2 '@ethersproject/bytes@5.7.0': dependencies: @@ -10117,7 +10124,7 @@ snapshots: '@ethersproject/bytes': 5.8.0 '@ethersproject/logger': 5.8.0 '@ethersproject/properties': 5.8.0 - bn.js: 5.2.1 + bn.js: 5.2.2 elliptic: 6.5.4 hash.js: 1.1.7 @@ -10126,7 +10133,7 @@ snapshots: '@ethersproject/bytes': 5.8.0 '@ethersproject/logger': 5.8.0 '@ethersproject/properties': 5.8.0 - bn.js: 5.2.1 + bn.js: 5.2.2 elliptic: 6.6.1 hash.js: 1.1.7 @@ -11616,6 +11623,10 @@ snapshots: dependencies: undici-types: 6.19.8 + '@types/node@24.10.14': + dependencies: + undici-types: 7.16.0 + '@types/node@25.0.9': dependencies: undici-types: 7.16.0 @@ -12760,8 +12771,6 @@ snapshots: bn.js@4.12.1: {} - bn.js@5.2.1: {} - bn.js@5.2.2: {} body-parser@1.20.3: @@ -14307,7 +14316,7 @@ snapshots: eth-sig-util@1.4.2: dependencies: - ethereumjs-abi: git+https://git@github.com:ethereumjs/ethereumjs-abi.git#ee3994657fa7a427238e6ba92a84d0b529bbcde0 + ethereumjs-abi: https://codeload.github.com/ethereumjs/ethereumjs-abi/tar.gz/ee3994657fa7a427238e6ba92a84d0b529bbcde0 ethereumjs-util: 5.2.1 eth-sig-util@3.0.0: @@ -14422,7 +14431,7 @@ snapshots: bn.js: 4.12.1 ethereumjs-util: 6.2.1 - ethereumjs-abi@git+https://git@github.com:ethereumjs/ethereumjs-abi.git#ee3994657fa7a427238e6ba92a84d0b529bbcde0: + ethereumjs-abi@https://codeload.github.com/ethereumjs/ethereumjs-abi/tar.gz/ee3994657fa7a427238e6ba92a84d0b529bbcde0: dependencies: bn.js: 4.12.1 ethereumjs-util: 6.2.1 @@ -14519,7 +14528,7 @@ snapshots: ethereumjs-util@7.1.5: dependencies: '@types/bn.js': 5.1.6 - bn.js: 5.2.1 + bn.js: 5.2.2 create-hash: 1.2.0 ethereum-cryptography: 0.1.3 rlp: 2.2.7 @@ -17948,7 +17957,7 @@ snapshots: ripple-keypairs@1.3.1: dependencies: - bn.js: 5.2.1 + bn.js: 5.2.2 brorand: 1.1.0 elliptic: 6.6.1 hash.js: 1.1.7 @@ -17969,7 +17978,7 @@ snapshots: rlp@2.2.7: dependencies: - bn.js: 5.2.1 + bn.js: 5.2.2 rollup@4.34.8: dependencies: @@ -18949,26 +18958,6 @@ 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@25.0.9)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.3)))(typescript@5.9.3): - dependencies: - bs-logger: 0.2.6 - ejs: 3.1.10 - fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@25.0.9)(ts-node@10.9.2(@types/node@25.0.9)(typescript@5.9.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: 5.9.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 @@ -19577,7 +19566,7 @@ snapshots: web3-utils@1.10.4: dependencies: '@ethereumjs/util': 8.1.0 - bn.js: 5.2.1 + bn.js: 5.2.2 ethereum-bloom-filters: 1.2.0 ethereum-cryptography: 2.2.1 ethjs-unit: 0.1.6