@atomiqlabs/chain-solana 13.1.0 → 13.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -133,6 +133,10 @@ export declare class SolanaChainInterface implements ChainInterface<SolanaTx, Si
133
133
  * @inheritDoc
134
134
  */
135
135
  sendSignedAndConfirm(txs: SignedSolanaTx[], waitForConfirmation?: boolean, abortSignal?: AbortSignal, parallel?: boolean, onBeforePublish?: (txId: string, rawTx: string) => Promise<void>): Promise<string[]>;
136
+ /**
137
+ * @inheritDoc
138
+ */
139
+ prepareTxs(txs: SolanaTx[]): Promise<SolanaTx[]>;
136
140
  /**
137
141
  * @inheritDoc
138
142
  */
@@ -109,6 +109,13 @@ class SolanaChainInterface {
109
109
  sendSignedAndConfirm(txs, waitForConfirmation, abortSignal, parallel, onBeforePublish) {
110
110
  return this.Transactions.sendSignedAndConfirm(txs, waitForConfirmation, abortSignal, parallel, onBeforePublish);
111
111
  }
112
+ /**
113
+ * @inheritDoc
114
+ */
115
+ async prepareTxs(txs) {
116
+ await this.Transactions.prepareTransactions(txs);
117
+ return txs;
118
+ }
112
119
  /**
113
120
  * @inheritDoc
114
121
  */
@@ -73,11 +73,10 @@ export declare class SolanaTransactions extends SolanaModule {
73
73
  * Prepares solana transactions, assigns recentBlockhash if needed, applies Phantom hotfix,
74
74
  * sets feePayer to ourselves, calls beforeTxSigned callback & signs transaction with provided signers array
75
75
  *
76
- * @param signer
77
76
  * @param txs
78
- * @private
77
+ * @param signer
79
78
  */
80
- private prepareTransactions;
79
+ prepareTransactions(txs: SolanaTx[], signer?: SolanaSigner): Promise<void>;
81
80
  /**
82
81
  * Sends out a signed transaction to the RPC
83
82
  *
@@ -159,11 +159,15 @@ class SolanaTransactions extends SolanaModule_1.SolanaModule {
159
159
  * Prepares solana transactions, assigns recentBlockhash if needed, applies Phantom hotfix,
160
160
  * sets feePayer to ourselves, calls beforeTxSigned callback & signs transaction with provided signers array
161
161
  *
162
- * @param signer
163
162
  * @param txs
164
- * @private
163
+ * @param signer
165
164
  */
166
- async prepareTransactions(signer, txs) {
165
+ async prepareTransactions(txs, signer) {
166
+ if (txs.length === 0)
167
+ return;
168
+ const signerAddress = signer?.getPublicKey() ?? txs[0].tx.feePayer;
169
+ if (signerAddress == null)
170
+ throw new Error("Cannot get tx sender address!");
167
171
  let latestBlockData = null;
168
172
  for (let tx of txs) {
169
173
  if (tx.tx.recentBlockhash == null) {
@@ -177,13 +181,13 @@ class SolanaTransactions extends SolanaModule_1.SolanaModule {
177
181
  }
178
182
  //This is a hotfix for Phantom adding compute unit price instruction on the first position & breaking
179
183
  // required instructions order (e.g. btc relay verify needs to be 0th instruction in a tx)
180
- if (signer.keypair == null && tx.tx.signatures.length === 0) {
184
+ if ((signer == null || signer.keypair == null) && tx.tx.signatures.length === 0) {
181
185
  const foundIx = tx.tx.instructions.find(ix => ix.programId.equals(web3_js_1.ComputeBudgetProgram.programId) && web3_js_1.ComputeBudgetInstruction.decodeInstructionType(ix) === "SetComputeUnitPrice");
182
186
  if (foundIx == null)
183
187
  tx.tx.instructions.splice(tx.tx.instructions.length - 1, 0, web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 }));
184
188
  }
185
- tx.tx.feePayer = signer.getPublicKey();
186
- if (this.cbkBeforeTxSigned != null)
189
+ tx.tx.feePayer = signerAddress;
190
+ if (signer != null && this.cbkBeforeTxSigned != null)
187
191
  await this.cbkBeforeTxSigned(tx);
188
192
  if (tx.signers != null && tx.signers.length > 0)
189
193
  for (let signer of tx.signers)
@@ -235,7 +239,7 @@ class SolanaTransactions extends SolanaModule_1.SolanaModule {
235
239
  const signatures = [];
236
240
  for (let e = 0; e < _txs.length; e += BATCH_SIZE) {
237
241
  const txs = _txs.slice(e, e + BATCH_SIZE);
238
- await this.prepareTransactions(signer, txs);
242
+ await this.prepareTransactions(txs, signer);
239
243
  const signedTxs = await signer.wallet.signAllTransactions(txs.map(e => e.tx));
240
244
  signedTxs.forEach((tx, index) => {
241
245
  const solTx = txs[index];
@@ -305,7 +309,7 @@ class SolanaTransactions extends SolanaModule_1.SolanaModule {
305
309
  */
306
310
  serializeUnsignedTx(tx) {
307
311
  return JSON.stringify({
308
- tx: tx.tx.serialize().toString("hex"),
312
+ tx: tx.tx.serialize({ requireAllSignatures: false, verifySignatures: false }).toString("hex"),
309
313
  signers: tx.signers.map(e => buffer_1.Buffer.from(e.secretKey).toString("hex")),
310
314
  lastValidBlockheight: tx.tx.lastValidBlockHeight
311
315
  });
@@ -316,7 +320,7 @@ class SolanaTransactions extends SolanaModule_1.SolanaModule {
316
320
  * @param signedTx
317
321
  */
318
322
  serializeSignedTx(signedTx) {
319
- return signedTx.serialize().toString("hex");
323
+ return signedTx.serialize({ requireAllSignatures: false, verifySignatures: false }).toString("hex");
320
324
  }
321
325
  /**
322
326
  * Deserializes saved solana transaction, extracting the transaction, signers & last valid blockheight
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@atomiqlabs/chain-solana",
3
- "version": "13.1.0",
3
+ "version": "13.2.1",
4
4
  "description": "Solana specific base implementation",
5
5
  "main": "./dist/index.js",
6
6
  "types:": "./dist/index.d.ts",
7
7
  "scripts": {
8
+ "build": "npx -y -p typescript@4.9 tsc",
8
9
  "test": "echo \"Error: no test specified\" && exit 1",
9
10
  "build:ts4": "npx -p typescript@4.9 tsc --noEmit",
10
11
  "build:ts5": "npx -p typescript@5 tsc --noEmit"
@@ -25,7 +26,7 @@
25
26
  "author": "adambor",
26
27
  "license": "ISC",
27
28
  "dependencies": {
28
- "@atomiqlabs/base": "^13.0.4",
29
+ "@atomiqlabs/base": "^13.2.0",
29
30
  "@coral-xyz/anchor": "0.29.0",
30
31
  "@noble/hashes": "^1.7.1",
31
32
  "@solana/spl-token": "0.4.14",
@@ -216,6 +216,14 @@ export class SolanaChainInterface implements ChainInterface<
216
216
  return this.Transactions.sendSignedAndConfirm(txs, waitForConfirmation, abortSignal, parallel, onBeforePublish);
217
217
  }
218
218
 
219
+ /**
220
+ * @inheritDoc
221
+ */
222
+ async prepareTxs(txs: SolanaTx[]): Promise<SolanaTx[]> {
223
+ await this.Transactions.prepareTransactions(txs);
224
+ return txs;
225
+ }
226
+
219
227
  /**
220
228
  * @inheritDoc
221
229
  */
@@ -195,11 +195,14 @@ export class SolanaTransactions extends SolanaModule {
195
195
  * Prepares solana transactions, assigns recentBlockhash if needed, applies Phantom hotfix,
196
196
  * sets feePayer to ourselves, calls beforeTxSigned callback & signs transaction with provided signers array
197
197
  *
198
- * @param signer
199
198
  * @param txs
200
- * @private
199
+ * @param signer
201
200
  */
202
- private async prepareTransactions(signer: SolanaSigner, txs: SolanaTx[]): Promise<void> {
201
+ public async prepareTransactions(txs: SolanaTx[], signer?: SolanaSigner): Promise<void> {
202
+ if(txs.length===0) return;
203
+ const signerAddress = signer?.getPublicKey() ?? txs[0].tx.feePayer;
204
+ if(signerAddress==null) throw new Error("Cannot get tx sender address!");
205
+
203
206
  let latestBlockData: {blockhash: string, lastValidBlockHeight: number} | null = null;
204
207
 
205
208
  for(let tx of txs) {
@@ -215,13 +218,13 @@ export class SolanaTransactions extends SolanaModule {
215
218
 
216
219
  //This is a hotfix for Phantom adding compute unit price instruction on the first position & breaking
217
220
  // required instructions order (e.g. btc relay verify needs to be 0th instruction in a tx)
218
- if(signer.keypair==null && tx.tx.signatures.length===0) {
221
+ if((signer==null || signer.keypair==null) && tx.tx.signatures.length===0) {
219
222
  const foundIx = tx.tx.instructions.find(ix => ix.programId.equals(ComputeBudgetProgram.programId) && ComputeBudgetInstruction.decodeInstructionType(ix)==="SetComputeUnitPrice")
220
223
  if(foundIx==null) tx.tx.instructions.splice(tx.tx.instructions.length-1, 0, ComputeBudgetProgram.setComputeUnitPrice({microLamports: 1}));
221
224
  }
222
225
 
223
- tx.tx.feePayer = signer.getPublicKey();
224
- if(this.cbkBeforeTxSigned!=null) await this.cbkBeforeTxSigned(tx);
226
+ tx.tx.feePayer = signerAddress;
227
+ if(signer!=null && this.cbkBeforeTxSigned!=null) await this.cbkBeforeTxSigned(tx);
225
228
  if(tx.signers!=null && tx.signers.length>0) for(let signer of tx.signers) tx.tx.sign(signer);
226
229
  }
227
230
  }
@@ -275,7 +278,7 @@ export class SolanaTransactions extends SolanaModule {
275
278
  for(let e=0;e<_txs.length;e+=BATCH_SIZE) {
276
279
  const txs = _txs.slice(e, e+BATCH_SIZE);
277
280
 
278
- await this.prepareTransactions(signer, txs)
281
+ await this.prepareTransactions(txs, signer)
279
282
  const signedTxs = await signer.wallet.signAllTransactions(txs.map(e => e.tx));
280
283
  signedTxs.forEach((tx, index) => {
281
284
  const solTx = txs[index];
@@ -357,7 +360,7 @@ export class SolanaTransactions extends SolanaModule {
357
360
  */
358
361
  public serializeUnsignedTx(tx: SolanaTx): string {
359
362
  return JSON.stringify({
360
- tx: tx.tx.serialize().toString("hex"),
363
+ tx: tx.tx.serialize({requireAllSignatures: false, verifySignatures: false}).toString("hex"),
361
364
  signers: tx.signers.map(e => Buffer.from(e.secretKey).toString("hex")),
362
365
  lastValidBlockheight: tx.tx.lastValidBlockHeight
363
366
  });
@@ -369,7 +372,7 @@ export class SolanaTransactions extends SolanaModule {
369
372
  * @param signedTx
370
373
  */
371
374
  public serializeSignedTx(signedTx: Transaction): string {
372
- return signedTx.serialize().toString("hex");
375
+ return signedTx.serialize({requireAllSignatures: false, verifySignatures: false}).toString("hex");
373
376
  }
374
377
 
375
378
  /**