Skip to content

Commit

Permalink
Add caveat to connector balance checking
Browse files Browse the repository at this point in the history
  • Loading branch information
superduck35 committed Jan 1, 2021
1 parent b30c5a8 commit 558d86d
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 68 deletions.
36 changes: 23 additions & 13 deletions contracts/savings/SavingsContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ contract SavingsContract is

event AutomaticInterestCollectionSwitched(bool automationEnabled);

// Connector poking
event PokerUpdated(address poker);

event FractionUpdated(uint256 fraction);
Expand All @@ -54,6 +55,7 @@ contract SavingsContract is
// Rate between 'savings credits' and underlying
// e.g. 1 credit (1e17) mulTruncate(exchangeRate) = underlying, starts at 10:1
// exchangeRate increases over time
uint256 private constant startingRate = 1e17;
uint256 public exchangeRate;

// Underlying asset is underlying
Expand Down Expand Up @@ -99,7 +101,7 @@ contract SavingsContract is

fraction = 2e17;
automateInterestCollection = true;
exchangeRate = 1e17;
exchangeRate = startingRate;
}

/** @dev Only the savings managaer (pulled from Nexus) can execute this */
Expand Down Expand Up @@ -167,8 +169,8 @@ contract SavingsContract is
external
returns (uint256 creditsIssued)
{
require(exchangeRate == 1e17, "Can only use this method before streaming begins");
return _deposit(_underlying, _beneficiary, true);
require(exchangeRate == startingRate, "Can only use this method before streaming begins");
return _deposit(_underlying, _beneficiary, false);
}

/**
Expand All @@ -183,7 +185,7 @@ contract SavingsContract is
external
returns (uint256 creditsIssued)
{
return _deposit(_underlying, msg.sender, false);
return _deposit(_underlying, msg.sender, true);
}

/**
Expand All @@ -199,21 +201,21 @@ contract SavingsContract is
external
returns (uint256 creditsIssued)
{
return _deposit(_underlying, _beneficiary, false);
return _deposit(_underlying, _beneficiary, true);
}

/**
* @dev Internally deposit the _underlying from the sender and credit the beneficiary with new imUSD
*/
function _deposit(uint256 _underlying, address _beneficiary, bool _skipCollection)
function _deposit(uint256 _underlying, address _beneficiary, bool _collectInterest)
internal
returns (uint256 creditsIssued)
{
require(_underlying > 0, "Must deposit something");

// Collect recent interest generated by basket and update exchange rate
IERC20 mAsset = underlying;
if(!_skipCollection){
if(_collectInterest){
ISavingsManager(_savingsManager()).collectAndDistributeInterest(address(mAsset));
}

Expand Down Expand Up @@ -474,7 +476,7 @@ contract SavingsContract is

// check total collateralisation of credits
CachedData memory data = _cacheData();
// use rawBalance as the liquidity in the connector is not written off
// use rawBalance as the remaining liquidity in the connector is now written off
_refreshExchangeRate(data.rawBalance, data.totalCredits, true);

emit EmergencyUpdate();
Expand All @@ -501,24 +503,32 @@ contract SavingsContract is
// 2. Check and verify new connector balance
uint256 lastBalance_ = lastBalance;
uint256 connectorBalance = connector_.checkBalance();
// Always expect the collateral in the connector to increase in value
// Always expect the collateral in the connector to increase in value
require(connectorBalance >= lastBalance_, "Invalid yield");
if(connectorBalance > 0){
// Validate the collection by ensuring that the APY is not ridiculous (forked from SavingsManager)
// Validate the collection by ensuring that the APY is not ridiculous (forked from SavingsManager)
_validateCollection(lastBalance_, connectorBalance.sub(lastBalance_), timeSinceLastPoke);
}

// 3. Level the assets to Fraction (connector) & 100-fraction (raw)
uint256 realSum = _data.rawBalance.add(connectorBalance);
uint256 ideal = realSum.mulTruncate(_data.fraction);
// If there is not enough mAsset in the connector, then deposit
if(ideal > connectorBalance){
uint256 deposit = ideal.sub(connectorBalance);
underlying.approve(address(connector_), deposit);
connector_.deposit(deposit);
} else {
connector_.withdraw(connectorBalance.sub(ideal));
}
// TODO - check balance here again and update exchange rate accordingly
// Else withdraw, if there is too much mAsset in the connector
else if(connectorBalance > ideal) {
// If fraction == 0, then withdraw everything
if(ideal == 0){
connector_.withdrawAll();
} else {
connector_.withdraw(connectorBalance.sub(ideal));
}
}
// Else ideal == connectorBalance (e.g. 0), do nothing

// 4i. Refresh exchange rate and emit event
lastBalance = ideal;
Expand Down
6 changes: 6 additions & 0 deletions contracts/savings/peripheral/Connector_yVault_mUSD.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ contract Connector_yVault_mUSD is IConnector {
IERC20(mUSD).transfer(save, _amt);
}

function withdrawAll(uint256 _amt) external onlySave {
// getBalanceOf shares
// withdraw all
// send all to save
}

function checkBalance() external view returns (uint256) {
// TODO - if using meta pool LP token, account for coordinated flash loan scenario
uint256 sharePrice = IyVault(yVault).getPricePerFullShare();
Expand Down
10 changes: 8 additions & 2 deletions contracts/savings/peripheral/Connector_yVault_mUSD3Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,20 @@ contract Connector_yVault_mUSD3Pool is IConnector {
IERC20(mUSD).transfer(save, _amt);
}

function withdrawAll(uint256 _amt) external onlySave {
// getBalanceOf shares
// withdraw all
// send all to save
}

// Steps:
// - Get total mUSD3Pool balance held in yVault
// - Get yVault share balance
// - Get yVault share to mUSD3Pool ratio
// - Get exchange rate between mUSD3Pool LP and mUSD (virtual price?)
// To consider: if using virtual price, and mUSD is initially traded at a discount,
// then depositing 10k mUSD is likely to net a virtual amount of 9.97k or so. Somehow
// need to make
// then depositing 10k mUSD is likely to net a virtual amount of 9.97k or so. Can either take
// a deficit to begin with, or track the amount of units deposited
function checkBalance() external view returns (uint256) {
// TODO - if using meta pool LP token, account for coordinated flash loan scenario
uint256 sharePrice = IyVault(yVault).getPricePerFullShare();
Expand Down
28 changes: 26 additions & 2 deletions contracts/savings/peripheral/IConnector.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,31 @@ pragma solidity 0.5.16;


interface IConnector {
function deposit(uint256) external;
function withdraw(uint256) external;

/**
* @notice Deposits the mAsset into the connector
* @param _amount Units of mAsset to receive and deposit
*/
function deposit(uint256 _amount) external;

/**
* @notice Withdraws a specific amount of mAsset from the connector
* @param _amount Units of mAsset to withdraw
*/
function withdraw(uint256 _amount) external;

/**
* @notice Withdraws all mAsset from the connector
*/
function withdrawAll() external;

/**
* @notice Returns the available balance in the connector. In connections
* where there is likely to be an initial dip in value due to conservative
* exchange rates (e.g. with Curves `get_virtual_price`), it should return
* max(deposited, balance) to avoid temporary negative yield. Any negative yield
* should be corrected during a withdrawal or over time.
* @return Balance of mAsset in the connector
*/
function checkBalance() external view returns (uint256);
}
45 changes: 0 additions & 45 deletions contracts/savings/peripheral/SaveAndStake.sol

This file was deleted.

8 changes: 4 additions & 4 deletions test/masset/TestMassetCache.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -465,12 +465,12 @@ contract("Masset - Cache", async (accounts) => {
await massetDetails.mAsset.approve(systemMachine.savingsContract.address, new BN(1), {
from: sa.default,
});
await systemMachine.savingsContract.depositSavings(new BN(1), {
await systemMachine.savingsContract.methods["depositSavings(uint256)"](new BN(1), {
from: sa.default,
});
await assertSwap(massetDetails, bAssets[1], bAssets[2], new BN(1), true);
await massetDetails.mAsset.approve(systemMachine.savingsContract.address, new BN(1));
await systemMachine.savingsContract.depositSavings(new BN(1));
await systemMachine.savingsContract.methods["depositSavings(uint256)"](new BN(1));
};
it("should exec with 0%", async () => {
await massetDetails.mAsset.setCacheSize(0, {
Expand Down Expand Up @@ -707,7 +707,7 @@ contract("Masset - Cache", async (accounts) => {
await massetDetails.mAsset.approve(systemMachine.savingsContract.address, new BN(1), {
from: sa.default,
});
await systemMachine.savingsContract.depositSavings(new BN(1), {
await systemMachine.savingsContract.methods["depositSavings(uint256)"](new BN(1), {
from: sa.default,
});
const compositionAfter = await massetMachine.getBasketComposition(massetDetails);
Expand All @@ -722,7 +722,7 @@ contract("Masset - Cache", async (accounts) => {
await massetDetails.mAsset.approve(systemMachine.savingsContract.address, new BN(1), {
from: sa.default,
});
await systemMachine.savingsContract.depositSavings(new BN(1), {
await systemMachine.savingsContract.methods["depositSavings(uint256)"](new BN(1), {
from: sa.default,
});

Expand Down
2 changes: 1 addition & 1 deletion test/savings/TestSavingsContract.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ contract("SavingsContract", async (accounts) => {
const TEN_EXACT = new BN(10).mul(fullScale);
const ONE_EXACT = fullScale;
const initialMint = new BN(1000000000);
const initialExchangeRate = fullScale.divn(10);
const initialExchangeRate = simpleToExactAmount(1, 17);

let systemMachine: SystemMachine;
let massetDetails: MassetDetails;
Expand Down
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4860,7 +4860,7 @@ inherits@2.0.3:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=

ini@^1.3.4, ini@^1.3.5, ini@~1.3.0:
ini@^1.3.5:
version "1.3.8"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
Expand Down

0 comments on commit 558d86d

Please sign in to comment.