starknet 4.13.2 → 4.15.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.
- package/CHANGELOG.md +39 -0
- package/CODE_OF_CONDUCT.md +128 -0
- package/README.md +2 -2
- package/__mocks__/naming_compiled.json +53283 -0
- package/__mocks__/starknetId_compiled.json +44703 -0
- package/__tests__/account.test.ts +100 -15
- package/__tests__/contract.test.ts +70 -57
- package/__tests__/defaultProvider.test.ts +14 -13
- package/__tests__/fixtures.ts +27 -26
- package/__tests__/rpcProvider.test.ts +19 -16
- package/__tests__/sequencerProvider.test.ts +47 -55
- package/__tests__/utils/starknetId.test.ts +53 -0
- package/__tests__/utils/utils.test.ts +10 -0
- package/dist/index.d.ts +116 -30
- package/dist/index.global.js +660 -463
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +247 -51
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +247 -51
- package/dist/index.mjs.map +1 -1
- package/index.d.ts +116 -30
- package/index.global.js +660 -463
- package/index.global.js.map +1 -1
- package/index.js +247 -51
- package/index.js.map +1 -1
- package/index.mjs +247 -51
- package/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/account/default.ts +81 -8
- package/src/account/interface.ts +71 -5
- package/src/contract/contractFactory.ts +20 -13
- package/src/contract/default.ts +11 -2
- package/src/provider/default.ts +26 -11
- package/src/provider/interface.ts +9 -3
- package/src/provider/rpc.ts +15 -11
- package/src/provider/sequencer.ts +32 -20
- package/src/provider/utils.ts +19 -11
- package/src/types/account.ts +21 -1
- package/src/types/lib.ts +5 -2
- package/src/types/provider.ts +0 -5
- package/src/utils/events.ts +32 -0
- package/src/utils/number.ts +6 -0
- package/src/utils/starknetId.ts +116 -0
- package/www/docs/API/account.md +176 -2
- package/www/docs/API/contractFactory.md +7 -11
- package/www/docs/API/provider.md +5 -9
- package/www/docs/API/utils.md +8 -0
- package/www/guides/account.md +89 -38
- package/www/guides/erc20.md +115 -59
- package/www/guides/intro.md +11 -4
package/www/docs/API/utils.md
CHANGED
|
@@ -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`
|
package/www/guides/account.md
CHANGED
|
@@ -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
|
-
|
|
11
|
+
> Account contracts on StarkNet cannot be deployed without paying a fee.
|
|
12
12
|
|
|
13
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
62
|
+
You can also get a key pair from a private key using:
|
|
37
63
|
|
|
38
|
-
|
|
64
|
+
`getKeyPair(pk: BigNumberish)`
|
|
39
65
|
|
|
40
66
|
```javascript
|
|
41
|
-
const
|
|
42
|
-
|
|
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
|
-
|
|
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
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
75
|
+
const precalculatedAddress = hash.calculateContractAddressFromHash(
|
|
76
|
+
starkKeyPub, // salt
|
|
77
|
+
OZContractClassHash,
|
|
78
|
+
[starkKeyPub],
|
|
79
|
+
0
|
|
80
|
+
);
|
|
55
81
|
```
|
|
56
82
|
|
|
57
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
98
|
+
3. Send funds from an already existing account
|
|
70
99
|
|
|
71
|
-
|
|
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
|
-
|
|
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
|
-
|
|
112
|
+
const predeployedAccount = new Account(provider, devnetAccount0Address, devnetKeyPair);
|
|
78
113
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
+
```
|
package/www/guides/erc20.md
CHANGED
|
@@ -4,104 +4,160 @@ sidebar_position: 3
|
|
|
4
4
|
|
|
5
5
|
# Deploy an ERC20 Contract
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Deploying a contract relies on having an account already set up with enough ETH to pay fees for both:
|
|
8
|
+
|
|
9
|
+
1. The class declaration
|
|
10
|
+
2. The transaction interacting with the UDC (universal deployer contract)
|
|
11
|
+
|
|
12
|
+
> You must first declare your contract class and only then deploy a new instance of it!
|
|
13
|
+
|
|
14
|
+
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).
|
|
15
|
+
|
|
16
|
+
ERC20 implementations:
|
|
17
|
+
|
|
18
|
+
1. Argent ERC20 contract can be found [here](https://github.com/argentlabs/argent-contracts-starknet/blob/develop/contracts/lib/ERC20.cairo).
|
|
19
|
+
2. OpenZeppelin ERC20 can be found [here](https://github.com/OpenZeppelin/cairo-contracts/tree/main/src/openzeppelin/token/erc20).
|
|
20
|
+
|
|
21
|
+
## Setup
|
|
8
22
|
|
|
9
23
|
```javascript
|
|
10
24
|
const compiledErc20 = json.parse(
|
|
11
25
|
fs.readFileSync("./ERC20.json").toString("ascii")
|
|
12
26
|
);
|
|
13
|
-
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
// devnet private key from Account #0 if generated with --seed 0
|
|
31
|
+
const starkKeyPair = ec.getKeyPair("0xe3e70682c2094cac629f6fbed82c07cd");
|
|
32
|
+
const accountAddress = "0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a";
|
|
33
|
+
|
|
34
|
+
const recieverAddress = '0x69b49c2cc8b16e80e86bfc5b0614a59aa8c9b601569c7b80dde04d3f3151b79';
|
|
35
|
+
|
|
36
|
+
// Starknet.js currently doesn't have the functionality to calculate the class hash
|
|
37
|
+
const erc20ClassHash = '0x03f794a28472089a1a99b7969fc51cd5fbe22dd09e3f38d2bd6fa109cb3f4ecf';
|
|
38
|
+
|
|
39
|
+
const account = new Account(
|
|
40
|
+
provider,
|
|
41
|
+
accountAddress,
|
|
42
|
+
starkKeyPair
|
|
43
|
+
);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Declare contract
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
const erc20DeclareResponse = await account.declare({
|
|
50
|
+
classHash: erc20ClassHash,
|
|
14
51
|
contract: compiledErc20,
|
|
15
|
-
constructorCalldata: [encodeShortString('TokenName'), encodeShortString('TokenSymbol'), recipient], // Here the `recipient` receives the initial 1000 tokens
|
|
16
52
|
});
|
|
17
53
|
|
|
18
|
-
|
|
19
|
-
await defaultProvider.waitForTransaction(erc20Response.transaction_hash);
|
|
54
|
+
await provider.waitForTransaction(erc20DeclareResponse.transaction_hash);
|
|
20
55
|
```
|
|
21
56
|
|
|
22
|
-
|
|
23
|
-
>
|
|
24
|
-
> The ERC20 contract can be found [here](https://github.com/argentlabs/argent-contracts-starknet/blob/develop/contracts/lib/ERC20.cairo)
|
|
25
|
-
|
|
26
|
-
## Get the erc20 contract address and create the contact object
|
|
57
|
+
## Deploy contract
|
|
27
58
|
|
|
28
59
|
```javascript
|
|
29
|
-
const
|
|
30
|
-
|
|
60
|
+
const salt = '900080545022'; // use some random salt
|
|
61
|
+
|
|
62
|
+
const erc20Response = await account.deploy({
|
|
63
|
+
classHash: erc20ClassHash,
|
|
64
|
+
constructorCalldata: stark.compileCalldata({
|
|
65
|
+
name: shortString.encodeShortString('TestToken'),
|
|
66
|
+
symbol: shortString.encodeShortString('ERC20'),
|
|
67
|
+
decimals: 18,
|
|
68
|
+
initial_supply: ['1000'],
|
|
69
|
+
recipient: account.address,
|
|
70
|
+
}),
|
|
71
|
+
salt,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
await provider.waitForTransaction(erc20Response.transaction_hash);
|
|
75
|
+
|
|
76
|
+
const txReceipt = await provider.getTransactionReceipt(erc20Response.transaction_hash);
|
|
31
77
|
```
|
|
32
78
|
|
|
33
|
-
##
|
|
79
|
+
## Interact with contracts
|
|
34
80
|
|
|
35
|
-
|
|
81
|
+
We have 2 options to interact with contracts.
|
|
36
82
|
|
|
37
|
-
|
|
83
|
+
### Option 1 - call the contract object
|
|
38
84
|
|
|
39
85
|
```javascript
|
|
86
|
+
const erc20 = new Contract(compiledErc20.abi, erc20Address, provider);
|
|
87
|
+
|
|
40
88
|
erc20.connect(account);
|
|
41
89
|
|
|
42
|
-
const { transaction_hash: mintTxHash } = await erc20.
|
|
43
|
-
|
|
44
|
-
|
|
90
|
+
const { transaction_hash: mintTxHash } = await erc20.transfer(
|
|
91
|
+
recieverAddress,
|
|
92
|
+
['0', '10'], // send 10 tokens as Uint256
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
await provider.waitForTransaction(mintTxHash);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Option 2 - call contract from Account
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
const executeHash = await account.execute(
|
|
45
102
|
{
|
|
46
|
-
|
|
103
|
+
contractAddress: erc20Address,
|
|
104
|
+
entrypoint: 'transfer',
|
|
105
|
+
calldata: stark.compileCalldata({
|
|
106
|
+
recipient: recieverAddress,
|
|
107
|
+
amount: ['10']
|
|
108
|
+
})
|
|
47
109
|
}
|
|
48
110
|
);
|
|
49
111
|
|
|
50
|
-
|
|
51
|
-
await defaultProvider.waitForTransaction(mintTxHash);
|
|
112
|
+
await provider.waitForTransaction(executeHash.transaction_hash);
|
|
52
113
|
```
|
|
53
114
|
|
|
54
|
-
|
|
55
|
-
>
|
|
56
|
-
> Transaction can be rejected if `maxFee` is lower than actual.
|
|
57
|
-
>
|
|
58
|
-
> _Error: REJECTED: FEE_TRANSFER_FAILURE_
|
|
59
|
-
>
|
|
60
|
-
> _Actual fee exceeded max fee._
|
|
61
|
-
>
|
|
62
|
-
> If this occurs, set `maxFee` to a higher value, for example: 999999995330000
|
|
63
|
-
|
|
64
|
-
## Check balance after mint
|
|
115
|
+
## Check the balance
|
|
65
116
|
|
|
66
117
|
```javascript
|
|
67
|
-
console.log(`Calling StarkNet for account balance...`);
|
|
68
118
|
const balanceBeforeTransfer = await erc20.balanceOf(account.address);
|
|
69
119
|
|
|
70
120
|
console.log(
|
|
71
121
|
`account Address ${account.address} has a balance of:`,
|
|
72
|
-
number.toBN(balanceBeforeTransfer.
|
|
122
|
+
number.toBN(balanceBeforeTransfer[0].high).toString()
|
|
73
123
|
);
|
|
74
124
|
```
|
|
75
125
|
|
|
76
|
-
##
|
|
126
|
+
## Convenience Methods
|
|
77
127
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
contractAddress: erc20Address,
|
|
84
|
-
entrypoint: "transfer",
|
|
85
|
-
calldata: [erc20Address, "10", "0"],
|
|
86
|
-
},
|
|
87
|
-
undefined,
|
|
88
|
-
{ maxFee: "1" }
|
|
89
|
-
);
|
|
128
|
+
### deployContract convenience method
|
|
129
|
+
|
|
130
|
+
High level wrapper for deploy. Doesn't require `waitForTransaction`. Response similar to deprecated `provider.deployContract`.
|
|
131
|
+
|
|
132
|
+
Convenient also to get the address of the deployed contract in the same response - easier than using the `deploy` already mentioned in the guide.
|
|
90
133
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
134
|
+
```typescript
|
|
135
|
+
const deployResponse = await account.deployContract({
|
|
136
|
+
classHash: erc20ClassHash,
|
|
137
|
+
constructorCalldata: [
|
|
138
|
+
encodeShortString('Token'),
|
|
139
|
+
encodeShortString('ERC20'),
|
|
140
|
+
account.address,
|
|
141
|
+
],
|
|
142
|
+
});
|
|
94
143
|
```
|
|
95
144
|
|
|
96
|
-
|
|
145
|
+
### declareDeploy convenience method
|
|
97
146
|
|
|
98
|
-
|
|
99
|
-
// Check balance after transfer - should be 1990 (1000 initial supply + 1000 mint - 10 transfer)
|
|
100
|
-
console.log(`Calling StarkNet for account balance...`);
|
|
101
|
-
const balanceAfterTransfer = await erc20.balanceOf(account.address);
|
|
147
|
+
High level wrapper for declare & deploy. Doesn't require `waitForTransaction`. Functionality similar to deprecated `provider.deployContract`.
|
|
102
148
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
149
|
+
Declare and Deploy contract using single function:
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
const declareDeploy = await account.declareDeploy({
|
|
153
|
+
contract: compiledErc20,
|
|
154
|
+
classHash: '0x54328a1075b8820eb43caf0caa233923148c983742402dcfc38541dd843d01a',
|
|
155
|
+
constructorCalldata: [
|
|
156
|
+
encodeShortString('Token'),
|
|
157
|
+
encodeShortString('ERC20'),
|
|
158
|
+
account.address,
|
|
159
|
+
],
|
|
160
|
+
});
|
|
161
|
+
const declareTransactionHash = declareDeploy.declare.transaction_hash
|
|
162
|
+
const erc20Address = declareDeploy.deploy.contract_address;
|
|
107
163
|
```
|
package/www/guides/intro.md
CHANGED
|
@@ -5,9 +5,12 @@ sidebar_position: 1
|
|
|
5
5
|
# Getting Started
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
+
|
|
9
|
+
# use the main branch
|
|
10
|
+
|
|
8
11
|
npm install starknet
|
|
9
12
|
|
|
10
|
-
# to use latest features
|
|
13
|
+
# to use latest features (merges in develop branch)
|
|
11
14
|
|
|
12
15
|
npm install starknet@next
|
|
13
16
|
```
|
|
@@ -16,8 +19,12 @@ npm install starknet@next
|
|
|
16
19
|
|
|
17
20
|
Please check the StarkNet documentation <ins>[here](https://www.cairo-lang.org/docs/hello_starknet/intro.html)</ins> to compile starknet contracts.
|
|
18
21
|
|
|
19
|
-
Additional helpful resources can also be found at [OpenZeppelin](https://docs.openzeppelin.com/contracts-cairo/0.
|
|
22
|
+
Additional helpful resources can also be found at <ins>[OpenZeppelin](https://docs.openzeppelin.com/contracts-cairo/0.5.0/)</ins> documentation site.
|
|
23
|
+
|
|
24
|
+
Get the class hash of a contract: [starkli](https://github.com/xJonathanLEI/starkli).
|
|
25
|
+
|
|
26
|
+
## Full example with account & erc20 deployments
|
|
20
27
|
|
|
21
|
-
|
|
28
|
+
Please take a look at our workshop using OpenZeppelin contracts <ins>[here](https://github.com/0xs34n/starknet.js-workshop)</ins>.
|
|
22
29
|
|
|
23
|
-
|
|
30
|
+
Example with Argent contract <ins>[here](https://github.com/0xs34n/starknet.js-account)</ins>.
|