feat(wrapper-registry): adding wrapper-registry#50
Conversation
| * @title Wrapper Registry Interface | ||
| * @notice Interface for storing Wrapper addresses for tokens. Tokens are stored in bijection. | ||
| */ | ||
| interface IWrapperRegistry { |
There was a problem hiding this comment.
Nice and clean interface definition 👍
| override | ||
| returns (address) | ||
| { | ||
| for (uint256 i = 0; i < numWrappers(); i++) { |
There was a problem hiding this comment.
You could just invoke IWrapper(wrapper).underlying()? (which is one external storage read, rather than n internal reads)
There was a problem hiding this comment.
I guess this function also had the purpose of validating that the underlying<->wrapper entry was present in the registry. Since IWrapper already has that functionality, it might actually be redundant to include this function at all. Thoughts?
There was a problem hiding this comment.
I'd elect to remove. You could determine if the wrapper was already in the registry with a staticcall to addWrapper
| /** | ||
| * @dev Mapping of underlying tokens to wrapper tokens | ||
| */ | ||
| mapping(address => address) private _wrapperMapping; |
There was a problem hiding this comment.
You can make the _underlyingToWrapperMapping an EnumerableMap instead of the regular mapping and get rid of the _underlyingTokens address set.
https://docs.openzeppelin.com/contracts/3.x/api/utils#EnumerableMap
That should still accomplish what you want ie):
- O(1) add, remove and existence checks for underlying tokens
- O(n) enumeration
There was a problem hiding this comment.
@aalavandhan, I believe EnumerableMap currently only has support for UintToAddressMap. That's the reason why I use both EnumerableSet and mapping to achieve the same goal.
| override | ||
| returns (address) | ||
| { | ||
| for (uint256 i = 0; i < numWrappers(); i++) { |
There was a problem hiding this comment.
I'd elect to remove. You could determine if the wrapper was already in the registry with a staticcall to addWrapper
| returns (address) | ||
| { | ||
| address underlyingToken = IButtonWrapper(wrapperToken).underlying(); | ||
| if ( |
There was a problem hiding this comment.
Is this check really required? The owner can ensure that they only add immutable wrappers so this will always be true.
There was a problem hiding this comment.
@aalavandhan This is a non-permissioned view function that operates as the opposite of getWrapperFromUnderlying. The issue of not doing the check is that you can just take any wrapper and call IButtonWrapper(wrapperToken).underlying() without confirming if the wrapper is even in the registry or not. So if AMPL has one official wrapper and one unofficial bootleg wrapper, they'll both return AMPL even though only the first one is actually in the registry.
This isn't really a problem, but I think the point is that this function also operates as a check of "is this wrapper in the registry?". Otherwise people would just call .underlying() directly on the wrapper.
Changes:
IWrapperRegistryandWrapperRegistryTesting:
Reviewers:
@marktoda
@aalavandhan
@Melvillian
@Fiddlekins
@SocksNFlops
@MichalStachnik