Skip to content

Commit

Permalink
feat(billing): ensure master wallet sequence is correct
Browse files Browse the repository at this point in the history
refs #247
  • Loading branch information
ygrishajev committed Aug 8, 2024
1 parent efc0508 commit 8372f38
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { toHex } from "@cosmjs/encoding";
import { EncodeObject, Registry } from "@cosmjs/proto-signing";
import { calculateFee, GasPrice } from "@cosmjs/stargate";
import type { SignerData } from "@cosmjs/stargate/build/signingstargateclient";
import { IndexedTx } from "@cosmjs/stargate/build/stargateclient";
import { BroadcastTxSyncResponse } from "@cosmjs/tendermint-rpc/build/comet38";
import { Sema } from "async-sema";
import { TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx";
Expand All @@ -14,6 +15,7 @@ import { BillingConfig, InjectBillingConfig } from "@src/billing/providers";
import { InjectTypeRegistry } from "@src/billing/providers/type-registry.provider";
import { BatchSigningStargateClient } from "@src/billing/services/batch-signing-stargate-client/batch-signing-stargate-client";
import { MasterWalletService } from "@src/billing/services/master-wallet/master-wallet.service";
import { LoggerService } from "@src/core";

interface ShortAccountInfo {
accountNumber: number;
Expand All @@ -22,7 +24,7 @@ interface ShortAccountInfo {

@singleton()
export class MasterSigningClientService {
private readonly clientAsPromised: Promise<BatchSigningStargateClient>;
private clientAsPromised: Promise<BatchSigningStargateClient>;

private readonly semaphore = new Sema(1);

Expand All @@ -32,11 +34,13 @@ export class MasterSigningClientService {

private execTxLoader = new DataLoader(
async (batchedMessages: readonly EncodeObject[][]) => {
return this.executeTxBatch(batchedMessages);
return this.executeTxBatchBlocking(batchedMessages);
},
{ cache: false, batchScheduleFn: callback => setTimeout(callback, this.config.MASTER_WALLET_BATCHING_INTERVAL_MS) }
);

private readonly logger = new LoggerService({ context: MasterWalletService.name });

constructor(
@InjectBillingConfig() private readonly config: BillingConfig,
private readonly masterWalletService: MasterWalletService,
Expand Down Expand Up @@ -79,49 +83,55 @@ export class MasterSigningClientService {
return tx;
}

private async executeTxBatch(messages: readonly EncodeObject[][]) {
private async executeTxBatchBlocking(messages: readonly EncodeObject[][]): Promise<IndexedTx[]> {
await this.semaphore.acquire();
try {
return await this.executeTxBatch(messages);
} catch (error) {
if (error.message.includes("account sequence mismatch")) {
this.logger.debug("Account sequence mismatch, retrying...");

this.clientAsPromised = this.initClient();
return await this.executeTxBatch(messages);
}

throw error;
} finally {
this.semaphore.release();
}
}

private async executeTxBatch(messages: readonly EncodeObject[][]): Promise<IndexedTx[]> {
const txes: TxRaw[] = [];
let txIndex: number = 0;

try {
const client = await this.clientAsPromised;
const masterAddress = await this.masterWalletService.getFirstAddress();

while (txIndex < messages.length) {
txes.push(
await client.sign(
masterAddress,
messages[txIndex],
await this.estimateFee(messages[txIndex], this.config.TRIAL_ALLOWANCE_DENOM, { mock: true }),
"",
{
accountNumber: this.accountInfo.accountNumber,
sequence: this.accountInfo.sequence++,
chainId: this.chainId
}
)
);
txIndex++;
}
const client = await this.clientAsPromised;
const masterAddress = await this.masterWalletService.getFirstAddress();

while (txIndex < messages.length) {
txes.push(
await client.sign(masterAddress, messages[txIndex], await this.estimateFee(messages[txIndex], this.config.TRIAL_ALLOWANCE_DENOM, { mock: true }), "", {
accountNumber: this.accountInfo.accountNumber,
sequence: this.accountInfo.sequence++,
chainId: this.chainId
})
);
txIndex++;
}

const responses: BroadcastTxSyncResponse[] = [];
txIndex = 0;
const responses: BroadcastTxSyncResponse[] = [];
txIndex = 0;

while (txIndex < txes.length - 1) {
const txRaw: TxRaw = txes[txIndex];
responses.push(await client.tmBroadcastTxSync(TxRaw.encode(txRaw).finish()));
txIndex++;
}
while (txIndex < txes.length - 1) {
const txRaw: TxRaw = txes[txIndex];
responses.push(await client.tmBroadcastTxSync(TxRaw.encode(txRaw).finish()));
txIndex++;
}

const lastDelivery = await client.broadcastTx(TxRaw.encode(txes[txes.length - 1]).finish());
const hashes = [...responses.map(hash => toHex(hash.hash)), lastDelivery.transactionHash];
const lastDelivery = await client.broadcastTx(TxRaw.encode(txes[txes.length - 1]).finish());
const hashes = [...responses.map(hash => toHex(hash.hash)), lastDelivery.transactionHash];

return await Promise.all(hashes.map(hash => client.getTx(hash)));
} finally {
this.semaphore.release();
}
return await Promise.all(hashes.map(hash => client.getTx(hash)));
}

private async estimateFee(messages: readonly EncodeObject[], denom: string, options?: { mock?: boolean }) {
Expand Down
1 change: 0 additions & 1 deletion apps/deploy-web/src/components/layout/TransactionModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ export type LoadingState =
| "closingDeployment";

type Props = {
managed?: boolean;
state?: LoadingState;
onClose?: () => void;
children?: ReactNode;
Expand Down
4 changes: 2 additions & 2 deletions apps/deploy-web/src/context/WalletProvider/WalletProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ export const WalletProvider = ({ children }) => {
throw new Error(txResult.rawLog);
}

if (!managedWallet?.isWalletConnected) {
if (!managedWallet) {
showTransactionSnackbar("Transaction success!", "", txResult.transactionHash, "success");
}

Expand Down Expand Up @@ -349,7 +349,7 @@ export const WalletProvider = ({ children }) => {
logout,
signAndBroadcastTx,
refreshBalances,
isManaged: !!managedWallet?.isWalletConnected,
isManaged: !!managedWallet,
isWalletLoading: isLoading,
isTrialing: !!managedWallet?.isTrialing
}}
Expand Down

0 comments on commit 8372f38

Please sign in to comment.