Skip to content

L2: drip rewards from L1, introducing Reservoirs #701

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 47 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
c04c236
feat: implement distribution of rewards to L1 and L2 using a Reservoir
pcarranzav May 17, 2022
bef792e
fix: document potential drip reverts if issuance rate is updated [L-01]
pcarranzav Jul 11, 2022
a34e508
fix: document drip revert when l2RewardsFraction changed [L-02]
pcarranzav Jul 11, 2022
d2e53fd
fix: rename variables related to supply to issuanceBase to make it cl…
pcarranzav Jul 11, 2022
4ad867a
fix: use issuanceBase check to prevent calling initialSnapshot twice …
pcarranzav Jul 11, 2022
a8144df
test: fix tests after not allowing initialSnapshot to be called twice
pcarranzav Jul 12, 2022
5c6802f
fix: document the need for drip after a param update [L-06]
pcarranzav Jul 13, 2022
b6e1497
fix: validate L2Reservoir address on L1Reservoir [L-07]
pcarranzav Jul 12, 2022
ad09ca0
fix: rename normalizedSupply to l2IssuanceBase in L2 message to avoid…
pcarranzav Jul 13, 2022
8cd3270
fix: remove silent failure if rewardsManager is not set [L-12]
pcarranzav Jul 13, 2022
19dd310
fix: general code improvements [N-05]
pcarranzav Jul 13, 2022
6a50012
fix: use internal function to consistently set dripInterval [N-07]
pcarranzav Jul 13, 2022
965dbb3
fix: remove named returns [N-08]
pcarranzav Jul 13, 2022
f4bc6f9
fix: update some outdated docstrings and comments [N-09]
pcarranzav Jul 13, 2022
2c89ea7
fix: document why some variables are not set during initialization [N…
pcarranzav Jul 13, 2022
c1336ef
fix: add missing getters to Managed [N-11]
pcarranzav Jul 13, 2022
86cddb8
fix: separate contracts into different files [N-13]
pcarranzav Jul 14, 2022
d327b36
fix: rename some variables for clarity [N-14]
pcarranzav Jul 14, 2022
af81533
fix: document the need to retry tickets if drip is received out-of-or…
pcarranzav Jul 14, 2022
f20124a
fix: various typos [N-16]
pcarranzav Jul 14, 2022
1d1e319
fix: replace MAX_UINT256 with type().max [N-18] [N-20]
pcarranzav Jul 14, 2022
9031651
fix: remove an unused import [N-21]
pcarranzav Jul 14, 2022
e2e08d1
test: remove repeated addToCallhookWhitelist
pcarranzav Jul 15, 2022
bbb3fad
fix: use SafeMath more consistently
pcarranzav Jul 15, 2022
e2766b3
feat: keeper reward for reservoir drip through token issuance
pcarranzav Jun 5, 2022
fc42c3f
fix: don't use tx.origin as it will not work
pcarranzav Jun 8, 2022
e69c095
fix: only allow indexers, their operators, or whitelisted addresses t…
pcarranzav Jun 21, 2022
c274636
test: fix rewards and reservoir tests after restricting drip callers
pcarranzav Jun 21, 2022
51db5f9
test: add a test for the keeper reward delivery in L2
pcarranzav Jun 23, 2022
a54a629
fix: provide part of the keeper reward to L2 redeemer
pcarranzav Jun 27, 2022
e275908
fix: clean up comments about redeemer
pcarranzav Jul 15, 2022
6d0c39d
fix: more documentation details
pcarranzav Jul 15, 2022
e727133
fix: use safe math for minDripInterval
pcarranzav Jul 15, 2022
c4d583a
fix: validate input when granting/revoking drip permission
pcarranzav Jul 15, 2022
304d055
fix: docs and inheritance for IArbTxWithRedeemer
pcarranzav Jul 28, 2022
a570c8c
fix: remove minDripInterval from the drip keeper reward calculation […
pcarranzav Aug 5, 2022
2432862
fix: use L2 alias of l1ReservoirAddress when comparing getCurrentRede…
pcarranzav Aug 8, 2022
f1c9530
fix: don't include keeper reward twice when computing what to send to…
pcarranzav Aug 17, 2022
26a4922
test: add test to ensure no DoS if l2RewardsFraction is zeroed [H-04]
pcarranzav Aug 22, 2022
8869e69
test: optimize functions to advance blocks and fix some race conditions
pcarranzav Aug 22, 2022
7207a23
fix: add some missing validation on reservoirs [M-01]
pcarranzav Aug 22, 2022
117cb4a
fix: add some missing docstrings [L-04]
pcarranzav Aug 22, 2022
f2e1f81
fix: use a single-condition requires for the drip auth check [L-05]
pcarranzav Aug 22, 2022
33f7ec2
fix: add indexed params to dripper change events [N-01]
pcarranzav Aug 22, 2022
fb3ed11
fix: use explicit imports in relevant reservoir contracts [N-02]
pcarranzav Aug 22, 2022
53e0a80
test: fix call in l2Reservoir test
pcarranzav Sep 1, 2022
559ea00
fix: adjust gre, e2e and configs to account for reservoirs
pcarranzav Sep 27, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cli/commands/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ let allContracts = [
'AllocationExchange',
'L1GraphTokenGateway',
'BridgeEscrow',
'L1Reservoir',
]

const l2Contracts = [
Expand All @@ -55,6 +56,7 @@ const l2Contracts = [
'DisputeManager',
'AllocationExchange',
'L2GraphTokenGateway',
'L2Reservoir',
]

export const migrate = async (
Expand Down
4 changes: 4 additions & 0 deletions cli/contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import { L1GraphTokenGateway } from '../build/types/L1GraphTokenGateway'
import { L2GraphToken } from '../build/types/L2GraphToken'
import { L2GraphTokenGateway } from '../build/types/L2GraphTokenGateway'
import { BridgeEscrow } from '../build/types/BridgeEscrow'
import { L1Reservoir } from '../build/types/L1Reservoir'
import { L2Reservoir } from '../build/types/L2Reservoir'

export interface NetworkContracts {
EpochManager: EpochManager
Expand All @@ -49,6 +51,8 @@ export interface NetworkContracts {
BridgeEscrow: BridgeEscrow
L2GraphToken: L2GraphToken
L2GraphTokenGateway: L2GraphTokenGateway
L1Reservoir: L1Reservoir
L2Reservoir: L2Reservoir
}

export const loadAddressBookContract = (
Expand Down
10 changes: 10 additions & 0 deletions config/graph.arbitrum-goerli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ contracts:
- fn: "setContractProxy"
id: "0xd362cac9cb75c10d67bcc0b7eeb0b1ef48bb5420b556c092d4fd7f758816fcf0" # keccak256('GraphTokenGateway')
contractAddress: "${{L2GraphTokenGateway.address}}"
- fn: "setContractProxy"
id: "0x96ba401694892957e25e29c7a1e4171ae9945b5ee36339de79b199a530436e9e" # keccak256('Reservoir')
contractAddress: "${{L2Reservoir.address}}"
- fn: "setPauseGuardian"
pauseGuardian: *pauseGuardian
- fn: "transferOwnership"
Expand Down Expand Up @@ -149,3 +152,10 @@ contracts:
- fn: "syncAllContracts"
- fn: "setPauseGuardian"
pauseGuardian: *pauseGuardian
L2Reservoir:
proxy: true
init:
controller: "${{Controller.address}}"
calls:
- fn: "approveRewardsManager"
- fn: "syncAllContracts"
10 changes: 10 additions & 0 deletions config/graph.arbitrum-localhost.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ contracts:
- fn: "setContractProxy"
id: "0xd362cac9cb75c10d67bcc0b7eeb0b1ef48bb5420b556c092d4fd7f758816fcf0" # keccak256('GraphTokenGateway')
contractAddress: "${{L2GraphTokenGateway.address}}"
- fn: "setContractProxy"
id: "0x96ba401694892957e25e29c7a1e4171ae9945b5ee36339de79b199a530436e9e" # keccak256('Reservoir')
contractAddress: "${{L2Reservoir.address}}"
- fn: "setPauseGuardian"
pauseGuardian: *pauseGuardian
- fn: "transferOwnership"
Expand Down Expand Up @@ -149,3 +152,10 @@ contracts:
- fn: "syncAllContracts"
- fn: "setPauseGuardian"
pauseGuardian: *pauseGuardian
L2Reservoir:
proxy: true
init:
controller: "${{Controller.address}}"
calls:
- fn: "approveRewardsManager"
- fn: "syncAllContracts"
10 changes: 10 additions & 0 deletions config/graph.arbitrum-one.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ contracts:
- fn: "setContractProxy"
id: "0xd362cac9cb75c10d67bcc0b7eeb0b1ef48bb5420b556c092d4fd7f758816fcf0" # keccak256('GraphTokenGateway')
contractAddress: "${{L2GraphTokenGateway.address}}"
- fn: "setContractProxy"
id: "0x96ba401694892957e25e29c7a1e4171ae9945b5ee36339de79b199a530436e9e" # keccak256('Reservoir')
contractAddress: "${{L2Reservoir.address}}"
- fn: "setPauseGuardian"
pauseGuardian: *pauseGuardian
- fn: "transferOwnership"
Expand Down Expand Up @@ -149,3 +152,10 @@ contracts:
- fn: "syncAllContracts"
- fn: "setPauseGuardian"
pauseGuardian: *pauseGuardian
L2Reservoir:
proxy: true
init:
controller: "${{Controller.address}}"
calls:
- fn: "approveRewardsManager"
- fn: "syncAllContracts"
17 changes: 14 additions & 3 deletions config/graph.goerli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ contracts:
- fn: "setContractProxy"
id: "0xd362cac9cb75c10d67bcc0b7eeb0b1ef48bb5420b556c092d4fd7f758816fcf0" # keccak256('GraphTokenGateway')
contractAddress: "${{L1GraphTokenGateway.address}}"
- fn: "setContractProxy"
id: "0x96ba401694892957e25e29c7a1e4171ae9945b5ee36339de79b199a530436e9e" # keccak256('Reservoir')
contractAddress: "${{L1Reservoir.address}}"
- fn: "setPauseGuardian"
pauseGuardian: *pauseGuardian
- fn: "transferOwnership"
Expand All @@ -57,7 +60,7 @@ contracts:
initialSupply: "10000000000000000000000000000" # in wei
calls:
- fn: "addMinter"
minter: "${{RewardsManager.address}}"
minter: "${{L1Reservoir.address}}"
- fn: "renounceMinter"
- fn: "transferOwnership"
owner: *governor
Expand Down Expand Up @@ -131,8 +134,6 @@ contracts:
init:
controller: "${{Controller.address}}"
calls:
- fn: "setIssuanceRate"
issuanceRate: "1000000012184945188" # per block increase of total supply, blocks in a year = 365*60*60*24/13
- fn: "setSubgraphAvailabilityOracle"
subgraphAvailabilityOracle: *availabilityOracle
- fn: "syncAllContracts"
Expand All @@ -158,3 +159,13 @@ contracts:
controller: "${{Controller.address}}"
calls:
- fn: "syncAllContracts"
L1Reservoir:
proxy: true
init:
controller: "${{Controller.address}}"
dripInterval: 50400
calls:
- fn: "approveRewardsManager"
- fn: "initialSnapshot"
pendingRewards: "0"
- fn: "syncAllContracts"
17 changes: 14 additions & 3 deletions config/graph.localhost.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ contracts:
- fn: "setContractProxy"
id: "0xd362cac9cb75c10d67bcc0b7eeb0b1ef48bb5420b556c092d4fd7f758816fcf0" # keccak256('GraphTokenGateway')
contractAddress: "${{L1GraphTokenGateway.address}}"
- fn: "setContractProxy"
id: "0x96ba401694892957e25e29c7a1e4171ae9945b5ee36339de79b199a530436e9e" # keccak256('Reservoir')
contractAddress: "${{L1Reservoir.address}}"
- fn: "setPauseGuardian"
pauseGuardian: *pauseGuardian
- fn: "transferOwnership"
Expand All @@ -57,7 +60,7 @@ contracts:
initialSupply: "10000000000000000000000000000" # in wei
calls:
- fn: "addMinter"
minter: "${{RewardsManager.address}}"
minter: "${{L1Reservoir.address}}"
- fn: "renounceMinter"
- fn: "transferOwnership"
owner: *governor
Expand Down Expand Up @@ -131,8 +134,6 @@ contracts:
init:
controller: "${{Controller.address}}"
calls:
- fn: "setIssuanceRate"
issuanceRate: "1000000012184945188" # per block increase of total supply, blocks in a year = 365*60*60*24/13
- fn: "setSubgraphAvailabilityOracle"
subgraphAvailabilityOracle: *availabilityOracle
- fn: "syncAllContracts"
Expand All @@ -158,3 +159,13 @@ contracts:
controller: "${{Controller.address}}"
calls:
- fn: "syncAllContracts"
L1Reservoir:
proxy: true
init:
controller: "${{Controller.address}}"
dripInterval: 50400
calls:
- fn: "approveRewardsManager"
- fn: "initialSnapshot"
pendingRewards: "0"
- fn: "syncAllContracts"
17 changes: 14 additions & 3 deletions config/graph.mainnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ contracts:
- fn: "setContractProxy"
id: "0xd362cac9cb75c10d67bcc0b7eeb0b1ef48bb5420b556c092d4fd7f758816fcf0" # keccak256('GraphTokenGateway')
contractAddress: "${{L1GraphTokenGateway.address}}"
- fn: "setContractProxy"
id: "0x96ba401694892957e25e29c7a1e4171ae9945b5ee36339de79b199a530436e9e" # keccak256('Reservoir')
contractAddress: "${{L1Reservoir.address}}"
- fn: "setPauseGuardian"
pauseGuardian: *pauseGuardian
- fn: "transferOwnership"
Expand All @@ -57,7 +60,7 @@ contracts:
initialSupply: "10000000000000000000000000000" # in wei
calls:
- fn: "addMinter"
minter: "${{RewardsManager.address}}"
minter: "${{L1Reservoir.address}}"
- fn: "renounceMinter"
- fn: "transferOwnership"
owner: *governor
Expand Down Expand Up @@ -131,8 +134,6 @@ contracts:
init:
controller: "${{Controller.address}}"
calls:
- fn: "setIssuanceRate"
issuanceRate: "1000000012184945188" # per block increase of total supply, blocks in a year = 365*60*60*24/13
- fn: "setSubgraphAvailabilityOracle"
subgraphAvailabilityOracle: *availabilityOracle
- fn: "syncAllContracts"
Expand All @@ -158,3 +159,13 @@ contracts:
controller: "${{Controller.address}}"
calls:
- fn: "syncAllContracts"
L1Reservoir:
proxy: true
init:
controller: "${{Controller.address}}"
dripInterval: 50400
calls:
- fn: "approveRewardsManager"
- fn: "initialSnapshot"
pendingRewards: "0"
- fn: "syncAllContracts"
10 changes: 10 additions & 0 deletions contracts/governance/Managed.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import "../rewards/IRewardsManager.sol";
import "../staking/IStaking.sol";
import "../token/IGraphToken.sol";
import "../arbitrum/ITokenGateway.sol";
import "../reservoir/IReservoir.sol";

/**
* @title Graph Managed contract
Expand Down Expand Up @@ -154,6 +155,14 @@ contract Managed {
return ITokenGateway(_resolveContract(keccak256("GraphTokenGateway")));
}

/**
* @dev Return Reservoir (L1 or L2) interface.
* @return Reservoir contract registered with Controller
*/
function reservoir() internal view returns (IReservoir) {
return IReservoir(_resolveContract(keccak256("Reservoir")));
}

/**
* @dev Resolve a contract address from the cache or the Controller if not found.
* @return Address of the contract
Expand Down Expand Up @@ -192,5 +201,6 @@ contract Managed {
_syncContract("Staking");
_syncContract("GraphToken");
_syncContract("GraphTokenGateway");
_syncContract("Reservoir");
}
}
40 changes: 40 additions & 0 deletions contracts/l2/reservoir/IL2Reservoir.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.7.6;

import { IReservoir } from "../../reservoir/IReservoir.sol";

/**
* @title Interface for the L2 Rewards Reservoir
* @dev This exposes a specific function for the L2Reservoir that is called
* as a callhook from L1 to L2, so that state can be updated when dripped rewards
* are bridged between layers.
*/
interface IL2Reservoir is IReservoir {
/**
* @dev Receive dripped tokens from L1.
* This function can only be called by the gateway, as it is
* meant to be a callhook when receiving tokens from L1. It
* updates the issuanceBase and issuanceRate,
* and snapshots the accumulated rewards. If issuanceRate changes,
* it also triggers a snapshot of rewards per signal on the RewardsManager.
* Note that the transaction might revert if it's received out-of-order,
* because it checks an incrementing nonce. If that is the case, the retryable ticket can be redeemed
* again once the ticket for previous drip has been redeemed.
* A keeper reward will be sent to the keeper that dripped on L1, and part of it
* to whoever redeemed the current retryable ticket (as reported by ArbRetryableTx.getCurrentRedeemer) if
* the ticket is not auto-redeemed.
* @param _issuanceBase Base value for token issuance (approximation for token supply times L2 rewards fraction)
* @param _issuanceRate Rewards issuance rate, using fixed point at 1e18, and including a +1
* @param _nonce Incrementing nonce to ensure messages are received in order
* @param _keeperReward Keeper reward to distribute between keeper that called drip and keeper that redeemed the retryable tx
* @param _l1Keeper Address of the keeper that called drip in L1
*/
function receiveDrip(
uint256 _issuanceBase,
uint256 _issuanceRate,
uint256 _nonce,
uint256 _keeperReward,
address _l1Keeper
) external;
}
Loading