Skip to content

Commit

Permalink
feat: more WIP on Reservoirs and rewards distribution
Browse files Browse the repository at this point in the history
  • Loading branch information
pcarranzav committed May 17, 2022
1 parent 34f4083 commit c7e19da
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 53 deletions.
27 changes: 16 additions & 11 deletions contracts/l2/reservoir/L2Reservoir.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@ pragma abicoder v2;

import "@openzeppelin/contracts/math/SafeMath.sol";

import "../../arbitrum/L2ArbitrumMessenger.sol";

import "../../reservoir/IReservoir.sol";
import "../../reservoir/Reservoir.sol";
import "./L2ReservoirStorage.sol";

/**
* @title L2 Rewards Reservoir
* @dev TODO
*/
contract L2Reservoir is L2ReservoirV1Storage, Reservoir {
contract L2Reservoir is L2ReservoirV1Storage, Reservoir, IL2Reservoir {
using SafeMath for uint256;

modifier onlyL2Gateway() {
require(msg.sender == _resolveContract(keccak256("GraphTokenGateway")), "ONLY_GATEWAY");
_;
Expand All @@ -29,13 +30,12 @@ contract L2Reservoir is L2ReservoirV1Storage, Reservoir {
Managed._initialize(_controller);
}

function getAccumulatedRewards(uint256 blocknum) external override returns (uint256) {
// R(t) = R(t0) + (DeltaR2(t, t0))
// (deltaRewards implicitly uses lambda because it computes using normalizedTokenSupply)
return accumulatedLayerRewards + deltaRewards(blocknum, lastRewardsUpdateBlock);
}

function deltaRewards(uint256 t1, uint256 t0) public returns (uint256) {
function deltaRewards(uint256 t1, uint256 t0)
public
view
override(Reservoir, IReservoir)
returns (uint256)
{
if (issuanceRate <= MIN_ISSUANCE_RATE) {
return 0;
}
Expand All @@ -45,7 +45,12 @@ contract L2Reservoir is L2ReservoirV1Storage, Reservoir {
);
}

function receiveDrip(uint256 _normalizedTokenSupply) external onlyL2Gateway {
/**
* @dev TODO
* If we change bridge to use an onTokenTransfer function, we should make
* that function parse the calldata and call this.
*/
function receiveDrip(uint256 _normalizedTokenSupply) external override onlyL2Gateway {
if (_normalizedTokenSupply > normalizedTokenSupplyCache) {
normalizedTokenSupplyCache = _normalizedTokenSupply;
lastRewardsUpdateBlock = block.number;
Expand Down
6 changes: 1 addition & 5 deletions contracts/l2/reservoir/L2ReservoirStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@

pragma solidity ^0.7.6;

import "../../reservoir/IReservoir.sol";
import "../../governance/Managed.sol";

contract L2ReservoirV1Storage is Managed {
contract L2ReservoirV1Storage {
uint256 public normalizedTokenSupplyCache;
uint256 public lastRewardsUpdateBlock;
}
10 changes: 9 additions & 1 deletion contracts/reservoir/IReservoir.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,13 @@
pragma solidity ^0.7.6;

interface IReservoir {
function getAccumulatedRewards(uint256 blocknum) external;
function setIssuanceRate(uint256 _issuanceRate) external;

function getAccumulatedRewards(uint256 blocknum) external view returns (uint256);

function deltaRewards(uint256 t1, uint256 t0) external view returns (uint256);
}

interface IL2Reservoir is IReservoir {
function receiveDrip(uint256 _normalizedTokenSupply) external;
}
40 changes: 23 additions & 17 deletions contracts/reservoir/L1Reservoir.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,35 @@ pragma abicoder v2;

import "@openzeppelin/contracts/math/SafeMath.sol";

import "../upgrades/GraphUpgradeable.sol";
import "../arbitrum/ITokenGateway.sol";

import "./ReservoirStorage.sol";
import "./IReservoir.sol";
import "./Reservoir.sol";
import "./L1ReservoirStorage.sol";

/**
* @title Rewards Reservoir
* @dev TODO
*/
contract L1Reservoir is ReservoirV1Storage, Reservoir {
contract L1Reservoir is L1ReservoirV1Storage, Reservoir {
using SafeMath for uint256;

function getAccumulatedRewards(uint256 blocknum) external override returns (uint256) {
// R(t) = R(t0) + (1-lambda) * (DeltaR(t, t0))
return
accumulatedLayerRewards +
deltaRewards(blocknum, lastRewardsUpdateBlock)
.mul(TOKEN_DECIMALS.sub(l2RewardsFraction))
.div(TOKEN_DECIMALS);
}

function drip(
uint256 l2MaxGas,
uint256 l2GasPriceBid,
uint256 l2MaxSubmissionCost
) external payable {
uint256 mintedRewardsTotal = deltaRewards(rewardsMintedUntilBlock, lastRewardsUpdateBlock);
uint256 mintedRewardsActual = deltaRewards(block.number, lastRewardsUpdateBlock);
uint256 mintedRewardsTotal = deltaGlobalRewards(
rewardsMintedUntilBlock,
lastRewardsUpdateBlock
);
uint256 mintedRewardsActual = deltaGlobalRewards(block.number, lastRewardsUpdateBlock);
// eps = (signed int) mintedRewardsTotal - mintedRewardsActual

lastRewardsUpdateBlock = block.number;
rewardsMintedUntilBlock = block.number.add(MINT_SUPPLY_PERIOD);
// n:
uint256 newRewardsToDistribute = deltaRewards(
uint256 newRewardsToDistribute = deltaGlobalRewards(
rewardsMintedUntilBlock,
lastRewardsUpdateBlock
);
Expand Down Expand Up @@ -74,6 +69,10 @@ contract L1Reservoir is ReservoirV1Storage, Reservoir {
_sendNewTokensAndStateToL2(tokensToSendToL2, l2MaxSubmissionCost, l2GasPriceBid, l2MaxGas);
}

/**
* TODO: If we change the bridge to use onTokenTransfer, this
* interface will have to change to use that instead.
*/
function _sendNewTokensAndStateToL2(
uint256 nTokens,
uint256 maxGas,
Expand All @@ -82,7 +81,7 @@ contract L1Reservoir is ReservoirV1Storage, Reservoir {
) internal {
uint256 normalizedSupply = l2RewardsFraction * tokenSupplyCache;
bytes memory extraData = abi.encodeWithSelector(
L2Reservoir.receiveDrip.selector,
IL2Reservoir.receiveDrip.selector,
normalizedSupply
);
bytes memory data = abi.encode(maxSubmissionCost, extraData);
Expand All @@ -97,7 +96,7 @@ contract L1Reservoir is ReservoirV1Storage, Reservoir {
);
}

function deltaRewards(uint256 t1, uint256 t0) public returns (uint256) {
function deltaGlobalRewards(uint256 t1, uint256 t0) public view returns (uint256) {
if (issuanceRate <= MIN_ISSUANCE_RATE) {
return 0;
}
Expand All @@ -106,4 +105,11 @@ contract L1Reservoir is ReservoirV1Storage, Reservoir {
TOKEN_DECIMALS
);
}

function deltaRewards(uint256 t1, uint256 t0) public view override returns (uint256) {
return
deltaGlobalRewards(t1, t0).mul(TOKEN_DECIMALS.sub(l2RewardsFraction)).div(
TOKEN_DECIMALS
);
}
}
12 changes: 12 additions & 0 deletions contracts/reservoir/L1ReservoirStorage.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.7.6;

contract L1ReservoirV1Storage {
uint256 public l2RewardsFraction; // Expressed in base 1e18
uint256 public lastL2RewardsFraction;
address public l2ReservoirAddress;
uint256 public rewardsMintedUntilBlock;
uint256 public accumulatedGlobalRewards;
uint256 public tokenSupplyCache;
}
34 changes: 32 additions & 2 deletions contracts/reservoir/Reservoir.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,48 @@ import "./IReservoir.sol";
* @title Rewards Reservoir
* @dev TODO
*/
abstract contract Reservoir is GraphUpgradeable, Managed, IReservoir {
abstract contract Reservoir is GraphUpgradeable, ReservoirV1Storage, IReservoir {
using SafeMath for uint256;

uint256 internal constant TOKEN_DECIMALS = 1e18;
uint256 internal constant MIN_ISSUANCE_RATE = 1e18;
uint256 internal constant MINT_SUPPLY_PERIOD = 45815; // ~1 week in blocks

modifier onlyRewardsManager() {
require(
msg.sender == address(rewardsManager()),
"Only the RewardsManager can call this function"
);
_;
}

/**
* @dev Sets the issuance rate.
* The issuance rate is defined as a percentage increase of the total supply per block.
* This means that it needs to be greater than 1.0, any number under 1.0 is not
* allowed and an issuance rate of 1.0 means no issuance.
* To accommodate a high precision the issuance rate is expressed in wei.
* This is only callable by the RewardsManager, because it will need to snapshot
* the accumulated rewards per signal when the value changes.
* @param _issuanceRate Issuance rate expressed in wei
*/
function setIssuanceRate(uint256 _issuanceRate) external override onlyRewardsManager {
issuanceRate = (_issuanceRate);
}

function getAccumulatedRewards(uint256 blocknum) public view override returns (uint256) {
// R(t) = R(t0) + (DeltaR2(t, t0))
// (deltaRewards implicitly uses lambda because it computes using normalizedTokenSupply)
return accumulatedLayerRewards + deltaRewards(blocknum, lastRewardsUpdateBlock);
}

function deltaRewards(uint256 t1, uint256 t0) public view virtual override returns (uint256);

function _pow(
uint256 x,
uint256 n,
uint256 base
) private pure returns (uint256 z) {
) internal pure returns (uint256 z) {
// solhint-disable-next-line no-inline-assembly
assembly {
switch x
Expand Down
10 changes: 2 additions & 8 deletions contracts/reservoir/ReservoirStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,7 @@ import "./IReservoir.sol";
import "../governance/Managed.sol";

contract ReservoirV1Storage is Managed {
uint256 public l2RewardsFraction; // Expressed in base 1e18
uint256 public lastL2RewardsFraction;
address public l2ReservoirAddress;
uint256 public lastRewardsUpdateBlock;
uint256 public rewardsMintedUntilBlock;
uint256 public accumulatedGlobalRewards;
uint256 public accumulatedLayerRewards;
uint256 public tokenSupplyCache;
uint256 public issuanceRate;
uint256 public accumulatedLayerRewards;
uint256 public lastRewardsUpdateBlock;
}
9 changes: 2 additions & 7 deletions contracts/rewards/RewardsManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ contract RewardsManager is RewardsManagerV3Storage, GraphUpgradeable, IRewardsMa
// Called since `issuance rate` will change
updateAccRewardsPerSignal();

issuanceRate = _issuanceRate;
reservoir().setIssuanceRate(_issuanceRate);
emit ParameterUpdated("issuanceRate");
}

Expand Down Expand Up @@ -164,11 +164,6 @@ contract RewardsManager is RewardsManagerV3Storage, GraphUpgradeable, IRewardsMa
* @return newly accrued rewards per signal since last update
*/
function getNewRewardsPerSignal() public view override returns (uint256) {
// Zero issuance under a rate of 1.0
if (issuanceRate <= MIN_ISSUANCE_RATE) {
return 0;
}

// Zero issuance if no signalled tokens
IGraphToken graphToken = graphToken();
uint256 signalledTokens = graphToken.balanceOf(address(curation()));
Expand Down Expand Up @@ -446,7 +441,7 @@ contract RewardsManager is RewardsManagerV3Storage, GraphUpgradeable, IRewardsMa
}
}

function reservoir() private returns (IReservoir) {
function reservoir() internal view returns (IReservoir) {
return IReservoir(_resolveContract(keccak256("Reservoir")));
}
}
4 changes: 2 additions & 2 deletions contracts/rewards/RewardsManagerStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import "../governance/Managed.sol";
contract RewardsManagerV1Storage is Managed {
// -- State --

uint256 public issuanceRate;
uint256 public issuanceRateDeprecated;
uint256 public accRewardsPerSignal;
uint256 public accRewardsPerSignalLastBlockUpdated;

Expand All @@ -24,7 +24,7 @@ contract RewardsManagerV1Storage is Managed {

contract RewardsManagerV2Storage is RewardsManagerV1Storage {
// Snapshot of the total supply of GRT when accRewardsPerSignal was last updated
uint256 public tokenSupplySnapshot;
uint256 public tokenSupplySnapshotDeprecated;
}

contract RewardsManagerV3Storage is RewardsManagerV2Storage {
Expand Down

0 comments on commit c7e19da

Please sign in to comment.