@pickhooks/sdk 0.0.0-stage → 0.4.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.
Files changed (85) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +418 -3
  3. package/dist/abis/agents.d.ts +2418 -0
  4. package/dist/abis/agents.js +4 -0
  5. package/dist/abis/any3.d.ts +2123 -0
  6. package/dist/abis/any3.js +3 -0
  7. package/dist/abis/anytax.d.ts +1786 -0
  8. package/dist/abis/anytax.js +3 -0
  9. package/dist/abis/calls.d.ts +2515 -0
  10. package/dist/abis/calls.js +4 -0
  11. package/dist/abis/common.d.ts +449 -0
  12. package/dist/abis/common.js +91 -0
  13. package/dist/abis/dips.d.ts +897 -0
  14. package/dist/abis/dips.js +2 -0
  15. package/dist/abis/index.d.ts +14 -0
  16. package/dist/abis/index.js +14 -0
  17. package/dist/abis/infra.d.ts +701 -0
  18. package/dist/abis/infra.js +4 -0
  19. package/dist/abis/lever.d.ts +1710 -0
  20. package/dist/abis/lever.js +5 -0
  21. package/dist/abis/lever2.d.ts +2710 -0
  22. package/dist/abis/lever2.js +5 -0
  23. package/dist/abis/pools.d.ts +1898 -0
  24. package/dist/abis/pools.js +4 -0
  25. package/dist/abis/sticky.d.ts +953 -0
  26. package/dist/abis/sticky.js +4 -0
  27. package/dist/abis/sticky2.d.ts +3750 -0
  28. package/dist/abis/sticky2.js +8 -0
  29. package/dist/abis/v1.d.ts +1627 -0
  30. package/dist/abis/v1.js +5 -0
  31. package/dist/abis/v2.d.ts +3264 -0
  32. package/dist/abis/v2.js +8 -0
  33. package/dist/addresses.d.ts +100 -0
  34. package/dist/addresses.js +71 -0
  35. package/dist/agents-catalog.d.ts +318 -0
  36. package/dist/agents-catalog.js +353 -0
  37. package/dist/agents.d.ts +543 -0
  38. package/dist/agents.js +667 -0
  39. package/dist/any.d.ts +447 -0
  40. package/dist/any.js +729 -0
  41. package/dist/api.d.ts +62 -0
  42. package/dist/api.js +30 -0
  43. package/dist/blocks.d.ts +107 -0
  44. package/dist/blocks.js +126 -0
  45. package/dist/coin-rules-config.d.ts +8 -0
  46. package/dist/coin-rules-config.js +13 -0
  47. package/dist/coin-rules.d.ts +383 -0
  48. package/dist/coin-rules.js +878 -0
  49. package/dist/coins.d.ts +217 -0
  50. package/dist/coins.js +520 -0
  51. package/dist/desks.d.ts +298 -0
  52. package/dist/desks.js +343 -0
  53. package/dist/dips.d.ts +133 -0
  54. package/dist/dips.js +148 -0
  55. package/dist/errors.d.ts +35 -0
  56. package/dist/errors.js +414 -0
  57. package/dist/index.d.ts +104 -0
  58. package/dist/index.js +91 -0
  59. package/dist/infinity.d.ts +63 -0
  60. package/dist/infinity.js +96 -0
  61. package/dist/infra.d.ts +112 -0
  62. package/dist/infra.js +114 -0
  63. package/dist/lever.d.ts +391 -0
  64. package/dist/lever.js +419 -0
  65. package/dist/pools.d.ts +274 -0
  66. package/dist/pools.js +405 -0
  67. package/dist/sticky-rules.d.ts +179 -0
  68. package/dist/sticky-rules.js +580 -0
  69. package/dist/sticky-sim.d.ts +125 -0
  70. package/dist/sticky-sim.js +637 -0
  71. package/dist/sticky.d.ts +286 -0
  72. package/dist/sticky.js +420 -0
  73. package/dist/tlock.d.ts +67 -0
  74. package/dist/tlock.js +185 -0
  75. package/dist/tx.d.ts +72 -0
  76. package/dist/tx.js +78 -0
  77. package/dist/v2.d.ts +106 -0
  78. package/dist/v2.js +61 -0
  79. package/dist/v3.d.ts +42 -0
  80. package/dist/v3.js +98 -0
  81. package/dist/wallet.d.ts +80 -0
  82. package/dist/wallet.js +115 -0
  83. package/dist/watch.d.ts +82 -0
  84. package/dist/watch.js +194 -0
  85. package/package.json +67 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 pickhooks
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,4 +1,419 @@
1
- # Temporary Holding Version
1
+ # @pickhooks/sdk
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
4
- If no other versions are published within 30 days, this package and version will be deleted.
3
+ Read, quote, trade and launch on [pickhooks](https://pickhooks.com) from a bot, a launchpad or a trading terminal. BNB Chain, TypeScript, built on [viem](https://viem.sh).
4
+
5
+ Every pickhooks product, one client:
6
+
7
+ * **hook any coin** (`ph.any`): a PancakeSwap Infinity pool next to any coin that already trades. After every swap the pool's hook closes the gap to the coin's PancakeSwap V2 pair in the same transaction (**arb recapture**) and books a quarter of that profit to the trader. Fees and recapture profits are split between the pool's opener, a **partner** that brought the pool, a **router** that sent the trade, and pickhooks. A second line takes flap tax coins, their tax included.
8
+ * **sticky rules** (`ph.sticky`): coins whose rules stick to the coins, not to the wallet. Launch one from templates, read its table, and ask the coin which rule would stop a trade before anyone signs.
9
+ * **coins with rules** (`ph.coins`): the v1 and v2 coins, with their rules in the coin (also find the dev and CZ mode coins). Rules as sentences, the rule that would refuse a trade, launches.
10
+ * **pools** (`ph.pools`) and **curve calls** (`ph.calls`): coins with their rules in the pool's hook; renting a step of a coin's curve.
11
+ * **Lever** (`ph.lever`, the first lever: `ph.leverV1`): longs and shorts on a coin's own liquidity.
12
+ * **dip bids** (`ph.dips`): floors at a strike, bought from a maker's bid.
13
+ * **agents** (`ph.agents`): coins run by an agent that rewrites their rule program live, inside limits the chain checks. Read a coin's program as sentences, **be the agent yourself** (`brief` hands any model the pickhooks pilot's own prompt, `act` sends what it decided), veto a change or fire the agent as a holder, launch an agent coin with your own bot as its pilot.
14
+ * **watch** (`ph.watch`): live events for terminals and bots: every launch on the pad, every trade of a coin, everything that happens to an agent coin.
15
+ * **wallet** (`ph.wallet`): one address in, everything it holds on pickhooks out: coins by mode with what is sellable right now, BNB owed by the hooks, coins locked at the agents desk, dip bid floors.
16
+
17
+ For a terminal the point is the same everywhere: before a trade is signed, the SDK asks the coin, and a refusal comes back as the rule's sentence ("Refused by the rule "Max per buy". No buy over 0.5% of supply.") instead of "honeypot".
18
+
19
+ ```bash
20
+ npm install @pickhooks/sdk viem
21
+ ```
22
+
23
+ ```ts
24
+ import { createPickhooks } from "@pickhooks/sdk";
25
+ import { createWalletClient, http, parseEther } from "viem";
26
+ import { privateKeyToAccount } from "viem/accounts";
27
+ import { bsc } from "viem/chains";
28
+
29
+ const walletClient = createWalletClient({ account: privateKeyToAccount(KEY), chain: bsc, transport: http() });
30
+ const ph = createPickhooks({ walletClient });
31
+
32
+ const [pool] = await ph.any.pools({ limit: 1 });
33
+ const r = await ph.any.buy({ pool, bnbIn: parseEther("0.05") });
34
+ console.log(r.amountOut, r.recapture); // coins bought; the recapture of this transaction and your share of it
35
+ await ph.any.claim(); // your recapture shares (and, as an opener or partner, those shares)
36
+ ```
37
+
38
+ Without a `walletClient` everything that only reads works. Every write also exists as a builder (`ph.any.build.*`, `ph.sticky.build.*`) that returns plain `{ to, data, value, extraGas }` for wallets, multicalls and your own router contracts.
39
+
40
+ ## Who earns what (hook any coin)
41
+
42
+ | who | what | how it is paid |
43
+ |---|---|---|
44
+ | the trader | 25 % of every recapture its swap made possible | `claim()` |
45
+ | the opener | 35 % of the pool's BNB fees and of what is left of each recapture after the trader's share (part of it can feed a jackpot) | `claim()` |
46
+ | a partner | its listed share (up to 50 %) of the pickhooks part of every fee and recapture in pools opened with it | `claim()` |
47
+ | a router | its listed share (up to 50 %) of the pickhooks part of the fee of every buy it sends, and of the recapture profit its trades create | `claimRouter()` from the payout wallet |
48
+
49
+ The trader share applies to pools opened from now on (factory `traderBps`, each pool keeps its own). Partners and routers are listed by pickhooks (`partnerBps(partner)`, `router(contract)`): ask to be listed.
50
+
51
+ **A router is the contract that calls the pool manager.** Trades through PancakeSwap's UniversalRouter come from the UniversalRouter; a terminal with its own router contract is listed by that contract's address and gets paid to a wallet it names. Buy fees are credited at the swap and funded when the pool's fees are collected (`collect`: anyone can call it, and pickhooks' keeper runs it); recapture shares are funded at once. `earnings(payout).routerClaimable` is what `claimRouter()` pays now.
52
+
53
+ ## Gas: the recapture room
54
+
55
+ The hook recaptures inside the trader's transaction, after the swap, with its own gas budget (600k plus a 250k reserve). A wallet's plain estimate leaves that out, so the swap goes through without a recapture. Trades built by the SDK carry `extraGas: 900_000n`; `sendTx` uses estimate x 1.3 + extraGas. Only the gas used is paid (a recapture uses about 400k). Pass `recapture: false` to trade without the room. A terminal that routes through its own contract leaves at least 850k gas for the hook's `afterSwap`.
56
+
57
+ ## hook any coin: `ph.any`
58
+
59
+ Reading
60
+
61
+ ```ts
62
+ await ph.any.terms(); // { owner, platformWallet, openerBps, traderBps, hook }
63
+ await ph.any.pools({ limit, offset }); // newest first: id, key, token, symbol, config, counters, positions, price
64
+ await ph.any.pool(id); // one pool, or null
65
+ await ph.any.poolsOf(token); // every pool of a coin (one per slot)
66
+ await ph.any.check(token); // can this coin get a pool? price, price source, depth, free slot, pair
67
+ await ph.any.earnings(wallet); // { owed, routerCredit, routerClaimable, partnerBps }
68
+ await ph.any.router(contract); // { payout, bps }
69
+ await ph.any.partnerBps(partner);
70
+ await ph.any.bonusOf(pool, wallet); // lock to earn
71
+ await ph.any.pendingFees(pool); // what a collect would book now
72
+ ```
73
+
74
+ Trading (BNB in for buys, BNB out for sells; `pool` is an id, a key or a pool from `pools()`)
75
+
76
+ ```ts
77
+ const q = await ph.any.quote({ pool, side: "buy", amount: parseEther("0.1"), from: me }); // quote = fill
78
+ const b = await ph.any.buy({ pool, bnbIn: parseEther("0.1"), slippageBps: 100 });
79
+ const s = await ph.any.sell({ pool, amount: b.amountOut / 2n }); // approves Permit2 once, then the router for 30 days
80
+ // b.amountOut, b.recapture { profit, toTrader, soldHere }, b.routerCredit, b.hash, b.receipt
81
+ ```
82
+
83
+ Building instead of sending
84
+
85
+ ```ts
86
+ const key = await ph.any.key(poolId);
87
+ const tx = ph.any.build.buy({ key, bnbIn, minOut }); // { to: UniversalRouter, data, value, extraGas }
88
+ const approvals = await ph.any.sellApprovals(owner, key.currency1, amount); // TxRequest[]
89
+ ph.any.readTrade(receipt); // the trade, the recapture and the router credit of a receipt
90
+ ```
91
+
92
+ Opening a pool (as a launchpad or bot, with yourself as the partner)
93
+
94
+ ```ts
95
+ const c = await ph.any.check(coin); // c.ok, c.text, c.depth (BNB in the coin's main pool)
96
+ const need = ph.any.depthNeeds(c, "ladder10", c.freeSlot!); // coins a pool needs to be as deep (the factory refuses a shallower one)
97
+ const { id } = await ph.any.open({ token: coin, tokenAmount: need.coins, partner: MY_PARTNER_WALLET });
98
+ ph.any.partnerLink(MY_PARTNER_WALLET); // the site's open form with you named as partner
99
+ ```
100
+
101
+ Options and their defaults (the site's): `range` `"ladder10"` (coins only, up to 10x; `"ladder"` no top; `"around"` with BNB), `feeBps` 30, `holderFeeBps` 5 for wallets with `holderMin` 10,000 $hooks, `chestBps` 200 (the fire), `bonus` 5 % locked 7 days for buys from 0.05 BNB (`false` for none), `jackpot` off, `recapture` true, `maxMoveBps` 100. Each position stays in the pool 30 days.
102
+
103
+ Payouts and pool tools: `claim()`, `claimRouter()`, `collect(pool)`, `settleJackpot(pool)`, `fundPot(pool, wei)`, `feedChest(token, amount)`, `fundBonus(pool, amount)`, `lockBonus(pool, amount)`, `unlockBonus(pool)`, `addLiquidity(pool, range, coins, bnb)`, `removeLiquidity(pool, index)`, each also under `build`.
104
+
105
+ ### The tax line (flap tax coins)
106
+
107
+ Flap tax coins keep their tax in a pickhooks pool: buyers and sellers pay it like on the coin's main pool, and the tax goes where the coin sends it. They open on a second factory with its own hook (`addresses.anyTaxFactory`; `ph.any.taxLineOn` says whether it is set). The SDK routes for you: `check(token)` names the line (`line: "main" | "tax"`, with the coin's live tax in `tax`), and `pools()`, `pool()`, `quote()`, `buy()` and `sell()` work on both.
108
+
109
+ ```ts
110
+ const c = await ph.any.check(taxCoin); // c.line === "tax", c.tax { buyBps, sellBps, ... }
111
+ const t = await ph.any.taxOf(taxCoin); // the tax as it runs now
112
+ const fit = fitLadder(c, coins, c.freeSlot!, t.sellBps); // the range a ladder of `coins` needs to be as deep as the main pool
113
+ const q = await ph.any.quote({ pool, side: "buy", amount }); // { amountOut (after tax), gross, taxBps }
114
+ await ph.any.sell({ pool, amount }); // while the anti-farmer tax runs: pays the coins in first, then swaps
115
+ await ph.any.claim({ line: "tax" }); // the opener's side of the tax line's fees
116
+ ```
117
+
118
+ While a coin's anti-farmer tax runs, a sell in its pickhooks pool must pay its coins in first; a plain router sell is refused with `PayFirst`. The SDK's `sell()` does it right; terminals that route themselves sell such coins in their main pool.
119
+
120
+ ## sticky rules: `ph.sticky`
121
+
122
+ ```ts
123
+ import { TEMPLATES } from "@pickhooks/sdk"; // hold, sniper, devlock, drip, maxbuy, maxwallet, window, hours, burn, dipdrop, lucky, wakeup
124
+
125
+ const picks = [
126
+ { id: "sniper", params: { b: 20, h: 24 } }, // buys in the first 20 blocks are marked; marked coins cannot sell for 24 h, in any wallet
127
+ { id: "devlock", params: { d: 7 } }, // the creator's first buy cannot sell for 7 days
128
+ { id: "lucky", params: { pot: 2, n: 25, share: 100 } },
129
+ ];
130
+ const table = ph.sticky.compile(picks); // { rows, release, problems }
131
+ await ph.sticky.validate(table.rows, table.release); // null, or the validator's reason as a sentence
132
+ const { token } = await ph.sticky.launch({ name, symbol, metadata: "https://…/meta.json", picks, devBuy: parseEther("0.05") });
133
+ ```
134
+
135
+ A launch costs the factory's seed (0.01 BNB, into the coin's V2 pair) plus the creator's first buy; the creator gets half of the fees the coin's pool earns (`keepBps` of it, the rest buys back and burns $hooks). `metadata` is a link to the coin's JSON (name, symbol, description, image, website, twitter, telegram): host your own, or let pickhooks.com host it: `prepareMetadata({ name, symbol, description, website, twitter, telegram, image })` returns `{ metadata, image }`.
136
+
137
+ ```ts
138
+ await ph.sticky.coins({ limit }); // newest first: rows as sentences, scanner color, holders, pot, price
139
+ await ph.sticky.coin(token);
140
+ await ph.sticky.wallet(token, who); // balance, sellable now, lots (amount, locked, since, marks)
141
+ const v = await ph.sticky.check({ token, side: "sell", wallet, amount });
142
+ // { ok: true } or { ok: false, row: 1, text: "Refused by rule 2: Sniper jail. A sell is refused when …" }
143
+ await ph.sticky.buy({ token, bnbIn }); // quote, check, then the buy through the better of the coin's two venues
144
+ await ph.sticky.sell({ token, amount }); // check first: a refusing rule stops it before anything is signed
145
+ await ph.sticky.quote({ token, side: "sell", amount }); // { amountOut, venue: "v3" | "v2", v3, v2 }: the V3 pool and the V2 pair, the better one wins
146
+ await ph.sticky.lift(token, row); // the creator lifts a row for good
147
+ ```
148
+
149
+ **Hook script: your own rows.** With the factory's custom switch on (`terms().custom`, on since 08.10.2026), a coin can carry the creator's own rows after the templates, written like the site's editor:
150
+
151
+ ```ts
152
+ import { ACT, ON, OP, VAR, VARS } from "@pickhooks/sdk"; // VARS: every variable with its unit (minutes, % of supply, x, ...)
153
+
154
+ const noBigSells = { on: ON.SELL, act: ACT.DENY, arg: 0, conds: [{ v: VAR.AMOUNT, op: OP.GE, x: 1 }] }; // no sell of 1 % of supply or more
155
+ await ph.sticky.launch({ name, symbol, metadata, picks: [{ id: "devlock", params: { d: 7 } }], script: [noBigSells], devBuy });
156
+ ```
157
+
158
+ The editor's checks run first (a row the site would refuse stops before anything is signed, in words), then the validator on chain. Rows that lock shares take `scriptHours` (10 minutes to 30 days).
159
+
160
+ **The test run, before the launch.** The launcher's test run, offline: the table on a fresh coin with random trades (the creator's first buy, three snipers in the first blocks, wallets that buy, hold and sell, bags split to fresh wallets). It runs the coin's own rule engine, checked against the contract trade by trade. The same seed gives the same run.
161
+
162
+ ```ts
163
+ const run = ph.sticky.testRun({ picks, script, devBuyBnb: 0.05, seed: 7, trades: 200 });
164
+ run.report; // refusals per row, longest wait to sell, snipers, split bags, when everyone is free, burn, pot, a scanner's test
165
+ run.text; // the same as sentences: "A scanner's test: its sell right after the buy is refused by rule 1, Hold time: it can show a honeypot."
166
+ ```
167
+
168
+ Numbers left out of a pick take the template's defaults (`{ id: "hold" }` is a hold time of 30 minutes); `ph.sticky.table({ picks, script })` returns the rows and release a launch would send.
169
+
170
+ Sticky coins trade in a PancakeSwap V3 pool of 1 % and a V2 pair, so any router can trade them. For a terminal the point is `check()`: instead of "honeypot", show the row that stops the trade, in words.
171
+
172
+ **A quote that a rule refuses.** PancakeSwap's QuoterV2 runs the swap, so a buy a rule refuses fails in the quoter, and the quoter does not pass the coin's reason on (it says "Unexpected error"). `quote()` of sticky coins and of coins with rules then checks the buy again with `estimateBuy(token, bnbIn)` (the pool's liquidity at its price) and throws the rule's sentence (`code: "Blocked"`). Pass `wallet` to check for that wallet. The estimate names rules; never use it as a minimum.
173
+
174
+ ## Coins with rules: `ph.coins`
175
+
176
+ The v1 and v2 coins (`pickhooks.com/launch`): up to eight rules live in the coin itself and apply to every transfer with its PancakeSwap V3 pool.
177
+
178
+ ```ts
179
+ import { RULES } from "@pickhooks/sdk"; // the catalog: id, kind, name, fields (also @pickhooks/sdk/coin-rules)
180
+
181
+ await ph.coins.coins({ version: 2, limit: 20 }); // newest first: rules as sentences, holders, price
182
+ const c = await ph.coins.coin(token); // c.version, c.rules [{ name, text, ended }], c.extras
183
+ const v = await ph.coins.check({ token, side: "buy", wallet, amount: await ph.coins.estimateBuy(token, bnbIn) });
184
+ // { ok: true } or { ok: false, kind: 2, name: "Max per buy", text: "Refused by the rule "Max per buy". No buy over 0.5% of supply." }
185
+ await ph.coins.buy({ token, bnbIn }); // quote, check, buy; a refusing rule stops it before anything is signed
186
+ await ph.coins.sell({ token, amount });
187
+ ```
188
+
189
+ `check()` runs the coin's own transfer in an `eth_call` (a buy: the coins leaving the pool to the wallet), so the answer is the coin's, not a copy of its logic.
190
+
191
+ Launching (v2):
192
+
193
+ ```ts
194
+ const rules = [
195
+ { id: "max_wallet", values: { cap: 1 } }, // % of supply
196
+ { id: "max_tx", values: { cap: 0.5 } },
197
+ { id: "buyout", values: { rules: "2", price: 0.1 } }, // anyone can buy rule 2 off for 0.1 BNB
198
+ ];
199
+ const L = await ph.coins.launch({ name, symbol, metadata, rules, devBuy: parseEther("0.02") });
200
+ // L.token, L.burned: rules that need $hooks burn it in the launch, bought with BNB (payBurnIn: "hooks" uses yours)
201
+ ```
202
+
203
+ `burnFor(mask)` says what a set of rules burns and the BNB it costs. After launch: `wallet(token, who)`, `pendingFees(token)`, `collect(token)` (anyone; the creator gets its side), `claim(token)`, `buyout(token, kind)`, `fundPot(token, "jackpot" | "rewards", wei)`, `settleJackpot`, `withdrawRewards`, `poke`, `alive`, `release`, and under `build` the vote, duel, floor and payroll steps.
204
+
205
+ ## Pools and curve calls: `ph.pools`, `ph.calls`
206
+
207
+ Pool coins carry their rules in a PancakeSwap Infinity pool's hook instead of the coin; they trade through the UniversalRouter (Permit2 for sells).
208
+
209
+ ```ts
210
+ await ph.pools.knownKinds(); // the rules a pool can carry (Max wallet needs the coin, so no)
211
+ const P = await ph.pools.launch({ name, symbol, metadata, rules: [{ id: "max_tx", values: { cap: 0.5 } }], devBuy });
212
+ await ph.pools.check({ token, side: "buy", wallet, amount }); // the quoter runs the hook as the buyer and names the rule
213
+ await ph.pools.buy({ token, bnbIn }); await ph.pools.sell({ token, amount });
214
+ await ph.pools.owed(creator); await ph.pools.claim(); // the creator's share, booked on every swap
215
+ ```
216
+
217
+ `ph.calls` is the same for curve calls coins, plus the desk:
218
+
219
+ ```ts
220
+ const steps = await ph.calls.steps(token); // the steps above the price that are open (none in a coin's first 10 minutes)
221
+ const q = await ph.calls.quoteCall(token, step, coins, seconds); // { premium, liquidity }
222
+ const { id } = await ph.calls.openCall({ token, step, coins, seconds });
223
+ await ph.calls.payout(id, me); // what closing pays now
224
+ await ph.calls.closeCall(id); // the payout and the bond come back
225
+ await ph.calls.withdraw(); // anything the desk holds for you (ph.calls.pending(me))
226
+ ```
227
+
228
+ ## Lever: `ph.lever` and `ph.leverV1`
229
+
230
+ ```ts
231
+ const m = await ph.lever.coin(token); // the Lens: price, room for longs and shorts, open longs and shorts
232
+ const o = await ph.lever.quoteOpen(token, "long", gross, 2); // o.reason 0 = it opens; otherwise o.text says why
233
+ const { id } = await ph.lever.open({ token, side: "short", gross, leverage: 2 });
234
+ await ph.lever.positions(token); // { longs, shorts }: owner, margin, trigger, closeNet (what closing pays now)
235
+ await ph.lever.close({ token, side: "short", id });
236
+ await ph.lever.sell({ token, amount }); // sellPlan() splits a sale around open shorts when it must
237
+ await ph.lever.claim(token, "creator"); // "creator" | "refund" | "platform"
238
+ ```
239
+
240
+ `grossForMargin(margin, leverage)` is the BNB to send for a margin. `ph.leverV1` is the first lever (engine curve, longs only): `quoteBuy`, `quoteSell`, `quoteOpen`, `buy`, `sell`, `openLong`, `closeLong`, `closeExpired`, `claimRefund`, `claimCreator`, `launch`.
241
+
242
+ ## Dip bids: `ph.dips`
243
+
244
+ A maker posts a bid: BNB that buys coins at a strike, in floors that holders buy for a premium. A holder with a floor can sell up to its cover at the strike while it runs, even after a dip.
245
+
246
+ ```ts
247
+ const { id } = await ph.dips.post({ token, price: 0.000000003, duration: 86_400, premiumBps: 500, until, minCover, deposit });
248
+ await ph.dips.bids(token); // the coin's bids
249
+ const q = await ph.dips.quote(id, coins); // { cover, premium, fee, payout }
250
+ const f = await ph.dips.buyFloor(id, coins); // f.id: the floor
251
+ await ph.dips.exercise({ floorId: f.id, coins, token }); // approval, a dry run, then the coins go to the maker for BNB
252
+ await ph.dips.close(id); // the maker takes the free BNB back
253
+ ```
254
+
255
+ `strikeFromPrice(bnbPerCoin)`, `coverOf(strike, coins)` and `coinsFor(strike, cover)` convert; the strike is BNB wei per whole coin.
256
+
257
+ ## HOOKS infra: `ph.infra`
258
+
259
+ On mainnet since 09.10.2026 (executor `0xCCea8f8195Dd3c62C28e218C002316e67B95bb36`, floor factory `0xcaA38326d43071e5a7a940c144042a14DC42086F`; `ph.infra.on` says which part is live).
260
+
261
+ * **Floors:** a BNB reserve under a coin (one per coin, anyone can open and feed it). A holder hands coins in for reserve / circulating, less 2 % (1 % stays and lifts the floor, 1 % to the protocol); the coins go to 0xdead. No owner, no withdraw: the floor only rises.
262
+ * **Protected buy:** one transaction buys through PancakeSwap's own routers and a dip floor for what arrived. pickhooks.com picks the route and the bid; `protect()` sends what the site built, after checking it goes to the executor.
263
+
264
+ ```ts
265
+ const f = await ph.infra.floorOf(token); // { floor, reserve, circulating, perCoin, totalFed, totalPaid, totalRedeemed }
266
+ await ph.infra.quoteRedeem(token, coins); // { payout, kept, protocolFee }
267
+ await ph.infra.redeem({ token, coins }); // approval, then the hand in (quote less 0.5 % as the minimum)
268
+ await ph.infra.feed(token, parseEther("1")); // more BNB under the coin
269
+ await ph.infra.open({ token, seed }); // the coin's first floor
270
+ const o = await ph.infra.offer({ token, bnbIn }); // the route, the bids that can cover it, the transaction
271
+ await ph.infra.protect({ token, bnbIn }); // { coins, floorId, premium }
272
+ ```
273
+
274
+ ## sticky 2 and its desks: `ph.sticky2`, `ph.cover`, `ph.auction`, `ph.dark`, `ph.launchDesk`
275
+
276
+ On mainnet since 11.10.2026 (factory `0xB9b90378Cf621a625a4AcBA9B95a7f204e6Df54c`, dev cover `0xf6e66a4DadfB0700603342D244dE6F999B2725DF`, rule auction `0x874CA64571774f2ae0A3fFa0A578B046910aDb35`, dark launch `0x304c6604e96627FDdc7a94b7a691A0673A80F765`, launch desk `0x81508f3fCc535c29a49226E61D39188b6D479d61`). On a fork, pass other addresses with `createPickhooks({ addresses })`.
277
+
278
+ * **sticky 2** (`ph.sticky2`): everything `ph.sticky` does, on the second factory. The coin also counts what its creator sold, from any wallet the DEV coins went through, and can carry switch rows: rows that are off until a switcher (the rule auction) turns one on.
279
+ * **dev cover** (`ph.cover`): a writer puts BNB on a coin against its creator selling. A holder buys a policy for a premium; when the creator's sold share reaches the offer's mark (10, 25, 50 or 100 %), the policy pays its cover. Posted by the creator itself, it is a dev bond. A policy can only cover what the holder's coins are worth.
280
+ * **rule auction** (`ph.auction`): holders burn coins for one of the coin's switch rows; at the end of each round the game with the most burned is turned on.
281
+ * **dark launch** (`ph.dark`): a round before the coin exists. Bids show their BNB but seal their top price to a drand round that is signed only after the bidding. Once signed anyone opens the bids, everyone buys at one price, and the coin is born at that price with BNB on both sides. The round's BNB sits in the coin's V2 pair, so right after the birth a sell routes there (`quote` picks the venue; a sell into the one sided V3 curve would get almost nothing). Terminals do the same by themselves.
282
+ * **launch desk** (`ph.launchDesk`): a wallet's BNB that the pad's reply bot may launch with, only for that wallet, within the limits the wallet set.
283
+
284
+ ```ts
285
+ await ph.sticky2.devCounters(token); // { bought, sold, soldBps, at: { 10, 25, 50, 100 } }
286
+ await ph.sticky2.switches(token); // { mask, on, switcher }
287
+ await ph.sticky2.launch({ name, symbol, metadata, picks: [{ id: "lucky" }, { id: "dipdrop" }, { id: "wakeup" }], switchRows: [1, 3, 5] });
288
+ // drop rows that switch; the rule auction runs them
289
+
290
+ const { id } = await ph.cover.post({ token, mark: 25, premiumBps: 300, duration: 86_400, stopBps: 1000, deposit });
291
+ await ph.cover.offers(token); // with `bond` when the creator wrote it, `live` when it sells
292
+ const q = await ph.cover.quote(id, cover); // { premium, fee, payout }
293
+ const p = await ph.cover.buy(id, cover); // pays exactly the quoted premium; p.id is the policy
294
+ await ph.cover.claim(p.id); // once the creator's sold share reached the mark
295
+
296
+ await ph.auction.state(token); // { round, endsAt, burned[8], mask, on, settleable }
297
+ await ph.auction.burn(token, game, amount); // approval, then the burn
298
+
299
+ await ph.dark.round(roundId); // endsAt, drandRound, state (0 bidding, 1 born, 2 failed), step, token
300
+ await ph.dark.prices(); // BNB per coin at each of the 24 steps
301
+ const b = await ph.dark.bid({ roundId, step: 9, deposit }); // seals step 9 to the round's drand round, then bids
302
+ await ph.dark.owedOf(b.id); // { coins, paid, claimableNow }
303
+ await ph.dark.claim(b.id);
304
+ const o = await ph.dark.opener(roundId); // once drand signed: the open transaction (anyone may send it)
305
+ ```
306
+
307
+ The seal is time-lock encryption to drand quicknet, the same scheme as find the dev. `@pickhooks/sdk/tlock` holds it on its own entry (`encrypt`, `decrypt`, `darkMessage`, `fetchRoundSig`, `roundAt`), so the main import does not load BLS12-381.
308
+
309
+ ## Agents: `ph.agents`
310
+
311
+ On mainnet since 09.10.2026 (factory `0x5965e2D2128248ac2CB4FFf312CFB098a1eDA232`). An agent coin is a plain ERC20 in a PancakeSwap Infinity pool whose hook runs a **program**: the fee on each side (1 % up to the coin's cap), where the coin's part of every fee goes (burn, liquidity the coin owns for good, its HOOKS floor, a rewards pot, a jackpot, the creator, the treasury) and up to eight pool rules. The **pilot** (any wallet: the pickhooks agent, your bot, a model behind an MCP server) proposes a whole new program; the desk checks it against the coin's **envelope** (limits fixed for good at launch: max fee, max creator share, allowed rules, notice, gap, veto and fire shares) and the limits every agent coin lives with (sells can never be closed for good, no rule names a wallet, BNB never leaves the coin). The change is announced and lands after the notice; holders lock coins to **veto** it or to **fire** the pilot. Every router trades the coin.
312
+
313
+ ```ts
314
+ const c = await ph.agents.coin(token); // program as sentences (c.lines), env, pending change, fire tally, buckets, runs, price
315
+ await ph.agents.coins({ limit: 20 }); // newest first
316
+ await ph.agents.quote({ token, side: "buy", amount: parseEther("0.01"), from }); // a refusing rule comes back as its sentence
317
+ await ph.agents.buy({ token, bnbIn }); await ph.agents.sell({ token, amount }); // through the UniversalRouter, rules checked first
318
+
319
+ // be the agent: the pickhooks pilot's prompt for any model, its answer back into a transaction
320
+ const b = await ph.agents.brief(token); // { system, user, schema, look, profile }
321
+ const answer = await yourModel(b.system, b.user, { schema: b.schema }); // { title, body, action, plan, move, expect }
322
+ const { tx, proposal } = await ph.agents.act(token, answer); // propose / move / null for "none"
323
+ if (tx) await ph.send(tx); // from the pilot's wallet (or ph.agents.pilot(token, answer) in one go)
324
+
325
+ // or write the program yourself, in plain units
326
+ await ph.agents.propose(token, { buy_fee_pct: 1.5, sell_fee_pct: 2, route: { burn: 50, lp: 20, floor: 10 }, rules: [{ id: "max_buy", values: { cap_pct: 1 } }] }, { title, body });
327
+ ph.agents.problemsOf(program, env); // the limits' problems, offline; checkProgram(token, program) asks the desk (eth_call as the pilot)
328
+ await ph.agents.move(token, "treasury", "burn", wei); await ph.agents.cancel(token); await ph.agents.handOver(token, to);
329
+
330
+ // holders
331
+ await ph.agents.veto(token, coins); await ph.agents.fire(token, coins); await ph.agents.withdraw(token);
332
+ await ph.agents.activate(token); // anyone lands a change that is due (the pickhooks keeper does too)
333
+ await ph.agents.burn(token); await ph.agents.addLiquidity(token); await ph.agents.feedFloor(token); // the runs anyone may trigger
334
+
335
+ // launch with your own pilot
336
+ const { metadata } = await ph.agents.prepareMetadata({ name, symbol, image, agent: { name: "whiskers", personality: "degen", objectives: ["depth"], mission } });
337
+ await ph.agents.launch({ name, symbol, metadata, plan, envelope: { maxFeeBps: 500, notice: 1800 }, pilot: myBot, devBuy });
338
+ ```
339
+
340
+ `ph.agents.catalog()` is the vocabulary as plain data: the 18 rules an agent may use with their fields, the limits, the buckets, the personalities and objectives of a profile, the ABI tuples, the answer schema. The catalog, the pilot's prompt and the answer schema are a checked port of the site's and the keeper's (`npm run check`), so a bring your own agent runs on the same text the pickhooks agent does. The main import holds it all; `AGENT_RULES`, `toProgram`, `describeProgram`, `systemPrompt`, `ANSWER_SCHEMA`, `noteHash`, `parseAnswer` are exported on their own.
341
+
342
+ ## Live events: `ph.watch`
343
+
344
+ Each watcher polls the RPC (HTTP is enough; `pollingInterval` default 3 s) and returns a function that stops it.
345
+
346
+ ```ts
347
+ const stop = ph.watch.launches((l) => console.log(l.mode, l.symbol, l.token), { modes: ["sticky", "agents"] });
348
+ const stop2 = await ph.watch.trades(token, (t) => console.log(t.buy ? "buy" : "sell", t.coins, t.bnb ?? t.fee, t.trader));
349
+ const stop3 = await ph.watch.agent(token, (e) => console.log(e.event, e.args)); // Proposed, Activated, Vetoed, PilotFired, Burned, ...
350
+ ```
351
+
352
+ `launches` covers every factory (sticky, rules v2 and v1, pools, curve calls, Lever, agents, hook any coin's new pools; `ph.watch.modes` lists the live ones) and reads name and symbol from the token. `trades` finds the coin's mode itself: the hook's `Traded` events for pools, curve calls, agents and hook any coin pools, the `Swap` events of the PancakeSwap V3 pool and V2 pair for sticky and rules coins.
353
+
354
+ ## One address: `ph.wallet`
355
+
356
+ ```ts
357
+ const w = await ph.wallet(address);
358
+ w.coins // every pickhooks coin it holds: mode, name, symbol, balance, sellable now (sticky: the unlocked lots; others: the coin asked for the whole balance, the refusal in words), price, value, page
359
+ w.claims // BNB owed: hook any coin (recapture shares, router credits), pools, curve calls, agents; totalBnb
360
+ w.locks // coins locked at the agents desk, per coin, and what they back (a veto, the firing)
361
+ w.floors // dip bid floors it holds
362
+ w.scanned // the factories covered and how many of their coins (the newest `limit` each, default 300)
363
+ ```
364
+
365
+ ## Building blocks: `ph.blocks`
366
+
367
+ The vocabulary of every rule, as plain data and offline: sticky rules' 12 ready blocks (numbers with their ranges, the sentence, the rows they make, what scanners show), the hook script grammar (triggers, actions, marks, variables with their units, operators, the checks a table must pass) and the rule book of coins with rules (each rule with its fields).
368
+
369
+ ```ts
370
+ const c = ph.blocks.catalog(); // { version, sticky: { blocks, script, promises, limits }, coinRules: { groups, rules } }
371
+ ph.blocks.block("sniper"); // { name, line, example, params, rows, scanner, sticky }
372
+ await ph.api.blocks(); // the same object from pickhooks.com/api/blocks, once the site serves it
373
+ ```
374
+
375
+ It is built from the same files as the site's launchers (a checked copy), so a terminal, a bot or an agent can explain a coin's rules or compose a table without guessing.
376
+
377
+ ## pickhooks.com's API: `ph.api`
378
+
379
+ `launches({ since, before, limit })`, `launch(address)`, `coins()`, `activity()`, `official()`, `burners()`, or `get(path, query)`. No key; a limit per address per minute.
380
+
381
+ ## Errors
382
+
383
+ Every failure is a `PickhooksError` with `code` (the contract's error name, or `wallet`, `funds`, `pancake`, `reverted`, `input`) and a sentence as `message`. `explain(err)` turns any error (also from your own viem calls) into `{ code, text }`, including hook errors that PancakeSwap wraps.
384
+
385
+ ## Addresses (BNB Chain)
386
+
387
+ | | |
388
+ |---|---|
389
+ | hook any coin v3 factory | `0x1662668Ab8FaA612A7F615F1AccB90ceC20be117` |
390
+ | hook any coin v3 hook | `0x49892253A5E71f5DF0Fbc118bd7c15acAF55F767` |
391
+ | sticky factory | `0x385C273bDaBC5a0788dfBb648F05bE0C5EE018fd` |
392
+ | sticky validator | `0x057007a21330EA770f2Fcb61c8925C28c270480f` |
393
+ | coins with rules v1 factory | `0xecED45Ae3e85D947038009710594a50d422A54D8` |
394
+ | coins with rules v2 factory | `0x23cC366e1DDBc41CFD70011C4AaC14B79998B24F` |
395
+ | pools factory | `0x3F97831C8296D934d84357B619CfC44D32d0241B` |
396
+ | curve calls factory | `0x98D49C17458def2e5fdF00F20479658693498301` |
397
+ | Lever factory | `0x03EbF1558E2f9337E4d2FfCAcE3A5114aC32A87A` |
398
+ | Lever Lens | `0x3f1a660FC365Af192acE4E761657cE61A6ED0F13` |
399
+ | lever (v1) factory | `0xeaB93e923170bd5331Db4300aF6F2555eBBF9615` |
400
+ | dip bids desk | `0xc73bcB859C3fD5Bd38A10B0aD9A862EAAf6765bf` |
401
+ | HOOKS executor (protected buy) | `0xCCea8f8195Dd3c62C28e218C002316e67B95bb36` |
402
+ | HOOKS floor factory | `0xcaA38326d43071e5a7a940c144042a14DC42086F` |
403
+ | agents factory | `0x5965e2D2128248ac2CB4FFf312CFB098a1eDA232` |
404
+ | the pickhooks agent (pilot wallet) | `0x85b85b75806446BB7AFa324D67B20cc1C29eCFB5` |
405
+ | $hooks | `0x07bcB8E8226f671300e135b4A61Dc157359b7777` |
406
+
407
+ All verified on BscScan. `BSC_MAINNET` holds these and PancakeSwap's; `createPickhooks({ addresses })` points the SDK elsewhere (a fork). The tax line's factory is not set yet (`anyTaxFactory` is zero until it is on mainnet). ABIs: `@pickhooks/sdk/abis`; the drand time-lock: `@pickhooks/sdk/tlock`; the sticky encoder alone: `@pickhooks/sdk/rules`; the rule catalog of coins with rules: `@pickhooks/sdk/coin-rules`.
408
+
409
+ ## Examples
410
+
411
+ * `examples/terminal.mjs`: pools, routing a buy, sticky rows and coins with rules with the rule that refuses a trade, a wallet's earnings (read only)
412
+ * `examples/bot.mjs`: quote, buy with the recapture room, sell, claim
413
+ * `examples/launchpad.mjs`: a sticky launch from templates, a pool with you as the partner, the partner's claim
414
+
415
+ They send nothing without `--send`.
416
+
417
+ ## Tests
418
+
419
+ `npm test` (offline: pool ids, ranges, building, errors, the rule compiler, the time-lock against the site's copy). On a local BSC fork (`scripts/fork.sh`, anvil) against the live contracts: `npm run fork-proof` (hook any coin and sticky rules) and `npm run fork-proof-2` (coins with rules, pools, dip bids, Lever, lever v1, curve calls, and the tax line, which it deploys on the fork from a throwaway key). `npm run fork-proof-infra` runs floors and the protected buy on the infra rehearsal fork (`script/infra/rehearsal-fork.sh`, contracts deployed there by a throwaway key) against a dev server of the site. `npm run check` confirms the rule catalogs and the building blocks catalog are the site's, and that the agents catalog and the pilot's prompt behave like the site's and the keeper's. `node test/mainnet-read-agents.mjs` reads the agents, watch and wallet parts against mainnet (nothing sent); the fork proof of those parts lives with the MCP server (`mcp/test/fork-proof-agents.mjs`: launch, trades, a model's answer landing through the desk, veto, fire, the watchers seeing it all).