-
Notifications
You must be signed in to change notification settings - Fork 5
[DRAFT] V1 => V2 Contract Upgrade #32
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
Merged
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
0e6b554
add withdraw to token contract, update tests to confirm function as w…
JamesEarle a1ad152
changes to add burn on receipt of ERC20 tokens in v2 contract
JamesEarle 84b585e
modifications to more logically separate for multiple upgrades
JamesEarle a78964e
Merge branch 'support/wild-v1' into feat/token-upgrade
JamesEarle c9a0671
Merge branch 'feat/token-upgrade' of https://github.com/zer0-os/ZToke…
JamesEarle 18f6387
add CI
JamesEarle 63f2b56
update packages and HH config
Whytecrowe 0480df6
add storage helpers and weave into tests
Whytecrowe 39caf74
improve testing flow, add helper to simplify deploy and transfer owner
JamesEarle ba5e48d
Merge branch 'feat/token-upgrade' into state-validation
JamesEarle 8626217
snapshot of scripts so far up to post upgrade
JamesEarle 1bad9c3
Still WIP but changes to improve reusability in helpers for both scri…
JamesEarle 48217f9
some changes and remove unused imports
JamesEarle a78b2b1
cleanup, add more comments, reorganize helpers to be in test folder, …
JamesEarle 1b3f01f
updates to improve process and clearer instructions here and in the d…
JamesEarle 3edd214
Merge pull request #34 from zer0-os/state-validation
Whytecrowe File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
version: 2.1 | ||
|
||
orbs: | ||
node: circleci/[email protected] | ||
|
||
defaults: &defaults | ||
working_directory: ~/repo | ||
docker: | ||
- image: cimg/node:20.17.0 | ||
|
||
jobs: | ||
lint and build: | ||
<<: *defaults | ||
steps: | ||
- checkout | ||
- node/install-packages: | ||
pkg-manager: yarn | ||
- run: yarn build | ||
- run: yarn lint | ||
- persist_to_workspace: | ||
root: ~/repo | ||
paths: [.] | ||
workflows: | ||
version: 2 | ||
build: | ||
jobs: | ||
- lint and build |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,7 @@ bin | |
cache | ||
artifacts | ||
typechain/ | ||
.env | ||
*.env* | ||
|
||
# OpenZeppelin | ||
.openzeppelin/dev-*.json | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// SPDX-License-Identifier: MIT | ||
/* solhint-disable */ | ||
pragma solidity ^0.8.3; | ||
|
||
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | ||
|
||
/** | ||
* @title ERC20Mock | ||
* @dev Mock contract for testing purposes, allowing minting of tokens. Used as mock of MEOW token, | ||
* which is the main payment token in ZNS. | ||
*/ | ||
contract ERC20Mock is ERC20 { | ||
constructor( | ||
string memory name_, | ||
string memory symbol_ | ||
) ERC20(name_, symbol_) {} | ||
|
||
function mint(address account, uint256 amount) public { | ||
_mint(account, amount); | ||
} | ||
|
||
function decimals() public pure override returns (uint8) { | ||
return 6; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,259 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.3; | ||
|
||
// Slight modifiations from base Open Zeppelin Contracts | ||
// Consult /oz/README.md for more information | ||
import "./oz/ERC20Upgradeable.sol"; | ||
import "./oz/ERC20SnapshotUpgradeable.sol"; | ||
import "./oz/ERC20PausableUpgradeable.sol"; | ||
|
||
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; | ||
import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | ||
|
||
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; | ||
|
||
contract ZeroDAOTokenV2 is | ||
OwnableUpgradeable, | ||
ERC20Upgradeable, | ||
ERC20PausableUpgradeable, | ||
ERC20SnapshotUpgradeable | ||
{ | ||
using SafeERC20 for IERC20; | ||
|
||
event AuthorizedSnapshotter(address account); | ||
event DeauthorizedSnapshotter(address account); | ||
event ERC20TokenWithdrawn( | ||
IERC20 indexed token, | ||
address indexed to, | ||
uint256 indexed amount | ||
); | ||
|
||
// Mapping which stores all addresses allowed to snapshot | ||
mapping(address => bool) authorizedToSnapshot; | ||
|
||
function initialize( | ||
string memory name, | ||
string memory symbol | ||
) public initializer { | ||
__Ownable_init(); | ||
__ERC20_init(name, symbol); | ||
__ERC20Snapshot_init(); | ||
__ERC20Pausable_init(); | ||
} | ||
|
||
// Call this on the implementation contract (not the proxy) | ||
function initializeImplementation() public initializer { | ||
__Ownable_init(); | ||
_pause(); | ||
} | ||
|
||
/** | ||
* Mints new tokens. | ||
* @param account the account to mint the tokens for | ||
* @param amount the amount of tokens to mint. | ||
*/ | ||
function mint(address account, uint256 amount) external onlyOwner { | ||
_mint(account, amount); | ||
} | ||
|
||
/** | ||
* Burns tokens from an address. | ||
* @param account the account to mint the tokens for | ||
* @param amount the amount of tokens to mint. | ||
*/ | ||
function burn(address account, uint256 amount) external onlyOwner { | ||
JamesEarle marked this conversation as resolved.
Show resolved
Hide resolved
|
||
_burn(account, amount); | ||
} | ||
|
||
/** | ||
* Pauses the token contract preventing any token mint/transfer/burn operations. | ||
* Can only be called if the contract is unpaused. | ||
*/ | ||
function pause() external onlyOwner { | ||
_pause(); | ||
} | ||
|
||
/** | ||
* Unpauses the token contract preventing any token mint/transfer/burn operations | ||
* Can only be called if the contract is paused. | ||
*/ | ||
function unpause() external onlyOwner { | ||
_unpause(); | ||
} | ||
|
||
/** | ||
* Creates a token balance snapshot. Ideally this would be called by the | ||
* controlling DAO whenever a proposal is made. | ||
*/ | ||
function snapshot() external returns (uint256) { | ||
require( | ||
authorizedToSnapshot[_msgSender()] || _msgSender() == owner(), | ||
"zDAOToken: Not authorized to snapshot" | ||
); | ||
return _snapshot(); | ||
} | ||
|
||
/** | ||
* Authorizes an account to take snapshots | ||
* @param account The account to authorize | ||
*/ | ||
function authorizeSnapshotter(address account) external onlyOwner { | ||
require( | ||
!authorizedToSnapshot[account], | ||
"zDAOToken: Account already authorized" | ||
); | ||
|
||
authorizedToSnapshot[account] = true; | ||
emit AuthorizedSnapshotter(account); | ||
} | ||
|
||
/** | ||
* Deauthorizes an account to take snapshots | ||
* @param account The account to de-authorize | ||
*/ | ||
function deauthorizeSnapshotter(address account) external onlyOwner { | ||
require(authorizedToSnapshot[account], "zDAOToken: Account not authorized"); | ||
|
||
authorizedToSnapshot[account] = false; | ||
emit DeauthorizedSnapshotter(account); | ||
} | ||
|
||
/** | ||
* Withdraws ERC20 tokens that are stuck in this contract. | ||
* @param token The ERC20 token contract address to withdraw | ||
* @param to The address to send the tokens to | ||
* @param amount The amount of tokens to withdraw (0 means withdraw all available) | ||
*/ | ||
function withdrawERC20( | ||
IERC20 token, | ||
address to, | ||
uint256 amount | ||
) external onlyOwner { | ||
require( | ||
address(token) != address(0), | ||
"zDAOToken: Token address cannot be zero" | ||
); | ||
require( | ||
address(token) != address(this), | ||
"zDAOToken: Token address cannot be this token" | ||
); | ||
require(to != address(0), "zDAOToken: Recipient address cannot be zero"); | ||
|
||
uint256 withdrawAmount; | ||
if (amount == 0) { | ||
// If amount is 0, withdraw all available tokens | ||
withdrawAmount = token.balanceOf(address(this)); | ||
} else { | ||
// Otherwise, ensure the requested amount doesn't exceed the contract's balance | ||
withdrawAmount = amount; | ||
} | ||
|
||
token.safeTransfer(to, withdrawAmount); | ||
|
||
emit ERC20TokenWithdrawn(token, to, withdrawAmount); | ||
} | ||
|
||
/** | ||
* Utility function to transfer tokens to many addresses at once. | ||
* @param recipients The addresses to send tokens to | ||
* @param amount The amount of tokens to send | ||
* @return Boolean if the transfer was a success | ||
*/ | ||
function transferBulk( | ||
address[] calldata recipients, | ||
uint256 amount | ||
) external returns (bool) { | ||
address sender = _msgSender(); | ||
|
||
uint256 total = amount * recipients.length; | ||
require( | ||
_balances[sender] >= total, | ||
"ERC20: transfer amount exceeds balance" | ||
); | ||
|
||
require(!paused(), "ERC20Pausable: token transfer while paused"); | ||
|
||
_balances[sender] -= total; | ||
_updateAccountSnapshot(sender); | ||
|
||
for (uint256 i = 0; i < recipients.length; ++i) { | ||
address recipient = recipients[i]; | ||
require(recipient != address(0), "ERC20: transfer to the zero address"); | ||
|
||
// Note: _beforeTokenTransfer isn't called here | ||
// This function emulates what it would do (paused and snapshot) | ||
|
||
_balances[recipient] += amount; | ||
|
||
_updateAccountSnapshot(recipient); | ||
|
||
emit Transfer(sender, recipient, amount); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Utility function to transfer tokens to many addresses at once. | ||
* @param sender The address to send the tokens from | ||
* @param recipients The addresses to send tokens to | ||
* @param amount The amount of tokens to send | ||
* @return Boolean if the transfer was a success | ||
*/ | ||
function transferFromBulk( | ||
address sender, | ||
address[] calldata recipients, | ||
uint256 amount | ||
) external returns (bool) { | ||
require(!paused(), "ERC20Pausable: token transfer while paused"); | ||
|
||
uint256 total = amount * recipients.length; | ||
require( | ||
_balances[sender] >= total, | ||
"ERC20: transfer amount exceeds balance" | ||
); | ||
|
||
// Ensure enough allowance | ||
uint256 currentAllowance = _allowances[sender][_msgSender()]; | ||
require( | ||
currentAllowance >= total, | ||
"ERC20: transfer total exceeds allowance" | ||
); | ||
_approve(sender, _msgSender(), currentAllowance - total); | ||
|
||
_balances[sender] -= total; | ||
_updateAccountSnapshot(sender); | ||
|
||
for (uint256 i = 0; i < recipients.length; ++i) { | ||
address recipient = recipients[i]; | ||
require(recipient != address(0), "ERC20: transfer to the zero address"); | ||
|
||
// Note: _beforeTokenTransfer isn't called here | ||
// This function emulates what it would do (paused and snapshot) | ||
|
||
_balances[recipient] += amount; | ||
|
||
_updateAccountSnapshot(recipient); | ||
|
||
emit Transfer(sender, recipient, amount); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
function _beforeTokenTransfer( | ||
address from, | ||
address to, | ||
uint256 amount | ||
) | ||
internal | ||
virtual | ||
override( | ||
ERC20PausableUpgradeable, | ||
ERC20SnapshotUpgradeable, | ||
ERC20Upgradeable | ||
) | ||
{ | ||
super._beforeTokenTransfer(from, to, amount); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.