Skip to content

Commit 24cb9cf

Browse files
committed
Merge remote-tracking branch 'upstream/master' into erc20-encapsulation
2 parents 34a967b + d51e387 commit 24cb9cf

16 files changed

+143
-83
lines changed

contracts/math/Math.sol

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,9 @@ library Math {
1313
function min(uint256 _a, uint256 _b) internal pure returns (uint256) {
1414
return _a < _b ? _a : _b;
1515
}
16+
17+
function average(uint256 _a, uint256 _b) internal pure returns (uint256) {
18+
// (_a + _b) / 2 can overflow, so we distribute
19+
return (_a / 2) + (_b / 2) + ((_a % 2 + _b % 2) / 2);
20+
}
1621
}

contracts/math/SafeMath.sol

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,13 @@ library SafeMath {
5454

5555
return c;
5656
}
57+
58+
/**
59+
* @dev Divides two numbers and returns the remainder (unsigned integer modulo),
60+
* reverts when dividing by zero.
61+
*/
62+
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
63+
require(b != 0);
64+
return a % b;
65+
}
5766
}

contracts/mocks/ERC721TokenMock.sol

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,14 @@ contract ERC721TokenMock is ERC721Token {
2121
super._burn(ownerOf(_tokenId), _tokenId);
2222
}
2323

24+
function exists(uint256 _tokenId) public view returns (bool) {
25+
return super._exists(_tokenId);
26+
}
27+
2428
function setTokenURI(uint256 _tokenId, string _uri) public {
2529
super._setTokenURI(_tokenId, _uri);
2630
}
27-
31+
2832
function _removeTokenFrom(address _from, uint256 _tokenId) public {
2933
super.removeTokenFrom(_from, _tokenId);
3034
}

contracts/mocks/MathMock.sol

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,8 @@ contract MathMock {
1212
function min(uint256 _a, uint256 _b) public pure returns (uint256) {
1313
return Math.min(_a, _b);
1414
}
15+
16+
function average(uint256 _a, uint256 _b) public pure returns (uint256) {
17+
return Math.average(_a, _b);
18+
}
1519
}

contracts/mocks/SafeMathMock.sol

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,8 @@ contract SafeMathMock {
2121
function add(uint256 _a, uint256 _b) public pure returns (uint256) {
2222
return SafeMath.add(_a, _b);
2323
}
24+
25+
function mod(uint256 a, uint256 b) public pure returns (uint256) {
26+
return SafeMath.mod(a, b);
27+
}
2428
}

contracts/token/ERC721/ERC721Basic.sol

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,6 @@ contract ERC721Basic is ERC165 {
2323
* bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)'))
2424
*/
2525

26-
bytes4 internal constant InterfaceId_ERC721Exists = 0x4f558e79;
27-
/*
28-
* 0x4f558e79 ===
29-
* bytes4(keccak256('exists(uint256)'))
30-
*/
31-
3226
bytes4 internal constant InterfaceId_ERC721Enumerable = 0x780e9d63;
3327
/**
3428
* 0x780e9d63 ===
@@ -63,7 +57,6 @@ contract ERC721Basic is ERC165 {
6357

6458
function balanceOf(address _owner) public view returns (uint256 _balance);
6559
function ownerOf(uint256 _tokenId) public view returns (address _owner);
66-
function exists(uint256 _tokenId) public view returns (bool _exists);
6760

6861
function approve(address _to, uint256 _tokenId) public;
6962
function getApproved(uint256 _tokenId)

contracts/token/ERC721/ERC721BasicToken.sol

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ contract ERC721BasicToken is SupportsInterfaceWithLookup, ERC721Basic {
3737
{
3838
// register the supported interfaces to conform to ERC721 via ERC165
3939
_registerInterface(InterfaceId_ERC721);
40-
_registerInterface(InterfaceId_ERC721Exists);
4140
}
4241

4342
/**
@@ -61,16 +60,6 @@ contract ERC721BasicToken is SupportsInterfaceWithLookup, ERC721Basic {
6160
return owner;
6261
}
6362

64-
/**
65-
* @dev Returns whether the specified token exists
66-
* @param _tokenId uint256 ID of the token to query the existence of
67-
* @return whether the token exists
68-
*/
69-
function exists(uint256 _tokenId) public view returns (bool) {
70-
address owner = tokenOwner[_tokenId];
71-
return owner != address(0);
72-
}
73-
7463
/**
7564
* @dev Approves another address to transfer the given token ID
7665
* The zero address indicates there is no approved address.
@@ -200,6 +189,16 @@ contract ERC721BasicToken is SupportsInterfaceWithLookup, ERC721Basic {
200189
require(checkAndCallSafeTransfer(_from, _to, _tokenId, _data));
201190
}
202191

192+
/**
193+
* @dev Returns whether the specified token exists
194+
* @param _tokenId uint256 ID of the token to query the existence of
195+
* @return whether the token exists
196+
*/
197+
function _exists(uint256 _tokenId) internal view returns (bool) {
198+
address owner = tokenOwner[_tokenId];
199+
return owner != address(0);
200+
}
201+
203202
/**
204203
* @dev Returns whether the given spender can transfer a given token ID
205204
* @param _spender address of the spender to query

contracts/token/ERC721/ERC721Token.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ contract ERC721Token is SupportsInterfaceWithLookup, ERC721BasicToken, ERC721 {
6868
* @param _tokenId uint256 ID of the token to query
6969
*/
7070
function tokenURI(uint256 _tokenId) public view returns (string) {
71-
require(exists(_tokenId));
71+
require(_exists(_tokenId));
7272
return tokenURIs[_tokenId];
7373
}
7474

@@ -116,7 +116,7 @@ contract ERC721Token is SupportsInterfaceWithLookup, ERC721BasicToken, ERC721 {
116116
* @param _uri string URI to assign
117117
*/
118118
function _setTokenURI(uint256 _tokenId, string _uri) internal {
119-
require(exists(_tokenId));
119+
require(_exists(_tokenId));
120120
tokenURIs[_tokenId] = _uri;
121121
}
122122

ethpm.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"package_name": "zeppelin",
3-
"version": "1.11.0",
3+
"version": "1.12.0",
44
"description": "Secure Smart Contract library for Solidity",
55
"authors": [
66
"OpenZeppelin Community <[email protected]>"

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "openzeppelin-solidity",
3-
"version": "1.11.0",
3+
"version": "1.12.0",
44
"description": "Secure Smart Contract library for Solidity",
55
"files": [
66
"contracts",

test/library/Math.test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,28 @@ contract('Math', function () {
3737
result.should.be.bignumber.equal(min);
3838
});
3939
});
40+
41+
describe('average', function () {
42+
function bnAverage (a, b) {
43+
return a.plus(b).div(2).truncated();
44+
}
45+
46+
it('is correctly calculated with two odd numbers', async function () {
47+
const a = new BigNumber(57417);
48+
const b = new BigNumber(95431);
49+
(await this.math.average(a, b)).should.be.bignumber.equal(bnAverage(a, b));
50+
});
51+
52+
it('is correctly calculated with two even numbers', async function () {
53+
const a = new BigNumber(42304);
54+
const b = new BigNumber(84346);
55+
(await this.math.average(a, b)).should.be.bignumber.equal(bnAverage(a, b));
56+
});
57+
58+
it('is correctly calculated with one even and one odd number', async function () {
59+
const a = new BigNumber(57417);
60+
const b = new BigNumber(84346);
61+
(await this.math.average(a, b)).should.be.bignumber.equal(bnAverage(a, b));
62+
});
63+
});
4064
});

test/math/SafeMath.test.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const { assertRevert } = require('../helpers/assertRevert');
2+
23
const BigNumber = web3.BigNumber;
34
const SafeMathMock = artifacts.require('SafeMathMock');
45

@@ -88,4 +89,43 @@ contract('SafeMath', () => {
8889
await assertRevert(this.safeMath.div(a, b));
8990
});
9091
});
92+
93+
describe('mod', function () {
94+
describe('modulos correctly', async function () {
95+
it('when the dividend is smaller than the divisor', async function () {
96+
const a = new BigNumber(284);
97+
const b = new BigNumber(5678);
98+
99+
(await this.safeMath.mod(a, b)).should.be.bignumber.equal(a.mod(b));
100+
});
101+
102+
it('when the dividend is equal to the divisor', async function () {
103+
const a = new BigNumber(5678);
104+
const b = new BigNumber(5678);
105+
106+
(await this.safeMath.mod(a, b)).should.be.bignumber.equal(a.mod(b));
107+
});
108+
109+
it('when the dividend is larger than the divisor', async function () {
110+
const a = new BigNumber(7000);
111+
const b = new BigNumber(5678);
112+
113+
(await this.safeMath.mod(a, b)).should.be.bignumber.equal(a.mod(b));
114+
});
115+
116+
it('when the dividend is a multiple of the divisor', async function () {
117+
const a = new BigNumber(17034); // 17034 == 5678 * 3
118+
const b = new BigNumber(5678);
119+
120+
(await this.safeMath.mod(a, b)).should.be.bignumber.equal(a.mod(b));
121+
});
122+
});
123+
124+
it('reverts with a 0 divisor', async function () {
125+
const a = new BigNumber(5678);
126+
const b = new BigNumber(0);
127+
128+
await assertRevert(this.safeMath.mod(a, b));
129+
});
130+
});
91131
});
Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,37 @@
1-
const { expectThrow } = require('../../helpers/expectThrow');
2-
const expectEvent = require('../../helpers/expectEvent');
3-
4-
const BigNumber = web3.BigNumber;
5-
6-
require('chai')
7-
.use(require('chai-bignumber')(BigNumber))
8-
.should();
9-
10-
function shouldBehaveLikeCappedToken (minter, [anyone], cap) {
11-
describe('capped token', function () {
12-
const from = minter;
13-
14-
it('should start with the correct cap', async function () {
15-
(await this.token.cap()).should.be.bignumber.equal(cap);
16-
});
17-
18-
it('should mint when amount is less than cap', async function () {
19-
const { logs } = await this.token.mint(anyone, cap.sub(1), { from });
20-
expectEvent.inLogs(logs, 'Mint');
21-
});
22-
23-
it('should fail to mint if the ammount exceeds the cap', async function () {
24-
await this.token.mint(anyone, cap.sub(1), { from });
25-
await expectThrow(this.token.mint(anyone, 100, { from }));
26-
});
27-
28-
it('should fail to mint after cap is reached', async function () {
29-
await this.token.mint(anyone, cap, { from });
30-
await expectThrow(this.token.mint(anyone, 1, { from }));
31-
});
32-
});
33-
}
34-
35-
module.exports = {
36-
shouldBehaveLikeCappedToken,
37-
};
1+
const { expectThrow } = require('../../helpers/expectThrow');
2+
const expectEvent = require('../../helpers/expectEvent');
3+
4+
const BigNumber = web3.BigNumber;
5+
6+
require('chai')
7+
.use(require('chai-bignumber')(BigNumber))
8+
.should();
9+
10+
function shouldBehaveLikeCappedToken (minter, [anyone], cap) {
11+
describe('capped token', function () {
12+
const from = minter;
13+
14+
it('should start with the correct cap', async function () {
15+
(await this.token.cap()).should.be.bignumber.equal(cap);
16+
});
17+
18+
it('should mint when amount is less than cap', async function () {
19+
const { logs } = await this.token.mint(anyone, cap.sub(1), { from });
20+
expectEvent.inLogs(logs, 'Mint');
21+
});
22+
23+
it('should fail to mint if the ammount exceeds the cap', async function () {
24+
await this.token.mint(anyone, cap.sub(1), { from });
25+
await expectThrow(this.token.mint(anyone, 100, { from }));
26+
});
27+
28+
it('should fail to mint after cap is reached', async function () {
29+
await this.token.mint(anyone, cap, { from });
30+
await expectThrow(this.token.mint(anyone, 1, { from }));
31+
});
32+
});
33+
}
34+
35+
module.exports = {
36+
shouldBehaveLikeCappedToken,
37+
};

test/token/ERC721/ERC721BasicToken.behavior.js

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -47,26 +47,6 @@ function shouldBehaveLikeERC721BasicToken (accounts) {
4747
});
4848
});
4949

50-
describe('exists', function () {
51-
context('when the token exists', function () {
52-
const tokenId = firstTokenId;
53-
54-
it('should return true', async function () {
55-
const result = await this.token.exists(tokenId);
56-
result.should.be.true;
57-
});
58-
});
59-
60-
context('when the token does not exist', function () {
61-
const tokenId = unknownTokenId;
62-
63-
it('should return false', async function () {
64-
const result = await this.token.exists(tokenId);
65-
result.should.be.false;
66-
});
67-
});
68-
});
69-
7050
describe('ownerOf', function () {
7151
context('when the given token ID was tracked by this token', function () {
7252
const tokenId = firstTokenId;
@@ -554,7 +534,6 @@ function shouldBehaveLikeERC721BasicToken (accounts) {
554534
shouldSupportInterfaces([
555535
'ERC165',
556536
'ERC721',
557-
'ERC721Exists',
558537
]);
559538
});
560539
}

test/token/ERC721/ERC721Token.test.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,6 @@ contract('ERC721Token', function (accounts) {
225225
shouldSupportInterfaces([
226226
'ERC165',
227227
'ERC721',
228-
'ERC721Exists',
229228
'ERC721Enumerable',
230229
'ERC721Metadata',
231230
]);

0 commit comments

Comments
 (0)