Price Prediction Oracle
Oracle-settled price prediction payout.
txt
import std.schnorr
# A signed price report chooses the winner and directs the whole previous value to output 0.
# The report binds asset id, timestamp, and price before payout checks run.
Contract PricePrediction:
Struct Script:
SuffixData: string
PartialHash: string
Size: number
Struct Output:
Value: number
LockingScript: Script
Struct Input:
Data: {txid: hex32, vout: hex4, sequence: hex4}
Struct CurrentTX:
Outputs: Output[3]
Struct PreTX:
VLIO: string
Inputs: Input[3]
UnlockingScriptHash: string
Outputs: Output[3]
def settle(msg: hex, R: hex, s: hex, ctx: CurrentTX, pretx: PreTX):
# The current input tells us which previous output value is at stake.
utxoData: {txid: hex32, vout: hex4, sequence: hex4}
utxoData = Push(BVM.unlockingInput)
vout = BinToNum(utxoData.vout)
Delete(utxoData.sequence)
Delete(utxoData.txid)
# Save that previous value so output 0 can be checked later.
pre_value = pretx.Outputs[vout].Value.Clone()
SetAlt(pre_value)
# Recompute the previous txid from the supplied transaction pieces.
tx_data = Push(0)
SetAlt(tx_data)
for i in Range(2, -1, -1):
size_copy = pretx.Outputs[i].LockingScript.Size.Clone()
if size_copy != 0:
tx_data_temp = PartialHash(pretx.Outputs[i].LockingScript.SuffixData, pretx.Outputs[i].LockingScript.PartialHash, pretx.Outputs[i].LockingScript.Size)
tx_data_temp = Cat(pretx.Outputs[i].Value, tx_data_temp)
SetMain(tx_data)
tx_data = Cat(tx_data_temp, tx_data)
SetAlt(tx_data)
Keep(tx_data)
else:
Delete(pretx.Outputs[i].LockingScript.Size)
Delete(pretx.Outputs[i].LockingScript.PartialHash)
Delete(pretx.Outputs[i].LockingScript.SuffixData)
Delete(pretx.Outputs[i].Value)
SetMain(tx_data)
tx_data = Sha256(tx_data)
tx_data = Cat(pretx.UnlockingScriptHash, tx_data)
SetAlt(tx_data)
tx_input_data = Push(0)
for i in Range(2, -1, -1):
tx_input_data = Cat(pretx.Inputs[i].Data, tx_input_data)
tx_input_hash = Sha256(tx_input_data)
SetMain(tx_data)
tx_data = Cat(tx_input_hash, tx_data)
tx_data = Cat(pretx.VLIO, tx_data)
txid = Hash256(tx_data)
preTXID = BVM.unlockingInput.Slice(0, 32)
EqualVerify(txid, preTXID)
# Clone the report bytes before 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 report as assetId(32) | timestamp(8) | price(8).
{msg_assetId, r1} = Split(msg_for_parse, 32)
{msg_ts_b, msg_price_b} = Split(r1, 8)
# The report must refer to the configured asset id.
EqualVerify(msg_assetId, self.assetId)
# Treat the timestamp as unsigned and require it to reach the settlement time.
msg_ts_num = BinToNum(Cat(msg_ts_b, 0x00))
settle_clone = self.settleTime.Clone()
settle_num = BinToNum(Cat(settle_clone, 0x00))
NumEqualVerify(GreaterOrEqual(msg_ts_num, settle_num), 1)
# The threshold comparison selects Alice on success and Bob otherwise.
price_num = BinToNum(Cat(msg_price_b, 0x00))
threshold_clone = self.threshold.Clone()
threshold_num = BinToNum(Cat(threshold_clone, 0x00))
winner_flag = GreaterOrEqual(price_num, threshold_num)
# Output 0 must be P2PKH and pay the selected winner's public-key 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_tail, 0x88ac)
if winner_flag == 1:
EqualVerify(out0_pkh, self.alice)
else:
EqualVerify(out0_pkh, self.bob)
# The winner receives the exact value that was previously locked.
SetMain(pre_value)
out0_value = ctx.Outputs[0].Value.Clone()
EqualVerify(out0_value, pre_value)
# Rebuild all declared outputs and bind them to the transaction output hash.
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_temp = PartialHash(ctx.Outputs[i].LockingScript.SuffixData, ctx.Outputs[i].LockingScript.PartialHash, ctx.Outputs[i].LockingScript.Size)
output_temp = Cat(ctx.Outputs[i].Value, output_temp)
SetMain(outputs_data)
outputs_data = Cat(output_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)