Skip to content

L2: linear rewards, and minting in L2 #700

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

Merged
merged 18 commits into from
Mar 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
1142934
feat: linear indexer rewards
pcarranzav Aug 31, 2022
5d20c86
feat: minting in L1 gateway with allowance
pcarranzav Sep 1, 2022
cc4a2dd
test: avoid issues with epoch boundary in allocation tests
pcarranzav Sep 2, 2022
51cc8cd
chore: add comment on setIssuancePerBlock to remind of L1 allowance c…
pcarranzav Sep 5, 2022
06b9774
fix(RewardsManager): skip calculations if issuance is zero
pcarranzav Sep 7, 2022
bbe2cff
fix(RewardsManagerStorage): make deprecated variables private
pcarranzav Sep 7, 2022
b77f501
fix(cli): replace issuanceRate getter/setter with one for issuancePer…
pcarranzav Sep 7, 2022
5124371
fix(e2e): issuanceRate replaced by issuancePerBlock
pcarranzav Sep 7, 2022
4f2262d
chore(L1GraphTokenGateway): rename _block parameter to _blockNum for …
pcarranzav Sep 7, 2022
6351786
test(L1GraphTokenGateway): remove redundant awaits and combine two ev…
pcarranzav Sep 7, 2022
263355d
fix: add RewardsManager as minter in L2
pcarranzav Sep 27, 2022
dbdda2f
fix: use strict < for block in L2 mint allowance (OZ N-02)
pcarranzav Oct 21, 2022
1845259
fix: remove the deprecated pow from RewardsManager (OZ N-03)
pcarranzav Oct 21, 2022
f340c3a
Merge branch 'dev' into pcv/l2-linear-rewards
pcarranzav Nov 24, 2022
ce1de68
Merge branch 'dev' into pcv/l2-linear-rewards-merge-dev-2
pcarranzav Dec 23, 2022
69e542d
fix: set issuancePerBlock on goerli config
pcarranzav Dec 23, 2022
c0383e1
Merge pull request #780 from graphprotocol/pcv/l2-linear-rewards-merg…
pcarranzav Dec 23, 2022
dc40106
fix(config): set L1 gateway as minter on localhost and goerli
pcarranzav Mar 15, 2023
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
1 change: 0 additions & 1 deletion .solhintignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,5 @@ node_modules
./contracts/discovery/erc1056
./contracts/rewards/RewardsManager.sol
./contracts/staking/libs/LibFixedMath.sol
./contracts/tests/RewardsManagerMock.sol
./contracts/tests/ens
./contracts/tests/testnet/GSRManager.sol
2 changes: 1 addition & 1 deletion cli/commands/protocol/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const gettersList = {
'epochs-length': { contract: 'EpochManager', name: 'epochLength' },
'epochs-current': { contract: 'EpochManager', name: 'currentEpoch' },
// Rewards
'rewards-issuance-rate': { contract: 'RewardsManager', name: 'issuanceRate' },
'rewards-issuance-per-block': { contract: 'RewardsManager', name: 'issuancePerBlock' },
'subgraph-availability-oracle': {
contract: 'RewardsManager',
name: 'subgraphAvailabilityOracle',
Expand Down
2 changes: 1 addition & 1 deletion cli/commands/protocol/set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const settersList = {
// Epochs
'epochs-length': { contract: 'EpochManager', name: 'setEpochLength' },
// Rewards
'rewards-issuance-rate': { contract: 'RewardsManager', name: 'setIssuanceRate' },
'rewards-issuance-per-block': { contract: 'RewardsManager', name: 'setIssuancePerBlock' },
'subgraph-availability-oracle': {
contract: 'RewardsManager',
name: 'setSubgraphAvailabilityOracle',
Expand Down
2 changes: 2 additions & 0 deletions config/graph.arbitrum-goerli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ contracts:
init:
owner: "${{Env.deployer}}"
calls:
- fn: "addMinter"
minter: "${{RewardsManager.address}}"
- fn: "renounceMinter"
- fn: "transferOwnership"
owner: *governor
Expand Down
2 changes: 2 additions & 0 deletions config/graph.arbitrum-localhost.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ contracts:
init:
owner: "${{Env.deployer}}"
calls:
- fn: "addMinter"
minter: "${{RewardsManager.address}}"
- fn: "renounceMinter"
- fn: "transferOwnership"
owner: *governor
Expand Down
2 changes: 2 additions & 0 deletions config/graph.arbitrum-one.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ contracts:
init:
owner: "${{Env.deployer}}"
calls:
- fn: "addMinter"
minter: "${{RewardsManager.address}}"
- fn: "renounceMinter"
- fn: "transferOwnership"
owner: *governor
Expand Down
6 changes: 4 additions & 2 deletions config/graph.goerli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ contracts:
calls:
- fn: "addMinter"
minter: "${{RewardsManager.address}}"
- fn: "addMinter"
minter: "${{L1GraphTokenGateway.address}}"
- fn: "renounceMinter"
- fn: "transferOwnership"
owner: *governor
Expand Down Expand Up @@ -131,8 +133,8 @@ contracts:
init:
controller: "${{Controller.address}}"
calls:
- fn: "setIssuanceRate"
issuanceRate: "1000000011247641700" # per block increase of total supply, blocks in a year = 365*60*60*24/13
- fn: "setIssuancePerBlock"
issuancePerBlock: "114155251141552511415" # per block increase of total supply, blocks in a year = 365*60*60*24/12
- fn: "setSubgraphAvailabilityOracle"
subgraphAvailabilityOracle: *availabilityOracle
- fn: "syncAllContracts"
Expand Down
6 changes: 4 additions & 2 deletions config/graph.localhost.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ contracts:
calls:
- fn: "addMinter"
minter: "${{RewardsManager.address}}"
- fn: "addMinter"
minter: "${{L1GraphTokenGateway.address}}"
- fn: "renounceMinter"
- fn: "transferOwnership"
owner: *governor
Expand Down Expand Up @@ -131,8 +133,8 @@ contracts:
init:
controller: "${{Controller.address}}"
calls:
- fn: "setIssuanceRate"
issuanceRate: "1000000011247641700" # per block increase of total supply, blocks in a year = 365*60*60*24/13
- fn: "setIssuancePerBlock"
issuancePerBlock: "114155251141552511415" # per block increase of total supply, blocks in a year = 365*60*60*24/12
- fn: "setSubgraphAvailabilityOracle"
subgraphAvailabilityOracle: *availabilityOracle
- fn: "syncAllContracts"
Expand Down
6 changes: 4 additions & 2 deletions config/graph.mainnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ contracts:
calls:
- fn: "addMinter"
minter: "${{RewardsManager.address}}"
- fn: "addMinter"
minter: "${{L1GraphTokenGateway.address}}"
- fn: "renounceMinter"
- fn: "transferOwnership"
owner: *governor
Expand Down Expand Up @@ -131,8 +133,8 @@ contracts:
init:
controller: "${{Controller.address}}"
calls:
- fn: "setIssuanceRate"
issuanceRate: "1000000011247641700" # per block increase of total supply, blocks in a year = 365*60*60*24/13
- fn: "setIssuancePerBlock"
issuancePerBlock: "114155251141552511415" # per block increase of total supply, blocks in a year = 365*60*60*24/12
- fn: "setSubgraphAvailabilityOracle"
subgraphAvailabilityOracle: *availabilityOracle
- fn: "syncAllContracts"
Expand Down
110 changes: 108 additions & 2 deletions contracts/gateway/L1GraphTokenGateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ contract L1GraphTokenGateway is Initializable, GraphTokenGateway, L1ArbitrumMess
address public escrow;
/// Addresses for which this mapping is true are allowed to send callhooks in outbound transfers
mapping(address => bool) public callhookAllowlist;
/// Total amount minted from L2
uint256 public totalMintedFromL2;
/// Accumulated allowance for tokens minted from L2 at lastL2MintAllowanceUpdateBlock
uint256 public accumulatedL2MintAllowanceSnapshot;
/// Block at which new L2 allowance starts accumulating
uint256 public lastL2MintAllowanceUpdateBlock;
/// New L2 mint allowance per block
uint256 public l2MintAllowancePerBlock;

/// Emitted when an outbound transfer is initiated, i.e. tokens are deposited from L1 to L2
event DepositInitiated(
Expand Down Expand Up @@ -71,6 +79,14 @@ contract L1GraphTokenGateway is Initializable, GraphTokenGateway, L1ArbitrumMess
event AddedToCallhookAllowlist(address newAllowlisted);
/// Emitted when an address is removed from the callhook allowlist
event RemovedFromCallhookAllowlist(address notAllowlisted);
/// Emitted when the L2 mint allowance per block is updated
event L2MintAllowanceUpdated(
uint256 accumulatedL2MintAllowanceSnapshot,
uint256 l2MintAllowancePerBlock,
uint256 lastL2MintAllowanceUpdateBlock
);
/// Emitted when tokens are minted due to an incoming transfer from L2
event TokensMintedFromL2(uint256 amount);

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

/**
* @dev Updates the L2 mint allowance per block
* It is meant to be called _after_ the issuancePerBlock is updated in L2.
* The caller should provide the new issuance per block and the block at which it was updated,
* the function will automatically compute the values so that the bridge's mint allowance
* correctly tracks the maximum rewards minted in L2.
* @param _l2IssuancePerBlock New issuancePerBlock that has been set in L2
* @param _updateBlockNum L1 Block number at which issuancePerBlock was updated in L2
*/
function updateL2MintAllowance(uint256 _l2IssuancePerBlock, uint256 _updateBlockNum)
external
onlyGovernor
{
require(_updateBlockNum < block.number, "BLOCK_MUST_BE_PAST");
require(_updateBlockNum > lastL2MintAllowanceUpdateBlock, "BLOCK_MUST_BE_INCREMENTING");
accumulatedL2MintAllowanceSnapshot = accumulatedL2MintAllowanceAtBlock(_updateBlockNum);
lastL2MintAllowanceUpdateBlock = _updateBlockNum;
l2MintAllowancePerBlock = _l2IssuancePerBlock;
emit L2MintAllowanceUpdated(
accumulatedL2MintAllowanceSnapshot,
l2MintAllowancePerBlock,
lastL2MintAllowanceUpdateBlock
);
}

/**
* @dev Manually sets the parameters used to compute the L2 mint allowance
* The use of this function is not recommended, use updateL2MintAllowance instead;
* this one is only meant to be used as a backup recovery if a previous call to
* updateL2MintAllowance was done with incorrect values.
* @param _accumulatedL2MintAllowanceSnapshot Accumulated L2 mint allowance at L1 block _lastL2MintAllowanceUpdateBlock
* @param _l2MintAllowancePerBlock L2 issuance per block since block number _lastL2MintAllowanceUpdateBlock
* @param _lastL2MintAllowanceUpdateBlock L1 Block number at which issuancePerBlock was last updated in L2
*/
function setL2MintAllowanceParametersManual(
uint256 _accumulatedL2MintAllowanceSnapshot,
uint256 _l2MintAllowancePerBlock,
uint256 _lastL2MintAllowanceUpdateBlock
) external onlyGovernor {
require(_lastL2MintAllowanceUpdateBlock < block.number, "BLOCK_MUST_BE_PAST");
accumulatedL2MintAllowanceSnapshot = _accumulatedL2MintAllowanceSnapshot;
l2MintAllowancePerBlock = _l2MintAllowancePerBlock;
lastL2MintAllowanceUpdateBlock = _lastL2MintAllowanceUpdateBlock;
emit L2MintAllowanceUpdated(
accumulatedL2MintAllowanceSnapshot,
l2MintAllowancePerBlock,
lastL2MintAllowanceUpdateBlock
);
}

/**
* @notice Creates and sends a retryable ticket to transfer GRT to L2 using the Arbitrum Inbox.
* The tokens are escrowed by the gateway until they are withdrawn back to L1.
Expand Down Expand Up @@ -277,8 +343,10 @@ contract L1GraphTokenGateway is Initializable, GraphTokenGateway, L1ArbitrumMess
require(_l1Token == address(token), "TOKEN_NOT_GRT");

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

emit WithdrawalFinalized(_l1Token, _from, _to, 0, _amount);
Expand Down Expand Up @@ -381,4 +449,42 @@ contract L1GraphTokenGateway is Initializable, GraphTokenGateway, L1ArbitrumMess
(maxSubmissionCost, extraData) = abi.decode(extraData, (uint256, bytes));
return (from, maxSubmissionCost, extraData);
}

/**
* @dev Get the accumulated L2 mint allowance at a particular block number
* @param _blockNum Block at which allowance will be computed
* @return The accumulated GRT amount that can be minted from L2 at the specified block
*/
function accumulatedL2MintAllowanceAtBlock(uint256 _blockNum) public view returns (uint256) {
require(_blockNum >= lastL2MintAllowanceUpdateBlock, "INVALID_BLOCK_FOR_MINT_ALLOWANCE");
return
accumulatedL2MintAllowanceSnapshot.add(
l2MintAllowancePerBlock.mul(_blockNum.sub(lastL2MintAllowanceUpdateBlock))
);
}

/**
* @dev Mint new L1 tokens coming from L2
* This will check if the amount to mint is within the L2's mint allowance, and revert otherwise.
* The tokens will be sent to the bridge escrow (from where they will then be sent to the destinatary
* of the current inbound transfer).
* @param _amount Number of tokens to mint
*/
function _mintFromL2(uint256 _amount) internal {
// If we're trying to mint more than allowed, something's gone terribly wrong
// (either the L2 issuance is wrong, or the Arbitrum bridge has been compromised)
require(_l2MintAmountAllowed(_amount), "INVALID_L2_MINT_AMOUNT");
totalMintedFromL2 = totalMintedFromL2.add(_amount);
graphToken().mint(escrow, _amount);
emit TokensMintedFromL2(_amount);
}

/**
* @dev Check if minting a certain amount of tokens from L2 is within allowance
* @param _amount Number of tokens that would be minted
* @return true if minting those tokens is allowed, or false if it would be over allowance
*/
function _l2MintAmountAllowed(uint256 _amount) internal view returns (bool) {
return (totalMintedFromL2.add(_amount) <= accumulatedL2MintAllowanceAtBlock(block.number));
}
}
2 changes: 1 addition & 1 deletion contracts/rewards/IRewardsManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ interface IRewardsManager {

// -- Config --

function setIssuanceRate(uint256 _issuanceRate) external;
function setIssuancePerBlock(uint256 _issuancePerBlock) external;

function setMinimumSubgraphSignal(uint256 _minimumSubgraphSignal) external;

Expand Down
Loading