@forgedevv/core 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +88 -5
- package/README.md +4 -3
- package/dist/addresses.d.ts +50 -3
- package/dist/addresses.js +70 -1
- package/dist/claims.d.ts +12 -2
- package/dist/claims.js +29 -11
- package/dist/config.d.ts +40 -37
- package/dist/config.js +265 -47
- package/dist/index.d.ts +4 -2
- package/dist/index.js +6 -1
- package/dist/jupiter-referral.d.ts +119 -0
- package/dist/jupiter-referral.js +295 -0
- package/dist/launch-metadata.d.ts +3 -1
- package/dist/pool.d.ts +68 -17
- package/dist/pool.js +112 -39
- package/dist/position-claims.d.ts +207 -0
- package/dist/position-claims.js +440 -0
- package/dist/settings.d.ts +73 -0
- package/dist/settings.js +119 -0
- package/dist/swap.d.ts +70 -17
- package/dist/swap.js +89 -24
- package/dist/validate.d.ts +14 -1
- package/dist/validate.js +86 -6
- package/package.json +3 -2
package/dist/pool.js
CHANGED
|
@@ -33,14 +33,20 @@
|
|
|
33
33
|
*
|
|
34
34
|
* `buildUserCoinLaunchTx` is the same launch for a coin created by a user on the client's
|
|
35
35
|
* launchpad config: the user is pool creator, rent payer, fee payer and buyer, the mint is the
|
|
36
|
-
* only other signer.
|
|
36
|
+
* only other signer. Its first buy pays the FORGE platform fee (0.3%, rounded up) like any swap
|
|
37
|
+
* built by core: one SOL transfer to `FORGE_PLATFORM_FEE_WALLET`, the last instruction.
|
|
38
|
+
*
|
|
39
|
+
* Both builders compare the on-chain config with what core builds for it, field by field
|
|
40
|
+
* (`onchainConfigMismatches` in config.ts), before building anything.
|
|
37
41
|
*/
|
|
38
42
|
import { DYNAMIC_BONDING_CURVE_PROGRAM_ID, DynamicBondingCurveClient, MigrationOption, TokenType, deriveDbcPoolAddress, } from '@meteora-ag/dynamic-bonding-curve-sdk';
|
|
39
43
|
import { ACCOUNT_SIZE, ASSOCIATED_TOKEN_PROGRAM_ID, MINT_SIZE, NATIVE_MINT, TOKEN_PROGRAM_ID, createAssociatedTokenAccountIdempotentInstruction, getAssociatedTokenAddressSync, } from '@solana/spl-token';
|
|
40
44
|
import { PublicKey, SystemProgram, Transaction, } from '@solana/web3.js';
|
|
41
45
|
import BN from 'bn.js';
|
|
42
|
-
import {
|
|
46
|
+
import { getPlatformFeeWallet } from './addresses.js';
|
|
47
|
+
import { onchainConfigMismatches, quoteFirstBuyOnConfig, } from './config.js';
|
|
43
48
|
import { FEES, MIGRATION_THRESHOLD_LAMPORTS, SOL_QUOTE_MINT } from './constants.js';
|
|
49
|
+
import { PLATFORM_FEE_BPS, platformFeeLamports } from './swap.js';
|
|
44
50
|
import { LaunchCoinError, assertFirstBuyLamports, assertLaunchMetadata, } from './launch-metadata.js';
|
|
45
51
|
import { MAX_TRANSACTION_BYTES, computeBudgetInstructions, priorityFeeLamports, readNonce, requiredSigners, transactionSize, } from './tx.js';
|
|
46
52
|
// The metadata and first buy checks live in launch-metadata.ts (shared with config.ts); they
|
|
@@ -84,14 +90,12 @@ function assertDistinctKeys(entries) {
|
|
|
84
90
|
}
|
|
85
91
|
}
|
|
86
92
|
/**
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* @throws LaunchCoinError `CONFIG_MISMATCH` listing every mismatch.
|
|
93
|
+
* The essential checks of a config a coin is launched on, with readable messages: SOL quote (SPL),
|
|
94
|
+
* SPL base token, first swap at the minimum fee (otherwise the first buy pays the anti-sniper
|
|
95
|
+
* fee), a fee scheduler base fee, DAMM v2 migration at exactly 10 SOL. The full field by field
|
|
96
|
+
* comparison (`onchainConfigMismatches`) follows them.
|
|
93
97
|
*/
|
|
94
|
-
|
|
98
|
+
function essentialConfigProblems(config) {
|
|
95
99
|
const problems = [];
|
|
96
100
|
if (!config.quoteMint.equals(SOL_QUOTE_MINT))
|
|
97
101
|
problems.push('quote mint is not SOL');
|
|
@@ -99,16 +103,6 @@ export function assertLaunchCoinConfig(config, owner) {
|
|
|
99
103
|
problems.push('quote token is not an SPL token');
|
|
100
104
|
if (config.tokenType !== TokenType.SPLToken)
|
|
101
105
|
problems.push('base token type is not SPL token');
|
|
102
|
-
if (!config.feeClaimer.equals(owner))
|
|
103
|
-
problems.push('fee claimer is not the owner wallet');
|
|
104
|
-
if (!config.leftoverReceiver.equals(owner))
|
|
105
|
-
problems.push('leftover receiver is not the owner');
|
|
106
|
-
if (config.creatorTradingFeePercentage !== FEES.forgeCreatorSharePct) {
|
|
107
|
-
problems.push(`creator trading fee is not ${FEES.forgeCreatorSharePct}%`);
|
|
108
|
-
}
|
|
109
|
-
if (!(config.creatorPermanentLockedLiquidityPercentage > 0)) {
|
|
110
|
-
problems.push('creator has no permanently locked liquidity');
|
|
111
|
-
}
|
|
112
106
|
if (config.enableFirstSwapWithMinFee !== 1) {
|
|
113
107
|
problems.push('first swap with minimum fee is disabled (the first buy would pay the anti-sniper fee)');
|
|
114
108
|
}
|
|
@@ -121,6 +115,40 @@ export function assertLaunchCoinConfig(config, owner) {
|
|
|
121
115
|
if (BigInt(config.migrationQuoteThreshold.toString()) !== MIGRATION_THRESHOLD_LAMPORTS) {
|
|
122
116
|
problems.push(`migration threshold is not ${MIGRATION_THRESHOLD_LAMPORTS} lamports`);
|
|
123
117
|
}
|
|
118
|
+
return problems;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Checks that an on-chain config is the launchpad coin config of `owner` and that it is safe to
|
|
122
|
+
* launch the coin on it. Besides the essential checks (SOL quote, SPL token, first swap at the
|
|
123
|
+
* minimum fee, fee scheduler, DAMM v2 at exactly 10 SOL), EVERY field is compared with what core
|
|
124
|
+
* builds for a launchpad coin config (`onchainConfigMismatches`): fee claimer and leftover
|
|
125
|
+
* receiver = owner, FORGE creator share, the 75 / 25 permanently locked liquidity, no pool
|
|
126
|
+
* creation fee, immutable metadata, the exact fee schedule, no migration fee, no locked vesting,
|
|
127
|
+
* FORGE's supply and curve, timestamp activation.
|
|
128
|
+
*
|
|
129
|
+
* With `spec` (the spec the config was built from), the reference is exactly
|
|
130
|
+
* `buildLaunchpadCoinConfig(spec)`; without it, the trading fee and the anti-sniper flag are read
|
|
131
|
+
* from the config and only have to be values a FORGE spec can hold (linear schedule, whole fee of
|
|
132
|
+
* 50..200 bps). Pass the spec whenever it is known.
|
|
133
|
+
*
|
|
134
|
+
* @throws LaunchCoinError `CONFIG_MISMATCH` listing every mismatch.
|
|
135
|
+
*/
|
|
136
|
+
export function assertLaunchCoinConfig(config, owner, spec) {
|
|
137
|
+
const problems = essentialConfigProblems(config);
|
|
138
|
+
if (!config.feeClaimer.equals(owner))
|
|
139
|
+
problems.push('fee claimer is not the owner wallet');
|
|
140
|
+
if (!config.leftoverReceiver.equals(owner))
|
|
141
|
+
problems.push('leftover receiver is not the owner');
|
|
142
|
+
if (config.creatorTradingFeePercentage !== FEES.forgeCreatorSharePct) {
|
|
143
|
+
problems.push(`creator trading fee is not ${FEES.forgeCreatorSharePct}%`);
|
|
144
|
+
}
|
|
145
|
+
if (!(config.creatorPermanentLockedLiquidityPercentage > 0)) {
|
|
146
|
+
problems.push('creator has no permanently locked liquidity');
|
|
147
|
+
}
|
|
148
|
+
problems.push(...onchainConfigMismatches(config, 'launchpadCoin', {
|
|
149
|
+
owner,
|
|
150
|
+
...(spec !== undefined ? { spec } : {}),
|
|
151
|
+
}));
|
|
124
152
|
if (problems.length > 0) {
|
|
125
153
|
fail('CONFIG_MISMATCH', `config is not a valid launchpad coin config: ${problems.join('; ')}`);
|
|
126
154
|
}
|
|
@@ -231,7 +259,8 @@ async function loadLaunchState(connection, accounts, checkConfig) {
|
|
|
231
259
|
* Quotes the first buy on the fresh pool at the minimum fee (exact: nothing else can trade before
|
|
232
260
|
* it, the pool is created in the same transaction) and assembles the transaction: nonce advance,
|
|
233
261
|
* compute budget, the buyer's WSOL account (idempotent), then the SDK instructions of
|
|
234
|
-
* `createPoolWithFirstBuy` (proven call pattern of devnet test 3), without referral
|
|
262
|
+
* `createPoolWithFirstBuy` (proven call pattern of devnet test 3), without referral, then the
|
|
263
|
+
* trailing instructions.
|
|
235
264
|
*/
|
|
236
265
|
async function assembleLaunch(input) {
|
|
237
266
|
const { buyer, nonce } = input;
|
|
@@ -273,7 +302,7 @@ async function assembleLaunch(input) {
|
|
|
273
302
|
if (quote && !createsAssociatedAccount(sdkTx.instructions, buyerWsol)) {
|
|
274
303
|
instructions.push(createAssociatedTokenAccountIdempotentInstruction(buyer, buyerWsol, buyer, NATIVE_MINT, TOKEN_PROGRAM_ID));
|
|
275
304
|
}
|
|
276
|
-
instructions.push(...sdkTx.instructions);
|
|
305
|
+
instructions.push(...sdkTx.instructions, ...(input.trailingInstructions ?? []));
|
|
277
306
|
const transaction = new Transaction({ feePayer: buyer, recentBlockhash: input.recentBlockhash });
|
|
278
307
|
if (input.lastValidBlockHeight !== null) {
|
|
279
308
|
transaction.lastValidBlockHeight = input.lastValidBlockHeight;
|
|
@@ -332,9 +361,11 @@ async function computeLaunchCosts(input) {
|
|
|
332
361
|
const rentPayerCosts = poolAccountsRentLamports +
|
|
333
362
|
METAPLEX_CREATE_METADATA_FEE_LAMPORTS +
|
|
334
363
|
input.poolCreationFeeLamports;
|
|
364
|
+
const platformFee = input.platformFeeLamports ?? 0n;
|
|
335
365
|
const ownerTotalLamports = firstBuy +
|
|
336
366
|
networkFeeLamports +
|
|
337
367
|
ownerTokenAccountRentLamports +
|
|
368
|
+
platformFee +
|
|
338
369
|
(input.rentPayerIsOwner ? rentPayerCosts : 0n);
|
|
339
370
|
return {
|
|
340
371
|
firstBuyLamports: firstBuy,
|
|
@@ -346,6 +377,7 @@ async function computeLaunchCosts(input) {
|
|
|
346
377
|
ownerTemporaryLamports,
|
|
347
378
|
networkFeeLamports,
|
|
348
379
|
networkFeeSource,
|
|
380
|
+
...(input.platformFeeLamports !== undefined ? { platformFeeLamports: platformFee } : {}),
|
|
349
381
|
ownerTotalLamports,
|
|
350
382
|
ownerRequiredBalanceLamports: ownerTotalLamports + ownerTemporaryLamports,
|
|
351
383
|
creatorTotalLamports: input.rentPayerIsOwner ? 0n : rentPayerCosts,
|
|
@@ -406,7 +438,7 @@ export async function buildLaunchCoinTx(params) {
|
|
|
406
438
|
const pool = deriveDbcPoolAddress(SOL_QUOTE_MINT, mint, config);
|
|
407
439
|
const rentPayer = rentPayerKind === 'owner' ? owner : creator;
|
|
408
440
|
// 2. On-chain state: config (this owner's launchpad coin config), pool and mint not existing.
|
|
409
|
-
const { poolConfig, client, program } = await loadLaunchState(connection, { config, pool, mint }, (decoded) => assertLaunchCoinConfig(decoded, owner));
|
|
441
|
+
const { poolConfig, client, program } = await loadLaunchState(connection, { config, pool, mint }, (decoded) => assertLaunchCoinConfig(decoded, owner, params.spec));
|
|
410
442
|
const poolCreationFeeLamports = toBigInt(poolConfig.poolCreationFee);
|
|
411
443
|
if (rentPayerKind === 'creator' && poolCreationFeeLamports !== 0n) {
|
|
412
444
|
fail('RENT_PAYER_REFUSED', `the creator wallet cannot pay the rent on a config with a pool creation fee (${poolCreationFeeLamports} lamports): it would pay the client's own fee`);
|
|
@@ -511,34 +543,49 @@ export async function buildLaunchCoinTx(params) {
|
|
|
511
543
|
};
|
|
512
544
|
}
|
|
513
545
|
/**
|
|
514
|
-
* Checks that an on-chain config
|
|
515
|
-
* quote, SPL token program for both tokens, `enableFirstSwapWithMinFee
|
|
516
|
-
*
|
|
546
|
+
* Checks that an on-chain config is a FORGE launchpad config a user coin can be launched on:
|
|
547
|
+
* the essential checks (SOL quote, SPL token program for both tokens, `enableFirstSwapWithMinFee`,
|
|
548
|
+
* fee scheduler, DAMM v2 at exactly 10 SOL), then EVERY field compared with what core builds for
|
|
549
|
+
* a launchpad config (`onchainConfigMismatches`): liquidity split following the creator share,
|
|
550
|
+
* immutable metadata, the exact fee schedule, no migration fee, no locked vesting, FORGE's supply
|
|
551
|
+
* and curve, timestamp activation. `expected` pins the owner wallet (fee claimer and leftover
|
|
552
|
+
* receiver), the pool creation fee, or the whole spec; without it the spec fields only have to be
|
|
553
|
+
* within the client bounds and the leftover receiver must be the fee claimer.
|
|
517
554
|
*
|
|
518
555
|
* @throws LaunchCoinError `CONFIG_MISMATCH` listing every mismatch.
|
|
519
556
|
*/
|
|
520
|
-
export function assertUserCoinConfig(config) {
|
|
521
|
-
const problems = [
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
problems.push('quote token is not an SPL token');
|
|
526
|
-
if (config.tokenType !== TokenType.SPLToken)
|
|
527
|
-
problems.push('base token type is not SPL token');
|
|
528
|
-
if (config.enableFirstSwapWithMinFee !== 1) {
|
|
529
|
-
problems.push('first swap with minimum fee is disabled (the first buy would pay the anti-sniper fee)');
|
|
530
|
-
}
|
|
557
|
+
export function assertUserCoinConfig(config, expected = {}) {
|
|
558
|
+
const problems = [
|
|
559
|
+
...essentialConfigProblems(config),
|
|
560
|
+
...onchainConfigMismatches(config, 'launchpad', expected),
|
|
561
|
+
];
|
|
531
562
|
if (problems.length > 0) {
|
|
532
563
|
fail('CONFIG_MISMATCH', `config cannot launch a user coin: ${problems.join('; ')}`);
|
|
533
564
|
}
|
|
534
565
|
}
|
|
566
|
+
/**
|
|
567
|
+
* The platform fee wallet must exist and be rent-exempt: a SOL transfer to an account below
|
|
568
|
+
* its rent-exempt minimum fails, and the whole launch with it.
|
|
569
|
+
*
|
|
570
|
+
* @throws LaunchCoinError `PLATFORM_FEE_WALLET_NOT_READY`.
|
|
571
|
+
*/
|
|
572
|
+
async function assertPlatformFeeWalletLive(connection, wallet) {
|
|
573
|
+
const info = await connection.getAccountInfo(wallet, 'confirmed');
|
|
574
|
+
const minimum = BigInt(await connection.getMinimumBalanceForRentExemption(info?.data.length ?? 0));
|
|
575
|
+
if (!info || BigInt(info.lamports) < minimum) {
|
|
576
|
+
fail('PLATFORM_FEE_WALLET_NOT_READY', 'FORGE_PLATFORM_FEE_WALLET must exist and be rent-exempt, otherwise the launch fails on-chain');
|
|
577
|
+
}
|
|
578
|
+
}
|
|
535
579
|
/**
|
|
536
580
|
* Builds the launch transaction of a coin created by a user on the client's launchpad config:
|
|
537
581
|
* pool creation + the user's first buy at the minimum fee (no referral), with a compute unit limit
|
|
538
582
|
* (and a priority fee when given) and a recent blockhash. The user is pool creator, rent payer,
|
|
539
|
-
* fee payer and buyer; the mint is the only other signer. Rent is read from the cluster.
|
|
583
|
+
* fee payer and buyer; the mint is the only other signer. Rent is read from the cluster. With a
|
|
584
|
+
* first buy, the last instruction transfers the platform fee (`platformFeeLamports(firstBuy)`) to
|
|
585
|
+
* `FORGE_PLATFORM_FEE_WALLET` (see `chargePlatformFee`).
|
|
540
586
|
*
|
|
541
|
-
* @throws LaunchCoinError (typed `code`
|
|
587
|
+
* @throws LaunchCoinError (typed `code`; `PLATFORM_FEE_WALLET_NOT_READY` when the fee wallet is
|
|
588
|
+
* not rent-exempt), or ForgeAddressError when `FORGE_PLATFORM_FEE_WALLET` is missing.
|
|
542
589
|
*/
|
|
543
590
|
export async function buildUserCoinLaunchTx(params) {
|
|
544
591
|
const { connection, config, wallet } = params;
|
|
@@ -568,9 +615,22 @@ export async function buildUserCoinLaunchTx(params) {
|
|
|
568
615
|
]);
|
|
569
616
|
const baseMint = mint;
|
|
570
617
|
const pool = deriveDbcPoolAddress(SOL_QUOTE_MINT, baseMint, config);
|
|
618
|
+
// FORGE platform fee on the first buy (rounded up), to FORGE_PLATFORM_FEE_WALLET only.
|
|
619
|
+
const platformFee = params.chargePlatformFee === false || params.firstBuyLamports <= 0n
|
|
620
|
+
? 0n
|
|
621
|
+
: platformFeeLamports(params.firstBuyLamports, PLATFORM_FEE_BPS);
|
|
622
|
+
const platformFeeWallet = platformFee > 0n ? getPlatformFeeWallet(params.env) : null;
|
|
623
|
+
if (platformFeeWallet &&
|
|
624
|
+
(platformFeeWallet.equals(baseMint) ||
|
|
625
|
+
platformFeeWallet.equals(config) ||
|
|
626
|
+
platformFeeWallet.equals(pool))) {
|
|
627
|
+
fail('INVALID_INPUT', 'FORGE_PLATFORM_FEE_WALLET must not be the mint, the config or the pool');
|
|
628
|
+
}
|
|
571
629
|
// 2. On-chain state.
|
|
572
|
-
const { poolConfig, client, program } = await loadLaunchState(connection, { config, pool, mint: baseMint }, assertUserCoinConfig);
|
|
630
|
+
const { poolConfig, client, program } = await loadLaunchState(connection, { config, pool, mint: baseMint }, (decoded) => assertUserCoinConfig(decoded, params.expectedConfig));
|
|
573
631
|
const poolCreationFeeLamports = toBigInt(poolConfig.poolCreationFee);
|
|
632
|
+
if (platformFeeWallet)
|
|
633
|
+
await assertPlatformFeeWalletLive(connection, platformFeeWallet);
|
|
574
634
|
// 3. Recent blockhash: the user signs right away, no durable nonce.
|
|
575
635
|
const latest = await connection.getLatestBlockhash('confirmed');
|
|
576
636
|
// 4. Quote and instructions.
|
|
@@ -591,6 +651,16 @@ export async function buildUserCoinLaunchTx(params) {
|
|
|
591
651
|
nonce: null,
|
|
592
652
|
recentBlockhash: latest.blockhash,
|
|
593
653
|
lastValidBlockHeight: latest.lastValidBlockHeight,
|
|
654
|
+
// Last, like on a swap (docs/METEORA.md, "The platform fee").
|
|
655
|
+
trailingInstructions: platformFeeWallet
|
|
656
|
+
? [
|
|
657
|
+
SystemProgram.transfer({
|
|
658
|
+
fromPubkey: wallet,
|
|
659
|
+
toPubkey: platformFeeWallet,
|
|
660
|
+
lamports: platformFee,
|
|
661
|
+
}),
|
|
662
|
+
]
|
|
663
|
+
: [],
|
|
594
664
|
});
|
|
595
665
|
// 5. Signers: exactly the wallet (fee payer, first) and the mint.
|
|
596
666
|
const signers = checkSigners(transaction, [wallet, baseMint], wallet);
|
|
@@ -611,6 +681,7 @@ export async function buildUserCoinLaunchTx(params) {
|
|
|
611
681
|
firstBuyLamports: params.firstBuyLamports,
|
|
612
682
|
poolCreationFeeLamports,
|
|
613
683
|
rentPayerIsOwner: true,
|
|
684
|
+
platformFeeLamports: platformFee,
|
|
614
685
|
});
|
|
615
686
|
return {
|
|
616
687
|
transaction,
|
|
@@ -626,6 +697,8 @@ export async function buildUserCoinLaunchTx(params) {
|
|
|
626
697
|
expectedTokensOut: quote ? quote.tokensOut : 0n,
|
|
627
698
|
minimumTokensOut: quote ? quote.minimumTokensOut : 0n,
|
|
628
699
|
slippageBps,
|
|
700
|
+
platformFeeLamports: platformFee,
|
|
701
|
+
platformFeeWallet,
|
|
629
702
|
costs,
|
|
630
703
|
recentBlockhash: latest.blockhash,
|
|
631
704
|
lastValidBlockHeight: latest.lastValidBlockHeight,
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { PublicKey, Transaction, type Connection } from '@solana/web3.js';
|
|
2
|
+
import { type PoolState as DammV2PoolState, type PositionState as DammV2PositionState } from '@meteora-ag/cp-amm-sdk';
|
|
3
|
+
import { type AddressEnv } from './addresses.js';
|
|
4
|
+
import { type ClaimOptions } from './claims.js';
|
|
5
|
+
import { type DbcPoolState, type ReadOptions, type TokenAmounts } from './reads.js';
|
|
6
|
+
export type { DammV2PoolState, DammV2PositionState };
|
|
7
|
+
/** DAMM v2 (cp-amm) program id, from the pinned SDK. */
|
|
8
|
+
export declare const DAMM_V2_PROGRAM_ID: PublicKey;
|
|
9
|
+
/** Anchor discriminator of `claim_position_fee` (sha256("global:claim_position_fee")[0..8]). */
|
|
10
|
+
export declare const CLAIM_POSITION_FEE_DISCRIMINATOR: Buffer<ArrayBuffer>;
|
|
11
|
+
/** Account indexes of `claim_position_fee` (cp-amm SDK 1.5.1 IDL). */
|
|
12
|
+
export declare const CLAIM_POSITION_FEE_ACCOUNTS: {
|
|
13
|
+
readonly poolAuthority: 0;
|
|
14
|
+
readonly pool: 1;
|
|
15
|
+
readonly position: 2;
|
|
16
|
+
readonly tokenAAccount: 3;
|
|
17
|
+
readonly tokenBAccount: 4;
|
|
18
|
+
readonly tokenAVault: 5;
|
|
19
|
+
readonly tokenBVault: 6;
|
|
20
|
+
readonly tokenAMint: 7;
|
|
21
|
+
readonly tokenBMint: 8;
|
|
22
|
+
readonly positionNftAccount: 9;
|
|
23
|
+
readonly owner: 10;
|
|
24
|
+
readonly tokenAProgram: 11;
|
|
25
|
+
readonly tokenBProgram: 12;
|
|
26
|
+
readonly eventAuthority: 13;
|
|
27
|
+
readonly program: 14;
|
|
28
|
+
};
|
|
29
|
+
/** `tokenAFlag` / `tokenBFlag` of a DAMM v2 pool: 0 = SPL Token, 1 = Token-2022. */
|
|
30
|
+
export declare function dammV2TokenProgram(flag: number): PublicKey;
|
|
31
|
+
export interface MigratedDammV2Pool {
|
|
32
|
+
/** The DAMM v2 pool the DBC pool migrated to. */
|
|
33
|
+
dammPool: PublicKey;
|
|
34
|
+
/** The DAMM v2 config of the migration fee option (`DAMM_V2_MIGRATION_FEE_ADDRESS`). */
|
|
35
|
+
dammConfig: PublicKey;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Pure: the DAMM v2 pool of a migrated DBC pool, derived like the SDK's `migrateToDammV2`
|
|
39
|
+
* (`deriveDammV2PoolAddress(dammConfig, baseMint, quoteMint)` with the DAMM v2 config the SDK
|
|
40
|
+
* pins for the config's `migrationFeeOption`, `DAMM_V2_MIGRATION_FEE_ADDRESS`). Null when the
|
|
41
|
+
* pool has not migrated yet, migrates to DAMM v1, or has a migration fee option the pinned SDK
|
|
42
|
+
* does not know (FORGE configs use `FixedBps25`, D27).
|
|
43
|
+
*/
|
|
44
|
+
export declare function migratedDammV2Pool(state: Pick<DbcPoolState, 'virtualPool' | 'config'>): MigratedDammV2Pool | null;
|
|
45
|
+
/** A DAMM v2 position: the account, the NFT that owns it and the NFT's token account. */
|
|
46
|
+
export interface DammV2PositionRef {
|
|
47
|
+
position: PublicKey;
|
|
48
|
+
nftMint: PublicKey;
|
|
49
|
+
positionNftAccount: PublicKey;
|
|
50
|
+
}
|
|
51
|
+
export interface DammV2PositionSummary extends DammV2PositionRef {
|
|
52
|
+
/** DAMM v2 pool of the position. */
|
|
53
|
+
dammPool: PublicKey;
|
|
54
|
+
liquidity: {
|
|
55
|
+
unlocked: bigint;
|
|
56
|
+
vested: bigint;
|
|
57
|
+
permanentLocked: bigint;
|
|
58
|
+
};
|
|
59
|
+
/** Fees claimable now: `base` = token A (the coin), `quote` = token B (SOL), raw units. */
|
|
60
|
+
pendingFees: TokenAmounts;
|
|
61
|
+
}
|
|
62
|
+
/** Pure: unclaimed fees of a position (SDK `getUnClaimLpFee`), as bigint. */
|
|
63
|
+
export declare function positionPendingFees(poolState: DammV2PoolState, positionState: DammV2PositionState): TokenAmounts;
|
|
64
|
+
/** Pure: summary of one position of `poolState`. */
|
|
65
|
+
export declare function summarizePosition(poolState: DammV2PoolState, ref: DammV2PositionRef, positionState: DammV2PositionState): DammV2PositionSummary;
|
|
66
|
+
/** Pure: sum of the pending fees of `positions`. */
|
|
67
|
+
export declare function sumPendingFees(positions: readonly DammV2PositionSummary[]): TokenAmounts;
|
|
68
|
+
/** Fetches a DAMM v2 pool. @throws ClaimError `damm_pool_not_found` when the account is missing. */
|
|
69
|
+
export declare function getDammV2PoolState(connection: Connection, dammPool: PublicKey, options?: ReadOptions): Promise<DammV2PoolState>;
|
|
70
|
+
/**
|
|
71
|
+
* The migrated DAMM v2 pool of a DBC pool and the creator's positions on it, with their fees.
|
|
72
|
+
* Null when the pool has not migrated (see `migratedDammV2Pool`).
|
|
73
|
+
*/
|
|
74
|
+
export interface CreatorDammV2Positions {
|
|
75
|
+
/** The DBC pool. */
|
|
76
|
+
pool: PublicKey;
|
|
77
|
+
dammPool: PublicKey;
|
|
78
|
+
dammConfig: PublicKey;
|
|
79
|
+
creator: PublicKey;
|
|
80
|
+
/** Positions whose NFT the creator holds, sorted by address. */
|
|
81
|
+
positions: DammV2PositionSummary[];
|
|
82
|
+
/** Sum of the positions' pending fees. */
|
|
83
|
+
claimable: TokenAmounts;
|
|
84
|
+
}
|
|
85
|
+
export interface FindCreatorPositionsParams {
|
|
86
|
+
/** The DBC pool, or its already-read state. */
|
|
87
|
+
pool: PublicKey | DbcPoolState;
|
|
88
|
+
/** The pool creator (must match the pool state). */
|
|
89
|
+
creator: PublicKey;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Finds the creator's positions on the migrated DAMM v2 pool of a DBC pool (SDK
|
|
93
|
+
* `getUserPositionByPool`: the Token-2022 accounts of the creator holding one NFT, then the
|
|
94
|
+
* position of each), checked again (pool, NFT held by the creator) and sorted by address.
|
|
95
|
+
* Returns null when the pool has not migrated to DAMM v2.
|
|
96
|
+
* @throws ClaimError `not_pool_creator`, `damm_pool_not_found`, `damm_pool_mismatch`.
|
|
97
|
+
* @throws DbcReadError when the DBC pool or its config does not exist.
|
|
98
|
+
*/
|
|
99
|
+
export declare function findCreatorDammV2Positions(connection: Connection, params: FindCreatorPositionsParams, options?: ReadOptions): Promise<CreatorDammV2Positions | null>;
|
|
100
|
+
/** Lamport costs of a position fee claim, as bigint. */
|
|
101
|
+
export interface PositionClaimCosts {
|
|
102
|
+
/** Signature fees (signers x 5000 lamports; no priority fee), paid by the payer. */
|
|
103
|
+
networkFeeLamports: bigint;
|
|
104
|
+
/**
|
|
105
|
+
* Rent of the receiver's coin account, created on the first claim of a pool (paid by the
|
|
106
|
+
* payer, kept in that account, which the receiver owns). 0 when it already exists.
|
|
107
|
+
*/
|
|
108
|
+
receiverTokenAccountRentLamports: bigint;
|
|
109
|
+
/**
|
|
110
|
+
* Rent of the temporary WSOL account the payer funds: closed to the receiver with the fees, it
|
|
111
|
+
* reaches the receiver as lamports (not refunded to the payer). 0 when the account exists.
|
|
112
|
+
*/
|
|
113
|
+
unwrapAccountRentLamports: bigint;
|
|
114
|
+
/** Everything the payer's balance decreases by: the three amounts above. */
|
|
115
|
+
payerTotalLamports: bigint;
|
|
116
|
+
/** Balance the payer needs before signing (same as the total: nothing is refunded). */
|
|
117
|
+
payerRequiredBalanceLamports: bigint;
|
|
118
|
+
}
|
|
119
|
+
export interface PositionClaimSummary {
|
|
120
|
+
kind: 'position';
|
|
121
|
+
/** The DBC pool. */
|
|
122
|
+
pool: PublicKey;
|
|
123
|
+
dammPool: PublicKey;
|
|
124
|
+
dammConfig: PublicKey;
|
|
125
|
+
baseMint: PublicKey;
|
|
126
|
+
/** The creator: owner of the positions, signs the claim. */
|
|
127
|
+
claimer: PublicKey;
|
|
128
|
+
receiver: PublicKey;
|
|
129
|
+
/** Fee payer of the transaction. */
|
|
130
|
+
payer: PublicKey;
|
|
131
|
+
/** The positions claimed (sorted by address), with their fees when the claim was built. */
|
|
132
|
+
positions: DammV2PositionSummary[];
|
|
133
|
+
/** Sum of the positions' pending fees when the claim was built (a lower bound at execution). */
|
|
134
|
+
claimable: TokenAmounts;
|
|
135
|
+
/**
|
|
136
|
+
* SOL the receiver gets from the transaction, lamports: the claimable SOL fees plus the
|
|
137
|
+
* lamports of the temporary WSOL account closed to it (its rent, and the WSOL it already held).
|
|
138
|
+
* A lower bound: the claim is uncapped and fees accrue until it executes. Never exact
|
|
139
|
+
* (`quoteIsExact` is always false).
|
|
140
|
+
*/
|
|
141
|
+
receiverQuoteLamports: bigint;
|
|
142
|
+
quoteIsExact: false;
|
|
143
|
+
/**
|
|
144
|
+
* WSOL the creator's temporary account already held when the transaction was built (anyone
|
|
145
|
+
* can send some to it): it reaches the receiver with the close, counted in
|
|
146
|
+
* `receiverQuoteLamports`. Zero when the account is empty or new.
|
|
147
|
+
*/
|
|
148
|
+
existingWsolLamports: bigint;
|
|
149
|
+
/** Zero costs when there is no transaction. */
|
|
150
|
+
costs: PositionClaimCosts;
|
|
151
|
+
/** `receiverQuoteLamports - costs.payerTotalLamports`. Coin fees are not valued. */
|
|
152
|
+
netLamports: bigint;
|
|
153
|
+
}
|
|
154
|
+
export type PositionClaimSkipReason = 'no_position' | 'nothing_to_claim' | 'not_worthwhile';
|
|
155
|
+
export interface PositionClaimTxResult {
|
|
156
|
+
/** Unsigned claim transaction, or `null` when skipped (see `skipReason`). */
|
|
157
|
+
transaction: Transaction | null;
|
|
158
|
+
lastValidBlockHeight: number | null;
|
|
159
|
+
skipReason: PositionClaimSkipReason | null;
|
|
160
|
+
summary: PositionClaimSummary;
|
|
161
|
+
}
|
|
162
|
+
export interface CreatorPositionClaimParams {
|
|
163
|
+
/** The DBC pool (the DAMM v2 pool is derived from it). */
|
|
164
|
+
pool: PublicKey;
|
|
165
|
+
/** Pool creator and owner of the positions; signs the claim. */
|
|
166
|
+
creator: PublicKey;
|
|
167
|
+
/** Where the fees go. */
|
|
168
|
+
receiver: PublicKey;
|
|
169
|
+
/** When set, `receiver` must equal it (`receiver_mismatch` otherwise). */
|
|
170
|
+
expectedReceiver?: PublicKey;
|
|
171
|
+
/** Fee payer; defaults to the creator. */
|
|
172
|
+
payer?: PublicKey;
|
|
173
|
+
/**
|
|
174
|
+
* Positions to claim (addresses). Each must belong to the migrated pool and be held by the
|
|
175
|
+
* creator. Default: every position of the creator on that pool.
|
|
176
|
+
*/
|
|
177
|
+
positions?: readonly PublicKey[];
|
|
178
|
+
}
|
|
179
|
+
/** True when the claim collects more SOL than it costs, by more than `minNetLamports`. */
|
|
180
|
+
export declare function isPositionClaimWorthwhile(summary: PositionClaimSummary, minNetLamports?: bigint): boolean;
|
|
181
|
+
/**
|
|
182
|
+
* Builds the claim of the creator's DAMM v2 position fees of a migrated DBC pool to `receiver`
|
|
183
|
+
* (see the module comment for the transaction).
|
|
184
|
+
* @throws ClaimError when `creator` is not the pool creator, the pool is not SOL-quoted or not
|
|
185
|
+
* migrated to DAMM v2 (`not_migrated`), the receiver is invalid or differs from
|
|
186
|
+
* `expectedReceiver`, a position is missing, on another pool or not held by the creator, or
|
|
187
|
+
* the creator's WSOL account holds WSOL while the receiver is someone else.
|
|
188
|
+
* @throws DbcReadError when the DBC pool or its config does not exist.
|
|
189
|
+
*/
|
|
190
|
+
export declare function buildCreatorPositionFeeClaimTx(connection: Connection, params: CreatorPositionClaimParams, options?: ClaimOptions): Promise<PositionClaimTxResult>;
|
|
191
|
+
export interface ForgeCreatorPositionClaimParams {
|
|
192
|
+
pool: PublicKey;
|
|
193
|
+
/** FORGE creator wallet of the launchpad (the pool creator); signs the claim. */
|
|
194
|
+
creator: PublicKey;
|
|
195
|
+
/** Fee payer; defaults to the creator. */
|
|
196
|
+
payer?: PublicKey;
|
|
197
|
+
positions?: readonly PublicKey[];
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* The position fee claim of a FORGE creator wallet: the receiver is always the FORGE multisig
|
|
201
|
+
* vault (`FORGE_MULTISIG_VAULT`, SECURITY.md §5), read from `env` (defaults to `process.env`).
|
|
202
|
+
* @throws ForgeAddressError when `FORGE_MULTISIG_VAULT` is missing or invalid; as
|
|
203
|
+
* `buildCreatorPositionFeeClaimTx` otherwise.
|
|
204
|
+
*/
|
|
205
|
+
export declare function buildForgeCreatorPositionFeeClaimTx(connection: Connection, params: ForgeCreatorPositionClaimParams, options?: ClaimOptions & {
|
|
206
|
+
env?: AddressEnv;
|
|
207
|
+
}): Promise<PositionClaimTxResult>;
|