starknet 4.3.0 → 4.3.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.
- package/CHANGELOG.md +16 -1
- package/__tests__/defaultProvider.test.ts +11 -24
- package/__tests__/rpcProvider.test.ts +3 -3
- package/__tests__/sequencerProvider.test.ts +9 -1
- package/dist/provider/default.d.ts +2 -2
- package/dist/provider/default.js +3 -3
- package/dist/provider/interface.d.ts +6 -3
- package/dist/provider/rpc.d.ts +9 -4
- package/dist/provider/rpc.js +67 -25
- package/dist/provider/sequencer.d.ts +2 -2
- package/dist/provider/sequencer.js +4 -4
- package/dist/provider/utils.d.ts +12 -0
- package/dist/provider/utils.js +17 -1
- package/dist/types/api/openrpc.d.ts +151 -0
- package/dist/types/api/openrpc.js +9 -0
- package/dist/types/api/rpc.d.ts +22 -43
- package/dist/types/provider.d.ts +5 -5
- package/dist/utils/ellipticCurve.d.ts +13 -0
- package/dist/utils/ellipticCurve.js +20 -16
- package/dist/utils/responseParser/rpc.d.ts +13 -3
- package/dist/utils/responseParser/rpc.js +2 -10
- package/dist/utils/responseParser/sequencer.d.ts +4 -1
- package/dist/utils/responseParser/sequencer.js +1 -7
- package/package.json +1 -1
- package/provider/default.d.ts +2 -2
- package/provider/default.js +3 -3
- package/provider/interface.d.ts +6 -3
- package/provider/rpc.d.ts +9 -4
- package/provider/rpc.js +67 -25
- package/provider/sequencer.d.ts +2 -2
- package/provider/sequencer.js +4 -4
- package/provider/utils.d.ts +12 -0
- package/provider/utils.js +17 -1
- package/src/provider/default.ts +2 -3
- package/src/provider/interface.ts +5 -3
- package/src/provider/rpc.ts +56 -34
- package/src/provider/sequencer.ts +3 -6
- package/src/provider/utils.ts +22 -1
- package/src/types/api/openrpc.ts +168 -0
- package/src/types/api/rpc.ts +22 -45
- package/src/types/provider.ts +5 -5
- package/src/utils/ellipticCurve.ts +20 -16
- package/src/utils/responseParser/rpc.ts +16 -13
- package/src/utils/responseParser/sequencer.ts +5 -8
- package/types/api/openrpc.d.ts +151 -0
- package/types/api/openrpc.js +9 -0
- package/types/api/rpc.d.ts +22 -43
- package/types/provider.d.ts +5 -5
- package/utils/ellipticCurve.d.ts +13 -0
- package/utils/ellipticCurve.js +20 -16
- package/utils/responseParser/rpc.d.ts +13 -3
- package/utils/responseParser/rpc.js +2 -10
- package/utils/responseParser/sequencer.d.ts +4 -1
- package/utils/responseParser/sequencer.js +1 -7
- package/www/docs/API/account.md +20 -18
- package/www/docs/API/contract.md +10 -10
- package/www/docs/API/contractFactory.md +14 -11
- package/www/docs/API/provider.md +29 -63
- package/www/docs/API/signer.md +8 -10
- package/www/docs/API/utils.md +151 -74
- package/www/guides/account.md +5 -5
- package/www/guides/erc20.md +20 -4
- package/www/guides/intro.md +3 -1
package/www/docs/API/utils.md
CHANGED
|
@@ -4,19 +4,21 @@ sidebar_position: 6
|
|
|
4
4
|
|
|
5
5
|
# Utils
|
|
6
6
|
|
|
7
|
-
Util functions are provided so you can use low level functions in your application.
|
|
7
|
+
Util functions are provided so you can use various low level functions in your application.
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## **address**
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Helper functions for starknet addresses.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
import { address } from 'starknet.js';
|
|
15
|
-
```
|
|
13
|
+
### validateAndParseAddress
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
`validateAndParseAddress(address: BigNumberish): string`
|
|
18
16
|
|
|
19
|
-
|
|
17
|
+
Checks if the address is valid and, if it is, parses it to the correct format (0x prefix is added if not provided).
|
|
18
|
+
|
|
19
|
+
### getChecksumAddress
|
|
20
|
+
|
|
21
|
+
`getChecksumAddress(address: BigNumberish): string`
|
|
20
22
|
|
|
21
23
|
This function accepts an address as a `BigNumberish` and returns the checksummed address as a string.
|
|
22
24
|
An example:
|
|
@@ -31,47 +33,53 @@ const checksummedAddress = address.getChecksumAddress(addressToCheck);
|
|
|
31
33
|
console.log(checksummedAddress); // 0x02FD23D9182193775423497Fc0c472E156C57C69E4089a1967fb288a2D84e914
|
|
32
34
|
```
|
|
33
35
|
|
|
34
|
-
|
|
36
|
+
### validateChecksumAddress
|
|
37
|
+
|
|
38
|
+
`validateChecksumAddress(address: string): boolean`
|
|
35
39
|
|
|
36
|
-
|
|
40
|
+
This function validates the checksum address.
|
|
37
41
|
|
|
38
|
-
|
|
42
|
+
Returns true if the address is valid, false otherwise.
|
|
39
43
|
|
|
40
44
|
<hr />
|
|
41
45
|
|
|
42
|
-
##
|
|
46
|
+
## **stark**
|
|
43
47
|
|
|
44
48
|
Functions for stark specific manipulations.
|
|
45
49
|
|
|
46
|
-
|
|
50
|
+
### compressProgram
|
|
47
51
|
|
|
48
|
-
|
|
52
|
+
`compressProgram(jsonProgram: Program | string): CompressedProgram`
|
|
49
53
|
|
|
50
54
|
Function to compress compiled cairo program. Accepts a json file representing the compiled cairo program and returns a compressed cairo program.
|
|
51
55
|
|
|
52
|
-
|
|
56
|
+
### randomAddress
|
|
53
57
|
|
|
54
|
-
|
|
58
|
+
`randomAddress(): string`
|
|
55
59
|
|
|
56
|
-
Function that generates a random
|
|
60
|
+
Function that generates a random stark address.
|
|
57
61
|
|
|
58
|
-
|
|
62
|
+
### makeAddress
|
|
59
63
|
|
|
60
|
-
|
|
64
|
+
`makeAddress(input: string): string`
|
|
61
65
|
|
|
62
|
-
Function that turns an incompatible address string into stark address format.
|
|
66
|
+
Function that turns an incompatible address string into stark address format.
|
|
67
|
+
|
|
68
|
+
Returns a string.
|
|
63
69
|
|
|
64
70
|
Example: `0xdFD0F27FCe99b50909de0bDD328Aed6eAbe76BC5` -> `0xdfd0f27fce99b50909de0bdd328aed6eabe76bc5`
|
|
65
71
|
|
|
66
|
-
|
|
72
|
+
### formatSignature
|
|
73
|
+
|
|
74
|
+
`formatSignature(sig?: Signature): string[]`
|
|
67
75
|
|
|
68
|
-
|
|
76
|
+
Function that formats a Signature to BigNum and then to string array.
|
|
69
77
|
|
|
70
|
-
|
|
78
|
+
Returns a string array.
|
|
71
79
|
|
|
72
|
-
|
|
80
|
+
### compileCalldata
|
|
73
81
|
|
|
74
|
-
|
|
82
|
+
`compileCalldata(args: RawArgs): Calldata`
|
|
75
83
|
|
|
76
84
|
Function that creates calldata that gets sent to the contract.
|
|
77
85
|
|
|
@@ -86,9 +94,9 @@ await this.callContract({
|
|
|
86
94
|
});
|
|
87
95
|
```
|
|
88
96
|
|
|
89
|
-
|
|
97
|
+
### estimatedFeeToMaxFee
|
|
90
98
|
|
|
91
|
-
|
|
99
|
+
`estimatedFeeToMaxFee(estimatedFee: BigNumberish, overhead: number = 0.5): BN`
|
|
92
100
|
|
|
93
101
|
Function that calculates and returns maximum fee based on the previously estimated one.
|
|
94
102
|
|
|
@@ -96,7 +104,7 @@ Returns a BN.
|
|
|
96
104
|
|
|
97
105
|
<hr />
|
|
98
106
|
|
|
99
|
-
##
|
|
107
|
+
## **number**
|
|
100
108
|
|
|
101
109
|
Various number formatting functions.
|
|
102
110
|
|
|
@@ -106,47 +114,53 @@ Various number formatting functions.
|
|
|
106
114
|
export type BigNumberish = string | number | BN;
|
|
107
115
|
```
|
|
108
116
|
|
|
109
|
-
|
|
117
|
+
### isHex
|
|
110
118
|
|
|
111
|
-
|
|
119
|
+
`isHex(hex: string): boolean`
|
|
112
120
|
|
|
113
121
|
Check if number is in hex format.
|
|
114
122
|
|
|
115
|
-
|
|
123
|
+
### toBN
|
|
124
|
+
|
|
125
|
+
`toBN(number: BigNumberish, base?: number | 'hex'): BN`
|
|
116
126
|
|
|
117
|
-
|
|
127
|
+
Converts BigNumberish to BN.
|
|
118
128
|
|
|
119
|
-
|
|
129
|
+
Returns a BN.
|
|
130
|
+
|
|
131
|
+
### toHex
|
|
120
132
|
|
|
121
|
-
|
|
133
|
+
`toHex(number: BN): string`
|
|
122
134
|
|
|
123
|
-
|
|
135
|
+
Converts BN to hex.
|
|
124
136
|
|
|
125
|
-
|
|
137
|
+
Returns a string.
|
|
126
138
|
|
|
127
|
-
|
|
139
|
+
### hexToDecimalString
|
|
128
140
|
|
|
129
|
-
|
|
141
|
+
`hexToDecimalString(hex: string): string`
|
|
130
142
|
|
|
131
143
|
Converts hex string to decimal string.
|
|
132
144
|
|
|
133
|
-
|
|
145
|
+
### toFelt
|
|
146
|
+
|
|
147
|
+
`toFelt(num: BigNumberish): string`
|
|
134
148
|
|
|
135
|
-
|
|
149
|
+
Converts BN to Felt.
|
|
136
150
|
|
|
137
|
-
|
|
151
|
+
Returns a string.
|
|
138
152
|
|
|
139
|
-
|
|
153
|
+
### assertInRange
|
|
140
154
|
|
|
141
|
-
|
|
155
|
+
`assertInRange(input: BigNumberish, lowerBound: BigNumberish, upperBound: BigNumberish, inputName = '')`
|
|
142
156
|
|
|
143
157
|
Asserts input is equal to or greater then `lowerBound` and lower then `upperBound`. Assert message specifies inputName.
|
|
144
158
|
`input`, `lowerBound`, and `upperBound` should be of type BN.
|
|
145
159
|
`inputName` should be a string.
|
|
146
160
|
|
|
147
|
-
|
|
161
|
+
### bigNumberishArrayToDecimalStringArray
|
|
148
162
|
|
|
149
|
-
|
|
163
|
+
`bigNumberishArrayToDecimalStringArray(rawCalldata: BigNumberish[]): string[]`
|
|
150
164
|
|
|
151
165
|
Convert BigNumberish array to decimal array. Used for signature conversion.
|
|
152
166
|
|
|
@@ -164,7 +178,7 @@ const signature = await this.signer.signTransaction(transactions, signerDetails)
|
|
|
164
178
|
|
|
165
179
|
<hr />
|
|
166
180
|
|
|
167
|
-
##
|
|
181
|
+
## **uint256**
|
|
168
182
|
|
|
169
183
|
```js
|
|
170
184
|
// Represents an integer in the range [0, 2^256).
|
|
@@ -176,74 +190,81 @@ export interface Uint256 {
|
|
|
176
190
|
}
|
|
177
191
|
```
|
|
178
192
|
|
|
179
|
-
|
|
193
|
+
### uint256ToBN
|
|
180
194
|
|
|
181
|
-
|
|
195
|
+
`uint256ToBN(uint256: Uint256): BN`
|
|
182
196
|
|
|
183
197
|
Function to convert `Uint256` to `BN` (big number), which uses the `bn.js` library.
|
|
184
198
|
|
|
185
|
-
|
|
199
|
+
### isUint256
|
|
186
200
|
|
|
187
|
-
|
|
201
|
+
`isUint256(bn: BigNumberish): boolean`
|
|
188
202
|
|
|
189
203
|
Function to check if `BN` is smaller or equal to `2**256-1`.
|
|
190
204
|
|
|
191
|
-
|
|
205
|
+
### bnToUint256
|
|
192
206
|
|
|
193
|
-
|
|
207
|
+
`bnToUint256(bignumber: BigNumberish): Uint256`
|
|
194
208
|
|
|
195
209
|
Function to convert `BN` to `Uint256`.
|
|
196
210
|
|
|
197
211
|
<hr />
|
|
198
212
|
|
|
199
|
-
##
|
|
213
|
+
## **hash**
|
|
200
214
|
|
|
201
215
|
Various hashing helpers.
|
|
202
216
|
|
|
203
|
-
###
|
|
217
|
+
### starknetKeccak
|
|
218
|
+
|
|
219
|
+
`starknetKeccak(value: string): BN`
|
|
204
220
|
|
|
205
221
|
Function to get the starknet keccak hash from a string. Returns starknet keccak hash as BigNumber.
|
|
206
|
-
nction to get the starknet keccak hash from a string. Returns starknet keccak hash as BigNumber.
|
|
207
222
|
|
|
208
|
-
|
|
223
|
+
Returns starknet keccak hash as BigNumber.
|
|
224
|
+
|
|
225
|
+
### getSelectorFromName
|
|
226
|
+
|
|
227
|
+
`getSelectorFromName(funcName: string)`
|
|
209
228
|
|
|
210
|
-
|
|
229
|
+
Function to get the hex selector from a given function name.
|
|
211
230
|
|
|
212
|
-
|
|
231
|
+
Returns hex selector of given abi function name.
|
|
213
232
|
|
|
214
|
-
|
|
233
|
+
### pedersen
|
|
215
234
|
|
|
216
|
-
|
|
235
|
+
`pedersen(input: [BigNumberish, BigNumberish])`
|
|
217
236
|
|
|
218
|
-
|
|
237
|
+
Function to get the Pedersen hash for two arguments.
|
|
219
238
|
|
|
220
|
-
|
|
239
|
+
Returns a string.
|
|
221
240
|
|
|
222
|
-
###
|
|
241
|
+
### computeHashOnElements
|
|
223
242
|
|
|
224
|
-
|
|
243
|
+
`computeHashOnElements(data: BigNumberish[])`
|
|
225
244
|
|
|
226
|
-
Function to compute a Pedersen hash on a array of elements.
|
|
245
|
+
Function to compute a Pedersen hash on a array of elements.
|
|
227
246
|
|
|
228
|
-
|
|
247
|
+
Returns a string.
|
|
229
248
|
|
|
230
|
-
###
|
|
249
|
+
### calculateTransactionHashCommon
|
|
250
|
+
|
|
251
|
+
`calculateTransactionHashCommon(txHashPrefix: TransactionHashPrefix, version: BigNumberish,contractAddress: BigNumberish, entryPointSelector: BigNumberish, calldata: BigNumberish[], maxFee: BigNumberish, chainId: StarknetChainId, additionalData: BigNumberish[] = []): string`
|
|
231
252
|
|
|
232
253
|
Calculates the transaction hash in the StarkNet network - a unique identifier of the transaction.
|
|
233
254
|
|
|
234
255
|
Called internally in `calculateDeployTransactionHash` and `calculcateTransactionHash`.
|
|
235
256
|
|
|
236
|
-
|
|
257
|
+
### calculateDeployTransactionHash
|
|
237
258
|
|
|
238
|
-
|
|
259
|
+
`calculateDeployTransactionHash(contractAddress: BigNumberish, constructorCalldata: BigNumberish[], version: BigNumberish, chainId: StarknetChainId): string`
|
|
239
260
|
|
|
240
261
|
Function that calculates the deployment transaction hash in the StarkNet network.
|
|
241
262
|
|
|
242
263
|
Internally calls `calculateTransactionHashCommon` with `TransactionHashPrefix.DEPLOY`.
|
|
243
264
|
|
|
244
|
-
|
|
265
|
+
### calculcateTransactionHash
|
|
245
266
|
|
|
246
|
-
|
|
267
|
+
`calculcateTransactionHash(contractAddress: BigNumberish, version: BigNumberish, entryPointSelector: BigNumberish, calldata: BigNumberish[], maxFee: BigNumberish, chainId: StarknetChainId): string`
|
|
247
268
|
|
|
248
269
|
Function that internally calls `calculateTransactionHashCommon`, with `TransactionHashPrefix.INVOKE`.
|
|
249
270
|
|
|
@@ -258,8 +279,64 @@ const hashMsg = calculcateTransactionHash(
|
|
|
258
279
|
);
|
|
259
280
|
```
|
|
260
281
|
|
|
261
|
-
|
|
282
|
+
### calculateContractAddressFromHash
|
|
283
|
+
|
|
284
|
+
`calculateContractAddressFromHash(salt: BigNumberish, classHash: BigNumberish, constructorCalldata: RawCalldata, deployerAddress: BigNumberish)`
|
|
285
|
+
|
|
286
|
+
Function that calculates contract address from hash.
|
|
287
|
+
|
|
288
|
+
Returns a string.
|
|
289
|
+
|
|
290
|
+
<hr />
|
|
291
|
+
|
|
292
|
+
## **ellipticCurve**
|
|
293
|
+
|
|
294
|
+
Wrapper around the javascript `elliptic` library with additional functionality.
|
|
295
|
+
|
|
296
|
+
### genKeyPair
|
|
297
|
+
|
|
298
|
+
`ec.genKeyPair()`
|
|
299
|
+
|
|
300
|
+
Generate a random key pair.
|
|
301
|
+
|
|
302
|
+
### getKeyPair
|
|
303
|
+
|
|
304
|
+
`getKeyPair(pk: BigNumberish): KeyPair`
|
|
305
|
+
|
|
306
|
+
Get a key pair from a private key.
|
|
307
|
+
|
|
308
|
+
### getStarkKey
|
|
309
|
+
|
|
310
|
+
`getStarkKey(keyPair: KeyPair): string`
|
|
311
|
+
|
|
312
|
+
Public key defined over a Stark-friendly elliptic curve that is different from the standard Ethereum elliptic curve
|
|
313
|
+
|
|
314
|
+
### getKeyPairFromPublicKey
|
|
315
|
+
|
|
316
|
+
`getKeyPairFromPublicKey(publicKey: BigNumberish): KeyPair`
|
|
317
|
+
|
|
318
|
+
Takes a public key and casts it into `elliptic` KeyPair format.
|
|
319
|
+
|
|
320
|
+
Returns keyPair with public key only, which can be used to verify signatures, but can't sign anything.
|
|
321
|
+
|
|
322
|
+
### sign
|
|
323
|
+
|
|
324
|
+
`sign(keyPair: KeyPair, msgHash: string): Signature`
|
|
325
|
+
|
|
326
|
+
Signs a message using the provided key.
|
|
327
|
+
|
|
328
|
+
keyPair should be an KeyPair with a valid private key.
|
|
329
|
+
|
|
330
|
+
Returns an Signature.
|
|
331
|
+
|
|
332
|
+
### verify
|
|
333
|
+
|
|
334
|
+
`verify(keyPair: KeyPair | KeyPair[], msgHash: string, sig: Signature): boolean`
|
|
335
|
+
|
|
336
|
+
Verifies a message using the provided key.
|
|
337
|
+
|
|
338
|
+
keyPair should be an KeyPair with a valid public key.
|
|
262
339
|
|
|
263
|
-
|
|
340
|
+
sig should be an Signature.
|
|
264
341
|
|
|
265
|
-
|
|
342
|
+
Returns true if the verification succeeds.
|
package/www/guides/account.md
CHANGED
|
@@ -76,14 +76,14 @@ await defaultProvider.waitForTransaction(accountResponse.transaction_hash);
|
|
|
76
76
|
|
|
77
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!
|
|
78
78
|
|
|
79
|
-
> **Note**
|
|
80
|
-
>
|
|
81
|
-
> Make sure your Account has enough funds to execute invocations. Use this [faucet](https://faucet.goerli.starknet.io/) for funding on testnet.
|
|
82
|
-
|
|
83
79
|
```js
|
|
84
80
|
const account = new Account(
|
|
85
81
|
defaultProvider,
|
|
86
|
-
accountResponse.
|
|
82
|
+
accountResponse.contract_address,
|
|
87
83
|
starkKeyPair
|
|
88
84
|
);
|
|
89
85
|
```
|
|
86
|
+
|
|
87
|
+
## Fund your new account!
|
|
88
|
+
|
|
89
|
+
Make sure your Account has enough funds to execute invocations. Use this [faucet](https://faucet.goerli.starknet.io/) for funding on testnet.
|
package/www/guides/erc20.md
CHANGED
|
@@ -20,26 +20,42 @@ await defaultProvider.waitForTransaction(erc20Response.transaction_hash);
|
|
|
20
20
|
## Get the erc20 contract address and create the contact object
|
|
21
21
|
|
|
22
22
|
```javascript
|
|
23
|
-
const erc20Address = erc20Response.
|
|
24
|
-
const erc20 = new Contract(compiledErc20.abi, erc20Address);
|
|
23
|
+
const erc20Address = erc20Response.contract_address;
|
|
24
|
+
const erc20 = new Contract(compiledErc20.abi, erc20Address, defaultProvider);
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
|
|
27
28
|
## Mint tokens to an account address
|
|
28
29
|
|
|
29
30
|
Make sure you created the `Account` instance following the [Creating an Account](./account.md) guide.
|
|
30
31
|
|
|
32
|
+
Also make sure you added funds to your account!
|
|
33
|
+
|
|
31
34
|
```javascript
|
|
32
35
|
erc20.connect(account);
|
|
33
36
|
|
|
34
37
|
const { transaction_hash: mintTxHash } = await erc20.mint(
|
|
35
38
|
account.address,
|
|
36
|
-
"1000"
|
|
39
|
+
"1000",
|
|
40
|
+
{
|
|
41
|
+
maxFee: "1"
|
|
42
|
+
}
|
|
37
43
|
);
|
|
38
44
|
|
|
39
45
|
console.log(`Waiting for Tx to be Accepted on Starknet - Minting...`);
|
|
40
46
|
await defaultProvider.waitForTransaction(mintTxHash);
|
|
41
47
|
```
|
|
42
48
|
|
|
49
|
+
> **Note**
|
|
50
|
+
>
|
|
51
|
+
> Transaction can be rejected if `maxFee` is lower than actual.
|
|
52
|
+
>
|
|
53
|
+
> _Error: REJECTED: FEE_TRANSFER_FAILURE_
|
|
54
|
+
>
|
|
55
|
+
> _Actual fee exceeded max fee._
|
|
56
|
+
>
|
|
57
|
+
> If this occurs, set `maxFee` to a higher value, for example: 999999995330000
|
|
58
|
+
|
|
43
59
|
## Check balance after mint
|
|
44
60
|
|
|
45
61
|
```javascript
|
|
@@ -64,7 +80,7 @@ const { transaction_hash: transferTxHash } = await account.execute(
|
|
|
64
80
|
calldata: [erc20Address, "10"],
|
|
65
81
|
},
|
|
66
82
|
undefined,
|
|
67
|
-
{ maxFee: "
|
|
83
|
+
{ maxFee: "1" }
|
|
68
84
|
);
|
|
69
85
|
|
|
70
86
|
// Wait for the invoke transaction to be accepted on StarkNet
|
package/www/guides/intro.md
CHANGED
|
@@ -16,6 +16,8 @@ npm install starknet@next
|
|
|
16
16
|
|
|
17
17
|
Please check the StarkNet documentation <ins>[here](https://www.cairo-lang.org/docs/hello_starknet/intro.html)</ins> to compile starknet contracts.
|
|
18
18
|
|
|
19
|
+
Additional helpful resources can also be found at [OpenZeppelin](https://docs.openzeppelin.com/contracts-cairo/0.3.1/) documentation site.
|
|
20
|
+
|
|
19
21
|
## Full example with account & erc20
|
|
20
22
|
|
|
21
|
-
Please
|
|
23
|
+
Please take a look at our workshop <ins>[here](https://github.com/0xs34n/starknet.js-workshop)</ins>.
|