diff --git a/src/sdk/tx/account.test.ts b/src/sdk/tx/account.test.ts new file mode 100644 index 00000000..e0f0ed67 --- /dev/null +++ b/src/sdk/tx/account.test.ts @@ -0,0 +1,83 @@ +import { accountFromEthAccount, accountFromNibiru } from "./account" +import { EthAccount } from "src/protojs/eth/types/v1/account" +import { Any } from "cosmjs-types/google/protobuf/any" +import Long from "long" + +describe("accountFromEthAccount", () => { + it("should return valid account information with nibi address and Long types", () => { + const ethAccount: EthAccount = { + baseAccount: { + address: "nibi1234567", // Use nibi Bech32 encoding + pubKey: { + typeUrl: "/cosmos.crypto.secp256k1.PubKey", + value: new Uint8Array([1, 2, 3]), + }, + accountNumber: Long.fromNumber(123), + sequence: Long.fromNumber(1), + }, + codeHash: "", + } + + const account = accountFromEthAccount(ethAccount) + + expect(account.address).toEqual("nibi1234567") + expect(account.pubkey).toEqual({ + typeUrl: "/cosmos.crypto.secp256k1.PubKey", + value: new Uint8Array([1, 2, 3]), + }) + expect(account.accountNumber).toEqual(Long.fromNumber(123)) + expect(account.sequence).toEqual(Long.fromNumber(1)) + }) + + it("should handle null/undefined baseAccount fields and return Long.ZERO", () => { + const ethAccount: EthAccount = { baseAccount: undefined, codeHash: "" } + + const account = accountFromEthAccount(ethAccount) + + expect(account.address).toEqual("") + expect(account.pubkey).toBeNull() + expect(account.accountNumber).toEqual(Long.ZERO) + expect(account.sequence).toEqual(Long.ZERO) + }) +}) + +describe("accountFromNibiru", () => { + it("should parse EthAccount typeUrl", () => { + const input: Any = { + typeUrl: "/eth.types.v1.EthAccount", + value: EthAccount.encode({ + baseAccount: { + address: "nibi1234567", + pubKey: { + typeUrl: "/cosmos.crypto.secp256k1.PubKey", + value: new Uint8Array([4, 5, 6]), + }, + accountNumber: Long.fromNumber(456), + sequence: Long.fromNumber(2), + }, + codeHash: "", + }).finish(), + } + + const account = accountFromNibiru(input) + + expect(account.address).toEqual("nibi1234567") // Ensure the prefix is 'nibi' + expect(account.pubkey).toEqual({ + typeUrl: "/cosmos.crypto.secp256k1.PubKey", + value: new Uint8Array([4, 5, 6]), + }) + expect(account.accountNumber).toEqual(Long.fromNumber(456)) + expect(account.sequence).toEqual(Long.fromNumber(2)) + }) + + it("should call accountFromAny for non-EthAccount typeUrl", () => { + const input: Any = { + typeUrl: "/other.types.v1.Account", + value: new Uint8Array([7, 8, 9]), + } + + const account = accountFromNibiru(input) + + expect(account.address).toBe("nibi1otheraddress") + }) +}) diff --git a/src/sdk/tx/account.ts b/src/sdk/tx/account.ts new file mode 100644 index 00000000..808351bf --- /dev/null +++ b/src/sdk/tx/account.ts @@ -0,0 +1,36 @@ +import { decodeOptionalPubkey } from "@cosmjs/proto-signing" +import { Account, accountFromAny, AccountParser } from "@cosmjs/stargate" +import { EthAccount } from "src/protojs/eth/types/v1/account" +import { Any } from "src/protojs/google/protobuf/any" + +/** + * Converts an EthAccount to a general Cosmos Account object. + * + * @param {EthAccount} ethAccount - The EthAccount object containing the account's base information. + * @returns {Account} The Cosmos account object. + */ +export const accountFromEthAccount = ({ + baseAccount, +}: EthAccount): Account => ({ + address: baseAccount?.address ?? "", + pubkey: decodeOptionalPubkey(baseAccount?.pubKey) ?? null, + accountNumber: baseAccount?.accountNumber?.toNumber() ?? 0, + sequence: baseAccount?.sequence?.toNumber() ?? 0, +}) + +/** + * Parses an account input into a Cosmos account. Handles both EthAccount and other standard accounts. + * + * @param {Any} input - The input account information, containing the typeUrl and value. + * @returns {Account} Parsed account object. + */ +export const accountFromNibiru: AccountParser = (input: Any): Account => { + const { typeUrl, value } = input + + if (typeUrl === "/eth.types.v1.EthAccount") { + const ethAccount = EthAccount.decode(value) + return accountFromEthAccount(ethAccount) + } + + return accountFromAny(input) +} diff --git a/src/sdk/tx/txClient.ts b/src/sdk/tx/txClient.ts index 38b718b0..838df533 100644 --- a/src/sdk/tx/txClient.ts +++ b/src/sdk/tx/txClient.ts @@ -18,6 +18,7 @@ import { setupWasmExtension, } from "@cosmjs/cosmwasm-stargate" import { NibiruExtensions, setupNibiruExtension } from ".." +import { accountFromNibiru } from "./account" export const nibiruRegistryTypes: ReadonlyArray<[string, GeneratedType]> = [ ...defaultRegistryTypes, @@ -69,6 +70,7 @@ export class NibiruTxClient extends SigningStargateClient { registry: new Registry(nibiruRegistryTypes), gasPrice: GasPrice.fromString("0.025unibi"), broadcastPollIntervalMs: 1_000, // 1 second poll times + accountParser: accountFromNibiru, ...options, }, wasmClient diff --git a/src/sdk/utils/t.json b/src/sdk/utils/t.json new file mode 100644 index 00000000..d1c73380 --- /dev/null +++ b/src/sdk/utils/t.json @@ -0,0 +1,41 @@ +{ + "chainId": "cataclysm-1", + "chainName": "cataclysm-1", + "rpc": "https://rpc.nibiru.fi", + "rest": "https://lcd.nibiru.fi", + "stakeCurrency": { + "coinDenom": "NIBI", + "coinMinimalDenom": "unibi", + "coinDecimals": 6 + }, + "bip44": { + "coinType": 118 + }, + "bech32Config": { + "bech32PrefixAccAddr": "nibi", + "bech32PrefixAccPub": "nibipub", + "bech32PrefixValAddr": "nibivaloper", + "bech32PrefixValPub": "nibivaloperpub", + "bech32PrefixConsAddr": "nibivalcons", + "bech32PrefixConsPub": "nibivalconspub" + }, + "currencies": [ + { + "coinDenom": "NIBI", + "coinMinimalDenom": "unibi", + "coinDecimals": 6 + } + ], + "feeCurrencies": [ + { + "coinDenom": "NIBI", + "coinMinimalDenom": "unibi", + "coinDecimals": 6, + "gasPriceStep": { + "low": 0.05, + "average": 0.125, + "high": 0.2 + } + } + ] +}