@paul.lumberwork/bonding-curve-sdk 1.4.0 → 1.6.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/README.md +140 -112
- package/dist/index.d.mts +93 -6
- package/dist/index.d.ts +93 -6
- package/dist/index.js +42 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +42 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Kick.fun SDK
|
|
2
2
|
|
|
3
|
-
Solana program with Linear Bonding Curve for token launches
|
|
3
|
+
Solana program with Linear Bonding Curve for token launches. SDK package: `@paul.lumberwork/bonding-curve-sdk`
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
@@ -12,22 +12,23 @@ Solana program with Linear Bonding Curve for token launches, similar to pump.fun
|
|
|
12
12
|
|
|
13
13
|
| Allocation | Percent | Description |
|
|
14
14
|
|------------|---------|-------------|
|
|
15
|
-
| Bonding Curve |
|
|
15
|
+
| Bonding Curve | 70% | Available for trading |
|
|
16
16
|
| LP Reserve | 20% | Reserved for DEX migration |
|
|
17
|
+
| Treasury | 10% | Platform treasury |
|
|
17
18
|
|
|
18
19
|
## Trading Fees (Hardcoded)
|
|
19
20
|
|
|
20
21
|
| Fee | Percent | Recipient |
|
|
21
22
|
|-----|---------|-----------|
|
|
22
|
-
|
|
|
23
|
-
| Admin Fee | 0.5% | Platform admin |
|
|
23
|
+
| Accumulated Fee | 0.5% | Accumulated in curve (withdrawn by admin) |
|
|
24
|
+
| Admin Fee | 0.5% | Platform admin (immediate) |
|
|
24
25
|
| **Total** | **1%** | |
|
|
25
26
|
|
|
26
27
|
## Bonding Curve Formula
|
|
27
28
|
|
|
28
29
|
```
|
|
29
|
-
Price = K
|
|
30
|
-
Cost = K
|
|
30
|
+
Price = K x sold_supply
|
|
31
|
+
Cost = K x (s2² - s1²) / 2 / K_SCALE
|
|
31
32
|
```
|
|
32
33
|
|
|
33
34
|
Where `K_SCALE = 10^22`
|
|
@@ -41,7 +42,9 @@ Where `K_SCALE = 10^22`
|
|
|
41
42
|
| 2156 | ~69 SOL | pump.fun style |
|
|
42
43
|
| 3125 | ~100 SOL | Large launch |
|
|
43
44
|
|
|
44
|
-
**Formula**: `Target SOL
|
|
45
|
+
**Formula**: `Target SOL = K x 0.032`
|
|
46
|
+
|
|
47
|
+
> **Note:** `total_supply` and `k` are configured by admin in the Launchpad contract. Creators do not set these values.
|
|
45
48
|
|
|
46
49
|
---
|
|
47
50
|
|
|
@@ -50,7 +53,7 @@ Where `K_SCALE = 10^22`
|
|
|
50
53
|
### Installation
|
|
51
54
|
|
|
52
55
|
```bash
|
|
53
|
-
npm install
|
|
56
|
+
npm install @paul.lumberwork/bonding-curve-sdk
|
|
54
57
|
```
|
|
55
58
|
|
|
56
59
|
### Setup
|
|
@@ -59,8 +62,8 @@ npm install github:lumberworks/kickdotfun-contracts-sdk
|
|
|
59
62
|
import * as anchor from "@coral-xyz/anchor";
|
|
60
63
|
import { Program } from "@coral-xyz/anchor";
|
|
61
64
|
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
|
|
62
|
-
import {
|
|
63
|
-
import idl from "
|
|
65
|
+
import { KickFunSDK, formatTokens, formatSol, PROGRAM_ID } from "@paul.lumberwork/bonding-curve-sdk";
|
|
66
|
+
import idl from "@paul.lumberwork/bonding-curve-sdk/idl/kick_fun_program.json";
|
|
64
67
|
|
|
65
68
|
// Setup connection and wallet
|
|
66
69
|
const connection = new Connection("https://api.devnet.solana.com", "confirmed");
|
|
@@ -71,10 +74,10 @@ const provider = new anchor.AnchorProvider(connection, wallet, { commitment: "co
|
|
|
71
74
|
const program = new Program(idl as anchor.Idl, provider);
|
|
72
75
|
|
|
73
76
|
// Create SDK instance
|
|
74
|
-
const sdk = new
|
|
77
|
+
const sdk = new KickFunSDK(program, wallet);
|
|
75
78
|
```
|
|
76
79
|
|
|
77
|
-
### 1. Initialize Launchpad (one-time)
|
|
80
|
+
### 1. Initialize Launchpad (one-time, admin only)
|
|
78
81
|
|
|
79
82
|
```typescript
|
|
80
83
|
const result = await sdk.initializeLaunchpad();
|
|
@@ -83,14 +86,11 @@ const result = await sdk.initializeLaunchpad();
|
|
|
83
86
|
|
|
84
87
|
### 2. Create Token Launch
|
|
85
88
|
|
|
86
|
-
**Default (creator = transaction signer):**
|
|
87
89
|
```typescript
|
|
88
90
|
const { txSignature, addresses, mintKeypair } = await sdk.createTokenLaunch({
|
|
89
91
|
name: "My Token",
|
|
90
92
|
symbol: "MTK",
|
|
91
93
|
uri: "https://example.com/metadata.json",
|
|
92
|
-
totalSupply: 1_000_000_000, // 1B tokens
|
|
93
|
-
k: 60, // ~2 SOL target
|
|
94
94
|
});
|
|
95
95
|
|
|
96
96
|
const mint = mintKeypair.publicKey;
|
|
@@ -100,38 +100,29 @@ console.log("Token Launch PDA:", addresses.tokenLaunch.toString());
|
|
|
100
100
|
|
|
101
101
|
**With Custom Creator Wallet:**
|
|
102
102
|
```typescript
|
|
103
|
-
import { PublicKey } from "@solana/web3.js";
|
|
104
|
-
|
|
105
|
-
const customCreator = new PublicKey("YourCreatorWalletAddress...");
|
|
106
|
-
|
|
107
103
|
const { txSignature, addresses, mintKeypair } = await sdk.createTokenLaunch({
|
|
108
104
|
name: "My Token",
|
|
109
105
|
symbol: "MTK",
|
|
110
106
|
uri: "https://example.com/metadata.json",
|
|
111
|
-
|
|
112
|
-
k: 60,
|
|
113
|
-
creatorWallet: customCreator, // Optional: receives 0.5% trading fees
|
|
107
|
+
creatorWallet: new PublicKey("YourCreatorWalletAddress..."),
|
|
114
108
|
});
|
|
115
109
|
```
|
|
116
110
|
|
|
117
111
|
**Parameters:**
|
|
118
112
|
- `name`: Token name
|
|
119
113
|
- `symbol`: Token symbol
|
|
120
|
-
- `uri`: Metadata URI
|
|
121
|
-
- `
|
|
122
|
-
- `k`: K value for bonding curve
|
|
123
|
-
- `creatorWallet`: (Optional) Custom creator wallet to receive trading fees. Defaults to SDK wallet if not provided.
|
|
114
|
+
- `uri`: Metadata URI (Metaplex standard)
|
|
115
|
+
- `creatorWallet`: (Optional) Custom creator wallet. Defaults to SDK wallet.
|
|
124
116
|
|
|
125
117
|
**Returns:**
|
|
126
118
|
- `txSignature`: Transaction hash
|
|
127
|
-
- `addresses.mint`: Token mint address
|
|
128
119
|
- `addresses.tokenLaunch`: Token launch PDA
|
|
129
120
|
- `addresses.bondingCurve`: Bonding curve PDA
|
|
130
121
|
- `addresses.vault`: SOL vault PDA
|
|
122
|
+
- `addresses.curveTokenAccount`: Token account for curve
|
|
123
|
+
- `addresses.metadata`: Metaplex metadata PDA
|
|
131
124
|
- `mintKeypair`: Keypair of the new token
|
|
132
125
|
|
|
133
|
-
**Note:** The creator wallet will receive 0.5% of all trading fees (buy/sell). Use `creatorWallet` parameter if you want fees to go to a different address than the transaction signer.
|
|
134
|
-
|
|
135
126
|
### 3. Buy Tokens
|
|
136
127
|
|
|
137
128
|
```typescript
|
|
@@ -140,7 +131,6 @@ const result = await sdk.buy(mint, 0.5, { computeUnits: 400_000 });
|
|
|
140
131
|
console.log("Tokens received:", formatTokens(result.tokensTraded));
|
|
141
132
|
console.log("Progress:", result.newProgress.toFixed(2) + "%");
|
|
142
133
|
console.log("Curve complete:", result.isCurveComplete);
|
|
143
|
-
console.log("Tx:", result.txSignature);
|
|
144
134
|
```
|
|
145
135
|
|
|
146
136
|
**Parameters:**
|
|
@@ -148,13 +138,6 @@ console.log("Tx:", result.txSignature);
|
|
|
148
138
|
- `solAmount`: SOL to spend (number, e.g., 0.5 for 0.5 SOL)
|
|
149
139
|
- `options.computeUnits`: Optional compute budget (default: none)
|
|
150
140
|
|
|
151
|
-
**Returns:**
|
|
152
|
-
- `txSignature`: Transaction hash
|
|
153
|
-
- `tokensTraded`: Tokens received (bigint, raw with 6 decimals)
|
|
154
|
-
- `solTraded`: SOL spent (bigint, lamports)
|
|
155
|
-
- `newProgress`: Progress percentage (0-100)
|
|
156
|
-
- `isCurveComplete`: True if 80% sold
|
|
157
|
-
|
|
158
141
|
### 4. Sell Tokens
|
|
159
142
|
|
|
160
143
|
```typescript
|
|
@@ -170,26 +153,52 @@ console.log("Progress:", result.newProgress.toFixed(2) + "%");
|
|
|
170
153
|
- `minSolOut`: Minimum SOL to receive, slippage protection (default: 0)
|
|
171
154
|
- `options.computeUnits`: Optional compute budget
|
|
172
155
|
|
|
173
|
-
### 5. Estimate Buy
|
|
156
|
+
### 5. Estimate Buy (SOL -> Tokens)
|
|
174
157
|
|
|
175
158
|
```typescript
|
|
176
159
|
const estimate = await sdk.estimateBuy(mint, 0.5);
|
|
177
160
|
|
|
178
161
|
console.log("Tokens out:", formatTokens(estimate.tokensOut));
|
|
179
|
-
console.log("
|
|
162
|
+
console.log("SOL in (total):", formatSol(estimate.solIn));
|
|
163
|
+
console.log("SOL after fee:", formatSol(estimate.solAfterFee));
|
|
164
|
+
console.log("Fee:", formatSol(estimate.fee));
|
|
180
165
|
console.log("Price impact:", estimate.priceImpactBps, "bps");
|
|
181
166
|
```
|
|
182
167
|
|
|
183
|
-
### 6. Estimate
|
|
168
|
+
### 6. Estimate Buy by Tokens (Tokens -> SOL needed)
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
const estimate = await sdk.estimateBuyByTokens(mint, 1_000_000); // 1M tokens
|
|
172
|
+
|
|
173
|
+
console.log("SOL needed:", formatSol(estimate.solIn));
|
|
174
|
+
console.log("SOL to curve:", formatSol(estimate.solAfterFee));
|
|
175
|
+
console.log("Fee:", formatSol(estimate.fee));
|
|
176
|
+
console.log("Tokens out:", formatTokens(estimate.tokensOut));
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 7. Estimate Sell (Tokens -> SOL)
|
|
184
180
|
|
|
185
181
|
```typescript
|
|
186
182
|
const estimate = await sdk.estimateSell(mint, 10_000_000);
|
|
187
183
|
|
|
188
|
-
console.log("SOL
|
|
189
|
-
console.log("
|
|
184
|
+
console.log("SOL before fee:", formatSol(estimate.solBeforeFee));
|
|
185
|
+
console.log("SOL out (net):", formatSol(estimate.solOut));
|
|
186
|
+
console.log("Fee:", formatSol(estimate.fee));
|
|
187
|
+
console.log("Tokens in:", formatTokens(estimate.tokensIn));
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### 8. Estimate Sell by SOL (SOL desired -> Tokens to sell)
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
const estimate = await sdk.estimateSellBySol(mint, 0.5); // want 0.5 SOL
|
|
194
|
+
|
|
195
|
+
console.log("Tokens to sell:", formatTokens(estimate.tokensIn));
|
|
196
|
+
console.log("SOL before fee:", formatSol(estimate.solBeforeFee));
|
|
197
|
+
console.log("SOL out (net):", formatSol(estimate.solOut));
|
|
198
|
+
console.log("Fee:", formatSol(estimate.fee));
|
|
190
199
|
```
|
|
191
200
|
|
|
192
|
-
###
|
|
201
|
+
### 9. Get Progress
|
|
193
202
|
|
|
194
203
|
```typescript
|
|
195
204
|
const progress = await sdk.getProgress(mint);
|
|
@@ -200,19 +209,19 @@ console.log("Current price:", progress.currentPrice.toString(), "lamports/token"
|
|
|
200
209
|
console.log("Complete:", progress.isComplete);
|
|
201
210
|
```
|
|
202
211
|
|
|
203
|
-
###
|
|
212
|
+
### 10. Get Curve State
|
|
204
213
|
|
|
205
214
|
```typescript
|
|
206
215
|
const curve = await sdk.getCurveState(mint);
|
|
207
216
|
|
|
208
217
|
console.log("K:", curve.k.toString());
|
|
209
218
|
console.log("Sold:", formatTokens(curve.soldSupply));
|
|
210
|
-
console.log("
|
|
219
|
+
console.log("For curve:", formatTokens(curve.tokensForCurve));
|
|
211
220
|
console.log("SOL reserves:", formatSol(curve.realSolReserves));
|
|
212
221
|
console.log("Complete:", curve.complete);
|
|
213
222
|
```
|
|
214
223
|
|
|
215
|
-
###
|
|
224
|
+
### 11. Get Token Launch State
|
|
216
225
|
|
|
217
226
|
```typescript
|
|
218
227
|
const launch = await sdk.getTokenLaunchState(mint);
|
|
@@ -223,27 +232,64 @@ console.log("Trading active:", launch.tradingActive);
|
|
|
223
232
|
console.log("Migrated:", launch.migrated);
|
|
224
233
|
```
|
|
225
234
|
|
|
226
|
-
###
|
|
235
|
+
### 12. Admin Withdraw (Admin Only)
|
|
227
236
|
|
|
228
237
|
```typescript
|
|
229
|
-
// Only ADMIN_WALLET can call this
|
|
230
238
|
if (wallet.publicKey.equals(ADMIN_WALLET)) {
|
|
231
239
|
const result = await sdk.adminWithdraw(mint);
|
|
232
240
|
console.log("SOL withdrawn:", formatSol(result.solWithdrawn));
|
|
233
241
|
console.log("LP tokens:", formatTokens(result.tokensWithdrawn));
|
|
242
|
+
console.log("Fees to treasury:", formatSol(result.feesToTreasury));
|
|
243
|
+
console.log("Treasury tokens:", formatTokens(result.treasuryTokens));
|
|
234
244
|
}
|
|
235
245
|
```
|
|
236
246
|
|
|
237
247
|
**Requirements:**
|
|
238
248
|
- Caller must be `ADMIN_WALLET`
|
|
239
|
-
- Curve must be complete (
|
|
249
|
+
- Curve must be complete (70% sold)
|
|
240
250
|
- Token not already migrated
|
|
241
251
|
|
|
242
252
|
---
|
|
243
253
|
|
|
254
|
+
## Estimate Return Types
|
|
255
|
+
|
|
256
|
+
### EstimateBuyResult
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
interface EstimateBuyResult {
|
|
260
|
+
solIn: bigint; // Total SOL user pays (including fee)
|
|
261
|
+
solAfterFee: bigint; // SOL that goes into the curve (after fee)
|
|
262
|
+
tokensOut: bigint; // Tokens user receives
|
|
263
|
+
fee: bigint; // Fee in SOL (lamports)
|
|
264
|
+
pricePerToken: bigint;
|
|
265
|
+
priceImpactBps: number;
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Used by: `estimateBuy()`, `estimateBuyByTokens()`
|
|
270
|
+
|
|
271
|
+
### EstimateSellResult
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
interface EstimateSellResult {
|
|
275
|
+
tokensIn: bigint; // Tokens user sells
|
|
276
|
+
solBeforeFee: bigint; // Gross SOL from curve (before fee)
|
|
277
|
+
solOut: bigint; // Net SOL user receives (after fee)
|
|
278
|
+
fee: bigint; // Fee in SOL (lamports)
|
|
279
|
+
pricePerToken: bigint;
|
|
280
|
+
priceImpactBps: number;
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Used by: `estimateSell()`, `estimateSellBySol()`
|
|
285
|
+
|
|
286
|
+
> **Note:** Fee is always denominated in SOL (lamports).
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
244
290
|
## Event Listeners
|
|
245
291
|
|
|
246
|
-
Subscribe to real-time events from the
|
|
292
|
+
Subscribe to real-time events from the program.
|
|
247
293
|
|
|
248
294
|
### Available Events
|
|
249
295
|
|
|
@@ -258,17 +304,17 @@ Subscribe to real-time events from the Pump.fun program.
|
|
|
258
304
|
### Listen for Token Purchases
|
|
259
305
|
|
|
260
306
|
```typescript
|
|
261
|
-
// Subscribe to buy events
|
|
262
307
|
const listenerId = sdk.onTokensPurchased((event, slot, signature) => {
|
|
263
308
|
console.log("Buy Event:", {
|
|
264
309
|
buyer: event.buyer.toString(),
|
|
265
310
|
mint: event.mint.toString(),
|
|
311
|
+
solAmount: formatSol(event.solAmount),
|
|
312
|
+
solAfterFees: formatSol(event.solAfterFees),
|
|
266
313
|
tokensReceived: formatTokens(event.tokensReceived),
|
|
267
|
-
|
|
314
|
+
curveFee: formatSol(event.curveFee),
|
|
315
|
+
adminFee: formatSol(event.adminFee),
|
|
268
316
|
progress: event.progress + "%",
|
|
269
317
|
complete: event.isCurveComplete,
|
|
270
|
-
slot,
|
|
271
|
-
signature,
|
|
272
318
|
});
|
|
273
319
|
});
|
|
274
320
|
|
|
@@ -283,7 +329,10 @@ const listenerId = sdk.onTokensSold((event, slot, signature) => {
|
|
|
283
329
|
console.log("Sell Event:", {
|
|
284
330
|
seller: event.seller.toString(),
|
|
285
331
|
tokensSold: formatTokens(event.tokensSold),
|
|
286
|
-
|
|
332
|
+
grossSolRefund: formatSol(event.grossSolRefund),
|
|
333
|
+
netSolRefund: formatSol(event.netSolRefund),
|
|
334
|
+
curveFee: formatSol(event.curveFee),
|
|
335
|
+
adminFee: formatSol(event.adminFee),
|
|
287
336
|
progress: event.progress + "%",
|
|
288
337
|
});
|
|
289
338
|
});
|
|
@@ -299,6 +348,9 @@ sdk.onLaunchCreated((event, slot, signature) => {
|
|
|
299
348
|
mint: event.mint.toString(),
|
|
300
349
|
creator: event.creator.toString(),
|
|
301
350
|
totalSupply: formatTokens(event.totalSupply),
|
|
351
|
+
curveAllocation: formatTokens(event.curveAllocation),
|
|
352
|
+
lpAllocation: formatTokens(event.lpAllocation),
|
|
353
|
+
treasuryAllocation: formatTokens(event.treasuryAllocation),
|
|
302
354
|
initialK: event.initialK.toString(),
|
|
303
355
|
});
|
|
304
356
|
});
|
|
@@ -324,54 +376,18 @@ sdk.onAdminWithdraw((event, slot, signature) => {
|
|
|
324
376
|
mint: event.mint.toString(),
|
|
325
377
|
solWithdrawn: formatSol(event.solWithdrawn),
|
|
326
378
|
tokensWithdrawn: formatTokens(event.tokensWithdrawn),
|
|
379
|
+
feesToTreasury: formatSol(event.feesToTreasury),
|
|
380
|
+
treasuryTokens: formatTokens(event.treasuryTokens),
|
|
327
381
|
});
|
|
328
382
|
});
|
|
329
383
|
```
|
|
330
384
|
|
|
331
|
-
### Complete Event Listener Example
|
|
332
|
-
|
|
333
|
-
```typescript
|
|
334
|
-
import { PumpFunSDK, formatTokens, formatSol } from "pump-fun-sdk";
|
|
335
|
-
|
|
336
|
-
async function watchToken(sdk: PumpFunSDK, mint: PublicKey) {
|
|
337
|
-
// Track buys
|
|
338
|
-
const buyListener = sdk.onTokensPurchased((event, slot, sig) => {
|
|
339
|
-
if (event.mint.equals(mint)) {
|
|
340
|
-
console.log(`[Buy] ${formatTokens(event.tokensReceived)} tokens bought`);
|
|
341
|
-
|
|
342
|
-
if (event.isCurveComplete) {
|
|
343
|
-
console.log("🎉 Curve completed!");
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
// Track sells
|
|
349
|
-
const sellListener = sdk.onTokensSold((event, slot, sig) => {
|
|
350
|
-
if (event.mint.equals(mint)) {
|
|
351
|
-
console.log(`[Sell] ${formatTokens(event.tokensSold)} tokens sold`);
|
|
352
|
-
}
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
// Wait for curve completion
|
|
356
|
-
const completeListener = sdk.onCurveComplete((event, slot, sig) => {
|
|
357
|
-
if (event.mint.equals(mint)) {
|
|
358
|
-
console.log(`Curve complete! Total raised: ${formatSol(event.totalSolRaised)} SOL`);
|
|
359
|
-
|
|
360
|
-
// Clean up listeners
|
|
361
|
-
sdk.removeEventListener(buyListener);
|
|
362
|
-
sdk.removeEventListener(sellListener);
|
|
363
|
-
sdk.removeEventListener(completeListener);
|
|
364
|
-
}
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
```
|
|
368
|
-
|
|
369
385
|
---
|
|
370
386
|
|
|
371
387
|
## Utility Functions
|
|
372
388
|
|
|
373
389
|
```typescript
|
|
374
|
-
import { formatTokens, formatSol, parseSol, parseTokens } from "
|
|
390
|
+
import { formatTokens, formatSol, parseSol, parseTokens } from "@paul.lumberwork/bonding-curve-sdk";
|
|
375
391
|
|
|
376
392
|
// Format raw values to readable strings
|
|
377
393
|
formatTokens(1000000000000n); // "1,000,000" (1M tokens)
|
|
@@ -387,12 +403,16 @@ parseTokens(1000000); // 1000000000000n (raw with 6 decimals)
|
|
|
387
403
|
## Constants
|
|
388
404
|
|
|
389
405
|
```typescript
|
|
390
|
-
import { ADMIN_WALLET, K_SCALE, TOKEN_DECIMALS, FEE_BPS } from "
|
|
406
|
+
import { ADMIN_WALLET, K_SCALE, TOKEN_DECIMALS, FEE_BPS, PROGRAM_ID } from "@paul.lumberwork/bonding-curve-sdk";
|
|
391
407
|
|
|
408
|
+
PROGRAM_ID // PublicKey: "6o7oTqg2CfvcMCJTLNEJsef7c875zGpTvcnFctNAjudL"
|
|
392
409
|
ADMIN_WALLET // PublicKey: "7eGpbyRpcM7WpNKQtd6XkteNQWHbWXP7icZjKzNK2aTk"
|
|
393
410
|
K_SCALE // 10^22 (bigint)
|
|
394
411
|
TOKEN_DECIMALS // 6
|
|
395
412
|
FEE_BPS // 100 (1%)
|
|
413
|
+
CURVE_PERCENT // 70
|
|
414
|
+
LP_PERCENT // 20
|
|
415
|
+
TREASURY_PERCENT // 10
|
|
396
416
|
```
|
|
397
417
|
|
|
398
418
|
---
|
|
@@ -414,42 +434,50 @@ FEE_BPS // 100 (1%)
|
|
|
414
434
|
```typescript
|
|
415
435
|
import * as anchor from "@coral-xyz/anchor";
|
|
416
436
|
import { Program } from "@coral-xyz/anchor";
|
|
417
|
-
import {
|
|
418
|
-
import {
|
|
437
|
+
import { Connection, Keypair } from "@solana/web3.js";
|
|
438
|
+
import { KickFunSDK, formatTokens, formatSol, ADMIN_WALLET } from "@paul.lumberwork/bonding-curve-sdk";
|
|
439
|
+
import idl from "@paul.lumberwork/bonding-curve-sdk/idl/kick_fun_program.json";
|
|
419
440
|
|
|
420
441
|
async function main() {
|
|
421
|
-
const
|
|
422
|
-
anchor.
|
|
423
|
-
const
|
|
424
|
-
const
|
|
425
|
-
const sdk = new
|
|
442
|
+
const connection = new Connection("https://api.devnet.solana.com", "confirmed");
|
|
443
|
+
const wallet = new anchor.Wallet(keypair);
|
|
444
|
+
const provider = new anchor.AnchorProvider(connection, wallet, { commitment: "confirmed" });
|
|
445
|
+
const program = new Program(idl as anchor.Idl, provider) as any;
|
|
446
|
+
const sdk = new KickFunSDK(program, wallet);
|
|
426
447
|
|
|
427
|
-
// 1. Initialize launchpad
|
|
448
|
+
// 1. Initialize launchpad (admin only, one-time)
|
|
428
449
|
await sdk.initializeLaunchpad();
|
|
429
450
|
|
|
430
|
-
// 2. Create token
|
|
451
|
+
// 2. Create token (total_supply and k are set by admin)
|
|
431
452
|
const { addresses, mintKeypair } = await sdk.createTokenLaunch({
|
|
432
453
|
name: "Test Token",
|
|
433
454
|
symbol: "TEST",
|
|
434
455
|
uri: "https://example.com/metadata.json",
|
|
435
|
-
totalSupply: 1_000_000_000,
|
|
436
|
-
k: 60,
|
|
437
456
|
});
|
|
438
457
|
const mint = mintKeypair.publicKey;
|
|
439
458
|
|
|
440
|
-
// 3.
|
|
459
|
+
// 3. Estimate before buying
|
|
460
|
+
const buyEstimate = await sdk.estimateBuy(mint, 0.5);
|
|
461
|
+
console.log("Will receive:", formatTokens(buyEstimate.tokensOut), "tokens");
|
|
462
|
+
console.log("Fee:", formatSol(buyEstimate.fee));
|
|
463
|
+
|
|
464
|
+
// 4. Buy tokens
|
|
441
465
|
const buy = await sdk.buy(mint, 0.5, { computeUnits: 400_000 });
|
|
442
466
|
console.log("Bought:", formatTokens(buy.tokensTraded));
|
|
443
467
|
|
|
444
|
-
//
|
|
468
|
+
// 5. Estimate sell by desired SOL
|
|
469
|
+
const sellEstimate = await sdk.estimateSellBySol(mint, 0.3);
|
|
470
|
+
console.log("Need to sell:", formatTokens(sellEstimate.tokensIn), "tokens to get 0.3 SOL");
|
|
471
|
+
|
|
472
|
+
// 6. Sell tokens
|
|
445
473
|
const sell = await sdk.sell(mint, 10_000_000, 0, { computeUnits: 400_000 });
|
|
446
474
|
console.log("Sold for:", formatSol(sell.solTraded), "SOL");
|
|
447
475
|
|
|
448
|
-
//
|
|
476
|
+
// 7. Check progress
|
|
449
477
|
const progress = await sdk.getProgress(mint);
|
|
450
478
|
console.log("Progress:", progress.percent + "%");
|
|
451
479
|
|
|
452
|
-
//
|
|
480
|
+
// 8. Admin withdraw (when curve complete)
|
|
453
481
|
if (progress.isComplete && wallet.publicKey.equals(ADMIN_WALLET)) {
|
|
454
482
|
const withdraw = await sdk.adminWithdraw(mint);
|
|
455
483
|
console.log("Withdrawn:", formatSol(withdraw.solWithdrawn), "SOL");
|
|
@@ -468,7 +496,7 @@ main().catch(console.error);
|
|
|
468
496
|
solana-test-validator --reset
|
|
469
497
|
|
|
470
498
|
# In another terminal
|
|
471
|
-
cd
|
|
499
|
+
cd kick_fun_program
|
|
472
500
|
anchor build && anchor deploy
|
|
473
501
|
|
|
474
502
|
# Run test
|
package/dist/index.d.mts
CHANGED
|
@@ -11,7 +11,7 @@ import { PublicKey, Connection, Keypair } from '@solana/web3.js';
|
|
|
11
11
|
type KickFunProgram = {
|
|
12
12
|
"address": "6o7oTqg2CfvcMCJTLNEJsef7c875zGpTvcnFctNAjudL";
|
|
13
13
|
"metadata": {
|
|
14
|
-
"name": "
|
|
14
|
+
"name": "kickFunProgram";
|
|
15
15
|
"version": "0.1.0";
|
|
16
16
|
"spec": "0.1.0";
|
|
17
17
|
"description": "Kick.fun Clone - IDO Launchpad with Bonding Curve";
|
|
@@ -2403,13 +2403,78 @@ type KickFunProgram = {
|
|
|
2403
2403
|
"errors": [
|
|
2404
2404
|
{
|
|
2405
2405
|
"code": 6000;
|
|
2406
|
-
"name": "
|
|
2407
|
-
"msg": "
|
|
2406
|
+
"name": "platformPaused";
|
|
2407
|
+
"msg": "Platform is currently paused";
|
|
2408
2408
|
},
|
|
2409
2409
|
{
|
|
2410
2410
|
"code": 6001;
|
|
2411
|
-
"name": "
|
|
2412
|
-
"msg": "
|
|
2411
|
+
"name": "unauthorized";
|
|
2412
|
+
"msg": "Unauthorized: only authority can perform this action";
|
|
2413
|
+
},
|
|
2414
|
+
{
|
|
2415
|
+
"code": 6002;
|
|
2416
|
+
"name": "tradingNotActive";
|
|
2417
|
+
"msg": "Trading is not active";
|
|
2418
|
+
},
|
|
2419
|
+
{
|
|
2420
|
+
"code": 6003;
|
|
2421
|
+
"name": "alreadyMigrated";
|
|
2422
|
+
"msg": "Token has already migrated to DEX";
|
|
2423
|
+
},
|
|
2424
|
+
{
|
|
2425
|
+
"code": 6004;
|
|
2426
|
+
"name": "insufficientSol";
|
|
2427
|
+
"msg": "Insufficient SOL balance";
|
|
2428
|
+
},
|
|
2429
|
+
{
|
|
2430
|
+
"code": 6005;
|
|
2431
|
+
"name": "insufficientTokens";
|
|
2432
|
+
"msg": "Insufficient token balance";
|
|
2433
|
+
},
|
|
2434
|
+
{
|
|
2435
|
+
"code": 6006;
|
|
2436
|
+
"name": "slippageExceeded";
|
|
2437
|
+
"msg": "Slippage tolerance exceeded";
|
|
2438
|
+
},
|
|
2439
|
+
{
|
|
2440
|
+
"code": 6007;
|
|
2441
|
+
"name": "mathOverflow";
|
|
2442
|
+
"msg": "Math overflow error";
|
|
2443
|
+
},
|
|
2444
|
+
{
|
|
2445
|
+
"code": 6008;
|
|
2446
|
+
"name": "invalidAmount";
|
|
2447
|
+
"msg": "Invalid amount: must be greater than zero";
|
|
2448
|
+
},
|
|
2449
|
+
{
|
|
2450
|
+
"code": 6009;
|
|
2451
|
+
"name": "alreadyClaimed";
|
|
2452
|
+
"msg": "Tokens already claimed";
|
|
2453
|
+
},
|
|
2454
|
+
{
|
|
2455
|
+
"code": 6010;
|
|
2456
|
+
"name": "noTokensToClaim";
|
|
2457
|
+
"msg": "No tokens to claim";
|
|
2458
|
+
},
|
|
2459
|
+
{
|
|
2460
|
+
"code": 6011;
|
|
2461
|
+
"name": "invalidFee";
|
|
2462
|
+
"msg": "Invalid fee: must be less than 10000 basis points";
|
|
2463
|
+
},
|
|
2464
|
+
{
|
|
2465
|
+
"code": 6012;
|
|
2466
|
+
"name": "invalidReserves";
|
|
2467
|
+
"msg": "Invalid virtual reserves";
|
|
2468
|
+
},
|
|
2469
|
+
{
|
|
2470
|
+
"code": 6013;
|
|
2471
|
+
"name": "launchNotMigrated";
|
|
2472
|
+
"msg": "Launch not migrated yet";
|
|
2473
|
+
},
|
|
2474
|
+
{
|
|
2475
|
+
"code": 6014;
|
|
2476
|
+
"name": "curveNotComplete";
|
|
2477
|
+
"msg": "Bonding curve is not complete yet";
|
|
2413
2478
|
}
|
|
2414
2479
|
];
|
|
2415
2480
|
"types": [
|
|
@@ -3418,6 +3483,23 @@ declare class KickFunSDK {
|
|
|
3418
3483
|
currentPrice: bigint;
|
|
3419
3484
|
isComplete: boolean;
|
|
3420
3485
|
}>;
|
|
3486
|
+
/**
|
|
3487
|
+
* Get the initial/starting price for a token launch.
|
|
3488
|
+
* Linear curve starts at price=0, so this returns the theoretical price
|
|
3489
|
+
* after 1 display token is sold — useful as the "open" price for the first candle.
|
|
3490
|
+
*/
|
|
3491
|
+
getInitialPrice(mint: PublicKey): Promise<{
|
|
3492
|
+
priceLamports: bigint;
|
|
3493
|
+
priceSol: number;
|
|
3494
|
+
}>;
|
|
3495
|
+
/**
|
|
3496
|
+
* Get the price at any given sold supply (display tokens).
|
|
3497
|
+
* Useful for calculating open/close prices on candlestick charts.
|
|
3498
|
+
*/
|
|
3499
|
+
getPriceAtSupply(k: bigint, soldDisplayTokens: number): {
|
|
3500
|
+
priceLamports: bigint;
|
|
3501
|
+
priceSol: number;
|
|
3502
|
+
};
|
|
3421
3503
|
/**
|
|
3422
3504
|
* Listen for LaunchCreated events
|
|
3423
3505
|
* @param callback Function to call when event is emitted
|
|
@@ -3453,8 +3535,13 @@ declare class KickFunSDK {
|
|
|
3453
3535
|
* @param listenerId The ID returned from addEventListener
|
|
3454
3536
|
*/
|
|
3455
3537
|
removeEventListener(listenerId: number): Promise<void>;
|
|
3456
|
-
/** Calculate price at a given supply
|
|
3538
|
+
/** Calculate price at a given supply in lamports per display token.
|
|
3539
|
+
* Formula: price = k × supply × 10^DECIMALS / K_SCALE
|
|
3540
|
+
* Returns lamports per 1 display token (not per raw token). */
|
|
3457
3541
|
calculatePrice(k: bigint, supply: bigint): bigint;
|
|
3542
|
+
/** Calculate price per display token in SOL (float).
|
|
3543
|
+
* Useful for charts where sub-lamport precision matters. */
|
|
3544
|
+
calculatePriceSol(k: bigint, supply: bigint): number;
|
|
3458
3545
|
/** Calculate cost to buy from s1 to s2: cost = (k/2) × (s2² - s1²) / K_SCALE */
|
|
3459
3546
|
calculateCost(k: bigint, s1: bigint, s2: bigint): bigint;
|
|
3460
3547
|
/** Calculate tokens received for SOL: s2 = sqrt(s1² + 2×sol×K_SCALE/k) */
|