@inco/shield-js 0.0.0-bootstrap.0 → 0.2.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/README.md +52 -308
- package/dist/contracts/abi.d.ts +2000 -4513
- package/dist/contracts/abi.js +2400 -5651
- package/dist/contracts/index.d.ts +2 -2
- package/dist/contracts/index.js +2 -2
- package/dist/contracts/utils.d.ts +5 -24
- package/dist/contracts/utils.js +13 -24
- package/dist/errors.d.ts +16 -47
- package/dist/errors.js +6 -53
- package/dist/generated/inco/shield/v2/conductor_pb.d.ts +77 -0
- package/dist/generated/inco/shield/v2/conductor_pb.js +6 -0
- package/dist/generated/inco/shield/v2/deposit_pb.d.ts +12 -103
- package/dist/generated/inco/shield/v2/deposit_pb.js +4 -141
- package/dist/generated/inco/shield/v2/drafting_pb.d.ts +45 -269
- package/dist/generated/inco/shield/v2/drafting_pb.js +8 -361
- package/dist/generated/inco/shield/v2/types_pb.d.ts +47 -166
- package/dist/generated/inco/shield/v2/types_pb.js +12 -261
- package/dist/index.d.ts +1 -7
- package/dist/index.js +1 -14
- package/dist/shield/abi.d.ts +5 -0
- package/dist/shield/abi.js +28 -0
- package/dist/shield/client.d.ts +27 -51
- package/dist/shield/client.js +73 -65
- package/dist/shield/convert.d.ts +2 -14
- package/dist/shield/convert.js +39 -115
- package/dist/shield/encryption.d.ts +0 -67
- package/dist/shield/encryption.js +0 -67
- package/dist/shield/envelope.d.ts +10 -11
- package/dist/shield/envelope.js +15 -14
- package/dist/shield/fee.d.ts +24 -0
- package/dist/shield/fee.js +151 -0
- package/dist/shield/index.d.ts +9 -3
- package/dist/shield/index.js +7 -2
- package/dist/shield/intent.d.ts +20 -933
- package/dist/shield/intent.js +92 -112
- package/dist/shield/permission-status.d.ts +9 -0
- package/dist/shield/permission-status.js +8 -0
- package/dist/shield/rpc.d.ts +50 -49
- package/dist/shield/rpc.js +207 -354
- package/dist/shield/shield.eip712.gen.d.ts +1096 -43
- package/dist/shield/shield.eip712.gen.js +572 -62
- package/dist/shield/types.d.ts +7 -102
- package/dist/shield/types.js +1 -4
- package/dist/shield/userop/gas-estimation.d.ts +8 -23
- package/dist/shield/userop/gas-estimation.js +100 -137
- package/dist/shield/userop/paymaster.d.ts +15 -0
- package/dist/shield/userop/paymaster.js +17 -0
- package/dist/shield/userop/token-exchange.d.ts +5 -52
- package/dist/shield/userop/token-exchange.js +41 -149
- package/dist/shield/userop/types.d.ts +3 -28
- package/dist/shield/userop/types.js +0 -3
- package/dist/shield/userop/userOp.d.ts +0 -19
- package/dist/shield/userop/userOp.js +4 -22
- package/dist/shield/utils/chain.d.ts +1 -0
- package/dist/shield/utils/chain.js +3 -0
- package/dist/shield/validate-withdrawal-split.d.ts +13 -0
- package/dist/shield/validate-withdrawal-split.js +93 -0
- package/package.json +18 -27
- package/dist/generated/inco/shield/v2/conductor_connect.d.ts +0 -137
- package/dist/generated/inco/shield/v2/conductor_connect.js +0 -141
- package/dist/generated/inco/shield/v2/permission_pb.d.ts +0 -443
- package/dist/generated/inco/shield/v2/permission_pb.js +0 -639
- package/dist/generated/inco/shield/v2/query_pb.d.ts +0 -103
- package/dist/generated/inco/shield/v2/query_pb.js +0 -141
- package/dist/shield/userop/index.d.ts +0 -1
- package/dist/shield/userop/index.js +0 -1
- package/dist/uniswap-adapter/config.d.ts +0 -34
- package/dist/uniswap-adapter/config.js +0 -45
- package/dist/uniswap-adapter/find-pools.d.ts +0 -91
- package/dist/uniswap-adapter/find-pools.js +0 -108
- package/dist/uniswap-adapter/index.d.ts +0 -10
- package/dist/uniswap-adapter/index.js +0 -13
- package/dist/uniswap-adapter/swap.d.ts +0 -344
- package/dist/uniswap-adapter/swap.js +0 -309
package/README.md
CHANGED
|
@@ -4,347 +4,92 @@ TypeScript SDK for interacting with IncoShield contracts from browsers and Node.
|
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
```bash
|
|
8
|
+
bun add @inco/shield-js
|
|
9
|
+
```
|
|
9
10
|
|
|
10
11
|
## Shield Client
|
|
11
12
|
|
|
12
|
-
The SDK wraps the
|
|
13
|
+
The SDK wraps the Shield conductor's gRPC API with a typed TypeScript client. `createShieldClient` accepts the network, contract, transport, signer, serialized TEE public key, and protocol-fee routing configuration. Client creation is asynchronous because it resolves the configured Shield contract's paymaster.
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
Install a Connect transport for the target environment, such as `@connectrpc/connect-web` for browsers or `@connectrpc/connect-node` for Node.js.
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
### Create a client
|
|
17
18
|
|
|
18
19
|
```typescript
|
|
19
|
-
import { createShieldClient } from "@inco/shield-js";
|
|
20
|
-
|
|
21
|
-
// Browser
|
|
22
20
|
import { createConnectTransport } from "@connectrpc/connect-web";
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
21
|
+
import {
|
|
22
|
+
createShieldClient,
|
|
23
|
+
type ShieldSignerInput,
|
|
24
|
+
} from "@inco/shield-js";
|
|
25
|
+
import { http } from "viem";
|
|
26
|
+
|
|
27
|
+
declare const shieldAddress: `0x${string}`;
|
|
28
|
+
declare const signer: ShieldSignerInput;
|
|
29
|
+
declare const teePublicKey: Uint8Array;
|
|
30
|
+
declare const feeAccrualAdapter: `0x${string}`;
|
|
31
|
+
declare const protocolFeeTreasury: `0x${string}`;
|
|
32
|
+
|
|
33
|
+
const shield = await createShieldClient({
|
|
34
|
+
grpcTransport: createConnectTransport({
|
|
35
|
+
baseUrl: "https://conductor.example.com",
|
|
36
|
+
}),
|
|
37
|
+
viemTransport: http("https://rpc.example.com"),
|
|
38
|
+
chainId: 84532n,
|
|
39
|
+
shieldAddress,
|
|
40
|
+
signer,
|
|
41
|
+
teePublicKey,
|
|
42
|
+
feeAccrualAdapter,
|
|
43
|
+
protocolFeeTreasury,
|
|
44
44
|
});
|
|
45
|
-
|
|
46
|
-
// note.spends contains the signed spends to submit on-chain
|
|
47
|
-
// note.signer is the covalidator address
|
|
48
45
|
```
|
|
49
46
|
|
|
50
|
-
### Issue a
|
|
51
|
-
|
|
52
|
-
Submit a private-to-public withdrawal intent:
|
|
53
|
-
|
|
54
|
-
```typescript
|
|
55
|
-
const note = await shield.issueWithdraw({
|
|
56
|
-
sender: "0x2222222222222222222222222222222222222222",
|
|
57
|
-
to: "0x4444444444444444444444444444444444444444",
|
|
58
|
-
assetId: "0x0000000000000000000000000000000000000000000000000000000000000001",
|
|
59
|
-
amount: 500n,
|
|
60
|
-
assetMovement: {
|
|
61
|
-
assetAdapter: erc20AdapterAddress,
|
|
62
|
-
assetIdentificationArgs: "0x...",
|
|
63
|
-
movementArgs: "0x...",
|
|
64
|
-
},
|
|
65
|
-
sessionKeyHash: "0x0000000000000000000000000000000000000000000000000000000000000001",
|
|
66
|
-
memo: "0x",
|
|
67
|
-
}, "0x2222222222222222222222222222222222222222");
|
|
68
|
-
|
|
69
|
-
// note.spends[0].spendType will be "withdraw"
|
|
70
|
-
```
|
|
47
|
+
### Issue a transfer
|
|
71
48
|
|
|
72
|
-
|
|
49
|
+
Draft a shielded transfer as an ERC-4337 user operation, then submit it through the client's configured bundler:
|
|
73
50
|
|
|
74
51
|
```typescript
|
|
75
|
-
const
|
|
76
|
-
|
|
52
|
+
const { userOp } = await shield.issueTransfer({
|
|
53
|
+
receiver: "0x3333333333333333333333333333333333333333",
|
|
77
54
|
assetId: "0x0000000000000000000000000000000000000000000000000000000000000001",
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
console.log(balance.confirmed, balance.pending, balance.available);
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## Contract Interactions
|
|
84
|
-
|
|
85
|
-
The `contracts` module provides typed helpers for all IncoShield on-chain operations.
|
|
86
|
-
|
|
87
|
-
```typescript
|
|
88
|
-
import { contracts } from "@inco/shield-js";
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
### Deposit
|
|
92
|
-
|
|
93
|
-
```typescript
|
|
94
|
-
// 1. Request the TEE attestation. The enclave returns toCiphertext (the
|
|
95
|
-
// AEAD-sealed recipient address) and the TEE signature over the deposit.
|
|
96
|
-
const attestation = await shield.requestDepositAttestation({
|
|
97
|
-
recipient: account.address,
|
|
98
|
-
assetAdapter: erc20AdapterAddress,
|
|
99
|
-
assetIdentificationArgs: encodedTokenAddress,
|
|
55
|
+
amount: 1000n,
|
|
100
56
|
memo: "0x",
|
|
101
|
-
escapeHatch: "0x",
|
|
102
57
|
});
|
|
103
58
|
|
|
104
|
-
|
|
105
|
-
const { txHash } = await contracts.deposit(
|
|
106
|
-
walletClient,
|
|
107
|
-
publicClient,
|
|
108
|
-
shieldAddress,
|
|
109
|
-
{
|
|
110
|
-
toCiphertext: attestation.toCiphertext,
|
|
111
|
-
from: account.address,
|
|
112
|
-
assetMovement: {
|
|
113
|
-
assetAdapter: erc20AdapterAddress,
|
|
114
|
-
assetIdentificationArgs: encodedTokenAddress,
|
|
115
|
-
movementArgs: encodedAmount,
|
|
116
|
-
},
|
|
117
|
-
amount: 1000n,
|
|
118
|
-
memo: "0x",
|
|
119
|
-
escapeHatch: "0x",
|
|
120
|
-
},
|
|
121
|
-
attestation.teeSignature,
|
|
122
|
-
);
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
### Transfer, Withdraw, DeFi Interaction
|
|
126
|
-
|
|
127
|
-
```typescript
|
|
128
|
-
// Transfer (with TEE signature)
|
|
129
|
-
await contracts.transfer(walletClient, publicClient, shieldAddress, transferData, signature);
|
|
130
|
-
|
|
131
|
-
// Withdraw (with TEE signature)
|
|
132
|
-
await contracts.withdraw(walletClient, publicClient, shieldAddress, withdrawData, signature);
|
|
133
|
-
|
|
134
|
-
// DeFi interaction (with TEE signature)
|
|
135
|
-
await contracts.performDefiInteraction(walletClient, publicClient, shieldAddress, interaction, signature);
|
|
59
|
+
const { receipt } = await shield.submitUserOp(userOp);
|
|
136
60
|
```
|
|
137
61
|
|
|
138
|
-
###
|
|
139
|
-
|
|
140
|
-
```typescript
|
|
141
|
-
// Execute operations via protocol-managed proxy account
|
|
142
|
-
await contracts.performProxyAccountOperation(walletClient, publicClient, shieldAddress, {
|
|
143
|
-
account: proxyAddress, // or address(0) to deploy new
|
|
144
|
-
nonce: await contracts.getProxyAccountOperationNonce(publicClient, shieldAddress, proxyAddress),
|
|
145
|
-
batch: [{ target: tokenAddress, value: 0n, data: calldata }],
|
|
146
|
-
escapeHatchData: "0x",
|
|
147
|
-
}, signature);
|
|
148
|
-
|
|
149
|
-
// Query proxy accounts
|
|
150
|
-
const proxies = await contracts.getDeployedProxyAccounts(publicClient, shieldAddress);
|
|
151
|
-
const isOwned = await contracts.isProxyAccountOwnedByProtocol(publicClient, shieldAddress, proxyAddress);
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### Digests and State
|
|
155
|
-
|
|
156
|
-
```typescript
|
|
157
|
-
// Get current handle
|
|
158
|
-
const handle = await contracts.getHandle(publicClient, shieldAddress);
|
|
159
|
-
|
|
160
|
-
// Compute operation digests (for TEE signing)
|
|
161
|
-
const digest = await contracts.getTransferDigest(publicClient, shieldAddress, transferData);
|
|
162
|
-
const digest = await contracts.getWithdrawDigest(publicClient, shieldAddress, withdrawData);
|
|
163
|
-
const digest = await contracts.getProxyAccountOperationDigest(publicClient, shieldAddress, operation);
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
### Watch Settlement Events
|
|
167
|
-
|
|
168
|
-
```typescript
|
|
169
|
-
const unwatch = contracts.watchSettlementEvents(publicClient, shieldAddress, {
|
|
170
|
-
onTransferSettled: (event, log) => {
|
|
171
|
-
console.log("Transfer settled:", event.newShieldHandle);
|
|
172
|
-
},
|
|
173
|
-
onDepositSettled: (event, log) => {
|
|
174
|
-
console.log("Deposit:", event.deposit.from, event.assetId, event.deposit.amount);
|
|
175
|
-
},
|
|
176
|
-
onWithdrawSettled: (event, log) => {
|
|
177
|
-
console.log("Withdraw:", event.withdraw.to, event.assetId, event.withdraw.amount);
|
|
178
|
-
},
|
|
179
|
-
onProxyAccountOperationSettled: (event, log) => {
|
|
180
|
-
console.log("Proxy op:", event.proxyAccount);
|
|
181
|
-
},
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
// Stop watching
|
|
185
|
-
unwatch();
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### Parse individual event logs
|
|
189
|
-
|
|
190
|
-
```typescript
|
|
191
|
-
import { contracts } from "@inco/shield-js";
|
|
192
|
-
|
|
193
|
-
const transferEvent = contracts.parseTransferSettledLog(log);
|
|
194
|
-
const depositEvent = contracts.parseDepositSettledLog(log);
|
|
195
|
-
const withdrawEvent = contracts.parseWithdrawSettledLog(log);
|
|
196
|
-
const proxyOpEvent = contracts.parseProxyAccountOperationSettledLog(log);
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
## Uniswap Adapter
|
|
62
|
+
### Query a balance
|
|
200
63
|
|
|
201
|
-
|
|
64
|
+
Balance, portfolio, and history queries are authorized by a signed viewing session. Sign one once and reuse it for every query until it expires:
|
|
202
65
|
|
|
203
66
|
```typescript
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
import { sepolia } from "viem/chains";
|
|
207
|
-
|
|
208
|
-
const account = privateKeyToAccount("0x...");
|
|
209
|
-
|
|
210
|
-
const publicClient = createPublicClient({
|
|
211
|
-
chain: sepolia,
|
|
212
|
-
transport: http("https://rpc.sepolia.org"),
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
const walletClient = createWalletClient({
|
|
216
|
-
account,
|
|
217
|
-
chain: sepolia,
|
|
218
|
-
transport: http("https://rpc.sepolia.org"),
|
|
67
|
+
const viewing = await shield.createViewingSession({
|
|
68
|
+
expiresAt: BigInt(Math.floor(Date.now() / 1000) + 3600),
|
|
219
69
|
});
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### Authorize a DeFi Adapter
|
|
223
70
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
const result = await authorizeAdapter({
|
|
228
|
-
publicClient,
|
|
229
|
-
walletClient,
|
|
230
|
-
incoShieldAddress: "0x...",
|
|
231
|
-
adapterAddress: "0x...",
|
|
71
|
+
const balance = await shield.getBalance(viewing, {
|
|
72
|
+
assetId: "0x0000000000000000000000000000000000000000000000000000000000000001",
|
|
232
73
|
});
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
### Find Uniswap V4 Pools
|
|
236
|
-
|
|
237
|
-
```typescript
|
|
238
|
-
import { findPoolsWithLiquidity, UNISWAP_V4_SEPOLIA } from "@inco/shield-js";
|
|
239
74
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
{
|
|
245
|
-
name: "ETH/USDC 0.3%",
|
|
246
|
-
currency0: "0x0000000000000000000000000000000000000000",
|
|
247
|
-
currency1: "0x...",
|
|
248
|
-
fee: 3000,
|
|
249
|
-
tickSpacing: 60,
|
|
250
|
-
hooks: "0x0000000000000000000000000000000000000000",
|
|
251
|
-
},
|
|
252
|
-
],
|
|
75
|
+
console.log(
|
|
76
|
+
balance.bankBalance,
|
|
77
|
+
balance.outstandingBalance,
|
|
78
|
+
balance.bookBalance,
|
|
253
79
|
);
|
|
254
80
|
```
|
|
255
81
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
```typescript
|
|
259
|
-
import {
|
|
260
|
-
approveToken,
|
|
261
|
-
buildEncodedV4Actions,
|
|
262
|
-
encodeSwapArgs,
|
|
263
|
-
buildDefiInteraction,
|
|
264
|
-
depositToShield,
|
|
265
|
-
executeDefiInteraction,
|
|
266
|
-
generateNullifier,
|
|
267
|
-
getDefiInteractionDigest,
|
|
268
|
-
signDefiInteraction,
|
|
269
|
-
DEPLOYED_CONTRACTS,
|
|
270
|
-
SEPOLIA_TOKENS,
|
|
271
|
-
POOL_CONFIG,
|
|
272
|
-
} from "@inco/shield-js";
|
|
273
|
-
|
|
274
|
-
const {
|
|
275
|
-
incoShield: incoShieldAddress,
|
|
276
|
-
erc20Adapter: erc20AdapterAddress,
|
|
277
|
-
uniswapV4Adapter: uniswapAdapterAddress,
|
|
278
|
-
} = DEPLOYED_CONTRACTS;
|
|
82
|
+
## Contract Exports
|
|
279
83
|
|
|
280
|
-
|
|
84
|
+
The `contracts` namespace exports the generated contract ABIs and the ERC-20 asset ID helper. Use the ABIs with a viem client for direct contract interactions.
|
|
281
85
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
const { stateAfterDeposit } = await depositToShield(
|
|
286
|
-
walletClient,
|
|
287
|
-
publicClient,
|
|
288
|
-
incoShieldAddress,
|
|
289
|
-
{
|
|
290
|
-
toCiphertext: "0x01",
|
|
291
|
-
from: account.address,
|
|
292
|
-
assetAdapter: erc20AdapterAddress,
|
|
293
|
-
tokenAddress: SEPOLIA_TOKENS.WETH,
|
|
294
|
-
amount,
|
|
295
|
-
},
|
|
296
|
-
);
|
|
297
|
-
|
|
298
|
-
// 2. Build swap args
|
|
299
|
-
const poolKey = {
|
|
300
|
-
currency0: SEPOLIA_TOKENS.NATIVE_ETH,
|
|
301
|
-
currency1: SEPOLIA_TOKENS.USDC,
|
|
302
|
-
fee: POOL_CONFIG.FEE,
|
|
303
|
-
tickSpacing: POOL_CONFIG.TICK_SPACING,
|
|
304
|
-
hooks: POOL_CONFIG.HOOKS,
|
|
305
|
-
};
|
|
306
|
-
|
|
307
|
-
const encodedV4Actions = buildEncodedV4Actions({
|
|
308
|
-
poolKey,
|
|
309
|
-
zeroForOne: true,
|
|
310
|
-
amountIn: amount,
|
|
311
|
-
amountOutMinimum: 1n,
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
const swapArgs = encodeSwapArgs({
|
|
315
|
-
encodedV4Actions,
|
|
316
|
-
tokenIn: SEPOLIA_TOKENS.WETH,
|
|
317
|
-
tokenOut: SEPOLIA_TOKENS.USDC,
|
|
318
|
-
amountOutMinimum: 1n,
|
|
319
|
-
toCiphertext: "0x01",
|
|
320
|
-
deadline: BigInt(Math.floor(Date.now() / 1000) + 1800),
|
|
321
|
-
unwrapWeth: true,
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
// 3. Build and sign defi interaction
|
|
325
|
-
const defiInteraction = buildDefiInteraction({
|
|
326
|
-
to: uniswapAdapterAddress,
|
|
327
|
-
nullifier: generateNullifier(account.address),
|
|
328
|
-
pastShieldHandle: stateAfterDeposit,
|
|
329
|
-
assetAdapter: erc20AdapterAddress,
|
|
330
|
-
tokenAddress: SEPOLIA_TOKENS.WETH,
|
|
331
|
-
amount,
|
|
332
|
-
defiAdapter: uniswapAdapterAddress,
|
|
333
|
-
adapterArgs: swapArgs,
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
const digest = await getDefiInteractionDigest(publicClient, incoShieldAddress, defiInteraction);
|
|
337
|
-
const signature = await signDefiInteraction(account, digest);
|
|
86
|
+
```typescript
|
|
87
|
+
import { computeErc20AssetId, contracts } from "@inco/shield-js";
|
|
338
88
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
walletClient,
|
|
342
|
-
publicClient,
|
|
343
|
-
incoShieldAddress,
|
|
344
|
-
defiInteraction,
|
|
345
|
-
signature,
|
|
346
|
-
{ gas: 1_000_000n },
|
|
89
|
+
const assetId = computeErc20AssetId(
|
|
90
|
+
"0x1111111111111111111111111111111111111111",
|
|
347
91
|
);
|
|
92
|
+
const { erc20AdapterAbi, incoShieldAbi } = contracts;
|
|
348
93
|
```
|
|
349
94
|
|
|
350
95
|
## Development
|
|
@@ -355,5 +100,4 @@ bun run generate # Generate proto types + ABIs
|
|
|
355
100
|
bun run build # Generate + compile TypeScript
|
|
356
101
|
bun run test # Run tests
|
|
357
102
|
bun run typecheck # Type-check only
|
|
358
|
-
bun run uniswap # Run example swap script
|
|
359
103
|
```
|