Skip to content

Commit 23611af

Browse files
authored
Merge pull request #700 from graphprotocol/pcv/l2-linear-rewards
L2: linear rewards, and minting in L2
2 parents 8fd6ff3 + dc40106 commit 23611af

23 files changed

+498
-278
lines changed

.solhintignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,5 @@ node_modules
44
./contracts/discovery/erc1056
55
./contracts/rewards/RewardsManager.sol
66
./contracts/staking/libs/LibFixedMath.sol
7-
./contracts/tests/RewardsManagerMock.sol
87
./contracts/tests/ens
98
./contracts/tests/testnet/GSRManager.sol

cli/commands/protocol/get.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export const gettersList = {
3434
'epochs-length': { contract: 'EpochManager', name: 'epochLength' },
3535
'epochs-current': { contract: 'EpochManager', name: 'currentEpoch' },
3636
// Rewards
37-
'rewards-issuance-rate': { contract: 'RewardsManager', name: 'issuanceRate' },
37+
'rewards-issuance-per-block': { contract: 'RewardsManager', name: 'issuancePerBlock' },
3838
'subgraph-availability-oracle': {
3939
contract: 'RewardsManager',
4040
name: 'subgraphAvailabilityOracle',

cli/commands/protocol/set.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export const settersList = {
3939
// Epochs
4040
'epochs-length': { contract: 'EpochManager', name: 'setEpochLength' },
4141
// Rewards
42-
'rewards-issuance-rate': { contract: 'RewardsManager', name: 'setIssuanceRate' },
42+
'rewards-issuance-per-block': { contract: 'RewardsManager', name: 'setIssuancePerBlock' },
4343
'subgraph-availability-oracle': {
4444
contract: 'RewardsManager',
4545
name: 'setSubgraphAvailabilityOracle',

config/graph.arbitrum-goerli.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ contracts:
5757
init:
5858
owner: "${{Env.deployer}}"
5959
calls:
60+
- fn: "addMinter"
61+
minter: "${{RewardsManager.address}}"
6062
- fn: "renounceMinter"
6163
- fn: "transferOwnership"
6264
owner: *governor

config/graph.arbitrum-localhost.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ contracts:
5757
init:
5858
owner: "${{Env.deployer}}"
5959
calls:
60+
- fn: "addMinter"
61+
minter: "${{RewardsManager.address}}"
6062
- fn: "renounceMinter"
6163
- fn: "transferOwnership"
6264
owner: *governor

config/graph.arbitrum-one.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ contracts:
5757
init:
5858
owner: "${{Env.deployer}}"
5959
calls:
60+
- fn: "addMinter"
61+
minter: "${{RewardsManager.address}}"
6062
- fn: "renounceMinter"
6163
- fn: "transferOwnership"
6264
owner: *governor

config/graph.goerli.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ contracts:
5858
calls:
5959
- fn: "addMinter"
6060
minter: "${{RewardsManager.address}}"
61+
- fn: "addMinter"
62+
minter: "${{L1GraphTokenGateway.address}}"
6163
- fn: "renounceMinter"
6264
- fn: "transferOwnership"
6365
owner: *governor
@@ -131,8 +133,8 @@ contracts:
131133
init:
132134
controller: "${{Controller.address}}"
133135
calls:
134-
- fn: "setIssuanceRate"
135-
issuanceRate: "1000000011247641700" # per block increase of total supply, blocks in a year = 365*60*60*24/13
136+
- fn: "setIssuancePerBlock"
137+
issuancePerBlock: "114155251141552511415" # per block increase of total supply, blocks in a year = 365*60*60*24/12
136138
- fn: "setSubgraphAvailabilityOracle"
137139
subgraphAvailabilityOracle: *availabilityOracle
138140
- fn: "syncAllContracts"

config/graph.localhost.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ contracts:
5858
calls:
5959
- fn: "addMinter"
6060
minter: "${{RewardsManager.address}}"
61+
- fn: "addMinter"
62+
minter: "${{L1GraphTokenGateway.address}}"
6163
- fn: "renounceMinter"
6264
- fn: "transferOwnership"
6365
owner: *governor
@@ -131,8 +133,8 @@ contracts:
131133
init:
132134
controller: "${{Controller.address}}"
133135
calls:
134-
- fn: "setIssuanceRate"
135-
issuanceRate: "1000000011247641700" # per block increase of total supply, blocks in a year = 365*60*60*24/13
136+
- fn: "setIssuancePerBlock"
137+
issuancePerBlock: "114155251141552511415" # per block increase of total supply, blocks in a year = 365*60*60*24/12
136138
- fn: "setSubgraphAvailabilityOracle"
137139
subgraphAvailabilityOracle: *availabilityOracle
138140
- fn: "syncAllContracts"

config/graph.mainnet.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ contracts:
5858
calls:
5959
- fn: "addMinter"
6060
minter: "${{RewardsManager.address}}"
61+
- fn: "addMinter"
62+
minter: "${{L1GraphTokenGateway.address}}"
6163
- fn: "renounceMinter"
6264
- fn: "transferOwnership"
6365
owner: *governor
@@ -131,8 +133,8 @@ contracts:
131133
init:
132134
controller: "${{Controller.address}}"
133135
calls:
134-
- fn: "setIssuanceRate"
135-
issuanceRate: "1000000011247641700" # per block increase of total supply, blocks in a year = 365*60*60*24/13
136+
- fn: "setIssuancePerBlock"
137+
issuancePerBlock: "114155251141552511415" # per block increase of total supply, blocks in a year = 365*60*60*24/12
136138
- fn: "setSubgraphAvailabilityOracle"
137139
subgraphAvailabilityOracle: *availabilityOracle
138140
- fn: "syncAllContracts"

contracts/gateway/L1GraphTokenGateway.sol

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ contract L1GraphTokenGateway is Initializable, GraphTokenGateway, L1ArbitrumMess
4040
address public escrow;
4141
/// Addresses for which this mapping is true are allowed to send callhooks in outbound transfers
4242
mapping(address => bool) public callhookAllowlist;
43+
/// Total amount minted from L2
44+
uint256 public totalMintedFromL2;
45+
/// Accumulated allowance for tokens minted from L2 at lastL2MintAllowanceUpdateBlock
46+
uint256 public accumulatedL2MintAllowanceSnapshot;
47+
/// Block at which new L2 allowance starts accumulating
48+
uint256 public lastL2MintAllowanceUpdateBlock;
49+
/// New L2 mint allowance per block
50+
uint256 public l2MintAllowancePerBlock;
4351

4452
/// Emitted when an outbound transfer is initiated, i.e. tokens are deposited from L1 to L2
4553
event DepositInitiated(
@@ -71,6 +79,14 @@ contract L1GraphTokenGateway is Initializable, GraphTokenGateway, L1ArbitrumMess
7179
event AddedToCallhookAllowlist(address newAllowlisted);
7280
/// Emitted when an address is removed from the callhook allowlist
7381
event RemovedFromCallhookAllowlist(address notAllowlisted);
82+
/// Emitted when the L2 mint allowance per block is updated
83+
event L2MintAllowanceUpdated(
84+
uint256 accumulatedL2MintAllowanceSnapshot,
85+
uint256 l2MintAllowancePerBlock,
86+
uint256 lastL2MintAllowanceUpdateBlock
87+
);
88+
/// Emitted when tokens are minted due to an incoming transfer from L2
89+
event TokensMintedFromL2(uint256 amount);
7490

7591
/**
7692
* @dev Allows a function to be called only by the gateway's L2 counterpart.
@@ -182,6 +198,56 @@ contract L1GraphTokenGateway is Initializable, GraphTokenGateway, L1ArbitrumMess
182198
emit RemovedFromCallhookAllowlist(_notAllowlisted);
183199
}
184200

201+
/**
202+
* @dev Updates the L2 mint allowance per block
203+
* It is meant to be called _after_ the issuancePerBlock is updated in L2.
204+
* The caller should provide the new issuance per block and the block at which it was updated,
205+
* the function will automatically compute the values so that the bridge's mint allowance
206+
* correctly tracks the maximum rewards minted in L2.
207+
* @param _l2IssuancePerBlock New issuancePerBlock that has been set in L2
208+
* @param _updateBlockNum L1 Block number at which issuancePerBlock was updated in L2
209+
*/
210+
function updateL2MintAllowance(uint256 _l2IssuancePerBlock, uint256 _updateBlockNum)
211+
external
212+
onlyGovernor
213+
{
214+
require(_updateBlockNum < block.number, "BLOCK_MUST_BE_PAST");
215+
require(_updateBlockNum > lastL2MintAllowanceUpdateBlock, "BLOCK_MUST_BE_INCREMENTING");
216+
accumulatedL2MintAllowanceSnapshot = accumulatedL2MintAllowanceAtBlock(_updateBlockNum);
217+
lastL2MintAllowanceUpdateBlock = _updateBlockNum;
218+
l2MintAllowancePerBlock = _l2IssuancePerBlock;
219+
emit L2MintAllowanceUpdated(
220+
accumulatedL2MintAllowanceSnapshot,
221+
l2MintAllowancePerBlock,
222+
lastL2MintAllowanceUpdateBlock
223+
);
224+
}
225+
226+
/**
227+
* @dev Manually sets the parameters used to compute the L2 mint allowance
228+
* The use of this function is not recommended, use updateL2MintAllowance instead;
229+
* this one is only meant to be used as a backup recovery if a previous call to
230+
* updateL2MintAllowance was done with incorrect values.
231+
* @param _accumulatedL2MintAllowanceSnapshot Accumulated L2 mint allowance at L1 block _lastL2MintAllowanceUpdateBlock
232+
* @param _l2MintAllowancePerBlock L2 issuance per block since block number _lastL2MintAllowanceUpdateBlock
233+
* @param _lastL2MintAllowanceUpdateBlock L1 Block number at which issuancePerBlock was last updated in L2
234+
*/
235+
function setL2MintAllowanceParametersManual(
236+
uint256 _accumulatedL2MintAllowanceSnapshot,
237+
uint256 _l2MintAllowancePerBlock,
238+
uint256 _lastL2MintAllowanceUpdateBlock
239+
) external onlyGovernor {
240+
require(_lastL2MintAllowanceUpdateBlock < block.number, "BLOCK_MUST_BE_PAST");
241+
accumulatedL2MintAllowanceSnapshot = _accumulatedL2MintAllowanceSnapshot;
242+
l2MintAllowancePerBlock = _l2MintAllowancePerBlock;
243+
lastL2MintAllowanceUpdateBlock = _lastL2MintAllowanceUpdateBlock;
244+
emit L2MintAllowanceUpdated(
245+
accumulatedL2MintAllowanceSnapshot,
246+
l2MintAllowancePerBlock,
247+
lastL2MintAllowanceUpdateBlock
248+
);
249+
}
250+
185251
/**
186252
* @notice Creates and sends a retryable ticket to transfer GRT to L2 using the Arbitrum Inbox.
187253
* The tokens are escrowed by the gateway until they are withdrawn back to L1.
@@ -277,8 +343,10 @@ contract L1GraphTokenGateway is Initializable, GraphTokenGateway, L1ArbitrumMess
277343
require(_l1Token == address(token), "TOKEN_NOT_GRT");
278344

279345
uint256 escrowBalance = token.balanceOf(escrow);
280-
// If the bridge doesn't have enough tokens, something's very wrong!
281-
require(_amount <= escrowBalance, "BRIDGE_OUT_OF_FUNDS");
346+
if (_amount > escrowBalance) {
347+
// This will revert if trying to mint more than allowed
348+
_mintFromL2(_amount.sub(escrowBalance));
349+
}
282350
token.transferFrom(escrow, _to, _amount);
283351

284352
emit WithdrawalFinalized(_l1Token, _from, _to, 0, _amount);
@@ -381,4 +449,42 @@ contract L1GraphTokenGateway is Initializable, GraphTokenGateway, L1ArbitrumMess
381449
(maxSubmissionCost, extraData) = abi.decode(extraData, (uint256, bytes));
382450
return (from, maxSubmissionCost, extraData);
383451
}
452+
453+
/**
454+
* @dev Get the accumulated L2 mint allowance at a particular block number
455+
* @param _blockNum Block at which allowance will be computed
456+
* @return The accumulated GRT amount that can be minted from L2 at the specified block
457+
*/
458+
function accumulatedL2MintAllowanceAtBlock(uint256 _blockNum) public view returns (uint256) {
459+
require(_blockNum >= lastL2MintAllowanceUpdateBlock, "INVALID_BLOCK_FOR_MINT_ALLOWANCE");
460+
return
461+
accumulatedL2MintAllowanceSnapshot.add(
462+
l2MintAllowancePerBlock.mul(_blockNum.sub(lastL2MintAllowanceUpdateBlock))
463+
);
464+
}
465+
466+
/**
467+
* @dev Mint new L1 tokens coming from L2
468+
* This will check if the amount to mint is within the L2's mint allowance, and revert otherwise.
469+
* The tokens will be sent to the bridge escrow (from where they will then be sent to the destinatary
470+
* of the current inbound transfer).
471+
* @param _amount Number of tokens to mint
472+
*/
473+
function _mintFromL2(uint256 _amount) internal {
474+
// If we're trying to mint more than allowed, something's gone terribly wrong
475+
// (either the L2 issuance is wrong, or the Arbitrum bridge has been compromised)
476+
require(_l2MintAmountAllowed(_amount), "INVALID_L2_MINT_AMOUNT");
477+
totalMintedFromL2 = totalMintedFromL2.add(_amount);
478+
graphToken().mint(escrow, _amount);
479+
emit TokensMintedFromL2(_amount);
480+
}
481+
482+
/**
483+
* @dev Check if minting a certain amount of tokens from L2 is within allowance
484+
* @param _amount Number of tokens that would be minted
485+
* @return true if minting those tokens is allowed, or false if it would be over allowance
486+
*/
487+
function _l2MintAmountAllowed(uint256 _amount) internal view returns (bool) {
488+
return (totalMintedFromL2.add(_amount) <= accumulatedL2MintAllowanceAtBlock(block.number));
489+
}
384490
}

0 commit comments

Comments
 (0)