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

fix: lottery tests and align design to factory #41

Merged
merged 4 commits into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
56 changes: 32 additions & 24 deletions contracts/apps/factory/lotteryFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ pragma solidity ^0.8.24;

import { NFTLottery } from "../lottery.sol";
import { ERC721Handler, ERC1155Handler } from "./lotteryTokens.sol";
import { INFTLotteryFactory, INFTHandler } from "./lotteryinterface.sol";
import { INFTLotteryFactory } from "./lotteryinterface.sol";
import { IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.sol";
import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import { IERC1155 } from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "hardhat/console.sol";

abstract contract NFTLotteryFactory is INFTLotteryFactory {
contract NFTLotteryFactory is INFTLotteryFactory {
enum NFTStandards {
ERC721,
ERC1155
Expand All @@ -22,44 +23,42 @@ abstract contract NFTLotteryFactory is INFTLotteryFactory {

function createLottery(
address nftContract,
address decrypter,
uint256 fee,
uint8 threshold,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Mmmm...
Is there any reason to remove the threshold param from the function signature?? Cause it is required at the time of deployment of lottery

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We change the requirement specification requested by Olli. Its probably that after this PR some more changes will be require. Hope doesnt change to much on the re-design part.

address fairyring
) public returns (address) {
address fairyringContract,
address decrypter
) external override returns (NFTLottery) {
// console.log("createLottery");
bool isERC721 = _supportsInterface(nftContract, type(IERC721).interfaceId);
bool isERC1155 = _supportsInterface(nftContract, type(IERC1155).interfaceId);

address nftHandler;
NFTStandards standard;

if (isERC721) {
// console.log("ERC721");
nftHandler = address(new ERC721Handler(nftContract));
standard = NFTStandards.ERC721;
} else if (isERC1155) {
// console.log("ERC1155");
// Example
uint256[] memory ids;
ids[0] = 1;
// ids[1] = 2;
// ids[2] = 3;

uint256[] memory amounts;
uint256[] memory ids = new uint256[](12);
ids[0] = 1;
uint256[] memory amounts = new uint256[](12);
amounts[0] = 1000;
// amounts[1] = 1000;
// amounts[2] = 2000;

nftHandler = address(new ERC1155Handler(nftContract, ids, amounts));
standard = NFTStandards.ERC1155;
} else {
revert NFTLotteryFactory__UnsupportedNFTStandards();
}

address lotteryAddress = _deployLottery(nftHandler, fee, threshold, fairyring, decrypter);
NFTLottery lottery = _deployLottery(nftHandler, fee, fairyringContract, decrypter);

lotteryTypes[lotteryAddress] = standard;
emit LotteryCreated(lotteryAddress, standard);
lotteryTypes[address(lottery)] = standard;
emit LotteryCreated(address(lottery), standard);

return lotteryAddress;
return lottery;
}

function _supportsInterface(address contractAddress, bytes4 interfaceId) internal view returns (bool) {
Expand All @@ -73,12 +72,13 @@ abstract contract NFTLotteryFactory is INFTLotteryFactory {
function _deployLottery(
address nftHandler,
uint256 fee,
uint8 threshold,
address fairyringContract,
address decrypter
) internal returns (address) {
NFTLotteryProxy lottery = new NFTLotteryProxy(nftHandler, fee, threshold, fairyringContract, decrypter);
return address(lottery);
) internal returns (NFTLottery) {
// console.log("_deployLottery called.");
NFTLotteryProxy lotteryProxy = new NFTLotteryProxy(nftHandler, fee, fairyringContract, decrypter);
// console.log("_deployLottery finish.");
return lotteryProxy.getLottery();
}
}

Expand All @@ -90,15 +90,23 @@ contract NFTLotteryProxy {
uint256 private immutable fee;
address private immutable implementation;

constructor(address _nftHandler, uint256 _fee, uint8 _threshold, address _fairyringContract, address _decrypter) {
NFTLottery private _lottery;

constructor(address _nftHandler, uint256 _fee, address _fairyringContract, address _decrypter) {
// console.log("NFTLotteryProxy called.");
nftHandler = _nftHandler;

// Deploy implementation contract
// implementation = address(new NFTLottery(_nftHandler, _fee, _threshold, _fairyringContract, _decrypter)); // Temporary Soln
_lottery = new NFTLottery(_nftHandler, _fee, _fairyringContract, _decrypter);
implementation = address(_lottery);
fee = _fee;
th = _threshold;
fairyring = _fairyringContract;
decrypter = _decrypter;
// console.log("NFTLotteryProxy finish.");
}

function getLottery() external view returns (NFTLottery) {
return _lottery;
}

fallback() external payable {
Expand Down
20 changes: 18 additions & 2 deletions contracts/apps/factory/lotteryTokens.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ pragma solidity ^0.8.24;

import { INFTLotteryFactory, INFTHandler } from "./lotteryinterface.sol";
import { IERC1155 } from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import { ILazy1155 } from "../../interfaces/token/ILazy1155.sol";
import { IERC721Enumerable } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import "hardhat/console.sol";

contract ERC721Handler is INFTHandler {
IERC721Enumerable private nftContract;
error LazyERC721__TokenIdDoesntExist();

constructor(address _nftContract) {
// console.log("ERC721Handler ctor");
nftContract = IERC721Enumerable(_nftContract);
}

Expand All @@ -33,10 +37,16 @@ contract ERC721Handler is INFTHandler {
function isApprovedForAll(address owner, address operator) external view returns (bool) {
return nftContract.isApprovedForAll(owner, operator);
}

function tokenExists(uint256 ) public pure returns (bool) {
// console.log("ERC721 tokenExists.");
// revert LazyERC721__TokenIdDoesntExist();
return true; // TODO: here we need to check for token id
}
}

contract ERC1155Handler is INFTHandler {
IERC1155 private nftContract;
ILazy1155 private nftContract;

mapping(uint256 => uint256) private supply; // tokenId => maxSupply
mapping(uint256 => uint256) private allocatedAmounts; // tokenId => amount
Expand All @@ -45,13 +55,15 @@ contract ERC1155Handler is INFTHandler {
error ERC1155Handler__NotSupported();

constructor(address _nftContract, uint256[] memory _tokenIds, uint256[] memory _maxSupplies) {
// console.log("ERC1155Handler ctor");
require(_tokenIds.length == _maxSupplies.length, "Arrays length mismatch");
nftContract = IERC1155(_nftContract);
nftContract = ILazy1155(_nftContract);

for (uint256 i = 0; i < _tokenIds.length; i++) {
supply[_tokenIds[i]] = _maxSupplies[i];
supportedTokenIds.push(_tokenIds[i]);
}
// console.log("ERC1155Handler ctor finish");
}

function transferNFT(address from, address to, uint256[] memory tokenIds, uint256[] memory amounts) external {
Expand Down Expand Up @@ -93,4 +105,8 @@ contract ERC1155Handler is INFTHandler {
function isApprovedForAll(address owner, address operator) external view returns (bool) {
return nftContract.isApprovedForAll(owner, operator);
}

function tokenExists(uint256 _tokenId) public view returns (bool) {
return nftContract.tokenExists(_tokenId);
}
}
6 changes: 4 additions & 2 deletions contracts/apps/factory/lotteryinterface.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import { NFTLottery } from "../lottery.sol";

interface INFTHandler {
function transferNFT(address from, address to, uint256[] memory tokenIds, uint256[] memory amounts) external;
Expand All @@ -11,14 +12,15 @@ interface INFTHandler {
function balanceOf(address user, uint256 tokenId) external view returns (uint256);

function isApprovedForAll(address owner, address operator) external view returns (bool);

function tokenExists(uint256 _tokenId) external view returns (bool);
}

interface INFTLotteryFactory {
function createLottery(
address nftContract,
uint256 fee,
uint8 threshold,
address fairyringContract,
address decrypter
) external returns (address);
) external returns (NFTLottery);
}
58 changes: 35 additions & 23 deletions contracts/apps/lazy1155.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,82 +11,83 @@ import "hardhat/console.sol";

import { Strings } from "../utils/Strings.sol";
import { Integers } from "../utils/Integers.sol";
import { ILazy1155 } from "../interfaces/token/ILazy1155.sol";

contract Lazy1155 is ERC1155, Ownable, ERC1155Pausable, ERC1155Burnable, ERC1155Supply {
uint256 public constant INITIAL_ID = 0;
uint16 private _tokenCap;
contract Lazy1155 is ILazy1155, ERC1155, Ownable, ERC1155Pausable, ERC1155Burnable, ERC1155Supply {
uint256 private _totalEmittion;

error Lazy1155__TokenIdDoesntExist(); // TODO: Look for how to check Ids in batch
error Lazy1155__TokenCapExceeded();
error Lazy1155__QuantityMustBeGreaterThanCero();
error Lazy1155__NoBalanceForTokenId();

// Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
constructor(uint16 tokenCap, string memory _uri, uint256 quantity) ERC1155(_uri) Ownable(msg.sender) {
_tokenCap = tokenCap;
// Creates amount tokens of token type id, and assigns them to account.
if (quantity > 0) {
mint(msg.sender, INITIAL_ID, quantity, ""); // Token ID 0, quantity 100
}
constructor(uint256 totalEmmition, string memory _uri) ERC1155(_uri) Ownable(msg.sender) {
_totalEmittion = totalEmmition;
}

function setURI(string memory newuri) public onlyOwner {
function setURI(string memory newuri) external onlyOwner {
_setURI(newuri);
}

function tokenURI(address from, uint256 tokenId) public view returns (string memory) {
if (!tokenExists(tokenId)) revert Lazy1155__TokenIdDoesntExist();
if (!isOwnerOfToken(from, tokenId)) revert Lazy1155__NoBalanceForTokenId();
function tokenURI(address from, uint256 tokenId) external view returns (string memory) {
// console.log("tokenURI called.");
if (!this.tokenExists(tokenId)) revert Lazy1155__TokenIdDoesntExist();
if (!this.isOwnerOfToken(from, tokenId)) revert Lazy1155__NoBalanceForTokenId();

string memory uri = Strings.replace(super.uri(tokenId), "{id}", Integers.toString(tokenId), 1);
console.log("[%s]", uri);
//console.log("[%s]", uri);
return uri;
}

function isOwnerOfToken(address _owner, uint256 _tokenId) public view returns (bool) {
function isOwnerOfToken(address _owner, uint256 _tokenId) external view returns (bool) {
uint256 balance = super.balanceOf(_owner, _tokenId);
return balance > 0;
}

function tokenExists(uint256 _tokenId) public view returns (bool) {
function tokenExists(uint256 _tokenId) external view returns (bool) {
// Check the total supply of the token ID
// console.log("tokenExists called.");
uint256 totalSupply = totalSupply(_tokenId);
return totalSupply > 0;
}

function pause() public onlyOwner {
function pause() external onlyOwner {
_pause();
}

function unpause() public onlyOwner {
function unpause() external onlyOwner {
_unpause();
}

function mint(address account, uint256 id, uint256 amount, bytes memory data) public onlyOwner {
function mint(address account, uint256 id, uint256 amount, bytes memory data) external onlyOwner {
uint256 totalSuply = totalSupply();
//console.log("[%s]", totalSuply);
// TODO: overflow?
if (totalSuply + amount > _tokenCap) {
if (totalSuply + amount > _totalEmittion) {
revert Lazy1155__TokenCapExceeded();
}
_mint(account, id, amount, data);
}

function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) public onlyOwner {
function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) external onlyOwner {
uint256 totalSuply = totalSupply();
//console.log("mintBatch [%s]", totalSuply);
uint256 totalAmount = 0;
for (uint256 i = 0; i < amounts.length; ++i) {
// TODO: overflow?
totalAmount += amounts[i];
//console.log("ammount [%s]", amounts[i]);
}
if (totalSuply + totalAmount > _tokenCap) {
//console.log("[%s] > [%s]", totalSuply + totalAmount, _totalEmittion);
if (totalSuply + totalAmount > _totalEmittion) {
// TODO: overflow?
revert Lazy1155__TokenCapExceeded();
}
_mintBatch(to, ids, amounts, data);
}

// The following functions are overrides required by Solidity.

function _update(
address from,
address to,
Expand All @@ -95,4 +96,15 @@ contract Lazy1155 is ERC1155, Ownable, ERC1155Pausable, ERC1155Burnable, ERC1155
) internal override(ERC1155, ERC1155Pausable, ERC1155Supply) {
super._update(from, to, ids, values);
}

function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) public override(ILazy1155, ERC1155) {
super.safeTransferFrom(from,to,id,value,data);
}

function balanceOf(address account, uint256 id) public view override(ILazy1155, ERC1155) returns (uint256){
return super.balanceOf(account,id);
}
function isApprovedForAll(address owner, address operator) public view override(ILazy1155, ERC1155) returns (bool){
return super.isApprovedForAll(owner,operator);
}
}
2 changes: 1 addition & 1 deletion contracts/apps/lazy721a.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ contract Lazy721A is ERC721A, Ownable {
*/
function safeMint(address to, uint256 quantity) external onlyOwner {
uint256 totalSuply = totalSupply();
console.log("TS[%s] Q[%s] C[%s]", totalSuply, quantity, _tokenCap);
// console.log("TS[%s] Q[%s] C[%s]", totalSuply, quantity, _tokenCap);
if (quantity == 0) revert Lazy721A__QuantityMustBeGreaterThanCero();
if (totalSuply + quantity > _tokenCap) revert Lazy721A__TokenCapExceeded();
_mint(to, quantity);
Expand Down
Loading