@gearbox-protocol/sdk 14.12.0-next.48 → 14.12.0-next.49

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.
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var ILiquidationCompressorV313_exports = {};
20
+ __export(ILiquidationCompressorV313_exports, {
21
+ iLiquidationCompressorV313Abi: () => iLiquidationCompressorV313Abi
22
+ });
23
+ module.exports = __toCommonJS(ILiquidationCompressorV313_exports);
24
+ const iLiquidationCompressorV313Abi = [
25
+ {
26
+ type: "function",
27
+ name: "contractType",
28
+ inputs: [],
29
+ outputs: [{ name: "", type: "bytes32", internalType: "bytes32" }],
30
+ stateMutability: "view"
31
+ },
32
+ {
33
+ type: "function",
34
+ name: "getLiquidationData",
35
+ inputs: [
36
+ { name: "liquidator", type: "address", internalType: "address" },
37
+ { name: "creditAccount", type: "address", internalType: "address" },
38
+ {
39
+ name: "priceUpdates",
40
+ type: "tuple[]",
41
+ internalType: "struct PriceUpdate[]",
42
+ components: [
43
+ { name: "priceFeed", type: "address", internalType: "address" },
44
+ { name: "data", type: "bytes", internalType: "bytes" }
45
+ ]
46
+ }
47
+ ],
48
+ outputs: [
49
+ {
50
+ name: "",
51
+ type: "tuple",
52
+ internalType: "struct LiquidationData",
53
+ components: [
54
+ {
55
+ name: "requiredUnderlyingAmount",
56
+ type: "uint256",
57
+ internalType: "uint256"
58
+ },
59
+ {
60
+ name: "expectedOutputs",
61
+ type: "tuple[]",
62
+ internalType: "struct LiquidationOutput[]",
63
+ components: [
64
+ { name: "token", type: "address", internalType: "address" },
65
+ { name: "amount", type: "uint256", internalType: "uint256" },
66
+ { name: "delayed", type: "bool", internalType: "bool" },
67
+ {
68
+ name: "redeemerAddress",
69
+ type: "address",
70
+ internalType: "address"
71
+ },
72
+ { name: "claimableAt", type: "uint256", internalType: "uint256" }
73
+ ]
74
+ },
75
+ {
76
+ name: "liquidationCall",
77
+ type: "tuple",
78
+ internalType: "struct MultiCall",
79
+ components: [
80
+ { name: "target", type: "address", internalType: "address" },
81
+ { name: "callData", type: "bytes", internalType: "bytes" }
82
+ ]
83
+ },
84
+ { name: "isLiquidatorEligible", type: "bool", internalType: "bool" },
85
+ { name: "kycProtocol", type: "string", internalType: "string" },
86
+ { name: "kycToken", type: "address", internalType: "address" }
87
+ ]
88
+ }
89
+ ],
90
+ stateMutability: "nonpayable"
91
+ },
92
+ {
93
+ type: "function",
94
+ name: "version",
95
+ inputs: [],
96
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
97
+ stateMutability: "view"
98
+ }
99
+ ];
100
+ // Annotate the CommonJS export names for ESM import in node:
101
+ 0 && (module.exports = {
102
+ iLiquidationCompressorV313Abi
103
+ });
@@ -21,18 +21,17 @@ __export(LiquidationsService_exports, {
21
21
  LiquidationsService: () => LiquidationsService
22
22
  });
23
23
  module.exports = __toCommonJS(LiquidationsService_exports);
24
+ var import_ILiquidationCompressorV313 = require("../../../abi/ILiquidationCompressorV313.js");
24
25
  var import_base = require("../../base/index.js");
25
26
  var import_constants = require("../../constants/index.js");
26
27
  var import_utils = require("../../utils/index.js");
28
+ var import_constants2 = require("./constants.js");
27
29
  var import_helpers = require("./helpers.js");
28
30
  class LiquidationsService extends import_base.SDKConstruct {
29
31
  /**
30
32
  * {@inheritDoc ILiquidationsService.getLiquidatableAccounts}
31
33
  **/
32
34
  async getLiquidatableAccounts(props) {
33
- if (props?.networks && !props.networks.includes(this.sdk.networkType)) {
34
- return [];
35
- }
36
35
  await this.sdk.withdrawalCompressor?.loadWithdrawableAssets();
37
36
  const accounts = await this.sdk.accounts.getCreditAccounts({
38
37
  maxHealthFactor: import_constants.WAD - 1n,
@@ -67,67 +66,58 @@ class LiquidationsService extends import_base.SDKConstruct {
67
66
  * {@inheritDoc ILiquidationsService.getLiquidationDetails}
68
67
  **/
69
68
  async getLiquidationDetails(props) {
70
- const { network, creditAccount } = props;
71
- if (network !== this.sdk.networkType) {
72
- throw new Error(
73
- `network mismatch: this SDK is attached to ${this.sdk.networkType}, requested ${network}`
74
- );
75
- }
76
- const ca = await this.sdk.accounts.getCreditAccountData(creditAccount);
77
- if (!ca) {
78
- throw new Error(`credit account ${creditAccount} not found`);
79
- }
80
- if (!ca.success) {
81
- throw new Error(
82
- `cannot compute liquidation details for ${creditAccount}: collateral computation failed`
83
- );
84
- }
85
- const compressor = this.sdk.withdrawalCompressor;
86
- await compressor?.loadWithdrawableAssets();
69
+ const { creditAccount, liquidator, ignoreReservePrices } = props;
70
+ const ca = await this.#getCreditAccountData(creditAccount);
71
+ await this.sdk.withdrawalCompressor?.loadWithdrawableAssets();
87
72
  const account = this.#buildAccount(ca);
88
- const receivedAssets = [];
89
- for (const t of ca.tokens) {
90
- if (t.balance > import_helpers.DUST_THRESHOLD && !compressor?.getWithdrawalSourceToken(t.token)) {
91
- receivedAssets.push({
92
- isDelayed: false,
93
- token: t.token,
94
- amount: t.balance
95
- });
96
- }
97
- }
98
- if (account.isDelayed && compressor) {
99
- const { claimable, pending } = await compressor.getCurrentWithdrawals(creditAccount);
100
- for (const w of claimable) {
101
- for (const o of w.outputs) {
102
- receivedAssets.push({
103
- isDelayed: true,
104
- token: o.token,
105
- amount: o.amount,
106
- sourceToken: w.token
107
- });
108
- }
109
- }
110
- for (const w of pending) {
111
- for (const o of w.expectedOutputs) {
112
- receivedAssets.push({
113
- isDelayed: true,
114
- token: o.token,
115
- amount: o.amount,
116
- sourceToken: w.token,
117
- claimableAt: w.claimableAt
118
- });
119
- }
120
- }
121
- }
122
- return { ...account, receivedAssets };
73
+ const data = await this.#getLiquidationData(
74
+ ca,
75
+ liquidator,
76
+ ignoreReservePrices
77
+ );
78
+ const suite = this.sdk.marketRegister.findCreditManager(ca.creditManager);
79
+ return {
80
+ ...account,
81
+ // the compressor reports the exact amounts of the liquidation path it
82
+ // selected, which supersede the estimates of the list row
83
+ repaymentAmount: {
84
+ token: account.totalValue.token,
85
+ balance: data.requiredUnderlyingAmount
86
+ },
87
+ isDelayed: data.expectedOutputs.some((o) => o.delayed),
88
+ receivedAssets: (0, import_helpers.toReceivedAssets)(data.expectedOutputs),
89
+ isLiquidatorEligible: data.isLiquidatorEligible,
90
+ kycProtocol: data.kycProtocol || void 0,
91
+ kycToken: (0, import_utils.hexEq)(data.kycToken, import_constants.ADDRESS_0X0) ? void 0 : data.kycToken,
92
+ approve: (0, import_helpers.toLiquidationApproval)({
93
+ target: data.liquidationCall.target,
94
+ creditFacade: suite.creditFacade.address,
95
+ creditManager: ca.creditManager,
96
+ token: suite.underlying,
97
+ amount: data.requiredUnderlyingAmount
98
+ })
99
+ };
100
+ }
101
+ /**
102
+ * {@inheritDoc ILiquidationsService.buildLiquidationTx}
103
+ **/
104
+ async buildLiquidationTx(props) {
105
+ const { creditAccount, liquidator, ignoreReservePrices } = props;
106
+ const ca = await this.#getCreditAccountData(creditAccount);
107
+ const data = await this.#getLiquidationData(
108
+ ca,
109
+ liquidator,
110
+ ignoreReservePrices
111
+ );
112
+ return (0, import_helpers.liquidationCallToRawTx)(
113
+ data.liquidationCall,
114
+ `liquidate credit account ${this.labelAddress(creditAccount)} to ${this.labelAddress(liquidator)}`
115
+ );
123
116
  }
124
117
  /**
125
118
  * {@inheritDoc ILiquidationsService.getLiquidatorWithdrawals}
126
119
  **/
127
120
  async getLiquidatorWithdrawals(props) {
128
- if (props.networks && !props.networks.includes(this.sdk.networkType)) {
129
- return [];
130
- }
131
121
  const compressor = this.sdk.withdrawalCompressor;
132
122
  if (!compressor) {
133
123
  return [];
@@ -142,6 +132,39 @@ class LiquidationsService extends import_base.SDKConstruct {
142
132
  );
143
133
  return (0, import_helpers.toLiquidatorWithdrawals)(current, this.sdk.networkType);
144
134
  }
135
+ async #getCreditAccountData(creditAccount) {
136
+ const ca = await this.sdk.accounts.getCreditAccountData(creditAccount);
137
+ if (!ca) {
138
+ throw new Error(`credit account ${creditAccount} not found`);
139
+ }
140
+ if (!ca.success) {
141
+ throw new Error(
142
+ `cannot compute liquidation details for ${creditAccount}: collateral computation failed`
143
+ );
144
+ }
145
+ return ca;
146
+ }
147
+ /**
148
+ * Previews the liquidation via the liquidation compressor.
149
+ *
150
+ * @param ca - Credit account to liquidate
151
+ * @param liquidator - Liquidator wallet, zero address when not known: it only
152
+ * affects the KYC eligibility fields and the receiver encoded into the calls
153
+ * @param ignoreReservePrices - Exclude reserve price feeds from the updates
154
+ **/
155
+ async #getLiquidationData(ca, liquidator = import_constants.ADDRESS_0X0, ignoreReservePrices) {
156
+ const priceUpdates = await this.sdk.accounts.getOnDemandPriceUpdates(
157
+ ca,
158
+ ignoreReservePrices
159
+ );
160
+ const { result } = await this.client.simulateContract({
161
+ address: import_constants2.LIQUIDATION_COMPRESSOR_V313_ADDRESS,
162
+ abi: import_ILiquidationCompressorV313.iLiquidationCompressorV313Abi,
163
+ functionName: "getLiquidationData",
164
+ args: [liquidator, ca.creditAccount, priceUpdates]
165
+ });
166
+ return result;
167
+ }
145
168
  /**
146
169
  * Accounts of expired credit managers with outstanding debt are liquidatable
147
170
  * regardless of their health factor.
@@ -58,6 +58,12 @@ class MultichainLiquidationsService {
58
58
  async getLiquidationDetails(props) {
59
59
  return this.#sdk.chain(props.network).liquidations.getLiquidationDetails(props);
60
60
  }
61
+ /**
62
+ * {@inheritDoc ILiquidationsService.buildLiquidationTx}
63
+ **/
64
+ async buildLiquidationTx(props) {
65
+ return this.#sdk.chain(props.network).liquidations.buildLiquidationTx(props);
66
+ }
61
67
  /**
62
68
  * {@inheritDoc ILiquidationsService.getLiquidatorWithdrawals}
63
69
  **/
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var constants_exports = {};
20
+ __export(constants_exports, {
21
+ LIQUIDATION_COMPRESSOR_V313_ADDRESS: () => LIQUIDATION_COMPRESSOR_V313_ADDRESS
22
+ });
23
+ module.exports = __toCommonJS(constants_exports);
24
+ var import_constants = require("../../constants/index.js");
25
+ const LIQUIDATION_COMPRESSOR_V313_ADDRESS = import_constants.ADDRESS_0X0;
26
+ // Annotate the CommonJS export names for ESM import in node:
27
+ 0 && (module.exports = {
28
+ LIQUIDATION_COMPRESSOR_V313_ADDRESS
29
+ });
@@ -21,10 +21,14 @@ __export(helpers_exports, {
21
21
  DUST_THRESHOLD: () => DUST_THRESHOLD,
22
22
  calcEstimatedProfit: () => calcEstimatedProfit,
23
23
  calcRepaymentAmount: () => calcRepaymentAmount,
24
+ liquidationCallToRawTx: () => liquidationCallToRawTx,
24
25
  pickMainAsset: () => pickMainAsset,
25
- toLiquidatorWithdrawals: () => toLiquidatorWithdrawals
26
+ toLiquidationApproval: () => toLiquidationApproval,
27
+ toLiquidatorWithdrawals: () => toLiquidatorWithdrawals,
28
+ toReceivedAssets: () => toReceivedAssets
26
29
  });
27
30
  module.exports = __toCommonJS(helpers_exports);
31
+ var import_viem = require("viem");
28
32
  var import_constants = require("../../constants/index.js");
29
33
  var import_utils = require("../../utils/index.js");
30
34
  const DUST_THRESHOLD = 10n;
@@ -80,11 +84,54 @@ function toLiquidatorWithdrawals(current, network) {
80
84
  }
81
85
  return rows;
82
86
  }
87
+ function toReceivedAssets(outputs) {
88
+ return outputs.map((o) => {
89
+ if (!o.delayed) {
90
+ return { isDelayed: false, token: o.token, amount: o.amount };
91
+ }
92
+ return {
93
+ isDelayed: true,
94
+ token: o.token,
95
+ amount: o.amount,
96
+ redeemerAddress: (0, import_utils.hexEq)(o.redeemerAddress, import_constants.ADDRESS_0X0) ? void 0 : o.redeemerAddress,
97
+ claimableAt: o.claimableAt === 0n ? void 0 : o.claimableAt
98
+ };
99
+ });
100
+ }
101
+ function toLiquidationApproval(props) {
102
+ const { target, creditFacade, creditManager, token, amount } = props;
103
+ if (amount === 0n) {
104
+ return void 0;
105
+ }
106
+ return {
107
+ spender: (0, import_utils.hexEq)(target, creditFacade) ? creditManager : target,
108
+ token,
109
+ amount
110
+ };
111
+ }
112
+ function liquidationCallToRawTx(call, description) {
113
+ return {
114
+ to: call.target,
115
+ value: "0",
116
+ signature: "",
117
+ callData: call.callData,
118
+ contractMethod: {
119
+ name: (0, import_viem.slice)(call.callData, 0, 4),
120
+ inputs: [],
121
+ payable: false
122
+ },
123
+ contractInputsValues: {},
124
+ description
125
+ };
126
+ }
83
127
  // Annotate the CommonJS export names for ESM import in node:
84
128
  0 && (module.exports = {
85
129
  DUST_THRESHOLD,
86
130
  calcEstimatedProfit,
87
131
  calcRepaymentAmount,
132
+ liquidationCallToRawTx,
88
133
  pickMainAsset,
89
- toLiquidatorWithdrawals
134
+ toLiquidationApproval,
135
+ toLiquidatorWithdrawals,
136
+ toReceivedAssets
90
137
  });
@@ -15,13 +15,13 @@ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "defau
15
15
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
16
16
  var liquidations_exports = {};
17
17
  module.exports = __toCommonJS(liquidations_exports);
18
- __reExport(liquidations_exports, require("./helpers.js"), module.exports);
18
+ __reExport(liquidations_exports, require("./constants.js"), module.exports);
19
19
  __reExport(liquidations_exports, require("./LiquidationsService.js"), module.exports);
20
20
  __reExport(liquidations_exports, require("./MultichainLiquidationsService.js"), module.exports);
21
21
  __reExport(liquidations_exports, require("./types.js"), module.exports);
22
22
  // Annotate the CommonJS export names for ESM import in node:
23
23
  0 && (module.exports = {
24
- ...require("./helpers.js"),
24
+ ...require("./constants.js"),
25
25
  ...require("./LiquidationsService.js"),
26
26
  ...require("./MultichainLiquidationsService.js"),
27
27
  ...require("./types.js")
@@ -0,0 +1,79 @@
1
+ const iLiquidationCompressorV313Abi = [
2
+ {
3
+ type: "function",
4
+ name: "contractType",
5
+ inputs: [],
6
+ outputs: [{ name: "", type: "bytes32", internalType: "bytes32" }],
7
+ stateMutability: "view"
8
+ },
9
+ {
10
+ type: "function",
11
+ name: "getLiquidationData",
12
+ inputs: [
13
+ { name: "liquidator", type: "address", internalType: "address" },
14
+ { name: "creditAccount", type: "address", internalType: "address" },
15
+ {
16
+ name: "priceUpdates",
17
+ type: "tuple[]",
18
+ internalType: "struct PriceUpdate[]",
19
+ components: [
20
+ { name: "priceFeed", type: "address", internalType: "address" },
21
+ { name: "data", type: "bytes", internalType: "bytes" }
22
+ ]
23
+ }
24
+ ],
25
+ outputs: [
26
+ {
27
+ name: "",
28
+ type: "tuple",
29
+ internalType: "struct LiquidationData",
30
+ components: [
31
+ {
32
+ name: "requiredUnderlyingAmount",
33
+ type: "uint256",
34
+ internalType: "uint256"
35
+ },
36
+ {
37
+ name: "expectedOutputs",
38
+ type: "tuple[]",
39
+ internalType: "struct LiquidationOutput[]",
40
+ components: [
41
+ { name: "token", type: "address", internalType: "address" },
42
+ { name: "amount", type: "uint256", internalType: "uint256" },
43
+ { name: "delayed", type: "bool", internalType: "bool" },
44
+ {
45
+ name: "redeemerAddress",
46
+ type: "address",
47
+ internalType: "address"
48
+ },
49
+ { name: "claimableAt", type: "uint256", internalType: "uint256" }
50
+ ]
51
+ },
52
+ {
53
+ name: "liquidationCall",
54
+ type: "tuple",
55
+ internalType: "struct MultiCall",
56
+ components: [
57
+ { name: "target", type: "address", internalType: "address" },
58
+ { name: "callData", type: "bytes", internalType: "bytes" }
59
+ ]
60
+ },
61
+ { name: "isLiquidatorEligible", type: "bool", internalType: "bool" },
62
+ { name: "kycProtocol", type: "string", internalType: "string" },
63
+ { name: "kycToken", type: "address", internalType: "address" }
64
+ ]
65
+ }
66
+ ],
67
+ stateMutability: "nonpayable"
68
+ },
69
+ {
70
+ type: "function",
71
+ name: "version",
72
+ inputs: [],
73
+ outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
74
+ stateMutability: "view"
75
+ }
76
+ ];
77
+ export {
78
+ iLiquidationCompressorV313Abi
79
+ };
@@ -1,21 +1,23 @@
1
+ import { iLiquidationCompressorV313Abi } from "../../../abi/ILiquidationCompressorV313.js";
1
2
  import { SDKConstruct } from "../../base/index.js";
2
- import { WAD } from "../../constants/index.js";
3
- import { AddressSet } from "../../utils/index.js";
3
+ import { ADDRESS_0X0, WAD } from "../../constants/index.js";
4
+ import { AddressSet, hexEq } from "../../utils/index.js";
5
+ import { LIQUIDATION_COMPRESSOR_V313_ADDRESS } from "./constants.js";
4
6
  import {
5
7
  calcEstimatedProfit,
6
8
  calcRepaymentAmount,
7
9
  DUST_THRESHOLD,
10
+ liquidationCallToRawTx,
8
11
  pickMainAsset,
9
- toLiquidatorWithdrawals
12
+ toLiquidationApproval,
13
+ toLiquidatorWithdrawals,
14
+ toReceivedAssets
10
15
  } from "./helpers.js";
11
16
  class LiquidationsService extends SDKConstruct {
12
17
  /**
13
18
  * {@inheritDoc ILiquidationsService.getLiquidatableAccounts}
14
19
  **/
15
20
  async getLiquidatableAccounts(props) {
16
- if (props?.networks && !props.networks.includes(this.sdk.networkType)) {
17
- return [];
18
- }
19
21
  await this.sdk.withdrawalCompressor?.loadWithdrawableAssets();
20
22
  const accounts = await this.sdk.accounts.getCreditAccounts({
21
23
  maxHealthFactor: WAD - 1n,
@@ -50,67 +52,58 @@ class LiquidationsService extends SDKConstruct {
50
52
  * {@inheritDoc ILiquidationsService.getLiquidationDetails}
51
53
  **/
52
54
  async getLiquidationDetails(props) {
53
- const { network, creditAccount } = props;
54
- if (network !== this.sdk.networkType) {
55
- throw new Error(
56
- `network mismatch: this SDK is attached to ${this.sdk.networkType}, requested ${network}`
57
- );
58
- }
59
- const ca = await this.sdk.accounts.getCreditAccountData(creditAccount);
60
- if (!ca) {
61
- throw new Error(`credit account ${creditAccount} not found`);
62
- }
63
- if (!ca.success) {
64
- throw new Error(
65
- `cannot compute liquidation details for ${creditAccount}: collateral computation failed`
66
- );
67
- }
68
- const compressor = this.sdk.withdrawalCompressor;
69
- await compressor?.loadWithdrawableAssets();
55
+ const { creditAccount, liquidator, ignoreReservePrices } = props;
56
+ const ca = await this.#getCreditAccountData(creditAccount);
57
+ await this.sdk.withdrawalCompressor?.loadWithdrawableAssets();
70
58
  const account = this.#buildAccount(ca);
71
- const receivedAssets = [];
72
- for (const t of ca.tokens) {
73
- if (t.balance > DUST_THRESHOLD && !compressor?.getWithdrawalSourceToken(t.token)) {
74
- receivedAssets.push({
75
- isDelayed: false,
76
- token: t.token,
77
- amount: t.balance
78
- });
79
- }
80
- }
81
- if (account.isDelayed && compressor) {
82
- const { claimable, pending } = await compressor.getCurrentWithdrawals(creditAccount);
83
- for (const w of claimable) {
84
- for (const o of w.outputs) {
85
- receivedAssets.push({
86
- isDelayed: true,
87
- token: o.token,
88
- amount: o.amount,
89
- sourceToken: w.token
90
- });
91
- }
92
- }
93
- for (const w of pending) {
94
- for (const o of w.expectedOutputs) {
95
- receivedAssets.push({
96
- isDelayed: true,
97
- token: o.token,
98
- amount: o.amount,
99
- sourceToken: w.token,
100
- claimableAt: w.claimableAt
101
- });
102
- }
103
- }
104
- }
105
- return { ...account, receivedAssets };
59
+ const data = await this.#getLiquidationData(
60
+ ca,
61
+ liquidator,
62
+ ignoreReservePrices
63
+ );
64
+ const suite = this.sdk.marketRegister.findCreditManager(ca.creditManager);
65
+ return {
66
+ ...account,
67
+ // the compressor reports the exact amounts of the liquidation path it
68
+ // selected, which supersede the estimates of the list row
69
+ repaymentAmount: {
70
+ token: account.totalValue.token,
71
+ balance: data.requiredUnderlyingAmount
72
+ },
73
+ isDelayed: data.expectedOutputs.some((o) => o.delayed),
74
+ receivedAssets: toReceivedAssets(data.expectedOutputs),
75
+ isLiquidatorEligible: data.isLiquidatorEligible,
76
+ kycProtocol: data.kycProtocol || void 0,
77
+ kycToken: hexEq(data.kycToken, ADDRESS_0X0) ? void 0 : data.kycToken,
78
+ approve: toLiquidationApproval({
79
+ target: data.liquidationCall.target,
80
+ creditFacade: suite.creditFacade.address,
81
+ creditManager: ca.creditManager,
82
+ token: suite.underlying,
83
+ amount: data.requiredUnderlyingAmount
84
+ })
85
+ };
86
+ }
87
+ /**
88
+ * {@inheritDoc ILiquidationsService.buildLiquidationTx}
89
+ **/
90
+ async buildLiquidationTx(props) {
91
+ const { creditAccount, liquidator, ignoreReservePrices } = props;
92
+ const ca = await this.#getCreditAccountData(creditAccount);
93
+ const data = await this.#getLiquidationData(
94
+ ca,
95
+ liquidator,
96
+ ignoreReservePrices
97
+ );
98
+ return liquidationCallToRawTx(
99
+ data.liquidationCall,
100
+ `liquidate credit account ${this.labelAddress(creditAccount)} to ${this.labelAddress(liquidator)}`
101
+ );
106
102
  }
107
103
  /**
108
104
  * {@inheritDoc ILiquidationsService.getLiquidatorWithdrawals}
109
105
  **/
110
106
  async getLiquidatorWithdrawals(props) {
111
- if (props.networks && !props.networks.includes(this.sdk.networkType)) {
112
- return [];
113
- }
114
107
  const compressor = this.sdk.withdrawalCompressor;
115
108
  if (!compressor) {
116
109
  return [];
@@ -125,6 +118,39 @@ class LiquidationsService extends SDKConstruct {
125
118
  );
126
119
  return toLiquidatorWithdrawals(current, this.sdk.networkType);
127
120
  }
121
+ async #getCreditAccountData(creditAccount) {
122
+ const ca = await this.sdk.accounts.getCreditAccountData(creditAccount);
123
+ if (!ca) {
124
+ throw new Error(`credit account ${creditAccount} not found`);
125
+ }
126
+ if (!ca.success) {
127
+ throw new Error(
128
+ `cannot compute liquidation details for ${creditAccount}: collateral computation failed`
129
+ );
130
+ }
131
+ return ca;
132
+ }
133
+ /**
134
+ * Previews the liquidation via the liquidation compressor.
135
+ *
136
+ * @param ca - Credit account to liquidate
137
+ * @param liquidator - Liquidator wallet, zero address when not known: it only
138
+ * affects the KYC eligibility fields and the receiver encoded into the calls
139
+ * @param ignoreReservePrices - Exclude reserve price feeds from the updates
140
+ **/
141
+ async #getLiquidationData(ca, liquidator = ADDRESS_0X0, ignoreReservePrices) {
142
+ const priceUpdates = await this.sdk.accounts.getOnDemandPriceUpdates(
143
+ ca,
144
+ ignoreReservePrices
145
+ );
146
+ const { result } = await this.client.simulateContract({
147
+ address: LIQUIDATION_COMPRESSOR_V313_ADDRESS,
148
+ abi: iLiquidationCompressorV313Abi,
149
+ functionName: "getLiquidationData",
150
+ args: [liquidator, ca.creditAccount, priceUpdates]
151
+ });
152
+ return result;
153
+ }
128
154
  /**
129
155
  * Accounts of expired credit managers with outstanding debt are liquidatable
130
156
  * regardless of their health factor.