Skip to content

Commit

Permalink
ERC721 pausable token
Browse files Browse the repository at this point in the history
  • Loading branch information
exemplarov committed Aug 5, 2018
1 parent 1200969 commit 33db2b1
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 0 deletions.
18 changes: 18 additions & 0 deletions contracts/mocks/ERC721PausableTokenMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
pragma solidity ^0.4.24;

import "../token/ERC721/ERC721PausableToken.sol";


/**
* @title ERC721PausableTokenMock
* This mock just provides a public mint and burn functions for testing purposes
*/
contract ERC721PausableTokenMock is ERC721PausableToken {
function mint(address _to, uint256 _tokenId) public {
super._mint(_to, _tokenId);
}

function burn(uint256 _tokenId) public {
super._burn(ownerOf(_tokenId), _tokenId);
}
}
43 changes: 43 additions & 0 deletions contracts/token/ERC721/ERC721PausableToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
pragma solidity ^0.4.24;

import "./ERC721BasicToken.sol";
import "../../lifecycle/Pausable.sol";


/**
* @title ERC721 Non-Fungible Pausable token
* @dev ERC721BasicToken modified with pausable transfers.
**/
contract ERC721PausableToken is ERC721BasicToken, Pausable {

function approve(
address _to,
uint256 _tokenId
)
public
whenNotPaused
{
super.approve(_to, _tokenId);
}

function setApprovalForAll(
address _to,
bool _approved
)
public
whenNotPaused
{
super.setApprovalForAll(_to, _approved);
}

function transferFrom(
address _from,
address _to,
uint256 _tokenId
)
public
whenNotPaused
{
super.transferFrom(_from, _to, _tokenId);
}
}
120 changes: 120 additions & 0 deletions test/token/ERC721/ERC721PausableToken.behavior.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
const { assertRevert } = require('../../helpers/assertRevert');
const { sendTransaction } = require('../../helpers/sendTransaction');

const BigNumber = web3.BigNumber;

require('chai')
.use(require('chai-bignumber')(BigNumber))
.should();

function shouldBehaveLikeERC721PausableToken (accounts) {
const firstTokenId = 1;
const owner = accounts[0];
const recipient = accounts[1];
const operator = accounts[2];
const data = '0x42';
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';

const safeTransferFromWithData = function (token, from, to, tokenId, opts) {
return sendTransaction(
token,
'safeTransferFrom',
'address,address,uint256,bytes',
[from, to, tokenId, data],
opts
);
};

const shouldBehaveLikeUnpausedToken = function () {
it('approves token transfer', async function () {
await this.token.approve(recipient, firstTokenId, { from: owner });
const approvedAccount = await this.token.getApproved(firstTokenId);
approvedAccount.should.be.equal(recipient);
});

it('approves operator via setApprovalForAll', async function () {
await this.token.setApprovalForAll(operator, true, { from: owner });
const isApprovedForOperator = await this.token.isApprovedForAll(owner, operator);
isApprovedForOperator.should.be.true;
});

it('transfers token', async function () {
await this.token.transferFrom(owner, recipient, firstTokenId, { from: owner });
const firstTokenOwner = await this.token.ownerOf(firstTokenId);
firstTokenOwner.should.be.equal(recipient);
});

it('transfers token via safeTransferFrom', async function () {
await this.token.safeTransferFrom(owner, recipient, firstTokenId, { from: owner });
const firstTokenOwner = await this.token.ownerOf(firstTokenId);
firstTokenOwner.should.be.equal(recipient);
});

it('transfers token via safeTransferFrom with data', async function () {
await safeTransferFromWithData(this.token, owner, recipient, firstTokenId, { from: owner });
const firstTokenOwner = await this.token.ownerOf(firstTokenId);
firstTokenOwner.should.be.equal(recipient);
});
};

describe('when token is not paused yet', function () {
beforeEach(async function () {
await this.token.mint(owner, firstTokenId, { from: owner });
});

shouldBehaveLikeUnpausedToken();
});

describe('when token is paused and unpaused', function () {
beforeEach(async function () {
await this.token.mint(owner, firstTokenId, { from: owner });
await this.token.pause({ from: owner });
await this.token.unpause({ from: owner });
});

shouldBehaveLikeUnpausedToken();
});

describe('when token is paused', function () {
beforeEach(async function () {
await this.token.mint(owner, firstTokenId, { from: owner });
await this.token.pause({ from: owner });
});

it('reverts when trying to approve', async function () {
await assertRevert(this.token.approve(recipient, firstTokenId, { from: owner }));
const approvedAccount = await this.token.getApproved(firstTokenId);
approvedAccount.should.be.equal(ZERO_ADDRESS);
});

it('reverts when trying to setApprovalForAll', async function () {
await assertRevert(this.token.setApprovalForAll(operator, true, { from: owner }));
const isApprovedForOperator = await this.token.isApprovedForAll(owner, operator);
isApprovedForOperator.should.be.false;
});

it('reverts when trying to transferFrom', async function () {
await assertRevert(this.token.transferFrom(owner, recipient, firstTokenId, { from: owner }));
const firstTokenOwner = await this.token.ownerOf(firstTokenId);
firstTokenOwner.should.be.equal(owner);
});

it('reverts when trying to safeTransferFrom', async function () {
await assertRevert(this.token.safeTransferFrom(owner, recipient, firstTokenId, { from: owner }));
const firstTokenOwner = await this.token.ownerOf(firstTokenId);
firstTokenOwner.should.be.equal(owner);
});

it('reverts when trying to safeTransferFrom', async function () {
await assertRevert(
safeTransferFromWithData(this.token, owner, recipient, firstTokenId, { from: owner })
);
const firstTokenOwner = await this.token.ownerOf(firstTokenId);
firstTokenOwner.should.be.equal(owner);
});
});
}

module.exports = {
shouldBehaveLikeERC721PausableToken,
};
16 changes: 16 additions & 0 deletions test/token/ERC721/ERC721PausableToken.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const { shouldBehaveLikeERC721PausableToken } = require('./ERC721PausableToken.behavior');

const BigNumber = web3.BigNumber;
const ERC721PausableToken = artifacts.require('ERC721PausableTokenMock.sol');

require('chai')
.use(require('chai-bignumber')(BigNumber))
.should();

contract('ERC721PausableToken', function (accounts) {
beforeEach(async function () {
this.token = await ERC721PausableToken.new({ from: accounts[0] });
});

shouldBehaveLikeERC721PausableToken(accounts);
});

0 comments on commit 33db2b1

Please sign in to comment.