@liens/cli 0.1.0 → 0.1.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 CHANGED
@@ -1,18 +1,48 @@
1
- # lien-cli
1
+ # @liens/cli
2
+
3
+ The command-line half of the same toolkit the LIEN Designer runs in the browser. Both call `@liens/sdk`; both fold a Composition through the same Rust `hook-runtime` the Anchor executor links. The number `lien` prints is the number the chain runs.
2
4
 
3
5
  ```
4
- npm i -g lien-cli
6
+ npm i -g @liens/cli
7
+ lien list # the six standard knots
8
+ lien create slip-knot --pool SOL-USDC --venue marginfi # scaffold a Composition
9
+ lien simulate --pool SOL-USDC --steps 240 # backtest against pool history
10
+ lien deploy --cluster devnet # print the on-chain install plan (does NOT broadcast)
5
11
  ```
6
12
 
7
- ## Commands
13
+ The actual broadcast is `lien deploy --cluster <cluster> --execute --keypair <path>`. The `--execute` flag is explicit by design — a fat-fingered `lien deploy` should not write to mainnet.
8
14
 
9
- ```
10
- lien list print the standard hook library
11
- lien create hook --name MyHook scaffold a hook source file
12
- lien create composition prompt-driven composition.ts
13
- lien simulate --pool SOL-USDC run the deterministic simulator
14
- lien action write .github/workflows/lien-hook-ci.yml
15
- lien deploy --cluster mainnet print an Anchor deploy plan (does not broadcast)
16
- ```
15
+ ## Six commands
16
+
17
+ | command | what it does |
18
+ |---|---|
19
+ | `lien list` | print the six standard knots with their flags, lifecycle events, params |
20
+ | `lien create <knot> --pool <pair> --venue <lender>` | scaffold a `lien.toml` with the named knot installed |
21
+ | `lien simulate --pool <pair> --steps <n>` | run the Composition against `<n>` steps of pool history; print accept / reject / side-effects |
22
+ | `lien deploy --cluster <cluster>` | print the install plan; `--execute --keypair <path>` to broadcast |
23
+ | `lien action --workflow <name>` | write a GitHub Actions workflow that runs `lien simulate` on every push |
24
+ | `lien publish <knot>` | (coming) wrap `publish_hook` for knot authors |
25
+
26
+ ## Six standard knots
27
+
28
+ | knot | code id | fires on |
29
+ |---|---|---|
30
+ | the slip knot | `DynamicLTV` | beforeBorrow / afterDeposit |
31
+ | the timer hitch | `TimeTriggerLiq` | beforeLiquidate |
32
+ | the lock knot | `WhitelistBorrow` | beforeBorrow |
33
+ | the double bowline | `AntiMEVLiq` | beforeLiquidate |
34
+ | the double helix | `AutoHedge` | afterBorrow / afterDeposit |
35
+ | the rolling hitch | `ReputationRate` | beforeBorrow |
36
+
37
+ Each is a real implementation with passing tests on the Rust side. The CLI prints them out so you don't have to open the browser.
38
+
39
+ ## Lender targets
40
+
41
+ Marginfi v2 · Kamino Lend · Save (formerly Solend). Adapters ship from source for the moment — `pnpm -r build` from the monorepo covers them — npm publish for adapter packages tracks the next stable release.
42
+
43
+ ## Links
17
44
 
18
- `lien deploy` is plan-only by design — actually running `anchor deploy` requires the operator to confirm the keypair pubkey and balance.
45
+ - Site: https://liens.fi
46
+ - SDK: `npm i @liens/sdk`
47
+ - Source: https://github.com/liens-fi/lien
48
+ - License: Apache-2.0
package/dist/bin.js CHANGED
@@ -5,16 +5,18 @@ import { simulateCommand } from "./commands/simulate.js";
5
5
  import { deployCommand } from "./commands/deploy.js";
6
6
  import { listCommand } from "./commands/list.js";
7
7
  import { actionCommand } from "./commands/action.js";
8
+ import { receiptsCommand } from "./commands/receipts.js";
8
9
  const program = new Command();
9
10
  program
10
11
  .name("lien")
11
12
  .description("Lien — tie your loans. Create, simulate, and deploy Solana lending hooks.")
12
- .version("0.1.0");
13
+ .version("0.1.2");
13
14
  program.addCommand(createCommand());
14
15
  program.addCommand(simulateCommand());
15
16
  program.addCommand(deployCommand());
16
17
  program.addCommand(listCommand());
17
18
  program.addCommand(actionCommand());
19
+ program.addCommand(receiptsCommand());
18
20
  program.parseAsync(process.argv).catch((err) => {
19
21
  console.error(err instanceof Error ? err.message : err);
20
22
  process.exitCode = 1;
package/dist/bin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAC9B,OAAO;KACJ,IAAI,CAAC,MAAM,CAAC;KACZ,WAAW,CACV,2EAA2E,CAC5E;KACA,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,eAAe,EAAE,CAAC,CAAC;AACtC,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC;AAEpC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IAC7C,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACxD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAC9B,OAAO;KACJ,IAAI,CAAC,MAAM,CAAC;KACZ,WAAW,CACV,2EAA2E,CAC5E;KACA,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,eAAe,EAAE,CAAC,CAAC;AACtC,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,eAAe,EAAE,CAAC,CAAC;AAEtC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IAC7C,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACxD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function receiptsCommand(): Command;
3
+ //# sourceMappingURL=receipts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"receipts.d.ts","sourceRoot":"","sources":["../../src/commands/receipts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA8DpC,wBAAgB,eAAe,IAAI,OAAO,CA2EzC"}
@@ -0,0 +1,109 @@
1
+ import { Command } from "commander";
2
+ import kleur from "kleur";
3
+ import { Connection, PublicKey } from "@solana/web3.js";
4
+ const LIEN_EXECUTOR_ID = "5yNMqcyZsGQJk4xvw4jjvoRBSnGs8mgramEa3HQe5faD";
5
+ const EVENT_KIND_LABEL = {
6
+ 0: "beforeDeposit",
7
+ 1: "afterDeposit",
8
+ 2: "beforeBorrow",
9
+ 3: "afterBorrow",
10
+ 4: "beforeRepay",
11
+ 5: "afterRepay",
12
+ 6: "beforeLiquidate",
13
+ 7: "afterLiquidate",
14
+ };
15
+ function parseExecutorLogs(logs) {
16
+ // The executor emits a CompositionExecuted event via Anchor's `emit!`. Anchor
17
+ // prints "Program data: <base64>" lines for these. We don't decode the full
18
+ // borsh payload here — that's what @liens/sdk does. The CLI surface is a
19
+ // human-readable summary, so we look for the program log markers and pull
20
+ // the obvious bytes (event kind + counts) from the borsh prefix.
21
+ const out = {};
22
+ for (const line of logs) {
23
+ if (!line.includes("Program data:"))
24
+ continue;
25
+ const b64 = line.split("Program data:")[1]?.trim();
26
+ if (!b64)
27
+ continue;
28
+ let buf;
29
+ try {
30
+ buf = Buffer.from(b64, "base64");
31
+ }
32
+ catch {
33
+ continue;
34
+ }
35
+ // Anchor event layout: 8-byte discriminator + struct fields.
36
+ // CompositionExecuted: composition(32) + pool(32) + event_kind(u8) +
37
+ // position_owner(32) + adapter(u8) + hook_count_eligible(u8) +
38
+ // hook_count_skipped(u8) + timestamp(i64)
39
+ if (buf.length < 8 + 32 + 32 + 1 + 32 + 1 + 1 + 1)
40
+ continue;
41
+ out.composition = new PublicKey(buf.subarray(8, 40)).toBase58();
42
+ out.pool = new PublicKey(buf.subarray(40, 72)).toBase58();
43
+ out.event_kind = buf[72];
44
+ // position_owner = bytes 73..105
45
+ // adapter = byte 105
46
+ out.hook_count_eligible = buf[106];
47
+ out.hook_count_skipped = buf[107];
48
+ break;
49
+ }
50
+ return out;
51
+ }
52
+ export function receiptsCommand() {
53
+ return new Command("receipts")
54
+ .description("Pull a HookRan receipt off the chain and pretty-print it. Single signature for now; per-pool window coming next.")
55
+ .option("--signature <sig>", "Transaction signature to inspect")
56
+ .option("--rpc <url>", "RPC endpoint", "https://api.mainnet-beta.solana.com")
57
+ .action(async (opts) => {
58
+ if (!opts.signature) {
59
+ console.error(kleur.red("error:") +
60
+ " --signature is required. example: lien receipts --signature 3AWddY...");
61
+ process.exitCode = 1;
62
+ return;
63
+ }
64
+ const conn = new Connection(opts.rpc, "confirmed");
65
+ const tx = await conn.getTransaction(opts.signature, {
66
+ maxSupportedTransactionVersion: 0,
67
+ });
68
+ if (!tx) {
69
+ console.error(kleur.red("error:") +
70
+ ` no transaction found at ${opts.signature} on ${opts.rpc}`);
71
+ process.exitCode = 1;
72
+ return;
73
+ }
74
+ const logs = tx.meta?.logMessages ?? [];
75
+ const parsed = parseExecutorLogs(logs);
76
+ const receipt = {
77
+ signature: opts.signature,
78
+ slot: tx.slot,
79
+ blockTime: tx.blockTime ?? null,
80
+ ...parsed,
81
+ };
82
+ console.log(kleur.bold().yellow("lien receipts"));
83
+ console.log(` signature ${receipt.signature}`);
84
+ console.log(` slot ${receipt.slot}`);
85
+ console.log(` block time ${receipt.blockTime
86
+ ? new Date(receipt.blockTime * 1000).toISOString()
87
+ : "(unknown)"}`);
88
+ console.log(` executor ${LIEN_EXECUTOR_ID}`);
89
+ if (receipt.event_kind !== undefined) {
90
+ console.log(` event ${EVENT_KIND_LABEL[receipt.event_kind] ?? "?"} (kind=${receipt.event_kind})`);
91
+ console.log(` pool ${receipt.pool ?? "?"}`);
92
+ console.log(` composition ${receipt.composition ?? "?"}`);
93
+ console.log(` hooks eligible ${receipt.hook_count_eligible ?? "?"}`);
94
+ console.log(` hooks skipped ${receipt.hook_count_skipped ?? "?"}`);
95
+ }
96
+ else {
97
+ console.log(kleur.dim(" (no CompositionExecuted event in this transaction — was the signature an executor call?)"));
98
+ }
99
+ // Raw logs for forensics
100
+ console.log("");
101
+ console.log(kleur.dim(" raw program logs:"));
102
+ for (const line of logs) {
103
+ if (line.startsWith("Program log:") || line.includes("Program data:")) {
104
+ console.log(kleur.dim(` ${line}`));
105
+ }
106
+ }
107
+ });
108
+ }
109
+ //# sourceMappingURL=receipts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"receipts.js","sourceRoot":"","sources":["../../src/commands/receipts.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liens/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Lien command-line tools \u2014 create, simulate, and deploy lending hooks on Solana.",
5
5
  "type": "module",
6
6
  "bin": {