forked from bgd-labs/example-liquidity-mining-aave-v3
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEmissionTestOpOptimism.t.sol
165 lines (143 loc) · 7.09 KB
/
EmissionTestOpOptimism.t.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Test} from 'forge-std/Test.sol';
import {IERC20} from 'forge-std/interfaces/IERC20.sol';
import {AaveV3Optimism} from 'aave-address-book/AaveV3Optimism.sol';
import {IEmissionManager, ITransferStrategyBase, RewardsDataTypes, IEACAggregatorProxy} from '../src/interfaces/IEmissionManager.sol';
import {BaseTest} from './utils/BaseTest.sol';
import {AddEmissionAdminPayload} from '../src/contracts/AddEmissionAdminPayload.sol';
contract EmissionTestOpOptimism is BaseTest {
/// @dev Used to simplify the definition of a program of emissions
/// @param asset The asset on which to put reward on, usually Aave atokens or variable debt tokens
/// @param emission Total emission of a `reward` token during the whole distribution duration defined
/// E.g. With an emission of 1_000_000 OP tokens during 10 days, an emission of 10% for aUSDC would be
/// 1_000_000 * 1e18 * 10% / 10 days in seconds = 100_000 * 1e18 / 864_000 = ~ 0.11574 * 1e18
struct EmissionPerAsset {
address asset;
uint256 emission;
}
address constant GUARDIAN = 0xE50c8C619d05ff98b22Adf991F17602C774F785c;
IEmissionManager constant EMISSION_MANAGER =
IEmissionManager(0x048f2228D7Bf6776f99aB50cB1b1eaB4D1d4cA73);
address constant OP_EMISSION_ADMIN = 0x2501c477D0A35545a387Aa4A3EEe4292A9a8B3F0;
address constant OP = 0x4200000000000000000000000000000000000042;
IEACAggregatorProxy constant REWARD_ORACLE =
IEACAggregatorProxy(0x0D276FC14719f9292D5C1eA2198673d1f4269246); // OP/USD
ITransferStrategyBase constant TRANSFER_STRATEGY =
ITransferStrategyBase(0x80B2a024A0f347e774ec3bc58304978FB3DFc940);
uint256 constant TOTAL_DISTRIBUTION = 5_000_000 ether; // 5m OP
uint88 constant DURATION_DISTRIBUTION = 90 days;
function setUp() public {
vm.createSelectFork(vm.rpcUrl('optimism'), 33341802);
/// @dev chains that are controlled by crosschain governance need to execute a proposal to set the emission admin
// AddEmissionAdminPayload payload = new AddEmissionAdminPayload(
// EMISSION_MANAGER,
// OP,
// OP_EMISSION_ADMIN
// );
// _setUp(AaveV3Optimism.ACL_ADMIN);
// _execute(address(payload));
// vm.startPrank(GUARDIAN);
/// @dev only necessary if the OP_EMISSION_ADMIN doesn't have permissions
// EMISSION_MANAGER.setEmissionAdmin(OP, OP_EMISSION_ADMIN);
// vm.stopPrank();
}
function test_activation() public {
vm.startPrank(OP_EMISSION_ADMIN);
/// @dev IMPORTANT!!
/// The emissions admin should have OP funds, and have approved the TOTAL_DISTRIBUTION
/// amount to the transfer strategy. If not, REWARDS WILL ACCRUE FINE AFTER `configureAssets()`, BUT THEY
/// WIL NOT BE CLAIMABLE UNTIL THERE IS FUNDS AND ALLOWANCE.
/// It is possible to approve less than TOTAL_DISTRIBUTION and doing it progressively over time as users
/// accrue more, but that is a decision of the emission's admin
IERC20(OP).approve(address(TRANSFER_STRATEGY), TOTAL_DISTRIBUTION);
EMISSION_MANAGER.configureAssets(_getAssetConfigs());
emit log_bytes(
abi.encodeWithSelector(EMISSION_MANAGER.configureAssets.selector, _getAssetConfigs())
);
vm.stopPrank();
}
function _getAssetConfigs() internal view returns (RewardsDataTypes.RewardsConfigInput[] memory) {
uint32 distributionEnd = uint32(block.timestamp + DURATION_DISTRIBUTION);
EmissionPerAsset[] memory emissionsPerAsset = _getEmissionsPerAsset();
RewardsDataTypes.RewardsConfigInput[]
memory configs = new RewardsDataTypes.RewardsConfigInput[](emissionsPerAsset.length);
for (uint256 i = 0; i < emissionsPerAsset.length; i++) {
configs[i] = RewardsDataTypes.RewardsConfigInput({
emissionPerSecond: _toUint88(emissionsPerAsset[i].emission / DURATION_DISTRIBUTION),
totalSupply: 0, // IMPORTANT this will not be taken into account by the contracts, so 0 is fine
distributionEnd: distributionEnd,
asset: emissionsPerAsset[i].asset,
reward: OP,
transferStrategy: TRANSFER_STRATEGY,
rewardOracle: REWARD_ORACLE
});
}
return configs;
}
function _getEmissionsPerAsset() internal pure returns (EmissionPerAsset[] memory) {
EmissionPerAsset[] memory emissionsPerAsset = new EmissionPerAsset[](13);
emissionsPerAsset[0] = EmissionPerAsset({
asset: 0x625E7708f30cA75bfd92586e17077590C60eb4cD, // aOptUSDC
emission: 517_500 ether // 10.35% of TOTAL_DISTRIBUTION
});
emissionsPerAsset[1] = EmissionPerAsset({
asset: 0xFCCf3cAbbe80101232d343252614b6A3eE81C989, // variableDebtOptUSDC
emission: 1_207_500 ether // 24.15% of TOTAL_DISTRIBUTION
});
emissionsPerAsset[2] = EmissionPerAsset({
asset: 0x82E64f49Ed5EC1bC6e43DAD4FC8Af9bb3A2312EE, // aOptDAI
emission: 315_000 ether // 6.3% of TOTAL_DISTRIBUTION
});
emissionsPerAsset[3] = EmissionPerAsset({
asset: 0x8619d80FB0141ba7F184CbF22fd724116D9f7ffC, // variableDebtOptDAI
emission: 735_000 ether // 14.7% of TOTAL_DISTRIBUTION
});
emissionsPerAsset[4] = EmissionPerAsset({
asset: 0x6ab707Aca953eDAeFBc4fD23bA73294241490620, // aOptUSDT
emission: 180_000 ether // 3.6% of TOTAL_DISTRIBUTION
});
emissionsPerAsset[5] = EmissionPerAsset({
asset: 0xfb00AC187a8Eb5AFAE4eACE434F493Eb62672df7, // variableDebtOptUSDT
emission: 420_000 ether // 8.4% of TOTAL_DISTRIBUTION
});
emissionsPerAsset[6] = EmissionPerAsset({
asset: 0x6d80113e533a2C0fe82EaBD35f1875DcEA89Ea97, // aOptSUSD
emission: 120_000 ether // 2.4% of TOTAL_DISTRIBUTION
});
emissionsPerAsset[7] = EmissionPerAsset({
asset: 0x4a1c3aD6Ed28a636ee1751C69071f6be75DEb8B8, // variableDebtOptSUSD
emission: 280_000 ether // 5.6% of TOTAL_DISTRIBUTION
});
emissionsPerAsset[8] = EmissionPerAsset({
asset: 0xe50fA9b3c56FfB159cB0FCA61F5c9D750e8128c8, // aOptWETH
emission: 675_000 ether // 13.5% of TOTAL_DISTRIBUTION
});
emissionsPerAsset[9] = EmissionPerAsset({
asset: 0x0c84331e39d6658Cd6e6b9ba04736cC4c4734351, // variableDebtOptWETH
emission: 75_000 ether // 1.5% of TOTAL_DISTRIBUTION
});
emissionsPerAsset[10] = EmissionPerAsset({
asset: 0x078f358208685046a11C85e8ad32895DED33A249, // aOptWBTC
emission: 225_000 ether // 4.5% of TOTAL_DISTRIBUTION
});
emissionsPerAsset[11] = EmissionPerAsset({
asset: 0x92b42c66840C7AD907b4BF74879FF3eF7c529473, // variableDebtOptWBTC
emission: 25_000 ether // 0.5% of TOTAL_DISTRIBUTION
});
emissionsPerAsset[12] = EmissionPerAsset({
asset: 0xf329e36C7bF6E5E86ce2150875a84Ce77f477375, // aOptAAVE
emission: 225_000 ether // 4.5% of TOTAL_DISTRIBUTION
});
uint256 totalDistribution;
for (uint256 i = 0; i < emissionsPerAsset.length; i++) {
totalDistribution += emissionsPerAsset[i].emission;
}
require(totalDistribution == TOTAL_DISTRIBUTION, 'INVALID_SUM_OF_EMISSIONS');
return emissionsPerAsset;
}
function _toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
}