import { DEAD_ADDRESS , ZERO_ADDRESS } from "@utils/constants" ; import { BN , simpleToExactAmount } from "@utils/math" ; import { Signer } from "ethers" ; import { formatEther } from "ethers/lib/utils" ; import { HardhatRuntimeEnvironment } from "hardhat/types/runtime" ; import { FeederPool , NonPeggedFeederPool , BoostedVault , MockERC20__factory , MockInitializableToken__factory , AssetProxy__factory , MockERC20 , FeederPool__factory , NonPeggedFeederPool__factory , BoostedVault__factory , Masset__factory , BoostedDualVault , StakingRewardsWithPlatformToken , StakingRewards , BoostedDualVault__factory , StakingRewardsWithPlatformToken__factory , StakingRewards__factory , IRedemptionPriceSnap__factory , } from "types/generated" ; import { deployContract } from "./deploy-utils" ; import { verifyEtherscan } from "./etherscan" ; import { getChain , getChainAddress } from "./networkAddressFactory" ; import { getSigner } from "./signerFactory" ; import { Token } from "./tokens" ; interface Config { a : BN ; limits : { min : BN ; max : BN ; } ; } export interface FeederData { mAsset : Token ; fAsset : Token ; fAssetRedemptionPriceGetter ? : string ; name : string ; symbol : string ; config : Config ; } export interface VaultData { boosted : boolean ; name : string ; symbol : string ; priceCoeff ? : BN ; stakingToken : string ; rewardToken : string ; dualRewardToken ? : string ; boostCoeff ? : number ; } export const deployFasset = async ( sender , name , symbol , decimals = 18 , initialMint = BN . from ( 500000 ) ) : Promise < MockERC20 > => { const impl = await deployContract ( new MockInitializableToken__factory ( sender ) , `MockInitializableToken with name ${ name }, symbol ${ symbol } and decimals ${ decimals }` ) ; const data = impl . interface . encodeFunctionData ( "initialize" , [ name , symbol , decimals , await sender . getAddress ( ) , initialMint ] ) ; const proxy = await deployContract ( new AssetProxy__factory ( sender ) , "AssetProxy" , [ impl . address , DEAD_ADDRESS , data ] ) ; return new MockERC20__factory ( sender ) . attach ( proxy . address ) ; } ; export const deployFeederPool = async ( signer , feederData , hre ) : Promise < FeederPool > => { const chain = getChain ( hre ) ; const feederManagerAddress = getChainAddress ( "FeederManager" , chain ) ; const feederLogicAddress = getChainAddress ( "FeederLogic" , chain ) ; const linkedAddress = { "contracts/feeders/FeederLogic.sol:FeederLogic" : feederLogicAddress , "contracts/feeders/FeederManager.sol:FeederManager" : feederManagerAddress , } ; let impl ; let fpConstructorArgs ; if ( feederData . fAssetRedemptionPriceGetter ) { await IRedemptionPriceSnap__factory . connect ( feederData . fAssetRedemptionPriceGetter , signer ) . updateSnappedPrice ( ) ; fpConstructorArgs = [ getChainAddress ( "Nexus" , chain ) , feederData . mAsset . address , feederData . fAssetRedemptionPriceGetter ] ; impl = await deployContract ( new NonPeggedFeederPool__factory ( linkedAddress , signer ) , "NonPeggedFeederPool" , fpConstructorArgs ) ; } else { fpConstructorArgs = [ getChainAddress ( "Nexus" , chain ) , feederData . mAsset . address ] ; impl = await deployContract ( new FeederPool__factory ( linkedAddress , signer ) , "FeederPool" , fpConstructorArgs ) ; } await verifyEtherscan ( hre , { address : impl . address , constructorArguments : fpConstructorArgs , libraries : { FeederManager : feederManagerAddress , FeederLogic : feederLogicAddress , } , contract : "contracts/feeders/FeederPool.sol:FeederPool" , } ) ; const mAsset = Masset__factory . connect ( feederData . mAsset . address , signer ) ; const bAssets = await mAsset . getBassets ( ) ; const mpAssets = bAssets . personal . map ( ( bAsset ) => bAsset . addr ) ; console . log ( `mpAssets. count = ${ mpAssets . length }, list: ` , mpAssets ) ; console . log ( `Initializing FeederPool with: ${ feederData . name }, ${ feederData . symbol }, mAsset ${ feederData . mAsset . address }, fAsset ${ feederData . fAsset . address }, A: ${ feederData . config . a . toString ( ) }, min: ${ formatEther ( feederData . config . limits . min ) }, max: ${ formatEther ( feederData . config . limits . max ) }` ) ; const initializeData = impl . interface . encodeFunctionData ( "initialize" , [ feederData . name , feederData . symbol , { addr : feederData . mAsset . address , integrator : feederData . mAsset . integrator || ZERO_ADDRESS , hasTxFee : false , status : 0 , } , { addr : feederData . fAsset . address , integrator : feederData . fAsset . integrator || ZERO_ADDRESS , hasTxFee : false , status : 0 , } , mpAssets , feederData . config , ] ) ; const feederPoolProxy = await deployContract ( new AssetProxy__factory ( signer ) , "Feeder Pool Proxy" , [ impl . address , getChainAddress ( "DelayedProxyAdmin" , chain ) , initializeData , ] ) ; return new FeederPool__factory ( linkedAddress , signer ) . attach ( feederPoolProxy . address ) ; } ; export const deployVault = async ( hre , vaultData ) : Promise < BoostedDualVault | BoostedVault | StakingRewardsWithPlatformToken | StakingRewards > => { const signer = await getSigner ( hre ) ; const chain = getChain ( hre ) ; const rewardsDistributorAddress = getChainAddress ( "RewardsDistributor" , chain ) ; let vault ; let constructorArguments ; if ( vaultData . boosted ) { if ( vaultData . dualRewardToken ) { constructorArguments = [ getChainAddress ( "Nexus" , chain ) , vaultData . stakingToken , getChainAddress ( "BoostDirector" , chain ) , vaultData . priceCoeff , vaultData . boostCoeff , vaultData . rewardToken , vaultData . dualRewardToken , ] ; vault = await deployContract < BoostedDualVault > ( new BoostedDualVault__factory ( signer ) , "BoostedDualVault" , constructorArguments ) ; } else { constructorArguments = [ getChainAddress ( "Nexus" , chain ) , vaultData . stakingToken , getChainAddress ( "BoostDirector" , chain ) , vaultData . priceCoeff , vaultData . boostCoeff , vaultData . rewardToken , ] ; vault = await deployContract < BoostedVault > ( new BoostedVault__factory ( signer ) , "BoostedVault" , constructorArguments ) ; } } else if ( vaultData . dualRewardToken ) { constructorArguments = [ getChainAddress ( "Nexus" , chain ) , vaultData . stakingToken , vaultData . rewardToken , vaultData . dualRewardToken ] ; vault = await deployContract < StakingRewardsWithPlatformToken > ( new StakingRewardsWithPlatformToken__factory ( signer ) , "StakingRewardsWithPlatformToken" , constructorArguments ) ; } else { constructorArguments = [ getChainAddress ( "Nexus" , chain ) , vaultData . stakingToken , getChainAddress ( "BoostDirector" , chain ) , vaultData . priceCoeff , vaultData . boostCoeff , vaultData . rewardToken , ] ; vault = await deployContract < StakingRewards > ( new StakingRewards__factory ( signer ) , "StakingRewards" , constructorArguments ) ; } await verifyEtherscan ( hre , { address : vault . address , constructorArguments , contract : "contracts/rewards/boosted-staking/BoostedDualVault.sol:BoostedDualVault" , } ) ; const initializeData = vault . interface . encodeFunctionData ( "initialize" , [ rewardsDistributorAddress , vaultData . name , vaultData . symbol ] ) ; const proxyAdminAddress = getChainAddress ( "DelayedProxyAdmin" , chain ) ; const proxy = await deployContract ( new AssetProxy__factory ( signer ) , "AssetProxy for vault" , [ vault . address , proxyAdminAddress , initializeData , ] ) ; return vault . attach ( proxy . address ) ; } ;