Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: handle new morpho token and wrapper #4050

Merged
merged 4 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions blockchain/abi/erc20-proxy-actions.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,34 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "oldToken",
"type": "address"
},
{
"internalType": "address",
"name": "newToken",
"type": "address"
},
{
"internalType": "address",
"name": "wrapper",
"type": "address"
},
{
"internalType": "uint256",
"name": "value",
"type": "uint256"
}
],
"name": "approveAndWrap",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
Comment on lines +25 to +52
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Wrapper contract integration not found

No implementation of the wrapper contract was detected in the codebase. Please ensure that the wrapper contract is properly implemented and integrated.

🔗 Analysis chain

Implementation looks good with security considerations.

The approveAndWrap function ABI is well-structured for the MORPHO token migration process. The parameter ordering and types are appropriate for the intended functionality.

Let's verify the wrapper contract integration:

Security Considerations:

  1. Ensure the wrapper contract is audited and properly verified on Etherscan
  2. Verify that the wrapper contract follows the check-effects-interactions pattern
  3. Consider adding explicit approval checks before wrapping
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the wrapper contract implementation and integration
# Expected: Find wrapper contract implementation and any direct interactions with it

# Search for wrapper contract implementation
ast-grep --pattern 'contract $_ is $_* {
  $$$
  function wrap($$$) {
    $$$
  }
  $$$
}'

# Search for direct wrapper contract interactions
rg -A 5 'wrapper.*wrap'

Length of output: 475

{
"inputs": [
{
Expand Down
65 changes: 65 additions & 0 deletions blockchain/better-calls/erc20.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,3 +200,68 @@ export async function encodeTransferToOwnerProxyAction({
value: '0',
}
}

/**
* Encodes a transaction to approve and wrap an ERC20 token using OpenZeppelin's ERC20Wrapper pattern.
* This function prepares a transaction that will:
* 1. Approve the wrapper contract to spend the old token
* 2. Deposit the old token into the wrapper contract ( from proxy)
* 3.Send the new wrapped token to the owner
*
* The wrapper contract must implement the IERC20Wrapper interface which includes:
* - depositFor(address account, uint256 value)
* - withdrawTo(address account, uint256 value)
*
* @param {object} params - The parameters object
* @param {NetworkIds} params.networkId - The network ID where the transaction will be executed
* @param {string} params.oldToken - The symbol of the token to be wrapped (underlying token)
* @param {string} params.newToken - The symbol of the wrapped token to receive
* @param {string} params.wrapper - The address of the ERC20Wrapper contract
* @param {BigNumber} params.amount - The amount of tokens to wrap
* @returns {Promise<OmniTxData>} The encoded transaction data ready to be executed
* @throws Will throw if the contracts or tokens don't exist in the network configuration
* @throws Will throw if the token addresses cannot be resolved
*/
export async function encodeApproveAndWrapProxyAction({
networkId,
oldToken,
newToken,
wrapper,
amount,
}: {
networkId: NetworkIds
oldToken: string
newToken: string
wrapper: string
amount: BigNumber
}): Promise<OmniTxData> {
const contracts = getNetworkContracts(networkId)

ensureContractsExist(networkId, contracts, ['erc20ProxyActions'])
ensureGivenTokensExist(networkId, contracts, [oldToken, newToken])

Comment on lines +225 to +242
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add essential input validation.

The function should validate the wrapper address format and verify that required contracts exist.

 export async function encodeApproveAndWrapProxyAction({
   networkId,
   oldToken,
   newToken,
   wrapper,
   amount,
 }: {
   networkId: NetworkIds
   oldToken: string
   newToken: string
   wrapper: string
   amount: BigNumber
 }): Promise<OmniTxData> {
+  if (!ethers.utils.isAddress(wrapper)) {
+    throw new Error('Invalid wrapper address format')
+  }
+
   const contracts = getNetworkContracts(networkId)
 
   ensureContractsExist(networkId, contracts, ['erc20ProxyActions'])
   ensureGivenTokensExist(networkId, contracts, [oldToken, newToken])
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function encodeApproveAndWrapProxyAction({
networkId,
oldToken,
newToken,
wrapper,
amount,
}: {
networkId: NetworkIds
oldToken: string
newToken: string
wrapper: string
amount: BigNumber
}): Promise<OmniTxData> {
const contracts = getNetworkContracts(networkId)
ensureContractsExist(networkId, contracts, ['erc20ProxyActions'])
ensureGivenTokensExist(networkId, contracts, [oldToken, newToken])
export async function encodeApproveAndWrapProxyAction({
networkId,
oldToken,
newToken,
wrapper,
amount,
}: {
networkId: NetworkIds
oldToken: string
newToken: string
wrapper: string
amount: BigNumber
}): Promise<OmniTxData> {
if (!ethers.utils.isAddress(wrapper)) {
throw new Error('Invalid wrapper address format')
}
const contracts = getNetworkContracts(networkId)
ensureContractsExist(networkId, contracts, ['erc20ProxyActions'])
ensureGivenTokensExist(networkId, contracts, [oldToken, newToken])

const { erc20ProxyActions, tokens } = contracts

const oldTokenAddress = tokens[oldToken].address
const newTokenAddress = tokens[newToken].address

const proxyActionContract = Erc20ProxyActions__factory.connect(
erc20ProxyActions.address,
getRpcProvider(networkId),
)

const amountInWei = amountToWei(amount, oldToken).toFixed()

const encodeFunctionData = proxyActionContract.interface.encodeFunctionData('approveAndWrap', [
oldTokenAddress,
newTokenAddress,
wrapper,
ethers.BigNumber.from(amountInWei),
])

return {
to: erc20ProxyActions.address,
data: encodeFunctionData,
value: '0',
}
}
9 changes: 9 additions & 0 deletions blockchain/token-metadata-list/token-configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -997,6 +997,15 @@ export const tokenConfigs: TokenConfig[] = [
iconCircle: morpho_circle_color,
tags: [],
},
{
symbol: 'MORPHO_LEGACY',
precision: 18,
digits: 5,
name: 'Legacy Morpho Blue',
icon: morpho_circle_color,
iconCircle: morpho_circle_color,
tags: [],
},
{
symbol: 'RBN',
precision: 18,
Expand Down
1 change: 1 addition & 0 deletions blockchain/tokens/mainnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export const tokensMainnet = {
LUSD: contractDesc(erc20, mainnet.common.LUSD),
MKR: contractDesc(erc20, mainnet.maker.common.McdGov),
MORPHO: contractDesc(erc20, mainnet.common.MORPHO),
MORPHO_LEGACY: contractDesc(erc20, mainnet.common.MORPHO_LEGACY),
RENBTC: contractDesc(erc20, mainnet.common.RENBTC),
RETH: contractDesc(erc20, mainnet.common.RETH),
RSETH: contractDesc(erc20, mainnet.common.RSETH),
Expand Down
1 change: 1 addition & 0 deletions features/notices/VaultsNoticesView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ export function VaultLiquidatedNotice({
})}
</Text>
<ReclaimCollateralButton {...{ token, id, amount: unlockedCollateral }} />
{console.debug('ReclaimCollateralButton props:', { token, id, amount: unlockedCollateral })}
</>
) : (
fallbackSubheader
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
import { networkIdToLibraryNetwork } from 'actions/aave-like/helpers'
import type BigNumber from 'bignumber.js'
import { encodeClaimAllRewards, getAllUserRewards } from 'blockchain/better-calls/aave-like-rewards'
import { encodeTransferToOwnerProxyAction, tokenBalance } from 'blockchain/better-calls/erc20'
import {
encodeApproveAndWrapProxyAction,
encodeTransferToOwnerProxyAction,
tokenBalance,
} from 'blockchain/better-calls/erc20'
import { NetworkIds } from 'blockchain/networks'
import { tokenPriceStore } from 'blockchain/prices.constants'
import { getTokenByAddress } from 'blockchain/tokensMetadata'
Expand All @@ -17,7 +21,13 @@
import { OmniDetailsSectionContentRewardsLoadingState } from './OmniDetailsSectionContentRewardsLoadingState'
import { OmniRewardsClaims } from './OmniRewardsClaims'

const claimableErc20: Record<NetworkIds, string[]> = {
interface OmniDetailSectionRewardsClaimsInternalProps {
isEligibleForErc20Claims: boolean
isEligibleForProtocolRewards: boolean
isEligibleForMorphoLegacy: boolean
}

const claimableErc20ByNetwork: Record<NetworkIds, string[]> = {
[NetworkIds.MAINNET]: ['ENA', 'SENA'],
[NetworkIds.OPTIMISMMAINNET]: [],
[NetworkIds.ARBITRUMMAINNET]: [],
Expand All @@ -32,13 +42,21 @@
[NetworkIds.OPTIMISMGOERLI]: [],
}

const morphoLegacyByNetwork: Partial<Record<NetworkIds, string>> = {
[NetworkIds.MAINNET]: 'MORPHO_LEGACY',
}

type Claim = {
token: string
claimable: BigNumber
tx: OmniTxData
}

const OmniDetailSectionRewardsClaimsInternal: FC = () => {
const OmniDetailSectionRewardsClaimsInternal: FC<OmniDetailSectionRewardsClaimsInternalProps> = ({
isEligibleForErc20Claims,
isEligibleForProtocolRewards,
isEligibleForMorphoLegacy,
}) => {
const {
environment: { dpmProxy, networkId, protocol, quoteAddress },
} = useOmniGeneralContext()
Expand All @@ -48,9 +66,9 @@
}, [])

useEffect(() => {
if (dpmProxy) {
// Existing ERC20 claims logic
claimableErc20[networkId].forEach((token) => {
if (!dpmProxy) return
if (isEligibleForErc20Claims) {
claimableErc20ByNetwork[networkId].forEach((token) => {
tokenBalance({ token, account: dpmProxy, networkId: networkId })
.then((balance) => {
if (balance.gt(zero)) {
Expand All @@ -72,64 +90,97 @@
console.error(`Error fetching token balance for ${token}: ${error}`)
})
})

// New Aave and Spark rewards check
if ([LendingProtocol.AaveV3, LendingProtocol.SparkV3].includes(protocol)) {
let rewardsControllerAddress: string | undefined
let poolDataProviderAddress: string | undefined
}
if (isEligibleForMorphoLegacy) {
const morphoLegacyToken = morphoLegacyByNetwork[networkId]
console.log('morphoLegacyToken', morphoLegacyToken)

Check failure on line 96 in features/omni-kit/components/details-section/OmniDetailSectionRewardsClaims.tsx

View workflow job for this annotation

GitHub Actions / Linter

Unexpected console statement

Check failure on line 96 in features/omni-kit/components/details-section/OmniDetailSectionRewardsClaims.tsx

View workflow job for this annotation

GitHub Actions / Linter

Unexpected console statement
if (morphoLegacyToken) {
console.log('morphoLegacyToken', morphoLegacyToken)

Check failure on line 98 in features/omni-kit/components/details-section/OmniDetailSectionRewardsClaims.tsx

View workflow job for this annotation

GitHub Actions / Linter

Unexpected console statement

Check failure on line 98 in features/omni-kit/components/details-section/OmniDetailSectionRewardsClaims.tsx

View workflow job for this annotation

GitHub Actions / Linter

Unexpected console statement
const network = networkIdToLibraryNetwork(networkId)
if (
protocol === LendingProtocol.AaveV3 &&
network !== Network.HARDHAT &&
network !== Network.LOCAL &&
network !== Network.TENDERLY
) {
rewardsControllerAddress = ADDRESSES[network].aave.v3.RewardsController
poolDataProviderAddress = ADDRESSES[network].aave.v3.PoolDataProvider
} else if (
protocol === LendingProtocol.SparkV3 &&
network !== Network.HARDHAT &&
network !== Network.LOCAL &&
network !== Network.TENDERLY
) {
rewardsControllerAddress = ADDRESSES[network].spark.RewardsController
poolDataProviderAddress = ADDRESSES[network].spark.PoolDataProvider
} else {
console.warn(`Unsupported protocol or network for rewards: ${protocol} on ${network}`)
throw new Error(`Unsupported protocol or network for rewards: ${protocol} on ${network}`)
console.log('network', network)

Check failure on line 100 in features/omni-kit/components/details-section/OmniDetailSectionRewardsClaims.tsx

View workflow job for this annotation

GitHub Actions / Linter

Unexpected console statement

Check failure on line 100 in features/omni-kit/components/details-section/OmniDetailSectionRewardsClaims.tsx

View workflow job for this annotation

GitHub Actions / Linter

Unexpected console statement
if (network === Network.MAINNET) {
tokenBalance({ token: morphoLegacyToken, account: dpmProxy, networkId })
.then((balance) => {
console.log('balance mmm', balance)

Check failure on line 104 in features/omni-kit/components/details-section/OmniDetailSectionRewardsClaims.tsx

View workflow job for this annotation

GitHub Actions / Linter

Unexpected console statement

Check failure on line 104 in features/omni-kit/components/details-section/OmniDetailSectionRewardsClaims.tsx

View workflow job for this annotation

GitHub Actions / Linter

Unexpected console statement
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove debugging console.log statements

The console.log statements at lines 96, 98, 100, and 104 are likely meant for debugging purposes and should be removed to keep the production code clean and to pass the linter checks.

Apply this diff to remove the unnecessary console.log statements:

96,98,100,104
-          console.log('morphoLegacyToken', morphoLegacyToken)
-            console.log('morphoLegacyToken', morphoLegacyToken)
-            console.log('network', network)
-                  console.log('balance mmm', balance)

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 GitHub Check: Linter

[failure] 96-96:
Unexpected console statement


[failure] 98-98:
Unexpected console statement


[failure] 100-100:
Unexpected console statement


[failure] 104-104:
Unexpected console statement

🪛 eslint

[error] 96-96: Unexpected console statement.

(no-console)


[error] 98-98: Unexpected console statement.

(no-console)


[error] 100-100: Unexpected console statement.

(no-console)


[error] 104-104: Unexpected console statement.

(no-console)

if (balance.gt(zero)) {
encodeApproveAndWrapProxyAction({
oldToken: morphoLegacyToken,
newToken: 'MORPHO',
wrapper: ADDRESSES[network].morphoblue.Wrapper,
amount: balance,
networkId,
})
.then((tx) => {
dispatchClaim({ token: 'MORPHO', claimable: balance, tx })
})
.catch((error) => {
console.error(
`Error encoding approve and wrap action for MORPHO_LEGACY: ${error}`,
)
})
}
})
.catch((error) => {
console.error(`Error fetching MORPHO_LEGACY balance: ${error}`)
})
}
}
}
if (isEligibleForProtocolRewards) {
let rewardsControllerAddress: string | undefined
let poolDataProviderAddress: string | undefined
const network = networkIdToLibraryNetwork(networkId)
if (
protocol === LendingProtocol.AaveV3 &&
network !== Network.HARDHAT &&
network !== Network.LOCAL &&
network !== Network.TENDERLY
) {
rewardsControllerAddress = ADDRESSES[network].aave.v3.RewardsController
poolDataProviderAddress = ADDRESSES[network].aave.v3.PoolDataProvider
} else if (
protocol === LendingProtocol.SparkV3 &&
network !== Network.HARDHAT &&
network !== Network.LOCAL &&
network !== Network.TENDERLY
) {
rewardsControllerAddress = ADDRESSES[network].spark.RewardsController
poolDataProviderAddress = ADDRESSES[network].spark.PoolDataProvider
} else {
console.warn(`Unsupported protocol or network for rewards: ${protocol} on ${network}`)
throw new Error(`Unsupported protocol or network for rewards: ${protocol} on ${network}`)
}

getAllUserRewards({
networkId,
token: quoteAddress,
account: dpmProxy,
rewardsController: rewardsControllerAddress as string,
poolDataProvider: poolDataProviderAddress as string,
})
.then(async ({ rewardsList, unclaimedAmounts, assets }) => {
if (unclaimedAmounts.some((amount) => amount.gt(zero))) {
const tx = encodeClaimAllRewards({
networkId,
assets: assets as string[],
dpmAccount: dpmProxy,
rewardsController: rewardsControllerAddress as string,
})
getAllUserRewards({
networkId,
token: quoteAddress,
account: dpmProxy,
rewardsController: rewardsControllerAddress as string,
poolDataProvider: poolDataProviderAddress as string,
})
.then(async ({ rewardsList, unclaimedAmounts, assets }) => {
if (unclaimedAmounts.some((amount) => amount.gt(zero))) {
const tx = encodeClaimAllRewards({
networkId,
assets: assets as string[],
dpmAccount: dpmProxy,
rewardsController: rewardsControllerAddress as string,
})

rewardsList.forEach((token, index) => {
if (unclaimedAmounts[index].gt(zero)) {
dispatchClaim({
token: getTokenByAddress(token, networkId).symbol,
claimable: unclaimedAmounts[index],
tx,
})
}
})
}
})
.catch((error) => {
console.error(`Error fetching ${protocol} rewards:`, error)
})
}
rewardsList.forEach((token, index) => {
if (unclaimedAmounts[index].gt(zero)) {
dispatchClaim({
token: getTokenByAddress(token, networkId).symbol,
claimable: unclaimedAmounts[index],
tx,
})
}
})
}
})
.catch((error) => {
console.error(`Error fetching ${protocol} rewards:`, error)
})
Comment on lines +125 to +179
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve protocol rewards handling with early validation and proper error handling

The protocol rewards handling could be improved with early validation and proper error handling.

Consider this implementation:

 if (isEligibleForProtocolRewards) {
+  const network = networkIdToLibraryNetwork(networkId)
+  if ([Network.HARDHAT, Network.LOCAL, Network.TENDERLY].includes(network)) {
+    logger.warn(`Protocol rewards not supported on network: ${network}`)
+    return
+  }
+
   let rewardsControllerAddress: string | undefined
   let poolDataProviderAddress: string | undefined
-  const network = networkIdToLibraryNetwork(networkId)
-  if (
-    protocol === LendingProtocol.AaveV3 &&
-    network !== Network.HARDHAT &&
-    network !== Network.LOCAL &&
-    network !== Network.TENDERLY
-  ) {
-    rewardsControllerAddress = ADDRESSES[network].aave.v3.RewardsController
-    poolDataProviderAddress = ADDRESSES[network].aave.v3.PoolDataProvider
-  } else if (
-    protocol === LendingProtocol.SparkV3 &&
-    network !== Network.HARDHAT &&
-    network !== Network.LOCAL &&
-    network !== Network.TENDERLY
-  ) {
-    rewardsControllerAddress = ADDRESSES[network].spark.RewardsController
-    poolDataProviderAddress = ADDRESSES[network].spark.PoolDataProvider
-  } else {
-    console.warn(`Unsupported protocol or network for rewards: ${protocol} on ${network}`)
+
+  switch (protocol) {
+    case LendingProtocol.AaveV3:
+      rewardsControllerAddress = ADDRESSES[network].aave.v3.RewardsController
+      poolDataProviderAddress = ADDRESSES[network].aave.v3.PoolDataProvider
+      break
+    case LendingProtocol.SparkV3:
+      rewardsControllerAddress = ADDRESSES[network].spark.RewardsController
+      poolDataProviderAddress = ADDRESSES[network].spark.PoolDataProvider
+      break
+    default:
+      logger.warn(`Unsupported protocol for rewards: ${protocol}`)
+      return
   }
+
+  if (!rewardsControllerAddress || !poolDataProviderAddress) {
+    logger.error(`Missing contract addresses for protocol ${protocol} on network ${network}`)
     throw new Error(`Unsupported protocol or network for rewards: ${protocol} on ${network}`)
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (isEligibleForProtocolRewards) {
let rewardsControllerAddress: string | undefined
let poolDataProviderAddress: string | undefined
const network = networkIdToLibraryNetwork(networkId)
if (
protocol === LendingProtocol.AaveV3 &&
network !== Network.HARDHAT &&
network !== Network.LOCAL &&
network !== Network.TENDERLY
) {
rewardsControllerAddress = ADDRESSES[network].aave.v3.RewardsController
poolDataProviderAddress = ADDRESSES[network].aave.v3.PoolDataProvider
} else if (
protocol === LendingProtocol.SparkV3 &&
network !== Network.HARDHAT &&
network !== Network.LOCAL &&
network !== Network.TENDERLY
) {
rewardsControllerAddress = ADDRESSES[network].spark.RewardsController
poolDataProviderAddress = ADDRESSES[network].spark.PoolDataProvider
} else {
console.warn(`Unsupported protocol or network for rewards: ${protocol} on ${network}`)
throw new Error(`Unsupported protocol or network for rewards: ${protocol} on ${network}`)
}
getAllUserRewards({
networkId,
token: quoteAddress,
account: dpmProxy,
rewardsController: rewardsControllerAddress as string,
poolDataProvider: poolDataProviderAddress as string,
})
.then(async ({ rewardsList, unclaimedAmounts, assets }) => {
if (unclaimedAmounts.some((amount) => amount.gt(zero))) {
const tx = encodeClaimAllRewards({
networkId,
assets: assets as string[],
dpmAccount: dpmProxy,
rewardsController: rewardsControllerAddress as string,
})
getAllUserRewards({
networkId,
token: quoteAddress,
account: dpmProxy,
rewardsController: rewardsControllerAddress as string,
poolDataProvider: poolDataProviderAddress as string,
})
.then(async ({ rewardsList, unclaimedAmounts, assets }) => {
if (unclaimedAmounts.some((amount) => amount.gt(zero))) {
const tx = encodeClaimAllRewards({
networkId,
assets: assets as string[],
dpmAccount: dpmProxy,
rewardsController: rewardsControllerAddress as string,
})
rewardsList.forEach((token, index) => {
if (unclaimedAmounts[index].gt(zero)) {
dispatchClaim({
token: getTokenByAddress(token, networkId).symbol,
claimable: unclaimedAmounts[index],
tx,
})
}
})
}
})
.catch((error) => {
console.error(`Error fetching ${protocol} rewards:`, error)
})
}
rewardsList.forEach((token, index) => {
if (unclaimedAmounts[index].gt(zero)) {
dispatchClaim({
token: getTokenByAddress(token, networkId).symbol,
claimable: unclaimedAmounts[index],
tx,
})
}
})
}
})
.catch((error) => {
console.error(`Error fetching ${protocol} rewards:`, error)
})
if (isEligibleForProtocolRewards) {
const network = networkIdToLibraryNetwork(networkId)
if ([Network.HARDHAT, Network.LOCAL, Network.TENDERLY].includes(network)) {
logger.warn(`Protocol rewards not supported on network: ${network}`)
return
}
let rewardsControllerAddress: string | undefined
let poolDataProviderAddress: string | undefined
switch (protocol) {
case LendingProtocol.AaveV3:
rewardsControllerAddress = ADDRESSES[network].aave.v3.RewardsController
poolDataProviderAddress = ADDRESSES[network].aave.v3.PoolDataProvider
break
case LendingProtocol.SparkV3:
rewardsControllerAddress = ADDRESSES[network].spark.RewardsController
poolDataProviderAddress = ADDRESSES[network].spark.PoolDataProvider
break
default:
logger.warn(`Unsupported protocol for rewards: ${protocol}`)
return
}
if (!rewardsControllerAddress || !poolDataProviderAddress) {
logger.error(`Missing contract addresses for protocol ${protocol} on network ${network}`)
throw new Error(`Unsupported protocol or network for rewards: ${protocol} on ${network}`)
}
getAllUserRewards({
networkId,
token: quoteAddress,
account: dpmProxy,
rewardsController: rewardsControllerAddress as string,
poolDataProvider: poolDataProviderAddress as string,
})
.then(async ({ rewardsList, unclaimedAmounts, assets }) => {
if (unclaimedAmounts.some((amount) => amount.gt(zero))) {
const tx = encodeClaimAllRewards({
networkId,
assets: assets as string[],
dpmAccount: dpmProxy,
rewardsController: rewardsControllerAddress as string,
})
rewardsList.forEach((token, index) => {
if (unclaimedAmounts[index].gt(zero)) {
dispatchClaim({
token: getTokenByAddress(token, networkId).symbol,
claimable: unclaimedAmounts[index],
tx,
})
}
})
}
})
.catch((error) => {
console.error(`Error fetching ${protocol} rewards:`, error)
})

}
}, [dpmProxy, networkId, protocol, quoteAddress])

Expand All @@ -152,19 +203,33 @@

export const OmniDetailSectionRewardsClaims: FC = () => {
const {
environment: { protocol, collateralToken, quoteToken },
environment: { protocol, collateralToken, quoteToken, networkId },
} = useOmniGeneralContext()

const eligibleTokens = ['SUSDE', 'USDE', 'WETH', 'ETH']
const rewardsEligibleTokens = ['SUSDE', 'USDE', 'WETH', 'ETH']

// Regular ERC20 claims eligibility
const isEligibleForErc20Claims = claimableErc20ByNetwork[networkId].length > 0

// Aave/Spark rewards eligibility
const isEligibleForProtocolRewards =
[LendingProtocol.AaveV3, LendingProtocol.SparkV3].includes(protocol) &&
(rewardsEligibleTokens.includes(collateralToken) || rewardsEligibleTokens.includes(quoteToken))

const isEligible =
[
LendingProtocol.MorphoBlue,
LendingProtocol.Ajna,
LendingProtocol.AaveV3,
LendingProtocol.SparkV3,
].includes(protocol) &&
(eligibleTokens.includes(collateralToken) || eligibleTokens.includes(quoteToken))
// Legacy Morpho claims eligibility
const isEligibleForMorphoLegacy =
networkId === NetworkIds.MAINNET && protocol === LendingProtocol.MorphoBlue

return isEligible ? <OmniDetailSectionRewardsClaimsInternal /> : <></>
const hasAnyEligibleClaims =
isEligibleForErc20Claims || isEligibleForProtocolRewards || isEligibleForMorphoLegacy

return hasAnyEligibleClaims ? (
<OmniDetailSectionRewardsClaimsInternal
isEligibleForErc20Claims={isEligibleForErc20Claims}
isEligibleForProtocolRewards={isEligibleForProtocolRewards}
isEligibleForMorphoLegacy={isEligibleForMorphoLegacy}
/>
) : (
<></>
)
}
Loading
Loading