Skip to content
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

erc20 proxy deploy #115

Merged
merged 11 commits into from
Mar 27, 2024
Merged

erc20 proxy deploy #115

merged 11 commits into from
Mar 27, 2024

Conversation

mejango
Copy link
Contributor

@mejango mejango commented Mar 18, 2024

Description

Deploy ERC-20's using proxy pattern to reduce gas.

Limitations & risks

New token deploy pattern, needs to be double checked but its similar to the 721 hook implementation

Check-list

  • Tests are covering the new feature
  • Code is natspec'd
  • Code is linted and formatted
  • I have run the test locally (and they pass)
  • I have rebased to the latest main commit (and tests still pass)

Interactions

These changes will impact the following contracts:

  • Directly:

JBTokens
JBERC20

  • Indirectly:

_symbol = symbol_;

// Transfer ownership to the initializer.
_transferOwnership(owner);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of transferring to an external owner besides JBTokens?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

none ever. should always be JBTokens, but JBTokens will always send itself.

src/JBERC20.sol Outdated Show resolved Hide resolved
@@ -74,7 +74,8 @@ contract TestTokenFlow_Local is TestBaseWorkflow {
_controller.deployERC20For({projectId: _projectId, name: "TestName", symbol: "TestSymbol", salt: bytes32(0)});
} else {
// Create a new `IJBToken` and change it's owner to the `JBTokens` contract.
IJBToken _newToken = new JBERC20({name: "NewTestName", symbol: "NewTestSymbol", owner: _projectOwner});
IJBToken _newToken = new JBERC20();
_newToken.initialize({id: _projectId, name: "NewTestName", symbol: "NewTestSymbol", owner: _projectOwner});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we make changes to the impl, should we explore/test unintended uses/circumventions and ensure they fail? i.e. I don't initialize my token but transfer ownership to JBTokens, and try to configure my project with that token.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you've got a fun edge case in mind, always worth documenting with a test imo. please and thanks!

src/JBTokens.sol Outdated
? new JBERC20(name, symbol, address(this))
: new JBERC20{salt: salt}(name, symbol, address(this));
? IJBToken(Clones.clone(address(TOKEN)))
: IJBToken(Clones.cloneDeterministic(address(TOKEN), salt));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we add an
salt = keccak256(abi.encode(msg.sender, salt));

Otherwise you can steal another projects salt by configuring a controller that lets you pass any salt.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

src/JBERC20.sol Outdated
ERC20Permit(name)
Ownable(owner)
{}
constructor() Ownable(address(this)) ERC20("", "") ERC20Permit("JBToken") {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we do something like

Suggested change
constructor() Ownable(address(this)) ERC20("", "") ERC20Permit("JBToken") {}
constructor() Ownable(address(this)) ERC20("", "") ERC20Permit("JBToken") {
// Disable initialization on singleton instance.
projectId = type(uint256).max;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

srry, projectId is removed!!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps if we use DrG suggestion about using the name and/or symbol as a stop for re-initialization we can do

Suggested change
constructor() Ownable(address(this)) ERC20("", "") ERC20Permit("JBToken") {}
constructor() Ownable(address(this)) ERC20("invalid", "invalid") ERC20Permit("JBToken") {}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i hadn't pushed up my local commits... @xBA5ED review the latest and lets see if this still makes sense. we use name, but just check for empty string.

src/JBERC20.sol Outdated
/// @param owner The owner of the token.
function initialize(string memory name_, string memory symbol_, address owner) public override {
// Stop re-initialization.
if (this.owner() != address(0) || owner == address(0)) revert();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the owner calls Ownable::renounceOwnership(), then anyone can re-initialise it - rn it's ok as it should always be JBTokens the owner, but isn't a bit smelly for the long run? Why not just checking if the name/symbol are already set instead (there is no "clearNameAndSymbol()")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea!

/// @param owner The owner of the token.
function initialize(string memory name_, string memory symbol_, address owner) public override {
// Stop re-initialization.
if (bytes(_name).length != 0 || bytes(name_).length == 0) revert();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fine but had to read it twice before understanding it :D

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm good feedback. how might we improve

@mejango mejango merged commit 05836ad into main Mar 27, 2024
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants