-
Notifications
You must be signed in to change notification settings - Fork 841
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 ERC721ALowCap + tests #114
Changes from 6 commits
bb0c41d
beab3db
7c3e2b4
8f4bf17
eb926dd
0f6f5fd
77c5a10
1d8e427
8a5e791
dbe5929
c52bba1
758c127
d203c9f
ac997dc
ea1e548
342580f
83465ad
9717a0b
a93fe7e
e5f3076
07e522a
5f97b61
062bffc
845b0f9
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 |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// SPDX-License-Identifier: MIT | ||
// Creator: Chiru Labs | ||
|
||
pragma solidity ^0.8.4; | ||
|
||
import '../ERC721A.sol'; | ||
|
||
/** | ||
* @title ERC721A Low Cap | ||
* @dev ERC721A Helper functions for Low Cap (<= 10,000) totalSupply. | ||
*/ | ||
abstract contract ERC721ALowCap is ERC721A { | ||
|
||
/** | ||
* @dev Returns the tokenIds of the address. O(totalSupply) in complexity. | ||
*/ | ||
function tokensOfOwner(address owner) public view returns (uint256[] memory) { | ||
uint256 holdingAmount = balanceOf(owner); | ||
uint256 currSupply = _currentIndex; | ||
uint256 tokenIdsIdx; | ||
address currOwnershipAddr; | ||
|
||
uint256[] memory list = new uint256[](holdingAmount); | ||
|
||
unchecked { | ||
for (uint256 i; i < currSupply; i++) { | ||
TokenOwnership memory ownership = _ownerships[i]; | ||
|
||
if (ownership.burned) { | ||
continue; | ||
} | ||
|
||
// Find out who owns this sequence | ||
if (ownership.addr != address(0)) { | ||
currOwnershipAddr = ownership.addr; | ||
} | ||
|
||
// Append tokens the last found owner owns in the sequence | ||
if (currOwnershipAddr == owner) { | ||
list[tokenIdsIdx++] = i; | ||
} | ||
|
||
// All tokens have been found, we don't need to keep searching | ||
if(tokenIdsIdx == holdingAmount) { | ||
break; | ||
} | ||
} | ||
} | ||
|
||
return list; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// SPDX-License-Identifier: MIT | ||
// Creators: Chiru Labs | ||
|
||
pragma solidity ^0.8.4; | ||
|
||
import '../extensions/ERC721ALowCap.sol'; | ||
|
||
contract ERC721ALowCapMock is ERC721ALowCap { | ||
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. Filename should be the same as contract name, try changing the filename to |
||
constructor(string memory name_, string memory symbol_) ERC721A(name_, symbol_) {} | ||
|
||
function safeMint(address to, uint256 quantity) public { | ||
_safeMint(to, quantity); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
const { expect } = require('chai'); | ||
|
||
describe('ERC721ALowCap', function () { | ||
beforeEach(async function () { | ||
this.ERC721ALowCap = await ethers.getContractFactory('ERC721ALowCapMock'); | ||
this.token = await this.ERC721ALowCap.deploy('Azuki', 'AZUKI'); | ||
await this.token.deployed(); | ||
}); | ||
|
||
context('with minted tokens', async function() { | ||
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. Use 2 spaces for indentation in this context instead of 4. 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. Should be able to run |
||
beforeEach(async function () { | ||
const [owner, addr1, addr2, addr3, addr4] = await ethers.getSigners(); | ||
this.owner = owner; | ||
this.addr1 = addr1; | ||
this.addr2 = addr2; | ||
this.addr3 = addr3; | ||
this.addr4 = addr4; | ||
await this.token['safeMint(address,uint256)'](addr1.address, 1); | ||
await this.token['safeMint(address,uint256)'](addr2.address, 2); | ||
await this.token['safeMint(address,uint256)'](addr3.address, 3); | ||
}); | ||
|
||
describe('tokensOfOwner', async function() { | ||
it('returns the correct token ids', async function() { | ||
const expected_results = [ | ||
// Address 1 -- Single token | ||
{ owner: this.addr1, tokens : [0] }, | ||
// Address 3 -- Multiple tokens | ||
{ owner: this.addr3, tokens : [3,4,5] }, | ||
// Address 4 -- No tokens | ||
{ owner: this.addr4, tokens : [] } | ||
]; | ||
|
||
for(const expected_result of expected_results) { | ||
const bn_tokens = await this.token['tokensOfOwner(address)'](expected_result.owner.address); | ||
expect(bn_tokens.map(bn => bn.toNumber())).to.eql(expected_result.tokens); | ||
} | ||
}); | ||
|
||
it('returns the correct token ids after a transfer interferes with the normal logic', async function() { | ||
// Owner of 6,7,8 | ||
await this.token['safeMint(address,uint256)'](this.owner.address, 3); | ||
|
||
// Break sequential order | ||
await this.token['transferFrom(address,address,uint256)'](this.owner.address, this.addr4.address, 7); | ||
|
||
// Load balances | ||
const owner_bn_tokens = await this.token['tokensOfOwner(address)'](this.owner.address); | ||
const addr4_bn_tokens = await this.token['tokensOfOwner(address)'](this.addr4.address); | ||
|
||
// Verify the function can still read the correct token ids | ||
expect(owner_bn_tokens.map(bn => bn.toNumber())).to.eql([6,8]); | ||
expect(addr4_bn_tokens.map(bn => bn.toNumber())).to.eql([7]); | ||
}); | ||
}); | ||
}); | ||
|
||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove extra white spaces before the assignment
=
. docs