Skip to content
Merged

Main #578

Show file tree
Hide file tree
Changes from all commits
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
4 changes: 4 additions & 0 deletions .github/workflows/process-issue.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ jobs:
SONIC_RPC_URL: ${{ secrets.SONIC_RPC_URL }}
HYPEREVM_RPC_URL: ${{ secrets.HYPEREVM_RPC_URL }}
PLASMA_RPC_URL: ${{ secrets.PLASMA_RPC_URL }}
XLAYER_API_KEY: ${{ secrets.XLAYER_API_KEY }}
XLAYER_SECRET_KEY: ${{ secrets.XLAYER_SECRET_KEY }}
XLAYER_PASSPHRASE: ${{ secrets.XLAYER_PASSPHRASE }}
XLAYER_RPC_URL: ${{ secrets.XLAYER_RPC_URL }}
HYPERNATIVE_CLIENT_ID: ${{ secrets.HYPERNATIVE_CLIENT_ID }}
HYPERNATIVE_CLIENT_SECRET: ${{ secrets.HYPERNATIVE_CLIENT_SECRET }}
- name: Validate registry format
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Rate Provider Factories for reference
| zkEVM | 0x4132f7AcC9dB7A6cF7BE2Dd3A9DC8b30C7E6E6c8 | N/A |
| HyperEVM | 0x03362f847b4fabc12e1ce98b6b59f94401e4588e | 0xec2c6184761ab7fe061130b4a7e3da89c72f8395 |
| Plasma | 0x138D9E0d0Cc4906C4cD865b38c9340A5CeDD9850 | 0x4E185b1502Fea7a06B63fDdA6de38F92C9528566 |
| Xlayer | 0x467665D4ae90e7A99c9C9AF785791058426d6eA0 | 0xeC2C6184761ab7fE061130B4A7e3Da89c72F8395 |

Rate Transformer Factories
Use these factories when an ERC4626 vault contains a yield bearing token to combine their resepctive rates of growth. This denominates the vault asset in the underlying for correlated pairs. For example Aave-wstETH pairing with Aave-wETH by denominating the assets in wETH.
Expand Down Expand Up @@ -54,6 +55,8 @@ Use this factories to combine rate providers, similar to AaveRateTransformers. T
| Optimism | 0x7d9507014cc564e3b95e4d0972a878d0862af7ae |
| HyperEVM | 0x138d9e0d0cc4906c4cd865b38c9340a5cedd9850 |
| Plasma | 0x470C9034F50afe6633f7e84A80B9961baa893d77 |
| Xlayer | 0x138D9E0d0Cc4906C4cD865b38c9340A5CeDD9850 |

---

## Setup
Expand Down
9 changes: 6 additions & 3 deletions scripts/process-issue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
polygonZkEvm,
mode,
} from 'viem/chains'
import { hyperEvm, plasma } from '../src/utils/customChains'
import { hyperEvm, plasma, xlayer } from '../src/utils/customChains'
import { Hex } from 'viem'

/*
Expand Down Expand Up @@ -70,11 +70,12 @@ async function processIssue(issueJson: string) {
optimism,
sonic,
sepolia,
polygon,
polygon,
polygonZkEvm,
mode,
hyperEvm,
plasma,
xlayer,
}
let network = networks[issueData.network]

Expand All @@ -101,7 +102,9 @@ async function processIssue(issueJson: string) {
rpcUrl as string,
issueData.protocol_documentation,
issueData.audits,
issueData.additional_contract_information.selected.includes('Is the rate provider reporting a market rate?') ? { isMarketRate: true } : undefined,
issueData.additional_contract_information.selected.includes('Is the rate provider reporting a market rate?')
? { isMarketRate: true }
: undefined,
)

// this step requires the registry to be read thus having the registry updated already
Expand Down
19 changes: 16 additions & 3 deletions scripts/write-erc4626-review.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
mode,
} from 'viem/chains'

import { hyperEvm, plasma } from '../src/utils/customChains'
import { hyperEvm, plasma, xlayer } from '../src/utils/customChains'
import { writeReviewAndUpdateRegistry } from '../src/utils/write-erc4626-review'

dotenv.config()
Expand All @@ -42,7 +42,19 @@ async function main() {
alias: 'n',
type: 'string',
description: 'The network the rate provider is deployed on',
choices: ['base', 'mainnet', 'arbitrum', 'avalanche', 'gnosis', 'fraxtal', 'optimism', 'sonic', 'hyperEvm', 'plasma'],
choices: [
'base',
'mainnet',
'arbitrum',
'avalanche',
'gnosis',
'fraxtal',
'optimism',
'sonic',
'hyperEvm',
'plasma',
'xlayer',
],
demandOption: true,
})
.option('rpcUrl', {
Expand All @@ -67,7 +79,8 @@ async function main() {
polygonZkEvm,
mode,
hyperEvm,
plasma
plasma,
xlayer,
}

let network = networks[argv.network]
Expand Down
19 changes: 16 additions & 3 deletions scripts/write-review.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
mode,
} from 'viem/chains'

import { hyperEvm, plasma } from '../src/utils/customChains'
import { hyperEvm, plasma, xlayer } from '../src/utils/customChains'
import { writeReviewAndUpdateRegistry } from '../src/utils/write-rp-review'

dotenv.config()
Expand All @@ -44,7 +44,19 @@ async function main() {
alias: 'n',
type: 'string',
description: 'The network the rate provider is deployed on',
choices: ['base', 'mainnet', 'arbitrum', 'avalanche', 'gnosis', 'fraxtal', 'optimism', 'sonic', 'hyperEvm', 'plasma'],
choices: [
'base',
'mainnet',
'arbitrum',
'avalanche',
'gnosis',
'fraxtal',
'optimism',
'sonic',
'hyperEvm',
'plasma',
'xlayer',
],
demandOption: true,
})
.option('rateProviderAsset', {
Expand Down Expand Up @@ -75,7 +87,8 @@ async function main() {
polygonZkEvm,
mode,
hyperEvm,
plasma
plasma,
xlayer,
}

let network = networks[argv.network]
Expand Down
54 changes: 30 additions & 24 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { Address, parseEventLogs } from 'viem'
import { CreateAccessListReturnType } from 'viem/_types/actions/public/createAccessList'
import { createPublicClient, encodeFunctionData, http } from 'viem'
import { Chain, Hex, Abi } from 'viem'
import EtherscanApi from './services/etherscanApi'
import { rateProviderAbi } from './utils/abi/rateProvider'
import { xlayer } from './utils/customChains'
import { ChainApi } from './types/types'
import { createChainApi } from './utils/factories'

class RateProviderDataService {
public rateProvider: Address
Expand All @@ -22,6 +24,7 @@ class RateProviderDataService {
}

private apiKey!: string
private chainApi!: ChainApi
public tenderlySettings!: {
accountSlug: string
projectSlug: string
Expand All @@ -32,6 +35,7 @@ class RateProviderDataService {
this.rateProvider = rateProvider
this.chain = chain
this.setApiBasedOnChain(chain)
this.chainApi = createChainApi(chain)
this.tenderlySettings = {
accountSlug:
process.env.TENDERLY_ACCOUNT_SLUG ||
Expand Down Expand Up @@ -89,16 +93,14 @@ class RateProviderDataService {
* @returns An array of deployment information.
*/
public async getDeploymentBlocks(addresses: Address[]): Promise<{ address: Address; deploymentTxHash: Hex }[]> {
const etherscanApi = new EtherscanApi(this.chain, this.apiKey)

// The addresses length can be arbitrary but the etherscan API only allows 5 addresses at a time
// so we need to chunk the addresses and call the API sequentially
const chunkSize = 5
const txHashes = []

for (let i = 0; i < addresses.length; i += chunkSize) {
const chunk = addresses.slice(i, i + chunkSize)
const chunkTxHashes = await etherscanApi.getDeploymentTxHashAndBlock(chunk)
const chunkTxHashes = await this.chainApi.getDeploymentTxHashAndBlock(chunk)
txHashes.push(...chunkTxHashes)
}

Expand All @@ -113,8 +115,7 @@ class RateProviderDataService {
public async getContractInfo(
addresses: Address[],
): Promise<{ address: Address; Proxy: string; ContractName: string; ABI: string; Implementation: Address }[]> {
const etherscanApi = new EtherscanApi(this.chain, this.apiKey)
return await etherscanApi.getSourceCode(addresses)
return await this.chainApi.getSourceCode(addresses)
}

/**
Expand All @@ -136,8 +137,11 @@ class RateProviderDataService {
allContractAddresses.push(this.rateProvider)
}

// get info on all contracts in the access list
const proxiesWithRateProvider = await this.getContractInfo(allContractAddresses)
// filter out the contracts that are not proxies
const filteredProxiesList = proxiesWithRateProvider.filter((p) => p.Proxy === '1')

const proxiesWithRateProviderDeploymentInfo = await this.getDeploymentBlocks(
filteredProxiesList.map((p) => p.address),
)
Expand All @@ -164,21 +168,21 @@ class RateProviderDataService {
const proxiesWithRateProviderCompleteInfo = await Promise.all(
receipts.map(async (info) => {
try {
if (!info.ABI) {
throw new Error(`ABI not provided for contract at address ${info.address}`)
}
const events = parseEventLogs({
logs: info.receipt.logs,
abi: JSON.parse(info.ABI),
eventName: 'Upgraded',
})
const wasUpgraded = events.length > 0

return { ...info, events, wasUpgraded }
} catch (error) {
console.error(`Error processing contract at address ${info.address}:`, error)
return { ...info, events: [], wasUpgraded: false, error }
}
if (!info.ABI) {
throw new Error(`ABI not provided for contract at address ${info.address}`)
}
const events = parseEventLogs({
logs: info.receipt.logs,
abi: JSON.parse(info.ABI),
eventName: 'Upgraded',
})
const wasUpgraded = events.length > 0

return { ...info, events, wasUpgraded }
} catch (error) {
console.error(`Error processing contract at address ${info.address}:`, error)
return { ...info, events: [], wasUpgraded: false, error }
}
}),
)

Expand Down Expand Up @@ -211,8 +215,7 @@ class RateProviderDataService {
public async getContractSourceCode(
address: Address,
): Promise<{ address: Address; Proxy: string; ContractName: string; ABI: string; Implementation: Address }> {
const etherscanApi = new EtherscanApi(this.chain, this.apiKey)
const sourceCodeArray = await etherscanApi.getSourceCode([address])
const sourceCodeArray = await this.chainApi.getSourceCode([address])
return sourceCodeArray[0]
}

Expand Down Expand Up @@ -320,7 +323,7 @@ class RateProviderDataService {
return (
item.type === 'function' &&
item.name === 'getRate' &&
item.stateMutability === 'view' &&
(item.stateMutability === 'view' || item.stateMutability === 'pure') &&
item.outputs?.length === 1 &&
item.outputs[0].internalType === 'uint256'
)
Expand All @@ -338,6 +341,9 @@ class RateProviderDataService {
: (() => {
throw new Error(`ETHERSCAN_API_KEY Environment variable is not set`)
})()
if (chain.id === xlayer.id) {
this.apiKey = process.env.XLAYER_API_KEY || ''
}
}
}

Expand Down
12 changes: 8 additions & 4 deletions src/services/etherscanApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import { Address, Hex, Chain } from 'viem'
import { TransactionData, GetContractSourceCodeResponse } from '../types/types'
import { avalanche } from 'viem/chains'
import { plasma } from '../utils/customChains'
import { ChainApi } from '../types/types'

/**
* EtherscanApi class to interact with Etherscan API
* It uses the Etherscan API 2.0
* Supported chains can be found at https://docs.etherscan.io/etherscan-v2/supported-chains
*/
class EtherscanApi {
class EtherscanApi implements ChainApi {
public chain: Chain
private apiKey: string

Expand Down Expand Up @@ -44,7 +45,10 @@ class EtherscanApi {
const snowtraceResponse = await fetch(snowtraceUrl)
if (snowtraceResponse.ok) {
const fallbackData = await snowtraceResponse.json()
if (fallbackData.status === '1' && fallbackData.result[0].ABI !== 'Contract source code not verified') {
if (
fallbackData.status === '1' &&
fallbackData.result[0].ABI !== 'Contract source code not verified'
) {
console.log(`Successfully found contract on Snowscan for address ${address}`)
return fallbackData
}
Expand Down Expand Up @@ -93,15 +97,15 @@ class EtherscanApi {
// the contract can be unverified
if (data.result[0].ABI === 'Contract source code not verified') {
console.log(`Contract is unverified for address ${address}, trying fallback block explorer`)

// Try fallback explorer (e.g., Snowscan for Avalanche)
const fallbackData = await this.tryFallbackExplorer(this.chain, address)
if (fallbackData) {
const { Proxy, ContractName, ABI, Implementation } = fallbackData.result[0]
results.push({ address, Proxy, ContractName, ABI, Implementation })
continue
}

console.log(`Contract is unverified on all explorers for address ${address}`)
continue // Skip this address
}
Expand Down
Loading