@defisaver/positions-sdk 0.0.16 → 0.0.18

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 (62) hide show
  1. package/cjs/aaveV3/index.d.ts +1 -1
  2. package/cjs/aaveV3/index.js +2 -3
  3. package/cjs/helpers/compoundHelpers/index.js +2 -2
  4. package/cjs/morphoAaveV3/index.d.ts +1 -1
  5. package/cjs/morphoAaveV3/index.js +2 -3
  6. package/cjs/types/compound.d.ts +1 -0
  7. package/esm/aaveV3/index.d.ts +1 -1
  8. package/esm/aaveV3/index.js +2 -3
  9. package/esm/helpers/compoundHelpers/index.js +2 -2
  10. package/esm/morphoAaveV3/index.d.ts +1 -1
  11. package/esm/morphoAaveV3/index.js +2 -3
  12. package/esm/types/compound.d.ts +1 -0
  13. package/package.json +40 -40
  14. package/src/aaveV2/index.ts +220 -220
  15. package/src/aaveV3/index.ts +554 -556
  16. package/src/assets/index.ts +60 -60
  17. package/src/chickenBonds/index.ts +123 -123
  18. package/src/compoundV2/index.ts +206 -206
  19. package/src/compoundV3/index.ts +270 -269
  20. package/src/config/contracts.js +651 -651
  21. package/src/constants/index.ts +3 -3
  22. package/src/contracts.ts +100 -100
  23. package/src/curveUsd/index.ts +228 -228
  24. package/src/exchange/index.ts +17 -17
  25. package/src/helpers/aaveHelpers/index.ts +134 -134
  26. package/src/helpers/chickenBondsHelpers/index.ts +23 -23
  27. package/src/helpers/compoundHelpers/index.ts +181 -181
  28. package/src/helpers/curveUsdHelpers/index.ts +32 -32
  29. package/src/helpers/index.ts +5 -5
  30. package/src/helpers/makerHelpers/index.ts +94 -94
  31. package/src/helpers/sparkHelpers/index.ts +106 -106
  32. package/src/index.ts +40 -40
  33. package/src/liquity/index.ts +103 -103
  34. package/src/maker/index.ts +101 -101
  35. package/src/markets/aave/index.ts +80 -80
  36. package/src/markets/aave/marketAssets.ts +32 -32
  37. package/src/markets/compound/index.ts +85 -85
  38. package/src/markets/compound/marketsAssets.ts +35 -35
  39. package/src/markets/curveUsd/index.ts +69 -69
  40. package/src/markets/index.ts +3 -3
  41. package/src/markets/spark/index.ts +29 -29
  42. package/src/markets/spark/marketAssets.ts +9 -9
  43. package/src/moneymarket/moneymarketCommonService.ts +75 -75
  44. package/src/morpho/markets.ts +39 -39
  45. package/src/morphoAaveV2/index.ts +254 -254
  46. package/src/morphoAaveV3/index.ts +614 -617
  47. package/src/multicall/index.ts +22 -22
  48. package/src/services/dsrService.ts +15 -15
  49. package/src/services/priceService.ts +21 -21
  50. package/src/services/utils.ts +34 -34
  51. package/src/spark/index.ts +413 -413
  52. package/src/staking/staking.ts +167 -167
  53. package/src/types/aave.ts +256 -256
  54. package/src/types/chickenBonds.ts +45 -45
  55. package/src/types/common.ts +83 -83
  56. package/src/types/compound.ts +122 -121
  57. package/src/types/curveUsd.ts +112 -112
  58. package/src/types/index.ts +6 -6
  59. package/src/types/liquity.ts +29 -29
  60. package/src/types/maker.ts +50 -50
  61. package/src/types/spark.ts +106 -106
  62. package/yarn-error.log +0 -64
@@ -29,5 +29,5 @@ export declare const EMPTY_AAVE_DATA: {
29
29
  suppliedCollateralUsd: string;
30
30
  };
31
31
  export declare const getAaveV3AccountBalances: (web3: Web3, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress) => Promise<PositionBalances>;
32
- export declare const getAaveV3AccountData: (web3: Web3, network: NetworkNumber, address: EthAddress, extractedState: any, customGetAggregatedDataFunction?: Function) => Promise<AaveV3PositionData>;
32
+ export declare const getAaveV3AccountData: (web3: Web3, network: NetworkNumber, address: EthAddress, extractedState: any) => Promise<AaveV3PositionData>;
33
33
  export declare const getAaveV3FullPositionData: (web3: Web3, network: NetworkNumber, address: string, market: AaveMarketInfo, mainnetWeb3: Web3) => Promise<AaveV3PositionData>;
@@ -288,7 +288,7 @@ const getAaveV3AccountBalances = (web3, network, block, addressMapping, address)
288
288
  return balances;
289
289
  });
290
290
  exports.getAaveV3AccountBalances = getAaveV3AccountBalances;
291
- const getAaveV3AccountData = (web3, network, address, extractedState, customGetAggregatedDataFunction) => __awaiter(void 0, void 0, void 0, function* () {
291
+ const getAaveV3AccountData = (web3, network, address, extractedState) => __awaiter(void 0, void 0, void 0, function* () {
292
292
  const { selectedMarket: market, assetsData, } = extractedState;
293
293
  let payload = Object.assign(Object.assign({}, exports.EMPTY_AAVE_DATA), { lastUpdated: Date.now() });
294
294
  if (!address) {
@@ -359,9 +359,8 @@ const getAaveV3AccountData = (web3, network, address, extractedState, customGetA
359
359
  usedAssets[asset] = Object.assign(Object.assign({}, usedAssets[asset]), { symbol: asset, supplied, suppliedUsd: new decimal_js_1.default(supplied).mul(assetsData[asset].price).toString(), isSupplied, collateral: enabledAsCollateral, stableBorrowRate: new decimal_js_1.default(tokenInfo.stableBorrowRate).div(1e25).toString(), discountedBorrowRate: new decimal_js_1.default(assetsData[asset].borrowRate).mul(1 - parseFloat(discountRateOnBorrow)).toString(), borrowedStable,
360
360
  borrowedVariable, borrowedUsdStable: new decimal_js_1.default(borrowedStable).mul(assetsData[asset].price).toString(), borrowedUsdVariable: new decimal_js_1.default(borrowedVariable).mul(assetsData[asset].price).toString(), borrowed, borrowedUsd: new decimal_js_1.default(new decimal_js_1.default(borrowedVariable).add(borrowedStable)).mul(assetsData[asset].price).toString(), isBorrowed, eModeCategory: assetsData[asset].eModeCategory, interestMode });
361
361
  }));
362
- const aggregateFunction = customGetAggregatedDataFunction || aaveHelpers_1.aaveAnyGetAggregatedPositionData;
363
362
  payload.eModeCategory = +multicallRes[0][0];
364
- payload = Object.assign(Object.assign(Object.assign({}, payload), { usedAssets }), aggregateFunction(Object.assign(Object.assign({}, extractedState), { usedAssets, eModeCategory: payload.eModeCategory })));
363
+ payload = Object.assign(Object.assign(Object.assign({}, payload), { usedAssets }), (0, aaveHelpers_1.aaveAnyGetAggregatedPositionData)(Object.assign(Object.assign({}, extractedState), { usedAssets, eModeCategory: payload.eModeCategory })));
365
364
  payload.eModeCategories = (0, exports.aaveV3EmodeCategoriesMapping)(extractedState, usedAssets);
366
365
  payload.isInIsolationMode = (0, aaveHelpers_1.aaveV3IsInIsolationMode)({ usedAssets, assetsData });
367
366
  payload.isInSiloedMode = (0, aaveHelpers_1.aaveV3IsInSiloedMode)({ usedAssets, assetsData });
@@ -42,8 +42,8 @@ const formatBaseData = (data, network, baseAssetPrice) => {
42
42
  };
43
43
  exports.formatBaseData = formatBaseData;
44
44
  const getIncentiveApys = (baseData, compPrice) => {
45
- const incentiveSupplyApy = (0, moneymarket_1.aprToApy)((100 * constants_1.SECONDS_PER_YEAR * +baseData.rewardSupplySpeed * +compPrice) / +baseData.price / +baseData.totalSupply).toString();
46
- const incentiveBorrowApy = (0, moneymarket_1.aprToApy)((100 * constants_1.SECONDS_PER_YEAR * +baseData.rewardBorrowSpeed * +compPrice) / +baseData.price / +baseData.totalBorrow).toString();
45
+ const incentiveSupplyApy = (0, moneymarket_1.aprToApy)((100 * constants_1.SECONDS_PER_YEAR * +baseData.rewardSupplySpeed * +compPrice) / +baseData.priceInBaseAsset / +baseData.totalSupply).toString();
46
+ const incentiveBorrowApy = (0, moneymarket_1.aprToApy)((100 * constants_1.SECONDS_PER_YEAR * +baseData.rewardBorrowSpeed * +compPrice) / +baseData.priceInBaseAsset / +baseData.totalBorrow).toString();
47
47
  return {
48
48
  incentiveSupplyApy,
49
49
  incentiveBorrowApy,
@@ -3,5 +3,5 @@ import { Blockish, EthAddress, NetworkNumber, PositionBalances } from '../types/
3
3
  import { MorphoAaveV3AssetsData, MorphoAaveV3MarketData, MorphoAaveV3MarketInfo, MorphoAaveV3PositionData } from '../types';
4
4
  export declare const getMorphoAaveV3MarketsData: (web3: Web3, network: NetworkNumber, selectedMarket: MorphoAaveV3MarketInfo, mainnetWeb3: Web3) => Promise<MorphoAaveV3MarketData>;
5
5
  export declare const getMorphoAaveV3AccountBalances: (web3: Web3, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress) => Promise<PositionBalances>;
6
- export declare const getMorphoAaveV3AccountData: (web3: Web3, network: NetworkNumber, address: string, assetsData: MorphoAaveV3AssetsData, delegator: string, selectedMarket: MorphoAaveV3MarketInfo, customGetAggregatedDataFunction?: Function) => Promise<MorphoAaveV3PositionData>;
6
+ export declare const getMorphoAaveV3AccountData: (web3: Web3, network: NetworkNumber, address: string, assetsData: MorphoAaveV3AssetsData, delegator: string, selectedMarket: MorphoAaveV3MarketInfo) => Promise<MorphoAaveV3PositionData>;
7
7
  export declare const getMorphoAaveV3FullPositionData: (web3: Web3, network: NetworkNumber, address: string, delegator: string, market: MorphoAaveV3MarketInfo, mainnetWeb3: Web3) => Promise<MorphoAaveV3PositionData>;
@@ -316,7 +316,7 @@ const getMorphoAaveV3AccountBalances = (web3, network, block, addressMapping, ad
316
316
  return balances;
317
317
  });
318
318
  exports.getMorphoAaveV3AccountBalances = getMorphoAaveV3AccountBalances;
319
- const getMorphoAaveV3AccountData = (web3, network, address, assetsData, delegator, selectedMarket, customGetAggregatedDataFunction) => __awaiter(void 0, void 0, void 0, function* () {
319
+ const getMorphoAaveV3AccountData = (web3, network, address, assetsData, delegator, selectedMarket) => __awaiter(void 0, void 0, void 0, function* () {
320
320
  var _g;
321
321
  if (!address) {
322
322
  throw new Error('No address provided.');
@@ -421,8 +421,7 @@ const getMorphoAaveV3AccountData = (web3, network, address, assetsData, delegato
421
421
  };
422
422
  }
423
423
  });
424
- const aggregateFunction = customGetAggregatedDataFunction || aaveHelpers_1.aaveAnyGetAggregatedPositionData;
425
- payload = Object.assign(Object.assign({}, payload), aggregateFunction({
424
+ payload = Object.assign(Object.assign({}, payload), (0, aaveHelpers_1.aaveAnyGetAggregatedPositionData)({
426
425
  usedAssets: payload.usedAssets, assetsData, eModeCategory, selectedMarket,
427
426
  }));
428
427
  // Calculate borrow limits per asset
@@ -49,6 +49,7 @@ export interface CompoundV3AssetData extends CompoundAssetData {
49
49
  minDebt: string;
50
50
  liquidationRatio: string;
51
51
  supplyCap: string;
52
+ priceInBaseAsset: string;
52
53
  }
53
54
  export interface CompoundAssetsData<T> {
54
55
  [token: string]: T;
@@ -29,5 +29,5 @@ export declare const EMPTY_AAVE_DATA: {
29
29
  suppliedCollateralUsd: string;
30
30
  };
31
31
  export declare const getAaveV3AccountBalances: (web3: Web3, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress) => Promise<PositionBalances>;
32
- export declare const getAaveV3AccountData: (web3: Web3, network: NetworkNumber, address: EthAddress, extractedState: any, customGetAggregatedDataFunction?: Function) => Promise<AaveV3PositionData>;
32
+ export declare const getAaveV3AccountData: (web3: Web3, network: NetworkNumber, address: EthAddress, extractedState: any) => Promise<AaveV3PositionData>;
33
33
  export declare const getAaveV3FullPositionData: (web3: Web3, network: NetworkNumber, address: string, market: AaveMarketInfo, mainnetWeb3: Web3) => Promise<AaveV3PositionData>;
@@ -277,7 +277,7 @@ export const getAaveV3AccountBalances = (web3, network, block, addressMapping, a
277
277
  });
278
278
  return balances;
279
279
  });
280
- export const getAaveV3AccountData = (web3, network, address, extractedState, customGetAggregatedDataFunction) => __awaiter(void 0, void 0, void 0, function* () {
280
+ export const getAaveV3AccountData = (web3, network, address, extractedState) => __awaiter(void 0, void 0, void 0, function* () {
281
281
  const { selectedMarket: market, assetsData, } = extractedState;
282
282
  let payload = Object.assign(Object.assign({}, EMPTY_AAVE_DATA), { lastUpdated: Date.now() });
283
283
  if (!address) {
@@ -348,9 +348,8 @@ export const getAaveV3AccountData = (web3, network, address, extractedState, cus
348
348
  usedAssets[asset] = Object.assign(Object.assign({}, usedAssets[asset]), { symbol: asset, supplied, suppliedUsd: new Dec(supplied).mul(assetsData[asset].price).toString(), isSupplied, collateral: enabledAsCollateral, stableBorrowRate: new Dec(tokenInfo.stableBorrowRate).div(1e25).toString(), discountedBorrowRate: new Dec(assetsData[asset].borrowRate).mul(1 - parseFloat(discountRateOnBorrow)).toString(), borrowedStable,
349
349
  borrowedVariable, borrowedUsdStable: new Dec(borrowedStable).mul(assetsData[asset].price).toString(), borrowedUsdVariable: new Dec(borrowedVariable).mul(assetsData[asset].price).toString(), borrowed, borrowedUsd: new Dec(new Dec(borrowedVariable).add(borrowedStable)).mul(assetsData[asset].price).toString(), isBorrowed, eModeCategory: assetsData[asset].eModeCategory, interestMode });
350
350
  }));
351
- const aggregateFunction = customGetAggregatedDataFunction || aaveAnyGetAggregatedPositionData;
352
351
  payload.eModeCategory = +multicallRes[0][0];
353
- payload = Object.assign(Object.assign(Object.assign({}, payload), { usedAssets }), aggregateFunction(Object.assign(Object.assign({}, extractedState), { usedAssets, eModeCategory: payload.eModeCategory })));
352
+ payload = Object.assign(Object.assign(Object.assign({}, payload), { usedAssets }), aaveAnyGetAggregatedPositionData(Object.assign(Object.assign({}, extractedState), { usedAssets, eModeCategory: payload.eModeCategory })));
354
353
  payload.eModeCategories = aaveV3EmodeCategoriesMapping(extractedState, usedAssets);
355
354
  payload.isInIsolationMode = aaveV3IsInIsolationMode({ usedAssets, assetsData });
356
355
  payload.isInSiloedMode = aaveV3IsInSiloedMode({ usedAssets, assetsData });
@@ -34,8 +34,8 @@ export const formatBaseData = (data, network, baseAssetPrice) => {
34
34
  totalBorrow, marketLiquidity: new Dec(totalSupply).minus(totalBorrow).toString(), symbol: wethToEth(assetInfo.symbol), priceInBaseAsset: getEthAmountForDecimals(data.price, 8), price: baseAssetPrice, collateralFactor: '0', liquidationRatio: '0', canBeBorrowed: true, canBeSupplied: true, supplyCap: '0', rewardSupplySpeed: getEthAmountForDecimals(data.baseTrackingSupplyRewardsSpeed, 15), rewardBorrowSpeed: getEthAmountForDecimals(data.baseTrackingBorrowRewardsSpeed, 15), minDebt: getEthAmountForDecimals(data.baseBorrowMin, assetInfo.decimals), isBase: true }));
35
35
  };
36
36
  export const getIncentiveApys = (baseData, compPrice) => {
37
- const incentiveSupplyApy = aprToApy((100 * SECONDS_PER_YEAR * +baseData.rewardSupplySpeed * +compPrice) / +baseData.price / +baseData.totalSupply).toString();
38
- const incentiveBorrowApy = aprToApy((100 * SECONDS_PER_YEAR * +baseData.rewardBorrowSpeed * +compPrice) / +baseData.price / +baseData.totalBorrow).toString();
37
+ const incentiveSupplyApy = aprToApy((100 * SECONDS_PER_YEAR * +baseData.rewardSupplySpeed * +compPrice) / +baseData.priceInBaseAsset / +baseData.totalSupply).toString();
38
+ const incentiveBorrowApy = aprToApy((100 * SECONDS_PER_YEAR * +baseData.rewardBorrowSpeed * +compPrice) / +baseData.priceInBaseAsset / +baseData.totalBorrow).toString();
39
39
  return {
40
40
  incentiveSupplyApy,
41
41
  incentiveBorrowApy,
@@ -3,5 +3,5 @@ import { Blockish, EthAddress, NetworkNumber, PositionBalances } from '../types/
3
3
  import { MorphoAaveV3AssetsData, MorphoAaveV3MarketData, MorphoAaveV3MarketInfo, MorphoAaveV3PositionData } from '../types';
4
4
  export declare const getMorphoAaveV3MarketsData: (web3: Web3, network: NetworkNumber, selectedMarket: MorphoAaveV3MarketInfo, mainnetWeb3: Web3) => Promise<MorphoAaveV3MarketData>;
5
5
  export declare const getMorphoAaveV3AccountBalances: (web3: Web3, network: NetworkNumber, block: Blockish, addressMapping: boolean, address: EthAddress) => Promise<PositionBalances>;
6
- export declare const getMorphoAaveV3AccountData: (web3: Web3, network: NetworkNumber, address: string, assetsData: MorphoAaveV3AssetsData, delegator: string, selectedMarket: MorphoAaveV3MarketInfo, customGetAggregatedDataFunction?: Function) => Promise<MorphoAaveV3PositionData>;
6
+ export declare const getMorphoAaveV3AccountData: (web3: Web3, network: NetworkNumber, address: string, assetsData: MorphoAaveV3AssetsData, delegator: string, selectedMarket: MorphoAaveV3MarketInfo) => Promise<MorphoAaveV3PositionData>;
7
7
  export declare const getMorphoAaveV3FullPositionData: (web3: Web3, network: NetworkNumber, address: string, delegator: string, market: MorphoAaveV3MarketInfo, mainnetWeb3: Web3) => Promise<MorphoAaveV3PositionData>;
@@ -308,7 +308,7 @@ export const getMorphoAaveV3AccountBalances = (web3, network, block, addressMapp
308
308
  });
309
309
  return balances;
310
310
  });
311
- export const getMorphoAaveV3AccountData = (web3, network, address, assetsData, delegator, selectedMarket, customGetAggregatedDataFunction) => __awaiter(void 0, void 0, void 0, function* () {
311
+ export const getMorphoAaveV3AccountData = (web3, network, address, assetsData, delegator, selectedMarket) => __awaiter(void 0, void 0, void 0, function* () {
312
312
  var _g;
313
313
  if (!address) {
314
314
  throw new Error('No address provided.');
@@ -413,8 +413,7 @@ export const getMorphoAaveV3AccountData = (web3, network, address, assetsData, d
413
413
  };
414
414
  }
415
415
  });
416
- const aggregateFunction = customGetAggregatedDataFunction || aaveAnyGetAggregatedPositionData;
417
- payload = Object.assign(Object.assign({}, payload), aggregateFunction({
416
+ payload = Object.assign(Object.assign({}, payload), aaveAnyGetAggregatedPositionData({
418
417
  usedAssets: payload.usedAssets, assetsData, eModeCategory, selectedMarket,
419
418
  }));
420
419
  // Calculate borrow limits per asset
@@ -49,6 +49,7 @@ export interface CompoundV3AssetData extends CompoundAssetData {
49
49
  minDebt: string;
50
50
  liquidationRatio: string;
51
51
  supplyCap: string;
52
+ priceInBaseAsset: string;
52
53
  }
53
54
  export interface CompoundAssetsData<T> {
54
55
  [token: string]: T;
package/package.json CHANGED
@@ -1,40 +1,40 @@
1
- {
2
- "name": "@defisaver/positions-sdk",
3
- "version": "0.0.16",
4
- "description": "",
5
- "main": "./cjs/index.js",
6
- "module": "./esm/index.js",
7
- "types": "./esm/index.d.ts",
8
- "scripts": {
9
- "build:esm": "rm -rf esm && tsc -p tsconfig.json",
10
- "build:cjs": "rm -rf cjs && tsc -p tsconfig.cjs.json",
11
- "build": "npm run generate-contracts && npm run build:cjs && npm run build:esm",
12
- "dev": "npm run generate-contracts && tsc -p tsconfig.cjs.json --watch",
13
- "lint": "eslint src/ --fix",
14
- "generate-contracts": "node scripts/generateContracts.js",
15
- "test": "mocha tests/*",
16
- "build-test": "npm run build && mocha tests/*"
17
- },
18
- "keywords": [],
19
- "author": "",
20
- "license": "ISC",
21
- "dependencies": {
22
- "@defisaver/tokens": "^1.5.3",
23
- "decimal.js": "^10.4.3",
24
- "@morpho-org/morpho-aave-v3-sdk": "^1.5.3",
25
- "@ethersproject/bignumber": "^5.7.0"
26
- },
27
- "devDependencies": {
28
- "@defisaver/eslint-config": "^1.0.1",
29
- "chai": "^4.3.8",
30
- "dotenv": "^16.3.1",
31
- "eslint": "^8.49.0",
32
- "mocha": "^10.2.0",
33
- "typechain": "^8.3.1",
34
- "typechain-target-web3-v1-3mihai3": "^6.0.2",
35
- "typescript": "^5.2.2"
36
- },
37
- "peerDependencies": {
38
- "web3": "^1.10.2"
39
- }
40
- }
1
+ {
2
+ "name": "@defisaver/positions-sdk",
3
+ "version": "0.0.18",
4
+ "description": "",
5
+ "main": "./cjs/index.js",
6
+ "module": "./esm/index.js",
7
+ "types": "./esm/index.d.ts",
8
+ "scripts": {
9
+ "build:esm": "rm -rf esm && tsc -p tsconfig.json",
10
+ "build:cjs": "rm -rf cjs && tsc -p tsconfig.cjs.json",
11
+ "build": "npm run generate-contracts && npm run build:cjs && npm run build:esm",
12
+ "dev": "npm run generate-contracts && tsc -p tsconfig.cjs.json --watch",
13
+ "lint": "eslint src/ --fix",
14
+ "generate-contracts": "node scripts/generateContracts.js",
15
+ "test": "mocha tests/*",
16
+ "build-test": "npm run build && mocha tests/*"
17
+ },
18
+ "keywords": [],
19
+ "author": "",
20
+ "license": "ISC",
21
+ "dependencies": {
22
+ "@defisaver/tokens": "^1.5.3",
23
+ "decimal.js": "^10.4.3",
24
+ "@morpho-org/morpho-aave-v3-sdk": "^1.5.3",
25
+ "@ethersproject/bignumber": "^5.7.0"
26
+ },
27
+ "devDependencies": {
28
+ "@defisaver/eslint-config": "^1.0.1",
29
+ "chai": "^4.3.8",
30
+ "dotenv": "^16.3.1",
31
+ "eslint": "^8.49.0",
32
+ "mocha": "^10.2.0",
33
+ "typechain": "^8.3.1",
34
+ "typechain-target-web3-v1-3mihai3": "^6.0.2",
35
+ "typescript": "^5.2.2"
36
+ },
37
+ "peerDependencies": {
38
+ "web3": "^1.10.2"
39
+ }
40
+ }