Skip to content
Open
12 changes: 12 additions & 0 deletions examples/sandbox/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,18 @@ <h4>Osmosis</h4>
<input type="text" id="osmosisResults" />
</div>

<div class="container">
<h4>Kujira</h4>
<button class="button button-outline" id="kujiraAddress">Get Address</button>
<button class="button button-outline" id="kujiraSend">Send</button>
<button class="button button-outline" id="kujiraDelegate">Delegate</button>
<button class="button button-outline" id="kujiraUndelegate">Undelegate</button>
<button class="button button-outline" id="kujiraRedelegate">Redelegate</button>
<button class="button button-outline" id="kujiraRewards">Rewards</button>
<button class="button button-outline" id="kujiraIBCTransfer">IBC Transfer</button>
<input type="text" id="kujiraResults" />
</div>

<div class="container">
<h4>Arkeo</h4>
<button class="button button-outline" id="arkeoGetAddress">Get Address</button>
Expand Down
182 changes: 182 additions & 0 deletions examples/sandbox/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ import {
osmosisSwapTx,
osmosisUndelegateTx,
} from "./json/osmosis/osmosisAminoTx.json";
import {
kujiraDelegateTx,
kujiraIBCTransferTx,
kujiraRedelegateTx,
kujiraRewardsTx,
kujiraSendTx,
kujiraUndelegateTx,
} from "./json/kujira/kujiraAminoTx.json";
import * as rippleTxJson from "./json/rippleTx.json";
import {
thorchainBinanceBaseTx,
Expand Down Expand Up @@ -1818,6 +1826,180 @@ $osmosisSwap.on("click", async (e) => {
}
});

/*
* Kujira
*/
const $kujiraAddress = $("#kujiraAddress");
const $kujiraSend = $("#kujiraSend");
const $kujiraDelegate = $("#kujiraDelegate");
const $kujiraUndelegate = $("#kujiraUndelegate");
const $kujiraRedelegate = $("#kujiraRedelegate");
const $kujiraRewards = $("#kujiraRewards");
const $kujiraIBCTransfer = $("#kujiraIBCTransfer");

const $kujiraResults = $("#kujiraResults");

$kujiraAddress.on("click", async (e) => {
e.preventDefault();
if (!wallet) {
$kujiraResults.val("No wallet?");
return;
}
if (core.supportsKujira(wallet)) {
const { addressNList } = wallet.kujiraGetAccountPaths({ accountIdx: 0 })[0];
const result = await wallet.kujiraGetAddress({
addressNList,
showDisplay: false,
});
await wallet.kujiraGetAddress({
addressNList,
showDisplay: true,
});
$kujiraResults.val(result);
} else {
const label = await wallet.getLabel();
$kujiraResults.val(label + " does not support Lujira");
}
});

$kujiraSend.on("click", async (e) => {
e.preventDefault();
if (!wallet) {
$kujiraResults.val("No wallet?");
return;
}
if (core.supportsKujira(wallet)) {
const unsigned: core.Kujira.StdTx = kujiraSendTx;

const res = await wallet.kujiraSignTx({
addressNList: core.bip32ToAddressNList(`m/44'/118'/0'/0/0`),
chain_id: unsigned.chain_id,
account_number: unsigned.account_number,
sequence: unsigned.sequence,
tx: unsigned,
});
$kujiraResults.val(JSON.stringify(res));
} else {
const label = await wallet.getLabel();
$kujiraResults.val(label + " does not support Kujira");
}
});

$kujiraDelegate.on("click", async (e) => {
e.preventDefault();
if (!wallet) {
$kujiraResults.val("No wallet?");
return;
}
if (core.supportsKujira(wallet)) {
const unsigned: core.Kujira.StdTx = kujiraDelegateTx;

const res = await wallet.kujiraSignTx({
addressNList: core.bip32ToAddressNList(`m/44'/118'/0'/0/0`),
chain_id: unsigned.chain_id,
account_number: unsigned.account_number,
sequence: unsigned.sequence,
tx: unsigned,
});
$kujiraResults.val(JSON.stringify(res));
} else {
const label = await wallet.getLabel();
$kujiraResults.val(label + " does not support Kujira");
}
});

$kujiraUndelegate.on("click", async (e) => {
e.preventDefault();
if (!wallet) {
$kujiraResults.val("No wallet?");
return;
}
if (core.supportsKujira(wallet)) {
const unsigned: core.Kujira.StdTx = kujiraUndelegateTx;

const res = await wallet.kujiraSignTx({
addressNList: core.bip32ToAddressNList(`m/44'/118'/0'/0/0`),
chain_id: unsigned.chain_id,
account_number: unsigned.account_number,
sequence: unsigned.sequence,
tx: unsigned,
});
$kujiraResults.val(JSON.stringify(res));
} else {
const label = await wallet.getLabel();
$kujiraResults.val(label + " does not support Kujira");
}
});

$kujiraRedelegate.on("click", async (e) => {
e.preventDefault();
if (!wallet) {
$kujiraResults.val("No wallet?");
return;
}
if (core.supportsKujira(wallet)) {
const unsigned: core.Kujira.StdTx = kujiraRedelegateTx;

const res = await wallet.kujiraSignTx({
addressNList: core.bip32ToAddressNList(`m/44'/118'/0'/0/0`),
chain_id: unsigned.chain_id,
account_number: unsigned.account_number,
sequence: unsigned.sequence,
tx: unsigned,
});
$kujiraResults.val(JSON.stringify(res));
} else {
const label = await wallet.getLabel();
$kujiraResults.val(label + " does not support Kujira");
}
});

$kujiraRewards.on("click", async (e) => {
e.preventDefault();
if (!wallet) {
$kujiraResults.val("No wallet?");
return;
}
if (core.supportsKujira(wallet)) {
const unsigned: core.Kujira.StdTx = kujiraRewardsTx;

const res = await wallet.kujiraSignTx({
addressNList: core.bip32ToAddressNList(`m/44'/118'/0'/0/0`),
chain_id: unsigned.chain_id,
account_number: unsigned.account_number,
sequence: unsigned.sequence,
tx: unsigned,
});
$kujiraResults.val(JSON.stringify(res));
} else {
const label = await wallet.getLabel();
$kujiraResults.val(label + " does not support Kujira");
}
});

$kujiraIBCTransfer.on("click", async (e) => {
e.preventDefault();
if (!wallet) {
$kujiraResults.val("No wallet?");
return;
}
if (core.supportsKujira(wallet)) {
const unsigned: core.Kujira.StdTx = kujiraIBCTransferTx;

const res = await wallet.kujiraSignTx({
addressNList: core.bip32ToAddressNList(`m/44'/118'/0'/0/0`),
chain_id: unsigned.chain_id,
account_number: unsigned.account_number,
sequence: unsigned.sequence,
tx: unsigned,
});
$kujiraResults.val(JSON.stringify(res));
} else {
const label = await wallet.getLabel();
$kujiraResults.val(label + " does not support Kujira");
}
});

/*
* Arkeo
*/
Expand Down
1 change: 1 addition & 0 deletions examples/sandbox/json/kujira/kujiraAnomiTx.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
//todo
7 changes: 7 additions & 0 deletions integration/src/kujira/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as core from "@keepkey/hdwallet-core";

import { kujiraTests as tests } from "./kujira";

export function kujiraTests(get: () => { wallet: core.HDWallet; info: core.HDWalletInfo }): void {
tests(get);
}
3 changes: 2 additions & 1 deletion packages/hdwallet-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ export * from "./exceptions";
export * from "./fio";
export * from "./kava";
export * from "./keyring";
export * from "./kujira";
export * from "./mayachain";
export * from "./ripple";
export * from "./secret";
export * from "./terra";
export * from "./thorchain";
export * from "./mayachain";
export * from "./transport";
export * from "./utils";
export * from "./wallet";
139 changes: 139 additions & 0 deletions packages/hdwallet-core/src/kujira.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import { addressNListToBIP32, slip44ByCoin } from "./utils";
import { BIP32Path, HDWallet, HDWalletInfo, PathDescription } from "./wallet";

export interface KujiraGetAddress {
addressNList: BIP32Path;
showDisplay?: boolean;
}

// eslint-disable-next-line @typescript-eslint/no-namespace
export namespace Kujira {
export interface Msg {
type: string;
value: any;
}

export type Coins = Coin[];

export interface Coin {
denom: string;
amount: string;
}

export interface StdFee {
amount: Coins;
gas: string;
}

// eslint-disable-next-line @typescript-eslint/no-namespace
namespace crypto {
export interface PubKey {
type: string;
value: string;
}
}

export interface StdSignature {
pub_key?: crypto.PubKey;
signature: string;
}

export interface StdTx {
msg: Msg[];
fee: StdFee;
signatures: StdSignature[];
memo?: string;
}
}

export interface KujiraTx {
msg: Kujira.Msg[];
fee: Kujira.StdFee;
signatures: Kujira.StdSignature[];
memo?: string;
}

export interface KujiraSignTx {
addressNList: BIP32Path;
tx: Kujira.StdTx;
chain_id: string;
account_number: string;
sequence: string;
fee?: number;
}

export interface KujiraSignedTx {
serialized: string;
body: string;
authInfoBytes: string;
signatures: string[];
}

export interface KujiraGetAccountPaths {
accountIdx: number;
}

export interface KujiraAccountPath {
addressNList: BIP32Path;
}

export interface KujiraWalletInfo extends HDWalletInfo {
readonly _supportsKujiraInfo: boolean;

/**
* Returns a list of bip32 paths for a given account index in preferred order
* from most to least preferred.
*/
KujiraGetAccountPaths(msg: KujiraGetAccountPaths): Array<KujiraAccountPath>;

/**
* Returns the "next" account path, if any.
*/
kujiraNextAccountPath(msg: KujiraAccountPath): KujiraAccountPath | undefined;
}

export interface KujiraWallet extends KujiraWalletInfo, HDWallet {
readonly _supportsKujira: boolean;

kujiraGetAddress(msg: KujiraGetAddress): Promise<string | null>;
kujiraSignTx(msg: KujiraSignTx): Promise<KujiraSignedTx | null>;
}

export function kujiraDescribePath(path: BIP32Path): PathDescription {
const pathStr = addressNListToBIP32(path);
const unknown: PathDescription = {
verbose: pathStr,
coin: "Kuji",
isKnown: false,
};

if (path.length != 5) {
return unknown;
}

if (path[0] != 0x80000000 + 44) {
return unknown;
}

if (path[1] != 0x80000000 + slip44ByCoin("Kuji")) {
return unknown;
}

if ((path[2] & 0x80000000) >>> 0 !== 0x80000000) {
return unknown;
}

if (path[3] !== 0 || path[4] !== 0) {
return unknown;
}

const index = path[2] & 0x7fffffff;
return {
verbose: `Kujira Account #${index}`,
accountIdx: index,
wholeAccount: true,
coin: "Kuji",
isKnown: true,
isPrefork: false,
};
}
1 change: 1 addition & 0 deletions packages/hdwallet-core/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ const slip44Table = Object.freeze({
ArbitrumNova: 60,
Mayachain: 931,
Cacao: 931,
Kujira: 118,
} as const);
type Slip44ByCoin<T> = T extends keyof typeof slip44Table ? typeof slip44Table[T] : number | undefined;
export function slip44ByCoin<T extends Coin>(coin: T): Slip44ByCoin<T> {
Expand Down
Loading