From 125fc622ff83cee539a48f6996d62e2685d18ddd Mon Sep 17 00:00:00 2001 From: LukasDeco Date: Thu, 30 May 2024 10:32:16 -0600 Subject: [PATCH] feat: refactor SDK to return tx observables --- lib/client/client.ts | 41 ++-- .../indexer/market-clients/ammMarkets.ts | 6 +- .../indexer/market-clients/openbookMarkets.ts | 7 +- lib/client/indexer/proposals.ts | 61 ++--- lib/client/rpc/market-clients/ammMarkets.ts | 46 ++-- .../rpc/market-clients/openbookMarkets.ts | 47 +--- lib/client/rpc/proposals/createProposal.ts | 50 ++-- lib/client/rpc/proposals/proposals.ts | 2 +- lib/transactions.ts | 218 ++++++++++-------- 9 files changed, 243 insertions(+), 235 deletions(-) diff --git a/lib/client/client.ts b/lib/client/client.ts index 903d5bb..5e4fb74 100644 --- a/lib/client/client.ts +++ b/lib/client/client.ts @@ -27,7 +27,10 @@ import { SpotObservation, TwapObservation } from "@/types/prices"; -import { SendTransactionResponse } from "@/types/transactions"; +import { + SendTransactionResponse, + TransactionProcessingUpdate +} from "@/types/transactions"; import { BN } from "@coral-xyz/anchor"; import { CreateProposalInstruction, @@ -64,16 +67,20 @@ export interface FutarchyProposalsClient { amount: number, vaultAccountAddress: PublicKey, vaultAccount: VaultAccountWithProtocol - ): SendTransactionResponse; - withdraw(proposal: Proposal): SendTransactionResponse; + ): Promise | undefined>; + withdraw( + proposal: Proposal + ): Promise | undefined>; createProposal( daoAggregate: DaoAggregate, version: ProgramVersionLabel, instructionParams: CreateProposalInstruction, marketParams: MarketParams, proposalDetails: ProposalDetails - ): SendTransactionResponse; - finalizeProposal(proposal: Proposal): SendTransactionResponse; + ): Promise | undefined>; + finalizeProposal( + proposal: Proposal + ): Promise | undefined>; saveProposalDetails(proposalDetails: ProposalDetails): void; updateProposalAccounts(accounts: ProposalAccounts): void; mergeConditionalTokensForUnderlyingTokens( @@ -81,8 +88,11 @@ export interface FutarchyProposalsClient { amoutn: BN, proposal: Proposal, underlyingToken: "base" | "quote" - ): SendTransactionResponse; - watchReactions?: (proposal: string, user?: string) => Observable + ): Promise | undefined>; + watchReactions?: ( + proposal: string, + user?: string + ) => Observable; } export interface FutarchyBalancesClient { @@ -148,8 +158,11 @@ export interface FutarchyOrderbookMarketsClient< market: M, order: Omit, placeOrderType: PlaceOrderType - ): SendTransactionResponse; - cancelOrder(market: M, order: O): SendTransactionResponse; + ): Promise | undefined>; + cancelOrder( + market: M, + order: O + ): Promise | undefined>; } export interface FutarchyAmmMarketsClient { @@ -160,12 +173,12 @@ export interface FutarchyAmmMarketsClient { inputAmount: number, outputAmountMin: number, slippage: number - ): SendTransactionResponse; + ): Promise | undefined>; removeLiquidity( ammMarket: AmmMarket, lpTokensToBurn: number, slippage: number - ): SendTransactionResponse; + ): Promise | undefined>; validateAddLiquidity( ammMarket: AmmMarket, quoteAmount: number, @@ -179,11 +192,13 @@ export interface FutarchyAmmMarketsClient { quoteAmount: number, maxBaseAmount: number, slippage: number - ): SendTransactionResponse; + ): Promise | undefined>; } export interface FinalizeProposal { - finalizeProposal(proposal: Proposal): SendTransactionResponse; + finalizeProposal( + proposal: Proposal + ): Promise | undefined>; } export interface CreateProposal { diff --git a/lib/client/indexer/market-clients/ammMarkets.ts b/lib/client/indexer/market-clients/ammMarkets.ts index 5831fd9..c68bede 100644 --- a/lib/client/indexer/market-clients/ammMarkets.ts +++ b/lib/client/indexer/market-clients/ammMarkets.ts @@ -52,7 +52,7 @@ export class FutarchyIndexerAmmMarketsClient quoteAmount: number, maxBaseAmount: number, slippage: number - ): SendTransactionResponse { + ) { return this.rpcMarketsClient.addLiquidity( ammMarket, quoteAmount, @@ -77,7 +77,7 @@ export class FutarchyIndexerAmmMarketsClient ammMarket: AmmMarket, lpTokensToBurn: number, slippage: number - ): SendTransactionResponse { + ) { return this.rpcMarketsClient.removeLiquidity( ammMarket, lpTokensToBurn, @@ -101,7 +101,7 @@ export class FutarchyIndexerAmmMarketsClient inputAmount: number, outputAmountMin: number, slippage: number - ): SendTransactionResponse { + ) { return this.rpcMarketsClient.swap( ammMarket, swapType, diff --git a/lib/client/indexer/market-clients/openbookMarkets.ts b/lib/client/indexer/market-clients/openbookMarkets.ts index a0d0752..065c6c3 100644 --- a/lib/client/indexer/market-clients/openbookMarkets.ts +++ b/lib/client/indexer/market-clients/openbookMarkets.ts @@ -19,10 +19,7 @@ export class FutarchyIndexerOpenbookMarketsClient constructor(rpcMarketsClient: FutarchyOpenbookMarketsRPCClient) { this.rpcMarketsClient = rpcMarketsClient; } - async cancelOrder( - market: OpenbookMarket, - order: OpenbookOrder - ): SendTransactionResponse { + async cancelOrder(market: OpenbookMarket, order: OpenbookOrder) { return this.rpcMarketsClient.cancelOrder(market, order); } @@ -52,7 +49,7 @@ export class FutarchyIndexerOpenbookMarketsClient market: OpenbookMarket, order: Omit, placeOrderType: PlaceOrderType - ): SendTransactionResponse { + ) { return this.rpcMarketsClient.placeOrder(market, order, placeOrderType); } } diff --git a/lib/client/indexer/proposals.ts b/lib/client/indexer/proposals.ts index bca0f06..0e3b4b0 100644 --- a/lib/client/indexer/proposals.ts +++ b/lib/client/indexer/proposals.ts @@ -11,7 +11,10 @@ import { } from "@/types"; import { FutarchyProposalsClient } from "@/client"; import { FutarchyRPCProposalsClient } from "@/client/rpc"; -import { Client as IndexerGraphQLClient, generateSubscriptionOp } from "./__generated__"; +import { + Client as IndexerGraphQLClient, + generateSubscriptionOp +} from "./__generated__"; import { SendTransactionResponse } from "@/types/transactions"; import { CreateProposalInstruction, @@ -25,7 +28,6 @@ import { Client as GQLWebSocketClient } from "graphql-ws"; import { SUPPORTED_EMOJIS } from "@/constants/reactions"; import { ReactionType } from "@/types/reactions"; - export class FutarchyIndexerProposalsClient implements FutarchyProposalsClient { private protocolMap: Map; private rpcProposalsClient: FutarchyRPCProposalsClient; @@ -198,7 +200,7 @@ export class FutarchyIndexerProposalsClient implements FutarchyProposalsClient { new BN(curr.filled_base_amount), new BN(d.tokenByBaseAcct?.decimals ?? 6) ) * - curr.quote_price, + curr.quote_price, 0 ) ?? 0; const failVolume = @@ -209,7 +211,7 @@ export class FutarchyIndexerProposalsClient implements FutarchyProposalsClient { new BN(curr.filled_base_amount), new BN(d.tokenByBaseAcct?.decimals ?? 6) ) * - curr.quote_price, + curr.quote_price, 0 ) ?? 0; @@ -282,10 +284,10 @@ export class FutarchyIndexerProposalsClient implements FutarchyProposalsClient { endDate: p.ended_at ? new Date(p.ended_at) : new Date( - new Date(p.created_at).setDate( - new Date(p.created_at).getDate() + 3 - ) - ), + new Date(p.created_at).setDate( + new Date(p.created_at).getDate() + 3 + ) + ), // TODO figure this out by slot enqueued maybe finalizationDate: p.completed_at, dao: { @@ -373,7 +375,7 @@ export class FutarchyIndexerProposalsClient implements FutarchyProposalsClient { amount: number, vaultAccountAddress: PublicKey, vaultAccount: VaultAccountWithProtocol - ): SendTransactionResponse { + ) { return this.rpcProposalsClient.deposit( amount, vaultAccountAddress, @@ -381,7 +383,7 @@ export class FutarchyIndexerProposalsClient implements FutarchyProposalsClient { ); } - async withdraw(proposal: Proposal): SendTransactionResponse { + async withdraw(proposal: Proposal) { return this.rpcProposalsClient.withdraw(proposal); } @@ -391,7 +393,7 @@ export class FutarchyIndexerProposalsClient implements FutarchyProposalsClient { instructionParams: CreateProposalInstruction, marketParams: MarketParams, proposalDetails: ProposalDetails - ): SendTransactionResponse { + ) { return this.rpcProposalsClient.createProposal( daoAggregate, version, @@ -418,7 +420,7 @@ export class FutarchyIndexerProposalsClient implements FutarchyProposalsClient { amount: BN, proposal: Proposal, underlyingToken: "base" | "quote" - ): SendTransactionResponse { + ) { return this.rpcProposalsClient.mergeConditionalTokensForUnderlyingTokens( programVersion, amount, @@ -427,7 +429,12 @@ export class FutarchyIndexerProposalsClient implements FutarchyProposalsClient { ); } - watchReactions(proposal: string, user?: string) : Observable<{ [key in ReactionType]: { count: number, userReacted: boolean } }> { + watchReactions( + proposal: string, + user?: string + ): Observable<{ + [key in ReactionType]: { count: number; userReacted: boolean }; + }> { const { query, variables } = generateSubscriptionOp({ reactions: { __args: { @@ -438,37 +445,39 @@ export class FutarchyIndexerProposalsClient implements FutarchyProposalsClient { reactor_acct: true, updated_at: true, reaction: true, - proposal_acct: true, + proposal_acct: true } }); return new Observable((subscriber) => { - const subscriptionCleanup:() => void = this.graphqlWSClient.subscribe<{ + const subscriptionCleanup: () => void = this.graphqlWSClient.subscribe<{ reactions: { - reactor_acct: string, - updated_at: string, - reaction: string, - proposal_acct: string, + reactor_acct: string; + updated_at: string; + reaction: string; + proposal_acct: string; }[]; }>( { query, variables }, { next: (data) => { - const reactions = data.data - - const reactionCounts: { [key in ReactionType]: { count: number, userReacted: boolean } } = {}; + const reactions = data.data; + + const reactionCounts: { + [key in ReactionType]: { count: number; userReacted: boolean }; + } = {}; // Initialize each reaction type SUPPORTED_EMOJIS.forEach((reactionType) => { reactionCounts[reactionType] = { count: 0, userReacted: false }; - }) + }); // Might need some optimization later reactions?.reactions.forEach((reaction) => { reactionCounts[reaction.reaction]!!.count += 1; if (user && reaction.reactor_acct === user) reactionCounts[reaction.reaction]!!.userReacted = true; - }) - + }); + subscriber.next(reactionCounts); }, error: (error) => subscriber.error(error), @@ -479,5 +488,3 @@ export class FutarchyIndexerProposalsClient implements FutarchyProposalsClient { }); } } - - diff --git a/lib/client/rpc/market-clients/ammMarkets.ts b/lib/client/rpc/market-clients/ammMarkets.ts index ec9db11..3850bb2 100644 --- a/lib/client/rpc/market-clients/ammMarkets.ts +++ b/lib/client/rpc/market-clients/ammMarkets.ts @@ -10,7 +10,10 @@ import { LiquidityAddError, SwapPreview } from "@/types/amm"; -import { SendTransactionResponse } from "@/types/transactions"; +import { + SendTransactionResponse, + TransactionProcessingUpdate +} from "@/types/transactions"; import { BN, Program, Provider } from "@coral-xyz/anchor"; import { AMM_PROGRAM_ID, @@ -24,6 +27,7 @@ import { import { Amm as AmmIDLType } from "@/idl/amm_v0.3"; import { getAssociatedTokenAddressSync } from "@solana/spl-token"; import { AccountInfo, PublicKey } from "@solana/web3.js"; +import { Observable } from "rxjs"; export class FutarchyAmmMarketsRPCClient implements FutarchyAmmMarketsClient { private rpcProvider: Provider; @@ -166,17 +170,11 @@ export class FutarchyAmmMarketsRPCClient implements FutarchyAmmMarketsClient { quoteAmount: number, maxBaseAmount: number, slippage: number - ): SendTransactionResponse { - if (!this.transactionSender) - return { - signatures: [], - errors: [ - { - message: "Transaction sender is undefined", - name: "Transaction Sender Error" - } - ] - }; + ) { + if (!this.transactionSender) { + console.error("Transaction sender is undefined"); + return; + } const validationError = this.validateAddLiquidity( ammMarket, @@ -185,10 +183,8 @@ export class FutarchyAmmMarketsRPCClient implements FutarchyAmmMarketsClient { slippage ); if (validationError) { - return { - signatures: [], - errors: [{ message: validationError, name: "Failed to Add Liquidity." }] - }; + console.error("failed to add liquidity", validationError); + return; } const quoteAmountArg = PriceMath.getChainAmount( @@ -286,7 +282,7 @@ export class FutarchyAmmMarketsRPCClient implements FutarchyAmmMarketsClient { ammMarket: AmmMarket, lpTokensToBurn: number, slippage: number - ) { + ): Promise | undefined> { // fetch or have lp token account const lpTokensLots = PriceMath.getChainAmount(lpTokensToBurn, 9); @@ -345,17 +341,11 @@ export class FutarchyAmmMarketsRPCClient implements FutarchyAmmMarketsClient { inputAmount: number, outputAmountMin: number, slippage: number - ): SendTransactionResponse { - if (!this.transactionSender) - return { - signatures: [], - errors: [ - { - message: "Transaction sender is undefined", - name: "Transaction Sender Error" - } - ] - }; + ) { + if (!this.transactionSender) { + console.error("Transaction sender is undefined"); + return; + } let [inputToken, outputToken] = swapType.buy ? [ammMarket.quoteToken, ammMarket.baseToken] : [ammMarket.baseToken, ammMarket.quoteToken]; diff --git a/lib/client/rpc/market-clients/openbookMarkets.ts b/lib/client/rpc/market-clients/openbookMarkets.ts index 9b38907..d740667 100644 --- a/lib/client/rpc/market-clients/openbookMarkets.ts +++ b/lib/client/rpc/market-clients/openbookMarkets.ts @@ -216,17 +216,11 @@ export class FutarchyOpenbookMarketsRPCClient "owner" | "transactionStatus" | "status" | "filled" >, placeOrderType: PlaceOrderType - ): SendTransactionResponse { - if (!this.transactionSender) - return { - signatures: [], - errors: [ - { - message: "Transaction sender is undefined", - name: "Transaction Sender Error" - } - ] - }; + ) { + if (!this.transactionSender) { + console.error("Transaction sender is undefined"); + return; + } const mint = order.side === "ask" ? market.marketInstance.account.baseMint @@ -261,15 +255,7 @@ export class FutarchyOpenbookMarketsRPCClient if (!placeLimitOrderArgs) { console.error("failed to create place limit order args"); - return { - signatures: [], - errors: [ - { - name: "Limit order args", - message: "failed to create place limit order args" - } - ] - }; + return; } const placeTx = await market.twapProgram.methods @@ -390,20 +376,11 @@ export class FutarchyOpenbookMarketsRPCClient : MAX_MARKET_PRICE; } - async cancelOrder( - market: OpenbookMarket, - order: OpenbookOrder - ): SendTransactionResponse { - if (!this.transactionSender) - return { - signatures: [], - errors: [ - { - message: "Transaction sender is undefined", - name: "Transaction Sender Error" - } - ] - }; + async cancelOrder(market: OpenbookMarket, order: OpenbookOrder) { + if (!this.transactionSender) { + console.error("Transaction sender is undefined"); + return; + } const tx = await this.cancelAndSettleFundsTransactions(order, market); if (tx) { return this.transactionSender.send([tx], this.rpcProvider.connection, { @@ -464,7 +441,7 @@ export class FutarchyOpenbookMarketsRPCClient >, placeOrderType: PlaceOrderType, openOrdersAccountAddress?: PublicKey - ): SendTransactionResponse { + ) { // consider just creating an open orders account everytime if (!this.transactionSender) return { diff --git a/lib/client/rpc/proposals/createProposal.ts b/lib/client/rpc/proposals/createProposal.ts index 7402236..889a126 100644 --- a/lib/client/rpc/proposals/createProposal.ts +++ b/lib/client/rpc/proposals/createProposal.ts @@ -129,7 +129,7 @@ export class CreateProposalClient implements CreateProposal { dao: Dao, onPassIx: ProposalInstructionWithPreinstructions, marketParams: OpenbookMarketParams - ): SendTransactionResponse { + ) { const proposalKP = Keypair.generate(); const basePassMint = Keypair.generate(); @@ -348,18 +348,19 @@ export class CreateProposalClient implements CreateProposal { { title: "Creating Proposal" } ); - const accounts = { - proposer_acct: this.rpcProvider.publicKey, - base_cond_vault_acct: txResp?.signatures.length == 1 ? baseVault : null, - quote_cond_vault_acct: txResp?.signatures.length == 2 ? quoteVault : null, - pass_market_acct: - txResp?.signatures.length == 3 ? passMarketKP.publicKey : null, - fail_market_acct: - txResp?.signatures.length == 4 ? failMarketKP.publicKey : null, - proposal_acct: - txResp?.signatures.length == allTxs.length ? proposalKP.publicKey : null - }; - await this.proposalsClient.updateProposalAccounts(accounts); + // TODO commenting out since this does nothing right now, address later + // const accounts = { + // proposer_acct: this.rpcProvider.publicKey, + // base_cond_vault_acct: txResp?.signatures.length == 1 ? baseVault : null, + // quote_cond_vault_acct: txResp?.signatures.length == 2 ? quoteVault : null, + // pass_market_acct: + // txResp?.signatures.length == 3 ? passMarketKP.publicKey : null, + // fail_market_acct: + // txResp?.signatures.length == 4 ? failMarketKP.publicKey : null, + // proposal_acct: + // txResp?.signatures.length == allTxs.length ? proposalKP.publicKey : null + // }; + // await this.proposalsClient.updateProposalAccounts(accounts); return txResp; } @@ -368,7 +369,7 @@ export class CreateProposalClient implements CreateProposal { dao: Dao, onPassIx: ProposalInstructionWithPreinstructions, marketParams: AmmMarketParams - ): SendTransactionResponse { + ) { if (!this.transactionSender) return; const nonce = new BN(Math.random() * 2 ** 50); @@ -521,16 +522,17 @@ export class CreateProposalClient implements CreateProposal { { title: "Creating Proposal" } ); - const accounts = { - proposer_acct: this.rpcProvider.publicKey, - base_cond_vault_acct: txResp?.signatures.length == 1 ? baseVault : null, - quote_cond_vault_acct: txResp?.signatures.length == 1 ? quoteVault : null, - pass_market_acct: txResp?.signatures.length == 2 ? passAmm : null, - fail_market_acct: txResp?.signatures.length == 2 ? failAmm : null, - proposal_acct: - txResp?.signatures.length == allTxs.length ? proposal : null - }; - this.proposalsClient.updateProposalAccounts(accounts); + // TODO commenting out since this does nothing right now, address later + // const accounts = { + // proposer_acct: this.rpcProvider.publicKey, + // base_cond_vault_acct: txResp?.signatures.length == 1 ? baseVault : null, + // quote_cond_vault_acct: txResp?.signatures.length == 1 ? quoteVault : null, + // pass_market_acct: txResp?.signatures.length == 2 ? passAmm : null, + // fail_market_acct: txResp?.signatures.length == 2 ? failAmm : null, + // proposal_acct: + // txResp?.signatures.length == allTxs.length ? proposal : null + // }; + // this.proposalsClient.updateProposalAccounts(accounts); return txResp; } diff --git a/lib/client/rpc/proposals/proposals.ts b/lib/client/rpc/proposals/proposals.ts index 77ab716..83d3061 100644 --- a/lib/client/rpc/proposals/proposals.ts +++ b/lib/client/rpc/proposals/proposals.ts @@ -133,7 +133,7 @@ export class FutarchyRPCProposalsClient implements FutarchyProposalsClient { amount: number, vaultAccountAddress: PublicKey, vaultAccount: VaultAccountWithProtocol - ): SendTransactionResponse { + ) { if (!this.rpcProvider.publicKey || !this.transactionSender) { return; } diff --git a/lib/transactions.ts b/lib/transactions.ts index 193e403..32a8192 100644 --- a/lib/transactions.ts +++ b/lib/transactions.ts @@ -18,6 +18,7 @@ import { SendTransactionOptions } from "./types/transactions"; import { AnchorProvider } from "@coral-xyz/anchor"; +import { Observable, Subscriber } from "rxjs"; type SingleOrArray = T | T[]; @@ -78,106 +79,121 @@ export class TransactionSender { this.onTransactionUpdate?.(update); } - async send( + send( tx: T[], connection: Connection, opts?: SendTransactionOptions, displayMetadata?: TransactionDisplayMetadata - ): SendTransactionResponse { - let signatureSubscriptionIds: number[] = []; - try { - const sendRes = await this.sendInner(tx, connection, opts); - if ((sendRes?.errors?.length ?? 0) > 0) { - if ( - sendRes?.errors?.some((e) => e.name === "WalletSignTransactionError") - ) { - this.handleTransactionUpdate( - { + ): Observable { + return new Observable((subscriber) => { + let signatureSubscriptionIds: number[] = []; + this.sendInner(tx, connection, opts) + .then((sendRes) => { + if ((sendRes?.errors?.length ?? 0) > 0) { + if ( + sendRes?.errors?.some( + (e) => e.name === "WalletSignTransactionError" + ) + ) { + const txUpdate: TransactionProcessingUpdate = { + signature: sendRes?.signatures[0] ?? "", + errors: sendRes?.errors ?? [], + status: "unsigned", + displayMetadata + }; + this.handleTransactionUpdate( + txUpdate, + connection, + signatureSubscriptionIds + ); + subscriber.next(txUpdate); + return; + } + const txUpdate: TransactionProcessingUpdate = { signature: sendRes?.signatures[0] ?? "", errors: sendRes?.errors ?? [], - status: "unsigned", + status: "failed", + displayMetadata + }; + this.handleTransactionUpdate( + txUpdate, + connection, + signatureSubscriptionIds + ); + subscriber.next(txUpdate); + return; + } + if (!sendRes?.signatures[0]) { + const txUpdate: TransactionProcessingUpdate = { + signature: "", + errors: [ + { + message: "no signature returned", + name: "Signature Missing" + } + ], + status: "failed", + displayMetadata + }; + this.handleTransactionUpdate( + txUpdate, + connection, + signatureSubscriptionIds + ); + subscriber.next(txUpdate); + return; + } + + const txSignature = sendRes.signatures[0]; + this.handleTransactionUpdate( + { + status: "sent", + errors: [], + signature: txSignature, displayMetadata }, connection, signatureSubscriptionIds ); - return; - } - this.handleTransactionUpdate( - { - signature: sendRes?.signatures[0] ?? "", - errors: sendRes?.errors ?? [], - status: "failed", - displayMetadata - }, - connection, - signatureSubscriptionIds - ); - return; - } - if (!sendRes?.signatures[0]) { - this.handleTransactionUpdate( - { - signature: "", - errors: [ - { message: "no signature returned", name: "Signature Missing" } - ], - status: "failed", - displayMetadata - }, - connection, - signatureSubscriptionIds - ); - return; - } - - const txSignature = sendRes.signatures[0]; - this.handleTransactionUpdate( - { - status: "sent", - errors: [], - signature: txSignature, - displayMetadata - }, - connection, - signatureSubscriptionIds - ); - signatureSubscriptionIds = COMMITMENTS_TO_WATCH.map((s) => { - return connection.onSignature( - txSignature, - (signatureResult: SignatureResult, _context: Context) => - this.handleSignatureResult( + signatureSubscriptionIds = COMMITMENTS_TO_WATCH.map((s) => { + return connection.onSignature( txSignature, - signatureResult, - connection, - signatureSubscriptionIds, - displayMetadata - ), - s - ); - }); + (signatureResult: SignatureResult, _context: Context) => + this.handleSignatureResult( + txSignature, + signatureResult, + connection, + signatureSubscriptionIds, + subscriber, + displayMetadata + ), + s + ); + }); - return sendRes; - } catch (e) { - const error = { - message: JSON.stringify(e), - name: "general error" - }; - this.handleTransactionUpdate( - { - signature: "", - errors: [error], - status: "failed", - displayMetadata - }, - connection, - signatureSubscriptionIds - ); - return { - signatures: [], - errors: [error] - }; - } + return sendRes; + }) + .catch((e) => { + const error = { + message: JSON.stringify(e), + name: "general error" + }; + this.handleTransactionUpdate( + { + signature: "", + errors: [error], + status: "failed", + displayMetadata + }, + connection, + signatureSubscriptionIds + ); + return { + signatures: [], + errors: [error] + }; + }); + }); } private async handleSignatureResult( @@ -185,6 +201,7 @@ export class TransactionSender { signatureResult: SignatureResult, connection: Connection, signatureSubscriptionIds: number[], + txObserverSubscriber: Subscriber, displayMetadata?: TransactionDisplayMetadata ) { if (signatureResult.err) { @@ -197,29 +214,32 @@ export class TransactionSender { name: JSON.stringify(signatureResult.err) } ]; + const txUpdate: TransactionProcessingUpdate = { + signature: txSignature, + errors: errors, + status: "failed", + displayMetadata + }; this.handleTransactionUpdate( - { - signature: txSignature, - errors: errors, - status: "failed", - displayMetadata - }, + txUpdate, connection, signatureSubscriptionIds ); + txObserverSubscriber.next(txUpdate); return; } const statusRes = await connection.getSignatureStatus(txSignature); const status = statusRes.value; if (status?.confirmationStatus) { + const txUpdate: TransactionProcessingUpdate = { + signature: txSignature, + errors: [], + status: status.confirmationStatus, + displayMetadata + }; this.handleTransactionUpdate( - { - signature: txSignature, - errors: [], - status: status.confirmationStatus, - displayMetadata - }, + txUpdate, connection, signatureSubscriptionIds );