starknet 4.13.2 → 4.14.0

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.
Files changed (46) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/CODE_OF_CONDUCT.md +128 -0
  3. package/README.md +2 -2
  4. package/__tests__/account.test.ts +38 -14
  5. package/__tests__/contract.test.ts +70 -57
  6. package/__tests__/defaultProvider.test.ts +14 -13
  7. package/__tests__/fixtures.ts +26 -27
  8. package/__tests__/rpcProvider.test.ts +19 -16
  9. package/__tests__/sequencerProvider.test.ts +47 -55
  10. package/__tests__/utils/utils.test.ts +10 -0
  11. package/dist/index.d.ts +112 -28
  12. package/dist/index.global.js +511 -453
  13. package/dist/index.global.js.map +1 -1
  14. package/dist/index.js +107 -49
  15. package/dist/index.js.map +1 -1
  16. package/dist/index.mjs +107 -49
  17. package/dist/index.mjs.map +1 -1
  18. package/index.d.ts +112 -28
  19. package/index.global.js +511 -453
  20. package/index.global.js.map +1 -1
  21. package/index.js +107 -49
  22. package/index.js.map +1 -1
  23. package/index.mjs +107 -49
  24. package/index.mjs.map +1 -1
  25. package/package.json +2 -2
  26. package/src/account/default.ts +29 -7
  27. package/src/account/interface.ts +71 -5
  28. package/src/contract/contractFactory.ts +20 -13
  29. package/src/contract/default.ts +10 -1
  30. package/src/provider/default.ts +26 -11
  31. package/src/provider/interface.ts +9 -3
  32. package/src/provider/rpc.ts +15 -11
  33. package/src/provider/sequencer.ts +11 -6
  34. package/src/provider/utils.ts +19 -11
  35. package/src/types/account.ts +21 -1
  36. package/src/types/lib.ts +5 -2
  37. package/src/types/provider.ts +0 -5
  38. package/src/utils/events.ts +32 -0
  39. package/src/utils/number.ts +6 -0
  40. package/www/docs/API/account.md +156 -2
  41. package/www/docs/API/contractFactory.md +7 -11
  42. package/www/docs/API/provider.md +5 -9
  43. package/www/docs/API/utils.md +8 -0
  44. package/www/guides/account.md +89 -38
  45. package/www/guides/erc20.md +115 -59
  46. package/www/guides/intro.md +11 -4
@@ -0,0 +1,32 @@
1
+ import { UDC } from '../constants';
2
+ import { InvokeTransactionReceiptResponse } from '../types/provider';
3
+ import { cleanHex } from './number';
4
+
5
+ /**
6
+ * Parse Transaction Receipt Event from UDC invoke transaction and
7
+ * create DeployContractResponse compatibile response with adition of UDC Event data
8
+ *
9
+ * @param txReceipt
10
+ * @returns DeployContractResponse | UDC Event Response data
11
+ */
12
+ export function parseUDCEvent(txReceipt: InvokeTransactionReceiptResponse) {
13
+ if (!txReceipt.events) {
14
+ throw new Error('UDC emited event is empty');
15
+ }
16
+ const event = txReceipt.events.find(
17
+ (it) => cleanHex(it.from_address) === cleanHex(UDC.ADDRESS)
18
+ ) || {
19
+ data: [],
20
+ };
21
+ return {
22
+ transaction_hash: txReceipt.transaction_hash,
23
+ contract_address: event.data[0],
24
+ address: event.data[0],
25
+ deployer: event.data[1],
26
+ unique: event.data[2],
27
+ classHash: event.data[3],
28
+ calldata_len: event.data[4],
29
+ calldata: event.data.slice(5, 5 + parseInt(event.data[4], 16)),
30
+ salt: event.data[event.data.length - 1],
31
+ };
32
+ }
@@ -34,6 +34,12 @@ export function toFelt(num: BigNumberish): string {
34
34
  return toBN(num).toString();
35
35
  }
36
36
 
37
+ /**
38
+ * Remove hex string leading zero and lower case '0x01A'.. -> '0x1a..'
39
+ * @param hex string
40
+ */
41
+ export const cleanHex = (hex: string) => hex.toLowerCase().replace(/^(0x)0+/, '$1');
42
+
37
43
  /*
38
44
  Asserts input is equal to or greater then lowerBound and lower then upperBound.
39
45
  Assert message specifies inputName.
@@ -6,7 +6,7 @@ sidebar_position: 2
6
6
 
7
7
  An Account extends <ins>[`Provider`](/docs/API/provider)</ins> and inherits all of its methods.
8
8
 
9
- It also introduces new methods that allow Accounts to create and verify signatures with a custom <ins>[`Signer`](/docs/API/signer)</ins>.
9
+ It also introduces new methods that allow Accounts to create and verify signatures with a custom <ins>[`Signer`](/docs/API/signer)</ins>, declare and deploy Contract and deploy new Account
10
10
 
11
11
  This API is the primary way to interact with an account contract on StarkNet.
12
12
 
@@ -89,7 +89,7 @@ The _estimateFeeDetails_ object may include any of:
89
89
 
90
90
  account.**estimateAccountDeployFee**(contractPayload [ , estimateFeeDetails ]) => _Promise < EstimateFeeResponse >_
91
91
 
92
- Estimate Fee for executing a DEPLOY_ACCOUNT transaction on starknet
92
+ Estimate Fee for executing a DEPLOY_ACCOUNT transaction on StarkNet
93
93
 
94
94
  The _contractPayload_ object structure:
95
95
 
@@ -142,6 +142,8 @@ The _transactionsDetail_ object may include any of:
142
142
 
143
143
  <hr />
144
144
 
145
+ ### Declare
146
+
145
147
  account.**declare**(contractPayload [ , transactionsDetail ]) => _Promise < DeclareContractResponse >_
146
148
 
147
149
  Declares a given compiled contract (json) to starknet.
@@ -180,6 +182,158 @@ const declareTx = await account.declare({
180
182
 
181
183
  <hr />
182
184
 
185
+ ### Deploy
186
+
187
+ Deploys a given compiled contract (json) to starknet, wrapper around _execute_ invoke function
188
+
189
+ **deploy**(deployContractPayload [ , transactionsDetail ]) => _Promise < InvokeFunctionResponse >_
190
+
191
+ @param object **_deployContractPayload_**
192
+
193
+ - **classHash**: computed class hash of compiled contract
194
+ - **constructorCalldata**: constructor calldata
195
+ - optional salt: address salt - default random
196
+ - optional unique: bool if true ensure unique salt - default true
197
+ - optional additionalCalls - optional additional calls array to support multi-call
198
+
199
+ @param object **transactionsDetail** Invocation Details
200
+
201
+ - optional nonce
202
+ - optional version
203
+ - optional maxFee
204
+
205
+ @returns **transaction_hash**
206
+
207
+ Example:
208
+
209
+ ```typescript
210
+ const deployment = await account.deploy({
211
+ classHash: erc20ClassHash,
212
+ constructorCalldata: [
213
+ encodeShortString('Token'),
214
+ encodeShortString('ERC20'),
215
+ account.address,
216
+ ],
217
+ salt: randomAddress(),
218
+ unique: true, // Using true here so as not to clash with normal erc20 deploy in account and provider test
219
+ });
220
+
221
+ await provider.waitForTransaction(deployment.transaction_hash);
222
+ ```
223
+
224
+ Example multi-call:
225
+
226
+ ```typescript
227
+ TODO Example with multi-call
228
+ ```
229
+
230
+ <hr />
231
+
232
+ ### DeployContract
233
+
234
+ ✅ NEW
235
+ High level wrapper for deploy. Doesn't require waitForTransaction. Response similar to deprecated provider deployContract.
236
+
237
+ **deployContract**(payload [ , details ]) => _Promise < DeployContractUDCResponse >_
238
+
239
+ @param object **_payload_** UniversalDeployerContractPayload
240
+
241
+ - **classHash**: computed class hash of compiled contract
242
+ - **constructorCalldata**: constructor calldata
243
+ - optional salt: address salt - default random
244
+ - optional unique: bool if true ensure unique salt - default true
245
+ - optional additionalCalls - optional additional calls array to support multi-call
246
+
247
+ @param object **details** InvocationsDetails
248
+
249
+ - optional nonce
250
+ - optional version
251
+ - optional maxFee
252
+
253
+ @returns Promise DeployContractUDCResponse
254
+
255
+ - contract_address
256
+ - transaction_hash
257
+ - address
258
+ - deployer
259
+ - unique
260
+ - classHash
261
+ - calldata_len
262
+ - calldata
263
+ - salt
264
+
265
+ Example:
266
+
267
+ ```typescript
268
+ const deployResponse = await account.deployContract({
269
+ classHash: erc20ClassHash,
270
+ constructorCalldata: [
271
+ encodeShortString('Token'),
272
+ encodeShortString('ERC20'),
273
+ account.address,
274
+ ],
275
+ });
276
+ ```
277
+
278
+ <hr />
279
+
280
+ ### DeclareDeploy
281
+
282
+ ✅ NEW
283
+ High level wrapper for declare & deploy. Doesn't require waitForTransaction. Functionality similar to deprecated provider deployContract. Declare and Deploy contract using single function.
284
+
285
+ **declareDeploy**(payload [ , details ]) => _Promise < DeclareDeployContractResponse >_
286
+
287
+ @param object **_payload_** DeclareDeployContractPayload
288
+
289
+ - **contract**: compiled contract code
290
+ - **classHash**: computed class hash of compiled contract
291
+ - optional constructorCalldata: constructor calldata
292
+ - optional salt: address salt - default random
293
+ - optional unique: bool if true ensure unique salt - default true
294
+ - optional additionalCalls - optional additional calls array to support multi-call
295
+
296
+ @param object **details** InvocationsDetails
297
+
298
+ - optional nonce
299
+ - optional version
300
+ - optional maxFee
301
+
302
+ @returns Promise object DeclareDeployContractResponse
303
+
304
+ - declare: CommonTransactionReceiptResponse
305
+ - transaction_hash
306
+ - deploy: DeployContractUDCResponse;
307
+ - contract_address
308
+ - transaction_hash
309
+ - address
310
+ - deployer
311
+ - unique
312
+ - classHash
313
+ - calldata_len
314
+ - calldata
315
+ - salt
316
+ <hr />
317
+
318
+ Example:
319
+
320
+ ```typescript
321
+ const declareDeploy = await account.declareDeploy({
322
+ contract: compiledErc20,
323
+ classHash: '0x54328a1075b8820eb43caf0caa233923148c983742402dcfc38541dd843d01a',
324
+ constructorCalldata: [
325
+ encodeShortString('Token'),
326
+ encodeShortString('ERC20'),
327
+ account.address,
328
+ ],
329
+ });
330
+
331
+ const declareTransactionHash = declareDeploy.declare.transaction_hash
332
+ const erc20Address = declareDeploy.deploy.contract_address;
333
+ ```
334
+
335
+ ### deployAccount
336
+
183
337
  account.**deployAccount**(contractPayload [ , transactionsDetail ]) => _Promise < DeployContractResponse >_
184
338
 
185
339
  Declares a given compiled contract (json) to starknet.
@@ -8,33 +8,29 @@ Contract Factory allow you to deploy contracts to StarkNet. To deploy a Contract
8
8
 
9
9
  ## Creating an instance
10
10
 
11
- `new starknet.ContractFactory( compiledContract , providerOrAccount, [ , abi ] )`
11
+ `new starknet.ContractFactory( compiledContract, classHash, account, [ , abi ] )`
12
12
 
13
13
  Creates a new instance of a ContractFactory for the contract described by the _compiledContract_.
14
14
 
15
- `contractFactory.connect(providerOrAccount)` _for changing the provider or account_
15
+ `contractFactory.connect(account)` _for changing the provider or account_
16
16
 
17
17
  `contractFactory.attach(address)` _for changing the address of the connected contract factory_
18
18
 
19
19
  ## Properties
20
20
 
21
- contractFactory.**abi** => _Abi_
21
+ contractFactory.**compiledContract** => _CompiledContract_ (the compiled contract the contractFactory was constructed with)
22
22
 
23
- The ABI the contractFactory was constructed with.
23
+ contractFactory.**classHash** => _string_ (contract classHash can be obtained using tool for compiling contract)
24
24
 
25
- contractFactory.**compiledContract** => _CompiledContract_
25
+ contractFactory.**account** => _AccountInterface_ (account that are used to interact with the network)
26
26
 
27
- The compiled contract the contractFactory was constructed with.
28
-
29
- contractFactory.**providerOrAccount** => _ProviderInterface | AccountInterface_
30
-
31
- Provider or account that are used to interact with the network.
27
+ contractFactory.**abi** => _Abi_ (the ABI the contractFactory was constructed with)
32
28
 
33
29
  ## Methods
34
30
 
35
31
  contractFactory.**attach**( address ) ⇒ _Contract_
36
32
 
37
- Return an instance of a _Contract_ attached to address. This is the same as using the _Contract_ constructor with address and this _compiledContract_ and _providerOrAccount_ passed in when creating the ContractFactory.
33
+ Return an instance of a _Contract_ attached to address. This is the same as using the _Contract_ constructor with address and this _compiledContract_ and _account_ passed in when creating the ContractFactory.
38
34
 
39
35
  <hr />
40
36
 
@@ -141,9 +141,9 @@ Estimate fee for invoke transaction.
141
141
 
142
142
  <hr/>
143
143
 
144
- provider.**getNonce**(contractAddress, blockIdentifier) => _Promise < BigNumberish >_
144
+ provider.**getNonceForAddress**(contractAddress, blockIdentifier) => _Promise < BigNumberish >_
145
145
 
146
- Gets the nonce of the provided contractAddress.
146
+ Gets the nonce of the provided contractAddress. This was renamed from `getNonce` to `getNonceForAddress` to avoid confusion when inheriting an Account from the Provider class.
147
147
 
148
148
  <hr/>
149
149
 
@@ -242,7 +242,9 @@ Estimate fee for declare transaction.
242
242
 
243
243
  <hr/>
244
244
 
245
- provider.**waitForTransaction**(txHash [ , retryInterval]) => _Promise < void >_
245
+ ### waitForTransaction
246
+
247
+ provider.**waitForTransaction**(txHash [ , retryInterval]) => _Promise < GetTransactionReceiptResponse >_
246
248
 
247
249
  Wait for the transaction to be accepted on L2 or L1.
248
250
 
@@ -476,12 +478,6 @@ Gets the latest block number.
476
478
 
477
479
  <hr/>
478
480
 
479
- provider.**getNonce**(contractAddress, blockIdentifier) => _Promise < BigNumberish >_
480
-
481
- Gets the nonce of the provided contractAddress
482
-
483
- <hr/>
484
-
485
481
  provider.**getPendingTransactions**() => _Promise < PendingTransactions >_
486
482
 
487
483
  ###### _PendingTransactions_
@@ -136,6 +136,14 @@ Converts BN to hex.
136
136
 
137
137
  Returns a string.
138
138
 
139
+ ### cleanHex
140
+
141
+ `cleanHex(hex: string): string`
142
+
143
+ Remove leading zeroes and lowercase hex string after '0x'
144
+
145
+ `0x01AFF` -> `0x1aff`
146
+
139
147
  ### hexToDecimalString
140
148
 
141
149
  `hexToDecimalString(hex: string): string`
@@ -8,9 +8,22 @@ Since there are no Externally Owned Accounts (EOA) in StarkNet, all Accounts in
8
8
 
9
9
  Unlike in Ethereum where a wallet is created with a public and private key pair, StarkNet Accounts are the only way to sign transactions and messages, and verify signatures. Therefore a Account - Contract interface is needed.
10
10
 
11
- ## Install and import StarkNet
11
+ > Account contracts on StarkNet cannot be deployed without paying a fee.
12
12
 
13
- Install the latest version of starknet with `npm install starknet@next`
13
+ High level explanations from StarkWare can be found in this Notion [page](https://starkware.notion.site/Deploy-a-contract-and-an-account-on-StarkNet-ed2fd13301d2414e8223bb72bb90e386), but in short, the process is:
14
+
15
+ 1. Decide on your account type (OpenZeppelin, Argent, ...)
16
+ 2. Compute the address of our would-be account off-chain (adressess on StarkNet are deterministic)
17
+ 3. Send funds to this pre-computed address. The funds will be used to pay for the account contract deployment
18
+ 4. Actual deployment of the Account
19
+
20
+ ## Install and setup
21
+
22
+ Install the latest version of starknet with
23
+
24
+ `npm install starknet@next`
25
+
26
+ Imports example:
14
27
 
15
28
  ```javascript
16
29
  import fs from "fs";
@@ -21,69 +34,107 @@ import {
21
34
  ec,
22
35
  json,
23
36
  number,
37
+ hash
24
38
  } from "starknet";
25
39
  ```
26
40
 
27
- ## Generate random key pair.
41
+ Starknet.js currently doesn't have the functionality to calculate the class hash needed for the account deployment, so we need to calculate it with some other tool, for example: [Starkli](https://github.com/xJonathanLEI/starkli)
42
+
43
+ ```javascript
44
+ // class hash of OpenZeppelin Account contract version 0.5.1
45
+ const OZContractClassHash = '0x058d97f7d76e78f44905cc30cb65b91ea49a4b908a76703c54197bca90f81773';
46
+ ```
47
+
48
+ ```javascript
49
+ // get the compiled contract ABI, in this case OpenZeppelin
50
+ const compiledOZAccount = json.parse(
51
+ fs.readFileSync("./Account.json").toString("ascii")
52
+ );
53
+ ```
28
54
 
29
- You can also get a key pair from a private key using `getKeyPair(pk: BigNumberish)`
55
+ ## Generate random key pair
30
56
 
31
57
  ```javascript
32
58
  const starkKeyPair = ec.genKeyPair();
33
59
  const starkKeyPub = ec.getStarkKey(starkKeyPair);
34
60
  ```
35
61
 
36
- ## Deploy Account Contract
62
+ You can also get a key pair from a private key using:
37
63
 
38
- Deploy the Account contract and wait for it to be verified on StarkNet.
64
+ `getKeyPair(pk: BigNumberish)`
39
65
 
40
66
  ```javascript
41
- const compiledAccount = json.parse(
42
- fs.readFileSync("./Account.json").toString("ascii")
43
- );
67
+ const privateKey = '0x-Some-Existing-Private-Key'; // you can use stark.randomAddress();
68
+ const starkKeyPair = ec.getKeyPair(privateKey);
69
+ const starkKeyPub = ec.getStarkKey(starkKeyPair);
44
70
  ```
45
71
 
46
- > **Note**
47
- >
48
- > below example uses [Argent's](https://github.com/argentlabs/argent-contracts-starknet/blob/develop/contracts/account/ArgentAccount.cairo) account contract
72
+ ## Pre-compute address of the Account
49
73
 
50
74
  ```javascript
51
- const accountResponse = await defaultProvider.deployContract({
52
- contract: compiledAccount,
53
- addressSalt: starkKeyPub,
54
- });
75
+ const precalculatedAddress = hash.calculateContractAddressFromHash(
76
+ starkKeyPub, // salt
77
+ OZContractClassHash,
78
+ [starkKeyPub],
79
+ 0
80
+ );
55
81
  ```
56
82
 
57
- > **Note**
58
- >
59
- > below example uses [OpenZeppelin's](https://github.com/OpenZeppelin/cairo-contracts/blob/main/src/openzeppelin/account/presets/Account.cairo) account contract
83
+ ## Funding options for the pre-computed address
60
84
 
61
- ```javascript
62
- const accountResponse = await defaultProvider.deployContract({
63
- contract: compiledAccount,
64
- constructorCalldata: [starkKeyPub],
65
- addressSalt: starkKeyPub,
66
- });
85
+ 1. TESTNET
86
+
87
+ You can do so by using a faucet: https://faucet.goerli.starknet.io/
88
+
89
+ 2. DEVNET
90
+
91
+ Address is the newly `precalculatedAddress`.
92
+
93
+ ```bash
94
+ curl -X POST http://127.0.0.1:5050/mint -d '{"address":"0x04a093c37ab61065d001550089b1089922212c60b34e662bb14f2f91faee2979","amount":50000000000000000000,"lite":true}' -H "Content-Type:application/json"
95
+ // {"new_balance":50000000000000000000,"tx_hash":null,"unit":"wei"}
67
96
  ```
68
97
 
69
- ## Use your new account
98
+ 3. Send funds from an already existing account
70
99
 
71
- Wait for the deployment transaction to be accepted and assign the address of the deployed account to the Account object.
100
+ ## OPTIONAL - Declare Account
101
+
102
+ > NOTE: This step will fail if you haven't sent funds to the pre-calculated address.
103
+
104
+ We need to use an already deployed account in order to declare ours. StarkNet will always have at least 1 already declared/deployed account for this purpose.
72
105
 
73
106
  ```javascript
74
- await defaultProvider.waitForTransaction(accountResponse.transaction_hash);
75
- ```
107
+ // In this case we will use the devnet's predeployed OZ account, after you start the devnet with: `starknet-devnet --seed 0`
108
+ const devnetPrivateKey = '0xe3e70682c2094cac629f6fbed82c07cd';
109
+ const devnetAccount0Address = '0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a';
110
+ const devnetKeyPair = ec.getKeyPair(devnetPrivateKey);
76
111
 
77
- Once account contract is deployed [Account](../docs/API/account.md) instance can be created. Use your new account instance to sign transactions, messages or verify signatures!
112
+ const predeployedAccount = new Account(provider, devnetAccount0Address, devnetKeyPair);
78
113
 
79
- ```js
80
- const account = new Account(
81
- defaultProvider,
82
- accountResponse.contract_address,
83
- starkKeyPair
84
- );
114
+ const declareTx = await predeployedAccount.declare({
115
+ classHash: OZContractClassHash,
116
+ contract: compiledOZAccount
117
+ });
118
+
119
+ await provider.waitForTransaction(declareTx.transaction_hash);
85
120
  ```
86
121
 
87
- ## Fund your new account!
122
+ ## Deploy Account Contract
123
+
124
+ Deploy the Account contract and wait for it to be verified on StarkNet.
125
+
126
+ > NOTE: This step will fail if you haven't sent funds to the pre-calculated address.
88
127
 
89
- Make sure your Account has enough funds to execute invocations. Use this [faucet](https://faucet.goerli.starknet.io/) for funding on testnet.
128
+ ```javascript
129
+ const account = new Account(provider, precalculatedAddress, starkKeyPair);
130
+
131
+ // This is OpenZeppelin account contract deployment
132
+ const accountResponse = await account.deployAccount({
133
+ classHash: OZContractClassHash,
134
+ constructorCalldata: [starkKeyPub],
135
+ contractAddress: precalculatedAddress,
136
+ addressSalt: starkKeyPub
137
+ });
138
+
139
+ await provider.waitForTransaction(accountResponse.transaction_hash);
140
+ ```