@paul.lumberwork/bonding-curve-sdk 1.0.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 +484 -0
- package/dist/index.d.mts +3411 -0
- package/dist/index.d.ts +3411 -0
- package/dist/index.js +560 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +544 -0
- package/dist/index.mjs.map +1 -0
- package/idl/pump_fun_program.json +3051 -0
- package/package.json +55 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,560 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var anchor = require('@coral-xyz/anchor');
|
|
4
|
+
var web3_js = require('@solana/web3.js');
|
|
5
|
+
var splToken = require('@solana/spl-token');
|
|
6
|
+
|
|
7
|
+
// src/sdk/index.ts
|
|
8
|
+
var PROGRAM_ID = new web3_js.PublicKey("6o7oTqg2CfvcMCJTLNEJsef7c875zGpTvcnFctNAjudL");
|
|
9
|
+
var ADMIN_WALLET = new web3_js.PublicKey("7eGpbyRpcM7WpNKQtd6XkteNQWHbWXP7icZjKzNK2aTk");
|
|
10
|
+
var METADATA_PROGRAM_ID = new web3_js.PublicKey("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s");
|
|
11
|
+
var K_SCALE = 10000000000000000000000n;
|
|
12
|
+
var LAMPORTS = web3_js.LAMPORTS_PER_SOL;
|
|
13
|
+
var TOKEN_DECIMALS = 6;
|
|
14
|
+
var FEE_BPS = 100;
|
|
15
|
+
var CURVE_PERCENT = 70;
|
|
16
|
+
var LP_PERCENT = 20;
|
|
17
|
+
var TREASURY_PERCENT = 10;
|
|
18
|
+
var PumpFunSDK = class {
|
|
19
|
+
constructor(program, wallet) {
|
|
20
|
+
this.program = program;
|
|
21
|
+
this.connection = program.provider.connection;
|
|
22
|
+
this.wallet = wallet;
|
|
23
|
+
[this.launchpadPda] = web3_js.PublicKey.findProgramAddressSync(
|
|
24
|
+
[Buffer.from("launchpad")],
|
|
25
|
+
program.programId
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
29
|
+
// PDA Derivation Helpers
|
|
30
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
31
|
+
deriveAddresses(mint) {
|
|
32
|
+
const [tokenLaunch] = web3_js.PublicKey.findProgramAddressSync(
|
|
33
|
+
[Buffer.from("token_launch"), mint.toBuffer()],
|
|
34
|
+
this.program.programId
|
|
35
|
+
);
|
|
36
|
+
const [bondingCurve] = web3_js.PublicKey.findProgramAddressSync(
|
|
37
|
+
[Buffer.from("bonding_curve"), tokenLaunch.toBuffer()],
|
|
38
|
+
this.program.programId
|
|
39
|
+
);
|
|
40
|
+
const [vault] = web3_js.PublicKey.findProgramAddressSync(
|
|
41
|
+
[Buffer.from("vault"), tokenLaunch.toBuffer()],
|
|
42
|
+
this.program.programId
|
|
43
|
+
);
|
|
44
|
+
const curveTokenAccount = splToken.getAssociatedTokenAddressSync(mint, bondingCurve, true);
|
|
45
|
+
const [metadata] = web3_js.PublicKey.findProgramAddressSync(
|
|
46
|
+
[Buffer.from("metadata"), METADATA_PROGRAM_ID.toBuffer(), mint.toBuffer()],
|
|
47
|
+
METADATA_PROGRAM_ID
|
|
48
|
+
);
|
|
49
|
+
return { mint, tokenLaunch, bondingCurve, vault, curveTokenAccount, metadata };
|
|
50
|
+
}
|
|
51
|
+
deriveUserPosition(tokenLaunch, user) {
|
|
52
|
+
const [userPosition] = web3_js.PublicKey.findProgramAddressSync(
|
|
53
|
+
[Buffer.from("user_position"), tokenLaunch.toBuffer(), user.toBuffer()],
|
|
54
|
+
this.program.programId
|
|
55
|
+
);
|
|
56
|
+
return userPosition;
|
|
57
|
+
}
|
|
58
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
59
|
+
// Initialize Launchpad (one-time setup)
|
|
60
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
61
|
+
async initializeLaunchpad(platformFeeBps = 200) {
|
|
62
|
+
try {
|
|
63
|
+
await this.program.account.launchpad.fetch(this.launchpadPda);
|
|
64
|
+
return "already_initialized";
|
|
65
|
+
} catch {
|
|
66
|
+
const tx = await this.program.methods.initializeLaunchpad(platformFeeBps).accountsPartial({
|
|
67
|
+
authority: this.wallet.publicKey,
|
|
68
|
+
launchpad: this.launchpadPda,
|
|
69
|
+
treasury: this.wallet.publicKey,
|
|
70
|
+
systemProgram: web3_js.SystemProgram.programId
|
|
71
|
+
}).rpc();
|
|
72
|
+
return tx;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
76
|
+
// Create Token Launch
|
|
77
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
78
|
+
async createTokenLaunch(config) {
|
|
79
|
+
const mintKeypair = web3_js.Keypair.generate();
|
|
80
|
+
const addresses = this.deriveAddresses(mintKeypair.publicKey);
|
|
81
|
+
const creatorWallet = config.creatorWallet || this.wallet.publicKey;
|
|
82
|
+
const totalSupplyRaw = new anchor.BN(config.totalSupply).mul(new anchor.BN(10 ** TOKEN_DECIMALS));
|
|
83
|
+
const kValue = new anchor.BN(config.k);
|
|
84
|
+
const tx = await this.program.methods.createTokenLaunch(config.name, config.symbol, config.uri, totalSupplyRaw, kValue).accountsPartial({
|
|
85
|
+
creator: creatorWallet,
|
|
86
|
+
launchpad: this.launchpadPda,
|
|
87
|
+
mint: mintKeypair.publicKey,
|
|
88
|
+
tokenLaunch: addresses.tokenLaunch,
|
|
89
|
+
bondingCurve: addresses.bondingCurve,
|
|
90
|
+
vault: addresses.vault,
|
|
91
|
+
curveTokenAccount: addresses.curveTokenAccount,
|
|
92
|
+
metadata: addresses.metadata,
|
|
93
|
+
tokenProgram: splToken.TOKEN_PROGRAM_ID,
|
|
94
|
+
associatedTokenProgram: splToken.ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
95
|
+
metadataProgram: METADATA_PROGRAM_ID,
|
|
96
|
+
systemProgram: web3_js.SystemProgram.programId,
|
|
97
|
+
rent: web3_js.SYSVAR_RENT_PUBKEY
|
|
98
|
+
}).signers([mintKeypair]).transaction();
|
|
99
|
+
const { blockhash } = await this.connection.getLatestBlockhash();
|
|
100
|
+
tx.recentBlockhash = blockhash;
|
|
101
|
+
tx.feePayer = this.wallet.publicKey;
|
|
102
|
+
tx.partialSign(mintKeypair);
|
|
103
|
+
const signedTx = await this.wallet.signTransaction(tx);
|
|
104
|
+
const txSignature = await this.connection.sendRawTransaction(signedTx.serialize(), {
|
|
105
|
+
skipPreflight: true
|
|
106
|
+
});
|
|
107
|
+
await this.connection.confirmTransaction({
|
|
108
|
+
signature: txSignature,
|
|
109
|
+
...await this.connection.getLatestBlockhash()
|
|
110
|
+
});
|
|
111
|
+
return { txSignature, addresses, mintKeypair };
|
|
112
|
+
}
|
|
113
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
114
|
+
// Buy Tokens
|
|
115
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
116
|
+
async buy(mint, solAmount, options) {
|
|
117
|
+
const addresses = this.deriveAddresses(mint);
|
|
118
|
+
const userTokenAccount = splToken.getAssociatedTokenAddressSync(mint, this.wallet.publicKey);
|
|
119
|
+
const userPosition = this.deriveUserPosition(addresses.tokenLaunch, this.wallet.publicKey);
|
|
120
|
+
await this.program.account.bondingCurve.fetch(addresses.bondingCurve);
|
|
121
|
+
let tokensBefore = 0n;
|
|
122
|
+
try {
|
|
123
|
+
const account = await splToken.getAccount(this.connection, userTokenAccount);
|
|
124
|
+
tokensBefore = account.amount;
|
|
125
|
+
} catch {
|
|
126
|
+
}
|
|
127
|
+
const solLamports = new anchor.BN(Math.floor(solAmount * web3_js.LAMPORTS_PER_SOL));
|
|
128
|
+
const preInstructions = [];
|
|
129
|
+
if (options?.computeUnits) {
|
|
130
|
+
preInstructions.push(
|
|
131
|
+
web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: options.computeUnits })
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
const tx = await this.program.methods.buyTokens(solLamports).accountsPartial({
|
|
135
|
+
contributor: this.wallet.publicKey,
|
|
136
|
+
launchpad: this.launchpadPda,
|
|
137
|
+
adminWallet: ADMIN_WALLET,
|
|
138
|
+
tokenLaunch: addresses.tokenLaunch,
|
|
139
|
+
bondingCurve: addresses.bondingCurve,
|
|
140
|
+
mint,
|
|
141
|
+
vault: addresses.vault,
|
|
142
|
+
curveTokenAccount: addresses.curveTokenAccount,
|
|
143
|
+
userTokenAccount,
|
|
144
|
+
userPosition,
|
|
145
|
+
systemProgram: web3_js.SystemProgram.programId,
|
|
146
|
+
tokenProgram: splToken.TOKEN_PROGRAM_ID,
|
|
147
|
+
associatedTokenProgram: splToken.ASSOCIATED_TOKEN_PROGRAM_ID
|
|
148
|
+
}).preInstructions(preInstructions).rpc();
|
|
149
|
+
const curveAfter = await this.program.account.bondingCurve.fetch(addresses.bondingCurve);
|
|
150
|
+
const tokensAfter = (await splToken.getAccount(this.connection, userTokenAccount)).amount;
|
|
151
|
+
const tokensReceived = tokensAfter - tokensBefore;
|
|
152
|
+
const progress = Number(curveAfter.soldSupply.toString()) / Number(curveAfter.tokensForCurve.toString()) * 100;
|
|
153
|
+
return {
|
|
154
|
+
txSignature: tx,
|
|
155
|
+
tokensTraded: tokensReceived,
|
|
156
|
+
solTraded: BigInt(solLamports.toString()),
|
|
157
|
+
newProgress: progress,
|
|
158
|
+
isCurveComplete: curveAfter.complete
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
162
|
+
// Sell Tokens
|
|
163
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
164
|
+
async sell(mint, tokenAmount, minSolOut = 0, options) {
|
|
165
|
+
const addresses = this.deriveAddresses(mint);
|
|
166
|
+
const userTokenAccount = splToken.getAssociatedTokenAddressSync(mint, this.wallet.publicKey);
|
|
167
|
+
const userPosition = this.deriveUserPosition(addresses.tokenLaunch, this.wallet.publicKey);
|
|
168
|
+
await this.program.account.bondingCurve.fetch(addresses.bondingCurve);
|
|
169
|
+
const walletBefore = await this.connection.getBalance(this.wallet.publicKey);
|
|
170
|
+
const tokensRaw = new anchor.BN(tokenAmount).mul(new anchor.BN(10 ** TOKEN_DECIMALS));
|
|
171
|
+
const minSolLamports = new anchor.BN(Math.floor(minSolOut * web3_js.LAMPORTS_PER_SOL));
|
|
172
|
+
const preInstructions = [];
|
|
173
|
+
if (options?.computeUnits) {
|
|
174
|
+
preInstructions.push(
|
|
175
|
+
web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: options.computeUnits })
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
const tx = await this.program.methods.sellTokens(tokensRaw, minSolLamports).accountsPartial({
|
|
179
|
+
contributor: this.wallet.publicKey,
|
|
180
|
+
launchpad: this.launchpadPda,
|
|
181
|
+
adminWallet: ADMIN_WALLET,
|
|
182
|
+
tokenLaunch: addresses.tokenLaunch,
|
|
183
|
+
bondingCurve: addresses.bondingCurve,
|
|
184
|
+
mint,
|
|
185
|
+
vault: addresses.vault,
|
|
186
|
+
curveTokenAccount: addresses.curveTokenAccount,
|
|
187
|
+
userTokenAccount,
|
|
188
|
+
userPosition,
|
|
189
|
+
systemProgram: web3_js.SystemProgram.programId,
|
|
190
|
+
tokenProgram: splToken.TOKEN_PROGRAM_ID
|
|
191
|
+
}).preInstructions(preInstructions).rpc();
|
|
192
|
+
const curveAfter = await this.program.account.bondingCurve.fetch(addresses.bondingCurve);
|
|
193
|
+
const walletAfter = await this.connection.getBalance(this.wallet.publicKey);
|
|
194
|
+
const solReceived = BigInt(walletAfter - walletBefore);
|
|
195
|
+
const progress = Number(curveAfter.soldSupply.toString()) / Number(curveAfter.tokensForCurve.toString()) * 100;
|
|
196
|
+
return {
|
|
197
|
+
txSignature: tx,
|
|
198
|
+
tokensTraded: BigInt(tokensRaw.toString()),
|
|
199
|
+
solTraded: solReceived,
|
|
200
|
+
newProgress: progress,
|
|
201
|
+
isCurveComplete: curveAfter.complete
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
205
|
+
// Admin Withdraw
|
|
206
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
207
|
+
async adminWithdraw(mint) {
|
|
208
|
+
const addresses = this.deriveAddresses(mint);
|
|
209
|
+
const adminTokenAccount = splToken.getAssociatedTokenAddressSync(mint, this.wallet.publicKey);
|
|
210
|
+
const launchpad = await this.program.account.launchpad.fetch(this.launchpadPda);
|
|
211
|
+
const treasuryWallet = launchpad.treasury;
|
|
212
|
+
const treasuryTokenAccount = splToken.getAssociatedTokenAddressSync(mint, treasuryWallet, true);
|
|
213
|
+
const curve = await this.program.account.bondingCurve.fetch(addresses.bondingCurve);
|
|
214
|
+
const lpSol = BigInt(curve.realSolReserves.toString());
|
|
215
|
+
const lpTokens = BigInt(curve.tokenReservesForLp.toString());
|
|
216
|
+
const accumulatedFees = BigInt(curve.accumulatedFees.toString());
|
|
217
|
+
const treasuryTokensAmount = BigInt(curve.tokenReservesForTreasury.toString());
|
|
218
|
+
const tx = await this.program.methods.adminWithdraw().accountsPartial({
|
|
219
|
+
admin: this.wallet.publicKey,
|
|
220
|
+
launchpad: this.launchpadPda,
|
|
221
|
+
tokenLaunch: addresses.tokenLaunch,
|
|
222
|
+
bondingCurve: addresses.bondingCurve,
|
|
223
|
+
mint,
|
|
224
|
+
vault: addresses.vault,
|
|
225
|
+
curveTokenAccount: addresses.curveTokenAccount,
|
|
226
|
+
adminTokenAccount,
|
|
227
|
+
treasuryWallet,
|
|
228
|
+
treasuryTokenAccount,
|
|
229
|
+
systemProgram: web3_js.SystemProgram.programId,
|
|
230
|
+
tokenProgram: splToken.TOKEN_PROGRAM_ID,
|
|
231
|
+
associatedTokenProgram: splToken.ASSOCIATED_TOKEN_PROGRAM_ID
|
|
232
|
+
}).rpc();
|
|
233
|
+
return {
|
|
234
|
+
txSignature: tx,
|
|
235
|
+
solWithdrawn: lpSol,
|
|
236
|
+
tokensWithdrawn: lpTokens,
|
|
237
|
+
feesToTreasury: accumulatedFees,
|
|
238
|
+
treasuryTokens: treasuryTokensAmount
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
242
|
+
// Estimate Buy (tokens received for SOL)
|
|
243
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
244
|
+
async estimateBuy(mint, solAmount) {
|
|
245
|
+
const addresses = this.deriveAddresses(mint);
|
|
246
|
+
const curve = await this.program.account.bondingCurve.fetch(addresses.bondingCurve);
|
|
247
|
+
const k = BigInt(curve.k.toString());
|
|
248
|
+
const soldSupply = BigInt(curve.soldSupply.toString());
|
|
249
|
+
const tokensForCurve = BigInt(curve.tokensForCurve.toString());
|
|
250
|
+
const solLamports = BigInt(Math.floor(solAmount * web3_js.LAMPORTS_PER_SOL));
|
|
251
|
+
const feeAmount = solLamports / 100n;
|
|
252
|
+
const solAfterFees = solLamports - feeAmount;
|
|
253
|
+
const tokensOut = this.calculateTokensForSol(k, soldSupply, solAfterFees);
|
|
254
|
+
const available = tokensForCurve - soldSupply;
|
|
255
|
+
const actualTokensOut = tokensOut > available ? available : tokensOut;
|
|
256
|
+
const pricePerToken = solAfterFees / (actualTokensOut / BigInt(10 ** TOKEN_DECIMALS));
|
|
257
|
+
const newSoldSupply = soldSupply + actualTokensOut;
|
|
258
|
+
const priceBefore = this.calculatePrice(k, soldSupply);
|
|
259
|
+
const priceAfter = this.calculatePrice(k, newSoldSupply);
|
|
260
|
+
const priceImpactBps = priceBefore > 0n ? Number((priceAfter - priceBefore) * 10000n / priceBefore) : 0;
|
|
261
|
+
return {
|
|
262
|
+
tokensOut: actualTokensOut,
|
|
263
|
+
solCost: solLamports,
|
|
264
|
+
pricePerToken,
|
|
265
|
+
priceImpactBps,
|
|
266
|
+
feeAmount
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
270
|
+
// Estimate Sell (SOL received for tokens)
|
|
271
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
272
|
+
async estimateSell(mint, tokenAmount) {
|
|
273
|
+
const addresses = this.deriveAddresses(mint);
|
|
274
|
+
const curve = await this.program.account.bondingCurve.fetch(addresses.bondingCurve);
|
|
275
|
+
const k = BigInt(curve.k.toString());
|
|
276
|
+
const soldSupply = BigInt(curve.soldSupply.toString());
|
|
277
|
+
const realSolReserves = BigInt(curve.realSolReserves.toString());
|
|
278
|
+
const tokensRaw = BigInt(tokenAmount) * BigInt(10 ** TOKEN_DECIMALS);
|
|
279
|
+
if (tokensRaw > soldSupply) {
|
|
280
|
+
throw new Error(`Cannot sell ${tokenAmount} tokens. Only ${soldSupply / BigInt(10 ** TOKEN_DECIMALS)} available.`);
|
|
281
|
+
}
|
|
282
|
+
const grossRefund = this.calculateRefund(k, soldSupply, soldSupply - tokensRaw);
|
|
283
|
+
const cappedRefund = grossRefund > realSolReserves ? realSolReserves : grossRefund;
|
|
284
|
+
const feeAmount = cappedRefund / 100n;
|
|
285
|
+
const netSolOut = cappedRefund - feeAmount;
|
|
286
|
+
const pricePerToken = netSolOut / BigInt(tokenAmount);
|
|
287
|
+
const newSoldSupply = soldSupply - tokensRaw;
|
|
288
|
+
const priceBefore = this.calculatePrice(k, soldSupply);
|
|
289
|
+
const priceAfter = this.calculatePrice(k, newSoldSupply);
|
|
290
|
+
const priceImpactBps = priceBefore > 0n ? Number((priceBefore - priceAfter) * 10000n / priceBefore) : 0;
|
|
291
|
+
return {
|
|
292
|
+
tokensOut: tokensRaw,
|
|
293
|
+
// tokens being sold
|
|
294
|
+
solCost: netSolOut,
|
|
295
|
+
// SOL to receive
|
|
296
|
+
pricePerToken,
|
|
297
|
+
priceImpactBps,
|
|
298
|
+
feeAmount
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
302
|
+
// Get Curve State
|
|
303
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
304
|
+
async getCurveState(mint) {
|
|
305
|
+
const addresses = this.deriveAddresses(mint);
|
|
306
|
+
const curve = await this.program.account.bondingCurve.fetch(addresses.bondingCurve);
|
|
307
|
+
return {
|
|
308
|
+
tokenLaunch: curve.tokenLaunch,
|
|
309
|
+
k: BigInt(curve.k.toString()),
|
|
310
|
+
totalSupply: BigInt(curve.totalSupply.toString()),
|
|
311
|
+
soldSupply: BigInt(curve.soldSupply.toString()),
|
|
312
|
+
realSolReserves: BigInt(curve.realSolReserves.toString()),
|
|
313
|
+
tokenReservesForLp: BigInt(curve.tokenReservesForLp.toString()),
|
|
314
|
+
tokenReservesForTreasury: BigInt(curve.tokenReservesForTreasury.toString()),
|
|
315
|
+
tokensForCurve: BigInt(curve.tokensForCurve.toString()),
|
|
316
|
+
accumulatedFees: BigInt(curve.accumulatedFees.toString()),
|
|
317
|
+
complete: curve.complete,
|
|
318
|
+
bump: curve.bump
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
322
|
+
// Get Token Launch State
|
|
323
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
324
|
+
async getTokenLaunchState(mint) {
|
|
325
|
+
const addresses = this.deriveAddresses(mint);
|
|
326
|
+
const launch = await this.program.account.tokenLaunch.fetch(addresses.tokenLaunch);
|
|
327
|
+
return {
|
|
328
|
+
creator: launch.creator,
|
|
329
|
+
mint: launch.mint,
|
|
330
|
+
vault: launch.vault,
|
|
331
|
+
bondingCurve: launch.bondingCurve,
|
|
332
|
+
totalSupply: BigInt(launch.totalSupply.toString()),
|
|
333
|
+
curveAllocation: BigInt(launch.curveAllocation.toString()),
|
|
334
|
+
lpAllocation: BigInt(launch.lpAllocation.toString()),
|
|
335
|
+
treasuryAllocation: BigInt(launch.treasuryAllocation.toString()),
|
|
336
|
+
totalSolRaised: BigInt(launch.totalSolRaised.toString()),
|
|
337
|
+
tradingActive: launch.tradingActive,
|
|
338
|
+
migrated: launch.migrated,
|
|
339
|
+
initialK: BigInt(launch.initialK.toString()),
|
|
340
|
+
name: launch.name,
|
|
341
|
+
symbol: launch.symbol
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
345
|
+
// Get Progress
|
|
346
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
347
|
+
async getProgress(mint) {
|
|
348
|
+
const curve = await this.getCurveState(mint);
|
|
349
|
+
const percent = Number(curve.soldSupply * 100n / curve.tokensForCurve);
|
|
350
|
+
const currentPrice = this.calculatePrice(curve.k, curve.soldSupply);
|
|
351
|
+
return {
|
|
352
|
+
percent,
|
|
353
|
+
soldSupply: curve.soldSupply,
|
|
354
|
+
tokensForCurve: curve.tokensForCurve,
|
|
355
|
+
solRaised: curve.realSolReserves,
|
|
356
|
+
currentPrice,
|
|
357
|
+
isComplete: curve.complete
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
361
|
+
// Event Listeners
|
|
362
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
363
|
+
/**
|
|
364
|
+
* Listen for LaunchCreated events
|
|
365
|
+
* @param callback Function to call when event is emitted
|
|
366
|
+
* @returns Listener ID for removal
|
|
367
|
+
*/
|
|
368
|
+
onLaunchCreated(callback) {
|
|
369
|
+
return this.program.addEventListener("launchCreated", (event, slot, signature) => {
|
|
370
|
+
callback({
|
|
371
|
+
tokenLaunch: event.tokenLaunch,
|
|
372
|
+
mint: event.mint,
|
|
373
|
+
creator: event.creator,
|
|
374
|
+
name: event.name,
|
|
375
|
+
symbol: event.symbol,
|
|
376
|
+
totalSupply: BigInt(event.totalSupply.toString()),
|
|
377
|
+
curveAllocation: BigInt(event.curveAllocation.toString()),
|
|
378
|
+
lpAllocation: BigInt(event.lpAllocation.toString()),
|
|
379
|
+
treasuryAllocation: BigInt(event.treasuryAllocation.toString()),
|
|
380
|
+
initialK: BigInt(event.initialK.toString()),
|
|
381
|
+
initialPrice: BigInt(event.initialPrice.toString()),
|
|
382
|
+
timestamp: BigInt(event.timestamp.toString())
|
|
383
|
+
}, slot, signature);
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Listen for TokensPurchased events
|
|
388
|
+
* @param callback Function to call when event is emitted
|
|
389
|
+
* @returns Listener ID for removal
|
|
390
|
+
*/
|
|
391
|
+
onTokensPurchased(callback) {
|
|
392
|
+
return this.program.addEventListener("tokensPurchased", (event, slot, signature) => {
|
|
393
|
+
callback({
|
|
394
|
+
tokenLaunch: event.tokenLaunch,
|
|
395
|
+
mint: event.mint,
|
|
396
|
+
buyer: event.buyer,
|
|
397
|
+
solAmount: BigInt(event.solAmount.toString()),
|
|
398
|
+
solAfterFees: BigInt(event.solAfterFees.toString()),
|
|
399
|
+
tokensReceived: BigInt(event.tokensReceived.toString()),
|
|
400
|
+
curveFee: BigInt(event.curveFee.toString()),
|
|
401
|
+
adminFee: BigInt(event.adminFee.toString()),
|
|
402
|
+
priceAfter: BigInt(event.priceAfter.toString()),
|
|
403
|
+
totalSold: BigInt(event.totalSold.toString()),
|
|
404
|
+
progress: event.progress,
|
|
405
|
+
timestamp: BigInt(event.timestamp.toString()),
|
|
406
|
+
isCurveComplete: event.isCurveComplete
|
|
407
|
+
}, slot, signature);
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Listen for TokensSold events
|
|
412
|
+
* @param callback Function to call when event is emitted
|
|
413
|
+
* @returns Listener ID for removal
|
|
414
|
+
*/
|
|
415
|
+
onTokensSold(callback) {
|
|
416
|
+
return this.program.addEventListener("tokensSold", (event, slot, signature) => {
|
|
417
|
+
callback({
|
|
418
|
+
tokenLaunch: event.tokenLaunch,
|
|
419
|
+
mint: event.mint,
|
|
420
|
+
seller: event.seller,
|
|
421
|
+
tokensSold: BigInt(event.tokensSold.toString()),
|
|
422
|
+
grossSolRefund: BigInt(event.grossSolRefund.toString()),
|
|
423
|
+
netSolRefund: BigInt(event.netSolRefund.toString()),
|
|
424
|
+
curveFee: BigInt(event.curveFee.toString()),
|
|
425
|
+
adminFee: BigInt(event.adminFee.toString()),
|
|
426
|
+
priceAfter: BigInt(event.priceAfter.toString()),
|
|
427
|
+
totalSold: BigInt(event.totalSold.toString()),
|
|
428
|
+
progress: event.progress,
|
|
429
|
+
timestamp: BigInt(event.timestamp.toString())
|
|
430
|
+
}, slot, signature);
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Listen for CurveComplete events
|
|
435
|
+
* @param callback Function to call when event is emitted
|
|
436
|
+
* @returns Listener ID for removal
|
|
437
|
+
*/
|
|
438
|
+
onCurveComplete(callback) {
|
|
439
|
+
return this.program.addEventListener("curveComplete", (event, slot, signature) => {
|
|
440
|
+
callback({
|
|
441
|
+
tokenLaunch: event.tokenLaunch,
|
|
442
|
+
mint: event.mint,
|
|
443
|
+
totalSolRaised: BigInt(event.totalSolRaised.toString()),
|
|
444
|
+
finalPrice: BigInt(event.finalPrice.toString()),
|
|
445
|
+
timestamp: BigInt(event.timestamp.toString())
|
|
446
|
+
}, slot, signature);
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Listen for AdminWithdraw events
|
|
451
|
+
* @param callback Function to call when event is emitted
|
|
452
|
+
* @returns Listener ID for removal
|
|
453
|
+
*/
|
|
454
|
+
onAdminWithdraw(callback) {
|
|
455
|
+
return this.program.addEventListener("adminWithdraw", (event, slot, signature) => {
|
|
456
|
+
callback({
|
|
457
|
+
tokenLaunch: event.tokenLaunch,
|
|
458
|
+
mint: event.mint,
|
|
459
|
+
admin: event.admin,
|
|
460
|
+
creator: event.creator,
|
|
461
|
+
treasury: event.treasury,
|
|
462
|
+
solWithdrawn: BigInt(event.solWithdrawn.toString()),
|
|
463
|
+
tokensWithdrawn: BigInt(event.tokensWithdrawn.toString()),
|
|
464
|
+
feesToTreasury: BigInt(event.feesToTreasury.toString()),
|
|
465
|
+
treasuryTokens: BigInt(event.treasuryTokens.toString()),
|
|
466
|
+
timestamp: BigInt(event.timestamp.toString())
|
|
467
|
+
}, slot, signature);
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Remove an event listener
|
|
472
|
+
* @param listenerId The ID returned from addEventListener
|
|
473
|
+
*/
|
|
474
|
+
async removeEventListener(listenerId) {
|
|
475
|
+
await this.program.removeEventListener(listenerId);
|
|
476
|
+
}
|
|
477
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
478
|
+
// Math Helpers (Pure functions, no async)
|
|
479
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
480
|
+
/** Calculate price at a given supply: price = k × supply / K_SCALE */
|
|
481
|
+
calculatePrice(k, supply) {
|
|
482
|
+
if (supply === 0n) return 0n;
|
|
483
|
+
return k * supply / K_SCALE;
|
|
484
|
+
}
|
|
485
|
+
/** Calculate cost to buy from s1 to s2: cost = (k/2) × (s2² - s1²) / K_SCALE */
|
|
486
|
+
calculateCost(k, s1, s2) {
|
|
487
|
+
if (s2 <= s1) return 0n;
|
|
488
|
+
const s1Sq = s1 * s1;
|
|
489
|
+
const s2Sq = s2 * s2;
|
|
490
|
+
const diffSq = s2Sq - s1Sq;
|
|
491
|
+
return k * diffSq / 2n / K_SCALE;
|
|
492
|
+
}
|
|
493
|
+
/** Calculate tokens received for SOL: s2 = sqrt(s1² + 2×sol×K_SCALE/k) */
|
|
494
|
+
calculateTokensForSol(k, currentSupply, solIn) {
|
|
495
|
+
if (solIn === 0n || k === 0n) return 0n;
|
|
496
|
+
const s1Sq = currentSupply * currentSupply;
|
|
497
|
+
const addition = 2n * solIn * K_SCALE / k;
|
|
498
|
+
const s2Sq = s1Sq + addition;
|
|
499
|
+
const s2 = this.isqrt(s2Sq);
|
|
500
|
+
return s2 - currentSupply;
|
|
501
|
+
}
|
|
502
|
+
/** Calculate refund for selling tokens: refund = (k/2) × (s1² - s2²) / K_SCALE */
|
|
503
|
+
calculateRefund(k, s1, s2) {
|
|
504
|
+
if (s1 <= s2) return 0n;
|
|
505
|
+
const s1Sq = s1 * s1;
|
|
506
|
+
const s2Sq = s2 * s2;
|
|
507
|
+
const diffSq = s1Sq - s2Sq;
|
|
508
|
+
return k * diffSq / 2n / K_SCALE;
|
|
509
|
+
}
|
|
510
|
+
/** Integer square root using Newton's method */
|
|
511
|
+
isqrt(n) {
|
|
512
|
+
if (n === 0n) return 0n;
|
|
513
|
+
if (n === 1n) return 1n;
|
|
514
|
+
let x = n;
|
|
515
|
+
let y = (x + 1n) / 2n;
|
|
516
|
+
while (y < x) {
|
|
517
|
+
x = y;
|
|
518
|
+
y = (x + n / x) / 2n;
|
|
519
|
+
}
|
|
520
|
+
return x;
|
|
521
|
+
}
|
|
522
|
+
/** Calculate K for a given target SOL and curve supply */
|
|
523
|
+
static calculateK(curveSupply, targetSol) {
|
|
524
|
+
const numerator = 2n * targetSol * K_SCALE;
|
|
525
|
+
const denominator = curveSupply * curveSupply;
|
|
526
|
+
return numerator / denominator;
|
|
527
|
+
}
|
|
528
|
+
};
|
|
529
|
+
function formatTokens(raw) {
|
|
530
|
+
const tokens = Number(raw) / 10 ** TOKEN_DECIMALS;
|
|
531
|
+
return tokens.toLocaleString(void 0, { maximumFractionDigits: 2 });
|
|
532
|
+
}
|
|
533
|
+
function formatSol(lamports) {
|
|
534
|
+
const sol = Number(lamports) / web3_js.LAMPORTS_PER_SOL;
|
|
535
|
+
return sol.toFixed(4);
|
|
536
|
+
}
|
|
537
|
+
function parseSol(sol) {
|
|
538
|
+
return BigInt(Math.floor(sol * web3_js.LAMPORTS_PER_SOL));
|
|
539
|
+
}
|
|
540
|
+
function parseTokens(tokens) {
|
|
541
|
+
return BigInt(Math.floor(tokens * 10 ** TOKEN_DECIMALS));
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
exports.ADMIN_WALLET = ADMIN_WALLET;
|
|
545
|
+
exports.CURVE_PERCENT = CURVE_PERCENT;
|
|
546
|
+
exports.FEE_BPS = FEE_BPS;
|
|
547
|
+
exports.K_SCALE = K_SCALE;
|
|
548
|
+
exports.LAMPORTS = LAMPORTS;
|
|
549
|
+
exports.LP_PERCENT = LP_PERCENT;
|
|
550
|
+
exports.METADATA_PROGRAM_ID = METADATA_PROGRAM_ID;
|
|
551
|
+
exports.PROGRAM_ID = PROGRAM_ID;
|
|
552
|
+
exports.PumpFunSDK = PumpFunSDK;
|
|
553
|
+
exports.TOKEN_DECIMALS = TOKEN_DECIMALS;
|
|
554
|
+
exports.TREASURY_PERCENT = TREASURY_PERCENT;
|
|
555
|
+
exports.formatSol = formatSol;
|
|
556
|
+
exports.formatTokens = formatTokens;
|
|
557
|
+
exports.parseSol = parseSol;
|
|
558
|
+
exports.parseTokens = parseTokens;
|
|
559
|
+
//# sourceMappingURL=index.js.map
|
|
560
|
+
//# sourceMappingURL=index.js.map
|