Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: account parser #374

Merged
merged 12 commits into from
Oct 9, 2024
3 changes: 3 additions & 0 deletions .github/issue-labeler-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Adds the "S-triage" label ot any issue that gets opened.
S-triage:
- "/.*/"
38 changes: 38 additions & 0 deletions .github/workflows/gh-issues.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: "Auto-add GH issues to project"
# Add all issues opened to the issue board for triage and assignment
# GitHub Org and Project Automation
# https://www.notion.so/nibiru/GitHub-Org-and-Project-Automation-c771d671109849ee9fda7c8b741cd66a?pvs=4

on:
issues:
types: ["opened", "labeled"]

permissions:
issues: write
contents: read

jobs:
# https:/actions/add-to-project
add-to-project:
name: "Add GH ticket to project"
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected]
with:
project-url: https:/orgs/NibiruChain/projects/8
github-token: ${{ secrets.NIBIRU_PM }}

label-triage:
name: "Add GH ticket to project"
runs-on: ubuntu-latest
# The action comes from the "Activty types" for the "issues" webhook event
# https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#issues
if: "github.event.action == 'opened'"
steps:
- uses: github/[email protected]
if: join(github.event.issue.labels) == ''
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
configuration-path: ".github/issue-labeler-config.yml"
enable-versioned-regex: 0
not-before: "2024-05-01T00:00:00Z"
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
### [4.5.2](https:/NibiruChain/ts-sdk/compare/v4.5.1...v4.5.2) (2024-09-24)

### Miscellaneous Chores

- develop -> main ([#370](https:/NibiruChain/ts-sdk/issues/370)) ([ec2a25b](https:/NibiruChain/ts-sdk/commit/ec2a25bd3d02cdeb6b56fad1b1a85c9c249dc697)), closes [#362](https:/NibiruChain/ts-sdk/issues/362) [#366](https:/NibiruChain/ts-sdk/issues/366) [#367](https:/NibiruChain/ts-sdk/issues/367) [#369](https:/NibiruChain/ts-sdk/issues/369) [#368](https:/NibiruChain/ts-sdk/issues/368) [#362](https:/NibiruChain/ts-sdk/issues/362) [#366](https:/NibiruChain/ts-sdk/issues/366) [#367](https:/NibiruChain/ts-sdk/issues/367) [#362](https:/NibiruChain/ts-sdk/issues/362) [#366](https:/NibiruChain/ts-sdk/issues/366) [#367](https:/NibiruChain/ts-sdk/issues/367)
- **github:** Add project automation for https://tinyurl.com/25uty9w5 ([c2c27e5](https:/NibiruChain/ts-sdk/commit/c2c27e57a5f94f2180f2df0ad67597790809b143))

### [4.5.1](https:/NibiruChain/ts-sdk/compare/v4.5.0...v4.5.1) (2024-08-09)

### Miscellaneous Chores
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@nibiruchain/nibijs",
"description": "The TypeScript SDK for the Nibiru blockchain.",
"version": "4.5.1",
"version": "4.5.2",
"license": "MIT",
"repository": {
"type": "git",
Expand Down
105 changes: 105 additions & 0 deletions src/sdk/tx/account.test.ts
Original file line number Diff line number Diff line change
@@ -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"
CalicoNino marked this conversation as resolved.
Show resolved Hide resolved
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)
})
})
40 changes: 40 additions & 0 deletions src/sdk/tx/account.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
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 = (baseAccount: BaseAccount): Account => {
const { address, pubKey, accountNumber, sequence } = baseAccount
CalicoNino marked this conversation as resolved.
Show resolved Hide resolved
return {
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)
}
2 changes: 2 additions & 0 deletions src/sdk/tx/txClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
41 changes: 41 additions & 0 deletions src/sdk/utils/t.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"chainId": "cataclysm-1",
CalicoNino marked this conversation as resolved.
Show resolved Hide resolved
"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
}
}
]
CalicoNino marked this conversation as resolved.
Show resolved Hide resolved
}
Loading