@defisaver/positions-sdk 2.1.23 → 2.1.24-dev-savings-2

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 (159) hide show
  1. package/.mocharc.json +4 -4
  2. package/.nvmrc +1 -1
  3. package/README.md +64 -64
  4. package/cjs/config/contracts.d.ts +173 -0
  5. package/cjs/config/contracts.js +23 -1
  6. package/cjs/contracts.d.ts +1650 -0
  7. package/cjs/contracts.js +22 -1
  8. package/cjs/helpers/morphoBlueHelpers/index.js +66 -66
  9. package/cjs/index.d.ts +2 -1
  10. package/cjs/index.js +3 -1
  11. package/cjs/markets/aave/marketAssets.js +1 -1
  12. package/cjs/savings/index.d.ts +7 -0
  13. package/cjs/savings/index.js +75 -0
  14. package/cjs/savings/makerDSR/index.d.ts +7 -0
  15. package/cjs/savings/makerDSR/index.js +94 -0
  16. package/cjs/savings/makerDSR/options.d.ts +2 -0
  17. package/cjs/savings/makerDSR/options.js +11 -0
  18. package/cjs/savings/morphoVaults/index.d.ts +7 -0
  19. package/cjs/savings/morphoVaults/index.js +118 -0
  20. package/cjs/savings/morphoVaults/options.d.ts +16 -0
  21. package/cjs/savings/morphoVaults/options.js +112 -0
  22. package/cjs/savings/yearnVaults/index.d.ts +9 -0
  23. package/cjs/savings/yearnVaults/index.js +113 -0
  24. package/cjs/savings/yearnVaults/options.d.ts +6 -0
  25. package/cjs/savings/yearnVaults/options.js +29 -0
  26. package/cjs/types/index.d.ts +1 -0
  27. package/cjs/types/index.js +1 -0
  28. package/cjs/types/savings/index.d.ts +15 -0
  29. package/cjs/types/savings/index.js +19 -0
  30. package/cjs/types/savings/makerDsr.d.ts +11 -0
  31. package/cjs/types/savings/makerDsr.js +7 -0
  32. package/cjs/types/savings/morphoVaults.d.ts +23 -0
  33. package/cjs/types/savings/morphoVaults.js +19 -0
  34. package/cjs/types/savings/yearnVaults.d.ts +12 -0
  35. package/cjs/types/savings/yearnVaults.js +9 -0
  36. package/esm/config/contracts.d.ts +173 -0
  37. package/esm/config/contracts.js +22 -0
  38. package/esm/contracts.d.ts +1650 -0
  39. package/esm/contracts.js +18 -0
  40. package/esm/helpers/morphoBlueHelpers/index.js +66 -66
  41. package/esm/index.d.ts +2 -1
  42. package/esm/index.js +2 -1
  43. package/esm/markets/aave/marketAssets.js +1 -1
  44. package/esm/savings/index.d.ts +7 -0
  45. package/esm/savings/index.js +36 -0
  46. package/esm/savings/makerDSR/index.d.ts +7 -0
  47. package/esm/savings/makerDSR/index.js +53 -0
  48. package/esm/savings/makerDSR/options.d.ts +2 -0
  49. package/esm/savings/makerDSR/options.js +8 -0
  50. package/esm/savings/morphoVaults/index.d.ts +7 -0
  51. package/esm/savings/morphoVaults/index.js +77 -0
  52. package/esm/savings/morphoVaults/options.d.ts +16 -0
  53. package/esm/savings/morphoVaults/options.js +108 -0
  54. package/esm/savings/yearnVaults/index.d.ts +9 -0
  55. package/esm/savings/yearnVaults/index.js +70 -0
  56. package/esm/savings/yearnVaults/options.d.ts +6 -0
  57. package/esm/savings/yearnVaults/options.js +25 -0
  58. package/esm/types/index.d.ts +1 -0
  59. package/esm/types/index.js +1 -0
  60. package/esm/types/savings/index.d.ts +15 -0
  61. package/esm/types/savings/index.js +3 -0
  62. package/esm/types/savings/makerDsr.d.ts +11 -0
  63. package/esm/types/savings/makerDsr.js +4 -0
  64. package/esm/types/savings/morphoVaults.d.ts +23 -0
  65. package/esm/types/savings/morphoVaults.js +16 -0
  66. package/esm/types/savings/yearnVaults.d.ts +12 -0
  67. package/esm/types/savings/yearnVaults.js +6 -0
  68. package/package.json +48 -47
  69. package/src/aaveV2/index.ts +240 -240
  70. package/src/aaveV3/index.ts +614 -614
  71. package/src/aaveV3/merit.ts +97 -97
  72. package/src/aaveV3/merkl.ts +74 -74
  73. package/src/claiming/aaveV3.ts +154 -154
  74. package/src/claiming/compV3.ts +22 -22
  75. package/src/claiming/ethena.ts +61 -61
  76. package/src/claiming/index.ts +12 -12
  77. package/src/claiming/king.ts +66 -66
  78. package/src/claiming/morphoBlue.ts +118 -118
  79. package/src/claiming/spark.ts +225 -225
  80. package/src/compoundV2/index.ts +244 -244
  81. package/src/compoundV3/index.ts +274 -274
  82. package/src/config/contracts.ts +1282 -1260
  83. package/src/constants/index.ts +10 -10
  84. package/src/contracts.ts +143 -121
  85. package/src/curveUsd/index.ts +254 -254
  86. package/src/eulerV2/index.ts +324 -324
  87. package/src/exchange/index.ts +25 -25
  88. package/src/fluid/index.ts +1774 -1774
  89. package/src/helpers/aaveHelpers/index.ts +187 -187
  90. package/src/helpers/compoundHelpers/index.ts +283 -283
  91. package/src/helpers/curveUsdHelpers/index.ts +40 -40
  92. package/src/helpers/eulerHelpers/index.ts +222 -222
  93. package/src/helpers/fluidHelpers/index.ts +326 -326
  94. package/src/helpers/index.ts +10 -10
  95. package/src/helpers/liquityV2Helpers/index.ts +82 -82
  96. package/src/helpers/llamaLendHelpers/index.ts +53 -53
  97. package/src/helpers/makerHelpers/index.ts +52 -52
  98. package/src/helpers/morphoBlueHelpers/index.ts +396 -396
  99. package/src/helpers/sparkHelpers/index.ts +158 -158
  100. package/src/index.ts +49 -47
  101. package/src/liquity/index.ts +159 -159
  102. package/src/liquityV2/index.ts +703 -703
  103. package/src/llamaLend/index.ts +305 -305
  104. package/src/maker/index.ts +223 -223
  105. package/src/markets/aave/index.ts +116 -116
  106. package/src/markets/aave/marketAssets.ts +54 -54
  107. package/src/markets/compound/index.ts +238 -238
  108. package/src/markets/compound/marketsAssets.ts +97 -97
  109. package/src/markets/curveUsd/index.ts +69 -69
  110. package/src/markets/euler/index.ts +26 -26
  111. package/src/markets/fluid/index.ts +2900 -2900
  112. package/src/markets/index.ts +25 -25
  113. package/src/markets/liquityV2/index.ts +102 -102
  114. package/src/markets/llamaLend/contractAddresses.ts +141 -141
  115. package/src/markets/llamaLend/index.ts +235 -235
  116. package/src/markets/morphoBlue/index.ts +971 -971
  117. package/src/markets/spark/index.ts +29 -29
  118. package/src/markets/spark/marketAssets.ts +12 -12
  119. package/src/moneymarket/moneymarketCommonService.ts +84 -84
  120. package/src/morphoBlue/index.ts +274 -274
  121. package/src/portfolio/index.ts +598 -598
  122. package/src/savings/index.ts +43 -0
  123. package/src/savings/makerDsr/index.ts +54 -0
  124. package/src/savings/makerDsr/options.ts +9 -0
  125. package/src/savings/morphoVaults/index.ts +81 -0
  126. package/src/savings/morphoVaults/options.ts +123 -0
  127. package/src/savings/yearnVaults/index.ts +74 -0
  128. package/src/savings/yearnVaults/options.ts +30 -0
  129. package/src/services/priceService.ts +278 -278
  130. package/src/services/utils.ts +115 -115
  131. package/src/services/viem.ts +34 -34
  132. package/src/setup.ts +8 -8
  133. package/src/spark/index.ts +456 -456
  134. package/src/staking/eligibility.ts +53 -53
  135. package/src/staking/index.ts +1 -1
  136. package/src/staking/staking.ts +183 -183
  137. package/src/types/aave.ts +189 -189
  138. package/src/types/claiming.ts +114 -114
  139. package/src/types/common.ts +107 -107
  140. package/src/types/compound.ts +136 -136
  141. package/src/types/curveUsd.ts +123 -123
  142. package/src/types/euler.ts +175 -175
  143. package/src/types/fluid.ts +483 -483
  144. package/src/types/index.ts +15 -14
  145. package/src/types/liquity.ts +30 -30
  146. package/src/types/liquityV2.ts +126 -126
  147. package/src/types/llamaLend.ts +159 -159
  148. package/src/types/maker.ts +63 -63
  149. package/src/types/merit.ts +1 -1
  150. package/src/types/merkl.ts +70 -70
  151. package/src/types/morphoBlue.ts +200 -200
  152. package/src/types/portfolio.ts +60 -60
  153. package/src/types/savings/index.ts +18 -0
  154. package/src/types/savings/makerDsr.ts +13 -0
  155. package/src/types/savings/morphoVaults.ts +25 -0
  156. package/src/types/savings/yearnVaults.ts +14 -0
  157. package/src/types/spark.ts +133 -133
  158. package/src/umbrella/index.ts +69 -69
  159. package/src/umbrella/umbrellaUtils.ts +29 -29
@@ -1,23 +1,23 @@
1
- import { Client } from 'viem';
2
- import { assetAmountInEth, getAssetInfoByAddress } from '@defisaver/tokens';
3
- import { EthAddress, NetworkNumber } from '../types/common';
4
- import { CompV3ViewContractViem } from '../contracts';
5
- import { ClaimType } from '../types/claiming';
6
-
7
- export const getCompoundV3Rewards = async (provider: Client, network: NetworkNumber, user: EthAddress, market: any) => {
8
- const compV3View = CompV3ViewContractViem(provider, network);
9
- const rewards = await compV3View.read.getRewardsOwed([market, user]);
10
- if (!rewards || rewards.owed.toString() === '0' || getAssetInfoByAddress(rewards.token, network).symbol !== 'COMP') return [];
11
- return [{
12
- symbol: 'COMP',
13
- underlyingSymbol: 'COMP',
14
- tokenAddress: rewards.token,
15
- amount: assetAmountInEth(rewards.owed.toString() || 0, 'COMP'),
16
- walletAddress: user,
17
- label: 'Compound V3',
18
- claimType: ClaimType.COMPOUND_V3_COMP,
19
- additionalClaimFields: {
20
- marketAddress: market,
21
- },
22
- }];
1
+ import { Client } from 'viem';
2
+ import { assetAmountInEth, getAssetInfoByAddress } from '@defisaver/tokens';
3
+ import { EthAddress, NetworkNumber } from '../types/common';
4
+ import { CompV3ViewContractViem } from '../contracts';
5
+ import { ClaimType } from '../types/claiming';
6
+
7
+ export const getCompoundV3Rewards = async (provider: Client, network: NetworkNumber, user: EthAddress, market: any) => {
8
+ const compV3View = CompV3ViewContractViem(provider, network);
9
+ const rewards = await compV3View.read.getRewardsOwed([market, user]);
10
+ if (!rewards || rewards.owed.toString() === '0' || getAssetInfoByAddress(rewards.token, network).symbol !== 'COMP') return [];
11
+ return [{
12
+ symbol: 'COMP',
13
+ underlyingSymbol: 'COMP',
14
+ tokenAddress: rewards.token,
15
+ amount: assetAmountInEth(rewards.owed.toString() || 0, 'COMP'),
16
+ walletAddress: user,
17
+ label: 'Compound V3',
18
+ claimType: ClaimType.COMPOUND_V3_COMP,
19
+ additionalClaimFields: {
20
+ marketAddress: market,
21
+ },
22
+ }];
23
23
  };
@@ -1,61 +1,61 @@
1
- import { getAssetInfo } from '@defisaver/tokens';
2
- import Dec from 'decimal.js';
3
- import { getAddress } from 'viem';
4
- import { EthAddress } from '../types/common';
5
- import { ClaimType } from '../types/claiming';
6
- import { getEthAmountForDecimals } from '../services/utils';
7
-
8
- export const fetchEthenaAirdropReward = async (address: EthAddress) => {
9
- try {
10
- const checksumAddress = getAddress(address);
11
- const response = await fetch(`https://airdrop-data-ethena-s4.s3.us-west-2.amazonaws.com/${checksumAddress}/0x3d99219fbd49ace3f48d6ca1340e505ec1bdf27d1f8d0e15ec9f286cc9215fcd-${checksumAddress}.json`);
12
-
13
- if (!response.ok) {
14
- if (response.status === 403) {
15
- // This is also okay, means that there are no rewards for the address
16
- return;
17
- }
18
- throw new Error(`HTTP error! status: ${response.status}`);
19
- }
20
-
21
- return await response.json();
22
- } catch (error) {
23
- console.error('Error fetching Ethena airdrop rewards:', error);
24
- }
25
- };
26
-
27
- export const fetchEthenaAirdropRewards = async (walletAddresses: EthAddress[]): Promise<Record<string, any[]>> => {
28
- const apiDataPromises = walletAddresses.map(address => fetchEthenaAirdropReward(address));
29
- const apiDataArray = await Promise.all(apiDataPromises);
30
-
31
- const results: Record<string, any[]> = {};
32
- for (let i = 0; i < walletAddresses.length; i++) {
33
- const walletAddress = walletAddresses[i];
34
- const data = apiDataArray[i];
35
-
36
- if (!data || data.claimed) {
37
- continue;
38
- }
39
-
40
- const processedRewards = [];
41
- const assetInfo = getAssetInfo('sENA');
42
-
43
- const amount = getEthAmountForDecimals(data.events[0].awardAmount, assetInfo.decimals);
44
-
45
- if (new Dec(amount).gt('0')) {
46
- processedRewards.push({
47
- symbol: assetInfo.symbol,
48
- underlyingSymbol: assetInfo.symbol,
49
- amount,
50
- claimType: ClaimType.ETHENA_AIRDROP,
51
- tokenAddress: assetInfo.address,
52
- walletAddress,
53
- label: 'Ethena Airdrop',
54
- });
55
- }
56
-
57
- results[walletAddress.toLowerCase() as EthAddress] = processedRewards;
58
- }
59
-
60
- return results;
61
- };
1
+ import { getAssetInfo } from '@defisaver/tokens';
2
+ import Dec from 'decimal.js';
3
+ import { getAddress } from 'viem';
4
+ import { EthAddress } from '../types/common';
5
+ import { ClaimType } from '../types/claiming';
6
+ import { getEthAmountForDecimals } from '../services/utils';
7
+
8
+ export const fetchEthenaAirdropReward = async (address: EthAddress) => {
9
+ try {
10
+ const checksumAddress = getAddress(address);
11
+ const response = await fetch(`https://airdrop-data-ethena-s4.s3.us-west-2.amazonaws.com/${checksumAddress}/0x3d99219fbd49ace3f48d6ca1340e505ec1bdf27d1f8d0e15ec9f286cc9215fcd-${checksumAddress}.json`);
12
+
13
+ if (!response.ok) {
14
+ if (response.status === 403) {
15
+ // This is also okay, means that there are no rewards for the address
16
+ return;
17
+ }
18
+ throw new Error(`HTTP error! status: ${response.status}`);
19
+ }
20
+
21
+ return await response.json();
22
+ } catch (error) {
23
+ console.error('Error fetching Ethena airdrop rewards:', error);
24
+ }
25
+ };
26
+
27
+ export const fetchEthenaAirdropRewards = async (walletAddresses: EthAddress[]): Promise<Record<string, any[]>> => {
28
+ const apiDataPromises = walletAddresses.map(address => fetchEthenaAirdropReward(address));
29
+ const apiDataArray = await Promise.all(apiDataPromises);
30
+
31
+ const results: Record<string, any[]> = {};
32
+ for (let i = 0; i < walletAddresses.length; i++) {
33
+ const walletAddress = walletAddresses[i];
34
+ const data = apiDataArray[i];
35
+
36
+ if (!data || data.claimed) {
37
+ continue;
38
+ }
39
+
40
+ const processedRewards = [];
41
+ const assetInfo = getAssetInfo('sENA');
42
+
43
+ const amount = getEthAmountForDecimals(data.events[0].awardAmount, assetInfo.decimals);
44
+
45
+ if (new Dec(amount).gt('0')) {
46
+ processedRewards.push({
47
+ symbol: assetInfo.symbol,
48
+ underlyingSymbol: assetInfo.symbol,
49
+ amount,
50
+ claimType: ClaimType.ETHENA_AIRDROP,
51
+ tokenAddress: assetInfo.address,
52
+ walletAddress,
53
+ label: 'Ethena Airdrop',
54
+ });
55
+ }
56
+
57
+ results[walletAddress.toLowerCase() as EthAddress] = processedRewards;
58
+ }
59
+
60
+ return results;
61
+ };
@@ -1,13 +1,13 @@
1
- import * as aaveV3Claim from './aaveV3';
2
- import * as compV3Claim from './compV3';
3
- import * as kingV3Claim from './king';
4
- import * as morphoBlueClaim from './morphoBlue';
5
- import * as sparkClaim from './spark';
6
-
7
- export {
8
- aaveV3Claim,
9
- compV3Claim,
10
- kingV3Claim,
11
- morphoBlueClaim,
12
- sparkClaim,
1
+ import * as aaveV3Claim from './aaveV3';
2
+ import * as compV3Claim from './compV3';
3
+ import * as kingV3Claim from './king';
4
+ import * as morphoBlueClaim from './morphoBlue';
5
+ import * as sparkClaim from './spark';
6
+
7
+ export {
8
+ aaveV3Claim,
9
+ compV3Claim,
10
+ kingV3Claim,
11
+ morphoBlueClaim,
12
+ sparkClaim,
13
13
  };
@@ -1,66 +1,66 @@
1
- import Dec from 'decimal.js';
2
- import { assetAmountInEth } from '@defisaver/tokens';
3
- import { Client } from 'viem';
4
- import { UUPSViem } from '../contracts';
5
- import { EthAddress, HexString, NetworkNumber } from '../types/common';
6
- import { ClaimType } from '../types/claiming';
7
-
8
- export const fetchKingRewards = async (walletAddress: EthAddress) => {
9
- try {
10
- const res = await fetch(`https://fe.defisaver.com/api/etherfi/get-king-rewards/${walletAddress}`,
11
- { signal: AbortSignal.timeout(5000) });
12
-
13
- if (!res.ok) throw new Error(await res.text());
14
-
15
- return await res.json();
16
- } catch (err) {
17
- console.error('External API Error: Error fetching KING rewards:', err);
18
- return { Amount: '0', Root: '', Proofs: [] };
19
- }
20
- };
21
-
22
- export const getKingRewards = async (provider: Client, network: NetworkNumber, walletAddresses: EthAddress[]) => {
23
- // Fetch all API data in parallel (these are external API calls, can't be batched with multicall)
24
- const apiDataPromises = walletAddresses.map(address => fetchKingRewards(address));
25
- const apiDataArray = await Promise.all(apiDataPromises);
26
-
27
- // Batch all contract calls using multicall
28
- const contract = UUPSViem(provider, network);
29
- const cumulativePromises = walletAddresses.map(address => contract.read.cumulativeClaimed([address]),
30
- );
31
- const cumulativeResults = await Promise.all(cumulativePromises);
32
-
33
- // Process results
34
- const results: Record<string, any[]> = {};
35
-
36
- for (let i = 0; i < walletAddresses.length; i++) {
37
- const walletAddress = walletAddresses[i];
38
- const data = apiDataArray[i];
39
- const cumulative = cumulativeResults[i];
40
-
41
- const allRewardsAmount = assetAmountInEth(data.Amount, 'KING');
42
- const claimedAmount = assetAmountInEth(cumulative.toString(), 'KING');
43
- const amountToClaim = new Dec(allRewardsAmount).sub(claimedAmount);
44
-
45
- if (amountToClaim.lessThanOrEqualTo('0')) {
46
- results[walletAddress.toLowerCase() as EthAddress] = [];
47
- } else {
48
- results[walletAddress.toLowerCase() as EthAddress] = [{
49
- symbol: 'KING',
50
- underlyingSymbol: 'KING',
51
- tokenAddress: '0x8F08B70456eb22f6109F57b8fafE862ED28E6040',
52
- amount: amountToClaim.toString(),
53
- walletAddress,
54
- label: 'weETH',
55
- claimType: ClaimType.KING_REWARDS,
56
- additionalClaimFields: {
57
- allRewardsAmount,
58
- merkleRoot: data.Root,
59
- merkleProofs: data.Proofs,
60
- },
61
- }];
62
- }
63
- }
64
-
65
- return results;
66
- };
1
+ import Dec from 'decimal.js';
2
+ import { assetAmountInEth } from '@defisaver/tokens';
3
+ import { Client } from 'viem';
4
+ import { UUPSViem } from '../contracts';
5
+ import { EthAddress, HexString, NetworkNumber } from '../types/common';
6
+ import { ClaimType } from '../types/claiming';
7
+
8
+ export const fetchKingRewards = async (walletAddress: EthAddress) => {
9
+ try {
10
+ const res = await fetch(`https://fe.defisaver.com/api/etherfi/get-king-rewards/${walletAddress}`,
11
+ { signal: AbortSignal.timeout(5000) });
12
+
13
+ if (!res.ok) throw new Error(await res.text());
14
+
15
+ return await res.json();
16
+ } catch (err) {
17
+ console.error('External API Error: Error fetching KING rewards:', err);
18
+ return { Amount: '0', Root: '', Proofs: [] };
19
+ }
20
+ };
21
+
22
+ export const getKingRewards = async (provider: Client, network: NetworkNumber, walletAddresses: EthAddress[]) => {
23
+ // Fetch all API data in parallel (these are external API calls, can't be batched with multicall)
24
+ const apiDataPromises = walletAddresses.map(address => fetchKingRewards(address));
25
+ const apiDataArray = await Promise.all(apiDataPromises);
26
+
27
+ // Batch all contract calls using multicall
28
+ const contract = UUPSViem(provider, network);
29
+ const cumulativePromises = walletAddresses.map(address => contract.read.cumulativeClaimed([address]),
30
+ );
31
+ const cumulativeResults = await Promise.all(cumulativePromises);
32
+
33
+ // Process results
34
+ const results: Record<string, any[]> = {};
35
+
36
+ for (let i = 0; i < walletAddresses.length; i++) {
37
+ const walletAddress = walletAddresses[i];
38
+ const data = apiDataArray[i];
39
+ const cumulative = cumulativeResults[i];
40
+
41
+ const allRewardsAmount = assetAmountInEth(data.Amount, 'KING');
42
+ const claimedAmount = assetAmountInEth(cumulative.toString(), 'KING');
43
+ const amountToClaim = new Dec(allRewardsAmount).sub(claimedAmount);
44
+
45
+ if (amountToClaim.lessThanOrEqualTo('0')) {
46
+ results[walletAddress.toLowerCase() as EthAddress] = [];
47
+ } else {
48
+ results[walletAddress.toLowerCase() as EthAddress] = [{
49
+ symbol: 'KING',
50
+ underlyingSymbol: 'KING',
51
+ tokenAddress: '0x8F08B70456eb22f6109F57b8fafE862ED28E6040',
52
+ amount: amountToClaim.toString(),
53
+ walletAddress,
54
+ label: 'weETH',
55
+ claimType: ClaimType.KING_REWARDS,
56
+ additionalClaimFields: {
57
+ allRewardsAmount,
58
+ merkleRoot: data.Root,
59
+ merkleProofs: data.Proofs,
60
+ },
61
+ }];
62
+ }
63
+ }
64
+
65
+ return results;
66
+ };
@@ -1,119 +1,119 @@
1
- import { assetAmountInEth, getAssetInfoByAddress } from '@defisaver/tokens';
2
- import { Client } from 'viem';
3
- import Dec from 'decimal.js';
4
- import { ClaimableToken, ClaimType } from '../types/claiming';
5
- import { EthAddress, NetworkNumber } from '../types/common';
6
- import { createViemContractFromConfigFunc } from '../contracts';
7
- import { getMorphoUnderlyingSymbol } from '../helpers/morphoBlueHelpers';
8
-
9
- const MORPHO_ALLOWED_CONTRACTS = [
10
- '0x330eefa8a787552DC5cAd3C3cA644844B1E61Ddb',
11
- '0x678dDC1d07eaa166521325394cDEb1E4c086DF43',
12
- '0x2efd4625d0c149ebadf118ec5446c6de24d916a4',
13
- ];
14
-
15
- const MORPHO_ALLOWED_TOKENS = [
16
- 'MORPHO',
17
- 'MORPHO Legacy',
18
- ];
19
-
20
-
21
- export const getMorphoBlueRewardsInfo = async (address: EthAddress) => {
22
- if (!address) return { claimable: '0' };
23
-
24
- try {
25
- const res = await fetch(`https://rewards.morpho.org/v1/users/${address}/distributions`,
26
- { signal: AbortSignal.timeout(3000) });
27
-
28
- if (!res.ok) throw new Error(await res.text());
29
- return await res.json();
30
- } catch (error) {
31
- console.error('External API Failure: Morpho Merit', error);
32
- return { claimable: '0' };
33
- }
34
- };
35
-
36
- export const fetchMorphoBlueRewards = async (
37
- provider: Client,
38
- network: NetworkNumber,
39
- walletAddresses: EthAddress[],
40
- ): Promise<Record<string, ClaimableToken[]>> => {
41
- // Fetch all API data in parallel (these are external API calls, can't be batched with multicall)
42
- const apiDataPromises = walletAddresses.map(address => getMorphoBlueRewardsInfo(address));
43
- const apiDataArray = await Promise.all(apiDataPromises);
44
-
45
- // Process API data to get claimable tokens for each wallet
46
- const allClaimableTokens: Array<{ walletAddress: EthAddress; tokens: ClaimableToken[] }> = [];
47
- const contractCallsData: Array<{ walletAddress: EthAddress; tokenAddress: EthAddress; distributor: EthAddress }> = [];
48
-
49
- for (let i = 0; i < walletAddresses.length; i++) {
50
- const walletAddress = walletAddresses[i];
51
- const data = apiDataArray[i];
52
-
53
- const claimableTokens = data?.data?.reduce((acc: ClaimableToken[], reward: any) => {
54
- const token = getAssetInfoByAddress(reward.asset.address);
55
- if (!MORPHO_ALLOWED_CONTRACTS.includes(reward?.distributor?.address) || !MORPHO_ALLOWED_TOKENS.includes(token.symbol)) {
56
- return acc;
57
- }
58
-
59
- // Store contract call data for batching
60
- contractCallsData.push({
61
- walletAddress,
62
- tokenAddress: reward.asset.address,
63
- distributor: reward?.distributor?.address,
64
- });
65
-
66
- return [
67
- ...acc,
68
- {
69
- symbol: token.symbol,
70
- underlyingSymbol: getMorphoUnderlyingSymbol(token.symbol),
71
- tokenAddress: reward.asset.address,
72
- amount: assetAmountInEth(reward.claimable, token.symbol),
73
- walletAddress,
74
- label: token.symbol,
75
- claimType: ClaimType.MORPHO,
76
- additionalClaimFields: {
77
- originalAmount: reward.claimable,
78
- distributor: reward?.distributor?.address,
79
- merkleProofs: reward?.proof,
80
- isLegacy: token.symbol === 'MORPHO Legacy',
81
- txData: reward?.tx_data,
82
- },
83
- }];
84
- }, []) || [];
85
-
86
- allClaimableTokens.push({ walletAddress, tokens: claimableTokens });
87
- }
88
-
89
- // Batch all contract calls using multicall
90
- const contractPromises = contractCallsData.map(({ walletAddress, tokenAddress, distributor }) => {
91
- const distributorContract = createViemContractFromConfigFunc('MorphoDistributor', distributor)(provider, network);
92
- return distributorContract.read.claimed([walletAddress, tokenAddress]);
93
- });
94
- const contractResults = await Promise.all(contractPromises);
95
-
96
- // Process results
97
- const results: Record<string, ClaimableToken[]> = {};
98
- let contractCallIndex = 0;
99
-
100
- for (const { walletAddress, tokens } of allClaimableTokens) {
101
- const updatedTokens: ClaimableToken[] = [];
102
-
103
- for (let i = 0; i < tokens.length; i++) {
104
- const claimableToken = tokens[i];
105
- const claimed = assetAmountInEth(contractResults[contractCallIndex].toString(), claimableToken.underlyingSymbol);
106
- contractCallIndex++;
107
-
108
- const updatedToken = { ...claimableToken };
109
- updatedToken.amount = new Dec(claimableToken.amount).sub(claimed).toString();
110
- updatedTokens.push(updatedToken);
111
- }
112
-
113
- results[walletAddress.toLowerCase() as EthAddress] = updatedTokens.filter(
114
- (claimableToken) => new Dec(claimableToken.amount).gt(0),
115
- );
116
- }
117
-
118
- return results;
1
+ import { assetAmountInEth, getAssetInfoByAddress } from '@defisaver/tokens';
2
+ import { Client } from 'viem';
3
+ import Dec from 'decimal.js';
4
+ import { ClaimableToken, ClaimType } from '../types/claiming';
5
+ import { EthAddress, NetworkNumber } from '../types/common';
6
+ import { createViemContractFromConfigFunc } from '../contracts';
7
+ import { getMorphoUnderlyingSymbol } from '../helpers/morphoBlueHelpers';
8
+
9
+ const MORPHO_ALLOWED_CONTRACTS = [
10
+ '0x330eefa8a787552DC5cAd3C3cA644844B1E61Ddb',
11
+ '0x678dDC1d07eaa166521325394cDEb1E4c086DF43',
12
+ '0x2efd4625d0c149ebadf118ec5446c6de24d916a4',
13
+ ];
14
+
15
+ const MORPHO_ALLOWED_TOKENS = [
16
+ 'MORPHO',
17
+ 'MORPHO Legacy',
18
+ ];
19
+
20
+
21
+ export const getMorphoBlueRewardsInfo = async (address: EthAddress) => {
22
+ if (!address) return { claimable: '0' };
23
+
24
+ try {
25
+ const res = await fetch(`https://rewards.morpho.org/v1/users/${address}/distributions`,
26
+ { signal: AbortSignal.timeout(3000) });
27
+
28
+ if (!res.ok) throw new Error(await res.text());
29
+ return await res.json();
30
+ } catch (error) {
31
+ console.error('External API Failure: Morpho Merit', error);
32
+ return { claimable: '0' };
33
+ }
34
+ };
35
+
36
+ export const fetchMorphoBlueRewards = async (
37
+ provider: Client,
38
+ network: NetworkNumber,
39
+ walletAddresses: EthAddress[],
40
+ ): Promise<Record<string, ClaimableToken[]>> => {
41
+ // Fetch all API data in parallel (these are external API calls, can't be batched with multicall)
42
+ const apiDataPromises = walletAddresses.map(address => getMorphoBlueRewardsInfo(address));
43
+ const apiDataArray = await Promise.all(apiDataPromises);
44
+
45
+ // Process API data to get claimable tokens for each wallet
46
+ const allClaimableTokens: Array<{ walletAddress: EthAddress; tokens: ClaimableToken[] }> = [];
47
+ const contractCallsData: Array<{ walletAddress: EthAddress; tokenAddress: EthAddress; distributor: EthAddress }> = [];
48
+
49
+ for (let i = 0; i < walletAddresses.length; i++) {
50
+ const walletAddress = walletAddresses[i];
51
+ const data = apiDataArray[i];
52
+
53
+ const claimableTokens = data?.data?.reduce((acc: ClaimableToken[], reward: any) => {
54
+ const token = getAssetInfoByAddress(reward.asset.address);
55
+ if (!MORPHO_ALLOWED_CONTRACTS.includes(reward?.distributor?.address) || !MORPHO_ALLOWED_TOKENS.includes(token.symbol)) {
56
+ return acc;
57
+ }
58
+
59
+ // Store contract call data for batching
60
+ contractCallsData.push({
61
+ walletAddress,
62
+ tokenAddress: reward.asset.address,
63
+ distributor: reward?.distributor?.address,
64
+ });
65
+
66
+ return [
67
+ ...acc,
68
+ {
69
+ symbol: token.symbol,
70
+ underlyingSymbol: getMorphoUnderlyingSymbol(token.symbol),
71
+ tokenAddress: reward.asset.address,
72
+ amount: assetAmountInEth(reward.claimable, token.symbol),
73
+ walletAddress,
74
+ label: token.symbol,
75
+ claimType: ClaimType.MORPHO,
76
+ additionalClaimFields: {
77
+ originalAmount: reward.claimable,
78
+ distributor: reward?.distributor?.address,
79
+ merkleProofs: reward?.proof,
80
+ isLegacy: token.symbol === 'MORPHO Legacy',
81
+ txData: reward?.tx_data,
82
+ },
83
+ }];
84
+ }, []) || [];
85
+
86
+ allClaimableTokens.push({ walletAddress, tokens: claimableTokens });
87
+ }
88
+
89
+ // Batch all contract calls using multicall
90
+ const contractPromises = contractCallsData.map(({ walletAddress, tokenAddress, distributor }) => {
91
+ const distributorContract = createViemContractFromConfigFunc('MorphoDistributor', distributor)(provider, network);
92
+ return distributorContract.read.claimed([walletAddress, tokenAddress]);
93
+ });
94
+ const contractResults = await Promise.all(contractPromises);
95
+
96
+ // Process results
97
+ const results: Record<string, ClaimableToken[]> = {};
98
+ let contractCallIndex = 0;
99
+
100
+ for (const { walletAddress, tokens } of allClaimableTokens) {
101
+ const updatedTokens: ClaimableToken[] = [];
102
+
103
+ for (let i = 0; i < tokens.length; i++) {
104
+ const claimableToken = tokens[i];
105
+ const claimed = assetAmountInEth(contractResults[contractCallIndex].toString(), claimableToken.underlyingSymbol);
106
+ contractCallIndex++;
107
+
108
+ const updatedToken = { ...claimableToken };
109
+ updatedToken.amount = new Dec(claimableToken.amount).sub(claimed).toString();
110
+ updatedTokens.push(updatedToken);
111
+ }
112
+
113
+ results[walletAddress.toLowerCase() as EthAddress] = updatedTokens.filter(
114
+ (claimableToken) => new Dec(claimableToken.amount).gt(0),
115
+ );
116
+ }
117
+
118
+ return results;
119
119
  };