Skip to content

Commit

Permalink
Merge pull request #431 from DistributedCollective/sip-0044-to-master
Browse files Browse the repository at this point in the history
Sip-0044-to-master
  • Loading branch information
tjcloa authored Apr 16, 2022
2 parents cba5a0b + 778e41b commit 101c27a
Show file tree
Hide file tree
Showing 39 changed files with 84,998 additions and 38,166 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ jobs:
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
persist-credentials: false

- name: Reconfigure git to use HTTP authentication
run: >
git config --global url."https://github.com/".insteadOf
ssh://[email protected]/
- name: Cache node modules
uses: actions/cache@v2
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ Each lender has 2 balances on the iToken contract. The balance of iTokens (e.g.

The loan token (iToken) contract as well as the protocol contract act as proxies, delegating all calls to underlying contracts. Therefore, if you want to interact with them using web3, you need to use the ABIs from the contracts containing the actual logic or the interface contract.

ABI for `LoanToken` contracts: `LoanTokenLogicStandard`
ABI for `LoanToken` contracts: `LoanTokenLogicLM` (if the underlying asset is any but RBTC) and `LoanTokenLogicWrbtc` (if the underlying asset is RBTC)

ABI for `Protocol` contract: `ISovryn`

Expand Down
2 changes: 1 addition & 1 deletion brownie-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ networks:
cmd_settings:
port: 443
gas_limit: 6800000
gas_price: 79000010 # 25000000000 25 GWEI
gas_price: 66000010 # 25000000000 25 GWEI
reverting_tx_gas_limit: false
default_contract_owner: false

Expand Down
2 changes: 2 additions & 0 deletions contracts/events/ProtocolSettingsEvents.sol
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,6 @@ contract ProtocolSettingsEvents is ModulesCommonEvents {
event TogglePaused(address indexed sender, bool indexed oldFlag, bool indexed newFlag);

event SetTradingRebateRewardsBasisPoint(address indexed sender, uint256 oldBasisPoint, uint256 newBasisPoint);

event SetRolloverFlexFeePercent(address indexed sender, uint256 oldRolloverFlexFeePercent, uint256 newRolloverFlexFeePercent);
}
36 changes: 29 additions & 7 deletions contracts/governance/Staking/Staking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import "./IStaking.sol";
import "../../rsk/RSKAddrValidator.sol";
import "../Vesting/ITeamVesting.sol";
import "../Vesting/IVesting.sol";
import "../ApprovalReceiver.sol";
// import "../ApprovalReceiver.sol"; //uncomment when refactoring
import "../../openzeppelin/SafeMath.sol";

/**
Expand All @@ -20,7 +20,10 @@ import "../../openzeppelin/SafeMath.sol";
* plus revenues from stakers who have a portion of their SOV slashed for
* early unstaking.
* */
contract Staking is IStaking, WeightedStaking, ApprovalReceiver {
contract Staking is
IStaking,
WeightedStaking /*, ApprovalReceiver //TODO: uncomment after refactoring*/
{
using SafeMath for uint256;

/// @notice Constant used for computing the vesting dates.
Expand All @@ -39,6 +42,7 @@ contract Staking is IStaking, WeightedStaking, ApprovalReceiver {
address stakeFor,
address delegatee
) external whenNotPaused {
_notSameBlockAsStakingCheckpoint(until); // must wait a block before staking again for that same deadline
_stake(msg.sender, amount, until, stakeFor, delegatee, false);
}

Expand All @@ -52,6 +56,7 @@ contract Staking is IStaking, WeightedStaking, ApprovalReceiver {
* @param stakeFor The address to stake the tokens for or 0x0 if staking for oneself.
* @param delegatee The address of the delegatee or 0x0 if there is none.
* */
/* //TODO: uncomment after refactoring
function stakeWithApproval(
address sender,
uint96 amount,
Expand All @@ -60,7 +65,7 @@ contract Staking is IStaking, WeightedStaking, ApprovalReceiver {
address delegatee
) public onlyThisContract whenNotPaused {
_stake(sender, amount, until, stakeFor, delegatee, false);
}
}*/

/**
* @notice Send sender's tokens to this contract and update its staked balance.
Expand Down Expand Up @@ -137,6 +142,8 @@ contract Staking is IStaking, WeightedStaking, ApprovalReceiver {
until = timestampToLockDate(until);
require(previousLock < until, "S04"); // must increase staking duration

_notSameBlockAsStakingCheckpoint(previousLock);

/// @dev Do not exceed the max duration, no overflow possible.
uint256 latest = timestampToLockDate(block.timestamp + MAX_DURATION);
if (until > latest) until = latest;
Expand Down Expand Up @@ -223,6 +230,7 @@ contract Staking is IStaking, WeightedStaking, ApprovalReceiver {
* the total duration might end up a bit shorter than specified
* depending on the date of staking.
* */

uint256 start = timestampToLockDate(block.timestamp + cliff);
if (duration > MAX_DURATION) {
duration = MAX_DURATION;
Expand All @@ -237,6 +245,7 @@ contract Staking is IStaking, WeightedStaking, ApprovalReceiver {
/// @dev Stake the rest in 4 week intervals.
for (uint256 i = start + intervalLength; i <= end; i += intervalLength) {
/// @dev Stakes for itself, delegates to the owner.
_notSameBlockAsStakingCheckpoint(i); // must wait a block before staking again for that same deadline
_stake(msg.sender, uint96(stakedPerInterval), i, stakeFor, delegatee, true);
}
}
Expand All @@ -252,10 +261,12 @@ contract Staking is IStaking, WeightedStaking, ApprovalReceiver {
uint256 until,
address receiver
) public whenNotFrozen {
_notSameBlockAsStakingCheckpoint(until);

_withdraw(amount, until, receiver, false);
// @dev withdraws tokens for lock date 2 weeks later than given lock date if sender is a contract
// we need to check block.timestamp here
_withdrawNext(amount, until, receiver, false);
_withdrawNext(until, receiver, false);
}

/**
Expand All @@ -272,10 +283,12 @@ contract Staking is IStaking, WeightedStaking, ApprovalReceiver {
) public whenNotFrozen {
require(vestingWhitelist[msg.sender], "S07"); // unauthorized

_notSameBlockAsStakingCheckpoint(until);

_withdraw(amount, until, receiver, true);
// @dev withdraws tokens for lock date 2 weeks later than given lock date if sender is a contract
// we don't need to check block.timestamp here
_withdrawNext(amount, until, receiver, true);
_withdrawNext(until, receiver, true);
}

/**
Expand Down Expand Up @@ -352,7 +365,6 @@ contract Staking is IStaking, WeightedStaking, ApprovalReceiver {

// @dev withdraws tokens for lock date 2 weeks later than given lock date
function _withdrawNext(
uint96 amount,
uint256 until,
address receiver,
bool isGovernance
Expand Down Expand Up @@ -430,6 +442,8 @@ contract Staking is IStaking, WeightedStaking, ApprovalReceiver {
* @param lockDate the date if the position to delegate.
* */
function delegate(address delegatee, uint256 lockDate) public whenNotPaused {
_notSameBlockAsStakingCheckpoint(lockDate);

_delegate(msg.sender, delegatee, lockDate);
// @dev delegates tokens for lock date 2 weeks later than given lock date
// if message sender is a contract
Expand Down Expand Up @@ -475,6 +489,8 @@ contract Staking is IStaking, WeightedStaking, ApprovalReceiver {
bytes32 r,
bytes32 s
) public whenNotPaused {
_notSameBlockAsStakingCheckpoint(lockDate);

/**
* @dev The DOMAIN_SEPARATOR is a hash that uniquely identifies a
* smart contract. It is built from a string denoting it as an
Expand Down Expand Up @@ -719,9 +735,15 @@ contract Staking is IStaking, WeightedStaking, ApprovalReceiver {
* register stakeWithApproval selector on this contract.
* @return The array of registered selectors on this contract.
* */
function _getSelectors() internal view returns (bytes4[] memory) {
/*function _getSelectors() internal view returns (bytes4[] memory) {
bytes4[] memory selectors = new bytes4[](1);
selectors[0] = this.stakeWithApproval.selector;
return selectors;
}*/

function _notSameBlockAsStakingCheckpoint(uint256 lockDate) internal view {
uint32 nCheckpoints = numUserStakingCheckpoints[msg.sender][lockDate];
bool notSameBlock = userStakingCheckpoints[msg.sender][lockDate][nCheckpoints - 1].fromBlock != block.number;
require(notSameBlock, "S20"); //S20 : "cannot be mined in the same block as last stake"
}
}
25 changes: 20 additions & 5 deletions contracts/governance/StakingRewards/StakingRewards.sol
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,13 @@ contract StakingRewards is StakingRewardsStorage {
* The weighted stake is calculated using getPriorWeightedStake. Block number sent to the functon
* must be a finalised block, hence we deduct 1 from the current block. User is only allowed to withdraw
* after intervals of 14 days.
* @param restartTime The time from which the staking rewards calculation shall restart.
* The issue is that we can only run for a max duration and if someone stakes for the
* first time after the max duration is over, the reward will always return 0. Thus, we need to restart
* from the duration that elapsed without generating rewards.
* */
function collectReward() external {
(uint256 withdrawalTime, uint256 amount) = getStakerCurrentReward(true);
function collectReward(uint256 restartTime) external {
(uint256 withdrawalTime, uint256 amount) = getStakerCurrentReward(true, restartTime);
require(withdrawalTime > 0 && amount > 0, "no valid reward");
withdrawals[msg.sender] = withdrawalTime;
_payReward(msg.sender, amount);
Expand Down Expand Up @@ -96,7 +100,7 @@ contract StakingRewards is StakingRewardsStorage {
* checkpoint which is added to the mapping `checkpointBlockDetails`.
* @param _time Exact staking checkpoint time
*/
function setHistoricalBlock(uint256 _time) external onlyOwner {
function setHistoricalBlock(uint256 _time) external {
_setBlock(_time);
}

Expand Down Expand Up @@ -184,10 +188,15 @@ contract StakingRewards is StakingRewardsStorage {
* @dev The collectReward() function internally calls this function to calculate reward amount
* @param considerMaxDuration True: Runs for the maximum duration - used in tx not to run out of gas
* False - to query total rewards
* @param restartTime The time from which the staking rewards calculation shall restart.
* @return The timestamp of last withdrawal
* @return The accumulated reward
*/
function getStakerCurrentReward(bool considerMaxDuration) public view returns (uint256 lastWithdrawalInterval, uint256 amount) {
function getStakerCurrentReward(bool considerMaxDuration, uint256 restartTime)
public
view
returns (uint256 lastWithdrawalInterval, uint256 amount)
{
uint256 weightedStake;
uint256 lastFinalisedBlock = _getCurrentBlockNumber() - 1;
uint256 currentTS = block.timestamp;
Expand All @@ -198,6 +207,13 @@ contract StakingRewards is StakingRewardsStorage {
uint256 lastStakingInterval = staking.timestampToLockDate(currentTS);
lastWithdrawalInterval = lastWithdrawal > 0 ? lastWithdrawal : startTime;
if (lastStakingInterval <= lastWithdrawalInterval) return (0, 0);
/* Normally the restart time is 0. If this function returns a valid lastWithdrawalInterval
and zero amount - that means there were no valid rewards for that period. So the new period must start
from the end of the last interval or till the time no rewards are accumulated i.e. restartTime */
if (restartTime >= lastWithdrawalInterval) {
uint256 latestRestartTime = staking.timestampToLockDate(restartTime);
lastWithdrawalInterval = latestRestartTime;
}

if (considerMaxDuration) {
uint256 addedMaxDuration = lastWithdrawalInterval.add(maxDuration);
Expand All @@ -215,7 +231,6 @@ contract StakingRewards is StakingRewardsStorage {
weightedStake = weightedStake.add(_computeRewardForDate(staker, referenceBlock, i));
}

if (weightedStake == 0) return (0, 0);
lastWithdrawalInterval = duration;
amount = weightedStake.mul(BASE_RATE).div(DIVISOR);
}
Expand Down
39 changes: 38 additions & 1 deletion contracts/interfaces/ISovryn.sol
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,6 @@ contract ISovryn is
bytes32 loanId;
address loanToken;
address collateralToken;
address borrower;
uint256 principal;
uint256 collateral;
uint256 interestOwedPerDay;
Expand All @@ -311,6 +310,25 @@ contract ISovryn is
uint256 endTimestamp;
uint256 maxLiquidatable;
uint256 maxSeizable;
}

struct LoanReturnDataV2 {
bytes32 loanId;
address loanToken;
address collateralToken;
address borrower;
uint256 principal;
uint256 collateral;
uint256 interestOwedPerDay;
uint256 interestDepositRemaining;
uint256 startRate; /// collateralToLoanRate
uint256 startMargin;
uint256 maintenanceMargin;
uint256 currentMargin;
uint256 maxLoanTerm;
uint256 endTimestamp;
uint256 maxLiquidatable;
uint256 maxSeizable;
uint256 creationTimestamp;
}

Expand All @@ -323,14 +341,31 @@ contract ISovryn is
bool unsafeOnly
) external view returns (LoanReturnData[] memory loansData);

function getUserLoansV2(
address user,
uint256 start,
uint256 count,
uint256 loanType,
bool isLender,
bool unsafeOnly
) external view returns (LoanReturnDataV2[] memory loansDataV2);

function getLoan(bytes32 loanId) external view returns (LoanReturnData memory loanData);

function getLoanV2(bytes32 loanId) external view returns (LoanReturnDataV2 memory loanDataV2);

function getActiveLoans(
uint256 start,
uint256 count,
bool unsafeOnly
) external view returns (LoanReturnData[] memory loansData);

function getActiveLoansV2(
uint256 start,
uint256 count,
bool unsafeOnly
) external view returns (LoanReturnDataV2[] memory loansDataV2);

////// Protocol Migration //////

function setLegacyOracles(address[] calldata refs, address[] calldata oracles) external;
Expand Down Expand Up @@ -421,4 +456,6 @@ contract ISovryn is
function getTradingRebateRewardsBasisPoint() external view returns (uint256);

function getDedicatedSOVRebate() external view returns (uint256);

function setRolloverFlexFeePercent(uint256 newRolloverFlexFeePercent) external;
}
Loading

0 comments on commit 101c27a

Please sign in to comment.