From c28cc0748df1a67de8977faf0286566f74ad1faa Mon Sep 17 00:00:00 2001 From: Yolley Date: Fri, 8 Dec 2023 15:06:31 +0900 Subject: [PATCH] execute multiple tx in seq for SquadsX (#113) --- lerna.json | 2 +- package-lock.json | 2 +- packages/stream/package.json | 2 +- packages/stream/solana/StreamClient.ts | 73 ++++++++++++++------------ packages/stream/solana/types.ts | 2 +- 5 files changed, 44 insertions(+), 37 deletions(-) diff --git a/lerna.json b/lerna.json index 4d958721..d65f93fd 100644 --- a/lerna.json +++ b/lerna.json @@ -2,6 +2,6 @@ "packages": [ "packages/*" ], - "version": "5.7.0", + "version": "5.7.1", "$schema": "node_modules/lerna/schemas/lerna-schema.json" } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 85147616..35235f6c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22169,7 +22169,7 @@ }, "packages/stream": { "name": "@streamflow/stream", - "version": "5.6.3", + "version": "5.7.1", "dependencies": { "@manahippo/aptos-wallet-adapter": "1.0.6", "@mysten/sui.js": "^0.40.0", diff --git a/packages/stream/package.json b/packages/stream/package.json index e8c07551..7c614d1f 100644 --- a/packages/stream/package.json +++ b/packages/stream/package.json @@ -1,6 +1,6 @@ { "name": "@streamflow/stream", - "version": "5.7.0", + "version": "5.7.1", "description": "JavaScript SDK to interact with Streamflow protocol.", "main": "dist/index.js", "homepage": "https://github.com/streamflow-finance/js-sdk/", diff --git a/packages/stream/solana/StreamClient.ts b/packages/stream/solana/StreamClient.ts index deef4599..0c76bda7 100644 --- a/packages/stream/solana/StreamClient.ts +++ b/packages/stream/solana/StreamClient.ts @@ -147,14 +147,7 @@ export default class SolanaStreamClient extends BaseStreamClient { const mintPublicKey = isNative ? NATIVE_MINT : new PublicKey(mint); const recipientPublicKey = new PublicKey(recipient); - let metadata: Keypair | null = null; - let metadataPubKey: PublicKey; - if (!metadataPubKeys) { - metadata = Keypair.generate(); - metadataPubKey = metadata.publicKey; - } else { - metadataPubKey = metadataPubKeys[0]; - } + const { metadata, metadataPubKey } = this.getOrCreateStreamMetadata(metadataPubKeys); const [escrowTokens] = PublicKey.findProgramAddressSync( [Buffer.from("strm"), metadataPubKey.toBuffer()], this.programId @@ -271,15 +264,7 @@ export default class SolanaStreamClient extends BaseStreamClient { const mintPublicKey = new PublicKey(mint); const recipientPublicKey = new PublicKey(recipient); - - let metadata: Keypair | null = null; - let metadataPubKey: PublicKey; - if (!metadataPubKeys) { - metadata = Keypair.generate(); - metadataPubKey = metadata.publicKey; - } else { - metadataPubKey = metadataPubKeys[0]; - } + const { metadata, metadataPubKey } = this.getOrCreateStreamMetadata(metadataPubKeys); const rentToExempt = await this.connection.getMinimumBalanceForRentExemption(METADATA_ACC_SIZE); const createMetadataInstruction = SystemProgram.createAccount({ @@ -423,14 +408,26 @@ export default class SolanaStreamClient extends BaseStreamClient { await sendAndConfirmStreamRawTransaction(this.connection, prepareTx!); } - //send all transactions in parallel and wait for them to settle. - //it allows to speed up the process of sending transactions - //we then filter all promise responses and handle failed transactions - const batchTransactionsCalls = signedBatch.map((el) => - sendAndConfirmStreamRawTransaction(this.connection, el) - ); - - const responses = await Promise.allSettled(batchTransactionsCalls); + const responses: PromiseSettledResult[] = []; + if (metadataPubKeys.length > 0) { + //if metadata pub keys were passed we should execute transaction sequentially + //ephemeral signer need to be used first before proceeding with the next + for (const batchTx of signedBatch) { + responses.push( + ...(await Promise.allSettled([ + sendAndConfirmStreamRawTransaction(this.connection, batchTx), + ])) + ); + } + } else { + //send all transactions in parallel and wait for them to settle. + //it allows to speed up the process of sending transactions + //we then filter all promise responses and handle failed transactions + const batchTransactionsCalls = signedBatch.map((el) => + sendAndConfirmStreamRawTransaction(this.connection, el) + ); + responses.push(...(await Promise.allSettled(batchTransactionsCalls))); + } const successes = responses .filter((el): el is PromiseFulfilledResult => el.status === "fulfilled") @@ -842,14 +839,7 @@ export default class SolanaStreamClient extends BaseStreamClient { typeof this.commitment == "string" ? this.commitment : this.commitment.commitment; const recipientPublicKey = new PublicKey(recipient.recipient); const mintPublicKey = new PublicKey(mint); - let metadata: Keypair | null = null; - let metadataPubKey: PublicKey; - if (!metadataPubKeys) { - metadata = Keypair.generate(); - metadataPubKey = metadata.publicKey; - } else { - metadataPubKey = metadataPubKeys[0]; - } + const { metadata, metadataPubKey } = this.getOrCreateStreamMetadata(metadataPubKeys); const [escrowTokens] = PublicKey.findProgramAddressSync( [Buffer.from("strm"), metadataPubKey.toBuffer()], this.programId @@ -915,4 +905,21 @@ export default class SolanaStreamClient extends BaseStreamClient { } return { tx, metadataPubKey }; } + + /** + * Utility function to generate metadata for a Contract or return existing Pubkey + */ + private getOrCreateStreamMetadata(metadataPubKeys?: PublicKey[]) { + let metadata; + let metadataPubKey; + + if (!metadataPubKeys) { + metadata = Keypair.generate(); + metadataPubKey = metadata.publicKey; + } else { + metadataPubKey = metadataPubKeys[0]; + } + + return { metadata, metadataPubKey }; + } } diff --git a/packages/stream/solana/types.ts b/packages/stream/solana/types.ts index 2bc1894e..aec06878 100644 --- a/packages/stream/solana/types.ts +++ b/packages/stream/solana/types.ts @@ -23,7 +23,7 @@ export interface Account { export interface ICreateStreamSolanaExt { sender: SignerWalletAdapter | Keypair; - // allow custom Metadata Account to be passed, i.e. an ephemeral signer, accepts array to be compatible in createMultiple + // allow custom Metadata Account to be passed, ephemeral signer is most cases, accepts array to be compatible in createMultiple metadataPubKeys?: PublicKey[]; partner?: string | null; isNative?: boolean;