-
Notifications
You must be signed in to change notification settings - Fork 146
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: starting to look at rewards distribution for L2
- Loading branch information
1 parent
1576535
commit 34f4083
Showing
8 changed files
with
299 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
pragma solidity ^0.7.6; | ||
pragma abicoder v2; | ||
|
||
import "@openzeppelin/contracts/math/SafeMath.sol"; | ||
|
||
import "../../arbitrum/L2ArbitrumMessenger.sol"; | ||
|
||
import "../../reservoir/IReservoir.sol"; | ||
import "./L2ReservoirStorage.sol"; | ||
|
||
/** | ||
* @title L2 Rewards Reservoir | ||
* @dev TODO | ||
*/ | ||
contract L2Reservoir is L2ReservoirV1Storage, Reservoir { | ||
modifier onlyL2Gateway() { | ||
require(msg.sender == _resolveContract(keccak256("GraphTokenGateway")), "ONLY_GATEWAY"); | ||
_; | ||
} | ||
|
||
/** | ||
* @dev Initialize this contract. | ||
* The contract will be paused. | ||
* @param _controller Address of the Controller that manages this contract | ||
*/ | ||
function initialize(address _controller) external onlyImpl { | ||
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) { | ||
if (issuanceRate <= MIN_ISSUANCE_RATE) { | ||
return 0; | ||
} | ||
return | ||
normalizedTokenSupplyCache.mul(_pow(issuanceRate, t1.sub(t0), TOKEN_DECIMALS)).div( | ||
TOKEN_DECIMALS | ||
); | ||
} | ||
|
||
function receiveDrip(uint256 _normalizedTokenSupply) external onlyL2Gateway { | ||
if (_normalizedTokenSupply > normalizedTokenSupplyCache) { | ||
normalizedTokenSupplyCache = _normalizedTokenSupply; | ||
lastRewardsUpdateBlock = block.number; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
pragma solidity ^0.7.6; | ||
|
||
import "../../reservoir/IReservoir.sol"; | ||
import "../../governance/Managed.sol"; | ||
|
||
contract L2ReservoirV1Storage is Managed { | ||
uint256 public normalizedTokenSupplyCache; | ||
uint256 public lastRewardsUpdateBlock; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
pragma solidity ^0.7.6; | ||
|
||
interface IReservoir { | ||
function getAccumulatedRewards(uint256 blocknum) external; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
pragma solidity ^0.7.6; | ||
pragma abicoder v2; | ||
|
||
import "@openzeppelin/contracts/math/SafeMath.sol"; | ||
|
||
import "../upgrades/GraphUpgradeable.sol"; | ||
|
||
import "./ReservoirStorage.sol"; | ||
import "./IReservoir.sol"; | ||
|
||
/** | ||
* @title Rewards Reservoir | ||
* @dev TODO | ||
*/ | ||
contract L1Reservoir is ReservoirV1Storage, 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); | ||
// eps = (signed int) mintedRewardsTotal - mintedRewardsActual | ||
|
||
lastRewardsUpdateBlock = block.number; | ||
rewardsMintedUntilBlock = block.number.add(MINT_SUPPLY_PERIOD); | ||
// n: | ||
uint256 newRewardsToDistribute = deltaRewards( | ||
rewardsMintedUntilBlock, | ||
lastRewardsUpdateBlock | ||
); | ||
// N = n - eps | ||
uint256 tokensToMint = newRewardsToDistribute.add(mintedRewardsActual).sub( | ||
mintedRewardsTotal | ||
); | ||
|
||
if (tokensToMint > 0) { | ||
graphToken().mint(address(this), tokensToMint); | ||
} | ||
|
||
accumulatedLayerRewards = getAccumulatedRewards(block.number); | ||
|
||
tokenSupplyCache = graphToken().totalSupply(); | ||
|
||
uint256 tokensToSendToL2 = l2RewardsFraction.mul(newRewardsToDistribute).div( | ||
TOKEN_DECIMALS | ||
); | ||
if (l2RewardsFraction != lastL2RewardsFraction) { | ||
if (mintedRewardsTotal > mintedRewardsActual) { | ||
// eps > 0, i.e. t < t1_old | ||
tokensToSendToL2 = tokensToSendToL2.sub( | ||
lastL2RewardsFraction.mul(mintedRewardsTotal.sub(mintedRewardsActual)) | ||
); | ||
} else { | ||
tokensToSendToL2 = tokensToSendToL2.add( | ||
lastL2RewardsFraction.mul(mintedRewardsActual.sub(mintedRewardsTotal)) | ||
); | ||
} | ||
lastL2RewardsFraction = l2RewardsFraction; | ||
} | ||
_sendNewTokensAndStateToL2(tokensToSendToL2, l2MaxSubmissionCost, l2GasPriceBid, l2MaxGas); | ||
} | ||
|
||
function _sendNewTokensAndStateToL2( | ||
uint256 nTokens, | ||
uint256 maxGas, | ||
uint256 gasPriceBid, | ||
uint256 maxSubmissionCost | ||
) internal { | ||
uint256 normalizedSupply = l2RewardsFraction * tokenSupplyCache; | ||
bytes memory extraData = abi.encodeWithSelector( | ||
L2Reservoir.receiveDrip.selector, | ||
normalizedSupply | ||
); | ||
bytes memory data = abi.encode(maxSubmissionCost, extraData); | ||
ITokenGateway gateway = ITokenGateway(_resolveContract(keccak256("GraphTokenGateway"))); | ||
gateway.outboundTransfer{ value: msg.value }( | ||
address(graphToken()), | ||
l2ReservoirAddress, | ||
nTokens, | ||
maxGas, | ||
gasPriceBid, | ||
data | ||
); | ||
} | ||
|
||
function deltaRewards(uint256 t1, uint256 t0) public returns (uint256) { | ||
if (issuanceRate <= MIN_ISSUANCE_RATE) { | ||
return 0; | ||
} | ||
return | ||
tokenSupplyCache.mul(_pow(issuanceRate, t1.sub(t0), TOKEN_DECIMALS)).div( | ||
TOKEN_DECIMALS | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
pragma solidity ^0.7.6; | ||
pragma abicoder v2; | ||
|
||
import "@openzeppelin/contracts/math/SafeMath.sol"; | ||
|
||
import "../upgrades/GraphUpgradeable.sol"; | ||
|
||
import "./ReservoirStorage.sol"; | ||
import "./IReservoir.sol"; | ||
|
||
/** | ||
* @title Rewards Reservoir | ||
* @dev TODO | ||
*/ | ||
abstract contract Reservoir is GraphUpgradeable, Managed, 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 | ||
|
||
function _pow( | ||
uint256 x, | ||
uint256 n, | ||
uint256 base | ||
) private pure returns (uint256 z) { | ||
// solhint-disable-next-line no-inline-assembly | ||
assembly { | ||
switch x | ||
case 0 { | ||
switch n | ||
case 0 { | ||
z := base | ||
} | ||
default { | ||
z := 0 | ||
} | ||
} | ||
default { | ||
switch mod(n, 2) | ||
case 0 { | ||
z := base | ||
} | ||
default { | ||
z := x | ||
} | ||
let half := div(base, 2) // for rounding. | ||
for { | ||
n := div(n, 2) | ||
} n { | ||
n := div(n, 2) | ||
} { | ||
let xx := mul(x, x) | ||
if iszero(eq(div(xx, x), x)) { | ||
revert(0, 0) | ||
} | ||
let xxRound := add(xx, half) | ||
if lt(xxRound, xx) { | ||
revert(0, 0) | ||
} | ||
x := div(xxRound, base) | ||
if mod(n, 2) { | ||
let zx := mul(z, x) | ||
if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { | ||
revert(0, 0) | ||
} | ||
let zxRound := add(zx, half) | ||
if lt(zxRound, zx) { | ||
revert(0, 0) | ||
} | ||
z := div(zxRound, base) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
pragma solidity ^0.7.6; | ||
|
||
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters