Deduplicate makeSignBytes
This commit is contained in:
parent
44182e96b7
commit
2d14efa4cd
@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable @typescript-eslint/camelcase */
|
/* eslint-disable @typescript-eslint/camelcase */
|
||||||
import { marshalTx, sortJson, unmarshalTx } from "@cosmwasm/sdk";
|
import { makeSignBytes, marshalTx, types, unmarshalTx } from "@cosmwasm/sdk";
|
||||||
import {
|
import {
|
||||||
Address,
|
Address,
|
||||||
ChainId,
|
ChainId,
|
||||||
@ -14,7 +14,6 @@ import {
|
|||||||
TxCodec,
|
TxCodec,
|
||||||
UnsignedTransaction,
|
UnsignedTransaction,
|
||||||
} from "@iov/bcp";
|
} from "@iov/bcp";
|
||||||
import { Encoding } from "@iov/encoding";
|
|
||||||
|
|
||||||
import { CosmosBech32Prefix, isValidAddress, pubkeyToAddress } from "./address";
|
import { CosmosBech32Prefix, isValidAddress, pubkeyToAddress } from "./address";
|
||||||
import { Caip5 } from "./caip5";
|
import { Caip5 } from "./caip5";
|
||||||
@ -22,8 +21,6 @@ import { parseTx } from "./decode";
|
|||||||
import { buildSignedTx, buildUnsignedTx } from "./encode";
|
import { buildSignedTx, buildUnsignedTx } from "./encode";
|
||||||
import { nonceToAccountNumber, nonceToSequence, TokenInfos } from "./types";
|
import { nonceToAccountNumber, nonceToSequence, TokenInfos } from "./types";
|
||||||
|
|
||||||
const { toUtf8 } = Encoding;
|
|
||||||
|
|
||||||
export class CosmWasmCodec implements TxCodec {
|
export class CosmWasmCodec implements TxCodec {
|
||||||
private readonly prefix: CosmosBech32Prefix;
|
private readonly prefix: CosmosBech32Prefix;
|
||||||
private readonly tokens: TokenInfos;
|
private readonly tokens: TokenInfos;
|
||||||
@ -34,18 +31,19 @@ export class CosmWasmCodec implements TxCodec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public bytesToSign(unsigned: UnsignedTransaction, nonce: Nonce): SigningJob {
|
public bytesToSign(unsigned: UnsignedTransaction, nonce: Nonce): SigningJob {
|
||||||
const memo = (unsigned as any).memo;
|
|
||||||
const built = buildUnsignedTx(unsigned, this.tokens);
|
const built = buildUnsignedTx(unsigned, this.tokens);
|
||||||
|
|
||||||
const signMsg = sortJson({
|
const nonceInfo: types.NonceInfo = {
|
||||||
account_number: nonceToAccountNumber(nonce).toString(),
|
account_number: nonceToAccountNumber(nonce),
|
||||||
chain_id: Caip5.decode(unsigned.chainId),
|
sequence: nonceToSequence(nonce),
|
||||||
fee: (built.value as any).fee,
|
};
|
||||||
memo: memo,
|
const signBytes = makeSignBytes(
|
||||||
msgs: (built.value as any).msg,
|
built.value.msg[0],
|
||||||
sequence: nonceToSequence(nonce).toString(),
|
built.value.fee,
|
||||||
});
|
Caip5.decode(unsigned.chainId),
|
||||||
const signBytes = toUtf8(JSON.stringify(signMsg));
|
built.value.memo || "",
|
||||||
|
nonceInfo,
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
bytes: signBytes as SignableBytes,
|
bytes: signBytes as SignableBytes,
|
||||||
|
|||||||
@ -23,13 +23,9 @@ const maxAcct = 1 << 23;
|
|||||||
// tslint:disable-next-line:no-bitwise
|
// tslint:disable-next-line:no-bitwise
|
||||||
const maxSeq = 1 << 20;
|
const maxSeq = 1 << 20;
|
||||||
|
|
||||||
// NonceInfo is the data we need from account to create a nonce
|
|
||||||
// Use this so no confusion about order of arguments
|
|
||||||
export type NonceInfo = Pick<types.BaseAccount, "account_number" | "sequence">;
|
|
||||||
|
|
||||||
// this (lossily) encodes the two pieces of info (uint64) needed to sign into
|
// this (lossily) encodes the two pieces of info (uint64) needed to sign into
|
||||||
// one (53-bit) number. Cross your fingers.
|
// one (53-bit) number. Cross your fingers.
|
||||||
export function accountToNonce({ account_number: account, sequence }: NonceInfo): Nonce {
|
export function accountToNonce({ account_number: account, sequence }: types.NonceInfo): Nonce {
|
||||||
// we allow 23 bits (8 million) for accounts, and 20 bits (1 million) for tx/account
|
// we allow 23 bits (8 million) for accounts, and 20 bits (1 million) for tx/account
|
||||||
// let's fix this soon
|
// let's fix this soon
|
||||||
if (account > maxAcct) {
|
if (account > maxAcct) {
|
||||||
|
|||||||
3
packages/bcp/types/types.d.ts
vendored
3
packages/bcp/types/types.d.ts
vendored
@ -15,7 +15,6 @@ export interface TokenInfo {
|
|||||||
readonly fractionalDigits: number;
|
readonly fractionalDigits: number;
|
||||||
}
|
}
|
||||||
export declare type TokenInfos = ReadonlyArray<TokenInfo>;
|
export declare type TokenInfos = ReadonlyArray<TokenInfo>;
|
||||||
export declare type NonceInfo = Pick<types.BaseAccount, "account_number" | "sequence">;
|
export declare function accountToNonce({ account_number: account, sequence }: types.NonceInfo): Nonce;
|
||||||
export declare function accountToNonce({ account_number: account, sequence }: NonceInfo): Nonce;
|
|
||||||
export declare function nonceToAccountNumber(nonce: Nonce): number;
|
export declare function nonceToAccountNumber(nonce: Nonce): number;
|
||||||
export declare function nonceToSequence(nonce: Nonce): number;
|
export declare function nonceToSequence(nonce: Nonce): number;
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { Secp256k1 } from "@iov/crypto";
|
import { Secp256k1 } from "@iov/crypto";
|
||||||
import { Encoding } from "@iov/encoding";
|
import { Encoding } from "@iov/encoding";
|
||||||
|
|
||||||
import { StdSignature, StdTx } from "./types";
|
import { Msg, NonceInfo, StdFee, StdSignature, StdTx } from "./types";
|
||||||
|
|
||||||
const { toBase64 } = Encoding;
|
const { toBase64, toUtf8 } = Encoding;
|
||||||
|
|
||||||
export function sortJson(json: any): any {
|
function sortJson(json: any): any {
|
||||||
if (typeof json !== "object" || json === null) {
|
if (typeof json !== "object" || json === null) {
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
@ -28,6 +28,26 @@ export function marshalTx(tx: StdTx): Uint8Array {
|
|||||||
return Encoding.toUtf8(json);
|
return Encoding.toUtf8(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function makeSignBytes(
|
||||||
|
msg: Msg,
|
||||||
|
fee: StdFee,
|
||||||
|
chainId: string,
|
||||||
|
memo: string,
|
||||||
|
account: NonceInfo,
|
||||||
|
): Uint8Array {
|
||||||
|
const signMsg = sortJson({
|
||||||
|
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||||
|
account_number: account.account_number.toString(),
|
||||||
|
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||||
|
chain_id: chainId,
|
||||||
|
fee: fee,
|
||||||
|
memo: memo,
|
||||||
|
msgs: msg,
|
||||||
|
sequence: account.sequence.toString(),
|
||||||
|
});
|
||||||
|
return toUtf8(JSON.stringify(signMsg));
|
||||||
|
}
|
||||||
|
|
||||||
export function encodeSecp256k1Signature(pubkey: Uint8Array, signature: Uint8Array): StdSignature {
|
export function encodeSecp256k1Signature(pubkey: Uint8Array, signature: Uint8Array): StdSignature {
|
||||||
return {
|
return {
|
||||||
// eslint-disable-next-line @typescript-eslint/camelcase
|
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import * as types from "./types";
|
import * as types from "./types";
|
||||||
|
|
||||||
export { unmarshalTx } from "./decoding";
|
export { unmarshalTx } from "./decoding";
|
||||||
export { encodeSecp256k1Signature, marshalTx, sortJson } from "./encoding";
|
export { encodeSecp256k1Signature, makeSignBytes, marshalTx } from "./encoding";
|
||||||
export { RestClient, TxsResponse } from "./restclient";
|
export { RestClient, TxsResponse } from "./restclient";
|
||||||
export { types };
|
export { types };
|
||||||
|
|||||||
@ -3,13 +3,13 @@ import { ChainId, PrehashType, SignableBytes } from "@iov/bcp";
|
|||||||
import { Encoding } from "@iov/encoding";
|
import { Encoding } from "@iov/encoding";
|
||||||
import { HdPaths, Secp256k1HdWallet } from "@iov/keycontrol";
|
import { HdPaths, Secp256k1HdWallet } from "@iov/keycontrol";
|
||||||
|
|
||||||
import { encodeSecp256k1Signature, marshalTx, sortJson } from "./encoding";
|
import { encodeSecp256k1Signature, makeSignBytes, marshalTx } from "./encoding";
|
||||||
import { RestClient } from "./restclient";
|
import { RestClient } from "./restclient";
|
||||||
import contract from "./testdata/contract.json";
|
import contract from "./testdata/contract.json";
|
||||||
import data from "./testdata/cosmoshub.json";
|
import data from "./testdata/cosmoshub.json";
|
||||||
import { MsgStoreCode, StdTx } from "./types";
|
import { MsgStoreCode, StdFee, StdTx } from "./types";
|
||||||
|
|
||||||
const { fromBase64, toUtf8 } = Encoding;
|
const { fromBase64 } = Encoding;
|
||||||
|
|
||||||
const httpUrl = "http://localhost:1317";
|
const httpUrl = "http://localhost:1317";
|
||||||
const defaultNetworkId = "testing";
|
const defaultNetworkId = "testing";
|
||||||
@ -75,41 +75,25 @@ describe("RestClient", () => {
|
|||||||
builder: "v0.0.1",
|
builder: "v0.0.1",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const fee: StdFee = {
|
||||||
const unsigned: StdTx = {
|
amount: [
|
||||||
msg: [theMsg],
|
{
|
||||||
memo: memo,
|
amount: "5000",
|
||||||
signatures: [],
|
denom: "ucosm",
|
||||||
fee: {
|
},
|
||||||
amount: [
|
],
|
||||||
{
|
gas: "89000000",
|
||||||
amount: "5000",
|
|
||||||
denom: "ucosm",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
gas: "89000000",
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const client = new RestClient(httpUrl);
|
const client = new RestClient(httpUrl);
|
||||||
const account = (await client.authAccounts(faucetAddress)).result.value;
|
const account = (await client.authAccounts(faucetAddress)).result.value;
|
||||||
|
const signBytes = makeSignBytes(theMsg, fee, defaultNetworkId, memo, account) as SignableBytes;
|
||||||
const signMsg = sortJson({
|
|
||||||
account_number: account.account_number.toString(),
|
|
||||||
chain_id: defaultNetworkId,
|
|
||||||
fee: unsigned.fee,
|
|
||||||
memo: memo,
|
|
||||||
msgs: unsigned.msg,
|
|
||||||
sequence: account.sequence.toString(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const signBytes = toUtf8(JSON.stringify(signMsg)) as SignableBytes;
|
|
||||||
const rawSignature = await wallet.createTransactionSignature(signer, signBytes, PrehashType.Sha256);
|
const rawSignature = await wallet.createTransactionSignature(signer, signBytes, PrehashType.Sha256);
|
||||||
const signature = encodeSecp256k1Signature(signer.pubkey.data, rawSignature);
|
const signature = encodeSecp256k1Signature(signer.pubkey.data, rawSignature);
|
||||||
|
|
||||||
const tx: StdTx = {
|
const tx: StdTx = {
|
||||||
msg: unsigned.msg,
|
msg: [theMsg],
|
||||||
fee: unsigned.fee,
|
fee: fee,
|
||||||
memo: memo,
|
memo: memo,
|
||||||
signatures: [signature],
|
signatures: [signature],
|
||||||
};
|
};
|
||||||
|
|||||||
@ -97,3 +97,6 @@ export interface BaseAccount {
|
|||||||
readonly account_number: number;
|
readonly account_number: number;
|
||||||
readonly sequence: number;
|
readonly sequence: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The data we need from BaseAccount to create a nonce */
|
||||||
|
export type NonceInfo = Pick<BaseAccount, "account_number" | "sequence">;
|
||||||
|
|||||||
10
packages/sdk/types/encoding.d.ts
vendored
10
packages/sdk/types/encoding.d.ts
vendored
@ -1,4 +1,10 @@
|
|||||||
import { StdSignature, StdTx } from "./types";
|
import { Msg, NonceInfo, StdFee, StdSignature, StdTx } from "./types";
|
||||||
export declare function sortJson(json: any): any;
|
|
||||||
export declare function marshalTx(tx: StdTx): Uint8Array;
|
export declare function marshalTx(tx: StdTx): Uint8Array;
|
||||||
|
export declare function makeSignBytes(
|
||||||
|
msg: Msg,
|
||||||
|
fee: StdFee,
|
||||||
|
chainId: string,
|
||||||
|
memo: string,
|
||||||
|
account: NonceInfo,
|
||||||
|
): Uint8Array;
|
||||||
export declare function encodeSecp256k1Signature(pubkey: Uint8Array, signature: Uint8Array): StdSignature;
|
export declare function encodeSecp256k1Signature(pubkey: Uint8Array, signature: Uint8Array): StdSignature;
|
||||||
|
|||||||
2
packages/sdk/types/index.d.ts
vendored
2
packages/sdk/types/index.d.ts
vendored
@ -1,5 +1,5 @@
|
|||||||
import * as types from "./types";
|
import * as types from "./types";
|
||||||
export { unmarshalTx } from "./decoding";
|
export { unmarshalTx } from "./decoding";
|
||||||
export { encodeSecp256k1Signature, marshalTx, sortJson } from "./encoding";
|
export { encodeSecp256k1Signature, makeSignBytes, marshalTx } from "./encoding";
|
||||||
export { RestClient, TxsResponse } from "./restclient";
|
export { RestClient, TxsResponse } from "./restclient";
|
||||||
export { types };
|
export { types };
|
||||||
|
|||||||
2
packages/sdk/types/types.d.ts
vendored
2
packages/sdk/types/types.d.ts
vendored
@ -69,4 +69,6 @@ export interface BaseAccount {
|
|||||||
readonly account_number: number;
|
readonly account_number: number;
|
||||||
readonly sequence: number;
|
readonly sequence: number;
|
||||||
}
|
}
|
||||||
|
/** The data we need from BaseAccount to create a nonce */
|
||||||
|
export declare type NonceInfo = Pick<BaseAccount, "account_number" | "sequence">;
|
||||||
export {};
|
export {};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user