@ickb/sdk 1000.0.43 → 1000.0.71
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/dist/cjs/codec.d.ts +14 -0
- package/dist/cjs/codec.d.ts.map +1 -0
- package/dist/cjs/codec.js +125 -0
- package/dist/cjs/codec.js.map +1 -0
- package/dist/cjs/constants.d.ts +49 -0
- package/dist/cjs/constants.d.ts.map +1 -0
- package/dist/cjs/constants.js +156 -0
- package/dist/cjs/constants.js.map +1 -0
- package/dist/cjs/index.d.ts +3 -78
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +17 -232
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/sdk.d.ts +178 -0
- package/dist/cjs/sdk.d.ts.map +1 -0
- package/dist/cjs/sdk.js +362 -0
- package/dist/cjs/sdk.js.map +1 -0
- package/dist/esm/codec.d.ts +14 -0
- package/dist/esm/codec.d.ts.map +1 -0
- package/dist/esm/codec.js +122 -0
- package/dist/esm/codec.js.map +1 -0
- package/dist/esm/constants.d.ts +49 -0
- package/dist/esm/constants.d.ts.map +1 -0
- package/dist/esm/constants.js +152 -0
- package/dist/esm/constants.js.map +1 -0
- package/dist/esm/index.d.ts +3 -78
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +3 -230
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/sdk.d.ts +178 -0
- package/dist/esm/sdk.d.ts.map +1 -0
- package/dist/esm/sdk.js +358 -0
- package/dist/esm/sdk.js.map +1 -0
- package/package.json +9 -9
- package/src/codec.ts +138 -0
- package/src/constants.ts +200 -0
- package/src/index.ts +3 -407
- package/src/sdk.ts +513 -0
package/src/index.ts
CHANGED
|
@@ -1,407 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
epochCompare,
|
|
5
|
-
CapacityManager,
|
|
6
|
-
SmartTransaction,
|
|
7
|
-
type ScriptDeps,
|
|
8
|
-
type UdtCell,
|
|
9
|
-
type CapacityCell,
|
|
10
|
-
epochAdd,
|
|
11
|
-
asyncBinarySearch,
|
|
12
|
-
RestrictedTransaction,
|
|
13
|
-
type ExchangeRatio,
|
|
14
|
-
} from "@ickb/utils";
|
|
15
|
-
import {
|
|
16
|
-
convert,
|
|
17
|
-
ICKB_DEPOSIT_CAP,
|
|
18
|
-
ickbExchangeRatio,
|
|
19
|
-
IckbUdtManager,
|
|
20
|
-
LogicManager,
|
|
21
|
-
OwnedOwnerManager,
|
|
22
|
-
type IckbDepositCell,
|
|
23
|
-
type ReceiptCell,
|
|
24
|
-
type WithdrawalGroup,
|
|
25
|
-
} from "@ickb/core";
|
|
26
|
-
import { DaoManager, type DaoCell } from "@ickb/dao";
|
|
27
|
-
import {
|
|
28
|
-
Info,
|
|
29
|
-
OrderManager,
|
|
30
|
-
type OrderCell,
|
|
31
|
-
type OrderGroup,
|
|
32
|
-
} from "@ickb/order";
|
|
33
|
-
|
|
34
|
-
export class IckbController {
|
|
35
|
-
constructor(
|
|
36
|
-
public readonly ickbUdtManager: IckbUdtManager,
|
|
37
|
-
public readonly logicManager: LogicManager,
|
|
38
|
-
public readonly ownedOwnerManager: OwnedOwnerManager,
|
|
39
|
-
public readonly orderManager: OrderManager,
|
|
40
|
-
public readonly daoManager: DaoManager,
|
|
41
|
-
) {}
|
|
42
|
-
|
|
43
|
-
static fromDeps({
|
|
44
|
-
xudt,
|
|
45
|
-
dao,
|
|
46
|
-
ickbLogic,
|
|
47
|
-
ownedOwner,
|
|
48
|
-
order,
|
|
49
|
-
}: {
|
|
50
|
-
xudt: ScriptDeps;
|
|
51
|
-
dao: ScriptDeps;
|
|
52
|
-
ickbLogic: ScriptDeps;
|
|
53
|
-
ownedOwner: ScriptDeps;
|
|
54
|
-
order: ScriptDeps;
|
|
55
|
-
}): IckbController {
|
|
56
|
-
const daoManager = DaoManager.fromDeps(dao);
|
|
57
|
-
|
|
58
|
-
const {
|
|
59
|
-
script: { codeHash, hashType },
|
|
60
|
-
cellDeps,
|
|
61
|
-
} = xudt;
|
|
62
|
-
const ickbXudt = {
|
|
63
|
-
script: new ccc.Script(
|
|
64
|
-
codeHash,
|
|
65
|
-
hashType,
|
|
66
|
-
[ickbLogic.script.hash(), "00000080"].join("") as ccc.Hex,
|
|
67
|
-
),
|
|
68
|
-
cellDeps,
|
|
69
|
-
};
|
|
70
|
-
const ickbUdtManager = IckbUdtManager.fromDeps(ickbXudt, daoManager);
|
|
71
|
-
|
|
72
|
-
return new IckbController(
|
|
73
|
-
ickbUdtManager,
|
|
74
|
-
LogicManager.fromDeps(ickbLogic, daoManager, ickbUdtManager),
|
|
75
|
-
OwnedOwnerManager.fromDeps(ownedOwner, daoManager, ickbUdtManager),
|
|
76
|
-
OrderManager.fromDeps(order, ickbUdtManager),
|
|
77
|
-
daoManager,
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// fee examples:
|
|
82
|
-
// 100000n => 0.001%
|
|
83
|
-
// 10000n => 0.01%
|
|
84
|
-
// 1000n => 0.1%
|
|
85
|
-
// 100n => 1%
|
|
86
|
-
// 10n => 10%
|
|
87
|
-
// 1n => 100%
|
|
88
|
-
// less than 1n => 0%
|
|
89
|
-
static previewConversion(conversion: {
|
|
90
|
-
isCkb2Udt: boolean;
|
|
91
|
-
amount: ccc.FixedPoint;
|
|
92
|
-
rate: ExchangeRatio | ccc.ClientBlockHeader;
|
|
93
|
-
fee: ccc.Num;
|
|
94
|
-
}): { rate: ExchangeRatio; convertedAmount: ccc.FixedPoint } {
|
|
95
|
-
const { isCkb2Udt, amount, fee } = conversion;
|
|
96
|
-
let rate = conversion.rate;
|
|
97
|
-
rate = "dao" in rate ? ickbExchangeRatio(rate) : rate;
|
|
98
|
-
|
|
99
|
-
if (fee > ccc.Zero) {
|
|
100
|
-
const { ckbScale, udtScale } = rate;
|
|
101
|
-
rate = {
|
|
102
|
-
ckbScale,
|
|
103
|
-
// Worst case scenario where fee applies to the full amount
|
|
104
|
-
udtScale: udtScale + (isCkb2Udt ? 1n : -1n) * (udtScale / fee),
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const convertedAmount =
|
|
109
|
-
amount > ccc.Zero ? convert(isCkb2Udt, amount, rate) : ccc.Zero;
|
|
110
|
-
|
|
111
|
-
return { rate, convertedAmount };
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
async convert(options: {
|
|
115
|
-
conversion: Parameters<typeof IckbController.previewConversion>[0] & {
|
|
116
|
-
ckbMinMatchLog?: number;
|
|
117
|
-
ckbMinFee?: ccc.Num;
|
|
118
|
-
};
|
|
119
|
-
signer: ccc.Signer;
|
|
120
|
-
userCells: UserCells;
|
|
121
|
-
system: SystemState;
|
|
122
|
-
filters: {
|
|
123
|
-
isReadyOnly: boolean;
|
|
124
|
-
isFulfilledOnly: boolean;
|
|
125
|
-
};
|
|
126
|
-
}): Promise<Conversion | undefined> {
|
|
127
|
-
// Get user lock
|
|
128
|
-
const { system, signer } = options;
|
|
129
|
-
const lock = (await signer.getRecommendedAddressObj()).script;
|
|
130
|
-
|
|
131
|
-
// Normalize rate
|
|
132
|
-
const { rate } = IckbController.previewConversion({
|
|
133
|
-
...options.conversion,
|
|
134
|
-
amount: ccc.Zero,
|
|
135
|
-
});
|
|
136
|
-
const { isCkb2Udt, amount, ckbMinMatchLog } = options.conversion;
|
|
137
|
-
const info = Info.create(isCkb2Udt, rate, ckbMinMatchLog);
|
|
138
|
-
// feeRate is a good approximation of the bot tx size matching the order
|
|
139
|
-
const ckbMinFee = options.conversion.ckbMinFee ?? 10n * system.feeRate;
|
|
140
|
-
const conversion = {
|
|
141
|
-
isCkb2Udt,
|
|
142
|
-
amount,
|
|
143
|
-
rate,
|
|
144
|
-
info,
|
|
145
|
-
ckbMinFee,
|
|
146
|
-
lock,
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
const N = isCkb2Udt
|
|
150
|
-
? Number(amount / system.ckbDepositCap)
|
|
151
|
-
: system.depositPool.slice(0, 30).length;
|
|
152
|
-
|
|
153
|
-
const cache = Array<ReturnType<IckbController["convert"]>>(N);
|
|
154
|
-
const cachedAttempt = (
|
|
155
|
-
n: number,
|
|
156
|
-
): ReturnType<IckbController["convert"]> => {
|
|
157
|
-
n = N - n;
|
|
158
|
-
return (cache[n] = cache[n] ?? this.attempt(n, conversion, options));
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
return cachedAttempt(
|
|
162
|
-
await asyncBinarySearch(
|
|
163
|
-
N,
|
|
164
|
-
async (n: number) => (await cachedAttempt(n)) !== undefined,
|
|
165
|
-
),
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
private async attempt(
|
|
170
|
-
n: number,
|
|
171
|
-
conversion: {
|
|
172
|
-
isCkb2Udt: boolean;
|
|
173
|
-
amount: bigint;
|
|
174
|
-
rate: ExchangeRatio;
|
|
175
|
-
info: Info;
|
|
176
|
-
ckbMinFee: ccc.Num;
|
|
177
|
-
lock: ccc.Script;
|
|
178
|
-
},
|
|
179
|
-
options: Omit<Parameters<IckbController["convert"]>[0], "conversion">,
|
|
180
|
-
): ReturnType<IckbController["convert"]> {
|
|
181
|
-
try {
|
|
182
|
-
const { isCkb2Udt, rate, info, ckbMinFee, lock } = conversion;
|
|
183
|
-
const { signer, userCells, system, filters } = options;
|
|
184
|
-
const { feeRate, depositPool, ckbDepositCap, exchangeRatio } = system;
|
|
185
|
-
|
|
186
|
-
const tx = SmartTransaction.default();
|
|
187
|
-
const maturities: ccc.Epoch[] = [];
|
|
188
|
-
let ckbFee = ccc.Zero;
|
|
189
|
-
let amount = conversion.amount;
|
|
190
|
-
|
|
191
|
-
// Core protocol
|
|
192
|
-
if (n > 0) {
|
|
193
|
-
if (isCkb2Udt) {
|
|
194
|
-
amount -= ckbDepositCap * BigInt(n);
|
|
195
|
-
if (amount < ccc.Zero) {
|
|
196
|
-
// Too many Deposits respectfully to the amount
|
|
197
|
-
return undefined;
|
|
198
|
-
}
|
|
199
|
-
this.logicManager.deposit(tx, n, ckbDepositCap, lock);
|
|
200
|
-
} else {
|
|
201
|
-
const myDeposits = depositPool.slice(0, n);
|
|
202
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
203
|
-
amount -= myDeposits.slice(-1)[0]!.udtCumulative;
|
|
204
|
-
if (amount < ccc.Zero) {
|
|
205
|
-
// Too many Withdrawal Requests respectfully to the amount
|
|
206
|
-
return undefined;
|
|
207
|
-
}
|
|
208
|
-
this.ownedOwnerManager.requestWithdrawal(tx, myDeposits, lock);
|
|
209
|
-
maturities.push(...myDeposits.map((d) => d.maturity));
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Order protocol
|
|
214
|
-
if (amount > ccc.Zero) {
|
|
215
|
-
this.orderManager.mint(tx, lock, info, {
|
|
216
|
-
ckbValue: isCkb2Udt ? amount : ccc.Zero,
|
|
217
|
-
udtValue: isCkb2Udt ? ccc.Zero : amount,
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
const convertedAmount = convert(isCkb2Udt, amount, rate);
|
|
221
|
-
ckbFee = isCkb2Udt
|
|
222
|
-
? amount - convert(false, convertedAmount, exchangeRatio)
|
|
223
|
-
: convert(true, amount, exchangeRatio) - convertedAmount;
|
|
224
|
-
|
|
225
|
-
maturities.push(
|
|
226
|
-
// TODO: use real world data from deposits, open orders and bot balances
|
|
227
|
-
orderMaturityEstimate(isCkb2Udt, amount, system.tip),
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Check that order provides enough fee to the bot for being matched
|
|
232
|
-
if (ckbFee < ckbMinFee) {
|
|
233
|
-
return undefined;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
const { receipts, withdrawalGroups, orders, udts, capacities } =
|
|
237
|
-
userCells;
|
|
238
|
-
|
|
239
|
-
this.logicManager.completeDeposit(tx, receipts);
|
|
240
|
-
this.ownedOwnerManager.withdraw(tx, withdrawalGroups, filters);
|
|
241
|
-
this.orderManager.melt(tx, orders, filters);
|
|
242
|
-
this.ickbUdtManager.addUdts(tx, udts);
|
|
243
|
-
CapacityManager.addCapacities(tx, capacities);
|
|
244
|
-
|
|
245
|
-
// Throw an error if inputs do not cover for outputs
|
|
246
|
-
await new RestrictedTransaction(tx).completeFeeBy(signer, feeRate);
|
|
247
|
-
|
|
248
|
-
// Find the maturity most distant in the future
|
|
249
|
-
const maturity = maturities.reduce((a, b) =>
|
|
250
|
-
epochCompare(a, b) === -1 ? b : a,
|
|
251
|
-
);
|
|
252
|
-
|
|
253
|
-
return {
|
|
254
|
-
tx,
|
|
255
|
-
ckbFee,
|
|
256
|
-
maturity,
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
260
|
-
} catch (_) {
|
|
261
|
-
return undefined;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
async getL1State(
|
|
266
|
-
client: ccc.Client,
|
|
267
|
-
filter: Set<keyof UserCells | "depositPool">,
|
|
268
|
-
locks: ccc.Script[],
|
|
269
|
-
options?: {
|
|
270
|
-
minLockUp?: ccc.Epoch;
|
|
271
|
-
maxLockUp?: ccc.Epoch;
|
|
272
|
-
},
|
|
273
|
-
): Promise<{
|
|
274
|
-
system: SystemState;
|
|
275
|
-
user: UserCells;
|
|
276
|
-
}> {
|
|
277
|
-
const tip = await client.getTipHeader();
|
|
278
|
-
const onChain = true;
|
|
279
|
-
const opts = { ...options, tip, onChain };
|
|
280
|
-
const [
|
|
281
|
-
feeRate,
|
|
282
|
-
depositPool,
|
|
283
|
-
capacities,
|
|
284
|
-
udts,
|
|
285
|
-
receipts,
|
|
286
|
-
withdrawalGroups,
|
|
287
|
-
orders,
|
|
288
|
-
deposits,
|
|
289
|
-
withdrawalRequests,
|
|
290
|
-
] = await Promise.all([
|
|
291
|
-
client.getFeeRate(),
|
|
292
|
-
filter.has("depositPool")
|
|
293
|
-
? collect(this.logicManager.findDeposits(client, opts))
|
|
294
|
-
: [],
|
|
295
|
-
filter.has("capacities")
|
|
296
|
-
? collect(CapacityManager.findCapacities(client, locks, opts))
|
|
297
|
-
: [],
|
|
298
|
-
filter.has("udts")
|
|
299
|
-
? collect(this.ickbUdtManager.findUdts(client, locks, opts))
|
|
300
|
-
: [],
|
|
301
|
-
filter.has("receipts")
|
|
302
|
-
? collect(this.logicManager.findReceipts(client, locks, opts))
|
|
303
|
-
: [],
|
|
304
|
-
filter.has("withdrawalGroups")
|
|
305
|
-
? collect(
|
|
306
|
-
this.ownedOwnerManager.findWithdrawalGroups(client, locks, opts),
|
|
307
|
-
)
|
|
308
|
-
: [],
|
|
309
|
-
filter.has("orders") ? collect(this.orderManager.findOrders(client)) : [],
|
|
310
|
-
filter.has("deposits")
|
|
311
|
-
? collect(this.daoManager.findDeposits(client, locks, opts))
|
|
312
|
-
: [],
|
|
313
|
-
filter.has("withdrawalRequests")
|
|
314
|
-
? collect(this.daoManager.findWithdrawalRequests(client, locks, opts))
|
|
315
|
-
: [],
|
|
316
|
-
// TODO: fetch bot cells for estimating timings
|
|
317
|
-
]);
|
|
318
|
-
|
|
319
|
-
// Sort depositPool by maturity
|
|
320
|
-
depositPool.sort((a, b) => epochCompare(a.maturity, b.maturity));
|
|
321
|
-
// Calculate cumulative value of deposits in the pool
|
|
322
|
-
let udtCumulative = 0n;
|
|
323
|
-
const cumulativeDepositPool: SystemState["depositPool"] = [];
|
|
324
|
-
for (const deposit of depositPool) {
|
|
325
|
-
udtCumulative += deposit.udtValue;
|
|
326
|
-
cumulativeDepositPool.push({ ...deposit, udtCumulative });
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
const userOrders: OrderGroup[] = [];
|
|
330
|
-
const nonUserOrders: OrderCell[] = [];
|
|
331
|
-
for (const group of orders) {
|
|
332
|
-
if (group.isOwner(...locks)) {
|
|
333
|
-
userOrders.push(group);
|
|
334
|
-
} else {
|
|
335
|
-
nonUserOrders.push(group.order);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
const exchangeRatio = ickbExchangeRatio(tip);
|
|
340
|
-
const ckbDepositCap = convert(false, ICKB_DEPOSIT_CAP, exchangeRatio);
|
|
341
|
-
|
|
342
|
-
return {
|
|
343
|
-
system: {
|
|
344
|
-
feeRate,
|
|
345
|
-
tip,
|
|
346
|
-
exchangeRatio,
|
|
347
|
-
ckbDepositCap,
|
|
348
|
-
udtDepositCap: ICKB_DEPOSIT_CAP,
|
|
349
|
-
depositPool: cumulativeDepositPool,
|
|
350
|
-
orderPool: nonUserOrders,
|
|
351
|
-
},
|
|
352
|
-
user: {
|
|
353
|
-
capacities,
|
|
354
|
-
udts,
|
|
355
|
-
receipts,
|
|
356
|
-
withdrawalGroups,
|
|
357
|
-
orders: userOrders,
|
|
358
|
-
deposits,
|
|
359
|
-
withdrawalRequests,
|
|
360
|
-
},
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
export interface SystemState {
|
|
366
|
-
feeRate: ccc.Num;
|
|
367
|
-
tip: ccc.ClientBlockHeader;
|
|
368
|
-
exchangeRatio: {
|
|
369
|
-
ckbScale: ccc.Num;
|
|
370
|
-
udtScale: ccc.Num;
|
|
371
|
-
};
|
|
372
|
-
ckbDepositCap: ccc.FixedPoint;
|
|
373
|
-
udtDepositCap: ccc.FixedPoint;
|
|
374
|
-
depositPool: (IckbDepositCell & { udtCumulative: bigint })[];
|
|
375
|
-
orderPool: OrderCell[];
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
export interface UserCells {
|
|
379
|
-
capacities: CapacityCell[];
|
|
380
|
-
udts: UdtCell[];
|
|
381
|
-
receipts: ReceiptCell[];
|
|
382
|
-
withdrawalGroups: WithdrawalGroup[];
|
|
383
|
-
orders: OrderGroup[];
|
|
384
|
-
deposits: DaoCell[];
|
|
385
|
-
withdrawalRequests: DaoCell[];
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
export interface Conversion {
|
|
389
|
-
tx: SmartTransaction;
|
|
390
|
-
ckbFee: ccc.FixedPoint;
|
|
391
|
-
maturity: ccc.Epoch;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
// Estimate bot ability to fulfill orders:
|
|
395
|
-
// - CKB to iCKB orders at 100k CKB every minute
|
|
396
|
-
// - iCKB to CKB orders at 200 CKB every minute
|
|
397
|
-
function orderMaturityEstimate(
|
|
398
|
-
isCkb2Udt: boolean,
|
|
399
|
-
amount: bigint,
|
|
400
|
-
tip: ccc.ClientBlockHeader,
|
|
401
|
-
): ccc.Epoch {
|
|
402
|
-
return epochAdd(tip.epoch, [
|
|
403
|
-
0n,
|
|
404
|
-
1n + amount / ccc.fixedPointFrom(isCkb2Udt ? 100000 : 200),
|
|
405
|
-
4n * 60n,
|
|
406
|
-
]);
|
|
407
|
-
}
|
|
1
|
+
export * from "./sdk.js";
|
|
2
|
+
export * from "./codec.js";
|
|
3
|
+
export * from "./constants.js";
|