Skip to content

Commit

Permalink
Merge c527e66 into 603fb76
Browse files Browse the repository at this point in the history
  • Loading branch information
alsco77 committed Mar 29, 2021
2 parents 603fb76 + c527e66 commit 4eeffeb
Show file tree
Hide file tree
Showing 144 changed files with 231,297 additions and 7,258 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ module.exports = {
"rules": {
"@typescript-eslint/no-use-before-define": 1,
"import/no-extraneous-dependencies": 1,
"no-nested-ternary": 1
"no-nested-ternary": 1,
"@typescript-eslint/dot-notation": 1
},
"overrides": [
{
Expand Down
2 changes: 1 addition & 1 deletion .solhint.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"rules": {
"avoid-suicide": "error",
"avoid-sha3": "warn",
"compiler-version": ["warn","^0.8.0"],
"compiler-version": ["warn","^0.8.2"],
"func-visibility": ["warn",{"ignoreConstructors":true}]
}
}
2 changes: 1 addition & 1 deletion contracts/buy-and-make/IConfigurableRightsPool.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.8.0;
pragma solidity 0.8.2;

interface IConfigurableRightsPool {
function joinswapExternAmountIn(
Expand Down
2 changes: 1 addition & 1 deletion contracts/buy-and-make/RevenueRecipient.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.8.0;
pragma solidity 0.8.2;

import { IRevenueRecipient } from "../interfaces/IRevenueRecipient.sol";
import { IConfigurableRightsPool } from "./IConfigurableRightsPool.sol";
Expand Down
938 changes: 938 additions & 0 deletions contracts/feeders/FeederLogic.sol

Large diffs are not rendered by default.

218 changes: 218 additions & 0 deletions contracts/feeders/FeederManager.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity 0.8.2;
pragma abicoder v2;

// External
import { IPlatformIntegration } from "../interfaces/IPlatformIntegration.sol";

// Internal
import "../masset/MassetStructs.sol";

// Libs
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { StableMath } from "../shared/StableMath.sol";

/**
* @title FeederManager
* @author mStable
* @notice Manager contract for fPools. Forked from `masset/Manager.sol`, and performs a subset of functionality
* related to basket management.
* @dev VERSION: 1.0
* DATE: 2021-03-01
*/
library FeederManager {
using SafeERC20 for IERC20;
using StableMath for uint256;

event BassetsMigrated(address[] bAssets, address newIntegrator);
event StartRampA(uint256 currentA, uint256 targetA, uint256 startTime, uint256 rampEndTime);
event StopRampA(uint256 currentA, uint256 time);

uint256 private constant MIN_RAMP_TIME = 1 days;
uint256 private constant MAX_A = 1e6;

/**
* @dev Calculates the gains accrued across all lending markets.
* @param _bAssetPersonal Basset personal storage array
* @param _bAssetData Basset data storage array
* @return idxs Array [0,1]
* @return rawGains Raw increases in vault Balance
*/
function calculatePlatformInterest(
BassetPersonal[] memory _bAssetPersonal,
BassetData[] storage _bAssetData
) external returns (uint8[] memory idxs, uint256[] memory rawGains) {
// Get basket details
BassetData[] memory bAssetData_ = _bAssetData;
uint256 count = bAssetData_.length;
idxs = new uint8[](count);
rawGains = new uint256[](count);
// 1. Calculate rawGains in each bAsset, in comparison to current vault balance
for (uint256 i = 0; i < count; i++) {
idxs[i] = uint8(i);
BassetPersonal memory bPersonal = _bAssetPersonal[i];
BassetData memory bData = bAssetData_[i];
// If there is no integration, then nothing can have accrued
if (bPersonal.integrator == address(0)) continue;
uint256 lending =
IPlatformIntegration(bPersonal.integrator).checkBalance(bPersonal.addr);
uint256 cache = 0;
if (!bPersonal.hasTxFee) {
cache = IERC20(bPersonal.addr).balanceOf(bPersonal.integrator);
}
uint256 balance = lending + cache;
uint256 oldVaultBalance = bData.vaultBalance;
if (balance > oldVaultBalance && bPersonal.status == BassetStatus.Normal) {
_bAssetData[i].vaultBalance = SafeCast.toUint128(balance);
uint256 interestDelta = balance - oldVaultBalance;
rawGains[i] = interestDelta;
} else {
rawGains[i] = 0;
}
}
}

/**
* @dev Transfers all collateral from one lending market to another - used initially
* to handle the migration between Aave V1 and Aave V2. Note - only supports non
* tx fee enabled assets. Supports going from no integration to integration, but
* not the other way around.
* @param _bAssetPersonal Basset data storage array
* @param _bAssets Array of basket assets to migrate
* @param _newIntegration Address of the new platform integration
*/
function migrateBassets(
BassetPersonal[] storage _bAssetPersonal,
address[] calldata _bAssets,
address _newIntegration
) external {
uint256 len = _bAssets.length;
require(len > 0, "Must migrate some bAssets");

for (uint256 i = 0; i < len; i++) {
// 1. Check that the bAsset is in the basket
address bAsset = _bAssets[i];
uint256 index = _getAssetIndex(_bAssetPersonal, bAsset);
require(!_bAssetPersonal[index].hasTxFee, "A bAsset has a transfer fee");

// 2. Withdraw everything from the old platform integration
address oldAddress = _bAssetPersonal[index].integrator;
require(oldAddress != _newIntegration, "Must transfer to new integrator");
(uint256 cache, uint256 lendingBal) = (0, 0);
if (oldAddress == address(0)) {
cache = IERC20(bAsset).balanceOf(address(this));
} else {
IPlatformIntegration oldIntegration = IPlatformIntegration(oldAddress);
cache = IERC20(bAsset).balanceOf(address(oldIntegration));
// 2.1. Withdraw from the lending market
lendingBal = oldIntegration.checkBalance(bAsset);
if (lendingBal > 0) {
oldIntegration.withdraw(address(this), bAsset, lendingBal, false);
}
// 2.2. Withdraw from the cache, if any
if (cache > 0) {
oldIntegration.withdrawRaw(address(this), bAsset, cache);
}
}
uint256 sum = lendingBal + cache;

// 3. Update the integration address for this bAsset
_bAssetPersonal[index].integrator = _newIntegration;

// 4. Deposit everything into the new
// This should fail if we did not receive the full amount from the platform withdrawal
// 4.1. Deposit all bAsset
IERC20(bAsset).safeTransfer(_newIntegration, sum);
IPlatformIntegration newIntegration = IPlatformIntegration(_newIntegration);
if (lendingBal > 0) {
newIntegration.deposit(bAsset, lendingBal, false);
}
// 4.2. Check balances
uint256 newLendingBal = newIntegration.checkBalance(bAsset);
uint256 newCache = IERC20(bAsset).balanceOf(address(newIntegration));
uint256 upperMargin = 10001e14;
uint256 lowerMargin = 9999e14;

require(
newLendingBal >= lendingBal.mulTruncate(lowerMargin) &&
newLendingBal <= lendingBal.mulTruncate(upperMargin),
"Must transfer full amount"
);
require(
newCache >= cache.mulTruncate(lowerMargin) &&
newCache <= cache.mulTruncate(upperMargin),
"Must transfer full amount"
);
}

emit BassetsMigrated(_bAssets, _newIntegration);
}

/**
* @dev Simply gets the asset index by looping through bAssets. Given there are only
* ever 2 assets, should not be gas intensive.
*/
function _getAssetIndex(BassetPersonal[] storage _bAssetPersonal, address _asset)
internal
view
returns (uint8 idx)
{
uint256 len = _bAssetPersonal.length;
for (uint8 i = 0; i < len; i++) {
if (_bAssetPersonal[i].addr == _asset) return i;
}
revert("Invalid asset");
}

/**
* @dev Starts changing of the amplification var A
* @param _targetA Target A value
* @param _rampEndTime Time at which A will arrive at _targetA
*/
function startRampA(
AmpData storage _ampData,
uint256 _targetA,
uint256 _rampEndTime,
uint256 _currentA,
uint256 _precision
) external {
require(
block.timestamp >= (_ampData.rampStartTime + MIN_RAMP_TIME),
"Sufficient period of previous ramp has not elapsed"
);
require(_rampEndTime >= (block.timestamp + MIN_RAMP_TIME), "Ramp time too short");
require(_targetA > 0 && _targetA < MAX_A, "A target out of bounds");

uint256 preciseTargetA = _targetA * _precision;

if (preciseTargetA > _currentA) {
require(preciseTargetA <= _currentA * 10, "A target increase too big");
} else {
require(preciseTargetA >= _currentA / 10, "A target decrease too big");
}

_ampData.initialA = SafeCast.toUint64(_currentA);
_ampData.targetA = SafeCast.toUint64(preciseTargetA);
_ampData.rampStartTime = SafeCast.toUint64(block.timestamp);
_ampData.rampEndTime = SafeCast.toUint64(_rampEndTime);

emit StartRampA(_currentA, preciseTargetA, block.timestamp, _rampEndTime);
}

/**
* @dev Stops the changing of the amplification var A, setting
* it to whatever the current value is.
*/
function stopRampA(AmpData storage _ampData, uint256 _currentA) external {
require(block.timestamp < _ampData.rampEndTime, "Amplification not changing");

_ampData.initialA = SafeCast.toUint64(_currentA);
_ampData.targetA = SafeCast.toUint64(_currentA);
_ampData.rampStartTime = SafeCast.toUint64(block.timestamp);
_ampData.rampEndTime = SafeCast.toUint64(block.timestamp);

emit StopRampA(_currentA, block.timestamp);
}
}

0 comments on commit 4eeffeb

Please sign in to comment.