-
Notifications
You must be signed in to change notification settings - Fork 369
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
Added adapters mappings and helpers #10910
Changes from 8 commits
ad6c956
5dd80a9
d6ebd5f
04d055a
f491391
4d39bb6
3c72fa6
d51a58f
7ffdbba
89cdd27
bea8ee7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,10 +20,17 @@ contract FeeCurrencyWhitelist is | |
{ | ||
// Array of all the tokens enabled | ||
address[] public whitelist; | ||
// it is not enforce that underlyingTokens in the same order as their underlying | ||
martinvol marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// whitelisted address | ||
address[] public underlyingTokens; | ||
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. We could make this AddressSet which would allow to add underlyingTokens directly in setAdaptor rather than have special method for it 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. This will not work if we want to have multiple adapters for one token .. 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. I'd rather not update this to 0.8 and leave as is 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 problem with current approach is that it is rather manual. You can setAdapter and you can forget to setUnderlyingToken which will result in inconsistent behaviour. If we will introduce AddressSet instead of array, then we can remove 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. I can make setAdapter also set the underlying token, so it's one call and there's no chance for error. 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. And regarding this will not work for more than a token, yes, that's correct. But in reality I don't see how we could have more than one adaptor for a token, |
||
mapping(address => address) public adapters; | ||
|
||
event FeeCurrencyWhitelisted(address token); | ||
|
||
event FeeCurrencyWhitelistRemoved(address token); | ||
event AdaptorSet(address underlyingToken, address adapter); | ||
event UnderlyinTokenSet(address underlyingToken); | ||
event UnderlyinTokenRemoved(address underlyingToken); | ||
|
||
/** | ||
* @notice Sets initialized == true on implementation contracts | ||
|
@@ -46,7 +53,51 @@ contract FeeCurrencyWhitelist is | |
* @return Patch version of the contract. | ||
*/ | ||
function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) { | ||
return (1, 1, 1, 0); | ||
return (1, 1, 2, 0); | ||
} | ||
|
||
// removed with address zero | ||
function setAdaptor(address token, address adaptor) external onlyOwner { | ||
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. We should also be able to remove Adapter 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. you can set it to zero 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. it is not the same though ... it will not remove it from the storage |
||
adapters[token] = adaptor; | ||
emit AdaptorSet(token, adaptor); | ||
} | ||
|
||
// TODO make external | ||
function getAdaptor(address underlyingToken) public view returns(address){ | ||
martinvol marked this conversation as resolved.
Show resolved
Hide resolved
|
||
address result = adapters[underlyingToken]; | ||
return (result != address(0))? result: underlyingToken; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in this case the if i call getAdaptor with an random address the random address will be returned. from what we said last night we wanted to restrict to valid ones right? 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. It's actually hard to check now if something is or not a whitelisted gas fee address as it's an array and not a mapping. You'll get that but it doesn't mean anything. 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. fair enough. In that case Id argue it should return address(0) when nothing is found. The method is getAdapter() so it returning null when either address is wrong or when address does not need work is intuitive. |
||
|
||
function setUnderlyinToken(address tokenAddress) external onlyOwner() { | ||
underlyingTokens.push(tokenAddress); | ||
emit UnderlyinTokenSet(tokenAddress); | ||
} | ||
|
||
function getUnderlyingTokens() external view returns(address[] memory){ | ||
return underlyingTokens; | ||
} | ||
|
||
// TODO when this contracts gets moved to Solidity 0.8 it should | ||
// return an array of tuples | ||
// secuence of underlyingtoken and it's corresponding adapter | ||
function getWhitelistUnderlyngPairs() external view returns(address[] memory){ | ||
martinvol marked this conversation as resolved.
Show resolved
Hide resolved
|
||
uint256 outLenght = underlyingTokens.length*2; | ||
address[] memory result = new address[](outLenght); | ||
|
||
for (uint256 i=0; i < underlyingTokens.length; i++){ | ||
address underlyingToken = underlyingTokens[i]; | ||
result[i*2] = getAdaptor(underlyingToken); | ||
result[(i*2)+1] = underlyingToken; | ||
} | ||
return result; | ||
} | ||
|
||
function removeUnderlyinTokens(address tokenAddress, uint256 index) external onlyOwner { | ||
require(underlyingTokens[index] == tokenAddress, "Index does not match"); | ||
uint256 length = underlyingTokens.length; | ||
underlyingTokens[index] = underlyingTokens[length - 1]; | ||
underlyingTokens.pop(); | ||
emit UnderlyinTokenRemoved(tokenAddress); | ||
} | ||
|
||
/** | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.5.13; | ||
|
||
import "celo-foundry/Test.sol"; | ||
import "../../contracts/common/FeeCurrencyWhitelist.sol"; | ||
|
||
contract FeeCurrencyWhitelistTest is Test { | ||
FeeCurrencyWhitelist feeCurrencyWhitelist; | ||
address nonOwner; | ||
address owner; | ||
|
||
function setUp() public { | ||
owner = address(this); | ||
nonOwner = actor("nonOwner"); | ||
|
||
feeCurrencyWhitelist = new FeeCurrencyWhitelist(true); | ||
feeCurrencyWhitelist.initialize(); | ||
} | ||
} | ||
|
||
contract FeeCurrencyWhitelistInitialize is FeeCurrencyWhitelistTest { | ||
function test_InitializeOwner() public { | ||
assertTrue(feeCurrencyWhitelist.isOwner()); | ||
assertEq(feeCurrencyWhitelist.owner(), address(this)); | ||
} | ||
|
||
function test_ShouldNotBeCallableAgain() public { | ||
vm.expectRevert("contract already initialized"); | ||
feeCurrencyWhitelist.initialize(); | ||
} | ||
} | ||
|
||
contract FeeCurrencyWhitelist_adaptedTokens is FeeCurrencyWhitelistTest{ | ||
address whitelistedAddress1 = address(1); | ||
address whitelistedAddress2 = address(2); | ||
address whitelistedAddress3 = address(3); | ||
|
||
address token1 = address(4); | ||
address token2 = address(5); | ||
|
||
function setUp() public { | ||
|
||
super.setUp(); | ||
|
||
feeCurrencyWhitelist.addToken(whitelistedAddress1); // real token | ||
feeCurrencyWhitelist.addToken(whitelistedAddress2); // adaptor of token 1 | ||
feeCurrencyWhitelist.addToken(whitelistedAddress3); // adaptor of token 2 | ||
|
||
feeCurrencyWhitelist.setUnderlyinToken(whitelistedAddress1); | ||
feeCurrencyWhitelist.setUnderlyinToken(token1); | ||
feeCurrencyWhitelist.setUnderlyinToken(token2); | ||
|
||
feeCurrencyWhitelist.setAdaptor(token1, whitelistedAddress2); | ||
|
||
} | ||
} | ||
|
||
contract FeeCurrencyWhitelist_setAdaptor is FeeCurrencyWhitelist_adaptedTokens { | ||
event AdaptorSet(address underlyingToken, address adapter); | ||
function test_geTokenForVanillaGasCurrency() public{ | ||
// should be the same, it doesn't require addaptor | ||
assertEq(feeCurrencyWhitelist.getAdaptor(whitelistedAddress1), whitelistedAddress1); | ||
} | ||
|
||
function test_geTokenForAdaptedGasCurrency() public{ | ||
// should be the same, it doesn't require addaptor | ||
assertEq(feeCurrencyWhitelist.getAdaptor(token1), whitelistedAddress2); | ||
} | ||
|
||
function test_Reverts_WhenNonOwnerAddsAToken() public { | ||
vm.expectRevert("Ownable: caller is not the owner"); | ||
vm.prank(nonOwner); | ||
feeCurrencyWhitelist.setAdaptor(token2, whitelistedAddress3); | ||
} | ||
|
||
function test_ShouldEmitAdaptorSet() public { | ||
vm.expectEmit(true, true, true, true); | ||
emit AdaptorSet(token2, whitelistedAddress3); | ||
feeCurrencyWhitelist.setAdaptor(token2, whitelistedAddress3); | ||
} | ||
} | ||
|
||
contract FeeCurrencyWhitelist_setUnderlyinTokens is FeeCurrencyWhitelist_adaptedTokens { | ||
event UnderlyinTokenSet(address underlyingToken); | ||
|
||
function test_ShouldReturnUnderlyingToken() external { | ||
address[3] memory addresses = [whitelistedAddress1, token1, token2]; | ||
address[] memory results = feeCurrencyWhitelist.getUnderlyingTokens(); | ||
|
||
// TODO forge has a helper for comparing arrays? | ||
assertEq(results.length, addresses.length); | ||
for (uint256 i=0; i<results.length; i++){ | ||
assertEq(results[i], addresses[i]); | ||
} | ||
} | ||
|
||
function test_ShouldEmitUnderlyinTokenSet() public { | ||
vm.expectEmit(true, true, true, true); | ||
emit UnderlyinTokenSet(token1); | ||
feeCurrencyWhitelist.setUnderlyinToken(token1); | ||
} | ||
|
||
function test_Reverts_WhenNonOwnerSetsUnderlyinTokenn() public { | ||
vm.expectRevert("Ownable: caller is not the owner"); | ||
vm.prank(nonOwner); | ||
feeCurrencyWhitelist.setUnderlyinToken(token1); | ||
} | ||
} | ||
|
||
contract FeeCurrencyWhitelist_removeUnderlyinTokens is FeeCurrencyWhitelist_adaptedTokens { | ||
event UnderlyinTokenRemoved(address underlyingToken); | ||
|
||
function test_ShouldRemoveToken() public { | ||
feeCurrencyWhitelist.removeUnderlyinTokens(token1, 1); | ||
address[] memory result = feeCurrencyWhitelist.getUnderlyingTokens(); | ||
assertEq(result.length, 2); | ||
assertEq(result[0], whitelistedAddress1); | ||
assertEq(result[1], token2); | ||
} | ||
|
||
function test_ShouldEmitUnderlyinTokenRemoved() public { | ||
vm.expectEmit(true, true, true, true); | ||
emit UnderlyinTokenRemoved(token1); | ||
feeCurrencyWhitelist.removeUnderlyinTokens(token1, 1); | ||
} | ||
|
||
function test_ShouldRevert_WhenIndexIsWrong() public { | ||
vm.expectRevert("Index does not match"); | ||
feeCurrencyWhitelist.removeUnderlyinTokens(token1, 2); | ||
} | ||
|
||
function test_ShouldRevert_WhenNonOwnerRemovesToken() public { | ||
vm.expectRevert("Ownable: caller is not the owner"); | ||
vm.prank(nonOwner); | ||
feeCurrencyWhitelist.removeUnderlyinTokens(token1, 2); | ||
} | ||
} | ||
|
||
contract FeeCurrencyWhitelist_getWhitelistUnderlyngPairs is FeeCurrencyWhitelist_adaptedTokens { | ||
|
||
function test_getsRightTouples() external { | ||
feeCurrencyWhitelist.setAdaptor(token2, whitelistedAddress3); | ||
address[6] memory addresses = [whitelistedAddress1, whitelistedAddress1, whitelistedAddress2, token1, whitelistedAddress3, token2]; | ||
address[] memory results = feeCurrencyWhitelist.getWhitelistUnderlyngPairs(); | ||
|
||
assertEq(results.length, addresses.length); | ||
for (uint256 i=0; i<results.length; i++){ | ||
assertEq(results[i], addresses[i]); | ||
|
||
} | ||
} | ||
} | ||
|
||
|
||
contract FeeCurrencyWhitelistAddToken is FeeCurrencyWhitelistTest { | ||
function test_ShouldAllowTheOwnerToAddAToken() public { | ||
feeCurrencyWhitelist.addToken(address(1)); | ||
address[] memory whitelist = feeCurrencyWhitelist.getWhitelist(); | ||
assertEq(whitelist.length, 1); | ||
assertEq(whitelist[0], address(1)); | ||
} | ||
|
||
function test_ShouldRevert_WhenNonOwnerAddsAToken() public { | ||
vm.expectRevert("Ownable: caller is not the owner"); | ||
vm.prank(nonOwner); | ||
feeCurrencyWhitelist.addToken(address(1)); | ||
} | ||
} | ||
|
||
contract FeeCurrencyWhitelistRemoveToken is FeeCurrencyWhitelistTest { | ||
function setUp() public { | ||
super.setUp(); | ||
feeCurrencyWhitelist.addToken(address(1)); | ||
feeCurrencyWhitelist.addToken(address(2)); | ||
feeCurrencyWhitelist.addToken(address(3)); | ||
} | ||
|
||
function test_ShouldRemoveToken() public { | ||
feeCurrencyWhitelist.removeToken(address(2), 1); | ||
address[] memory whitelist = feeCurrencyWhitelist.getWhitelist(); | ||
assertEq(whitelist.length, 2); | ||
assertEq(whitelist[0], address(1)); | ||
assertEq(whitelist[1], address(3)); | ||
} | ||
|
||
// TODO this test should check emits | ||
|
||
function test_ShouldRevert_WhenIndexIsWrong() public { | ||
vm.expectRevert("Index does not match"); | ||
feeCurrencyWhitelist.removeToken(address(2), 2); | ||
} | ||
|
||
function test_ShouldRevert_WhenNonOwnerRemovesToken() public { | ||
vm.expectRevert("Ownable: caller is not the owner"); | ||
vm.prank(nonOwner); | ||
feeCurrencyWhitelist.removeToken(address(2), 1); | ||
} | ||
} |
This file was deleted.
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.
I should update interface as well.