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

Add ERC20 token with snapshoting mechanism (#1209) #1331

Closed

Conversation

jbogacz
Copy link
Contributor

@jbogacz jbogacz commented Sep 18, 2018

🚀 Description

This pull request is based on changes introduced with frangio:feature-snapshot-token. It adds snapshoting mechanism to regular ERC20 token.

Fixes #1209

  • [+ ] 📘 I've reviewed the OpenZeppelin Contributor Guidelines
  • [ +] ✅ I've added tests where applicable to test my new functionality.
  • [ +] 📖 I've made sure that my contracts are well-documented.
  • [ +] 🎨 I've run the JS/Solidity linters and fixed any issues (npm run lint:fix).

@nventuro nventuro added feature New contracts, functions, or helpers. contracts Smart contract code. labels Sep 18, 2018
Copy link
Contributor

@frangio frangio left a comment

Choose a reason for hiding this comment

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

Awesome @jbogacz! Here's some initial comments. I'll get back to you on the tests tomorrow.

contracts/token/ERC20/ERC20Snapshot.sol Outdated Show resolved Hide resolved
contracts/token/ERC20/ERC20Snapshot.sol Outdated Show resolved Hide resolved
contracts/token/ERC20/ERC20Snapshot.sol Outdated Show resolved Hide resolved
contracts/token/ERC20/ERC20Snapshot.sol Outdated Show resolved Hide resolved
contracts/token/ERC20/ERC20Snapshot.sol Outdated Show resolved Hide resolved
contracts/token/ERC20/ERC20Snapshot.sol Show resolved Hide resolved
contracts/token/ERC20/ERC20Snapshot.sol Outdated Show resolved Hide resolved
contracts/token/ERC20/ERC20Snapshot.sol Outdated Show resolved Hide resolved
contracts/utils/Arrays.sol Show resolved Hide resolved
@jbogacz
Copy link
Contributor Author

jbogacz commented Sep 21, 2018

@frangio thanks for nice code review. I will apply your comments.

Jakub Bogacz and others added 2 commits September 23, 2018 11:53
Require reason message removed
Inline documentation in NatSpec added
Snapshot added to _mint and _burn method
@jbogacz jbogacz force-pushed the fix/ERC20-token-with-snapshots-#1209 branch from 61e76c4 to 1302e6a Compare September 23, 2018 09:56
@jbogacz
Copy link
Contributor Author

jbogacz commented Sep 23, 2018

Hey, @frangio I have followed your comments and hope this time it looks better.

nventuro and others added 9 commits September 26, 2018 11:36
…lin#1329)

* release candidate v2.0.0-rc.1

* fix linter error

(cherry picked from commit c12a1c6)

* Roles now emit events in construction and when renouncing.
* Add the missing test for ERC721Holder

* fix lint

* Move the holder test to a separate file
* Removed mintingFinished from ERC20Mintable.

* Removed MintingFinished from ERC721Mintable.

* Removed MintingFinished event.
* Improved bounty tests.

* Fixed linter errors.

* Addressed review comments.
…Zeppelin#1338)

* Add BigNumber support to expectEvent/inLogs (OpenZeppelin#1026)

* switched direct logs array check to expectEvent method in AllowanceCrowdsale.test.js

* Refactor expectEvent.inLogs function to use simple value number check

* Introduced should.be.bignumber method to compare BigNumber values

* Destructure transaction object to extract logs field
* fix: refactor sign.js and related tests

* fix: remove unused dep

* fix: update package.json correctly

* Add missing tests to ECRecovery

* fix lint

* Reorganize the tests

* Reuse signature

* fix static errors

* Apply suggestions by @frangion and @nventuro

* Remove only

* More suggestions

* Remove unnecessary max-len

* remove only
…penZeppelin#1343)

* Add BigNumber support to expectEvent/inLogs (OpenZeppelin#1026)

* switched direct logs array check to expectEvent method in AllowanceCrowdsale.test.js

* Refactor expectEvent.inLogs function to use simple value number check

* Introduced should.be.bignumber method to compare BigNumber values

* Use expectEvent to test logs (OpenZeppelin#1232)

* Removed trailing space
…n#1360)

* add test for msg.data too short

* fix test to hit that branch

* Update SignatureBouncer.test.js
@nventuro nventuro self-assigned this Sep 28, 2018
Copy link
Contributor

@nventuro nventuro left a comment

Choose a reason for hiding this comment

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

Hey there @jbogacz! This is in quite a good place, except that we're missing tests for the Arrays library. How would you feel about opening a new PR with just that library (and its tests), and then continuing this one on top? That way feedback can be more focused, and we don't have to be thinking about multiple things at once :)

@jbogacz
Copy link
Contributor Author

jbogacz commented Sep 28, 2018

Yeah, @nventuro you are absolutely right! I will go for Arrays unit test first.

@nventuro
Copy link
Contributor

Great! I'll put this PR on hold then until that one is merged.

@nventuro nventuro added the on hold Put on hold for some reason that must be specified in a comment. label Sep 28, 2018
nventuro and others added 3 commits September 28, 2018 19:20
* signing prefix added

* Minor improvement

* Tests changed

* Successfully tested

* Minor improvements

* Minor improvements

* Revert "Dangling commas are now required. (OpenZeppelin#1359)"

This reverts commit a688977.

* fixes OpenZeppelin#1358

* linting done

* suggested changes
…ppelin#1368)

* signing prefix added

* Minor improvement

* Tests changed

* Successfully tested

* Minor improvements

* Minor improvements

* Revert "Dangling commas are now required. (OpenZeppelin#1359)"

This reverts commit a688977.

* fixex OpenZeppelin#1355

* linting

* suggested changes

* Update BreakInvariantBounty.test.js
@frangio
Copy link
Contributor

frangio commented Oct 1, 2018

Definitely agree with @nventuro! Let's work on Arrays first and get back to this later.

The fixes to my previous review look good!

function burn(address account, uint256 amount) public {
_burn(account, amount);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Does not include _burnFrom from the current v2 RC2 OZ

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's a mock for unit test purpose so I don't know if this even need mint and burn functions.

Copy link
Contributor

Choose a reason for hiding this comment

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

burn and mint functions (and burnFrom) impact the total supply. Which is important to keep history of for specific purposes.

Examples include:
Voting Power
Dividend Share

Which both are dependent on the ratio of held tokens at a specified time. In which knowing the total supply is necessary.

* @return An uint256 representing current snapshot id.
*/
function snapshot() external returns (uint256) {
currentSnapshotId += 1;
Copy link
Contributor

Choose a reason for hiding this comment

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

Does not utilize SafeMath

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, you are right!

function transfer(address to, uint256 value) public returns (bool) {
updateSnapshot(msg.sender);
updateSnapshot(to);
return super.transfer(to, value);
Copy link
Contributor

Choose a reason for hiding this comment

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

super.transfer() should be called first to follow OZ's standard of failing early.
Also the balanceOf() function call made below after calling updateSnapshot() will not be correct as the state change has not occurred yet.

{
updateSnapshot(from);
updateSnapshot(to);
return super.transferFrom(from, to, value);
Copy link
Contributor

Choose a reason for hiding this comment

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

Again, super.transferFrom() should be called first.

*/
function _mint(address account, uint256 amount) internal {
updateSnapshot(account);
super._mint(account, amount);
Copy link
Contributor

Choose a reason for hiding this comment

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

super._mint() should be called first

*/
function _burn(address account, uint256 amount) internal {
updateSnapshot(account);
super._burn(account, amount);
Copy link
Contributor

Choose a reason for hiding this comment

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

super._burn() should be called first

function updateSnapshot(address account) private {
if (lastSnapshotId(account) < currentSnapshotId) {
snapshotIds[account].push(currentSnapshotId);
snapshotBalances[account].push(balanceOf(account));
Copy link
Contributor

Choose a reason for hiding this comment

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

balanceOf(account) will have the previous amount recorded. Perhaps this was a desired effect to have the history always behind and not current due to the nature of having to iterate a new snapshot manually.

A discussion is to be had about having snapshots with an on/off feature or have snapshots that are always active.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's desired flow to have history always behind. If you want to have snapshots off then use regular ERC20.

Copy link
Contributor

@mswezey23 mswezey23 Oct 10, 2018

Choose a reason for hiding this comment

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

In your implementation, snapshots are off until another iteration is called upon. It is not an always on feature.

I have to know which snapshot id I want to query, instead of using timestamp or blockNumber, you use a trivial number starting at 1 (0 == no snapshot exists yet). This will make it hard for user adoption as now I have to look up which snapshot id I want in relation to blockNumber/timestamp.

Also, one needs to define which state of the balance do you care about at a specific block number? The balance before the block has been applied to the state or after?

* @dev An ERC20 token which enables taking snapshots of account balances.
* This can be useful to safely implement voting weighed by balance.
*/
contract ERC20Snapshot is ERC20 {
Copy link
Contributor

Choose a reason for hiding this comment

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

There is no tracking of the total supply history of the token if it was mintable or burnable

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 don't see the reason to keep racking total supply. Could you elaborate ?

Copy link
Contributor

@mswezey23 mswezey23 Oct 10, 2018

Choose a reason for hiding this comment

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

Voting power and dividend payments require knowing the proper ratio of tokens held against the current token supply at a specified time in history.

Choose a reason for hiding this comment

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

Small typo in the comment here, should be "weighted" by balance.

Copy link
Contributor

@mswezey23 mswezey23 left a comment

Choose a reason for hiding this comment

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

Please see my comments below I've included inline per file.
Noted, this PR was submitted awhile back and OZ's repo has been updated since then.

No tracking of totalSupply() history
Does not follow OZ's fail early standard
Not using SafeMath
Requires an external actor to trigger a snapshot (a discussion should be had about this)

Jakub Bogacz and others added 4 commits October 9, 2018 06:55
Require reason message removed
Inline documentation in NatSpec added
Snapshot added to _mint and _burn method
@nventuro nventuro removed the on hold Put on hold for some reason that must be specified in a comment. label Oct 9, 2018
@jbogacz
Copy link
Contributor Author

jbogacz commented Oct 13, 2018

@mswezey23 your comments sounds reasonable but with my coding I based on @frangio instructions and @nventuro comments so before any change it's kind to ask guys what do they think about it. @frangio @nventuro could you put your comments here ?

Anyway @mswezey23 implemented #1398 which pretty much covers snapshoting for particular block number and keep total supply as well. I did some research due devident payment and voting power and it follows these requirements so I'm fine to close this my PR and track work on SnapshotToken @mswezey23's PR #1398.

@mswezey23
Copy link
Contributor

Hey everyone - just checking in to see if there has been any updates in regards to this and the PR:
#1398

Thanks!

* @dev An ERC20 token which enables taking snapshots of account balances.
* This can be useful to safely implement voting weighed by balance.
*/
contract ERC20Snapshot is ERC20 {

Choose a reason for hiding this comment

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

Small typo in the comment here, should be "weighted" by balance.

event Snapshot(uint256 id);

/**
* @dev Increments current snapshot. Emites Snapshot event.

Choose a reason for hiding this comment

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

Should be "Emits Snapshot event." instead of "Emites".

@frangio frangio added this to the v2.1 milestone Nov 28, 2018
@nventuro nventuro assigned frangio and unassigned nventuro Dec 10, 2018
@frangio frangio modified the milestones: v2.1, v2.2 Dec 11, 2018
@nventuro nventuro assigned nventuro and unassigned frangio Jan 15, 2019
@nventuro
Copy link
Contributor

Hey @jbogacz, sorry for taking so long to review this! We intend to include snapshots in the upcoming release, which is scheduled for next week. Sadly it looks like the diff got too large, due to commits, etc. on master. Could you git rebase so that we get a cleaner changeset? Thanks!

@frangio
Copy link
Contributor

frangio commented Feb 6, 2019

The equivalent #1617 was just merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contracts Smart contract code. feature New contracts, functions, or helpers.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ERC20 token with snapshots
7 participants