From d7e324d9fd48f3a2f407573c0985d88e0b3b8a5f Mon Sep 17 00:00:00 2001 From: Calico Nino <54007257+CalicoNino@users.noreply.github.com> Date: Wed, 9 Oct 2024 09:04:13 -0400 Subject: [PATCH] feat: account parser (#374) * chore: develop -> main (#370) * revert: cosmos submodule only (#362) * revert: cosmos submodule only * fix: rem * fix: rem * fix: update * feat: add msg client * fix: paths * fix: try chaosnet ibc * fix: path again * fix: try hm * fix: fixes to pass * feat: eth protos (#366) * fix: eth protos * fix: client * fix: fixes * fix: try older nibiru * fix: index * fix: mainnet * fix: import * revert: build change * chore: tests (#367) * fix: all query tests * chore: final tests * fix: buf * fix: fix * fix: pull latest * fix: build * fix: build * refactor(faucet)!: set default tokens (#369) * chore: develop -> main (#368) * revert: cosmos submodule only (#362) * revert: cosmos submodule only * fix: rem * fix: rem * fix: update * feat: add msg client * fix: paths * fix: try chaosnet ibc * fix: path again * fix: try hm * fix: fixes to pass * feat: eth protos (#366) * fix: eth protos * fix: client * fix: fixes * fix: try older nibiru * fix: index * fix: mainnet * fix: import * revert: build change * chore: tests (#367) * fix: all query tests * chore: final tests * fix: buf * fix: fix * fix: pull latest * fix: build * fix: build * chore(release): 4.5.1 ### [4.5.1](https://github.com/NibiruChain/ts-sdk/compare/v4.5.0...v4.5.1) (2024-08-09) ### Miscellaneous Chores * develop -> main ([#368](https://github.com/NibiruChain/ts-sdk/issues/368)) ([c6d6570](https://github.com/NibiruChain/ts-sdk/commit/c6d657009eed49442243c4b0e9021afd34392a98)), closes [#362](https://github.com/NibiruChain/ts-sdk/issues/362) [#366](https://github.com/NibiruChain/ts-sdk/issues/366) [#367](https://github.com/NibiruChain/ts-sdk/issues/367) [skip ci] * fix(faucet): remove unused tokens from default faucet request * fix: bump test --------- Co-authored-by: Cameron Gilbert Co-authored-by: semantic-release-bot --------- Co-authored-by: Kevin Yang <5478483+k-yang@users.noreply.github.com> Co-authored-by: semantic-release-bot * chore(github): Add project automation for https://tinyurl.com/25uty9w5 * chore(release): 4.5.2 ### [4.5.2](https://github.com/NibiruChain/ts-sdk/compare/v4.5.1...v4.5.2) (2024-09-24) ### Miscellaneous Chores * develop -> main ([#370](https://github.com/NibiruChain/ts-sdk/issues/370)) ([ec2a25b](https://github.com/NibiruChain/ts-sdk/commit/ec2a25bd3d02cdeb6b56fad1b1a85c9c249dc697)), closes [#362](https://github.com/NibiruChain/ts-sdk/issues/362) [#366](https://github.com/NibiruChain/ts-sdk/issues/366) [#367](https://github.com/NibiruChain/ts-sdk/issues/367) [#369](https://github.com/NibiruChain/ts-sdk/issues/369) [#368](https://github.com/NibiruChain/ts-sdk/issues/368) [#362](https://github.com/NibiruChain/ts-sdk/issues/362) [#366](https://github.com/NibiruChain/ts-sdk/issues/366) [#367](https://github.com/NibiruChain/ts-sdk/issues/367) [#362](https://github.com/NibiruChain/ts-sdk/issues/362) [#366](https://github.com/NibiruChain/ts-sdk/issues/366) [#367](https://github.com/NibiruChain/ts-sdk/issues/367) * **github:** Add project automation for https://tinyurl.com/25uty9w5 ([c2c27e5](https://github.com/NibiruChain/ts-sdk/commit/c2c27e57a5f94f2180f2df0ad67597790809b143)) [skip ci] * feat: nibiru account parser * refactor: throw if baseaccount is undefined * test: fixing tests * chore: removing unnecessary ? * refactor: matching cosmjs implementation * chore: removing t.json * chore: pr comments --------- Co-authored-by: Cameron Gilbert Co-authored-by: Kevin Yang <5478483+k-yang@users.noreply.github.com> Co-authored-by: semantic-release-bot Co-authored-by: Unique Divine --- src/sdk/tx/account.test.ts | 105 +++++++++++++++++++++++++++++++++++++ src/sdk/tx/account.ts | 42 +++++++++++++++ src/sdk/tx/txClient.ts | 2 + 3 files changed, 149 insertions(+) create mode 100644 src/sdk/tx/account.test.ts create mode 100644 src/sdk/tx/account.ts diff --git a/src/sdk/tx/account.test.ts b/src/sdk/tx/account.test.ts new file mode 100644 index 00000000..d392b404 --- /dev/null +++ b/src/sdk/tx/account.test.ts @@ -0,0 +1,105 @@ +import { accountFromEthAccount, accountFromNibiru } from "./account" +import { EthAccount } from "src/protojs/eth/types/v1/account" +import { Any } from "src/protojs/google/protobuf/any" +import Long from "long" +import * as cosmjs from "@cosmjs/stargate" +import { decodeOptionalPubkey } from "@cosmjs/proto-signing" +import { BaseAccount } from "src/protojs/cosmos/auth/v1beta1/auth" + +// Mock decodeOptionalPubkey +jest.mock("@cosmjs/proto-signing", () => ({ + decodeOptionalPubkey: jest.fn(), +})) + +const mockedDecodeOptionalPubkey = decodeOptionalPubkey as jest.Mock + +describe("accountFromEthAccount", () => { + it("should throw an error if baseAccount is undefined", () => { + const baseAccount: BaseAccount = undefined as unknown as BaseAccount + + expect(() => accountFromEthAccount(baseAccount)).toThrow() + }) + + it("should return a valid account when baseAccount is defined", () => { + const baseAccount: BaseAccount = { + address: "nibi1testaddress", + pubKey: { + typeUrl: "/cosmos.crypto.secp256k1.PubKey", + value: new Uint8Array([1, 2, 3]), + }, + accountNumber: Long.fromNumber(123), + sequence: Long.fromNumber(1), + } + + mockedDecodeOptionalPubkey.mockReturnValue({ + typeUrl: "/cosmos.crypto.secp256k1.PubKey", + value: new Uint8Array([1, 2, 3]), + }) + + const account = accountFromEthAccount(baseAccount) + + expect(account.address).toBe("nibi1testaddress") + expect(account.pubkey).toEqual({ + typeUrl: "/cosmos.crypto.secp256k1.PubKey", + value: new Uint8Array([1, 2, 3]), + }) + expect(account.accountNumber).toEqual(123) + expect(account.sequence).toEqual(1) + }) +}) + +describe("accountFromNibiru", () => { + it("should parse EthAccount typeUrl and return valid account", () => { + const input: Any = { + typeUrl: "/eth.types.v1.EthAccount", + value: EthAccount.encode({ + baseAccount: { + address: "nibi1testaddress", + pubKey: { + typeUrl: "/cosmos.crypto.secp256k1.PubKey", + value: new Uint8Array([4, 5, 6]), + }, + accountNumber: Long.fromNumber(456), + sequence: Long.fromNumber(2), + }, + codeHash: "", + }).finish(), + } + + mockedDecodeOptionalPubkey.mockReturnValue({ + typeUrl: "/cosmos.crypto.secp256k1.PubKey", + value: new Uint8Array([4, 5, 6]), + }) + + const account = accountFromNibiru(input) + + expect(account.address).toBe("nibi1testaddress") + expect(account.pubkey).toEqual({ + typeUrl: "/cosmos.crypto.secp256k1.PubKey", + value: new Uint8Array([4, 5, 6]), + }) + expect(account.accountNumber).toEqual(456) + expect(account.sequence).toEqual(2) + }) + + it("should handle non-EthAccount typeUrl by calling accountFromAny", () => { + const mockAccountFromAny = jest + .spyOn(cosmjs, "accountFromAny") + .mockReturnValue({ + address: "nibi1otheraddress", + pubkey: null, + accountNumber: 789, + sequence: 3, + }) + + const input: Any = { + typeUrl: "/other.types.v1.Account", + value: new Uint8Array([7, 8, 9]), + } + + const account = accountFromNibiru(input) + + expect(account.address).toBe("nibi1otheraddress") + expect(mockAccountFromAny).toHaveBeenCalledWith(input) + }) +}) diff --git a/src/sdk/tx/account.ts b/src/sdk/tx/account.ts new file mode 100644 index 00000000..75d2fe05 --- /dev/null +++ b/src/sdk/tx/account.ts @@ -0,0 +1,42 @@ +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" +import { assert } from "@cosmjs/utils" +import { BaseAccount } from "src/protojs/cosmos/auth/v1beta1/auth" + +/** + * 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 = ({ + address, + pubKey, + accountNumber, + sequence, +}: BaseAccount): Account => ({ + address, + pubkey: decodeOptionalPubkey(pubKey), + accountNumber: accountNumber.toNumber(), + sequence: sequence.toNumber(), +}) + +/** + * 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 baseAccount = EthAccount.decode(value).baseAccount + assert(baseAccount) + return accountFromEthAccount(baseAccount) + } + + 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