Skip to content

Commit

Permalink
feat: implement distribution of rewards to L1 and L2 using a Reservoir
Browse files Browse the repository at this point in the history
BREAKING CHANGE: remove setIssuanceRate from RewardsManager interface
  • Loading branch information
pcarranzav committed May 25, 2022
1 parent 1576535 commit 574e962
Show file tree
Hide file tree
Showing 24 changed files with 1,192 additions and 483 deletions.
105 changes: 105 additions & 0 deletions arbitrum-graph.config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,123 @@ general:
contracts:
Controller:
calls:
- fn: "setContractProxy"
id: "0xe6876326c1291dfcbbd3864a6816d698cd591defc7aa2153d7f9c4c04016c89f" # keccak256('Curation')
contractAddress: "${{Curation.address}}"
- fn: "setContractProxy"
id: "0x39605a6c26a173774ca666c67ef70cf491880e5d3d6d0ca66ec0a31034f15ea3" # keccak256('GNS')
contractAddress: "${{GNS.address}}"
- fn: "setContractProxy"
id: "0xf942813d07d17b56de9a9afc8de0ced6e8c053bbfdcc87b7badea4ddcf27c307" # keccak256('DisputeManager')
contractAddress: "${{DisputeManager.address}}"
- fn: "setContractProxy"
id: "0xc713c3df6d14cdf946460395d09af88993ee2b948b1a808161494e32c5f67063" # keccak256('EpochManager')
contractAddress: "${{EpochManager.address}}"
- fn: "setContractProxy"
id: "0x966f1e8d8d8014e05f6ec4a57138da9be1f7c5a7f802928a18072f7c53180761" # keccak256('RewardsManager')
contractAddress: "${{RewardsManager.address}}"
- fn: "setContractProxy"
id: "0x1df41cd916959d1163dc8f0671a666ea8a3e434c13e40faef527133b5d167034" # keccak256('Staking')
contractAddress: "${{Staking.address}}"
- fn: "setContractProxy"
id: "0x45fc200c7e4544e457d3c5709bfe0d520442c30bbcbdaede89e8d4a4bbc19247" # keccak256('GraphToken')
contractAddress: "${{L2GraphToken.address}}"
- fn: "setContractProxy"
id: "0xd362cac9cb75c10d67bcc0b7eeb0b1ef48bb5420b556c092d4fd7f758816fcf0" # keccak256('GraphTokenGateway')
contractAddress: "${{L2GraphTokenGateway.address}}"
- fn: "setContractProxy"
id: "0x96ba401694892957e25e29c7a1e4171ae9945b5ee36339de79b199a530436e9e" # keccak256('Reservoir')
contractAddress: "${{L2Reservoir.address}}"
ServiceRegistry:
proxy: true
init:
controller: "${{Controller.address}}"
EpochManager:
proxy: true
init:
controller: "${{Controller.address}}"
lengthInBlocks: 1108 # 4 hours (in 13 second blocks)
L2GraphToken:
proxy: true
init:
owner: *governor
initialSupply: "0"
Curation:
proxy: true
init:
controller: "${{Controller.address}}"
bondingCurve: "${{BancorFormula.address}}"
curationTokenMaster: "${{GraphCurationToken.address}}"
reserveRatio: 500000 # 50% (parts per million)
curationTaxPercentage: 10000 # 1% (parts per million)
minimumCurationDeposit: "1000000000000000000" # 1 GRT
DisputeManager:
proxy: true
init:
controller: "${{Controller.address}}"
arbitrator: *arbitrator
minimumDeposit: "10000000000000000000000" # 10,000 GRT (in wei)
fishermanRewardPercentage: 500000 # 50% (parts per million)
idxSlashingPercentage: 25000 # 2.5% (parts per million)
qrySlashingPercentage: 5000 # 0.5% (parts per million)
GNS:
proxy: true
init:
controller: "${{Controller.address}}"
bondingCurve: "${{BancorFormula.address}}"
subgraphNFT: "${{SubgraphNFT.address}}"
calls:
- fn: "approveAll"
SubgraphNFT:
init:
governor: "${{Env.deployer}}"
calls:
- fn: "setTokenDescriptor"
tokenDescriptor: "${{SubgraphNFTDescriptor.address}}"
- fn: "setMinter"
minter: "${{GNS.address}}"
Staking:
proxy: true
init:
controller: "${{Controller.address}}"
minimumIndexerStake: "100000000000000000000000" # 100,000 GRT (in wei)
thawingPeriod: 6646 # 10 days (in blocks)
protocolPercentage: 10000 # 1% (parts per million)
curationPercentage: 100000 # 10% (parts per million)
channelDisputeEpochs: 2 # (in epochs)
maxAllocationEpochs: 6 # Based on epoch length this is 28 days (in epochs)
delegationUnbondingPeriod: 6 # Based on epoch length this is 28 days (in epochs)
delegationRatio: 16 # 16x (delegated stake to indexer stake multiplier)
rebateAlphaNumerator: 77 # rebateAlphaNumerator / rebateAlphaDenominator
rebateAlphaDenominator: 100 # rebateAlphaNumerator / rebateAlphaDenominator
calls:
- fn: "setDelegationTaxPercentage"
delegationTaxPercentage: 5000 # 0.5% (parts per million)
- fn: "setSlasher"
slasher: "${{DisputeManager.address}}"
allowed: true
- fn: "setAssetHolder"
assetHolder: "${{AllocationExchange.address}}"
allowed: true
RewardsManager:
proxy: true
init:
controller: "${{Controller.address}}"
AllocationExchange:
init:
graphToken: "${{GraphToken.address}}"
staking: "${{Staking.address}}"
governor: *governor
authority: *authority
calls:
- fn: "approveAll"
L2GraphTokenGateway:
proxy: true
init:
controller: "${{Controller.address}}"
L2Reservoir:
proxy: true
init:
controller: "${{Controller.address}}"
calls:
- fn: "approveRewardsManager"
42 changes: 20 additions & 22 deletions cli/commands/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,30 +35,28 @@ let allContracts = [
'AllocationExchange',
'L1GraphTokenGateway',
'BridgeEscrow',
'L1Reservoir',
]

// This is all we'll want to deploy to L2 eventually:
// const l2Contracts = [
// 'GraphProxyAdmin',
// 'BancorFormula',
// 'Controller',
// 'EpochManager',
// 'L2GraphToken',
// 'GraphCurationToken',
// 'ServiceRegistry',
// 'Curation',
// 'SubgraphNFTDescriptor',
// 'SubgraphNFT',
// 'GNS',
// 'Staking',
// 'RewardsManager',
// 'DisputeManager',
// 'AllocationExchange',
// 'L2GraphTokenGateway',
// ]
//
// But for now we'll only include a subset:
const l2Contracts = ['GraphProxyAdmin', 'Controller', 'L2GraphToken', 'L2GraphTokenGateway']
const l2Contracts = [
'GraphProxyAdmin',
'BancorFormula',
'Controller',
'EpochManager',
'L2GraphToken',
'GraphCurationToken',
'ServiceRegistry',
'Curation',
'SubgraphNFTDescriptor',
'SubgraphNFT',
'GNS',
'Staking',
'RewardsManager',
'DisputeManager',
'AllocationExchange',
'L2GraphTokenGateway',
'L2Reservoir',
]

export const migrate = async (cli: CLIEnvironment, cliArgs: CLIArgs): Promise<void> => {
const graphConfigPath = cliArgs.graphConfig
Expand Down
1 change: 1 addition & 0 deletions contracts/governance/Managed.sol
Original file line number Diff line number Diff line change
Expand Up @@ -183,5 +183,6 @@ contract Managed {
_syncContract("Staking");
_syncContract("GraphToken");
_syncContract("GraphTokenGateway");
_syncContract("Reservoir");
}
}
74 changes: 74 additions & 0 deletions contracts/l2/reservoir/L2Reservoir.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.7.6;
pragma abicoder v2;

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

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

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

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 deltaRewards(uint256 t1, uint256 t0)
public
view
override(Reservoir, IReservoir)
returns (uint256)
{
if (issuanceRate <= MIN_ISSUANCE_RATE || t1 == t0) {
return 0;
}
return
normalizedTokenSupplyCache.mul(_pow(issuanceRate, t1.sub(t0), TOKEN_DECIMALS)).div(
TOKEN_DECIMALS
);
}

/**
* @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, uint256 _issuanceRate)
external
override
onlyL2Gateway
{
if (_normalizedTokenSupply > normalizedTokenSupplyCache) {
if (_issuanceRate != issuanceRate) {
rewardsManager().updateAccRewardsPerSignal();
snapshotAccumulatedRewards();
issuanceRate = _issuanceRate;
} else {
snapshotAccumulatedRewards();
}
normalizedTokenSupplyCache = _normalizedTokenSupply;
}
}

function snapshotAccumulatedRewards() internal {
accumulatedLayerRewards = getAccumulatedRewards(block.number);
lastRewardsUpdateBlock = block.number;
}
}
7 changes: 7 additions & 0 deletions contracts/l2/reservoir/L2ReservoirStorage.sol
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;

contract L2ReservoirV1Storage {
uint256 public normalizedTokenSupplyCache;
}
15 changes: 15 additions & 0 deletions contracts/reservoir/IReservoir.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.7.6;

interface IReservoir {
function approveRewardsManager() 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, uint256 _issuanceRate) external;
}
Loading

0 comments on commit 574e962

Please sign in to comment.