Skip to content

Commit

Permalink
Merge 2951407 into 83d8e98
Browse files Browse the repository at this point in the history
  • Loading branch information
ororopickpocket authored Jun 9, 2021
2 parents 83d8e98 + 2951407 commit 2f5b900
Show file tree
Hide file tree
Showing 27 changed files with 843 additions and 222 deletions.
7 changes: 4 additions & 3 deletions contracts/connectors/loantoken/LoanTokenBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ contract LoanTokenBase is ReentrancyGuard, Ownable, Pausable {
/// Price of token at last user checkpoint.
mapping(address => uint256) internal checkpointPrices_;

/// The maximum trading/borrowing/lending limit per token address.
/// 0 -> no limit
mapping(address => uint256) public transactionLimit;
// the maximum trading/borrowing/lending limit per token address
mapping(address => uint256) public transactionLimit;
// 0 -> no limit

}
60 changes: 60 additions & 0 deletions contracts/connectors/loantoken/LoanTokenLogicLM.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
pragma solidity 0.5.17;
pragma experimental ABIEncoderV2;

import "./LoanTokenLogicStandard.sol";

contract LoanTokenLogicLM is LoanTokenLogicStandard {
/**
* @notice deposit into the lending pool and optionally participate at the Liquidity Mining Program
* @param receiver the receiver of the tokens
* @param depositAmount The amount of underlying tokens provided on the loan.
* (Not the number of loan tokens to mint).
* @param useLM if true -> deposit the pool tokens into the Liquidity Mining contract
*/
function mint(address receiver, uint256 depositAmount, bool useLM) external nonReentrant returns (uint256 minted) {
if(useLM) return _mintWithLM(receiver, depositAmount);
else return _mintToken(receiver, depositAmount);
}

function _mintWithLM(address receiver, uint256 depositAmount) internal returns (uint256 minted) {
//mint the tokens for the receiver
minted = _mintToken(receiver, depositAmount);

//transfer the tokens from the receiver to the LM address
_internalTransferFrom(receiver, liquidityMiningAddress, minted, minted);

//inform the LM mining contract
ILiquidityMining(liquidityMiningAddress).onTokensDeposited(receiver, minted);
}

/**
* @notice withdraws from the lending pool and optionally retrieves the pool tokens from the
* Liquidity Mining Contract
* @param receiver the receiver of the underlying tokens. note: potetial LM rewards are always sent to the msg.sender
* @param burnAmount The amount of pool tokens to redeem.
* @param useLM if true -> deposit the pool tokens into the Liquidity Mining contract
*/
function burn(address receiver, uint256 burnAmount, bool useLM) external nonReentrant returns (uint256 redeemed) {
if(useLM) redeemed = _burnFromLM(burnAmount);
else redeemed = _burnToken(burnAmount);
//this needs to be here and not in _burnTokens because of the WRBTC implementation
if (redeemed != 0) {
_safeTransfer(loanTokenAddress, receiver, redeemed, "asset transfer failed");
}
}

function _burnFromLM(uint256 burnAmount) internal returns (uint256) {
//withdraw pool tokens and LM rewards to the passed address
ILiquidityMining(liquidityMiningAddress).withdraw(address(this), burnAmount, msg.sender);
//burn the tokens of the msg.sender
return _burnToken(burnAmount);
}

/**
* @notice sets the liquidity mining contract address
* @param LMAddress the address of the liquidity mining contract
*/
function setLiquidityMiningAddress(address LMAddress) external onlyOwner {
liquidityMiningAddress = LMAddress;
}
}
90 changes: 54 additions & 36 deletions contracts/connectors/loantoken/LoanTokenLogicStandard.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pragma experimental ABIEncoderV2;
import "./LoanTokenSettingsLowerAdmin.sol";
import "./interfaces/ProtocolLike.sol";
import "./interfaces/FeedsLike.sol";
import "../../farm/ILiquidityMining.sol";

/**
* @title Loan Token Logic Standard contract.
Expand Down Expand Up @@ -79,10 +80,7 @@ contract LoanTokenLogicStandard is LoanTokenSettingsLowerAdmin {
*
* @return The amount of loan tokens minted.
* */
function mint(address receiver, uint256 depositAmount) external nonReentrant hasEarlyAccessToken returns (uint256 mintAmount) {
/// Temporary: limit transaction size
if (transactionLimit[loanTokenAddress] > 0) require(depositAmount <= transactionLimit[loanTokenAddress]);

function mint(address receiver, uint256 depositAmount) external nonReentrant returns (uint256 mintAmount) {
return _mintToken(receiver, depositAmount);
}

Expand All @@ -101,6 +99,7 @@ contract LoanTokenLogicStandard is LoanTokenSettingsLowerAdmin {
function burn(address receiver, uint256 burnAmount) external nonReentrant returns (uint256 loanAmountPaid) {
loanAmountPaid = _burnToken(burnAmount);

//this needs to be here and not in _burnTokens because of the WRBTC implementation
if (loanAmountPaid != 0) {
_safeTransfer(loanTokenAddress, receiver, loanAmountPaid, "5");
}
Expand Down Expand Up @@ -203,7 +202,6 @@ contract LoanTokenLogicStandard is LoanTokenSettingsLowerAdmin {
public
payable
nonReentrant /// Note: needs to be removed to allow flashloan use cases.
hasEarlyAccessToken
returns (
uint256,
uint256 /// Returns new principal and new collateral added to loan.
Expand Down Expand Up @@ -309,7 +307,6 @@ contract LoanTokenLogicStandard is LoanTokenSettingsLowerAdmin {
public
payable
nonReentrant /// Note: needs to be removed to allow flashloan use cases.
hasEarlyAccessToken
returns (
uint256,
uint256 /// Returns new principal and new collateral added to trade.
Expand Down Expand Up @@ -438,8 +435,12 @@ contract LoanTokenLogicStandard is LoanTokenSettingsLowerAdmin {
/// @dev Handle checkpoint update.
uint256 _currentPrice = tokenPrice();

_updateCheckpoints(_from, _balancesFrom, _balancesFromNew, _currentPrice);
_updateCheckpoints(_to, _balancesTo, _balancesToNew, _currentPrice);
//checkpoints are not being used by the smart contract logic itself, but just for external use (query the profit)
//only update the checkpoints of a user if he's not depositing to / withdrawing from the lending pool
if (_from != liquidityMiningAddress && _to != liquidityMiningAddress) {
_updateCheckpoints(_from, _balancesFrom, _balancesFromNew, _currentPrice);
_updateCheckpoints(_to, _balancesTo, _balancesToNew, _currentPrice);
}

emit Transfer(_from, _to, _value);
return true;
Expand Down Expand Up @@ -489,7 +490,7 @@ contract LoanTokenLogicStandard is LoanTokenSettingsLowerAdmin {
function profitOf(address user) public view returns (int256) {
/// @dev keccak256("iToken_ProfitSoFar")
bytes32 slot = keccak256(abi.encodePacked(user, iToken_ProfitSoFar));

//TODO + LM balance
return _profitOf(slot, balances[user], tokenPrice(), checkpointPrices_[user]);
}

Expand Down Expand Up @@ -792,34 +793,50 @@ contract LoanTokenLogicStandard is LoanTokenSettingsLowerAdmin {
/* Internal functions */

/**
* @notice A wrapper for AdvancedToken::_mint
*
* @param receiver The account getting the minted tokens.
* @param depositAmount The amount of underlying tokens provided on the loan.
*
* @return The amount of loan tokens minted.
* */
* @notice transfers the underlying asset from the msg.sender and mints tokens for the receiver
* @param receiver the address of the iToken receiver
* @param depositAmount the amount of underlying assets to be deposited
* @return the amount of iTokens issued
*/
function _mintToken(address receiver, uint256 depositAmount) internal returns (uint256 mintAmount) {
uint256 currentPrice;

//calculate amount to mint and transfer the underlying asset
(mintAmount, currentPrice) = _prepareMinting(depositAmount);

//compute balances needed for checkpoint update, considering that the user might have a pool token balance
//on the liquidity mining contract
uint256 balanceOnLM = 0;
if (liquidityMiningAddress != address(0))
balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(address(this), receiver);
uint256 oldBalance = balances[receiver].add(balanceOnLM);
uint256 newBalance = oldBalance.add(mintAmount);

//mint the tokens to the receiver
_mint(receiver, mintAmount, depositAmount, currentPrice);

//update the checkpoint of the receiver
_updateCheckpoints(receiver, oldBalance, newBalance, currentPrice);
}

/**
* calculates the amount of tokens to mint and transfers the underlying asset to this contract
* @param depositAmount the amount of the underyling asset deposited
* @return the amount to be minted
*/
function _prepareMinting(uint256 depositAmount) internal returns (uint256 mintAmount, uint256 currentPrice) {
require(depositAmount != 0, "17");

_settleInterest();

uint256 currentPrice = _tokenPrice(_totalAssetSupply(0));
currentPrice = _tokenPrice(_totalAssetSupply(0));
mintAmount = depositAmount.mul(10**18).div(currentPrice);

if (msg.value == 0) {
_safeTransferFrom(loanTokenAddress, msg.sender, address(this), depositAmount, "18");
} else {
IWrbtc(wrbtcTokenAddress).deposit.value(depositAmount)();
}

uint256 oldBalance = balances[receiver];
_updateCheckpoints(
receiver,
oldBalance,
_mint(receiver, mintAmount, depositAmount, currentPrice), /// newBalance
currentPrice
);
}

/**
Expand Down Expand Up @@ -847,18 +864,19 @@ contract LoanTokenLogicStandard is LoanTokenSettingsLowerAdmin {
loanAmountPaid = loanAmountOwed;
require(loanAmountPaid <= loanAmountAvailableInContract, "37");

uint256 oldBalance = balances[msg.sender];
//compute balances needed for checkpoint update, considering that the user might have a pool token balance
//on the liquidity mining contract
uint256 balanceOnLM = 0;
if (liquidityMiningAddress != address(0))
balanceOnLM = ILiquidityMining(liquidityMiningAddress).getUserPoolTokenBalance(address(this), msg.sender);
uint256 oldBalance = balances[msg.sender].add(balanceOnLM);
uint256 newBalance = oldBalance.sub(burnAmount);

/**
* @dev This function does not only update the checkpoints but also
* the current profit of the user.
* */
_updateCheckpoints(
msg.sender,
oldBalance,
_burn(msg.sender, burnAmount, loanAmountPaid, currentPrice), /// newBalance
currentPrice
);
_burn(msg.sender, burnAmount, loanAmountPaid, currentPrice);

//this function does not only update the checkpoints but also the current profit of the user
//all for external use only
_updateCheckpoints(msg.sender, oldBalance, newBalance, currentPrice);
}

/**
Expand Down
40 changes: 13 additions & 27 deletions contracts/connectors/loantoken/LoanTokenLogicWrbtc.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,22 @@
pragma solidity 0.5.17;
pragma experimental ABIEncoderV2;

import "./LoanTokenLogicStandard.sol";
import "./LoanTokenLogicLM.sol";

/**
* @title Loan Token Logic for wrBTC contract.
* @notice This contract code comes from bZx. bZx is a protocol for tokenized margin
* trading and lending https://bzx.network similar to the dYdX protocol.
*
* Wrapped RSK BTC (wrBTC) is the ERC-20 token pegged to Bitcoin. This contract
* manages loan functionalities deployed as un upgradable logic instance.
* */
contract LoanTokenLogicWrbtc is LoanTokenLogicStandard {
/**
* @notice Mint wrBTC tokens.
* @dev External wrapper that calls _mintToken internal function.
* @param receiver The address to get the minted tokens.
* @return mintAmount The amount of tokens minted.
* */
function mintWithBTC(address receiver) external payable nonReentrant returns (uint256 mintAmount) {
return _mintToken(receiver, msg.value);
contract LoanTokenLogicWrbtc is LoanTokenLogicLM {

function mintWithBTC(address receiver, bool useLM) external payable nonReentrant returns (uint256 mintAmount) {
if (useLM) return _mintWithLM(receiver, msg.value);
else return _mintToken(receiver, msg.value);
}

/**
* @notice Burn wrBTC tokens.
* @dev External wrapper that calls _burnToken internal function
* and withdraws rBTC value.
* @param receiver The address to get the rBTC value.
* @return mintAmount The amount of tokens minted.
* */
function burnToBTC(address receiver, uint256 burnAmount) external nonReentrant returns (uint256 loanAmountPaid) {
loanAmountPaid = _burnToken(burnAmount);
function burnToBTC(
address receiver,
uint256 burnAmount,
bool useLM
) external nonReentrant returns (uint256 loanAmountPaid) {
if (useLM) loanAmountPaid = _burnFromLM(burnAmount);
else loanAmountPaid = _burnToken(burnAmount);

if (loanAmountPaid != 0) {
IWrbtcERC20(wrbtcTokenAddress).withdraw(loanAmountPaid);
Expand Down
23 changes: 3 additions & 20 deletions contracts/connectors/loantoken/LoanTokenSettingsLowerAdmin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,11 @@ contract LoanTokenSettingsLowerAdmin is AdvancedToken {
/// ------------- END MUST BE THE SAME AS IN LoanToken CONTRACT -------------------

/// @dev Add new variables here on the bottom.
address public earlyAccessToken;
address public earlyAccessToken; //not used anymore, but staying for upgradability
address public pauser;
/** The address of the liquidity mining contract */
address public liquidityMiningAddress;

/* Events */

event SetEarlyAccessToken(address oldValue, address newValue);

/* Modifiers */

modifier hasEarlyAccessToken() {
if (earlyAccessToken != address(0)) require(IERC20(earlyAccessToken).balanceOf(msg.sender) > 0, "No early access tokens");
_;
}

/// @dev TODO: Check for restrictions in this contract.
modifier onlyAdmin() {
Expand Down Expand Up @@ -222,13 +214,4 @@ contract LoanTokenSettingsLowerAdmin is AdvancedToken {
symbol = _symbol;
}

/**
* @notice Set early access token.
* @param _earlyAccessTokenAddress The early access token.
* */
function setEarlyAccessToken(address _earlyAccessTokenAddress) public onlyAdmin {
address oldEarlyAccessToken = earlyAccessToken;
earlyAccessToken = _earlyAccessTokenAddress;
emit SetEarlyAccessToken(oldEarlyAccessToken, earlyAccessToken);
}
}
13 changes: 13 additions & 0 deletions contracts/farm/ILiquidityMining.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
pragma solidity >=0.5.0 <0.6.0;

interface ILiquidityMining {
function withdraw(
address _poolToken,
uint256 _amount,
address _user
) external;

function onTokensDeposited(address _user, uint256 _amount) external;

function getUserPoolTokenBalance(address _poolToken, address _user) external view returns (uint256);
}
Loading

0 comments on commit 2f5b900

Please sign in to comment.