Skip to content

Commit

Permalink
feat(timeout-height): allow define optional timeout height parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
janfabian committed Oct 17, 2023
1 parent 2125ce8 commit 2bf0e05
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 6 deletions.
3 changes: 3 additions & 0 deletions packages/amino/src/signdoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export interface StdSignDoc {
readonly fee: StdFee;
readonly msgs: readonly AminoMsg[];
readonly memo: string;
readonly timeout_height?: string;
}

function sortedObject(obj: any): any {
Expand Down Expand Up @@ -61,6 +62,7 @@ export function makeSignDoc(
memo: string | undefined,
accountNumber: number | string,
sequence: number | string,
timeout_height?: string,
): StdSignDoc {
return {
chain_id: chainId,
Expand All @@ -69,6 +71,7 @@ export function makeSignDoc(
fee: fee,
msgs: msgs,
memo: memo || "",
...(timeout_height && { timeout_height }),
};
}

Expand Down
76 changes: 76 additions & 0 deletions packages/cosmwasm-stargate/src/signingcosmwasmclient.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,44 @@ describe("SigningCosmWasmClient", () => {

client.disconnect();
});

it("works with a custom timeout height", async () => {
pendingWithoutWasmd();
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix });
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, {
...defaultSigningClientOptions,
});

const msg = MsgSend.fromPartial({
fromAddress: alice.address0,
toAddress: alice.address0,
amount: [coin(1, "ucosm")],
});
const msgAny: MsgSendEncodeObject = {
typeUrl: "/cosmos.bank.v1beta1.MsgSend",
value: msg,
};
const fee = {
amount: coins(2000, "ucosm"),
gas: "222000", // 222k
};
const memo = "Use your power wisely";
const height = await client.getHeight();
const signed = await client.sign(
alice.address0,
[msgAny],
fee,
memo,
undefined,
Long.fromNumber(height + 1),
);

// ensure signature is valid
const result = await client.broadcastTx(Uint8Array.from(TxRaw.encode(signed).finish()));
assertIsDeliverTxSuccess(result);

client.disconnect();
});
});

describe("legacy Amino mode", () => {
Expand Down Expand Up @@ -1413,6 +1451,44 @@ describe("SigningCosmWasmClient", () => {

client.disconnect();
});

it("works with custom timeoutHeight", async () => {
pendingWithoutWasmd();
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic, { prefix: wasmd.prefix });
const client = await SigningCosmWasmClient.connectWithSigner(wasmd.endpoint, wallet, {
...defaultSigningClientOptions,
});

const msg = MsgSend.fromPartial({
fromAddress: alice.address0,
toAddress: alice.address0,
amount: [coin(1, "ucosm")],
});
const msgAny: MsgSendEncodeObject = {
typeUrl: "/cosmos.bank.v1beta1.MsgSend",
value: msg,
};
const fee = {
amount: coins(2000, "ucosm"),
gas: "200000",
};
const memo = "Use your tokens wisely";
const height = await client.getHeight();
const signed = await client.sign(
alice.address0,
[msgAny],
fee,
memo,
undefined,
Long.fromNumber(height + 1),
);

// ensure signature is valid
const result = await client.broadcastTx(Uint8Array.from(TxRaw.encode(signed).finish()));
assertIsDeliverTxSuccess(result);

client.disconnect();
});
});
});
});
19 changes: 16 additions & 3 deletions packages/cosmwasm-stargate/src/signingcosmwasmclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
fee: StdFee,
memo: string,
explicitSignerData?: SignerData,
timeoutHeight?: Long,
): Promise<TxRaw> {
let signerData: SignerData;
if (explicitSignerData) {
Expand All @@ -659,8 +660,8 @@ export class SigningCosmWasmClient extends CosmWasmClient {
}

return isOfflineDirectSigner(this.signer)
? this.signDirect(signerAddress, messages, fee, memo, signerData)
: this.signAmino(signerAddress, messages, fee, memo, signerData);
? this.signDirect(signerAddress, messages, fee, memo, signerData, timeoutHeight)
: this.signAmino(signerAddress, messages, fee, memo, signerData, timeoutHeight);
}

private async signAmino(
Expand All @@ -669,6 +670,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
fee: StdFee,
memo: string,
{ accountNumber, sequence, chainId }: SignerData,
timeoutHeight?: Long,
): Promise<TxRaw> {
assert(!isOfflineDirectSigner(this.signer));
const accountFromSigner = (await this.signer.getAccounts()).find(
Expand All @@ -680,13 +682,22 @@ export class SigningCosmWasmClient extends CosmWasmClient {
const pubkey = encodePubkey(encodeSecp256k1Pubkey(accountFromSigner.pubkey));
const signMode = SignMode.SIGN_MODE_LEGACY_AMINO_JSON;
const msgs = messages.map((msg) => this.aminoTypes.toAmino(msg));
const signDoc = makeSignDocAmino(msgs, fee, chainId, memo, accountNumber, sequence);
const signDoc = makeSignDocAmino(
msgs,
fee,
chainId,
memo,
accountNumber,
sequence,
timeoutHeight?.toString(),
);
const { signature, signed } = await this.signer.signAmino(signerAddress, signDoc);
const signedTxBody: TxBodyEncodeObject = {
typeUrl: "/cosmos.tx.v1beta1.TxBody",
value: {
messages: signed.msgs.map((msg) => this.aminoTypes.fromAmino(msg)),
memo: signed.memo,
timeoutHeight: timeoutHeight,
},
};
const signedTxBodyBytes = this.registry.encode(signedTxBody);
Expand All @@ -713,6 +724,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
fee: StdFee,
memo: string,
{ accountNumber, sequence, chainId }: SignerData,
timeoutHeight?: Long,
): Promise<TxRaw> {
assert(isOfflineDirectSigner(this.signer));
const accountFromSigner = (await this.signer.getAccounts()).find(
Expand All @@ -727,6 +739,7 @@ export class SigningCosmWasmClient extends CosmWasmClient {
value: {
messages: messages,
memo: memo,
timeoutHeight: timeoutHeight,
},
};
const txBodyBytes = this.registry.encode(txBody);
Expand Down
76 changes: 76 additions & 0 deletions packages/stargate/src/signingstargateclient.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,44 @@ describe("SigningStargateClient", () => {
const result = await client.broadcastTx(Uint8Array.from(TxRaw.encode(signed).finish()));
assertIsDeliverTxSuccess(result);
});

it("works with custom timeoutHeight", async () => {
pendingWithoutSimapp();
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic);
const client = await SigningStargateClient.connectWithSigner(
simapp.tendermintUrl,
wallet,
defaultSigningClientOptions,
);

const msg = MsgSend.fromPartial({
fromAddress: faucet.address0,
toAddress: faucet.address0,
amount: [coin(1, "ucosm")],
});
const msgAny: MsgSendEncodeObject = {
typeUrl: "/cosmos.bank.v1beta1.MsgSend",
value: msg,
};
const fee = {
amount: coins(2000, "ucosm"),
gas: "222000", // 222k
};
const memo = "Use your power wisely";
const height = await client.getHeight();
const signed = await client.sign(
faucet.address0,
[msgAny],
fee,
memo,
undefined,
Long.fromNumber(height + 1),
);

// ensure signature is valid
const result = await client.broadcastTx(Uint8Array.from(TxRaw.encode(signed).finish()));
assertIsDeliverTxSuccess(result);
});
});

describe("legacy Amino mode", () => {
Expand Down Expand Up @@ -1124,6 +1162,44 @@ describe("SigningStargateClient", () => {
const result = await client.broadcastTx(Uint8Array.from(TxRaw.encode(signed).finish()));
assertIsDeliverTxSuccess(result);
});

it("works with custom timeoutHeight", async () => {
pendingWithoutSimapp();
const wallet = await Secp256k1HdWallet.fromMnemonic(faucet.mnemonic);
const client = await SigningStargateClient.connectWithSigner(
simapp.tendermintUrl,
wallet,
defaultSigningClientOptions,
);

const msg = MsgSend.fromPartial({
fromAddress: faucet.address0,
toAddress: faucet.address0,
amount: [coin(1, "ucosm")],
});
const msgAny: MsgSendEncodeObject = {
typeUrl: "/cosmos.bank.v1beta1.MsgSend",
value: msg,
};
const fee = {
amount: coins(2000, "ucosm"),
gas: "200000",
};
const memo = "Use your tokens wisely";
const height = await client.getHeight();
const signed = await client.sign(
faucet.address0,
[msgAny],
fee,
memo,
undefined,
Long.fromNumber(height + 1),
);

// ensure signature is valid
const result = await client.broadcastTx(Uint8Array.from(TxRaw.encode(signed).finish()));
assertIsDeliverTxSuccess(result);
});
});
});
});
19 changes: 16 additions & 3 deletions packages/stargate/src/signingstargateclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ export class SigningStargateClient extends StargateClient {
fee: StdFee,
memo: string,
explicitSignerData?: SignerData,
timeoutHeight?: Long,
): Promise<TxRaw> {
let signerData: SignerData;
if (explicitSignerData) {
Expand All @@ -387,8 +388,8 @@ export class SigningStargateClient extends StargateClient {
}

return isOfflineDirectSigner(this.signer)
? this.signDirect(signerAddress, messages, fee, memo, signerData)
: this.signAmino(signerAddress, messages, fee, memo, signerData);
? this.signDirect(signerAddress, messages, fee, memo, signerData, timeoutHeight)
: this.signAmino(signerAddress, messages, fee, memo, signerData, timeoutHeight);
}

private async signAmino(
Expand All @@ -397,6 +398,7 @@ export class SigningStargateClient extends StargateClient {
fee: StdFee,
memo: string,
{ accountNumber, sequence, chainId }: SignerData,
timeoutHeight?: Long,
): Promise<TxRaw> {
assert(!isOfflineDirectSigner(this.signer));
const accountFromSigner = (await this.signer.getAccounts()).find(
Expand All @@ -408,11 +410,20 @@ export class SigningStargateClient extends StargateClient {
const pubkey = encodePubkey(encodeSecp256k1Pubkey(accountFromSigner.pubkey));
const signMode = SignMode.SIGN_MODE_LEGACY_AMINO_JSON;
const msgs = messages.map((msg) => this.aminoTypes.toAmino(msg));
const signDoc = makeSignDocAmino(msgs, fee, chainId, memo, accountNumber, sequence);
const signDoc = makeSignDocAmino(
msgs,
fee,
chainId,
memo,
accountNumber,
sequence,
timeoutHeight?.toString(),
);
const { signature, signed } = await this.signer.signAmino(signerAddress, signDoc);
const signedTxBody = {
messages: signed.msgs.map((msg) => this.aminoTypes.fromAmino(msg)),
memo: signed.memo,
timeoutHeight: timeoutHeight,
};
const signedTxBodyEncodeObject: TxBodyEncodeObject = {
typeUrl: "/cosmos.tx.v1beta1.TxBody",
Expand Down Expand Up @@ -442,6 +453,7 @@ export class SigningStargateClient extends StargateClient {
fee: StdFee,
memo: string,
{ accountNumber, sequence, chainId }: SignerData,
timeoutHeight?: Long,
): Promise<TxRaw> {
assert(isOfflineDirectSigner(this.signer));
const accountFromSigner = (await this.signer.getAccounts()).find(
Expand All @@ -456,6 +468,7 @@ export class SigningStargateClient extends StargateClient {
value: {
messages: messages,
memo: memo,
timeoutHeight: timeoutHeight,
},
};
const txBodyBytes = this.registry.encode(txBodyEncodeObject);
Expand Down

0 comments on commit 2bf0e05

Please sign in to comment.