Merge pull request #84 from confio/dont-query-nonce
Don't query nonces in searchTx
This commit is contained in:
commit
984df700b2
@ -23,7 +23,7 @@ import {
|
||||
|
||||
import { pubkeyToAddress } from "./address";
|
||||
import { Caip5 } from "./caip5";
|
||||
import { parseTx } from "./decode";
|
||||
import { parseSignedTx } from "./decode";
|
||||
import { buildSignedTx, buildUnsignedTx } from "./encode";
|
||||
import { BankTokens, Erc20Token, nonceToAccountNumber, nonceToSequence } from "./types";
|
||||
|
||||
@ -81,7 +81,7 @@ export class CosmWasmCodec implements TxCodec {
|
||||
throw new Error("Nonce is required");
|
||||
}
|
||||
const parsed = unmarshalTx(bytes);
|
||||
return parseTx(parsed, chainId, nonce, this.bankTokens);
|
||||
return parseSignedTx(parsed, chainId, nonce, this.bankTokens);
|
||||
}
|
||||
|
||||
public identityToAddress(identity: Identity): Address {
|
||||
|
||||
@ -38,7 +38,7 @@ import { Stream } from "xstream";
|
||||
|
||||
import { decodeCosmosPubkey, pubkeyToAddress } from "./address";
|
||||
import { Caip5 } from "./caip5";
|
||||
import { decodeAmount, parseTxsResponse } from "./decode";
|
||||
import { decodeAmount, parseTxsResponseSigned, parseTxsResponseUnsigned } from "./decode";
|
||||
import { buildSignedTx } from "./encode";
|
||||
import { accountToNonce, BankToken, Erc20Token } from "./types";
|
||||
|
||||
@ -234,8 +234,7 @@ export class CosmWasmConnection implements BlockchainConnection {
|
||||
try {
|
||||
// tslint:disable-next-line: deprecation
|
||||
const response = await this.restClient.txsById(id);
|
||||
const chainId = this.chainId();
|
||||
return this.parseAndPopulateTxResponse(response, chainId);
|
||||
return this.parseAndPopulateTxResponseSigned(response);
|
||||
} catch (error) {
|
||||
if (error.response.status === 404) {
|
||||
throw new Error("Transaction does not exist");
|
||||
@ -319,8 +318,7 @@ export class CosmWasmConnection implements BlockchainConnection {
|
||||
throw new Error("Unsupported query");
|
||||
}
|
||||
|
||||
const chainId = this.chainId();
|
||||
return Promise.all(txs.map(tx => this.parseAndPopulateTxResponse(tx, chainId)));
|
||||
return txs.map(tx => this.parseAndPopulateTxResponseUnsigned(tx));
|
||||
}
|
||||
|
||||
public listenTx(
|
||||
@ -357,34 +355,42 @@ export class CosmWasmConnection implements BlockchainConnection {
|
||||
};
|
||||
}
|
||||
|
||||
private async parseAndPopulateTxResponse(
|
||||
private parseAndPopulateTxResponseUnsigned(
|
||||
response: TxsResponse,
|
||||
): ConfirmedTransaction<UnsignedTransaction> | FailedTransaction {
|
||||
const chainId = this.chainId();
|
||||
return parseTxsResponseUnsigned(chainId, parseInt(response.height, 10), response, this.bankTokens);
|
||||
}
|
||||
|
||||
private async parseAndPopulateTxResponseSigned(
|
||||
response: TxsResponse,
|
||||
chainId: ChainId,
|
||||
): Promise<ConfirmedAndSignedTransaction<UnsignedTransaction> | FailedTransaction> {
|
||||
const firstMsg = response.tx.value.msg.find(() => true);
|
||||
if (!firstMsg) throw new Error("Got transaction without a first message. What is going on here?");
|
||||
|
||||
let senderAddress: string;
|
||||
// needed to get the (account_number, sequence) for the primary signature
|
||||
let primarySignerAddress: string;
|
||||
if (types.isMsgSend(firstMsg)) {
|
||||
senderAddress = firstMsg.value.from_address;
|
||||
primarySignerAddress = firstMsg.value.from_address;
|
||||
} else if (
|
||||
types.isMsgStoreCode(firstMsg) ||
|
||||
types.isMsgInstantiateContract(firstMsg) ||
|
||||
types.isMsgExecuteContract(firstMsg)
|
||||
) {
|
||||
senderAddress = firstMsg.value.sender;
|
||||
primarySignerAddress = firstMsg.value.sender;
|
||||
} else {
|
||||
throw new Error(`Got unsupported type of message: ${firstMsg.type}`);
|
||||
}
|
||||
|
||||
// tslint:disable-next-line: deprecation
|
||||
const accountForHeight = await this.restClient.authAccounts(senderAddress, response.height);
|
||||
const accountForHeight = await this.restClient.authAccounts(primarySignerAddress, response.height);
|
||||
const accountNumber = accountForHeight.result.value.account_number;
|
||||
// this is technically not the proper sequence. maybe this causes issues for sig validation?
|
||||
// leaving for now unless it causes issues
|
||||
const sequence = accountForHeight.result.value.sequence - 1;
|
||||
const nonce = accountToNonce(accountNumber, sequence);
|
||||
|
||||
return parseTxsResponse(chainId, parseInt(response.height, 10), nonce, response, this.bankTokens);
|
||||
const chainId = this.chainId();
|
||||
return parseTxsResponseSigned(chainId, parseInt(response.height, 10), nonce, response, this.bankTokens);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
import { types } from "@cosmwasm/sdk";
|
||||
import { Address, Algorithm, TokenTicker } from "@iov/bcp";
|
||||
import { Address, Algorithm, SendTransaction, TokenTicker } from "@iov/bcp";
|
||||
import { Encoding } from "@iov/encoding";
|
||||
|
||||
import {
|
||||
@ -10,11 +10,13 @@ import {
|
||||
decodeSignature,
|
||||
parseFee,
|
||||
parseMsg,
|
||||
parseTx,
|
||||
parseTxsResponse,
|
||||
parseSignedTx,
|
||||
parseTxsResponseSigned,
|
||||
parseTxsResponseUnsigned,
|
||||
parseUnsignedTx,
|
||||
} from "./decode";
|
||||
import { chainId, nonce, signedTxJson, txId } from "./testdata.spec";
|
||||
import data from "./testdata/cosmoshub.json";
|
||||
import * as testdata from "./testdata.spec";
|
||||
import cosmoshub from "./testdata/cosmoshub.json";
|
||||
import { BankTokens } from "./types";
|
||||
|
||||
const { fromBase64, fromHex } = Encoding;
|
||||
@ -28,7 +30,7 @@ describe("decode", () => {
|
||||
"1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==",
|
||||
);
|
||||
const defaultFullSignature = {
|
||||
nonce: nonce,
|
||||
nonce: testdata.nonce,
|
||||
pubkey: defaultPubkey,
|
||||
signature: defaultSignature,
|
||||
};
|
||||
@ -37,12 +39,14 @@ describe("decode", () => {
|
||||
quantity: "11657995",
|
||||
tokenTicker: "ATOM" as TokenTicker,
|
||||
};
|
||||
const defaultSendTransaction = {
|
||||
kind: "bcp/send" as const,
|
||||
chainId: chainId,
|
||||
const defaultMemo = "Best greetings";
|
||||
const defaultSendTransaction: SendTransaction = {
|
||||
kind: "bcp/send",
|
||||
chainId: testdata.chainId,
|
||||
sender: "cosmos1h806c7khnvmjlywdrkdgk2vrayy2mmvf9rxk2r" as Address,
|
||||
recipient: "cosmos1z7g5w84ynmjyg0kqpahdjqpj7yq34v3suckp0e" as Address,
|
||||
amount: defaultAmount,
|
||||
memo: defaultMemo,
|
||||
};
|
||||
const defaultFee = {
|
||||
tokens: {
|
||||
@ -107,7 +111,7 @@ describe("decode", () => {
|
||||
},
|
||||
signature: "1nUcIH0CLT0/nQ0mBTDrT6kMG20NY/PsH7P2gc4bpYNGLEYjBmdWevXUJouSE/9A/60QG9cYeqyTe5kFDeIPxQ==",
|
||||
};
|
||||
expect(decodeFullSignature(fullSignature, nonce)).toEqual(defaultFullSignature);
|
||||
expect(decodeFullSignature(fullSignature, testdata.nonce)).toEqual(defaultFullSignature);
|
||||
});
|
||||
});
|
||||
|
||||
@ -136,7 +140,7 @@ describe("decode", () => {
|
||||
],
|
||||
},
|
||||
};
|
||||
expect(parseMsg(msg, chainId, defaultTokens)).toEqual(defaultSendTransaction);
|
||||
expect(parseMsg(msg, defaultMemo, testdata.chainId, defaultTokens)).toEqual(defaultSendTransaction);
|
||||
});
|
||||
});
|
||||
|
||||
@ -155,29 +159,63 @@ describe("decode", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("parseTx", () => {
|
||||
describe("parseUnsignedTx", () => {
|
||||
it("works", () => {
|
||||
expect(parseTx(data.tx.value, chainId, nonce, defaultTokens)).toEqual(signedTxJson);
|
||||
expect(parseUnsignedTx(cosmoshub.tx.value, testdata.chainId, defaultTokens)).toEqual(
|
||||
testdata.sendTxJson,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("parseTxsResponse", () => {
|
||||
describe("parseSignedTx", () => {
|
||||
it("works", () => {
|
||||
expect(parseSignedTx(cosmoshub.tx.value, testdata.chainId, testdata.nonce, defaultTokens)).toEqual(
|
||||
testdata.signedTxJson,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("parseTxsResponseUnsigned", () => {
|
||||
it("works", () => {
|
||||
const currentHeight = 2923;
|
||||
const txsResponse = {
|
||||
height: "2823",
|
||||
txhash: txId,
|
||||
txhash: testdata.txId,
|
||||
raw_log: '[{"msg_index":0,"success":true,"log":""}]',
|
||||
tx: data.tx,
|
||||
tx: cosmoshub.tx,
|
||||
};
|
||||
const expected = {
|
||||
...signedTxJson,
|
||||
transaction: testdata.sendTxJson,
|
||||
height: 2823,
|
||||
confirmations: 101,
|
||||
transactionId: txId,
|
||||
transactionId: testdata.txId,
|
||||
log: '[{"msg_index":0,"success":true,"log":""}]',
|
||||
};
|
||||
expect(parseTxsResponse(chainId, currentHeight, nonce, txsResponse, defaultTokens)).toEqual(expected);
|
||||
expect(parseTxsResponseUnsigned(testdata.chainId, currentHeight, txsResponse, defaultTokens)).toEqual(
|
||||
expected,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("parseTxsResponseSigned", () => {
|
||||
it("works", () => {
|
||||
const currentHeight = 2923;
|
||||
const txsResponse = {
|
||||
height: "2823",
|
||||
txhash: testdata.txId,
|
||||
raw_log: '[{"msg_index":0,"success":true,"log":""}]',
|
||||
tx: cosmoshub.tx,
|
||||
};
|
||||
const expected = {
|
||||
...testdata.signedTxJson,
|
||||
height: 2823,
|
||||
confirmations: 101,
|
||||
transactionId: testdata.txId,
|
||||
log: '[{"msg_index":0,"success":true,"log":""}]',
|
||||
};
|
||||
expect(
|
||||
parseTxsResponseSigned(testdata.chainId, currentHeight, testdata.nonce, txsResponse, defaultTokens),
|
||||
).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -5,6 +5,7 @@ import {
|
||||
Amount,
|
||||
ChainId,
|
||||
ConfirmedAndSignedTransaction,
|
||||
ConfirmedTransaction,
|
||||
Fee,
|
||||
FullSignature,
|
||||
Nonce,
|
||||
@ -70,7 +71,12 @@ export function decodeAmount(tokens: BankTokens, coin: types.Coin): Amount {
|
||||
};
|
||||
}
|
||||
|
||||
export function parseMsg(msg: types.Msg, chainId: ChainId, tokens: BankTokens): UnsignedTransaction {
|
||||
export function parseMsg(
|
||||
msg: types.Msg,
|
||||
memo: string | undefined,
|
||||
chainId: ChainId,
|
||||
tokens: BankTokens,
|
||||
): UnsignedTransaction {
|
||||
if (types.isMsgSend(msg)) {
|
||||
if (msg.value.amount.length !== 1) {
|
||||
throw new Error("Only MsgSend with one amount is supported");
|
||||
@ -81,6 +87,7 @@ export function parseMsg(msg: types.Msg, chainId: ChainId, tokens: BankTokens):
|
||||
sender: msg.value.from_address as Address,
|
||||
recipient: msg.value.to_address as Address,
|
||||
amount: decodeAmount(tokens, msg.value.amount[0]),
|
||||
memo: memo,
|
||||
};
|
||||
return send;
|
||||
} else {
|
||||
@ -103,12 +110,11 @@ export function parseFee(fee: types.StdFee, tokens: BankTokens): Fee {
|
||||
};
|
||||
}
|
||||
|
||||
export function parseTx(
|
||||
export function parseUnsignedTx(
|
||||
txValue: types.StdTx,
|
||||
chainId: ChainId,
|
||||
nonce: Nonce,
|
||||
tokens: BankTokens,
|
||||
): SignedTransaction {
|
||||
): UnsignedTransaction {
|
||||
if (!types.isStdTx(txValue)) {
|
||||
throw new Error("Only StdTx is supported");
|
||||
}
|
||||
@ -116,24 +122,46 @@ export function parseTx(
|
||||
throw new Error("Only single-message transactions currently supported");
|
||||
}
|
||||
|
||||
const [primarySignature] = txValue.signatures.map(signature => decodeFullSignature(signature, nonce));
|
||||
const msg = parseMsg(txValue.msg[0], chainId, tokens);
|
||||
const msg = parseMsg(txValue.msg[0], txValue.memo, chainId, tokens);
|
||||
const fee = parseFee(txValue.fee, tokens);
|
||||
|
||||
const transaction = {
|
||||
return {
|
||||
...msg,
|
||||
chainId: chainId,
|
||||
memo: txValue.memo,
|
||||
fee: fee,
|
||||
};
|
||||
}
|
||||
|
||||
export function parseSignedTx(
|
||||
txValue: types.StdTx,
|
||||
chainId: ChainId,
|
||||
nonce: Nonce,
|
||||
tokens: BankTokens,
|
||||
): SignedTransaction {
|
||||
const [primarySignature] = txValue.signatures.map(signature => decodeFullSignature(signature, nonce));
|
||||
return {
|
||||
transaction: transaction,
|
||||
transaction: parseUnsignedTx(txValue, chainId, tokens),
|
||||
signatures: [primarySignature],
|
||||
};
|
||||
}
|
||||
|
||||
export function parseTxsResponse(
|
||||
export function parseTxsResponseUnsigned(
|
||||
chainId: ChainId,
|
||||
currentHeight: number,
|
||||
response: TxsResponse,
|
||||
tokens: BankTokens,
|
||||
): ConfirmedTransaction<UnsignedTransaction> {
|
||||
const height = parseInt(response.height, 10);
|
||||
return {
|
||||
transaction: parseUnsignedTx(response.tx.value, chainId, tokens),
|
||||
height: height,
|
||||
confirmations: currentHeight - height + 1,
|
||||
transactionId: response.txhash as TransactionId,
|
||||
log: response.raw_log,
|
||||
};
|
||||
}
|
||||
|
||||
export function parseTxsResponseSigned(
|
||||
chainId: ChainId,
|
||||
currentHeight: number,
|
||||
nonce: Nonce,
|
||||
@ -142,7 +170,7 @@ export function parseTxsResponse(
|
||||
): ConfirmedAndSignedTransaction<UnsignedTransaction> {
|
||||
const height = parseInt(response.height, 10);
|
||||
return {
|
||||
...parseTx(response.tx.value, chainId, nonce, tokens),
|
||||
...parseSignedTx(response.tx.value, chainId, nonce, tokens),
|
||||
height: height,
|
||||
confirmations: currentHeight - height + 1,
|
||||
transactionId: response.txhash as TransactionId,
|
||||
|
||||
3
packages/bcp/types/cosmwasmconnection.d.ts
vendored
3
packages/bcp/types/cosmwasmconnection.d.ts
vendored
@ -85,5 +85,6 @@ export declare class CosmWasmConnection implements BlockchainConnection {
|
||||
liveTx(_query: TransactionQuery): Stream<ConfirmedTransaction<UnsignedTransaction> | FailedTransaction>;
|
||||
getFeeQuote(tx: UnsignedTransaction): Promise<Fee>;
|
||||
withDefaultFee<T extends UnsignedTransaction>(tx: T): Promise<T>;
|
||||
private parseAndPopulateTxResponse;
|
||||
private parseAndPopulateTxResponseUnsigned;
|
||||
private parseAndPopulateTxResponseSigned;
|
||||
}
|
||||
|
||||
23
packages/bcp/types/decode.d.ts
vendored
23
packages/bcp/types/decode.d.ts
vendored
@ -3,6 +3,7 @@ import {
|
||||
Amount,
|
||||
ChainId,
|
||||
ConfirmedAndSignedTransaction,
|
||||
ConfirmedTransaction,
|
||||
Fee,
|
||||
FullSignature,
|
||||
Nonce,
|
||||
@ -18,15 +19,31 @@ export declare function decodeSignature(signature: string): SignatureBytes;
|
||||
export declare function decodeFullSignature(signature: types.StdSignature, nonce: number): FullSignature;
|
||||
export declare function coinToDecimal(tokens: BankTokens, coin: types.Coin): readonly [Decimal, string];
|
||||
export declare function decodeAmount(tokens: BankTokens, coin: types.Coin): Amount;
|
||||
export declare function parseMsg(msg: types.Msg, chainId: ChainId, tokens: BankTokens): UnsignedTransaction;
|
||||
export declare function parseMsg(
|
||||
msg: types.Msg,
|
||||
memo: string | undefined,
|
||||
chainId: ChainId,
|
||||
tokens: BankTokens,
|
||||
): UnsignedTransaction;
|
||||
export declare function parseFee(fee: types.StdFee, tokens: BankTokens): Fee;
|
||||
export declare function parseTx(
|
||||
export declare function parseUnsignedTx(
|
||||
txValue: types.StdTx,
|
||||
chainId: ChainId,
|
||||
tokens: BankTokens,
|
||||
): UnsignedTransaction;
|
||||
export declare function parseSignedTx(
|
||||
txValue: types.StdTx,
|
||||
chainId: ChainId,
|
||||
nonce: Nonce,
|
||||
tokens: BankTokens,
|
||||
): SignedTransaction;
|
||||
export declare function parseTxsResponse(
|
||||
export declare function parseTxsResponseUnsigned(
|
||||
chainId: ChainId,
|
||||
currentHeight: number,
|
||||
response: TxsResponse,
|
||||
tokens: BankTokens,
|
||||
): ConfirmedTransaction<UnsignedTransaction>;
|
||||
export declare function parseTxsResponseSigned(
|
||||
chainId: ChainId,
|
||||
currentHeight: number,
|
||||
nonce: Nonce,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user