Skip to content

Ordinal Swap

Ordinal swap settlement and cancel flow.

txt
Contract OrdinalSwap:
    Struct Script:
        SuffixData: string
        PartialHash: string
        Size: number

    Struct Output:
        Value: number
        LockingScript: Script

    Struct CurrentTX:
        Outputs: Output[3]

    def swap(aliceSig: hex, ctx: CurrentTX, prevouts: hex, path: number):
        if path == 1:
            Delete(aliceSig)

            # The supplied prevouts bytes must hash to the transaction input digest.
            prevouts_for_hash = prevouts.Clone()
            EqualVerify(Sha256(prevouts_for_hash), BVM.inputsHash)

            # Input 0 is reserved for the outpoint being unlocked now.
            prevouts_for_first = prevouts.Clone()
            first_outpoint = prevouts_for_first.Slice(0, 36)
            current_outpoint = BVM.unlockingInput.Slice(0, 36)
            EqualVerify(first_outpoint, current_outpoint)

            # Input 1 must match Bob's pre-agreed outpoint and amount.
            second_outpoint = prevouts.Slice(40, 36)
            EqualVerify(second_outpoint, self.prevoutBob)

            # Output 0 sends the one-satoshi item to Bob's P2PKH address.
            out0_suffix = ctx.Outputs[0].LockingScript.SuffixData.Clone()
            { out0_prefix, out0_suffix } = Split(out0_suffix, 3)
            EqualVerify(out0_prefix, 0x76a914)
            { out0_pkh, out0_tail } = Split(out0_suffix, 20)
            EqualVerify(out0_tail, 0x88ac)
            EqualVerify(out0_pkh, Hash160(self.bob))
            out0_value_num = BinToNum(ctx.Outputs[0].Value.Clone())
            NumEqualVerify(out0_value_num, 1)

            # Output 1 pays Alice the agreed value from Bob's side of the swap.
            out1_suffix = ctx.Outputs[1].LockingScript.SuffixData.Clone()
            { out1_prefix, out1_suffix } = Split(out1_suffix, 3)
            EqualVerify(out1_prefix, 0x76a914)
            { out1_pkh, out1_tail } = Split(out1_suffix, 20)
            EqualVerify(out1_tail, 0x88ac)
            EqualVerify(out1_pkh, Hash160(self.alice))
            out1_value_num = BinToNum(ctx.Outputs[1].Value.Clone())
            NumEqualVerify(out1_value_num, self.prevoutBobAmount)

            # Hash the three expected outputs and bind them to the current transaction.
            outputs_data = Push(0)
            SetAlt(outputs_data)
            for i in Range(2, -1, -1):
                size = ctx.Outputs[i].LockingScript.Size.Clone()
                if size != 0:
                    outputs_data_temp = PartialHash(ctx.Outputs[i].LockingScript.SuffixData, ctx.Outputs[i].LockingScript.PartialHash, ctx.Outputs[i].LockingScript.Size)
                    outputs_data_temp = Cat(ctx.Outputs[i].Value, outputs_data_temp)
                    SetMain(outputs_data)
                    outputs_data = Cat(outputs_data_temp, outputs_data)
                    SetAlt(outputs_data)
                    Keep(outputs_data)
                else:
                    Delete(ctx.Outputs[i].LockingScript.Size)
                    Delete(ctx.Outputs[i].LockingScript.PartialHash)
                    Delete(ctx.Outputs[i].LockingScript.SuffixData)
                    Delete(ctx.Outputs[i].Value)

            SetMain(outputs_data)
            outputs_data = Sha256(outputs_data)
            EqualVerify(outputs_data, BVM.outputsHash)
        else:
            # Cancel is a simple Alice-signed branch; transaction-shape data is discarded.
            Delete(prevouts)
            Delete(ctx)
            CheckSigVerify(self.alice, aliceSig)