@gearbox-protocol/sdk 14.12.0-next.29 → 14.12.0-next.30
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/preview/preview/CreditAccountState.js +154 -0
- package/dist/cjs/preview/preview/buildDelayedPreview.js +111 -0
- package/dist/cjs/preview/preview/detectDelayedOperation.js +71 -0
- package/dist/cjs/preview/preview/errors.js +17 -0
- package/dist/cjs/preview/preview/index.js +10 -4
- package/dist/cjs/preview/preview/previewAdjustCreditAccount.js +16 -39
- package/dist/cjs/preview/preview/previewCloseOrRepayCreditAccount.js +11 -37
- package/dist/cjs/preview/preview/previewOpenCreditAccount.js +13 -8
- package/dist/cjs/preview/preview/previewOperation.js +46 -5
- package/dist/cjs/preview/preview/{applyInnerOperations.js → replayInnerOperations.js} +24 -35
- package/dist/cjs/preview/preview/{applyQuotaChanges.js → replayMulticall.js} +14 -20
- package/dist/cjs/preview/preview/types.js +5 -2
- package/dist/esm/preview/preview/CreditAccountState.js +133 -0
- package/dist/esm/preview/preview/buildDelayedPreview.js +90 -0
- package/dist/esm/preview/preview/detectDelayedOperation.js +51 -0
- package/dist/esm/preview/preview/errors.js +16 -0
- package/dist/esm/preview/preview/index.js +5 -2
- package/dist/esm/preview/preview/previewAdjustCreditAccount.js +19 -48
- package/dist/esm/preview/preview/previewCloseOrRepayCreditAccount.js +14 -44
- package/dist/esm/preview/preview/previewOpenCreditAccount.js +15 -10
- package/dist/esm/preview/preview/previewOperation.js +52 -6
- package/dist/esm/preview/preview/{applyInnerOperations.js → replayInnerOperations.js} +20 -34
- package/dist/esm/preview/preview/replayMulticall.js +16 -0
- package/dist/esm/preview/preview/types.js +3 -1
- package/dist/types/preview/preview/CreditAccountState.d.ts +83 -0
- package/dist/types/preview/preview/buildDelayedPreview.d.ts +41 -0
- package/dist/types/preview/preview/detectDelayedOperation.d.ts +29 -0
- package/dist/types/preview/preview/errors.d.ts +15 -0
- package/dist/types/preview/preview/index.d.ts +5 -2
- package/dist/types/preview/preview/previewAdjustCreditAccount.d.ts +3 -3
- package/dist/types/preview/preview/previewCloseOrRepayCreditAccount.d.ts +2 -2
- package/dist/types/preview/preview/replayInnerOperations.d.ts +44 -0
- package/dist/types/preview/preview/replayMulticall.d.ts +38 -0
- package/dist/types/preview/preview/types.d.ts +58 -3
- package/dist/types/preview/types.d.ts +17 -6
- package/package.json +1 -1
- package/dist/esm/preview/preview/applyQuotaChanges.js +0 -19
- package/dist/types/preview/preview/applyInnerOperations.d.ts +0 -59
- package/dist/types/preview/preview/applyQuotaChanges.d.ts +0 -24
|
@@ -1,27 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AP_WETH_TOKEN,
|
|
3
|
-
NO_VERSION
|
|
4
|
-
} from "../../sdk/index.js";
|
|
5
|
-
import {
|
|
6
|
-
applyInnerOperations,
|
|
7
|
-
makeInnerOperationsState
|
|
8
|
-
} from "./applyInnerOperations.js";
|
|
1
|
+
import { AP_WETH_TOKEN, NO_VERSION } from "../../sdk/index.js";
|
|
9
2
|
import { classifyCloseOrRepay } from "./detectCloseOrRepay.js";
|
|
3
|
+
import {
|
|
4
|
+
replayMulticall
|
|
5
|
+
} from "./replayMulticall.js";
|
|
10
6
|
import { unwrapNativeCollateral } from "./unwrapNativeCollateral.js";
|
|
11
7
|
async function previewCloseOrRepayCreditAccount(input, operation, permanent, options) {
|
|
12
8
|
const { sdk } = input;
|
|
13
9
|
const market = sdk.marketRegister.findByCreditManager(
|
|
14
10
|
operation.creditManager
|
|
15
11
|
);
|
|
12
|
+
const replay = await replayMulticall(sdk, operation, options);
|
|
16
13
|
const kind = classifyCloseOrRepay(operation.multicall, market.underlying);
|
|
17
|
-
return kind === "close" ? previewCloseCreditAccount(input, operation, permanent,
|
|
14
|
+
return kind === "close" ? previewCloseCreditAccount(input, operation, permanent, replay) : previewRepayCreditAccount(input, operation, permanent, replay);
|
|
18
15
|
}
|
|
19
|
-
|
|
16
|
+
function previewCloseCreditAccount(input, operation, permanent, replay) {
|
|
20
17
|
const { sdk } = input;
|
|
21
18
|
const market = sdk.marketRegister.findByCreditManager(
|
|
22
19
|
operation.creditManager
|
|
23
20
|
);
|
|
24
|
-
const {
|
|
21
|
+
const { after, error } = replay;
|
|
25
22
|
return {
|
|
26
23
|
operation: "CloseCreditAccount",
|
|
27
24
|
permanent,
|
|
@@ -29,59 +26,32 @@ async function previewCloseCreditAccount(input, operation, permanent, options) {
|
|
|
29
26
|
creditAccount: operation.creditAccount,
|
|
30
27
|
// On a malformed multicall the withdrawn amount depends on best-effort
|
|
31
28
|
// replayed balances and may be unreliable
|
|
32
|
-
receivedAmount:
|
|
29
|
+
receivedAmount: after.collateralWithdrawn.getOrZero(market.underlying),
|
|
33
30
|
error
|
|
34
31
|
};
|
|
35
32
|
}
|
|
36
|
-
|
|
33
|
+
function previewRepayCreditAccount(input, operation, permanent, replay) {
|
|
37
34
|
const { sdk, value = 0n } = input;
|
|
38
|
-
const {
|
|
39
|
-
ca,
|
|
40
|
-
state,
|
|
41
|
-
error: replayError
|
|
42
|
-
} = await replayMulticall(sdk, operation, options);
|
|
35
|
+
const { before, after, error: replayError } = replay;
|
|
43
36
|
const { assets: collateralAdded, error: unwrapError } = unwrapNativeCollateral(
|
|
44
|
-
|
|
37
|
+
after.collateralAdded.toAssets(),
|
|
45
38
|
value,
|
|
46
39
|
sdk.addressProvider.getAddress(AP_WETH_TOKEN, NO_VERSION)
|
|
47
40
|
);
|
|
48
41
|
const error = replayError ?? unwrapError;
|
|
49
|
-
const initialTotalDebt = ca.debt + ca.accruedInterest + ca.accruedFees;
|
|
50
42
|
return {
|
|
51
43
|
operation: "RepayCreditAccount",
|
|
52
44
|
permanent,
|
|
53
45
|
creditManager: operation.creditManager,
|
|
54
46
|
creditAccount: operation.creditAccount,
|
|
55
47
|
collateralAdded,
|
|
56
|
-
debtRepaid:
|
|
48
|
+
debtRepaid: before.totalDebt - after.account.totalDebt,
|
|
57
49
|
// On a malformed multicall the MAX_UINT256 withdrawal sentinel resolves
|
|
58
50
|
// against best-effort replayed balances and may be unreliable
|
|
59
|
-
collateralWithdrawn:
|
|
51
|
+
collateralWithdrawn: after.collateralWithdrawn.toAssets(),
|
|
60
52
|
error
|
|
61
53
|
};
|
|
62
54
|
}
|
|
63
|
-
async function replayMulticall(sdk, operation, options) {
|
|
64
|
-
let ca = options?.creditAccount;
|
|
65
|
-
if (!ca) {
|
|
66
|
-
ca = await sdk.accounts.getCreditAccountData(
|
|
67
|
-
operation.creditAccount,
|
|
68
|
-
options?.blockNumber
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
if (!ca) {
|
|
72
|
-
throw new Error(`credit account ${operation.creditAccount} not found`);
|
|
73
|
-
}
|
|
74
|
-
const state = makeInnerOperationsState();
|
|
75
|
-
for (const t of ca.tokens) {
|
|
76
|
-
if (t.balance > 1n) {
|
|
77
|
-
state.balances.upsert(t.token, t.balance);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
state.debt = ca.debt;
|
|
81
|
-
state.totalDebt = ca.debt + ca.accruedInterest + ca.accruedFees;
|
|
82
|
-
const error = await applyInnerOperations(sdk, operation.multicall, state);
|
|
83
|
-
return { ca, state, error };
|
|
84
|
-
}
|
|
85
55
|
export {
|
|
86
56
|
previewCloseOrRepayCreditAccount
|
|
87
57
|
};
|
|
@@ -2,10 +2,11 @@ import {
|
|
|
2
2
|
AP_WETH_TOKEN,
|
|
3
3
|
NO_VERSION
|
|
4
4
|
} from "../../sdk/index.js";
|
|
5
|
+
import { CreditAccountState } from "./CreditAccountState.js";
|
|
5
6
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from "./
|
|
7
|
+
makeReplayState,
|
|
8
|
+
replayInnerOperations
|
|
9
|
+
} from "./replayInnerOperations.js";
|
|
9
10
|
import {
|
|
10
11
|
ERROR_UNPRICEABLE_TOKEN
|
|
11
12
|
} from "./types.js";
|
|
@@ -15,8 +16,11 @@ async function previewOpenCreditAccount(input, operation) {
|
|
|
15
16
|
const market = sdk.marketRegister.findByCreditManager(
|
|
16
17
|
operation.creditManager
|
|
17
18
|
);
|
|
18
|
-
const state =
|
|
19
|
-
|
|
19
|
+
const state = makeReplayState(
|
|
20
|
+
CreditAccountState.beforeOpen(operation.creditManager, market.underlying)
|
|
21
|
+
);
|
|
22
|
+
let error = await replayInnerOperations(sdk, operation.multicall, state);
|
|
23
|
+
const account = state.account;
|
|
20
24
|
let priceError;
|
|
21
25
|
const collateralValue = state.collateralAdded.sum((token, balance) => {
|
|
22
26
|
try {
|
|
@@ -35,16 +39,17 @@ async function previewOpenCreditAccount(input, operation) {
|
|
|
35
39
|
sdk.addressProvider.getAddress(AP_WETH_TOKEN, NO_VERSION)
|
|
36
40
|
);
|
|
37
41
|
error ??= unwrapError ?? priceError;
|
|
38
|
-
const assets =
|
|
42
|
+
const assets = account.balances.toAssets(1n);
|
|
39
43
|
return {
|
|
40
44
|
operation: operation.operation,
|
|
41
45
|
creditManager: operation.creditManager,
|
|
42
|
-
target: inferTargetAsset(operation.multicall,
|
|
46
|
+
target: inferTargetAsset(operation.multicall, account.balances),
|
|
43
47
|
collateral,
|
|
44
48
|
collateralValue,
|
|
45
|
-
debt:
|
|
46
|
-
// On opening, initial quotas are zero, so the
|
|
47
|
-
|
|
49
|
+
debt: account.debt,
|
|
50
|
+
// On opening, initial quotas are zero, so the folded quotas are the
|
|
51
|
+
// applied changes.
|
|
52
|
+
quotas: account.quotas.toAssets(0n),
|
|
48
53
|
assets,
|
|
49
54
|
error
|
|
50
55
|
};
|
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
isPoolOperation,
|
|
3
|
+
parseOperationCalldata
|
|
4
|
+
} from "../parse/index.js";
|
|
5
|
+
import { buildDelayedPreview } from "./buildDelayedPreview.js";
|
|
2
6
|
import { isCloseOrRepay } from "./detectCloseOrRepay.js";
|
|
7
|
+
import { detectDelayedOperation } from "./detectDelayedOperation.js";
|
|
3
8
|
import { UnsupportedOperationError } from "./errors.js";
|
|
4
9
|
import { previewAdjustCreditAccount } from "./previewAdjustCreditAccount.js";
|
|
5
10
|
import { previewCloseOrRepayCreditAccount } from "./previewCloseOrRepayCreditAccount.js";
|
|
6
11
|
import { previewOpenCreditAccount } from "./previewOpenCreditAccount.js";
|
|
7
12
|
import { previewPoolOperation } from "./previewPoolOperation.js";
|
|
13
|
+
import {
|
|
14
|
+
replayMulticall
|
|
15
|
+
} from "./replayMulticall.js";
|
|
8
16
|
async function previewOperation(input, options) {
|
|
9
17
|
const operation = parseOperationCalldata(input);
|
|
10
18
|
if (isPoolOperation(operation)) {
|
|
@@ -14,16 +22,54 @@ async function previewOperation(input, options) {
|
|
|
14
22
|
return previewOpenCreditAccount(input, operation);
|
|
15
23
|
}
|
|
16
24
|
if (operation.operation === "CloseCreditAccount") {
|
|
17
|
-
|
|
25
|
+
const resolved = await resolveCreditAccount(input, operation, options);
|
|
26
|
+
return previewCloseOrRepayCreditAccount(input, operation, true, resolved);
|
|
18
27
|
}
|
|
19
28
|
if (operation.operation === "MultiCall" || operation.operation === "BotMulticall" || operation.operation === "RWAMulticall") {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
return previewAdjustCreditAccount(input, operation, options);
|
|
29
|
+
const resolved = await resolveCreditAccount(input, operation, options);
|
|
30
|
+
return previewMulticallOperation(input, operation, resolved);
|
|
24
31
|
}
|
|
25
32
|
throw new UnsupportedOperationError(operation.operation);
|
|
26
33
|
}
|
|
34
|
+
async function resolveCreditAccount(input, operation, options) {
|
|
35
|
+
let creditAccount = options?.creditAccount;
|
|
36
|
+
if (!creditAccount) {
|
|
37
|
+
creditAccount = await input.sdk.accounts.getCreditAccountData(
|
|
38
|
+
operation.creditAccount,
|
|
39
|
+
options?.blockNumber
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
if (!creditAccount) {
|
|
43
|
+
throw new Error(`credit account ${operation.creditAccount} not found`);
|
|
44
|
+
}
|
|
45
|
+
return { ...options, creditAccount };
|
|
46
|
+
}
|
|
47
|
+
async function previewMulticallOperation(input, operation, options) {
|
|
48
|
+
const { sdk } = input;
|
|
49
|
+
const instantPreview = isCloseOrRepay(operation.multicall) ? await previewCloseOrRepayCreditAccount(input, operation, false, options) : await previewAdjustCreditAccount(input, operation, options);
|
|
50
|
+
const delayed = detectDelayedOperation(sdk, operation.multicall);
|
|
51
|
+
if (!delayed) {
|
|
52
|
+
return instantPreview;
|
|
53
|
+
}
|
|
54
|
+
const { before, after } = await replayMulticall(sdk, operation, options);
|
|
55
|
+
const market = sdk.marketRegister.findByCreditManager(
|
|
56
|
+
operation.creditManager
|
|
57
|
+
);
|
|
58
|
+
const convert = (token, to, amount) => market.priceOracle.convert(token, to, amount);
|
|
59
|
+
return {
|
|
60
|
+
operation: "DelayedCreditAccountOperation",
|
|
61
|
+
creditAccount: operation.creditAccount,
|
|
62
|
+
creditManager: operation.creditManager,
|
|
63
|
+
intent: delayed.intent,
|
|
64
|
+
instantPreview,
|
|
65
|
+
delayedPreview: buildDelayedPreview(
|
|
66
|
+
after.account,
|
|
67
|
+
before,
|
|
68
|
+
delayed,
|
|
69
|
+
convert
|
|
70
|
+
)
|
|
71
|
+
};
|
|
72
|
+
}
|
|
27
73
|
export {
|
|
28
74
|
previewOperation
|
|
29
75
|
};
|
|
@@ -2,10 +2,7 @@ import {
|
|
|
2
2
|
AbstractAdapterContract,
|
|
3
3
|
ERC4626AdapterContract
|
|
4
4
|
} from "../../plugins/adapters/index.js";
|
|
5
|
-
import {
|
|
6
|
-
AssetsMap,
|
|
7
|
-
MAX_UINT256
|
|
8
|
-
} from "../../sdk/index.js";
|
|
5
|
+
import { AssetsMap, MAX_UINT256 } from "../../sdk/index.js";
|
|
9
6
|
import { applyRWAWrapUnwrap } from "./applyRWAWrapUnwrap.js";
|
|
10
7
|
import {
|
|
11
8
|
ERROR_ADAPTER_CALL_OUTSIDE_BRACKET,
|
|
@@ -14,17 +11,14 @@ import {
|
|
|
14
11
|
ERROR_UNPREVIEWABLE_ADAPTER_CALL,
|
|
15
12
|
ERROR_UNPREVIEWABLE_RWA_WRAP_UNWRAP
|
|
16
13
|
} from "./types.js";
|
|
17
|
-
function
|
|
14
|
+
function makeReplayState(account) {
|
|
18
15
|
return {
|
|
19
|
-
|
|
20
|
-
debt: 0n,
|
|
21
|
-
totalDebt: 0n,
|
|
16
|
+
account,
|
|
22
17
|
collateralAdded: new AssetsMap(),
|
|
23
|
-
collateralWithdrawn: new AssetsMap()
|
|
24
|
-
quotaChanges: []
|
|
18
|
+
collateralWithdrawn: new AssetsMap()
|
|
25
19
|
};
|
|
26
20
|
}
|
|
27
|
-
async function
|
|
21
|
+
async function replayInnerOperations(sdk, multicall, state) {
|
|
28
22
|
let inBracket = false;
|
|
29
23
|
let error;
|
|
30
24
|
for (const op of multicall) {
|
|
@@ -37,13 +31,13 @@ async function applyInnerOperations(sdk, multicall, state) {
|
|
|
37
31
|
applyWithdrawCollateral(state, op);
|
|
38
32
|
break;
|
|
39
33
|
case "IncreaseBorrowedAmount":
|
|
40
|
-
|
|
34
|
+
state.account.increaseDebt(op.amount);
|
|
41
35
|
break;
|
|
42
36
|
case "DecreaseBorrowedAmount":
|
|
43
|
-
|
|
37
|
+
state.account.repay(op.amount);
|
|
44
38
|
break;
|
|
45
39
|
case "UpdateQuota":
|
|
46
|
-
state.
|
|
40
|
+
state.account.updateQuota(op.token, op.change);
|
|
47
41
|
break;
|
|
48
42
|
case "StoreExpectedBalances":
|
|
49
43
|
if (inBracket) {
|
|
@@ -54,7 +48,7 @@ async function applyInnerOperations(sdk, multicall, state) {
|
|
|
54
48
|
}
|
|
55
49
|
inBracket = true;
|
|
56
50
|
for (const { token, balance } of op.deltas) {
|
|
57
|
-
state.balances.inc(token, balance);
|
|
51
|
+
state.account.balances.inc(token, balance);
|
|
58
52
|
}
|
|
59
53
|
break;
|
|
60
54
|
case "CompareBalances":
|
|
@@ -67,7 +61,12 @@ async function applyInnerOperations(sdk, multicall, state) {
|
|
|
67
61
|
inBracket = false;
|
|
68
62
|
break;
|
|
69
63
|
case "Execute":
|
|
70
|
-
opError = await applyExecute(
|
|
64
|
+
opError = await applyExecute(
|
|
65
|
+
sdk,
|
|
66
|
+
op,
|
|
67
|
+
inBracket,
|
|
68
|
+
state.account.balances
|
|
69
|
+
);
|
|
71
70
|
break;
|
|
72
71
|
}
|
|
73
72
|
error ??= opError;
|
|
@@ -82,27 +81,14 @@ async function applyInnerOperations(sdk, multicall, state) {
|
|
|
82
81
|
}
|
|
83
82
|
function applyAddCollateral(state, op) {
|
|
84
83
|
state.collateralAdded.inc(op.token, op.amount);
|
|
85
|
-
state.balances.inc(op.token, op.amount);
|
|
84
|
+
state.account.balances.inc(op.token, op.amount);
|
|
86
85
|
}
|
|
87
86
|
function applyWithdrawCollateral(state, op) {
|
|
88
|
-
const running = state.balances.getOrZero(op.token);
|
|
87
|
+
const running = state.account.balances.getOrZero(op.token);
|
|
89
88
|
const amount = op.amount === MAX_UINT256 ? running > 0n ? running : 0n : op.amount;
|
|
90
|
-
state.balances.dec(op.token, amount);
|
|
89
|
+
state.account.balances.dec(op.token, amount);
|
|
91
90
|
state.collateralWithdrawn.inc(op.token, amount);
|
|
92
91
|
}
|
|
93
|
-
function applyIncreaseDebt(state, op) {
|
|
94
|
-
state.debt += op.amount;
|
|
95
|
-
state.totalDebt += op.amount;
|
|
96
|
-
state.balances.inc(op.token, op.amount);
|
|
97
|
-
}
|
|
98
|
-
function applyDecreaseDebt(state, op) {
|
|
99
|
-
const repaid = op.amount > state.totalDebt ? state.totalDebt : op.amount;
|
|
100
|
-
state.balances.dec(op.token, repaid);
|
|
101
|
-
state.totalDebt -= repaid;
|
|
102
|
-
if (state.debt > state.totalDebt) {
|
|
103
|
-
state.debt = state.totalDebt;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
92
|
async function applyExecute(sdk, op, inBracket, balances) {
|
|
107
93
|
const adapter = sdk.getContract(op.adapter);
|
|
108
94
|
if (!inBracket) {
|
|
@@ -146,6 +132,6 @@ function isRWAShare(sdk, adapter) {
|
|
|
146
132
|
return false;
|
|
147
133
|
}
|
|
148
134
|
export {
|
|
149
|
-
|
|
150
|
-
|
|
135
|
+
makeReplayState,
|
|
136
|
+
replayInnerOperations
|
|
151
137
|
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { CreditAccountState } from "./CreditAccountState.js";
|
|
2
|
+
import {
|
|
3
|
+
makeReplayState,
|
|
4
|
+
replayInnerOperations
|
|
5
|
+
} from "./replayInnerOperations.js";
|
|
6
|
+
async function replayMulticall(sdk, operation, options) {
|
|
7
|
+
const before = CreditAccountState.fromCreditAccountData(
|
|
8
|
+
options.creditAccount
|
|
9
|
+
);
|
|
10
|
+
const after = makeReplayState(before.clone());
|
|
11
|
+
const error = await replayInnerOperations(sdk, operation.multicall, after);
|
|
12
|
+
return { before, after, error };
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
replayMulticall
|
|
16
|
+
};
|
|
@@ -5,6 +5,7 @@ const ERROR_UNPREVIEWABLE_ADAPTER_CALL = 1004;
|
|
|
5
5
|
const ERROR_UNPREVIEWABLE_RWA_WRAP_UNWRAP = 1005;
|
|
6
6
|
const ERROR_INVALID_TRANSACTION_VALUE = 1006;
|
|
7
7
|
const ERROR_UNPRICEABLE_TOKEN = 2001;
|
|
8
|
+
const PREVIEW_DUST = 10n;
|
|
8
9
|
export {
|
|
9
10
|
ERROR_ADAPTER_CALL_OUTSIDE_BRACKET,
|
|
10
11
|
ERROR_INVALID_TRANSACTION_VALUE,
|
|
@@ -12,5 +13,6 @@ export {
|
|
|
12
13
|
ERROR_NON_ADAPTER_CALL_IN_BRACKET,
|
|
13
14
|
ERROR_UNPREVIEWABLE_ADAPTER_CALL,
|
|
14
15
|
ERROR_UNPREVIEWABLE_RWA_WRAP_UNWRAP,
|
|
15
|
-
ERROR_UNPRICEABLE_TOKEN
|
|
16
|
+
ERROR_UNPRICEABLE_TOKEN,
|
|
17
|
+
PREVIEW_DUST
|
|
16
18
|
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { Address } from "viem";
|
|
2
|
+
import { AssetsMap, type CreditAccountData } from "../../sdk/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Constructor properties of {@link CreditAccountState}.
|
|
5
|
+
*/
|
|
6
|
+
export interface CreditAccountStateProps {
|
|
7
|
+
creditAccount: Address;
|
|
8
|
+
creditManager: Address;
|
|
9
|
+
underlying: Address;
|
|
10
|
+
balances?: AssetsMap;
|
|
11
|
+
quotas?: AssetsMap;
|
|
12
|
+
debt?: bigint;
|
|
13
|
+
totalDebt?: bigint;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A snapshot of a credit account's economic state (balances, quotas, debt)
|
|
17
|
+
* as used by operation previews, together with the account's identity.
|
|
18
|
+
*
|
|
19
|
+
* Used both as the pre-state seed of a multicall replay and as the running
|
|
20
|
+
* post-state mutated by it; changes are derived by diffing two snapshots.
|
|
21
|
+
*/
|
|
22
|
+
export declare class CreditAccountState {
|
|
23
|
+
creditAccount: Address;
|
|
24
|
+
creditManager: Address;
|
|
25
|
+
/**
|
|
26
|
+
* Credit manager underlying
|
|
27
|
+
*/
|
|
28
|
+
underlying: Address;
|
|
29
|
+
/**
|
|
30
|
+
* Per-token balances
|
|
31
|
+
*/
|
|
32
|
+
balances: AssetsMap;
|
|
33
|
+
/**
|
|
34
|
+
* Per-token quotas
|
|
35
|
+
*/
|
|
36
|
+
quotas: AssetsMap;
|
|
37
|
+
/**
|
|
38
|
+
* Debt principal
|
|
39
|
+
*/
|
|
40
|
+
debt: bigint;
|
|
41
|
+
/**
|
|
42
|
+
* Total debt: principal + accrued interest + accrued fees.
|
|
43
|
+
* `decreaseDebt` amounts operate on total debt (interest and fees are
|
|
44
|
+
* repaid before principal), so principal alone is not enough to resolve
|
|
45
|
+
* either the underlying balance decrement or the final principal.
|
|
46
|
+
*/
|
|
47
|
+
totalDebt: bigint;
|
|
48
|
+
constructor(props: CreditAccountStateProps);
|
|
49
|
+
/**
|
|
50
|
+
* The account-opening seed: everything zero/empty. The account doesn't
|
|
51
|
+
* exist yet at preview time, so `creditAccount` is the zero address;
|
|
52
|
+
* opening previews take identity from the parsed operation instead.
|
|
53
|
+
*/
|
|
54
|
+
static beforeOpen(creditManager: Address, underlying: Address): CreditAccountState;
|
|
55
|
+
/**
|
|
56
|
+
* Pre-state of an existing account from its on-chain data, with dust
|
|
57
|
+
* balances and quotas (≤ 1 wei) filtered out.
|
|
58
|
+
*/
|
|
59
|
+
static fromCreditAccountData(ca: CreditAccountData): CreditAccountState;
|
|
60
|
+
clone(): CreditAccountState;
|
|
61
|
+
/**
|
|
62
|
+
* Borrows `amount` of underlying: debt, total debt and the underlying
|
|
63
|
+
* balance all increase by it.
|
|
64
|
+
*/
|
|
65
|
+
increaseDebt(amount: bigint): void;
|
|
66
|
+
/**
|
|
67
|
+
* Repays up to `amount` of underlying against the debt, clamped to the
|
|
68
|
+
* total debt (the facade never repays more than is owed). Interest and
|
|
69
|
+
* fees are repaid before principal (CreditLogic.calcDecrease), so
|
|
70
|
+
* principal only decreases once total debt drops below it. The underlying
|
|
71
|
+
* balance decreases by the repaid amount.
|
|
72
|
+
*
|
|
73
|
+
* @returns The actually repaid (post-clamp) amount.
|
|
74
|
+
*/
|
|
75
|
+
repay(amount: bigint): bigint;
|
|
76
|
+
/**
|
|
77
|
+
* Applies a relative `updateQuota` change to the token's quota:
|
|
78
|
+
* `MIN_INT96` is the facade "disable quota" sentinel and zeroes it, other
|
|
79
|
+
* changes are added with the result clamped at zero (quotas cannot go
|
|
80
|
+
* negative on-chain).
|
|
81
|
+
*/
|
|
82
|
+
updateQuota(token: Address, change: bigint): void;
|
|
83
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type Address } from "viem";
|
|
2
|
+
import type { CreditAccountState } from "./CreditAccountState.js";
|
|
3
|
+
import type { DetectedDelayedOperation } from "./detectDelayedOperation.js";
|
|
4
|
+
import { type InstantOperationPreview } from "./types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Oracle conversion, injected so unit tests don't need a market
|
|
7
|
+
*/
|
|
8
|
+
export type ConvertFn = (token: Address, to: Address, amount: bigint) => bigint;
|
|
9
|
+
/**
|
|
10
|
+
* Builds the best-effort preview of the account state after the detected
|
|
11
|
+
* delayed withdrawal is claimed and its intent (if any) is resumed.
|
|
12
|
+
*
|
|
13
|
+
* Pure function: reads the post-instant account state, never mutates it and
|
|
14
|
+
* performs no network access. Swaps that the resume flow would route through
|
|
15
|
+
* the router are estimated with the injected oracle conversion; tokens the
|
|
16
|
+
* oracle cannot price contribute nothing and set a non-fatal
|
|
17
|
+
* `ERROR_UNPRICEABLE_TOKEN` error on the preview.
|
|
18
|
+
*
|
|
19
|
+
* Common claim step (all intents): the phantom token is burned (balance and
|
|
20
|
+
* quota zeroed) and the claim token is credited with the same amount 1:1.
|
|
21
|
+
*
|
|
22
|
+
* Intent-specific resume:
|
|
23
|
+
* - `CLOSE_ACCOUNT`: everything is swapped into the underlying, the debt is
|
|
24
|
+
* fully repaid and the rest is withdrawn to the user.
|
|
25
|
+
* - `DECREASE_LEVERAGE`: the claimed amount is swapped into the underlying
|
|
26
|
+
* and used to decrease the debt.
|
|
27
|
+
* - `WITHDRAW_COLLATERAL`: the recorded amount of the recorded token is
|
|
28
|
+
* withdrawn to the user, the rest of the claimed amount decreases the debt.
|
|
29
|
+
* - other intents and `intent: undefined`: claim-only, the post-claim swap
|
|
30
|
+
* target is not recoverable from the intent.
|
|
31
|
+
*
|
|
32
|
+
* The changes (`debtChange`, `quotasChange`, `assetsChange`) are reported
|
|
33
|
+
* relative to the account state before the whole transaction, not the
|
|
34
|
+
* post-instant state: to the user the delayed preview answers "where will
|
|
35
|
+
* the account end up compared to now", so the transient phantom token
|
|
36
|
+
* (minted by the instant part, burned by the claim) nets out to nothing.
|
|
37
|
+
*
|
|
38
|
+
* @param state - Account state after the instant part of the transaction.
|
|
39
|
+
* @param before - Account state before the transaction (the diff base).
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildDelayedPreview(state: CreditAccountState, before: CreditAccountState, detected: DetectedDelayedOperation, convert: ConvertFn): InstantOperationPreview;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type DelayedWithdrawalRequest, type SdkWithAdapters } from "../../plugins/adapters/index.js";
|
|
2
|
+
import { type DelayedIntent, type PluginsMap } from "../../sdk/index.js";
|
|
3
|
+
import type { InnerOperation } from "../parse/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* A delayed-withdrawal request detected in a credit-facade multicall,
|
|
6
|
+
* produced by `detectDelayedOperation`.
|
|
7
|
+
*/
|
|
8
|
+
export interface DetectedDelayedOperation {
|
|
9
|
+
/**
|
|
10
|
+
* Phantom/claim tokens from the adapter's `parseDelayedWithdrawalRequest`
|
|
11
|
+
*/
|
|
12
|
+
request: DelayedWithdrawalRequest;
|
|
13
|
+
/**
|
|
14
|
+
* Decoded delayed intent; undefined when the request carries none, in
|
|
15
|
+
* which case the delayed preview is claim-only
|
|
16
|
+
*/
|
|
17
|
+
intent?: DelayedIntent;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Scans a credit-facade multicall for a delayed-withdrawal request.
|
|
21
|
+
*
|
|
22
|
+
* @param sdk - SDK with the adapters plugin attached.
|
|
23
|
+
* @param multicall - Parsed inner operations of the multicall.
|
|
24
|
+
* @returns The detected request, or `undefined` when
|
|
25
|
+
* the multicall contains no delayed-withdrawal request.
|
|
26
|
+
* @throws InvalidDelayedIntentError when a request carries non-empty
|
|
27
|
+
* `extraData` that cannot be decoded as a `DelayedIntent`.
|
|
28
|
+
*/
|
|
29
|
+
export declare function detectDelayedOperation<P extends PluginsMap>(sdk: SdkWithAdapters<P>, multicall: InnerOperation[]): DetectedDelayedOperation | undefined;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Address, Hex } from "viem";
|
|
1
2
|
/**
|
|
2
3
|
* Thrown by `previewOperation` for parsed operations it cannot preview yet.
|
|
3
4
|
* Currently only pool operations and credit account opening are supported.
|
|
@@ -7,3 +8,17 @@ export declare class UnsupportedOperationError extends Error {
|
|
|
7
8
|
readonly operation: string;
|
|
8
9
|
constructor(operation: string);
|
|
9
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Thrown when a delayed-withdrawal request carries non-empty `extraData`
|
|
13
|
+
* that cannot be decoded as a `DelayedIntent`. Requests produced by our
|
|
14
|
+
* stack always encode a valid intent, so garbage here means a
|
|
15
|
+
* malformed/foreign transaction that must not be previewed as if it were
|
|
16
|
+
* fine.
|
|
17
|
+
*/
|
|
18
|
+
export declare class InvalidDelayedIntentError extends Error {
|
|
19
|
+
/** Adapter the withdrawal request was addressed to. */
|
|
20
|
+
readonly adapter: Address;
|
|
21
|
+
/** Raw `extraData` that failed to decode. */
|
|
22
|
+
readonly extraData: Hex;
|
|
23
|
+
constructor(adapter: Address, extraData: Hex, cause?: unknown);
|
|
24
|
+
}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
export * from "./
|
|
2
|
-
export * from "./
|
|
1
|
+
export * from "./buildDelayedPreview.js";
|
|
2
|
+
export * from "./CreditAccountState.js";
|
|
3
3
|
export * from "./detectCloseOrRepay.js";
|
|
4
|
+
export * from "./detectDelayedOperation.js";
|
|
4
5
|
export * from "./errors.js";
|
|
5
6
|
export * from "./previewAdjustCreditAccount.js";
|
|
6
7
|
export * from "./previewCloseOrRepayCreditAccount.js";
|
|
7
8
|
export * from "./previewOperation.js";
|
|
9
|
+
export * from "./replayInnerOperations.js";
|
|
10
|
+
export * from "./replayMulticall.js";
|
|
8
11
|
export * from "./types.js";
|
|
@@ -4,9 +4,9 @@ import type { PreviewOperationInput, PreviewOperationOptions } from "../types.js
|
|
|
4
4
|
import { type AdjustCreditAccountPreview } from "./types.js";
|
|
5
5
|
/**
|
|
6
6
|
* Previews a `multicall`/`botMulticall` operation on an existing credit
|
|
7
|
-
* account:
|
|
8
|
-
*
|
|
7
|
+
* account: threads the multicall through {@link replayMulticall} over the
|
|
8
|
+
* pre-resolved account state (`options.creditAccount`) and reports the
|
|
9
9
|
* minimal guaranteed post-state alongside the changes relative to the
|
|
10
10
|
* pre-state.
|
|
11
11
|
*/
|
|
12
|
-
export declare function previewAdjustCreditAccount<P extends PluginsMap>(input: PreviewOperationInput<P>, operation: MulticallOperation | RWAMulticallOperation, options
|
|
12
|
+
export declare function previewAdjustCreditAccount<P extends PluginsMap>(input: PreviewOperationInput<P>, operation: MulticallOperation | RWAMulticallOperation, options: PreviewOperationOptions<true>): Promise<AdjustCreditAccountPreview>;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { type PluginsMap } from "../../sdk/index.js";
|
|
2
2
|
import type { CloseCreditAccountOperation, MulticallOperation, RWAMulticallOperation } from "../parse/index.js";
|
|
3
3
|
import type { PreviewOperationInput, PreviewOperationOptions } from "../types.js";
|
|
4
|
-
import type {
|
|
4
|
+
import type { CloseCreditAccountPreview, RepayCreditAccountPreview } from "./types.js";
|
|
5
5
|
/**
|
|
6
6
|
* Any parsed operation that fully closes or repays a credit account: the
|
|
7
7
|
* facade `closeCreditAccount` entry point (permanent closure) or a plain
|
|
8
8
|
* multicall detected by `isCloseOrRepay` (zero-debt closure/repay).
|
|
9
9
|
*/
|
|
10
10
|
export type CloseOrRepayOperation = CloseCreditAccountOperation | MulticallOperation | RWAMulticallOperation;
|
|
11
|
-
export declare function previewCloseOrRepayCreditAccount<P extends PluginsMap>(input: PreviewOperationInput<P>, operation: CloseOrRepayOperation, permanent: boolean, options
|
|
11
|
+
export declare function previewCloseOrRepayCreditAccount<P extends PluginsMap>(input: PreviewOperationInput<P>, operation: CloseOrRepayOperation, permanent: boolean, options: PreviewOperationOptions<true>): Promise<CloseCreditAccountPreview | RepayCreditAccountPreview>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type SdkWithAdapters } from "../../plugins/adapters/index.js";
|
|
2
|
+
import { AssetsMap, type PluginsMap } from "../../sdk/index.js";
|
|
3
|
+
import type { InnerOperation } from "../parse/index.js";
|
|
4
|
+
import type { CreditAccountState } from "./CreditAccountState.js";
|
|
5
|
+
import { type OperationPreviewError } from "./types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Running state threaded through a credit-facade multicall by
|
|
8
|
+
* {@link replayInnerOperations}: the account's post-state being mutated in
|
|
9
|
+
* facade execution order, plus per-multicall bookkeeping that is not account
|
|
10
|
+
* state (what was added from / withdrawn to the wallet).
|
|
11
|
+
*/
|
|
12
|
+
export interface ReplayState {
|
|
13
|
+
/**
|
|
14
|
+
* Running account state, mutated in facade execution order. Seeded by the
|
|
15
|
+
* caller: `CreditAccountState.beforeOpen` for account opening, a clone of
|
|
16
|
+
* `CreditAccountState.fromCreditAccountData` for an existing account.
|
|
17
|
+
*/
|
|
18
|
+
account: CreditAccountState;
|
|
19
|
+
/**
|
|
20
|
+
* Cumulative amounts added via `addCollateral`.
|
|
21
|
+
*/
|
|
22
|
+
collateralAdded: AssetsMap;
|
|
23
|
+
/**
|
|
24
|
+
* Cumulative amounts withdrawn via `withdrawCollateral`, with `MAX_UINT256`
|
|
25
|
+
* resolved against the running balance at the point of the call.
|
|
26
|
+
*/
|
|
27
|
+
collateralWithdrawn: AssetsMap;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Creates a {@link ReplayState} around the given account seed, with empty
|
|
31
|
+
* bookkeeping.
|
|
32
|
+
*/
|
|
33
|
+
export declare function makeReplayState(account: CreditAccountState): ReplayState;
|
|
34
|
+
/**
|
|
35
|
+
* Replays a credit-facade multicall over `state`, mutating it in place in
|
|
36
|
+
* facade execution order. The result is the *minimal guaranteed* post-state.
|
|
37
|
+
*
|
|
38
|
+
* The function assumes that the call was generated by our frontend using
|
|
39
|
+
* router/withdrawal compressor, otherwise it returns an error, but still
|
|
40
|
+
* proceeds best-effort.
|
|
41
|
+
*
|
|
42
|
+
* @returns `undefined` on success, the error on a malformed multicall.
|
|
43
|
+
*/
|
|
44
|
+
export declare function replayInnerOperations<P extends PluginsMap>(sdk: SdkWithAdapters<P>, multicall: InnerOperation[], state: ReplayState): Promise<OperationPreviewError | undefined>;
|