pons-client 0.1.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/index.js ADDED
@@ -0,0 +1,1021 @@
1
+ import { parseAbi, isAddress, createPublicClient, http, getAddress, formatEther, formatUnits, decodeEventLog, keccak256, encodeAbiParameters, parseAbiItem } from 'viem';
2
+ export { decodeEventLog } from 'viem';
3
+
4
+ // src/client.ts
5
+
6
+ // src/constants.ts
7
+ var ROBINHOOD_CHAIN_ID = 4663;
8
+ var BPS = 10000n;
9
+ var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
10
+ var ADDRESSES = {
11
+ factory: "0x7eD598BcEf8bd9Edd8C97A195C6d13f40801EC7e",
12
+ memeHook: "0xE5e702641Ea86F4ae6cC3cDaeD2B886f976Be044",
13
+ feeEscrow: "0xd3AFEB2a57f70eF218Aa82451c51B2fb0416Ac9e",
14
+ buybackVault: "0x42df2a798f82289E177311362e8f5ccC45c1219c",
15
+ launchLocker: "0x267444D099b10fB5Ed7c3Cc7B7c767AdcA574952",
16
+ launchAndBuy: "0xe33E9E479dF8802cb0866d5d05258bEc4cF62948",
17
+ launchDeployer: "0x3711ceA4feaDE896C913C68F01Eda97Cb06D1A42",
18
+ graduationExecutor: "0xC7819B64A1dAECD7eC19856d026cb14EfBd89046",
19
+ graduationGuard: "0xf5695117b99B6f6401e67d4195BD653628176C6C"
20
+ };
21
+ var PHASE = {
22
+ NotGraduated: 0,
23
+ Swept: 1,
24
+ PoolCreated: 2,
25
+ Rescued: 3
26
+ };
27
+ var SNIPE_TAX_DECAY_NS = 5000000000n;
28
+ var MAX_SNIPE_EXEMPTIONS = 32;
29
+ var VESTING_DURATION_SECS = 157680000n;
30
+ var MIGRATION_CLAIM_WINDOW_SECS = 7776000n;
31
+ var factoryAbi = parseAbi([
32
+ // ── Structs ──────────────────────────────────────────────────────────────
33
+ "struct LaunchConfig { uint256 supply; uint256 curveFeeBps; uint256 phantomQuote; uint256 graduationThreshold; uint24 poolFee; int24 tickSpacing; bool enabled; }",
34
+ "struct Socials { string twitter; string telegram; string discord; string website; string farcaster; }",
35
+ "struct TokenParams { string name; string symbol; string logo; string description; Socials socials; address creatorFeeRecipient; uint16 creatorTaxBps; bool buybackEnabled; bytes32 expectedEconomics; bytes32 salt; }",
36
+ "struct LaunchedToken { address token; address curve; address deployer; address creatorFeeRecipient; address pairToken; uint256 graduationThreshold; uint24 poolFee; int24 tickSpacing; uint16 creatorTaxBps; bool buybackEnabled; uint8 phase; uint256 sweptQuote; uint256 sweptTokens; uint256 sweptAt; bool exists; }",
37
+ "struct FeePolicy { address protocolFeeRecipient; uint16 protocolFeeShareBps; uint16 buybackBurnBps; uint16 hookFeeBps; uint16 maxInternalPriceImpactBps; }",
38
+ // ── Read Functions ───────────────────────────────────────────────────────
39
+ "function launchConfigCount() view returns (uint256)",
40
+ "function getLaunchConfig(uint256 id) view returns (LaunchConfig)",
41
+ "function getLaunchedToken(address token) view returns (LaunchedToken)",
42
+ "function previewLaunchEconomics(uint256 launchConfigId, address pairToken) view returns (bytes32)",
43
+ "function launchFee() view returns (uint256)",
44
+ "function canLaunch(address launcher) view returns (bool)",
45
+ "function maxCreatorTaxBps() view returns (uint16)",
46
+ "function approvedPairTokens(address pairToken) view returns (bool)",
47
+ "function pairTokenEconomics(address pairToken) view returns (uint256 phantomQuote, uint256 graduationThreshold, uint8 decimals)",
48
+ "function getLaunchFeePolicy(address token) view returns (FeePolicy)",
49
+ "function pendingCreatorFeeRecipient(address token) view returns (address recipient, uint256 effectiveAt, uint256 expiresAt)",
50
+ // ── Write Functions ──────────────────────────────────────────────────────
51
+ "function launchToken(TokenParams params, uint256 launchConfigId, address pairToken) payable returns (address token, address curve)",
52
+ "function launchToken(TokenParams params, uint256 launchConfigId, address pairToken, address[] snipeTaxExemptions) payable returns (address token, address curve)",
53
+ "function createGraduatedPool(address token)",
54
+ "function transferCreatorFeeRecipient(address token, address newRecipient)",
55
+ // ── Events ───────────────────────────────────────────────────────────────
56
+ "event TokenLaunched(address indexed token, address indexed curve, address indexed deployer, address pairToken, uint256 launchConfigId, uint256 graduationThreshold)",
57
+ "event LaunchSwept(address indexed token, uint256 sweptQuote, uint256 sweptTokens)",
58
+ "event PoolGraduated(address indexed token, address indexed pool)",
59
+ "event CreatorFeeRecipientChangeProposed(address indexed token, address indexed newRecipient, uint256 effectiveAt)",
60
+ "event CreatorFeeRecipientUpdated(address indexed token, address indexed oldRecipient, address indexed newRecipient)"
61
+ ]);
62
+ var routerAbi = parseAbi([
63
+ // ── Structs ──────────────────────────────────────────────────────────────
64
+ "struct Socials { string twitter; string telegram; string discord; string website; string farcaster; }",
65
+ "struct TokenParams { string name; string symbol; string logo; string description; Socials socials; address creatorFeeRecipient; uint16 creatorTaxBps; bool buybackEnabled; bytes32 expectedEconomics; bytes32 salt; }",
66
+ // ── Write Functions ──────────────────────────────────────────────────────
67
+ "function launchAndBuy(TokenParams params, uint256 launchConfigId, address pairToken, uint256 quoteIn, uint256 minTokensOut, address recipient, address[] snipeTaxExemptions) payable returns (address token, address curve, uint256 tokensOut)"
68
+ ]);
69
+ function requireValidAddress(address, label) {
70
+ if (!isAddress(address)) {
71
+ throw new Error(`Invalid ${label} address: ${address}`);
72
+ }
73
+ }
74
+ function requireValidCreatorTax(taxBps, maxBps) {
75
+ if (taxBps < 0) {
76
+ throw new Error("Creator tax cannot be negative");
77
+ }
78
+ if (BigInt(taxBps) > maxBps) {
79
+ throw new Error(`Creator tax ${taxBps} bps exceeds protocol max ${maxBps} bps`);
80
+ }
81
+ }
82
+ function requireValidExemptions(exemptions) {
83
+ if (exemptions.length > MAX_SNIPE_EXEMPTIONS) {
84
+ throw new Error(
85
+ `Snipe tax exemption list too long: ${exemptions.length} (max ${MAX_SNIPE_EXEMPTIONS})`
86
+ );
87
+ }
88
+ }
89
+ function requirePositiveAmount(amount, label) {
90
+ if (amount <= 0n) {
91
+ throw new Error(`${label} must be positive, got ${amount}`);
92
+ }
93
+ }
94
+ function requireValidSlippage(slippageBps) {
95
+ if (slippageBps < 0 || slippageBps > Number(BPS)) {
96
+ throw new Error(`Invalid slippage: ${slippageBps} bps (must be 0-${BPS})`);
97
+ }
98
+ }
99
+ function minOutputWithSlippage(quoted, slippageBps) {
100
+ const tolerance = quoted * BigInt(slippageBps) / BPS;
101
+ return quoted - tolerance;
102
+ }
103
+
104
+ // src/modules/factory/index.ts
105
+ function createFactoryModule(publicClient, wallet, addresses) {
106
+ const read = async (functionName, args) => publicClient.readContract({
107
+ address: addresses.factory,
108
+ abi: factoryAbi,
109
+ functionName,
110
+ args
111
+ });
112
+ const write = async (functionName, args, value) => {
113
+ if (!wallet) throw new Error("Wallet required for write operations");
114
+ const { request } = await publicClient.simulateContract({
115
+ address: addresses.factory,
116
+ abi: factoryAbi,
117
+ functionName,
118
+ args,
119
+ account: wallet.account,
120
+ value
121
+ });
122
+ return wallet.writeContract(request);
123
+ };
124
+ return {
125
+ async openLaunchConfigs() {
126
+ const count = await read("launchConfigCount");
127
+ const configs = await Promise.all(
128
+ Array.from(
129
+ { length: Number(count) },
130
+ (_, id) => read("getLaunchConfig", [BigInt(id)])
131
+ )
132
+ );
133
+ return configs.map((config, id) => ({
134
+ id: BigInt(id),
135
+ supply: config.supply,
136
+ curveFeeBps: config.curveFeeBps,
137
+ phantomQuote: config.phantomQuote,
138
+ graduationThreshold: config.graduationThreshold,
139
+ poolFee: config.poolFee,
140
+ tickSpacing: config.tickSpacing,
141
+ enabled: config.enabled
142
+ })).filter((config) => config.enabled);
143
+ },
144
+ async getLaunchConfig(id) {
145
+ return read("getLaunchConfig", [id]);
146
+ },
147
+ async getLaunchedToken(token) {
148
+ return read("getLaunchedToken", [token]);
149
+ },
150
+ async previewLaunchEconomics(configId, pairToken) {
151
+ return read("previewLaunchEconomics", [configId, pairToken]);
152
+ },
153
+ async launchFee() {
154
+ return read("launchFee");
155
+ },
156
+ async canLaunch(address) {
157
+ return read("canLaunch", [address]);
158
+ },
159
+ async maxCreatorTaxBps() {
160
+ return read("maxCreatorTaxBps");
161
+ },
162
+ async approvedPairTokens(pairToken) {
163
+ return read("approvedPairTokens", [pairToken]);
164
+ },
165
+ async pairTokenEconomics(pairToken) {
166
+ const result = await read("pairTokenEconomics", [
167
+ pairToken
168
+ ]);
169
+ return {
170
+ phantomQuote: result[0],
171
+ graduationThreshold: result[1],
172
+ decimals: Number(result[2])
173
+ };
174
+ },
175
+ async launchToken(params, configId, pairToken, snipeTaxExemptions = []) {
176
+ requireValidAddress(pairToken, "pairToken");
177
+ requireValidCreatorTax(params.creatorTaxBps, await this.maxCreatorTaxBps());
178
+ requireValidExemptions(snipeTaxExemptions);
179
+ const [expectedEconomics, launchFeeAmount] = await Promise.all([
180
+ this.previewLaunchEconomics(configId, pairToken),
181
+ this.launchFee()
182
+ ]);
183
+ const pinnedParams = {
184
+ name: params.name,
185
+ symbol: params.symbol,
186
+ logo: params.logo,
187
+ description: params.description,
188
+ socials: params.socials,
189
+ creatorFeeRecipient: params.creatorFeeRecipient,
190
+ creatorTaxBps: params.creatorTaxBps,
191
+ buybackEnabled: params.buybackEnabled,
192
+ expectedEconomics,
193
+ salt: params.salt
194
+ };
195
+ if (snipeTaxExemptions.length > 0) {
196
+ return write(
197
+ "launchToken",
198
+ [pinnedParams, configId, pairToken, snipeTaxExemptions],
199
+ launchFeeAmount
200
+ );
201
+ }
202
+ return write("launchToken", [pinnedParams, configId, pairToken], launchFeeAmount);
203
+ },
204
+ async launchAndBuy(params, configId, pairToken, quoteIn, minTokensOut, recipient, snipeTaxExemptions = []) {
205
+ requireValidAddress(pairToken, "pairToken");
206
+ requireValidAddress(recipient, "recipient");
207
+ requireValidCreatorTax(params.creatorTaxBps, await this.maxCreatorTaxBps());
208
+ requireValidExemptions(snipeTaxExemptions);
209
+ if (!wallet) throw new Error("Wallet required for write operations");
210
+ const [expectedEconomics, launchFeeAmount] = await Promise.all([
211
+ this.previewLaunchEconomics(configId, pairToken),
212
+ this.launchFee()
213
+ ]);
214
+ const pinnedParams = {
215
+ name: params.name,
216
+ symbol: params.symbol,
217
+ logo: params.logo,
218
+ description: params.description,
219
+ socials: params.socials,
220
+ creatorFeeRecipient: params.creatorFeeRecipient,
221
+ creatorTaxBps: params.creatorTaxBps,
222
+ buybackEnabled: params.buybackEnabled,
223
+ expectedEconomics,
224
+ salt: params.salt
225
+ };
226
+ const value = pairToken === ZERO_ADDRESS ? launchFeeAmount + quoteIn : launchFeeAmount;
227
+ const { request, result } = await publicClient.simulateContract({
228
+ address: addresses.launchAndBuy,
229
+ abi: routerAbi,
230
+ functionName: "launchAndBuy",
231
+ args: [
232
+ pinnedParams,
233
+ configId,
234
+ pairToken,
235
+ quoteIn,
236
+ minTokensOut,
237
+ recipient,
238
+ snipeTaxExemptions
239
+ ],
240
+ account: wallet.account,
241
+ value
242
+ });
243
+ const hash = await wallet.writeContract(request);
244
+ const typedResult = result;
245
+ return {
246
+ hash,
247
+ token: typedResult[0],
248
+ curve: typedResult[1],
249
+ tokensOut: typedResult[2]
250
+ };
251
+ }
252
+ };
253
+ }
254
+ var curveAbi = parseAbi([
255
+ // ── Read Functions ───────────────────────────────────────────────────────
256
+ "function getReserves() view returns (uint256 quoteReserve, uint256 tokenReserve)",
257
+ "function realQuoteReserve() view returns (uint256)",
258
+ "function sellableTokens() view returns (uint256)",
259
+ "function reservedTokens() view returns (uint256)",
260
+ "function graduationThreshold() view returns (uint256)",
261
+ "function readyToGraduate() view returns (bool)",
262
+ "function graduated() view returns (bool)",
263
+ "function feeBps() view returns (uint256)",
264
+ "function creatorTaxBps() view returns (uint256)",
265
+ "function buybackEnabled() view returns (bool)",
266
+ "function isNativeQuote() view returns (bool)",
267
+ "function pairToken() view returns (address)",
268
+ "function currentSnipeTaxBps(address recipient) view returns (uint256)",
269
+ "function quoteFeeBalance() view returns (uint256)",
270
+ "function creatorTaxBalance() view returns (uint256)",
271
+ // ── Write Functions ──────────────────────────────────────────────────────
272
+ "function buy(uint256 quoteIn, uint256 minTokensOut, address recipient) payable returns (uint256 tokensOut)",
273
+ "function sell(uint256 tokensIn, uint256 minQuoteOut, address recipient) returns (uint256 quoteOut)",
274
+ "function sweepFees(uint256 minBuybackTokensOut)",
275
+ // ── Events ───────────────────────────────────────────────────────────────
276
+ "event CurveBuy(address indexed buyer, address indexed recipient, uint256 quoteIn, uint256 tokensOut, uint256 fee, uint256 tax)",
277
+ "event CurveSell(address indexed seller, address indexed recipient, uint256 tokensIn, uint256 quoteOut, uint256 fee, uint256 tax)",
278
+ "event CurveBuyRefunded(address indexed buyer, uint256 refundedQuote)",
279
+ "event CurveCompleted(address indexed token)",
280
+ "event CurveGraduated(address indexed token)",
281
+ "event AutoGraduationFailed(address indexed token)",
282
+ "event FeesSwept(uint256 quoteFees, uint256 tokenFees, uint256 buybackTokens)",
283
+ "event BuybackLocked(address indexed token, uint256 quoteSpent, uint256 tokensLocked)"
284
+ ]);
285
+
286
+ // src/utils/math.ts
287
+ function ceilDiv(a, b) {
288
+ if (b === 0n) throw new Error("Division by zero");
289
+ return (a + b - 1n) / b;
290
+ }
291
+ function amountOut(inAmount, reserveIn, reserveOut) {
292
+ if (inAmount === 0n || reserveIn === 0n || reserveOut === 0n) return 0n;
293
+ return inAmount * reserveOut / (reserveIn + inAmount);
294
+ }
295
+ function amountIn(outAmount, reserveIn, reserveOut) {
296
+ if (outAmount === 0n || reserveOut === 0n) return 0n;
297
+ if (outAmount >= reserveOut) throw new Error("Output exceeds reserve");
298
+ return outAmount * reserveIn / (reserveOut - outAmount) + 1n;
299
+ }
300
+ function applyBps(amount, bps) {
301
+ return amount * bps / BPS;
302
+ }
303
+ function subtractBps(amount, bps) {
304
+ return amount - applyBps(amount, bps);
305
+ }
306
+ function marginalPrice(quoteReserve, tokenReserve) {
307
+ if (tokenReserve === 0n) return 0;
308
+ return Number(quoteReserve) / Number(tokenReserve);
309
+ }
310
+ function graduationProgress(raised, threshold) {
311
+ if (threshold === 0n) return 0;
312
+ const clamped = raised > threshold ? threshold : raised;
313
+ return Number(clamped) / Number(threshold);
314
+ }
315
+
316
+ // src/modules/curve/index.ts
317
+ function createCurveModule(publicClient, wallet, _addresses) {
318
+ const read = async (contractAddress, functionName, args) => publicClient.readContract({
319
+ address: contractAddress,
320
+ abi: curveAbi,
321
+ functionName,
322
+ args
323
+ });
324
+ const write = async (contractAddress, functionName, args, value) => {
325
+ if (!wallet) throw new Error("Wallet required for write operations");
326
+ const { request } = await publicClient.simulateContract({
327
+ address: contractAddress,
328
+ abi: curveAbi,
329
+ functionName,
330
+ args,
331
+ account: wallet.account,
332
+ value
333
+ });
334
+ return wallet.writeContract(request);
335
+ };
336
+ return {
337
+ async buy(curve, quoteIn, minTokensOut, recipient, value) {
338
+ const isNative = await read(curve, "isNativeQuote");
339
+ const sendValue = isNative ? quoteIn : value ?? 0n;
340
+ const hash = await write(curve, "buy", [quoteIn, minTokensOut, recipient], sendValue);
341
+ const receipt = await publicClient.waitForTransactionReceipt({ hash });
342
+ let tokensOut = 0n;
343
+ for (const log of receipt.logs) {
344
+ try {
345
+ const decoded = decodeEventLog({
346
+ abi: curveAbi,
347
+ eventName: "CurveBuy",
348
+ data: log.data,
349
+ topics: log.topics
350
+ });
351
+ if (decoded.eventName === "CurveBuy") {
352
+ tokensOut = decoded.args.tokensOut;
353
+ break;
354
+ }
355
+ } catch {
356
+ }
357
+ }
358
+ return { tokensOut, hash };
359
+ },
360
+ async sell(curve, tokensIn, minQuoteOut, recipient) {
361
+ const hash = await write(curve, "sell", [tokensIn, minQuoteOut, recipient]);
362
+ const receipt = await publicClient.waitForTransactionReceipt({ hash });
363
+ let quoteOut = 0n;
364
+ for (const log of receipt.logs) {
365
+ try {
366
+ const decoded = decodeEventLog({
367
+ abi: curveAbi,
368
+ eventName: "CurveSell",
369
+ data: log.data,
370
+ topics: log.topics
371
+ });
372
+ if (decoded.eventName === "CurveSell") {
373
+ quoteOut = decoded.args.quoteOut;
374
+ break;
375
+ }
376
+ } catch {
377
+ }
378
+ }
379
+ return { quoteOut, hash };
380
+ },
381
+ async quoteBuy(curve, quoteIn, recipient) {
382
+ const results = await Promise.all([
383
+ read(curve, "getReserves"),
384
+ read(curve, "sellableTokens"),
385
+ read(curve, "feeBps"),
386
+ read(curve, "creatorTaxBps"),
387
+ read(curve, "currentSnipeTaxBps", [recipient])
388
+ ]);
389
+ const reserves = results[0];
390
+ const sellable = results[1];
391
+ const feeBps = results[2];
392
+ const creatorTaxBps = results[3];
393
+ const rawSnipeBps = results[4];
394
+ const quoteReserve = reserves[0];
395
+ const tokenReserve = reserves[1];
396
+ let snipeBps = rawSnipeBps;
397
+ if (snipeBps > 0n) {
398
+ const maxSnipeBps = BPS - feeBps - creatorTaxBps - 100n;
399
+ if (snipeBps > maxSnipeBps) snipeBps = maxSnipeBps;
400
+ }
401
+ let spent = quoteIn;
402
+ const fee = spent * feeBps / BPS;
403
+ const tax = spent * creatorTaxBps / BPS;
404
+ const snipeTax = spent * snipeBps / BPS;
405
+ let tokensOut = amountOut(spent - fee - tax - snipeTax, quoteReserve, tokenReserve);
406
+ if (tokensOut > sellable) {
407
+ tokensOut = sellable;
408
+ const net = amountIn(sellable, quoteReserve, tokenReserve);
409
+ const totalBps = BPS - feeBps - creatorTaxBps - snipeBps;
410
+ if (totalBps <= 0n) {
411
+ return { tokensOut, spent: 0n, refund: quoteIn };
412
+ }
413
+ const grossed = ceilDiv(net * BPS, totalBps);
414
+ spent = grossed < quoteIn ? grossed : quoteIn;
415
+ }
416
+ return { tokensOut, spent, refund: quoteIn - spent };
417
+ },
418
+ async quoteSell(curve, tokensIn) {
419
+ const results = await Promise.all([
420
+ read(curve, "getReserves"),
421
+ read(curve, "feeBps"),
422
+ read(curve, "creatorTaxBps")
423
+ ]);
424
+ const reserves = results[0];
425
+ const feeBps = results[1];
426
+ const creatorTaxBps = results[2];
427
+ const quoteReserve = reserves[0];
428
+ const tokenReserve = reserves[1];
429
+ const gross = amountOut(tokensIn, tokenReserve, quoteReserve);
430
+ const fee = gross * feeBps / BPS;
431
+ const tax = gross * creatorTaxBps / BPS;
432
+ return { quoteOut: gross - fee - tax };
433
+ },
434
+ async getState(curve) {
435
+ const reserves = await read(curve, "getReserves");
436
+ const [
437
+ realQuoteReserve,
438
+ sellableTokens,
439
+ graduationThreshold,
440
+ readyToGraduate,
441
+ graduated,
442
+ feeBps,
443
+ creatorTaxBps,
444
+ buybackEnabled,
445
+ isNativeQuote,
446
+ pairToken
447
+ ] = await Promise.all([
448
+ read(curve, "realQuoteReserve"),
449
+ read(curve, "sellableTokens"),
450
+ read(curve, "graduationThreshold"),
451
+ read(curve, "readyToGraduate"),
452
+ read(curve, "graduated"),
453
+ read(curve, "feeBps"),
454
+ read(curve, "creatorTaxBps"),
455
+ read(curve, "buybackEnabled"),
456
+ read(curve, "isNativeQuote"),
457
+ read(curve, "pairToken")
458
+ ]);
459
+ return {
460
+ reserves: {
461
+ quoteReserve: reserves[0],
462
+ tokenReserve: reserves[1]
463
+ },
464
+ realQuoteReserve,
465
+ sellableTokens,
466
+ graduationThreshold,
467
+ readyToGraduate,
468
+ graduated,
469
+ feeBps,
470
+ creatorTaxBps,
471
+ buybackEnabled,
472
+ isNativeQuote,
473
+ pairToken
474
+ };
475
+ },
476
+ async getReserves(curve) {
477
+ const reserves = await read(curve, "getReserves");
478
+ return { quoteReserve: reserves[0], tokenReserve: reserves[1] };
479
+ },
480
+ async sellableTokens(curve) {
481
+ return read(curve, "sellableTokens");
482
+ },
483
+ async readyToGraduate(curve) {
484
+ return read(curve, "readyToGraduate");
485
+ },
486
+ async currentSnipeTaxBps(curve, recipient) {
487
+ return read(curve, "currentSnipeTaxBps", [recipient]);
488
+ }
489
+ };
490
+ }
491
+ var hookAbi = parseAbi([
492
+ // ── Read Functions ───────────────────────────────────────────────────────
493
+ "function pendingFees(bytes32 poolId, address currency) view returns (uint256)",
494
+ "function pendingCreatorTax(bytes32 poolId, address currency) view returns (uint256)",
495
+ // ── Events ───────────────────────────────────────────────────────────────
496
+ "event PoolRegistered(bytes32 indexed poolId, address indexed token, address indexed quoteToken)",
497
+ "event PoolFeesSwept(bytes32 indexed poolId, uint256 quoteFees, uint256 tokenFees, uint256 buybackTokens)",
498
+ "event PoolConversionSkipped(bytes32 indexed poolId, string reason)",
499
+ "event PoolBuybackSkipped(bytes32 indexed poolId, string reason)"
500
+ ]);
501
+
502
+ // src/modules/pool/index.ts
503
+ function createPoolModule(publicClient, addresses) {
504
+ return {
505
+ buildPoolKey(launch) {
506
+ const [currency0, currency1] = launch.pairToken.toLowerCase() < launch.token.toLowerCase() ? [launch.pairToken, launch.token] : [launch.token, launch.pairToken];
507
+ return {
508
+ currency0,
509
+ currency1,
510
+ fee: launch.poolFee,
511
+ tickSpacing: launch.tickSpacing,
512
+ hooks: addresses.memeHook
513
+ };
514
+ },
515
+ getPoolId(launch) {
516
+ const poolKey = this.buildPoolKey(launch);
517
+ return keccak256(
518
+ encodeAbiParameters(
519
+ [
520
+ { type: "address" },
521
+ { type: "address" },
522
+ { type: "uint24" },
523
+ { type: "int24" },
524
+ { type: "address" }
525
+ ],
526
+ [poolKey.currency0, poolKey.currency1, poolKey.fee, poolKey.tickSpacing, poolKey.hooks]
527
+ )
528
+ );
529
+ },
530
+ async pendingFees(poolId, currency) {
531
+ return publicClient.readContract({
532
+ address: addresses.memeHook,
533
+ abi: hookAbi,
534
+ functionName: "pendingFees",
535
+ args: [poolId, currency]
536
+ });
537
+ },
538
+ async pendingCreatorTax(poolId, currency) {
539
+ return publicClient.readContract({
540
+ address: addresses.memeHook,
541
+ abi: hookAbi,
542
+ functionName: "pendingCreatorTax",
543
+ args: [poolId, currency]
544
+ });
545
+ }
546
+ };
547
+ }
548
+ var escrowAbi = parseAbi([
549
+ // ── Read Functions ───────────────────────────────────────────────────────
550
+ "function balanceOf(address recipient) view returns (uint256)",
551
+ "function balanceOfToken(address recipient, address token) view returns (uint256)",
552
+ // ── Write Functions ──────────────────────────────────────────────────────
553
+ "function claim()",
554
+ "function claimToken(address token)",
555
+ // ── Events ───────────────────────────────────────────────────────────────
556
+ "event Credited(address indexed recipient, uint256 amount)",
557
+ "event Claimed(address indexed recipient, uint256 amount)",
558
+ "event CreditedToken(address indexed recipient, address indexed token, uint256 amount)",
559
+ "event ClaimedToken(address indexed recipient, address indexed token, uint256 amount)"
560
+ ]);
561
+
562
+ // src/modules/fees/index.ts
563
+ function createFesModule(publicClient, wallet, addresses) {
564
+ return {
565
+ async getBalance(recipient) {
566
+ return publicClient.readContract({
567
+ address: addresses.feeEscrow,
568
+ abi: escrowAbi,
569
+ functionName: "balanceOf",
570
+ args: [recipient]
571
+ });
572
+ },
573
+ async getERC20Balance(recipient, token) {
574
+ return publicClient.readContract({
575
+ address: addresses.feeEscrow,
576
+ abi: escrowAbi,
577
+ functionName: "balanceOfToken",
578
+ args: [recipient, token]
579
+ });
580
+ },
581
+ async claim() {
582
+ if (!wallet) throw new Error("Wallet required for claim");
583
+ const { request } = await publicClient.simulateContract({
584
+ address: addresses.feeEscrow,
585
+ abi: escrowAbi,
586
+ functionName: "claim",
587
+ account: wallet.account
588
+ });
589
+ return wallet.writeContract(request);
590
+ },
591
+ async claimToken(token) {
592
+ if (!wallet) throw new Error("Wallet required for claimToken");
593
+ const { request } = await publicClient.simulateContract({
594
+ address: addresses.feeEscrow,
595
+ abi: escrowAbi,
596
+ functionName: "claimToken",
597
+ args: [token],
598
+ account: wallet.account
599
+ });
600
+ return wallet.writeContract(request);
601
+ },
602
+ async getUnsweptBalance(curve, _creatorFeeRecipient) {
603
+ const [pendingFees, pendingCreatorTax] = await Promise.all([
604
+ publicClient.readContract({
605
+ address: curve,
606
+ abi: curveAbi,
607
+ functionName: "quoteFeeBalance"
608
+ }),
609
+ publicClient.readContract({
610
+ address: curve,
611
+ abi: curveAbi,
612
+ functionName: "creatorTaxBalance"
613
+ })
614
+ ]);
615
+ return { pendingFees, pendingCreatorTax };
616
+ },
617
+ async getHookPendingFees(poolId, quoteCurrency) {
618
+ const [pendingFees, pendingCreatorTax] = await Promise.all([
619
+ publicClient.readContract({
620
+ address: addresses.memeHook,
621
+ abi: hookAbi,
622
+ functionName: "pendingFees",
623
+ args: [poolId, quoteCurrency]
624
+ }),
625
+ publicClient.readContract({
626
+ address: addresses.memeHook,
627
+ abi: hookAbi,
628
+ functionName: "pendingCreatorTax",
629
+ args: [poolId, quoteCurrency]
630
+ })
631
+ ]);
632
+ return { pendingFees, pendingCreatorTax };
633
+ },
634
+ async getFeePolicy(token) {
635
+ return publicClient.readContract({
636
+ address: addresses.factory,
637
+ abi: factoryAbi,
638
+ functionName: "getLaunchFeePolicy",
639
+ args: [token]
640
+ });
641
+ }
642
+ };
643
+ }
644
+ var vaultAbi = parseAbi([
645
+ // ── Read Functions ───────────────────────────────────────────────────────
646
+ "function totalLocked(address token) view returns (uint256)",
647
+ "function totalReleased(address token) view returns (uint256)",
648
+ "function vestedAmount(address token) view returns (uint256)",
649
+ "function releasable(address token) view returns (uint256)",
650
+ "function vestingStart(address token) view returns (uint256)",
651
+ "function VESTING_DURATION() view returns (uint256)",
652
+ // ── Write Functions ──────────────────────────────────────────────────────
653
+ "function release(address token) returns (uint256 released)",
654
+ // ── Events ───────────────────────────────────────────────────────────────
655
+ "event Locked(address indexed token, uint256 amount, uint256 vestingStart)",
656
+ "event Released(address indexed token, address indexed recipient, uint256 amount)"
657
+ ]);
658
+
659
+ // src/modules/buyback/index.ts
660
+ function createBuybackModule(publicClient, wallet, addresses) {
661
+ return {
662
+ async getState(token) {
663
+ const [totalLocked, totalReleased, vestedAmount, releasable, vestingStart, vestingDuration] = await Promise.all([
664
+ publicClient.readContract({
665
+ address: addresses.buybackVault,
666
+ abi: vaultAbi,
667
+ functionName: "totalLocked",
668
+ args: [token]
669
+ }),
670
+ publicClient.readContract({
671
+ address: addresses.buybackVault,
672
+ abi: vaultAbi,
673
+ functionName: "totalReleased",
674
+ args: [token]
675
+ }),
676
+ publicClient.readContract({
677
+ address: addresses.buybackVault,
678
+ abi: vaultAbi,
679
+ functionName: "vestedAmount",
680
+ args: [token]
681
+ }),
682
+ publicClient.readContract({
683
+ address: addresses.buybackVault,
684
+ abi: vaultAbi,
685
+ functionName: "releasable",
686
+ args: [token]
687
+ }),
688
+ publicClient.readContract({
689
+ address: addresses.buybackVault,
690
+ abi: vaultAbi,
691
+ functionName: "vestingStart",
692
+ args: [token]
693
+ }),
694
+ publicClient.readContract({
695
+ address: addresses.buybackVault,
696
+ abi: vaultAbi,
697
+ functionName: "VESTING_DURATION"
698
+ })
699
+ ]);
700
+ const progress = totalLocked > 0n ? Number(vestedAmount) / Number(totalLocked) : 0;
701
+ return {
702
+ totalLocked,
703
+ totalReleased,
704
+ vestedAmount,
705
+ releasable,
706
+ vestingStart,
707
+ vestingDuration,
708
+ progress
709
+ };
710
+ },
711
+ async release(token) {
712
+ if (!wallet) throw new Error("Wallet required for release");
713
+ const { request } = await publicClient.simulateContract({
714
+ address: addresses.buybackVault,
715
+ abi: vaultAbi,
716
+ functionName: "release",
717
+ args: [token],
718
+ account: wallet.account
719
+ });
720
+ return wallet.writeContract(request);
721
+ }
722
+ };
723
+ }
724
+ function createEventsModule(publicClient, addresses) {
725
+ return {
726
+ async getLaunches(fromBlock, toBlock = "latest") {
727
+ const logs = await publicClient.getLogs({
728
+ address: addresses.factory,
729
+ event: parseAbiItem(
730
+ "event TokenLaunched(address indexed token, address indexed curve, address indexed deployer, address pairToken, uint256 launchConfigId, uint256 graduationThreshold)"
731
+ ),
732
+ fromBlock,
733
+ toBlock
734
+ });
735
+ return logs.map((log) => ({
736
+ token: log.args.token,
737
+ curve: log.args.curve,
738
+ deployer: log.args.deployer,
739
+ pairToken: log.args.pairToken,
740
+ launchConfigId: log.args.launchConfigId,
741
+ graduationThreshold: log.args.graduationThreshold,
742
+ blockNumber: log.blockNumber,
743
+ transactionHash: log.transactionHash
744
+ }));
745
+ },
746
+ async getTrades(curve, fromBlock, toBlock = "latest") {
747
+ const logs = await publicClient.getLogs({
748
+ address: curve,
749
+ events: [
750
+ parseAbiItem(
751
+ "event CurveBuy(address indexed buyer, address indexed recipient, uint256 quoteIn, uint256 tokensOut, uint256 fee, uint256 tax)"
752
+ ),
753
+ parseAbiItem(
754
+ "event CurveSell(address indexed seller, address indexed recipient, uint256 tokensIn, uint256 quoteOut, uint256 fee, uint256 tax)"
755
+ )
756
+ ],
757
+ fromBlock,
758
+ toBlock
759
+ });
760
+ const events = [];
761
+ for (const log of logs) {
762
+ if (log.eventName === "CurveBuy") {
763
+ events.push({
764
+ type: "buy",
765
+ buyer: log.args.buyer,
766
+ recipient: log.args.recipient,
767
+ quoteIn: log.args.quoteIn,
768
+ tokensOut: log.args.tokensOut,
769
+ fee: log.args.fee,
770
+ tax: log.args.tax,
771
+ blockNumber: log.blockNumber,
772
+ transactionHash: log.transactionHash
773
+ });
774
+ } else if (log.eventName === "CurveSell") {
775
+ events.push({
776
+ type: "sell",
777
+ seller: log.args.seller,
778
+ recipient: log.args.recipient,
779
+ tokensIn: log.args.tokensIn,
780
+ quoteOut: log.args.quoteOut,
781
+ fee: log.args.fee,
782
+ tax: log.args.tax,
783
+ blockNumber: log.blockNumber,
784
+ transactionHash: log.transactionHash
785
+ });
786
+ }
787
+ }
788
+ return events;
789
+ },
790
+ async getFeeSweeps(hook, fromBlock, toBlock = "latest") {
791
+ const logs = await publicClient.getLogs({
792
+ address: hook,
793
+ event: parseAbiItem(
794
+ "event PoolFeesSwept(bytes32 indexed poolId, uint256 quoteFees, uint256 tokenFees, uint256 buybackTokens)"
795
+ ),
796
+ fromBlock,
797
+ toBlock
798
+ });
799
+ return logs.map((log) => ({
800
+ poolId: log.args.poolId,
801
+ quoteFees: log.args.quoteFees,
802
+ tokenFees: log.args.tokenFees,
803
+ blockNumber: log.blockNumber,
804
+ transactionHash: log.transactionHash
805
+ }));
806
+ },
807
+ async getTakeoverProposals(fromBlock, toBlock = "latest") {
808
+ const logs = await publicClient.getLogs({
809
+ address: addresses.factory,
810
+ event: parseAbiItem(
811
+ "event CreatorFeeRecipientChangeProposed(address indexed token, address indexed newRecipient, uint256 effectiveAt)"
812
+ ),
813
+ fromBlock,
814
+ toBlock
815
+ });
816
+ return logs.map((log) => ({
817
+ token: log.args.token,
818
+ newRecipient: log.args.newRecipient,
819
+ effectiveAt: log.args.effectiveAt,
820
+ blockNumber: log.blockNumber,
821
+ transactionHash: log.transactionHash
822
+ }));
823
+ }
824
+ };
825
+ }
826
+
827
+ // src/modules/takeover/index.ts
828
+ function createTakeoverModule(publicClient, addresses) {
829
+ return {
830
+ async getPending(token) {
831
+ const [recipient, effectiveAt, expiresAt] = await publicClient.readContract({
832
+ address: addresses.factory,
833
+ abi: factoryAbi,
834
+ functionName: "pendingCreatorFeeRecipient",
835
+ args: [token]
836
+ });
837
+ const isPending = recipient !== ZERO_ADDRESS && effectiveAt > 0n && expiresAt > 0n;
838
+ return {
839
+ proposedRecipient: recipient,
840
+ effectiveAt,
841
+ expiresAt,
842
+ isPending
843
+ };
844
+ }
845
+ };
846
+ }
847
+ var migrationAbi = parseAbi([
848
+ "function mandate() view returns (uint256)",
849
+ "function totalDeposited() view returns (uint256)",
850
+ "function settled() view returns (bool)",
851
+ "function claimable() view returns (bool)",
852
+ "function epochCount() view returns (uint256)",
853
+ "function getEpoch(uint256 index) view returns (uint256 rate, uint256 cap, uint256 deposited, bool closed)",
854
+ "function deposit(uint256 amount)",
855
+ "function claim()"
856
+ ]);
857
+ function createMigrationModule(publicClient, wallet, _addresses) {
858
+ return {
859
+ async getStatus(migrationAddress) {
860
+ const mandate = await publicClient.readContract({
861
+ address: migrationAddress,
862
+ abi: migrationAbi,
863
+ functionName: "mandate"
864
+ });
865
+ const totalDeposited = await publicClient.readContract({
866
+ address: migrationAddress,
867
+ abi: migrationAbi,
868
+ functionName: "totalDeposited"
869
+ });
870
+ const settled = await publicClient.readContract({
871
+ address: migrationAddress,
872
+ abi: migrationAbi,
873
+ functionName: "settled"
874
+ });
875
+ const claimable = await publicClient.readContract({
876
+ address: migrationAddress,
877
+ abi: migrationAbi,
878
+ functionName: "claimable"
879
+ });
880
+ const epochCount = await publicClient.readContract({
881
+ address: migrationAddress,
882
+ abi: migrationAbi,
883
+ functionName: "epochCount"
884
+ });
885
+ const epochPromises = [];
886
+ for (let i = 0; i < Number(epochCount); i++) {
887
+ epochPromises.push(
888
+ publicClient.readContract({
889
+ address: migrationAddress,
890
+ abi: migrationAbi,
891
+ functionName: "getEpoch",
892
+ args: [BigInt(i)]
893
+ }).then((result) => ({
894
+ rate: result[0],
895
+ cap: result[1],
896
+ deposited: result[2],
897
+ closed: result[3]
898
+ }))
899
+ );
900
+ }
901
+ const epochs = await Promise.all(epochPromises);
902
+ return { mandate, totalDeposited, settled, claimable, epochs };
903
+ },
904
+ async deposit(migrationAddress, amount) {
905
+ if (!wallet) throw new Error("Wallet required for deposit");
906
+ const { request } = await publicClient.simulateContract({
907
+ address: migrationAddress,
908
+ abi: migrationAbi,
909
+ functionName: "deposit",
910
+ args: [amount],
911
+ account: wallet.account
912
+ });
913
+ return wallet.writeContract(request);
914
+ },
915
+ async claim(migrationAddress) {
916
+ if (!wallet) throw new Error("Wallet required for claim");
917
+ const { request } = await publicClient.simulateContract({
918
+ address: migrationAddress,
919
+ abi: migrationAbi,
920
+ functionName: "claim",
921
+ account: wallet.account
922
+ });
923
+ return wallet.writeContract(request);
924
+ }
925
+ };
926
+ }
927
+
928
+ // src/client.ts
929
+ var robinhoodChain = {
930
+ id: ROBINHOOD_CHAIN_ID,
931
+ name: "Robinhood Chain",
932
+ nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
933
+ rpcUrls: {
934
+ default: { http: ["https://rpc.robinhood.com"] }
935
+ }
936
+ };
937
+ function createPonsClient(config) {
938
+ const chain = {
939
+ ...robinhoodChain,
940
+ id: config.chainId ?? ROBINHOOD_CHAIN_ID
941
+ };
942
+ const publicClient = config.publicClient ?? createPublicClient({
943
+ chain,
944
+ transport: http(config.rpcUrl)
945
+ });
946
+ const wallet = config.wallet;
947
+ const addresses = ADDRESSES;
948
+ const factory = createFactoryModule(publicClient, wallet, addresses);
949
+ const curve = createCurveModule(publicClient, wallet);
950
+ const pool = createPoolModule(publicClient, addresses);
951
+ const fees = createFesModule(publicClient, wallet, addresses);
952
+ const buyback = createBuybackModule(publicClient, wallet, addresses);
953
+ const events = createEventsModule(publicClient, addresses);
954
+ const takeover = createTakeoverModule(publicClient, addresses);
955
+ const migration = createMigrationModule(publicClient, wallet);
956
+ return {
957
+ publicClient,
958
+ wallet,
959
+ chainId: chain.id,
960
+ factory,
961
+ curve,
962
+ pool,
963
+ fees,
964
+ buyback,
965
+ events,
966
+ takeover,
967
+ migration
968
+ };
969
+ }
970
+ var tokenAbi = parseAbi([
971
+ // ── ERC-20 Standard ──────────────────────────────────────────────────────
972
+ "function name() view returns (string)",
973
+ "function symbol() view returns (string)",
974
+ "function decimals() view returns (uint8)",
975
+ "function totalSupply() view returns (uint256)",
976
+ "function balanceOf(address account) view returns (uint256)",
977
+ "function transfer(address to, uint256 amount) returns (bool)",
978
+ "function allowance(address owner, address spender) view returns (uint256)",
979
+ "function approve(address spender, uint256 amount) returns (bool)",
980
+ "function transferFrom(address from, address to, uint256 amount) returns (bool)",
981
+ // ── Pons Token Info ──────────────────────────────────────────────────────
982
+ "struct Socials { string twitter; string telegram; string discord; string website; string farcaster; }",
983
+ "function getTokenInfo() view returns (address tokenDeployer, string tokenLogo, string tokenDescription, Socials tokenSocials)",
984
+ // ── Events ───────────────────────────────────────────────────────────────
985
+ "event Transfer(address indexed from, address indexed to, uint256 value)",
986
+ "event Approval(address indexed owner, address indexed spender, uint256 value)"
987
+ ]);
988
+ var poolManagerAbi = parseAbi([
989
+ // ── Pool Key Struct ──────────────────────────────────────────────────────
990
+ "struct PoolKey { address currency0; address currency1; uint24 fee; int24 tickSpacing; address hooks; }",
991
+ // ── Read Functions ───────────────────────────────────────────────────────
992
+ "function getPool(PoolKey key) view returns (uint160 sqrtPriceX96, int24 tick, uint24 protocolFeesToken0, uint24 protocolFeesToken1, uint24 lpFeesToken0, uint24 lpFeesToken1)",
993
+ "function getSlot0(bytes32 poolId) view returns (uint160 sqrtPriceX96, int24 tick, uint24 protocolFeesToken0, uint24 protocolFeesToken1, uint24 lpFeesToken0, uint24 lpFeesToken1)",
994
+ // ── Events ───────────────────────────────────────────────────────────────
995
+ "event Swap(bytes32 indexed poolId, address indexed sender, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick)",
996
+ "event Initialize(bytes32 indexed poolId, address indexed currency0, address indexed currency1, int24 tickSpacing, address hooks)"
997
+ ]);
998
+ function normalizeAddress(address) {
999
+ if (!address || address === ZERO_ADDRESS) return ZERO_ADDRESS;
1000
+ return getAddress(address);
1001
+ }
1002
+ function isValidAddress(address) {
1003
+ try {
1004
+ return isAddress(address);
1005
+ } catch {
1006
+ return false;
1007
+ }
1008
+ }
1009
+ function formatETH(value) {
1010
+ return formatEther(value);
1011
+ }
1012
+ function formatTokenAmount(value, decimals) {
1013
+ return formatUnits(value, decimals);
1014
+ }
1015
+ function shortenAddress(address) {
1016
+ return `${address.slice(0, 6)}...${address.slice(-4)}`;
1017
+ }
1018
+
1019
+ export { ADDRESSES, BPS, MAX_SNIPE_EXEMPTIONS, MIGRATION_CLAIM_WINDOW_SECS, PHASE, ROBINHOOD_CHAIN_ID, SNIPE_TAX_DECAY_NS, VESTING_DURATION_SECS, ZERO_ADDRESS, amountIn, amountOut, applyBps, ceilDiv, createPonsClient, curveAbi, escrowAbi, factoryAbi, formatETH, formatTokenAmount, graduationProgress, hookAbi, isValidAddress, marginalPrice, minOutputWithSlippage, normalizeAddress, poolManagerAbi, requirePositiveAmount, requireValidAddress, requireValidCreatorTax, requireValidExemptions, requireValidSlippage, routerAbi, shortenAddress, subtractBps, tokenAbi, vaultAbi };
1020
+ //# sourceMappingURL=index.js.map
1021
+ //# sourceMappingURL=index.js.map