📝In-depth smart contract
A detailed description about the smart contract
Smart contract Deployement
The smart contract will be deployed juste one time on the Polygon Network. After that, the lottery starts and renews automatically with each winner draw
Imports
import "./ERC721A.sol";
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
This is all the contracts that we are gonna need:
ERC721A is popular for reduce gas price then you mint multiple items
Chainlink contracts are tools to generate a random number in a decentralized way via a chainlink oracle.
All the Constants
///parameters allowing the counting of nft already minted and still available
uint public supplyLottery = 2;
uint public alreadySupply = 0;
///Max number of NFT that 1 wallet is allow to mint
uint public max_mint_allowed = 50;
///The price of 1 NFT in $MATIC
uint public priceSale = 0.01 ether;
///We "define" the baseURI
string public baseURI;
///we "set" the extension to .json
string public baseExtension = ".json";
///Boolean to set if lottery is open/closed
bool public lotteryClosed;
Constructor
constructor(uint64 subscriptionId, string memory _theBaseURI, address _team) VRFConsumerBaseV2(vrfCoordinator) ERC721A("DefiLottery", "DFL") {
team = payable(_team);
COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator);
s_owner = 0xF15130b822eE961Aa42C6a48c5966F9Eb229e865;
s_subscriptionId = subscriptionId;
baseURI = _theBaseURI;
}
This is the constructor of the contract, with ERC721A and Chainlink. The constructor has some parameters:
-string memory _theBaseURI
--> To link the IPFS to the collection.
ERC721A:
-DeFiLottery
--> The name of the token (NFT).
-DFL
--> The symbol of the tokens
Line 1: team = payable(_team);
--> Address for the team payment
Line 2: COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator);
--> Address of the Chainlik vrfCoordinator
Line 3: s_owner;
--> A function to transfer the Ownership,from the Owner to the new Owner,if somebody is going wrong with our smart contract deployer...
Line 4: s_subscriptionId = subscriptionId;
--> The Id of subscription on Chainlink services
Line 5: baseURI = theBaseURI;
--> To redefines the name of theBaseURI to baseURI (wich is use to link the IPFS to the collection)
Functions
In the smart contract,we are using some functions to make different actions...
///To change the maxMint allowed
function changeMaxMintAllowed(uint _maxMintAllowed) external onlyOwner {
max_mint_allowed = _maxMintAllowed;
}
///To change the price sale (if the market is too volatile)
function changePriceSale(uint _priceSale) external onlyOwner {
priceSale = _priceSale;
}
///To change the BaseURI
function setBaseUri(string memory _newBaseURI) external onlyOwner {
baseURI = _newBaseURI;
}
///Return the BaseURI
function _baseURI() internal view virtual override returns (string memory) {
return baseURI;
}
///To set the base extension
function setBaseExtension(string memory _baseExtension) external onlyOwner {
baseExtension = _baseExtension;
}
///Return the token URI from the token ID
function tokenURI(uint _tokenId) public view virtual override returns (string memory) {
require(_exists(_tokenId), "URI query for nonexistent token");
return string(abi.encodePacked(baseURI, _tokenId.toString(), ".json"));
}
///Return the balance of the contract
function getBalance() public view returns(uint) {
return address(this).balance;
}
///Define the number of available tickets for the lottery
function changeSupplyLottery(uint _supplyLottery) external onlyOwner {
supplyLottery = _supplyLottery;
}
///For update the number of tickets already sell
function changeAlreadySupply(uint _alreadySupply) external onlyOwner {
alreadySupply = _alreadySupply;
}
///Return the winner address for selected lottery
function getWinner(uint _idLottery) external view returns(address) {
return winners[_idLottery];
}
The Mint
function enter(address _account, uint256 _ammount) external payable nonReentrant {
require(!lotteryClosed, "Lottery is closed");
The lottery must be open for initiate the mint
uint price = priceSale; require(msg.value >= price * _ammount, "Not enought funds.");
The funds in your wallet must be superior than the price of 1 ou multiples tickets
require(_ammount <= max_mint_allowed, "You can't mint more than 50 tickets");
The quantity of tickets you would mint must inferior than the limit. Limit is defined by max_mint_allowed
require(totalSupply() + _ammount <= supplyLottery + alreadySupply, "Number of remaining tickets is insufficient");
the number of tickets youls purchase must be inferior than the remaining tickets of the current lottery
players.push(payable(msg.sender));
If you mint, your address is added to the table of players
if(totalSupply() + _ammount == supplyLottery + alreadySupply) { lotteryClosed = true; }
When the last ticket is minted, the lottery will be closed
_safeMint(_account, _ammount); }
Transfer the quantity of purchase's tickets in your wallet
The Draw
function requestRandomWords() external onlyOwner {
require(lotteryClosed, "Lottery is not closed");
s_requestId = COORDINATOR.requestRandomWords(
keyHash,
s_subscriptionId,
requestConfirmations,
callbackGasLimit,
numWords
);
}
This function allows to draw a random number via chainlink oracle. Without this, it's impossible to define the winner, pay the winner and pay the team
require(lotteryClosed, "Lottery is not closed");
The lottery must be closed for initiate this function
uint winner = s_randomWords[0] % players.length;
the winner address is picked using the random number and the total of addresses register in the table of players
players[winner].transfer(address(this).balance / 100 * 80);
Automatically, the winner address receive 80% of contract's balance
team.transfer(address(this).balance);
After the first transfer, the team receive the remaing balance
winners[idLottery] = players[winner];
The winner address is indexed on the table of winner
idLottery++;
the lottery moves to a higher rank
players = new address payable[](0);
the table of players is reset
alreadySupply = totalSupply();
The number of tickets sold during the current lottery change for the number of tickets sold during all the lotteries
lotteryClosed = false;
The new lottery is now open
s_randomWords = new uint256[](0);
The table of random number is reset. By this way a new random number must be drawn for each lottery
Last updated