Introduction
- Front-end repository
- Lottery contract
- Remix
- Unix Timestamp generator
- Ethereum Unit Converter
- Random Byte Generator
We will use Goerli test network.
tx - short name for transaction
Table of contents
Deploy with Remix
-
Remix editor
Go to Remix editor and create there file: Lottery.sol
-
Lottery contract code
Copy Pancakeswap Lottery contract code from the Bscscan: https://bscscan.com/address/0x5aF6D33DE2ccEC94efb1bDF8f92Bd58085432d2c#contracts And paste it into the new Lottery.sol file:
-
Contract preparation
Set up basic lottery rules
MAX_TREASURY_FEE - Your commission
maxPriceTicketInCake - Maximum ticket price
minPriceTicketInCake - Minimum ticket price
MIN_DISCOUNT_DIVISOR - Minimum discount if the user buys many tickets at once
MIN_LENGTH_LOTTERY - Minimum round duration
MAX_LENGTH_LOTTERY - Maximum round duration
Set the address where the commission will be transferred and who will be able to manage the lottery by adding this code to the constructor
injectorAddress = msg.sender;
operatorAddress = msg.sender;
treasuryAddress = msg.sender;
msg.sender; - Returns the address of the account from which the lottery contract will be deployed
Add this code to the contract constructor.
currentLotteryId++;
Comment out this line in the method
_lotteries[currentLotteryId] = Lottery({
status: Status.Claimable,
startTime: block.timestamp,
endTime: block.timestamp,
priceTicketInCake: 0,
discountDivisor: 0,
rewardsBreakdown: [uint256(250),uint256(375),uint256(625),uint256(1250),uint256(2500),uint256(5000)],
treasuryFee: 2000,
cakePerBracket: [uint256(0), uint256(0), uint256(0), uint256(0), uint256(0), uint256(0)],
countWinnersPerBracket: [uint256(0), uint256(0), uint256(0), uint256(0), uint256(0), uint256(0)],
firstTicketId: currentTicketId,
firstTicketIdNextLottery: currentTicketId,
amountCollectedInCake: pendingInjectionNextLottery,
finalNumber: 1000000
});
closeLottery
Add thebytes32 _seed
parameter to thedrawFinalNumberAndMakeLotteryClaimable
function of theIPancakeSwapLottery
interface
Add thebytes32 _seed
parameter to thedrawFinalNumberAndMakeLotteryClaimable
function
Comment out the line
require(_lotteryId == randomGenerator.viewLatestLotteryId(), "Numbers not drawn");
in thedrawFinalNumberAndMakeLotteryClaimable
method
Replace the random number generator in thedrawFinalNumberAndMakeLotteryClaimable
method
to this code
uint256 randomness = uint(keccak256(abi.encodePacked(
block.timestamp,
_seed,
_lotteryId,
_lotteries[_lotteryId].firstTicketId,
_lotteries[_lotteryId].firstTicketIdNextLottery,
_lotteries[_lotteryId].amountCollectedInCake,
block.coinbase,
block.difficulty,
block.gaslimit,
tx.gasprice
)));
uint32 finalNumber = uint32(1000000 + (randomness % 1000000));
-
Contract Compilation
Go to "Solidity Compiler" tab. Change compiler version with 0.8.18 if it's different. Enable optimization option to 99999 and click button "Compile":
-
Deploy contract
Go to "Deploy & run transaction" tab. Select Injected Web3 in the ENVIRONMENT drop-down. It will use your external wallet. We will use Metamask wallet. If you didn't login in the wallet then login it now, reload page, come back and compile lottery contract one more time. And again chose Injected Web3 option. Chose Goerli network in the Metamask. Select PancakeSwapLottery in the CONTRACT drop-down (probably it's already made by default).
Set an address of your ERC20 token in the _CAKETOKENADDRESS field.
Set0x0000000000000000000000000000000000000000
in the _RANDOMGENERATORADDRESS field
Now you can see something like this in the deploy tab:
So now click on "transact" button and confirm a modal window from external wallet with transaction fee: -
Save Lottery contract address
After transaction has been mined you can see all details in the Remix terminal: Copy a transaction hash and go to Goerli etherscan. Paste this hash in the search field and go to a new contract page. Copy his address and save it somewhere.
Now we have this data:
PancakeSwapLottery:0xad661a60bd10caf905a177ac36cefdab43744a8a
Frontend
Main changes in this interface template:
- Removed all (or almost all) info about pancakeswap
- Installing Our Lottery Contract
- Set lottery page as default
- Changed source styles just a little.
-
Cloning PancakeSwap Lottery
Create a new directory: Lottery. Copy front-endcode in this directory then install dependencies
yarn
After installing the dependencies, you will see the following -
Home page customization
Let's make the lottery the main page
Open file\apps\web\src\pages\_app.tsx
Add an import
import Lottery from "./lottery"
Add a lottery call<Lottery {...pageProps} />
and comment out the code below as shown in the image -
Setting up a contract
Open the file \apps\web\src\utils\addressHelpers.ts and add the following code
return '0xad661a60bd10caf905a177ac36cefdab43744a8a'
Enter the address of your lottery contract that you created earlier
-
Blockchain setup
Set up the blockchain that will run the lottery
Open \apps\web\src\config\constants\supportChains.ts
And enter your network ID
Open file \apps\web\src\hooks\useProviderOrSigner.ts
And enter your network ID
Open \apps\web\src\utils\contractHelpers.ts
And enter your network ID
Open file \apps\web\src\state\lottery\helpers.ts And specify your network ID in all calls to multicallv2 Open \apps\web\src\state\lottery\fetchUnclaimedUserRewards.ts And specify your network ID in all calls to multicallv2 -
Setting up a token
Open \apps\web\src\utils\contractHelpers.ts
Specify your network ID and the address of your token Open \apps\web\src\config\constants\tokenLists\pancake-default.tokenlist.json
Add information about your token as shown in the example
{
Open file \apps\web\src\views\Lottery\components\BuyTicketsModal\BuyTicketsModal.tsx
"name": "WEENUS",
"symbol": "WEENUS",
"address": "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
"chainId": 5,
"decimals": 18,
"logoURI": "https://pancakeswap.finance/images/lottery/star-small.png"
}
And find the lineconst { balance: userCake, fetchStatus } = useTokenBalance(bscTokens.cake.address)
ReplacebscTokens.cake.address
with the address of your token
Replace all references to "CAKE" with to the character of your token.
To do this, just edit the files in the folder \apps\web\src\views\Lottery\
Be careful. Replace only strings -
Launch of the project
To start the project, run the command in the root directory
yarn dev
If done correctly, the lottery will be available at http://localhost:3000/
These were the minimum actions needed for the lottery to work and to collect the commission.
Lottery Rounds control
-
Round life cycle
In the lottery rounds have the following states
-
Open
- The round is active. Users can buy tickets -
Close
- The round is closed. Waiting for the calculation of winnings -
Pending
- Waiting for results. Users cannot buy tickets -
Claimable
- Winning this round is calculated. Users can find out the result and get a reward
Life cycle:
Open
>Close
>Pending
>Claimable
To manage the lifecycle of rounds in a contract, the appropriate methods are -
-
Connection with a contract
To manage the rounds, you need to interact with the contract. To do this, you need to connect to the contract. For interaction with the contract will use Remix
Go to Remix editor and select contract file Lottery.solCompile the contract by compile instructions
Go to "Deploy & run transaction" tab. Select Injected Web3 in the ENVIRONMENT drop-down. It will use your external wallet. We will use Metamask wallet. If you didn't login in the wallet then login it now, reload page, come back and compile lottery contract one more time. And again chose Injected Web3 option. Chose Goerli network in the Metamask. Select PancakeSwapLottery in the CONTRACT drop-down (probably it's already made by default).
Enter your contract address and click "At Address" After that, the contract control panel will appear at the bottom. Click on it to display the control panel. -
Active round number
Most contract methods use the current round number. To find out it, execute the "currentLotteryId" method After pressing the button, the current lottery round will be shown
-
Start of a new round
To start a new round, use the startLottery
method Method parameters:
-
_endTime
- The time the round will end. Value in UnixTimestamp -
_priceTicketInCake
- Price of a ticket in the current round. Meaning in Wei -
_discountDivisor
- Discount when buying several tickets at once in one transaction.
Calculation formula_discountDivisor = needValue% * 100
.
Example: 0.5% = 0.5 * 100 = 50, 2% = 2 * 100 = 200 -
_rewardsBreakdown
- Win percentage for each matched combination of balls
An array of six numbers. The sum of the numbers must be equal to 10000
Calculation formulaV = needValue% * 100
Example:
Desired win distribution percentage:[0%, 7%, 13%, 20%, 25%, 30%]
Method call data:[0, 700, 1300, 2000, 2500, 3500]
-
_treasuryFee
- Your commission in the current round
Calculation formulaV = needValue% * 100
-
-
Closing the round
When the time of the round is over, it must be closed. To close, use the "closeLottery" method Method parameters:
-
_lotteryId
- Number of the round to be closed
Specify current round number and click "transact" to close the round -
-
Winning combination calculation
The final step in the life cycle of a round is the calculation of the winning numbers. To do this, use the
drawFinalNumberAndMakeLotteryClaimable
method Method parameters:
-
_lotteryId
- Round number -
_seed
- Random set of bytes of length 32.
Example: Let's create 32 random numbers through the service Random.org The service will generate 32 random numbers HEX string of these numbers will be
0xf708a0a28a75973d69ea1d04065f62d57c135def2d750beb0ed39ae55a262cf9
-
_autoInjection
- TRUE | FALSE, if set to TRUE, the balance of not won tokens will be automatically transferred to a new round
To calculate the winning numbers, specify the parameters and click "transact" to calculate the winnings After that, the round is over. You can now start a new round -