Ordinal Lock
Permissionless ordinal purchase with seller-signed cancellation.
txt
# A listed ordinal can be purchased permissionlessly if outputs pay the item and price correctly.
# The seller can also cancel the listing with a matching signature.
Contract OrdinalLock:
Struct Script:
SuffixData: string
PartialHash: string
Size: number
Struct Output:
Value: number
LockingScript: Script
Struct CurrentTX:
Outputs: Output[3]
# `path == 1` purchases the ordinal; any other path cancels with the seller signature.
def main(dest: hex, sig: hex, pubkey: hex, ctx: CurrentTX, path: number):
if path == 1:
Delete(sig)
Delete(pubkey)
# Output 0 sends the one-satoshi ordinal to the buyer-supplied address hash.
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_pkh, dest)
EqualVerify(out0_tail, 0x88ac)
out0_value = BinToNum(ctx.Outputs[0].Value.Clone())
NumEqualVerify(out0_value, 1)
# Output 1 pays the configured price to the seller address hash.
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_pkh, self.seller)
EqualVerify(out1_tail, 0x88ac)
out1_value = BinToNum(ctx.Outputs[1].Value.Clone())
NumEqualVerify(out1_value, self.price)
# Bind the two required outputs and optional change 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:
output_script = PartialHash(ctx.Outputs[i].LockingScript.SuffixData, ctx.Outputs[i].LockingScript.PartialHash, ctx.Outputs[i].LockingScript.Size)
output = Cat(ctx.Outputs[i].Value, output_script)
SetMain(outputs_data)
outputs_data = Cat(output, 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 does not constrain outputs; ownership is proven by the seller key.
Delete(dest)
Delete(ctx)
EqualVerify(Hash160(pubkey.Clone()), self.seller)
CheckSigVerify(pubkey, sig)