Skip to content

Commit

Permalink
refact: adds peer review comments to reebasefeederpool
Browse files Browse the repository at this point in the history
  • Loading branch information
doncesarts committed May 9, 2022
1 parent 9422b49 commit 0cb0015
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 43 deletions.
8 changes: 4 additions & 4 deletions contracts/feeders/FeederPool.sol
Expand Up @@ -186,7 +186,7 @@ contract FeederPool is
* @param _input Address of the bAsset to deposit.
* @param _inputQuantity Quantity in input token units.
* @param _minOutputQuantity Minimum fpToken quantity to be minted. This protects against slippage.
* @param _recipient Receipient of the newly minted fpTokens
* @param _recipient Recipient of the newly minted fpTokens
* @return mintOutput Quantity of fpToken minted from the deposited bAsset.
*/
function mint(
Expand Down Expand Up @@ -219,7 +219,7 @@ contract FeederPool is
* @param _inputs Address of the bAssets to deposit.
* @param _inputQuantities Quantity in input token units.
* @param _minOutputQuantity Minimum fpToken quantity to be minted. This protects against slippage.
* @param _recipient Receipient of the newly minted fpTokens
* @param _recipient Recipient of the newly minted fpTokens
* @return mintOutput Quantity of fpToken minted from the deposited bAssets.
*/
function mintMulti(
Expand Down Expand Up @@ -727,7 +727,7 @@ contract FeederPool is
uint64 endA = ampData_.targetA;
uint64 endTime = ampData_.rampEndTime;

// If still changing, work out based on current timestmap
// If still changing, work out based on current timestamp
if (block.timestamp < endTime) {
uint64 startA = ampData_.initialA;
uint64 startTime = ampData_.rampStartTime;
Expand Down Expand Up @@ -819,7 +819,7 @@ contract FeederPool is
}

/**
* @dev Set the ecosystem fee for sewapping bAssets or redeeming specific bAssets
* @dev Set the ecosystem fee for swapping bAssets or redeeming specific bAssets
* @param _swapFee Fee calculated in (%/100 * 1e18)
* @param _redemptionFee Fee calculated in (%/100 * 1e18)
* @param _govFee Fee calculated in (%/100 * 1e18)
Expand Down
14 changes: 11 additions & 3 deletions tasks/deployFeeders.ts
Expand Up @@ -11,7 +11,8 @@ import {
AlchemixIntegration,
AlchemixIntegration__factory,
FeederWrapper__factory,
} from "types/generated"
FeederPoolTypes,
} from "types"
import { simpleToExactAmount } from "@utils/math"
import { ALCX, alUSD, BUSD, CREAM, cyMUSD, GUSD, mUSD, tokens } from "./utils/tokens"
import { deployContract, logTxDetails } from "./utils/deploy-utils"
Expand All @@ -26,7 +27,9 @@ task("deployFeederPool", "Deploy Feeder Pool")
.addOptionalParam("min", "Minimum asset weight of the basket as a percentage. eg 10 for 10% of the basket.", 10, types.int)
.addOptionalParam("max", "Maximum asset weight of the basket as a percentage. eg 90 for 90% of the basket.", 90, types.int)
.addOptionalParam("speed", "Defender Relayer speed param: 'safeLow' | 'average' | 'fast' | 'fastest'", "fast", types.string)
.addOptionalParam("type", "Type of feeder pool 'FeederPool' | 'RebasedFeederPool'", "FeederPool", types.string)
.setAction(async (taskArgs, hre) => {
// TODO - usd+ , no need to add a new one , this can be reused.
const signer = await getSigner(hre, taskArgs.speed)
const chain = getChain(hre)

Expand All @@ -52,7 +55,12 @@ task("deployFeederPool", "Deploy Feeder Pool")
}

// Deploy Feeder Pool
await deployFeederPool(signer, poolData, hre)
await deployFeederPool(
signer,
poolData,
hre,
taskArgs.max === "FeederPool" ? FeederPoolTypes.FeederPool : FeederPoolTypes.RebasedFeederPool,
)
})

task("deployNonPeggedFeederPool", "Deploy Non Pegged Feeder Pool")
Expand Down Expand Up @@ -91,7 +99,7 @@ task("deployNonPeggedFeederPool", "Deploy Non Pegged Feeder Pool")
}

// Deploy Feeder Pool
await deployFeederPool(signer, poolData, hre)
await deployFeederPool(signer, poolData, hre, FeederPoolTypes.NonPeggedFeederPool)
})

task("deployAlcxInt", "Deploy Alchemix integration contract for alUSD Feeder Pool")
Expand Down
43 changes: 29 additions & 14 deletions tasks/utils/feederUtils.ts
@@ -1,20 +1,21 @@
/* eslint-disable @typescript-eslint/no-shadow */
/* eslint-disable no-restricted-syntax */
/* eslint-disable no-await-in-loop */
import { DEAD_ADDRESS, ZERO_ADDRESS } from "@utils/constants"
import { BN, simpleToExactAmount } from "@utils/math"
import { BN } 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,
RebasedFeederPool__factory,
BoostedVault__factory,
Masset__factory,
BoostedDualVault,
Expand All @@ -24,7 +25,9 @@ import {
StakingRewardsWithPlatformToken__factory,
StakingRewards__factory,
IRedemptionPriceSnap__factory,
} from "types/generated"
FeederPoolType,
FeederPoolTypes,
} from "types"
import { deployContract } from "./deploy-utils"
import { verifyEtherscan } from "./etherscan"
import { getChain, getChainAddress } from "./networkAddressFactory"
Expand Down Expand Up @@ -79,7 +82,12 @@ export const deployFasset = async (
return new MockERC20__factory(sender).attach(proxy.address)
}

export const deployFeederPool = async (signer: Signer, feederData: FeederData, hre: HardhatRuntimeEnvironment): Promise<FeederPool> => {
export const deployFeederPool = async (
signer: Signer,
feederData: FeederData,
hre: HardhatRuntimeEnvironment,
type: FeederPoolTypes = FeederPoolTypes.FeederPool,
): Promise<FeederPool> => {
const chain = getChain(hre)
const feederManagerAddress = getChainAddress("FeederManager", chain)
const feederLogicAddress = getChainAddress("FeederLogic", chain)
Expand All @@ -90,17 +98,24 @@ export const deployFeederPool = async (signer: Signer, feederData: FeederData, h
"contracts/feeders/FeederManager.sol:FeederManager": feederManagerAddress,
}

let impl: FeederPool | NonPeggedFeederPool
let impl: FeederPoolType
let fpConstructorArgs: Array<string>

if (feederData.fAssetRedemptionPriceGetter) {
// Update fAssetRedemptionPriceGetter price oracle
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)
switch (type) {
case FeederPoolTypes.NonPeggedFeederPool:
// Update fAssetRedemptionPriceGetter price oracle
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)
break
case FeederPoolTypes.RebasedFeederPool:
fpConstructorArgs = [getChainAddress("Nexus", chain), feederData.mAsset.address]
impl = await deployContract(new RebasedFeederPool__factory(linkedAddress, signer), "RebasedFeederPool", fpConstructorArgs)
break
case FeederPoolTypes.FeederPool:
default:
fpConstructorArgs = [getChainAddress("Nexus", chain), feederData.mAsset.address]
impl = await deployContract(new FeederPool__factory(linkedAddress, signer), "FeederPool", fpConstructorArgs)
break
}

await verifyEtherscan(hre, {
Expand Down
2 changes: 2 additions & 0 deletions tasks/utils/tokens.ts
Expand Up @@ -508,6 +508,8 @@ export const RmBPT: Token = {
quantityFormatter: "USD",
}

// TODO - add usd+ configuration here.

export const tokens = [
AAVE,
stkAAVE,
Expand Down
74 changes: 74 additions & 0 deletions test-fork/feeders/feeders-musd-overnight.spec.ts
@@ -0,0 +1,74 @@
import { impersonateAccount } from "@utils/fork"
import { simpleToExactAmount } from "@utils/math"
import { expect } from "chai"
import { ethers, network } from "hardhat"
import { PFRAX, PmUSD } from "tasks/utils"
import { Account } from "types"
import { ERC20, ERC20__factory, RebasedFeederPool, RebasedFeederPool__factory, IERC20, IERC20__factory } from "types/generated"

const accountAddress = "0xdccb7a6567603af223c090be4b9c83eced210f18"

// set the correct hardhat configuration file at "test:file:fork": "yarn hardhat --config hardhat-fork.config.ts test",
// set env variable NODE_URL pointing to the correct node,
// yarn test:file:fork TEST_FILE.spec.ts

// Integration tests with day to day actions for example :
// Deployment of the fPool with close to real data.
// Alice deposits some tokens, bob deposits some tokens, alice withdraw after some days and bob withdraw after some days.
// Alice mints some tokens, bob redeems some tokens
// Permutations of multiple mints and redeems
// Stress the behavior of _getMemBassetData()#bAssetData[F_INDEX].vaultBalance is it prone to price manipulation ? For example, flash loan attacks
// Stress the behavior of _updateBassetData()#data.bAssetData[F_INDEX].vaultBalance is it prone to price manipulation ?
// Are those 2 scenarios cover by contracts/feeders/FeederLogic.sol#computeMint? require(_inBounds(x, sum, _config.limits), "Exceeds weight limits");
// The price of the fpToken can be manipulated by sending fasset token directly to the pool,
// await fAsset.connect(sa.default.signer).approve(details.pool.address, simpleToExactAmount(XXXXX, 6))
// await fAsset.connect(sa.default.signer).transfer(details.pool.address, simpleToExactAmount(XXXXX, 6)) // this will increase the price
// TWAP
context.skip("Overnight Feeder Pool on Polygon", () => {
let account: Account

let musd: IERC20

before("reset block number", async () => {
await network.provider.request({
method: "hardhat_reset",
params: [
{
forking: {
jsonRpcUrl: process.env.NODE_URL,
blockNumber: 16440763,
},
},
],
})
account = await impersonateAccount(accountAddress)

musd = await IERC20__factory.connect(PmUSD.address, account.signer)
})
it("Test connectivity", async () => {
const currentBlock = await ethers.provider.getBlockNumber()
console.log(`Current block ${currentBlock}`)
const startEther = await account.signer.getBalance()
console.log(`Deployer ${account} has ${startEther} Ether`)
})
it("Approve spend of usd+", async () => {
// TODO
})
it("Approve spend of mUSD", async () => {
// TODO
})
it("Mint usdFp", async () => {
// TODO
})
it("vaultBalance behavior when a whale deposits or flashloan attack, how does it behave?", async () => {
// function _getMemBassetData() internal view returns (BassetData[] memory bAssetData) {
// bAssetData = new BassetData[](NUM_ASSETS);
// bAssetData[M_INDEX] = data.bAssetData[M_INDEX];
// bAssetData[F_INDEX].vaultBalance = uint128(IERC20(data.bAssetPersonal[F_INDEX].addr).balanceOf(address(this)));
// bAssetData[F_INDEX].ratio = data.bAssetData[F_INDEX].ratio;
// }
// function _updateBassetData() internal {
// data.bAssetData[F_INDEX].vaultBalance = uint128(IERC20(data.bAssetPersonal[F_INDEX].addr).balanceOf(address(this)));
// }
})
})
15 changes: 13 additions & 2 deletions test/feeders/mint.spec.ts
Expand Up @@ -30,8 +30,14 @@ describe("Feeder - Mint", () => {
use2dp = false,
useRedemptionPrice = false,
): Promise<void> => {
details = await feederMachine.deployFeeder(feederWeights, mAssetWeights, useLendingMarkets,
useInterestValidator, use2dp, useRedemptionPrice)
details = await feederMachine.deployFeeder(
feederWeights,
mAssetWeights,
useLendingMarkets,
useInterestValidator,
use2dp,
useRedemptionPrice,
)
}

before("Init contract", async () => {
Expand Down Expand Up @@ -142,6 +148,8 @@ describe("Feeder - Mint", () => {
sender: Account = sa.default,
quantitiesAreExact = true,
): Promise<MintOutput> => {
const priceBefore = await fd.pool.getPrice()

const pool = fd.pool.connect(sender.signer)

// Get before balances
Expand Down Expand Up @@ -213,6 +221,9 @@ describe("Feeder - Mint", () => {
// VaultBalance should update for this asset
const assetAfter = await feederMachine.getAsset(details, inputAsset.address)
expect(BN.from(assetAfter.vaultBalance), "vault balance after").eq(BN.from(assetBefore.vaultBalance).add(assetQuantityExact))
const priceAfter = await fd.pool.getPrice()

console.log("priceBefore", priceBefore.toString(), "priceAfter", priceAfter.toString())

return {
outputQuantity: outputQuantityExact,
Expand Down

0 comments on commit 0cb0015

Please sign in to comment.