diff --git a/contracts/AllowedRecipientsBuilder.sol b/contracts/AllowedRecipientsBuilder.sol index d525dc80..06e2b634 100644 --- a/contracts/AllowedRecipientsBuilder.sol +++ b/contracts/AllowedRecipientsBuilder.sol @@ -3,43 +3,9 @@ pragma solidity ^0.8.4; -interface IEasyTrack { - function evmScriptExecutor() external view returns (address); -} - -interface IAllowedRecipientsRegistry { - function addRecipient(address _recipient, string memory _title) external; - - function renounceRole(bytes32 role, address account) external; - - function isRecipientAllowed(address _recipient) external view returns (bool); - - function setLimitParameters(uint256 _limit, uint256 _periodDurationMonths) external; - - function getLimitParameters() external view returns (uint256, uint256); - - function updateSpentAmount(uint256 _payoutAmount) external; - - function spendableBalance() external view returns (uint256); - - function hasRole(bytes32 role, address account) external view returns (bool); - - function getAllowedRecipients() external view returns (address[] memory); - - function bokkyPooBahsDateTimeContract() external view returns (address); -} - -interface IAllowedTokensRegistry { - function addToken(address _token) external; - - function renounceRole(bytes32 role, address account) external; - - function isTokenAllowed(address _token) external view returns (bool); - - function hasRole(bytes32 role, address account) external view returns (bool); - - function getAllowedTokens() external view returns (address[] memory); -} +import "./interfaces/IAllowedRecipientsRegistry.sol"; +import "./interfaces/IAllowedTokensRegistry.sol"; +import "./interfaces/IEasyTrack.sol"; interface ITopUpAllowedRecipients { function token() external view returns (address); @@ -51,6 +17,8 @@ interface ITopUpAllowedRecipients { function trustedCaller() external view returns (address); function allowedRecipientsRegistry() external view returns (address); + + function allowedTokensRegistry() external view returns (address); } interface IAddAllowedRecipient { @@ -85,7 +53,6 @@ interface IAllowedRecipientsFactory { address _trustedCaller, address _allowedRecipientsRegistry, address _allowedTokensRegistry, - address _token, address _finance, address _easyTrack ) external returns (ITopUpAllowedRecipients topUpAllowedRecipients); @@ -131,15 +98,14 @@ contract AllowedRecipientsBuilder { bokkyPooBahsDateTimeContract = _bokkyPooBahsDateTimeContract; } - function deployRegistries( + function deployAllowedRecipientsRegistry( uint256 _limit, uint256 _periodDurationMonths, - address[] memory _tokens, address[] memory _recipients, string[] memory _titles, uint256 _spentAmount, bool _grantRightsToEVMScriptExecutor - ) public returns (IAllowedRecipientsRegistry recipientRegistry, IAllowedTokensRegistry tokenRegistry) { + ) public returns (IAllowedRecipientsRegistry registry) { require(_recipients.length == _titles.length, "Recipients data length mismatch"); require(_spentAmount <= _limit, "_spentAmount must be lower or equal to limit"); @@ -166,7 +132,7 @@ contract AllowedRecipientsBuilder { updateSpentAmountRoleHolders[1] = evmScriptExecutor; updateSpentAmountRoleHolders[2] = address(this); - recipientRegistry = factory.deployAllowedRecipientsRegistry( + registry = factory.deployAllowedRecipientsRegistry( admin, addRecipientToAllowedListRoleHolders, removeRecipientFromAllowedListRoleHolders, @@ -175,93 +141,99 @@ contract AllowedRecipientsBuilder { bokkyPooBahsDateTimeContract ); - assert(recipientRegistry.bokkyPooBahsDateTimeContract() == bokkyPooBahsDateTimeContract); + assert(registry.bokkyPooBahsDateTimeContract() == bokkyPooBahsDateTimeContract); for (uint256 i = 0; i < _recipients.length; i++) { - recipientRegistry.addRecipient(_recipients[i], _titles[i]); + registry.addRecipient(_recipients[i], _titles[i]); } - recipientRegistry.renounceRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, address(this)); + registry.renounceRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, address(this)); - assert(recipientRegistry.getAllowedRecipients().length == _recipients.length); + assert(registry.getAllowedRecipients().length == _recipients.length); for (uint256 i = 0; i < _recipients.length; i++) { - assert(recipientRegistry.isRecipientAllowed(_recipients[i])); + assert(registry.isRecipientAllowed(_recipients[i])); } - tokenRegistry = factory.deployAllowedTokensRegistry( - admin, addRecipientToAllowedListRoleHolders, removeRecipientFromAllowedListRoleHolders - ); + registry.setLimitParameters(_limit, _periodDurationMonths); + registry.renounceRole(SET_PARAMETERS_ROLE, address(this)); - for (uint256 i = 0; i < _tokens.length; i++) { - tokenRegistry.addToken(_tokens[i]); - } - tokenRegistry.renounceRole(ADD_TOKEN_TO_ALLOWED_LIST_ROLE, address(this)); + (uint256 registryLimit, uint256 registryPeriodDuration) = registry.getLimitParameters(); + assert(registryLimit == _limit); + assert(registryPeriodDuration == _periodDurationMonths); - assert(tokenRegistry.getAllowedTokens().length == _tokens.length); + registry.updateSpentAmount(_spentAmount); + registry.renounceRole(UPDATE_SPENT_AMOUNT_ROLE, address(this)); - for (uint256 i = 0; i < _tokens.length; i++) { - assert(tokenRegistry.isTokenAllowed(_tokens[i])); + assert(registry.spendableBalance() == _limit - _spentAmount); + + assert(registry.hasRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, admin)); + assert(registry.hasRole(REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE, admin)); + assert(registry.hasRole(SET_PARAMETERS_ROLE, admin)); + assert(registry.hasRole(UPDATE_SPENT_AMOUNT_ROLE, admin)); + assert(registry.hasRole(DEFAULT_ADMIN_ROLE, admin)); + + if (_grantRightsToEVMScriptExecutor) { + assert(registry.hasRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, evmScriptExecutor)); + assert(registry.hasRole(REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE, evmScriptExecutor)); + } else { + assert(!registry.hasRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, evmScriptExecutor)); + assert(!registry.hasRole(REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE, evmScriptExecutor)); } + assert(registry.hasRole(UPDATE_SPENT_AMOUNT_ROLE, evmScriptExecutor)); + assert(!registry.hasRole(SET_PARAMETERS_ROLE, evmScriptExecutor)); + assert(!registry.hasRole(DEFAULT_ADMIN_ROLE, evmScriptExecutor)); + + assert(!registry.hasRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, address(this))); + assert(!registry.hasRole(REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE, address(this))); + assert(!registry.hasRole(SET_PARAMETERS_ROLE, address(this))); + assert(!registry.hasRole(UPDATE_SPENT_AMOUNT_ROLE, address(this))); + assert(!registry.hasRole(DEFAULT_ADMIN_ROLE, address(this))); + } - recipientRegistry.setLimitParameters(_limit, _periodDurationMonths); - recipientRegistry.renounceRole(SET_PARAMETERS_ROLE, address(this)); + function deployAllowedTokensRegistry(address[] memory _tokens) public returns (IAllowedTokensRegistry registry) { + address[] memory addTokenRoleHolders = new address[](2); + address[] memory removeTokenRoleHolders = new address[](1); - (uint256 registryLimit, uint256 registryPeriodDuration) = recipientRegistry.getLimitParameters(); - assert(registryLimit == _limit); - assert(registryPeriodDuration == _periodDurationMonths); + addTokenRoleHolders[0] = admin; + addTokenRoleHolders[1] = address(this); - recipientRegistry.updateSpentAmount(_spentAmount); - recipientRegistry.renounceRole(UPDATE_SPENT_AMOUNT_ROLE, address(this)); + removeTokenRoleHolders[0] = admin; - assert(recipientRegistry.spendableBalance() == _limit - _spentAmount); + registry = factory.deployAllowedTokensRegistry(admin, addTokenRoleHolders, removeTokenRoleHolders); - assert(recipientRegistry.hasRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, admin)); - assert(recipientRegistry.hasRole(REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE, admin)); - assert(recipientRegistry.hasRole(SET_PARAMETERS_ROLE, admin)); - assert(recipientRegistry.hasRole(UPDATE_SPENT_AMOUNT_ROLE, admin)); - assert(recipientRegistry.hasRole(DEFAULT_ADMIN_ROLE, admin)); - assert(tokenRegistry.hasRole(ADD_TOKEN_TO_ALLOWED_LIST_ROLE, admin)); - assert(tokenRegistry.hasRole(REMOVE_TOKEN_FROM_ALLOWED_LIST_ROLE, admin)); + for (uint256 i = 0; i < _tokens.length; i++) { + registry.addToken(_tokens[i]); + } - if (_grantRightsToEVMScriptExecutor) { - assert(recipientRegistry.hasRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, evmScriptExecutor)); - assert(recipientRegistry.hasRole(REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE, evmScriptExecutor)); - assert(tokenRegistry.hasRole(ADD_TOKEN_TO_ALLOWED_LIST_ROLE, evmScriptExecutor)); - assert(tokenRegistry.hasRole(REMOVE_TOKEN_FROM_ALLOWED_LIST_ROLE, evmScriptExecutor)); - } else { - assert(!recipientRegistry.hasRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, evmScriptExecutor)); - assert(!recipientRegistry.hasRole(REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE, evmScriptExecutor)); - assert(!tokenRegistry.hasRole(ADD_TOKEN_TO_ALLOWED_LIST_ROLE, evmScriptExecutor)); - assert(!tokenRegistry.hasRole(REMOVE_TOKEN_FROM_ALLOWED_LIST_ROLE, evmScriptExecutor)); + registry.renounceRole(ADD_TOKEN_TO_ALLOWED_LIST_ROLE, address(this)); + + for (uint256 i = 0; i < _tokens.length; i++) { + assert(registry.isTokenAllowed(_tokens[i])); } - assert(recipientRegistry.hasRole(UPDATE_SPENT_AMOUNT_ROLE, evmScriptExecutor)); - assert(!recipientRegistry.hasRole(SET_PARAMETERS_ROLE, evmScriptExecutor)); - assert(!recipientRegistry.hasRole(DEFAULT_ADMIN_ROLE, evmScriptExecutor)); - - assert(!recipientRegistry.hasRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, address(this))); - assert(!recipientRegistry.hasRole(REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE, address(this))); - assert(!recipientRegistry.hasRole(SET_PARAMETERS_ROLE, address(this))); - assert(!recipientRegistry.hasRole(UPDATE_SPENT_AMOUNT_ROLE, address(this))); - assert(!recipientRegistry.hasRole(DEFAULT_ADMIN_ROLE, address(this))); - assert(!tokenRegistry.hasRole(ADD_TOKEN_TO_ALLOWED_LIST_ROLE, address(this))); - assert(!tokenRegistry.hasRole(REMOVE_TOKEN_FROM_ALLOWED_LIST_ROLE, address(this))); + + assert(registry.hasRole(ADD_TOKEN_TO_ALLOWED_LIST_ROLE, admin)); + assert(registry.hasRole(REMOVE_TOKEN_FROM_ALLOWED_LIST_ROLE, admin)); + assert(registry.hasRole(DEFAULT_ADMIN_ROLE, admin)); + + assert(!registry.hasRole(ADD_TOKEN_TO_ALLOWED_LIST_ROLE, address(this))); + assert(!registry.hasRole(REMOVE_TOKEN_FROM_ALLOWED_LIST_ROLE, address(this))); + assert(!registry.hasRole(DEFAULT_ADMIN_ROLE, address(this))); } function deployTopUpAllowedRecipients( address _trustedCaller, address _allowedRecipientsRegistry, - address _allowedTokensRegistry, - address _token + address _allowedTokensRegistry ) public returns (ITopUpAllowedRecipients topUpAllowedRecipients) { topUpAllowedRecipients = factory.deployTopUpAllowedRecipients( - _trustedCaller, _allowedRecipientsRegistry, _allowedTokensRegistry, _token, finance, address(easyTrack) + _trustedCaller, _allowedRecipientsRegistry, _allowedTokensRegistry, finance, address(easyTrack) ); - assert(topUpAllowedRecipients.token() == _token); assert(topUpAllowedRecipients.finance() == finance); assert(topUpAllowedRecipients.easyTrack() == easyTrack); assert(topUpAllowedRecipients.trustedCaller() == _trustedCaller); assert(address(topUpAllowedRecipients.allowedRecipientsRegistry()) == _allowedRecipientsRegistry); + assert(address(topUpAllowedRecipients.allowedTokensRegistry()) == _allowedTokensRegistry); } function deployAddAllowedRecipient(address _trustedCaller, address _allowedRecipientsRegistry) @@ -293,14 +265,11 @@ contract AllowedRecipientsBuilder { string[] memory _titles, uint256 _spentAmount ) public { - (IAllowedRecipientsRegistry allowedRecipientsRegistry, IAllowedTokensRegistry allowedTokensRegistry) = - deployRegistries(_limit, _periodDurationMonths, _tokens, _recipients, _titles, _spentAmount, true); + IAllowedRecipientsRegistry allowedRecipientsRegistry = + deployAllowedRecipientsRegistry(_limit, _periodDurationMonths, _recipients, _titles, _spentAmount, true); + IAllowedTokensRegistry allowedTokensRegistry = deployAllowedTokensRegistry(_tokens); - for (uint256 i = 0; i < _tokens.length; i++) { - deployTopUpAllowedRecipients( - _trustedCaller, address(allowedRecipientsRegistry), address(allowedTokensRegistry), _tokens[i] - ); - } + deployTopUpAllowedRecipients(_trustedCaller, address(allowedRecipientsRegistry), address(allowedTokensRegistry)); deployAddAllowedRecipient(_trustedCaller, address(allowedRecipientsRegistry)); @@ -321,13 +290,10 @@ contract AllowedRecipientsBuilder { string[] memory titles = new string[](1); titles[0] = _title; - (IAllowedRecipientsRegistry allowedRecipientsRegistry, IAllowedTokensRegistry allowedTokensRegistry) = - deployRegistries(_limit, _periodDurationMonths, _tokens, recipients, titles, _spentAmount, false); + IAllowedRecipientsRegistry allowedRecipientsRegistry = + deployAllowedRecipientsRegistry(_limit, _periodDurationMonths, recipients, titles, _spentAmount, false); + IAllowedTokensRegistry allowedTokensRegistry = deployAllowedTokensRegistry(_tokens); - for (uint256 i = 0; i < _tokens.length; i++) { - deployTopUpAllowedRecipients( - _recipient, address(allowedRecipientsRegistry), address(allowedTokensRegistry), _tokens[i] - ); - } + deployTopUpAllowedRecipients(_recipient, address(allowedRecipientsRegistry), address(allowedTokensRegistry)); } } diff --git a/contracts/AllowedRecipientsFactory.sol b/contracts/AllowedRecipientsFactory.sol index 73c05a59..1f3992aa 100644 --- a/contracts/AllowedRecipientsFactory.sol +++ b/contracts/AllowedRecipientsFactory.sol @@ -38,7 +38,6 @@ contract AllowedRecipientsFactory { address allowedRecipientsRegistry, address allowedTokenssRegistry, address finance, - address token, address easyTrack ); @@ -109,7 +108,6 @@ contract AllowedRecipientsFactory { address _trustedCaller, address _allowedRecipientsRegistry, address _allowedTokensRegistry, - address _token, address _finance, address _easyTrack ) public returns (TopUpAllowedRecipients topUpAllowedRecipients) { @@ -118,7 +116,6 @@ contract AllowedRecipientsFactory { _allowedRecipientsRegistry, _allowedTokensRegistry, _finance, - _token, _easyTrack ); @@ -129,7 +126,6 @@ contract AllowedRecipientsFactory { _allowedRecipientsRegistry, _allowedTokensRegistry, _finance, - _token, _easyTrack ); diff --git a/contracts/AllowedTokensRegistry.sol b/contracts/AllowedTokensRegistry.sol index 42d9f9f9..6beaec30 100644 --- a/contracts/AllowedTokensRegistry.sol +++ b/contracts/AllowedTokensRegistry.sol @@ -31,13 +31,13 @@ contract AllowedTokensRegistry is AccessControl { // ------------- /// @dev List of allowed tokens for payouts address[] public allowedTokens; - + // Position of the address in the `allowedTokens` array, // plus 1 because index 0 means a value is not in the set. mapping(address => uint256) private allowedTokenIndices; /// @notice Precise number of tokens in the system - uint8 public constant PRECISION = 18; + uint8 internal constant DECIMALS = 18; constructor( address _admin, @@ -102,9 +102,9 @@ contract AllowedTokensRegistry is AccessControl { uint8 tokenDecimals = IERC20Metadata(_token).decimals(); - if (tokenDecimals == PRECISION) return _tokenAmount; - if (tokenDecimals > PRECISION) { - uint256 difference = tokenDecimals - PRECISION; + if (tokenDecimals == DECIMALS) return _tokenAmount; + if (tokenDecimals > DECIMALS) { + uint256 difference = tokenDecimals - DECIMALS; uint256 remainder = _tokenAmount % (10 ** difference); uint256 quotient = _tokenAmount / (10 ** difference); if (remainder > 0) { @@ -112,7 +112,12 @@ contract AllowedTokensRegistry is AccessControl { } return quotient; } - return _tokenAmount * 10 ** (PRECISION - tokenDecimals); + return _tokenAmount * 10 ** (DECIMALS - tokenDecimals); + } + + /// @notice Returns precision of the token + function decimals() pure external returns (uint8) { + return DECIMALS; } // ------------------ diff --git a/contracts/EVMScriptFactories/TopUpAllowedRecipients.sol b/contracts/EVMScriptFactories/TopUpAllowedRecipients.sol index d336ee2f..bc745e4c 100644 --- a/contracts/EVMScriptFactories/TopUpAllowedRecipients.sol +++ b/contracts/EVMScriptFactories/TopUpAllowedRecipients.sol @@ -4,12 +4,12 @@ pragma solidity ^0.8.4; import "../TrustedCaller.sol"; -import "../AllowedRecipientsRegistry.sol"; -import "../AllowedTokensRegistry.sol"; +import "../interfaces/IAllowedRecipientsRegistry.sol"; +import "../interfaces/IAllowedTokensRegistry.sol"; import "../interfaces/IFinance.sol"; import "../libraries/EVMScriptCreator.sol"; import "../interfaces/IEVMScriptFactory.sol"; -import "../EasyTrack.sol"; +import "../interfaces/IEasyTrack.sol"; /// @notice Creates EVMScript to top up allowed recipients addresses within the current spendable balance contract TopUpAllowedRecipients is TrustedCaller, IEVMScriptFactory { @@ -28,19 +28,16 @@ contract TopUpAllowedRecipients is TrustedCaller, IEVMScriptFactory { // ------------- /// @notice Address of EasyTrack contract - EasyTrack public immutable easyTrack; + IEasyTrack public immutable easyTrack; /// @notice Address of Aragon's Finance contract IFinance public immutable finance; - /// @notice Address of payout token - address public token; - /// @notice Address of AllowedRecipientsRegistry contract - AllowedRecipientsRegistry public allowedRecipientsRegistry; + IAllowedRecipientsRegistry public immutable allowedRecipientsRegistry; - /// @notice Address of AllowedTokenssRegistry contract - AllowedTokensRegistry public allowedTokensRegistry; + /// @notice Address of AllowedTokensRegistry contract + IAllowedTokensRegistry public immutable allowedTokensRegistry; // ------------- // CONSTRUCTOR @@ -50,21 +47,18 @@ contract TopUpAllowedRecipients is TrustedCaller, IEVMScriptFactory { /// Set once on deployment and can't be changed. /// @param _allowedRecipientsRegistry Address of AllowedRecipientsRegistry contract /// @param _finance Address of Aragon's Finance contract - /// @param _token Address of payout token /// @param _easyTrack Address of EasyTrack contract constructor( address _trustedCaller, address _allowedRecipientsRegistry, address _allowedTokensRegistry, address _finance, - address _token, address _easyTrack ) TrustedCaller(_trustedCaller) { finance = IFinance(_finance); - token = _token; - allowedRecipientsRegistry = AllowedRecipientsRegistry(_allowedRecipientsRegistry); - allowedTokensRegistry = AllowedTokensRegistry(_allowedTokensRegistry); - easyTrack = EasyTrack(_easyTrack); + allowedRecipientsRegistry = IAllowedRecipientsRegistry(_allowedRecipientsRegistry); + allowedTokensRegistry = IAllowedTokensRegistry(_allowedTokensRegistry); + easyTrack = IEasyTrack(_easyTrack); } // ------------- @@ -84,8 +78,9 @@ contract TopUpAllowedRecipients is TrustedCaller, IEVMScriptFactory { onlyTrustedCaller(_creator) returns (bytes memory) { - (address[] memory recipients, uint256[] memory amounts) = _decodeEVMScriptCallData(_evmScriptCallData); - uint256 totalAmount = _validateEVMScriptCallData(recipients, amounts); + (address token, address[] memory recipients, uint256[] memory amounts) = + _decodeEVMScriptCallData(_evmScriptCallData); + uint256 normalizedAmount = _validateEVMScriptCallData(token, recipients, amounts); address[] memory to = new address[](recipients.length + 1); bytes4[] memory methodIds = new bytes4[](recipients.length + 1); @@ -93,7 +88,7 @@ contract TopUpAllowedRecipients is TrustedCaller, IEVMScriptFactory { to[0] = address(allowedRecipientsRegistry); methodIds[0] = allowedRecipientsRegistry.updateSpentAmount.selector; - evmScriptsCalldata[0] = abi.encode(allowedTokensRegistry.normalizeAmount(totalAmount, token)); + evmScriptsCalldata[0] = abi.encode(normalizedAmount); for (uint256 i = 0; i < recipients.length; ++i) { to[i + 1] = address(finance); @@ -108,12 +103,13 @@ contract TopUpAllowedRecipients is TrustedCaller, IEVMScriptFactory { /// @param _evmScriptCallData Encoded tuple: (address[] recipients, uint256[] amounts) where /// recipients - addresses of recipients to top up /// amounts - corresponding amounts of token to transfer + /// @return token Address of payout token /// @return recipients Addresses of recipients to top up /// @return amounts Amounts of token to transfer function decodeEVMScriptCallData(bytes memory _evmScriptCallData) external pure - returns (address[] memory recipients, uint256[] memory amounts) + returns (address token, address[] memory recipients, uint256[] memory amounts) { return _decodeEVMScriptCallData(_evmScriptCallData); } @@ -122,30 +118,34 @@ contract TopUpAllowedRecipients is TrustedCaller, IEVMScriptFactory { // PRIVATE METHODS // ------------------ - function _validateEVMScriptCallData(address[] memory _recipients, uint256[] memory _amounts) + function _validateEVMScriptCallData(address token, address[] memory _recipients, uint256[] memory _amounts) private view - returns (uint256 totalAmount) + returns (uint256 normalizedAmount) { require(_amounts.length == _recipients.length, ERROR_LENGTH_MISMATCH); require(_recipients.length > 0, ERROR_EMPTY_DATA); require(allowedTokensRegistry.isTokenAllowed(token), ERROR_TOKEN_NOT_ALLOWED); + uint256 totalAmount = 0; + for (uint256 i = 0; i < _recipients.length; ++i) { require(_amounts[i] > 0, ERROR_ZERO_AMOUNT); require(allowedRecipientsRegistry.isRecipientAllowed(_recipients[i]), ERROR_RECIPIENT_NOT_ALLOWED); totalAmount += _amounts[i]; } - _validateSpendableBalance(allowedTokensRegistry.normalizeAmount(totalAmount, token)); + normalizedAmount = allowedTokensRegistry.normalizeAmount(totalAmount, token); + + _validateSpendableBalance(normalizedAmount); } function _decodeEVMScriptCallData(bytes memory _evmScriptCallData) private pure - returns (address[] memory recipients, uint256[] memory amounts) + returns (address token, address[] memory recipients, uint256[] memory amounts) { - return abi.decode(_evmScriptCallData, (address[], uint256[])); + return abi.decode(_evmScriptCallData, (address, address[], uint256[])); } function _validateSpendableBalance(uint256 _amount) private view { diff --git a/contracts/interfaces/IAllowedRecipientsRegistry.sol b/contracts/interfaces/IAllowedRecipientsRegistry.sol new file mode 100644 index 00000000..9de089a1 --- /dev/null +++ b/contracts/interfaces/IAllowedRecipientsRegistry.sol @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: 2022 Lido +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity ^0.8.4; + +interface IAllowedRecipientsRegistry { + function addRecipient(address _recipient, string memory _title) external; + + function renounceRole(bytes32 role, address account) external; + + function isRecipientAllowed(address _recipient) external view returns (bool); + + function setLimitParameters(uint256 _limit, uint256 _periodDurationMonths) external; + + function getLimitParameters() external view returns (uint256, uint256); + + function updateSpentAmount(uint256 _payoutAmount) external; + + function spendableBalance() external view returns (uint256); + + function hasRole(bytes32 role, address account) external view returns (bool); + + function getAllowedRecipients() external view returns (address[] memory); + + function bokkyPooBahsDateTimeContract() external view returns (address); + + function isUnderSpendableBalance(uint256 _amount, uint256 _motionDuration) external view returns (bool); +} \ No newline at end of file diff --git a/contracts/interfaces/IAllowedTokensRegistry.sol b/contracts/interfaces/IAllowedTokensRegistry.sol new file mode 100644 index 00000000..fa62ef6b --- /dev/null +++ b/contracts/interfaces/IAllowedTokensRegistry.sol @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: 2022 Lido +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity ^0.8.4; + +interface IAllowedTokensRegistry { + function addToken(address _token) external; + + function removeToken(address _token) external; + + function renounceRole(bytes32 role, address account) external; + + function isTokenAllowed(address _token) external view returns (bool); + + function hasRole(bytes32 role, address account) external view returns (bool); + + function getAllowedTokens() external view returns (address[] memory); + + function decimals() external view returns (uint8); + + function normalizeAmount(uint256 _amount, address _token) external view returns (uint256); +} \ No newline at end of file diff --git a/contracts/interfaces/IEasyTrack.sol b/contracts/interfaces/IEasyTrack.sol new file mode 100644 index 00000000..7a1468e8 --- /dev/null +++ b/contracts/interfaces/IEasyTrack.sol @@ -0,0 +1,9 @@ +// SPDX-FileCopyrightText: 2022 Lido +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity ^0.8.4; + +interface IEasyTrack { + function motionDuration() external view returns (uint256); + function evmScriptExecutor() external view returns (address); +} \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index ff0a02d9..b1b85f45 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -300,7 +300,6 @@ def top_up_allowed_recipients( allowed_tokens_registry, accounts, finance, - ldo, easy_track, TopUpAllowedRecipients, ): @@ -315,7 +314,6 @@ def top_up_allowed_recipients( recipients_registry, tokens_registry, finance, - ldo, easy_track, ) @@ -341,6 +339,10 @@ def steth(lido_contracts): def usdc(): return external_contracts(network=brownie.network.show_active())["usdc"] +@pytest.fixture(scope="module") +def dai(): + return external_contracts(network=brownie.network.show_active())["dai"] + @pytest.fixture(scope="module") def node_operators_registry(lido_contracts): diff --git a/tests/evm_script_factories/test_top_up_allowed_recipients.py b/tests/evm_script_factories/test_top_up_allowed_recipients.py index 2c9a39e0..36ff310a 100644 --- a/tests/evm_script_factories/test_top_up_allowed_recipients.py +++ b/tests/evm_script_factories/test_top_up_allowed_recipients.py @@ -6,8 +6,8 @@ from utils.evm_script import encode_calldata, encode_call_script -def make_call_data(recipients, amounts): - return encode_calldata("(address[],uint256[])", [recipients, amounts]) +def make_call_data(token, recipients, amounts): + return encode_calldata("(address,address[],uint256[])", [token, recipients, amounts]) def test_top_up_factory_initial_state( @@ -15,7 +15,6 @@ def test_top_up_factory_initial_state( allowed_tokens_registry, accounts, finance, - ldo, easy_track, TopUpAllowedRecipients, ): @@ -30,12 +29,11 @@ def test_top_up_factory_initial_state( recipients_registry, tokens_registry, finance, - ldo, easy_track, ) - assert top_up_factory.token() == ldo assert top_up_factory.allowedRecipientsRegistry() == recipients_registry + assert top_up_factory.allowedTokensRegistry() == tokens_registry assert top_up_factory.trustedCaller() == trusted_caller assert top_up_factory.easyTrack() == easy_track assert top_up_factory.finance() == finance @@ -45,7 +43,6 @@ def test_fail_if_zero_trusted_caller( allowed_recipients_registry, allowed_tokens_registry, finance, - ldo, easy_track, TopUpAllowedRecipients, ): @@ -54,7 +51,7 @@ def test_fail_if_zero_trusted_caller( with reverts("TRUSTED_CALLER_IS_ZERO_ADDRESS"): owner.deploy( - TopUpAllowedRecipients, ZERO_ADDRESS, registry, tokens_registry, finance, ldo, easy_track + TopUpAllowedRecipients, ZERO_ADDRESS, registry, tokens_registry, finance, easy_track ) @@ -70,7 +67,6 @@ def test_top_up_factory_constructor_zero_argument_addresses_allowed( ZERO_ADDRESS, ZERO_ADDRESS, ZERO_ADDRESS, - ZERO_ADDRESS, ) @@ -78,11 +74,11 @@ def test_fail_create_evm_script_if_not_trusted_caller( top_up_allowed_recipients, stranger ): with reverts("CALLER_IS_FORBIDDEN"): - top_up_allowed_recipients.createEVMScript(stranger, make_call_data([], [])) + top_up_allowed_recipients.createEVMScript(stranger, make_call_data(ZERO_ADDRESS, [], [])) def test_create_evm_script_is_permissionless( - allowed_recipients_registry, allowed_tokens_registry, stranger, top_up_allowed_recipients + allowed_recipients_registry, allowed_tokens_registry, stranger, top_up_allowed_recipients, ldo ): ( registry, @@ -93,12 +89,12 @@ def test_create_evm_script_is_permissionless( _, ) = allowed_recipients_registry (token_registry, _, add_token_role_holder, _) = allowed_tokens_registry - token_registry.addToken(top_up_allowed_recipients.token(), {"from": add_token_role_holder}) + token_registry.addToken(ldo, {"from": add_token_role_holder}) registry.addRecipient( stranger.address, "Test Recipient", {"from": add_recipient_role_holder} ) registry.setLimitParameters(int(100e18), 12, {"from": set_limit_role_holder}) - call_data = make_call_data([stranger.address], [123]) + call_data = make_call_data(ldo.address, [stranger.address], [123]) trusted_caller = top_up_allowed_recipients.trustedCaller() top_up_allowed_recipients.createEVMScript( trusted_caller, call_data, {"from": stranger} @@ -106,30 +102,30 @@ def test_create_evm_script_is_permissionless( def test_decode_evm_script_calldata_is_permissionless( - stranger, top_up_allowed_recipients + stranger, top_up_allowed_recipients, ldo ): - call_data = make_call_data([stranger.address], [123]) + call_data = make_call_data(ldo.address, [stranger.address], [123]) top_up_allowed_recipients.decodeEVMScriptCallData(call_data, {"from": stranger}) -def test_fail_create_evm_script_if_length_mismatch(top_up_allowed_recipients, accounts): +def test_fail_create_evm_script_if_length_mismatch(top_up_allowed_recipients, accounts, ldo): factory = top_up_allowed_recipients trusted_caller = top_up_allowed_recipients.trustedCaller() recipient = accounts[2].address with reverts("LENGTH_MISMATCH"): - factory.createEVMScript(trusted_caller, make_call_data([recipient], [])) + factory.createEVMScript(trusted_caller, make_call_data(ldo.address, [recipient], [])) with reverts("LENGTH_MISMATCH"): - factory.createEVMScript(trusted_caller, make_call_data([], [123])) + factory.createEVMScript(trusted_caller, make_call_data(ldo.address, [], [123])) -def test_fail_create_evm_script_if_empty_data(top_up_allowed_recipients, accounts): +def test_fail_create_evm_script_if_empty_data(top_up_allowed_recipients): factory = top_up_allowed_recipients trusted_caller = top_up_allowed_recipients.trustedCaller() with reverts("EMPTY_DATA"): - factory.createEVMScript(trusted_caller, make_call_data([], [])) + factory.createEVMScript(trusted_caller, make_call_data(ZERO_ADDRESS, [], [])) def test_fail_create_evm_script_if_zero_amount( @@ -161,17 +157,17 @@ def test_fail_create_evm_script_if_zero_amount( registry.setLimitParameters(int(100e18), 12, {"from": set_limit_role_holder}) top_up_factory = owner.deploy( - TopUpAllowedRecipients, trusted_caller, registry, tokens_registry, finance, ldo, easy_track + TopUpAllowedRecipients, trusted_caller, registry, tokens_registry, finance, easy_track ) - tokens_registry.addToken(top_up_factory.token(), {"from": add_token_role_holder}) + tokens_registry.addToken(ldo, {"from": add_token_role_holder}) with reverts("ZERO_AMOUNT"): - top_up_factory.createEVMScript(trusted_caller, make_call_data([recipient], [0])) + top_up_factory.createEVMScript(trusted_caller, make_call_data(ldo.address, [recipient], [0])) with reverts("ZERO_AMOUNT"): top_up_factory.createEVMScript( - trusted_caller, make_call_data([recipient, recipient], [123, 0]) + trusted_caller, make_call_data(ldo.address, [recipient, recipient], [123, 0]) ) @@ -204,14 +200,14 @@ def test_fail_create_evm_script_if_recipient_not_allowed( registry.setLimitParameters(int(100e18), 12, {"from": set_limit_role_holder}) top_up_factory = owner.deploy( - TopUpAllowedRecipients, trusted_caller, registry, tokens_registry, finance, ldo, easy_track + TopUpAllowedRecipients, trusted_caller, registry, tokens_registry, finance, easy_track ) - tokens_registry.addToken(top_up_factory.token(), {"from": add_token_role_holder}) + tokens_registry.addToken(ldo, {"from": add_token_role_holder}) with reverts("RECIPIENT_NOT_ALLOWED"): top_up_factory.createEVMScript( - trusted_caller, make_call_data([stranger.address], [123]) + trusted_caller, make_call_data(ldo.address, [stranger.address], [123]) ) @@ -243,12 +239,12 @@ def test_fail_create_evm_script_if_token_not_allowed( registry.setLimitParameters(int(100e18), 12, {"from": set_limit_role_holder}) top_up_factory = owner.deploy( - TopUpAllowedRecipients, trusted_caller, registry, tokens_registry, finance, ldo, easy_track + TopUpAllowedRecipients, trusted_caller, registry, tokens_registry, finance, easy_track ) with reverts("TOKEN_NOT_ALLOWED"): top_up_factory.createEVMScript( - trusted_caller, make_call_data([recipient], [123]) + trusted_caller, make_call_data(ldo.address, [recipient], [123]) ) @@ -280,15 +276,15 @@ def test_top_up_factory_evm_script_creation_happy_path( registry.setLimitParameters(int(100e18), 12, {"from": set_limit_role_holder}) top_up_factory = owner.deploy( - TopUpAllowedRecipients, trusted_caller, registry, tokens_registry, finance, ldo, easy_track + TopUpAllowedRecipients, trusted_caller, registry, tokens_registry, finance, easy_track ) - tokens_registry.addToken(top_up_factory.token(), {"from": add_token_role_holder}) + tokens_registry.addToken(ldo, {"from": add_token_role_holder}) payout = int(1e18) - call_data = make_call_data([recipient], [payout]) + call_data = make_call_data(ldo.address, [recipient], [payout]) evm_script = top_up_factory.createEVMScript(trusted_caller, call_data) - assert top_up_factory.decodeEVMScriptCallData(call_data) == ([recipient], [payout]) + assert top_up_factory.decodeEVMScriptCallData(call_data) == (ldo.address, [recipient], [payout]) assert "Easy Track: top up recipient".encode("utf-8").hex() in str(evm_script) @@ -323,15 +319,15 @@ def test_top_up_factory_evm_script_creation_multiple_recipients_happy_path( registry.setLimitParameters(int(100e18), 12, {"from": set_limit_role_holder}) top_up_factory = owner.deploy( - TopUpAllowedRecipients, trusted_caller, registry, tokens_registry, finance, ldo, easy_track + TopUpAllowedRecipients, trusted_caller, registry, tokens_registry, finance, easy_track ) - tokens_registry.addToken(top_up_factory.token(), {"from": add_token_role_holder}) + tokens_registry.addToken(ldo, {"from": add_token_role_holder}) payouts = [int(1e18), int(2e18)] - call_data = make_call_data(recipients, payouts) + call_data = make_call_data(ldo.address, recipients, payouts) evm_script = top_up_factory.createEVMScript(trusted_caller, call_data) - assert top_up_factory.decodeEVMScriptCallData(call_data) == (recipients, payouts) + assert top_up_factory.decodeEVMScriptCallData(call_data) == (ldo.address, recipients, payouts) assert "Easy Track: top up recipient".encode("utf-8").hex() in str(evm_script) @@ -346,7 +342,7 @@ def test_fail_create_evm_script_if_sum_exceeds_limit( ): recipients = [accounts[4].address, accounts[5].address] payouts = [int(10e18), int(20e18)] - call_data = make_call_data(recipients, payouts) + call_data = make_call_data(ldo.address, recipients, payouts) ( registry, @@ -367,10 +363,10 @@ def test_fail_create_evm_script_if_sum_exceeds_limit( registry.setLimitParameters(int(20e18), 12, {"from": set_limit_role_holder}) top_up_factory = owner.deploy( - TopUpAllowedRecipients, owner, registry, tokens_registry, finance, ldo, easy_track + TopUpAllowedRecipients, owner, registry, tokens_registry, finance, easy_track ) - tokens_registry.addToken(top_up_factory.token(), {"from": add_token_role_holder}) + tokens_registry.addToken(ldo, {"from": add_token_role_holder}) with reverts("SUM_EXCEEDS_SPENDABLE_BALANCE"): top_up_factory.createEVMScript(owner, call_data) @@ -408,12 +404,12 @@ def test_create_evm_script_correctly( registry.setLimitParameters(int(100e18), 12, {"from": set_limit_role_holder}) top_up_factory = owner.deploy( - TopUpAllowedRecipients, owner, registry, tokens_registry, finance, ldo, easy_track + TopUpAllowedRecipients, owner, registry, tokens_registry, finance, easy_track ) - tokens_registry.addToken(top_up_factory.token(), {"from": add_token_role_holder}) + tokens_registry.addToken(ldo, {"from": add_token_role_holder}) - call_data = make_call_data(recipients, payouts) + call_data = make_call_data(ldo.address, recipients, payouts) evm_script = top_up_factory.createEVMScript(owner, call_data) expected_evm_script = encode_call_script( [ @@ -439,12 +435,13 @@ def test_create_evm_script_correctly( assert evm_script == expected_evm_script -def test_decode_evm_script_call_data(top_up_allowed_recipients, accounts): +def test_decode_evm_script_call_data(top_up_allowed_recipients, ldo, accounts): recipient = accounts[4].address payout = int(1e18) - call_data = make_call_data([recipient], [payout]) + call_data = make_call_data(ldo.address, [recipient], [payout]) assert top_up_allowed_recipients.decodeEVMScriptCallData(call_data) == [ + ldo.address, [recipient], [payout], ] diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 929cef99..e407033d 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -329,7 +329,6 @@ def top_up_allowed_recipients_evm_script_factory( trusted_caller, allowed_recipients_registry, allowed_tokens_registry, - lido_contracts.ldo, {"from": deployer}, ) @@ -380,13 +379,14 @@ def _create_add_allowed_recipient_motion( def create_top_up_allowed_recipients_motion(easy_track): def _create_top_up_allowed_recipients_motion( top_up_allowed_recipients_evm_script_factory, + token, recipient_addresses, top_up_amounts, ): return easy_track.createMotion( top_up_allowed_recipients_evm_script_factory, evm_script.encode_calldata( - "(address[],uint256[])", [recipient_addresses, top_up_amounts] + "(address,address[],uint256[])", [token, recipient_addresses, top_up_amounts] ), {"from": top_up_allowed_recipients_evm_script_factory.trustedCaller()}, ) @@ -402,11 +402,13 @@ def top_up_allowed_recipient_by_motion( ): def _top_up_allowed_recipient_by_motion( top_up_allowed_recipients_evm_script_factory, + token_address, recipient_addresses, top_up_amounts, ): motion_creation_tx = create_top_up_allowed_recipients_motion( top_up_allowed_recipients_evm_script_factory, + token_address, recipient_addresses, top_up_amounts, ) @@ -442,14 +444,13 @@ def _enact_top_up_allowed_recipient_motion_by_creation_tx(motion_creation_tx): ) ( + top_up_token, recipients, amounts, ) = top_up_allowed_recipients_evm_script_factory.decodeEVMScriptCallData( motion_creation_tx.events["MotionCreated"]["_evmScriptCallData"] ) - top_up_token = top_up_allowed_recipients_evm_script_factory.token() - (sender_balance_before,) = get_balances( top_up_token, [lido_contracts.aragon.agent] ) @@ -481,6 +482,7 @@ def _enact_top_up_allowed_recipient_motion_by_creation_tx(motion_creation_tx): recipients_balances_before=recipients_balances_before, sender_shares_balance_before=sender_shares_balance_before, recipients_shares_balance_before=recipients_shares_balance_before, + top_up_token=top_up_token, top_up_recipients=recipients, top_up_amounts=amounts, ) @@ -502,10 +504,10 @@ def _check_top_up_motion_enactment( recipients_balances_before, sender_shares_balance_before, recipients_shares_balance_before, + top_up_token, top_up_recipients, top_up_amounts, ): - top_up_token = top_up_allowed_recipients_evm_script_factory.token() allowed_recipients_registry = AllowedRecipientsRegistry.at( top_up_allowed_recipients_evm_script_factory.allowedRecipientsRegistry() ) @@ -646,22 +648,23 @@ def registries( allowed_recipients_registry = load_deployed_contract("AllowedRecipientsRegistry") if allowed_recipients_registry is None: - tx = allowed_recipients_builder.deployRegistries( + tx_recipients = allowed_recipients_builder.deployAllowedRecipientsRegistry( allowed_recipients_default_params.limit, allowed_recipients_default_params.period_duration_months, [], [], - [], allowed_recipients_default_params.spent_amount, True, {"from": deployer}, ) + tx_tokens = allowed_recipients_builder.deployAllowedTokensRegistry([]) + allowed_recipients_registry = AllowedRecipientsRegistry.at( - tx.events["AllowedRecipientsRegistryDeployed"]["allowedRecipientsRegistry"] + tx_recipients.events["AllowedRecipientsRegistryDeployed"]["allowedRecipientsRegistry"] ) allowed_tokens_registry = AllowedTokensRegistry.at( - tx.events["AllowedTokensRegistryDeployed"]["allowedTokensRegistry"] + tx_tokens.events["AllowedTokensRegistryDeployed"]["allowedTokensRegistry"] ) if not allowed_recipients_registry.hasRole( diff --git a/tests/integration/test_allowed_recipients_happy_path.py b/tests/integration/test_allowed_recipients_happy_path.py index ed31bdf4..768ed6b2 100644 --- a/tests/integration/test_allowed_recipients_happy_path.py +++ b/tests/integration/test_allowed_recipients_happy_path.py @@ -16,8 +16,8 @@ @dataclass class SingleRecipientTopUpOnlySetup: allowed_recipients_registry: AllowedRecipientsRegistry - top_up_allowed_recipients_ldo_evm_script_factory: TopUpAllowedRecipients - top_up_allowed_recipients_usdc_evm_script_factory: TopUpAllowedRecipients + top_up_allowed_recipients_evm_script_factory: TopUpAllowedRecipients + allowed_tokens: list[str] @dataclass @@ -42,16 +42,19 @@ def single_recipient_top_up_only_setup( TopUpAllowedRecipients, easy_track, lido_contracts, - external_contracts, allowed_recipient, allowed_recipients_builder, allowed_recipients_default_params, deployer, + dai, + usdc, ): + allowed_tokens = [dai, usdc] + deploy_tx = allowed_recipients_builder.deploySingleRecipientTopUpOnlySetup( allowed_recipient.address, allowed_recipient.title, - [lido_contracts.ldo, external_contracts["usdc"]], + allowed_tokens, allowed_recipients_default_params.limit, allowed_recipients_default_params.period_duration_months, allowed_recipients_default_params.spent_amount, @@ -63,25 +66,12 @@ def single_recipient_top_up_only_setup( "allowedRecipientsRegistry" ] ) - top_up_allowed_recipients_ldo_evm_script_factory = TopUpAllowedRecipients.at( - deploy_tx.events["TopUpAllowedRecipientsDeployed"][0]["topUpAllowedRecipients"] - ) - top_up_allowed_recipients_usdc_evm_script_factory = TopUpAllowedRecipients.at( - deploy_tx.events["TopUpAllowedRecipientsDeployed"][1]["topUpAllowedRecipients"] + top_up_allowed_recipients_evm_script_factory = TopUpAllowedRecipients.at( + deploy_tx.events["TopUpAllowedRecipientsDeployed"]["topUpAllowedRecipients"] ) easy_track.addEVMScriptFactory( - top_up_allowed_recipients_ldo_evm_script_factory, - deployment.create_permission( - lido_contracts.aragon.finance, "newImmediatePayment" - ) - + deployment.create_permission( - allowed_recipients_registry, "updateSpentAmount" - )[2:], - {"from": lido_contracts.aragon.voting}, - ) - easy_track.addEVMScriptFactory( - top_up_allowed_recipients_usdc_evm_script_factory, + top_up_allowed_recipients_evm_script_factory, deployment.create_permission( lido_contracts.aragon.finance, "newImmediatePayment" ) @@ -92,8 +82,8 @@ def single_recipient_top_up_only_setup( ) return SingleRecipientTopUpOnlySetup( allowed_recipients_registry, - top_up_allowed_recipients_ldo_evm_script_factory, - top_up_allowed_recipients_usdc_evm_script_factory, + top_up_allowed_recipients_evm_script_factory, + allowed_tokens ) @@ -109,14 +99,15 @@ def full_setup( lido_contracts, allowed_recipients_default_params, deployer, - ldo, - usdc + dai, + usdc, ): + allowed_tokens = [dai, usdc] deploy_tx = allowed_recipients_builder.deployFullSetup( trusted_caller, allowed_recipients_default_params.limit, allowed_recipients_default_params.period_duration_months, - [ldo, usdc], + [dai, usdc], [], [], allowed_recipients_default_params.spent_amount, @@ -148,24 +139,11 @@ def full_setup( {"from": lido_contracts.aragon.voting}, ) - top_up_allowed_recipients_ldo_evm_script_factory = TopUpAllowedRecipients.at( - deploy_tx.events["TopUpAllowedRecipientsDeployed"][0]["topUpAllowedRecipients"] - ) - top_up_allowed_recipients_usdc_evm_script_factory = TopUpAllowedRecipients.at( - deploy_tx.events["TopUpAllowedRecipientsDeployed"][1]["topUpAllowedRecipients"] - ) - easy_track.addEVMScriptFactory( - top_up_allowed_recipients_ldo_evm_script_factory, - deployment.create_permission( - lido_contracts.aragon.finance, "newImmediatePayment" - ) - + deployment.create_permission( - allowed_recipients_registry, "updateSpentAmount" - )[2:], - {"from": lido_contracts.aragon.voting}, + top_up_allowed_recipients_evm_script_factory = TopUpAllowedRecipients.at( + deploy_tx.events["TopUpAllowedRecipientsDeployed"]["topUpAllowedRecipients"] ) easy_track.addEVMScriptFactory( - top_up_allowed_recipients_usdc_evm_script_factory, + top_up_allowed_recipients_evm_script_factory, deployment.create_permission( lido_contracts.aragon.finance, "newImmediatePayment" ) @@ -176,9 +154,9 @@ def full_setup( ) return FullSetup( + allowed_tokens, allowed_recipients_registry, - top_up_allowed_recipients_ldo_evm_script_factory, - top_up_allowed_recipients_usdc_evm_script_factory, + top_up_allowed_recipients_evm_script_factory, add_allowed_recipient_evm_script_factory, remove_allowed_recipient_evm_script_factory, ) @@ -193,8 +171,8 @@ def test_single_recipient_top_up_only_setup_happy_path( allowed_recipient, new_recipient, ): - first_top_up_amount = 100 * 10**6 - second_top_up_amount = 100 * 10**18 + first_top_up_amount = 100 * 10**18 + second_top_up_amount = 100 * 10**6 test_helpers.advance_chain_time_to_beginning_of_the_next_period( allowed_recipients_default_params.period_duration_months @@ -203,17 +181,17 @@ def test_single_recipient_top_up_only_setup_happy_path( allowed_recipients_registry = ( single_recipient_top_up_only_setup.allowed_recipients_registry ) - top_up_allowed_recipients_ldo_evm_script_factory = ( - single_recipient_top_up_only_setup.top_up_allowed_recipients_ldo_evm_script_factory - ) - top_up_allowed_recipients_usdc_evm_script_factory = ( - single_recipient_top_up_only_setup.top_up_allowed_recipients_usdc_evm_script_factory + top_up_allowed_recipients_evm_script_factory = ( + single_recipient_top_up_only_setup.top_up_allowed_recipients_evm_script_factory ) + [dai, usdc] = single_recipient_top_up_only_setup.allowed_tokens + # Top up allowed recipient top_up_allowed_recipient_by_motion( - top_up_allowed_recipients_usdc_evm_script_factory, + top_up_allowed_recipients_evm_script_factory, + dai, [allowed_recipient.address], [first_top_up_amount], ) @@ -267,7 +245,8 @@ def test_single_recipient_top_up_only_setup_happy_path( # Top up newly added recipient top_up_allowed_recipient_by_motion( - top_up_allowed_recipients_ldo_evm_script_factory, + top_up_allowed_recipients_evm_script_factory, + usdc, [new_recipient.address], [second_top_up_amount], ) @@ -275,7 +254,8 @@ def test_single_recipient_top_up_only_setup_happy_path( # Validate motion creation fails if the limit was exceeded with reverts("SUM_EXCEEDS_SPENDABLE_BALANCE"): top_up_allowed_recipient_by_motion( - top_up_allowed_recipients_ldo_evm_script_factory, + top_up_allowed_recipients_evm_script_factory, + usdc, [new_recipient.address], [1], ) @@ -294,6 +274,10 @@ def test_full_setup_happy_path( first_top_up_amount = 50 * 10**6 second_top_up_amount = 100 * 10**18 + print(full_setup) + + [dai, usdc] = full_setup.allowed_tokens + test_helpers.advance_chain_time_to_beginning_of_the_next_period( allowed_recipients_default_params.period_duration_months ) @@ -309,11 +293,12 @@ def test_full_setup_happy_path( ) # Top up allowed recipient by motion - top_up_allowed_recipients_ldo_evm_script_factory = ( - full_setup.top_up_allowed_recipients_ldo_evm_script_factory + top_up_allowed_recipients_evm_script_factory = ( + full_setup.top_up_allowed_recipients_evm_script_factory ) top_up_allowed_recipient_by_motion( - top_up_allowed_recipients_ldo_evm_script_factory, + top_up_allowed_recipients_evm_script_factory, + usdc, [allowed_recipient.address], [first_top_up_amount], ) @@ -343,11 +328,12 @@ def test_full_setup_happy_path( ) # Top up newly allowed recipient by motion - top_up_allowed_recipients_ldo_evm_script_factory = ( - full_setup.top_up_allowed_recipients_ldo_evm_script_factory + top_up_allowed_recipients_evm_script_factory = ( + full_setup.top_up_allowed_recipients_evm_script_factory ) top_up_allowed_recipient_by_motion( - top_up_allowed_recipients_ldo_evm_script_factory, + top_up_allowed_recipients_evm_script_factory, + dai, [new_recipient.address], [second_top_up_amount], ) @@ -355,7 +341,8 @@ def test_full_setup_happy_path( # Validate motion creation cause limit was spent with reverts("SUM_EXCEEDS_SPENDABLE_BALANCE"): top_up_allowed_recipient_by_motion( - top_up_allowed_recipients_ldo_evm_script_factory, + top_up_allowed_recipients_evm_script_factory, + dai, [new_recipient.address], [1], ) diff --git a/tests/integration/test_allowed_recipients_motions.py b/tests/integration/test_allowed_recipients_motions.py index 1c55a929..23b5fcb3 100644 --- a/tests/integration/test_allowed_recipients_motions.py +++ b/tests/integration/test_allowed_recipients_motions.py @@ -215,6 +215,7 @@ def test_fail_remove_recipient_if_it_is_not_allowed( def test_top_up_single_recipient( recipients, + dai, add_allowed_token, allowed_recipients_limit_params, add_allowed_recipient_by_motion, @@ -230,7 +231,7 @@ def test_top_up_single_recipient( allowed_recipient.title, ) - add_allowed_token(top_up_allowed_recipients_evm_script_factory.token()) + add_allowed_token(dai) top_up_recipient_addresses = [allowed_recipient.address] top_up_amounts = [2 * 10**18] @@ -241,6 +242,7 @@ def test_top_up_single_recipient( top_up_allowed_recipient_by_motion( top_up_allowed_recipients_evm_script_factory, + dai, top_up_recipient_addresses, top_up_amounts, ) @@ -254,6 +256,7 @@ def test_top_up_multiple_recipients( top_up_allowed_recipient_by_motion, add_allowed_recipient_evm_script_factory, top_up_allowed_recipients_evm_script_factory, + dai, ): allowed_recipients = recipients[:2] @@ -268,7 +271,7 @@ def test_top_up_multiple_recipients( allowed_recipients[1].title, ) - add_allowed_token(top_up_allowed_recipients_evm_script_factory.token()) + add_allowed_token(dai) test_helpers.advance_chain_time_to_beginning_of_the_next_period( allowed_recipients_limit_params.duration @@ -278,12 +281,14 @@ def test_top_up_multiple_recipients( top_up_allowed_recipient_by_motion( top_up_allowed_recipients_evm_script_factory, + dai, [r.address for r in allowed_recipients], top_up_amounts, ) def test_top_up_motion_enacted_in_next_period( + dai, recipients, add_allowed_token, allowed_recipients_limit_params, @@ -306,7 +311,7 @@ def test_top_up_motion_enacted_in_next_period( allowed_recipients[1].title, ) - add_allowed_token(top_up_allowed_recipients_evm_script_factory.token()) + add_allowed_token(dai) top_up_amounts = [int(3e18), int(90e18)] @@ -316,6 +321,7 @@ def test_top_up_motion_enacted_in_next_period( motion_creation_tx = create_top_up_allowed_recipients_motion( top_up_allowed_recipients_evm_script_factory, + dai, [r.address for r in allowed_recipients], top_up_amounts, ) @@ -327,6 +333,7 @@ def test_top_up_motion_enacted_in_next_period( def test_top_up_motion_ended_and_enacted_in_next_period( + dai, recipients, easy_track, allowed_recipients_limit_params, @@ -354,7 +361,7 @@ def test_top_up_motion_ended_and_enacted_in_next_period( top_up_amounts = [int(3e18), int(90e18)] - add_allowed_token(top_up_allowed_recipients_evm_script_factory.token()) + add_allowed_token(dai) test_helpers.advance_chain_time_to_beginning_of_the_next_period( allowed_recipients_limit_params.duration @@ -365,6 +372,7 @@ def test_top_up_motion_ended_and_enacted_in_next_period( motion_creation_tx = create_top_up_allowed_recipients_motion( top_up_allowed_recipients_evm_script_factory, + dai, [r.address for r in allowed_recipients], top_up_amounts, ) @@ -380,6 +388,7 @@ def test_top_up_motion_ended_and_enacted_in_next_period( def test_top_up_motion_enacted_in_second_next_period( + dai, recipients, add_allowed_token, allowed_recipients_limit_params, @@ -402,7 +411,7 @@ def test_top_up_motion_enacted_in_second_next_period( allowed_recipients[1].title, ) - add_allowed_token(top_up_allowed_recipients_evm_script_factory.token()) + add_allowed_token(dai) top_up_amounts = [int(3e18), int(90e18)] @@ -412,6 +421,7 @@ def test_top_up_motion_enacted_in_second_next_period( motion_creation_tx = create_top_up_allowed_recipients_motion( top_up_allowed_recipients_evm_script_factory, + dai, [r.address for r in allowed_recipients], top_up_amounts, ) @@ -422,6 +432,7 @@ def test_top_up_motion_enacted_in_second_next_period( def test_spendable_balance_is_renewed_in_next_period( + dai, recipients, allowed_recipients_limit_params, registries, @@ -454,7 +465,7 @@ def test_spendable_balance_is_renewed_in_next_period( allowed_recipients[1].title, ) - add_allowed_token(top_up_allowed_recipients_evm_script_factory.token()) + add_allowed_token(dai) top_up_amounts = [ int(allowed_recipients_limit_params.limit // 10**18 * 0.1) * 10**18, @@ -463,6 +474,7 @@ def test_spendable_balance_is_renewed_in_next_period( top_up_allowed_recipient_by_motion( top_up_allowed_recipients_evm_script_factory, + dai, [r.address for r in allowed_recipients], top_up_amounts, ) @@ -477,6 +489,7 @@ def test_spendable_balance_is_renewed_in_next_period( with reverts("SUM_EXCEEDS_SPENDABLE_BALANCE"): top_up_allowed_recipient_by_motion( top_up_allowed_recipients_evm_script_factory, + dai, [allowed_recipients[0].address], [1], ) @@ -488,6 +501,7 @@ def test_spendable_balance_is_renewed_in_next_period( # or setLimitParameters. So trying to make a full period limit amount payout top_up_allowed_recipient_by_motion( top_up_allowed_recipients_evm_script_factory, + dai, [allowed_recipients[0].address], [allowed_recipients_limit_params.limit], ) @@ -500,6 +514,7 @@ def test_spendable_balance_is_renewed_in_next_period( def test_fail_if_token_not_allowed( + dai, recipients, add_allowed_recipient_by_motion, allowed_recipients_limit_params, @@ -522,12 +537,14 @@ def test_fail_if_token_not_allowed( with reverts("TOKEN_NOT_ALLOWED"): create_top_up_allowed_recipients_motion( top_up_allowed_recipients_evm_script_factory, + dai, [allowed_recipient.address], [allowed_recipients_limit_params.limit], ) def test_fail_enact_top_up_motion_if_recipient_removed_by_other_motion( + dai, recipients, add_allowed_token, allowed_recipients_limit_params, @@ -556,13 +573,14 @@ def test_fail_enact_top_up_motion_if_recipient_removed_by_other_motion( allowed_recipients[1].title, ) - add_allowed_token(top_up_allowed_recipients_evm_script_factory.token()) + add_allowed_token(dai) recipient_to_remove = allowed_recipients[0] top_up_amounts = [int(40e18), int(30e18)] motion_creation_tx = create_top_up_allowed_recipients_motion( top_up_allowed_recipients_evm_script_factory, + dai, [r.address for r in allowed_recipients], top_up_amounts, ) @@ -576,6 +594,7 @@ def test_fail_enact_top_up_motion_if_recipient_removed_by_other_motion( def test_fail_create_top_up_motion_if_exceeds_limit( + dai, recipients, add_allowed_token, allowed_recipients_limit_params, @@ -592,7 +611,7 @@ def test_fail_create_top_up_motion_if_exceeds_limit( allowed_recipient.title, ) - add_allowed_token(top_up_allowed_recipients_evm_script_factory.token()) + add_allowed_token(dai) test_helpers.advance_chain_time_to_beginning_of_the_next_period( allowed_recipients_limit_params.duration @@ -602,12 +621,14 @@ def test_fail_create_top_up_motion_if_exceeds_limit( exceeded_top_up_amounts = [allowed_recipients_limit_params.limit + 1] create_top_up_allowed_recipients_motion( top_up_allowed_recipients_evm_script_factory, + dai, [allowed_recipient.address], exceeded_top_up_amounts, ) def test_fail_to_create_top_up_motion_which_exceeds_spendable( + dai, recipients, add_allowed_token, allowed_recipients_limit_params, @@ -629,7 +650,7 @@ def test_fail_to_create_top_up_motion_which_exceeds_spendable( allowed_recipients[1].title, ) - add_allowed_token(top_up_allowed_recipients_evm_script_factory.token()) + add_allowed_token(dai) test_helpers.advance_chain_time_to_beginning_of_the_next_period( allowed_recipients_limit_params.duration @@ -644,6 +665,7 @@ def test_fail_to_create_top_up_motion_which_exceeds_spendable( top_up_allowed_recipient_by_motion( top_up_allowed_recipients_evm_script_factory, + dai, [r.address for r in allowed_recipients], first_top_up_amounts, ) @@ -652,12 +674,14 @@ def test_fail_to_create_top_up_motion_which_exceeds_spendable( second_top_up_amounts = [1, 1] top_up_allowed_recipient_by_motion( top_up_allowed_recipients_evm_script_factory, + dai, [r.address for r in allowed_recipients], second_top_up_amounts, ) def test_fail_2nd_top_up_motion_enactment_due_limit_but_can_enact_in_next( + dai, recipients, add_allowed_token, allowed_recipients_limit_params, @@ -680,7 +704,7 @@ def test_fail_2nd_top_up_motion_enactment_due_limit_but_can_enact_in_next( allowed_recipients[1].title, ) - add_allowed_token(top_up_allowed_recipients_evm_script_factory.token()) + add_allowed_token(dai) test_helpers.advance_chain_time_to_beginning_of_the_next_period( allowed_recipients_limit_params.duration @@ -701,11 +725,13 @@ def test_fail_2nd_top_up_motion_enactment_due_limit_but_can_enact_in_next( ) first_motion_creation_tx = create_top_up_allowed_recipients_motion( top_up_allowed_recipients_evm_script_factory, + dai, [r.address for r in allowed_recipients], first_top_up_amount, ) second_motion_creation_tx = create_top_up_allowed_recipients_motion( top_up_allowed_recipients_evm_script_factory, + dai, [r.address for r in allowed_recipients], second_top_up_amount, ) @@ -721,6 +747,7 @@ def test_fail_2nd_top_up_motion_enactment_due_limit_but_can_enact_in_next( def test_fail_2nd_top_up_motion_creation_in_period_if_it_exceeds_spendable( + dai, recipients, registries, add_allowed_token, @@ -746,7 +773,7 @@ def test_fail_2nd_top_up_motion_creation_in_period_if_it_exceeds_spendable( allowed_recipients[1].title, ) - add_allowed_token(top_up_allowed_recipients_evm_script_factory.token()) + add_allowed_token(dai) test_helpers.advance_chain_time_to_beginning_of_the_next_period( allowed_recipients_limit_params.duration @@ -768,6 +795,7 @@ def test_fail_2nd_top_up_motion_creation_in_period_if_it_exceeds_spendable( top_up_allowed_recipient_by_motion( top_up_allowed_recipients_evm_script_factory, + dai, [r.address for r in allowed_recipients], first_top_up_amounts, ) @@ -777,12 +805,14 @@ def test_fail_2nd_top_up_motion_creation_in_period_if_it_exceeds_spendable( with reverts("SUM_EXCEEDS_SPENDABLE_BALANCE"): top_up_allowed_recipient_by_motion( top_up_allowed_recipients_evm_script_factory, + dai, [r.address for r in allowed_recipients], second_top_up_amounts, ) def test_fail_top_up_if_limit_decreased_while_motion_is_in_flight( + dai, recipients, lido_contracts, registries, @@ -803,7 +833,7 @@ def test_fail_top_up_if_limit_decreased_while_motion_is_in_flight( allowed_recipients[0].title, ) - add_allowed_token(top_up_allowed_recipients_evm_script_factory.token()) + add_allowed_token(dai) test_helpers.advance_chain_time_to_beginning_of_the_next_period( allowed_recipients_limit_params.duration @@ -812,6 +842,7 @@ def test_fail_top_up_if_limit_decreased_while_motion_is_in_flight( top_up_amounts = [allowed_recipients_limit_params.limit] motion_creation_tx = create_top_up_allowed_recipients_motion( top_up_allowed_recipients_evm_script_factory, + dai, [r.address for r in allowed_recipients], top_up_amounts, ) @@ -827,6 +858,7 @@ def test_fail_top_up_if_limit_decreased_while_motion_is_in_flight( def test_top_up_if_limit_increased_while_motion_is_in_flight( + dai, recipients, lido_contracts, registries, @@ -847,7 +879,7 @@ def test_top_up_if_limit_increased_while_motion_is_in_flight( allowed_recipients[0].title, ) - add_allowed_token(top_up_allowed_recipients_evm_script_factory.token()) + add_allowed_token(dai) test_helpers.advance_chain_time_to_beginning_of_the_next_period( allowed_recipients_limit_params.duration @@ -856,6 +888,7 @@ def test_top_up_if_limit_increased_while_motion_is_in_flight( top_up_amounts = [allowed_recipients_limit_params.limit] motion_creation_tx = create_top_up_allowed_recipients_motion( top_up_allowed_recipients_evm_script_factory, + dai, [r.address for r in allowed_recipients], top_up_amounts, ) @@ -870,6 +903,7 @@ def test_top_up_if_limit_increased_while_motion_is_in_flight( def test_two_motion_seconds_failed_to_enact_due_limit_but_succeeded_after_limit_increased( + dai, easy_track, recipients, lido_contracts, @@ -897,7 +931,7 @@ def test_two_motion_seconds_failed_to_enact_due_limit_but_succeeded_after_limit_ allowed_recipients[1].title, ) - add_allowed_token(top_up_allowed_recipients_evm_script_factory.token()) + add_allowed_token(dai) test_helpers.advance_chain_time_to_beginning_of_the_next_period( allowed_recipients_limit_params.duration @@ -912,12 +946,14 @@ def test_two_motion_seconds_failed_to_enact_due_limit_but_succeeded_after_limit_ first_motion_creation_tx = create_top_up_allowed_recipients_motion( top_up_allowed_recipients_evm_script_factory, + dai, [r.address for r in allowed_recipients], first_top_up_amounts, ) second_motion_creation_tx = create_top_up_allowed_recipients_motion( top_up_allowed_recipients_evm_script_factory, + dai, [r.address for r in allowed_recipients], second_top_up_amounts, ) @@ -944,6 +980,7 @@ def test_two_motion_seconds_failed_to_enact_due_limit_but_succeeded_after_limit_ "initial_period_duration,new_period_duration", [(3, 2), (3, 6), (12, 1), (1, 12)] ) def test_top_up_spendable_renewal_if_period_duration_changed( + dai, recipients, registries, add_allowed_token, @@ -966,7 +1003,7 @@ def test_top_up_spendable_renewal_if_period_duration_changed( allowed_recipients[0].title, ) - add_allowed_token(top_up_allowed_recipients_evm_script_factory.token()) + add_allowed_token(dai) first_top_up_amount = [period_limit] second_top_up_amount = [1] # just 1 wei @@ -980,6 +1017,7 @@ def test_top_up_spendable_renewal_if_period_duration_changed( top_up_allowed_recipient_by_motion( top_up_allowed_recipients_evm_script_factory, + dai, [r.address for r in allowed_recipients], first_top_up_amount, ) @@ -987,6 +1025,7 @@ def test_top_up_spendable_renewal_if_period_duration_changed( with reverts("SUM_EXCEEDS_SPENDABLE_BALANCE"): create_top_up_allowed_recipients_motion( top_up_allowed_recipients_evm_script_factory, + dai, [r.address for r in allowed_recipients], second_top_up_amount, ) @@ -1000,6 +1039,7 @@ def test_top_up_spendable_renewal_if_period_duration_changed( with reverts("SUM_EXCEEDS_SPENDABLE_BALANCE"): create_top_up_allowed_recipients_motion( top_up_allowed_recipients_evm_script_factory, + dai, [r.address for r in allowed_recipients], second_top_up_amount, ) @@ -1010,6 +1050,7 @@ def test_top_up_spendable_renewal_if_period_duration_changed( # expect the spendable get renewed top_up_allowed_recipient_by_motion( top_up_allowed_recipients_evm_script_factory, + dai, [r.address for r in allowed_recipients], second_top_up_amount, ) diff --git a/tests/test_allowed_recipients_builder.py b/tests/test_allowed_recipients_builder.py index 174b1d78..4fa6577d 100644 --- a/tests/test_allowed_recipients_builder.py +++ b/tests/test_allowed_recipients_builder.py @@ -78,7 +78,7 @@ def test_deploy_top_up_allowed_recipients( tokens_registry = accounts[4] tx = allowed_recipients_builder.deployTopUpAllowedRecipients( - trusted_caller, recipients_registry, tokens_registry, ldo, {"from": stranger} + trusted_caller, recipients_registry, tokens_registry, {"from": stranger} ) top_up_address = tx.events["TopUpAllowedRecipientsDeployed"][ @@ -97,18 +97,15 @@ def test_deploy_top_up_allowed_recipients( == recipients_registry ) assert tx.events["TopUpAllowedRecipientsDeployed"]["finance"] == finance - assert tx.events["TopUpAllowedRecipientsDeployed"]["token"] == ldo assert tx.events["TopUpAllowedRecipientsDeployed"]["easyTrack"] == easy_track topUpAllowedRecipients = Contract.from_abi( "TopUpAllowedRecipients", top_up_address, TopUpAllowedRecipients.abi ) - assert topUpAllowedRecipients.token() == ldo assert topUpAllowedRecipients.allowedRecipientsRegistry() == recipients_registry assert topUpAllowedRecipients.allowedTokensRegistry() == tokens_registry assert topUpAllowedRecipients.trustedCaller() == trusted_caller assert topUpAllowedRecipients.finance() == finance - assert topUpAllowedRecipients.token() == ldo assert topUpAllowedRecipients.easyTrack() == easy_track @@ -197,14 +194,16 @@ def test_deploy_allowed_recipients_registry( titles = ["account 3", "account 4"] spentAmount = 1e10 - tx = allowed_recipients_builder.deployRegistries( - limit, period, tokens, recipients, titles, spentAmount, True, {"from": stranger} + tx_recipients = allowed_recipients_builder.deployAllowedRecipientsRegistry( + limit, period, recipients, titles, spentAmount, True, {"from": stranger} ) - recipient_registry_address = tx.events["AllowedRecipientsRegistryDeployed"][ + tx_tokens = allowed_recipients_builder.deployAllowedTokensRegistry(tokens, {"from": stranger}) + + recipient_registry_address = tx_recipients.events["AllowedRecipientsRegistryDeployed"][ "allowedRecipientsRegistry" ] - token_registry_address = tx.events["AllowedTokensRegistryDeployed"][ + token_registry_address = tx_tokens.events["AllowedTokensRegistryDeployed"][ "allowedTokensRegistry" ] @@ -249,8 +248,6 @@ def test_deploy_allowed_recipients_registry( assert token_registry.hasRole(ADD_TOKEN_TO_ALLOWED_LIST_ROLE, agent) assert token_registry.hasRole(REMOVE_TOKEN_FROM_ALLOWED_LIST_ROLE, agent) - assert token_registry.hasRole(ADD_TOKEN_TO_ALLOWED_LIST_ROLE, evm_script_executor) - assert token_registry.hasRole(REMOVE_TOKEN_FROM_ALLOWED_LIST_ROLE, evm_script_executor) def test_deploy_recipients_registry_reverts_recipients_length( @@ -259,13 +256,12 @@ def test_deploy_recipients_registry_reverts_recipients_length( limit = 1e18 period = 1 recipients = [accounts[3], accounts[4]] - tokens = [ldo] titles = ["account 3"] spentAmount = 1e10 with reverts(): - allowed_recipients_builder.deployRegistries( - limit, period, tokens, recipients, titles, spentAmount, False, {"from": stranger} + allowed_recipients_builder.deployAllowedRecipientsRegistry( + limit, period, recipients, titles, spentAmount, False, {"from": stranger} ) @@ -280,8 +276,8 @@ def test_deploy_recipients_registry_reverts_spentAmount_gt_limit( spentAmount = 1e10 with reverts("_spentAmount must be lower or equal to limit"): - allowed_recipients_builder.deployRegistries( - limit, period, tokens, recipients, titles, spentAmount, False, {"from": stranger} + allowed_recipients_builder.deployAllowedRecipientsRegistry( + limit, period, recipients, titles, spentAmount, False, {"from": stranger} ) @@ -292,6 +288,7 @@ def test_deploy_full_setup( ldo, evm_script_executor, AllowedRecipientsRegistry, + AllowedTokensRegistry, AddAllowedRecipient, RemoveAllowedRecipient, TopUpAllowedRecipients, @@ -327,9 +324,12 @@ def test_deploy_full_setup( {"from": stranger}, ) - registry_address = tx.events["AllowedRecipientsRegistryDeployed"][ + recipients_registry_address = tx.events["AllowedRecipientsRegistryDeployed"][ "allowedRecipientsRegistry" ] + tokens_registry_address = tx.events["AllowedTokensRegistryDeployed"][ + "allowedTokensRegistry" + ] top_up_address = tx.events["TopUpAllowedRecipientsDeployed"][ "topUpAllowedRecipients" ] @@ -340,8 +340,12 @@ def test_deploy_full_setup( "removeAllowedRecipient" ] - registry = Contract.from_abi( - "AllowedRecipientsRegistry", registry_address, AllowedRecipientsRegistry.abi + recipients_registry = Contract.from_abi( + "AllowedRecipientsRegistry", recipients_registry_address, AllowedRecipientsRegistry.abi + ) + + tokens_registry = Contract.from_abi( + "AllowedTokensRegistry", tokens_registry_address, AllowedTokensRegistry.abi ) top_up_allowed_recipients = Contract.from_abi( @@ -358,46 +362,50 @@ def test_deploy_full_setup( RemoveAllowedRecipient.abi, ) - assert top_up_allowed_recipients.token() == ldo - assert top_up_allowed_recipients.allowedRecipientsRegistry() == registry + assert top_up_allowed_recipients.allowedRecipientsRegistry() == recipients_registry assert top_up_allowed_recipients.trustedCaller() == trusted_caller - assert add_allowed_recipient.allowedRecipientsRegistry() == registry + assert add_allowed_recipient.allowedRecipientsRegistry() == recipients_registry assert add_allowed_recipient.trustedCaller() == trusted_caller - assert remove_allowed_recipient.allowedRecipientsRegistry() == registry + assert remove_allowed_recipient.allowedRecipientsRegistry() == recipients_registry assert remove_allowed_recipient.trustedCaller() == trusted_caller - assert len(registry.getAllowedRecipients()) == len(recipients) + assert len(recipients_registry.getAllowedRecipients()) == len(recipients) for recipient in recipients: - assert registry.isRecipientAllowed(recipient) + assert recipients_registry.isRecipientAllowed(recipient) - registry_limit, registry_period_duration = registry.getLimitParameters() + registry_limit, registry_period_duration = recipients_registry.getLimitParameters() assert registry_limit == limit assert registry_period_duration == period - assert registry.spendableBalance() == limit - spent_amount + assert recipients_registry.spendableBalance() == limit - spent_amount - assert registry.hasRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, agent) - assert registry.hasRole(REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE, agent) - assert registry.hasRole(SET_PARAMETERS_ROLE, agent) - assert registry.hasRole(UPDATE_SPENT_AMOUNT_ROLE, agent) - assert registry.hasRole(DEFAULT_ADMIN_ROLE, agent) + assert recipients_registry.hasRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, agent) + assert recipients_registry.hasRole(REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE, agent) + assert recipients_registry.hasRole(SET_PARAMETERS_ROLE, agent) + assert recipients_registry.hasRole(UPDATE_SPENT_AMOUNT_ROLE, agent) + assert recipients_registry.hasRole(DEFAULT_ADMIN_ROLE, agent) - assert registry.hasRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, evm_script_executor) - assert registry.hasRole( + assert recipients_registry.hasRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, evm_script_executor) + assert recipients_registry.hasRole( REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE, evm_script_executor ) - assert registry.hasRole(UPDATE_SPENT_AMOUNT_ROLE, evm_script_executor) - assert not registry.hasRole(SET_PARAMETERS_ROLE, evm_script_executor) - assert not registry.hasRole(DEFAULT_ADMIN_ROLE, evm_script_executor) + assert recipients_registry.hasRole(UPDATE_SPENT_AMOUNT_ROLE, evm_script_executor) + assert not recipients_registry.hasRole(SET_PARAMETERS_ROLE, evm_script_executor) + assert not recipients_registry.hasRole(DEFAULT_ADMIN_ROLE, evm_script_executor) - assert not registry.hasRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, registry_address) - assert not registry.hasRole( - REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE, registry_address + assert not recipients_registry.hasRole(ADD_RECIPIENT_TO_ALLOWED_LIST_ROLE, recipients_registry_address) + assert not recipients_registry.hasRole( + REMOVE_RECIPIENT_FROM_ALLOWED_LIST_ROLE, recipients_registry_address ) - assert not registry.hasRole(SET_PARAMETERS_ROLE, registry_address) - assert not registry.hasRole(UPDATE_SPENT_AMOUNT_ROLE, registry_address) - assert not registry.hasRole(DEFAULT_ADMIN_ROLE, registry_address) + assert not recipients_registry.hasRole(SET_PARAMETERS_ROLE, recipients_registry_address) + assert not recipients_registry.hasRole(UPDATE_SPENT_AMOUNT_ROLE, recipients_registry_address) + assert not recipients_registry.hasRole(DEFAULT_ADMIN_ROLE, recipients_registry_address) + assert tokens_registry.hasRole(ADD_TOKEN_TO_ALLOWED_LIST_ROLE, agent) + assert tokens_registry.hasRole(REMOVE_TOKEN_FROM_ALLOWED_LIST_ROLE, agent) + + assert not tokens_registry.hasRole(ADD_TOKEN_TO_ALLOWED_LIST_ROLE, tokens_registry_address) + assert not tokens_registry.hasRole(REMOVE_TOKEN_FROM_ALLOWED_LIST_ROLE, tokens_registry_address) def test_deploy_deploy_single_recipient_top_up_only_setup( allowed_recipients_builder, @@ -407,6 +415,7 @@ def test_deploy_deploy_single_recipient_top_up_only_setup( stranger, evm_script_executor, AllowedRecipientsRegistry, + AllowedTokensRegistry, TopUpAllowedRecipients, ): @@ -423,6 +432,9 @@ def test_deploy_deploy_single_recipient_top_up_only_setup( registry_address = tx.events["AllowedRecipientsRegistryDeployed"][ "allowedRecipientsRegistry" ] + tokens_registry_address = tx.events["AllowedTokensRegistryDeployed"][ + "allowedTokensRegistry" + ] top_up_address = tx.events["TopUpAllowedRecipientsDeployed"][ "topUpAllowedRecipients" ] @@ -430,13 +442,15 @@ def test_deploy_deploy_single_recipient_top_up_only_setup( registry = Contract.from_abi( "AllowedRecipientsRegistry", registry_address, AllowedRecipientsRegistry.abi ) + tokens_registry = Contract.from_abi( + "AllowedTokensRegistry", tokens_registry_address, AllowedTokensRegistry.abi + ) top_up_allowed_recipients = Contract.from_abi( "TopUpAllowedRecipients", top_up_address, TopUpAllowedRecipients.abi ) assert top_up_allowed_recipients.allowedRecipientsRegistry() == registry - assert top_up_allowed_recipients.token() == ldo assert len(registry.getAllowedRecipients()) == 1 assert registry.isRecipientAllowed(recipient) @@ -468,3 +482,9 @@ def test_deploy_deploy_single_recipient_top_up_only_setup( assert not registry.hasRole(SET_PARAMETERS_ROLE, registry_address) assert not registry.hasRole(UPDATE_SPENT_AMOUNT_ROLE, registry_address) assert not registry.hasRole(DEFAULT_ADMIN_ROLE, registry_address) + + assert tokens_registry.hasRole(ADD_TOKEN_TO_ALLOWED_LIST_ROLE, agent) + assert tokens_registry.hasRole(REMOVE_TOKEN_FROM_ALLOWED_LIST_ROLE, agent) + + assert not tokens_registry.hasRole(ADD_TOKEN_TO_ALLOWED_LIST_ROLE, tokens_registry_address) + assert not tokens_registry.hasRole(REMOVE_TOKEN_FROM_ALLOWED_LIST_ROLE, tokens_registry_address) diff --git a/tests/test_allowed_tokens_registry.py b/tests/test_allowed_tokens_registry.py index c9521b21..1e2e8301 100644 --- a/tests/test_allowed_tokens_registry.py +++ b/tests/test_allowed_tokens_registry.py @@ -231,14 +231,14 @@ def test_normalize_amount(allowed_tokens_registry): registry.normalizeAmount(1, ZERO_ADDRESS) - amount1 = 1000000000000000000 + amount1 = 1000000000000000999 assert registry.normalizeAmount(amount1, erc20decimals18) == amount1 erc20decimals21 = MockERC20.deploy(21, {"from": accounts[0]}) - amount2 = 1000000000000000000000 + amount2 = 1000000000000000999000 assert registry.normalizeAmount(amount2, erc20decimals21) == amount1 assert registry.normalizeAmount(amount2 + 1, erc20decimals21) == amount1 + 1 erc20decimals12 = MockERC20.deploy(12, {"from": accounts[0]}) - amount3 = 1000000000000 # 1 token with 12 decimals - assert registry.normalizeAmount(amount3, erc20decimals12) == amount1 + amount3 = 1000000000009 + assert registry.normalizeAmount(amount3, erc20decimals12) == 1000000000009000000 diff --git a/utils/lido.py b/utils/lido.py index b425dd56..59eb0b29 100644 --- a/utils/lido.py +++ b/utils/lido.py @@ -40,11 +40,13 @@ def addresses(network=DEFAULT_NETWORK): def external_contracts(network=DEFAULT_NETWORK): if network == "mainnet" or network == "mainnet-fork": return { - "usdc": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" + "usdc": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "dai": "0x6B175474E89094C44Da98b954EedeAC495271d0F", } if network == "goerli" or network == "goerli-fork": return { - "usdc": "0x07865c6E87B9F70255377e024ace6630C1Eaa37F" + "usdc": "0x07865c6E87B9F70255377e024ace6630C1Eaa37F", + "dai": "0x56340274fB5a72af1A3C6609061c451De7961Bd4", } raise NameError( f"""Unknown network "{network}". Supported networks: mainnet, mainnet-fork goerli, goerli-fork"""