@wildcatfi/wildcat-sdk 2.0.82 → 3.0.1

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 (130) hide show
  1. package/dist/access/access-control.d.ts +67 -0
  2. package/dist/access/access-control.d.ts.map +1 -0
  3. package/dist/access/access-control.js +176 -0
  4. package/dist/access/access-control.js.map +1 -0
  5. package/dist/access/fixed-term.d.ts +73 -0
  6. package/dist/access/fixed-term.d.ts.map +1 -0
  7. package/dist/access/fixed-term.js +179 -0
  8. package/dist/access/fixed-term.js.map +1 -0
  9. package/dist/access/index.d.ts +13 -0
  10. package/dist/access/index.d.ts.map +1 -0
  11. package/dist/access/index.js +47 -0
  12. package/dist/access/index.js.map +1 -0
  13. package/dist/access/utils.d.ts +3 -0
  14. package/dist/access/utils.d.ts.map +1 -0
  15. package/dist/access/utils.js +24 -0
  16. package/dist/access/utils.js.map +1 -0
  17. package/dist/access/validation.d.ts +20 -0
  18. package/dist/access/validation.d.ts.map +1 -0
  19. package/dist/access/validation.js +12 -0
  20. package/dist/access/validation.js.map +1 -0
  21. package/dist/{account.d.ts → account/index.d.ts} +58 -83
  22. package/dist/account/index.d.ts.map +1 -0
  23. package/dist/{account.js → account/index.js} +346 -149
  24. package/dist/account/index.js.map +1 -0
  25. package/dist/account/validation.d.ts +88 -0
  26. package/dist/account/validation.d.ts.map +1 -0
  27. package/dist/account/validation.js +61 -0
  28. package/dist/account/validation.js.map +1 -0
  29. package/dist/constants.d.ts +7 -2
  30. package/dist/constants.d.ts.map +1 -1
  31. package/dist/constants.js +27 -2
  32. package/dist/constants.js.map +1 -1
  33. package/dist/controller.d.ts +1 -0
  34. package/dist/controller.d.ts.map +1 -1
  35. package/dist/controller.js +1 -0
  36. package/dist/controller.js.map +1 -1
  37. package/dist/gql/getAuthorizedLendersByMarket.js +1 -1
  38. package/dist/gql/getAuthorizedLendersByMarket.js.map +1 -1
  39. package/dist/gql/getMarketsForBorrower.d.ts.map +1 -1
  40. package/dist/gql/getMarketsForBorrower.js +1 -5
  41. package/dist/gql/getMarketsForBorrower.js.map +1 -1
  42. package/dist/gql/graphql.d.ts +5923 -1369
  43. package/dist/gql/graphql.d.ts.map +1 -1
  44. package/dist/gql/graphql.js +1289 -29
  45. package/dist/gql/graphql.js.map +1 -1
  46. package/dist/hooks/useMarketsForBorrower.js +1 -1
  47. package/dist/hooks/useMarketsForBorrower.js.map +1 -1
  48. package/dist/market.d.ts +38 -22
  49. package/dist/market.d.ts.map +1 -1
  50. package/dist/market.js +299 -101
  51. package/dist/market.js.map +1 -1
  52. package/dist/mockerc20factory.d.ts +1 -0
  53. package/dist/mockerc20factory.d.ts.map +1 -1
  54. package/dist/mockerc20factory.js +1 -0
  55. package/dist/mockerc20factory.js.map +1 -1
  56. package/dist/token.d.ts +1 -0
  57. package/dist/token.d.ts.map +1 -1
  58. package/dist/token.js +1 -0
  59. package/dist/token.js.map +1 -1
  60. package/dist/typechain/AccountQuery.d.ts +1 -1
  61. package/dist/typechain/AccountQuery.d.ts.map +1 -1
  62. package/dist/typechain/AccountsQuery.d.ts +1 -1
  63. package/dist/typechain/AccountsQuery.d.ts.map +1 -1
  64. package/dist/typechain/HooksFactory.d.ts +593 -0
  65. package/dist/typechain/HooksFactory.d.ts.map +1 -0
  66. package/dist/typechain/HooksFactory.js +3 -0
  67. package/dist/typechain/HooksFactory.js.map +1 -0
  68. package/dist/typechain/IFixedTermHooks.d.ts +1016 -0
  69. package/dist/typechain/IFixedTermHooks.d.ts.map +1 -0
  70. package/dist/typechain/IFixedTermHooks.js +3 -0
  71. package/dist/typechain/IFixedTermHooks.js.map +1 -0
  72. package/dist/typechain/IOpenTermHooks.d.ts +971 -0
  73. package/dist/typechain/IOpenTermHooks.d.ts.map +1 -0
  74. package/dist/typechain/IOpenTermHooks.js +3 -0
  75. package/dist/typechain/IOpenTermHooks.js.map +1 -0
  76. package/dist/typechain/MarketLens.d.ts +12 -115
  77. package/dist/typechain/MarketLens.d.ts.map +1 -1
  78. package/dist/typechain/MarketLensV2.d.ts +692 -0
  79. package/dist/typechain/MarketLensV2.d.ts.map +1 -0
  80. package/dist/typechain/MarketLensV2.js +3 -0
  81. package/dist/typechain/MarketLensV2.js.map +1 -0
  82. package/dist/typechain/WildcatMarket.d.ts +3 -17
  83. package/dist/typechain/WildcatMarket.d.ts.map +1 -1
  84. package/dist/typechain/WildcatMarketController.d.ts +2 -28
  85. package/dist/typechain/WildcatMarketController.d.ts.map +1 -1
  86. package/dist/typechain/WildcatMarketControllerFactory.d.ts +2 -29
  87. package/dist/typechain/WildcatMarketControllerFactory.d.ts.map +1 -1
  88. package/dist/typechain/WildcatMarketV2.d.ts +1086 -0
  89. package/dist/typechain/WildcatMarketV2.d.ts.map +1 -0
  90. package/dist/typechain/WildcatMarketV2.js +3 -0
  91. package/dist/typechain/WildcatMarketV2.js.map +1 -0
  92. package/dist/typechain/factories/HooksFactory__factory.d.ts +902 -0
  93. package/dist/typechain/factories/HooksFactory__factory.d.ts.map +1 -0
  94. package/dist/typechain/factories/HooksFactory__factory.js +1168 -0
  95. package/dist/typechain/factories/HooksFactory__factory.js.map +1 -0
  96. package/dist/typechain/factories/IFixedTermHooks__factory.d.ts +1884 -0
  97. package/dist/typechain/factories/IFixedTermHooks__factory.d.ts.map +1 -0
  98. package/dist/typechain/factories/IFixedTermHooks__factory.js +2410 -0
  99. package/dist/typechain/factories/IFixedTermHooks__factory.js.map +1 -0
  100. package/dist/typechain/factories/IOpenTermHooks__factory.d.ts +1781 -0
  101. package/dist/typechain/factories/IOpenTermHooks__factory.d.ts.map +1 -0
  102. package/dist/typechain/factories/IOpenTermHooks__factory.js +2280 -0
  103. package/dist/typechain/factories/IOpenTermHooks__factory.js.map +1 -0
  104. package/dist/typechain/factories/MarketLensV2__factory.d.ts +5786 -0
  105. package/dist/typechain/factories/MarketLensV2__factory.d.ts.map +1 -0
  106. package/dist/typechain/factories/MarketLensV2__factory.js +7396 -0
  107. package/dist/typechain/factories/MarketLensV2__factory.js.map +1 -0
  108. package/dist/typechain/factories/WildcatMarketV2__factory.d.ts +1304 -0
  109. package/dist/typechain/factories/WildcatMarketV2__factory.d.ts.map +1 -0
  110. package/dist/typechain/factories/WildcatMarketV2__factory.js +1680 -0
  111. package/dist/typechain/factories/WildcatMarketV2__factory.js.map +1 -0
  112. package/dist/typechain/factories/index.d.ts +5 -0
  113. package/dist/typechain/factories/index.d.ts.map +1 -1
  114. package/dist/typechain/factories/index.js +11 -1
  115. package/dist/typechain/factories/index.js.map +1 -1
  116. package/dist/typechain/index.d.ts +15 -1
  117. package/dist/typechain/index.d.ts.map +1 -1
  118. package/dist/typechain/index.js +11 -1
  119. package/dist/typechain/index.js.map +1 -1
  120. package/dist/types.d.ts +138 -1
  121. package/dist/types.d.ts.map +1 -1
  122. package/dist/types.js +73 -3
  123. package/dist/types.js.map +1 -1
  124. package/dist/utils/type-parsers.d.ts +9 -2
  125. package/dist/utils/type-parsers.d.ts.map +1 -1
  126. package/dist/utils/type-parsers.js +64 -1
  127. package/dist/utils/type-parsers.js.map +1 -1
  128. package/package.json +4 -4
  129. package/dist/account.d.ts.map +0 -1
  130. package/dist/account.js.map +0 -1
@@ -1,12 +1,30 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
2
16
  Object.defineProperty(exports, "__esModule", { value: true });
3
17
  exports.MarketAccount = exports.LenderRole = void 0;
4
18
  const ethers_1 = require("ethers");
5
- const token_1 = require("./token");
6
- const market_1 = require("./market");
7
- const utils_1 = require("./utils");
8
- const constants_1 = require("./constants");
9
- const withdrawal_status_1 = require("./withdrawal-status");
19
+ const token_1 = require("../token");
20
+ const market_1 = require("../market");
21
+ const typechain_1 = require("../typechain");
22
+ const utils_1 = require("../utils");
23
+ const constants_1 = require("../constants");
24
+ const types_1 = require("../types");
25
+ const withdrawal_status_1 = require("../withdrawal-status");
26
+ const validation_1 = require("./validation");
27
+ __exportStar(require("./validation"), exports);
10
28
  var LenderRole;
11
29
  (function (LenderRole) {
12
30
  LenderRole[LenderRole["Null"] = 0] = "Null";
@@ -14,9 +32,7 @@ var LenderRole;
14
32
  LenderRole[LenderRole["WithdrawOnly"] = 2] = "WithdrawOnly";
15
33
  LenderRole[LenderRole["DepositAndWithdraw"] = 3] = "DepositAndWithdraw";
16
34
  })(LenderRole = exports.LenderRole || (exports.LenderRole = {}));
17
- const isMarketInstanceArray = (markets) => {
18
- return typeof markets[0] !== "string";
19
- };
35
+ const NullProviderIndex = ethers_1.BigNumber.from(2).pow(24).sub(1).toNumber();
20
36
  /**
21
37
  * Class to provide information about a market user's account
22
38
  * and to wrap interactions.
@@ -26,21 +42,9 @@ const isMarketInstanceArray = (markets) => {
26
42
  *
27
43
  */
28
44
  class MarketAccount {
29
- constructor(account, isAuthorizedOnController, role, scaledMarketBalance, marketBalance, underlyingBalance, underlyingApproval, market, deposits = [], totalDeposited, lastScaleFactor, lastUpdatedTimestamp, totalInterestEarned, numPendingWithdrawalBatches) {
30
- this.account = account;
31
- this.isAuthorizedOnController = isAuthorizedOnController;
32
- this.role = role;
33
- this.scaledMarketBalance = scaledMarketBalance;
34
- this.marketBalance = marketBalance;
35
- this.underlyingBalance = underlyingBalance;
36
- this.underlyingApproval = underlyingApproval;
37
- this.market = market;
38
- this.deposits = deposits;
39
- this.totalDeposited = totalDeposited;
40
- this.lastScaleFactor = lastScaleFactor;
41
- this.lastUpdatedTimestamp = lastUpdatedTimestamp;
42
- this.totalInterestEarned = totalInterestEarned;
43
- this.numPendingWithdrawalBatches = numPendingWithdrawalBatches;
45
+ constructor(args) {
46
+ Object.assign(this, args);
47
+ this.depositRecords = (args.deposits ?? []).map((log) => (0, utils_1.parseMarketRecord)(this.market.underlyingToken, log));
44
48
  }
45
49
  get chainId() {
46
50
  return this.market.chainId;
@@ -54,42 +58,108 @@ class MarketAccount {
54
58
  get isBorrower() {
55
59
  return this.market.borrower.toLowerCase() === this.account.toLowerCase();
56
60
  }
57
- get canDeposit() {
58
- return (this.role === LenderRole.DepositAndWithdraw ||
59
- (this.role === LenderRole.Null && this.isAuthorizedOnController));
61
+ get credentialExpiry() {
62
+ if (this.credential && this.credential.lastProvider) {
63
+ return this.credential.lastApprovalTimestamp + this.credential.lastProvider.timeToLive;
64
+ }
65
+ return undefined;
66
+ }
67
+ get hasValidCredential() {
68
+ const expiry = this.credentialExpiry;
69
+ return expiry !== undefined && expiry >= Date.now() / 1000;
70
+ }
71
+ get depositAvailability() {
72
+ if (this.market.isClosed)
73
+ return validation_1.DepositStatus.MarketClosed;
74
+ if (this.market.version === types_1.MarketVersion.V1) {
75
+ if (this.role === LenderRole.Blocked)
76
+ return validation_1.DepositStatus.Blocked;
77
+ if (this.role === LenderRole.DepositAndWithdraw ||
78
+ (this.role === LenderRole.Null && !!this.isAuthorizedOnController)) {
79
+ return validation_1.DepositStatus.Ready;
80
+ }
81
+ return validation_1.DepositStatus.InsufficientRole;
82
+ }
83
+ else {
84
+ const config = this.market.hooksConfig;
85
+ (0, utils_1.assert)(config !== undefined, `V2 market missing hooksConfig`);
86
+ // Can deposit if the market does not use the onDeposit hook
87
+ if (!config.flags.useOnDeposit)
88
+ return validation_1.DepositStatus.Ready;
89
+ // Can not deposit if the lender is blocked
90
+ if (this.credential?.isBlockedFromDeposits)
91
+ return validation_1.DepositStatus.Blocked;
92
+ // Can deposit if lender has credential or market does not require one
93
+ if (config.depositRequiresAccess && !this.hasValidCredential) {
94
+ return validation_1.DepositStatus.RequiresAccess;
95
+ }
96
+ return validation_1.DepositStatus.Ready;
97
+ }
60
98
  }
61
- get canWithdraw() {
62
- return (this.role === LenderRole.WithdrawOnly ||
63
- this.role === LenderRole.DepositAndWithdraw ||
64
- (this.role === LenderRole.Null && this.isAuthorizedOnController));
99
+ get withdrawalAvailability() {
100
+ if (this.market.version === types_1.MarketVersion.V1) {
101
+ if (this.role === LenderRole.WithdrawOnly ||
102
+ this.role === LenderRole.DepositAndWithdraw ||
103
+ (this.role === LenderRole.Null && !!this.isAuthorizedOnController)) {
104
+ return validation_1.QueueWithdrawalStatus.Ready;
105
+ }
106
+ return validation_1.QueueWithdrawalStatus.InsufficientRole;
107
+ }
108
+ else {
109
+ const config = this.market.hooksConfig;
110
+ (0, utils_1.assert)(config !== undefined, `V2 market missing hooksConfig`);
111
+ // Can withdraw if market does not use wd hook
112
+ if (!config.flags.useOnQueueWithdrawal)
113
+ return validation_1.QueueWithdrawalStatus.Ready;
114
+ // Can not withdraw if market in fixed term
115
+ if (this.market.isInFixedTerm)
116
+ return validation_1.QueueWithdrawalStatus.MarketInClosedTerm;
117
+ // Can not withdraw if market requires access and lender has no credential and is not a known lender
118
+ if (config.flags.useOnQueueWithdrawal &&
119
+ (config.kind === types_1.HooksKind.FixedTerm
120
+ ? config.queueWithdrawalRequiresAccess
121
+ : config.flags.useOnQueueWithdrawal) &&
122
+ !(this.hasValidCredential || this.isKnownLender)) {
123
+ return validation_1.QueueWithdrawalStatus.RequiresAccess;
124
+ }
125
+ return validation_1.QueueWithdrawalStatus.Ready;
126
+ }
65
127
  }
66
128
  canChangeAPR(apr) {
67
129
  return this.isBorrower && apr > 0 && apr <= 10000 && this.market.canChangeAPR(apr);
68
130
  }
69
- checkCloseMarketStep() {
131
+ previewCloseMarket() {
70
132
  if (!this.isBorrower)
71
- return { status: "NotBorrower" };
133
+ return { status: validation_1.CloseMarketStatus.NotBorrower };
134
+ if (this.market.version === types_1.MarketVersion.V2) {
135
+ const config = this.market.hooksConfig;
136
+ (0, utils_1.assert)(config !== undefined, `V2 market missing hooksConfig`);
137
+ if (this.market.isInFixedTerm &&
138
+ config.kind === types_1.HooksKind.FixedTerm &&
139
+ config.allowClosureBeforeTerm) {
140
+ return { status: validation_1.CloseMarketStatus.EarlyClosureNotAllowed };
141
+ }
142
+ }
72
143
  // add 0.1% to account for interest
73
144
  const amount = this.market.underlyingToken.getAmount((0, utils_1.bipMul)(this.market.outstandingDebt.raw, (0, token_1.toBn)(10010)));
74
145
  if (amount.gt(this.underlyingBalance)) {
75
- return { status: "InsufficientBalance" };
146
+ return { status: validation_1.CloseMarketStatus.InsufficientBalance };
76
147
  }
77
148
  if (this.market.unpaidWithdrawalBatchExpiries.length > 0) {
78
- return { status: "UnpaidWithdrawalBatches" };
149
+ return { status: validation_1.CloseMarketStatus.UnpaidWithdrawalBatches };
79
150
  }
80
- if (!this.isApprovedFor(this.market.underlyingToken.getAmount((0, utils_1.bipMul)(this.market.outstandingDebt.raw, (0, token_1.toBn)(10006))))) {
81
- return {
82
- status: "InsufficientAllowance",
83
- remainder: amount
84
- };
151
+ if (
152
+ // @todo proper calculation
153
+ !this.isApprovedFor(this.market.underlyingToken.getAmount((0, utils_1.bipMul)(this.market.outstandingDebt.raw, (0, token_1.toBn)(10006))))) {
154
+ return { status: validation_1.CloseMarketStatus.InsufficientAllowance };
85
155
  }
86
- return { status: "Ready" };
156
+ return { status: validation_1.CloseMarketStatus.Ready };
87
157
  }
88
- checkSetAPRStep(apr) {
158
+ previewSetAPR(apr) {
89
159
  if (!this.isBorrower)
90
- return { status: "NotBorrower" };
160
+ return { status: validation_1.SetAprStatus.NotBorrower };
91
161
  if (!(apr > 0 && apr <= 10000))
92
- return { status: "InvalidApr" };
162
+ return { status: validation_1.SetAprStatus.InvalidApr };
93
163
  const [originalReserveRatioBips, originalAnnualInterestBips] = this.market.originalReserveRatioAndAnnualInterestBips;
94
164
  const newReserveRatioBips = this.market.getReserveRatioForNewAPR(apr);
95
165
  const willChangeReserveRatio = newReserveRatioBips !== this.market.reserveRatioBips;
@@ -103,7 +173,7 @@ class MarketAccount {
103
173
  const newCoverageLiquidity = this.market.calculateLiquidityCoverageForReserveRatio(reserveRatioThatMustNotBeDelinquent);
104
174
  if (this.market.totalAssets.lt(newCoverageLiquidity)) {
105
175
  return {
106
- status: "InsufficientReserves",
176
+ status: validation_1.SetAprStatus.InsufficientReserves,
107
177
  newCoverageLiquidity,
108
178
  newReserveRatio: newReserveRatioBips,
109
179
  missingReserves: newCoverageLiquidity.sub(this.market.totalAssets),
@@ -112,7 +182,7 @@ class MarketAccount {
112
182
  }
113
183
  else {
114
184
  return {
115
- status: "Ready",
185
+ status: validation_1.SetAprStatus.Ready,
116
186
  willChangeReserveRatio: true,
117
187
  newCoverageLiquidity,
118
188
  newReserveRatio: newReserveRatioBips,
@@ -122,50 +192,74 @@ class MarketAccount {
122
192
  }
123
193
  else {
124
194
  return {
125
- status: "Ready",
195
+ status: validation_1.SetAprStatus.Ready,
126
196
  willChangeReserveRatio: false
127
197
  };
128
198
  }
129
199
  }
200
+ previewSetMaxTotalSupply(amount) {
201
+ if (!this.isBorrower)
202
+ return { status: validation_1.SetMaxTotalSupplyStatus.NotBorrower };
203
+ if (this.market.version === types_1.MarketVersion.V1 && amount.lt(this.market.totalSupply)) {
204
+ return { status: validation_1.SetMaxTotalSupplyStatus.BelowCurrentSupply };
205
+ }
206
+ return { status: validation_1.SetMaxTotalSupplyStatus.Ready };
207
+ }
130
208
  /* -------------------------------------------------------------------------- */
131
209
  /* Management Actions */
132
210
  /* -------------------------------------------------------------------------- */
133
211
  async closeMarket() {
134
- const { status } = this.checkCloseMarketStep();
135
- if (status !== "Ready") {
136
- throw Error(`Cannot close market: ${status}`);
212
+ const { status } = this.previewCloseMarket();
213
+ (0, utils_1.assert)(status === validation_1.CloseMarketStatus.Ready, `Cannot close market: ${status}`);
214
+ if (this.market.version === types_1.MarketVersion.V1) {
215
+ (0, utils_1.assert)(this.market.controller !== undefined, "Controller address is required for V1 markets");
216
+ const controller = (0, constants_1.getControllerContract)(this.market.signer, this.market.controller);
217
+ return controller.closeMarket(this.market.address);
137
218
  }
138
- const controller = (0, constants_1.getControllerContract)(this.market.signer, this.market.controller);
139
- return controller.closeMarket(this.market.address);
219
+ return this.market.contract.closeMarket();
140
220
  }
141
221
  async populateCloseMarket() {
142
- const { status } = this.checkCloseMarketStep();
143
- if (status !== "Ready") {
144
- throw Error(`Cannot close market: ${status}`);
222
+ const { status } = this.previewCloseMarket();
223
+ (0, utils_1.assert)(status === validation_1.CloseMarketStatus.Ready, `Cannot close market: ${status}`);
224
+ if (this.market.version === types_1.MarketVersion.V1) {
225
+ (0, utils_1.assert)(this.market.controller !== undefined, "Controller address is required for V1 markets");
226
+ const controller = (0, constants_1.getControllerContract)(this.market.signer, this.market.controller);
227
+ return {
228
+ to: controller.address,
229
+ data: controller.interface.encodeFunctionData("closeMarket", [this.market.address]),
230
+ value: "0"
231
+ };
145
232
  }
146
- const controller = (0, constants_1.getControllerContract)(this.market.signer, this.market.controller);
147
233
  return {
148
- to: controller.address,
149
- data: controller.interface.encodeFunctionData("closeMarket", [this.market.address]),
234
+ to: this.market.address,
235
+ data: this.market.contract.interface.encodeFunctionData("closeMarket"),
150
236
  value: "0"
151
237
  };
152
238
  }
153
239
  async setMaxTotalSupply(amount) {
154
- (0, utils_1.assert)(this.isBorrower, "Only borrower can set maxTotalSupply");
155
- if (amount.lt(this.market.totalSupply)) {
156
- throw Error("New max total supply must be at least current total supply");
240
+ const { status } = this.previewSetMaxTotalSupply(amount);
241
+ (0, utils_1.assert)(status === validation_1.SetMaxTotalSupplyStatus.Ready, `Cannot close market: ${status}`);
242
+ if (this.market.version === types_1.MarketVersion.V1) {
243
+ (0, utils_1.assert)(this.market.controller !== undefined, "Controller address is required for V1 markets");
244
+ const controller = (0, constants_1.getControllerContract)(this.market.signer, this.market.controller);
245
+ return controller.setMaxTotalSupply(this.market.address, amount.raw);
246
+ }
247
+ else {
248
+ return this.market.contract.setMaxTotalSupply(amount.raw);
157
249
  }
158
- const controller = (0, constants_1.getControllerContract)(this.market.signer, this.market.controller);
159
- return controller.setMaxTotalSupply(this.market.address, amount.raw);
160
250
  }
161
251
  async setAnnualInterestBips(newAprBips) {
162
- const { status } = this.checkSetAPRStep(newAprBips);
163
- if (status !== "Ready") {
164
- throw Error(`Cannot set new APR of ${newAprBips / 10000}%: ${status}`);
252
+ const { status } = this.previewSetAPR(newAprBips);
253
+ (0, utils_1.assert)(status === validation_1.SetAprStatus.Ready, `Cannot set new APR of ${newAprBips / 10000}%: ${status}`);
254
+ if (this.market.version === types_1.MarketVersion.V1) {
255
+ (0, utils_1.assert)(this.market.controller !== undefined, "Controller address is required for V1 markets");
256
+ const controller = (0, constants_1.getControllerContract)(this.market.provider, this.market.controller);
257
+ return controller.setAnnualInterestBips(this.market.address, newAprBips);
258
+ }
259
+ else {
260
+ const contract = typechain_1.WildcatMarketV2__factory.connect(this.market.address, this.market.signer);
261
+ return contract.setAnnualInterestAndReserveRatioBips(newAprBips, this.market.reserveRatioBips);
165
262
  }
166
- const controller = (0, constants_1.getControllerContract)(this.market.provider, this.market.controller);
167
- (0, utils_1.assert)(this.market.controller === controller.address, "Unexpected controller address");
168
- return controller.setAnnualInterestBips(this.market.address, newAprBips);
169
263
  }
170
264
  /* -------------------------------------------------------------------------- */
171
265
  /* Approval */
@@ -173,22 +267,12 @@ class MarketAccount {
173
267
  isApprovedFor(amount) {
174
268
  return this.underlyingApproval.gte(amount.raw);
175
269
  }
176
- /**
177
- * @returns Amount of underlying token user must approve
178
- * market to spend to make a deposit.
179
- */
180
- getAllowanceRemainder(amount) {
181
- return this.underlyingApproval.gte(amount.raw)
182
- ? this.market.underlyingToken.getAmount(0)
183
- : amount;
184
- }
185
- async approveAllowanceRemainder(amount) {
270
+ async approveMarket(amount) {
186
271
  const token = this.market.underlyingToken;
187
272
  const signer = await token.signer.getAddress();
188
273
  if (signer.toLowerCase() !== this.account.toLowerCase()) {
189
274
  throw Error(`MarketAccount signer ${signer} does not match ${this.account}`);
190
275
  }
191
- amount = this.getAllowanceRemainder(amount);
192
276
  return token.contract.approve(this.market.address, amount.raw);
193
277
  }
194
278
  async populateApproveMarket(amount) {
@@ -197,7 +281,6 @@ class MarketAccount {
197
281
  if (signer.toLowerCase() !== this.account.toLowerCase()) {
198
282
  throw Error(`MarketAccount signer ${signer} does not match ${this.account}`);
199
283
  }
200
- amount = this.getAllowanceRemainder(amount);
201
284
  return {
202
285
  to: token.address,
203
286
  data: token.contract.interface.encodeFunctionData("approve", [
@@ -224,66 +307,56 @@ class MarketAccount {
224
307
  getDepositAmount(amount) {
225
308
  return (0, token_1.minTokenAmount)(amount, this.maximumDeposit);
226
309
  }
227
- /**
228
- * @returns Status for deposit
229
- */
230
- checkDepositStep(amount) {
231
- if (!this.canDeposit) {
232
- return { status: "InsufficientRole" };
233
- }
310
+ previewDeposit(amount) {
311
+ const status = this.depositAvailability;
312
+ if (status !== validation_1.DepositStatus.Ready)
313
+ return { status };
234
314
  if (amount.gt(this.market.maximumDeposit)) {
235
- return { status: "ExceedsMaximumDeposit" };
315
+ return { status: validation_1.DepositStatus.ExceedsMaximumDeposit };
236
316
  }
237
317
  if (amount.gt(this.underlyingBalance)) {
238
- return { status: "InsufficientBalance" };
318
+ return { status: validation_1.DepositStatus.InsufficientBalance };
239
319
  }
240
320
  if (!this.isApprovedFor(amount)) {
241
- return {
242
- status: "InsufficientAllowance",
243
- remainder: this.getAllowanceRemainder(amount)
244
- };
321
+ return { status: validation_1.DepositStatus.InsufficientAllowance };
245
322
  }
246
- return { status: "Ready" };
323
+ return { status: validation_1.DepositStatus.Ready };
247
324
  }
248
325
  async populateDeposit(amount) {
326
+ const { status } = this.previewDeposit(amount);
327
+ (0, utils_1.assert)(status === validation_1.DepositStatus.Ready, `Cannot deposit: ${status}`);
249
328
  const signer = await this.market.signer.getAddress();
250
329
  if (signer.toLowerCase() !== this.account.toLowerCase()) {
251
330
  throw Error(`MarketAccount signer ${signer} does not match ${this.account}`);
252
331
  }
253
- if (amount.gt(this.underlyingBalance)) {
254
- throw Error("Insufficient balance");
255
- }
256
332
  return {
257
333
  to: this.market.address,
258
334
  data: this.market.contract.interface.encodeFunctionData("deposit", [amount.raw]),
259
335
  value: "0"
260
336
  };
261
337
  }
262
- // TODO: Add support for depositUpTo
263
338
  async deposit(amount) {
339
+ const { status } = this.previewDeposit(amount);
340
+ (0, utils_1.assert)(status === validation_1.DepositStatus.Ready, `Cannot deposit: ${status}`);
264
341
  const signer = await this.market.signer.getAddress();
265
342
  if (signer.toLowerCase() !== this.account.toLowerCase()) {
266
343
  throw Error(`MarketAccount signer ${signer} does not match ${this.account}`);
267
344
  }
268
- if (amount.gt(this.underlyingBalance)) {
269
- throw Error("Insufficient balance");
270
- }
271
345
  return this.market.contract.deposit(amount.raw);
272
346
  }
273
347
  /* ------ Withdrawals ------ */
274
- checkQueueWithdrawalStep(amount) {
275
- if (!this.canWithdraw) {
276
- return { status: "InsufficientRole" };
277
- }
348
+ previewQueueWithdrawal(amount) {
349
+ const status = this.withdrawalAvailability;
350
+ if (status !== validation_1.QueueWithdrawalStatus.Ready)
351
+ return { status };
278
352
  if (amount.gt(this.marketBalance)) {
279
- return { status: "InsufficientBalance" };
353
+ return { status: validation_1.QueueWithdrawalStatus.InsufficientBalance };
280
354
  }
281
- return { status: "Ready" };
355
+ return { status: validation_1.QueueWithdrawalStatus.Ready };
282
356
  }
283
357
  async queueWithdrawal(amount) {
284
- if (!this.canWithdraw) {
285
- throw Error(`Lender role insufficient to withdraw`);
286
- }
358
+ const { status } = this.previewQueueWithdrawal(amount);
359
+ (0, utils_1.assert)(status === validation_1.QueueWithdrawalStatus.Ready, `Cannot queue withdrawal: ${status}`);
287
360
  const signer = await this.market.signer.getAddress();
288
361
  if (signer.toLowerCase() !== this.account.toLowerCase()) {
289
362
  throw Error(`MarketAccount signer ${signer} does not match ${this.account}`);
@@ -292,9 +365,8 @@ class MarketAccount {
292
365
  const receipt = await transaction.wait();
293
366
  const queuedWithdrawalTopic = this.market.contract.interface.getEventTopic("WithdrawalQueued");
294
367
  const queuedWithdrawalTransaction = toQueueWithdrawalTransaction(this.market.underlyingToken, receipt.events.find((e) => e.topics[0] === queuedWithdrawalTopic));
295
- if (!queuedWithdrawalTransaction) {
368
+ if (!queuedWithdrawalTransaction)
296
369
  throw Error("No queued withdrawal event found");
297
- }
298
370
  const withdrawal = await withdrawal_status_1.LenderWithdrawalStatus.getWithdrawalForLender(this.market, queuedWithdrawalTransaction.expiry, this.account);
299
371
  return {
300
372
  withdrawal,
@@ -321,29 +393,24 @@ class MarketAccount {
321
393
  getRepayAmount(amount) {
322
394
  return (0, token_1.minTokenAmount)(amount, this.maximumRepay);
323
395
  }
324
- /**
325
- * @returns Status for deposit
326
- */
327
- checkRepayStep(amount) {
396
+ previewRepay(amount) {
397
+ if (this.market.isClosed)
398
+ return { status: validation_1.RepayStatus.MarketClosed };
328
399
  if (amount.gt(this.underlyingBalance)) {
329
- return { status: "InsufficientBalance" };
400
+ return { status: validation_1.RepayStatus.InsufficientBalance };
330
401
  }
331
402
  if (!this.isApprovedFor(amount)) {
332
- return {
333
- status: "InsufficientAllowance",
334
- remainder: this.getAllowanceRemainder(amount)
335
- };
403
+ return { status: validation_1.RepayStatus.InsufficientAllowance };
336
404
  }
337
- return { status: "Ready" };
405
+ return { status: validation_1.RepayStatus.Ready };
338
406
  }
339
407
  async repay(amount) {
340
408
  const signer = await this.market.signer.getAddress();
341
409
  if (signer.toLowerCase() !== this.account.toLowerCase()) {
342
410
  throw Error(`MarketAccount signer ${signer} does not match ${this.account}`);
343
411
  }
344
- if (!this.isBorrower) {
412
+ if (!this.isBorrower)
345
413
  throw Error("Only borrower can repay");
346
- }
347
414
  return this.market.contract.repay(amount);
348
415
  }
349
416
  async populateRepay(amount) {
@@ -351,9 +418,8 @@ class MarketAccount {
351
418
  if (signer.toLowerCase() !== this.account.toLowerCase()) {
352
419
  throw Error(`MarketAccount signer ${signer} does not match ${this.account}`);
353
420
  }
354
- if (!this.isBorrower) {
421
+ if (!this.isBorrower)
355
422
  throw Error("Only borrower can repay");
356
- }
357
423
  return {
358
424
  to: this.market.address,
359
425
  data: this.market.contract.interface.encodeFunctionData("repay", [amount]),
@@ -361,23 +427,27 @@ class MarketAccount {
361
427
  };
362
428
  }
363
429
  async repayOutstandingDebt() {
430
+ if (this.market.version !== types_1.MarketVersion.V1) {
431
+ throw Error(`Only V1 supports repayOutstandingDebt`);
432
+ }
433
+ if (!this.isBorrower)
434
+ throw Error("Only borrower can repay");
364
435
  const signer = await this.market.signer.getAddress();
365
436
  if (signer.toLowerCase() !== this.account.toLowerCase()) {
366
437
  throw Error(`MarketAccount signer ${signer} does not match ${this.account}`);
367
438
  }
368
- if (!this.isBorrower) {
369
- throw Error("Only borrower can repay");
370
- }
371
439
  return this.market.contract.repayOutstandingDebt();
372
440
  }
373
441
  async populateRepayOutstandingDebt() {
442
+ if (this.market.version !== types_1.MarketVersion.V1) {
443
+ throw Error(`Only V1 supports repayOutstandingDebt`);
444
+ }
445
+ if (!this.isBorrower)
446
+ throw Error("Only borrower can repay");
374
447
  const signer = await this.market.signer.getAddress();
375
448
  if (signer.toLowerCase() !== this.account.toLowerCase()) {
376
449
  throw Error(`MarketAccount signer ${signer} does not match ${this.account}`);
377
450
  }
378
- if (!this.isBorrower) {
379
- throw Error("Only borrower can repay");
380
- }
381
451
  return {
382
452
  to: this.market.address,
383
453
  data: this.market.contract.interface.encodeFunctionData("repayOutstandingDebt"),
@@ -385,23 +455,27 @@ class MarketAccount {
385
455
  };
386
456
  }
387
457
  async repayDelinquentDebt() {
458
+ if (this.market.version !== types_1.MarketVersion.V1) {
459
+ throw Error(`Only V1 supports repayDelinquentDebt`);
460
+ }
461
+ if (!this.isBorrower)
462
+ throw Error("Only borrower can repay");
388
463
  const signer = await this.market.signer.getAddress();
389
464
  if (signer.toLowerCase() !== this.account.toLowerCase()) {
390
465
  throw Error(`MarketAccount signer ${signer} does not match ${this.account}`);
391
466
  }
392
- if (!this.isBorrower) {
393
- throw Error("Only borrower can repay");
394
- }
395
467
  return this.market.contract.repayDelinquentDebt();
396
468
  }
397
469
  async populateRepayDelinquentDebt() {
470
+ if (this.market.version !== types_1.MarketVersion.V1) {
471
+ throw Error(`Only V1 supports repayDelinquentDebt`);
472
+ }
473
+ if (!this.isBorrower)
474
+ throw Error("Only borrower can repay");
398
475
  const signer = await this.market.signer.getAddress();
399
476
  if (signer.toLowerCase() !== this.account.toLowerCase()) {
400
477
  throw Error(`MarketAccount signer ${signer} does not match ${this.account}`);
401
478
  }
402
- if (!this.isBorrower) {
403
- throw Error("Only borrower can repay");
404
- }
405
479
  return {
406
480
  to: this.market.address,
407
481
  data: this.market.contract.interface.encodeFunctionData("repayDelinquentDebt"),
@@ -419,12 +493,11 @@ class MarketAccount {
419
493
  }
420
494
  async borrow(amount) {
421
495
  const signer = await this.market.signer.getAddress();
496
+ if (!this.isBorrower)
497
+ throw Error("Only borrower can borrow");
422
498
  if (signer.toLowerCase() !== this.account.toLowerCase()) {
423
499
  throw Error(`MarketAccount signer ${signer} does not match ${this.account}`);
424
500
  }
425
- if (!this.isBorrower) {
426
- throw Error("Only borrower can borrow");
427
- }
428
501
  if (amount.gt(this.market.borrowableAssets)) {
429
502
  throw Error("Insufficient borrowable assets");
430
503
  }
@@ -438,8 +511,29 @@ class MarketAccount {
438
511
  this.updateWith(acccountMarketInfo);
439
512
  }
440
513
  updateWith(info) {
441
- this.isAuthorizedOnController = info.isAuthorizedOnController;
442
- this.role = info.role;
514
+ if ("isAuthorizedOnController" in info) {
515
+ (0, utils_1.assert)(this.market.version === types_1.MarketVersion.V1, "V2 market can not be updated with V1 lens data");
516
+ this.isAuthorizedOnController = info.isAuthorizedOnController;
517
+ this.role = info.role;
518
+ }
519
+ else {
520
+ (0, utils_1.assert)(this.market.version === types_1.MarketVersion.V2, "V1 market can not be updated with V2 lens data");
521
+ this.credential = {
522
+ canRefresh: info.canRefresh,
523
+ isBlockedFromDeposits: info.isBlockedFromDeposits,
524
+ lastApprovalTimestamp: info.lastApprovalTimestamp,
525
+ lastProvider: {
526
+ isApproved: true,
527
+ providerAddress: info.lastProvider.providerAddress,
528
+ isPullProvider: info.lastProvider.pullProviderIndex !== NullProviderIndex,
529
+ isPushProvider: info.lastProvider.pushProviderIndex !== NullProviderIndex,
530
+ pullProviderIndex: info.lastProvider.pullProviderIndex,
531
+ pushProviderIndex: info.lastProvider.pushProviderIndex,
532
+ timeToLive: info.lastProvider.timeToLive
533
+ }
534
+ };
535
+ this.isKnownLender = info.isKnownLender;
536
+ }
443
537
  this.scaledMarketBalance = info.scaledBalance;
444
538
  this.marketBalance = this.market.marketToken.getAmount(info.normalizedBalance);
445
539
  this.underlyingBalance = this.market.underlyingToken.getAmount(info.underlyingBalance);
@@ -479,18 +573,87 @@ class MarketAccount {
479
573
  DepositAndWithdraw: LenderRole.DepositAndWithdraw
480
574
  };
481
575
  const scaledBalance = ethers_1.BigNumber.from(data.scaledBalance);
482
- const account = new MarketAccount(data.address, data.controllerAuthorization.authorized, RolesMap[data.role], scaledBalance, market.marketToken.getAmount((0, utils_1.rayMul)(scaledBalance, market.scaleFactor)), market.underlyingToken.getAmount(0), ethers_1.BigNumber.from(0), market, data.deposits, market.underlyingToken.getAmount(data.totalDeposited), ethers_1.BigNumber.from(data.lastScaleFactor), data.lastUpdatedTimestamp, market.underlyingToken.getAmount(data.totalInterestEarned), data.numPendingWithdrawalBatches);
576
+ const account = new MarketAccount({
577
+ account: data.address,
578
+ isAuthorizedOnController: data.controllerAuthorization?.authorized ?? false,
579
+ role: RolesMap[data.role],
580
+ scaledMarketBalance: scaledBalance,
581
+ marketBalance: market.marketToken.getAmount((0, utils_1.rayMul)(scaledBalance, market.scaleFactor)),
582
+ underlyingBalance: market.underlyingToken.getAmount(0),
583
+ underlyingApproval: ethers_1.BigNumber.from(0),
584
+ market,
585
+ deposits: data.deposits,
586
+ totalDeposited: market.underlyingToken.getAmount(data.totalDeposited),
587
+ lastScaleFactor: ethers_1.BigNumber.from(data.lastScaleFactor),
588
+ lastUpdatedTimestamp: data.lastUpdatedTimestamp,
589
+ totalInterestEarned: market.underlyingToken.getAmount(data.totalInterestEarned),
590
+ numPendingWithdrawalBatches: data.numPendingWithdrawalBatches,
591
+ credential: data.hooksAccess ? toCredential(data.hooksAccess) : undefined,
592
+ isKnownLender: !!data.knownLenderStatus?.id
593
+ });
483
594
  account.processInterestAccrued();
484
595
  return account;
485
596
  }
486
597
  static fromMarketLenderStatus(account, info, market) {
487
- return new MarketAccount(account, info.isAuthorizedOnController, info.role, info.scaledBalance, market.marketToken.getAmount(info.normalizedBalance), market.underlyingToken.getAmount(info.underlyingBalance), info.underlyingApproval, market);
598
+ return new MarketAccount({
599
+ account,
600
+ isAuthorizedOnController: info.isAuthorizedOnController,
601
+ role: info.role,
602
+ scaledMarketBalance: info.scaledBalance,
603
+ marketBalance: market.marketToken.getAmount(info.normalizedBalance),
604
+ underlyingBalance: market.underlyingToken.getAmount(info.underlyingBalance),
605
+ underlyingApproval: info.underlyingApproval,
606
+ market
607
+ });
608
+ }
609
+ static fromLenderAccountData(market, data) {
610
+ return new MarketAccount({
611
+ account: data.lender,
612
+ market,
613
+ role: LenderRole.Null,
614
+ marketBalance: market.marketToken.getAmount(data.normalizedBalance),
615
+ scaledMarketBalance: data.scaledBalance,
616
+ underlyingApproval: data.underlyingApproval,
617
+ underlyingBalance: market.underlyingToken.getAmount(data.underlyingBalance),
618
+ isAuthorizedOnController: false,
619
+ isKnownLender: data.isKnownLender,
620
+ credential: {
621
+ canRefresh: data.canRefresh,
622
+ isBlockedFromDeposits: data.isBlockedFromDeposits,
623
+ lastApprovalTimestamp: data.lastApprovalTimestamp,
624
+ lastProvider: {
625
+ isApproved: true,
626
+ providerAddress: data.lastProvider.providerAddress,
627
+ isPullProvider: data.lastProvider.pullProviderIndex !== NullProviderIndex,
628
+ pullProviderIndex: data.lastProvider.pullProviderIndex,
629
+ isPushProvider: data.lastProvider.pushProviderIndex !== NullProviderIndex,
630
+ pushProviderIndex: data.lastProvider.pushProviderIndex,
631
+ timeToLive: data.lastProvider.timeToLive
632
+ }
633
+ }
634
+ });
488
635
  }
489
636
  static fromMarketDataWithLenderStatus(chainId, provider, account, info) {
490
- return MarketAccount.fromMarketLenderStatus(account, info.lenderStatus, market_1.Market.fromMarketData(chainId, info.market, provider));
637
+ if ("controller" in info.market) {
638
+ info = info;
639
+ return MarketAccount.fromMarketLenderStatus(account, info.lenderStatus, market_1.Market.fromMarketData(chainId, info.market, provider));
640
+ }
641
+ else {
642
+ info = info;
643
+ return MarketAccount.fromLenderAccountData(market_1.Market.fromMarketDataV2(chainId, provider, info.market), info.lenderStatus);
644
+ }
491
645
  }
492
646
  static fromMarketDataOnly(market, account, isAuthorizedOnController) {
493
- return new MarketAccount(account, isAuthorizedOnController, LenderRole.Null, ethers_1.BigNumber.from(0), market.marketToken.getAmount(0), market.underlyingToken.getAmount(0), ethers_1.BigNumber.from(0), market);
647
+ return new MarketAccount({
648
+ account,
649
+ isAuthorizedOnController,
650
+ role: LenderRole.Null,
651
+ scaledMarketBalance: ethers_1.BigNumber.from(0),
652
+ marketBalance: market.marketToken.getAmount(0),
653
+ underlyingBalance: market.underlyingToken.getAmount(0),
654
+ underlyingApproval: ethers_1.BigNumber.from(0),
655
+ market
656
+ });
494
657
  }
495
658
  /**
496
659
  * Get a `MarketAccount` for a given account and existing `Market` instance.
@@ -509,6 +672,23 @@ class MarketAccount {
509
672
  .then((info) => MarketAccount.fromMarketDataWithLenderStatus(chainId, provider, account, info));
510
673
  }
511
674
  }
675
+ /**
676
+ * Get a `MarketAccount` for a given account and existing `Market` instance.
677
+ * If `market` is a string, the market data will be fetched in the same call as the account data.
678
+ */
679
+ static async getMarketAccountV2(chainId, provider, account, market) {
680
+ const lens = (0, constants_1.getLensV2Contract)(chainId, provider);
681
+ if (market instanceof market_1.Market) {
682
+ return lens
683
+ .getMarketDataWithLenderStatus(account, market.address)
684
+ .then((info) => MarketAccount.fromMarketDataWithLenderStatus(chainId, provider, account, info));
685
+ }
686
+ else {
687
+ return lens
688
+ .getMarketDataWithLenderStatus(account, market)
689
+ .then((info) => MarketAccount.fromMarketDataWithLenderStatus(chainId, provider, account, info));
690
+ }
691
+ }
512
692
  /**
513
693
  * Get multiple `MarketAccount`s given an account and existing list of `Market`
514
694
  * instances or market addresses. If `markets` is an array of strings, the market
@@ -519,7 +699,7 @@ class MarketAccount {
519
699
  if (markets.length === 0) {
520
700
  return [];
521
701
  }
522
- if (isMarketInstanceArray(markets)) {
702
+ if ((0, validation_1.isMarketInstanceArray)(markets)) {
523
703
  return lens
524
704
  .getMarketsLenderStatus(account, markets.map((v) => v.address))
525
705
  .then((infos) => infos.map((info, i) => MarketAccount.fromMarketLenderStatus(account, info, markets[i])));
@@ -562,4 +742,21 @@ const toQueueWithdrawalTransaction = (underlyingToken, log) => ({
562
742
  scaledAmount: log.args.scaledAmount,
563
743
  originalAmount: underlyingToken.getAmount(log.args.normalizedAmount)
564
744
  });
565
- //# sourceMappingURL=account.js.map
745
+ const toCredential = ({ canRefresh, isBlockedFromDeposits, lastApprovalTimestamp, lender, lastProvider }) => {
746
+ const { isApproved, providerAddress, isPullProvider, pullProviderIndex, isPushProvider, pushProviderIndex, timeToLive } = lastProvider;
747
+ return {
748
+ canRefresh,
749
+ isBlockedFromDeposits,
750
+ lastApprovalTimestamp,
751
+ lastProvider: {
752
+ isApproved,
753
+ providerAddress,
754
+ isPullProvider,
755
+ pullProviderIndex,
756
+ isPushProvider,
757
+ pushProviderIndex,
758
+ timeToLive
759
+ }
760
+ };
761
+ };
762
+ //# sourceMappingURL=index.js.map