Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
1192e68
Rename current ERC721 implementation to BaseERC721
facuspagnuolo Feb 26, 2018
ca163a8
Implement ERC721 optional & approveAll functionality
facuspagnuolo Feb 26, 2018
71cbc51
Support for new ERC721 interface
spalladino Mar 7, 2018
3745025
Add more tests for ERC721
spalladino Mar 8, 2018
559df81
Implement suggestions by @dekz
spalladino Mar 8, 2018
d726c79
Update comments in ERC721 contracts
spalladino Mar 8, 2018
54a1d2e
Implement tokensByIndex extension
spalladino Mar 9, 2018
851685c
Add default implementation for metadata URI
spalladino Mar 9, 2018
3cef880
Allow operators to call approve on a token
spalladino Mar 9, 2018
6f180a6
Remove gas stipend restriction in call to 721 receiver
spalladino Mar 9, 2018
6fbe771
Remove deprecated implementation
spalladino Mar 9, 2018
626742e
Add notice to isContract helper on constract constructors
spalladino Mar 20, 2018
95a1f9a
Change natspec delimiters for consistency
spalladino Mar 21, 2018
15f9556
Minor linting fixes
spalladino Mar 21, 2018
b332995
Add constant modifier to ERC721_RECEIVED magic value
spalladino Mar 21, 2018
f4748da
Use 4-params safeTransferFrom for implementing the 3-params overload
spalladino Mar 21, 2018
fb4f728
Minor text changes in natspec comments
spalladino Mar 21, 2018
6b98e4e
Use address(0) instead of 0 or 0x0
spalladino Mar 21, 2018
3f2ea8a
Use if-statements instead of boolean one-liners for clarity
spalladino Mar 21, 2018
74db03b
Keep ownedTokensCount state var in sync in full ERC721 implementation
spalladino Mar 21, 2018
981c6f7
Fix incorrect comparison when burning ERC721 tokens with metadata
spalladino Mar 21, 2018
73b77ae
Use address(0) instead of 0 in one more place in ERC721
spalladino Mar 21, 2018
eee5b0e
Throw when querying balance for the zero address
spalladino Mar 21, 2018
9deb637
Update links to approved version of EIP721
spalladino Mar 21, 2018
fe6e4ff
Use explicit size for uint
spalladino Mar 22, 2018
4836279
Remove unneeded internal function in ERC721
spalladino Mar 22, 2018
619ae84
Use underscore instead of 'do' prefix for internal methods in ERC721
spalladino Mar 22, 2018
2e593f2
Fix failing test due to events reordering in ERC721 safe transfer
spalladino Mar 22, 2018
6c09d20
Fix bug introduced in 74db03ba06
spalladino Mar 22, 2018
37929c8
Remove do prefix for internal setTokenUri method
spalladino Mar 22, 2018
3676b55
Allow transfers to self in ERC721
spalladino Mar 23, 2018
7815cc5
Merge branch 'master' into feature/full_erc721
frangio Mar 23, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Allow operators to call approve on a token
  • Loading branch information
spalladino committed Mar 9, 2018
commit 3cef880803da7f8cfabc09f7748f3ba0eaaad0fe
5 changes: 4 additions & 1 deletion contracts/token/ERC721/ERC721BasicToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,15 @@ contract ERC721BasicToken is ERC721Basic {
* @dev Approves another address to transfer the given token ID
* @dev The zero address indicates there is no approved address.
* @dev There can only be one approved address per token at a given time.
* @dev Can only be called by the token owner or an approved operator.
* @param _to address to be approved for the given token ID
* @param _tokenId uint256 ID of the token to be approved
*/
function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) {
function approve(address _to, uint256 _tokenId) public {
address owner = ownerOf(_tokenId);
require(_to != owner);
require(msg.sender == owner || isApprovedForAll(owner, msg.sender));

if (getApproved(_tokenId) != 0 || _to != 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

address(0)

tokenApprovals[_tokenId] = _to;
Approval(owner, _to, _tokenId);
Expand Down
96 changes: 44 additions & 52 deletions test/token/ERC721/ERC721BasicToken.behaviour.js
Original file line number Diff line number Diff line change
Expand Up @@ -287,17 +287,38 @@ export default function shouldBehaveLikeERC721BasicToken (accounts) {
const to = accounts[1];

let logs = null;

const itClearsApproval = function () {
it('clears approval for the token', async function () {
const approvedAccount = await this.token.getApproved(tokenId);
approvedAccount.should.be.equal(ZERO_ADDRESS);
});
};

const itApproves = function (address) {
it('sets the approval for the target address', async function () {
const approvedAccount = await this.token.getApproved(tokenId);
approvedAccount.should.be.equal(address);
});
};

const itEmitsApprovalEvent = function (address) {
it('emits an approval event', async function () {
logs.length.should.be.equal(1);
logs[0].event.should.be.eq('Approval');
logs[0].args._owner.should.be.equal(sender);
logs[0].args._approved.should.be.equal(address);
logs[0].args._tokenId.should.be.bignumber.equal(tokenId);
});
};

describe('when clearing approval', function () {
describe('when there was no prior approval', function () {
beforeEach(async function () {
({ logs } = await this.token.approve(ZERO_ADDRESS, tokenId, { from: sender }));
});

it('clears the approval for that token', async function () {
const approvedAccount = await this.token.getApproved(tokenId);
approvedAccount.should.be.equal(ZERO_ADDRESS);
});
itClearsApproval();

it('does not emit an approval event', async function () {
logs.length.should.be.equal(0);
Expand All @@ -310,18 +331,8 @@ export default function shouldBehaveLikeERC721BasicToken (accounts) {
({ logs } = await this.token.approve(ZERO_ADDRESS, tokenId, { from: sender }));
});

it('clears the approval for that token', async function () {
const approvedAccount = await this.token.getApproved(tokenId);
approvedAccount.should.be.equal(ZERO_ADDRESS);
});

it('emits an approval event', async function () {
logs.length.should.be.equal(1);
logs[0].event.should.be.eq('Approval');
logs[0].args._owner.should.be.equal(sender);
logs[0].args._approved.should.be.equal(ZERO_ADDRESS);
logs[0].args._tokenId.should.be.bignumber.equal(tokenId);
});
itClearsApproval();
itEmitsApprovalEvent(ZERO_ADDRESS);
});
});

Expand All @@ -331,18 +342,8 @@ export default function shouldBehaveLikeERC721BasicToken (accounts) {
({ logs } = await this.token.approve(to, tokenId, { from: sender }));
});

it('sets the approval for that token', async function () {
const approvedAccount = await this.token.getApproved(tokenId);
approvedAccount.should.be.equal(to);
});

it('emits an approval event', async function () {
logs.length.should.be.equal(1);
logs[0].event.should.be.eq('Approval');
logs[0].args._owner.should.be.equal(sender);
logs[0].args._approved.should.be.equal(to);
logs[0].args._tokenId.should.be.bignumber.equal(tokenId);
});
itApproves(to);
itEmitsApprovalEvent(to);
});

describe('when there was a prior approval to the same address', function () {
Expand All @@ -351,18 +352,8 @@ export default function shouldBehaveLikeERC721BasicToken (accounts) {
({ logs } = await this.token.approve(to, tokenId, { from: sender }));
});

it('keeps the approval for that token', async function () {
const approvedAccount = await this.token.getApproved(tokenId);
approvedAccount.should.be.equal(to);
});

it('emits an approval event', async function () {
logs.length.should.be.equal(1);
logs[0].event.should.be.eq('Approval');
logs[0].args._owner.should.be.equal(sender);
logs[0].args._approved.should.be.equal(to);
logs[0].args._tokenId.should.be.bignumber.equal(tokenId);
});
itApproves(to);
itEmitsApprovalEvent(to);
});

describe('when there was a prior approval to a different address', function () {
Expand All @@ -371,18 +362,8 @@ export default function shouldBehaveLikeERC721BasicToken (accounts) {
({ logs } = await this.token.approve(to, tokenId, { from: sender }));
});

it('sets the approval for that token', async function () {
const approvedAccount = await this.token.getApproved(tokenId);
approvedAccount.should.be.equal(to);
});

it('emits an approval event', async function () {
logs.length.should.be.equal(1);
logs[0].event.should.be.eq('Approval');
logs[0].args._owner.should.be.equal(sender);
logs[0].args._approved.should.be.equal(to);
logs[0].args._tokenId.should.be.bignumber.equal(tokenId);
});
itApproves(to);
itEmitsApprovalEvent(to);
});
});

Expand All @@ -405,6 +386,17 @@ export default function shouldBehaveLikeERC721BasicToken (accounts) {
});
});

describe('when the sender is an operator', function () {
const operator = accounts[2];
beforeEach(async function () {
await this.token.setApprovalForAll(operator, true, { from: sender });
({ logs } = await this.token.approve(to, tokenId, { from: operator }));
});

itApproves(to);
itEmitsApprovalEvent(to);
});

describe('when the given token ID does not exist', function () {
it('reverts', async function () {
await assertRevert(this.token.approve(to, unknownTokenId, { from: sender }));
Expand Down