-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ET factories for stablecoins #58
base: develop
Are you sure you want to change the base?
Changes from 1 commit
a3e9ac3
a7eafa7
0b1e3b3
425f4a2
7e467c2
733ef7c
feb440d
480c3f1
9e4f813
f4efe8e
3b718ad
52b1b1d
35b01d1
19e760e
bf6c9c5
1c8f7c1
f6bf883
f081888
d8fcc33
00305fe
afbd0df
e385d5d
b4c77ca
c176cb1
e1f84d6
363e6d6
cb09953
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ import "./EVMScriptFactories/AddAllowedRecipient.sol"; | |
import "./EVMScriptFactories/RemoveAllowedRecipient.sol"; | ||
import "./EVMScriptFactories/TopUpAllowedRecipients.sol"; | ||
import "./AllowedRecipientsRegistry.sol"; | ||
import "./AllowedTokensRegistry.sol"; | ||
|
||
/// @author bulbozaur | ||
/// @notice Factory for Allowed Recipient Easy Track contracts | ||
|
@@ -22,11 +23,20 @@ contract AllowedRecipientsFactory { | |
IBokkyPooBahsDateTimeContract bokkyPooBahsDateTimeContract | ||
); | ||
|
||
event AllowedTokensRegistryDeployed( | ||
address indexed creator, | ||
address indexed allowedTokensRegistry, | ||
address _defaultAdmin, | ||
address[] addTokenToAllowedListRoleHolders, | ||
address[] removeTokenFromAllowedListRoleHolders | ||
); | ||
|
||
event TopUpAllowedRecipientsDeployed( | ||
address indexed creator, | ||
address indexed topUpAllowedRecipients, | ||
address trustedCaller, | ||
address allowedRecipientsRegistry, | ||
address allowedTokenssRegistry, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. typo |
||
address finance, | ||
address token, | ||
address easyTrack | ||
|
@@ -75,16 +85,38 @@ contract AllowedRecipientsFactory { | |
); | ||
} | ||
|
||
function deployAllowedTokensRegistry( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
address _defaultAdmin, | ||
address[] memory _addTokensToAllowedListRoleHolders, | ||
address[] memory _removeTokensFromAllowedListRoleHolders | ||
) public returns (AllowedTokensRegistry registry) { | ||
registry = new AllowedTokensRegistry( | ||
_defaultAdmin, | ||
_addTokensToAllowedListRoleHolders, | ||
_removeTokensFromAllowedListRoleHolders | ||
); | ||
|
||
emit AllowedTokensRegistryDeployed( | ||
msg.sender, | ||
address(registry), | ||
_defaultAdmin, | ||
_addTokensToAllowedListRoleHolders, | ||
_removeTokensFromAllowedListRoleHolders | ||
); | ||
} | ||
|
||
|
||
function deployTopUpAllowedRecipients( | ||
address _trustedCaller, | ||
address _allowedRecipientsRegistry, | ||
address _allowedTokensRegistry, | ||
address _token, | ||
address _finance, | ||
address _easyTrack | ||
) public returns (TopUpAllowedRecipients topUpAllowedRecipients) { | ||
topUpAllowedRecipients = new TopUpAllowedRecipients( | ||
_trustedCaller, | ||
_allowedRecipientsRegistry, | ||
_allowedTokensRegistry, | ||
_finance, | ||
_token, | ||
_easyTrack | ||
|
@@ -95,6 +127,7 @@ contract AllowedRecipientsFactory { | |
address(topUpAllowedRecipients), | ||
_trustedCaller, | ||
_allowedRecipientsRegistry, | ||
_allowedTokensRegistry, | ||
_finance, | ||
_token, | ||
_easyTrack | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
// SPDX-FileCopyrightText: 2022 Lido <[email protected]> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. old copyright (not only in this file) |
||
// SPDX-License-Identifier: GPL-3.0 | ||
pragma solidity ^0.8.4; | ||
|
||
import "OpenZeppelin/[email protected]/contracts/access/AccessControl.sol"; | ||
import "OpenZeppelin/[email protected]/contracts/token/ERC20/extensions/IERC20Metadata.sol"; | ||
|
||
contract AllowedTokensRegistry is AccessControl { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why not |
||
// ------------- | ||
// EVENTS | ||
// ------------- | ||
event TokenAdded(address indexed _token); | ||
event TokenRemoved(address indexed _token); | ||
|
||
// ------------- | ||
// ROLES | ||
// ------------- | ||
|
||
bytes32 public constant ADD_TOKEN_TO_ALLOWED_LIST_ROLE = keccak256("ADD_TOKEN_TO_ALLOWED_LIST_ROLE"); | ||
bytes32 public constant REMOVE_TOKEN_FROM_ALLOWED_LIST_ROLE = keccak256("REMOVE_TOKEN_FROM_ALLOWED_LIST_ROLE"); | ||
|
||
// ------------- | ||
// ERRORS | ||
// ------------- | ||
string private constant ERROR_TOKEN_ALREADY_ADDED_TO_ALLOWED_LIST = "TOKEN_ALREADY_ADDED_TO_ALLOWED_LIST"; | ||
string private constant ERROR_TOKEN_NOT_FOUND_IN_ALLOWED_LIST = "TOKEN_NOT_FOUND_IN_ALLOWED_LIST"; | ||
string private constant ERROR_TOKEN_ADDRESS_IS_ZERO = "TOKEN_ADDRESS_IS_ZERO"; | ||
|
||
// ------------- | ||
// VARIABLES | ||
// ------------- | ||
/// @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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the comment is misleading a bit (the definition is close to 'total supply') |
||
uint8 public constant PRECISION = 18; | ||
rkolpakov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
constructor( | ||
address _admin, | ||
address[] memory _addTokenToAllowedListRoleHolders, | ||
address[] memory _removeTokenFromAllowedListRoleHolders | ||
) { | ||
_setupRole(DEFAULT_ADMIN_ROLE, _admin); | ||
for (uint256 i = 0; i < _addTokenToAllowedListRoleHolders.length; i++) { | ||
_setupRole(ADD_TOKEN_TO_ALLOWED_LIST_ROLE, _addTokenToAllowedListRoleHolders[i]); | ||
} | ||
for (uint256 i = 0; i < _removeTokenFromAllowedListRoleHolders.length; i++) { | ||
_setupRole(REMOVE_TOKEN_FROM_ALLOWED_LIST_ROLE, _removeTokenFromAllowedListRoleHolders[i]); | ||
} | ||
} | ||
|
||
// ------------- | ||
// EXTERNAL METHODS | ||
// ------------- | ||
|
||
/// @notice Adds address to list of allowed tokens for payouts | ||
function addToken(address _token) external onlyRole(ADD_TOKEN_TO_ALLOWED_LIST_ROLE) { | ||
require(_token != address(0), ERROR_TOKEN_ADDRESS_IS_ZERO); | ||
require(allowedTokenIndices[_token] == 0, ERROR_TOKEN_ALREADY_ADDED_TO_ALLOWED_LIST); | ||
|
||
allowedTokens.push(_token); | ||
allowedTokenIndices[_token] = allowedTokens.length; | ||
emit TokenAdded(_token); | ||
} | ||
|
||
/// @notice Removes address from list of allowed tokens for payouts | ||
/// @dev To delete an allowed token from the allowedTokens array in O(1), | ||
/// we swap the element to delete with the last one in the array, | ||
/// and then remove the last element (sometimes called as 'swap and pop'). | ||
function removeToken(address _token) external onlyRole(REMOVE_TOKEN_FROM_ALLOWED_LIST_ROLE) { | ||
uint256 index = _getAllowedTokenIndex(_token); | ||
uint256 lastIndex = allowedTokens.length - 1; | ||
|
||
if (index != lastIndex) { | ||
address lastAllowedToken = allowedTokens[lastIndex]; | ||
allowedTokens[index] = lastAllowedToken; | ||
allowedTokenIndices[lastAllowedToken] = index + 1; | ||
} | ||
|
||
allowedTokens.pop(); | ||
delete allowedTokenIndices[_token]; | ||
emit TokenRemoved(_token); | ||
} | ||
|
||
/// @notice Returns if passed address is listed as allowed token in the registry | ||
function isTokenAllowed(address _token) external view returns (bool) { | ||
return allowedTokenIndices[_token] > 0; | ||
} | ||
|
||
/// @notice Returns current list of allowed tokens | ||
function getAllowedTokens() external view returns (address[] memory) { | ||
return allowedTokens; | ||
} | ||
|
||
/// @notice Transforms amout from token format to precise format | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. typo 'amout' |
||
function normalizeAmount(uint256 _tokenAmount, address _token) external view returns (uint256) { | ||
require(_token != address(0), ERROR_TOKEN_ADDRESS_IS_ZERO); | ||
|
||
uint8 tokenDecimals = IERC20Metadata(_token).decimals(); | ||
rkolpakov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if (tokenDecimals == PRECISION) return _tokenAmount; | ||
if (tokenDecimals > PRECISION) { | ||
uint256 difference = tokenDecimals - PRECISION; | ||
rkolpakov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
uint256 remainder = _tokenAmount % (10 ** difference); | ||
uint256 quotient = _tokenAmount / (10 ** difference); | ||
if (remainder > 0) { | ||
quotient += 1; | ||
} | ||
return quotient; | ||
} | ||
return _tokenAmount * 10 ** (PRECISION - tokenDecimals); | ||
} | ||
|
||
// ------------------ | ||
// PRIVATE METHODS | ||
// ------------------ | ||
|
||
function _getAllowedTokenIndex(address _token) private view returns (uint256 _index) { | ||
_index = allowedTokenIndices[_token]; | ||
require(_index > 0, ERROR_TOKEN_NOT_FOUND_IN_ALLOWED_LIST); | ||
_index -= 1; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// SPDX-FileCopyrightText: 2021 Lido <[email protected]> | ||
// SPDX-License-Identifier: GPL-3.0 | ||
|
||
pragma solidity ^0.8.4; | ||
|
||
contract MockERC20 { | ||
|
||
uint8 public decimals; | ||
|
||
constructor(uint8 _decimals) { | ||
decimals = _decimals; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// SPDX-License-Identifier: MIT | ||
|
||
pragma solidity ^0.8.0; | ||
|
||
/** | ||
* @dev Interface of the ERC20 standard as defined in the EIP. | ||
*/ | ||
interface IERC20 { | ||
/** | ||
* @dev Returns the amount of tokens in existence. | ||
*/ | ||
function totalSupply() external view returns (uint256); | ||
|
||
/** | ||
* @dev Returns the amount of tokens owned by `account`. | ||
*/ | ||
function balanceOf(address account) external view returns (uint256); | ||
|
||
/** | ||
* @dev Moves `amount` tokens from the caller's account to `recipient`. | ||
* | ||
* Returns a boolean value indicating whether the operation succeeded. | ||
* | ||
* Emits a {Transfer} event. | ||
*/ | ||
function transfer(address recipient, uint256 amount) external returns (bool); | ||
|
||
/** | ||
* @dev Returns the remaining number of tokens that `spender` will be | ||
* allowed to spend on behalf of `owner` through {transferFrom}. This is | ||
* zero by default. | ||
* | ||
* This value changes when {approve} or {transferFrom} are called. | ||
*/ | ||
function allowance(address owner, address spender) external view returns (uint256); | ||
|
||
/** | ||
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens. | ||
* | ||
* Returns a boolean value indicating whether the operation succeeded. | ||
* | ||
* IMPORTANT: Beware that changing an allowance with this method brings the risk | ||
* that someone may use both the old and the new allowance by unfortunate | ||
* transaction ordering. One possible solution to mitigate this race | ||
* condition is to first reduce the spender's allowance to 0 and set the | ||
* desired value afterwards: | ||
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 | ||
* | ||
* Emits an {Approval} event. | ||
*/ | ||
function approve(address spender, uint256 amount) external returns (bool); | ||
|
||
/** | ||
* @dev Moves `amount` tokens from `sender` to `recipient` using the | ||
* allowance mechanism. `amount` is then deducted from the caller's | ||
* allowance. | ||
* | ||
* Returns a boolean value indicating whether the operation succeeded. | ||
* | ||
* Emits a {Transfer} event. | ||
*/ | ||
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); | ||
|
||
/** | ||
* @dev Emitted when `value` tokens are moved from one account (`from`) to | ||
* another (`to`). | ||
* | ||
* Note that `value` may be zero. | ||
*/ | ||
event Transfer(address indexed from, address indexed to, uint256 value); | ||
|
||
/** | ||
* @dev Emitted when the allowance of a `spender` for an `owner` is set by | ||
* a call to {approve}. `value` is the new allowance. | ||
*/ | ||
event Approval(address indexed owner, address indexed spender, uint256 value); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there some
memory[]
external func args left still