@gearbox-protocol/sdk 13.2.0 → 13.3.0-next.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 (96) hide show
  1. package/dist/cjs/abi/310/iSecuritizeDegenNFT.js +263 -0
  2. package/dist/cjs/abi/310/iSecuritizeKYCFactory.js +278 -0
  3. package/dist/cjs/{sdk/pools/PoolServiceV310.js → abi/iStateSerializer.js} +14 -8
  4. package/dist/cjs/dev/AccountOpener.js +45 -5
  5. package/dist/cjs/sdk/accounts/AbstractCreditAccountsService.js +462 -104
  6. package/dist/cjs/sdk/accounts/CreditAccountsServiceV310.js +16 -5
  7. package/dist/cjs/sdk/base/ChainContractsRegister.js +1 -1
  8. package/dist/cjs/sdk/base/TokensMeta.js +255 -32
  9. package/dist/cjs/sdk/base/index.js +2 -0
  10. package/dist/cjs/sdk/{constants/phantom-tokens.js → base/token-types.js} +9 -3
  11. package/dist/cjs/sdk/chain/chains.js +2 -1
  12. package/dist/cjs/sdk/constants/index.js +0 -2
  13. package/dist/cjs/sdk/market/MarketRegister.js +2 -2
  14. package/dist/cjs/sdk/market/MarketSuite.js +6 -0
  15. package/dist/cjs/{plugins/zappers/extraZappers.js → sdk/market/ZapperRegister.js} +110 -6
  16. package/dist/cjs/sdk/market/index.js +3 -1
  17. package/dist/cjs/sdk/market/pool/PoolSuite.js +3 -0
  18. package/dist/cjs/sdk/market/pool/PoolV310Contract.js +17 -2
  19. package/dist/cjs/sdk/market/pool/SecuritizeKYCFactory.js +97 -0
  20. package/dist/cjs/sdk/market/pool/index.js +4 -0
  21. package/dist/cjs/sdk/pools/PoolService.js +391 -0
  22. package/dist/cjs/sdk/pools/index.js +2 -4
  23. package/dist/cjs/sdk/utils/AddressMap.js +1 -1
  24. package/dist/cjs/sdk/utils/viem/sendRawTx.js +16 -0
  25. package/dist/esm/abi/310/iSecuritizeDegenNFT.js +239 -0
  26. package/dist/esm/abi/310/iSecuritizeKYCFactory.js +254 -0
  27. package/dist/esm/abi/iStateSerializer.js +12 -0
  28. package/dist/esm/dev/AccountOpener.js +47 -6
  29. package/dist/esm/sdk/accounts/AbstractCreditAccountsService.js +462 -104
  30. package/dist/esm/sdk/accounts/CreditAccountsServiceV310.js +16 -5
  31. package/dist/esm/sdk/base/ChainContractsRegister.js +1 -1
  32. package/dist/esm/sdk/base/TokensMeta.js +261 -32
  33. package/dist/esm/sdk/base/index.js +1 -0
  34. package/dist/esm/sdk/{constants/phantom-tokens.js → base/token-types.js} +4 -0
  35. package/dist/esm/sdk/chain/chains.js +2 -1
  36. package/dist/esm/sdk/constants/index.js +0 -1
  37. package/dist/esm/sdk/market/MarketRegister.js +2 -2
  38. package/dist/esm/sdk/market/MarketSuite.js +6 -0
  39. package/dist/esm/{plugins/zappers/extraZappers.js → sdk/market/ZapperRegister.js} +109 -2
  40. package/dist/esm/sdk/market/index.js +1 -0
  41. package/dist/esm/sdk/market/pool/PoolSuite.js +3 -0
  42. package/dist/esm/sdk/market/pool/PoolV310Contract.js +17 -2
  43. package/dist/esm/sdk/market/pool/SecuritizeKYCFactory.js +73 -0
  44. package/dist/esm/sdk/market/pool/index.js +2 -0
  45. package/dist/esm/sdk/pools/PoolService.js +371 -0
  46. package/dist/esm/sdk/pools/index.js +1 -2
  47. package/dist/esm/sdk/utils/AddressMap.js +1 -1
  48. package/dist/esm/sdk/utils/viem/sendRawTx.js +19 -1
  49. package/dist/types/abi/310/iSecuritizeDegenNFT.d.ts +324 -0
  50. package/dist/types/abi/310/iSecuritizeKYCFactory.d.ts +322 -0
  51. package/dist/types/abi/iStateSerializer.d.ts +11 -0
  52. package/dist/types/sdk/accounts/AbstractCreditAccountsService.d.ts +123 -27
  53. package/dist/types/sdk/accounts/CreditAccountsServiceV310.d.ts +1 -1
  54. package/dist/types/sdk/accounts/types.d.ts +108 -8
  55. package/dist/types/sdk/base/TokensMeta.d.ts +34 -18
  56. package/dist/types/sdk/base/index.d.ts +1 -0
  57. package/dist/types/sdk/base/token-types.d.ts +33 -0
  58. package/dist/types/sdk/base/types.d.ts +0 -1
  59. package/dist/types/sdk/chain/chains.d.ts +1 -1
  60. package/dist/types/sdk/constants/index.d.ts +0 -1
  61. package/dist/types/sdk/market/MarketRegister.d.ts +2 -2
  62. package/dist/types/sdk/market/MarketSuite.d.ts +3 -0
  63. package/dist/types/sdk/market/ZapperRegister.d.ts +17 -0
  64. package/dist/types/sdk/market/index.d.ts +1 -0
  65. package/dist/types/sdk/market/pool/PoolSuite.d.ts +2 -0
  66. package/dist/types/sdk/market/pool/PoolV310Contract.d.ts +6 -2
  67. package/dist/types/sdk/market/pool/SecuritizeKYCFactory.d.ts +345 -0
  68. package/dist/types/sdk/market/pool/index.d.ts +2 -0
  69. package/dist/types/sdk/market/types.d.ts +10 -0
  70. package/dist/types/sdk/pools/PoolService.d.ts +14 -0
  71. package/dist/types/sdk/pools/index.d.ts +1 -2
  72. package/dist/types/sdk/pools/types.d.ts +84 -63
  73. package/dist/types/sdk/utils/AddressMap.d.ts +1 -1
  74. package/dist/types/sdk/utils/viem/sendRawTx.d.ts +5 -1
  75. package/package.json +1 -1
  76. package/dist/cjs/plugins/zappers/ZappersPlugin.js +0 -144
  77. package/dist/cjs/plugins/zappers/index.js +0 -26
  78. package/dist/cjs/plugins/zappers/package.json +0 -1
  79. package/dist/cjs/sdk/pools/AbstractPoolService.js +0 -137
  80. package/dist/cjs/sdk/pools/createPoolService.js +0 -35
  81. package/dist/esm/plugins/zappers/ZappersPlugin.js +0 -126
  82. package/dist/esm/plugins/zappers/index.js +0 -3
  83. package/dist/esm/plugins/zappers/package.json +0 -1
  84. package/dist/esm/sdk/pools/AbstractPoolService.js +0 -113
  85. package/dist/esm/sdk/pools/PoolServiceV310.js +0 -6
  86. package/dist/esm/sdk/pools/createPoolService.js +0 -11
  87. package/dist/types/plugins/zappers/ZappersPlugin.d.ts +0 -18
  88. package/dist/types/plugins/zappers/extraZappers.d.ts +0 -6
  89. package/dist/types/plugins/zappers/index.d.ts +0 -3
  90. package/dist/types/plugins/zappers/types.d.ts +0 -12
  91. package/dist/types/sdk/constants/phantom-tokens.d.ts +0 -2
  92. package/dist/types/sdk/pools/AbstractPoolService.d.ts +0 -9
  93. package/dist/types/sdk/pools/PoolServiceV310.d.ts +0 -4
  94. package/dist/types/sdk/pools/createPoolService.d.ts +0 -3
  95. /package/dist/cjs/{plugins/zappers → sdk/market}/types.js +0 -0
  96. /package/dist/esm/{plugins/zappers → sdk/market}/types.js +0 -0
@@ -42,7 +42,7 @@ class CreditAccountServiceV310 extends AbstractCreditAccountService {
42
42
  })
43
43
  };
44
44
  const calls = [...priceUpdatesCalls, addBotCall];
45
- const tx = targetContract.type === "creditAccount" ? cm.creditFacade.multicall(targetContract.creditAccount, calls) : void 0;
45
+ const tx = targetContract.type === "creditAccount" ? await this.multicallTx(cm, targetContract.creditAccount, calls) : void 0;
46
46
  return { tx, calls, creditFacade: cm.creditFacade };
47
47
  }
48
48
  /**
@@ -77,7 +77,7 @@ class CreditAccountServiceV310 extends AbstractCreditAccountService {
77
77
  averageQuota
78
78
  })
79
79
  ];
80
- const tx = cm.creditFacade.multicall(creditAccount.creditAccount, calls);
80
+ const tx = await this.multicallTx(cm, creditAccount.creditAccount, calls);
81
81
  return { tx, calls, creditFacade: cm.creditFacade };
82
82
  }
83
83
  /**
@@ -90,11 +90,13 @@ class CreditAccountServiceV310 extends AbstractCreditAccountService {
90
90
  creditAccount: ca,
91
91
  permits,
92
92
  to,
93
- tokensToClaim
93
+ tokensToClaim,
94
+ calls: wrapCalls = []
94
95
  }) {
95
96
  const cm = this.sdk.marketRegister.findCreditManager(ca.creditManager);
96
97
  const addCollateral = collateralAssets.filter((a) => a.balance > 0);
97
98
  const router = this.sdk.routerFor(ca);
99
+ const unwrapCalls = await this.getRedeemDiffCalls(1n, ca.creditManager) ?? [];
98
100
  const claimPath = await router.findClaimAllRewards({
99
101
  tokensToClaim,
100
102
  creditAccount: ca
@@ -106,14 +108,21 @@ class CreditAccountServiceV310 extends AbstractCreditAccountService {
106
108
  const calls = [
107
109
  ...operation === "close" ? [] : priceUpdates,
108
110
  ...this.prepareAddCollateral(ca.creditFacade, addCollateral, permits),
111
+ ...wrapCalls,
109
112
  ...this.prepareDisableQuotas(ca),
110
113
  ...this.prepareDecreaseDebt(ca),
114
+ ...unwrapCalls,
111
115
  ...claimPath.calls,
112
116
  ...assetsToWithdraw.map(
113
117
  (t) => this.prepareWithdrawToken(ca.creditFacade, t.token, MAX_UINT256, to)
114
118
  )
115
119
  ];
116
- const tx = operation === "close" ? cm.creditFacade.closeCreditAccount(ca.creditAccount, calls) : cm.creditFacade.multicall(ca.creditAccount, calls);
120
+ const tx = await this.closeCreditAccountTx(
121
+ cm,
122
+ ca.creditAccount,
123
+ calls,
124
+ operation
125
+ );
117
126
  return { tx, calls, creditFacade: cm.creditFacade };
118
127
  }
119
128
  /**
@@ -137,11 +146,13 @@ class CreditAccountServiceV310 extends AbstractCreditAccountService {
137
146
  creditManager: ca.creditManager,
138
147
  creditAccount: ca
139
148
  });
149
+ const wrapCalls = await this.getDepositDiffCalls(1n, ca.creditManager) ?? [];
140
150
  const addCollateral = collateralAssets.filter((a) => a.balance > 0);
141
151
  const calls = [
142
152
  ...priceUpdates,
143
153
  ...this.prepareAddCollateral(ca.creditFacade, addCollateral, permits),
144
154
  ...claimPath.calls,
155
+ ...wrapCalls,
145
156
  ...assetsToWithdraw.map(
146
157
  (t) => this.prepareWithdrawToken(ca.creditFacade, t.token, MAX_UINT256, to)
147
158
  )
@@ -185,7 +196,7 @@ class CreditAccountServiceV310 extends AbstractCreditAccountService {
185
196
  ...claimPath.calls,
186
197
  ...this.prepareUpdateQuotas(ca.creditFacade, { minQuota, averageQuota })
187
198
  ];
188
- const tx = cm.creditFacade.multicall(ca.creditAccount, calls);
199
+ const tx = await this.multicallTx(cm, ca.creditAccount, calls);
189
200
  return { tx, calls, creditFacade: cm.creditFacade };
190
201
  }
191
202
  async previewWithdrawLlamathenaProportionally(_) {
@@ -15,7 +15,7 @@ class ChainContractsRegister {
15
15
  logger;
16
16
  constructor(client, logger) {
17
17
  this.client = client;
18
- this.tokensMeta = new TokensMeta(client);
18
+ this.tokensMeta = new TokensMeta(client, logger);
19
19
  this.logger = logger;
20
20
  }
21
21
  resetContracts() {
@@ -1,3 +1,10 @@
1
+ import {
2
+ decodeAbiParameters,
3
+ erc20Abi
4
+ } from "viem";
5
+ import { iSecuritizeDegenNFTAbi } from "../../abi/310/iSecuritizeDegenNFT.js";
6
+ import { iSecuritizeKYCFactoryAbi } from "../../abi/310/iSecuritizeKYCFactory.js";
7
+ import { iStateSerializerAbi } from "../../abi/iStateSerializer.js";
1
8
  import { iVersionAbi } from "../../abi/iVersion.js";
2
9
  import {
3
10
  AddressMap,
@@ -5,16 +12,33 @@ import {
5
12
  bytes32ToString,
6
13
  formatBN
7
14
  } from "../utils/index.js";
15
+ import {
16
+ KYC_UNDERLYING_DEFAULT,
17
+ KYC_UNDERLYING_ON_DEMAND
18
+ } from "./token-types.js";
8
19
  class TokensMeta extends AddressMap {
9
20
  #client;
10
- #phantomTokensLoaded;
11
- constructor(client) {
21
+ #tokenDataLoaded = new AddressSet();
22
+ #logger;
23
+ constructor(client, logger) {
12
24
  super(void 0, "tokensMeta");
13
25
  this.#client = client;
26
+ this.#logger = logger?.child?.({ name: "TokensMeta" }) ?? logger;
14
27
  }
15
28
  reset() {
16
29
  this.clear();
17
- this.#phantomTokensLoaded = void 0;
30
+ this.#tokenDataLoaded.clear();
31
+ }
32
+ upsert(address, value) {
33
+ let v = value;
34
+ const existing = this.get(address);
35
+ if (existing && v) {
36
+ v = {
37
+ ...existing,
38
+ ...v
39
+ };
40
+ }
41
+ super.upsert(address, v);
18
42
  }
19
43
  symbol(token) {
20
44
  return this.mustGet(token).symbol;
@@ -23,27 +47,78 @@ class TokensMeta extends AddressMap {
23
47
  return this.mustGet(token).decimals;
24
48
  }
25
49
  /**
26
- * Returns the phantom token type for a given token, or undefined for normal tokens
27
- * Throws if the phantom token data is not loaded
50
+ * Returns true if the token is a phantom token, throws if the token data is not loaded
51
+ * @param t
52
+ * @returns
53
+ */
54
+ isPhantomToken(t) {
55
+ if (!this.#tokenDataLoaded.has(t.addr)) {
56
+ throw new Error(
57
+ `extended token data not loaded for ${t.symbol} (${t.addr})`
58
+ );
59
+ }
60
+ return !!t.contractType?.startsWith("PHANTOM_TOKEN::");
61
+ }
62
+ /**
63
+ * Returns true if the token is a KYC underlying token, throws if the token data is not loaded
64
+ * @param t
65
+ * @returns
66
+ */
67
+ isKYCUnderlying(t) {
68
+ if (!this.#tokenDataLoaded.has(t.addr)) {
69
+ throw new Error(
70
+ `extended token data not loaded for ${t.symbol} (${t.addr})`
71
+ );
72
+ }
73
+ return !!t.contractType?.startsWith("KYC_UNDERLYING::");
74
+ }
75
+ /**
76
+ * Returns true if the token is a DSToken, throws if the token data is not loaded
77
+ * @param t
78
+ * @returns
28
79
  */
29
- phantomTokenType(token) {
30
- if (!this.#phantomTokensLoaded?.has(token)) {
31
- throw new Error("phantom token data not loaded");
80
+ isDSToken(t) {
81
+ if (!this.#tokenDataLoaded.has(t.addr)) {
82
+ throw new Error(
83
+ `extended token data not loaded for ${t.symbol} (${t.addr})`
84
+ );
32
85
  }
33
- return this.mustGet(token).phantomTokenType;
86
+ return !!t.isDSToken;
34
87
  }
35
88
  /**
36
89
  * Returns a map of all phantom tokens
37
- * Throws if the phantom token data is not loaded
90
+ * Throws if token data is not loaded
38
91
  */
39
92
  get phantomTokens() {
40
- if (!this.#phantomTokensLoaded) {
41
- throw new Error("phantom tokens not loaded");
93
+ const result = new AddressMap();
94
+ for (const [token, meta] of this.entries()) {
95
+ if (this.isPhantomToken(meta)) {
96
+ result.upsert(token, meta);
97
+ }
42
98
  }
43
- return new AddressMap(
44
- this.entries().filter(([_, v]) => !!v.phantomTokenType),
45
- "phantomTokens"
46
- );
99
+ return result;
100
+ }
101
+ /**
102
+ * Returns a map of all KYC underlying tokens
103
+ * Throws if token data is not loaded
104
+ */
105
+ get kycUnderlyings() {
106
+ const result = new AddressMap();
107
+ for (const [token, meta] of this.entries()) {
108
+ if (this.isKYCUnderlying(meta)) {
109
+ result.upsert(token, meta);
110
+ }
111
+ }
112
+ return result;
113
+ }
114
+ get dsTokens() {
115
+ const result = new AddressMap();
116
+ for (const [token, meta] of this.entries()) {
117
+ if (this.isDSToken(meta)) {
118
+ result.upsert(token, meta);
119
+ }
120
+ }
121
+ return result;
47
122
  }
48
123
  formatBN(arg0, arg1, arg2) {
49
124
  const token = typeof arg0 === "object" ? arg0.token : arg0;
@@ -64,30 +139,184 @@ class TokensMeta extends AddressMap {
64
139
  return meta;
65
140
  }
66
141
  /**
67
- * Loads phantom token data for all known tokens from chain
142
+ * Loads token information about phantom tokens, KYC underlying tokens and DSTokens
143
+ *
144
+ * @param tokens - tokens to load data for, defaults to all tokens
68
145
  */
69
- async loadPhantomTokens() {
70
- this.#phantomTokensLoaded = new AddressSet();
71
- const tokens = this.keys();
146
+ async loadTokenData(...tokens) {
147
+ const tokenz = new AddressSet(tokens.length > 0 ? tokens : this.keys());
148
+ const tokensToLoad = Array.from(tokenz.difference(this.#tokenDataLoaded));
149
+ if (tokensToLoad.length === 0) {
150
+ return;
151
+ }
72
152
  const resp = await this.#client.multicall({
73
- contracts: tokens.map(
74
- (t) => ({
75
- address: t,
76
- abi: iVersionAbi,
77
- functionName: "contractType"
78
- })
153
+ contracts: tokensToLoad.flatMap(
154
+ (t) => [
155
+ {
156
+ address: t,
157
+ abi: iVersionAbi,
158
+ functionName: "contractType"
159
+ },
160
+ {
161
+ address: t,
162
+ abi: iStateSerializerAbi,
163
+ functionName: "serialize"
164
+ }
165
+ ]
79
166
  ),
80
167
  allowFailure: true,
81
168
  batchSize: 0
82
169
  });
83
- for (let i = 0; i < resp.length; i++) {
84
- if (resp[i].status === "success") {
85
- const contractType = bytes32ToString(resp[i].result);
86
- if (contractType.startsWith("PHANTOM_TOKEN::")) {
87
- this.mustGet(tokens[i]).phantomTokenType = contractType;
170
+ this.#logger?.debug(`loaded ${resp.length} contract types`);
171
+ const kycFactories = new AddressSet();
172
+ for (let i = 0; i < tokensToLoad.length; i++) {
173
+ const meta = this.#overrideTokenMeta(
174
+ tokensToLoad[i],
175
+ resp[2 * i],
176
+ resp[2 * i + 1]
177
+ );
178
+ this.#tokenDataLoaded.add(tokensToLoad[i]);
179
+ if (this.isKYCUnderlying(meta)) {
180
+ kycFactories.add(meta.kycFactory);
181
+ }
182
+ }
183
+ this.#logger?.debug(`found ${kycFactories.size} KYC factories`);
184
+ await this.#loadDSTokens(kycFactories);
185
+ }
186
+ #overrideTokenMeta(token, contractTypeResp, serializeResp) {
187
+ const meta = this.mustGet(token);
188
+ if (contractTypeResp.status === "success") {
189
+ const contractType = bytes32ToString(contractTypeResp.result);
190
+ if (contractType.startsWith("KYC_UNDERLYING::")) {
191
+ if (serializeResp.status === "success") {
192
+ this.#overrideKYCUnderlying(meta, contractType, serializeResp.result);
193
+ } else {
194
+ throw new Error(
195
+ `token ${meta.symbol} (${token}) is ${contractType} but serialize failed: ${serializeResp.error}`
196
+ );
88
197
  }
198
+ } else {
199
+ this.upsert(token, {
200
+ ...meta,
201
+ contractType
202
+ });
89
203
  }
90
- this.#phantomTokensLoaded.add(tokens[i]);
204
+ this.#logger?.debug(`token ${meta.symbol} is ${contractType}`);
205
+ }
206
+ return this.mustGet(token);
207
+ }
208
+ #overrideKYCUnderlying(meta, contractType, serialized) {
209
+ if (contractType === KYC_UNDERLYING_DEFAULT) {
210
+ const decoded = decodeAbiParameters(
211
+ [
212
+ { type: "address", name: "kycFactory" },
213
+ { type: "address", name: "asset" }
214
+ ],
215
+ serialized
216
+ );
217
+ this.upsert(meta.addr, {
218
+ ...meta,
219
+ contractType,
220
+ kycFactory: decoded[0],
221
+ asset: decoded[1]
222
+ });
223
+ } else if (contractType === KYC_UNDERLYING_ON_DEMAND) {
224
+ const decoded = decodeAbiParameters(
225
+ [
226
+ { type: "address", name: "kycFactory" },
227
+ { type: "address", name: "asset" },
228
+ { type: "address", name: "pool" },
229
+ { type: "address", name: "liquidityProvider" }
230
+ ],
231
+ serialized
232
+ );
233
+ this.upsert(meta.addr, {
234
+ ...meta,
235
+ contractType,
236
+ kycFactory: decoded[0],
237
+ asset: decoded[1],
238
+ pool: decoded[2],
239
+ liquidityProvider: decoded[3]
240
+ });
241
+ }
242
+ }
243
+ async #loadDSTokens(kycFactories) {
244
+ const degenNFTs = await this.#client.multicall({
245
+ contracts: kycFactories.map((address) => {
246
+ return {
247
+ address,
248
+ abi: iSecuritizeKYCFactoryAbi,
249
+ functionName: "getDegenNFT"
250
+ };
251
+ }),
252
+ allowFailure: false,
253
+ batchSize: 0
254
+ });
255
+ const resp = await this.#client.multicall({
256
+ contracts: degenNFTs.map((address) => {
257
+ return {
258
+ address,
259
+ abi: iSecuritizeDegenNFTAbi,
260
+ functionName: "getDSTokens"
261
+ };
262
+ }),
263
+ allowFailure: false,
264
+ batchSize: 0
265
+ });
266
+ const dsToken = new AddressSet(resp.flat());
267
+ const tokensToLoad = dsToken.difference(new Set(this.keys()));
268
+ this.#logger?.debug(
269
+ `found ${dsToken.size} DSTokens in KYC factories, need to load ${tokensToLoad.size} basic metadata`
270
+ );
271
+ await this.#loadWithoutCompressor(tokensToLoad);
272
+ for (const token of dsToken) {
273
+ const meta = this.mustGet(token);
274
+ this.upsert(token, {
275
+ ...meta,
276
+ isDSToken: true
277
+ });
278
+ this.#tokenDataLoaded.add(token);
279
+ this.#logger?.debug(`token ${meta.symbol} (${token}) is a DSToken`);
280
+ }
281
+ }
282
+ async #loadWithoutCompressor(tokens_) {
283
+ if (tokens_.size === 0) {
284
+ return;
285
+ }
286
+ const tokens = Array.from(tokens_);
287
+ const resp = await this.#client.multicall({
288
+ contracts: tokens.flatMap(
289
+ (t) => [
290
+ {
291
+ address: t,
292
+ abi: erc20Abi,
293
+ functionName: "symbol"
294
+ },
295
+ {
296
+ address: t,
297
+ abi: erc20Abi,
298
+ functionName: "name"
299
+ },
300
+ {
301
+ address: t,
302
+ abi: erc20Abi,
303
+ functionName: "decimals"
304
+ }
305
+ ]
306
+ ),
307
+ allowFailure: false,
308
+ batchSize: 0
309
+ });
310
+ this.#logger?.debug(
311
+ `loaded ${resp.length} basic metadata without compressor`
312
+ );
313
+ for (let i = 0; i < tokens.length; i++) {
314
+ this.upsert(tokens[i], {
315
+ addr: tokens[i],
316
+ symbol: resp[3 * i],
317
+ name: resp[3 * i + 1],
318
+ decimals: resp[3 * i + 2]
319
+ });
91
320
  }
92
321
  }
93
322
  }
@@ -5,4 +5,5 @@ export * from "./errors.js";
5
5
  export * from "./PlaceholderContract.js";
6
6
  export * from "./SDKConstruct.js";
7
7
  export * from "./TokensMeta.js";
8
+ export * from "./token-types.js";
8
9
  export * from "./types.js";
@@ -7,6 +7,10 @@ const PHANTOM_TOKEN_CONTRACT_TYPES = [
7
7
  "PHANTOM_TOKEN::STAKING_REWARDS",
8
8
  "PHANTOM_TOKEN::UPSHIFT_WITHDRAW"
9
9
  ];
10
+ const KYC_UNDERLYING_DEFAULT = "KYC_UNDERLYING::DEFAULT";
11
+ const KYC_UNDERLYING_ON_DEMAND = "KYC_UNDERLYING::ON_DEMAND";
10
12
  export {
13
+ KYC_UNDERLYING_DEFAULT,
14
+ KYC_UNDERLYING_ON_DEMAND,
11
15
  PHANTOM_TOKEN_CONTRACT_TYPES
12
16
  };
@@ -65,7 +65,8 @@ const chains = {
65
65
  "0x601067eba24bb5b558a184fc082525637e96a42d": "Gami Labs"
66
66
  },
67
67
  testMarketConfigurators: {
68
- "0x99df7330bf42d596af2e9d9836d4fc2077c574aa": "M11 Credit"
68
+ "0x99df7330bf42d596af2e9d9836d4fc2077c574aa": "M11 Credit",
69
+ "0xE0527dE5908B3fc2e054B7eEE0DeF6c9965AbF24": "Securitize"
69
70
  },
70
71
  isPublic: true,
71
72
  wellKnownToken: {
@@ -4,5 +4,4 @@ export * from "./bot-permissions.js";
4
4
  export * from "./math.js";
5
5
  export * from "./networks.js";
6
6
  export * from "./periphery.js";
7
- export * from "./phantom-tokens.js";
8
7
  export * from "./versions.js";
@@ -1,5 +1,4 @@
1
1
  import { marketCompressorAbi } from "../../abi/compressors/marketCompressor.js";
2
- import { SDKConstruct } from "../base/index.js";
3
2
  import {
4
3
  ADDRESS_0X0,
5
4
  AP_MARKET_COMPRESSOR,
@@ -9,7 +8,8 @@ import { AddressMap } from "../utils/index.js";
9
8
  import { simulateWithPriceUpdates } from "../utils/viem/index.js";
10
9
  import { MarketConfiguratorContract } from "./MarketConfiguratorContract.js";
11
10
  import { MarketSuite } from "./MarketSuite.js";
12
- class MarketRegister extends SDKConstruct {
11
+ import { ZapperRegister } from "./ZapperRegister.js";
12
+ class MarketRegister extends ZapperRegister {
13
13
  /**
14
14
  * Mapping pool.address -> MarketSuite
15
15
  */
@@ -41,6 +41,12 @@ class MarketSuite extends SDKConstruct {
41
41
  this.priceOracle = createPriceOracle(sdk, marketData.priceOracle);
42
42
  this.lossPolicy = createLossPolicy(sdk, marketData.lossPolicy);
43
43
  }
44
+ get underlying() {
45
+ return this.pool.underlying;
46
+ }
47
+ async getKYCFactory() {
48
+ return this.pool.getKYCFactory();
49
+ }
44
50
  get dirty() {
45
51
  return this.configurator.dirty || this.pool.dirty || this.priceOracle.dirty || this.creditManagers.some((cm) => cm.dirty);
46
52
  }
@@ -1,4 +1,110 @@
1
- const extraZappers = {
1
+ import { peripheryCompressorAbi } from "../../abi/compressors/peripheryCompressor.js";
2
+ import { SDKConstruct } from "../base/index.js";
3
+ import {
4
+ AP_PERIPHERY_COMPRESSOR,
5
+ VERSION_RANGE_310
6
+ } from "../constants/index.js";
7
+ import { AddressMap, hexEq } from "../utils/index.js";
8
+ class ZapperRegister extends SDKConstruct {
9
+ /**
10
+ * Mapping pool.address -> ZapperData[]
11
+ * Needs to be loaded explicitly using loadZappers method
12
+ */
13
+ #zappers;
14
+ /**
15
+ * Load zappers for all pools using periphery compressor, adds hardcoded zappers
16
+ */
17
+ async loadZappers(force) {
18
+ if (!force && this.#zappers) {
19
+ return;
20
+ }
21
+ const [pcAddr] = this.sdk.addressProvider.mustGetLatest(
22
+ AP_PERIPHERY_COMPRESSOR,
23
+ VERSION_RANGE_310
24
+ );
25
+ this.logger?.debug(`loading zappers with periphery compressor ${pcAddr}`);
26
+ const markets = this.sdk.marketRegister.markets;
27
+ const resp = await this.client.multicall({
28
+ contracts: markets.map(
29
+ (m) => ({
30
+ abi: peripheryCompressorAbi,
31
+ address: pcAddr,
32
+ functionName: "getZappers",
33
+ args: [m.configurator.address, m.pool.pool.address]
34
+ })
35
+ ),
36
+ allowFailure: true,
37
+ batchSize: 0
38
+ });
39
+ this.#zappers = new AddressMap(void 0, "zappers");
40
+ for (let i = 0; i < resp.length; i++) {
41
+ const { status, result, error } = resp[i];
42
+ const marketConfigurator = markets[i].configurator.address;
43
+ const pool = markets[i].pool.pool.address;
44
+ if (status === "success") {
45
+ for (const z of result) {
46
+ this.#addZapper({ ...z, pool, type: "base" });
47
+ }
48
+ } else {
49
+ this.logger?.error(
50
+ `failed to load zapper for market configurator ${this.labelAddress(
51
+ marketConfigurator
52
+ )} and pool ${this.labelAddress(pool)}: ${error}`
53
+ );
54
+ }
55
+ }
56
+ for (const z of KYC_ZAPPERS[this.networkType] ?? []) {
57
+ this.#addZapper({ ...z, type: "kyc" });
58
+ }
59
+ for (const z of MIGRATION_ZAPPERS[this.networkType] ?? []) {
60
+ this.#addZapper({ ...z, type: "migration" });
61
+ }
62
+ }
63
+ #addZapper(z) {
64
+ if (BROKEN_ZAPPERS.has(z.baseParams.addr)) {
65
+ return;
66
+ }
67
+ const existing = this.zappers.get(z.pool);
68
+ if (existing) {
69
+ const hasZapper = existing.some(
70
+ (zz) => hexEq(zz.baseParams.addr, z.baseParams.addr)
71
+ );
72
+ if (!hasZapper) {
73
+ existing.push(z);
74
+ }
75
+ } else {
76
+ this.zappers.upsert(z.pool, [z]);
77
+ }
78
+ const zappersTokens = [z.tokenIn, z.tokenOut];
79
+ for (const t of zappersTokens) {
80
+ this.sdk.tokensMeta.upsert(t.addr, t);
81
+ this.sdk.setAddressLabel(t.addr, t.symbol);
82
+ }
83
+ }
84
+ get zappers() {
85
+ if (!this.#zappers) {
86
+ throw new Error("zappers not loaded, call loadZappers first");
87
+ }
88
+ return this.#zappers;
89
+ }
90
+ poolZappers(pool) {
91
+ return this.zappers.get(pool) ?? [];
92
+ }
93
+ /**
94
+ * Can return multiple zappers if there are multiple zappers for the same tokenIn and tokenOut
95
+ */
96
+ getZapper(pool, tokenIn, tokenOut) {
97
+ const zappers = this.zappers.get(pool)?.filter(
98
+ (z) => hexEq(z.tokenIn.addr, tokenIn) && hexEq(z.tokenOut.addr, tokenOut)
99
+ );
100
+ return zappers;
101
+ }
102
+ }
103
+ const BROKEN_ZAPPERS = new AddressMap(
104
+ [["0x90D66b03EC4D462e42e3c7741049FB46a4a03B69", true]],
105
+ "brokenZappers"
106
+ );
107
+ const MIGRATION_ZAPPERS = {
2
108
  Mainnet: [
3
109
  {
4
110
  baseParams: {
@@ -107,6 +213,7 @@ const extraZappers = {
107
213
  }
108
214
  ]
109
215
  };
216
+ const KYC_ZAPPERS = {};
110
217
  export {
111
- extraZappers
218
+ ZapperRegister
112
219
  };
@@ -5,3 +5,4 @@ export * from "./MarketSuite.js";
5
5
  export * from "./oracle/index.js";
6
6
  export * from "./pool/index.js";
7
7
  export * from "./pricefeeds/index.js";
8
+ export * from "./types.js";
@@ -55,6 +55,9 @@ class PoolSuite extends SDKConstruct {
55
55
  get underlying() {
56
56
  return this.pool.underlying;
57
57
  }
58
+ async getKYCFactory() {
59
+ return this.pool.getKYCFactory();
60
+ }
58
61
  get dirty() {
59
62
  return this.pool.dirty || this.rateKeeper.dirty || this.pqk.dirty || this.interestRateModel.dirty;
60
63
  }
@@ -7,16 +7,20 @@ import {
7
7
  formatBNvalue,
8
8
  percentFmt
9
9
  } from "../../utils/index.js";
10
+ import { SecuritizeKYCFactory } from "./SecuritizeKYCFactory.js";
10
11
  const abi = [...iPoolV310Abi, ...iPausableAbi];
11
12
  class PoolV310Contract extends BaseContract {
12
13
  creditManagerDebtParams;
13
- constructor(options, data) {
14
+ #sdk;
15
+ #kycFactory;
16
+ constructor(sdk, data) {
14
17
  const { baseParams, creditManagerDebtParams, ...rest } = data;
15
- super(options, {
18
+ super(sdk, {
16
19
  ...data.baseParams,
17
20
  name: `PoolV3(${data.name})`,
18
21
  abi
19
22
  });
23
+ this.#sdk = sdk;
20
24
  Object.assign(this, rest);
21
25
  this.creditManagerDebtParams = new AddressMap(
22
26
  creditManagerDebtParams.map((p) => [p.creditManager, p])
@@ -28,6 +32,17 @@ class PoolV310Contract extends BaseContract {
28
32
  symbol: data.symbol
29
33
  });
30
34
  }
35
+ async getKYCFactory() {
36
+ if (this.#kycFactory) {
37
+ return this.#kycFactory;
38
+ }
39
+ await this.#sdk.tokensMeta.loadTokenData(this.underlying);
40
+ const u = this.#sdk.tokensMeta.mustGet(this.underlying);
41
+ if (this.#sdk.tokensMeta.isKYCUnderlying(u)) {
42
+ this.#kycFactory = new SecuritizeKYCFactory(this.#sdk, u.kycFactory);
43
+ }
44
+ return this.#kycFactory;
45
+ }
31
46
  stateHuman(raw = true) {
32
47
  return {
33
48
  ...super.stateHuman(raw),