@interest-protocol/blast-migrators-sdk 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/dist/bluefin-pool.d.ts +57 -0
- package/dist/bluefin-pool.d.ts.map +1 -0
- package/dist/bluefin-pool.js +102 -0
- package/dist/bluefin-pool.js.map +1 -0
- package/dist/cetus-pool.d.ts +44 -0
- package/dist/cetus-pool.d.ts.map +1 -0
- package/dist/cetus-pool.js +57 -0
- package/dist/cetus-pool.js.map +1 -0
- package/dist/client.d.ts +25 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +34 -0
- package/dist/client.js.map +1 -0
- package/dist/events.d.ts +168 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +180 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/reducer.d.ts +139 -0
- package/dist/reducer.d.ts.map +1 -0
- package/dist/reducer.js +376 -0
- package/dist/reducer.js.map +1 -0
- package/dist/state.d.ts +166 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +187 -0
- package/dist/state.js.map +1 -0
- package/dist/transactions.d.ts +314 -0
- package/dist/transactions.d.ts.map +1 -0
- package/dist/transactions.js +604 -0
- package/dist/transactions.js.map +1 -0
- package/package.json +68 -4
- package/src/bluefin-pool.ts +180 -0
- package/src/cetus-pool.ts +107 -0
- package/src/client.ts +76 -0
- package/src/events.ts +285 -0
- package/src/index.ts +8 -0
- package/src/reducer.ts +562 -0
- package/src/state.ts +316 -0
- package/src/transactions.ts +1068 -0
package/src/state.ts
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import {
|
|
2
|
+
moveTypeNameBcs,
|
|
3
|
+
suiBalanceBcs,
|
|
4
|
+
suiIdBcs,
|
|
5
|
+
suiObjectIdBcs,
|
|
6
|
+
suiUidBcs,
|
|
7
|
+
} 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
|
+
import { bcs } from "@mysten/sui/bcs";
|
|
16
|
+
import type { ClientWithCoreApi } from "@mysten/sui/client";
|
|
17
|
+
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
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
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.
|
|
39
|
+
*/
|
|
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
|
+
});
|
|
87
|
+
|
|
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,
|
|
92
|
+
});
|
|
93
|
+
|
|
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
|
+
};
|
|
136
|
+
|
|
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
|
+
}
|
|
204
|
+
|
|
205
|
+
export async function getLpVault(
|
|
206
|
+
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
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** Reads the shared `LpFeePolicy` singleton. */
|
|
230
|
+
export async function getLpFeePolicy(
|
|
231
|
+
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
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
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.
|
|
277
|
+
*/
|
|
278
|
+
export async function getLpFeeShares(
|
|
279
|
+
client: ClientWithCoreApi,
|
|
280
|
+
policy: Pick<LpFeePolicyState, "coinSharesTableId" | "defaultShares">,
|
|
281
|
+
memeType: string,
|
|
282
|
+
): Promise<LpFeeShares & { source: "coin" | "default" }> {
|
|
283
|
+
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
|
+
},
|
|
292
|
+
});
|
|
293
|
+
const pair = lpFeeSharePairBcs.parse(dynamicField.value.bcs);
|
|
294
|
+
return { memeBps: pair.meme_bps, quoteBps: pair.quote_bps, source: "coin" };
|
|
295
|
+
} catch (error) {
|
|
296
|
+
if (!(error instanceof ObjectError) || error.reason !== "notFound") {
|
|
297
|
+
throw error;
|
|
298
|
+
}
|
|
299
|
+
return { ...policy.defaultShares, source: "default" };
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
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;
|
|
307
|
+
}
|
|
308
|
+
|
|
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");
|
|
314
|
+
}
|
|
315
|
+
return normalizeStructTag(type);
|
|
316
|
+
}
|