@pickhooks/sdk 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/modes.js ADDED
@@ -0,0 +1,86 @@
1
+ import { encodeFunctionData, } from "viem";
2
+ import { comboModeAbi, forwardModeAbi, sticky3FactoryAbi, sticky3TokenAbi, } from "./abis/sticky3.js";
3
+ import { MODE_NAMES, ZERO_ADDRESS } from "./addresses.js";
4
+ import { PickhooksError } from "./errors.js";
5
+ import { MODE_LIST, MODES, encodeModeData, modeBps } from "./modes-catalog.js";
6
+ import { sendTx, } from "./tx.js";
7
+ export function modesModule(ctx) {
8
+ const { pub, a } = ctx;
9
+ const call = (address, abi, functionName, args = []) => pub.readContract({ address, abi: abi, functionName, args });
10
+ const tx = (to, abi, functionName, args, label, value = 0n) => ({
11
+ to,
12
+ value,
13
+ data: encodeFunctionData({ abi: abi, functionName, args }),
14
+ label,
15
+ });
16
+ const playTx = (coin, data, label) => tx(coin, sticky3TokenAbi, "play", [data], label);
17
+ const pokeTx = (coin, data, label) => tx(coin, sticky3TokenAbi, "poke", [data], label);
18
+ const send = (t, s = {}) => sendTx(ctx, t, s);
19
+ const now = async () => Number((await pub.getBlock()).timestamp);
20
+ const modeAddr = (n) => {
21
+ const m = a.modes[n];
22
+ if (m.toLowerCase() === ZERO_ADDRESS)
23
+ throw new PickhooksError(`The mode ${MODES[n].title} is not deployed yet.`, { code: "input" });
24
+ return m;
25
+ };
26
+ /** The coin's mode: its name (null: no mode, "other": a mode the SDK does not know), address, share of buys, game pot. */
27
+ async function of(coin) {
28
+ const [m, bps, pot] = await Promise.all([
29
+ call(coin, sticky3TokenAbi, "mode"),
30
+ call(coin, sticky3TokenAbi, "gameBps"),
31
+ call(coin, sticky3TokenAbi, "gamePot"),
32
+ ]);
33
+ const name = m.toLowerCase() === ZERO_ADDRESS ? null : (MODE_NAMES.find((n) => a.modes[n].toLowerCase() === m.toLowerCase()) ?? "other");
34
+ return { name, address: m, gameBps: Number(bps), gamePot: pot, info: name && name !== "other" ? MODES[name] : null };
35
+ }
36
+ /** A holder's custody in a coin: coins, of them DEV, until, since, the shadow address they sit at, and whether anyone may release it now. */
37
+ async function custody(coin, who) {
38
+ const [h, shadow, t] = await Promise.all([
39
+ call(coin, sticky3TokenAbi, "heldOf", [who]),
40
+ call(coin, sticky3TokenAbi, "shadow", [who]),
41
+ now(),
42
+ ]);
43
+ return { amount: h[0], dev: h[1], until: Number(h[2]), since: Number(h[3]), shadow, releasable: h[0] > 0n && t >= Number(h[2]) };
44
+ }
45
+ const buildRelease = (coin, who) => tx(coin, sticky3TokenAbi, "releaseHeld", [who], "Releasing the custody");
46
+ /** Is the mode open for launches on the factory now (listed). */
47
+ const listed = async (n) => a.modes[n].toLowerCase() !== ZERO_ADDRESS && (await call(a.sticky3Factory, sticky3FactoryAbi, "modes", [a.modes[n]]).catch(() => false));
48
+ // ---------------------------------------------------------------- the modes that live on trades
49
+ const combo = {
50
+ async state(coin) {
51
+ const g = await call(modeAddr("combo"), comboModeAbi, "games", [coin]);
52
+ const c = Number(g[0]);
53
+ const next = Number(await call(modeAddr("combo"), comboModeAbi, "nextAt", [BigInt(c)]));
54
+ const share = Number(await call(modeAddr("combo"), comboModeAbi, "shareAt", [BigInt(next)]));
55
+ return { combo: c, best: Number(g[1]), hits: Number(g[2]), bps: Number(g[3]), minPpm: Number(g[4]), breaker: g[5], brokeAt: Number(g[6]), next, nextSharePct: share / 100 };
56
+ },
57
+ };
58
+ const forward = {
59
+ async state(coin) {
60
+ const g = await call(modeAddr("forward"), forwardModeAbi, "games", [coin]);
61
+ return { last: g[0], lastGot: g[1], bps: Number(g[2]), minPpm: Number(g[3]), forwards: Number(g[4]) };
62
+ },
63
+ };
64
+ return {
65
+ /** the modes: line, how they play, share of buys and bounds, actions (offline) */
66
+ catalog: MODES,
67
+ list: MODE_LIST,
68
+ info: (n) => MODES[n],
69
+ /** a mode's settings encoded for the launch (zeros: defaults) */
70
+ encode: encodeModeData,
71
+ /** the share of buys a mode takes with these settings */
72
+ bps: modeBps,
73
+ /** is the mode open for launches on the factory now */
74
+ listed,
75
+ of,
76
+ custody,
77
+ build: { release: buildRelease, play: playTx, poke: pokeTx },
78
+ /** anyone: a holder's custody back to the wallet once its time is up */
79
+ release: (coin, who, s) => send(buildRelease(coin, who), s),
80
+ /** a raw play or poke (data: abi.encode(action, ...)) for modes the SDK does not know */
81
+ play: (coin, data, s) => send(playTx(coin, data, "The play"), s),
82
+ poke: (coin, data, s) => send(pokeTx(coin, data, "The poke"), s),
83
+ combo,
84
+ forward,
85
+ };
86
+ }
@@ -0,0 +1,75 @@
1
+ import { type Address, type Hex } from "viem";
2
+ import { type Ctx, type TxRequest } from "./tx.js";
3
+ import { type Venue } from "./v2.js";
4
+ export type SimResult = {
5
+ ok: boolean;
6
+ /** why it would fail, as a sentence (the rule, the mode, PancakeSwap) */
7
+ refused?: {
8
+ code: string;
9
+ text: string;
10
+ };
11
+ /** what reaches the wallet: coins on a buy, BNB (wei) on a sell, 0 on a send or a play */
12
+ out: bigint;
13
+ /** coins that burn (takes of the rows, the mode's burns) */
14
+ burned: bigint;
15
+ /** coins into the coin's pots (the rows' pot and the game pot together) */
16
+ toPots: bigint;
17
+ /** the game pot before and after (sticky 3) */
18
+ gamePot?: {
19
+ before: bigint;
20
+ after: bigint;
21
+ };
22
+ /** coins the pots pay to this wallet (a drop row, the mode's bonus) */
23
+ bonus: bigint;
24
+ /** coins that go into this wallet's custody */
25
+ intoCustody: bigint;
26
+ /** coins that leave this wallet's custody */
27
+ outOfCustody: bigint;
28
+ /** pot payouts to other wallets (pay it forward pays the last buyer) */
29
+ paidOthers: {
30
+ to: Address;
31
+ amount: bigint;
32
+ }[];
33
+ /** the mode's events and the coin's custody events, as sentences */
34
+ events: string[];
35
+ gas: bigint;
36
+ venue?: Venue;
37
+ };
38
+ /** The shadow address a sticky 3 coin keeps `who`'s custody at. */
39
+ export declare function shadowOf(who: Address): Address;
40
+ /** A mode event or a coin event as a sentence (null for events nobody needs to read). */
41
+ export declare function eventText(name: string, args: Record<string, unknown>): string | null;
42
+ export declare function simulateModule(ctx: Ctx): {
43
+ buy: (b: {
44
+ token: Address;
45
+ wallet: Address;
46
+ bnbIn: bigint;
47
+ venue?: Venue;
48
+ }) => Promise<SimResult>;
49
+ sell: (x: {
50
+ token: Address;
51
+ wallet: Address;
52
+ amount: bigint;
53
+ venue?: Venue;
54
+ }) => Promise<SimResult>;
55
+ send: (x: {
56
+ token: Address;
57
+ wallet: Address;
58
+ to: Address;
59
+ amount: bigint;
60
+ }) => Promise<SimResult>;
61
+ play: (x: {
62
+ token: Address;
63
+ wallet: Address;
64
+ data: Hex;
65
+ poke?: boolean;
66
+ }) => Promise<SimResult>;
67
+ tx: (x: {
68
+ token: Address;
69
+ wallet: Address;
70
+ tx: TxRequest;
71
+ }) => Promise<SimResult>;
72
+ shadowOf: typeof shadowOf;
73
+ eventText: typeof eventText;
74
+ };
75
+ export type SimulateModule = ReturnType<typeof simulateModule>;
@@ -0,0 +1,225 @@
1
+ import { concat, decodeEventLog, encodeFunctionData, erc20Abi, getAddress, keccak256, maxUint256, slice, toHex } from "viem";
2
+ import { comboModeAbi, forwardModeAbi, sticky3TokenAbi, } from "./abis/sticky3.js";
3
+ import { stickyTokenAbi } from "./abis/sticky.js";
4
+ import { ZERO_ADDRESS } from "./addresses.js";
5
+ import { errorText, explain } from "./errors.js";
6
+ import { describeRows } from "./sticky.js";
7
+ import { v3EstimateBuy } from "./v3.js";
8
+ import {} from "./tx.js";
9
+ import { buildV2Buy, buildV2Sell } from "./v2.js";
10
+ import { buildV3Buy, buildV3Sell } from "./v3.js";
11
+ /**
12
+ * ph.simulate: every buy, sell, send or play tried first against the chain as it is now (eth_simulateV1, nothing is
13
+ * sent). What comes back is what the coin would do: the coins or BNB that arrive, what burns, what goes into the pots,
14
+ * what a pot pays out (a drop row, the mode's bonus), what goes into custody, the mode's own events as sentences, or the
15
+ * rule, the mode or PancakeSwap reason that would stop it. For agents: trade safely. For terminals: "this is a rule, not
16
+ * a honeypot", in black and white.
17
+ */
18
+ const DEAD = "0x000000000000000000000000000000000000dEaD";
19
+ const FAR = 2n ** 40n;
20
+ const MODE_ABIS = [
21
+ comboModeAbi,
22
+ forwardModeAbi,
23
+ ];
24
+ const short = (x) => `${x.slice(0, 6)}…${x.slice(-4)}`;
25
+ const coins = (x) => {
26
+ const n = Number(x) / 1e18;
27
+ return n >= 1e6 ? `${+(n / 1e6).toFixed(2)}M` : n >= 1e3 ? `${+(n / 1e3).toFixed(1)}k` : `${+n.toFixed(2)}`;
28
+ };
29
+ /** The shadow address a sticky 3 coin keeps `who`'s custody at. */
30
+ export function shadowOf(who) {
31
+ return getAddress(slice(keccak256(concat([toHex("pickhooks.custody"), who])), 12));
32
+ }
33
+ /** A mode event or a coin event as a sentence (null for events nobody needs to read). */
34
+ export function eventText(name, args) {
35
+ const a = (k) => args[k];
36
+ switch (name) {
37
+ case "ModeSkipped":
38
+ return "The mode failed on this trade: the trade goes through without its effect.";
39
+ case "Held":
40
+ return `${short(a("who"))} has ${coins(a("amount"))} coins in custody until ${new Date(Number(a("until")) * 1000).toISOString().slice(0, 16).replace("T", " ")} UTC.`;
41
+ case "ComboUp":
42
+ return `The combo is at ${a("combo")}.`;
43
+ case "ComboHit":
44
+ return `Combo ${a("combo")}: this buy wins ${coins(a("paid"))} coins from the pot.`;
45
+ case "ComboBroken":
46
+ return `This sell breaks the combo at ${a("combo")}.`;
47
+ case "Forwarded":
48
+ return a("amount") > 0n ? `${coins(a("amount"))} coins go to the last buyer ${short(a("paid"))}; ${coins(a("burned"))} burn.` : `${coins(a("burned"))} coins burn (nobody to pay forward).`;
49
+ default:
50
+ return null;
51
+ }
52
+ }
53
+ export function simulateModule(ctx) {
54
+ const { pub, a } = ctx;
55
+ async function run(o) {
56
+ const { token, wallet } = o;
57
+ const v3 = await pub
58
+ .readContract({ address: token, abi: sticky3TokenAbi, functionName: "gamePot" })
59
+ .then(() => true)
60
+ .catch(() => false);
61
+ const potCall = { to: token, data: encodeFunctionData({ abi: sticky3TokenAbi, functionName: "gamePot" }) };
62
+ const bal = await pub.getBalance({ address: wallet });
63
+ const need = (o.bnb ?? 0n) + 10n ** 18n;
64
+ const calls = [...(v3 ? [potCall] : []), ...o.calls.map((c) => ({ to: c.to, data: c.data, value: c.value })), ...(v3 ? [potCall] : [])];
65
+ let r;
66
+ try {
67
+ r = (await pub.simulateCalls({ account: wallet, calls, stateOverrides: bal < need ? [{ address: wallet, balance: need }] : undefined }));
68
+ }
69
+ catch (e) {
70
+ return { ok: false, refused: explain(e, "The trade would fail."), out: 0n, burned: 0n, toPots: 0n, bonus: 0n, intoCustody: 0n, outOfCustody: 0n, paidOthers: [], events: [], gas: 0n };
71
+ }
72
+ const results = r.results;
73
+ const mine = v3 ? results.slice(1, -1) : results;
74
+ const fail = mine.find((x) => x.status !== "success");
75
+ const gas = mine.reduce((s, x) => s + (x.gasUsed ?? 0n), 0n);
76
+ if (fail) {
77
+ let e = explain(fail.error ?? Object.assign(new Error("reverted"), { data: fail.data }), "The trade would fail.");
78
+ // PancakeSwap's routers pass a refused transfer on as STF or TF: ask the coin which rule it was
79
+ if (o.check && !/^(Blocked|Bad|LowGas|Busy|BadOrder|NoMode)$/.test(e.code))
80
+ e = (await whyNot(token, o.check)) ?? e;
81
+ return { ok: false, refused: { code: e.code, text: e.text }, out: 0n, burned: 0n, toPots: 0n, bonus: 0n, intoCustody: 0n, outOfCustody: 0n, paidOthers: [], events: [], gas };
82
+ }
83
+ const logs = mine.flatMap((x) => x.logs ?? []);
84
+ const res = { ok: true, out: 0n, burned: 0n, toPots: 0n, bonus: 0n, intoCustody: 0n, outOfCustody: 0n, paidOthers: [], events: [], gas };
85
+ if (v3) {
86
+ const before = BigInt(results[0].data);
87
+ const after = BigInt(results[results.length - 1].data);
88
+ res.gamePot = { before, after };
89
+ }
90
+ const pools = o.pools.map((p) => p.toLowerCase());
91
+ const me = wallet.toLowerCase();
92
+ const sh = shadowOf(wallet).toLowerCase();
93
+ const coin = token.toLowerCase();
94
+ for (const l of logs) {
95
+ const at = l.address.toLowerCase();
96
+ if (at === coin) {
97
+ let ev;
98
+ try {
99
+ ev = decodeEventLog({ abi: sticky3TokenAbi, data: l.data, topics: l.topics });
100
+ }
101
+ catch {
102
+ try {
103
+ ev = decodeEventLog({ abi: stickyTokenAbi, data: l.data, topics: l.topics });
104
+ }
105
+ catch {
106
+ continue;
107
+ }
108
+ }
109
+ if (ev.eventName === "Transfer") {
110
+ const from = String(ev.args.from).toLowerCase();
111
+ const to = String(ev.args.to).toLowerCase();
112
+ const v = ev.args.value;
113
+ if (to === DEAD.toLowerCase())
114
+ res.burned += v;
115
+ else if (to === coin && from !== coin)
116
+ res.toPots += v;
117
+ else if (from === coin && to === me)
118
+ res.bonus += v;
119
+ else if (from === coin && to === sh)
120
+ res.intoCustody += v;
121
+ else if (from === coin)
122
+ res.paidOthers.push({ to: getAddress(to), amount: v });
123
+ else if (to === sh)
124
+ res.intoCustody += v;
125
+ else if (from === sh)
126
+ res.outOfCustody += v;
127
+ if (to === me && pools.includes(from))
128
+ res.out += v;
129
+ continue;
130
+ }
131
+ const t = eventText(ev.eventName, ev.args);
132
+ if (t)
133
+ res.events.push(t);
134
+ continue;
135
+ }
136
+ for (const abi of MODE_ABIS) {
137
+ try {
138
+ const ev = decodeEventLog({ abi, data: l.data, topics: l.topics });
139
+ const t = eventText(ev.eventName, ev.args);
140
+ if (t)
141
+ res.events.push(t);
142
+ break;
143
+ }
144
+ catch {
145
+ /* another mode's event */
146
+ }
147
+ }
148
+ }
149
+ return res;
150
+ }
151
+ /** The coin's own answer for a trade (check()), as a sentence, or null when it would let it through. */
152
+ async function whyNot(token, c) {
153
+ try {
154
+ const amount = typeof c.amount === "function" ? await c.amount() : c.amount;
155
+ const r = Number(await pub.readContract({ address: token, abi: stickyTokenAbi, functionName: "check", args: [c.kind, c.from, c.to, amount] }));
156
+ if (r === 255)
157
+ return null;
158
+ if (r === 254)
159
+ return { code: "Blocked", text: errorText("Blocked", [254]) };
160
+ const [raw, release, off] = (await pub.readContract({ address: token, abi: stickyTokenAbi, functionName: "script" }));
161
+ const row = describeRows(raw, Number(release), Number(off))[r];
162
+ return { code: "Blocked", text: `Refused by rule ${r + 1}${row ? `: ${row.name}. ${row.text}` : "."}` };
163
+ }
164
+ catch {
165
+ return null;
166
+ }
167
+ }
168
+ const poolsOf = async (token) => {
169
+ const [p, p2] = await Promise.all([
170
+ pub.readContract({ address: token, abi: stickyTokenAbi, functionName: "pool" }).catch(() => ZERO_ADDRESS),
171
+ pub.readContract({ address: token, abi: stickyTokenAbi, functionName: "pool2" }).catch(() => ZERO_ADDRESS),
172
+ ]);
173
+ return [p, p2];
174
+ };
175
+ /** A buy of `bnbIn` (wei) by `wallet` through PancakeSwap (V3 by default, `venue` "v2" for the pair). */
176
+ async function buy(b) {
177
+ const venue = b.venue ?? "v3";
178
+ const t = venue === "v2" ? buildV2Buy(a, { token: b.token, bnbIn: b.bnbIn, minOut: 0n, recipient: b.wallet, deadline: FAR }) : buildV3Buy(a, { token: b.token, bnbIn: b.bnbIn, minOut: 0n, recipient: b.wallet, deadline: FAR });
179
+ const pools = await poolsOf(b.token);
180
+ const check = { kind: 1, from: ZERO_ADDRESS, to: b.wallet, amount: () => v3EstimateBuy(ctx, pools[0], b.token, b.bnbIn) };
181
+ return { ...(await run({ token: b.token, wallet: b.wallet, calls: [t], bnb: b.bnbIn, pools, check })), venue };
182
+ }
183
+ /** A sell of `amount` coins by `wallet` for BNB (the approval to the router included in the run). */
184
+ async function sell(x) {
185
+ const venue = x.venue ?? "v3";
186
+ const router = venue === "v2" ? a.v2Router : a.v3Router;
187
+ const approve = { to: x.token, value: 0n, data: encodeFunctionData({ abi: erc20Abi, functionName: "approve", args: [router, maxUint256] }) };
188
+ const t = venue === "v2" ? buildV2Sell(a, { token: x.token, amount: x.amount, minOut: 0n, recipient: x.wallet, deadline: FAR }) : buildV3Sell(a, { token: x.token, amount: x.amount, minOut: 0n, recipient: x.wallet, deadline: FAR });
189
+ const before = await pub.getBalance({ address: x.wallet });
190
+ const pools = await poolsOf(x.token);
191
+ const r = await run({ token: x.token, wallet: x.wallet, calls: [approve, t], pools, check: { kind: 2, from: x.wallet, to: pools[0], amount: x.amount } });
192
+ // the BNB out: the router unwraps to the wallet (native BNB, no Transfer log); ask the chain for the balance after
193
+ if (r.ok) {
194
+ const sim = await pub
195
+ .simulateCalls({
196
+ account: x.wallet,
197
+ calls: [{ to: approve.to, data: approve.data }, { to: t.to, data: t.data }, { to: "0xcA11bde05977b3631167028862bE2a173976CA11", data: encodeFunctionData({ abi: [{ type: "function", name: "getEthBalance", stateMutability: "view", inputs: [{ name: "a", type: "address" }], outputs: [{ type: "uint256" }] }], functionName: "getEthBalance", args: [x.wallet] }) }],
198
+ })
199
+ .catch(() => null);
200
+ const last = sim?.results[2];
201
+ if (last?.status === "success") {
202
+ const after = BigInt(last.data);
203
+ const spent = sim.results[0].gasUsed + sim.results[1].gasUsed;
204
+ r.out = after > before ? after - before : 0n;
205
+ void spent; // eth_simulateV1 runs without a gas price: the balance moves by the trade only
206
+ }
207
+ }
208
+ return { ...r, venue };
209
+ }
210
+ /** A send of `amount` coins from `wallet` to `to` (a forward of a router, too). */
211
+ async function send(x) {
212
+ const t = { to: x.token, value: 0n, data: encodeFunctionData({ abi: erc20Abi, functionName: "transfer", args: [x.to, x.amount] }) };
213
+ return run({ token: x.token, wallet: x.wallet, calls: [t], pools: await poolsOf(x.token), check: { kind: 4, from: x.wallet, to: x.to, amount: x.amount } });
214
+ }
215
+ /** A play (abi.encode(action, ...)) or a poke by `wallet`: what the mode would do with it. */
216
+ async function play(x) {
217
+ const t = { to: x.token, value: 0n, data: encodeFunctionData({ abi: sticky3TokenAbi, functionName: x.poke ? "poke" : "play", args: [x.data] }) };
218
+ return run({ token: x.token, wallet: x.wallet, calls: [t], pools: await poolsOf(x.token) });
219
+ }
220
+ /** Any request the SDK builds (ph.modes.*.build, ph.sticky3.build.*), as `wallet`. */
221
+ async function tx(x) {
222
+ return run({ token: x.token, wallet: x.wallet, calls: [x.tx], bnb: x.tx.value, pools: await poolsOf(x.token) });
223
+ }
224
+ return { buy, sell, send, play, tx, shadowOf, eventText };
225
+ }
package/dist/sticky.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { type Address, type Hex } from "viem";
2
+ import { type ModeName } from "./addresses.js";
3
+ import { type ModeSettings } from "./modes-catalog.js";
2
4
  import { type EditRow, type Pick as RulePick, compile } from "./sticky-rules.js";
3
5
  import { type SimReport } from "./sticky-sim.js";
4
6
  import { type Ctx, type SendOptions, type Sent, type TxRequest } from "./tx.js";
@@ -54,6 +56,13 @@ export type StickyCoin = {
54
56
  /** BNB per coin at the V3 pool's price, and the market cap in BNB */
55
57
  priceBnb: number;
56
58
  mcapBnb: number;
59
+ /** sticky 3: the coin's mode (its name, or "other" for a mode the SDK does not know), its share of buys and the game pot */
60
+ mode?: {
61
+ name: ModeName | "other" | null;
62
+ address: Address;
63
+ gameBps: number;
64
+ gamePot: bigint;
65
+ };
57
66
  };
58
67
  export type StickyLot = {
59
68
  amount: bigint;
@@ -102,6 +111,9 @@ export type StickyLaunch = {
102
111
  */
103
112
  switchRows?: number[];
104
113
  switcher?: Address;
114
+ /** sticky 3 only: the coin's mode (fixed for good) and its settings within the mode's bounds (defaults when left out) */
115
+ mode?: ModeName;
116
+ modeSettings?: ModeSettings;
105
117
  };
106
118
  export type StickyTerms = {
107
119
  seed: bigint;
@@ -145,13 +157,16 @@ export declare function stickyTestRun(l: Pick<StickyLaunch, "picks" | "script" |
145
157
  }): StickyTestRun;
146
158
  /**
147
159
  * The sticky module. `v2` points it at the sticky 2 factory (same coins, same rules, same calls; its coins also count
148
- * the creator's sold coins and can carry switch rows, see ph.sticky2).
160
+ * the creator's sold coins and can carry switch rows, see ph.sticky2). `3` points it at sticky 3: the same again, plus a
161
+ * mode per coin (launch with `mode` and `modeSettings`; the game itself is ph.modes); a sticky 3 coin leaves its lot
162
+ * views to the lens.
149
163
  */
150
- export declare function stickyModule(ctx: Ctx, v2?: boolean): {
164
+ export declare function stickyModule(ctx: Ctx, version?: boolean | 3): {
151
165
  factory: `0x${string}`;
152
166
  terms: () => Promise<StickyTerms>;
153
167
  validate: (rows: bigint[], release: number, custom?: boolean) => Promise<string | null>;
154
168
  validateSwitch: (rows: bigint[], mask: number, validator?: Address) => Promise<string | null>;
169
+ validateMode: (mode: ModeName, settings: ModeSettings | undefined, rows: bigint[], validator?: Address, creator?: Address) => Promise<string | null>;
155
170
  compile: typeof compile;
156
171
  table: typeof stickyTable;
157
172
  testRun: typeof stickyTestRun;
@@ -182,6 +197,7 @@ export declare function stickyModule(ctx: Ctx, v2?: boolean): {
182
197
  balance: bigint;
183
198
  sellable: bigint;
184
199
  lots: StickyLot[];
200
+ held?: bigint;
185
201
  }>;
186
202
  check: (c: {
187
203
  token: Address;
@@ -202,6 +218,7 @@ export declare function stickyModule(ctx: Ctx, v2?: boolean): {
202
218
  v2: bigint | null;
203
219
  }>;
204
220
  estimateBuy: (token: Address, bnbIn: bigint) => Promise<bigint>;
221
+ buyTakeBps: (token: Address) => Promise<number>;
205
222
  sellApproval: (owner: Address, token: Address, amount: bigint) => Promise<TxRequest | null>;
206
223
  build: {
207
224
  launch: (l: {
@@ -215,6 +232,8 @@ export declare function stickyModule(ctx: Ctx, v2?: boolean): {
215
232
  minCreatorBps: number;
216
233
  switcher?: Address;
217
234
  switchMask?: number;
235
+ mode?: ModeName;
236
+ modeSettings?: ModeSettings;
218
237
  }, value: bigint) => TxRequest;
219
238
  buy: (b: {
220
239
  token: Address;