@ilalv3/cli 0.2.0 → 0.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.
- package/README.md +49 -15
- package/dist/commands/demo.d.ts +5 -0
- package/dist/commands/demo.js +59 -8
- package/dist/commands/deploy.js +3 -1
- package/dist/commands/init.js +17 -10
- package/dist/commands/liquidity.js +50 -1
- package/dist/commands/mint.js +22 -7
- package/dist/commands/oracle.d.ts +2 -2
- package/dist/commands/oracle.js +2 -2
- package/dist/commands/prove.d.ts +1 -1
- package/dist/commands/prove.js +1 -1
- package/dist/commands/status.js +13 -3
- package/dist/commands/swap.js +69 -23
- package/dist/index.js +11 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -18,19 +18,42 @@ npx @ilalv3/cli <command>
|
|
|
18
18
|
|
|
19
19
|
## Quick start (Base Sepolia demo)
|
|
20
20
|
|
|
21
|
+
`ilal init` points at the current seeded Base Sepolia demo stack. The demo issuer
|
|
22
|
+
uses MockEAS, so reviewers can verify the full path without waiting for a real
|
|
23
|
+
Coinbase attestation. The seeded reviewer wallet already has CNF + TOKA/TOKB;
|
|
24
|
+
for your own wallet, deploy a mock stack with `ilal deploy --mock`.
|
|
25
|
+
|
|
21
26
|
```bash
|
|
22
27
|
# 1. Point CLI at the live demo deployment
|
|
23
28
|
ilal init
|
|
24
29
|
|
|
25
|
-
# 2. Check credential + pool status
|
|
26
|
-
ilal status
|
|
30
|
+
# 2. Check credential + pool status for the seeded reviewer wallet
|
|
31
|
+
ilal status --wallet 0xc0807D4778a9E5FE15ad68A8500e64d65BA78D58
|
|
27
32
|
|
|
28
|
-
# 3.
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
# 3. Full readiness verdict
|
|
34
|
+
ilal demo check --wallet 0xc0807D4778a9E5FE15ad68A8500e64d65BA78D58
|
|
35
|
+
|
|
36
|
+
# 4. Execute a compliant swap with the seeded reviewer key
|
|
37
|
+
PRIVATE_KEY=0x... ilal swap --amount-in 1 --token-in 0x582362E608F36850F6f641510d5D19C1EaB4cb27 --min-amount-out 0
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
For a fully seeded local/testnet demo, deploy mock EAS + demo pool pieces:
|
|
31
41
|
|
|
32
|
-
|
|
33
|
-
PRIVATE_KEY=0x... ilal
|
|
42
|
+
```bash
|
|
43
|
+
PRIVATE_KEY=0x... ilal deploy \
|
|
44
|
+
--chain 84532 \
|
|
45
|
+
--mock \
|
|
46
|
+
--wallet-to-seed 0xYourWallet \
|
|
47
|
+
--broadcast
|
|
48
|
+
|
|
49
|
+
# Then mint the seeded CNF from the printed AttestationUID:
|
|
50
|
+
PRIVATE_KEY=0x... ilal credential mint \
|
|
51
|
+
--issuer <CNFIssuer> \
|
|
52
|
+
--attestation <AttestationUID> \
|
|
53
|
+
--chain 84532
|
|
54
|
+
|
|
55
|
+
# If the wallet needs more demo tokens:
|
|
56
|
+
PRIVATE_KEY=0x... ilal demo faucet --wallet 0xYourWallet
|
|
34
57
|
```
|
|
35
58
|
|
|
36
59
|
## Getting a CNF credential
|
|
@@ -75,6 +98,8 @@ Generates a Groth16 proof locally (~5s), verifies it on-chain, and mints/renews
|
|
|
75
98
|
| `ilal oracle activate-verifier` | Operator flow: activate the pending ZK verifier after timelock |
|
|
76
99
|
| `ilal session sign` | Sign a standalone SessionToken |
|
|
77
100
|
| `ilal proof mint` | Mint CNF from existing proof.json + public.json |
|
|
101
|
+
| `ilal deploy --mock` | Deploy a seeded testnet demo stack with MockEAS, tokens, router, hook, and policy |
|
|
102
|
+
| `ilal demo faucet` | Mint mock demo TOKA/TOKB to a wallet |
|
|
78
103
|
| `ilal deploy` | Deploy full ILAL contract stack |
|
|
79
104
|
|
|
80
105
|
## Configuration
|
|
@@ -83,10 +108,10 @@ The CLI reads `.ilal.json` in the current directory. Run `ilal init` to create i
|
|
|
83
108
|
|
|
84
109
|
```bash
|
|
85
110
|
ilal swap \
|
|
86
|
-
--router
|
|
87
|
-
--hook
|
|
88
|
-
--issuer
|
|
89
|
-
--pool-id
|
|
111
|
+
--router 0x7727F0f3EBe99A558487394D001950ee6B33BB86 \
|
|
112
|
+
--hook 0xF5066ad9c25F3f54cfb19609A60187C48C184A80 \
|
|
113
|
+
--issuer 0xc4E032A7574016bd0e3d1a5BbFdE886af09CeD9A \
|
|
114
|
+
--pool-id 0xc1c8f29d6f03b5cd18bf2b862d48f45cc338022a154945b89c4bcb0a3e11e87f \
|
|
90
115
|
--amount-in 0.001
|
|
91
116
|
```
|
|
92
117
|
|
|
@@ -94,10 +119,19 @@ ilal swap \
|
|
|
94
119
|
|
|
95
120
|
| Contract | Address |
|
|
96
121
|
|---|---|
|
|
97
|
-
| CNFIssuer | `
|
|
98
|
-
| ComplianceHook | `
|
|
99
|
-
| ILALRouter | `
|
|
100
|
-
| PolicyRegistry | `
|
|
122
|
+
| CNFIssuer | `0xc4E032A7574016bd0e3d1a5BbFdE886af09CeD9A` |
|
|
123
|
+
| ComplianceHook | `0xF5066ad9c25F3f54cfb19609A60187C48C184A80` |
|
|
124
|
+
| ILALRouter | `0x7727F0f3EBe99A558487394D001950ee6B33BB86` |
|
|
125
|
+
| PolicyRegistry | `0x910a3efDc426f3216738106dd0DC6EA696477233` |
|
|
126
|
+
| TokenA / TOKA | `0x582362E608F36850F6f641510d5D19C1EaB4cb27` |
|
|
127
|
+
| TokenB / TOKB | `0x6eBBdAC70EC422C512727B25c7F0D9120ed101Ff` |
|
|
128
|
+
| Pool ID | `0xc1c8f29d6f03b5cd18bf2b862d48f45cc338022a154945b89c4bcb0a3e11e87f` |
|
|
129
|
+
|
|
130
|
+
Live proof:
|
|
131
|
+
|
|
132
|
+
- CNF mint tx: `0x676ca67698eb8fed6c905c2b3a9536d4d056e89c199c41c44085a29db8b4d462`
|
|
133
|
+
- Add liquidity tx: `0x531fac3678878e4855471318b8ea39b2b2f3ced3d890d9d7c40721af296084ca`
|
|
134
|
+
- Swap tx: `0xdaf4136d305e546d6936715cc0101efb4dc88abcb779add9ee03591fdf555a5a`
|
|
101
135
|
|
|
102
136
|
## License
|
|
103
137
|
|
package/dist/commands/demo.d.ts
CHANGED
package/dist/commands/demo.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { createPublicClient, formatUnits, http, isAddress, isHex, } from "viem";
|
|
1
|
+
import { createPublicClient, createWalletClient, formatUnits, http, isAddress, isHex, parseUnits, } from "viem";
|
|
2
2
|
import { privateKeyToAccount } from "viem/accounts";
|
|
3
3
|
import { base, baseSepolia } from "viem/chains";
|
|
4
4
|
import { loadConfig } from "../config.js";
|
|
5
|
-
import { fmt, header, log } from "../ui.js";
|
|
5
|
+
import { die, fmt, header, log, Spinner } from "../ui.js";
|
|
6
6
|
const CHAINS = { "8453": base, "84532": baseSepolia };
|
|
7
7
|
const POOL_MANAGER = {
|
|
8
8
|
"84532": "0x05E73354cFDd6745C338b50BcFDfA3Aa6fA03408",
|
|
9
9
|
"8453": "0x498581fF718922c3f8e6A244956aF099B2652b2b",
|
|
10
10
|
};
|
|
11
11
|
const SAMPLE = {
|
|
12
|
-
wallet: "
|
|
13
|
-
issuer: "
|
|
14
|
-
hook: "
|
|
15
|
-
router: "
|
|
16
|
-
pool: "
|
|
12
|
+
wallet: "0xc0807D4778a9E5FE15ad68A8500e64d65BA78D58",
|
|
13
|
+
issuer: "0xc4E032A7574016bd0e3d1a5BbFdE886af09CeD9A",
|
|
14
|
+
hook: "0xF5066ad9c25F3f54cfb19609A60187C48C184A80",
|
|
15
|
+
router: "0x7727F0f3EBe99A558487394D001950ee6B33BB86",
|
|
16
|
+
pool: "0xc1c8f29d6f03b5cd18bf2b862d48f45cc338022a154945b89c4bcb0a3e11e87f",
|
|
17
17
|
proof: "0x91f2b8a0c43e902f7f1a8c0d",
|
|
18
18
|
session: "0x6b84eac5e0db21f8d5d43b7a",
|
|
19
19
|
};
|
|
@@ -23,6 +23,7 @@ const CNF_ABI = [
|
|
|
23
23
|
{ name: "credentialOf", type: "function", stateMutability: "view", inputs: [{ name: "wallet", type: "address" }], outputs: [{ type: "uint256" }] },
|
|
24
24
|
{ name: "merkleRoot", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "uint256" }] },
|
|
25
25
|
{ name: "zkVerifier", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
26
|
+
{ name: "eas", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
26
27
|
];
|
|
27
28
|
const REGISTRY_ABI = [
|
|
28
29
|
{ name: "getPolicy", type: "function", stateMutability: "view", inputs: [{ name: "poolId", type: "bytes32" }], outputs: [{ type: "tuple", components: [{ name: "cnfIssuer", type: "address" }, { name: "requiredCredentialType", type: "bytes32" }, { name: "enabled", type: "bool" }] }] },
|
|
@@ -36,6 +37,7 @@ const ERC20_ABI = [
|
|
|
36
37
|
{ name: "decimals", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "uint8" }] },
|
|
37
38
|
{ name: "balanceOf", type: "function", stateMutability: "view", inputs: [{ name: "owner", type: "address" }], outputs: [{ type: "uint256" }] },
|
|
38
39
|
{ name: "allowance", type: "function", stateMutability: "view", inputs: [{ name: "owner", type: "address" }, { name: "spender", type: "address" }], outputs: [{ type: "uint256" }] },
|
|
40
|
+
{ name: "mint", type: "function", stateMutability: "nonpayable", inputs: [{ name: "to", type: "address" }, { name: "amount", type: "uint256" }], outputs: [] },
|
|
39
41
|
];
|
|
40
42
|
function stage(n, title, subtitle) {
|
|
41
43
|
console.log();
|
|
@@ -222,10 +224,19 @@ export async function demoCheck(opts) {
|
|
|
222
224
|
if (cfg.issuer && isAddress(cfg.issuer)) {
|
|
223
225
|
log.section("Issuer State");
|
|
224
226
|
try {
|
|
225
|
-
const [root, verifier] = await Promise.all([
|
|
227
|
+
const [root, verifier, eas] = await Promise.all([
|
|
226
228
|
client.readContract({ address: cfg.issuer, abi: CNF_ABI, functionName: "merkleRoot" }),
|
|
227
229
|
client.readContract({ address: cfg.issuer, abi: CNF_ABI, functionName: "zkVerifier" }),
|
|
230
|
+
client.readContract({ address: cfg.issuer, abi: CNF_ABI, functionName: "eas" }),
|
|
228
231
|
]);
|
|
232
|
+
const hasEASPath = eas !== ZERO;
|
|
233
|
+
const hasZKPath = root !== 0n && verifier !== ZERO;
|
|
234
|
+
if (hasEASPath)
|
|
235
|
+
ok("issuance path", `${fmt.badge("EAS/mock", "green")} ${fmt.addr(eas)}`);
|
|
236
|
+
else if (hasZKPath)
|
|
237
|
+
ok("issuance path", fmt.badge("ZK", "green"));
|
|
238
|
+
else
|
|
239
|
+
warn("issuance path", fmt.badge("not ready", "yellow"));
|
|
229
240
|
if (root === 0n)
|
|
230
241
|
warn("merkleRoot", fmt.badge("not set", "yellow"));
|
|
231
242
|
else
|
|
@@ -234,9 +245,11 @@ export async function demoCheck(opts) {
|
|
|
234
245
|
warn("zkVerifier", fmt.badge("not set", "yellow"));
|
|
235
246
|
else
|
|
236
247
|
ok("zkVerifier", fmt.addr(verifier));
|
|
248
|
+
pass(hasEASPath || hasZKPath);
|
|
237
249
|
}
|
|
238
250
|
catch (e) {
|
|
239
251
|
bad("issuer reads", e instanceof Error ? e.message.split("\n")[0] : String(e));
|
|
252
|
+
pass(false);
|
|
240
253
|
}
|
|
241
254
|
if (wallet && isAddress(wallet)) {
|
|
242
255
|
try {
|
|
@@ -344,3 +357,41 @@ export async function demoCheck(opts) {
|
|
|
344
357
|
log.command(`ilal swap --amount-in 0.001 --token-in ${suggestedTokenIn}`);
|
|
345
358
|
console.log();
|
|
346
359
|
}
|
|
360
|
+
export async function demoFaucet(opts) {
|
|
361
|
+
const cfg = loadConfig();
|
|
362
|
+
const chain = CHAINS[cfg.chain ?? "84532"] ?? baseSepolia;
|
|
363
|
+
const rawKey = opts.privateKey ?? process.env["PRIVATE_KEY"];
|
|
364
|
+
if (!rawKey || !isHex(rawKey) || rawKey.length !== 66) {
|
|
365
|
+
die("Private key required. Use --private-key or set PRIVATE_KEY env var.");
|
|
366
|
+
}
|
|
367
|
+
if (!cfg.tokenA || !cfg.tokenB || !isAddress(cfg.tokenA) || !isAddress(cfg.tokenB)) {
|
|
368
|
+
die("tokenA/tokenB required. Run `ilal init` with demo token addresses first.");
|
|
369
|
+
}
|
|
370
|
+
const account = privateKeyToAccount(rawKey);
|
|
371
|
+
const wallet = opts.wallet ?? account.address;
|
|
372
|
+
if (!isAddress(wallet))
|
|
373
|
+
die(`Invalid wallet address: ${wallet}`);
|
|
374
|
+
const client = createPublicClient({ chain, transport: http(cfg.rpc) });
|
|
375
|
+
const walletClient = createWalletClient({ account, chain, transport: http(cfg.rpc) });
|
|
376
|
+
header("ILAL Demo Faucet", chain.name);
|
|
377
|
+
log.kv("recipient", fmt.addr(wallet));
|
|
378
|
+
log.line();
|
|
379
|
+
for (const token of [cfg.tokenA, cfg.tokenB]) {
|
|
380
|
+
const [symbol, decimals] = await Promise.all([
|
|
381
|
+
client.readContract({ address: token, abi: ERC20_ABI, functionName: "symbol" }),
|
|
382
|
+
client.readContract({ address: token, abi: ERC20_ABI, functionName: "decimals" }),
|
|
383
|
+
]);
|
|
384
|
+
const amount = parseUnits(opts.amount ?? "10000", decimals);
|
|
385
|
+
const spin = new Spinner(`Minting ${opts.amount ?? "10000"} ${symbol}…`).start();
|
|
386
|
+
const hash = await walletClient.writeContract({
|
|
387
|
+
address: token,
|
|
388
|
+
abi: ERC20_ABI,
|
|
389
|
+
functionName: "mint",
|
|
390
|
+
args: [wallet, amount],
|
|
391
|
+
});
|
|
392
|
+
await client.waitForTransactionReceipt({ hash });
|
|
393
|
+
spin.succeed(`Minted ${symbol} ${fmt.hash(hash)}`);
|
|
394
|
+
}
|
|
395
|
+
log.callout("Demo tokens ready", "wallet can now pass token-balance preflight checks", "green");
|
|
396
|
+
console.log();
|
|
397
|
+
}
|
package/dist/commands/deploy.js
CHANGED
|
@@ -58,13 +58,15 @@ export async function deploy(opts) {
|
|
|
58
58
|
};
|
|
59
59
|
if (isMock) {
|
|
60
60
|
env["WALLET_TO_SEED"] = opts.walletToSeed;
|
|
61
|
+
env["WALLET"] = opts.walletToSeed;
|
|
62
|
+
env["MOCK_EAS"] = "true";
|
|
61
63
|
}
|
|
62
64
|
else {
|
|
63
65
|
env["EAS_ADDRESS"] = easAddress;
|
|
64
66
|
env["SCHEMA_UID"] = COINBASE_SCHEMA_UID;
|
|
65
67
|
env["TRUSTED_ATTESTER"] = COINBASE_ATTESTER;
|
|
66
68
|
}
|
|
67
|
-
const script = isMock ? "script/
|
|
69
|
+
const script = isMock ? "script/DeployDemo.s.sol" : "script/Deploy.s.sol";
|
|
68
70
|
const flags = [
|
|
69
71
|
`--rpc-url ${rpc}`,
|
|
70
72
|
opts.broadcast ? "--broadcast" : "",
|
package/dist/commands/init.js
CHANGED
|
@@ -10,9 +10,16 @@ import { fmt, log, header, die } from "../ui.js";
|
|
|
10
10
|
// Known testnet / mainnet addresses for quick init
|
|
11
11
|
const PRESETS = {
|
|
12
12
|
"84532": {
|
|
13
|
-
issuer: "
|
|
14
|
-
hook: "
|
|
15
|
-
registry: "
|
|
13
|
+
issuer: "0xc4E032A7574016bd0e3d1a5BbFdE886af09CeD9A",
|
|
14
|
+
hook: "0xF5066ad9c25F3f54cfb19609A60187C48C184A80",
|
|
15
|
+
registry: "0x910a3efDc426f3216738106dd0DC6EA696477233",
|
|
16
|
+
router: "0x7727F0f3EBe99A558487394D001950ee6B33BB86",
|
|
17
|
+
treasury: "0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38",
|
|
18
|
+
tokenA: "0x582362E608F36850F6f641510d5D19C1EaB4cb27",
|
|
19
|
+
tokenB: "0x6eBBdAC70EC422C512727B25c7F0D9120ed101Ff",
|
|
20
|
+
poolId: "0xc1c8f29d6f03b5cd18bf2b862d48f45cc338022a154945b89c4bcb0a3e11e87f",
|
|
21
|
+
fee: "8388608",
|
|
22
|
+
tickSpacing: "60",
|
|
16
23
|
rpc: "https://sepolia.base.org",
|
|
17
24
|
},
|
|
18
25
|
"8453": {
|
|
@@ -35,13 +42,13 @@ export async function init(opts) {
|
|
|
35
42
|
issuer: opts.issuer ?? preset["issuer"],
|
|
36
43
|
hook: opts.hook ?? preset["hook"],
|
|
37
44
|
registry: opts.registry ?? preset["registry"],
|
|
38
|
-
router: opts.router,
|
|
39
|
-
treasury: opts.treasury,
|
|
40
|
-
tokenA: opts.tokenA,
|
|
41
|
-
tokenB: opts.tokenB,
|
|
42
|
-
poolId: opts.poolId,
|
|
43
|
-
fee: opts.fee,
|
|
44
|
-
tickSpacing: opts.tickSpacing,
|
|
45
|
+
router: opts.router ?? preset["router"],
|
|
46
|
+
treasury: opts.treasury ?? preset["treasury"],
|
|
47
|
+
tokenA: opts.tokenA ?? preset["tokenA"],
|
|
48
|
+
tokenB: opts.tokenB ?? preset["tokenB"],
|
|
49
|
+
poolId: opts.poolId ?? preset["poolId"],
|
|
50
|
+
fee: opts.fee ?? preset["fee"],
|
|
51
|
+
tickSpacing: opts.tickSpacing ?? preset["tickSpacing"],
|
|
45
52
|
rpc: opts.rpc ?? preset["rpc"],
|
|
46
53
|
...(opts.circuitDir ? { circuitDir: opts.circuitDir } : {}),
|
|
47
54
|
};
|
|
@@ -23,9 +23,17 @@ const CHAINS = { "8453": base, "84532": baseSepolia };
|
|
|
23
23
|
const ERC20_ABI = [
|
|
24
24
|
{ name: "symbol", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "string" }] },
|
|
25
25
|
{ name: "decimals", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "uint8" }] },
|
|
26
|
+
{ name: "balanceOf", type: "function", stateMutability: "view", inputs: [{ name: "owner", type: "address" }], outputs: [{ type: "uint256" }] },
|
|
26
27
|
{ name: "allowance", type: "function", stateMutability: "view", inputs: [{ name: "owner", type: "address" }, { name: "spender", type: "address" }], outputs: [{ type: "uint256" }] },
|
|
27
28
|
{ name: "approve", type: "function", stateMutability: "nonpayable", inputs: [{ name: "spender", type: "address" }, { name: "amount", type: "uint256" }], outputs: [{ type: "bool" }] },
|
|
28
29
|
];
|
|
30
|
+
const CNF_ABI = [
|
|
31
|
+
{ name: "isValid", type: "function", stateMutability: "view", inputs: [{ name: "wallet", type: "address" }], outputs: [{ type: "bool" }] },
|
|
32
|
+
{ name: "credentialOf", type: "function", stateMutability: "view", inputs: [{ name: "wallet", type: "address" }], outputs: [{ type: "uint256" }] },
|
|
33
|
+
{ name: "merkleRoot", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "uint256" }] },
|
|
34
|
+
{ name: "zkVerifier", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
35
|
+
{ name: "eas", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
36
|
+
];
|
|
29
37
|
const ROUTER_LIQUIDITY_ABI = [
|
|
30
38
|
{
|
|
31
39
|
name: "addLiquidity", type: "function", stateMutability: "payable",
|
|
@@ -94,6 +102,7 @@ function txUrl(chain, hash) {
|
|
|
94
102
|
const baseUrl = chain.blockExplorers?.default?.url;
|
|
95
103
|
return baseUrl ? `${baseUrl}/tx/${hash}` : undefined;
|
|
96
104
|
}
|
|
105
|
+
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
97
106
|
// ─── Shared core ──────────────────────────────────────────────────────────────
|
|
98
107
|
async function executeLiquidity(action, opts) {
|
|
99
108
|
const cfg = withConfig(opts);
|
|
@@ -143,11 +152,51 @@ async function executeLiquidity(action, opts) {
|
|
|
143
152
|
log.kv("tickUpper", tickUpper.toString());
|
|
144
153
|
log.kv("liquidity", liquidity.toString());
|
|
145
154
|
log.line();
|
|
155
|
+
if (liquidity <= 0n) {
|
|
156
|
+
die("liquidity must be greater than 0. No approval or liquidity transaction was sent.");
|
|
157
|
+
}
|
|
158
|
+
const preflightSpin = new Spinner("Running preflight checks…").start();
|
|
159
|
+
const [root, verifier, eas, valid, tokenId, sym0, sym1, bal0, bal1] = await Promise.all([
|
|
160
|
+
pubClient.readContract({ address: cfg.issuer, abi: CNF_ABI, functionName: "merkleRoot" }),
|
|
161
|
+
pubClient.readContract({ address: cfg.issuer, abi: CNF_ABI, functionName: "zkVerifier" }),
|
|
162
|
+
pubClient.readContract({ address: cfg.issuer, abi: CNF_ABI, functionName: "eas" }),
|
|
163
|
+
pubClient.readContract({ address: cfg.issuer, abi: CNF_ABI, functionName: "isValid", args: [account.address] }),
|
|
164
|
+
pubClient.readContract({ address: cfg.issuer, abi: CNF_ABI, functionName: "credentialOf", args: [account.address] }),
|
|
165
|
+
pubClient.readContract({ address: c0, abi: ERC20_ABI, functionName: "symbol" }),
|
|
166
|
+
pubClient.readContract({ address: c1, abi: ERC20_ABI, functionName: "symbol" }),
|
|
167
|
+
pubClient.readContract({ address: c0, abi: ERC20_ABI, functionName: "balanceOf", args: [account.address] }),
|
|
168
|
+
pubClient.readContract({ address: c1, abi: ERC20_ABI, functionName: "balanceOf", args: [account.address] }),
|
|
169
|
+
]);
|
|
170
|
+
preflightSpin.stop();
|
|
171
|
+
const preflightErrors = [];
|
|
172
|
+
const hasEASPath = eas !== ZERO_ADDRESS;
|
|
173
|
+
const hasZKPath = verifier !== ZERO_ADDRESS && root !== 0n;
|
|
174
|
+
if (tokenId === 0n) {
|
|
175
|
+
preflightErrors.push("wallet has no CNF credential; mint one before changing liquidity.");
|
|
176
|
+
if (hasEASPath)
|
|
177
|
+
preflightErrors.push("issuer supports EAS/mock attestation minting: run `ilal credential mint --attestation <uid>`.");
|
|
178
|
+
else if (hasZKPath)
|
|
179
|
+
preflightErrors.push(`issuer supports ZK minting: run \`ilal credential prove --wallet ${account.address}\`.`);
|
|
180
|
+
else
|
|
181
|
+
preflightErrors.push("issuer has no active issuance path: EAS is unset and ZK verifier/root are not both configured.");
|
|
182
|
+
}
|
|
183
|
+
else if (!valid)
|
|
184
|
+
preflightErrors.push("wallet CNF credential exists but is not valid.");
|
|
185
|
+
if (action === "add" && (bal0 === 0n || bal1 === 0n)) {
|
|
186
|
+
preflightErrors.push(`token balances are not ready for adding liquidity: ${sym0}=${bal0.toString()} wei, ${sym1}=${bal1.toString()} wei.`);
|
|
187
|
+
}
|
|
188
|
+
if (preflightErrors.length > 0) {
|
|
189
|
+
log.section("Preflight Failed");
|
|
190
|
+
for (const error of preflightErrors)
|
|
191
|
+
log.warn(error);
|
|
192
|
+
console.log();
|
|
193
|
+
die(`${verb} liquidity not sent. Fix the preflight issues above.`);
|
|
194
|
+
}
|
|
146
195
|
// Approve both tokens if adding liquidity
|
|
147
196
|
if (action === "add") {
|
|
148
197
|
const MAX = 2n ** 256n - 1n;
|
|
149
198
|
for (const token of [c0, c1]) {
|
|
150
|
-
const sym =
|
|
199
|
+
const sym = token.toLowerCase() === c0.toLowerCase() ? sym0 : sym1;
|
|
151
200
|
const allowed = await pubClient.readContract({
|
|
152
201
|
address: token, abi: ERC20_ABI, functionName: "allowance",
|
|
153
202
|
args: [account.address, cfg.router],
|
package/dist/commands/mint.js
CHANGED
|
@@ -26,7 +26,11 @@ const CNF_ISSUER_ABI = [
|
|
|
26
26
|
inputs: [{ name: "wallet", type: "address" }],
|
|
27
27
|
outputs: [{ type: "bool" }],
|
|
28
28
|
},
|
|
29
|
+
{ name: "eas", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
30
|
+
{ name: "schemaUID", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "bytes32" }] },
|
|
31
|
+
{ name: "trustedAttester", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
29
32
|
];
|
|
33
|
+
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
30
34
|
async function sendMintTx(mode, opts) {
|
|
31
35
|
const rawKey = opts.privateKey ?? process.env["PRIVATE_KEY"];
|
|
32
36
|
if (!rawKey)
|
|
@@ -54,9 +58,14 @@ async function sendMintTx(mode, opts) {
|
|
|
54
58
|
log.line();
|
|
55
59
|
// Verify EAS attestation exists on-chain before sending tx
|
|
56
60
|
log.step("Verifying attestation on EAS…");
|
|
57
|
-
const
|
|
61
|
+
const [issuerEAS, issuerSchema, issuerAttester] = await Promise.all([
|
|
62
|
+
publicClient.readContract({ address: opts.issuer, abi: CNF_ISSUER_ABI, functionName: "eas" }),
|
|
63
|
+
publicClient.readContract({ address: opts.issuer, abi: CNF_ISSUER_ABI, functionName: "schemaUID" }),
|
|
64
|
+
publicClient.readContract({ address: opts.issuer, abi: CNF_ISSUER_ABI, functionName: "trustedAttester" }),
|
|
65
|
+
]);
|
|
66
|
+
const easAddress = issuerEAS !== ZERO_ADDRESS ? issuerEAS : EAS_ADDRESSES[chain.id];
|
|
58
67
|
if (!easAddress)
|
|
59
|
-
die(`No EAS contract known for chain ${chain.id}. Use
|
|
68
|
+
die(`No EAS contract known for chain ${chain.id}. Use an issuer with eas() configured.`);
|
|
60
69
|
const EAS_ABI = [
|
|
61
70
|
{
|
|
62
71
|
name: "getAttestation",
|
|
@@ -95,18 +104,24 @@ async function sendMintTx(mode, opts) {
|
|
|
95
104
|
if (attestation.recipient.toLowerCase() !== account.address.toLowerCase())
|
|
96
105
|
die(`Attestation recipient (${attestation.recipient}) does not match your wallet (${account.address}).`);
|
|
97
106
|
log.ok(`Attester: ${attestation.attester}`);
|
|
98
|
-
if (attestation.attester.toLowerCase() ===
|
|
107
|
+
if (attestation.attester.toLowerCase() === issuerAttester.toLowerCase()) {
|
|
108
|
+
log.ok("Issuer trusted attester confirmed");
|
|
109
|
+
}
|
|
110
|
+
else if (attestation.attester.toLowerCase() === COINBASE_ATTESTER.toLowerCase()) {
|
|
99
111
|
log.ok("Coinbase Verifications attester confirmed");
|
|
100
112
|
}
|
|
101
113
|
else {
|
|
102
|
-
log.warn(`
|
|
114
|
+
log.warn(`Attester mismatch — issuer expects ${issuerAttester}`);
|
|
103
115
|
}
|
|
104
|
-
if (attestation.schema.toLowerCase() !==
|
|
105
|
-
log.warn(`Schema mismatch —
|
|
116
|
+
if (attestation.schema.toLowerCase() !== issuerSchema.toLowerCase()) {
|
|
117
|
+
log.warn(`Schema mismatch — issuer expects ${issuerSchema}, got ${attestation.schema}`);
|
|
106
118
|
}
|
|
107
|
-
else {
|
|
119
|
+
else if (attestation.schema.toLowerCase() === COINBASE_SCHEMA_UID.toLowerCase()) {
|
|
108
120
|
log.ok("Coinbase Account Verification schema confirmed");
|
|
109
121
|
}
|
|
122
|
+
else {
|
|
123
|
+
log.ok("Issuer schema confirmed");
|
|
124
|
+
}
|
|
110
125
|
log.line();
|
|
111
126
|
if (opts.simulate) {
|
|
112
127
|
log.ok("Simulation complete — attestation valid, tx would succeed");
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
* # Step 1 — queue a new root (requires owner key, executes immediately)
|
|
13
13
|
* PRIVATE_KEY=0x... ilal oracle propose-root \
|
|
14
14
|
* --root 0xDEADBEEF... \
|
|
15
|
-
* --issuer
|
|
15
|
+
* --issuer 0xc4E032...
|
|
16
16
|
*
|
|
17
17
|
* # Step 2 — after ROOT_DELAY (48 h) has elapsed, activate it
|
|
18
18
|
* PRIVATE_KEY=0x... ilal oracle activate-root \
|
|
19
|
-
* --issuer
|
|
19
|
+
* --issuer 0xc4E032...
|
|
20
20
|
*
|
|
21
21
|
* # Same pattern for the ZK verifier (VERIFIER_DELAY = 72 h)
|
|
22
22
|
* PRIVATE_KEY=0x... ilal oracle propose-verifier --verifier 0x... --issuer 0x...
|
package/dist/commands/oracle.js
CHANGED
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
* # Step 1 — queue a new root (requires owner key, executes immediately)
|
|
13
13
|
* PRIVATE_KEY=0x... ilal oracle propose-root \
|
|
14
14
|
* --root 0xDEADBEEF... \
|
|
15
|
-
* --issuer
|
|
15
|
+
* --issuer 0xc4E032...
|
|
16
16
|
*
|
|
17
17
|
* # Step 2 — after ROOT_DELAY (48 h) has elapsed, activate it
|
|
18
18
|
* PRIVATE_KEY=0x... ilal oracle activate-root \
|
|
19
|
-
* --issuer
|
|
19
|
+
* --issuer 0xc4E032...
|
|
20
20
|
*
|
|
21
21
|
* # Same pattern for the ZK verifier (VERIFIER_DELAY = 72 h)
|
|
22
22
|
* PRIVATE_KEY=0x... ilal oracle propose-verifier --verifier 0x... --issuer 0x...
|
package/dist/commands/prove.d.ts
CHANGED
package/dist/commands/prove.js
CHANGED
package/dist/commands/status.js
CHANGED
|
@@ -14,6 +14,7 @@ const CNF_ABI = [
|
|
|
14
14
|
{ name: "getCredential", type: "function", stateMutability: "view", inputs: [{ name: "tokenId", type: "uint256" }], outputs: [{ type: "tuple", components: [{ name: "holder", type: "address" }, { name: "issuer", type: "address" }, { name: "credentialType", type: "bytes32" }, { name: "issuedAt", type: "uint64" }, { name: "expiresAt", type: "uint64" }, { name: "revoked", type: "bool" }] }] },
|
|
15
15
|
{ name: "merkleRoot", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "uint256" }] },
|
|
16
16
|
{ name: "zkVerifier", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
17
|
+
{ name: "eas", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
17
18
|
];
|
|
18
19
|
const HOOK_ABI = [
|
|
19
20
|
{ name: "issuer", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
@@ -21,6 +22,7 @@ const HOOK_ABI = [
|
|
|
21
22
|
const REGISTRY_ABI = [
|
|
22
23
|
{ name: "getPolicy", type: "function", stateMutability: "view", inputs: [{ name: "poolId", type: "bytes32" }], outputs: [{ type: "tuple", components: [{ name: "cnfIssuer", type: "address" }, { name: "requiredCredentialType", type: "bytes32" }, { name: "enabled", type: "bool" }] }] },
|
|
23
24
|
];
|
|
25
|
+
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
24
26
|
function daysUntil(unixSec) {
|
|
25
27
|
return Math.floor((unixSec * 1000 - Date.now()) / 86_400_000);
|
|
26
28
|
}
|
|
@@ -88,20 +90,28 @@ export async function status(opts) {
|
|
|
88
90
|
if (cfg.issuer && isAddress(cfg.issuer)) {
|
|
89
91
|
const spin = new Spinner("Fetching issuer config…").start();
|
|
90
92
|
try {
|
|
91
|
-
const [root, verifier] = await Promise.all([
|
|
93
|
+
const [root, verifier, eas] = await Promise.all([
|
|
92
94
|
client.readContract({ address: cfg.issuer, abi: CNF_ABI, functionName: "merkleRoot" }),
|
|
93
95
|
client.readContract({ address: cfg.issuer, abi: CNF_ABI, functionName: "zkVerifier" }),
|
|
96
|
+
client.readContract({ address: cfg.issuer, abi: CNF_ABI, functionName: "eas" }),
|
|
94
97
|
]);
|
|
95
98
|
spin.stop();
|
|
99
|
+
const hasEASPath = eas !== ZERO_ADDRESS;
|
|
100
|
+
const hasZKPath = root !== 0n && verifier !== ZERO_ADDRESS;
|
|
96
101
|
log.section("Issuer");
|
|
97
102
|
log.kv("address", fmt.cyan(cfg.issuer));
|
|
98
|
-
log.kv("
|
|
103
|
+
log.kv("issuance", hasEASPath
|
|
104
|
+
? `${fmt.badge("EAS", "green")} ${fmt.addr(eas)}`
|
|
105
|
+
: hasZKPath
|
|
106
|
+
? fmt.badge("ZK", "green")
|
|
107
|
+
: fmt.badge("not ready", "red"));
|
|
108
|
+
log.kv("zkVerifier", verifier === ZERO_ADDRESS
|
|
99
109
|
? fmt.badge("not set", "red")
|
|
100
110
|
: fmt.green(fmt.addr(verifier)));
|
|
101
111
|
log.kv("merkleRoot", root === 0n
|
|
102
112
|
? fmt.badge("not set", "red")
|
|
103
113
|
: fmt.gray(root.toString().slice(0, 20) + "…"));
|
|
104
|
-
issuerReady =
|
|
114
|
+
issuerReady = hasEASPath || hasZKPath;
|
|
105
115
|
}
|
|
106
116
|
catch (e) {
|
|
107
117
|
spin.stop();
|
package/dist/commands/swap.js
CHANGED
|
@@ -56,6 +56,13 @@ const ROUTER_ABI = [
|
|
|
56
56
|
outputs: [{ name: "delta", type: "int256" }],
|
|
57
57
|
},
|
|
58
58
|
];
|
|
59
|
+
const CNF_ABI = [
|
|
60
|
+
{ name: "isValid", type: "function", stateMutability: "view", inputs: [{ name: "wallet", type: "address" }], outputs: [{ type: "bool" }] },
|
|
61
|
+
{ name: "credentialOf", type: "function", stateMutability: "view", inputs: [{ name: "wallet", type: "address" }], outputs: [{ type: "uint256" }] },
|
|
62
|
+
{ name: "merkleRoot", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "uint256" }] },
|
|
63
|
+
{ name: "zkVerifier", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
64
|
+
{ name: "eas", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] },
|
|
65
|
+
];
|
|
59
66
|
// ─── Session helpers ──────────────────────────────────────────────────────────
|
|
60
67
|
const SESSION_TOKEN_TYPE = [
|
|
61
68
|
{ name: "user", type: "address" },
|
|
@@ -77,6 +84,7 @@ const MIN_SQRT_PRICE = 4295128740n; // TickMath.MIN_SQRT_PRICE + 1
|
|
|
77
84
|
const MAX_SQRT_PRICE = 1461446703485210103287273052203988822378723970341n; // MAX - 1
|
|
78
85
|
const DYNAMIC_FEE_FLAG = 8388608;
|
|
79
86
|
const PIPS_DENOMINATOR = 1000000n;
|
|
87
|
+
const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
80
88
|
function txUrl(chain, hash) {
|
|
81
89
|
const baseUrl = chain.blockExplorers?.default?.url;
|
|
82
90
|
return baseUrl ? `${baseUrl}/tx/${hash}` : undefined;
|
|
@@ -148,6 +156,9 @@ export async function swap(opts) {
|
|
|
148
156
|
]);
|
|
149
157
|
spin.stop();
|
|
150
158
|
const amountIn = parseUnits(opts.amountIn, decimals);
|
|
159
|
+
if (amountIn <= 0n) {
|
|
160
|
+
die("amount-in must be greater than 0. Use `ilal swap --simulate` for a dry run.");
|
|
161
|
+
}
|
|
151
162
|
log.kv("amount", `${opts.amountIn} ${fmt.cyan(symbol)} (${amountIn.toString()} wei)`);
|
|
152
163
|
let protocolFeePips = 0;
|
|
153
164
|
let treasury;
|
|
@@ -162,34 +173,47 @@ export async function swap(opts) {
|
|
|
162
173
|
}
|
|
163
174
|
const protocolFeeAmount = amountIn * BigInt(protocolFeePips) / PIPS_DENOMINATOR;
|
|
164
175
|
const totalDebit = amountIn + protocolFeeAmount;
|
|
176
|
+
const preflightSpin = new Spinner("Running preflight checks…").start();
|
|
177
|
+
const [root, verifier, eas, valid, tokenId, balance] = await Promise.all([
|
|
178
|
+
pubClient.readContract({ address: cfg.issuer, abi: CNF_ABI, functionName: "merkleRoot" }),
|
|
179
|
+
pubClient.readContract({ address: cfg.issuer, abi: CNF_ABI, functionName: "zkVerifier" }),
|
|
180
|
+
pubClient.readContract({ address: cfg.issuer, abi: CNF_ABI, functionName: "eas" }),
|
|
181
|
+
pubClient.readContract({ address: cfg.issuer, abi: CNF_ABI, functionName: "isValid", args: [account.address] }),
|
|
182
|
+
pubClient.readContract({ address: cfg.issuer, abi: CNF_ABI, functionName: "credentialOf", args: [account.address] }),
|
|
183
|
+
pubClient.readContract({ address: tokenIn, abi: ERC20_ABI, functionName: "balanceOf", args: [account.address] }),
|
|
184
|
+
]);
|
|
185
|
+
preflightSpin.stop();
|
|
186
|
+
const preflightErrors = [];
|
|
187
|
+
const hasEASPath = eas !== ZERO_ADDRESS;
|
|
188
|
+
const hasZKPath = verifier !== ZERO_ADDRESS && root !== 0n;
|
|
189
|
+
if (tokenId === 0n) {
|
|
190
|
+
preflightErrors.push(`wallet has no CNF credential; mint one before trading.`);
|
|
191
|
+
if (hasEASPath)
|
|
192
|
+
preflightErrors.push("issuer supports EAS/mock attestation minting: run `ilal credential mint --attestation <uid>`.");
|
|
193
|
+
else if (hasZKPath)
|
|
194
|
+
preflightErrors.push(`issuer supports ZK minting: run \`ilal credential prove --wallet ${account.address}\`.`);
|
|
195
|
+
else
|
|
196
|
+
preflightErrors.push("issuer has no active issuance path: EAS is unset and ZK verifier/root are not both configured.");
|
|
197
|
+
}
|
|
198
|
+
else if (!valid)
|
|
199
|
+
preflightErrors.push("wallet CNF credential exists but is not valid.");
|
|
200
|
+
if (balance < totalDebit)
|
|
201
|
+
preflightErrors.push(`insufficient ${symbol} balance: need ${totalDebit.toString()} wei including ILAL fee, have ${balance.toString()} wei.`);
|
|
202
|
+
if (preflightErrors.length > 0) {
|
|
203
|
+
log.section("Preflight Failed");
|
|
204
|
+
for (const error of preflightErrors)
|
|
205
|
+
log.warn(error);
|
|
206
|
+
console.log();
|
|
207
|
+
if (!opts.simulate) {
|
|
208
|
+
die("Swap not sent. Fix the preflight issues above, or use --simulate to inspect session/hookData only.");
|
|
209
|
+
}
|
|
210
|
+
}
|
|
165
211
|
log.deal([
|
|
166
212
|
{ label: "verified input", value: `${opts.amountIn} ${symbol}`, note: "exact-in swap", tone: "cyan" },
|
|
167
213
|
{ label: "LP fee", value: poolFeePercent(parseInt(cfg.fee ?? "3000")), note: "hook-priced flow", tone: "green" },
|
|
168
214
|
{ label: "ILAL fee", value: protocolFeePips > 0 ? pipsToPercent(protocolFeePips) : "off", note: protocolFeePips > 0 ? "protocol revenue" : "legacy router", tone: protocolFeePips > 0 ? "cyan" : "gray" },
|
|
169
215
|
]);
|
|
170
216
|
log.line();
|
|
171
|
-
// Check allowance — approve if needed
|
|
172
|
-
const approveSpin = new Spinner("Checking allowance…").start();
|
|
173
|
-
const allowed = await pubClient.readContract({
|
|
174
|
-
address: tokenIn,
|
|
175
|
-
abi: ERC20_ABI,
|
|
176
|
-
functionName: "allowance",
|
|
177
|
-
args: [account.address, cfg.router],
|
|
178
|
-
});
|
|
179
|
-
if (allowed < totalDebit) {
|
|
180
|
-
approveSpin.update(`Approving ${symbol} for ILALRouter…`);
|
|
181
|
-
const approveHash = await walClient.writeContract({
|
|
182
|
-
address: tokenIn,
|
|
183
|
-
abi: ERC20_ABI,
|
|
184
|
-
functionName: "approve",
|
|
185
|
-
args: [cfg.router, totalDebit * 10n], // approve 10× for future swaps
|
|
186
|
-
});
|
|
187
|
-
await pubClient.waitForTransactionReceipt({ hash: approveHash });
|
|
188
|
-
approveSpin.succeed(`Approved ${symbol} ${fmt.gray(fmt.hash(approveHash))}`);
|
|
189
|
-
}
|
|
190
|
-
else {
|
|
191
|
-
approveSpin.succeed(`Allowance ok (${fmt.gray(allowed.toString())} wei)`);
|
|
192
|
-
}
|
|
193
217
|
// Sign session token
|
|
194
218
|
const signSpin = new Spinner("Signing session token…").start();
|
|
195
219
|
const ttl = parseInt(opts.ttl ?? "600");
|
|
@@ -233,11 +257,33 @@ export async function swap(opts) {
|
|
|
233
257
|
}
|
|
234
258
|
log.line();
|
|
235
259
|
if (opts.simulate) {
|
|
236
|
-
log.ok("Simulation mode — skipping on-chain tx");
|
|
260
|
+
log.ok("Simulation mode — skipping approval and on-chain tx");
|
|
237
261
|
log.kv("hookData", hookData.slice(0, 22) + "…");
|
|
238
262
|
console.log();
|
|
239
263
|
return;
|
|
240
264
|
}
|
|
265
|
+
// Check allowance — approve if needed
|
|
266
|
+
const approveSpin = new Spinner("Checking allowance…").start();
|
|
267
|
+
const allowed = await pubClient.readContract({
|
|
268
|
+
address: tokenIn,
|
|
269
|
+
abi: ERC20_ABI,
|
|
270
|
+
functionName: "allowance",
|
|
271
|
+
args: [account.address, cfg.router],
|
|
272
|
+
});
|
|
273
|
+
if (allowed < totalDebit) {
|
|
274
|
+
approveSpin.update(`Approving ${symbol} for ILALRouter…`);
|
|
275
|
+
const approveHash = await walClient.writeContract({
|
|
276
|
+
address: tokenIn,
|
|
277
|
+
abi: ERC20_ABI,
|
|
278
|
+
functionName: "approve",
|
|
279
|
+
args: [cfg.router, totalDebit * 10n], // approve 10× for future swaps
|
|
280
|
+
});
|
|
281
|
+
await pubClient.waitForTransactionReceipt({ hash: approveHash });
|
|
282
|
+
approveSpin.succeed(`Approved ${symbol} ${fmt.gray(fmt.hash(approveHash))}`);
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
approveSpin.succeed(`Allowance ok (${fmt.gray(allowed.toString())} wei)`);
|
|
286
|
+
}
|
|
241
287
|
// Build PoolKey
|
|
242
288
|
const poolKey = {
|
|
243
289
|
currency0: c0,
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { proofMint, proofRenew } from "./commands/proof.js";
|
|
|
8
8
|
import { sessionSign } from "./commands/session.js";
|
|
9
9
|
import { poolPolicySet, poolPolicyGet } from "./commands/pool.js";
|
|
10
10
|
import { deploy } from "./commands/deploy.js";
|
|
11
|
-
import { demo, demoCheck } from "./commands/demo.js";
|
|
11
|
+
import { demo, demoCheck, demoFaucet } from "./commands/demo.js";
|
|
12
12
|
import { init } from "./commands/init.js";
|
|
13
13
|
import { status } from "./commands/status.js";
|
|
14
14
|
import { swap } from "./commands/swap.js";
|
|
@@ -19,7 +19,7 @@ const program = new Command();
|
|
|
19
19
|
program
|
|
20
20
|
.name("ilal")
|
|
21
21
|
.description("ILAL Protocol CLI — Uniswap v4 compliance hook toolkit")
|
|
22
|
-
.version("0.
|
|
22
|
+
.version("0.2.2")
|
|
23
23
|
.addHelpText("before", `\n ${fmt.bold(fmt.cyan("◆"))} ${fmt.bold("ILAL Protocol")} ${fmt.gray("Uniswap v4 Compliance Hook")}\n`);
|
|
24
24
|
// ─── init ─────────────────────────────────────────────────────────────────────
|
|
25
25
|
program
|
|
@@ -72,6 +72,15 @@ demoCommand
|
|
|
72
72
|
.action(async (opts) => {
|
|
73
73
|
await demoCheck(opts).catch(err);
|
|
74
74
|
});
|
|
75
|
+
demoCommand
|
|
76
|
+
.command("faucet")
|
|
77
|
+
.description("Mint mock demo TOKA/TOKB to a wallet (testnet mock tokens only)")
|
|
78
|
+
.option("-w, --wallet <address>", "Recipient wallet (defaults to PRIVATE_KEY address)")
|
|
79
|
+
.option("--amount <tokens>", "Human token amount to mint for each token", "10000")
|
|
80
|
+
.option("-k, --private-key <hex>", "Private key that pays gas")
|
|
81
|
+
.action(async (opts) => {
|
|
82
|
+
await demoFaucet(opts).catch(err);
|
|
83
|
+
});
|
|
75
84
|
const err = (e) => {
|
|
76
85
|
console.error(fmt.red(`\nError: ${e instanceof Error ? e.message : String(e)}\n`));
|
|
77
86
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ilalv3/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "ILAL Protocol CLI — compliant swaps and credential management for Uniswap v4",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
],
|
|
24
24
|
"repository": {
|
|
25
25
|
"type": "git",
|
|
26
|
-
"url": "git+https://github.com/ilal-
|
|
26
|
+
"url": "git+https://github.com/rpnny/ilal-cli.git"
|
|
27
27
|
},
|
|
28
|
-
"homepage": "https://github.com/ilal-
|
|
28
|
+
"homepage": "https://github.com/rpnny/ilal-cli#readme",
|
|
29
29
|
"publishConfig": {
|
|
30
30
|
"access": "public"
|
|
31
31
|
},
|