Skip to content

Commit

Permalink
remove keplr related deps (#254)
Browse files Browse the repository at this point in the history
* remove keplr related deps; refactor functions to utilize cosmjs packages instead

* changeset
  • Loading branch information
BurntVal authored Jan 7, 2025
1 parent 9fad9c4 commit ad2160d
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 645 deletions.
6 changes: 6 additions & 0 deletions .changeset/swift-toys-buy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@burnt-labs/abstraxion-core": minor
"demo-app": minor
---

Remove keplr dependencies to resolve related bugs
2 changes: 1 addition & 1 deletion apps/demo-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
"@burnt-labs/ui": "workspace:*",
"@cosmjs/amino": "^0.32.4",
"@cosmjs/cosmwasm-stargate": "^0.32.4",
"@cosmjs/crypto": "^0.32.4",
"@heroicons/react": "^2.1.4",
"@keplr-wallet/cosmos": "^0.12.80",
"cosmjs-types": "^0.9.0",
"next": "^14.0.3",
"react": "^18.2.0",
Expand Down
53 changes: 44 additions & 9 deletions apps/demo-app/pages/api/check-signature.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { verifyADR36Amino } from "@keplr-wallet/cosmos";
import { serializeSignDoc } from "@cosmjs/amino";
import { Secp256k1, Secp256k1Signature, Sha256 } from "@cosmjs/crypto";

// This import will need to change based on the chain you are confirming against.
import { testnetChainInfo } from "@burnt-labs/constants";
Expand All @@ -9,6 +10,34 @@ function isString(test: unknown): test is string {
return typeof test === "string";
}

function makeADR36AminoSignDoc(
signer: string,
message: string | Uint8Array,
): any {
return {
chain_id: "",
account_number: "0",
sequence: "0",
fee: {
amount: [],
gas: "0",
},
msgs: [
{
type: "sign/MsgSignData",
value: {
signer: signer,
data:
typeof message === "string"
? Buffer.from(message).toString("base64")
: Buffer.from(message).toString("base64"),
},
},
],
memo: "",
};
}

/**
* Verify that the given XION signature corresponds to the given message and address.
*
Expand All @@ -18,23 +47,29 @@ function isString(test: unknown): test is string {
* @param signature - The signature to verify against the message and address.
* @returns True if the signature is valid, false otherwise.
*/
export function verifyXionSignature(
export async function verifyXionSignature(
address: string,
pubKey: string,
messageString: string,
signature: string,
): boolean {
): Promise<boolean> {
const signatureBuffer = Buffer.from(signature, "base64");
const uint8Signature = new Uint8Array(signatureBuffer); // Convert the buffer to an Uint8Array
const pubKeyValueBuffer = Buffer.from(pubKey, "base64"); // Decode the base64 encoded value
const pubKeyUint8Array = new Uint8Array(pubKeyValueBuffer); // Convert the buffer to an Uint8Array

return verifyADR36Amino(
"xion",
address,
messageString,
const signDoc = makeADR36AminoSignDoc(address, messageString);
const serializedSignDoc = serializeSignDoc(signDoc);

const messageHash = new Sha256(serializedSignDoc).digest();
const signatureObject = new Secp256k1Signature(
uint8Signature.slice(0, 32),
uint8Signature.slice(32, 64),
);
return Secp256k1.verifySignature(
signatureObject,
messageHash,
pubKeyUint8Array,
uint8Signature,
);
}

Expand All @@ -58,7 +93,7 @@ export async function verifyXionSignatureAndGrants(
messageString: string,
signature: string,
): Promise<boolean> {
const isValid = verifyXionSignature(
const isValid = await verifyXionSignature(
sessionAddress,
pubKey,
messageString,
Expand Down
2 changes: 0 additions & 2 deletions packages/abstraxion-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@
"@cosmjs/stargate": "^0.32.4",
"@cosmjs/tendermint-rpc": "^0.32.4",
"@cosmjs/utils": "^0.32.4",
"@keplr-wallet/cosmos": "^0.12.67",
"@keplr-wallet/crypto": "^0.12.69",
"cosmjs-types": "^0.9.0",
"jose": "^5.1.3"
}
Expand Down
14 changes: 8 additions & 6 deletions packages/abstraxion-core/src/SignArbSecp256k1HdWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import {
encodeSecp256k1Signature,
makeCosmoshubPath,
rawSecp256k1PubkeyToRawAddress,
serializeSignDoc,
} from "@cosmjs/amino";
import { assert, isNonNullObject } from "@cosmjs/utils";
import { Hash, PrivKeySecp256k1 } from "@keplr-wallet/crypto";
import type { HdPath, Secp256k1Keypair } from "@cosmjs/crypto";
import {
Argon2id,
Expand All @@ -17,6 +17,7 @@ import {
pathToString,
Random,
Secp256k1,
Sha256,
sha256,
Slip10,
Slip10Curve,
Expand All @@ -29,7 +30,6 @@ import {
toBech32,
toUtf8,
} from "@cosmjs/encoding";
import { makeADR36AminoSignDoc, serializeSignDoc } from "@keplr-wallet/cosmos";
import type { EncryptionConfiguration } from "@cosmjs/proto-signing/build/wallet";
import {
cosmjsSalt,
Expand All @@ -39,6 +39,7 @@ import {
supportedAlgorithms,
} from "@cosmjs/proto-signing/build/wallet";
import { SignDoc } from "cosmjs-types/cosmos/tx/v1beta1/tx";
import { makeADR36AminoSignDoc } from "./utils";

const serializationTypeV1 = "directsecp256k1hdwallet-v1";

Expand Down Expand Up @@ -378,11 +379,12 @@ export class SignArbSecp256k1HdWallet {
const { privkey } = account;
const signDoc = makeADR36AminoSignDoc(signerAddress, message);
const serializedSignDoc = serializeSignDoc(signDoc);
const digest = Hash.sha256(serializedSignDoc);
const cryptoPrivKey = new PrivKeySecp256k1(privkey);
const signature = cryptoPrivKey.signDigest32(digest);

const digest = new Sha256(serializedSignDoc).digest();
const signature = await Secp256k1.createSignature(digest, privkey);

return Buffer.from(
new Uint8Array([...signature.r, ...signature.s]),
new Uint8Array([...signature.r(32), ...signature.s(32)]),
).toString("base64");
};
}
18 changes: 18 additions & 0 deletions packages/abstraxion-core/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,21 @@ export type ContractGrantDescription =
address: string;
amounts: SpendLimit[];
};

export interface AminoSignDoc {
chain_id: string;
account_number: string;
sequence: string;
fee: {
amount: never[];
gas: string;
};
msgs: {
type: string;
value: {
signer: string;
data: string;
};
}[];
memo: string;
}
30 changes: 30 additions & 0 deletions packages/abstraxion-core/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
import { AminoSignDoc } from "@/types";

export function wait(ms = 1000) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}

export function makeADR36AminoSignDoc(
signer: string,
message: string | Uint8Array,
): AminoSignDoc {
return {
chain_id: "",
account_number: "0",
sequence: "0",
fee: {
amount: [],
gas: "0",
},
msgs: [
{
type: "sign/MsgSignData",
value: {
signer: signer,
data:
typeof message === "string"
? Buffer.from(message).toString("base64")
: Buffer.from(message).toString("base64"),
},
},
],
memo: "",
};
}
21 changes: 15 additions & 6 deletions packages/abstraxion-core/tests/SignArbSecp256k1HdWallet.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { TextDecoder, TextEncoder } from "node:util";
import { verifyADR36Amino } from "@keplr-wallet/cosmos";
import { SignArbSecp256k1HdWallet } from "../src/SignArbSecp256k1HdWallet";
import { AccountData } from "@cosmjs/proto-signing";
import { serializeSignDoc } from "@cosmjs/amino";
import { Secp256k1, Secp256k1Signature, Sha256 } from "@cosmjs/crypto";
import { makeADR36AminoSignDoc } from "@/utils";

global.TextEncoder = TextEncoder;
// @ts-expect-error: TextDecoder is not available in testing environment by default.
Expand Down Expand Up @@ -39,12 +41,19 @@ describe("SignArbSecp256k1HdWallet", () => {
const pubKeyValueBuffer = Buffer.from(pubKey, "base64"); // Decode the base64 encoded value
const pubKeyUint8Array = new Uint8Array(pubKeyValueBuffer); // Convert the buffer to an Uint8Array

return verifyADR36Amino(
"xion",
address,
messageString,
const signDoc = makeADR36AminoSignDoc(address, messageString);
const serializedSignDoc = serializeSignDoc(signDoc);

const messageHash = new Sha256(serializedSignDoc).digest();
const signatureObject = new Secp256k1Signature(
uint8Signature.slice(0, 32),
uint8Signature.slice(32, 64),
);

return Secp256k1.verifySignature(
signatureObject,
messageHash,
pubKeyUint8Array,
uint8Signature,
);
}

Expand Down
Loading

0 comments on commit ad2160d

Please sign in to comment.