@ickb/sdk 1000.0.26 → 1000.0.43
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/index.d.ts +35 -37
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +139 -172
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.d.ts +35 -37
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +142 -175
- package/dist/esm/index.js.map +1 -1
- package/package.json +5 -5
- package/src/index.ts +204 -276
package/src/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ccc
|
|
1
|
+
import { ccc } from "@ckb-ccc/core";
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
collect,
|
|
4
4
|
epochCompare,
|
|
5
5
|
CapacityManager,
|
|
6
6
|
SmartTransaction,
|
|
@@ -8,34 +8,36 @@ import {
|
|
|
8
8
|
type UdtCell,
|
|
9
9
|
type CapacityCell,
|
|
10
10
|
epochAdd,
|
|
11
|
-
|
|
11
|
+
asyncBinarySearch,
|
|
12
|
+
RestrictedTransaction,
|
|
13
|
+
type ExchangeRatio,
|
|
12
14
|
} from "@ickb/utils";
|
|
13
15
|
import {
|
|
14
16
|
convert,
|
|
15
17
|
ICKB_DEPOSIT_CAP,
|
|
16
18
|
ickbExchangeRatio,
|
|
17
|
-
|
|
19
|
+
IckbUdtManager,
|
|
18
20
|
LogicManager,
|
|
19
21
|
OwnedOwnerManager,
|
|
20
22
|
type IckbDepositCell,
|
|
21
23
|
type ReceiptCell,
|
|
22
|
-
type
|
|
24
|
+
type WithdrawalGroup,
|
|
23
25
|
} from "@ickb/core";
|
|
24
|
-
import { DaoManager } from "@ickb/dao";
|
|
26
|
+
import { DaoManager, type DaoCell } from "@ickb/dao";
|
|
25
27
|
import {
|
|
26
28
|
Info,
|
|
27
29
|
OrderManager,
|
|
28
|
-
Ratio,
|
|
29
30
|
type OrderCell,
|
|
30
31
|
type OrderGroup,
|
|
31
32
|
} from "@ickb/order";
|
|
32
33
|
|
|
33
34
|
export class IckbController {
|
|
34
35
|
constructor(
|
|
35
|
-
public
|
|
36
|
-
public logicManager: LogicManager,
|
|
37
|
-
public ownedOwnerManager: OwnedOwnerManager,
|
|
38
|
-
public orderManager: OrderManager,
|
|
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,
|
|
39
41
|
) {}
|
|
40
42
|
|
|
41
43
|
static fromDeps({
|
|
@@ -65,190 +67,205 @@ export class IckbController {
|
|
|
65
67
|
),
|
|
66
68
|
cellDeps,
|
|
67
69
|
};
|
|
68
|
-
const
|
|
70
|
+
const ickbUdtManager = IckbUdtManager.fromDeps(ickbXudt, daoManager);
|
|
69
71
|
|
|
70
72
|
return new IckbController(
|
|
71
|
-
|
|
72
|
-
LogicManager.fromDeps(ickbLogic, daoManager,
|
|
73
|
-
OwnedOwnerManager.fromDeps(ownedOwner, daoManager,
|
|
74
|
-
OrderManager.fromDeps(order,
|
|
73
|
+
ickbUdtManager,
|
|
74
|
+
LogicManager.fromDeps(ickbLogic, daoManager, ickbUdtManager),
|
|
75
|
+
OwnedOwnerManager.fromDeps(ownedOwner, daoManager, ickbUdtManager),
|
|
76
|
+
OrderManager.fromDeps(order, ickbUdtManager),
|
|
77
|
+
daoManager,
|
|
75
78
|
);
|
|
76
79
|
}
|
|
77
80
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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),
|
|
85
105
|
};
|
|
86
|
-
},
|
|
87
|
-
): ccc.FixedPoint {
|
|
88
|
-
// TODO: make compatible with logic.convert(isCkb2Udt, amount, options)!!!
|
|
89
|
-
|
|
90
|
-
const { ckbScale, udtScale } =
|
|
91
|
-
"ratio" in options ? options.ratio : ickbExchangeRatio(options.tip);
|
|
92
|
-
|
|
93
|
-
let convertedAmount = isCkb2Udt
|
|
94
|
-
? (amount * ckbScale) / udtScale
|
|
95
|
-
: (amount * udtScale) / ckbScale;
|
|
96
|
-
|
|
97
|
-
if (options.fee) {
|
|
98
|
-
const { numerator, denominator } = options.fee;
|
|
99
|
-
convertedAmount -= (convertedAmount * numerator) / denominator;
|
|
100
106
|
}
|
|
101
107
|
|
|
102
|
-
|
|
108
|
+
const convertedAmount =
|
|
109
|
+
amount > ccc.Zero ? convert(isCkb2Udt, amount, rate) : ccc.Zero;
|
|
110
|
+
|
|
111
|
+
return { rate, convertedAmount };
|
|
103
112
|
}
|
|
104
113
|
|
|
105
|
-
// TODO streamline parameters with previewConversion
|
|
106
114
|
async convert(options: {
|
|
115
|
+
conversion: Parameters<typeof IckbController.previewConversion>[0] & {
|
|
116
|
+
ckbMinMatchLog?: number;
|
|
117
|
+
ckbMinFee?: ccc.Num;
|
|
118
|
+
};
|
|
107
119
|
signer: ccc.Signer;
|
|
108
|
-
isCkb2Udt: boolean;
|
|
109
|
-
amount: ccc.FixedPoint;
|
|
110
120
|
userCells: UserCells;
|
|
111
|
-
minCkbChange: ccc.FixedPoint;
|
|
112
121
|
system: SystemState;
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
denominator: ccc.Num;
|
|
122
|
+
filters: {
|
|
123
|
+
isReadyOnly: boolean;
|
|
124
|
+
isFulfilledOnly: boolean;
|
|
117
125
|
};
|
|
118
126
|
}): Promise<Conversion | undefined> {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
+
|
|
124
149
|
const N = isCkb2Udt
|
|
125
150
|
? Number(amount / system.ckbDepositCap)
|
|
126
|
-
: system.
|
|
151
|
+
: system.depositPool.slice(0, 30).length;
|
|
152
|
+
|
|
127
153
|
const cache = Array<ReturnType<IckbController["convert"]>>(N);
|
|
128
|
-
const
|
|
154
|
+
const cachedAttempt = (
|
|
155
|
+
n: number,
|
|
156
|
+
): ReturnType<IckbController["convert"]> => {
|
|
129
157
|
n = N - n;
|
|
130
|
-
return (cache[n] =
|
|
131
|
-
cache[n] ?? this.attemptConversion(n, info, address, options));
|
|
158
|
+
return (cache[n] = cache[n] ?? this.attempt(n, conversion, options));
|
|
132
159
|
};
|
|
133
|
-
|
|
160
|
+
|
|
161
|
+
return cachedAttempt(
|
|
134
162
|
await asyncBinarySearch(
|
|
135
163
|
N,
|
|
136
|
-
async (n: number) => (await
|
|
164
|
+
async (n: number) => (await cachedAttempt(n)) !== undefined,
|
|
137
165
|
),
|
|
138
166
|
);
|
|
139
167
|
}
|
|
140
168
|
|
|
141
|
-
private async
|
|
169
|
+
private async attempt(
|
|
142
170
|
n: number,
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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">,
|
|
152
180
|
): ReturnType<IckbController["convert"]> {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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));
|
|
172
210
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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),
|
|
177
228
|
);
|
|
178
|
-
maturities.push(...myDeposits.map((d) => d.maturity));
|
|
179
229
|
}
|
|
180
|
-
}
|
|
181
230
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
info,
|
|
187
|
-
isCkb2Udt ? amount : ccc.Zero,
|
|
188
|
-
isCkb2Udt ? ccc.Zero : amount,
|
|
189
|
-
);
|
|
231
|
+
// Check that order provides enough fee to the bot for being matched
|
|
232
|
+
if (ckbFee < ckbMinFee) {
|
|
233
|
+
return undefined;
|
|
234
|
+
}
|
|
190
235
|
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
ckbFee = isCkb2Udt
|
|
194
|
-
? amount - convert(false, convertedAmount, exchangeRatio)
|
|
195
|
-
: convert(true, amount, exchangeRatio) - convertedAmount;
|
|
236
|
+
const { receipts, withdrawalGroups, orders, udts, capacities } =
|
|
237
|
+
userCells;
|
|
196
238
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
);
|
|
201
|
-
|
|
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);
|
|
202
244
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
if (10n * (feeRate - ckbFee) > ckbFee) {
|
|
206
|
-
return undefined;
|
|
207
|
-
}
|
|
245
|
+
// Throw an error if inputs do not cover for outputs
|
|
246
|
+
await new RestrictedTransaction(tx).completeFeeBy(signer, feeRate);
|
|
208
247
|
|
|
209
|
-
|
|
248
|
+
// Find the maturity most distant in the future
|
|
249
|
+
const maturity = maturities.reduce((a, b) =>
|
|
250
|
+
epochCompare(a, b) === -1 ? b : a,
|
|
251
|
+
);
|
|
210
252
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
// const outputLen = tx.inputs.length;??
|
|
217
|
-
// Give choice that let user add this cells the way he prefer!! (Either here or at completeFeeBy)
|
|
218
|
-
this.ickbManager.addUdts(tx, udts);
|
|
219
|
-
CapacityManager.addCapacities(tx, capacities);
|
|
220
|
-
const outputLen = tx.outputs.length;
|
|
253
|
+
return {
|
|
254
|
+
tx,
|
|
255
|
+
ckbFee,
|
|
256
|
+
maturity,
|
|
257
|
+
};
|
|
221
258
|
|
|
222
|
-
try {
|
|
223
|
-
await tx.completeFeeBy(signer, feeRate);
|
|
224
|
-
// TODO: check in SmartTransaction for 64 output cells in DAO transactions
|
|
225
|
-
if (tx.outputs.length > 64) {
|
|
226
|
-
return undefined;
|
|
227
|
-
}
|
|
228
259
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
229
260
|
} catch (_) {
|
|
230
261
|
return undefined;
|
|
231
262
|
}
|
|
232
|
-
|
|
233
|
-
// Revert any change cells
|
|
234
|
-
tx.outputs = tx.outputs.slice(outputLen);
|
|
235
|
-
tx = SmartTransaction.from(tx);
|
|
236
|
-
|
|
237
|
-
const maturity = maturities.reduce((a, b) =>
|
|
238
|
-
epochCompare(a, b) === -1 ? b : a,
|
|
239
|
-
);
|
|
240
|
-
|
|
241
|
-
return {
|
|
242
|
-
tx,
|
|
243
|
-
ckbFee,
|
|
244
|
-
maturity,
|
|
245
|
-
};
|
|
246
263
|
}
|
|
247
264
|
|
|
248
|
-
// TODO: Allow filtering which cells are fetched
|
|
249
265
|
async getL1State(
|
|
250
266
|
client: ccc.Client,
|
|
251
|
-
|
|
267
|
+
filter: Set<keyof UserCells | "depositPool">,
|
|
268
|
+
locks: ccc.Script[],
|
|
252
269
|
options?: {
|
|
253
270
|
minLockUp?: ccc.Epoch;
|
|
254
271
|
maxLockUp?: ccc.Epoch;
|
|
@@ -268,25 +285,42 @@ export class IckbController {
|
|
|
268
285
|
receipts,
|
|
269
286
|
withdrawalGroups,
|
|
270
287
|
orders,
|
|
288
|
+
deposits,
|
|
289
|
+
withdrawalRequests,
|
|
271
290
|
] = await Promise.all([
|
|
272
|
-
// TODO: fetch user NervosDAO cells
|
|
273
|
-
// TODO: fetch bot cells for estimating timings
|
|
274
291
|
client.getFeeRate(),
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
)
|
|
282
|
-
|
|
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
|
|
283
317
|
]);
|
|
284
318
|
|
|
285
319
|
// Sort depositPool by maturity
|
|
286
320
|
depositPool.sort((a, b) => epochCompare(a.maturity, b.maturity));
|
|
287
321
|
// Calculate cumulative value of deposits in the pool
|
|
288
322
|
let udtCumulative = 0n;
|
|
289
|
-
const cumulativeDepositPool: SystemState["
|
|
323
|
+
const cumulativeDepositPool: SystemState["depositPool"] = [];
|
|
290
324
|
for (const deposit of depositPool) {
|
|
291
325
|
udtCumulative += deposit.udtValue;
|
|
292
326
|
cumulativeDepositPool.push({ ...deposit, udtCumulative });
|
|
@@ -303,7 +337,7 @@ export class IckbController {
|
|
|
303
337
|
}
|
|
304
338
|
|
|
305
339
|
const exchangeRatio = ickbExchangeRatio(tip);
|
|
306
|
-
const ckbDepositCap = convert(false, ICKB_DEPOSIT_CAP, exchangeRatio);
|
|
340
|
+
const ckbDepositCap = convert(false, ICKB_DEPOSIT_CAP, exchangeRatio);
|
|
307
341
|
|
|
308
342
|
return {
|
|
309
343
|
system: {
|
|
@@ -312,8 +346,8 @@ export class IckbController {
|
|
|
312
346
|
exchangeRatio,
|
|
313
347
|
ckbDepositCap,
|
|
314
348
|
udtDepositCap: ICKB_DEPOSIT_CAP,
|
|
315
|
-
|
|
316
|
-
|
|
349
|
+
depositPool: cumulativeDepositPool,
|
|
350
|
+
orderPool: nonUserOrders,
|
|
317
351
|
},
|
|
318
352
|
user: {
|
|
319
353
|
capacities,
|
|
@@ -321,45 +355,11 @@ export class IckbController {
|
|
|
321
355
|
receipts,
|
|
322
356
|
withdrawalGroups,
|
|
323
357
|
orders: userOrders,
|
|
358
|
+
deposits,
|
|
359
|
+
withdrawalRequests,
|
|
324
360
|
},
|
|
325
361
|
};
|
|
326
362
|
}
|
|
327
|
-
|
|
328
|
-
// TODO: Allow filtering which cells are accounted for
|
|
329
|
-
static getBalance({
|
|
330
|
-
capacities,
|
|
331
|
-
udts,
|
|
332
|
-
receipts,
|
|
333
|
-
withdrawalGroups,
|
|
334
|
-
orders,
|
|
335
|
-
}: UserCells): Balance {
|
|
336
|
-
const cells: { cell: ccc.Cell; udtValue?: ccc.FixedPoint }[] = [
|
|
337
|
-
capacities,
|
|
338
|
-
udts,
|
|
339
|
-
receipts,
|
|
340
|
-
].flat();
|
|
341
|
-
for (const { owner, owned } of withdrawalGroups) {
|
|
342
|
-
cells.push(owned, owner);
|
|
343
|
-
}
|
|
344
|
-
for (const { master, order } of orders) {
|
|
345
|
-
cells.push(master, order);
|
|
346
|
-
}
|
|
347
|
-
let ckb = ccc.Zero;
|
|
348
|
-
let udt = ccc.Zero;
|
|
349
|
-
for (const cell of cells) {
|
|
350
|
-
ckb += cell.cell.cellOutput.capacity;
|
|
351
|
-
udt += cell.udtValue ?? ccc.Zero;
|
|
352
|
-
}
|
|
353
|
-
return {
|
|
354
|
-
ckb,
|
|
355
|
-
udt,
|
|
356
|
-
};
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
export interface Balance {
|
|
361
|
-
ckb: ccc.FixedPoint;
|
|
362
|
-
udt: ccc.FixedPoint;
|
|
363
363
|
}
|
|
364
364
|
|
|
365
365
|
export interface SystemState {
|
|
@@ -371,22 +371,24 @@ export interface SystemState {
|
|
|
371
371
|
};
|
|
372
372
|
ckbDepositCap: ccc.FixedPoint;
|
|
373
373
|
udtDepositCap: ccc.FixedPoint;
|
|
374
|
-
|
|
375
|
-
|
|
374
|
+
depositPool: (IckbDepositCell & { udtCumulative: bigint })[];
|
|
375
|
+
orderPool: OrderCell[];
|
|
376
376
|
}
|
|
377
377
|
|
|
378
378
|
export interface UserCells {
|
|
379
379
|
capacities: CapacityCell[];
|
|
380
380
|
udts: UdtCell[];
|
|
381
381
|
receipts: ReceiptCell[];
|
|
382
|
-
withdrawalGroups:
|
|
382
|
+
withdrawalGroups: WithdrawalGroup[];
|
|
383
383
|
orders: OrderGroup[];
|
|
384
|
+
deposits: DaoCell[];
|
|
385
|
+
withdrawalRequests: DaoCell[];
|
|
384
386
|
}
|
|
385
387
|
|
|
386
388
|
export interface Conversion {
|
|
387
389
|
tx: SmartTransaction;
|
|
388
390
|
ckbFee: ccc.FixedPoint;
|
|
389
|
-
maturity: Epoch;
|
|
391
|
+
maturity: ccc.Epoch;
|
|
390
392
|
}
|
|
391
393
|
|
|
392
394
|
// Estimate bot ability to fulfill orders:
|
|
@@ -403,77 +405,3 @@ function orderMaturityEstimate(
|
|
|
403
405
|
4n * 60n,
|
|
404
406
|
]);
|
|
405
407
|
}
|
|
406
|
-
|
|
407
|
-
class OfflineTransaction extends SmartTransaction {
|
|
408
|
-
override clone(): OfflineTransaction {
|
|
409
|
-
const result = super.clone();
|
|
410
|
-
// Keep inputs metadata when cloning, so it will not refetch that data
|
|
411
|
-
result.inputs = [...this.inputs];
|
|
412
|
-
return new OfflineTransaction(result);
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
416
|
-
override async completeInputs<T>(
|
|
417
|
-
_0: never,
|
|
418
|
-
_1: never,
|
|
419
|
-
_2: never,
|
|
420
|
-
init: T,
|
|
421
|
-
): Promise<{ addedCount: number; accumulated?: T }> {
|
|
422
|
-
// Disable completeInputs, so it will not fetch additional cells
|
|
423
|
-
return {
|
|
424
|
-
addedCount: 0,
|
|
425
|
-
accumulated: init,
|
|
426
|
-
};
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
// Reimplement the rest of transformations
|
|
430
|
-
|
|
431
|
-
constructor(tx: SmartTransaction) {
|
|
432
|
-
super(
|
|
433
|
-
tx.version,
|
|
434
|
-
tx.cellDeps,
|
|
435
|
-
tx.headerDeps,
|
|
436
|
-
tx.inputs,
|
|
437
|
-
tx.outputs,
|
|
438
|
-
tx.outputsData,
|
|
439
|
-
tx.witnesses,
|
|
440
|
-
tx.udtHandlers,
|
|
441
|
-
tx.headers,
|
|
442
|
-
);
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
static override default(): OfflineTransaction {
|
|
446
|
-
return new OfflineTransaction(super.default());
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
static override fromLumosSkeleton(
|
|
450
|
-
skeleton: ccc.LumosTransactionSkeletonType,
|
|
451
|
-
): OfflineTransaction {
|
|
452
|
-
return new OfflineTransaction(super.fromLumosSkeleton(skeleton));
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
static override from(txLike: SmartTransactionLike): OfflineTransaction {
|
|
456
|
-
return new OfflineTransaction(SmartTransaction.from(txLike));
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
// TODO: utils.binarySearch is sync, need an async one for await the result!!!!!!!!!!!!
|
|
461
|
-
async function asyncBinarySearch(
|
|
462
|
-
n: number,
|
|
463
|
-
f: (i: number) => Promise<boolean>,
|
|
464
|
-
): Promise<number> {
|
|
465
|
-
// Define f(-1) == false and f(n) == true.
|
|
466
|
-
// Invariant: f(i-1) == false, f(j) == true.
|
|
467
|
-
let [i, j] = [0, n];
|
|
468
|
-
while (i < j) {
|
|
469
|
-
const h = Math.trunc((i + j) / 2);
|
|
470
|
-
// i ≤ h < j
|
|
471
|
-
if (!(await f(h))) {
|
|
472
|
-
i = h + 1; // preserves f(i-1) == false
|
|
473
|
-
} else {
|
|
474
|
-
j = h; // preserves f(j) == true
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
// i == j, f(i-1) == false, and f(j) (= f(i)) == true => answer is i.
|
|
478
|
-
return i;
|
|
479
|
-
}
|