Our contract is almost finished. We are able to initiate flips and generate their results, but at the moment we only have logic for generate a single flip result. We will write the bounty endpoint that will be call the previously written function make_flip for each initiated flip.
Waiting flips
Earlier, when writing the storage, we wrote two values : lastFlipId and lastBountyFlipId.
Theses two values let us know which flips need to be made, the flips are in the range lastBountyFlipId (excluded) to lastFlipId (included).
Here is a timeline example, let's assume minimumBlockBounty is 2, meaning that a flip's result can only be generate two blocks after initialisation :
Block 1 : Our contract is deployed
Block 2 : Alice bets 0.5 $EGLD, flip with id = 1 is created and lastFlipId is now 1
Block 4 : Bob calls bounty endpoint and makes Alice's flip, lastBountyFlipId is now 1
Block 5 : Alice bets 0.5 $EGLD (flip with id 2), Bob bets 1 $EGLD (flip with id 3), lastFlipId is now 3
Block 6 : Charles bets 1 $EGLD (flip with id 4), lastFlipId is now 4. Note that lastBountyFlip is still 1, meaning that flips 2, 3 and 4 are waiting for bounty.
Block 7 : David call bounty endpoint and makes Alice and Bob flips but NOT Charles one because at least 2 blocks are required between the bet and the generation. lastBountyFlipId is now 3
Block 8 : David calls again bounty and makes Charles' flip, lastBountyFlipId is now 4, the same as lastFlipId, no flips are waiting for bounty.
Bounty endpoint code
Here is the bounty endpoint code :
bounty(): void{constcaller=this.blockchain.callerthis.require(!this.blockchain.isSmartContract(caller),"caller is a smart contract" )constlastBountyFlipId=this.lastBountyFlipId().get()constlastFlipId=this.lastFlipId().get()this.require(lastBountyFlipId<lastFlipId,"last bounty flip id >= last flip id" )constcurrentBlockNonce=this.blockchain.currentBlockNonceletbountyFlipId=lastBountyFlipIdwhile (bountyFlipId<lastFlipId) {constflipId=bountyFlipId+ManagedU64.fromValue(1)if (this.flipForId(flipId).isEmpty()) {break}constflip=this.flipForId(flipId).get()if (currentBlockNonce<flip.blockNonce+flip.minimumBlockBounty) {break}this.makeFlip(caller,flip )bountyFlipId=bountyFlipId+ManagedU64.fromValue(1)}this.require(bountyFlipId!=lastBountyFlipId,"no bounty" )this.lastBountyFlipId().set(bountyFlipId)}
With explanations above this code should not be difficult to read. The only new method used is isSmartContract that indicates if whether or not an address is a smart contract, here we don't want smart contracts to call this endpoint. A smart contract calling this endpoint has the ability to revert the transaction if the result doesn't suit it.
Notice that we break the while loop if we cannot generate a flip's result for any reason because in a such case there is no chance next flips can be made (for the same reason).
Next up
We finished writing our contract ! In the next part we will talk about testing.