@pickhooks/sdk 0.0.0-stage → 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.
Files changed (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +309 -3
  3. package/dist/abis/any3.d.ts +2123 -0
  4. package/dist/abis/any3.js +3 -0
  5. package/dist/abis/anytax.d.ts +1786 -0
  6. package/dist/abis/anytax.js +3 -0
  7. package/dist/abis/calls.d.ts +2515 -0
  8. package/dist/abis/calls.js +4 -0
  9. package/dist/abis/common.d.ts +449 -0
  10. package/dist/abis/common.js +91 -0
  11. package/dist/abis/dips.d.ts +897 -0
  12. package/dist/abis/dips.js +2 -0
  13. package/dist/abis/index.d.ts +12 -0
  14. package/dist/abis/index.js +12 -0
  15. package/dist/abis/infra.d.ts +701 -0
  16. package/dist/abis/infra.js +4 -0
  17. package/dist/abis/lever.d.ts +1710 -0
  18. package/dist/abis/lever.js +5 -0
  19. package/dist/abis/lever2.d.ts +2710 -0
  20. package/dist/abis/lever2.js +5 -0
  21. package/dist/abis/pools.d.ts +1898 -0
  22. package/dist/abis/pools.js +4 -0
  23. package/dist/abis/sticky.d.ts +953 -0
  24. package/dist/abis/sticky.js +4 -0
  25. package/dist/abis/v1.d.ts +1627 -0
  26. package/dist/abis/v1.js +5 -0
  27. package/dist/abis/v2.d.ts +3264 -0
  28. package/dist/abis/v2.js +8 -0
  29. package/dist/addresses.d.ts +87 -0
  30. package/dist/addresses.js +62 -0
  31. package/dist/any.d.ts +447 -0
  32. package/dist/any.js +729 -0
  33. package/dist/api.d.ts +62 -0
  34. package/dist/api.js +30 -0
  35. package/dist/blocks.d.ts +107 -0
  36. package/dist/blocks.js +126 -0
  37. package/dist/coin-rules-config.d.ts +8 -0
  38. package/dist/coin-rules-config.js +13 -0
  39. package/dist/coin-rules.d.ts +383 -0
  40. package/dist/coin-rules.js +878 -0
  41. package/dist/coins.d.ts +217 -0
  42. package/dist/coins.js +520 -0
  43. package/dist/dips.d.ts +133 -0
  44. package/dist/dips.js +148 -0
  45. package/dist/errors.d.ts +35 -0
  46. package/dist/errors.js +347 -0
  47. package/dist/index.d.ts +73 -0
  48. package/dist/index.js +58 -0
  49. package/dist/infinity.d.ts +63 -0
  50. package/dist/infinity.js +96 -0
  51. package/dist/infra.d.ts +112 -0
  52. package/dist/infra.js +114 -0
  53. package/dist/lever.d.ts +391 -0
  54. package/dist/lever.js +419 -0
  55. package/dist/pools.d.ts +274 -0
  56. package/dist/pools.js +405 -0
  57. package/dist/sticky-rules.d.ts +179 -0
  58. package/dist/sticky-rules.js +580 -0
  59. package/dist/sticky.d.ts +216 -0
  60. package/dist/sticky.js +292 -0
  61. package/dist/tx.d.ts +70 -0
  62. package/dist/tx.js +69 -0
  63. package/dist/v3.d.ts +42 -0
  64. package/dist/v3.js +98 -0
  65. package/package.json +58 -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,310 @@
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
+
14
+ 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".
15
+
16
+ ```bash
17
+ npm install @pickhooks/sdk viem
18
+ ```
19
+
20
+ ```ts
21
+ import { createPickhooks } from "@pickhooks/sdk";
22
+ import { createWalletClient, http, parseEther } from "viem";
23
+ import { privateKeyToAccount } from "viem/accounts";
24
+ import { bsc } from "viem/chains";
25
+
26
+ const walletClient = createWalletClient({ account: privateKeyToAccount(KEY), chain: bsc, transport: http() });
27
+ const ph = createPickhooks({ walletClient });
28
+
29
+ const [pool] = await ph.any.pools({ limit: 1 });
30
+ const r = await ph.any.buy({ pool, bnbIn: parseEther("0.05") });
31
+ console.log(r.amountOut, r.recapture); // coins bought; the recapture of this transaction and your share of it
32
+ await ph.any.claim(); // your recapture shares (and, as an opener or partner, those shares)
33
+ ```
34
+
35
+ 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.
36
+
37
+ ## Who earns what (hook any coin)
38
+
39
+ | who | what | how it is paid |
40
+ |---|---|---|
41
+ | the trader | 25 % of every recapture its swap made possible | `claim()` |
42
+ | 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()` |
43
+ | a partner | its listed share (up to 50 %) of the pickhooks part of every fee and recapture in pools opened with it | `claim()` |
44
+ | 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 |
45
+
46
+ 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.
47
+
48
+ **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.
49
+
50
+ ## Gas: the recapture room
51
+
52
+ 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`.
53
+
54
+ ## hook any coin: `ph.any`
55
+
56
+ Reading
57
+
58
+ ```ts
59
+ await ph.any.terms(); // { owner, platformWallet, openerBps, traderBps, hook }
60
+ await ph.any.pools({ limit, offset }); // newest first: id, key, token, symbol, config, counters, positions, price
61
+ await ph.any.pool(id); // one pool, or null
62
+ await ph.any.poolsOf(token); // every pool of a coin (one per slot)
63
+ await ph.any.check(token); // can this coin get a pool? price, price source, depth, free slot, pair
64
+ await ph.any.earnings(wallet); // { owed, routerCredit, routerClaimable, partnerBps }
65
+ await ph.any.router(contract); // { payout, bps }
66
+ await ph.any.partnerBps(partner);
67
+ await ph.any.bonusOf(pool, wallet); // lock to earn
68
+ await ph.any.pendingFees(pool); // what a collect would book now
69
+ ```
70
+
71
+ Trading (BNB in for buys, BNB out for sells; `pool` is an id, a key or a pool from `pools()`)
72
+
73
+ ```ts
74
+ const q = await ph.any.quote({ pool, side: "buy", amount: parseEther("0.1"), from: me }); // quote = fill
75
+ const b = await ph.any.buy({ pool, bnbIn: parseEther("0.1"), slippageBps: 100 });
76
+ const s = await ph.any.sell({ pool, amount: b.amountOut / 2n }); // approves Permit2 once, then the router for 30 days
77
+ // b.amountOut, b.recapture { profit, toTrader, soldHere }, b.routerCredit, b.hash, b.receipt
78
+ ```
79
+
80
+ Building instead of sending
81
+
82
+ ```ts
83
+ const key = await ph.any.key(poolId);
84
+ const tx = ph.any.build.buy({ key, bnbIn, minOut }); // { to: UniversalRouter, data, value, extraGas }
85
+ const approvals = await ph.any.sellApprovals(owner, key.currency1, amount); // TxRequest[]
86
+ ph.any.readTrade(receipt); // the trade, the recapture and the router credit of a receipt
87
+ ```
88
+
89
+ Opening a pool (as a launchpad or bot, with yourself as the partner)
90
+
91
+ ```ts
92
+ const c = await ph.any.check(coin); // c.ok, c.text, c.depth (BNB in the coin's main pool)
93
+ const need = ph.any.depthNeeds(c, "ladder10", c.freeSlot!); // coins a pool needs to be as deep (the factory refuses a shallower one)
94
+ const { id } = await ph.any.open({ token: coin, tokenAmount: need.coins, partner: MY_PARTNER_WALLET });
95
+ ph.any.partnerLink(MY_PARTNER_WALLET); // the site's open form with you named as partner
96
+ ```
97
+
98
+ 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.
99
+
100
+ 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`.
101
+
102
+ ### The tax line (flap tax coins)
103
+
104
+ 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.
105
+
106
+ ```ts
107
+ const c = await ph.any.check(taxCoin); // c.line === "tax", c.tax { buyBps, sellBps, ... }
108
+ const t = await ph.any.taxOf(taxCoin); // the tax as it runs now
109
+ const fit = fitLadder(c, coins, c.freeSlot!, t.sellBps); // the range a ladder of `coins` needs to be as deep as the main pool
110
+ const q = await ph.any.quote({ pool, side: "buy", amount }); // { amountOut (after tax), gross, taxBps }
111
+ await ph.any.sell({ pool, amount }); // while the anti-farmer tax runs: pays the coins in first, then swaps
112
+ await ph.any.claim({ line: "tax" }); // the opener's side of the tax line's fees
113
+ ```
114
+
115
+ 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.
116
+
117
+ ## sticky rules: `ph.sticky`
118
+
119
+ ```ts
120
+ import { TEMPLATES } from "@pickhooks/sdk"; // hold, sniper, devlock, drip, maxbuy, maxwallet, window, hours, burn, dipdrop, lucky, wakeup
121
+
122
+ const picks = [
123
+ { 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
124
+ { id: "devlock", params: { d: 7 } }, // the creator's first buy cannot sell for 7 days
125
+ { id: "lucky", params: { pot: 2, n: 25, share: 100 } },
126
+ ];
127
+ const table = ph.sticky.compile(picks); // { rows, release, problems }
128
+ await ph.sticky.validate(table.rows, table.release); // null, or the validator's reason as a sentence
129
+ const { token } = await ph.sticky.launch({ name, symbol, metadata: "https://…/meta.json", picks, devBuy: parseEther("0.05") });
130
+ ```
131
+
132
+ 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 }`.
133
+
134
+ ```ts
135
+ await ph.sticky.coins({ limit }); // newest first: rows as sentences, scanner color, holders, pot, price
136
+ await ph.sticky.coin(token);
137
+ await ph.sticky.wallet(token, who); // balance, sellable now, lots (amount, locked, since, marks)
138
+ const v = await ph.sticky.check({ token, side: "sell", wallet, amount });
139
+ // { ok: true } or { ok: false, row: 1, text: "Refused by rule 2: Sniper jail. A sell is refused when …" }
140
+ await ph.sticky.buy({ token, bnbIn }); // quote, check, then the buy through PancakeSwap V3
141
+ await ph.sticky.sell({ token, amount }); // check first: a refusing rule stops it before anything is signed
142
+ await ph.sticky.lift(token, row); // the creator lifts a row for good
143
+ ```
144
+
145
+ **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:
146
+
147
+ ```ts
148
+ import { ACT, ON, OP, VAR, VARS } from "@pickhooks/sdk"; // VARS: every variable with its unit (minutes, % of supply, x, ...)
149
+
150
+ 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
151
+ await ph.sticky.launch({ name, symbol, metadata, picks: [{ id: "devlock", params: { d: 7 } }], script: [noBigSells], devBuy });
152
+ ```
153
+
154
+ 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).
155
+
156
+ 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.
157
+
158
+ **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.
159
+
160
+ ## Coins with rules: `ph.coins`
161
+
162
+ 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.
163
+
164
+ ```ts
165
+ import { RULES } from "@pickhooks/sdk"; // the catalog: id, kind, name, fields (also @pickhooks/sdk/coin-rules)
166
+
167
+ await ph.coins.coins({ version: 2, limit: 20 }); // newest first: rules as sentences, holders, price
168
+ const c = await ph.coins.coin(token); // c.version, c.rules [{ name, text, ended }], c.extras
169
+ const v = await ph.coins.check({ token, side: "buy", wallet, amount: await ph.coins.estimateBuy(token, bnbIn) });
170
+ // { 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." }
171
+ await ph.coins.buy({ token, bnbIn }); // quote, check, buy; a refusing rule stops it before anything is signed
172
+ await ph.coins.sell({ token, amount });
173
+ ```
174
+
175
+ `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.
176
+
177
+ Launching (v2):
178
+
179
+ ```ts
180
+ const rules = [
181
+ { id: "max_wallet", values: { cap: 1 } }, // % of supply
182
+ { id: "max_tx", values: { cap: 0.5 } },
183
+ { id: "buyout", values: { rules: "2", price: 0.1 } }, // anyone can buy rule 2 off for 0.1 BNB
184
+ ];
185
+ const L = await ph.coins.launch({ name, symbol, metadata, rules, devBuy: parseEther("0.02") });
186
+ // L.token, L.burned: rules that need $hooks burn it in the launch, bought with BNB (payBurnIn: "hooks" uses yours)
187
+ ```
188
+
189
+ `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.
190
+
191
+ ## Pools and curve calls: `ph.pools`, `ph.calls`
192
+
193
+ Pool coins carry their rules in a PancakeSwap Infinity pool's hook instead of the coin; they trade through the UniversalRouter (Permit2 for sells).
194
+
195
+ ```ts
196
+ await ph.pools.knownKinds(); // the rules a pool can carry (Max wallet needs the coin, so no)
197
+ const P = await ph.pools.launch({ name, symbol, metadata, rules: [{ id: "max_tx", values: { cap: 0.5 } }], devBuy });
198
+ await ph.pools.check({ token, side: "buy", wallet, amount }); // the quoter runs the hook as the buyer and names the rule
199
+ await ph.pools.buy({ token, bnbIn }); await ph.pools.sell({ token, amount });
200
+ await ph.pools.owed(creator); await ph.pools.claim(); // the creator's share, booked on every swap
201
+ ```
202
+
203
+ `ph.calls` is the same for curve calls coins, plus the desk:
204
+
205
+ ```ts
206
+ const steps = await ph.calls.steps(token); // the steps above the price that are open (none in a coin's first 10 minutes)
207
+ const q = await ph.calls.quoteCall(token, step, coins, seconds); // { premium, liquidity }
208
+ const { id } = await ph.calls.openCall({ token, step, coins, seconds });
209
+ await ph.calls.payout(id, me); // what closing pays now
210
+ await ph.calls.closeCall(id); // the payout and the bond come back
211
+ await ph.calls.withdraw(); // anything the desk holds for you (ph.calls.pending(me))
212
+ ```
213
+
214
+ ## Lever: `ph.lever` and `ph.leverV1`
215
+
216
+ ```ts
217
+ const m = await ph.lever.coin(token); // the Lens: price, room for longs and shorts, open longs and shorts
218
+ const o = await ph.lever.quoteOpen(token, "long", gross, 2); // o.reason 0 = it opens; otherwise o.text says why
219
+ const { id } = await ph.lever.open({ token, side: "short", gross, leverage: 2 });
220
+ await ph.lever.positions(token); // { longs, shorts }: owner, margin, trigger, closeNet (what closing pays now)
221
+ await ph.lever.close({ token, side: "short", id });
222
+ await ph.lever.sell({ token, amount }); // sellPlan() splits a sale around open shorts when it must
223
+ await ph.lever.claim(token, "creator"); // "creator" | "refund" | "platform"
224
+ ```
225
+
226
+ `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`.
227
+
228
+ ## Dip bids: `ph.dips`
229
+
230
+ 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.
231
+
232
+ ```ts
233
+ const { id } = await ph.dips.post({ token, price: 0.000000003, duration: 86_400, premiumBps: 500, until, minCover, deposit });
234
+ await ph.dips.bids(token); // the coin's bids
235
+ const q = await ph.dips.quote(id, coins); // { cover, premium, fee, payout }
236
+ const f = await ph.dips.buyFloor(id, coins); // f.id: the floor
237
+ await ph.dips.exercise({ floorId: f.id, coins, token }); // approval, a dry run, then the coins go to the maker for BNB
238
+ await ph.dips.close(id); // the maker takes the free BNB back
239
+ ```
240
+
241
+ `strikeFromPrice(bnbPerCoin)`, `coverOf(strike, coins)` and `coinsFor(strike, cover)` convert; the strike is BNB wei per whole coin.
242
+
243
+ ## HOOKS infra: `ph.infra`
244
+
245
+ Off until its contracts are on mainnet (`addresses.hooksExecutor`, `addresses.hooksFloorFactory`; `ph.infra.on` says which part is live).
246
+
247
+ * **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.
248
+ * **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.
249
+
250
+ ```ts
251
+ const f = await ph.infra.floorOf(token); // { floor, reserve, circulating, perCoin, totalFed, totalPaid, totalRedeemed }
252
+ await ph.infra.quoteRedeem(token, coins); // { payout, kept, protocolFee }
253
+ await ph.infra.redeem({ token, coins }); // approval, then the hand in (quote less 0.5 % as the minimum)
254
+ await ph.infra.feed(token, parseEther("1")); // more BNB under the coin
255
+ await ph.infra.open({ token, seed }); // the coin's first floor
256
+ const o = await ph.infra.offer({ token, bnbIn }); // the route, the bids that can cover it, the transaction
257
+ await ph.infra.protect({ token, bnbIn }); // { coins, floorId, premium }
258
+ ```
259
+
260
+ ## Building blocks: `ph.blocks`
261
+
262
+ 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).
263
+
264
+ ```ts
265
+ const c = ph.blocks.catalog(); // { version, sticky: { blocks, script, promises, limits }, coinRules: { groups, rules } }
266
+ ph.blocks.block("sniper"); // { name, line, example, params, rows, scanner, sticky }
267
+ await ph.api.blocks(); // the same object from pickhooks.com/api/blocks, once the site serves it
268
+ ```
269
+
270
+ 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.
271
+
272
+ ## pickhooks.com's API: `ph.api`
273
+
274
+ `launches({ since, before, limit })`, `launch(address)`, `coins()`, `activity()`, `official()`, `burners()`, or `get(path, query)`. No key; a limit per address per minute.
275
+
276
+ ## Errors
277
+
278
+ 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.
279
+
280
+ ## Addresses (BNB Chain)
281
+
282
+ | | |
283
+ |---|---|
284
+ | hook any coin v3 factory | `0x1662668Ab8FaA612A7F615F1AccB90ceC20be117` |
285
+ | hook any coin v3 hook | `0x49892253A5E71f5DF0Fbc118bd7c15acAF55F767` |
286
+ | sticky factory | `0x385C273bDaBC5a0788dfBb648F05bE0C5EE018fd` |
287
+ | sticky validator | `0x057007a21330EA770f2Fcb61c8925C28c270480f` |
288
+ | coins with rules v1 factory | `0xecED45Ae3e85D947038009710594a50d422A54D8` |
289
+ | coins with rules v2 factory | `0x23cC366e1DDBc41CFD70011C4AaC14B79998B24F` |
290
+ | pools factory | `0x3F97831C8296D934d84357B619CfC44D32d0241B` |
291
+ | curve calls factory | `0x98D49C17458def2e5fdF00F20479658693498301` |
292
+ | Lever factory | `0x03EbF1558E2f9337E4d2FfCAcE3A5114aC32A87A` |
293
+ | Lever Lens | `0x3f1a660FC365Af192acE4E761657cE61A6ED0F13` |
294
+ | lever (v1) factory | `0xeaB93e923170bd5331Db4300aF6F2555eBBF9615` |
295
+ | dip bids desk | `0xc73bcB859C3fD5Bd38A10B0aD9A862EAAf6765bf` |
296
+ | $hooks | `0x07bcB8E8226f671300e135b4A61Dc157359b7777` |
297
+
298
+ 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 sticky encoder alone: `@pickhooks/sdk/rules`; the rule catalog of coins with rules: `@pickhooks/sdk/coin-rules`.
299
+
300
+ ## Examples
301
+
302
+ * `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)
303
+ * `examples/bot.mjs`: quote, buy with the recapture room, sell, claim
304
+ * `examples/launchpad.mjs`: a sticky launch from templates, a pool with you as the partner, the partner's claim
305
+
306
+ They send nothing without `--send`.
307
+
308
+ ## Tests
309
+
310
+ `npm test` (offline: pool ids, ranges, building, errors, the rule compiler). 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.