The Flip Smart Contract part 8 : Bounty endpoint

Last endpoint but not the least : the bounty

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 {
    const caller = this.blockchain.caller

    this.require(
        !this.blockchain.isSmartContract(caller),
        "caller is a smart contract"
    )

    const lastBountyFlipId = this.lastBountyFlipId().get()
    const lastFlipId = this.lastFlipId().get()

    this.require(
        lastBountyFlipId < lastFlipId,
        "last bounty flip id >= last flip id"
    )

    const currentBlockNonce = this.blockchain.currentBlockNonce

    let bountyFlipId = lastBountyFlipId

    while (bountyFlipId < lastFlipId) {
        const flipId = bountyFlipId + ManagedU64.fromValue(1)

        if (this.flipForId(flipId).isEmpty()) {
            break
        }

        const flip = 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.

Last updated