@gearbox-protocol/sdk 14.12.0-next.33 → 14.12.0-next.34

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.
@@ -21,10 +21,13 @@ __export(buildCollateralPrerequisites_exports, {
21
21
  buildCollateralPrerequisites: () => buildCollateralPrerequisites
22
22
  });
23
23
  module.exports = __toCommonJS(buildCollateralPrerequisites_exports);
24
+ var import_viem = require("viem");
24
25
  var import_sdk = require("../../sdk/index.js");
26
+ var import_AllowancePrerequisite = require("./AllowancePrerequisite.js");
27
+ var import_BalancePrerequisite = require("./BalancePrerequisite.js");
25
28
  var import_helpers = require("./helpers.js");
26
29
  async function buildCollateralPrerequisites(spenderOptions, multicall, ctx) {
27
- const { sdk, wallet } = ctx;
30
+ const { sdk, wallet, value = 0n } = ctx;
28
31
  const required = new import_sdk.AssetsMap();
29
32
  for (const op of multicall) {
30
33
  if (op.operation !== "AddCollateral" || op.amount === 0n) {
@@ -32,12 +35,45 @@ async function buildCollateralPrerequisites(spenderOptions, multicall, ctx) {
32
35
  }
33
36
  required.inc(op.token, op.amount);
34
37
  }
35
- if (required.size === 0) {
38
+ if (required.size === 0 && value === 0n) {
36
39
  return [];
37
40
  }
38
- const spender = await sdk.accounts.getApprovalAddress(spenderOptions);
39
41
  const prereqs = [];
42
+ if (value > 0n) {
43
+ prereqs.push(
44
+ new import_BalancePrerequisite.BalancePrerequisite({
45
+ token: import_sdk.NATIVE_ADDRESS,
46
+ owner: wallet,
47
+ required: value
48
+ })
49
+ );
50
+ }
51
+ if (required.size === 0) {
52
+ return prereqs;
53
+ }
54
+ const spender = await sdk.accounts.getApprovalAddress(spenderOptions);
55
+ const weth = sdk.addressProvider.getAddress(import_sdk.AP_WETH_TOKEN, import_sdk.NO_VERSION);
40
56
  for (const [token, amount] of required.entries()) {
57
+ if (value > 0n && (0, import_viem.isAddressEqual)(token, weth)) {
58
+ prereqs.push(
59
+ new import_AllowancePrerequisite.AllowancePrerequisite({
60
+ token,
61
+ owner: wallet,
62
+ spender,
63
+ required: amount
64
+ })
65
+ );
66
+ if (amount > value) {
67
+ prereqs.push(
68
+ new import_BalancePrerequisite.BalancePrerequisite({
69
+ token,
70
+ owner: wallet,
71
+ required: amount - value
72
+ })
73
+ );
74
+ }
75
+ continue;
76
+ }
41
77
  prereqs.push(
42
78
  ...(0, import_helpers.allowanceAndBalance)({
43
79
  token,
@@ -32,7 +32,8 @@ async function checkPrerequisites(input, options) {
32
32
  const ctx = {
33
33
  sdk,
34
34
  wallet,
35
- blockNumber: options?.blockNumber
35
+ blockNumber: options?.blockNumber,
36
+ value: input.value ?? 0n
36
37
  };
37
38
  const prereqs = await buildPrerequisites(tx, ctx);
38
39
  return Promise.all(prereqs.map((p) => p.verify(ctx)));
@@ -25,7 +25,7 @@ var import_viem = require("viem");
25
25
  var import_common_utils = require("../../common-utils/index.js");
26
26
  var import_sdk = require("../../sdk/index.js");
27
27
  var import_types = require("./types.js");
28
- function buildDelayedPreview(afterInstant, before, detected, convert) {
28
+ function buildDelayedPreview(afterInstant, before, detected, convert, receivedToken) {
29
29
  const { request, intent } = detected;
30
30
  const post = afterInstant.clone();
31
31
  const converter = makeSafeConverter(convert);
@@ -33,7 +33,7 @@ function buildDelayedPreview(afterInstant, before, detected, convert) {
33
33
  const collateralWithdrawn = new import_sdk.AssetsMap();
34
34
  switch (intent?.type) {
35
35
  case "CLOSE_ACCOUNT":
36
- return buildClosePreview(post, converter);
36
+ return buildClosePreview(post, converter, receivedToken);
37
37
  case "DECREASE_LEVERAGE":
38
38
  repayFromClaim(post, request.claimToken, converter.convert, claimed);
39
39
  break;
@@ -104,16 +104,17 @@ function totalValueInUnderlying(post, convert, dust) {
104
104
  (token, balance) => balance > dust ? convert(token, post.underlying, balance) : 0n
105
105
  );
106
106
  }
107
- function buildClosePreview(post, converter) {
107
+ function buildClosePreview(post, converter, receivedToken) {
108
108
  const totalValue = totalValueInUnderlying(post, converter.convert, 0n);
109
109
  return {
110
110
  operation: "CloseCreditAccount",
111
111
  permanent: false,
112
112
  creditManager: post.creditManager,
113
113
  creditAccount: post.creditAccount,
114
- // Oracle estimate denominated in the underlying
114
+ // Oracle estimate computed in the underlying; RWA underlyings convert
115
+ // 1:1 with their vault asset, so the amount holds for `receivedToken`
115
116
  receivedAmount: {
116
- token: post.underlying,
117
+ token: receivedToken,
117
118
  balance: import_common_utils.BigIntMath.max(totalValue - post.totalDebt, 0n)
118
119
  },
119
120
  error: converter.error
@@ -74,6 +74,8 @@ async function previewMulticallOperation(input, operation, options) {
74
74
  operation.creditManager
75
75
  );
76
76
  const convert = (token, to, amount) => market.priceOracle.convert(token, to, amount);
77
+ const meta = sdk.tokensMeta.get(market.underlying);
78
+ const receivedToken = meta && sdk.tokensMeta.isRWAUnderlying(meta) ? meta.asset : market.underlying;
77
79
  return {
78
80
  operation: "DelayedCreditAccountOperation",
79
81
  creditAccount: operation.creditAccount,
@@ -84,7 +86,8 @@ async function previewMulticallOperation(input, operation, options) {
84
86
  after.account,
85
87
  before,
86
88
  delayed,
87
- convert
89
+ convert,
90
+ receivedToken
88
91
  )
89
92
  };
90
93
  }
@@ -1,9 +1,15 @@
1
+ import { isAddressEqual } from "viem";
1
2
  import {
2
- AssetsMap
3
+ AP_WETH_TOKEN,
4
+ AssetsMap,
5
+ NATIVE_ADDRESS,
6
+ NO_VERSION
3
7
  } from "../../sdk/index.js";
8
+ import { AllowancePrerequisite } from "./AllowancePrerequisite.js";
9
+ import { BalancePrerequisite } from "./BalancePrerequisite.js";
4
10
  import { allowanceAndBalance } from "./helpers.js";
5
11
  async function buildCollateralPrerequisites(spenderOptions, multicall, ctx) {
6
- const { sdk, wallet } = ctx;
12
+ const { sdk, wallet, value = 0n } = ctx;
7
13
  const required = new AssetsMap();
8
14
  for (const op of multicall) {
9
15
  if (op.operation !== "AddCollateral" || op.amount === 0n) {
@@ -11,12 +17,45 @@ async function buildCollateralPrerequisites(spenderOptions, multicall, ctx) {
11
17
  }
12
18
  required.inc(op.token, op.amount);
13
19
  }
14
- if (required.size === 0) {
20
+ if (required.size === 0 && value === 0n) {
15
21
  return [];
16
22
  }
17
- const spender = await sdk.accounts.getApprovalAddress(spenderOptions);
18
23
  const prereqs = [];
24
+ if (value > 0n) {
25
+ prereqs.push(
26
+ new BalancePrerequisite({
27
+ token: NATIVE_ADDRESS,
28
+ owner: wallet,
29
+ required: value
30
+ })
31
+ );
32
+ }
33
+ if (required.size === 0) {
34
+ return prereqs;
35
+ }
36
+ const spender = await sdk.accounts.getApprovalAddress(spenderOptions);
37
+ const weth = sdk.addressProvider.getAddress(AP_WETH_TOKEN, NO_VERSION);
19
38
  for (const [token, amount] of required.entries()) {
39
+ if (value > 0n && isAddressEqual(token, weth)) {
40
+ prereqs.push(
41
+ new AllowancePrerequisite({
42
+ token,
43
+ owner: wallet,
44
+ spender,
45
+ required: amount
46
+ })
47
+ );
48
+ if (amount > value) {
49
+ prereqs.push(
50
+ new BalancePrerequisite({
51
+ token,
52
+ owner: wallet,
53
+ required: amount - value
54
+ })
55
+ );
56
+ }
57
+ continue;
58
+ }
20
59
  prereqs.push(
21
60
  ...allowanceAndBalance({
22
61
  token,
@@ -9,7 +9,8 @@ async function checkPrerequisites(input, options) {
9
9
  const ctx = {
10
10
  sdk,
11
11
  wallet,
12
- blockNumber: options?.blockNumber
12
+ blockNumber: options?.blockNumber,
13
+ value: input.value ?? 0n
13
14
  };
14
15
  const prereqs = await buildPrerequisites(tx, ctx);
15
16
  return Promise.all(prereqs.map((p) => p.verify(ctx)));
@@ -5,7 +5,7 @@ import {
5
5
  ERROR_UNPRICEABLE_TOKEN,
6
6
  PREVIEW_DUST
7
7
  } from "./types.js";
8
- function buildDelayedPreview(afterInstant, before, detected, convert) {
8
+ function buildDelayedPreview(afterInstant, before, detected, convert, receivedToken) {
9
9
  const { request, intent } = detected;
10
10
  const post = afterInstant.clone();
11
11
  const converter = makeSafeConverter(convert);
@@ -13,7 +13,7 @@ function buildDelayedPreview(afterInstant, before, detected, convert) {
13
13
  const collateralWithdrawn = new AssetsMap();
14
14
  switch (intent?.type) {
15
15
  case "CLOSE_ACCOUNT":
16
- return buildClosePreview(post, converter);
16
+ return buildClosePreview(post, converter, receivedToken);
17
17
  case "DECREASE_LEVERAGE":
18
18
  repayFromClaim(post, request.claimToken, converter.convert, claimed);
19
19
  break;
@@ -84,16 +84,17 @@ function totalValueInUnderlying(post, convert, dust) {
84
84
  (token, balance) => balance > dust ? convert(token, post.underlying, balance) : 0n
85
85
  );
86
86
  }
87
- function buildClosePreview(post, converter) {
87
+ function buildClosePreview(post, converter, receivedToken) {
88
88
  const totalValue = totalValueInUnderlying(post, converter.convert, 0n);
89
89
  return {
90
90
  operation: "CloseCreditAccount",
91
91
  permanent: false,
92
92
  creditManager: post.creditManager,
93
93
  creditAccount: post.creditAccount,
94
- // Oracle estimate denominated in the underlying
94
+ // Oracle estimate computed in the underlying; RWA underlyings convert
95
+ // 1:1 with their vault asset, so the amount holds for `receivedToken`
95
96
  receivedAmount: {
96
- token: post.underlying,
97
+ token: receivedToken,
97
98
  balance: BigIntMath.max(totalValue - post.totalDebt, 0n)
98
99
  },
99
100
  error: converter.error
@@ -56,6 +56,8 @@ async function previewMulticallOperation(input, operation, options) {
56
56
  operation.creditManager
57
57
  );
58
58
  const convert = (token, to, amount) => market.priceOracle.convert(token, to, amount);
59
+ const meta = sdk.tokensMeta.get(market.underlying);
60
+ const receivedToken = meta && sdk.tokensMeta.isRWAUnderlying(meta) ? meta.asset : market.underlying;
59
61
  return {
60
62
  operation: "DelayedCreditAccountOperation",
61
63
  creditAccount: operation.creditAccount,
@@ -66,7 +68,8 @@ async function previewMulticallOperation(input, operation, options) {
66
68
  after.account,
67
69
  before,
68
70
  delayed,
69
- convert
71
+ convert,
72
+ receivedToken
70
73
  )
71
74
  };
72
75
  }
@@ -10,5 +10,6 @@ import type { PrerequisiteContext } from "./types.js";
10
10
  * the credit manager for classic markets, but a per-investor "special wallet"
11
11
  * for RWA markets. The resolution happens at build time because the spender is
12
12
  * part of the prerequisite's identity and UI detail.
13
+ *
13
14
  */
14
15
  export declare function buildCollateralPrerequisites(spenderOptions: GetApprovalAddressProps, multicall: InnerOperation[], ctx: PrerequisiteContext): Promise<Prerequisite[]>;
@@ -34,8 +34,16 @@ export type PrerequisiteKind = PrerequisiteResult["kind"];
34
34
  /** Shared inputs for building and verifying prerequisites. */
35
35
  export interface PrerequisiteContext {
36
36
  sdk: OnchainSDK;
37
- /** Address whose balances/allowances are checked (the tx sender). */
37
+ /**
38
+ * Address whose balances/allowances are checked (the tx sender).
39
+ **/
38
40
  wallet: Address;
39
- /** Block to read at; defaults to latest. Only set for testnet forks. */
41
+ /**
42
+ * Block to read at; defaults to latest. Only set for testnet forks.
43
+ **/
40
44
  blockNumber?: bigint;
45
+ /**
46
+ * Transaction `msg.value`
47
+ **/
48
+ value: bigint;
41
49
  }
@@ -21,7 +21,9 @@ export type ConvertFn = (token: Address, to: Address, amount: bigint) => bigint;
21
21
  *
22
22
  * Intent-specific resume:
23
23
  * - `CLOSE_ACCOUNT`: everything is swapped into the underlying, the debt is
24
- * fully repaid and the rest is withdrawn to the user.
24
+ * fully repaid and the rest is withdrawn to the user as `receivedToken`
25
+ * (the unwrapped underlying for RWA markets, converting 1:1 with the
26
+ * underlying; the underlying itself otherwise).
25
27
  * - `DECREASE_LEVERAGE`: the claimed amount is swapped into the underlying
26
28
  * and used to decrease the debt.
27
29
  * - `WITHDRAW_COLLATERAL`: the recorded amount of the recorded token is
@@ -38,5 +40,8 @@ export type ConvertFn = (token: Address, to: Address, amount: bigint) => bigint;
38
40
  * @param afterInstant - Account state after the instant part of the
39
41
  * transaction.
40
42
  * @param before - Account state before the transaction (the diff base).
43
+ * @param receivedToken - Token the `CLOSE_ACCOUNT` resume withdraws to the
44
+ * user: the unwrapped underlying (vault asset) for RWA markets, the
45
+ * underlying itself otherwise.
41
46
  */
42
- export declare function buildDelayedPreview(afterInstant: CreditAccountState, before: CreditAccountState, detected: DetectedDelayedOperation, convert: ConvertFn): InstantOperationPreview;
47
+ export declare function buildDelayedPreview(afterInstant: CreditAccountState, before: CreditAccountState, detected: DetectedDelayedOperation, convert: ConvertFn, receivedToken: Address): InstantOperationPreview;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gearbox-protocol/sdk",
3
- "version": "14.12.0-next.33",
3
+ "version": "14.12.0-next.34",
4
4
  "description": "Gearbox SDK",
5
5
  "license": "MIT",
6
6
  "repository": {