@gabox-labs/sdk 0.6.0 → 0.7.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 +84 -0
- package/README.md +113 -34
- package/dist/gabox-DGTCh34U.js +2338 -0
- package/dist/gabox-DGTCh34U.js.map +1 -0
- package/dist/generated/index.d.ts +89 -36
- package/dist/generated/index.js +2 -2289
- package/dist/generated/index.js.map +1 -1
- package/dist/{index-BDfGvmgF.d.ts → index-C4at2cZ_.d.ts} +304 -54
- package/dist/index.d.ts +333 -34
- package/dist/index.js +884 -506
- package/dist/index.js.map +1 -1
- package/dist/raydium/index.d.ts +2 -2
- package/dist/raydium/index.js +2 -2
- package/dist/{raydium-B-l9V3O-.js → raydium-CU-tZzIk.js} +869 -191
- package/dist/raydium-CU-tZzIk.js.map +1 -0
- package/llms.txt +4 -2
- package/package.json +1 -1
- package/skills/gabox-sdk/SKILL.md +27 -14
- package/skills/gabox-sdk/references/api.md +78 -26
- package/dist/raydium-B-l9V3O-.js.map +0 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
|
|
2
|
-
import {
|
|
2
|
+
import { Dt as POOL_DISCRIMINATOR, Et as getWalletActivitySize, Jt as getDrawSize, Lt as getPoolSize, Ot as decodePool, Rt as DRAW_DISCRIMINATOR, _t as decodeWalletActivity, ft as findPoolPda, ht as findActivityPda, mt as findDrawPda, pt as findIdentityPda, t as GABOX_PROGRAM_ADDRESS, zt as decodeDraw } from "./gabox-DGTCh34U.js";
|
|
3
|
+
import { AccountRole, Endian, addEncoderSizePrefix, appendTransactionMessageInstructions, compileTransaction, compressTransactionMessageUsingAddressLookupTables, createTransactionMessage, fetchEncodedAccount, fixDecoderSize, getAddressDecoder, getAddressEncoder, getBase58Decoder, getBase64Encoder, getBooleanDecoder, getBytesDecoder, getBytesEncoder, getProgramDerivedAddress, getStructDecoder, getStructEncoder, getTransactionEncoder, getU16Decoder, getU16Encoder, getU32Encoder, getU64Decoder, getU64Encoder, getU8Decoder, getU8Encoder, getUtf8Encoder, pipe, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash } from "@solana/kit";
|
|
3
4
|
import { getCloseAccountInstruction, getCreateAssociatedTokenIdempotentInstruction } from "@solana-program/token";
|
|
4
5
|
//#region src/raydium/abi.ts
|
|
5
6
|
const RAYDIUM_MAINNET_IDS = {
|
|
6
7
|
launchlab: "LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj",
|
|
7
8
|
launchlabAuthority: "WLHv2UAZm6z4KyaaELi5pjdbJh6RESMva1Rnn8pJVVh",
|
|
8
9
|
launchlabEventAuthority: "2DPAtwB8L12vrMRExbLuyGnC7n2J5LNoZQSejeQGpwkr",
|
|
9
|
-
solGlobalConfig: "6s1xP3hpbAfFoNtUNF8mfHsjr2Bd97JxFJRWLbL6aHuX",
|
|
10
10
|
gaboxPlatform: "8tXUG97CEpSKTNXdGtanYyC33RWmTTuSin4VdaWwNj8q",
|
|
11
11
|
cpmm: "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C",
|
|
12
12
|
cpmmAuthority: "GpMZbSM2GgvTKHJirzeGfMFoaZ8UR2X7F4v8vHTvxFbL",
|
|
@@ -16,13 +16,15 @@ const RAYDIUM_DEVNET_IDS = {
|
|
|
16
16
|
launchlab: "DRay6fNdQ5J82H7xV6uq2aV3mNrUZ1J4PgSKsWgptcm6",
|
|
17
17
|
launchlabAuthority: "5xqNaZXX5eUi4p5HU4oz9i5QnwRNT2y6oN7yyn4qENeq",
|
|
18
18
|
launchlabEventAuthority: "4uAB7seenFJKPUXqYewAdfra2u6baBgjiXU8x1SC7Ycz",
|
|
19
|
-
solGlobalConfig: "7ZR4zD7PYfY2XxoG1Gxcy2EgEeGYrpxrwzPuwdUBssEt",
|
|
20
19
|
gaboxPlatform: "DdEeCPXbCAzHE2PZSoR3RZng4WA4bSztrezQznrJ4ooB",
|
|
21
20
|
cpmm: "DRaycpLY18LhpbydsBWbVJtxpNv9oXPgjRSfpF2bWpYb",
|
|
22
21
|
cpmmAuthority: "CXniRufdq5xL8t8jZAPxsPZDpuudwuJSPWnbcD5Y5Nxq",
|
|
23
22
|
launchQuoteRaise: 3000000000n
|
|
24
23
|
};
|
|
25
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* Wrapped SOL: the default quote, and the one every price in SOL is measured in. Gabox accepts any
|
|
26
|
+
* quote Raydium enabled on LaunchLab, so this is not the only one.
|
|
27
|
+
*/
|
|
26
28
|
const WSOL_MINT = "So11111111111111111111111111111111111111112";
|
|
27
29
|
/** Metaplex Token Metadata, which LaunchLab's create instruction writes to. */
|
|
28
30
|
const METAPLEX_PROGRAM_ADDRESS = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s";
|
|
@@ -35,8 +37,13 @@ const PLATFORM_ADMIN = "5WcPTEQ59UqpQzjZUPbU8QRGCbj7NeQNLDa7DbsLkLKT";
|
|
|
35
37
|
const LAUNCH_SUPPLY = 1000000000000000n;
|
|
36
38
|
/** The part of the supply the LaunchLab curve sells: 793,100,000 coins. */
|
|
37
39
|
const LAUNCH_TOTAL_BASE_SELL = 793100000000000n;
|
|
38
|
-
/** Classic SPL Token.
|
|
40
|
+
/** Classic SPL Token. The base coin is always under it, on both venues. */
|
|
39
41
|
const TOKEN_PROGRAM_ADDRESS = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
|
|
42
|
+
/**
|
|
43
|
+
* Token-2022. A quote mint may be under it, inside the bounded profile the program's
|
|
44
|
+
* `tokens::validate_quote_mint` accepts. The base coin never is.
|
|
45
|
+
*/
|
|
46
|
+
const TOKEN_2022_PROGRAM_ADDRESS = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb";
|
|
40
47
|
const ASSOCIATED_TOKEN_PROGRAM_ADDRESS = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL";
|
|
41
48
|
const SYSTEM_PROGRAM_ADDRESS = "11111111111111111111111111111111";
|
|
42
49
|
/** The rent sysvar. LaunchLab's create instruction still takes it. */
|
|
@@ -862,8 +869,8 @@ const CPMM_COLLECT_CREATOR_FEE = {
|
|
|
862
869
|
* The Raydium addresses and launch numbers Gabox pins, per cluster.
|
|
863
870
|
*
|
|
864
871
|
* Mainnet and devnet run different Raydium deployments. Every program id and every PDA differs, and
|
|
865
|
-
* so does the
|
|
866
|
-
*
|
|
872
|
+
* so does the raise a WSOL-quoted curve must reach. So nothing here is a global: a caller passes the
|
|
873
|
+
* cluster, which comes from `createClient({ cluster })`.
|
|
867
874
|
*
|
|
868
875
|
* None of these strings is typed in this file. `scripts/codegen.mjs` reads them out of the Rust
|
|
869
876
|
* program's `programs/gabox/src/venue/ids.rs` and writes `abi.ts`. The Rust file is the source of
|
|
@@ -937,7 +944,7 @@ const SHARE_FEE_RATE = 0n;
|
|
|
937
944
|
const CONSTANT_CURVE_TAG = 0;
|
|
938
945
|
/** `migrate_type` 1: the coin graduates into a CPMM pool, not into an AMM pool. */
|
|
939
946
|
const MIGRATE_TO_CPMM = 1;
|
|
940
|
-
/** `AmmCreatorFeeOn::QuoteToken`, so the CPMM creator fee is paid in
|
|
947
|
+
/** `AmmCreatorFeeOn::QuoteToken`, so the CPMM creator fee is paid in the pool's quote asset. */
|
|
941
948
|
const CREATOR_FEE_ON_QUOTE = 0;
|
|
942
949
|
/** LaunchLab pool `status`: still selling on the curve. */
|
|
943
950
|
const LAUNCHLAB_STATUS_FUND = 0;
|
|
@@ -966,6 +973,307 @@ function compareAddresses(a, b) {
|
|
|
966
973
|
return 0;
|
|
967
974
|
}
|
|
968
975
|
//#endregion
|
|
976
|
+
//#region src/ids.ts
|
|
977
|
+
/** `declare_id!` in `programs/gabox/src/lib.rs`. */
|
|
978
|
+
const GABOX_PROGRAM_ID = GABOX_PROGRAM_ADDRESS;
|
|
979
|
+
/** MagicBlock's ephemeral VRF program. `vrf.rs` pins it and refuses any other. */
|
|
980
|
+
const VRF_PROGRAM_ADDRESS = "Vrf1RNUjXmQGjmQrQLvJHs9SNkvDJEsRVFPkfSQUwGz";
|
|
981
|
+
/**
|
|
982
|
+
* MagicBlock's default oracle queue. The program pins this one address, so a pool creator cannot
|
|
983
|
+
* point a draw at an oracle they control.
|
|
984
|
+
*/
|
|
985
|
+
const VRF_DEFAULT_QUEUE = "Cuj97ggrhhidhbu39TijNVqE74xvKJ69gDervRUXAxGh";
|
|
986
|
+
/** The seed of both identity PDAs. See `pdas.ts` — there are two, under different programs. */
|
|
987
|
+
const IDENTITY_SEED = new Uint8Array([
|
|
988
|
+
105,
|
|
989
|
+
100,
|
|
990
|
+
101,
|
|
991
|
+
110,
|
|
992
|
+
116,
|
|
993
|
+
105,
|
|
994
|
+
116,
|
|
995
|
+
121
|
|
996
|
+
]);
|
|
997
|
+
const SLOT_HASHES_SYSVAR = "SysvarS1otHashes111111111111111111111111111";
|
|
998
|
+
const INSTRUCTIONS_SYSVAR = "Sysvar1nstructions1111111111111111111111111";
|
|
999
|
+
/** `constants.rs`. A retry may not run sooner than this after the last attempt. */
|
|
1000
|
+
const RETRY_SLOTS = 300n;
|
|
1001
|
+
/** `constants.rs`. After this many slots from the purchase, anyone may expire the draw. */
|
|
1002
|
+
const TIMEOUT_SLOTS = 216000n;
|
|
1003
|
+
/** `constants.rs`. Three requests in total, counting the one `buy_pack` makes. */
|
|
1004
|
+
const MAX_ATTEMPTS = 3;
|
|
1005
|
+
/**
|
|
1006
|
+
* `constants.rs`. Tokens in one pack, in base units: 1,000,000 tokens at the fixed 6 decimals, or
|
|
1007
|
+
* 0.1% of the 1,000,000,000 supply. Every pool sells packs of this size. The venue decides what a
|
|
1008
|
+
* pack costs, so the pack price follows the coin. Read `pool.packTokens` rather than this when a
|
|
1009
|
+
* pool is at hand: a later program version may change the constant.
|
|
1010
|
+
*/
|
|
1011
|
+
const PACK_TOKENS = 1000000n * 1000000n;
|
|
1012
|
+
//#endregion
|
|
1013
|
+
//#region src/math.ts
|
|
1014
|
+
/**
|
|
1015
|
+
* A bigint port of `programs/gabox/src/math.rs`.
|
|
1016
|
+
*
|
|
1017
|
+
* The point is that a client can show a buyer the exact prize table the program will freeze into
|
|
1018
|
+
* their `Draw`, before they pay. Every rounding step here matches the Rust, including the direction
|
|
1019
|
+
* of each division. `test/math.test.ts` runs the same vectors as `programs/gabox/tests/math.rs`.
|
|
1020
|
+
*
|
|
1021
|
+
* All amounts are `bigint`, in the mint's smallest unit. `multiplierBps` and `tickets` are numbers
|
|
1022
|
+
* because both are `u32` in the program and both stay small.
|
|
1023
|
+
*/
|
|
1024
|
+
/** Basis points. A multiplier of 10_000 pays back exactly one pack. */
|
|
1025
|
+
const BPS = 10000n;
|
|
1026
|
+
/**
|
|
1027
|
+
* `constants::MIN_SEED_MULTIPLIER_BPS`. The mandatory seed makes a 3x top prize payable on the
|
|
1028
|
+
* first pack, or the full top prize when the table's top tier is below 3x. A creator can add more
|
|
1029
|
+
* seed on top through `extraSeedTokens`.
|
|
1030
|
+
*/
|
|
1031
|
+
const MIN_SEED_MULTIPLIER_BPS = 3e4;
|
|
1032
|
+
/**
|
|
1033
|
+
* `constants::MAX_MULTIPLIER_BPS`. A table's top tier can be at most 20x. Seed beyond what a 20x
|
|
1034
|
+
* prize needs stays in the vault as backup for the draws after a top-tier hit.
|
|
1035
|
+
*/
|
|
1036
|
+
const MAX_MULTIPLIER_BPS = 2e5;
|
|
1037
|
+
/** Ticket counts must sum to this. A uniform 16-bit word then maps with no modulo bias. */
|
|
1038
|
+
const TICKETS = 65536;
|
|
1039
|
+
/** The prize table has exactly this many slots. Unused slots are all-zero. */
|
|
1040
|
+
const TIERS = 8;
|
|
1041
|
+
/** Thrown by every function here. `code` matches a `GaboxError` variant name. */
|
|
1042
|
+
var GaboxMathError = class extends Error {
|
|
1043
|
+
code;
|
|
1044
|
+
constructor(code, message) {
|
|
1045
|
+
super(`${code}: ${message}`);
|
|
1046
|
+
this.name = "GaboxMathError";
|
|
1047
|
+
this.code = code;
|
|
1048
|
+
}
|
|
1049
|
+
};
|
|
1050
|
+
const U64_MAX = (1n << 64n) - 1n;
|
|
1051
|
+
const U32_MAX = 4294967295;
|
|
1052
|
+
/**
|
|
1053
|
+
* The default prize table. The program does not enforce this table: it accepts any table that
|
|
1054
|
+
* passes `validateTiers`. This is only the table the Gabox app creates its pools with, and the
|
|
1055
|
+
* starting point for a client that has no reason to pick another one.
|
|
1056
|
+
*
|
|
1057
|
+
* Common 75% at 0.52x, Rare 20% at 1.2x, Epic 4% at 3x, Mythic 1% at 20x. Expected payout is
|
|
1058
|
+
* 0.9499x of a pack, so the seed is 19 packs.
|
|
1059
|
+
*/
|
|
1060
|
+
const DEFAULT_TIERS = Object.freeze([
|
|
1061
|
+
Object.freeze({
|
|
1062
|
+
multiplierBps: 5201,
|
|
1063
|
+
tickets: 49153
|
|
1064
|
+
}),
|
|
1065
|
+
Object.freeze({
|
|
1066
|
+
multiplierBps: 12e3,
|
|
1067
|
+
tickets: 13107
|
|
1068
|
+
}),
|
|
1069
|
+
Object.freeze({
|
|
1070
|
+
multiplierBps: 3e4,
|
|
1071
|
+
tickets: 2621
|
|
1072
|
+
}),
|
|
1073
|
+
Object.freeze({
|
|
1074
|
+
multiplierBps: 2e5,
|
|
1075
|
+
tickets: 655
|
|
1076
|
+
}),
|
|
1077
|
+
Object.freeze({
|
|
1078
|
+
multiplierBps: 0,
|
|
1079
|
+
tickets: 0
|
|
1080
|
+
}),
|
|
1081
|
+
Object.freeze({
|
|
1082
|
+
multiplierBps: 0,
|
|
1083
|
+
tickets: 0
|
|
1084
|
+
}),
|
|
1085
|
+
Object.freeze({
|
|
1086
|
+
multiplierBps: 0,
|
|
1087
|
+
tickets: 0
|
|
1088
|
+
}),
|
|
1089
|
+
Object.freeze({
|
|
1090
|
+
multiplierBps: 0,
|
|
1091
|
+
tickets: 0
|
|
1092
|
+
})
|
|
1093
|
+
]);
|
|
1094
|
+
function checkedU64(value, what) {
|
|
1095
|
+
if (value < 0n || value > U64_MAX) throw new GaboxMathError("Arithmetic", `${what} does not fit in u64`);
|
|
1096
|
+
return value;
|
|
1097
|
+
}
|
|
1098
|
+
/** Tier fields encode as program `u32`s. Reject JavaScript-only values before `BigInt` or codecs. */
|
|
1099
|
+
function checkedU32(value, what) {
|
|
1100
|
+
if (!Number.isInteger(value) || value < 0 || value > U32_MAX) throw new GaboxMathError("InvalidDistribution", `${what} must be an integer from 0 to ${U32_MAX}`);
|
|
1101
|
+
return value;
|
|
1102
|
+
}
|
|
1103
|
+
/** `math::tokens`. Floor division, and an overflow past u64 is an error, not a wrap. */
|
|
1104
|
+
function tierAmount(base, multiplierBps) {
|
|
1105
|
+
return checkedU64(base * BigInt(checkedU32(multiplierBps, "multiplierBps")) / BPS, "tier amount");
|
|
1106
|
+
}
|
|
1107
|
+
/**
|
|
1108
|
+
* `math::validate`. Checks the table alone, with no base.
|
|
1109
|
+
*
|
|
1110
|
+
* Four rules, and each one closes a way to sell a bad ticket:
|
|
1111
|
+
* - ticket counts sum to exactly 65,536, so the 16-bit draw is uniform;
|
|
1112
|
+
* - an unused row is all-zero, so a hidden multiplier cannot ride along;
|
|
1113
|
+
* - a ticketed tier's multiplier is from 1 to `MAX_MULTIPLIER_BPS` (20x);
|
|
1114
|
+
* - the expected multiplier over all tickets is at most 1x, so the table cannot promise more
|
|
1115
|
+
* tokens than a pack buys. This bounds tokens, not cash value.
|
|
1116
|
+
*/
|
|
1117
|
+
function validateTiers(tiers) {
|
|
1118
|
+
if (tiers.length !== 8) throw new GaboxMathError("InvalidDistribution", `expected 8 tiers, got ${tiers.length}`);
|
|
1119
|
+
let count = 0n;
|
|
1120
|
+
let expected = 0n;
|
|
1121
|
+
for (const [index, tier] of tiers.entries()) {
|
|
1122
|
+
checkedU32(tier.tickets, `tier ${index} tickets`);
|
|
1123
|
+
checkedU32(tier.multiplierBps, `tier ${index} multiplierBps`);
|
|
1124
|
+
if (tier.tickets === 0) {
|
|
1125
|
+
if (tier.multiplierBps !== 0) throw new GaboxMathError("InvalidDistribution", "a tier with no tickets must have no multiplier");
|
|
1126
|
+
continue;
|
|
1127
|
+
}
|
|
1128
|
+
if (tier.multiplierBps <= 0) throw new GaboxMathError("InvalidDistribution", "a ticketed tier must pay something; it would sell a ticket that can only win zero");
|
|
1129
|
+
if (tier.multiplierBps > 2e5) throw new GaboxMathError("InvalidDistribution", `tier ${index} multiplierBps exceeds the ${MAX_MULTIPLIER_BPS} maximum (20x)`);
|
|
1130
|
+
count += BigInt(tier.tickets);
|
|
1131
|
+
expected += BigInt(tier.multiplierBps) * BigInt(tier.tickets);
|
|
1132
|
+
}
|
|
1133
|
+
if (count !== BigInt(65536)) throw new GaboxMathError("InvalidDistribution", `tickets must sum to ${TICKETS}, they sum to ${count}`);
|
|
1134
|
+
if (expected > 10000n * BigInt(65536)) throw new GaboxMathError("UnfundedExpectation", "the expected token award exceeds the tokens a pack buys");
|
|
1135
|
+
}
|
|
1136
|
+
/**
|
|
1137
|
+
* `math::validate_pack`. Every ticketed tier must pay at least one token for a pack of this size.
|
|
1138
|
+
*
|
|
1139
|
+
* The program checks this once at creation. At `PACK_TOKENS` no sane table fails it; it exists so
|
|
1140
|
+
* a table cannot sell a ticket that can only win zero.
|
|
1141
|
+
*/
|
|
1142
|
+
function validatePack(packTokens, tiers) {
|
|
1143
|
+
if (packTokens <= 0n) throw new GaboxMathError("ZeroAmount", "packTokens must be positive");
|
|
1144
|
+
checkedU64(packTokens, "pack tokens");
|
|
1145
|
+
validateTiers(tiers);
|
|
1146
|
+
for (const [i, tier] of tiers.entries()) {
|
|
1147
|
+
if (tier.tickets === 0) continue;
|
|
1148
|
+
if (tierAmount(packTokens, tier.multiplierBps) === 0n) throw new GaboxMathError("PackTooSmall", `tier ${i} rounds to zero tokens at this pack size`);
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
/**
|
|
1152
|
+
* `math::seed_tokens`. The mandatory seed a table needs, in tokens.
|
|
1153
|
+
*
|
|
1154
|
+
* The mandatory seed makes a 3x top prize payable on the first pack, or the full top prize when
|
|
1155
|
+
* the table's top tier is below 3x. A jackpot above 3x still shows the full table once later
|
|
1156
|
+
* packs grow the free vault; the mandatory seed alone does not have to fund it. The pack itself
|
|
1157
|
+
* brings `packTokens` into the vault, so the vault has to hold the rest beforehand:
|
|
1158
|
+
*
|
|
1159
|
+
* seedTokens = min(uncappedMaximum(packTokens, tiers), tierAmount(packTokens, MIN_SEED_MULTIPLIER_BPS)) - packTokens
|
|
1160
|
+
*
|
|
1161
|
+
* A 20x or a 3x top tier on a 1M-token pack both need a 2M-token seed, since the mandatory seed
|
|
1162
|
+
* stops at the 3x minimum. A 2x top tier needs a 1M-token seed, already below the minimum. A
|
|
1163
|
+
* table whose top tier pays exactly one pack needs no seed. A top tier below one pack is refused:
|
|
1164
|
+
* every ticket would lose. `createMachine` lets a creator add more seed on top of this mandatory
|
|
1165
|
+
* amount through `extraSeedTokens`, for example to fund a top tier above 3x from the first pack.
|
|
1166
|
+
*
|
|
1167
|
+
* Pool initialization computes this number itself and buys exactly that many tokens on the curve.
|
|
1168
|
+
* The creator only signs a maximum SOL cost.
|
|
1169
|
+
*/
|
|
1170
|
+
function seedTokens(packTokens, tiers) {
|
|
1171
|
+
validateTiers(tiers);
|
|
1172
|
+
const largest = uncappedMaximum(packTokens, tiers);
|
|
1173
|
+
if (largest < packTokens) throw new GaboxMathError("JackpotBelowOnePack", "the largest tier must pay at least one pack");
|
|
1174
|
+
const minimum = tierAmount(packTokens, MIN_SEED_MULTIPLIER_BPS);
|
|
1175
|
+
return (largest < minimum ? largest : minimum) - packTokens;
|
|
1176
|
+
}
|
|
1177
|
+
/**
|
|
1178
|
+
* `math::uncapped_maximum`. The largest tier's award for this base, before any inventory cap.
|
|
1179
|
+
*
|
|
1180
|
+
* At `packTokens` this is the jackpot in tokens. `seedTokens` is this minus one pack.
|
|
1181
|
+
*/
|
|
1182
|
+
function uncappedMaximum(base, tiers) {
|
|
1183
|
+
validateTiers(tiers);
|
|
1184
|
+
let largest = 0n;
|
|
1185
|
+
for (const tier of tiers) {
|
|
1186
|
+
if (tier.tickets === 0) continue;
|
|
1187
|
+
const amount = tierAmount(base, tier.multiplierBps);
|
|
1188
|
+
if (amount > largest) largest = amount;
|
|
1189
|
+
}
|
|
1190
|
+
return largest;
|
|
1191
|
+
}
|
|
1192
|
+
/**
|
|
1193
|
+
* `math::quote`. The offer a pack of `base` tokens would freeze right now. `base` is always
|
|
1194
|
+
* `pool.packTokens`; the parameter stays general so the vectors can use small numbers.
|
|
1195
|
+
*
|
|
1196
|
+
* `inventory` is the vault's token balance and `reserved` is `pool.reserved`. The difference is
|
|
1197
|
+
* free inventory. This pack's own `base` is added to it, because the purchase and the offer are
|
|
1198
|
+
* one transaction — the tokens are in the vault before the draw is written.
|
|
1199
|
+
*
|
|
1200
|
+
* Every amount is capped at what is actually available. A tier that rounds to zero tokens is an
|
|
1201
|
+
* error: the pool must not sell a ticket that can only win nothing.
|
|
1202
|
+
*/
|
|
1203
|
+
function quote(base, tiers, inventory, reserved) {
|
|
1204
|
+
validateTiers(tiers);
|
|
1205
|
+
if (inventory < reserved) throw new GaboxMathError("InsolventInventory", "the vault holds less than the pool has already reserved");
|
|
1206
|
+
const available = checkedU64(inventory - reserved + base, "available inventory");
|
|
1207
|
+
const prizes = Array.from({ length: 8 }, () => ({
|
|
1208
|
+
amount: 0n,
|
|
1209
|
+
tickets: 0
|
|
1210
|
+
}));
|
|
1211
|
+
let maximum = 0n;
|
|
1212
|
+
let minimum = U64_MAX;
|
|
1213
|
+
for (const [i, tier] of tiers.entries()) {
|
|
1214
|
+
if (tier.tickets === 0) continue;
|
|
1215
|
+
const uncapped = tierAmount(base, tier.multiplierBps);
|
|
1216
|
+
if (uncapped === 0n) throw new GaboxMathError("PackTooSmall", `tier ${i} rounds to zero tokens at this pack size`);
|
|
1217
|
+
const amount = uncapped < available ? uncapped : available;
|
|
1218
|
+
prizes[i] = {
|
|
1219
|
+
amount,
|
|
1220
|
+
tickets: tier.tickets
|
|
1221
|
+
};
|
|
1222
|
+
if (amount > maximum) maximum = amount;
|
|
1223
|
+
if (amount < minimum) minimum = amount;
|
|
1224
|
+
}
|
|
1225
|
+
return {
|
|
1226
|
+
prizes,
|
|
1227
|
+
maximum,
|
|
1228
|
+
minimum
|
|
1229
|
+
};
|
|
1230
|
+
}
|
|
1231
|
+
/**
|
|
1232
|
+
* `math::choose`. Which prize a 16-bit ticket wins.
|
|
1233
|
+
*
|
|
1234
|
+
* The rows are consecutive ranges in table order, so this is a running total and a comparison.
|
|
1235
|
+
* A ticket past the last row returns `0`, which cannot happen for a validated table.
|
|
1236
|
+
*/
|
|
1237
|
+
function choose(prizes, ticket) {
|
|
1238
|
+
let end = 0;
|
|
1239
|
+
for (const prize of prizes) {
|
|
1240
|
+
end += prize.tickets;
|
|
1241
|
+
if (ticket < end) return prize.amount;
|
|
1242
|
+
}
|
|
1243
|
+
return 0n;
|
|
1244
|
+
}
|
|
1245
|
+
/** `math::resolve_reservation`. Release the unwon part of a maximum, keep the award reserved. */
|
|
1246
|
+
function resolveReservation(reserved, maximum, award) {
|
|
1247
|
+
if (award > maximum) throw new GaboxMathError("InsolventInventory", "the award exceeds the reserved maximum");
|
|
1248
|
+
if (reserved < maximum) throw new GaboxMathError("Arithmetic", "the pool has reserved less than this draw holds");
|
|
1249
|
+
return checkedU64(reserved - maximum + award, "reserved");
|
|
1250
|
+
}
|
|
1251
|
+
/** The largest `multiplierBps` on any ticketed row. `0` for a table with no rows. */
|
|
1252
|
+
function maxMultiplierBps(tiers) {
|
|
1253
|
+
validateTiers(tiers);
|
|
1254
|
+
let largest = 0;
|
|
1255
|
+
for (const tier of tiers) {
|
|
1256
|
+
if (tier.tickets === 0) continue;
|
|
1257
|
+
if (tier.multiplierBps > largest) largest = tier.multiplierBps;
|
|
1258
|
+
}
|
|
1259
|
+
return largest;
|
|
1260
|
+
}
|
|
1261
|
+
/**
|
|
1262
|
+
* The expected multiplier over all 65,536 tickets, in basis points. Rounded down.
|
|
1263
|
+
*
|
|
1264
|
+
* `validateTiers` caps this at 10,000. A table at 9,800 keeps 2% of every pack's tokens in the
|
|
1265
|
+
* vault on average, which is what lets a pool survive a run of top-tier wins.
|
|
1266
|
+
*/
|
|
1267
|
+
function averageMultiplierBps(tiers) {
|
|
1268
|
+
validateTiers(tiers);
|
|
1269
|
+
let weighted = 0n;
|
|
1270
|
+
for (const tier of tiers) {
|
|
1271
|
+
if (tier.tickets === 0) continue;
|
|
1272
|
+
weighted += BigInt(tier.multiplierBps) * BigInt(tier.tickets);
|
|
1273
|
+
}
|
|
1274
|
+
return Number(weighted / BigInt(TICKETS));
|
|
1275
|
+
}
|
|
1276
|
+
//#endregion
|
|
969
1277
|
//#region src/raydium/pdas.ts
|
|
970
1278
|
/**
|
|
971
1279
|
* Every Raydium address a Gabox transaction derives.
|
|
@@ -1078,6 +1386,39 @@ const ata = async (owner, mint, tokenProgram = TOKEN_PROGRAM_ADDRESS) => await d
|
|
|
1078
1386
|
address$1.encode(mint)
|
|
1079
1387
|
]);
|
|
1080
1388
|
//#endregion
|
|
1389
|
+
//#region src/pdas.ts
|
|
1390
|
+
/**
|
|
1391
|
+
* Gabox's own program-derived addresses.
|
|
1392
|
+
*
|
|
1393
|
+
* Raydium's live in `src/raydium/pdas.ts`, because they depend on the cluster. These do not: the
|
|
1394
|
+
* Gabox program id is the same everywhere.
|
|
1395
|
+
*
|
|
1396
|
+
* Classic SPL Token only. Both venues use it, and the accepted LaunchLab create instruction mints
|
|
1397
|
+
* the coin with it, so no derivation here takes a token program any more.
|
|
1398
|
+
*/
|
|
1399
|
+
/** `["pool", mint]`. One pool per coin. */
|
|
1400
|
+
const poolAddress = async (mint) => (await findPoolPda({ mint }))[0];
|
|
1401
|
+
/** `["draw", pool, seq]`, with the sequence as eight little-endian bytes. */
|
|
1402
|
+
const drawAddress = async (pool, seq) => (await findDrawPda({
|
|
1403
|
+
pool,
|
|
1404
|
+
seq
|
|
1405
|
+
}))[0];
|
|
1406
|
+
/** The per-wallet `WalletActivity` PDA. `buy_pack` derives it from the purchaser automatically. */
|
|
1407
|
+
const activityAddress = async (wallet) => (await findActivityPda({ purchaser: wallet }))[0];
|
|
1408
|
+
/** `["identity"]` under Gabox. The PDA the program signs its randomness request with. */
|
|
1409
|
+
const vrfIdentityAddress = async () => (await findIdentityPda())[0];
|
|
1410
|
+
/** `["identity", gabox_program_id]` under the VRF program. MagicBlock signs the callback with it. */
|
|
1411
|
+
async function scopedVrfIdentityAddress() {
|
|
1412
|
+
return await getProgramDerivedAddress({
|
|
1413
|
+
programAddress: VRF_PROGRAM_ADDRESS,
|
|
1414
|
+
seeds: [getBytesEncoder().encode(IDENTITY_SEED), getAddressEncoder().encode(GABOX_PROGRAM_ID)]
|
|
1415
|
+
});
|
|
1416
|
+
}
|
|
1417
|
+
/** An associated token account under classic SPL Token. */
|
|
1418
|
+
const associatedTokenAddress = async (owner, mint, tokenProgram = TOKEN_PROGRAM_ADDRESS) => await ata(owner, mint, tokenProgram);
|
|
1419
|
+
/** The prize vault: the pool PDA's own associated token account for the coin. */
|
|
1420
|
+
const vaultAddress = async (mint) => await associatedTokenAddress(await poolAddress(mint), mint);
|
|
1421
|
+
//#endregion
|
|
1081
1422
|
//#region src/raydium/adapter.ts
|
|
1082
1423
|
/**
|
|
1083
1424
|
* Reading Raydium's accounts.
|
|
@@ -1096,7 +1437,7 @@ const ata = async (owner, mint, tokenProgram = TOKEN_PROGRAM_ADDRESS) => await d
|
|
|
1096
1437
|
* Kit's codecs, never `Buffer`. This module is vendored into a Next.js app, and `Buffer` does not
|
|
1097
1438
|
* exist in a browser.
|
|
1098
1439
|
*/
|
|
1099
|
-
const DISCRIMINATOR = 8;
|
|
1440
|
+
const DISCRIMINATOR$1 = 8;
|
|
1100
1441
|
const u8 = getU8Decoder();
|
|
1101
1442
|
const u16 = getU16Decoder();
|
|
1102
1443
|
const u64$1 = getU64Decoder();
|
|
@@ -1131,6 +1472,74 @@ function tokenAccountOwnerAndMint(data) {
|
|
|
1131
1472
|
owner: addressAt.decode(data, 32)
|
|
1132
1473
|
};
|
|
1133
1474
|
}
|
|
1475
|
+
/** The base SPL mint is 82 bytes. Token-2022 repeats those 82 and appends its extensions. */
|
|
1476
|
+
const MINT_BASE_SIZE = 82;
|
|
1477
|
+
/** `decimals` sits after `mint_authority` (4 + 32) and `supply` (8). */
|
|
1478
|
+
const MINT_DECIMALS_AT = 44;
|
|
1479
|
+
/**
|
|
1480
|
+
* The `decimals` of a mint. Both token programs share the first 82 bytes, so one reader covers a
|
|
1481
|
+
* classic SPL mint and a Token-2022 one.
|
|
1482
|
+
*/
|
|
1483
|
+
function mintDecimals(data) {
|
|
1484
|
+
if (data.length < MINT_BASE_SIZE) throw new Error(`not a mint: ${data.length} bytes, expected at least ${MINT_BASE_SIZE}`);
|
|
1485
|
+
return u8.decode(data, MINT_DECIMALS_AT);
|
|
1486
|
+
}
|
|
1487
|
+
/** A Borsh string: a u32 little-endian length, then that many UTF-8 bytes. */
|
|
1488
|
+
function borshString$1(data, at) {
|
|
1489
|
+
if (at + 4 > data.length) return null;
|
|
1490
|
+
const length = new DataView(data.buffer, data.byteOffset, data.byteLength).getUint32(at, true);
|
|
1491
|
+
const end = at + 4 + length;
|
|
1492
|
+
if (end > data.length) return null;
|
|
1493
|
+
return {
|
|
1494
|
+
text: new TextDecoder().decode(data.subarray(at + 4, end)),
|
|
1495
|
+
next: end
|
|
1496
|
+
};
|
|
1497
|
+
}
|
|
1498
|
+
/** Metaplex pads its three strings with NUL bytes up to their maximum length. */
|
|
1499
|
+
const trimmed = (text) => {
|
|
1500
|
+
const clean = text.replace(/\0+$/, "").trim();
|
|
1501
|
+
return clean.length > 0 ? clean : null;
|
|
1502
|
+
};
|
|
1503
|
+
/**
|
|
1504
|
+
* The `symbol` of a Metaplex token metadata account, or `null` when it carries none.
|
|
1505
|
+
*
|
|
1506
|
+
* Layout: a one-byte key, `update_authority` and `mint`, then the three Borsh strings `name`,
|
|
1507
|
+
* `symbol` and `uri`. Metaplex stores them at their maximum length, NUL padded.
|
|
1508
|
+
*/
|
|
1509
|
+
function metaplexSymbol(data) {
|
|
1510
|
+
const name = borshString$1(data, 65);
|
|
1511
|
+
if (!name) return null;
|
|
1512
|
+
const symbol = borshString$1(data, name.next);
|
|
1513
|
+
return symbol ? trimmed(symbol.text) : null;
|
|
1514
|
+
}
|
|
1515
|
+
/** The Token-2022 extension type of `TokenMetadata`, from the SPL token metadata interface. */
|
|
1516
|
+
const TOKEN_METADATA_EXTENSION = 19;
|
|
1517
|
+
/** Token-2022 writes one account-type byte after the 82-byte mint, then its TLV extensions. */
|
|
1518
|
+
const EXTENSION_START = 166;
|
|
1519
|
+
/**
|
|
1520
|
+
* The `symbol` a Token-2022 mint stores in its own `TokenMetadata` extension, or `null`.
|
|
1521
|
+
*
|
|
1522
|
+
* The extensions are a TLV list: a u16 type, a u16 length, then the value. The metadata value is
|
|
1523
|
+
* `update_authority`, `mint`, then the Borsh strings `name`, `symbol` and `uri`.
|
|
1524
|
+
*/
|
|
1525
|
+
function token2022Symbol(data) {
|
|
1526
|
+
let at = EXTENSION_START;
|
|
1527
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
1528
|
+
while (at + 4 <= data.length) {
|
|
1529
|
+
const type = view.getUint16(at, true);
|
|
1530
|
+
const length = view.getUint16(at + 2, true);
|
|
1531
|
+
const value = at + 4;
|
|
1532
|
+
if (value + length > data.length) return null;
|
|
1533
|
+
if (type === TOKEN_METADATA_EXTENSION) {
|
|
1534
|
+
const name = borshString$1(data.subarray(value, value + length), 64);
|
|
1535
|
+
if (!name) return null;
|
|
1536
|
+
const symbol = borshString$1(data.subarray(value, value + length), name.next);
|
|
1537
|
+
return symbol ? trimmed(symbol.text) : null;
|
|
1538
|
+
}
|
|
1539
|
+
at = value + length;
|
|
1540
|
+
}
|
|
1541
|
+
return null;
|
|
1542
|
+
}
|
|
1134
1543
|
/** Offsets follow the `PoolState` field list in `idl/raydium_launchpad.json`. */
|
|
1135
1544
|
const LAUNCHLAB_POOL_HEAD = getStructDecoder([
|
|
1136
1545
|
["epoch", u64$1],
|
|
@@ -1169,7 +1578,7 @@ const LAUNCHLAB_POOL_STATE_HEAD_SIZE = 367;
|
|
|
1169
1578
|
function decodeLaunchlabPool(data) {
|
|
1170
1579
|
checked(data, LAUNCHLAB_POOL_STATE_DISCRIMINATOR, "LaunchLab pool");
|
|
1171
1580
|
atLeast(data, 367, "LaunchLab pool");
|
|
1172
|
-
const head = LAUNCHLAB_POOL_HEAD.decode(data, DISCRIMINATOR);
|
|
1581
|
+
const head = LAUNCHLAB_POOL_HEAD.decode(data, DISCRIMINATOR$1);
|
|
1173
1582
|
return {
|
|
1174
1583
|
status: head.status,
|
|
1175
1584
|
baseDecimals: head.baseDecimals,
|
|
@@ -1211,12 +1620,13 @@ const LAUNCHLAB_GLOBAL_CONFIG_HEAD_SIZE = 115;
|
|
|
1211
1620
|
function decodeLaunchlabGlobalConfig(data) {
|
|
1212
1621
|
checked(data, LAUNCHLAB_GLOBAL_CONFIG_DISCRIMINATOR, "LaunchLab global config");
|
|
1213
1622
|
atLeast(data, 115, "LaunchLab global config");
|
|
1214
|
-
const head = LAUNCHLAB_GLOBAL_CONFIG_HEAD.decode(data, DISCRIMINATOR);
|
|
1623
|
+
const head = LAUNCHLAB_GLOBAL_CONFIG_HEAD.decode(data, DISCRIMINATOR$1);
|
|
1215
1624
|
return {
|
|
1216
1625
|
curveType: head.curveType,
|
|
1217
1626
|
index: head.index,
|
|
1218
1627
|
migrateFee: head.migrateFee,
|
|
1219
1628
|
tradeFeeRate: head.tradeFeeRate,
|
|
1629
|
+
minQuoteFundRaising: head.minQuoteFundRaising,
|
|
1220
1630
|
quoteMint: head.quoteMint
|
|
1221
1631
|
};
|
|
1222
1632
|
}
|
|
@@ -1241,7 +1651,7 @@ const LAUNCHLAB_PLATFORM_CONFIG_HEAD_SIZE = 940;
|
|
|
1241
1651
|
function decodeLaunchlabPlatformConfig(data) {
|
|
1242
1652
|
checked(data, LAUNCHLAB_PLATFORM_CONFIG_DISCRIMINATOR, "LaunchLab platform config");
|
|
1243
1653
|
atLeast(data, 940, "LaunchLab platform config");
|
|
1244
|
-
const head = LAUNCHLAB_PLATFORM_CONFIG_HEAD.decode(data, DISCRIMINATOR);
|
|
1654
|
+
const head = LAUNCHLAB_PLATFORM_CONFIG_HEAD.decode(data, DISCRIMINATOR$1);
|
|
1245
1655
|
return {
|
|
1246
1656
|
platformFeeWallet: head.platformFeeWallet,
|
|
1247
1657
|
feeRate: head.feeRate,
|
|
@@ -1299,7 +1709,7 @@ const CPMM_POOL_OFFSETS = {
|
|
|
1299
1709
|
function decodeCpmmPool(data) {
|
|
1300
1710
|
checked(data, CPMM_POOL_STATE_DISCRIMINATOR, "CPMM pool");
|
|
1301
1711
|
atLeast(data, 413, "CPMM pool");
|
|
1302
|
-
const head = CPMM_POOL_HEAD.decode(data, DISCRIMINATOR);
|
|
1712
|
+
const head = CPMM_POOL_HEAD.decode(data, DISCRIMINATOR$1);
|
|
1303
1713
|
return {
|
|
1304
1714
|
ammConfig: head.ammConfig,
|
|
1305
1715
|
poolCreator: head.poolCreator,
|
|
@@ -1340,7 +1750,7 @@ const CPMM_AMM_CONFIG_HEAD_SIZE = 116;
|
|
|
1340
1750
|
function decodeCpmmAmmConfig(data) {
|
|
1341
1751
|
checked(data, CPMM_AMM_CONFIG_DISCRIMINATOR, "CPMM amm config");
|
|
1342
1752
|
atLeast(data, 116, "CPMM amm config");
|
|
1343
|
-
const head = CPMM_AMM_CONFIG_HEAD.decode(data, DISCRIMINATOR);
|
|
1753
|
+
const head = CPMM_AMM_CONFIG_HEAD.decode(data, DISCRIMINATOR$1);
|
|
1344
1754
|
return {
|
|
1345
1755
|
index: head.index,
|
|
1346
1756
|
disableCreatePool: head.disableCreatePool,
|
|
@@ -1351,6 +1761,121 @@ function decodeCpmmAmmConfig(data) {
|
|
|
1351
1761
|
};
|
|
1352
1762
|
}
|
|
1353
1763
|
//#endregion
|
|
1764
|
+
//#region src/accounts.ts
|
|
1765
|
+
/** Account readers and bounded discovery scans. Old pool layouts are intentionally unsupported. */
|
|
1766
|
+
const DISCRIMINATOR = 8;
|
|
1767
|
+
const DRAW_POOL_OFFSET = DISCRIMINATOR;
|
|
1768
|
+
const DRAW_PURCHASER_OFFSET = 40;
|
|
1769
|
+
const POOL_CREATOR_OFFSET = DISCRIMINATOR;
|
|
1770
|
+
const POOL_MINT_OFFSET = 40;
|
|
1771
|
+
const base58 = getBase58Decoder();
|
|
1772
|
+
const base64$1 = getBase64Encoder();
|
|
1773
|
+
const asBase58 = (bytes) => base58.decode(bytes);
|
|
1774
|
+
const memcmp$1 = (offset, bytes) => ({ memcmp: {
|
|
1775
|
+
offset: BigInt(offset),
|
|
1776
|
+
bytes,
|
|
1777
|
+
encoding: "base58"
|
|
1778
|
+
} });
|
|
1779
|
+
const encoded = (address, data) => ({
|
|
1780
|
+
address,
|
|
1781
|
+
data,
|
|
1782
|
+
exists: true,
|
|
1783
|
+
executable: false,
|
|
1784
|
+
lamports: 0n,
|
|
1785
|
+
programAddress: GABOX_PROGRAM_ID,
|
|
1786
|
+
space: BigInt(data.length)
|
|
1787
|
+
});
|
|
1788
|
+
async function fetchPoolByMint(client, mint) {
|
|
1789
|
+
return await fetchPoolAt(client, await poolAddress(mint));
|
|
1790
|
+
}
|
|
1791
|
+
async function fetchPoolAt(client, address) {
|
|
1792
|
+
return decodeCurrentPool(await fetchEncodedAccount(client.rpc, address, { commitment: "confirmed" }));
|
|
1793
|
+
}
|
|
1794
|
+
function decodeCurrentPool(account) {
|
|
1795
|
+
if (!account.exists) return null;
|
|
1796
|
+
if (account.data.length !== getPoolSize()) throw new Error(`pool ${account.address} is not a Gabox pool and is intentionally unsupported`);
|
|
1797
|
+
return decodePool(account).data;
|
|
1798
|
+
}
|
|
1799
|
+
function decodeCurrentDraw(account) {
|
|
1800
|
+
if (!account.exists) return null;
|
|
1801
|
+
if (account.data.length !== getDrawSize()) throw new Error(`draw ${account.address} is not a Gabox draw and is intentionally unsupported`);
|
|
1802
|
+
return decodeDraw(account).data;
|
|
1803
|
+
}
|
|
1804
|
+
async function fetchDraw(client, address) {
|
|
1805
|
+
return decodeCurrentDraw(await fetchEncodedAccount(client.rpc, address, { commitment: "confirmed" }));
|
|
1806
|
+
}
|
|
1807
|
+
function decodeCurrentWalletActivity(account) {
|
|
1808
|
+
if (!account.exists) return null;
|
|
1809
|
+
if (account.data.length !== getWalletActivitySize()) throw new Error(`activity account ${account.address} is not a Gabox WalletActivity and is intentionally unsupported`);
|
|
1810
|
+
return decodeWalletActivity(account).data;
|
|
1811
|
+
}
|
|
1812
|
+
/**
|
|
1813
|
+
* A wallet's lifetime pack-buying activity, or `null` before it has bought its first pack.
|
|
1814
|
+
* `buy_pack` creates this account `init_if_needed`, so a fresh wallet has none yet.
|
|
1815
|
+
*/
|
|
1816
|
+
async function fetchWalletActivity(client, wallet) {
|
|
1817
|
+
return decodeCurrentWalletActivity(await fetchEncodedAccount(client.rpc, await activityAddress(wallet), { commitment: "confirmed" }));
|
|
1818
|
+
}
|
|
1819
|
+
async function scan(rpc, filters, decode) {
|
|
1820
|
+
return (await rpc.getProgramAccounts(GABOX_PROGRAM_ID, {
|
|
1821
|
+
encoding: "base64",
|
|
1822
|
+
commitment: "confirmed",
|
|
1823
|
+
filters
|
|
1824
|
+
}).send()).map(({ pubkey, account }) => decode(pubkey, new Uint8Array(base64$1.encode(account.data[0]))));
|
|
1825
|
+
}
|
|
1826
|
+
async function listPools(client) {
|
|
1827
|
+
return await scan(client.rpc, [memcmp$1(0, asBase58(POOL_DISCRIMINATOR)), { dataSize: BigInt(getPoolSize()) }], (address, data) => ({
|
|
1828
|
+
address,
|
|
1829
|
+
data: decodePool(encoded(address, data)).data
|
|
1830
|
+
}));
|
|
1831
|
+
}
|
|
1832
|
+
async function listDraws(client, query = {}) {
|
|
1833
|
+
const filters = [memcmp$1(0, asBase58(DRAW_DISCRIMINATOR)), { dataSize: BigInt(getDrawSize()) }];
|
|
1834
|
+
if (query.pool) filters.push(memcmp$1(8, query.pool));
|
|
1835
|
+
if (query.purchaser) filters.push(memcmp$1(40, query.purchaser));
|
|
1836
|
+
return await scan(client.rpc, filters, (address, data) => ({
|
|
1837
|
+
address,
|
|
1838
|
+
data: decodeDraw(encoded(address, data)).data
|
|
1839
|
+
}));
|
|
1840
|
+
}
|
|
1841
|
+
const listDrawsByPool = async (client, pool) => await listDraws(client, { pool });
|
|
1842
|
+
const listDrawsByPurchaser = async (client, purchaser) => await listDraws(client, { purchaser });
|
|
1843
|
+
async function fetchVaultBalance(client, mint) {
|
|
1844
|
+
const vault = await vaultAddress(mint);
|
|
1845
|
+
const { value } = await client.rpc.getAccountInfo(vault, {
|
|
1846
|
+
encoding: "base64",
|
|
1847
|
+
commitment: "confirmed"
|
|
1848
|
+
}).send();
|
|
1849
|
+
return value ? tokenAccountAmount(new Uint8Array(base64$1.encode(value.data[0]))) : 0n;
|
|
1850
|
+
}
|
|
1851
|
+
async function fetchPoolInventory(client, mint) {
|
|
1852
|
+
const poolPda = await poolAddress(mint);
|
|
1853
|
+
const vaultPda = await vaultAddress(mint);
|
|
1854
|
+
const { value } = await client.rpc.getMultipleAccounts([poolPda, vaultPda], {
|
|
1855
|
+
encoding: "base64",
|
|
1856
|
+
commitment: "confirmed"
|
|
1857
|
+
}).send();
|
|
1858
|
+
const poolAccount = value[0];
|
|
1859
|
+
if (!poolAccount) return null;
|
|
1860
|
+
const pool = decodeCurrentPool(encoded(poolPda, new Uint8Array(base64$1.encode(poolAccount.data[0]))));
|
|
1861
|
+
if (!pool) return null;
|
|
1862
|
+
if (pool.vault !== vaultPda) throw new Error(`pool ${poolPda} has an unexpected vault; it is not a supported Gabox pool`);
|
|
1863
|
+
const vaultAccount = value[1];
|
|
1864
|
+
const inventory = vaultAccount ? tokenAccountAmount(new Uint8Array(base64$1.encode(vaultAccount.data[0]))) : 0n;
|
|
1865
|
+
return {
|
|
1866
|
+
poolAddress: poolPda,
|
|
1867
|
+
pool,
|
|
1868
|
+
inventory,
|
|
1869
|
+
reserved: pool.reserved,
|
|
1870
|
+
free: inventory > pool.reserved ? inventory - pool.reserved : 0n
|
|
1871
|
+
};
|
|
1872
|
+
}
|
|
1873
|
+
const tiersOf = (pool) => pool.tiers.map(({ multiplierBps, tickets }) => ({
|
|
1874
|
+
multiplierBps,
|
|
1875
|
+
tickets
|
|
1876
|
+
}));
|
|
1877
|
+
const quotePool = (inventory) => quote(inventory.pool.packTokens, tiersOf(inventory.pool), inventory.inventory, inventory.reserved);
|
|
1878
|
+
//#endregion
|
|
1354
1879
|
//#region src/compute.ts
|
|
1355
1880
|
/**
|
|
1356
1881
|
* The two `ComputeBudget` instructions the transaction builders prepend.
|
|
@@ -1375,6 +1900,9 @@ function decodeCpmmAmmConfig(data) {
|
|
|
1375
1900
|
* same work, so the venue's own cost moves with state this SDK does not control. The 1.3x margin is
|
|
1376
1901
|
* there to absorb that, and the largest of the three is always the basis.
|
|
1377
1902
|
*
|
|
1903
|
+
* None of them covers a swap. When a builder puts a route in the same transaction, the route states
|
|
1904
|
+
* its own cost as `Route.computeUnits` and the builder adds it, capped at `MAX_COMPUTE_UNIT_LIMIT`.
|
|
1905
|
+
*
|
|
1378
1906
|
* Re-measure after a change to a builder or to a Raydium program. `test/devnet.e2e.test.ts` prints
|
|
1379
1907
|
* `CU <label>: <units> | <signature>` for every transaction it sends, which is where these came
|
|
1380
1908
|
* from.
|
|
@@ -1386,25 +1914,26 @@ const MAX_COMPUTE_UNIT_LIMIT = 14e5;
|
|
|
1386
1914
|
const DEFAULT_COMPUTE_UNIT_LIMIT = 2e5;
|
|
1387
1915
|
/**
|
|
1388
1916
|
* LaunchLab `initialize_v2`, the WSOL wrap, pool initialization with a seed buy, and the WSOL
|
|
1389
|
-
* close, in one transaction. Measured at `
|
|
1390
|
-
*
|
|
1917
|
+
* close, in one transaction. Measured at `266,488`, `258,988` and `267,988` over three devnet runs
|
|
1918
|
+
* against the slot-500297753 build.
|
|
1391
1919
|
*/
|
|
1392
|
-
const CREATE_MACHINE_COMPUTE_UNITS =
|
|
1920
|
+
const CREATE_MACHINE_COMPUTE_UNITS = 35e4;
|
|
1393
1921
|
/**
|
|
1394
1922
|
* A WSOL wrap, a venue buy, an escrow transfer, a draw init, a VRF request and the WSOL close.
|
|
1395
|
-
* Measured at `
|
|
1396
|
-
* `
|
|
1923
|
+
* Measured at `178,690`, `163,686` and `157,692` on the curve, and `113,891`, `110,922` and
|
|
1924
|
+
* `106,387` on CPMM. The curve buy is dearer because a coin's first trade also creates the platform
|
|
1397
1925
|
* and creator fee vaults.
|
|
1398
1926
|
*/
|
|
1399
|
-
const BUY_PACK_COMPUTE_UNITS =
|
|
1927
|
+
const BUY_PACK_COMPUTE_UNITS = 235e3;
|
|
1400
1928
|
/**
|
|
1401
|
-
* A WSOL wrap, a venue sale, and the WSOL close. Measured at `
|
|
1402
|
-
*
|
|
1929
|
+
* A WSOL wrap, a venue sale, and the WSOL close. Measured at `94,246`, `86,745` and `88,246` on the
|
|
1930
|
+
* curve, and `61,545`, `55,576` and `57,046` on CPMM.
|
|
1403
1931
|
*/
|
|
1404
|
-
const REDEEM_COMPUTE_UNITS =
|
|
1932
|
+
const REDEEM_COMPUTE_UNITS = 125e3;
|
|
1405
1933
|
/**
|
|
1406
|
-
* A creator fee claim: create the
|
|
1407
|
-
* `31,319` every run for the LaunchLab claim
|
|
1934
|
+
* A creator fee claim: create the quote account, claim or collect, and close it when it is WSOL.
|
|
1935
|
+
* Measured at `31,319` every run for the LaunchLab claim and `40,959` for the CPMM collect. A claim
|
|
1936
|
+
* on a pool quoted in another token is cheaper, `17,635`, because nothing has to be unwrapped.
|
|
1408
1937
|
*/
|
|
1409
1938
|
const CLAIM_COMPUTE_UNITS = 55e3;
|
|
1410
1939
|
/** `ComputeBudgetInstruction`'s discriminants. Positional and append-only upstream. */
|
|
@@ -1452,6 +1981,103 @@ function computeBudgetInstructions(units, microLamports) {
|
|
|
1452
1981
|
return instructions;
|
|
1453
1982
|
}
|
|
1454
1983
|
//#endregion
|
|
1984
|
+
//#region src/raydium/read.ts
|
|
1985
|
+
/**
|
|
1986
|
+
* One account reader, shared by every module that decodes a Raydium account.
|
|
1987
|
+
*
|
|
1988
|
+
* Kit's codecs, not `Buffer`. This SDK is vendored into a Next.js app and `Buffer` is not defined
|
|
1989
|
+
* in the browser.
|
|
1990
|
+
*/
|
|
1991
|
+
const base64 = getBase64Encoder();
|
|
1992
|
+
/** Read several accounts in one call. A missing account comes back as `null`, not as an error. */
|
|
1993
|
+
async function readAccounts(rpc, addresses) {
|
|
1994
|
+
const { value } = await rpc.getMultipleAccounts(addresses, {
|
|
1995
|
+
encoding: "base64",
|
|
1996
|
+
commitment: "confirmed"
|
|
1997
|
+
}).send();
|
|
1998
|
+
return value.map((account) => {
|
|
1999
|
+
if (!account) return null;
|
|
2000
|
+
const [encoded] = account.data;
|
|
2001
|
+
return {
|
|
2002
|
+
data: new Uint8Array(base64.encode(encoded)),
|
|
2003
|
+
owner: account.owner
|
|
2004
|
+
};
|
|
2005
|
+
});
|
|
2006
|
+
}
|
|
2007
|
+
/** Decode one base64 account payload the RPC returned inside another shape. */
|
|
2008
|
+
const decodeBase64 = (encoded) => new Uint8Array(base64.encode(encoded));
|
|
2009
|
+
//#endregion
|
|
2010
|
+
//#region src/raydium/quote.ts
|
|
2011
|
+
/**
|
|
2012
|
+
* LaunchLab's global config for one quote mint, or `null` when Raydium enabled no such quote.
|
|
2013
|
+
*
|
|
2014
|
+
* Index 0 is the usual config, and the constant-product curve is the only shape Gabox launches, so
|
|
2015
|
+
* those two are fixed here. The decoded `quoteMint` has to be the mint asked for: a config for a
|
|
2016
|
+
* different quote would price the wrong asset.
|
|
2017
|
+
*/
|
|
2018
|
+
async function fetchQuoteConfig(client, mint, ids = raydiumIds(client.cluster)) {
|
|
2019
|
+
const address = await launchlabGlobalConfig(ids.launchlab, mint, 0, 0);
|
|
2020
|
+
const [account] = await readAccounts(client.rpc, [address]);
|
|
2021
|
+
if (!account || account.owner !== ids.launchlab) return null;
|
|
2022
|
+
let config;
|
|
2023
|
+
try {
|
|
2024
|
+
config = decodeLaunchlabGlobalConfig(account.data);
|
|
2025
|
+
} catch {
|
|
2026
|
+
return null;
|
|
2027
|
+
}
|
|
2028
|
+
if (config.curveType !== 0 || config.quoteMint !== mint) return null;
|
|
2029
|
+
return {
|
|
2030
|
+
...config,
|
|
2031
|
+
address
|
|
2032
|
+
};
|
|
2033
|
+
}
|
|
2034
|
+
/** Can a Gabox machine be quoted in this mint? One account read. */
|
|
2035
|
+
async function isQuoteSupported(client, mint) {
|
|
2036
|
+
return await fetchQuoteConfig(client, mint) !== null;
|
|
2037
|
+
}
|
|
2038
|
+
/**
|
|
2039
|
+
* The full quote asset: its LaunchLab config, its token program, its decimals and its symbol.
|
|
2040
|
+
*
|
|
2041
|
+
* Two round trips. The first reads the global config, because the config address is derived from
|
|
2042
|
+
* the mint. The second reads the mint and its Metaplex metadata account together.
|
|
2043
|
+
*
|
|
2044
|
+
* Throws when Raydium has no config for the mint, because no pool can be created or traded then.
|
|
2045
|
+
*/
|
|
2046
|
+
async function fetchQuoteAsset(client, mint, ids = raydiumIds(client.cluster)) {
|
|
2047
|
+
const config = await fetchQuoteConfig(client, mint, ids);
|
|
2048
|
+
if (!config) throw new Error(`Raydium has no LaunchLab global config for ${mint}, so it is not a quote asset Gabox can use. Pick a quote Raydium enabled, such as wrapped SOL or USDC.`);
|
|
2049
|
+
const display = await fetchQuoteDisplay(client, mint);
|
|
2050
|
+
return {
|
|
2051
|
+
mint,
|
|
2052
|
+
config: config.address,
|
|
2053
|
+
tokenProgram: display.tokenProgram,
|
|
2054
|
+
decimals: display.decimals,
|
|
2055
|
+
symbol: display.symbol,
|
|
2056
|
+
tradeFeeRate: config.tradeFeeRate,
|
|
2057
|
+
migrateFee: config.migrateFee,
|
|
2058
|
+
minQuoteFundRaising: config.minQuoteFundRaising
|
|
2059
|
+
};
|
|
2060
|
+
}
|
|
2061
|
+
/**
|
|
2062
|
+
* Read a quote mint and its Metaplex metadata in one call.
|
|
2063
|
+
*
|
|
2064
|
+
* A Token-2022 mint may carry its own `TokenMetadata` extension, and that one wins: it is the
|
|
2065
|
+
* issuer's own record. A classic SPL mint keeps its symbol in a Metaplex account, and a mint with
|
|
2066
|
+
* neither reports `null`.
|
|
2067
|
+
*/
|
|
2068
|
+
async function fetchQuoteDisplay(client, mint) {
|
|
2069
|
+
const [mintAccount, metadata] = await readAccounts(client.rpc, [mint, await metadataAddress(mint)]);
|
|
2070
|
+
if (!mintAccount) throw new Error(`the quote mint ${mint} is not on chain`);
|
|
2071
|
+
const tokenProgram = mintAccount.owner;
|
|
2072
|
+
if (tokenProgram !== "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" && tokenProgram !== "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb") throw new Error(`the quote mint ${mint} is owned by ${tokenProgram}, which is neither classic SPL Token nor Token-2022`);
|
|
2073
|
+
const own = tokenProgram === "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" ? token2022Symbol(mintAccount.data) : null;
|
|
2074
|
+
return {
|
|
2075
|
+
tokenProgram,
|
|
2076
|
+
decimals: mintDecimals(mintAccount.data),
|
|
2077
|
+
symbol: own ?? (metadata ? metaplexSymbol(metadata.data) : null)
|
|
2078
|
+
};
|
|
2079
|
+
}
|
|
2080
|
+
//#endregion
|
|
1455
2081
|
//#region src/raydium/accounts.ts
|
|
1456
2082
|
/**
|
|
1457
2083
|
* The ordered account list of every Raydium trade Gabox forwards.
|
|
@@ -1475,7 +2101,14 @@ function computeBudgetInstructions(units, microLamports) {
|
|
|
1475
2101
|
*
|
|
1476
2102
|
* CPMM calls its four pairs `input_*` and `output_*`. A buy sends quote and receives the coin; a
|
|
1477
2103
|
* sell is the other way round. So the two builders below fill the same four names with opposite
|
|
1478
|
-
* addresses. LaunchLab names its accounts by role instead, and uses
|
|
2104
|
+
* addresses, the token programs included. LaunchLab names its accounts by role instead, and uses
|
|
2105
|
+
* one list for both sides.
|
|
2106
|
+
*
|
|
2107
|
+
* # The token programs are inputs, not constants
|
|
2108
|
+
*
|
|
2109
|
+
* The base coin is always classic SPL Token. The quote may be Token-2022, so its program travels
|
|
2110
|
+
* with the pool: `pool.quoteTokenProgram` on the curve, and the two programs a migrated CPMM pool
|
|
2111
|
+
* records in its own data. `venue/trade.rs` checks both slots against the same values.
|
|
1479
2112
|
*/
|
|
1480
2113
|
/**
|
|
1481
2114
|
* Turn `{name -> address}` into the ABI's ordered `AccountMeta[]`.
|
|
@@ -1508,7 +2141,7 @@ function launchlabTradeAccounts(abi, input) {
|
|
|
1508
2141
|
base_token_mint: input.mint,
|
|
1509
2142
|
quote_token_mint: input.quoteMint,
|
|
1510
2143
|
base_token_program: TOKEN_PROGRAM_ADDRESS,
|
|
1511
|
-
quote_token_program:
|
|
2144
|
+
quote_token_program: input.quoteTokenProgram,
|
|
1512
2145
|
event_authority: input.launchlabEventAuthority,
|
|
1513
2146
|
program: input.launchlab,
|
|
1514
2147
|
system_program: SYSTEM_PROGRAM_ADDRESS,
|
|
@@ -1537,8 +2170,8 @@ function cpmmTradeAccounts(abi, input, side) {
|
|
|
1537
2170
|
output_token_account: buying ? input.userBaseToken : input.userQuoteToken,
|
|
1538
2171
|
input_vault: buying ? input.quoteVault : input.baseVault,
|
|
1539
2172
|
output_vault: buying ? input.baseVault : input.quoteVault,
|
|
1540
|
-
input_token_program:
|
|
1541
|
-
output_token_program:
|
|
2173
|
+
input_token_program: buying ? input.quoteTokenProgram : input.baseTokenProgram,
|
|
2174
|
+
output_token_program: buying ? input.baseTokenProgram : input.quoteTokenProgram,
|
|
1542
2175
|
input_token_mint: buying ? input.quoteMint : input.mint,
|
|
1543
2176
|
output_token_mint: buying ? input.mint : input.quoteMint,
|
|
1544
2177
|
observation_state: input.observationState
|
|
@@ -1722,69 +2355,40 @@ function cpmmSwapBaseInput(sides, rates, amountIn) {
|
|
|
1722
2355
|
}
|
|
1723
2356
|
//#endregion
|
|
1724
2357
|
//#region src/raydium/venue.ts
|
|
2358
|
+
/** The quote binding a Gabox pool records. One account read. */
|
|
2359
|
+
async function fetchQuoteBinding(client, mint) {
|
|
2360
|
+
const pool = await fetchPoolByMint(client, mint);
|
|
2361
|
+
if (!pool) throw new Error(`no Gabox pool for mint ${mint}, so its quote asset is unknown. Pass \`quote\` to price a coin that has no pool.`);
|
|
2362
|
+
return {
|
|
2363
|
+
mint: pool.quoteMint,
|
|
2364
|
+
config: pool.quoteConfig,
|
|
2365
|
+
tokenProgram: pool.quoteTokenProgram
|
|
2366
|
+
};
|
|
2367
|
+
}
|
|
1725
2368
|
/**
|
|
1726
|
-
*
|
|
1727
|
-
* list for the trade.
|
|
1728
|
-
*
|
|
1729
|
-
* `resolveVenue` reads every account the answer depends on, decodes them, and hands back a plain
|
|
1730
|
-
* object whose methods are pure. A caller that wants to re-price a different token count calls
|
|
1731
|
-
* `quoteBuy` again with no further reads.
|
|
2369
|
+
* The user's quote associated token account, under the quote's own token program.
|
|
1732
2370
|
*
|
|
1733
|
-
*
|
|
1734
|
-
*
|
|
1735
|
-
*
|
|
1736
|
-
*
|
|
1737
|
-
* - `0`: the curve is still selling, so trade LaunchLab.
|
|
1738
|
-
* - `1`: the raise is finished and Raydium's own bot is moving the coin into a CPMM pool. Nothing
|
|
1739
|
-
* trades. This throws, and the message says to retry in a moment. On devnet the move usually
|
|
1740
|
-
* finishes within a minute.
|
|
1741
|
-
* - `2`: the coin graduated, so trade its CPMM pool.
|
|
1742
|
-
*
|
|
1743
|
-
* A coin can graduate between the read and the send. A pack buy then fails and no draw is created,
|
|
1744
|
-
* which is the intended outcome: refresh and retry.
|
|
1745
|
-
*
|
|
1746
|
-
* # Finding the migrated CPMM pool
|
|
1747
|
-
*
|
|
1748
|
-
* The pool is normally at `["pool", cpswap_config, token_0, token_1]` under CPMM, where
|
|
1749
|
-
* `cpswap_config` is the fee tier the Gabox platform config names. It is not always: when that
|
|
1750
|
-
* address is already taken, Raydium migrates into a random account instead. So this module tries
|
|
1751
|
-
* the derived address first and falls back to a filtered `getProgramAccounts` scan.
|
|
1752
|
-
*
|
|
1753
|
-
* Either way the pool has to prove itself from its own data, which is what `venue/trade.rs` checks
|
|
1754
|
-
* on chain as well: CPMM owns it, it carries the `PoolState` discriminator, its `pool_creator` is
|
|
1755
|
-
* the coin creator, its two mints are the sorted pair, and `enable_creator_fee` is true. That last
|
|
1756
|
-
* flag is the one that cannot be forged. A plain CPMM `initialize` always leaves it false; only a
|
|
1757
|
-
* creator Raydium has permissioned, such as LaunchLab's migration, can set it.
|
|
2371
|
+
* Both venues settle in this account, never in native SOL. It must exist and hold enough before a
|
|
2372
|
+
* pack is bought, and sale proceeds land in it. For a WSOL-quoted pool every builder in `tx/` wraps
|
|
2373
|
+
* the SOL it needs into this account and closes it again in the same transaction.
|
|
1758
2374
|
*/
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
return value.map((account) => {
|
|
1766
|
-
if (!account) return null;
|
|
1767
|
-
const [encoded] = account.data;
|
|
1768
|
-
return {
|
|
1769
|
-
data: new Uint8Array(base64$1.encode(encoded)),
|
|
1770
|
-
owner: account.owner
|
|
1771
|
-
};
|
|
1772
|
-
});
|
|
2375
|
+
async function quoteAccountFor(user, quoteMint, quoteTokenProgram = TOKEN_PROGRAM_ADDRESS) {
|
|
2376
|
+
return await ata(user, quoteMint, quoteTokenProgram);
|
|
2377
|
+
}
|
|
2378
|
+
/** The user's WSOL associated token account. WSOL is always classic SPL Token. */
|
|
2379
|
+
async function wsolAccountFor(user) {
|
|
2380
|
+
return await ata(user, WSOL_MINT, TOKEN_PROGRAM_ADDRESS);
|
|
1773
2381
|
}
|
|
1774
2382
|
/**
|
|
1775
|
-
*
|
|
2383
|
+
* Read the quote's global config and the Gabox platform config, and take the four numbers a quote
|
|
2384
|
+
* needs out of them.
|
|
1776
2385
|
*
|
|
1777
|
-
*
|
|
1778
|
-
*
|
|
1779
|
-
* this account and closes it again in the same transaction.
|
|
2386
|
+
* `quoteConfig` is the LaunchLab global config of the pool's quote asset: `pool.quoteConfig`, or
|
|
2387
|
+
* the address `raydium.fetchQuoteConfig` derives for a coin that has no pool yet.
|
|
1780
2388
|
*/
|
|
1781
|
-
async function
|
|
1782
|
-
|
|
1783
|
-
}
|
|
1784
|
-
/** Read the two pinned config accounts and take the four numbers a quote needs out of them. */
|
|
1785
|
-
async function fetchCurveSettings(client, ids = raydiumIds(client.cluster)) {
|
|
1786
|
-
const [globalAccount, platformAccount] = await readAccounts(client.rpc, [ids.solGlobalConfig, ids.gaboxPlatform]);
|
|
1787
|
-
if (!globalAccount) throw new Error(`LaunchLab's WSOL global config is missing at ${ids.solGlobalConfig}`);
|
|
2389
|
+
async function fetchCurveSettings(client, quoteConfig, ids = raydiumIds(client.cluster)) {
|
|
2390
|
+
const [globalAccount, platformAccount] = await readAccounts(client.rpc, [quoteConfig, ids.gaboxPlatform]);
|
|
2391
|
+
if (!globalAccount) throw new Error(`LaunchLab has no global config at ${quoteConfig}`);
|
|
1788
2392
|
if (!platformAccount) throw new Error(`the Gabox platform config is missing at ${ids.gaboxPlatform}`);
|
|
1789
2393
|
return settingsFrom(globalAccount.data, platformAccount.data);
|
|
1790
2394
|
}
|
|
@@ -1804,18 +2408,18 @@ function settingsFrom(globalData, platformData) {
|
|
|
1804
2408
|
async function resolveVenue(client, options) {
|
|
1805
2409
|
const ids = raydiumIds(client.cluster);
|
|
1806
2410
|
const { mint, user } = options;
|
|
1807
|
-
const
|
|
1808
|
-
const curvePool = await launchlabPoolAddress(ids.launchlab, mint,
|
|
2411
|
+
const quote = options.quote ?? await fetchQuoteBinding(client, mint);
|
|
2412
|
+
const curvePool = await launchlabPoolAddress(ids.launchlab, mint, quote.mint);
|
|
1809
2413
|
const [poolAccount, globalAccount, platformAccount] = await readAccounts(client.rpc, [
|
|
1810
2414
|
curvePool,
|
|
1811
|
-
|
|
2415
|
+
quote.config,
|
|
1812
2416
|
ids.gaboxPlatform
|
|
1813
2417
|
]);
|
|
1814
|
-
if (!poolAccount) throw new Error(`no LaunchLab pool at ${curvePool}. The coin was not launched on LaunchLab with
|
|
1815
|
-
if (!globalAccount) throw new Error(`LaunchLab
|
|
2418
|
+
if (!poolAccount) throw new Error(`no LaunchLab pool at ${curvePool}. The coin was not launched on LaunchLab with ${quote.mint} as its quote, so it has no Gabox venue.`);
|
|
2419
|
+
if (!globalAccount) throw new Error(`LaunchLab has no global config at ${quote.config}`);
|
|
1816
2420
|
if (!platformAccount) throw new Error(`the Gabox platform config is missing at ${ids.gaboxPlatform}`);
|
|
1817
2421
|
const pool = decodeLaunchlabPool(poolAccount.data);
|
|
1818
|
-
if (pool.baseMint !== mint || pool.quoteMint !==
|
|
2422
|
+
if (pool.baseMint !== mint || pool.quoteMint !== quote.mint) throw new Error(`the LaunchLab pool at ${curvePool} is not the pool of ${mint}`);
|
|
1819
2423
|
const settings = settingsFrom(globalAccount.data, platformAccount.data);
|
|
1820
2424
|
const kind = options.venue ?? (pool.status === 2 ? "cpmm" : "launchlab");
|
|
1821
2425
|
if (options.venue === void 0 && pool.status === 1) throw new Error(`${mint} is graduating: its LaunchLab curve is sold out and Raydium is moving it into a CPMM pool. Retry in a moment; the move usually finishes within a minute.`);
|
|
@@ -1823,35 +2427,37 @@ async function resolveVenue(client, options) {
|
|
|
1823
2427
|
if (pool.status !== 0) throw new Error(`${mint} no longer trades on its LaunchLab curve (status ${pool.status}). Use the CPMM venue.`);
|
|
1824
2428
|
return await launchlabVenue(ids, pool, settings.rates, {
|
|
1825
2429
|
mint,
|
|
1826
|
-
|
|
2430
|
+
quote,
|
|
1827
2431
|
user,
|
|
1828
2432
|
poolState: curvePool
|
|
1829
2433
|
});
|
|
1830
2434
|
}
|
|
1831
2435
|
return await cpmmVenue(client, ids, pool, settings.cpswapConfig, {
|
|
1832
2436
|
mint,
|
|
1833
|
-
|
|
2437
|
+
quote,
|
|
1834
2438
|
user
|
|
1835
2439
|
});
|
|
1836
2440
|
}
|
|
1837
2441
|
async function launchlabVenue(ids, pool, rates, where) {
|
|
1838
|
-
const { mint,
|
|
2442
|
+
const { mint, quote, user, poolState } = where;
|
|
2443
|
+
const userQuoteToken = await quoteAccountFor(user, quote.mint, quote.tokenProgram);
|
|
1839
2444
|
const shared = {
|
|
1840
2445
|
launchlab: ids.launchlab,
|
|
1841
2446
|
launchlabAuthority: ids.launchlabAuthority,
|
|
1842
2447
|
launchlabEventAuthority: ids.launchlabEventAuthority,
|
|
1843
|
-
globalConfig:
|
|
2448
|
+
globalConfig: quote.config,
|
|
1844
2449
|
platformConfig: ids.gaboxPlatform,
|
|
1845
2450
|
poolState,
|
|
1846
2451
|
mint,
|
|
1847
|
-
quoteMint,
|
|
2452
|
+
quoteMint: quote.mint,
|
|
1848
2453
|
baseVault: await launchlabVaultAddress(ids.launchlab, poolState, mint),
|
|
1849
|
-
quoteVault: await launchlabVaultAddress(ids.launchlab, poolState,
|
|
2454
|
+
quoteVault: await launchlabVaultAddress(ids.launchlab, poolState, quote.mint),
|
|
1850
2455
|
user,
|
|
1851
2456
|
userBaseToken: await ata(user, mint),
|
|
1852
|
-
userQuoteToken
|
|
1853
|
-
|
|
1854
|
-
|
|
2457
|
+
userQuoteToken,
|
|
2458
|
+
quoteTokenProgram: quote.tokenProgram,
|
|
2459
|
+
platformFeeVault: await platformFeeVaultAddress(ids.launchlab, ids.gaboxPlatform, quote.mint),
|
|
2460
|
+
creatorFeeVault: await creatorFeeVaultAddress(ids.launchlab, pool.creator, quote.mint)
|
|
1855
2461
|
};
|
|
1856
2462
|
const reserves = {
|
|
1857
2463
|
virtualBase: pool.virtualBase,
|
|
@@ -1865,7 +2471,9 @@ async function launchlabVenue(ids, pool, rates, where) {
|
|
|
1865
2471
|
kind: "launchlab",
|
|
1866
2472
|
program: ids.launchlab,
|
|
1867
2473
|
mint,
|
|
1868
|
-
quoteMint,
|
|
2474
|
+
quoteMint: quote.mint,
|
|
2475
|
+
quoteTokenProgram: quote.tokenProgram,
|
|
2476
|
+
userQuoteToken,
|
|
1869
2477
|
poolState,
|
|
1870
2478
|
status: pool.status,
|
|
1871
2479
|
creator: pool.creator,
|
|
@@ -1933,7 +2541,7 @@ async function findCpmmPool(client, options) {
|
|
|
1933
2541
|
}).send();
|
|
1934
2542
|
const matches = [];
|
|
1935
2543
|
for (const { pubkey, account: row } of rows) {
|
|
1936
|
-
const pool = decodeCpmmPoolOrNull(
|
|
2544
|
+
const pool = decodeCpmmPoolOrNull(decodeBase64(row.data[0]));
|
|
1937
2545
|
if (pool && cpmmPoolMatches(pool, expect)) matches.push({
|
|
1938
2546
|
address: pubkey,
|
|
1939
2547
|
pool
|
|
@@ -1961,16 +2569,19 @@ function decodeCpmmPoolOrNull(data) {
|
|
|
1961
2569
|
}
|
|
1962
2570
|
}
|
|
1963
2571
|
async function cpmmVenue(client, ids, curve, cpswapConfig, where) {
|
|
1964
|
-
const { mint,
|
|
2572
|
+
const { mint, quote, user } = where;
|
|
1965
2573
|
const { address: poolState, pool } = await findCpmmPool(client, {
|
|
1966
2574
|
mint,
|
|
1967
|
-
quoteMint,
|
|
2575
|
+
quoteMint: quote.mint,
|
|
1968
2576
|
creator: curve.creator,
|
|
1969
2577
|
cpswapConfig
|
|
1970
2578
|
});
|
|
1971
2579
|
const baseIsToken0 = pool.token0Mint === mint;
|
|
1972
2580
|
const baseVault = baseIsToken0 ? pool.token0Vault : pool.token1Vault;
|
|
1973
2581
|
const quoteVault = baseIsToken0 ? pool.token1Vault : pool.token0Vault;
|
|
2582
|
+
const baseTokenProgram = baseIsToken0 ? pool.token0Program : pool.token1Program;
|
|
2583
|
+
const quoteTokenProgram = baseIsToken0 ? pool.token1Program : pool.token0Program;
|
|
2584
|
+
if (baseTokenProgram !== "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" || quoteTokenProgram !== quote.tokenProgram) throw new Error(`the CPMM pool at ${poolState} records token programs ${baseTokenProgram} and ${quoteTokenProgram}, which are not the ones this coin trades under`);
|
|
1974
2585
|
const [configAccount, baseVaultAccount, quoteVaultAccount] = await readAccounts(client.rpc, [
|
|
1975
2586
|
pool.ammConfig,
|
|
1976
2587
|
baseVault,
|
|
@@ -1984,18 +2595,21 @@ async function cpmmVenue(client, ids, curve, cpswapConfig, where) {
|
|
|
1984
2595
|
const baseReserve = tokenAccountAmount(baseVaultAccount.data) - owedBase;
|
|
1985
2596
|
const quoteReserve = tokenAccountAmount(quoteVaultAccount.data) - owedQuote;
|
|
1986
2597
|
if (baseReserve <= 0n || quoteReserve <= 0n) throw new Error(`the CPMM pool at ${poolState} has no tradable reserves`);
|
|
2598
|
+
const userQuoteToken = await quoteAccountFor(user, quote.mint, quoteTokenProgram);
|
|
1987
2599
|
const shared = {
|
|
1988
2600
|
cpmmAuthority: ids.cpmmAuthority,
|
|
1989
2601
|
ammConfig: pool.ammConfig,
|
|
1990
2602
|
poolState,
|
|
1991
2603
|
mint,
|
|
1992
|
-
quoteMint,
|
|
2604
|
+
quoteMint: quote.mint,
|
|
1993
2605
|
baseVault,
|
|
1994
2606
|
quoteVault,
|
|
1995
2607
|
observationState: pool.observationKey,
|
|
1996
2608
|
user,
|
|
1997
2609
|
userBaseToken: await ata(user, mint),
|
|
1998
|
-
userQuoteToken
|
|
2610
|
+
userQuoteToken,
|
|
2611
|
+
baseTokenProgram,
|
|
2612
|
+
quoteTokenProgram
|
|
1999
2613
|
};
|
|
2000
2614
|
const creatorFeeRate = pool.enableCreatorFee ? config.creatorFeeRate : 0n;
|
|
2001
2615
|
const buySides = {
|
|
@@ -2009,7 +2623,7 @@ async function cpmmVenue(client, ids, curve, cpswapConfig, where) {
|
|
|
2009
2623
|
const buyRates = {
|
|
2010
2624
|
tradeFeeRate: config.tradeFeeRate,
|
|
2011
2625
|
creatorFeeRate,
|
|
2012
|
-
creatorFeeOnInput: creatorFeeOnInput(pool,
|
|
2626
|
+
creatorFeeOnInput: creatorFeeOnInput(pool, quote.mint)
|
|
2013
2627
|
};
|
|
2014
2628
|
const sellRates = {
|
|
2015
2629
|
tradeFeeRate: config.tradeFeeRate,
|
|
@@ -2020,7 +2634,9 @@ async function cpmmVenue(client, ids, curve, cpswapConfig, where) {
|
|
|
2020
2634
|
kind: "cpmm",
|
|
2021
2635
|
program: ids.cpmm,
|
|
2022
2636
|
mint,
|
|
2023
|
-
quoteMint,
|
|
2637
|
+
quoteMint: quote.mint,
|
|
2638
|
+
quoteTokenProgram,
|
|
2639
|
+
userQuoteToken,
|
|
2024
2640
|
poolState,
|
|
2025
2641
|
status: curve.status,
|
|
2026
2642
|
creator: pool.poolCreator,
|
|
@@ -2037,7 +2653,8 @@ async function cpmmVenue(client, ids, curve, cpswapConfig, where) {
|
|
|
2037
2653
|
*
|
|
2038
2654
|
* `creator_fee_on` is 0 when the fee follows the input token, 1 when it is always token 0, and 2
|
|
2039
2655
|
* when it is always token 1. LaunchLab migrates a Gabox coin with `AmmCreatorFeeOn::QuoteToken`, so
|
|
2040
|
-
* the pool charges the creator fee in
|
|
2656
|
+
* the pool charges the creator fee in the quote token only: on the input of a buy, on the output of
|
|
2657
|
+
* a sale.
|
|
2041
2658
|
*/
|
|
2042
2659
|
function creatorFeeOnInput(pool, inputMint) {
|
|
2043
2660
|
if (pool.creatorFeeOn === 0) return true;
|
|
@@ -2045,8 +2662,8 @@ function creatorFeeOnInput(pool, inputMint) {
|
|
|
2045
2662
|
return pool.creatorFeeOn === 1 ? inputIsToken0 : !inputIsToken0;
|
|
2046
2663
|
}
|
|
2047
2664
|
/**
|
|
2048
|
-
*
|
|
2049
|
-
* Pass `pool.packTokens` for the pack price.
|
|
2665
|
+
* Quote token an exact-coins-out buy of `tokens` costs right now, on whichever venue the coin
|
|
2666
|
+
* trades. Pass `pool.packTokens` for the pack price.
|
|
2050
2667
|
*
|
|
2051
2668
|
* Use `resolveVenue` when you also need the account list, which every transaction builder does.
|
|
2052
2669
|
* This is for a price display.
|
|
@@ -2055,37 +2672,44 @@ async function curveQuote(client, mint, tokens, options = {}) {
|
|
|
2055
2672
|
return (await resolveVenue(client, {
|
|
2056
2673
|
mint,
|
|
2057
2674
|
user: options.user ?? mint,
|
|
2058
|
-
...options.venue ? { venue: options.venue } : {}
|
|
2675
|
+
...options.venue ? { venue: options.venue } : {},
|
|
2676
|
+
...options.quote ? { quote: options.quote } : {}
|
|
2059
2677
|
})).quoteBuy(tokens);
|
|
2060
2678
|
}
|
|
2061
|
-
/**
|
|
2679
|
+
/** Quote token a sale of `tokens` returns right now, net of the venue's fees. */
|
|
2062
2680
|
async function sellQuote(client, mint, tokens, options = {}) {
|
|
2063
2681
|
return (await resolveVenue(client, {
|
|
2064
2682
|
mint,
|
|
2065
2683
|
user: options.user ?? mint,
|
|
2066
|
-
...options.venue ? { venue: options.venue } : {}
|
|
2684
|
+
...options.venue ? { venue: options.venue } : {},
|
|
2685
|
+
...options.quote ? { quote: options.quote } : {}
|
|
2067
2686
|
})).quoteSell(tokens);
|
|
2068
2687
|
}
|
|
2069
2688
|
/**
|
|
2070
|
-
*
|
|
2071
|
-
* included.
|
|
2689
|
+
* Quote token an exact-coins-out buy of `tokens` would cost on a curve that does not exist yet,
|
|
2690
|
+
* fees included.
|
|
2072
2691
|
*
|
|
2073
2692
|
* This is what the seed costs. `initialize_pool` buys it in the same transaction that creates the
|
|
2074
2693
|
* coin, so the curve is a brand-new LaunchLab curve with the pinned Gabox launch shape at that
|
|
2075
2694
|
* moment. Exact, unless Raydium changes a fee rate between this read and the send.
|
|
2076
2695
|
*/
|
|
2077
|
-
async function newCurveBuyCost(client, tokens) {
|
|
2696
|
+
async function newCurveBuyCost(client, tokens, launch) {
|
|
2078
2697
|
if (tokens <= 0n) return 0n;
|
|
2079
2698
|
const ids = raydiumIds(client.cluster);
|
|
2080
|
-
const settings = await fetchCurveSettings(client, ids);
|
|
2081
|
-
return curveBuyExactOut(newCurveReserves(
|
|
2699
|
+
const settings = await fetchCurveSettings(client, launch.quoteConfig, ids);
|
|
2700
|
+
return curveBuyExactOut(newCurveReserves(launch.raise, settings.migrateFee), settings.rates, tokens);
|
|
2082
2701
|
}
|
|
2083
|
-
/**
|
|
2084
|
-
|
|
2702
|
+
/**
|
|
2703
|
+
* The starting reserves of a brand-new Gabox curve.
|
|
2704
|
+
*
|
|
2705
|
+
* `raise` is `total_quote_fund_raising`, in the quote's own base units. It is the one launch number
|
|
2706
|
+
* the client picks, so the reserves follow it.
|
|
2707
|
+
*/
|
|
2708
|
+
function newCurveReserves(raise, migrateFee) {
|
|
2085
2709
|
return initialCurve({
|
|
2086
2710
|
supply: LAUNCH_SUPPLY,
|
|
2087
2711
|
totalBaseSell: LAUNCH_TOTAL_BASE_SELL,
|
|
2088
|
-
quoteRaise:
|
|
2712
|
+
quoteRaise: raise,
|
|
2089
2713
|
migrateFee
|
|
2090
2714
|
});
|
|
2091
2715
|
}
|
|
@@ -2136,11 +2760,11 @@ function withRemainingAccounts(instruction, remaining) {
|
|
|
2136
2760
|
*
|
|
2137
2761
|
* | Argument | Value |
|
|
2138
2762
|
* | --- | --- |
|
|
2139
|
-
* | `decimals` | 6 |
|
|
2763
|
+
* | `decimals` | 6 (the coin; the quote keeps its own) |
|
|
2140
2764
|
* | curve | `Constant` |
|
|
2141
2765
|
* | `supply` | 1,000,000,000 coins |
|
|
2142
2766
|
* | `total_base_sell` | 793,100,000 coins |
|
|
2143
|
-
* | `total_quote_fund_raising` | 85 SOL on mainnet
|
|
2767
|
+
* | `total_quote_fund_raising` | the caller's `raise`, pinned to 85 SOL on mainnet and 3 SOL on devnet for a WSOL pool |
|
|
2144
2768
|
* | `migrate_type` | 1, which means graduate into a CPMM pool |
|
|
2145
2769
|
* | `VestingParams` | all three fields 0 |
|
|
2146
2770
|
* | `AmmCreatorFeeOn` | `QuoteToken` |
|
|
@@ -2187,12 +2811,12 @@ async function getLaunchInstruction(input, ids) {
|
|
|
2187
2811
|
const name = bounded(input.name, METADATA_LIMITS.name, "name");
|
|
2188
2812
|
const symbol = bounded(input.symbol, METADATA_LIMITS.symbol, "symbol");
|
|
2189
2813
|
const uri = bounded(input.uri, METADATA_LIMITS.uri, "uri");
|
|
2190
|
-
const quoteMint =
|
|
2814
|
+
const { quoteMint, quoteTokenProgram } = input;
|
|
2191
2815
|
const poolState = await launchlabPoolAddress(ids.launchlab, mint.address, quoteMint);
|
|
2192
2816
|
const metas = order(LAUNCHLAB_INITIALIZE, {
|
|
2193
2817
|
payer: creator.address,
|
|
2194
2818
|
creator: creator.address,
|
|
2195
|
-
global_config:
|
|
2819
|
+
global_config: input.quoteConfig,
|
|
2196
2820
|
platform_config: ids.gaboxPlatform,
|
|
2197
2821
|
authority: ids.launchlabAuthority,
|
|
2198
2822
|
pool_state: poolState,
|
|
@@ -2202,7 +2826,7 @@ async function getLaunchInstruction(input, ids) {
|
|
|
2202
2826
|
quote_vault: await launchlabVaultAddress(ids.launchlab, poolState, quoteMint),
|
|
2203
2827
|
metadata_account: await metadataAddress(mint.address),
|
|
2204
2828
|
base_token_program: TOKEN_PROGRAM_ADDRESS,
|
|
2205
|
-
quote_token_program:
|
|
2829
|
+
quote_token_program: quoteTokenProgram,
|
|
2206
2830
|
metadata_program: METAPLEX_PROGRAM_ADDRESS,
|
|
2207
2831
|
system_program: SYSTEM_PROGRAM_ADDRESS,
|
|
2208
2832
|
rent_program: RENT_SYSVAR_ADDRESS,
|
|
@@ -2226,7 +2850,7 @@ async function getLaunchInstruction(input, ids) {
|
|
|
2226
2850
|
curveTag: 0,
|
|
2227
2851
|
supply: LAUNCH_SUPPLY,
|
|
2228
2852
|
totalBaseSell: LAUNCH_TOTAL_BASE_SELL,
|
|
2229
|
-
totalQuoteFundRaising:
|
|
2853
|
+
totalQuoteFundRaising: input.raise,
|
|
2230
2854
|
migrateType: 1,
|
|
2231
2855
|
totalLockedAmount: 0n,
|
|
2232
2856
|
cliffPeriod: 0n,
|
|
@@ -2247,36 +2871,41 @@ async function getLaunchInstruction(input, ids) {
|
|
|
2247
2871
|
* Gabox charges no fee at all. The creator's income is the share Raydium pays out of its own
|
|
2248
2872
|
* revenue, and it sits in two different places depending on where the coin trades:
|
|
2249
2873
|
*
|
|
2250
|
-
* - **On the curve.** LaunchLab pays 0.5% of every trade into `[creator,
|
|
2251
|
-
* One vault per wallet
|
|
2252
|
-
* that creator launched.
|
|
2874
|
+
* - **On the curve.** LaunchLab pays 0.5% of every trade into `[creator, quote_mint]` under
|
|
2875
|
+
* LaunchLab. One vault per wallet **per quote asset**, not one per coin, so a single
|
|
2876
|
+
* `claim_creator_fee` sweeps every coin that creator launched against that quote. A creator
|
|
2877
|
+
* with a SOL machine and a USDC machine claims twice, once per quote.
|
|
2253
2878
|
* - **After graduation.** The CPMM pool keeps the creator's fee inside the pool account, and
|
|
2254
2879
|
* `collect_creator_fee` pays it out. That is per pool, so it takes one call per coin.
|
|
2255
2880
|
*
|
|
2256
|
-
* Both instructions pay into the creator's
|
|
2257
|
-
*
|
|
2881
|
+
* Both instructions pay into the creator's associated token account for the quote mint, under that
|
|
2882
|
+
* mint's own token program. When the quote is WSOL, every builder here closes that account
|
|
2883
|
+
* afterwards, so the creator ends up with plain SOL. For any other quote the account is created if
|
|
2884
|
+
* missing and left alone: closing it would throw away a real balance.
|
|
2258
2885
|
*
|
|
2259
2886
|
* **Closing unwraps everything.** If the creator already held WSOL in that account before the
|
|
2260
2887
|
* claim, closing turns that into SOL too. Nothing is lost, but the balance moves.
|
|
2261
2888
|
*/
|
|
2262
|
-
const base64 = getBase64Encoder();
|
|
2263
2889
|
/**
|
|
2264
|
-
* Create the creator's
|
|
2890
|
+
* Create the creator's quote account, if it is missing, and close it again when it is WSOL.
|
|
2265
2891
|
*
|
|
2266
2892
|
* Raydium's own instructions create the account when they need to, but an idempotent create here
|
|
2267
|
-
* costs nothing and makes the flow the same whichever instruction runs. The close is what turns
|
|
2268
|
-
* WSOL into SOL
|
|
2893
|
+
* costs nothing and makes the flow the same whichever instruction runs. The close is what turns
|
|
2894
|
+
* WSOL into SOL, so it only belongs on a WSOL claim: closing a USDC account would throw the payout
|
|
2895
|
+
* away.
|
|
2269
2896
|
*/
|
|
2270
|
-
async function wrapAround(creator, middle) {
|
|
2271
|
-
const account = await ata(creator.address,
|
|
2897
|
+
async function wrapAround(creator, quote, middle) {
|
|
2898
|
+
const account = await ata(creator.address, quote.mint, quote.tokenProgram);
|
|
2899
|
+
const create = getCreateAssociatedTokenIdempotentInstruction({
|
|
2900
|
+
payer: creator,
|
|
2901
|
+
ata: account,
|
|
2902
|
+
owner: creator.address,
|
|
2903
|
+
mint: quote.mint,
|
|
2904
|
+
tokenProgram: quote.tokenProgram
|
|
2905
|
+
});
|
|
2906
|
+
if (quote.mint !== "So11111111111111111111111111111111111111112") return [create, ...middle];
|
|
2272
2907
|
return [
|
|
2273
|
-
|
|
2274
|
-
payer: creator,
|
|
2275
|
-
ata: account,
|
|
2276
|
-
owner: creator.address,
|
|
2277
|
-
mint: WSOL_MINT,
|
|
2278
|
-
tokenProgram: TOKEN_PROGRAM_ADDRESS
|
|
2279
|
-
}),
|
|
2908
|
+
create,
|
|
2280
2909
|
...middle,
|
|
2281
2910
|
getCloseAccountInstruction({
|
|
2282
2911
|
account,
|
|
@@ -2293,22 +2922,23 @@ function withSigner(accounts, signer) {
|
|
|
2293
2922
|
} : meta);
|
|
2294
2923
|
}
|
|
2295
2924
|
/**
|
|
2296
|
-
* The instructions of a curve fee claim: create the
|
|
2925
|
+
* The instructions of a curve fee claim, for one quote asset: create the quote account, claim, and
|
|
2926
|
+
* close it again when the quote is WSOL.
|
|
2297
2927
|
*
|
|
2298
|
-
* This sweeps **every** coin this wallet launched, because LaunchLab keeps one
|
|
2299
|
-
* quote asset. There is no per-coin version
|
|
2928
|
+
* This sweeps **every** coin this wallet launched against that quote, because LaunchLab keeps one
|
|
2929
|
+
* vault per wallet per quote asset. There is no per-coin version, and a creator with machines in
|
|
2930
|
+
* two quote assets claims once per asset.
|
|
2300
2931
|
*/
|
|
2301
|
-
async function getClaimCreatorFeeInstructions(creator, ids) {
|
|
2302
|
-
|
|
2303
|
-
return await wrapAround(creator, [{
|
|
2932
|
+
async function getClaimCreatorFeeInstructions(creator, ids, quote) {
|
|
2933
|
+
return await wrapAround(creator, quote, [{
|
|
2304
2934
|
programAddress: ids.launchlab,
|
|
2305
2935
|
accounts: withSigner(order(LAUNCHLAB_CLAIM_CREATOR_FEE, {
|
|
2306
2936
|
creator: creator.address,
|
|
2307
2937
|
fee_vault_authority: await creatorFeeVaultAuthority(ids.launchlab),
|
|
2308
|
-
creator_fee_vault: await creatorFeeVaultAddress(ids.launchlab, creator.address,
|
|
2309
|
-
recipient_token_account: await ata(creator.address,
|
|
2310
|
-
quote_mint:
|
|
2311
|
-
token_program:
|
|
2938
|
+
creator_fee_vault: await creatorFeeVaultAddress(ids.launchlab, creator.address, quote.mint),
|
|
2939
|
+
recipient_token_account: await ata(creator.address, quote.mint, quote.tokenProgram),
|
|
2940
|
+
quote_mint: quote.mint,
|
|
2941
|
+
token_program: quote.tokenProgram,
|
|
2312
2942
|
system_program: SYSTEM_PROGRAM_ADDRESS,
|
|
2313
2943
|
associated_token_program: ASSOCIATED_TOKEN_PROGRAM_ADDRESS
|
|
2314
2944
|
}), creator),
|
|
@@ -2316,13 +2946,15 @@ async function getClaimCreatorFeeInstructions(creator, ids) {
|
|
|
2316
2946
|
}]);
|
|
2317
2947
|
}
|
|
2318
2948
|
/**
|
|
2319
|
-
* Claim the curve creator fee
|
|
2949
|
+
* Claim the curve creator fee for one quote asset.
|
|
2320
2950
|
*
|
|
2321
|
-
*
|
|
2951
|
+
* A WSOL claim arrives as SOL, because the builder closes the WSOL account. Any other quote arrives
|
|
2952
|
+
* as that token, in the creator's own account.
|
|
2322
2953
|
*/
|
|
2323
2954
|
async function claimCreatorFee(client, input) {
|
|
2324
2955
|
const ids = raydiumIds(client.cluster);
|
|
2325
|
-
const
|
|
2956
|
+
const quote = await quoteOf(client, input.quoteMint ?? "So11111111111111111111111111111111111111112");
|
|
2957
|
+
const instructions = await getClaimCreatorFeeInstructions(input.creator, ids, quote);
|
|
2326
2958
|
return await buildMessage(client, input.creator, instructions, {
|
|
2327
2959
|
addressLookupTables: input.addressLookupTables,
|
|
2328
2960
|
computeUnitLimit: input.computeUnitLimit ?? 55e3,
|
|
@@ -2330,22 +2962,39 @@ async function claimCreatorFee(client, input) {
|
|
|
2330
2962
|
});
|
|
2331
2963
|
}
|
|
2332
2964
|
/**
|
|
2333
|
-
* The
|
|
2965
|
+
* The token program a quote mint lives under. WSOL is always classic SPL Token, so that one needs
|
|
2966
|
+
* no read at all.
|
|
2967
|
+
*/
|
|
2968
|
+
async function quoteOf(client, mint) {
|
|
2969
|
+
if (mint === "So11111111111111111111111111111111111111112") return {
|
|
2970
|
+
mint,
|
|
2971
|
+
tokenProgram: TOKEN_PROGRAM_ADDRESS
|
|
2972
|
+
};
|
|
2973
|
+
return {
|
|
2974
|
+
mint,
|
|
2975
|
+
tokenProgram: (await fetchQuoteDisplay(client, mint)).tokenProgram
|
|
2976
|
+
};
|
|
2977
|
+
}
|
|
2978
|
+
/**
|
|
2979
|
+
* The instructions of a graduated coin's fee collection: create the quote account, collect, and
|
|
2980
|
+
* close it again when the quote is WSOL.
|
|
2334
2981
|
*
|
|
2335
2982
|
* This is per coin. `collect_creator_fee` pays out both sides of the pair, so anything owed in the
|
|
2336
2983
|
* coin itself lands in the creator's coin account and stays there.
|
|
2984
|
+
*
|
|
2985
|
+
* The coin's quote asset comes from its Gabox pool, so a caller never has to name it.
|
|
2337
2986
|
*/
|
|
2338
2987
|
async function getCollectCreatorFeeInstructions(client, input, ids = raydiumIds(client.cluster)) {
|
|
2339
2988
|
const { mint, creator } = input;
|
|
2340
|
-
const
|
|
2341
|
-
const settings = await fetchCurveSettings(client, ids);
|
|
2989
|
+
const quote = input.quote ?? await fetchQuoteBinding(client, mint);
|
|
2990
|
+
const settings = await fetchCurveSettings(client, quote.config, ids);
|
|
2342
2991
|
const { address: poolState, pool } = await findCpmmPool(client, {
|
|
2343
2992
|
mint,
|
|
2344
|
-
quoteMint,
|
|
2993
|
+
quoteMint: quote.mint,
|
|
2345
2994
|
creator: creator.address,
|
|
2346
2995
|
cpswapConfig: settings.cpswapConfig
|
|
2347
2996
|
});
|
|
2348
|
-
|
|
2997
|
+
const collect = {
|
|
2349
2998
|
programAddress: ids.cpmm,
|
|
2350
2999
|
accounts: withSigner(order(CPMM_COLLECT_CREATOR_FEE, {
|
|
2351
3000
|
creator: creator.address,
|
|
@@ -2365,13 +3014,23 @@ async function getCollectCreatorFeeInstructions(client, input, ids = raydiumIds(
|
|
|
2365
3014
|
creator_fee_share: await cpmmCreatorFeeShare(ids.cpmm, creator.address, pool.ammConfig)
|
|
2366
3015
|
}), creator),
|
|
2367
3016
|
data: new Uint8Array(CPMM_COLLECT_CREATOR_FEE.discriminator)
|
|
2368
|
-
}
|
|
3017
|
+
};
|
|
3018
|
+
return await wrapAround(creator, {
|
|
3019
|
+
mint: quote.mint,
|
|
3020
|
+
tokenProgram: quote.tokenProgram
|
|
3021
|
+
}, [collect]);
|
|
2369
3022
|
}
|
|
2370
|
-
/**
|
|
3023
|
+
/**
|
|
3024
|
+
* Collect one graduated coin's CPMM creator fee.
|
|
3025
|
+
*
|
|
3026
|
+
* A WSOL-quoted coin pays the quote side out as SOL, because the builder closes the WSOL account.
|
|
3027
|
+
* Any other quote arrives as that token.
|
|
3028
|
+
*/
|
|
2371
3029
|
async function collectCreatorFee(client, input) {
|
|
2372
3030
|
const instructions = await getCollectCreatorFeeInstructions(client, {
|
|
2373
3031
|
mint: input.mint,
|
|
2374
|
-
creator: input.creator
|
|
3032
|
+
creator: input.creator,
|
|
3033
|
+
...input.quote ? { quote: input.quote } : {}
|
|
2375
3034
|
});
|
|
2376
3035
|
return await buildMessage(client, input.creator, instructions, {
|
|
2377
3036
|
addressLookupTables: input.addressLookupTables,
|
|
@@ -2380,27 +3039,28 @@ async function collectCreatorFee(client, input) {
|
|
|
2380
3039
|
});
|
|
2381
3040
|
}
|
|
2382
3041
|
/**
|
|
2383
|
-
* Read both places a creator's fees can sit.
|
|
3042
|
+
* Read both places a creator's fees can sit, for one quote asset.
|
|
3043
|
+
*
|
|
3044
|
+
* `quoteMint` defaults to wrapped SOL. LaunchLab keeps one vault per wallet per quote, so a creator
|
|
3045
|
+
* with machines in two quote assets reads this twice.
|
|
2384
3046
|
*
|
|
2385
3047
|
* `mint` is optional. Without it only the curve vault is read, which is the one number that covers
|
|
2386
|
-
* every coin at once. With it the coin's CPMM pool is read too, and a coin that has
|
|
2387
|
-
* reports zeros rather than failing.
|
|
3048
|
+
* every coin of that quote at once. With it the coin's CPMM pool is read too, and a coin that has
|
|
3049
|
+
* not graduated reports zeros rather than failing.
|
|
2388
3050
|
*/
|
|
2389
3051
|
async function fetchCreatorFees(client, input) {
|
|
2390
3052
|
const ids = raydiumIds(client.cluster);
|
|
2391
|
-
const quoteMint =
|
|
3053
|
+
const quoteMint = input.quoteMint ?? "So11111111111111111111111111111111111111112";
|
|
2392
3054
|
const vault = await creatorFeeVaultAddress(ids.launchlab, input.creator, quoteMint);
|
|
2393
|
-
const
|
|
2394
|
-
|
|
2395
|
-
commitment: "confirmed"
|
|
2396
|
-
}).send();
|
|
2397
|
-
const curveLamports = value ? tokenAccountAmount(new Uint8Array(base64.encode(value.data[0]))) : 0n;
|
|
3055
|
+
const [vaultAccount] = await readAccounts(client.rpc, [vault]);
|
|
3056
|
+
const curveQuote = vaultAccount ? tokenAccountAmount(vaultAccount.data) : 0n;
|
|
2398
3057
|
if (!input.mint) return {
|
|
2399
|
-
|
|
2400
|
-
|
|
3058
|
+
quoteMint,
|
|
3059
|
+
curveQuote,
|
|
3060
|
+
cpmmQuote: 0n,
|
|
2401
3061
|
cpmmTokens: 0n
|
|
2402
3062
|
};
|
|
2403
|
-
const settings = await fetchCurveSettings(client, ids);
|
|
3063
|
+
const settings = await fetchCurveSettings(client, await launchlabGlobalConfig(ids.launchlab, quoteMint), ids);
|
|
2404
3064
|
try {
|
|
2405
3065
|
const { pool } = await findCpmmPool(client, {
|
|
2406
3066
|
mint: input.mint,
|
|
@@ -2411,14 +3071,16 @@ async function fetchCreatorFees(client, input) {
|
|
|
2411
3071
|
const [token0] = sortedMints(input.mint, quoteMint);
|
|
2412
3072
|
const baseIsToken0 = token0 === input.mint;
|
|
2413
3073
|
return {
|
|
2414
|
-
|
|
2415
|
-
|
|
3074
|
+
quoteMint,
|
|
3075
|
+
curveQuote,
|
|
3076
|
+
cpmmQuote: baseIsToken0 ? pool.creatorFeesToken1 : pool.creatorFeesToken0,
|
|
2416
3077
|
cpmmTokens: baseIsToken0 ? pool.creatorFeesToken0 : pool.creatorFeesToken1
|
|
2417
3078
|
};
|
|
2418
3079
|
} catch {
|
|
2419
3080
|
return {
|
|
2420
|
-
|
|
2421
|
-
|
|
3081
|
+
quoteMint,
|
|
3082
|
+
curveQuote,
|
|
3083
|
+
cpmmQuote: 0n,
|
|
2422
3084
|
cpmmTokens: 0n
|
|
2423
3085
|
};
|
|
2424
3086
|
}
|
|
@@ -2438,22 +3100,25 @@ async function fetchCreatorFees(client, input) {
|
|
|
2438
3100
|
*/
|
|
2439
3101
|
const u64 = getU64Encoder();
|
|
2440
3102
|
/**
|
|
2441
|
-
* `buy_exact_in` on the curve: spend exactly `quoteIn`
|
|
3103
|
+
* `buy_exact_in` on the curve: spend exactly `quoteIn` of the quote token and take whatever coins
|
|
3104
|
+
* it buys.
|
|
2442
3105
|
*
|
|
2443
3106
|
* LaunchLab caps the trade at what the curve has left to sell, so a spend larger than the rest of
|
|
2444
|
-
* the raise still succeeds and graduates the coin.
|
|
2445
|
-
*
|
|
3107
|
+
* the raise still succeeds and graduates the coin. Fund the user's quote ATA first. On a WSOL pool
|
|
3108
|
+
* that means wrapping the SOL and closing the account afterwards, the same way the Gabox builders
|
|
3109
|
+
* do.
|
|
2446
3110
|
*/
|
|
2447
3111
|
async function getCurveBuyExactInInstruction(client, input, ids = raydiumIds(client.cluster)) {
|
|
2448
3112
|
if (input.quoteIn <= 0n) throw new Error("quoteIn must be positive");
|
|
2449
3113
|
if (input.minTokensOut < 0n) throw new Error("minTokensOut must not be negative");
|
|
2450
|
-
const quoteMint =
|
|
3114
|
+
const quoteMint = input.quoteMint ?? "So11111111111111111111111111111111111111112";
|
|
3115
|
+
const quoteTokenProgram = input.quoteTokenProgram ?? "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
|
|
2451
3116
|
const poolState = await launchlabPoolAddress(ids.launchlab, input.mint, quoteMint);
|
|
2452
3117
|
const accounts = launchlabBuyExactInAccounts({
|
|
2453
3118
|
launchlab: ids.launchlab,
|
|
2454
3119
|
launchlabAuthority: ids.launchlabAuthority,
|
|
2455
3120
|
launchlabEventAuthority: ids.launchlabEventAuthority,
|
|
2456
|
-
globalConfig: ids.
|
|
3121
|
+
globalConfig: await launchlabGlobalConfig(ids.launchlab, quoteMint),
|
|
2457
3122
|
platformConfig: ids.gaboxPlatform,
|
|
2458
3123
|
poolState,
|
|
2459
3124
|
mint: input.mint,
|
|
@@ -2462,7 +3127,8 @@ async function getCurveBuyExactInInstruction(client, input, ids = raydiumIds(cli
|
|
|
2462
3127
|
quoteVault: await launchlabVaultAddress(ids.launchlab, poolState, quoteMint),
|
|
2463
3128
|
user: input.user.address,
|
|
2464
3129
|
userBaseToken: await ata(input.user.address, input.mint),
|
|
2465
|
-
userQuoteToken: await ata(input.user.address, quoteMint),
|
|
3130
|
+
userQuoteToken: await ata(input.user.address, quoteMint, quoteTokenProgram),
|
|
3131
|
+
quoteTokenProgram,
|
|
2466
3132
|
platformFeeVault: await platformFeeVaultAddress(ids.launchlab, ids.gaboxPlatform, quoteMint),
|
|
2467
3133
|
creatorFeeVault: await creatorFeeVaultAddress(ids.launchlab, input.creator, quoteMint)
|
|
2468
3134
|
});
|
|
@@ -2537,6 +3203,7 @@ var raydium_exports = /* @__PURE__ */ __exportAll({
|
|
|
2537
3203
|
RENT_SYSVAR_ADDRESS: () => RENT_SYSVAR_ADDRESS,
|
|
2538
3204
|
SHARE_FEE_RATE: () => SHARE_FEE_RATE,
|
|
2539
3205
|
SYSTEM_PROGRAM_ADDRESS: () => SYSTEM_PROGRAM_ADDRESS,
|
|
3206
|
+
TOKEN_2022_PROGRAM_ADDRESS: () => TOKEN_2022_PROGRAM_ADDRESS,
|
|
2540
3207
|
TOKEN_PROGRAM_ADDRESS: () => TOKEN_PROGRAM_ADDRESS,
|
|
2541
3208
|
WSOL_MINT: () => WSOL_MINT,
|
|
2542
3209
|
ata: () => ata,
|
|
@@ -2560,6 +3227,7 @@ var raydium_exports = /* @__PURE__ */ __exportAll({
|
|
|
2560
3227
|
curveBuyExactOut: () => curveBuyExactOut,
|
|
2561
3228
|
curveQuote: () => curveQuote,
|
|
2562
3229
|
curveSellExactIn: () => curveSellExactIn,
|
|
3230
|
+
decodeBase64: () => decodeBase64,
|
|
2563
3231
|
decodeCpmmAmmConfig: () => decodeCpmmAmmConfig,
|
|
2564
3232
|
decodeCpmmPool: () => decodeCpmmPool,
|
|
2565
3233
|
decodeLaunchlabGlobalConfig: () => decodeLaunchlabGlobalConfig,
|
|
@@ -2567,12 +3235,17 @@ var raydium_exports = /* @__PURE__ */ __exportAll({
|
|
|
2567
3235
|
decodeLaunchlabPool: () => decodeLaunchlabPool,
|
|
2568
3236
|
fetchCreatorFees: () => fetchCreatorFees,
|
|
2569
3237
|
fetchCurveSettings: () => fetchCurveSettings,
|
|
3238
|
+
fetchQuoteAsset: () => fetchQuoteAsset,
|
|
3239
|
+
fetchQuoteBinding: () => fetchQuoteBinding,
|
|
3240
|
+
fetchQuoteConfig: () => fetchQuoteConfig,
|
|
3241
|
+
fetchQuoteDisplay: () => fetchQuoteDisplay,
|
|
2570
3242
|
findCpmmPool: () => findCpmmPool,
|
|
2571
3243
|
getClaimCreatorFeeInstructions: () => getClaimCreatorFeeInstructions,
|
|
2572
3244
|
getCollectCreatorFeeInstructions: () => getCollectCreatorFeeInstructions,
|
|
2573
3245
|
getCurveBuyExactInInstruction: () => getCurveBuyExactInInstruction,
|
|
2574
3246
|
getLaunchInstruction: () => getLaunchInstruction,
|
|
2575
3247
|
initialCurve: () => initialCurve,
|
|
3248
|
+
isQuoteSupported: () => isQuoteSupported,
|
|
2576
3249
|
launchlabAuthority: () => launchlabAuthority,
|
|
2577
3250
|
launchlabBuyAccounts: () => launchlabBuyAccounts,
|
|
2578
3251
|
launchlabBuyExactInAccounts: () => launchlabBuyExactInAccounts,
|
|
@@ -2583,22 +3256,27 @@ var raydium_exports = /* @__PURE__ */ __exportAll({
|
|
|
2583
3256
|
launchlabSellAccounts: () => launchlabSellAccounts,
|
|
2584
3257
|
launchlabVaultAddress: () => launchlabVaultAddress,
|
|
2585
3258
|
metadataAddress: () => metadataAddress,
|
|
3259
|
+
metaplexSymbol: () => metaplexSymbol,
|
|
3260
|
+
mintDecimals: () => mintDecimals,
|
|
2586
3261
|
newCurveBuyCost: () => newCurveBuyCost,
|
|
2587
3262
|
newCurveReserves: () => newCurveReserves,
|
|
2588
3263
|
order: () => order,
|
|
2589
3264
|
platformFeeVaultAddress: () => platformFeeVaultAddress,
|
|
2590
3265
|
preFeeAmount: () => preFeeAmount,
|
|
3266
|
+
quoteAccountFor: () => quoteAccountFor,
|
|
2591
3267
|
raydiumIds: () => raydiumIds,
|
|
3268
|
+
readAccounts: () => readAccounts,
|
|
2592
3269
|
remainingBase: () => remainingBase,
|
|
2593
3270
|
resolveVenue: () => resolveVenue,
|
|
2594
3271
|
sellQuote: () => sellQuote,
|
|
2595
3272
|
sortedMints: () => sortedMints,
|
|
3273
|
+
token2022Symbol: () => token2022Symbol,
|
|
2596
3274
|
tokenAccountAmount: () => tokenAccountAmount,
|
|
2597
3275
|
tokenAccountOwnerAndMint: () => tokenAccountOwnerAndMint,
|
|
2598
3276
|
totalCurveFeeRate: () => totalCurveFeeRate,
|
|
2599
3277
|
wsolAccountFor: () => wsolAccountFor
|
|
2600
3278
|
});
|
|
2601
3279
|
//#endregion
|
|
2602
|
-
export {
|
|
3280
|
+
export { computeBudgetInstructions as $, LAUNCHLAB_BUY_EXACT_OUT as $n, launchlabVaultAddress as $t, initialCurve as A, CPMM_SEEDS as An, metaplexSymbol as At, fetchQuoteAsset as B, RATE_DENOMINATOR as Bn, vaultAddress as Bt, ceilDiv as C, PACK_TOKENS as Cn, LAUNCHLAB_PLATFORM_CONFIG_HEAD_SIZE as Ct, curveBuyExactIn as D, VRF_DEFAULT_QUEUE as Dn, decodeLaunchlabGlobalConfig as Dt, cpmmSwapBaseOutput as E, TIMEOUT_SLOTS as En, decodeCpmmPool as Et, cpmmSellAccounts as F, LAUNCHLAB_STATUS_TRADE as Fn, activityAddress as Ft, readAccounts as G, sortedMints as Gn, cpmmPoolAddress as Gt, fetchQuoteDisplay as H, SHARE_FEE_RATE as Hn, ata as Ht, launchlabBuyAccounts as I, LAUNCH_DECIMALS as In, associatedTokenAddress as It, COMPUTE_BUDGET_PROGRAM_ADDRESS as J, CPMM_COLLECT_CREATOR_FEE as Jn, launchlabAuthority as Jt, BUY_PACK_COMPUTE_UNITS as K, ASSOCIATED_TOKEN_PROGRAM_ADDRESS as Kn, creatorFeeVaultAddress as Kt, launchlabBuyExactInAccounts as L, METADATA_LIMITS as Ln, drawAddress as Lt, remainingBase as M, LAUNCHLAB_SEEDS as Mn, token2022Symbol as Mt, totalCurveFeeRate as N, LAUNCHLAB_STATUS_FUND as Nn, tokenAccountAmount as Nt, curveBuyExactOut as O, VRF_PROGRAM_ADDRESS as On, decodeLaunchlabPlatformConfig as Ot, cpmmBuyAccounts as P, LAUNCHLAB_STATUS_MIGRATE as Pn, tokenAccountOwnerAndMint as Pt, REDEEM_COMPUTE_UNITS as Q, LAUNCHLAB_BUY_EXACT_IN as Qn, launchlabPoolAddress as Qt, launchlabSellAccounts as R, METADATA_SEED as Rn, poolAddress as Rt, wsolAccountFor as S, MAX_ATTEMPTS as Sn, LAUNCHLAB_GLOBAL_CONFIG_HEAD_SIZE as St, cpmmSwapBaseInput as T, SLOT_HASHES_SYSVAR as Tn, decodeCpmmAmmConfig as Tt, isQuoteSupported as U, compareAddresses as Un, cpmmAuthority as Ut, fetchQuoteConfig as V, RAYDIUM_IDS as Vn, vrfIdentityAddress as Vt, decodeBase64 as W, raydiumIds as Wn, cpmmCreatorFeeShare as Wt, DEFAULT_COMPUTE_UNIT_LIMIT as X, CPMM_SWAP_BASE_INPUT as Xn, launchlabGlobalConfig as Xt, CREATE_MACHINE_COMPUTE_UNITS as Y, CPMM_POOL_STATE_DISCRIMINATOR as Yn, launchlabEventAuthority as Yt, MAX_COMPUTE_UNIT_LIMIT as Z, CPMM_SWAP_BASE_OUTPUT as Zn, launchlabPlatformConfig as Zt, newCurveBuyCost as _, validatePack as _n, tiersOf as _t, fetchCreatorFees as a, MAX_MULTIPLIER_BPS as an, LAUNCHLAB_SELL_EXACT_IN as ar, POOL_MINT_OFFSET as at, resolveVenue as b, IDENTITY_SEED as bn, CPMM_POOL_STATE_HEAD_SIZE as bt, getLaunchInstruction as c, TIERS as cn, METAPLEX_PROGRAM_ADDRESS as cr, fetchPoolByMint as ct, cpmmPoolMatches as d, maxMultiplierBps as dn, RAYDIUM_MAINNET_IDS as dr, fetchWalletActivity as dt, metadataAddress as en, LAUNCHLAB_CLAIM_CREATOR_FEE as er, getSetComputeUnitLimitInstruction as et, creatorFeeOnInput as f, quote as fn, RENT_SYSVAR_ADDRESS as fr, listDraws as ft, findCpmmPool as g, uncappedMaximum as gn, WSOL_MINT as gr, quotePool as gt, fetchQuoteBinding as h, tierAmount as hn, TOKEN_PROGRAM_ADDRESS as hr, listPools as ht, collectCreatorFee as i, GaboxMathError as in, LAUNCHLAB_POOL_STATE_DISCRIMINATOR as ir, POOL_CREATOR_OFFSET as it, preFeeAmount as j, CREATOR_FEE_ON_QUOTE as jn, mintDecimals as jt, curveSellExactIn as k, CONSTANT_CURVE_TAG as kn, decodeLaunchlabPool as kt, buildMessage as l, averageMultiplierBps as ln, PLATFORM_ADMIN as lr, fetchPoolInventory as lt, fetchCurveSettings as m, seedTokens as mn, TOKEN_2022_PROGRAM_ADDRESS as mr, listDrawsByPurchaser as mt, getCurveBuyExactInInstruction as n, BPS as nn, LAUNCHLAB_INITIALIZE as nr, DRAW_POOL_OFFSET as nt, getClaimCreatorFeeInstructions as o, MIN_SEED_MULTIPLIER_BPS as on, LAUNCH_SUPPLY as or, fetchDraw as ot, curveQuote as p, resolveReservation as pn, SYSTEM_PROGRAM_ADDRESS as pr, listDrawsByPool as pt, CLAIM_COMPUTE_UNITS as q, CPMM_AMM_CONFIG_DISCRIMINATOR as qn, creatorFeeVaultAuthority as qt, claimCreatorFee as r, DEFAULT_TIERS as rn, LAUNCHLAB_PLATFORM_CONFIG_DISCRIMINATOR as rr, DRAW_PURCHASER_OFFSET as rt, getCollectCreatorFeeInstructions as s, TICKETS as sn, LAUNCH_TOTAL_BASE_SELL as sr, fetchPoolAt as st, raydium_exports as t, platformFeeVaultAddress as tn, LAUNCHLAB_GLOBAL_CONFIG_DISCRIMINATOR as tr, getSetComputeUnitPriceInstruction as tt, withRemainingAccounts as u, choose as un, RAYDIUM_DEVNET_IDS as ur, fetchVaultBalance as ut, newCurveReserves as v, validateTiers as vn, CPMM_AMM_CONFIG_HEAD_SIZE as vt, ceilDivRate as w, RETRY_SLOTS as wn, LAUNCHLAB_POOL_STATE_HEAD_SIZE as wt, sellQuote as x, INSTRUCTIONS_SYSVAR as xn, CPMM_POOL_STATE_SIZE as xt, quoteAccountFor as y, GABOX_PROGRAM_ID as yn, CPMM_POOL_OFFSETS as yt, order as z, MIGRATE_TO_CPMM as zn, scopedVrfIdentityAddress as zt };
|
|
2603
3281
|
|
|
2604
|
-
//# sourceMappingURL=raydium-
|
|
3282
|
+
//# sourceMappingURL=raydium-CU-tZzIk.js.map
|