Further reading/

English auction

In this example, we will rewrite the English auction contract from the Plutus Pioneer's program in Helios.

This validator can be used to lock assets that are to be auctioned in a UTxO.

main

spending english_auction

struct Datum {
    seller:         PubKeyHash
    bid_asset:      AssetClass     // allow alternative assets (not just lovelace)
    min_bid:        Int
    deadline:       Time
    for_sale:       Value          // the asset that is being auctioned
    highest_bid:    Int            // initialized at 0, which signifies the auction doesn't yet have valid bids
    highest_bidder: PubKeyHash

    func update(self, highest_bid: Int, highest_bidder: PubKeyHash) -> Datum {
        self.copy(highest_bid: highest_bid, highest_bigger: highest_bidder)
    }
}

enum Redeemer {
    Close 
    Bid {
        bidder: PubKeyHash
        bid: Int
    }
}

func main(datum: Datum, redeemer: Redeemer, ctx: ScriptContext) -> Bool {
    tx: Tx = ctx.tx;

    now: Time = tx.time_range.start;

    validator_hash: ValidatorHash = ctx.get_current_validator_hash();

    redeemer.switch {
        Close => {
            if (datum.highest_bid < datum.min_bid) {
                // the forSale asset must return to the seller, what happens to any erroneous bid value is irrelevant
                tx
                  .value_sent_to(datum.seller)
                  .contains(datum.for_sale + datum.highest_bid) &&
                // Check that the deadline has passed
                now > datum.deadline                                    
            } else {
                // Check that the seller receives the highest bid
                tx
                  .value_sent_to(datum.seller)
                  .contains(Value::new(datum.bid_asset, datum.highest_bid))    &&
                // Check that highest bidder is given the token being auctioned
                tx
                  .value_sent_to(datum.highest_bidder)
                  .contains(datum.for_sale)                                    &&
                // Check that the deadline has passed
                now > datum.deadline                                    
            }
        },
        b: Bid => {
            if (b.bid < datum.min_bid) {
                false
            } else if (b.bid <= datum.highest_bid) {
                false
            } else {
                // first bid is placed by the auction creator
                expected_datum: Datum = datum.update(b.bid, b.bidder);

                // Check that new Auction UTxO contains the token for sale and the new bid
                tx
                  .value_locked_by_datum(validator_hash, expected_datum)
                  .contains(datum.for_sale + Value::new(datum.bid_asset, b.bid)) &&
                // Check that the old highest bidder is repayed
                tx
                  .value_sent_to(datum.highest_bidder)
                  .contains(Value::new(datum.bid_asset, datum.highest_bid))      &&
                // Check that the deadline hasn't passed
                now < datum.deadline
            }
        }
    }
}