Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
rkolpakov committed Oct 8, 2023
1 parent a3e9ac3 commit 1937717
Show file tree
Hide file tree
Showing 15 changed files with 403 additions and 325 deletions.
188 changes: 77 additions & 111 deletions contracts/AllowedRecipientsBuilder.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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 {
Expand Down Expand Up @@ -85,7 +53,6 @@ interface IAllowedRecipientsFactory {
address _trustedCaller,
address _allowedRecipientsRegistry,
address _allowedTokensRegistry,
address _token,
address _finance,
address _easyTrack
) external returns (ITopUpAllowedRecipients topUpAllowedRecipients);
Expand Down Expand Up @@ -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");

Expand All @@ -166,7 +132,7 @@ contract AllowedRecipientsBuilder {
updateSpentAmountRoleHolders[1] = evmScriptExecutor;
updateSpentAmountRoleHolders[2] = address(this);

recipientRegistry = factory.deployAllowedRecipientsRegistry(
registry = factory.deployAllowedRecipientsRegistry(
admin,
addRecipientToAllowedListRoleHolders,
removeRecipientFromAllowedListRoleHolders,
Expand All @@ -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)
Expand Down Expand Up @@ -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));

Expand All @@ -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));
}
}
4 changes: 0 additions & 4 deletions contracts/AllowedRecipientsFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ contract AllowedRecipientsFactory {
address allowedRecipientsRegistry,
address allowedTokenssRegistry,
address finance,
address token,
address easyTrack
);

Expand Down Expand Up @@ -109,7 +108,6 @@ contract AllowedRecipientsFactory {
address _trustedCaller,
address _allowedRecipientsRegistry,
address _allowedTokensRegistry,
address _token,
address _finance,
address _easyTrack
) public returns (TopUpAllowedRecipients topUpAllowedRecipients) {
Expand All @@ -118,7 +116,6 @@ contract AllowedRecipientsFactory {
_allowedRecipientsRegistry,
_allowedTokensRegistry,
_finance,
_token,
_easyTrack
);

Expand All @@ -129,7 +126,6 @@ contract AllowedRecipientsFactory {
_allowedRecipientsRegistry,
_allowedTokensRegistry,
_finance,
_token,
_easyTrack
);

Expand Down
17 changes: 11 additions & 6 deletions contracts/AllowedTokensRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -102,17 +102,22 @@ 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) {
quotient += 1;
}
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;
}

// ------------------
Expand Down
Loading

0 comments on commit 1937717

Please sign in to comment.