@gearbox-protocol/sdk 14.12.0-next.4 → 14.12.0-next.5

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 (59) hide show
  1. package/dist/cjs/preview/index.js +2 -4
  2. package/dist/cjs/preview/parse/index.js +0 -2
  3. package/dist/cjs/preview/parse/parseFacadeOperationCalldata.js +5 -12
  4. package/dist/cjs/preview/parse/parseOperationCalldata.js +5 -3
  5. package/dist/cjs/preview/parse/parsePoolOperationCalldata.js +4 -0
  6. package/dist/cjs/preview/parse/parseRWAFactoryOperationCalldata.js +0 -4
  7. package/dist/cjs/preview/prerequisites/BalancePrerequisite.js +19 -1
  8. package/dist/cjs/preview/prerequisites/buildPrerequisites.js +24 -15
  9. package/dist/cjs/preview/{simulate/holders.js → preview/errors.js} +12 -21
  10. package/dist/cjs/preview/{parse → preview}/extractExpectedBalanceChanges.js +1 -1
  11. package/dist/cjs/preview/preview/index.js +26 -0
  12. package/dist/cjs/preview/preview/previewOpenCreditAccount.js +99 -0
  13. package/dist/cjs/preview/preview/previewOperation.js +41 -0
  14. package/dist/cjs/preview/preview/previewPoolOperation.js +75 -0
  15. package/dist/cjs/preview/preview/types.js +16 -0
  16. package/dist/cjs/preview/simulate/simulatePoolOperation.js +20 -116
  17. package/dist/cjs/sdk/market/zapper/ZapperContract.js +0 -3
  18. package/dist/esm/preview/index.js +1 -2
  19. package/dist/esm/preview/parse/index.js +0 -1
  20. package/dist/esm/preview/parse/parseFacadeOperationCalldata.js +5 -12
  21. package/dist/esm/preview/parse/parseOperationCalldata.js +5 -3
  22. package/dist/esm/preview/parse/parsePoolOperationCalldata.js +4 -0
  23. package/dist/esm/preview/parse/parseRWAFactoryOperationCalldata.js +0 -4
  24. package/dist/esm/preview/prerequisites/BalancePrerequisite.js +19 -1
  25. package/dist/esm/preview/prerequisites/buildPrerequisites.js +28 -16
  26. package/dist/esm/preview/preview/errors.js +12 -0
  27. package/dist/esm/preview/{parse → preview}/extractExpectedBalanceChanges.js +1 -1
  28. package/dist/esm/preview/preview/index.js +3 -0
  29. package/dist/esm/preview/preview/previewOpenCreditAccount.js +77 -0
  30. package/dist/esm/preview/preview/previewOperation.js +17 -0
  31. package/dist/esm/preview/preview/previewPoolOperation.js +53 -0
  32. package/dist/esm/preview/preview/types.js +0 -0
  33. package/dist/esm/preview/simulate/simulatePoolOperation.js +21 -120
  34. package/dist/esm/sdk/market/zapper/ZapperContract.js +0 -3
  35. package/dist/types/history/types.d.ts +4 -4
  36. package/dist/types/preview/index.d.ts +1 -2
  37. package/dist/types/preview/parse/index.d.ts +0 -1
  38. package/dist/types/preview/parse/types-facades.d.ts +0 -33
  39. package/dist/types/preview/parse/types-pools.d.ts +29 -1
  40. package/dist/types/preview/parse/types-rwa.d.ts +1 -13
  41. package/dist/types/preview/prerequisites/BalancePrerequisite.d.ts +8 -3
  42. package/dist/types/preview/prerequisites/buildPrerequisites.d.ts +15 -6
  43. package/dist/types/preview/preview/errors.d.ts +9 -0
  44. package/dist/types/preview/{parse → preview}/extractExpectedBalanceChanges.d.ts +4 -5
  45. package/dist/types/preview/preview/index.d.ts +3 -0
  46. package/dist/types/preview/preview/previewOpenCreditAccount.d.ts +4 -0
  47. package/dist/types/preview/preview/previewOperation.d.ts +8 -0
  48. package/dist/types/preview/preview/previewPoolOperation.d.ts +5 -0
  49. package/dist/types/preview/preview/types.d.ts +103 -0
  50. package/dist/types/preview/simulate/index.d.ts +1 -1
  51. package/dist/types/preview/simulate/simulateFacadeOperation.d.ts +0 -2
  52. package/dist/types/preview/simulate/simulateOperation.d.ts +0 -2
  53. package/dist/types/preview/simulate/simulatePoolOperation.d.ts +6 -18
  54. package/dist/types/preview/simulate/simulateRWAOperation.d.ts +0 -2
  55. package/dist/types/preview/simulate/types.d.ts +12 -26
  56. package/dist/types/sdk/market/zapper/types.d.ts +6 -6
  57. package/package.json +1 -1
  58. package/dist/esm/preview/simulate/holders.js +0 -21
  59. package/dist/types/preview/simulate/holders.d.ts +0 -7
@@ -18,16 +18,12 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var simulatePoolOperation_exports = {};
20
20
  __export(simulatePoolOperation_exports, {
21
- computePoolOpBalanceChanges: () => computePoolOpBalanceChanges,
22
21
  simulatePoolOperation: () => simulatePoolOperation
23
22
  });
24
23
  module.exports = __toCommonJS(simulatePoolOperation_exports);
25
24
  var import_generated = require("../../abi/310/generated.js");
26
- var import_iERC20 = require("../../abi/iERC20.js");
27
25
  var import_iZapper = require("../../abi/iZapper.js");
28
- var import_sdk = require("../../sdk/index.js");
29
26
  var import_errors = require("./errors.js");
30
- var import_holders = require("./holders.js");
31
27
  function previewRead(operation) {
32
28
  switch (operation.operation) {
33
29
  case "Deposit":
@@ -40,16 +36,6 @@ function previewRead(operation) {
40
36
  return { functionName: "previewRedeem", amount: operation.shares };
41
37
  }
42
38
  }
43
- function outsideToken(operation) {
44
- switch (operation.operation) {
45
- case "Deposit":
46
- case "Mint":
47
- return operation.tokenIn;
48
- case "Withdraw":
49
- case "Redeem":
50
- return operation.tokenOut;
51
- }
52
- }
53
39
  function previewContract(operation) {
54
40
  const { functionName, amount } = previewRead(operation);
55
41
  if (operation.zapper) {
@@ -67,60 +53,31 @@ function previewContract(operation) {
67
53
  args: [amount]
68
54
  };
69
55
  }
56
+ function amountsInOut(operation, previewAmount) {
57
+ switch (operation.operation) {
58
+ case "Deposit":
59
+ return { amountIn: operation.assets, amountOut: previewAmount };
60
+ case "Mint":
61
+ return { amountIn: previewAmount, amountOut: operation.shares };
62
+ case "Withdraw":
63
+ return { amountIn: previewAmount, amountOut: operation.assets };
64
+ case "Redeem":
65
+ return { amountIn: operation.shares, amountOut: previewAmount };
66
+ }
67
+ }
70
68
  async function simulatePoolOperation(input, options = {}) {
71
- const { sdk, operation, wallet } = input;
69
+ const { sdk, operation } = input;
72
70
  const { blockNumber, logger } = options;
73
- const { pool } = operation;
74
71
  try {
75
- const holders = (0, import_holders.watchedHolders)(operation, wallet);
76
- const tokens = [outsideToken(operation), pool];
77
- const balanceCalls = holders.flatMap(
78
- (holder) => tokens.map((token) => ({ holder, token }))
79
- );
80
- const balanceContracts = balanceCalls.map(
81
- ({ holder, token }) => ({
82
- address: token,
83
- abi: import_iERC20.ierc20Abi,
84
- functionName: "balanceOf",
85
- args: [holder]
86
- })
87
- );
88
- const preview = previewContract(operation);
89
- let results;
90
- try {
91
- results = await sdk.client.multicall({
92
- allowFailure: false,
93
- // `undefined` lets viem read at `latest`; `blockNumber` is only set for
94
- // testnet forks pinned to a specific block.
95
- blockNumber,
96
- contracts: [...balanceContracts, preview]
97
- });
98
- } catch (cause) {
99
- throw new import_errors.PreviewSimulationError([
100
- {
101
- source: "multicall",
102
- detail: (0, import_errors.decodeSimulationError)({
103
- error: cause instanceof Error ? cause : new Error(String(cause))
104
- })
105
- }
106
- ]);
107
- }
108
- const previewAmount = results[balanceContracts.length];
109
- const balances = new import_sdk.AddressMap();
110
- for (const [i, { holder, token }] of balanceCalls.entries()) {
111
- const tokenBalances = balances.get(holder) ?? new import_sdk.AddressMap();
112
- tokenBalances.upsert(token, results[i]);
113
- balances.upsert(holder, tokenBalances);
114
- }
115
- const before = (token, holder) => balances.get(holder)?.get(token) ?? 0n;
72
+ const previewAmount = await sdk.client.readContract({
73
+ // `undefined` lets viem read at `latest`; `blockNumber` is only set for
74
+ // testnet forks pinned to a specific block.
75
+ blockNumber,
76
+ ...previewContract(operation)
77
+ });
116
78
  return {
117
79
  status: "success",
118
- balanceChanges: computePoolOpBalanceChanges(
119
- operation,
120
- wallet,
121
- previewAmount,
122
- before
123
- )
80
+ ...amountsInOut(operation, previewAmount)
124
81
  };
125
82
  } catch (cause) {
126
83
  const error = (0, import_errors.asPreviewSimulationError)(cause, "multicall");
@@ -128,60 +85,7 @@ async function simulatePoolOperation(input, options = {}) {
128
85
  return { status: "failure", error };
129
86
  }
130
87
  }
131
- function balanceLegs(operation, wallet, previewAmount) {
132
- const { pool, receiver } = operation;
133
- switch (operation.operation) {
134
- case "Deposit":
135
- return [
136
- { address: wallet, token: operation.tokenIn, delta: -operation.assets },
137
- { address: receiver, token: pool, delta: previewAmount }
138
- ];
139
- case "Mint":
140
- return [
141
- { address: wallet, token: operation.tokenIn, delta: -previewAmount },
142
- { address: receiver, token: pool, delta: operation.shares }
143
- ];
144
- case "Withdraw":
145
- return [
146
- { address: operation.owner, token: pool, delta: -previewAmount },
147
- {
148
- address: receiver,
149
- token: operation.tokenOut,
150
- delta: operation.assets
151
- }
152
- ];
153
- case "Redeem":
154
- return [
155
- { address: operation.owner, token: pool, delta: -operation.shares },
156
- { address: receiver, token: operation.tokenOut, delta: previewAmount }
157
- ];
158
- }
159
- }
160
- function computePoolOpBalanceChanges(operation, wallet, previewAmount, before) {
161
- const byAddress = new import_sdk.AddressMap();
162
- for (const { address, token, delta } of balanceLegs(
163
- operation,
164
- wallet,
165
- previewAmount
166
- )) {
167
- const beforeBalance = before(token, address);
168
- const change = {
169
- token,
170
- before: beforeBalance,
171
- after: beforeBalance + delta,
172
- delta
173
- };
174
- const existing = byAddress.get(address);
175
- if (existing) {
176
- existing.changes.push(change);
177
- } else {
178
- byAddress.upsert(address, { address, changes: [change] });
179
- }
180
- }
181
- return byAddress.values();
182
- }
183
88
  // Annotate the CommonJS export names for ESM import in node:
184
89
  0 && (module.exports = {
185
- computePoolOpBalanceChanges,
186
90
  simulatePoolOperation
187
91
  });
@@ -55,7 +55,6 @@ class ZapperContract extends import_base.BaseContract {
55
55
  const { rawArgs } = parsed;
56
56
  const pool = this.pool;
57
57
  const zapper = this.address;
58
- const token = this.tokenIn.addr;
59
58
  const underlying = this.sdk.marketRegister.findByPool(pool).underlying;
60
59
  const receiver = rawArgs.receiver;
61
60
  if (parsed.functionName.startsWith("deposit")) {
@@ -65,7 +64,6 @@ class ZapperContract extends import_base.BaseContract {
65
64
  zapper,
66
65
  receiver,
67
66
  assets: rawArgs.tokenInAmount ?? value ?? 0n,
68
- token,
69
67
  underlying,
70
68
  referralCode: rawArgs.referralCode
71
69
  };
@@ -77,7 +75,6 @@ class ZapperContract extends import_base.BaseContract {
77
75
  zapper,
78
76
  receiver,
79
77
  shares: rawArgs.tokenOutAmount,
80
- token,
81
78
  underlying
82
79
  };
83
80
  }
@@ -1,4 +1,3 @@
1
- export * from "./parse/index.js";
2
1
  export * from "./prerequisites/index.js";
3
- export * from "./simulate/index.js";
2
+ export * from "./preview/index.js";
4
3
  export * from "./trace/index.js";
@@ -1,6 +1,5 @@
1
1
  export * from "./classifyInnerOperations.js";
2
2
  export * from "./errors.js";
3
- export * from "./extractExpectedBalanceChanges.js";
4
3
  export * from "./parseFacadeOperationCalldata.js";
5
4
  export * from "./parseOperationCalldata.js";
6
5
  export * from "./parsePoolOperationCalldata.js";
@@ -1,6 +1,5 @@
1
1
  import { isAddressEqual, zeroAddress } from "viem";
2
2
  import { classifyInnerOperations } from "./classifyInnerOperations.js";
3
- import { extractExpectedBalanceChanges } from "./extractExpectedBalanceChanges.js";
4
3
  function parseFacadeOperationCalldata(props) {
5
4
  const { sdk, facade, calldata } = props;
6
5
  const parsed = sdk.parseFunctionDataV2(facade.address, calldata);
@@ -21,23 +20,20 @@ function parseFacadeOperationCalldata(props) {
21
20
  sdk,
22
21
  underlying: suite.underlying
23
22
  });
24
- const expectedBalanceChanges = extractExpectedBalanceChanges(innerCalls);
25
23
  switch (functionName) {
26
24
  case "multicall":
27
25
  return {
28
26
  ...metadata,
29
27
  operation: "MultiCall",
30
28
  creditAccount: rawArgs.creditAccount,
31
- multicall,
32
- expectedBalanceChanges
29
+ multicall
33
30
  };
34
31
  case "botMulticall":
35
32
  return {
36
33
  ...metadata,
37
34
  operation: "BotMulticall",
38
35
  creditAccount: rawArgs.creditAccount,
39
- multicall,
40
- expectedBalanceChanges
36
+ multicall
41
37
  };
42
38
  case "openCreditAccount":
43
39
  return {
@@ -46,16 +42,14 @@ function parseFacadeOperationCalldata(props) {
46
42
  creditAccount: zeroAddress,
47
43
  onBehalfOf: rawArgs.onBehalfOf,
48
44
  referralCode: rawArgs.referralCode,
49
- multicall,
50
- expectedBalanceChanges
45
+ multicall
51
46
  };
52
47
  case "closeCreditAccount":
53
48
  return {
54
49
  ...metadata,
55
50
  operation: "CloseCreditAccount",
56
51
  creditAccount: rawArgs.creditAccount,
57
- multicall,
58
- expectedBalanceChanges
52
+ multicall
59
53
  };
60
54
  case "liquidateCreditAccount":
61
55
  return {
@@ -67,8 +61,7 @@ function parseFacadeOperationCalldata(props) {
67
61
  // liquidation, so they are not recoverable from raw calldata.
68
62
  token: zeroAddress,
69
63
  remainingFunds: 0n,
70
- multicall,
71
- expectedBalanceChanges
64
+ multicall
72
65
  };
73
66
  case "partiallyLiquidateCreditAccount":
74
67
  return {
@@ -23,7 +23,8 @@ function parseOperationCalldata(input) {
23
23
  receiver: parsed.receiver,
24
24
  assets: parsed.assets,
25
25
  underlying: parsed.underlying,
26
- tokenIn: parsed.token,
26
+ tokenIn: contract.tokenIn.addr,
27
+ tokenOut: contract.tokenOut.addr,
27
28
  zapper: parsed.zapper,
28
29
  referralCode: parsed.referralCode
29
30
  };
@@ -33,12 +34,13 @@ function parseOperationCalldata(input) {
33
34
  operation: "Redeem",
34
35
  pool: parsed.pool,
35
36
  receiver: parsed.receiver,
36
- // The zapper burns the caller's pool shares, so the share owner is the
37
+ // The zapper burns the caller's share tokens, so the share owner is the
37
38
  // transaction sender.
38
39
  owner: sender,
39
40
  shares: parsed.shares,
40
41
  underlying: parsed.underlying,
41
- tokenOut: parsed.token,
42
+ tokenIn: contract.tokenOut.addr,
43
+ tokenOut: contract.tokenIn.addr,
42
44
  zapper: parsed.zapper
43
45
  };
44
46
  return op;
@@ -15,6 +15,7 @@ function parsePoolOperationCalldata(props) {
15
15
  assets: rawArgs.assets,
16
16
  underlying,
17
17
  tokenIn: underlying,
18
+ tokenOut: pool.address,
18
19
  zapper: void 0,
19
20
  referralCode: functionName === "depositWithReferral" ? rawArgs.referralCode : void 0
20
21
  };
@@ -27,6 +28,7 @@ function parsePoolOperationCalldata(props) {
27
28
  shares: rawArgs.shares,
28
29
  underlying,
29
30
  tokenIn: underlying,
31
+ tokenOut: pool.address,
30
32
  zapper: void 0,
31
33
  referralCode: functionName === "mintWithReferral" ? rawArgs.referralCode : void 0
32
34
  };
@@ -38,6 +40,7 @@ function parsePoolOperationCalldata(props) {
38
40
  owner: rawArgs.owner,
39
41
  assets: rawArgs.assets,
40
42
  underlying,
43
+ tokenIn: pool.address,
41
44
  tokenOut: underlying,
42
45
  zapper: void 0
43
46
  };
@@ -49,6 +52,7 @@ function parsePoolOperationCalldata(props) {
49
52
  owner: rawArgs.owner,
50
53
  shares: rawArgs.shares,
51
54
  underlying,
55
+ tokenIn: pool.address,
52
56
  tokenOut: underlying,
53
57
  zapper: void 0
54
58
  };
@@ -6,7 +6,6 @@ import {
6
6
  RWA_FACTORY_SECURITIZE
7
7
  } from "../../sdk/index.js";
8
8
  import { classifyInnerOperations } from "./classifyInnerOperations.js";
9
- import { extractExpectedBalanceChanges } from "./extractExpectedBalanceChanges.js";
10
9
  function parseRWAFactoryOperationCalldata(props) {
11
10
  const { contractType, address } = props.factory;
12
11
  if (isRWAFactory(props.factory, RWA_FACTORY_SECURITIZE)) {
@@ -38,14 +37,12 @@ function parseSecuritizeOperationCalldata(props) {
38
37
  sdk,
39
38
  underlying: suite.underlying
40
39
  });
41
- const expectedBalanceChanges = extractExpectedBalanceChanges(innerCalls);
42
40
  switch (functionName) {
43
41
  case "openCreditAccount":
44
42
  return {
45
43
  ...metadata,
46
44
  operation: "SecuritizeOpenCreditAccount",
47
45
  multicall,
48
- expectedBalanceChanges,
49
46
  tokensToRegister,
50
47
  signaturesToCache
51
48
  };
@@ -55,7 +52,6 @@ function parseSecuritizeOperationCalldata(props) {
55
52
  operation: "SecuritizeMulticall",
56
53
  creditAccount: rawArgs.creditAccount,
57
54
  multicall,
58
- expectedBalanceChanges,
59
55
  tokensToRegister,
60
56
  signaturesToCache
61
57
  };
@@ -1,4 +1,6 @@
1
1
  import { erc20Abi } from "viem";
2
+ import { iMulticall3Abi } from "../../abi/iMulticall3.js";
3
+ import { hexEq, NATIVE_ADDRESS } from "../../sdk/index.js";
2
4
  import {
3
5
  Prerequisite,
4
6
  toPrerequisiteError
@@ -29,7 +31,23 @@ class BalancePrerequisite extends Prerequisite {
29
31
  get detail() {
30
32
  return this.#detail;
31
33
  }
32
- calls() {
34
+ calls(ctx) {
35
+ if (hexEq(this.#detail.token, NATIVE_ADDRESS)) {
36
+ const multicall3 = ctx.sdk.client.chain.contracts?.multicall3?.address;
37
+ if (!multicall3) {
38
+ throw new Error(
39
+ "multicall3 is not configured for this chain, cannot read native balance"
40
+ );
41
+ }
42
+ return [
43
+ {
44
+ address: multicall3,
45
+ abi: iMulticall3Abi,
46
+ functionName: "getEthBalance",
47
+ args: [this.#detail.owner]
48
+ }
49
+ ];
50
+ }
33
51
  return [
34
52
  {
35
53
  address: this.#detail.token,
@@ -1,12 +1,18 @@
1
1
  import { isAddressEqual } from "viem";
2
2
  import {
3
- AddressSet
3
+ AddressSet,
4
+ NATIVE_ADDRESS
4
5
  } from "../../sdk/index.js";
6
+ import {
7
+ parseOperationCalldata
8
+ } from "../parse/parseOperationCalldata.js";
5
9
  import { AllowancePrerequisite } from "./AllowancePrerequisite.js";
6
10
  import { BalancePrerequisite } from "./BalancePrerequisite.js";
7
11
  import { RWAOpenRequirementsPrerequisite } from "./RWAOpenRequirementsPrerequisite.js";
8
- async function buildPrerequisites(tx, ctx) {
9
- const { wallet } = ctx;
12
+ async function buildPrerequisites(input) {
13
+ const { sdk, sender: wallet, blockNumber } = input;
14
+ const tx = parseOperationCalldata(input);
15
+ const ctx = { sdk, wallet, blockNumber };
10
16
  switch (tx.operation) {
11
17
  // Deposit and Mint both pull the underlying from the caller into the pool;
12
18
  // they only differ in which side (assets vs shares) the caller specifies.
@@ -16,21 +22,27 @@ async function buildPrerequisites(tx, ctx) {
16
22
  // not knowable from calldata alone).
17
23
  case "Deposit":
18
24
  if (tx.zapper) {
19
- return [
20
- new AllowancePrerequisite({
21
- token: tx.tokenIn,
22
- owner: wallet,
23
- spender: tx.zapper,
24
- required: tx.assets,
25
- title: "Token approved to zapper"
26
- }),
25
+ const prereqs = [];
26
+ if (!isAddressEqual(tx.tokenIn, NATIVE_ADDRESS)) {
27
+ prereqs.push(
28
+ new AllowancePrerequisite({
29
+ token: tx.tokenIn,
30
+ owner: wallet,
31
+ spender: tx.zapper,
32
+ required: tx.assets,
33
+ title: "Token approved to zapper"
34
+ })
35
+ );
36
+ }
37
+ prereqs.push(
27
38
  new BalancePrerequisite({
28
39
  token: tx.tokenIn,
29
40
  owner: wallet,
30
41
  required: tx.assets,
31
42
  title: "Sufficient token balance"
32
43
  })
33
- ];
44
+ );
45
+ return prereqs;
34
46
  }
35
47
  return [
36
48
  new AllowancePrerequisite({
@@ -69,17 +81,17 @@ async function buildPrerequisites(tx, ctx) {
69
81
  if (tx.zapper) {
70
82
  return [
71
83
  new BalancePrerequisite({
72
- token: tx.pool,
84
+ token: tx.tokenIn,
73
85
  owner: wallet,
74
86
  required: tx.shares,
75
- title: "Sufficient LP token balance"
87
+ title: "Sufficient share token balance"
76
88
  }),
77
89
  new AllowancePrerequisite({
78
- token: tx.pool,
90
+ token: tx.tokenIn,
79
91
  owner: wallet,
80
92
  spender: tx.zapper,
81
93
  required: tx.shares,
82
- title: "LP token approved to zapper"
94
+ title: "Share token approved to zapper"
83
95
  })
84
96
  ];
85
97
  }
@@ -0,0 +1,12 @@
1
+ class UnsupportedOperationError extends Error {
2
+ /** The parsed operation kind (the `operation` discriminant). */
3
+ operation;
4
+ constructor(operation) {
5
+ super(`operation "${operation}" is not supported by previewOperation`);
6
+ this.name = "UnsupportedOperationError";
7
+ this.operation = operation;
8
+ }
9
+ }
10
+ export {
11
+ UnsupportedOperationError
12
+ };
@@ -14,7 +14,7 @@ function extractExpectedBalanceChanges(innerCalls) {
14
14
  if (!balanceDeltas) {
15
15
  return void 0;
16
16
  }
17
- return balanceDeltas.map(({ token, amount }) => ({ token, delta: amount }));
17
+ return balanceDeltas.map(({ token, amount }) => ({ token, balance: amount }));
18
18
  }
19
19
  function functionName(call) {
20
20
  return call.functionName.split("(")[0];
@@ -0,0 +1,3 @@
1
+ export * from "./errors.js";
2
+ export * from "./previewOperation.js";
3
+ export * from "./types.js";
@@ -0,0 +1,77 @@
1
+ import {
2
+ AddressMap
3
+ } from "../../sdk/index.js";
4
+ import { extractExpectedBalanceChanges } from "./extractExpectedBalanceChanges.js";
5
+ function previewOpenCreditAccount(input, operation) {
6
+ const { sdk, to, calldata } = input;
7
+ const market = sdk.marketRegister.findByCreditManager(
8
+ operation.creditManager
9
+ );
10
+ const collateralByToken = new AddressMap();
11
+ const balances = new AddressMap();
12
+ const addBalance = (token, amount) => {
13
+ balances.upsert(token, (balances.get(token) ?? 0n) + amount);
14
+ };
15
+ let debt = 0n;
16
+ const quotas = [];
17
+ for (const op of operation.multicall) {
18
+ switch (op.operation) {
19
+ case "AddCollateral": {
20
+ const balance = collateralByToken.get(op.token)?.balance ?? 0n;
21
+ collateralByToken.upsert(op.token, {
22
+ token: op.token,
23
+ balance: balance + op.amount
24
+ });
25
+ addBalance(op.token, op.amount);
26
+ break;
27
+ }
28
+ case "WithdrawCollateral":
29
+ addBalance(op.token, -op.amount);
30
+ break;
31
+ case "IncreaseBorrowedAmount":
32
+ debt += op.amount;
33
+ addBalance(op.token, op.amount);
34
+ break;
35
+ case "DecreaseBorrowedAmount":
36
+ debt -= op.amount;
37
+ addBalance(op.token, -op.amount);
38
+ break;
39
+ case "UpdateQuota":
40
+ quotas.push({ token: op.token, balance: op.change });
41
+ break;
42
+ }
43
+ }
44
+ const collateral = collateralByToken.values();
45
+ const collateralValue = collateral.reduce(
46
+ (acc, { token, balance }) => acc + market.priceOracle.convert(token, market.underlying, balance),
47
+ 0n
48
+ );
49
+ const parsed = sdk.parseFunctionDataV2(to, calldata);
50
+ const innerCalls = parsed.rawArgs.calls ?? [];
51
+ const deltas = extractExpectedBalanceChanges(innerCalls) ?? [];
52
+ for (const { token, balance } of deltas) {
53
+ addBalance(token, balance);
54
+ }
55
+ const assets = balances.entries().filter(([, balance]) => balance > 1n).map(([token, balance]) => ({ token, balance }));
56
+ return {
57
+ operation: operation.operation,
58
+ target: inferTargetAsset(operation.multicall, balances),
59
+ collateral,
60
+ collateralValue,
61
+ debt,
62
+ quotas,
63
+ assets
64
+ };
65
+ }
66
+ function inferTargetAsset(multicall, balances) {
67
+ for (const op of multicall) {
68
+ if (op.operation === "UpdateQuota" && op.change > 0n) {
69
+ const balance = balances.get(op.token);
70
+ return balance ? { token: op.token, balance } : void 0;
71
+ }
72
+ }
73
+ return void 0;
74
+ }
75
+ export {
76
+ previewOpenCreditAccount
77
+ };
@@ -0,0 +1,17 @@
1
+ import { isPoolOperation, parseOperationCalldata } from "../parse/index.js";
2
+ import { UnsupportedOperationError } from "./errors.js";
3
+ import { previewOpenCreditAccount } from "./previewOpenCreditAccount.js";
4
+ import { previewPoolOperation } from "./previewPoolOperation.js";
5
+ async function previewOperation(input, options) {
6
+ const operation = parseOperationCalldata(input);
7
+ if (isPoolOperation(operation)) {
8
+ return previewPoolOperation(input, operation, options);
9
+ }
10
+ if (operation.operation === "OpenCreditAccount" || operation.operation === "SecuritizeOpenCreditAccount") {
11
+ return previewOpenCreditAccount(input, operation);
12
+ }
13
+ throw new UnsupportedOperationError(operation.operation);
14
+ }
15
+ export {
16
+ previewOperation
17
+ };
@@ -0,0 +1,53 @@
1
+ import {
2
+ simulatePoolOperation
3
+ } from "../simulate/index.js";
4
+ async function previewPoolOperation(input, operation, options) {
5
+ const { sdk, to, calldata } = input;
6
+ const { tokenIn, tokenOut } = operation;
7
+ const sim = await simulatePoolOperation(
8
+ { sdk, operation, to, calldata },
9
+ options
10
+ );
11
+ if (sim.status === "success") {
12
+ return {
13
+ operation: operation.operation,
14
+ pool: operation.pool,
15
+ tokenIn: { token: tokenIn, balance: sim.amountIn },
16
+ tokenOut: { token: tokenOut, balance: sim.amountOut }
17
+ };
18
+ }
19
+ const { error } = sim;
20
+ switch (operation.operation) {
21
+ case "Deposit":
22
+ return {
23
+ operation: "Deposit",
24
+ pool: operation.pool,
25
+ tokenIn: { token: tokenIn, balance: operation.assets },
26
+ tokenOut: { token: tokenOut, error }
27
+ };
28
+ case "Mint":
29
+ return {
30
+ operation: "Mint",
31
+ pool: operation.pool,
32
+ tokenIn: { token: tokenIn, error },
33
+ tokenOut: { token: tokenOut, balance: operation.shares }
34
+ };
35
+ case "Withdraw":
36
+ return {
37
+ operation: "Withdraw",
38
+ pool: operation.pool,
39
+ tokenIn: { token: tokenIn, error },
40
+ tokenOut: { token: tokenOut, balance: operation.assets }
41
+ };
42
+ case "Redeem":
43
+ return {
44
+ operation: "Redeem",
45
+ pool: operation.pool,
46
+ tokenIn: { token: tokenIn, balance: operation.shares },
47
+ tokenOut: { token: tokenOut, error }
48
+ };
49
+ }
50
+ }
51
+ export {
52
+ previewPoolOperation
53
+ };
File without changes