@atomiqlabs/chain-starknet 8.1.13 → 8.2.2

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.
@@ -117,6 +117,10 @@ export declare class StarknetChainInterface implements ChainInterface<StarknetTx
117
117
  * @inheritDoc
118
118
  */
119
119
  sendSignedAndConfirm(signedTxs: SignedStarknetTx[], waitForConfirmation?: boolean, abortSignal?: AbortSignal, parallel?: boolean, onBeforePublish?: (txId: string, rawTx: string) => Promise<void>): Promise<string[]>;
120
+ /**
121
+ * @inheritDoc
122
+ */
123
+ prepareTxs(txs: StarknetTx[]): Promise<StarknetTx[]>;
120
124
  /**
121
125
  * @inheritDoc
122
126
  */
@@ -123,6 +123,13 @@ class StarknetChainInterface {
123
123
  sendSignedAndConfirm(signedTxs, waitForConfirmation, abortSignal, parallel, onBeforePublish) {
124
124
  return this.Transactions.sendSignedAndConfirm(signedTxs, waitForConfirmation, abortSignal, parallel, onBeforePublish);
125
125
  }
126
+ /**
127
+ * @inheritDoc
128
+ */
129
+ async prepareTxs(txs) {
130
+ await this.Transactions.prepareTransactions(txs);
131
+ return txs;
132
+ }
126
133
  /**
127
134
  * @inheritDoc
128
135
  */
@@ -90,13 +90,15 @@ export declare class StarknetTransactions extends StarknetModule {
90
90
  */
91
91
  private confirmTransaction;
92
92
  /**
93
- * Prepares starknet transactions, checks if the account is deployed, assigns nonces if needed & calls beforeTxSigned callback
93
+ * Prepares starknet transactions, checks if the account is deployed, assigns nonces if needed
94
+ * & calls beforeTxSigned callback (only if signer is passed!)
94
95
  *
95
96
  * @param signer
96
97
  * @param txs
97
- * @private
98
98
  */
99
- private prepareTransactions;
99
+ prepareTransactions(txs: (StarknetTx & {
100
+ addedInPrepare?: boolean;
101
+ })[], signer?: StarknetSigner): Promise<void>;
100
102
  /**
101
103
  * Sends out a signed transaction to the RPC
102
104
  *
@@ -214,29 +214,45 @@ class StarknetTransactions extends StarknetModule_1.StarknetModule {
214
214
  return result.txId;
215
215
  }
216
216
  /**
217
- * Prepares starknet transactions, checks if the account is deployed, assigns nonces if needed & calls beforeTxSigned callback
217
+ * Prepares starknet transactions, checks if the account is deployed, assigns nonces if needed
218
+ * & calls beforeTxSigned callback (only if signer is passed!)
218
219
  *
219
220
  * @param signer
220
221
  * @param txs
221
- * @private
222
222
  */
223
- async prepareTransactions(signer, txs) {
224
- let nonce = await this.getNonce(signer.getAddress());
225
- const latestPendingNonce = this.latestPendingNonces[(0, Utils_1.toHex)(signer.getAddress())];
223
+ async prepareTransactions(txs, signer) {
224
+ if (txs.length === 0)
225
+ return;
226
+ const signerAddress = signer?.getAddress() ?? txs[0].details.walletAddress;
227
+ if (signerAddress == null)
228
+ throw new Error("Cannot get tx sender address!");
229
+ let nonce = await this.getNonce(signerAddress);
230
+ const latestPendingNonce = this.latestPendingNonces[(0, Utils_1.toHex)(signerAddress)];
226
231
  if (latestPendingNonce != null && latestPendingNonce > nonce) {
227
232
  this.logger.debug("prepareTransactions(): Using 'pending' nonce from local cache!");
228
233
  nonce = latestPendingNonce;
229
234
  }
230
235
  //Add deploy account tx
231
236
  if (nonce === 0n) {
232
- const deployPayload = await signer.getDeployPayload();
233
- if (deployPayload != null) {
234
- const tx = await this.root.Accounts.getAccountDeployTransaction(deployPayload);
237
+ if (signer != null) {
238
+ const deployPayload = await signer.getDeployPayload();
239
+ if (deployPayload != null) {
240
+ const tx = await this.root.Accounts.getAccountDeployTransaction(deployPayload);
241
+ tx.addedInPrepare = true;
242
+ txs.unshift(tx);
243
+ }
244
+ }
245
+ else {
246
+ // Use a 0x0 class hash to indicate that deployment is needed by external signer
247
+ const tx = await this.root.Accounts.getAccountDeployTransaction({
248
+ classHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
249
+ contractAddress: signerAddress
250
+ });
235
251
  tx.addedInPrepare = true;
236
252
  txs.unshift(tx);
237
253
  }
238
254
  }
239
- if (!signer.isManagingNoncesInternally) {
255
+ if (signer == null || !signer.isManagingNoncesInternally) {
240
256
  if (nonce === 0n) {
241
257
  //Just increment the nonce by one and hope the wallet is smart enough to deploy account first
242
258
  nonce = 1n;
@@ -246,18 +262,19 @@ class StarknetTransactions extends StarknetModule_1.StarknetModule {
246
262
  if (tx.details.nonce != null)
247
263
  nonce = BigInt(tx.details.nonce); //Take the nonce from last tx
248
264
  if (nonce == null)
249
- nonce = BigInt(await this.root.provider.getNonceForAddress(signer.getAddress())); //Fetch the nonce
265
+ nonce = BigInt(await this.root.provider.getNonceForAddress(signerAddress)); //Fetch the nonce
250
266
  if (tx.details.nonce == null)
251
267
  tx.details.nonce = nonce;
252
268
  this.logger.debug("prepareTransactions(): transaction prepared (" + (i + 1) + "/" + txs.length + "), nonce: " + tx.details.nonce);
253
269
  nonce += BigInt(1);
254
270
  }
255
271
  }
256
- for (let tx of txs) {
257
- for (let callback of this.cbksBeforeTxSigned) {
258
- await callback(tx);
272
+ if (signer != null)
273
+ for (let tx of txs) {
274
+ for (let callback of this.cbksBeforeTxSigned) {
275
+ await callback(tx);
276
+ }
259
277
  }
260
- }
261
278
  }
262
279
  /**
263
280
  * Sends out a signed transaction to the RPC
@@ -293,13 +310,14 @@ class StarknetTransactions extends StarknetModule_1.StarknetModule {
293
310
  */
294
311
  async sendAndConfirm(signer, _txs, waitForConfirmation, abortSignal, parallel, onBeforePublish) {
295
312
  const txs = _txs;
296
- await this.prepareTransactions(signer, txs);
313
+ await this.prepareTransactions(txs, signer);
297
314
  const signedTxs = [];
298
315
  //Don't separate the signing process from the sending when using browser-based wallet
299
316
  if (signer.signTransaction != null)
300
317
  for (let i = 0; i < txs.length; i++) {
301
318
  const tx = txs[i];
302
319
  const signedTx = await signer.signTransaction(tx);
320
+ (0, Utils_1.calculateHash)(signedTx);
303
321
  signedTx.addedInPrepare = tx.addedInPrepare;
304
322
  signedTxs.push(signedTx);
305
323
  this.logger.debug("sendAndConfirm(): transaction signed (" + (i + 1) + "/" + txs.length + "): " + signedTx.txId);
@@ -384,9 +402,10 @@ class StarknetTransactions extends StarknetModule_1.StarknetModule {
384
402
  return txIds;
385
403
  }
386
404
  async sendSignedAndConfirm(signedTxs, waitForConfirmation, abortSignal, parallel, onBeforePublish) {
387
- signedTxs.forEach(val => {
388
- if (val.signed == null)
405
+ signedTxs.forEach(tx => {
406
+ if (tx.signed == null)
389
407
  throw new Error("Transactions have to be signed!");
408
+ (0, Utils_1.calculateHash)(tx);
390
409
  });
391
410
  this.logger.debug("sendSignedAndConfirm(): sending transactions, count: " + signedTxs.length +
392
411
  " waitForConfirmation: " + waitForConfirmation + " parallel: " + parallel);
@@ -113,11 +113,11 @@ function calculateHash(tx) {
113
113
  case "DEPLOY_ACCOUNT":
114
114
  if (tx.signed.constructorCalldata == null ||
115
115
  tx.signed.addressSalt == null ||
116
- tx.tx.contractAddress == null)
116
+ tx.details.walletAddress == null)
117
117
  throw new Error("TX not enough data to compute hash!");
118
118
  const deployAccountData = starknet_1.CallData.compile(tx.signed.constructorCalldata);
119
119
  return tx.txId = starknet_1.hash.calculateDeployAccountTransactionHash({
120
- contractAddress: tx.tx.contractAddress,
120
+ contractAddress: tx.details.walletAddress,
121
121
  classHash: tx.signed.classHash,
122
122
  compiledConstructorCalldata: deployAccountData,
123
123
  salt: tx.signed.addressSalt,
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@atomiqlabs/chain-starknet",
3
- "version": "8.1.13",
3
+ "version": "8.2.2",
4
4
  "description": "Starknet specific base implementation",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
7
7
  "scripts": {
8
- "build": "tsc",
8
+ "build": "npx -y -p typescript@4.9 tsc",
9
9
  "prepublishOnly": "npm run build",
10
10
  "test": "echo \"Error: no test specified\" && exit 1",
11
11
  "build:ts4": "npx -p typescript@4.9 tsc --noEmit",
@@ -31,7 +31,7 @@
31
31
  "url": "git+https://github.com/atomiqlabs/atomiq-chain-starknet.git"
32
32
  },
33
33
  "dependencies": {
34
- "@atomiqlabs/base": "^13.1.14",
34
+ "@atomiqlabs/base": "^13.2.0",
35
35
  "@noble/hashes": "^1.7.1",
36
36
  "@scure/btc-signer": "^1.6.0",
37
37
  "abi-wan-kanabi": "2.2.4",
@@ -211,6 +211,14 @@ export class StarknetChainInterface implements ChainInterface<StarknetTx, Signed
211
211
  return this.Transactions.sendSignedAndConfirm(signedTxs, waitForConfirmation, abortSignal, parallel, onBeforePublish);
212
212
  }
213
213
 
214
+ /**
215
+ * @inheritDoc
216
+ */
217
+ async prepareTxs(txs: StarknetTx[]): Promise<StarknetTx[]> {
218
+ await this.Transactions.prepareTransactions(txs);
219
+ return txs;
220
+ }
221
+
214
222
  /**
215
223
  * @inheritDoc
216
224
  */
@@ -13,10 +13,11 @@ import {
13
13
  CallData,
14
14
  Calldata,
15
15
  ResourceBounds,
16
- ResourceBoundsBN
16
+ ResourceBoundsBN, RawArgs
17
17
  } from "starknet";
18
18
  import {StarknetSigner} from "../../wallet/StarknetSigner";
19
19
  import {
20
+ calculateHash,
20
21
  deserializeResourceBounds,
21
22
  deserializeSignature,
22
23
  NoBigInt,
@@ -304,15 +305,19 @@ export class StarknetTransactions extends StarknetModule {
304
305
  }
305
306
 
306
307
  /**
307
- * Prepares starknet transactions, checks if the account is deployed, assigns nonces if needed & calls beforeTxSigned callback
308
+ * Prepares starknet transactions, checks if the account is deployed, assigns nonces if needed
309
+ * & calls beforeTxSigned callback (only if signer is passed!)
308
310
  *
309
311
  * @param signer
310
312
  * @param txs
311
- * @private
312
313
  */
313
- private async prepareTransactions(signer: StarknetSigner, txs: (StarknetTx & {addedInPrepare?: boolean})[]): Promise<void> {
314
- let nonce: bigint = await this.getNonce(signer.getAddress());
315
- const latestPendingNonce = this.latestPendingNonces[toHex(signer.getAddress())];
314
+ public async prepareTransactions(txs: (StarknetTx & {addedInPrepare?: boolean})[], signer?: StarknetSigner): Promise<void> {
315
+ if(txs.length===0) return;
316
+ const signerAddress = signer?.getAddress() ?? txs[0].details.walletAddress;
317
+ if(signerAddress==null) throw new Error("Cannot get tx sender address!");
318
+
319
+ let nonce: bigint = await this.getNonce(signerAddress);
320
+ const latestPendingNonce = this.latestPendingNonces[toHex(signerAddress)];
316
321
  if(latestPendingNonce!=null && latestPendingNonce > nonce) {
317
322
  this.logger.debug("prepareTransactions(): Using 'pending' nonce from local cache!");
318
323
  nonce = latestPendingNonce;
@@ -320,15 +325,25 @@ export class StarknetTransactions extends StarknetModule {
320
325
 
321
326
  //Add deploy account tx
322
327
  if(nonce===0n) {
323
- const deployPayload = await signer.getDeployPayload();
324
- if(deployPayload!=null) {
325
- const tx: (StarknetTx & {addedInPrepare?: boolean}) = await this.root.Accounts.getAccountDeployTransaction(deployPayload);
328
+ if(signer!=null) {
329
+ const deployPayload = await signer.getDeployPayload();
330
+ if(deployPayload!=null) {
331
+ const tx: (StarknetTx & {addedInPrepare?: boolean}) = await this.root.Accounts.getAccountDeployTransaction(deployPayload);
332
+ tx.addedInPrepare = true;
333
+ txs.unshift(tx);
334
+ }
335
+ } else {
336
+ // Use a 0x0 class hash to indicate that deployment is needed by external signer
337
+ const tx: (StarknetTx & {addedInPrepare?: boolean}) = await this.root.Accounts.getAccountDeployTransaction({
338
+ classHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
339
+ contractAddress: signerAddress
340
+ });
326
341
  tx.addedInPrepare = true;
327
342
  txs.unshift(tx);
328
343
  }
329
344
  }
330
345
 
331
- if(!signer.isManagingNoncesInternally) {
346
+ if(signer==null || !signer.isManagingNoncesInternally) {
332
347
  if(nonce===0n) {
333
348
  //Just increment the nonce by one and hope the wallet is smart enough to deploy account first
334
349
  nonce = 1n;
@@ -337,7 +352,7 @@ export class StarknetTransactions extends StarknetModule {
337
352
  for(let i=0;i<txs.length;i++) {
338
353
  const tx = txs[i];
339
354
  if(tx.details.nonce!=null) nonce = BigInt(tx.details.nonce); //Take the nonce from last tx
340
- if(nonce==null) nonce = BigInt(await this.root.provider.getNonceForAddress(signer.getAddress())); //Fetch the nonce
355
+ if(nonce==null) nonce = BigInt(await this.root.provider.getNonceForAddress(signerAddress)); //Fetch the nonce
341
356
  if(tx.details.nonce==null) tx.details.nonce = nonce;
342
357
 
343
358
  this.logger.debug("prepareTransactions(): transaction prepared ("+(i+1)+"/"+txs.length+"), nonce: "+tx.details.nonce);
@@ -346,7 +361,7 @@ export class StarknetTransactions extends StarknetModule {
346
361
  }
347
362
  }
348
363
 
349
- for(let tx of txs) {
364
+ if(signer!=null) for(let tx of txs) {
350
365
  for(let callback of this.cbksBeforeTxSigned) {
351
366
  await callback(tx);
352
367
  }
@@ -389,13 +404,14 @@ export class StarknetTransactions extends StarknetModule {
389
404
  */
390
405
  public async sendAndConfirm(signer: StarknetSigner, _txs: StarknetTx[], waitForConfirmation?: boolean, abortSignal?: AbortSignal, parallel?: boolean, onBeforePublish?: (txId: string, rawTx: string) => Promise<void>): Promise<string[]> {
391
406
  const txs: (StarknetTx & {addedInPrepare?: boolean})[] = _txs;
392
- await this.prepareTransactions(signer, txs);
407
+ await this.prepareTransactions(txs, signer);
393
408
  const signedTxs: (StarknetTx & {addedInPrepare?: boolean})[] = [];
394
409
 
395
410
  //Don't separate the signing process from the sending when using browser-based wallet
396
411
  if(signer.signTransaction!=null) for(let i=0;i<txs.length;i++) {
397
412
  const tx = txs[i];
398
413
  const signedTx: (StarknetTx & {addedInPrepare?: boolean}) = await signer.signTransaction(tx);
414
+ calculateHash(signedTx);
399
415
  signedTx.addedInPrepare = tx.addedInPrepare;
400
416
  signedTxs.push(signedTx);
401
417
  this.logger.debug("sendAndConfirm(): transaction signed ("+(i+1)+"/"+txs.length+"): "+signedTx.txId);
@@ -486,8 +502,9 @@ export class StarknetTransactions extends StarknetModule {
486
502
  signedTxs: SignedStarknetTx[], waitForConfirmation?: boolean, abortSignal?: AbortSignal,
487
503
  parallel?: boolean, onBeforePublish?: (txId: string, rawTx: string) => Promise<void>
488
504
  ): Promise<string[]> {
489
- signedTxs.forEach(val => {
490
- if(val.signed==null) throw new Error("Transactions have to be signed!");
505
+ signedTxs.forEach(tx => {
506
+ if(tx.signed==null) throw new Error("Transactions have to be signed!");
507
+ calculateHash(tx);
491
508
  });
492
509
 
493
510
  this.logger.debug("sendSignedAndConfirm(): sending transactions, count: "+signedTxs.length+
@@ -155,12 +155,12 @@ export function calculateHash(tx: StarknetTx): string {
155
155
  if(
156
156
  tx.signed.constructorCalldata==null ||
157
157
  tx.signed.addressSalt==null ||
158
- tx.tx.contractAddress==null
158
+ tx.details.walletAddress==null
159
159
  ) throw new Error("TX not enough data to compute hash!");
160
160
 
161
161
  const deployAccountData = CallData.compile(tx.signed.constructorCalldata);
162
162
  return tx.txId = hash.calculateDeployAccountTransactionHash({
163
- contractAddress: tx.tx.contractAddress,
163
+ contractAddress: tx.details.walletAddress,
164
164
  classHash: tx.signed.classHash,
165
165
  compiledConstructorCalldata: deployAccountData,
166
166
  salt: tx.signed.addressSalt,