From 7159d89609d420f229100b41516ea64354a3da98 Mon Sep 17 00:00:00 2001 From: Ashitaka Date: Tue, 26 Dec 2023 14:27:53 +0100 Subject: [PATCH] feat: last comments and native token --- solidity/contracts/AutomationVault.sol | 42 +++++++++-------- solidity/contracts/AutomationVaultFactory.sol | 8 +++- solidity/interfaces/IAutomationVault.sol | 15 ++++-- .../interfaces/IAutomationVaultFactory.sol | 7 ++- solidity/script/Deploy.s.sol | 3 +- solidity/test/unit/AutomationVault.t.sol | 19 ++++---- .../test/unit/AutomationVaultFactory.t.sol | 46 +++++++++++++------ solidity/test/unit/XKeeperMetadata.t.sol | 36 +++++++++------ 8 files changed, 113 insertions(+), 63 deletions(-) diff --git a/solidity/contracts/AutomationVault.sol b/solidity/contracts/AutomationVault.sol index 1cbd525..b497f96 100644 --- a/solidity/contracts/AutomationVault.sol +++ b/solidity/contracts/AutomationVault.sol @@ -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, _ALL} from '@utils/Constants.sol'; +import {_ALL} from '@utils/Constants.sol'; /** * @title AutomationVault @@ -19,7 +19,8 @@ contract AutomationVault is IAutomationVault { address public owner; /// @inheritdoc IAutomationVault address public pendingOwner; - + /// @inheritdoc IAutomationVault + address public immutable nativeToken; /** * @notice Callers that are approved to call a relay */ @@ -43,8 +44,9 @@ contract AutomationVault is IAutomationVault { /** * @param _owner The address of the owner */ - constructor(address _owner) { + constructor(address _owner, address _nativeToken) { owner = _owner; + nativeToken = _nativeToken; } /// @inheritdoc IAutomationVault @@ -58,13 +60,13 @@ contract AutomationVault is IAutomationVault { } /// @inheritdoc IAutomationVault - function relays() external view returns (address[] memory _listRelays) { - _listRelays = _relays.values(); + function relays() external view returns (address[] memory _relayList) { + _relayList = _relays.values(); } /// @inheritdoc IAutomationVault - function jobs() external view returns (address[] memory _listJobs) { - _listJobs = _jobs.values(); + function jobs() external view returns (address[] memory _jobList) { + _jobList = _jobs.values(); } /// @inheritdoc IAutomationVault @@ -82,10 +84,10 @@ contract AutomationVault is IAutomationVault { /// @inheritdoc IAutomationVault function withdrawFunds(address _token, uint256 _amount, address _receiver) external onlyOwner { - // If the token is ETH, transfer the funds to the receiver, otherwise transfer the tokens - if (_token == _ETH) { + // If the token is the native token, transfer the funds to the receiver, otherwise transfer the tokens + if (_token == nativeToken) { (bool _success,) = _receiver.call{value: _amount}(''); - if (!_success) revert AutomationVault_ETHTransferFailed(); + if (!_success) revert AutomationVault_NativeTokenTransferFailed(); } else { IERC20(_token).safeTransfer(_receiver, _amount); } @@ -217,24 +219,24 @@ contract AutomationVault is IAutomationVault { } // Create the fee data needed variables - FeeData memory _dataToFee; + FeeData memory _feeInfo; _dataLength = _feeData.length; _i = 0; // Iterate over the fee data to issue the payments for (_i; _i < _dataLength;) { - _dataToFee = _feeData[_i]; + _feeInfo = _feeData[_i]; - // If the token is ETH, transfer the funds to the receiver, otherwise transfer the tokens - if (_dataToFee.feeToken == _ETH) { - (_success,) = _dataToFee.feeRecipient.call{value: _dataToFee.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 == nativeToken) { + (_success,) = _feeInfo.feeRecipient.call{value: _feeInfo.fee}(''); + if (!_success) revert AutomationVault_NativeTokenTransferFailed(); } else { - IERC20(_dataToFee.feeToken).safeTransfer(_dataToFee.feeRecipient, _dataToFee.fee); + IERC20(_feeInfo.feeToken).safeTransfer(_feeInfo.feeRecipient, _feeInfo.fee); } // Emit the event - emit IssuePayment(msg.sender, _relayCaller, _dataToFee.feeRecipient, _dataToFee.feeToken, _dataToFee.fee); + emit IssuePayment(msg.sender, _relayCaller, _feeInfo.feeRecipient, _feeInfo.feeToken, _feeInfo.fee); unchecked { ++_i; @@ -261,9 +263,9 @@ contract AutomationVault is IAutomationVault { } /** - * @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); } } diff --git a/solidity/contracts/AutomationVaultFactory.sol b/solidity/contracts/AutomationVaultFactory.sol index 9c5c7ce..8752a6f 100644 --- a/solidity/contracts/AutomationVaultFactory.sol +++ b/solidity/contracts/AutomationVaultFactory.sol @@ -49,9 +49,13 @@ contract AutomationVaultFactory is IAutomationVaultFactory { } /// @inheritdoc IAutomationVaultFactory - function deployAutomationVault(address _owner, uint256 _salt) external returns (IAutomationVault _automationVault) { + function deployAutomationVault( + address _owner, + address _nativeToken, + uint256 _salt + ) external returns (IAutomationVault _automationVault) { // Create the new automation vault with the owner - _automationVault = new AutomationVault{salt: keccak256(abi.encodePacked(msg.sender, _salt))}(_owner); + _automationVault = new AutomationVault{salt: keccak256(abi.encodePacked(msg.sender, _salt))}(_owner, _nativeToken); // Add the automation vault to the list of automation vaults _automationVaults.add(address(_automationVault)); diff --git a/solidity/interfaces/IAutomationVault.sol b/solidity/interfaces/IAutomationVault.sol index d0cc106..0c1d41c 100644 --- a/solidity/interfaces/IAutomationVault.sol +++ b/solidity/interfaces/IAutomationVault.sol @@ -100,11 +100,11 @@ interface IAutomationVault { ); /** - * @notice Emitted when ETH is received in the automation vault + * @notice Emitted when native token is received in the automation vault * @param _sender The sender address - * @param _amount The amount of ETH + * @param _amount The amount of native token */ - event ETHReceived(address indexed _sender, uint256 _amount); + event NativeTokenReceived(address indexed _sender, uint256 _amount); /*/////////////////////////////////////////////////////////////// ERRORS @@ -113,7 +113,7 @@ interface IAutomationVault { /** * @notice Thrown when ether transfer fails */ - error AutomationVault_ETHTransferFailed(); + error AutomationVault_NativeTokenTransferFailed(); /** * @notice Thrown when a not approved relay caller is trying to execute a job @@ -176,6 +176,13 @@ interface IAutomationVault { */ function owner() external view returns (address _owner); + /** + * @notice Returns the address of the native token + * @return _nativeToken The address of the native token + */ + + function nativeToken() external view returns (address _nativeToken); + /** * @notice Returns the pending owner address * @return _pendingOwner The address of the pending owner diff --git a/solidity/interfaces/IAutomationVaultFactory.sol b/solidity/interfaces/IAutomationVaultFactory.sol index c965d84..0d4f880 100644 --- a/solidity/interfaces/IAutomationVaultFactory.sol +++ b/solidity/interfaces/IAutomationVaultFactory.sol @@ -40,8 +40,13 @@ interface IAutomationVaultFactory { /** * @notice Deploy a new automation vault * @param _owner The address of the owner + * @param _nativeToken The address of the native token * @param _salt The salt to use for the automation vault deployment * @return _automationVault The address of the automation vault deployed */ - function deployAutomationVault(address _owner, uint256 _salt) external returns (IAutomationVault _automationVault); + function deployAutomationVault( + address _owner, + address _nativeToken, + uint256 _salt + ) external returns (IAutomationVault _automationVault); } diff --git a/solidity/script/Deploy.s.sol b/solidity/script/Deploy.s.sol index 350a9b8..7d85bd8 100644 --- a/solidity/script/Deploy.s.sol +++ b/solidity/script/Deploy.s.sol @@ -10,6 +10,7 @@ import {GelatoRelay, IGelatoRelay} from '@contracts/GelatoRelay.sol'; import {Keep3rRelay, IKeep3rRelay} from '@contracts/Keep3rRelay.sol'; import {Keep3rBondedRelay, IKeep3rBondedRelay} from '@contracts/Keep3rBondedRelay.sol'; import {XKeeperMetadata, IXKeeperMetadata} from '@contracts/XKeeperMetadata.sol'; +import {_ETH} from '@utils/Constants.sol'; abstract contract Deploy is Script { // Deployer EOA @@ -37,7 +38,7 @@ abstract contract Deploy is Script { vm.startBroadcast(deployer); automationVaultFactory = new AutomationVaultFactory(); - automationVault = automationVaultFactory.deployAutomationVault(owner, 0); + automationVault = automationVaultFactory.deployAutomationVault(owner, _ETH, 0); openRelay = new OpenRelay(); gelatoRelay = new GelatoRelay(); diff --git a/solidity/test/unit/AutomationVault.t.sol b/solidity/test/unit/AutomationVault.t.sol index 4878a01..a25b6cc 100644 --- a/solidity/test/unit/AutomationVault.t.sol +++ b/solidity/test/unit/AutomationVault.t.sol @@ -11,7 +11,7 @@ contract AutomationVaultForTest is AutomationVault { using EnumerableSet for EnumerableSet.AddressSet; using EnumerableSet for EnumerableSet.Bytes32Set; - constructor(address _owner) AutomationVault(_owner) {} + constructor(address _owner, address _nativeToken) AutomationVault(_owner, _nativeToken) {} function setPendingOwnerForTest(address _pendingOwner) public { pendingOwner = _pendingOwner; @@ -87,7 +87,7 @@ abstract contract AutomationVaultUnitTest is Test { relay = makeAddr('Relay'); relayCaller = makeAddr('RelayCaller'); - automationVault = new AutomationVaultForTest(owner); + automationVault = new AutomationVaultForTest(owner, _ETH); } function _mockTokenTransfer(address _token) internal { @@ -98,6 +98,7 @@ abstract contract AutomationVaultUnitTest is Test { contract UnitAutomationVaultConstructor is AutomationVaultUnitTest { function testParamsAreSet() public { assertEq(automationVault.owner(), owner); + assertEq(automationVault.nativeToken(), _ETH); } } @@ -200,15 +201,15 @@ contract UnitAutomationVaultWithdrawFunds is AutomationVaultUnitTest { automationVault.withdrawFunds(_ETH, _amount, owner); } - function testRevertIfETHTransferFailed(uint160 _amount) public { + function testRevertIfNativeTokenTransferFailed(uint160 _amount) public { vm.assume(_amount == type(uint160).max); - vm.expectRevert(abi.encodeWithSelector(IAutomationVault.AutomationVault_ETHTransferFailed.selector)); + vm.expectRevert(abi.encodeWithSelector(IAutomationVault.AutomationVault_NativeTokenTransferFailed.selector)); automationVault.withdrawFunds(_ETH, _amount, address(automationVault)); } - function testWithdrawETHAmountUpdateBalances(uint128 _amount) public { + function testWithdrawNativeTokenAmountUpdateBalances(uint128 _amount) public { vm.assume(_amount > 0); uint256 _balance = address(automationVault).balance; @@ -218,7 +219,7 @@ contract UnitAutomationVaultWithdrawFunds is AutomationVaultUnitTest { assertEq(address(automationVault).balance, _balance - _amount); } - function testEmitWithdrawETHAmount(uint128 _balance, uint128 _amount) public { + function testEmitWithdrawNativeTokenAmount(uint128 _balance, uint128 _amount) public { vm.assume(_balance > _amount && _amount > 0); vm.expectEmit(); @@ -527,7 +528,7 @@ contract UnitAutomationVaultExec is AutomationVaultUnitTest { automationVault.exec(relayCaller, _execData, _feeData); } - function testRevertIfETHTransferFailed( + function testRevertIfNativeTokenTransferFailed( IAutomationVault.ExecData[] memory _execData, IAutomationVault.FeeData[] memory _feeData ) public happyPath(_execData, _feeData) { @@ -535,12 +536,12 @@ contract UnitAutomationVaultExec is AutomationVaultUnitTest { _feeData[1].feeToken = _ETH; vm.etch(_feeData[1].feeRecipient, type(NoFallbackForTest).runtimeCode); - vm.expectRevert(IAutomationVault.AutomationVault_ETHTransferFailed.selector); + vm.expectRevert(IAutomationVault.AutomationVault_NativeTokenTransferFailed.selector); automationVault.exec(relayCaller, _execData, _feeData); } - function testCallETHTransfer( + function testCallNativeTokenTransfer( IAutomationVault.ExecData[] memory _execData, IAutomationVault.FeeData[] memory _feeData, uint128 _fee diff --git a/solidity/test/unit/AutomationVaultFactory.t.sol b/solidity/test/unit/AutomationVaultFactory.t.sol index 680b653..a6c52c1 100644 --- a/solidity/test/unit/AutomationVaultFactory.t.sol +++ b/solidity/test/unit/AutomationVaultFactory.t.sol @@ -15,7 +15,11 @@ contract AutomationVaultFactoryForTest is AutomationVaultFactory { } } - function preComputeAddressForTest(address _owner, uint256 _salt) public view returns (address _precomputedAddress) { + function preComputeAddressForTest( + address _owner, + address _nativeToken, + uint256 _salt + ) public view returns (address _precomputedAddress) { bytes memory _bytecode = type(AutomationVault).creationCode; bytes32 _hashed = keccak256( @@ -23,7 +27,7 @@ contract AutomationVaultFactoryForTest is AutomationVaultFactory { bytes1(0xff), address(this), keccak256(abi.encodePacked(msg.sender, _salt)), - keccak256(abi.encodePacked(_bytecode, abi.encode(_owner))) + keccak256(abi.encodePacked(_bytecode, abi.encode(_owner, _nativeToken))) ) ); _precomputedAddress = address(uint160(uint256(_hashed))); @@ -93,32 +97,48 @@ contract UnitAutomationVaultFactoryGetAutomationVaults is AutomationVaultFactory contract UnitAutomationVaultFactoryDeployAutomationVault is AutomationVaultFactoryUnitTest { address internal _precomputedAddress; - modifier happyPath(address _owner, uint256 _salt) { - _precomputedAddress = automationVaultFactory.preComputeAddressForTest(_owner, _salt); + modifier happyPath(address _owner, address _nativeToken, uint256 _salt) { + _precomputedAddress = automationVaultFactory.preComputeAddressForTest(_owner, _nativeToken, _salt); _; } - function testDeployAutomationVault(address _owner, uint256 _salt) public happyPath(_owner, _salt) { - IAutomationVault _automaitonVault = automationVaultFactory.deployAutomationVault(_owner, _salt); + function testDeployAutomationVault( + address _owner, + address _nativeToken, + uint256 _salt + ) public happyPath(_owner, _nativeToken, _salt) { + IAutomationVault _automationVault = automationVaultFactory.deployAutomationVault(_owner, _nativeToken, _salt); // params - assertEq(_automaitonVault.owner(), _owner); + assertEq(_automationVault.owner(), _owner); } - function testSetAutomationVaults(address _owner, uint256 _salt) public happyPath(_owner, _salt) { - automationVaultFactory.deployAutomationVault(_owner, _salt); + function testSetAutomationVaults( + address _owner, + address _nativeToken, + uint256 _salt + ) public happyPath(_owner, _nativeToken, _salt) { + automationVaultFactory.deployAutomationVault(_owner, _nativeToken, _salt); assertEq(automationVaultFactory.automationVaults(0, 1)[0], _precomputedAddress); } - function testEmitDeployAutomationVault(address _owner, uint256 _salt) public happyPath(_owner, _salt) { + function testEmitDeployAutomationVault( + address _owner, + address _nativeToken, + uint256 _salt + ) public happyPath(_owner, _nativeToken, _salt) { vm.expectEmit(); emit DeployAutomationVault(_owner, _precomputedAddress); - automationVaultFactory.deployAutomationVault(_owner, _salt); + automationVaultFactory.deployAutomationVault(_owner, _nativeToken, _salt); } - function testReturnAutomationVault(address _owner, uint256 _salt) public happyPath(_owner, _salt) { - assertEq(address(automationVaultFactory.deployAutomationVault(_owner, _salt)), _precomputedAddress); + function testReturnAutomationVault( + address _owner, + address _nativeToken, + uint256 _salt + ) public happyPath(_owner, _nativeToken, _salt) { + assertEq(address(automationVaultFactory.deployAutomationVault(_owner, _nativeToken, _salt)), _precomputedAddress); } } diff --git a/solidity/test/unit/XKeeperMetadata.t.sol b/solidity/test/unit/XKeeperMetadata.t.sol index 98f0f4c..f602c1a 100644 --- a/solidity/test/unit/XKeeperMetadata.t.sol +++ b/solidity/test/unit/XKeeperMetadata.t.sol @@ -29,8 +29,12 @@ contract XKeeperMetadataUnitTest is Test { // EOAs address public owner; + // AutomationVault contract + IAutomationVault public automationVault; + function setUp() public virtual { xKeeperMetadata = new XKeeperMetadataForTest(); + automationVault = IAutomationVault(makeAddr('AutomationVault')); owner = makeAddr('Owner'); } } @@ -63,39 +67,45 @@ contract UnitXKeeperMetadataGetMetadata is XKeeperMetadataUnitTest { contract UnitXKeeperMetadataSetAutomationVaultMetadata is XKeeperMetadataUnitTest { IXKeeperMetadata.AutomationVaultMetadata internal _automationVaultMetadata; - modifier happyPath(IAutomationVault _automationVault) { - vm.mockCall(address(_automationVault), abi.encodeWithSelector(IAutomationVault.owner.selector), abi.encode(owner)); - _automationVaultMetadata = IXKeeperMetadata.AutomationVaultMetadata('name', 'description'); + modifier happyPath(string memory _name, string memory _description) { + vm.mockCall(address(automationVault), abi.encodeWithSelector(IAutomationVault.owner.selector), abi.encode(owner)); + _automationVaultMetadata = IXKeeperMetadata.AutomationVaultMetadata(_name, _description); vm.startPrank(owner); _; } function testRevertOnlyAutomationVaultOwner( - IAutomationVault _automationVault, - address _newOwner - ) public happyPath(_automationVault) { + address _newOwner, + string memory _name, + string memory _description + ) public happyPath(_name, _description) { vm.assume(_newOwner != owner); vm.expectRevert(IXKeeperMetadata.XKeeperMetadata_OnlyAutomationVaultOwner.selector); changePrank(_newOwner); - xKeeperMetadata.setAutomationVaultMetadata(_automationVault, _automationVaultMetadata); + xKeeperMetadata.setAutomationVaultMetadata(automationVault, _automationVaultMetadata); } - function testSetAutomationVaultMetadata(IAutomationVault _automationVault) public happyPath(_automationVault) { - xKeeperMetadata.setAutomationVaultMetadata(_automationVault, _automationVaultMetadata); - (string memory _name, string memory _description) = xKeeperMetadata.automationVaultMetadata(_automationVault); + function testSetAutomationVaultMetadata( + string memory _name, + string memory _description + ) public happyPath(_name, _description) { + xKeeperMetadata.setAutomationVaultMetadata(automationVault, _automationVaultMetadata); assertEq(_name, _automationVaultMetadata.name); assertEq(_description, _automationVaultMetadata.description); } - function testEmitAutomationVaultMetadataSetted(IAutomationVault _automationVault) public happyPath(_automationVault) { + function testEmitAutomationVaultMetadataSetted( + string memory _name, + string memory _description + ) public happyPath(_name, _description) { vm.expectEmit(); emit AutomationVaultMetadataSetted( - _automationVault, _automationVaultMetadata.name, _automationVaultMetadata.description + automationVault, _automationVaultMetadata.name, _automationVaultMetadata.description ); - xKeeperMetadata.setAutomationVaultMetadata(_automationVault, _automationVaultMetadata); + xKeeperMetadata.setAutomationVaultMetadata(automationVault, _automationVaultMetadata); } }