Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Boni #521

Open
wants to merge 25 commits into
base: develop
Choose a base branch
from
Open

Boni #521

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b03e197
adding additional storage variables
sypeer Dec 22, 2021
eae9d3a
updated tToken strategy for compound with bonus int
sypeer Dec 22, 2021
24295bc
using 365 days instead of BLOCKS_PER_YEAR constant
sypeer Dec 23, 2021
7eb578c
removing unused uint
sypeer Dec 23, 2021
797401e
updating return
sypeer Dec 23, 2021
60aa92b
removing mint
sypeer Dec 23, 2021
9ec8896
updating strategy2 to extend from strategy1
sypeer Dec 23, 2021
cd1eb3b
adding virtual modifier to strategy1 init to allow for extensibility
sypeer Dec 27, 2021
d4db271
updating ttoken strategy deployment to pass in additional arg
sypeer Dec 27, 2021
62a14d8
updating test setup to set an allowance on the tToken from the 'gnosis'
sypeer Dec 27, 2021
eae86ef
gnosisSafe address > immutable, updating the int calc, +ing constructor
sypeer Dec 27, 2021
f297d8b
updating market config to use compound strategy 2
sypeer Dec 27, 2021
a65503e
basic test setup
sypeer Dec 27, 2021
e3c206a
updating testEnv to return hre
sypeer Dec 27, 2021
457daf4
updating tToken strategy test
sypeer Dec 27, 2021
01ee254
init funny?
sypeer Dec 30, 2021
34285bc
updating test setup to use a fresh deployment
sypeer Jan 3, 2022
7aa78ff
updating test to use moment to advance time
sypeer Jan 3, 2022
52411e5
parsing interest calc
sypeer Jan 3, 2022
26150cf
moving bonus int token approval to deploy script
sypeer Jan 3, 2022
6827a21
remove poly ci
sypeer Jan 3, 2022
b72e604
adding named signer `gnosisSafe`
sypeer Jan 4, 2022
bca1349
using gnosisSafe signer in place of deployer account
sypeer Jan 4, 2022
4b54ff4
adding allowance check for gnosisSafe account
sypeer Jan 4, 2022
f90f553
Move balance check inside if statement
Jan 4, 2022
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
36 changes: 0 additions & 36 deletions .github/workflows/run-ci-polygon.yml

This file was deleted.

2 changes: 1 addition & 1 deletion config/markets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const parseCompoundWeth = (sym: string): string => {
}

const compoundStrategy = (tokenSym: string): MarketStrategy => ({
name: 'TTokenCompoundStrategy_1',
name: 'TTokenCompoundStrategy_2',
initArgs: [
{
type: 'TokenSymbol',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,23 @@ contract TTokenCompoundStrategy_1 is RolesMods, TTokenStrategy {
* @dev it creates a reference to the TToken storage
*/
function() pure returns (TokenStorage.Store storage)
private constant tokenStore = TokenStorage.store;
internal constant tokenStore = TokenStorage.store;

/**
* @dev it creates a reference to the Compound storage
*/
function() pure returns (CompoundStorage.Store storage)
private constant compoundStore = CompoundStorage.store;
internal constant compoundStore = CompoundStorage.store;

string public constant NAME = "CompoundStrategy_1";
string public NAME;

/* External Functions */

/**
* @notice it returns the total supply of an underlying asset in a Teller token.
* @return uint256 the underlying supply
*/
function totalUnderlyingSupply() external override returns (uint256) {
function totalUnderlyingSupply() public virtual override returns (uint256) {
return
tokenStore().underlying.balanceOf(address(this)) +
compoundStore().cToken.balanceOfUnderlying(address(this));
Expand Down Expand Up @@ -170,14 +170,15 @@ contract TTokenCompoundStrategy_1 is RolesMods, TTokenStrategy {
address cTokenAddress,
uint16 balanceRatioMin,
uint16 balanceRatioMax
) external {
) public virtual {
require(
balanceRatioMax > balanceRatioMin,
"Teller: Max ratio balance should be greater than Min ratio balance"
);
compoundStore().cToken = ICErc20(cTokenAddress);
compoundStore().balanceRatioMin = balanceRatioMin;
compoundStore().balanceRatioMax = balanceRatioMax;
NAME = "CompoundStrategy_1";
emit StrategyInitialized(NAME, cTokenAddress, LibMeta.msgSender());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Contracts
import { TTokenCompoundStrategy_1 } from "./TTokenCompoundStrategy_1.sol";

// Interfaces
import { ICErc20 } from "../../../../shared/interfaces/ICErc20.sol";
import { LibMeta } from "../../../../shared/libraries/LibMeta.sol";

contract TTokenCompoundStrategy_2 is TTokenCompoundStrategy_1 {
address immutable bonusGnosisSafe;

/* External Functions */

function totalUnderlyingSupply() public override returns (uint256) {
// Get current supply
uint256 currentSupply = super.totalUnderlyingSupply();

// Calculate bonus interest due
uint256 interestTimeperiod = block.timestamp -
compoundStore().lastBonusIntTimestamp;
uint256 dailyInterest = ((currentSupply / 10) / 365 days) * 1 days;
uint256 bonusInterest = dailyInterest * (interestTimeperiod / 1 days);

if (bonusInterest > 0) {
uint256 gnosisBalance = tokenStore().underlying.balanceOf(
bonusGnosisSafe
);
if (gnosisBalance < bonusInterest) {
bonusInterest = gnosisBalance;
}

// Deposit into
tokenStore().underlying.transferFrom(
bonusGnosisSafe,
address(this),
bonusInterest
);
}

return currentSupply + bonusInterest;
}

/**
* @notice Sets the Compound token that should be used to manage the underlying Teller Token asset.
* @param cTokenAddress Address of the Compound token that has the same underlying asset as the TToken.
* @param balanceRatioMin Percentage indicating the _ limit of underlying token balance should remain on the TToken
* @param balanceRatioMax Percentage indicating the _ limit of underlying token balance should remain on the TToken
* @dev Note that the balanceRatio percentages have to be scaled by ONE_HUNDRED_PERCENT
*/
function init(
address cTokenAddress,
uint16 balanceRatioMin,
uint16 balanceRatioMax
) public override {
super.init(cTokenAddress, balanceRatioMin, balanceRatioMax);
compoundStore().lastBonusIntTimestamp = block.timestamp;
NAME = "CompoundStrategy_2";
}

/**
* @notice Sets the address of the bonus gnosis safe for the bonus interest disbursment
* @param _bonusGnosisSafe The address of the gnosisSafe to pull funds from for bonus interest
*/
constructor(address _bonusGnosisSafe) {
bonusGnosisSafe = _bonusGnosisSafe;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ struct Store {
ICErc20 cToken;
uint16 balanceRatioMax;
uint16 balanceRatioMin;
address bonusGnosisSafe;
uint256 lastBonusIntTimestamp;
}

bytes32 constant POSITION = keccak256(
Expand Down
42 changes: 35 additions & 7 deletions deploy/markets.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import colors from 'colors'
import { ContractTransaction } from 'ethers'
import { Contract, ContractTransaction } from 'ethers'
import { toBN } from 'hardhat'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
import { DeployFunction } from 'hardhat-deploy/types'

import { getDappAddresses, getMarkets, getSigners, getTokens } from '../config'
import { ITellerDiamond, ITToken } from '../types/typechain'
import { IERC20, ITellerDiamond, ITToken } from '../types/typechain'
import { NULL_ADDRESS } from '../utils/consts'
import { deploy } from '../utils/deploy-helpers'

Expand Down Expand Up @@ -102,15 +103,42 @@ const initializeMarkets: DeployFunction = async (hre) => {
})
}

const tTokenStrategy = await deploy({
hre,
contract: market.strategy.name,
indent: 4,
})
let tTokenStrategy: Contract

if (market.strategy.name == 'TTokenCompoundStrategy_2') {
tTokenStrategy = await deploy({
hre,
contract: market.strategy.name,
indent: 4,
args: [await (await getNamedSigner('gnosisSafe')).getAddress()],
})
} else {
tTokenStrategy = await deploy({
hre,
contract: market.strategy.name,
indent: 4,
})
}

const tToken = await contracts.get<ITToken>('ITToken', {
at: tTokenAddress,
})
// Setting approval for bonus int from deployer account
if (market.strategy.name == 'TTokenCompoundStrategy_2') {
const lendingToken = await contracts.get<IERC20>('IERC20', {
at: lendingTokenAddress,
})
const currentAllowance = await lendingToken.allowance(
await (await getNamedSigner('gnosisSafe')).getAddress(),
tTokenAddress
)

if (currentAllowance.eq('0')) {
await lendingToken
.connect(await getNamedSigner('gnosisSafe'))
.approve(tTokenAddress, toBN('1000000', '18'))
}
}
const currentStrategy = await tToken.getStrategy()
if (currentStrategy !== tTokenStrategy.address) {
log(`Setting new TToken strategy...:`, {
Expand Down
4 changes: 4 additions & 0 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,10 @@ export default <HardhatUserConfig>{
hardhat: 11,
localhost: 11,
},
gnosisSafe: {
hardhat: 13,
localhost: 13,
},
},
networks: {
kovan: networkConfig({
Expand Down
20 changes: 18 additions & 2 deletions test/helpers/set-test-env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { Signer } from 'ethers'
import hre, { toBN } from 'hardhat'
import { HardhatRuntimeEnvironment } from 'hardhat/types'

import {
getPlatformSetting,
Expand All @@ -29,20 +30,24 @@ export interface TestEnv {
deployer: Signer
lender: Signer
borrower: Signer
gnosisSafe: Signer
tellerDiamond: ITellerDiamond
priceAggregator: PriceAggregator
nft: PolyTellerNFTMock | MainnetTellerNFT
tokens: TokenData[]
hre: HardhatRuntimeEnvironment
}

const testEnv: TestEnv = {
deployer: {} as Signer,
lender: {} as Signer,
borrower: {} as Signer,
gnosisSafe: {} as Signer,
tellerDiamond: {} as ITellerDiamond,
priceAggregator: {} as PriceAggregator,
nft: {} as PolyTellerNFTMock | MainnetTellerNFT,
tokens: [] as TokenData[],
hre: {} as HardhatRuntimeEnvironment,
} as TestEnv

const { contracts, deployments, getNamedSigner, tokens } = hre
Expand All @@ -52,10 +57,12 @@ export async function initTestEnv() {
testEnv.deployer = await getNamedSigner('deployer')
testEnv.lender = await getNamedSigner('lender')
testEnv.borrower = await getNamedSigner('borrower')
testEnv.gnosisSafe = await getNamedSigner('gnosisSafe')
testEnv.hre = hre

// Get a fresh market
await deployments.fixture('markets', {
keepExistingDeployments: true,
keepExistingDeployments: false,
})

testEnv.tellerDiamond = await contracts.get('TellerDiamond')
Expand Down Expand Up @@ -128,7 +135,7 @@ export const revertHead = async () => {
}

const fundMarket = async (testEnv: TestEnv) => {
const { tellerDiamond, lender } = testEnv
const { tellerDiamond, lender, deployer, gnosisSafe } = testEnv
// Get list of tokens
const dai = await tokens.get('DAI')
const collateralTokens = Array.from(
Expand Down Expand Up @@ -158,6 +165,15 @@ const fundMarket = async (testEnv: TestEnv) => {
amount: bnedAmount,
hre,
})

// Get funds for deployer for bonus int
await getFunds({
to: gnosisSafe,
tokenSym: await token.symbol(),
amount: bnedAmount,
hre,
})

// Approve protocol
await token
.connect(lender)
Expand Down
66 changes: 66 additions & 0 deletions test/lending/bonusIntStrategy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import chai, { expect } from 'chai'
import { solidity } from 'ethereum-waffle'
import { contracts, ethers, network, toBN } from 'hardhat'
import moment from 'moment'

import { ERC20, TTokenV3 } from '../../types/typechain'
import { getFunds } from '../helpers/get-funds'
import { advanceBlock } from '../helpers/misc'
import { setTestEnv, TestEnv } from '../helpers/set-test-env'

chai.should()
chai.use(solidity)

setTestEnv('Lending - TToken bonus interest', (testEnv: TestEnv) => {
it.only('Should accurately dispense the bonus interest', async () => {
// Load tToken
const { tokens, tellerDiamond, lender, hre } = testEnv

const dai: ERC20 = tokens.find((o) => o.name === 'DAI')!.token
sypeer marked this conversation as resolved.
Show resolved Hide resolved

const tDai = await contracts.get<TTokenV3>('ITToken', {
at: await tellerDiamond.getTTokenFor(dai.address),
})

const bnedAmount = toBN(1000, 18)

// Get funds for lender
await getFunds({
to: lender,
tokenSym: await dai.symbol(),
amount: bnedAmount,
hre,
})

// Deposit as lender
const exchangeRateBefore = await tDai.callStatic.exchangeRate()
const totalUnderlyingBefore = await tDai.callStatic.totalUnderlyingSupply()

// Approve protocol
await dai
.connect(lender)
.approve(tDai.address, bnedAmount)
.then(({ wait }) => wait())
// Deposit funds
await tDai
.connect(lender)
.mint(bnedAmount)
.then(({ wait }) => wait())

// Advance time
await hre.ethers.provider.send('evm_increaseTime', [
moment.duration(365, 'days').asSeconds(),
])
await hre.ethers.provider.send('evm_mine', [])

// Check tToken total underlying
const totalUnderlyingAfter = await tDai.callStatic.totalUnderlyingSupply()

// Check tToken exchange rate
const exchangeRateAfter = await tDai.callStatic.exchangeRate()

// Assertions
expect(totalUnderlyingAfter).to.be.gt(totalUnderlyingBefore.add(bnedAmount))
expect(exchangeRateAfter).to.be.gt(exchangeRateBefore)
})
})