feat: add sign and broadcast without polling

This commit is contained in:
DavideSegullo 2023-03-27 11:55:49 +02:00
parent a16755a122
commit 9bcc43977b
4 changed files with 114 additions and 0 deletions

View File

@ -332,6 +332,33 @@ export class CosmWasmClient {
);
}
/**
* Broadcasts a signed transaction to the network without monitoring it.
*
* If broadcasting is rejected by the node for some reason (e.g. because of a CheckTx failure),
* an error is thrown.
*
* If the transaction is broadcasted, a `string` containing the hash of the transaction is returned. The caller then
* usually needs to check if the transaction was included in a block and was successful.
*
* @returns Returns the hash of the transaction
*/
public async broadcastTxWithoutPolling(
tx: Uint8Array,
): Promise<string> {
const broadcasted = await this.forceGetTmClient().broadcastTxSync({ tx });
if (broadcasted.code) {
return Promise.reject(
new BroadcastTxError(broadcasted.code, broadcasted.codespace ?? "", broadcasted.log),
);
}
const transactionId = toHex(broadcasted.hash).toUpperCase();
return transactionId;
}
/**
* getCodes() returns all codes and is just looping through all pagination pages.
*

View File

@ -557,6 +557,40 @@ export class SigningCosmWasmClient extends CosmWasmClient {
return this.broadcastTx(txBytes, this.broadcastTimeoutMs, this.broadcastPollIntervalMs);
}
/**
* Creates a transaction with the given messages, fee and memo. Then signs and broadcasts the transaction.
*
* This method is useful if you want to send a transaction in broadcast,
* without waiting for it to be placed inside a block, because for example
* I would like to receive the hash to later track the transaction with another tool.
*
* @param signerAddress The address that will sign transactions using this instance. The signer must be able to sign with this address.
* @param messages
* @param fee
* @param memo
*
* @returns Returns the hash of the transaction
*/
public async signAndBroadcastWithoutPolling(
signerAddress: string,
messages: readonly EncodeObject[],
fee: StdFee | "auto" | number,
memo = "",
): Promise<string> {
let usedFee: StdFee;
if (fee == "auto" || typeof fee === "number") {
assertDefined(this.gasPrice, "Gas price must be set in the client options when auto gas is used.");
const gasEstimation = await this.simulate(signerAddress, messages, memo);
const multiplier = typeof fee === "number" ? fee : 1.3;
usedFee = calculateFee(Math.round(gasEstimation * multiplier), this.gasPrice);
} else {
usedFee = fee;
}
const txRaw = await this.sign(signerAddress, messages, usedFee, memo);
const txBytes = TxRaw.encode(txRaw).finish();
return this.broadcastTxWithoutPolling(txBytes);
}
public async sign(
signerAddress: string,
messages: readonly EncodeObject[],

View File

@ -310,6 +310,32 @@ export class SigningStargateClient extends StargateClient {
return this.broadcastTx(txBytes, this.broadcastTimeoutMs, this.broadcastPollIntervalMs);
}
/**
* This method is useful if you want to send a transaction in broadcast,
* without waiting for it to be placed inside a block, because for example
* I would like to receive the hash to later track the transaction with another tool.
* @returns Returns the hash of the transaction
*/
public async signAndBroadcastWithoutPolling(
signerAddress: string,
messages: readonly EncodeObject[],
fee: StdFee | "auto" | number,
memo = "",
): Promise<string> {
let usedFee: StdFee;
if (fee == "auto" || typeof fee === "number") {
assertDefined(this.gasPrice, "Gas price must be set in the client options when auto gas is used.");
const gasEstimation = await this.simulate(signerAddress, messages, memo);
const multiplier = typeof fee === "number" ? fee : 1.3;
usedFee = calculateFee(Math.round(gasEstimation * multiplier), this.gasPrice);
} else {
usedFee = fee;
}
const txRaw = await this.sign(signerAddress, messages, usedFee, memo);
const txBytes = TxRaw.encode(txRaw).finish();
return this.broadcastTxWithoutPolling(txBytes);
}
/**
* Gets account number and sequence from the API, creates a sign doc,
* creates a single signature and assembles the signed transaction.

View File

@ -491,6 +491,33 @@ export class StargateClient {
);
}
/**
* Broadcasts a signed transaction to the network without monitoring it.
*
* If broadcasting is rejected by the node for some reason (e.g. because of a CheckTx failure),
* an error is thrown.
*
* If the transaction is broadcasted, a `string` containing the hash of the transaction is returned. The caller then
* usually needs to check if the transaction was included in a block and was successful.
*
* @returns Returns the hash of the transaction
*/
public async broadcastTxWithoutPolling(
tx: Uint8Array,
): Promise<string> {
const broadcasted = await this.forceGetTmClient().broadcastTxSync({ tx });
if (broadcasted.code) {
return Promise.reject(
new BroadcastTxError(broadcasted.code, broadcasted.codespace ?? "", broadcasted.log),
);
}
const transactionId = toHex(broadcasted.hash).toUpperCase();
return transactionId;
}
private async txsQuery(query: string): Promise<readonly IndexedTx[]> {
const results = await this.forceGetTmClient().txSearchAll({ query: query });
return results.txs.map((tx) => {