Skip to content

Commit 7fa70d1

Browse files
committed
feat: prices automation support for chainlink v2.3
1 parent 9dd4cb1 commit 7fa70d1

18 files changed

Lines changed: 2000 additions & 96 deletions

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,13 @@ npx hardhat run scripts/emissions/<version>/register_log_upkeeps.ts --network <n
109109
1. Deploy and configure `TokenUpkeepManager` contract by running:
110110

111111
```bash
112-
npx hardhat run scripts/prices/deploy_upkeep_manager.ts --network <network>
112+
npx hardhat run scripts/prices/<version>/deploy_upkeep_manager.ts --network <network>
113113
```
114114

115115
2. Register log trigger upkeep for the deployed `TokenUpkeepManager` contract and set the trusted forwarder:
116116

117117
```bash
118-
npx hardhat run scripts/prices/register_log_upkeep.ts --network <network>
118+
npx hardhat run scripts/prices/<version>/register_log_upkeep.ts --network <network>
119119
```
120120

121121
**Note:** Make sure the account running the script has enough LINK to pay for the initial upkeep registration determined by the `LOG_UPKEEP_FUND_AMOUNT` and `LOG_UPKEEP_GAS_LIMIT` environment variables.

contracts/prices/TokenUpkeep.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
pragma solidity 0.8.6;
33

44
import {ITokenUpkeep} from "./interfaces/ITokenUpkeep.sol";
5-
import {ITokenUpkeepManager} from "./interfaces/ITokenUpkeepManager.sol";
5+
import {ITokenUpkeepManager} from "./interfaces/common/ITokenUpkeepManager.sol";
66

77
contract TokenUpkeep is ITokenUpkeep {
88
/// @inheritdoc ITokenUpkeep

contracts/prices/TokenUpkeepManager.sol renamed to contracts/prices/common/TokenUpkeepManager.sol

Lines changed: 14 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,20 @@ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
55
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
66
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
77
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
8-
import {StableEnumerableSet} from "./libraries/StableEnumerableSet.sol";
8+
import {StableEnumerableSet} from "../libraries/StableEnumerableSet.sol";
99
import {Log} from "@chainlink/contracts/src/v0.8/automation/interfaces/ILogAutomation.sol";
10-
import {IVoter} from "../../vendor/velodrome-contracts/contracts/interfaces/IVoter.sol";
11-
import {IKeeperRegistryMaster} from "@chainlink/contracts/src/v0.8/automation/interfaces/v2_1/IKeeperRegistryMaster.sol";
12-
import {IAutomationRegistrarV2_1} from "../interfaces/v2_1/IAutomationRegistrarV2_1.sol";
13-
import {IUpkeepBalanceMonitor} from "../interfaces/IUpkeepBalanceMonitor.sol";
14-
import {IPrices} from "./interfaces/IPrices.sol";
15-
import {TokenUpkeep} from "./TokenUpkeep.sol";
16-
import {ITokenUpkeepManager} from "./interfaces/ITokenUpkeepManager.sol";
17-
18-
contract TokenUpkeepManager is ITokenUpkeepManager, Ownable {
10+
import {IVoter} from "../../../vendor/velodrome-contracts/contracts/interfaces/IVoter.sol";
11+
import {IPrices} from "../interfaces/IPrices.sol";
12+
import {ITokenUpkeepManager} from "../interfaces/common/ITokenUpkeepManager.sol";
13+
14+
abstract contract TokenUpkeepManager is ITokenUpkeepManager, Ownable {
1915
using SafeERC20 for IERC20;
2016
using StableEnumerableSet for StableEnumerableSet.AddressSet;
2117
using EnumerableSet for EnumerableSet.UintSet;
2218

2319
/// @inheritdoc ITokenUpkeepManager
2420
address public immutable override linkToken;
2521
/// @inheritdoc ITokenUpkeepManager
26-
address public immutable override keeperRegistry;
27-
/// @inheritdoc ITokenUpkeepManager
2822
address public immutable override automationRegistrar;
2923
/// @inheritdoc ITokenUpkeepManager
3024
address public immutable override voter;
@@ -50,18 +44,17 @@ contract TokenUpkeepManager is ITokenUpkeepManager, Ownable {
5044
uint256[] public override upkeepIds;
5145

5246
StableEnumerableSet.AddressSet internal _tokenList;
53-
EnumerableSet.UintSet private _cancelledUpkeepIds;
47+
EnumerableSet.UintSet internal _cancelledUpkeepIds;
5448

55-
uint256 private constant TOKENS_PER_UPKEEP = 100;
56-
uint256 private constant UPKEEP_CANCEL_BUFFER = 20;
57-
uint8 private constant CONDITIONAL_TRIGGER_TYPE = 0;
58-
string private constant UPKEEP_NAME = "Token upkeep";
49+
uint256 internal constant TOKENS_PER_UPKEEP = 100;
50+
uint256 internal constant UPKEEP_CANCEL_BUFFER = 20;
51+
uint8 internal constant CONDITIONAL_TRIGGER_TYPE = 0;
52+
string internal constant UPKEEP_NAME = "Token upkeep";
5953

6054
bytes32 private constant WHITELIST_TOKEN_EVENT = 0x44948130cf88523dbc150908a47dd6332c33a01a3869d7f2fa78e51d5a5f9c57;
6155

6256
constructor(
6357
address _linkToken,
64-
address _keeperRegistry,
6558
address _automationRegistrar,
6659
address _voter,
6760
address _pricesOracle,
@@ -70,7 +63,6 @@ contract TokenUpkeepManager is ITokenUpkeepManager, Ownable {
7063
uint32 _newUpkeepGasLimit
7164
) {
7265
linkToken = _linkToken;
73-
keeperRegistry = _keeperRegistry;
7466
automationRegistrar = _automationRegistrar;
7567
voter = _voter;
7668
pricesOracle = _pricesOracle;
@@ -337,51 +329,11 @@ contract TokenUpkeepManager is ITokenUpkeepManager, Ownable {
337329
emit TokenDeregistered(_token);
338330
}
339331

340-
function _registerTokenUpkeep() internal {
341-
uint256 startIndex = _getNextUpkeepStartIndex(upkeepIds.length);
342-
uint256 endIndex = startIndex + TOKENS_PER_UPKEEP;
343-
address _tokenUpkeep = address(new TokenUpkeep(startIndex, endIndex));
344-
isTokenUpkeep[_tokenUpkeep] = true;
345-
IAutomationRegistrarV2_1.RegistrationParams memory params = IAutomationRegistrarV2_1.RegistrationParams({
346-
name: UPKEEP_NAME,
347-
encryptedEmail: "",
348-
upkeepContract: _tokenUpkeep,
349-
gasLimit: newUpkeepGasLimit,
350-
adminAddress: address(this),
351-
triggerType: CONDITIONAL_TRIGGER_TYPE,
352-
checkData: "",
353-
triggerConfig: "",
354-
offchainConfig: "",
355-
amount: newUpkeepFundAmount
356-
});
357-
uint256 upkeepId = _registerUpkeep(params);
358-
upkeepIds.push(upkeepId);
359-
tokenUpkeep[upkeepId] = _tokenUpkeep;
360-
address forwarder = IKeeperRegistryMaster(keeperRegistry).getForwarder(upkeepId);
361-
TokenUpkeep(_tokenUpkeep).setTrustedForwarder(forwarder);
362-
IUpkeepBalanceMonitor(upkeepBalanceMonitor).addToWatchList(upkeepId);
363-
emit TokenUpkeepRegistered(_tokenUpkeep, upkeepId, startIndex, endIndex);
364-
}
332+
function _registerTokenUpkeep() internal virtual;
365333

366-
function _registerUpkeep(IAutomationRegistrarV2_1.RegistrationParams memory _params) internal returns (uint256) {
367-
IERC20(linkToken).safeIncreaseAllowance(automationRegistrar, _params.amount);
368-
uint256 upkeepID = IAutomationRegistrarV2_1(automationRegistrar).registerUpkeep(_params);
369-
if (upkeepID != 0) {
370-
return upkeepID;
371-
} else {
372-
revert AutoApproveDisabled();
373-
}
374-
}
334+
function _cancelTokenUpkeep(uint256 _upkeepId) internal virtual;
375335

376-
function _cancelTokenUpkeep(uint256 _upkeepId) internal {
377-
upkeepIds.pop();
378-
delete isTokenUpkeep[tokenUpkeep[_upkeepId]];
379-
delete tokenUpkeep[_upkeepId];
380-
_cancelledUpkeepIds.add(_upkeepId);
381-
IUpkeepBalanceMonitor(upkeepBalanceMonitor).removeFromWatchList(_upkeepId);
382-
IKeeperRegistryMaster(keeperRegistry).cancelUpkeep(_upkeepId);
383-
emit TokenUpkeepCancelled(_upkeepId);
384-
}
336+
function _withdrawUpkeep(uint256 _upkeepId) internal virtual;
385337

386338
function _finishUpkeepAndCleanup(uint256 _lastRun) internal {
387339
finishedUpkeeps[_lastRun]++;
@@ -395,12 +347,6 @@ contract TokenUpkeepManager is ITokenUpkeepManager, Ownable {
395347
emit TokenListCleaned();
396348
}
397349

398-
function _withdrawUpkeep(uint256 _upkeepId) internal {
399-
_cancelledUpkeepIds.remove(_upkeepId);
400-
IKeeperRegistryMaster(keeperRegistry).withdrawFunds(_upkeepId, address(this));
401-
emit TokenUpkeepWithdrawn(_upkeepId);
402-
}
403-
404350
function _getNextUpkeepStartIndex(uint256 _upkeepCount) internal pure returns (uint256) {
405351
return _upkeepCount * TOKENS_PER_UPKEEP;
406352
}

contracts/prices/interfaces/ITokenUpkeepManager.sol renamed to contracts/prices/interfaces/common/ITokenUpkeepManager.sol

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@ interface ITokenUpkeepManager {
3636
/// @notice LINK token address
3737
function linkToken() external view returns (address);
3838

39-
/// @notice Keeper registry address
40-
function keeperRegistry() external view returns (address);
41-
4239
/// @notice Automation registrar address
4340
function automationRegistrar() external view returns (address);
4441

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.6;
3+
4+
import {ITokenUpkeepManager} from "../common/ITokenUpkeepManager.sol";
5+
6+
interface ITokenUpkeepManagerV2_1 is ITokenUpkeepManager {
7+
/// @notice Keeper registry address
8+
function keeperRegistry() external view returns (address);
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.6;
3+
4+
import {ITokenUpkeepManager} from "../common/ITokenUpkeepManager.sol";
5+
6+
interface ITokenUpkeepManagerV2_3 is ITokenUpkeepManager {
7+
/// @notice Keeper registry address
8+
function keeperRegistry() external view returns (address payable);
9+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.6;
3+
4+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
5+
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
6+
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
7+
import {IKeeperRegistryMaster} from "@chainlink/contracts/src/v0.8/automation/interfaces/v2_1/IKeeperRegistryMaster.sol";
8+
import {IAutomationRegistrarV2_1} from "../../interfaces/v2_1/IAutomationRegistrarV2_1.sol";
9+
import {ITokenUpkeepManagerV2_1} from "../interfaces/v2_1/ITokenUpkeepManagerV2_1.sol";
10+
import {IUpkeepBalanceMonitor} from "../../interfaces/IUpkeepBalanceMonitor.sol";
11+
import {TokenUpkeepManager} from "../common/TokenUpkeepManager.sol";
12+
import {TokenUpkeep} from "../TokenUpkeep.sol";
13+
14+
contract TokenUpkeepManagerV2_1 is TokenUpkeepManager, ITokenUpkeepManagerV2_1 {
15+
using SafeERC20 for IERC20;
16+
using EnumerableSet for EnumerableSet.UintSet;
17+
18+
/// @inheritdoc ITokenUpkeepManagerV2_1
19+
address public immutable override keeperRegistry;
20+
21+
constructor(
22+
address _linkToken,
23+
address _keeperRegistry,
24+
address _automationRegistrar,
25+
address _voter,
26+
address _pricesOracle,
27+
address _upkeepBalanceMonitor,
28+
uint96 _newUpkeepFundAmount,
29+
uint32 _newUpkeepGasLimit
30+
)
31+
TokenUpkeepManager(
32+
_linkToken,
33+
_automationRegistrar,
34+
_voter,
35+
_pricesOracle,
36+
_upkeepBalanceMonitor,
37+
_newUpkeepFundAmount,
38+
_newUpkeepGasLimit
39+
)
40+
{
41+
keeperRegistry = _keeperRegistry;
42+
}
43+
44+
function _registerTokenUpkeep() internal override {
45+
uint256 startIndex = _getNextUpkeepStartIndex(upkeepIds.length);
46+
uint256 endIndex = startIndex + TOKENS_PER_UPKEEP;
47+
address _tokenUpkeep = address(new TokenUpkeep(startIndex, endIndex));
48+
isTokenUpkeep[_tokenUpkeep] = true;
49+
IAutomationRegistrarV2_1.RegistrationParams memory params = IAutomationRegistrarV2_1.RegistrationParams({
50+
name: UPKEEP_NAME,
51+
encryptedEmail: "",
52+
upkeepContract: _tokenUpkeep,
53+
gasLimit: newUpkeepGasLimit,
54+
adminAddress: address(this),
55+
triggerType: CONDITIONAL_TRIGGER_TYPE,
56+
checkData: "",
57+
triggerConfig: "",
58+
offchainConfig: "",
59+
amount: newUpkeepFundAmount
60+
});
61+
uint256 upkeepId = _registerUpkeep(params);
62+
upkeepIds.push(upkeepId);
63+
tokenUpkeep[upkeepId] = _tokenUpkeep;
64+
address forwarder = IKeeperRegistryMaster(keeperRegistry).getForwarder(upkeepId);
65+
TokenUpkeep(_tokenUpkeep).setTrustedForwarder(forwarder);
66+
IUpkeepBalanceMonitor(upkeepBalanceMonitor).addToWatchList(upkeepId);
67+
emit TokenUpkeepRegistered(_tokenUpkeep, upkeepId, startIndex, endIndex);
68+
}
69+
70+
function _registerUpkeep(IAutomationRegistrarV2_1.RegistrationParams memory _params) internal returns (uint256) {
71+
IERC20(linkToken).safeIncreaseAllowance(automationRegistrar, _params.amount);
72+
uint256 upkeepID = IAutomationRegistrarV2_1(automationRegistrar).registerUpkeep(_params);
73+
if (upkeepID != 0) {
74+
return upkeepID;
75+
} else {
76+
revert AutoApproveDisabled();
77+
}
78+
}
79+
80+
function _cancelTokenUpkeep(uint256 _upkeepId) internal override {
81+
upkeepIds.pop();
82+
delete isTokenUpkeep[tokenUpkeep[_upkeepId]];
83+
delete tokenUpkeep[_upkeepId];
84+
_cancelledUpkeepIds.add(_upkeepId);
85+
IUpkeepBalanceMonitor(upkeepBalanceMonitor).removeFromWatchList(_upkeepId);
86+
IKeeperRegistryMaster(keeperRegistry).cancelUpkeep(_upkeepId);
87+
emit TokenUpkeepCancelled(_upkeepId);
88+
}
89+
90+
function _withdrawUpkeep(uint256 _upkeepId) internal override {
91+
_cancelledUpkeepIds.remove(_upkeepId);
92+
IKeeperRegistryMaster(keeperRegistry).withdrawFunds(_upkeepId, address(this));
93+
emit TokenUpkeepWithdrawn(_upkeepId);
94+
}
95+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.6;
3+
4+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
5+
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
6+
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
7+
import {IAutomationRegistryMaster2_3} from "@chainlink/contracts/src/v0.8/automation/interfaces/v2_3/IAutomationRegistryMaster2_3.sol";
8+
import {IAutomationRegistrarV2_3} from "../../interfaces/v2_3/IAutomationRegistrarV2_3.sol";
9+
import {ITokenUpkeepManagerV2_3} from "../interfaces/v2_3/ITokenUpkeepManagerV2_3.sol";
10+
import {IUpkeepBalanceMonitor} from "../../interfaces/IUpkeepBalanceMonitor.sol";
11+
import {TokenUpkeepManager} from "../common/TokenUpkeepManager.sol";
12+
import {TokenUpkeep} from "../TokenUpkeep.sol";
13+
14+
contract TokenUpkeepManagerV2_3 is TokenUpkeepManager, ITokenUpkeepManagerV2_3 {
15+
using SafeERC20 for IERC20;
16+
using EnumerableSet for EnumerableSet.UintSet;
17+
18+
/// @inheritdoc ITokenUpkeepManagerV2_3
19+
address payable public immutable override keeperRegistry;
20+
21+
constructor(
22+
address _linkToken,
23+
address payable _keeperRegistry,
24+
address _automationRegistrar,
25+
address _voter,
26+
address _pricesOracle,
27+
address _upkeepBalanceMonitor,
28+
uint96 _newUpkeepFundAmount,
29+
uint32 _newUpkeepGasLimit
30+
)
31+
TokenUpkeepManager(
32+
_linkToken,
33+
_automationRegistrar,
34+
_voter,
35+
_pricesOracle,
36+
_upkeepBalanceMonitor,
37+
_newUpkeepFundAmount,
38+
_newUpkeepGasLimit
39+
)
40+
{
41+
keeperRegistry = _keeperRegistry;
42+
}
43+
44+
function _registerTokenUpkeep() internal override {
45+
uint256 startIndex = _getNextUpkeepStartIndex(upkeepIds.length);
46+
uint256 endIndex = startIndex + TOKENS_PER_UPKEEP;
47+
address _tokenUpkeep = address(new TokenUpkeep(startIndex, endIndex));
48+
isTokenUpkeep[_tokenUpkeep] = true;
49+
IAutomationRegistrarV2_3.RegistrationParams memory params = IAutomationRegistrarV2_3.RegistrationParams({
50+
name: UPKEEP_NAME,
51+
encryptedEmail: "",
52+
upkeepContract: _tokenUpkeep,
53+
gasLimit: newUpkeepGasLimit,
54+
adminAddress: address(this),
55+
triggerType: CONDITIONAL_TRIGGER_TYPE,
56+
checkData: "",
57+
triggerConfig: "",
58+
offchainConfig: "",
59+
amount: newUpkeepFundAmount,
60+
billingToken: IERC20(linkToken)
61+
});
62+
uint256 upkeepId = _registerUpkeep(params);
63+
upkeepIds.push(upkeepId);
64+
tokenUpkeep[upkeepId] = _tokenUpkeep;
65+
address forwarder = IAutomationRegistryMaster2_3(keeperRegistry).getForwarder(upkeepId);
66+
TokenUpkeep(_tokenUpkeep).setTrustedForwarder(forwarder);
67+
IUpkeepBalanceMonitor(upkeepBalanceMonitor).addToWatchList(upkeepId);
68+
emit TokenUpkeepRegistered(_tokenUpkeep, upkeepId, startIndex, endIndex);
69+
}
70+
71+
function _registerUpkeep(IAutomationRegistrarV2_3.RegistrationParams memory _params) internal returns (uint256) {
72+
IERC20(linkToken).safeIncreaseAllowance(automationRegistrar, _params.amount);
73+
uint256 upkeepID = IAutomationRegistrarV2_3(automationRegistrar).registerUpkeep(_params);
74+
if (upkeepID != 0) {
75+
return upkeepID;
76+
} else {
77+
revert AutoApproveDisabled();
78+
}
79+
}
80+
81+
function _cancelTokenUpkeep(uint256 _upkeepId) internal override {
82+
upkeepIds.pop();
83+
delete isTokenUpkeep[tokenUpkeep[_upkeepId]];
84+
delete tokenUpkeep[_upkeepId];
85+
_cancelledUpkeepIds.add(_upkeepId);
86+
IUpkeepBalanceMonitor(upkeepBalanceMonitor).removeFromWatchList(_upkeepId);
87+
IAutomationRegistryMaster2_3(keeperRegistry).cancelUpkeep(_upkeepId);
88+
emit TokenUpkeepCancelled(_upkeepId);
89+
}
90+
91+
function _withdrawUpkeep(uint256 _upkeepId) internal override {
92+
_cancelledUpkeepIds.remove(_upkeepId);
93+
IAutomationRegistryMaster2_3(keeperRegistry).withdrawFunds(_upkeepId, address(this));
94+
emit TokenUpkeepWithdrawn(_upkeepId);
95+
}
96+
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"test:unit": "npx hardhat test test/unit/*.test.ts test/**/unit/*.test.ts test/**/unit/**/*.test.ts",
66
"test:fork": "FORK_ENABLED=true FORK_CHAIN=optimism BLOCK_NUMBER=128856225 npx hardhat test test/emissions/fork/v2_1/GaugeUpkeepManagerV2_1.test.ts",
77
"test:fork:v2_3": "FORK_ENABLED=true FORK_CHAIN=base BLOCK_NUMBER=27557816 npx hardhat test test/emissions/fork/v2_3/GaugeUpkeepManagerV2_3.test.ts",
8-
"test:fork:prices": "FORK_ENABLED=true FORK_CHAIN=optimism BLOCK_NUMBER=135890825 npx hardhat test test/prices/fork/TokenUpkeepManager.test.ts",
8+
"test:fork:prices": "FORK_ENABLED=true FORK_CHAIN=optimism BLOCK_NUMBER=135890825 npx hardhat test test/prices/fork/v2_1/TokenUpkeepManagerV2_1.test.ts",
99
"prettier:check": "prettier '**/*' --check",
1010
"prettier:write": "prettier '**/*' --write"
1111
},

scripts/prices/test/deploy_live_test.ts renamed to scripts/prices/test/v2_1/deploy_live_test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { ethers, run } from 'hardhat'
77
import * as assert from 'assert'
88
import * as dotenv from 'dotenv'
9-
import { registerLogTriggerUpkeep } from '../../utils'
9+
import { registerLogTriggerUpkeep } from '../../../utils'
1010

1111
// Load environment variables
1212
dotenv.config()

0 commit comments

Comments
 (0)