-
Notifications
You must be signed in to change notification settings - Fork 12.1k
Add ERC1155.totalSupply that returns overall supply count #3962
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
Changes from 8 commits
139363f
3902514
7a267c7
17de1d9
3776289
154605d
4dae02c
a27ba26
58b21c2
a634d58
d511fa6
7be1534
e143fae
737d014
73382df
7c88b4c
493c12d
2ddaded
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 |
---|---|---|
|
@@ -15,6 +15,7 @@ import "../ERC1155.sol"; | |
*/ | ||
abstract contract ERC1155Supply is ERC1155 { | ||
mapping(uint256 => uint256) private _totalSupply; | ||
uint256 private _totalSupplyAll; | ||
|
||
/** | ||
* @dev Total amount of tokens in with a given id. | ||
|
@@ -23,6 +24,13 @@ abstract contract ERC1155Supply is ERC1155 { | |
return _totalSupply[id]; | ||
} | ||
|
||
/** | ||
* @dev Total amount of tokens. | ||
*/ | ||
function totalSupply() public view virtual returns (uint256) { | ||
return _totalSupplyAll; | ||
} | ||
|
||
/** | ||
* @dev Indicates whether any token exist with a given id, or not. | ||
*/ | ||
|
@@ -41,21 +49,30 @@ abstract contract ERC1155Supply is ERC1155 { | |
bytes memory data | ||
) internal virtual override { | ||
if (from == address(0)) { | ||
uint256 totalMintAmount = 0; | ||
for (uint256 i = 0; i < ids.length; ++i) { | ||
_totalSupply[ids[i]] += amounts[i]; | ||
uint256 amount = amounts[i]; | ||
_totalSupply[ids[i]] += amount; | ||
totalMintAmount += amount; | ||
} | ||
_totalSupplyAll += totalMintAmount; | ||
} | ||
|
||
if (to == address(0)) { | ||
uint256 totalBurnAmount = 0; | ||
for (uint256 i = 0; i < ids.length; ++i) { | ||
uint256 id = ids[i]; | ||
uint256 amount = amounts[i]; | ||
uint256 supply = _totalSupply[id]; | ||
require(supply >= amount, "ERC1155: burn amount exceeds totalSupply"); | ||
unchecked { | ||
_totalSupply[id] = supply - amount; | ||
totalBurnAmount += amount; | ||
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 isn't obvious to me why this variable won't overflow. We need to add the explanation. 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 comes from two inequalities:
so 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. Technically we could even get rid of the check on line 67 if we were to check 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. @Amxx I think we didn't do that because we were concerned what would happen if ERC1155Supply was added in an upgrade... I wish we had a more consistent way of dealing with that kind of concern. |
||
} | ||
} | ||
unchecked { | ||
_totalSupplyAll -= totalBurnAmount; | ||
} | ||
} | ||
super._update(from, to, ids, amounts, data); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
const { BN } = require('@openzeppelin/test-helpers'); | ||
const { BN, constants } = require('@openzeppelin/test-helpers'); | ||
|
||
const { expect } = require('chai'); | ||
|
||
const { ZERO_ADDRESS } = constants; | ||
|
||
const ERC1155Supply = artifacts.require('$ERC1155Supply'); | ||
|
||
contract('ERC1155Supply', function (accounts) { | ||
|
@@ -25,7 +27,8 @@ contract('ERC1155Supply', function (accounts) { | |
}); | ||
|
||
it('totalSupply', async function () { | ||
expect(await this.token.totalSupply(firstTokenId)).to.be.bignumber.equal('0'); | ||
expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal('0'); | ||
expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal('0'); | ||
}); | ||
}); | ||
|
||
|
@@ -40,7 +43,8 @@ contract('ERC1155Supply', function (accounts) { | |
}); | ||
|
||
it('totalSupply', async function () { | ||
expect(await this.token.totalSupply(firstTokenId)).to.be.bignumber.equal(firstTokenAmount); | ||
expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal(firstTokenAmount); | ||
expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal(firstTokenAmount); | ||
}); | ||
}); | ||
|
||
|
@@ -60,8 +64,13 @@ contract('ERC1155Supply', function (accounts) { | |
}); | ||
|
||
it('totalSupply', async function () { | ||
expect(await this.token.totalSupply(firstTokenId)).to.be.bignumber.equal(firstTokenAmount); | ||
expect(await this.token.totalSupply(secondTokenId)).to.be.bignumber.equal(secondTokenAmount); | ||
expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal(firstTokenAmount); | ||
expect(await this.token.methods['totalSupply(uint256)'](secondTokenId)).to.be.bignumber.equal( | ||
secondTokenAmount, | ||
); | ||
expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal( | ||
firstTokenAmount.add(secondTokenAmount), | ||
); | ||
}); | ||
}); | ||
}); | ||
|
@@ -78,7 +87,8 @@ contract('ERC1155Supply', function (accounts) { | |
}); | ||
|
||
it('totalSupply', async function () { | ||
expect(await this.token.totalSupply(firstTokenId)).to.be.bignumber.equal('0'); | ||
expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal('0'); | ||
expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal('0'); | ||
}); | ||
}); | ||
|
||
|
@@ -99,9 +109,19 @@ contract('ERC1155Supply', function (accounts) { | |
}); | ||
|
||
it('totalSupply', async function () { | ||
expect(await this.token.totalSupply(firstTokenId)).to.be.bignumber.equal('0'); | ||
expect(await this.token.totalSupply(secondTokenId)).to.be.bignumber.equal('0'); | ||
expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal('0'); | ||
expect(await this.token.methods['totalSupply(uint256)'](secondTokenId)).to.be.bignumber.equal('0'); | ||
expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal('0'); | ||
}); | ||
}); | ||
}); | ||
|
||
context('total supply of token', function () { | ||
it('totalSupply unaffected by no-op', async function () { | ||
JulissaDantes marked this conversation as resolved.
Show resolved
Hide resolved
|
||
this.token.safeTransferFrom(ZERO_ADDRESS, ZERO_ADDRESS, firstTokenId, firstTokenAmount, '0x', { | ||
from: ZERO_ADDRESS, | ||
}); | ||
expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal('0'); | ||
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. Is there a reason not to check 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. Since Is checked multiple times before this test I did not think we needed it, but do you think we should include it for a no-op test? 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. Yes, |
||
}); | ||
}); | ||
}); |
Uh oh!
There was an error while loading. Please reload this page.