Skip to content

Oracle Demo BSV20

Schnorr-signed BSV20 oracle message verifier.

txt
# The Schnorr parameters are stored on the instance: generator, modulus, and oracle public key.
# The signed message is tied to the exact outpoint being spent.

import std.schnorr

Contract OracleDemoBsv20:

    def main(msg: hex, R: hex, s: hex):
        # Capture the outpoint bytes from the current unlocking input.
        outpoint = BVM.unlockingInput.Slice(0, 36)
        SetAlt(outpoint)

        # Clone `msg` so it can be parsed after Schnorr verification consumes the original.
        msg_for_parse = msg.Clone()
        SetAlt(msg_for_parse)

        schnorrVerify(msg, R, s, self.oraclePubKey, self.generator, self.modulus)
        SetMain(msg_for_parse)

        # Parse the signed payload in the agreed byte order.
        # marker(1) | timestamp(4) | network(1) | outpoint(36) | flag(1) | amount(8) | id(rest)

        {marker_b, r1} = Split(msg_for_parse, 1)
        NumEqualVerify(BinToNum(marker_b), 4)

        {ts_b, r2} = Split(r1, 4)
        Delete(ts_b)

        {net_b, r3} = Split(r2, 1)
        NumEqualVerify(BinToNum(net_b), 0)

        {op_b, r4} = Split(r3, 36)
        SetMain(outpoint)
        EqualVerify(op_b, outpoint)

        {fung_b, r5} = Split(r4, 1)
        NumEqualVerify(BinToNum(fung_b), 1)

        {amt_b, id_b} = Split(r5, 8)
        # Add a zero byte before numeric conversion so the amount is treated as unsigned.
        amt_chk = GreaterOrEqual(BinToNum(Cat(amt_b, 0x00)), self.amt)
        NumEqualVerify(amt_chk, 1)

        EqualVerify(id_b, self.inscriptionId)