diff --git a/common/configuration.ts b/common/configuration.ts index 178628243..c5b530ab6 100644 --- a/common/configuration.ts +++ b/common/configuration.ts @@ -15,6 +15,7 @@ export interface ITokens { TUSD?: string BUSD?: string sUSD?: string + RLUSD?: string FRAX?: string MIM?: string crvUSD?: string @@ -35,6 +36,8 @@ export interface ITokens { saEthUSDC?: string aEthUSDT?: string saEthUSDT?: string + aEthRLUSD?: string + saEthRLUSD?: string aBasUSDC?: string saBasUSDC?: string aArbUSDCn?: string @@ -335,6 +338,8 @@ export const networkConfig: { [key: string]: INetworkConfig } = { maWBTC: '0x1F423dC943738b9c31cB3d96c2A744dd7502593d', // our wrapper maWETH: '0xB7c4c4a2B7453E10d7e4e23Fa8E8D2335d09afab', // our wrapper maStETH: '0xAdc10669354aAd42A581E6F6cC8990B540AA5689', // our wrapper + RLUSD: '0x8292Bb45bf1Ee4d140127049757C2E0fF06317eD', + aEthRLUSD: '0xFa82580c16A31D0c1bC632A36F82e83EfEF3Eec0', }, chainlinkFeeds: { RSR: '0x759bBC1be8F90eE6457C44abc7d443842a976d02', @@ -366,6 +371,7 @@ export const networkConfig: { [key: string]: INetworkConfig } = { USDe: '0xa569d910839Ae8865Da8F8e70FfFb0cBA869F961', USDS: '0xfF30586cD0F29eD462364C7e81375FC0C71219b1', OETHETH: '0x703118C4CbccCBF2AB31913e0f8075fbbb15f563', // OETH/ETH + RLUSD: '0x26C46B7aD0012cA71F2298ada567dC9Af14E7f2A', }, AAVE_INCENTIVES: '0xd784927Ff2f95ba542BfC824c8a8a98F3495f6b5', AAVE_EMISSIONS_MGR: '0xEE56e2B3D491590B5b31738cC34d5232F378a8D5', diff --git a/scripts/addresses/1-tmp-assets-collateral.json b/scripts/addresses/1-tmp-assets-collateral.json index 189776255..29076377d 100644 --- a/scripts/addresses/1-tmp-assets-collateral.json +++ b/scripts/addresses/1-tmp-assets-collateral.json @@ -54,7 +54,8 @@ "sUSDe": "0x403623175656ED0CDF1F9efE54867761F1EBf1D8", "sUSDS": "0x4FD189996b5344Eb4CF9c749b97C7424D399d24e", "wOETH": "0xBFAc3e99263B7aE9704eC1c879f7c0a57C6b53e1", - "pyUSD": "0x9A65173df5D5B86E26300Cc9cA5Ff378be6DAeA5" + "pyUSD": "0x9A65173df5D5B86E26300Cc9cA5Ff378be6DAeA5", + "saEthRLUSD": "0xb1e61f452CFcF6609C2F4088EC36B4c8dd1806b5" }, "erc20s": { "stkAAVE": "0x4da27a545c0c5B758a6BA100e3a049001de870f5", @@ -109,6 +110,7 @@ "CVX": "0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B", "sUSDS": "0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD", "wOETH": "0xDcEe70654261AF21C44c093C300eD3Bb97b78192", - "pyUSD": "0x6c3ea9036406852006290770bedfcaba0e23a0e8" + "pyUSD": "0x6c3ea9036406852006290770bedfcaba0e23a0e8", + "saEthRLUSD": "0x4C813CE4e2FF315f0213563A994c20BBF4637444" } } \ No newline at end of file diff --git a/scripts/addresses/mainnet-4.2.0/1-tmp-assets-collateral.json b/scripts/addresses/mainnet-4.2.0/1-tmp-assets-collateral.json index 08bffbb26..cb75dca07 100644 --- a/scripts/addresses/mainnet-4.2.0/1-tmp-assets-collateral.json +++ b/scripts/addresses/mainnet-4.2.0/1-tmp-assets-collateral.json @@ -54,7 +54,8 @@ "sUSDe": "0x403623175656ED0CDF1F9efE54867761F1EBf1D8", "sUSDS": "0x4FD189996b5344Eb4CF9c749b97C7424D399d24e", "wOETH": "0xBFAc3e99263B7aE9704eC1c879f7c0a57C6b53e1", - "pyUSD": "0x9A65173df5D5B86E26300Cc9cA5Ff378be6DAeA5" + "pyUSD": "0x9A65173df5D5B86E26300Cc9cA5Ff378be6DAeA5", + "saEthRLUSD": "0xb1e61f452CFcF6609C2F4088EC36B4c8dd1806b5" }, "erc20s": { "stkAAVE": "0x4da27a545c0c5B758a6BA100e3a049001de870f5", @@ -109,6 +110,7 @@ "CVX": "0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B", "sUSDS": "0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD", "wOETH": "0xDcEe70654261AF21C44c093C300eD3Bb97b78192", - "pyUSD": "0x6c3ea9036406852006290770bedfcaba0e23a0e8" + "pyUSD": "0x6c3ea9036406852006290770bedfcaba0e23a0e8", + "saEthRLUSD": "0x4C813CE4e2FF315f0213563A994c20BBF4637444" } } diff --git a/scripts/deploy.ts b/scripts/deploy.ts index da57079f5..9d7dc5ae7 100644 --- a/scripts/deploy.ts +++ b/scripts/deploy.ts @@ -80,6 +80,7 @@ async function main() { 'phase2-assets/collaterals/deploy_aave_v3_usdc.ts', 'phase2-assets/collaterals/deploy_aave_v3_usdt.ts', 'phase2-assets/collaterals/deploy_aave_v3_pyusd.ts', + 'phase2-assets/collaterals/deploy_aave_v3_rlusd.ts', 'phase2-assets/collaterals/deploy_yearn_v2_curve_usdc.ts', 'phase2-assets/collaterals/deploy_sfrax.ts', 'phase2-assets/collaterals/deploy_sfrax_eth.ts', diff --git a/scripts/deployment/phase2-assets/collaterals/deploy_aave_v3_rlusd.ts b/scripts/deployment/phase2-assets/collaterals/deploy_aave_v3_rlusd.ts new file mode 100644 index 000000000..a3922ac01 --- /dev/null +++ b/scripts/deployment/phase2-assets/collaterals/deploy_aave_v3_rlusd.ts @@ -0,0 +1,111 @@ +import fs from 'fs' +import hre, { ethers } from 'hardhat' +import { getChainId } from '../../../../common/blockchain-utils' +import { baseL2Chains, networkConfig } from '../../../../common/configuration' +import { expect } from 'chai' +import { CollateralStatus } from '../../../../common/constants' +import { + getDeploymentFile, + getAssetCollDeploymentFilename, + IAssetCollDeployments, + getDeploymentFilename, + fileExists, +} from '../../common' +import { bn, fp } from '#/common/numbers' +import { AaveV3FiatCollateral } from '../../../../typechain' +import { priceTimeout, revenueHiding } from '../../utils' +import { + RLUSD_MAINNET_MAX_TRADE_VOLUME, + RLUSD_MAINNET_ORACLE_ERROR, + RLUSD_MAINNET_ORACLE_TIMEOUT, +} from '../../../../test/plugins/individual-collateral/aave-v3/constants' + +// This file specifically deploys Aave V3 RLUSD collateral on Mainnet + +async function main() { + // ==== Read Configuration ==== + const [deployer] = await hre.ethers.getSigners() + + const chainId = await getChainId(hre) + + console.log(`Deploying Collateral to network ${hre.network.name} (${chainId}) + with burner account: ${deployer.address}`) + + if (!networkConfig[chainId]) { + throw new Error(`Missing network configuration for ${hre.network.name}`) + } + + // Only exists on Mainnet + if (baseL2Chains.includes(hre.network.name)) { + throw new Error(`Invalid network ${hre.network.name} - only available on Mainnet`) + } + + // Get phase1 deployment + const phase1File = getDeploymentFilename(chainId) + if (!fileExists(phase1File)) { + throw new Error(`${phase1File} doesn't exist yet. Run phase 1`) + } + + // Check previous step completed + const assetCollDeploymentFilename = getAssetCollDeploymentFilename(chainId) + const assetCollDeployments = getDeploymentFile(assetCollDeploymentFilename) + + const deployedCollateral: string[] = [] + + const CollateralFactory = await ethers.getContractFactory('AaveV3FiatCollateral') + const StaticATokenFactory = await hre.ethers.getContractFactory('StaticATokenV3LM') + + /******** Deploy Aave V3 RLUSD ERC20 **************************/ + + const erc20 = await StaticATokenFactory.deploy( + networkConfig[chainId].AAVE_V3_POOL!, + networkConfig[chainId].AAVE_V3_INCENTIVES_CONTROLLER! + ) + await erc20.deployed() + await ( + await erc20.initialize( + networkConfig[chainId].tokens.aEthRLUSD!, + 'Static Aave Ethereum RLUSD', + 'saEthRLUSD' + ) + ).wait() + + /******** Deploy Aave V3 RLUSD collateral plugin **************************/ + + const collateral = await CollateralFactory.connect(deployer).deploy( + { + priceTimeout: priceTimeout, + chainlinkFeed: networkConfig[chainId].chainlinkFeeds.RLUSD!, + oracleError: RLUSD_MAINNET_ORACLE_ERROR, + erc20: erc20.address, + maxTradeVolume: RLUSD_MAINNET_MAX_TRADE_VOLUME, + oracleTimeout: RLUSD_MAINNET_ORACLE_TIMEOUT, + targetName: ethers.utils.formatBytes32String('USD'), + defaultThreshold: fp('0.01').add(RLUSD_MAINNET_ORACLE_ERROR), + delayUntilDefault: bn('86400'), + }, + revenueHiding + ) + await collateral.deployed() + await (await collateral.refresh()).wait() + expect(await collateral.status()).to.equal(CollateralStatus.SOUND) + + console.log( + `Deployed Aave V3 RLUSD collateral to ${hre.network.name} (${chainId}): ${collateral.address}` + ) + + assetCollDeployments.erc20s.saEthRLUSD = erc20.address + assetCollDeployments.collateral.saEthRLUSD = collateral.address + deployedCollateral.push(collateral.address.toString()) + + fs.writeFileSync(assetCollDeploymentFilename, JSON.stringify(assetCollDeployments, null, 2)) + + console.log(`Deployed collateral to ${hre.network.name} (${chainId}) + New deployments: ${deployedCollateral} + Deployment file: ${assetCollDeploymentFilename}`) +} + +main().catch((error) => { + console.error(error) + process.exitCode = 1 +}) diff --git a/scripts/verification/collateral-plugins/verify_aave_v3_rlusd.ts b/scripts/verification/collateral-plugins/verify_aave_v3_rlusd.ts new file mode 100644 index 000000000..5e710465e --- /dev/null +++ b/scripts/verification/collateral-plugins/verify_aave_v3_rlusd.ts @@ -0,0 +1,74 @@ +import hre, { ethers } from 'hardhat' +import { getChainId } from '../../../common/blockchain-utils' +import { developmentChains, networkConfig } from '../../../common/configuration' +import { + getDeploymentFile, + getAssetCollDeploymentFilename, + IAssetCollDeployments, +} from '../../deployment/common' +import { fp } from '../../../common/numbers' +import { priceTimeout, verifyContract, revenueHiding } from '../../deployment/utils' + +let deployments: IAssetCollDeployments + +async function main() { + // ********** Read config ********** + const chainId = await getChainId(hre) + if (!networkConfig[chainId]) { + throw new Error(`Missing network configuration for ${hre.network.name}`) + } + + if (developmentChains.includes(hre.network.name)) { + throw new Error(`Cannot verify contracts for development chain ${hre.network.name}`) + } + + const assetCollDeploymentFilename = getAssetCollDeploymentFilename(chainId) + deployments = getDeploymentFile(assetCollDeploymentFilename) + + const erc20s: { [key: string]: string } = { + '1': deployments.erc20s.saEthRLUSD!, + } + const erc20 = await ethers.getContractAt('ERC20Mock', erc20s[chainId]) + + const collaterals: { [key: string]: string } = { + '1': deployments.collateral.saEthRLUSD!, + } + const collateral = await ethers.getContractAt('AaveV3FiatCollateral', collaterals[chainId]) + + /******** Verify Aave V3 RLUSD ERC20 **************************/ + await verifyContract( + chainId, + erc20.address, + [networkConfig[chainId].AAVE_V3_POOL!, networkConfig[chainId].AAVE_V3_INCENTIVES_CONTROLLER!], + 'contracts/plugins/assets/aave-v3/vendor/StaticATokenV3LM.sol:StaticATokenV3LM' + ) + + /******** Verify Aave V3 RLUSD plugin **************************/ + + await verifyContract( + chainId, + collateral.address, + [ + { + erc20: await collateral.erc20(), + targetName: ethers.utils.formatBytes32String('USD'), + priceTimeout: priceTimeout.toString(), + chainlinkFeed: await collateral.chainlinkFeed(), + oracleError: await collateral.oracleError(), + oracleTimeout: await collateral.oracleTimeout(), + maxTradeVolume: await collateral.maxTradeVolume(), + defaultThreshold: fp('0.01') + .add(await collateral.oracleError()) + .toString(), + delayUntilDefault: await collateral.delayUntilDefault(), + }, + revenueHiding.toString(), + ], + 'contracts/plugins/assets/aave-v3/AaveV3FiatCollateral.sol:AaveV3FiatCollateral' + ) +} + +main().catch((error) => { + console.error(error) + process.exitCode = 1 +}) diff --git a/scripts/verify_etherscan.ts b/scripts/verify_etherscan.ts index 2b6832d61..c03ebc009 100644 --- a/scripts/verify_etherscan.ts +++ b/scripts/verify_etherscan.ts @@ -68,6 +68,7 @@ async function main() { 'collateral-plugins/verify_morpho.ts', 'collateral-plugins/verify_aave_v3_usdc.ts', 'collateral-plugins/verify_aave_v3_usdt.ts', + 'collateral-plugins/verify_aave_v3_rlusd.ts', 'collateral-plugins/verify_yearn_v2_curve_usdc.ts', 'collateral-plugins/verify_sfrax.ts', 'collateral-plugins/verify_sfrax_eth.ts', diff --git a/test/plugins/individual-collateral/aave-v3/AaveV3FiatCollateral.test.ts b/test/plugins/individual-collateral/aave-v3/AaveV3FiatCollateral.test.ts index 32c317ac3..64a7deaaa 100644 --- a/test/plugins/individual-collateral/aave-v3/AaveV3FiatCollateral.test.ts +++ b/test/plugins/individual-collateral/aave-v3/AaveV3FiatCollateral.test.ts @@ -22,6 +22,9 @@ import { USDT_MAINNET_MAX_TRADE_VOLUME, USDT_MAINNET_ORACLE_TIMEOUT, USDT_MAINNET_ORACLE_ERROR, + RLUSD_MAINNET_MAX_TRADE_VOLUME, + RLUSD_MAINNET_ORACLE_TIMEOUT, + RLUSD_MAINNET_ORACLE_ERROR, } from './constants' // Mainnet - USDC @@ -121,6 +124,30 @@ makeTests( } ) +// Mainnet - RLUSD +makeTests( + { + priceTimeout: PRICE_TIMEOUT, + chainlinkFeed: networkConfig[1].chainlinkFeeds['RLUSD']!, + oracleError: RLUSD_MAINNET_ORACLE_ERROR, + erc20: '', // to be set + maxTradeVolume: RLUSD_MAINNET_MAX_TRADE_VOLUME, + oracleTimeout: RLUSD_MAINNET_ORACLE_TIMEOUT, + targetName: ethers.utils.formatBytes32String('USD'), + defaultThreshold: fp('0.01').add(RLUSD_MAINNET_ORACLE_TIMEOUT), + delayUntilDefault: bn('86400'), + }, + { + testName: 'RLUSD - Mainnet', + aaveIncentivesController: networkConfig[1].AAVE_V3_INCENTIVES_CONTROLLER!, + aavePool: networkConfig[1].AAVE_V3_POOL!, + aToken: networkConfig[1].tokens['aEthRLUSD']!, + whaleTokenHolder: '0x1073d55Dfb892ed86151015402DB8B1CDb6edE78', + forkBlock: 23726585, + targetNetwork: 'mainnet', + } +) + // Arbitrum - USDC makeTests( { diff --git a/test/plugins/individual-collateral/aave-v3/common.ts b/test/plugins/individual-collateral/aave-v3/common.ts index 6b6c5d268..bd3fd467f 100644 --- a/test/plugins/individual-collateral/aave-v3/common.ts +++ b/test/plugins/individual-collateral/aave-v3/common.ts @@ -121,8 +121,6 @@ export const makeTests = (defaultCollateralOpts: CollateralParams, altParams: Al user: SignerWithAddress, recipient: string ) => { - const requiredCollat = await ctx.staticWrapper.previewMint(amount) - // Impersonate holder await whileImpersonating(altParams.whaleTokenHolder, async (signer) => { await ctx.baseToken.connect(signer).approve(ctx.staticWrapper.address, 0) // required for usdt @@ -131,9 +129,8 @@ export const makeTests = (defaultCollateralOpts: CollateralParams, altParams: Al .connect(signer) .approve(ctx.staticWrapper.address, ethers.constants.MaxUint256) - await ctx.staticWrapper - .connect(signer) - ['deposit(uint256,address,uint16,bool)'](requiredCollat, recipient, 0, true) + // Use mint() for exact shares without rounding loss + await ctx.staticWrapper.connect(signer)['mint(uint256,address)'](amount, recipient) }) } diff --git a/test/plugins/individual-collateral/aave-v3/constants.ts b/test/plugins/individual-collateral/aave-v3/constants.ts index d4bc6c2f2..fd960b077 100644 --- a/test/plugins/individual-collateral/aave-v3/constants.ts +++ b/test/plugins/individual-collateral/aave-v3/constants.ts @@ -23,3 +23,7 @@ export const USDT_MAINNET_ORACLE_ERROR = fp('0.0025') export const USDT_ARBITRUM_MAX_TRADE_VOLUME = fp('1e6') export const USDT_ARBITRUM_ORACLE_TIMEOUT = bn('86400') export const USDT_ARBITRUM_ORACLE_ERROR = fp('0.001') + +export const RLUSD_MAINNET_MAX_TRADE_VOLUME = fp('1e6') +export const RLUSD_MAINNET_ORACLE_TIMEOUT = bn('86400') +export const RLUSD_MAINNET_ORACLE_ERROR = fp('0.003')