@gearbox-protocol/sdk 14.12.0-next.21 → 14.12.0-next.23

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.
Files changed (53) hide show
  1. package/dist/cjs/abi/IWithdrawalCompressorV313.js +2 -1
  2. package/dist/cjs/abi/compressors/withdrawalCompressor.js +2 -1
  3. package/dist/cjs/plugins/delayed-withdrawal/DelayedWithdrawalPlugin.js +1 -5
  4. package/dist/cjs/preview/preview/applyInnerOperations.js +83 -58
  5. package/dist/cjs/preview/preview/applyQuotaChanges.js +43 -0
  6. package/dist/cjs/preview/preview/errors.js +0 -16
  7. package/dist/cjs/preview/preview/index.js +2 -0
  8. package/dist/cjs/preview/preview/previewAdjustCreditAccount.js +19 -8
  9. package/dist/cjs/preview/preview/previewCloseOrRepayCreditAccount.js +18 -7
  10. package/dist/cjs/preview/preview/previewOpenCreditAccount.js +18 -6
  11. package/dist/cjs/preview/preview/types.js +30 -0
  12. package/dist/cjs/preview/preview/unwrapNativeCollateral.js +10 -4
  13. package/dist/cjs/sdk/OnchainSDK.js +3 -6
  14. package/dist/cjs/sdk/accounts/CreditAccountsServiceV310.js +45 -37
  15. package/dist/cjs/sdk/accounts/withdrawal-compressor/AbstractWithdrawalCompressorContract.js +14 -22
  16. package/dist/cjs/sdk/accounts/withdrawal-compressor/addresses.js +6 -18
  17. package/dist/cjs/sdk/accounts/withdrawal-compressor/createWithdrawalCompressor.js +3 -5
  18. package/dist/esm/abi/IWithdrawalCompressorV313.js +2 -1
  19. package/dist/esm/abi/compressors/withdrawalCompressor.js +2 -1
  20. package/dist/esm/plugins/delayed-withdrawal/DelayedWithdrawalPlugin.js +2 -9
  21. package/dist/esm/preview/preview/applyInnerOperations.js +90 -59
  22. package/dist/esm/preview/preview/applyQuotaChanges.js +19 -0
  23. package/dist/esm/preview/preview/errors.js +0 -15
  24. package/dist/esm/preview/preview/index.js +1 -0
  25. package/dist/esm/preview/preview/previewAdjustCreditAccount.js +20 -8
  26. package/dist/esm/preview/preview/previewCloseOrRepayCreditAccount.js +18 -7
  27. package/dist/esm/preview/preview/previewOpenCreditAccount.js +20 -6
  28. package/dist/esm/preview/preview/types.js +16 -0
  29. package/dist/esm/preview/preview/unwrapNativeCollateral.js +12 -4
  30. package/dist/esm/sdk/OnchainSDK.js +3 -6
  31. package/dist/esm/sdk/accounts/CreditAccountsServiceV310.js +45 -37
  32. package/dist/esm/sdk/accounts/withdrawal-compressor/AbstractWithdrawalCompressorContract.js +14 -22
  33. package/dist/esm/sdk/accounts/withdrawal-compressor/addresses.js +6 -18
  34. package/dist/esm/sdk/accounts/withdrawal-compressor/createWithdrawalCompressor.js +3 -5
  35. package/dist/types/abi/IWithdrawalCompressorV313.d.ts +4 -0
  36. package/dist/types/abi/compressors/withdrawalCompressor.d.ts +4 -0
  37. package/dist/types/permissionless/bindings/compressors/withdrawal-compressor.d.ts +4 -0
  38. package/dist/types/preview/preview/applyInnerOperations.d.ts +8 -33
  39. package/dist/types/preview/preview/applyQuotaChanges.d.ts +24 -0
  40. package/dist/types/preview/preview/errors.d.ts +0 -12
  41. package/dist/types/preview/preview/index.d.ts +1 -0
  42. package/dist/types/preview/preview/previewAdjustCreditAccount.d.ts +1 -1
  43. package/dist/types/preview/preview/previewOpenCreditAccount.d.ts +1 -1
  44. package/dist/types/preview/preview/types.d.ts +81 -0
  45. package/dist/types/preview/preview/unwrapNativeCollateral.d.ts +19 -4
  46. package/dist/types/sdk/OnchainSDK.d.ts +3 -6
  47. package/dist/types/sdk/accounts/CreditAccountsServiceV310.d.ts +5 -1
  48. package/dist/types/sdk/accounts/types.d.ts +32 -3
  49. package/dist/types/sdk/accounts/withdrawal-compressor/WithdrawalCompressorV313Contract.d.ts +4 -0
  50. package/dist/types/sdk/accounts/withdrawal-compressor/addresses.d.ts +1 -2
  51. package/dist/types/sdk/accounts/withdrawal-compressor/createWithdrawalCompressor.d.ts +2 -4
  52. package/dist/types/sdk/accounts/withdrawal-compressor/types.d.ts +7 -0
  53. package/package.json +1 -1
@@ -786,8 +786,7 @@ class CreditAccountsServiceV310 extends import_base.SDKConstruct {
786
786
  token,
787
787
  intent
788
788
  }) {
789
- const compressor = this.sdk.withdrawalCompressor();
790
- return compressor.getWithdrawalRequestResult(
789
+ return this.sdk.withdrawalCompressor.getWithdrawalRequestResult(
791
790
  creditAccount,
792
791
  token,
793
792
  amount,
@@ -800,8 +799,7 @@ class CreditAccountsServiceV310 extends import_base.SDKConstruct {
800
799
  async getPendingWithdrawals({
801
800
  creditAccount
802
801
  }) {
803
- const compressor = this.sdk.withdrawalCompressor();
804
- const { claimable, pending } = await compressor.getCurrentWithdrawals(creditAccount);
802
+ const { claimable, pending } = await this.sdk.withdrawalCompressor.getCurrentWithdrawals(creditAccount);
805
803
  return {
806
804
  claimableNow: claimable,
807
805
  pending
@@ -843,6 +841,45 @@ class CreditAccountsServiceV310 extends import_base.SDKConstruct {
843
841
  };
844
842
  return [storeExpectedBalances, ...preview.requestCalls, compareBalances];
845
843
  }
844
+ /**
845
+ * {@inheritDoc ICreditAccountsService.assembleClaimDelayedCalls}
846
+ **/
847
+ assembleClaimDelayedCalls({
848
+ creditFacade,
849
+ claimableNow
850
+ }) {
851
+ const record = claimableNow.outputs.reduce(
852
+ (acc, o) => {
853
+ const token = o.token.toLowerCase();
854
+ acc[token] = (acc[token] || 0n) + o.amount;
855
+ return acc;
856
+ },
857
+ {}
858
+ );
859
+ const balances = Object.entries(record).filter(([, a]) => a > 10n);
860
+ const storeExpectedBalances = {
861
+ target: creditFacade,
862
+ callData: (0, import_viem.encodeFunctionData)({
863
+ abi: import_generated.iCreditFacadeMulticallV310Abi,
864
+ functionName: "storeExpectedBalances",
865
+ args: [
866
+ balances.map(([token, amount]) => ({
867
+ token,
868
+ amount: amount > 10n ? amount - 10n : 0n
869
+ }))
870
+ ]
871
+ })
872
+ };
873
+ const compareBalances = {
874
+ target: creditFacade,
875
+ callData: (0, import_viem.encodeFunctionData)({
876
+ abi: import_generated.iCreditFacadeMulticallV310Abi,
877
+ functionName: "compareBalances",
878
+ args: []
879
+ })
880
+ };
881
+ return [storeExpectedBalances, ...claimableNow.claimCalls, compareBalances];
882
+ }
846
883
  /**
847
884
  * {@inheritDoc ICreditAccountsService.startDelayedWithdrawal}
848
885
  **/
@@ -886,44 +923,15 @@ class CreditAccountsServiceV310 extends import_base.SDKConstruct {
886
923
  const cm = this.sdk.marketRegister.findCreditManager(
887
924
  creditAccount.creditManager
888
925
  );
889
- const record = claimableNow.outputs.reduce(
890
- (acc, o) => {
891
- const token = o.token.toLowerCase();
892
- acc[token] = (acc[token] || 0n) + o.amount;
893
- return acc;
894
- },
895
- {}
896
- );
897
- const balances = Object.entries(record).filter(([, a]) => a > 10n);
898
- const storeExpectedBalances = {
899
- target: cm.creditFacade.address,
900
- callData: (0, import_viem.encodeFunctionData)({
901
- abi: import_generated.iCreditFacadeMulticallV310Abi,
902
- functionName: "storeExpectedBalances",
903
- args: [
904
- balances.map(([token, amount]) => ({
905
- token,
906
- amount: amount > 10n ? amount - 10n : 0n
907
- }))
908
- ]
909
- })
910
- };
911
- const compareBalances = {
912
- target: cm.creditFacade.address,
913
- callData: (0, import_viem.encodeFunctionData)({
914
- abi: import_generated.iCreditFacadeMulticallV310Abi,
915
- functionName: "compareBalances",
916
- args: []
917
- })
918
- };
919
926
  const quotaCalls = zeroDebt ? [] : this.#prepareUpdateQuotas(cm.creditFacade.address, {
920
927
  minQuota,
921
928
  averageQuota
922
929
  });
923
930
  const operationCalls = [
924
- storeExpectedBalances,
925
- ...claimableNow.claimCalls,
926
- compareBalances,
931
+ ...this.assembleClaimDelayedCalls({
932
+ creditFacade: cm.creditFacade.address,
933
+ claimableNow
934
+ }),
927
935
  ...quotaCalls
928
936
  ];
929
937
  const calls = zeroDebt ? operationCalls : await this.#prependPriceUpdates(
@@ -107,7 +107,7 @@ class AbstractWithdrawalCompressorContract extends import_base.BaseContract {
107
107
  claimable: claimable.map(
108
108
  (w) => toClaimableWithdrawal(w, creditManager, this.version >= 313)
109
109
  ),
110
- pending: pending.map(toPendingWithdrawal).sort((a, b) => a.claimableAt < b.claimableAt ? -1 : 1)
110
+ pending: pending.map((w) => toPendingWithdrawal(w, creditManager, this.version >= 313)).sort((a, b) => a.claimableAt < b.claimableAt ? -1 : 1)
111
111
  };
112
112
  }
113
113
  /**
@@ -127,8 +127,8 @@ class AbstractWithdrawalCompressorContract extends import_base.BaseContract {
127
127
  return {
128
128
  token: resp.token,
129
129
  amountIn: resp.amountIn,
130
- outputs: resp.outputs.map(toWithdrawalOutput),
131
- requestCalls: resp.requestCalls.map(toMultiCall),
130
+ outputs: [...resp.outputs],
131
+ requestCalls: [...resp.requestCalls],
132
132
  claimableAt: resp.claimableAt
133
133
  };
134
134
  }
@@ -180,21 +180,8 @@ class AbstractWithdrawalCompressorContract extends import_base.BaseContract {
180
180
  ]);
181
181
  }
182
182
  }
183
- function toWithdrawalOutput(o) {
184
- return { token: o.token, isDelayed: o.isDelayed, amount: o.amount };
185
- }
186
- function toMultiCall(c) {
187
- return { target: c.target, callData: c.callData };
188
- }
189
183
  function toWithdrawableAsset(a, creditManager) {
190
- return {
191
- creditManager,
192
- token: a.token,
193
- withdrawalPhantomToken: a.withdrawalPhantomToken,
194
- underlying: a.underlying,
195
- withdrawalLength: a.withdrawalLength,
196
- maxWithdrawals: a.maxWithdrawals
197
- };
184
+ return { creditManager, ...a };
198
185
  }
199
186
  function toClaimableWithdrawal(w, creditManager, decodeIntent) {
200
187
  let intent;
@@ -205,17 +192,22 @@ function toClaimableWithdrawal(w, creditManager, decodeIntent) {
205
192
  token: w.token,
206
193
  withdrawalPhantomToken: w.withdrawalPhantomToken,
207
194
  withdrawalTokenSpent: w.withdrawalTokenSpent,
208
- outputs: w.outputs.map(toWithdrawalOutput),
209
- claimCalls: w.claimCalls.map(toMultiCall),
195
+ outputs: [...w.outputs],
196
+ claimCalls: [...w.claimCalls],
210
197
  intent
211
198
  };
212
199
  }
213
- function toPendingWithdrawal(w) {
200
+ function toPendingWithdrawal(w, creditManager, decodeIntent) {
201
+ let intent;
202
+ if (decodeIntent && w.extraData && w.extraData !== "0x") {
203
+ intent = { ...(0, import_intent_codec.decodeDelayedIntent)(w.extraData), creditManager };
204
+ }
214
205
  return {
215
206
  token: w.token,
216
207
  withdrawalPhantomToken: w.withdrawalPhantomToken,
217
- expectedOutputs: w.expectedOutputs.map(toWithdrawalOutput),
218
- claimableAt: w.claimableAt
208
+ expectedOutputs: [...w.expectedOutputs],
209
+ claimableAt: w.claimableAt,
210
+ intent
219
211
  };
220
212
  }
221
213
  // Annotate the CommonJS export names for ESM import in node:
@@ -23,28 +23,16 @@ __export(addresses_exports, {
23
23
  module.exports = __toCommonJS(addresses_exports);
24
24
  const WITHDRAWAL_COMPRESSORS = {
25
25
  Mainnet: {
26
- 310: "0x36F3d0Bb73CBC2E94fE24dF0f26a689409cF9023",
27
- 313: "0x9605D59E40963ADce8a6895Aa3Fa497320Ef3F3b"
26
+ address: "0x83e5AaC6590Cf9c6Dd323851a0D66fEc2Bc4F5A3",
27
+ version: 313
28
28
  },
29
29
  Monad: {
30
- 310: "0x36F3d0Bb73CBC2E94fE24dF0f26a689409cF9023"
30
+ address: "0x36F3d0Bb73CBC2E94fE24dF0f26a689409cF9023",
31
+ version: 310
31
32
  }
32
33
  };
33
- function getWithdrawalCompressorAddress(network, version) {
34
- const deployments = WITHDRAWAL_COMPRESSORS[network];
35
- if (!deployments) {
36
- return void 0;
37
- }
38
- if (version !== void 0) {
39
- const address2 = deployments[version];
40
- return address2 ? { address: address2, version } : void 0;
41
- }
42
- const latest = Object.keys(deployments).map(Number).sort((a, b) => b - a)[0];
43
- if (latest === void 0) {
44
- return void 0;
45
- }
46
- const address = deployments[latest];
47
- return address ? { address, version: latest } : void 0;
34
+ function getWithdrawalCompressorAddress(network) {
35
+ return WITHDRAWAL_COMPRESSORS[network];
48
36
  }
49
37
  // Annotate the CommonJS export names for ESM import in node:
50
38
  0 && (module.exports = {
@@ -25,12 +25,10 @@ var import_addresses = require("./addresses.js");
25
25
  var import_WithdrawalCompressorV310Contract = require("./WithdrawalCompressorV310Contract.js");
26
26
  var import_WithdrawalCompressorV311Contract = require("./WithdrawalCompressorV311Contract.js");
27
27
  var import_WithdrawalCompressorV313Contract = require("./WithdrawalCompressorV313Contract.js");
28
- function createWithdrawalCompressor(sdk, version) {
29
- const location = (0, import_addresses.getWithdrawalCompressorAddress)(sdk.networkType, version);
28
+ function createWithdrawalCompressor(sdk) {
29
+ const location = (0, import_addresses.getWithdrawalCompressorAddress)(sdk.networkType);
30
30
  if (!location) {
31
- throw new Error(
32
- `no withdrawal compressor${version ? ` v${version}` : ""} on ${sdk.networkType}`
33
- );
31
+ throw new Error(`no withdrawal compressor on ${sdk.networkType}`);
34
32
  }
35
33
  const cached = sdk.getContract(
36
34
  location.address
@@ -72,7 +72,8 @@ const iWithdrawalCompressorV313Abi = [
72
72
  { name: "amount", type: "uint256", internalType: "uint256" }
73
73
  ]
74
74
  },
75
- { name: "claimableAt", type: "uint256", internalType: "uint256" }
75
+ { name: "claimableAt", type: "uint256", internalType: "uint256" },
76
+ { name: "extraData", type: "bytes", internalType: "bytes" }
76
77
  ]
77
78
  }
78
79
  ],
@@ -94,7 +94,8 @@ const withdrawalCompressorAbi = [
94
94
  { name: "amount", type: "uint256", internalType: "uint256" }
95
95
  ]
96
96
  },
97
- { name: "claimableAt", type: "uint256", internalType: "uint256" }
97
+ { name: "claimableAt", type: "uint256", internalType: "uint256" },
98
+ { name: "extraData", type: "bytes", internalType: "bytes" }
98
99
  ]
99
100
  }
100
101
  ],
@@ -1,7 +1,4 @@
1
- import {
2
- AddressMap,
3
- BasePlugin
4
- } from "../../sdk/index.js";
1
+ import { AddressMap, BasePlugin } from "../../sdk/index.js";
5
2
  const MAP_LABEL = "delayedWithdrawal";
6
3
  class DelayedWithdrawalPlugin extends BasePlugin {
7
4
  #withdrawableAssets;
@@ -10,11 +7,7 @@ class DelayedWithdrawalPlugin extends BasePlugin {
10
7
  return this.state;
11
8
  }
12
9
  this.#withdrawableAssets = new AddressMap(void 0, MAP_LABEL);
13
- const compressor = this.sdk.withdrawalCompressor();
14
- this.sdk.logger?.debug(
15
- `loading delayed withdrawal plugin with compressor ${compressor.address}`
16
- );
17
- const resp = await compressor.getWithdrawableAssetsBatch();
10
+ const resp = await this.sdk.withdrawalCompressor.getWithdrawableAssetsBatch();
18
11
  const byCreditManager = /* @__PURE__ */ new Map();
19
12
  for (const cfg of resp) {
20
13
  const assets = byCreditManager.get(cfg.creditManager) ?? [];
@@ -4,10 +4,16 @@ import {
4
4
  } from "../../plugins/adapters/index.js";
5
5
  import {
6
6
  AssetsMap,
7
- MAX_UINT256,
8
- MIN_INT96
7
+ MAX_UINT256
9
8
  } from "../../sdk/index.js";
10
9
  import { applyRWAWrapUnwrap } from "./applyRWAWrapUnwrap.js";
10
+ import {
11
+ ERROR_ADAPTER_CALL_OUTSIDE_BRACKET,
12
+ ERROR_MALFORMED_BRACKET,
13
+ ERROR_NON_ADAPTER_CALL_IN_BRACKET,
14
+ ERROR_UNPREVIEWABLE_ADAPTER_CALL,
15
+ ERROR_UNPREVIEWABLE_RWA_WRAP_UNWRAP
16
+ } from "./types.js";
11
17
  function makeInnerOperationsState() {
12
18
  return {
13
19
  balances: new AssetsMap(),
@@ -21,41 +27,31 @@ function makeInnerOperationsState() {
21
27
  function applyInnerOperations(sdk, multicall, state) {
22
28
  let inBracket = false;
23
29
  let storeSeen = false;
30
+ let error;
24
31
  for (const op of multicall) {
32
+ let opError;
25
33
  switch (op.operation) {
26
34
  case "AddCollateral":
27
- state.collateralAdded.inc(op.token, op.amount);
28
- state.balances.inc(op.token, op.amount);
35
+ applyAddCollateral(state, op);
29
36
  break;
30
- case "WithdrawCollateral": {
31
- const running = state.balances.getOrZero(op.token);
32
- const amount = op.amount === MAX_UINT256 ? running > 0n ? running : 0n : op.amount;
33
- state.balances.dec(op.token, amount);
34
- state.collateralWithdrawn.inc(op.token, amount);
37
+ case "WithdrawCollateral":
38
+ applyWithdrawCollateral(state, op);
35
39
  break;
36
- }
37
40
  case "IncreaseBorrowedAmount":
38
- state.debt += op.amount;
39
- state.totalDebt += op.amount;
40
- state.balances.inc(op.token, op.amount);
41
+ applyIncreaseDebt(state, op);
41
42
  break;
42
- case "DecreaseBorrowedAmount": {
43
- const repaid = op.amount > state.totalDebt ? state.totalDebt : op.amount;
44
- state.balances.dec(op.token, repaid);
45
- state.totalDebt -= repaid;
46
- if (state.debt > state.totalDebt) {
47
- state.debt = state.totalDebt;
48
- }
43
+ case "DecreaseBorrowedAmount":
44
+ applyDecreaseDebt(state, op);
49
45
  break;
50
- }
51
46
  case "UpdateQuota":
52
47
  state.quotaChanges.push({ token: op.token, balance: op.change });
53
48
  break;
54
49
  case "StoreExpectedBalances":
55
50
  if (storeSeen) {
56
- throw new Error(
57
- "malformed multicall: duplicate storeExpectedBalances call"
58
- );
51
+ opError = {
52
+ code: ERROR_MALFORMED_BRACKET,
53
+ message: "duplicate storeExpectedBalances call"
54
+ };
59
55
  }
60
56
  storeSeen = true;
61
57
  inBracket = true;
@@ -65,32 +61,83 @@ function applyInnerOperations(sdk, multicall, state) {
65
61
  break;
66
62
  case "CompareBalances":
67
63
  if (!inBracket) {
68
- throw new Error(
69
- "malformed multicall: compareBalances without a preceding storeExpectedBalances"
70
- );
64
+ opError = {
65
+ code: ERROR_MALFORMED_BRACKET,
66
+ message: "compareBalances without a preceding storeExpectedBalances"
67
+ };
71
68
  }
72
69
  inBracket = false;
73
70
  break;
74
- case "Execute": {
75
- const adapter = sdk.getContract(op.adapter);
76
- if (inBracket) {
77
- if (!(adapter instanceof AbstractAdapterContract)) {
78
- throw new Error(
79
- `call to ${op.adapter} between storeExpectedBalances and compareBalances is not an adapter call`
80
- );
81
- }
82
- adapter.previewBalanceChanges(state.balances, op.calldata);
83
- } else if (isRWAShare(sdk, adapter)) {
84
- applyRWAWrapUnwrap(adapter, op.calldata, state.balances);
85
- }
71
+ case "Execute":
72
+ opError = applyExecute(sdk, op, inBracket, state.balances);
86
73
  break;
87
- }
88
74
  }
75
+ error ??= opError;
89
76
  }
90
77
  if (inBracket) {
91
- throw new Error(
92
- "malformed multicall: storeExpectedBalances without a matching compareBalances"
93
- );
78
+ error ??= {
79
+ code: ERROR_MALFORMED_BRACKET,
80
+ message: "storeExpectedBalances without a matching compareBalances"
81
+ };
82
+ }
83
+ return error;
84
+ }
85
+ function applyAddCollateral(state, op) {
86
+ state.collateralAdded.inc(op.token, op.amount);
87
+ state.balances.inc(op.token, op.amount);
88
+ }
89
+ function applyWithdrawCollateral(state, op) {
90
+ const running = state.balances.getOrZero(op.token);
91
+ const amount = op.amount === MAX_UINT256 ? running > 0n ? running : 0n : op.amount;
92
+ state.balances.dec(op.token, amount);
93
+ state.collateralWithdrawn.inc(op.token, amount);
94
+ }
95
+ function applyIncreaseDebt(state, op) {
96
+ state.debt += op.amount;
97
+ state.totalDebt += op.amount;
98
+ state.balances.inc(op.token, op.amount);
99
+ }
100
+ function applyDecreaseDebt(state, op) {
101
+ const repaid = op.amount > state.totalDebt ? state.totalDebt : op.amount;
102
+ state.balances.dec(op.token, repaid);
103
+ state.totalDebt -= repaid;
104
+ if (state.debt > state.totalDebt) {
105
+ state.debt = state.totalDebt;
106
+ }
107
+ }
108
+ function applyExecute(sdk, op, inBracket, balances) {
109
+ const adapter = sdk.getContract(op.adapter);
110
+ if (!inBracket) {
111
+ if (!isRWAShare(sdk, adapter)) {
112
+ return {
113
+ code: ERROR_ADAPTER_CALL_OUTSIDE_BRACKET,
114
+ message: `call to ${op.adapter} outside of a storeExpectedBalances/compareBalances bracket`
115
+ };
116
+ }
117
+ try {
118
+ applyRWAWrapUnwrap(adapter, op.calldata, balances);
119
+ return void 0;
120
+ } catch (e) {
121
+ return {
122
+ code: ERROR_UNPREVIEWABLE_RWA_WRAP_UNWRAP,
123
+ message: e instanceof Error ? e.message : String(e)
124
+ };
125
+ }
126
+ }
127
+ if (!(adapter instanceof AbstractAdapterContract)) {
128
+ return {
129
+ code: ERROR_NON_ADAPTER_CALL_IN_BRACKET,
130
+ message: `call to ${op.adapter} between storeExpectedBalances and compareBalances is not an adapter call`
131
+ };
132
+ }
133
+ try {
134
+ adapter.previewBalanceChanges(balances, op.calldata);
135
+ return void 0;
136
+ } catch (e) {
137
+ return {
138
+ code: ERROR_UNPREVIEWABLE_ADAPTER_CALL,
139
+ message: e instanceof Error ? e.message : String(e)
140
+ };
94
141
  }
95
142
  }
96
143
  function isRWAShare(sdk, adapter) {
@@ -100,23 +147,7 @@ function isRWAShare(sdk, adapter) {
100
147
  }
101
148
  return false;
102
149
  }
103
- function applyQuotaChanges(initialQuotas, changes) {
104
- const final = initialQuotas.clone();
105
- for (const { token, balance: change } of changes) {
106
- if (change === MIN_INT96) {
107
- final.upsert(token, 0n);
108
- } else {
109
- const next = final.getOrZero(token) + change;
110
- final.upsert(token, next > 0n ? next : 0n);
111
- }
112
- }
113
- return {
114
- quotas: final.toAssets(0n),
115
- quotasChange: final.difference(initialQuotas).toAssets()
116
- };
117
- }
118
150
  export {
119
151
  applyInnerOperations,
120
- applyQuotaChanges,
121
152
  makeInnerOperationsState
122
153
  };
@@ -0,0 +1,19 @@
1
+ import { MIN_INT96 } from "../../sdk/index.js";
2
+ function applyQuotaChanges(initialQuotas, changes) {
3
+ const final = initialQuotas.clone();
4
+ for (const { token, balance: change } of changes) {
5
+ if (change === MIN_INT96) {
6
+ final.upsert(token, 0n);
7
+ } else {
8
+ const next = final.getOrZero(token) + change;
9
+ final.upsert(token, next > 0n ? next : 0n);
10
+ }
11
+ }
12
+ return {
13
+ quotas: final.toAssets(0n),
14
+ quotasChange: final.difference(initialQuotas).toAssets()
15
+ };
16
+ }
17
+ export {
18
+ applyQuotaChanges
19
+ };
@@ -1,17 +1,3 @@
1
- class InvalidTransactionValueError extends Error {
2
- /** Transaction `msg.value`. */
3
- value;
4
- /** Amount of wrapped native token added as collateral. */
5
- wethCollateral;
6
- constructor(value, wethCollateral) {
7
- super(
8
- `transaction value ${value} exceeds WETH collateral ${wethCollateral}`
9
- );
10
- this.name = "InvalidTransactionValueError";
11
- this.value = value;
12
- this.wethCollateral = wethCollateral;
13
- }
14
- }
15
1
  class UnsupportedOperationError extends Error {
16
2
  /** The parsed operation kind (the `operation` discriminant). */
17
3
  operation;
@@ -22,6 +8,5 @@ class UnsupportedOperationError extends Error {
22
8
  }
23
9
  }
24
10
  export {
25
- InvalidTransactionValueError,
26
11
  UnsupportedOperationError
27
12
  };
@@ -1,4 +1,5 @@
1
1
  export * from "./applyInnerOperations.js";
2
+ export * from "./applyQuotaChanges.js";
2
3
  export * from "./detectCloseOrRepay.js";
3
4
  export * from "./errors.js";
4
5
  export * from "./previewAdjustCreditAccount.js";
@@ -5,9 +5,12 @@ import {
5
5
  } from "../../sdk/index.js";
6
6
  import {
7
7
  applyInnerOperations,
8
- applyQuotaChanges,
9
8
  makeInnerOperationsState
10
9
  } from "./applyInnerOperations.js";
10
+ import { applyQuotaChanges } from "./applyQuotaChanges.js";
11
+ import {
12
+ ERROR_UNPRICEABLE_TOKEN
13
+ } from "./types.js";
11
14
  import { unwrapNativeCollateral } from "./unwrapNativeCollateral.js";
12
15
  async function previewAdjustCreditAccount(input, operation, options) {
13
16
  const { sdk, value = 0n } = input;
@@ -38,22 +41,30 @@ async function previewAdjustCreditAccount(input, operation, options) {
38
41
  state.balances = initialBalances.clone();
39
42
  state.debt = ca.debt;
40
43
  state.totalDebt = ca.debt + ca.accruedInterest + ca.accruedFees;
41
- applyInnerOperations(sdk, operation.multicall, state);
42
- const collateralAdded = unwrapNativeCollateral(
44
+ let error = applyInnerOperations(sdk, operation.multicall, state);
45
+ const { assets: collateralAdded, error: unwrapError } = unwrapNativeCollateral(
43
46
  state.collateralAdded.toAssets(),
44
47
  value,
45
48
  sdk.addressProvider.getAddress(AP_WETH_TOKEN, NO_VERSION)
46
49
  );
50
+ error ??= unwrapError;
47
51
  const { quotas, quotasChange } = applyQuotaChanges(
48
52
  initialQuotas,
49
53
  state.quotaChanges
50
54
  );
51
55
  const assets = state.balances.toAssets(1n);
52
56
  const assetsChange = state.balances.difference(initialBalances).toAssets(1n);
53
- const totalValue = assets.reduce(
54
- (acc, { token, balance }) => acc + market.priceOracle.convert(token, market.underlying, balance),
55
- 0n
56
- );
57
+ const totalValue = assets.reduce((acc, { token, balance }) => {
58
+ try {
59
+ return acc + market.priceOracle.convert(token, market.underlying, balance);
60
+ } catch {
61
+ error ??= {
62
+ code: ERROR_UNPRICEABLE_TOKEN,
63
+ message: `cannot price token ${token}`
64
+ };
65
+ return acc;
66
+ }
67
+ }, 0n);
57
68
  return {
58
69
  operation: "AdjustCreditAccount",
59
70
  creditManager: operation.creditManager,
@@ -66,7 +77,8 @@ async function previewAdjustCreditAccount(input, operation, options) {
66
77
  quotas,
67
78
  quotasChange,
68
79
  assets,
69
- assetsChange
80
+ assetsChange,
81
+ error
70
82
  };
71
83
  }
72
84
  export {
@@ -21,23 +21,31 @@ async function previewCloseCreditAccount(input, operation, permanent, options) {
21
21
  const market = sdk.marketRegister.findByCreditManager(
22
22
  operation.creditManager
23
23
  );
24
- const { state } = await replayMulticall(sdk, operation, options);
24
+ const { state, error } = await replayMulticall(sdk, operation, options);
25
25
  return {
26
26
  operation: "CloseCreditAccount",
27
27
  permanent,
28
28
  creditManager: operation.creditManager,
29
29
  creditAccount: operation.creditAccount,
30
- receivedAmount: state.collateralWithdrawn.getOrZero(market.underlying)
30
+ // On a malformed multicall the withdrawn amount depends on best-effort
31
+ // replayed balances and may be unreliable
32
+ receivedAmount: state.collateralWithdrawn.getOrZero(market.underlying),
33
+ error
31
34
  };
32
35
  }
33
36
  async function previewRepayCreditAccount(input, operation, permanent, options) {
34
37
  const { sdk, value = 0n } = input;
35
- const { ca, state } = await replayMulticall(sdk, operation, options);
36
- const collateralAdded = unwrapNativeCollateral(
38
+ const {
39
+ ca,
40
+ state,
41
+ error: replayError
42
+ } = await replayMulticall(sdk, operation, options);
43
+ const { assets: collateralAdded, error: unwrapError } = unwrapNativeCollateral(
37
44
  state.collateralAdded.toAssets(),
38
45
  value,
39
46
  sdk.addressProvider.getAddress(AP_WETH_TOKEN, NO_VERSION)
40
47
  );
48
+ const error = replayError ?? unwrapError;
41
49
  const initialTotalDebt = ca.debt + ca.accruedInterest + ca.accruedFees;
42
50
  return {
43
51
  operation: "RepayCreditAccount",
@@ -46,7 +54,10 @@ async function previewRepayCreditAccount(input, operation, permanent, options) {
46
54
  creditAccount: operation.creditAccount,
47
55
  collateralAdded,
48
56
  debtRepaid: initialTotalDebt - state.totalDebt,
49
- collateralWithdrawn: state.collateralWithdrawn.toAssets()
57
+ // On a malformed multicall the MAX_UINT256 withdrawal sentinel resolves
58
+ // against best-effort replayed balances and may be unreliable
59
+ collateralWithdrawn: state.collateralWithdrawn.toAssets(),
60
+ error
50
61
  };
51
62
  }
52
63
  async function replayMulticall(sdk, operation, options) {
@@ -68,8 +79,8 @@ async function replayMulticall(sdk, operation, options) {
68
79
  }
69
80
  state.debt = ca.debt;
70
81
  state.totalDebt = ca.debt + ca.accruedInterest + ca.accruedFees;
71
- applyInnerOperations(sdk, operation.multicall, state);
72
- return { ca, state };
82
+ const error = applyInnerOperations(sdk, operation.multicall, state);
83
+ return { ca, state, error };
73
84
  }
74
85
  export {
75
86
  previewCloseOrRepayCreditAccount