-
Notifications
You must be signed in to change notification settings - Fork 5
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
refactor: approved relays, jobs and selectors #7
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
6d41df9
fix: audit comments
ashitakah cd3ffa7
feat: draft refactor
ashitakah 6d70542
feat: create2
ashitakah 51e1475
feat: gas saving
ashitakah f165b15
Merge branch 'feat/audit' of github.com:defi-wonderland/keep3r-framew…
ashitakah 8315298
feat: mappings
ashitakah bcdeafe
feat: mappings
ashitakah 7159d89
feat: last comments and native token
ashitakah 04a5fe1
fix: naming
ashitakah db71f45
fix: tests native token
ashitakah 510d7a7
fix: tests native token
ashitakah 7e54023
feat: merge
ashitakah 8f4ad75
feat: integration tests refactor
ashitakah a0e1a64
fix: linter
ashitakah e1288bf
feat: comments
ashitakah File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
solidity/contracts/utils/AutomateReady.sol | ||
solidity/contracts/utils/Types.sol | ||
solidity/interfaces/external/** | ||
*.ignore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ pragma solidity 0.8.19; | |
import {IAutomationVault} from '@interfaces/IAutomationVault.sol'; | ||
import {IERC20, SafeERC20} from '@openzeppelin/token/ERC20/utils/SafeERC20.sol'; | ||
import {EnumerableSet} from '@openzeppelin/utils/structs/EnumerableSet.sol'; | ||
import {_ETH, _NULL} from '@utils/Constants.sol'; | ||
import {_ALL} from '@utils/Constants.sol'; | ||
|
||
/** | ||
* @title AutomationVault | ||
|
@@ -15,20 +15,22 @@ contract AutomationVault is IAutomationVault { | |
using EnumerableSet for EnumerableSet.AddressSet; | ||
using EnumerableSet for EnumerableSet.Bytes32Set; | ||
|
||
/// @inheritdoc IAutomationVault | ||
address public immutable NATIVE_TOKEN; | ||
/// @inheritdoc IAutomationVault | ||
address public owner; | ||
/// @inheritdoc IAutomationVault | ||
address public pendingOwner; | ||
|
||
/** | ||
* @notice Callers that are approved to call a relay | ||
*/ | ||
mapping(address _relay => EnumerableSet.AddressSet _enabledCallers) internal _relayEnabledCallers; | ||
mapping(address _relay => EnumerableSet.AddressSet _enabledCallers) internal _relayCallers; | ||
|
||
/** | ||
* @notice Selectors that are approved to be called | ||
* @notice Relays that are approved to execute jobs with a specific selector | ||
*/ | ||
mapping(address _job => EnumerableSet.Bytes32Set _enabledSelectors) internal _jobEnabledSelectors; | ||
mapping(address _relay => mapping(address _job => EnumerableSet.Bytes32Set _enabledSelectors)) internal | ||
_relayJobSelectors; | ||
|
||
/** | ||
* @notice List of approved relays | ||
|
@@ -43,28 +45,31 @@ contract AutomationVault is IAutomationVault { | |
/** | ||
* @param _owner The address of the owner | ||
*/ | ||
constructor(address _owner) payable { | ||
constructor(address _owner, address _nativeToken) { | ||
owner = _owner; | ||
NATIVE_TOKEN = _nativeToken; | ||
} | ||
|
||
/// @inheritdoc IAutomationVault | ||
function relayEnabledCallers(address _relay) external view returns (address[] memory _enabledCallers) { | ||
_enabledCallers = _relayEnabledCallers[_relay].values(); | ||
function getRelayAndJobData( | ||
address _relay, | ||
address _job | ||
) public view returns (address[] memory _callers, bytes32[] memory _selectors) { | ||
// Get the list of callers | ||
_callers = _relayCallers[_relay].values(); | ||
|
||
// Get the list of selectors | ||
_selectors = _relayJobSelectors[_relay][_job].values(); | ||
} | ||
|
||
/// @inheritdoc IAutomationVault | ||
function jobEnabledSelectors(address _job) external view returns (bytes32[] memory _enabledSelectors) { | ||
_enabledSelectors = _jobEnabledSelectors[_job].values(); | ||
function relays() external view returns (address[] memory _relayList) { | ||
_relayList = _relays.values(); | ||
} | ||
|
||
/// @inheritdoc IAutomationVault | ||
function relays() external view returns (address[] memory __relays) { | ||
__relays = _relays.values(); | ||
} | ||
|
||
/// @inheritdoc IAutomationVault | ||
function jobs() external view returns (address[] memory __jobs) { | ||
__jobs = _jobs.values(); | ||
function jobs() external view returns (address[] memory _jobList) { | ||
_jobList = _jobs.values(); | ||
} | ||
|
||
/// @inheritdoc IAutomationVault | ||
|
@@ -81,11 +86,11 @@ contract AutomationVault is IAutomationVault { | |
} | ||
|
||
/// @inheritdoc IAutomationVault | ||
function withdrawFunds(address _token, uint256 _amount, address _receiver) external payable onlyOwner { | ||
// If the token is ETH, transfer the funds to the receiver, otherwise transfer the tokens | ||
if (_token == _ETH) { | ||
function withdrawFunds(address _token, uint256 _amount, address _receiver) external onlyOwner { | ||
// If the token is the native token, transfer the funds to the receiver, otherwise transfer the tokens | ||
if (_token == NATIVE_TOKEN) { | ||
(bool _success,) = _receiver.call{value: _amount}(''); | ||
if (!_success) revert AutomationVault_ETHTransferFailed(); | ||
if (!_success) revert AutomationVault_NativeTokenTransferFailed(); | ||
} else { | ||
IERC20(_token).safeTransfer(_receiver, _amount); | ||
} | ||
|
@@ -95,9 +100,12 @@ contract AutomationVault is IAutomationVault { | |
} | ||
|
||
/// @inheritdoc IAutomationVault | ||
function approveRelayCallers(address _relay, address[] calldata _callers) external onlyOwner { | ||
// Get the list of enabled callers for the relay | ||
EnumerableSet.AddressSet storage _enabledCallers = _relayEnabledCallers[_relay]; | ||
function approveRelayData( | ||
address _relay, | ||
address[] calldata _callers, | ||
IAutomationVault.JobData[] calldata _jobsData | ||
) external onlyOwner { | ||
if (_relay == address(0)) revert AutomationVault_RelayZero(); | ||
|
||
// If the relay is not approved, add it to the list of relays | ||
if (_relays.add(_relay)) { | ||
|
@@ -106,24 +114,52 @@ contract AutomationVault is IAutomationVault { | |
|
||
// Iterate over the callers to approve them | ||
for (uint256 _i; _i < _callers.length;) { | ||
if (_enabledCallers.add(_callers[_i])) { | ||
if (_relayCallers[_relay].add(_callers[_i])) { | ||
emit ApproveRelayCaller(_relay, _callers[_i]); | ||
} | ||
|
||
unchecked { | ||
++_i; | ||
} | ||
} | ||
|
||
// Iterate over the jobs to approve them and their selectors | ||
for (uint256 _i; _i < _jobsData.length;) { | ||
IAutomationVault.JobData memory _jobData = _jobsData[_i]; | ||
|
||
// If the job is not approved, add it to the list of jobs | ||
if (_jobs.add(_jobData.job)) { | ||
emit ApproveJob(_jobData.job); | ||
} | ||
|
||
// Iterate over the selectors to approve them | ||
for (uint256 _j; _j < _jobData.functionSelectors.length;) { | ||
if (_relayJobSelectors[_relay][_jobData.job].add(_jobData.functionSelectors[_j])) { | ||
emit ApproveJobSelector(_jobData.job, _jobData.functionSelectors[_j]); | ||
} | ||
|
||
unchecked { | ||
++_j; | ||
} | ||
} | ||
|
||
unchecked { | ||
++_i; | ||
} | ||
} | ||
} | ||
|
||
/// @inheritdoc IAutomationVault | ||
function revokeRelayCallers(address _relay, address[] calldata _callers) external onlyOwner { | ||
// Get the list of enabled callers for the relay | ||
EnumerableSet.AddressSet storage _enabledCallers = _relayEnabledCallers[_relay]; | ||
function revokeRelayData( | ||
address _relay, | ||
address[] calldata _callers, | ||
IAutomationVault.JobData[] calldata _jobsData | ||
) external onlyOwner { | ||
if (_relay == address(0)) revert AutomationVault_RelayZero(); | ||
|
||
// Iterate over the callers to revoke them | ||
for (uint256 _i; _i < _callers.length;) { | ||
if (_enabledCallers.remove(_callers[_i])) { | ||
if (_relayCallers[_relay].remove(_callers[_i])) { | ||
emit RevokeRelayCaller(_relay, _callers[_i]); | ||
} | ||
|
||
|
@@ -132,109 +168,89 @@ contract AutomationVault is IAutomationVault { | |
} | ||
} | ||
|
||
// If the relay has no more callers, remove it from the list of relays | ||
if (_enabledCallers.length() == 0) { | ||
// If the relay has no enabled callers, remove it from the list of relays | ||
if (_relayCallers[_relay].length() == 0) { | ||
_relays.remove(_relay); | ||
emit RevokeRelay(_relay); | ||
} | ||
} | ||
|
||
/// @inheritdoc IAutomationVault | ||
function approveJobSelectors(address _job, bytes4[] calldata _functionSelectors) external onlyOwner { | ||
// Get the list of enabled selectors for the job | ||
EnumerableSet.Bytes32Set storage _enabledSelectors = _jobEnabledSelectors[_job]; | ||
// Iterate over the jobs to revoke them and their selectors | ||
for (uint256 _i; _i < _jobsData.length;) { | ||
IAutomationVault.JobData memory _jobData = _jobsData[_i]; | ||
|
||
// If the job is not approved, add it to the list of jobs | ||
if (_jobs.add(_job)) { | ||
emit ApproveJob(_job); | ||
} | ||
|
||
// Iterate over the selectors to approve them | ||
for (uint256 _i; _i < _functionSelectors.length;) { | ||
if (_enabledSelectors.add(_functionSelectors[_i])) { | ||
emit ApproveJobSelector(_job, _functionSelectors[_i]); | ||
} | ||
// Iterate over the selectors to revoke them | ||
for (uint256 _j; _j < _jobData.functionSelectors.length;) { | ||
if (_relayJobSelectors[_relay][_jobData.job].remove(_jobData.functionSelectors[_j])) { | ||
emit RevokeJobSelector(_jobData.job, _jobData.functionSelectors[_j]); | ||
} | ||
|
||
unchecked { | ||
++_i; | ||
unchecked { | ||
++_j; | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// @inheritdoc IAutomationVault | ||
function revokeJobSelectors(address _job, bytes4[] calldata _functionSelectors) external onlyOwner { | ||
// Get the list of enabled selectors for the job | ||
EnumerableSet.Bytes32Set storage _enabledSelectors = _jobEnabledSelectors[_job]; | ||
|
||
// Iterate over the selectors to revoke them | ||
for (uint256 _i; _i < _functionSelectors.length;) { | ||
if (_enabledSelectors.remove(_functionSelectors[_i])) { | ||
emit RevokeJobSelector(_job, _functionSelectors[_i]); | ||
if (_relayJobSelectors[_relay][_jobData.job].length() == 0) { | ||
_jobs.remove(_jobData.job); | ||
emit RevokeJob(_jobData.job); | ||
} | ||
|
||
unchecked { | ||
++_i; | ||
} | ||
} | ||
|
||
// If the job has no more selectors, remove it from the list of jobs | ||
if (_enabledSelectors.length() == 0) { | ||
_jobs.remove(_job); | ||
emit RevokeJob(_job); | ||
} | ||
} | ||
|
||
/// @inheritdoc IAutomationVault | ||
function exec(address _relayCaller, ExecData[] calldata _execData, FeeData[] calldata _feeData) external payable { | ||
function exec(address _relayCaller, ExecData[] calldata _execData, FeeData[] calldata _feeData) external { | ||
// Check that the specific caller is approved to call the relay | ||
if (!_relayEnabledCallers[msg.sender].contains(_relayCaller) && !_relayEnabledCallers[msg.sender].contains(_NULL)) { | ||
if (!_relayCallers[msg.sender].contains(_relayCaller) && !_relayCallers[msg.sender].contains(_ALL)) { | ||
revert AutomationVault_NotApprovedRelayCaller(); | ||
} | ||
|
||
// Create the exec data needed variables | ||
ExecData memory _execDatum; | ||
ExecData memory _dataToExecute; | ||
Comment on lines
210
to
+211
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In views of normalization, I suggest naming this variable There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, the naming was review'd |
||
uint256 _dataLength = _execData.length; | ||
uint256 _i; | ||
bool _success; | ||
|
||
// Iterate over the exec data to execute the jobs | ||
for (_i; _i < _dataLength;) { | ||
_execDatum = _execData[_i]; | ||
_dataToExecute = _execData[_i]; | ||
|
||
// Check that the selector is approved to be called | ||
if (!_jobEnabledSelectors[_execDatum.job].contains(bytes4(_execDatum.jobData))) { | ||
if (!_relayJobSelectors[msg.sender][_dataToExecute.job].contains(bytes4(_dataToExecute.jobData))) { | ||
revert AutomationVault_NotApprovedJobSelector(); | ||
} | ||
(_success,) = _execDatum.job.call(_execDatum.jobData); | ||
(_success,) = _dataToExecute.job.call(_dataToExecute.jobData); | ||
if (!_success) revert AutomationVault_ExecFailed(); | ||
|
||
// Emit the event | ||
emit JobExecuted(msg.sender, _relayCaller, _execDatum.job, _execDatum.jobData); | ||
emit JobExecuted(msg.sender, _relayCaller, _dataToExecute.job, _dataToExecute.jobData); | ||
|
||
unchecked { | ||
++_i; | ||
} | ||
} | ||
|
||
// Create the fee data needed variables | ||
FeeData memory _feeDatum; | ||
FeeData memory _feeInfo; | ||
_dataLength = _feeData.length; | ||
_i = 0; | ||
|
||
// Iterate over the fee data to issue the payments | ||
for (_i; _i < _dataLength;) { | ||
_feeDatum = _feeData[_i]; | ||
_feeInfo = _feeData[_i]; | ||
|
||
// If the token is ETH, transfer the funds to the receiver, otherwise transfer the tokens | ||
if (_feeDatum.feeToken == _ETH) { | ||
(_success,) = _feeDatum.feeRecipient.call{value: _feeDatum.fee}(''); | ||
if (!_success) revert AutomationVault_ETHTransferFailed(); | ||
// If the token is the native token, transfer the funds to the receiver, otherwise transfer the tokens | ||
if (_feeInfo.feeToken == NATIVE_TOKEN) { | ||
(_success,) = _feeInfo.feeRecipient.call{value: _feeInfo.fee}(''); | ||
if (!_success) revert AutomationVault_NativeTokenTransferFailed(); | ||
} else { | ||
IERC20(_feeDatum.feeToken).safeTransfer(_feeDatum.feeRecipient, _feeDatum.fee); | ||
IERC20(_feeInfo.feeToken).safeTransfer(_feeInfo.feeRecipient, _feeInfo.fee); | ||
} | ||
|
||
// Emit the event | ||
emit IssuePayment(msg.sender, _relayCaller, _feeDatum.feeRecipient, _feeDatum.feeToken, _feeDatum.fee); | ||
emit IssuePayment(msg.sender, _relayCaller, _feeInfo.feeRecipient, _feeInfo.feeToken, _feeInfo.fee); | ||
|
||
unchecked { | ||
++_i; | ||
|
@@ -247,7 +263,7 @@ contract AutomationVault is IAutomationVault { | |
*/ | ||
modifier onlyOwner() { | ||
address _owner = owner; | ||
if (msg.sender != _owner) revert AutomationVault_OnlyOwner(_owner); | ||
if (msg.sender != _owner) revert AutomationVault_OnlyOwner(); | ||
_; | ||
} | ||
|
||
|
@@ -256,14 +272,14 @@ contract AutomationVault is IAutomationVault { | |
*/ | ||
modifier onlyPendingOwner() { | ||
address _pendingOwner = pendingOwner; | ||
if (msg.sender != _pendingOwner) revert AutomationVault_OnlyPendingOwner(_pendingOwner); | ||
if (msg.sender != _pendingOwner) revert AutomationVault_OnlyPendingOwner(); | ||
_; | ||
} | ||
|
||
/** | ||
* @notice Fallback function to receive ETH | ||
* @notice Fallback function to receive native tokens | ||
*/ | ||
receive() external payable { | ||
emit ETHReceived(msg.sender, msg.value); | ||
emit NativeTokenReceived(msg.sender, msg.value); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should there be a method to get a relay's approved jobs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be in the front end part. Ardy can collect all jobs and check if the job is for that relay