@interest-protocol/blast-migrators-sdk 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/aborts.d.ts +12 -0
  2. package/dist/aborts.d.ts.map +1 -0
  3. package/dist/aborts.js +21 -0
  4. package/dist/aborts.js.map +1 -0
  5. package/dist/client.d.ts +8 -11
  6. package/dist/client.d.ts.map +1 -1
  7. package/dist/client.js +12 -14
  8. package/dist/client.js.map +1 -1
  9. package/dist/events.d.ts +30 -160
  10. package/dist/events.d.ts.map +1 -1
  11. package/dist/events.js +33 -168
  12. package/dist/events.js.map +1 -1
  13. package/dist/index.d.ts +1 -3
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +1 -3
  16. package/dist/index.js.map +1 -1
  17. package/dist/reducer.d.ts +20 -132
  18. package/dist/reducer.d.ts.map +1 -1
  19. package/dist/reducer.js +28 -361
  20. package/dist/reducer.js.map +1 -1
  21. package/dist/state.d.ts +32 -152
  22. package/dist/state.d.ts.map +1 -1
  23. package/dist/state.js +61 -167
  24. package/dist/state.js.map +1 -1
  25. package/dist/transactions.d.ts +204 -259
  26. package/dist/transactions.d.ts.map +1 -1
  27. package/dist/transactions.js +347 -449
  28. package/dist/transactions.js.map +1 -1
  29. package/package.json +7 -10
  30. package/src/aborts.ts +24 -0
  31. package/src/client.ts +19 -34
  32. package/src/events.ts +54 -261
  33. package/src/index.ts +1 -3
  34. package/src/reducer.ts +46 -538
  35. package/src/state.ts +88 -282
  36. package/src/transactions.ts +569 -838
  37. package/dist/bluefin-pool.d.ts +0 -57
  38. package/dist/bluefin-pool.d.ts.map +0 -1
  39. package/dist/bluefin-pool.js +0 -102
  40. package/dist/bluefin-pool.js.map +0 -1
  41. package/dist/cetus-pool.d.ts +0 -44
  42. package/dist/cetus-pool.d.ts.map +0 -1
  43. package/dist/cetus-pool.js +0 -57
  44. package/dist/cetus-pool.js.map +0 -1
  45. package/src/bluefin-pool.ts +0 -180
  46. package/src/cetus-pool.ts +0 -107
package/src/state.ts CHANGED
@@ -1,316 +1,122 @@
1
1
  import {
2
- moveTypeNameBcs,
3
- suiBalanceBcs,
4
- suiIdBcs,
5
- suiObjectIdBcs,
6
2
  suiUidBcs,
3
+ u64Bcs,
4
+ unitKeyBcs,
7
5
  } from "@interest-protocol/blast-core/bcs";
8
- import { normalizePositiveU64 } from "@interest-protocol/blast-core/integers";
9
- import type { SharedObjectReference } from "@interest-protocol/blast-core/sui";
10
- import type { FeeSplit } from "@interest-protocol/blast-launchpad-sdk/allocation";
11
- import {
12
- bpsBcs,
13
- feeSplitBcs,
14
- } from "@interest-protocol/blast-launchpad-sdk/allocation";
15
6
  import { bcs } from "@mysten/sui/bcs";
16
7
  import type { ClientWithCoreApi } from "@mysten/sui/client";
17
8
  import { ObjectError } from "@mysten/sui/client";
18
- import {
19
- normalizeStructTag,
20
- normalizeSuiAddress,
21
- normalizeSuiObjectId,
22
- parseStructTag,
23
- } from "@mysten/sui/utils";
24
-
25
- /** Venues whose adapters the migrators package ships. */
26
- export const MIGRATOR_VENUES = ["bluefin", "cetus"] as const;
27
- export type MigratorVenue = (typeof MIGRATOR_VENUES)[number];
28
-
29
- export type LaunchMigrationRoute = {
30
- venue: MigratorVenue;
31
- tickSpacing: number;
32
- feeRate: bigint;
33
- };
9
+ import { normalizeStructTag, normalizeSuiObjectId } from "@mysten/sui/utils";
10
+ import type { MigratorsDeployment } from "./transactions.ts";
34
11
 
35
12
  /**
36
- * Identifies a launch's recorded route from its `migration_witness` (the
37
- * adapter's `Witness` type, by original package ID) and its pool tier. Rejects
38
- * a witness from another migrators package or a venue this SDK cannot route.
13
+ * BCS layout of `venue_config::VenueConfig`: its UID only. Venue records are
14
+ * dynamic fields of it, keyed by venue-sealed field-less structs
15
+ * (`PoolTierKey<Meme>()`, `CreationCapKey<Meme>()`) that encode as one zero
16
+ * byte.
39
17
  */
40
- export function launchMigrationRoute(
41
- launch: {
42
- migrationWitnessType: string;
43
- poolTickSpacing: number;
44
- poolFeeRate: bigint;
45
- },
46
- migratorsOriginalPackageId: string,
47
- ): LaunchMigrationRoute {
48
- const tag = parseStructTag(launch.migrationWitnessType);
49
- if (tag.address !== normalizeSuiAddress(migratorsOriginalPackageId)) {
50
- throw new TypeError(
51
- "the launch migrates through another migrators package",
52
- );
53
- }
54
- const venue = tag.module as MigratorVenue;
55
- if (!MIGRATOR_VENUES.includes(venue) || tag.name !== "Witness") {
56
- throw new RangeError(
57
- `unsupported migration route ${tag.module}::${tag.name}`,
58
- );
59
- }
60
- return {
61
- venue,
62
- tickSpacing: launch.poolTickSpacing,
63
- feeRate: launch.poolFeeRate,
64
- };
65
- }
66
-
67
- /** BCS layout of `blast_fun_migrators::vault::LpVault<Meme, Quote>`. */
68
- export const lpVaultBcs = bcs.struct("LpVault", {
69
- id: suiUidBcs,
70
- pool_id: suiIdBcs,
71
- partner_id: bcs.option(suiObjectIdBcs),
72
- protocol_meme_residual: suiBalanceBcs,
73
- protocol_quote_residual: suiBalanceBcs,
74
- unpaid_protocol_meme: suiBalanceBcs,
75
- unpaid_protocol_quote: suiBalanceBcs,
76
- fee_split: feeSplitBcs,
77
- creator_meme: suiBalanceBcs,
78
- creator_quote: suiBalanceBcs,
79
- auto_lp_meme: suiBalanceBcs,
80
- auto_lp_quote: suiBalanceBcs,
81
- rewards_meme: suiBalanceBcs,
82
- rewards_quote: suiBalanceBcs,
83
- burn_quote: suiBalanceBcs,
84
- next_round: bcs.u64(),
85
- last_checkpoint: bcs.option(bcs.u64()),
86
- });
18
+ export const venueConfigBcs = bcs.struct("VenueConfig", { id: suiUidBcs });
87
19
 
88
- /** BCS layout of `blast_fun_migrators::lp_fee_policy::SharePair`. */
89
- export const lpFeeSharePairBcs = bcs.struct("SharePair", {
90
- meme_bps: bpsBcs,
91
- quote_bps: bpsBcs,
20
+ /** `bluefin::PoolTier`: the Bluefin pool tier a Meme's migration uses. */
21
+ export const bluefinPoolTierBcs = bcs.struct("PoolTier", {
22
+ tick_spacing: bcs.u32(),
23
+ fee_rate: u64Bcs,
92
24
  });
93
25
 
94
- /** BCS layout of `blast_fun_migrators::lp_fee_policy::LpFeePolicy`. */
95
- export const lpFeePolicyBcs = bcs.struct("LpFeePolicy", {
96
- id: suiUidBcs,
97
- destination: bcs.Address,
98
- defaults: lpFeeSharePairBcs,
99
- coins: bcs.struct("Table", { id: suiUidBcs, size: bcs.u64() }),
100
- });
101
-
102
- export type LpVaultState = SharedObjectReference<true> & {
103
- memeType: string;
104
- quoteType: string;
105
- poolId: string;
106
- /** The partner the launch named, paid its cut of Blast's LP fees; null for none. */
107
- partnerId: string | null;
108
- /** Protocol-owned migration residuals, claimable by an administrator. */
109
- protocolMemeResidual: bigint;
110
- protocolQuoteResidual: bigint;
111
- /** Blast's LP fees a partnered vault holds until `claimProtocolLpFeesWithPartner`. */
112
- unpaidProtocolMeme: bigint;
113
- unpaidProtocolQuote: bigint;
114
- feeSplit: FeeSplit;
115
- /** Creator LP fees claimable by the launch's live `CurveFeeCap`. */
116
- creatorMeme: bigint;
117
- creatorQuote: bigint;
118
- /** Auto-LP amounts the pool did not take yet; the next collection retries. */
119
- autoLpMeme: bigint;
120
- autoLpQuote: bigint;
121
- /** Rewards not yet reserved by a holder-reward round. */
122
- rewardsMeme: bigint;
123
- rewardsQuote: bigint;
124
- /** Burn-share Quote waiting for a buyback admin to swap it for Meme to burn. */
125
- burnQuote: bigint;
126
- /** Number the next holder-reward round must carry. */
127
- nextRound: bigint;
128
- /** Checkpoint the next round must start at; null before the first round. */
129
- lastCheckpoint: bigint | null;
130
- };
131
-
132
- export type LpVaultObject = SharedObjectReference<true> & {
133
- type: string;
134
- content: Uint8Array;
135
- };
26
+ /** A Bluefin pool tier; `feeRate` is in Bluefin fee units (1,000,000 is 100%). */
27
+ export type BluefinPoolTier = { tickSpacing: number; feeRate: bigint };
136
28
 
137
- export type LpFeeShares = { memeBps: bigint; quoteBps: bigint };
138
-
139
- export type LpFeePolicyState = SharedObjectReference<false> & {
140
- /** Address every collection pays Blast's share to. */
141
- protocolDestination: string;
142
- defaultShares: LpFeeShares;
143
- /** Table of per-coin share pairs, keyed by original Meme `TypeName`. */
144
- coinSharesTableId: string;
145
- coinSharesCount: bigint;
146
- };
147
-
148
- export function decodeLpVaultObject(
149
- object: LpVaultObject,
150
- originalPackageId: string,
151
- ): LpVaultState {
152
- const tag = parseStructTag(object.type);
153
- if (tag.module !== "vault" || tag.name !== "LpVault") {
154
- throw new TypeError(`object ${object.objectId} is not an LP vault`);
155
- }
156
- if (tag.typeParams.length !== 2) {
157
- throw new TypeError(
158
- `LP vault ${object.objectId} must have two type arguments`,
159
- );
160
- }
161
- if (tag.address !== normalizeSuiAddress(originalPackageId)) {
162
- throw new TypeError(
163
- `LP vault ${object.objectId} has an unexpected package`,
164
- );
165
- }
166
- if (object.mutable !== true) {
167
- throw new TypeError(`LP vault ${object.objectId} must be mutable`);
168
- }
169
-
170
- const parsed = lpVaultBcs.parse(object.content);
171
- const objectId = normalizeSuiObjectId(object.objectId);
172
- if (normalizeSuiObjectId(parsed.id.id.bytes) !== objectId) {
173
- throw new TypeError(`LP vault ${object.objectId} has a mismatched UID`);
174
- }
175
-
176
- return {
177
- objectId,
178
- initialSharedVersion: normalizePositiveU64(
179
- "initialSharedVersion",
180
- object.initialSharedVersion,
181
- ),
182
- mutable: true,
183
- memeType: normalizeTypeParameter(tag.typeParams[0]),
184
- quoteType: normalizeTypeParameter(tag.typeParams[1]),
185
- poolId: normalizeSuiObjectId(parsed.pool_id.bytes),
186
- partnerId: parsed.partner_id,
187
- protocolMemeResidual: BigInt(parsed.protocol_meme_residual.value),
188
- protocolQuoteResidual: BigInt(parsed.protocol_quote_residual.value),
189
- unpaidProtocolMeme: BigInt(parsed.unpaid_protocol_meme.value),
190
- unpaidProtocolQuote: BigInt(parsed.unpaid_protocol_quote.value),
191
- feeSplit: parsed.fee_split,
192
- creatorMeme: BigInt(parsed.creator_meme.value),
193
- creatorQuote: BigInt(parsed.creator_quote.value),
194
- autoLpMeme: BigInt(parsed.auto_lp_meme.value),
195
- autoLpQuote: BigInt(parsed.auto_lp_quote.value),
196
- rewardsMeme: BigInt(parsed.rewards_meme.value),
197
- rewardsQuote: BigInt(parsed.rewards_quote.value),
198
- burnQuote: BigInt(parsed.burn_quote.value),
199
- nextRound: BigInt(parsed.next_round),
200
- lastCheckpoint:
201
- parsed.last_checkpoint === null ? null : BigInt(parsed.last_checkpoint),
202
- };
203
- }
29
+ type VenueConfigReader = Pick<
30
+ MigratorsDeployment,
31
+ "originalPackageId" | "venueConfig"
32
+ >;
204
33
 
205
- export async function getLpVault(
34
+ /**
35
+ * The tick spacing `cetus::prepare` recorded for `memeType`
36
+ * (`cetus::PoolTierKey<Meme>`), or null before the Meme is prepared for
37
+ * Cetus. Pass the Meme's original (defining) type address.
38
+ */
39
+ export async function getCetusPoolTier(
206
40
  client: ClientWithCoreApi,
207
- objectId: string,
208
- originalPackageId: string,
209
- ): Promise<LpVaultState> {
210
- const { object } = await client.core.getObject({
211
- objectId,
212
- include: { content: true },
213
- });
214
- if (object.owner.$kind !== "Shared") {
215
- throw new TypeError(`LP vault ${object.objectId} is not a shared object`);
216
- }
217
- return decodeLpVaultObject(
218
- {
219
- objectId: object.objectId,
220
- initialSharedVersion: object.owner.Shared.initialSharedVersion,
221
- mutable: true,
222
- type: object.type,
223
- content: object.content,
224
- },
225
- originalPackageId,
226
- );
41
+ migrators: VenueConfigReader,
42
+ memeType: string,
43
+ ): Promise<number | null> {
44
+ const value = await venueField(client, migrators, "cetus", memeType);
45
+ return value === null ? null : bcs.u32().parse(value);
227
46
  }
228
47
 
229
- /** Reads the shared `LpFeePolicy` singleton. */
230
- export async function getLpFeePolicy(
48
+ /**
49
+ * The tier `bluefin::prepare` recorded for `memeType`
50
+ * (`bluefin::PoolTierKey<Meme>`), or null before the Meme is prepared for
51
+ * Bluefin.
52
+ */
53
+ export async function getBluefinPoolTier(
231
54
  client: ClientWithCoreApi,
232
- objectId: string,
233
- originalPackageId: string,
234
- ): Promise<LpFeePolicyState> {
235
- const { object } = await client.core.getObject({
236
- objectId,
237
- include: { content: true },
238
- });
239
- if (object.owner.$kind !== "Shared") {
240
- throw new TypeError(`LP-fee policy ${object.objectId} is not shared`);
241
- }
242
- const expected = normalizeStructTag(
243
- `${normalizeSuiAddress(originalPackageId)}::lp_fee_policy::LpFeePolicy`,
244
- );
245
- if (normalizeStructTag(object.type) !== expected) {
246
- throw new TypeError(`object ${object.objectId} is not the LP-fee policy`);
247
- }
248
- const parsed = lpFeePolicyBcs.parse(object.content);
249
- if (
250
- normalizeSuiObjectId(parsed.id.id.bytes) !==
251
- normalizeSuiObjectId(object.objectId)
252
- ) {
253
- throw new TypeError(
254
- `LP-fee policy ${object.objectId} has a mismatched UID`,
255
- );
256
- }
257
- return {
258
- objectId: normalizeSuiObjectId(object.objectId),
259
- initialSharedVersion: normalizePositiveU64(
260
- "initialSharedVersion",
261
- object.owner.Shared.initialSharedVersion,
262
- ),
263
- mutable: false,
264
- protocolDestination: normalizeSuiAddress(parsed.destination),
265
- defaultShares: {
266
- memeBps: parsed.defaults.meme_bps,
267
- quoteBps: parsed.defaults.quote_bps,
268
- },
269
- coinSharesTableId: normalizeSuiObjectId(parsed.coins.id.id.bytes),
270
- coinSharesCount: BigInt(parsed.coins.size),
271
- };
55
+ migrators: VenueConfigReader,
56
+ memeType: string,
57
+ ): Promise<BluefinPoolTier | null> {
58
+ const value = await venueField(client, migrators, "bluefin", memeType);
59
+ if (value === null) return null;
60
+ const tier = bluefinPoolTierBcs.parse(value);
61
+ return { tickSpacing: tier.tick_spacing, feeRate: tier.fee_rate };
272
62
  }
273
63
 
274
64
  /**
275
- * Mirrors `lp_fee_policy::shares<Meme>`: the coin's own pair when an
276
- * administrator set one, otherwise the default pair. `source` says which.
65
+ * The ID of the Meme type's Cetus `PoolCreationCap`, kept in `VenueConfig`
66
+ * under `cetus::CreationCapKey<Meme>` (the `pool_creation_cap_id` of its
67
+ * `CetusPoolReserved`), or null before the Meme is prepared for Cetus.
277
68
  */
278
- export async function getLpFeeShares(
69
+ export async function getCetusPoolCreationCapId(
279
70
  client: ClientWithCoreApi,
280
- policy: Pick<LpFeePolicyState, "coinSharesTableId" | "defaultShares">,
71
+ migrators: VenueConfigReader,
281
72
  memeType: string,
282
- ): Promise<LpFeeShares & { source: "coin" | "default" }> {
73
+ ): Promise<string | null> {
283
74
  try {
284
- const { dynamicField } = await client.core.getDynamicField({
285
- parentId: policy.coinSharesTableId,
286
- name: {
287
- type: "0x1::type_name::TypeName",
288
- bcs: moveTypeNameBcs
289
- .serialize(originalTypeNameText(memeType))
290
- .toBytes(),
291
- },
75
+ const { object } = await client.core.getDynamicObjectField({
76
+ parentId: normalizeSuiObjectId(migrators.venueConfig.objectId),
77
+ name: venueKey(migrators, "cetus", "CreationCapKey", memeType),
292
78
  });
293
- const pair = lpFeeSharePairBcs.parse(dynamicField.value.bcs);
294
- return { memeBps: pair.meme_bps, quoteBps: pair.quote_bps, source: "coin" };
79
+ return normalizeSuiObjectId(object.objectId);
295
80
  } catch (error) {
296
- if (!(error instanceof ObjectError) || error.reason !== "notFound") {
297
- throw error;
298
- }
299
- return { ...policy.defaultShares, source: "default" };
81
+ if (error instanceof ObjectError && error.reason === "notFound")
82
+ return null;
83
+ throw error;
300
84
  }
301
85
  }
302
86
 
303
- /** Move `TypeName` text: the normalized tag without the `0x` address prefix. */
304
- function originalTypeNameText(type: string): string {
305
- const normalized = normalizeStructTag(type);
306
- return normalized.startsWith("0x") ? normalized.slice(2) : normalized;
87
+ /**
88
+ * The `VenueConfig` dynamic-field name `<original>::<venue>::<key><Meme>()`:
89
+ * the key type with the Meme's original type address, and one zero byte.
90
+ */
91
+ function venueKey(
92
+ migrators: Pick<MigratorsDeployment, "originalPackageId">,
93
+ venue: "cetus" | "bluefin",
94
+ key: "PoolTierKey" | "CreationCapKey",
95
+ memeType: string,
96
+ ): { type: string; bcs: Uint8Array } {
97
+ return {
98
+ type: normalizeStructTag(
99
+ `${normalizeSuiObjectId(migrators.originalPackageId)}::${venue}::${key}<${normalizeStructTag(memeType)}>`,
100
+ ),
101
+ bcs: unitKeyBcs.serialize(null).toBytes(),
102
+ };
307
103
  }
308
104
 
309
- function normalizeTypeParameter(
310
- type: ReturnType<typeof parseStructTag>["typeParams"][number] | undefined,
311
- ): string {
312
- if (type === undefined || typeof type === "string") {
313
- throw new TypeError("LP vault coin type must be a struct type");
105
+ async function venueField(
106
+ client: ClientWithCoreApi,
107
+ migrators: VenueConfigReader,
108
+ venue: "cetus" | "bluefin",
109
+ memeType: string,
110
+ ): Promise<Uint8Array | null> {
111
+ try {
112
+ const { dynamicField } = await client.core.getDynamicField({
113
+ parentId: normalizeSuiObjectId(migrators.venueConfig.objectId),
114
+ name: venueKey(migrators, venue, "PoolTierKey", memeType),
115
+ });
116
+ return dynamicField.value.bcs;
117
+ } catch (error) {
118
+ if (error instanceof ObjectError && error.reason === "notFound")
119
+ return null;
120
+ throw error;
314
121
  }
315
- return normalizeStructTag(type);
316
122
  }