Skip to content
Merged
1 change: 0 additions & 1 deletion contracts/connectors/loantoken/LoanTokenLogicLM.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,4 @@ contract LoanTokenLogicLM is LoanTokenLogicStandard {
_safeTransfer(loanTokenAddress, receiver, redeemed, "asset transfer failed");
}
}

}
3 changes: 1 addition & 2 deletions contracts/connectors/loantoken/LoanTokenLogicStandard.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1481,7 +1481,7 @@ contract LoanTokenLogicStandard is LoanTokenSettingsLowerAdmin {
}

function _burnFromLM(uint256 burnAmount) internal returns (uint256) {
uint balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(address(this), msg.sender);
uint256 balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(address(this), msg.sender);
require(balanceOnLM.add(balanceOf(msg.sender)) >= burnAmount, "not enough balance");

if (balanceOnLM > 0) {
Expand All @@ -1495,5 +1495,4 @@ contract LoanTokenLogicStandard is LoanTokenSettingsLowerAdmin {
//burn the tokens of the msg.sender
return _burnToken(burnAmount);
}

}
23 changes: 23 additions & 0 deletions contracts/feeds/IV1PoolOracle.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
pragma solidity >=0.5.0 <0.6.0;

interface IV1PoolOracle {
function read(uint256 price, uint256 timestamp)
external
view
returns (
uint256,
uint256,
uint256,
uint256,
uint256,
uint256
);

function latestAnswer() external view returns (uint256);

function liquidityPool() external view returns (address);
}

interface ILiquidityPoolV1Converter {
function reserveTokens(uint256 index) external view returns (address);
}
113 changes: 113 additions & 0 deletions contracts/feeds/PriceFeedV1PoolOracle.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
pragma solidity >=0.5.0 <0.6.0;

import "./PriceFeeds.sol";
import "./IV1PoolOracle.sol";
import "../openzeppelin/Ownable.sol";
import "../openzeppelin/Address.sol";
import "../openzeppelin/SafeMath.sol";
import "./IPriceFeeds.sol";

/**
* @notice The Price Feed V1 Pool Oracle contract.
*
* This contract implements V1 Pool Oracle query functionality,
* getting the price and the last timestamp from an external oracle contract.
* */
contract PriceFeedV1PoolOracle is IPriceFeedsExt, Ownable {
using SafeMath for uint256;
/* Storage */

address public v1PoolOracleAddress;
address public wRBTCAddress;
address public docAddress;

/* Events */
event SetV1PoolOracleAddress(address indexed v1PoolOracleAddress, address changerAddress);
event SetWRBTCAddress(address indexed wRBTCAddress, address changerAddress);
event SetDOCAddress(address indexed docAddress, address changerAddress);

/* Functions */

/**
* @notice Initialize a new V1 Pool Oracle.
*
* @param _v1PoolOracleAddress The V1 Pool Oracle address.
* @param _wRBTCAddress The wrbtc token address.
* @param _docAddress The doc token address.
* */
constructor(
address _v1PoolOracleAddress,
address _wRBTCAddress,
address _docAddress
) public {
setV1PoolOracleAddress(_v1PoolOracleAddress);
setRBTCAddress(_wRBTCAddress);
setDOCAddress(_docAddress);
}

/**
* @notice Get the oracle price.
* @return The price from Oracle.
* */
function latestAnswer() external view returns (uint256) {
IV1PoolOracle _v1PoolOracle = IV1PoolOracle(v1PoolOracleAddress);
// Need to check, if the requested asset is BTC
address liquidityPool = _v1PoolOracle.liquidityPool();
require(
ILiquidityPoolV1Converter(liquidityPool).reserveTokens(0) != wRBTCAddress ||
ILiquidityPoolV1Converter(liquidityPool).reserveTokens(1) != wRBTCAddress,
"wrBTC price feed cannot use the oracle v1 pool"
);

uint256 _price = _v1PoolOracle.latestAnswer();

// Need to convert to USD, since the V1 pool return value is based on BTC
uint256 priceInUSD = _convertAnswerToUsd(_price);
require(priceInUSD != 0, "price error");

return priceInUSD;
}

function _convertAnswerToUsd(uint256 _valueInBTC) private view returns (uint256) {
address _priceFeeds = msg.sender;

uint256 precision = IPriceFeeds(_priceFeeds).queryPrecision(wRBTCAddress, docAddress);
uint256 valueInUSD = IPriceFeeds(_priceFeeds).queryReturn(wRBTCAddress, docAddress, _valueInBTC);

/// Need to multiply by query precision (doc's precision) and divide by 1*10^8 (Because the based price in v1 pool is in rBTC(8 decimals))
return valueInUSD.mul(precision).div(1e8);
}

/**
* @notice Set the V1 Pool Oracle address.
*
* @param _v1PoolOracleAddress The V1 Pool Oracle address.
*/
function setV1PoolOracleAddress(address _v1PoolOracleAddress) public onlyOwner {
require(Address.isContract(_v1PoolOracleAddress), "_v1PoolOracleAddress not a contract");
v1PoolOracleAddress = _v1PoolOracleAddress;
emit SetV1PoolOracleAddress(v1PoolOracleAddress, msg.sender);
}

/**
* @notice Set the rBtc address. V1 pool based price is BTC, so need to convert the value from v1 pool to USD. That's why we need to get the price of the rBtc
*
* @param _wRBTCAddress The rBTC address
*/
function setRBTCAddress(address _wRBTCAddress) public onlyOwner {
require(_wRBTCAddress != address(0), "wRBTC address cannot be zero address");
wRBTCAddress = _wRBTCAddress;
emit SetWRBTCAddress(wRBTCAddress, msg.sender);
}

/**
* @notice Set the rBtc address. V1 pool based price is BTC, so need to convert the value from v1 pool to USD. That's why we need to get the price of the rBtc
*
* @param _docAddress The rBTC address
*/
function setDOCAddress(address _docAddress) public onlyOwner {
require(_docAddress != address(0), "DOC address cannot be zero address");
docAddress = _docAddress;
emit SetDOCAddress(_docAddress, msg.sender);
}
}
12 changes: 12 additions & 0 deletions contracts/mockup/LiquidityPoolV1ConverterMockup.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
pragma solidity 0.5.17;

import "../interfaces/IERC20.sol";

contract LiquidityPoolV1ConverterMockup {
IERC20[] public reserveTokens;

constructor(IERC20 _token0, IERC20 _token1) public {
reserveTokens.push(_token0);
reserveTokens.push(_token1);
}
}
Comment on lines +1 to +12
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider using hh waffle mock https://ethereum-waffle.readthedocs.io/en/latest/mock-contract.html
it prevents polluting the codebase, easy to use and flexible: just name methods and return values right in the test

5 changes: 2 additions & 3 deletions contracts/mockup/StakingMockup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ contract StakingMockup is Staking {
}

/**
* @dev We need this function to simulate zero delegate checkpoint value.
*/
* @dev We need this function to simulate zero delegate checkpoint value.
*/
function setDelegateStake(
address delegatee,
uint256 lockedTS,
Expand All @@ -60,5 +60,4 @@ contract StakingMockup is Staking {
bytes32 codeHash = _getCodeHash(_contract);
return vestingCodeHashes[codeHash];
}

}
30 changes: 14 additions & 16 deletions contracts/mockup/VestingLogicMockup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,18 @@ pragma experimental ABIEncoderV2;
import "../governance/Vesting/VestingLogic.sol";

contract VestingLogicMockup is VestingLogic {
/**
* @dev we had a bug in a loop: "i < endDate" instead of "i <= endDate"
*/
function delegate(address _delegatee) public onlyTokenOwner {
require(_delegatee != address(0), "delegatee address invalid");
Comment on lines +7 to +11
Copy link
Contributor

@tjcloa tjcloa Jul 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls check that your formatter settings correspond to those in development branch and prettier is active


/**
* @dev we had a bug in a loop: "i < endDate" instead of "i <= endDate"
*/
function delegate(address _delegatee) public onlyTokenOwner {
require(_delegatee != address(0), "delegatee address invalid");

/// @dev Withdraw for each unlocked position.
/// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS
/// workaround found, but it doesn't work with TWO_WEEKS
for (uint256 i = startDate + cliff; i < endDate; i += FOUR_WEEKS) {
staking.delegate(_delegatee, i);
}
emit VotesDelegated(msg.sender, _delegatee);
}

}
/// @dev Withdraw for each unlocked position.
/// @dev Don't change FOUR_WEEKS to TWO_WEEKS, a lot of vestings already deployed with FOUR_WEEKS
/// workaround found, but it doesn't work with TWO_WEEKS
for (uint256 i = startDate + cliff; i < endDate; i += FOUR_WEEKS) {
staking.delegate(_delegatee, i);
}
emit VotesDelegated(msg.sender, _delegatee);
}
}
1 change: 1 addition & 0 deletions hardhat-ganache-tests.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ require("@nomiclabs/hardhat-ganache");
require("@nomiclabs/hardhat-truffle5");
require("@nomiclabs/hardhat-ethers");
require("@nomiclabs/hardhat-web3");
require("@nomiclabs/hardhat-waffle");
require("hardhat-contract-sizer"); //yarn run hardhat size-contracts
require("solidity-coverage"); // $ npx hardhat coverage
require("hardhat-log-remover");
Expand Down
1 change: 1 addition & 0 deletions hardhat.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ require("@nomiclabs/hardhat-ganache");
require("@nomiclabs/hardhat-truffle5");
require("@nomiclabs/hardhat-ethers");
require("@nomiclabs/hardhat-web3");
require("@nomiclabs/hardhat-waffle");
require("hardhat-contract-sizer"); //yarn run hardhat size-contracts
require("solidity-coverage"); // $ npx hardhat coverage
require("hardhat-log-remover");
Expand Down
Loading