@gearbox-protocol/sdk 16.0.0-next.40 → 16.0.0-next.42
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/model/errors.js +1 -0
- package/dist/cjs/model/index.js +1 -0
- package/dist/cjs/onchain/accounts/intents/open-strategy.js +1 -1
- package/dist/cjs/onchain/positions/PositionsService.js +1 -11
- package/dist/cjs/sdk/execute/ExecuteApi.js +4 -4
- package/dist/cjs/sdk/index.js +5 -0
- package/dist/cjs/sdk/prepare/PrepareApi.js +326 -93
- package/dist/cjs/sdk/prepare/errors.js +90 -0
- package/dist/cjs/sdk/prepare/index.js +5 -0
- package/dist/esm/dev/AccountOpener.js +1 -1
- package/dist/esm/dev/withdrawalUtils.js +1 -1
- package/dist/esm/model/errors.js +1 -0
- package/dist/esm/model/index.js +1 -0
- package/dist/esm/onchain/accounts/CreditAccountsServiceV310.js +2 -2
- package/dist/esm/onchain/accounts/intents/open-strategy.js +1 -1
- package/dist/esm/onchain/accounts/liquidations/LiquidationsService.js +1 -1
- package/dist/esm/onchain/accounts/withdrawal-compressor/RedemptionLoggerV310Contract.js +1 -1
- package/dist/esm/onchain/accounts/withdrawal-compressor/WithdrawalCompressorV310Contract.js +1 -1
- package/dist/esm/onchain/accounts/withdrawal-compressor/WithdrawalCompressorV311Contract.js +1 -1
- package/dist/esm/onchain/accounts/withdrawal-compressor/WithdrawalCompressorV313Contract.js +1 -1
- package/dist/esm/onchain/base/TokensMeta.js +3 -3
- package/dist/esm/onchain/core/createAddressProvider.js +1 -1
- package/dist/esm/onchain/market/adapters/contracts/AccountMigratorAdapterContract.js +1 -1
- package/dist/esm/onchain/market/adapters/contracts/ERC4626AdapterContract.js +1 -1
- package/dist/esm/onchain/market/credit/CreditFacadeV310BaseContract.js +1 -1
- package/dist/esm/onchain/market/pool/PoolV310Contract.js +1 -1
- package/dist/esm/onchain/market/zapper/IETHZapperContract.js +1 -1
- package/dist/esm/onchain/market/zapper/ZapperContract.js +1 -1
- package/dist/esm/onchain/positions/PositionsService.js +1 -11
- package/dist/esm/onchain/utils/viem/simulateWithPriceUpdates.js +1 -1
- package/dist/esm/preview/simulate/simulatePoolOperation.js +1 -1
- package/dist/esm/preview/trace/extractTransfers.js +1 -1
- package/dist/esm/sdk/execute/ExecuteApi.js +4 -4
- package/dist/esm/sdk/index.js +2 -1
- package/dist/esm/sdk/prepare/PrepareApi.js +327 -94
- package/dist/esm/sdk/prepare/errors.js +86 -0
- package/dist/esm/sdk/prepare/index.js +2 -1
- package/dist/types/model/errors.d.ts +74 -0
- package/dist/types/model/index.d.ts +2 -1
- package/dist/types/onchain/accounts/intents/open-strategy.d.ts +3 -3
- package/dist/types/onchain/accounts/intents/types.d.ts +13 -14
- package/dist/types/onchain/positions/PositionsService.d.ts +0 -8
- package/dist/types/sdk/execute/types.d.ts +6 -6
- package/dist/types/sdk/index.d.ts +3 -2
- package/dist/types/sdk/prepare/PrepareApi.d.ts +11 -6
- package/dist/types/sdk/prepare/errors.d.ts +280 -0
- package/dist/types/sdk/prepare/index.d.ts +3 -2
- package/dist/types/sdk/prepare/types.d.ts +73 -46
- package/package.json +1 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { hexEq } from "../../onchain/utils/hex.js";
|
|
2
2
|
import { MultichainConstruct } from "../../onchain/base/MultichainConstruct.js";
|
|
3
|
-
import { refuse } from "../../onchain/validation/refusal.js";
|
|
4
3
|
import { toToken } from "../../onchain/validation/token.js";
|
|
5
|
-
import {
|
|
4
|
+
import { toCreditAccountSlice } from "../../onchain/accounts/intents/utils/credit-account-slice.js";
|
|
6
5
|
import { CreditAccountOperationsService } from "../../onchain/accounts/intents/index.js";
|
|
7
6
|
import "../../onchain/index.js";
|
|
7
|
+
import { creditAccountNotFound, noStrategyTargetCollateral, toPrepareError, unexpectedFailure } from "./errors.js";
|
|
8
8
|
import { withdrawableCollaterals } from "./withdrawable-collaterals.js";
|
|
9
9
|
//#region src/sdk/prepare/PrepareApi.ts
|
|
10
10
|
/**
|
|
@@ -17,8 +17,13 @@ import { withdrawableCollaterals } from "./withdrawable-collaterals.js";
|
|
|
17
17
|
*
|
|
18
18
|
* A prepared operation names one chain, so it reads through
|
|
19
19
|
* {@link MultichainConstruct.queryChain}: there is no second source to fall back
|
|
20
|
-
* to, hence a chain the SDK does not cover, or one that fails the read,
|
|
21
|
-
* rather than
|
|
20
|
+
* to, hence a chain the SDK does not cover, or one that fails the read, is a
|
|
21
|
+
* failure of the whole request rather than a thinner answer.
|
|
22
|
+
*
|
|
23
|
+
* No method here throws. Every way a preparation can fail — the market's own
|
|
24
|
+
* refusals, the two the namespace decides itself, and anything the chain or the
|
|
25
|
+
* engine raises — comes back described in the envelope, see {@link PrepareError}.
|
|
26
|
+
* A caller writes one branch, not a branch and a `try`.
|
|
22
27
|
**/
|
|
23
28
|
var PrepareApi = class extends MultichainConstruct {
|
|
24
29
|
#ensureFresh;
|
|
@@ -31,29 +36,77 @@ var PrepareApi = class extends MultichainConstruct {
|
|
|
31
36
|
return super.queryChain(props);
|
|
32
37
|
}
|
|
33
38
|
/**
|
|
39
|
+
* Runs a one-chain request whose answer is an envelope, describing whatever
|
|
40
|
+
* the chain, the read or the engine throws on the way rather than letting it
|
|
41
|
+
* escape.
|
|
42
|
+
*
|
|
43
|
+
* So every method below answers instead of rejecting, and a caller has one
|
|
44
|
+
* thing to branch on. "This cannot be done" and "we could not find out" are
|
|
45
|
+
* still told apart, by `error.code`: only the second is
|
|
46
|
+
* `unexpectedFailure`, and only it marks the chain failed in `meta`.
|
|
47
|
+
**/
|
|
48
|
+
async #answer(chainId, run) {
|
|
49
|
+
try {
|
|
50
|
+
return await this.queryChain({
|
|
51
|
+
network: chainId,
|
|
52
|
+
run
|
|
53
|
+
});
|
|
54
|
+
} catch (e) {
|
|
55
|
+
return {
|
|
56
|
+
data: {
|
|
57
|
+
success: false,
|
|
58
|
+
error: unexpectedFailure(e)
|
|
59
|
+
},
|
|
60
|
+
meta: { chains: [failedChain(chainId, e)] }
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
34
65
|
* {@inheritDoc IOpportunitiesPrepare.finalize}
|
|
35
66
|
**/
|
|
36
67
|
async finalize(position, params) {
|
|
37
|
-
return this.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
68
|
+
return this.#answer(position.chainId, async (sdk) => {
|
|
69
|
+
const intent = resumable(params.intent ?? params.claimable.intent);
|
|
70
|
+
if (!intent) return {
|
|
71
|
+
success: false,
|
|
72
|
+
error: toPrepareError({
|
|
73
|
+
reason: "noRecordedIntent",
|
|
74
|
+
detail: void 0
|
|
75
|
+
})
|
|
76
|
+
};
|
|
77
|
+
const creditAccount = await slice(sdk, position.creditAccount);
|
|
78
|
+
if (!creditAccount) return {
|
|
79
|
+
success: false,
|
|
80
|
+
error: creditAccountNotFound(position.creditAccount)
|
|
81
|
+
};
|
|
82
|
+
return planned(await service(sdk).finishIntent({
|
|
83
|
+
intent,
|
|
84
|
+
claimable: toClaimableWithdrawal(params.claimable),
|
|
85
|
+
creditAccount,
|
|
86
|
+
sdk,
|
|
87
|
+
slippage: params.slippage,
|
|
88
|
+
quotaReserve: params.quotaReserve
|
|
89
|
+
}));
|
|
51
90
|
});
|
|
52
91
|
}
|
|
53
92
|
/**
|
|
54
93
|
* {@inheritDoc IOpportunitiesPrepare.deposit}
|
|
55
94
|
**/
|
|
56
95
|
deposit(pool, params) {
|
|
96
|
+
try {
|
|
97
|
+
return this.#depositPlan(pool, params);
|
|
98
|
+
} catch (e) {
|
|
99
|
+
return {
|
|
100
|
+
success: false,
|
|
101
|
+
error: unexpectedFailure(e)
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The arithmetic behind {@link deposit}, which throws where the SDK holds
|
|
107
|
+
* nothing for the pool or the chain it was handed.
|
|
108
|
+
**/
|
|
109
|
+
#depositPlan(pool, params) {
|
|
57
110
|
const chain = this.sdk.chain(pool.chainId);
|
|
58
111
|
const { marketRegister, pools } = chain;
|
|
59
112
|
const tokenIn = params.tokenIn ?? marketRegister.findByPool(pool.pool).pool.underlying;
|
|
@@ -76,16 +129,31 @@ var PrepareApi = class extends MultichainConstruct {
|
|
|
76
129
|
});
|
|
77
130
|
if (!call) return unroutable(chain, tokenIn, tokenOut);
|
|
78
131
|
return {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
132
|
+
success: true,
|
|
133
|
+
data: {
|
|
134
|
+
operations: [],
|
|
135
|
+
state,
|
|
136
|
+
calls: call.calls
|
|
137
|
+
}
|
|
83
138
|
};
|
|
84
139
|
}
|
|
85
140
|
/**
|
|
86
141
|
* {@inheritDoc IOpportunitiesPrepare.withdraw}
|
|
87
142
|
**/
|
|
88
143
|
withdraw(pool, params) {
|
|
144
|
+
try {
|
|
145
|
+
return this.#withdrawPlan(pool, params);
|
|
146
|
+
} catch (e) {
|
|
147
|
+
return {
|
|
148
|
+
success: false,
|
|
149
|
+
error: unexpectedFailure(e)
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* {@inheritDoc PrepareApi.depositPlan}
|
|
155
|
+
**/
|
|
156
|
+
#withdrawPlan(pool, params) {
|
|
89
157
|
const chain = this.sdk.chain(pool.chainId);
|
|
90
158
|
const { pools } = chain;
|
|
91
159
|
const tokenIn = params.tokenIn ?? pool.pool;
|
|
@@ -106,16 +174,31 @@ var PrepareApi = class extends MultichainConstruct {
|
|
|
106
174
|
mode: "withdraw"
|
|
107
175
|
});
|
|
108
176
|
return {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
177
|
+
success: true,
|
|
178
|
+
data: {
|
|
179
|
+
operations: [],
|
|
180
|
+
state,
|
|
181
|
+
calls
|
|
182
|
+
}
|
|
113
183
|
};
|
|
114
184
|
}
|
|
115
185
|
/**
|
|
116
186
|
* {@inheritDoc IOpportunitiesPrepare.redeem}
|
|
117
187
|
**/
|
|
118
188
|
redeem(pool, params) {
|
|
189
|
+
try {
|
|
190
|
+
return this.#redeemPlan(pool, params);
|
|
191
|
+
} catch (e) {
|
|
192
|
+
return {
|
|
193
|
+
success: false,
|
|
194
|
+
error: unexpectedFailure(e)
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* {@inheritDoc PrepareApi.depositPlan}
|
|
200
|
+
**/
|
|
201
|
+
#redeemPlan(pool, params) {
|
|
119
202
|
const chain = this.sdk.chain(pool.chainId);
|
|
120
203
|
const { pools } = chain;
|
|
121
204
|
const tokenIn = params.tokenIn ?? pool.pool;
|
|
@@ -136,32 +219,34 @@ var PrepareApi = class extends MultichainConstruct {
|
|
|
136
219
|
mode: "redeem"
|
|
137
220
|
});
|
|
138
221
|
return {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
222
|
+
success: true,
|
|
223
|
+
data: {
|
|
224
|
+
operations: [],
|
|
225
|
+
state,
|
|
226
|
+
calls
|
|
227
|
+
}
|
|
143
228
|
};
|
|
144
229
|
}
|
|
145
230
|
/**
|
|
146
231
|
* {@inheritDoc IOpportunitiesPrepare.openNewStrategy}
|
|
147
232
|
**/
|
|
148
233
|
async openNewStrategy(strategy, params) {
|
|
149
|
-
return this.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
234
|
+
return this.#answer(strategy.chainId, async (sdk) => {
|
|
235
|
+
const targetToken = params.targetToken ?? sdk.marketRegister.findCreditManager(strategy.creditManager).strategyTargetCollateral;
|
|
236
|
+
if (!targetToken) return {
|
|
237
|
+
success: false,
|
|
238
|
+
error: noStrategyTargetCollateral(strategy.creditManager)
|
|
239
|
+
};
|
|
240
|
+
return opened(await service(sdk).openStrategyIntent({
|
|
241
|
+
sdk,
|
|
242
|
+
creditManager: strategy.creditManager,
|
|
243
|
+
collateral: params.collateral,
|
|
244
|
+
targetToken,
|
|
245
|
+
leverage: params.leverage,
|
|
246
|
+
leftoverBalances: params.leftoverBalances,
|
|
247
|
+
slippage: params.slippage,
|
|
248
|
+
quotaReserve: params.quotaReserve
|
|
249
|
+
}));
|
|
165
250
|
});
|
|
166
251
|
}
|
|
167
252
|
/**
|
|
@@ -193,12 +278,19 @@ var PrepareApi = class extends MultichainConstruct {
|
|
|
193
278
|
* {@inheritDoc IOpportunitiesPrepare.maxWithdraw}
|
|
194
279
|
**/
|
|
195
280
|
async maxWithdraw(position) {
|
|
196
|
-
return this.
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
281
|
+
return this.#answer(position.chainId, async (sdk) => {
|
|
282
|
+
const creditAccount = await slice(sdk, position.creditAccount);
|
|
283
|
+
if (!creditAccount) return {
|
|
284
|
+
success: false,
|
|
285
|
+
error: creditAccountNotFound(position.creditAccount)
|
|
286
|
+
};
|
|
287
|
+
return {
|
|
288
|
+
success: true,
|
|
289
|
+
data: await service(sdk).maxWithdraw({
|
|
290
|
+
creditAccount,
|
|
291
|
+
sdk
|
|
292
|
+
})
|
|
293
|
+
};
|
|
202
294
|
});
|
|
203
295
|
}
|
|
204
296
|
/**
|
|
@@ -216,12 +308,19 @@ var PrepareApi = class extends MultichainConstruct {
|
|
|
216
308
|
* {@inheritDoc IOpportunitiesPrepare.maxRepay}
|
|
217
309
|
**/
|
|
218
310
|
async maxRepay(position) {
|
|
219
|
-
return this.
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
}
|
|
311
|
+
return this.#answer(position.chainId, async (sdk) => {
|
|
312
|
+
const creditAccount = await slice(sdk, position.creditAccount);
|
|
313
|
+
if (!creditAccount) return {
|
|
314
|
+
success: false,
|
|
315
|
+
error: creditAccountNotFound(position.creditAccount)
|
|
316
|
+
};
|
|
317
|
+
return {
|
|
318
|
+
success: true,
|
|
319
|
+
data: await service(sdk).maxRepay({
|
|
320
|
+
creditAccount,
|
|
321
|
+
sdk
|
|
322
|
+
})
|
|
323
|
+
};
|
|
225
324
|
});
|
|
226
325
|
}
|
|
227
326
|
/**
|
|
@@ -278,14 +377,21 @@ var PrepareApi = class extends MultichainConstruct {
|
|
|
278
377
|
* {@inheritDoc IOpportunitiesPrepare.maxWithdrawCollateral}
|
|
279
378
|
**/
|
|
280
379
|
async maxWithdrawCollateral(position, token, targetHF) {
|
|
281
|
-
return this.
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
380
|
+
return this.#answer(position.chainId, async (sdk) => {
|
|
381
|
+
const creditAccount = await slice(sdk, position.creditAccount);
|
|
382
|
+
if (!creditAccount) return {
|
|
383
|
+
success: false,
|
|
384
|
+
error: creditAccountNotFound(position.creditAccount)
|
|
385
|
+
};
|
|
386
|
+
return {
|
|
387
|
+
success: true,
|
|
388
|
+
data: await service(sdk).maxWithdrawCollateral({
|
|
389
|
+
creditAccount,
|
|
390
|
+
sdk,
|
|
391
|
+
token,
|
|
392
|
+
targetHF
|
|
393
|
+
})
|
|
394
|
+
};
|
|
289
395
|
});
|
|
290
396
|
}
|
|
291
397
|
/**
|
|
@@ -293,42 +399,60 @@ var PrepareApi = class extends MultichainConstruct {
|
|
|
293
399
|
* two routes to offer: one account read, one intent, both routes quoted.
|
|
294
400
|
**/
|
|
295
401
|
async #startRoutes(position, options, intent) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
402
|
+
try {
|
|
403
|
+
return await this.queryChain({
|
|
404
|
+
network: position.chainId,
|
|
405
|
+
run: async (sdk) => {
|
|
406
|
+
const creditAccount = await slice(sdk, position.creditAccount);
|
|
407
|
+
if (!creditAccount) return neitherRoute(creditAccountNotFound(position.creditAccount));
|
|
408
|
+
return routed(await service(sdk).intentRoutes({
|
|
409
|
+
intent,
|
|
410
|
+
creditAccount,
|
|
411
|
+
sdk,
|
|
412
|
+
slippage: options.slippage,
|
|
413
|
+
quotaReserve: options.quotaReserve
|
|
414
|
+
}));
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
} catch (e) {
|
|
418
|
+
return {
|
|
419
|
+
data: neitherRoute(unexpectedFailure(e)),
|
|
420
|
+
meta: { chains: [failedChain(position.chainId, e)] }
|
|
421
|
+
};
|
|
422
|
+
}
|
|
306
423
|
}
|
|
307
424
|
/**
|
|
308
425
|
* Shared path of the five flows that act on an existing account: read the
|
|
309
426
|
* account, then run the intent through the engine.
|
|
310
427
|
**/
|
|
311
428
|
async #startIntent(position, options, intent) {
|
|
312
|
-
return this.
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
429
|
+
return this.#answer(position.chainId, async (sdk) => {
|
|
430
|
+
const creditAccount = await slice(sdk, position.creditAccount);
|
|
431
|
+
if (!creditAccount) return {
|
|
432
|
+
success: false,
|
|
433
|
+
error: creditAccountNotFound(position.creditAccount)
|
|
434
|
+
};
|
|
435
|
+
return planned(await service(sdk).startIntent({
|
|
436
|
+
intent,
|
|
437
|
+
creditAccount,
|
|
438
|
+
sdk,
|
|
439
|
+
slippage: options.slippage,
|
|
440
|
+
quotaReserve: options.quotaReserve
|
|
441
|
+
}));
|
|
324
442
|
});
|
|
325
443
|
}
|
|
326
444
|
};
|
|
327
445
|
function service(sdk) {
|
|
328
446
|
return new CreditAccountOperationsService(sdk);
|
|
329
447
|
}
|
|
330
|
-
|
|
331
|
-
|
|
448
|
+
/**
|
|
449
|
+
* The account the request names, or nothing where the markets this SDK is
|
|
450
|
+
* connected to hold no such account — closed since it was listed, or named on
|
|
451
|
+
* the wrong chain. Read rather than thrown, so the caller gets a code for it.
|
|
452
|
+
**/
|
|
453
|
+
async function slice(sdk, creditAccount) {
|
|
454
|
+
const data = await sdk.accounts.getCreditAccountData(creditAccount);
|
|
455
|
+
return data && toCreditAccountSlice(data);
|
|
332
456
|
}
|
|
333
457
|
/**
|
|
334
458
|
* The operation a claim resumes, or `undefined` when there is none to resume:
|
|
@@ -361,6 +485,36 @@ function toClaimableWithdrawal(claimable) {
|
|
|
361
485
|
};
|
|
362
486
|
}
|
|
363
487
|
/**
|
|
488
|
+
* A flow with two routes, refused before either could be quoted: the error is
|
|
489
|
+
* the same one any other flow would report, with nothing to say about the
|
|
490
|
+
* routes because neither was reached.
|
|
491
|
+
**/
|
|
492
|
+
function neitherRoute(error) {
|
|
493
|
+
return {
|
|
494
|
+
success: false,
|
|
495
|
+
error: {
|
|
496
|
+
...error,
|
|
497
|
+
refused: {
|
|
498
|
+
instant: void 0,
|
|
499
|
+
delayed: void 0
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* The chain entry for a request that was answered with
|
|
506
|
+
* {@link UnexpectedFailureError}: the read did not happen, so the metadata says
|
|
507
|
+
* so rather than reporting a block it never got.
|
|
508
|
+
**/
|
|
509
|
+
function failedChain(chainId, error) {
|
|
510
|
+
return {
|
|
511
|
+
chainId,
|
|
512
|
+
status: "error",
|
|
513
|
+
source: "onchain",
|
|
514
|
+
error
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
364
518
|
* A pool route the market does not offer, as the refusal a caller reads.
|
|
365
519
|
*
|
|
366
520
|
* `to` is absent where {@link lpRoute} found no output to name at all, which
|
|
@@ -368,10 +522,89 @@ function toClaimableWithdrawal(claimable) {
|
|
|
368
522
|
* ours implements it.
|
|
369
523
|
**/
|
|
370
524
|
function unroutable(sdk, from, to) {
|
|
371
|
-
return
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
525
|
+
return {
|
|
526
|
+
success: false,
|
|
527
|
+
error: toPrepareError({
|
|
528
|
+
reason: "unsupportedTokenPair",
|
|
529
|
+
detail: {
|
|
530
|
+
from: toToken(sdk, from),
|
|
531
|
+
to: to === void 0 ? void 0 : toToken(sdk, to)
|
|
532
|
+
}
|
|
533
|
+
})
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* The engine's answer, as the envelope the namespace speaks in: what the
|
|
538
|
+
* operation comes to under `data`, or the refusal as an error carrying its own
|
|
539
|
+
* numbers, see {@link toPrepareError}.
|
|
540
|
+
*
|
|
541
|
+
* The engine keeps its `ok` union — it is the shape the planners, the guards
|
|
542
|
+
* and their tests are written against — and the boundary is the one place the
|
|
543
|
+
* two vocabularies meet.
|
|
544
|
+
**/
|
|
545
|
+
function planned(result) {
|
|
546
|
+
if (!result.ok) return {
|
|
547
|
+
success: false,
|
|
548
|
+
error: toPrepareError(result)
|
|
549
|
+
};
|
|
550
|
+
const { operations, state, calls } = result;
|
|
551
|
+
return {
|
|
552
|
+
success: true,
|
|
553
|
+
data: {
|
|
554
|
+
operations,
|
|
555
|
+
state,
|
|
556
|
+
calls
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* {@inheritDoc planned}
|
|
562
|
+
**/
|
|
563
|
+
function opened(result) {
|
|
564
|
+
return result.ok ? {
|
|
565
|
+
success: true,
|
|
566
|
+
data: { state: result.state }
|
|
567
|
+
} : {
|
|
568
|
+
success: false,
|
|
569
|
+
error: toPrepareError(result)
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* {@inheritDoc planned}
|
|
574
|
+
*
|
|
575
|
+
* Both routes are payload, refusal and all: `refused` says why a missing one is
|
|
576
|
+
* missing, and it stays on the error when neither route answered, since that is
|
|
577
|
+
* the same question asked of a request that has no viable half at all.
|
|
578
|
+
**/
|
|
579
|
+
function routed(result) {
|
|
580
|
+
if (!result.ok) {
|
|
581
|
+
const { refused, ...issue } = result;
|
|
582
|
+
return {
|
|
583
|
+
success: false,
|
|
584
|
+
error: {
|
|
585
|
+
...toPrepareError(issue),
|
|
586
|
+
refused
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
const { instant, delayed, refused } = result;
|
|
591
|
+
return {
|
|
592
|
+
success: true,
|
|
593
|
+
data: {
|
|
594
|
+
instant: instant && {
|
|
595
|
+
operations: instant.operations,
|
|
596
|
+
state: instant.state,
|
|
597
|
+
calls: instant.calls
|
|
598
|
+
},
|
|
599
|
+
delayed: delayed && {
|
|
600
|
+
operations: delayed.operations,
|
|
601
|
+
state: delayed.state,
|
|
602
|
+
calls: delayed.calls,
|
|
603
|
+
delayed: delayed.delayed
|
|
604
|
+
},
|
|
605
|
+
refused
|
|
606
|
+
}
|
|
607
|
+
};
|
|
375
608
|
}
|
|
376
609
|
/**
|
|
377
610
|
* Picks the route the operation takes out of `tokenIn`, as a value rather than
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
//#region src/sdk/prepare/errors.ts
|
|
2
|
+
/**
|
|
3
|
+
* One sentence per refusal, naming what was ruled out rather than restating the
|
|
4
|
+
* numbers the error already carries.
|
|
5
|
+
*
|
|
6
|
+
* English and loggable, not a string to put on a screen: a form renders the
|
|
7
|
+
* code and the amounts in its own words, see {@link IGearboxError.message}.
|
|
8
|
+
**/
|
|
9
|
+
const MESSAGES = {
|
|
10
|
+
debtOutOfRange: "The debt this request implies is outside the market's band.",
|
|
11
|
+
leverageOutOfRange: "The leverage asked for cannot be expressed as a plan.",
|
|
12
|
+
insufficientSourceBalance: "Neither the account nor the wallet holds enough to fund this request.",
|
|
13
|
+
unsupportedCollateralToken: "This flow does not accept that token.",
|
|
14
|
+
unsupportedTokenPair: "No route exists between these two tokens.",
|
|
15
|
+
noDelayedRoute: "This request cannot be served as a delayed redemption.",
|
|
16
|
+
multipleDelayedWithdrawals: "The source asset has several redemption venues and none was named.",
|
|
17
|
+
withdrawalInProgress: "A redemption of this asset is already in flight on the account.",
|
|
18
|
+
noRecordedIntent: "The claim names no operation to resume.",
|
|
19
|
+
marketPaused: "The market is paused.",
|
|
20
|
+
marketExpired: "The market is past its expiration date.",
|
|
21
|
+
insufficientPoolLiquidity: "The pool cannot lend what this plan draws.",
|
|
22
|
+
quotaLimitReached: "The market takes no more quota for a token this plan holds.",
|
|
23
|
+
forbiddenToken: "This plan would increase the balance of a forbidden token.",
|
|
24
|
+
insufficientCollateral: "The account would end this transaction under-collateralised.",
|
|
25
|
+
poolSunset: "The pool is winding down and takes no more deposits.",
|
|
26
|
+
quotaCountExceeded: "The account would hold more quoted tokens than the facade enables at once.",
|
|
27
|
+
malformedTransaction: "The transaction could not be replayed."
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* The engine's refusal, as the error the namespace answers with.
|
|
31
|
+
*
|
|
32
|
+
* One place does the lifting, so the two shapes cannot drift: `reason` becomes
|
|
33
|
+
* `code`, the detail is spread onto the error, and the sentence comes from
|
|
34
|
+
* {@link MESSAGES}. A malformed transaction is spelled out rather than spread,
|
|
35
|
+
* because its detail names a `code` and a `message` of its own and they are not
|
|
36
|
+
* the envelope's.
|
|
37
|
+
**/
|
|
38
|
+
function toPrepareError(issue) {
|
|
39
|
+
if (issue.reason === "malformedTransaction") return {
|
|
40
|
+
code: "malformedTransaction",
|
|
41
|
+
message: MESSAGES.malformedTransaction,
|
|
42
|
+
previewCode: issue.detail.code,
|
|
43
|
+
detail: issue.detail.message
|
|
44
|
+
};
|
|
45
|
+
return {
|
|
46
|
+
code: issue.reason,
|
|
47
|
+
message: MESSAGES[issue.reason],
|
|
48
|
+
...issue.detail
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* {@inheritDoc NoStrategyTargetCollateralError}
|
|
53
|
+
**/
|
|
54
|
+
function noStrategyTargetCollateral(creditManager) {
|
|
55
|
+
return {
|
|
56
|
+
code: "noStrategyTargetCollateral",
|
|
57
|
+
message: `Credit manager ${creditManager} has no strategy target collateral, and none was named.`,
|
|
58
|
+
creditManager
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* {@inheritDoc CreditAccountNotFoundError}
|
|
63
|
+
**/
|
|
64
|
+
function creditAccountNotFound(creditAccount) {
|
|
65
|
+
return {
|
|
66
|
+
code: "creditAccountNotFound",
|
|
67
|
+
message: `Credit account not found: ${creditAccount}.`,
|
|
68
|
+
creditAccount
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* {@inheritDoc UnexpectedFailureError}
|
|
73
|
+
*
|
|
74
|
+
* Takes what was thrown, whatever that is: a `throw` is not obliged to raise an
|
|
75
|
+
* `Error`, and `cause` promises one.
|
|
76
|
+
**/
|
|
77
|
+
function unexpectedFailure(thrown) {
|
|
78
|
+
const cause = thrown instanceof Error ? thrown : new Error(String(thrown));
|
|
79
|
+
return {
|
|
80
|
+
code: "unexpectedFailure",
|
|
81
|
+
message: `The SDK could not prepare this operation: ${cause.message}`,
|
|
82
|
+
cause
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
//#endregion
|
|
86
|
+
export { creditAccountNotFound, noStrategyTargetCollateral, toPrepareError, unexpectedFailure };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { IntentPreviewError, raise, refuse } from "../../onchain/validation/refusal.js";
|
|
2
|
+
import { creditAccountNotFound, noStrategyTargetCollateral, toPrepareError, unexpectedFailure } from "./errors.js";
|
|
2
3
|
import { PrepareApi } from "./PrepareApi.js";
|
|
3
4
|
import "./types.js";
|
|
4
|
-
export { IntentPreviewError, PrepareApi, raise, refuse };
|
|
5
|
+
export { IntentPreviewError, PrepareApi, creditAccountNotFound, noStrategyTargetCollateral, raise, refuse, toPrepareError, unexpectedFailure };
|