Skip to content
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

Feat/nft collection #1568

Open
wants to merge 47 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
3f75816
feat: add a copy of AvatarCollection with tests
Aug 5, 2024
1d6ce1d
feat: remove enumerable
Aug 5, 2024
7e4fdaa
feat: mint sequentially (remove random)
Aug 5, 2024
2dd0e85
feat: remove access control (leave only owner)
Aug 5, 2024
35120ad
fix: make setAllowedExecuteMint non reentrant
Aug 5, 2024
776827a
chore: add hardhat-contract-sizer plugin
Aug 6, 2024
65376f3
feat: add ERC2981
Aug 6, 2024
a9fe81d
feat: add batch transfer methods
Aug 6, 2024
9fe4757
feat: change vars that has getters from public to internal
Aug 6, 2024
b2de601
feat: make the burn methods internal
Aug 6, 2024
898bfc4
feat: add batchMint, so the owner can mint
Aug 6, 2024
dbc10e7
fix: fix the event emmited in setBaseURI
Aug 6, 2024
6d431d6
feat: add operator to emmited events
Aug 6, 2024
d3d0dec
feat: change memory to calldata when possible
Aug 6, 2024
03aec45
feat: use latest ERC2771HandlerUpgradeable and UpdatableOperatorFilte…
Aug 6, 2024
09c66f4
fix: remove unused var _availableIds
Aug 6, 2024
d2c2640
feat: upgrade solc version, use only one OZ version
Aug 7, 2024
4b7430d
feat: natspec review plus improvements to setupWave
Aug 7, 2024
17c72c4
fix: small fix
Aug 7, 2024
b51a331
feat: add setOperatorRegistry and register
Aug 8, 2024
97ae8fd
chore: add initialization method to UpdatableOperatorFiltererUpgradeable
Aug 9, 2024
5f86c99
chore: function reorder
Aug 9, 2024
3d270e7
feat: add setTrusted forwarder
Aug 9, 2024
4d564e0
feat: remove the initialization of the operator filterer registry
Aug 9, 2024
3dc11ca
feat: split limit checks to batch minting is better
Aug 9, 2024
3d76309
feat: add minted and wave index to WaveSetup event
Aug 9, 2024
e295c73
feat: add amount to batchMint
Aug 12, 2024
a5be8b6
chore: some reorder in UpdatableOperatorFiltererUpgradeable
Aug 13, 2024
566b61b
fix: add missing event for royalties, add previous values for some ev…
Aug 13, 2024
c0d6cb3
feat: add tests, remove the dependecy from core (using mocks)
Aug 16, 2024
caedc96
test: add tests and mocks to get 100% coverage
Aug 22, 2024
97bdcb9
chore: yarn.lock
Aug 22, 2024
f615459
feat: remove minting defaults, add maxSupply setter
Aug 27, 2024
b3f3ed9
doc: add the doc of the NFTCollection contract
Sep 3, 2024
6c65b18
feat: OZ v5, custom errors and v5 storage style
Sep 5, 2024
836933b
feat: add _checkAndSetPersonalizationSignature
Sep 6, 2024
55848c8
fix: small doc fixes, add abstract
Sep 6, 2024
36be7ba
fix: remove some unnused comments reorder in waveSetup
Sep 10, 2024
f75f7ea
feat: move wave data to a struct
Sep 11, 2024
df972b0
feat: add different signatures, waveMint
Sep 24, 2024
3d37021
doc: update the docs
Oct 16, 2024
251f57e
doc: updated natspect
Dec 9, 2024
4291ff9
feat: deployment scripts for nft-collection
Dec 10, 2024
be592bc
feat: improve deployemnt scripts for nfg-collection
Dec 16, 2024
fc7fbd5
feat: improved deployments scripts
Dec 17, 2024
4beac30
chore: linter
Dec 17, 2024
a8b11e2
doc: change biconomy to meta transactions
Jan 2, 2025
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: MIT
// solhint-disable-next-line compiler-version
pragma solidity 0.8.15;

/// @dev minimal ERC2771 handler to keep bytecode-size down
Expand Down
15 changes: 0 additions & 15 deletions packages/avatar/contracts/mocks/FakePolygonSand.sol

This file was deleted.

145 changes: 143 additions & 2 deletions packages/avatar/contracts/mocks/MockERC20.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,151 @@
// SPDX-License-Identifier: MIT
// solhint-disable one-contract-per-file
pragma solidity 0.8.15;

import {Ownable} from "@openzeppelin/contracts-0.8.15/access/Ownable.sol";
import {ERC20} from "@openzeppelin/contracts-0.8.15/token/ERC20/ERC20.sol";

contract MockERC20 is ERC20 {
constructor(string memory _name, string memory _symbol, uint256 _initialSupply) ERC20(_name, _symbol) {
contract MockERC20 is ERC20, Ownable {
struct MintArgs {
address target;
address wallet;
uint256 amount;
uint256 waveIndex;
uint256 signatureId;
bytes signature;
}

MintArgs public mintArgs;

constructor(uint256 _initialSupply) ERC20("MOCKTOKEN", "MOCK") {
_mint(msg.sender, _initialSupply * 1e18);
}

function donateTo(address recipient, uint256 amount) external onlyOwner {
_mint(recipient, amount);
}

/// @dev instead of using approve and call we use this method directly for testing.
function mint(
MintInterface target,
address _wallet,
uint256 _amount,
uint256 _signatureId,
bytes calldata _signature
) external {
target.mint(_wallet, _amount, _signatureId, _signature);
}

function mintReenter(
address _target,
address _wallet,
uint256 _amount,
uint256 _signatureId,
bytes calldata _signature
) external {
mintArgs = MintArgs({target : _target, wallet : _wallet, amount : _amount, waveIndex : 0, signatureId : _signatureId, signature : _signature});
MintInterface(_target).mint(_wallet, _amount, _signatureId, _signature);
}

/// @dev instead of using approve and call we use this method directly for testing.
function waveMint(
MintInterface target,
address _wallet,
uint256 _amount,
uint256 _waveIndex,
uint256 _signatureId,
bytes calldata _signature
) external {
target.waveMint(_wallet, _amount, _waveIndex, _signatureId, _signature);
}

function waveMintReenter(
address _target,
address _wallet,
uint256 _amount,
uint256 _waveIndex,
uint256 _signatureId,
bytes calldata _signature
) external {
mintArgs = MintArgs({target : _target, wallet : _wallet, amount : _amount, waveIndex : _waveIndex, signatureId : _signatureId, signature : _signature});
MintInterface(_target).waveMint(_wallet, _amount, _waveIndex, _signatureId, _signature);
}

/// @notice Approve `target` to spend `amount` and call it with data.
/// @param target The address to be given rights to transfer and destination of the call.
/// @param amount The number of tokens allowed.
/// @param data The bytes for the call.
/// @return The data of the call.
function approveAndCall(
address target,
uint256 amount,
bytes calldata data
) external payable returns (bytes memory) {
require(doFirstParamEqualsAddress(data, _msgSender()), "FIRST_PARAM_NOT_SENDER");

_approve(_msgSender(), target, amount);

// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returnData) = target.call{value : msg.value}(data);
if (success) {
return returnData;
}
if (returnData.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returnData)
revert(add(32, returnData), returndata_size)
}
} else {
revert("Empty error from destination");
}
}

function doFirstParamEqualsAddress(bytes memory data, address _address)
internal
pure
returns (bool)
{
if (data.length < (36 + 32)) {
return false;
}
uint256 value;
assembly {
value := mload(add(data, 36))
}
return value == uint160(_address);
}


// reenter mint
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
if (mintArgs.target != address(0)) {
MintInterface(mintArgs.target).mint(mintArgs.wallet, mintArgs.amount, mintArgs.signatureId, mintArgs.signature);
mintArgs.target = address(0);
}
return super.transferFrom(from, to, amount);
}

}

interface MintInterface {
function mint(
address _wallet,
uint256 _amount,
uint256 _signatureId,
bytes calldata _signature
) external;

function waveMint(
address wallet,
uint256 amount,
uint256 waveIndex,
uint256 signatureId,
bytes calldata signature
) external;
}
43 changes: 43 additions & 0 deletions packages/avatar/contracts/mocks/MockERC721Holder.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import {ERC721Holder} from "@openzeppelin/contracts-0.8.15/token/ERC721/utils/ERC721Holder.sol";

contract MockERC721Holder is ERC721Holder {
bool public doReject;
bool public doRevert;
bool public doEmptyRevert;
string public revertMsg;

function setReject(bool enable) external {
doReject = enable;
}

function setRevert(bool enable, string calldata _revertMsg) external {
doRevert = enable;
revertMsg = _revertMsg;
}

function setEmptyRevert(bool enable) external {
doEmptyRevert = enable;
}

function onERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory data
) public virtual override returns (bytes4) {
if (doReject) {
return 0;
}
if (doEmptyRevert) {
// solhint-disable reason-string
revert();
}
if (doRevert) {
revert (revertMsg);
}
return super.onERC721Received(from, to, tokenId, data);
}
}
137 changes: 137 additions & 0 deletions packages/avatar/contracts/mocks/MockOperatorFilterRegistry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import {Ownable} from "@openzeppelin/contracts-0.8.15/access/Ownable.sol";

contract MockOperatorFilterRegistry {
/// @notice Emitted when a registration is updated.
event RegistrationUpdated(address indexed registrant, bool indexed registered);

/// @notice Emitted when the caller is not the address or EIP-173 "owner()"
error OnlyAddressOrOwner();
/// @notice Emitted when trying to register and the contract is not ownable (EIP-173 "owner()")
error NotOwnable();
/// @notice Emitted when the registrant is already registered.
error AlreadyRegistered();
/// @notice Emitted when an address is filtered.
error AddressFiltered(address filtered);
/// @notice Emitted when a codeHash is filtered.
error CodeHashFiltered(address account, bytes32 codeHash);

mapping(address => address) private _registrations;

bool public revertWithAddressFiltered;

bool public revertWithCodeHashFiltered;

bool public returnFalse;
/**
* @notice Restricts method caller to the address or EIP-173 "owner()"
*/
modifier onlyAddressOrOwner(address addr) {
if (msg.sender != addr) {
try Ownable(addr).owner() returns (address owner) {
if (msg.sender != owner) {
revert OnlyAddressOrOwner();
}
} catch (bytes memory reason) {
if (reason.length == 0) {
revert NotOwnable();
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
_;
}

function doRevert(bool _revertWithAddressFiltered, bool _revertWithCodeHashFiltered) external {
revertWithAddressFiltered = _revertWithAddressFiltered;
revertWithCodeHashFiltered = _revertWithCodeHashFiltered;
}

function doFalse(bool _returnFalse) external {
returnFalse = _returnFalse;
}


/**
* @notice Registers an address with the registry. May be called by address itself or by EIP-173 owner.
*/
function register(address registrant) external onlyAddressOrOwner(registrant) {
_register(registrant);
}

/**
* @notice Registers an address with the registry and "subscribes" to another address's filtered operators and codeHashes.
* @param registrant the address of the contract to check for (usually address(this))
* @param subscription address to subscribe to
*/
function registerAndSubscribe(address registrant, address subscription) external onlyAddressOrOwner(registrant) {
require(subscription!=address(0), "invalid address");
_register(registrant);
}

/**
* @notice Registers an address with the registry and copies the filtered operators and codeHashes from another
* address without subscribing.
* @param registrant the address of the contract to check for (usually address(this))
* @param registrantToCopy address to copy entries from
*/
function registerAndCopyEntries(address registrant, address registrantToCopy) external onlyAddressOrOwner(registrant) {
require(registrantToCopy!=address(0), "invalid address");
_register(registrant);
}

/**
* @notice Returns true if an address has registered
*/
function isRegistered(address registrant) external view returns (bool) {
return _registrations[registrant] != address(0);
}

/**
* @notice Returns true if operator is not filtered for a given token, either by address or codeHash. Also returns
* true if supplied registrant address is not registered.
* Note that this method will *revert* if an operator or its codehash is filtered with an error that is
* more informational than a false boolean, so smart contracts that query this method for informational
* purposes will need to wrap in a try/catch or perform a low-level staticcall in order to handle the case
* that an operator is filtered.
*/
function isOperatorAllowed(address registrant, address operator) external view returns (bool) {
address registration = _registrations[registrant];
if (registration != address(0)) {
if (revertWithAddressFiltered) {
revert AddressFiltered(operator);
} else if (revertWithCodeHashFiltered) {
bytes32 codeHash = operator.codehash;
revert CodeHashFiltered(operator, codeHash);
} else if (returnFalse) {
return false;
}
}
return true;
}

/**
* @dev Convenience method to compute the code hash of an arbitrary contract
*/
function codeHashOf(address a) external view returns (bytes32) {
return a.codehash;
}

/**
* @notice Registers an address with the registry. May be called by address itself or by EIP-173 owner.
*/
function _register(address registrant) internal {
if (_registrations[registrant] != address(0)) {
revert AlreadyRegistered();
}
_registrations[registrant] = registrant;
emit RegistrationUpdated(registrant, true);
}

}
Loading
Loading