Skip to content

Commit

Permalink
Merge pull request #284 from yieldprotocol/fix/no-fee-base-is-ilk
Browse files Browse the repository at this point in the history
fix: don't charge a borrowing fee if base == ilk
  • Loading branch information
alcueca authored Sep 13, 2021
2 parents 76461d3 + 8c057d0 commit b725a02
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 9 deletions.
6 changes: 4 additions & 2 deletions contracts/Ladle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,8 @@ contract Ladle is LadleStorage, AccessControl() {
if (art != 0) series = getSeries(vault.seriesId);

int128 fee;
if (art > 0) fee = ((series.maturity - block.timestamp) * uint256(int256(art)).wmul(borrowingFee)).i128();
if (art > 0 && vault.ilkId != series.baseId && borrowingFee != 0)
fee = ((series.maturity - block.timestamp) * uint256(int256(art)).wmul(borrowingFee)).i128();

// Update accounting
cauldron.pour(vaultId, ink, art + fee);
Expand Down Expand Up @@ -474,7 +475,8 @@ contract Ladle is LadleStorage, AccessControl() {
fyToken.burn(address(fyToken), (base * loan) - newDebt); // Burn the surplus
}

newDebt += ((newSeries.maturity - block.timestamp) * uint256(newDebt).wmul(borrowingFee)).u128(); // Add borrowing fee, also stops users form rolling to a mature series
if (vault.ilkId != newSeries.baseId && borrowingFee != 0)
newDebt += ((newSeries.maturity - block.timestamp) * uint256(newDebt).wmul(borrowingFee)).u128(); // Add borrowing fee, also stops users form rolling to a mature series

(vault,) = cauldron.roll(vaultId, newSeriesId, newDebt.i128() - balances.art.i128()); // Change the series and debt for the vault

Expand Down
2 changes: 1 addition & 1 deletion hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ module.exports = {
settings: {
optimizer: {
enabled: true,
runs: 2500,
runs: 1500,
}
}
},
Expand Down
13 changes: 13 additions & 0 deletions test/061_ladle_pour.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/dist/src/signer-wit
import { constants } from '@yield-protocol/utils-v2'
const { WAD } = constants
import { ETH } from '../src/constants'
import { getLastVaultId } from '../src/helpers'

import { Cauldron } from '../typechain/Cauldron'
import { Join } from '../typechain/Join'
Expand Down Expand Up @@ -49,6 +50,7 @@ describe('Ladle - pour', function () {
const ilkId = ETH
const seriesId = ethers.utils.hexlify(ethers.utils.randomBytes(6))
let vaultId: string
let baseVaultId: string

beforeEach(async () => {
env = await loadFixture(fixture)
Expand All @@ -62,6 +64,8 @@ describe('Ladle - pour', function () {

vaultId = (env.vaults.get(seriesId) as Map<string, string>).get(ilkId) as string
await cauldron.setDebtLimits(baseId, ilkId, WAD.mul(2).div(1000000), 1000000, 6)

baseVaultId = (env.vaults.get(seriesId) as Map<string, string>).get(baseId) as string
})

it('only the vault owner can manage its collateral', async () => {
Expand All @@ -79,6 +83,7 @@ describe('Ladle - pour', function () {
describe('with posted collateral', async () => {
beforeEach(async () => {
await ladle.pour(vaultId, owner, WAD, 0)
await ladle.pour(baseVaultId, owner, WAD, 0)
})

it('users can pour to withdraw collateral', async () => {
Expand Down Expand Up @@ -119,6 +124,14 @@ describe('Ladle - pour', function () {
expect(await fyToken.balanceOf(owner)).to.equal(WAD)
expect((await cauldron.balances(vaultId)).art).to.equal(WAD.add(appliedFee))
})

it('except if baseId == ilkId', async () => {
const fee = WAD.div(1000000000) // 0.000000 001% wei/second
await ladle.setFee(fee)
await ladle.pour(baseVaultId, owner, 0, WAD)
expect(await fyToken.balanceOf(owner)).to.equal(WAD)
expect((await cauldron.balances(baseVaultId)).art).to.equal(WAD)
})
})

it('users can pour to post collateral and borrow fyToken', async () => {
Expand Down
22 changes: 19 additions & 3 deletions test/065_ladle_roll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ describe('Ladle - roll', function () {
const baseId = ethers.utils.hexlify(ethers.utils.randomBytes(6))
const ilkId = ETH
const seriesId = ethers.utils.hexlify(ethers.utils.randomBytes(6))
const vaultId = ethers.utils.hexlify(ethers.utils.randomBytes(12))
const otherSeriesId = ethers.utils.hexlify(ethers.utils.randomBytes(6))
let vaultId: string
let baseVaultId: string

beforeEach(async () => {
env = await loadFixture(fixture)
Expand All @@ -65,8 +66,11 @@ describe('Ladle - roll', function () {
otherFYToken = env.series.get(otherSeriesId) as FYToken

// ==== Set testing environment ====
await cauldron.build(owner, vaultId, seriesId, ilkId)
vaultId = (env.vaults.get(seriesId) as Map<string, string>).get(ilkId) as string
await ladle.pour(vaultId, owner, WAD, WAD)

baseVaultId = (env.vaults.get(seriesId) as Map<string, string>).get(baseId) as string
await ladle.pour(baseVaultId, owner, WAD, WAD)
})

it('does not allow rolling vaults other than to the vault owner', async () => {
Expand All @@ -90,10 +94,22 @@ describe('Ladle - roll', function () {
const preFeeDebt = WAD.mul(105).div(100)
const appliedFee = (await otherFYToken.maturity()).sub(timestamp).mul(preFeeDebt).mul(fee).div(WAD)

expect(await fyToken.balanceOf(owner)).to.equal(WAD)
expect(await fyToken.balanceOf(owner)).to.equal(WAD.mul(2))
expect((await cauldron.balances(vaultId)).art).to.equal(preFeeDebt.add(appliedFee))
})

it('except if base == ilk', async () => {
await ladle.pour(baseVaultId, owner, WAD.mul(5).div(100), 0) // The exchange rate is 1:1, but YieldSpace charges a 5%

const fee = WAD.div(1000000000) // 0.000000 001% wei/second
await ladle.setFee(fee)
await ladle.roll(baseVaultId, otherSeriesId, loan, MAX)
const preFeeDebt = WAD.mul(105).div(100)

expect(await fyToken.balanceOf(owner)).to.equal(WAD.mul(2))
expect((await cauldron.balances(baseVaultId)).art).to.equal(preFeeDebt)
})

describe('after maturity', async () => {
beforeEach(async () => {
await ethers.provider.send('evm_mine', [(await fyToken.maturity()).toNumber()])
Expand Down
12 changes: 9 additions & 3 deletions test/shared/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,10 @@ export class YieldEnvironment {
await usdcAggregator.set(WAD.div(2))
sources.set(USDC, usdcAggregator)

const baseAggregator = (await deployContract(owner, ChainlinkAggregatorV3MockArtifact)) as ISourceMock
await baseAggregator.set(WAD)
sources.set(baseId, baseAggregator)

// ==== Libraries ====
const SafeERC20NamerFactory = await ethers.getContractFactory('SafeERC20Namer')
const safeERC20NamerLibrary = ((await SafeERC20NamerFactory.deploy()) as unknown) as SafeERC20Namer
Expand Down Expand Up @@ -359,7 +363,8 @@ export class YieldEnvironment {

// ==== Make ilkIds the ilks, creating spot oracles and settting debt limits ====
const ratio = 1000000 // 1000000 == 100% collateralization ratio
for (let ilkId of ilkIds) {
for (let ilkId of assetIds) {
// Including ilkId == baseId
const spotSource = sources.get(ilkId) as ISourceMock
const base = assets.get(baseId) as ERC20Mock
const ilk = assets.get(ilkId) as ERC20Mock
Expand All @@ -376,7 +381,7 @@ export class YieldEnvironment {
let count: number = 1
for (let seriesId of seriesIds) {
const maturity = timestamp + THREE_MONTHS * count++
await wand.addSeries(seriesId, baseId, maturity, ilkIds, seriesId, seriesId)
await wand.addSeries(seriesId, baseId, maturity, assetIds, seriesId, seriesId)
const fyToken = (await ethers.getContractAt(
'FYToken',
(await cauldron.series(seriesId)).fyToken,
Expand All @@ -401,7 +406,8 @@ export class YieldEnvironment {
// For each series and ilk we create a vault - vaults[seriesId][ilkId] = vaultId
for (let seriesId of seriesIds) {
const seriesVaults: Map<string, string> = new Map()
for (let ilkId of ilkIds) {
for (let ilkId of assetIds) {
// Including a vault whose ilk equals its base
await ladle.build(seriesId, ilkId)
seriesVaults.set(ilkId, await getLastVaultId(cauldron))
}
Expand Down

0 comments on commit b725a02

Please sign in to comment.