Skip to main content

Oracle

The Oracle contract is a way to access off-chain data on the blockchain. Below is a solution for implementing Oracle in a BTC environment with the OP_CAT opcode enabled.

Architecture

As shown in the diagram, the user provides their UTXO and feeRate. The Oracle service uses the UTXO to construct transactions. The outputs include a payload commit contract, user-defined outputs, service fees, and change for fees. Once the commit transaction is constructed, the Oracle service creates and signs a reveal transaction using the payload commit output. It returns both the commit and reveal PSBT hex strings along with the raw payload commit output. The following code demonstrates how to obtain a timestamp using this setup.

After receiving the commit and reveal transactions, the user signs the commit transaction and uses the signed reveal input to construct a new contract call transaction. This allows the contract to access Oracle data.

curl -X 'POST' \
'https://oracle.scrypt.io/v1/timestamp' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"utxos": [
{
"txId": "985fc2fb0ed1179672c1fd08afa81f19179aa6939622f6809659a3acfd9e0000",
"outputIndex": 5,
"script": "5120d9b50025be40bffc75ef262c020bfe2b52d0f5ecfeb280ecf5c35fbfdb856300",
"satoshis": 184814984
}
],
"publicKey": "02943e87ed8c2d38a8b3ec76999b70e4a605dbe041632099cac7387238b4012200",
"feeRate": 1
}'
{
"commitPsbt": "70736274ff0100d7020000000100009efdaca3599680f6229693a69a17191fa8af08fdc1729617d10efbc25f980500000000ffffffff0400000000000000001a6a1863617401f4d5ea814aabc273f329f3563848a090fc8c77cf4a01000000000000220020a110df5f2a3e0c0ea9ec2a96b58bc81a798175309b9134c5deca57111d9a2b3d220200000000000022512057a120ae7176b7ee20fbd6325aa98ea60c69b49ddf4c505756e2b8a5668d06023309040b00000000225120d9b50025be40bffc75ef262c020bfe2b52d0f5ecfeb280ecf5c35fbfdb856300000000000001012b880d040b00000000225120d9b50025be40bffc75ef262c020bfe2b52d0f5ecfeb280ecf5c35fbfdb8563000000000000",
"commitOptions": {
"autoFinalized": false,
"toSignInputs": [
{
"index": 0,
"address": "bc1pmx6sqfd7gzllca00yckqyzl79dfdpa0vl6egpm84cd0mlku9vvqqc5j5ng"
}
]
},
"revealPsbt": "70736274ff01005602000000011a7092fd91f79a8be40502c710165274348d7b2a6cbab776bc18b9b8ae81f4160100000000ffffffff0100000000000000001a6a1863617401f4d5ea814aabc273f329f3563848a090fc8c77cf000000000001012b4a01000000000000220020a110df5f2a3e0c0ea9ec2a96b58bc81a798175309b9134c5deca57111d9a2b3d22020293992068c88f47b988debe61ea9731c2a4d132da47f3591b2b89cfb0f9f7a25c473044022024c0c9f7622d5b5b2ba17377933f272a4d94bf8c742dd2bbb56b44839fc856e902206907a06457389df7a474f57a3d1aeab49b4a4945ab6b9940d1f35f01373c67c38201030482000000010567210293992068c88f47b988debe61ea9731c2a4d132da47f3591b2b89cfb0f9f7a25c14bbfa32c40aa80e2321daf64feb88ec4c0dba9e512102943e87ed8c2d38a8b3ec76999b70e4a605dbe041632099cac7387238b401220054795379ad537978ac6b6d6d6c770000",
"data": [
{
"name": "marker",
"type": "Int",
"value": "1"
},
{
"name": "timestamp",
"type": "Int",
"value": "1734450823"
}
],
"serializedData": "01879e6167"
}

DexUseTimestamp

https://oracle.scrypt.io/v1/timestamp

Contract invocation script link

import {
SHPreimage,
SigHashUtils,
SpentScriptsCtx,
} from '@cat-protocol/cat-sdk'
import { PubKey, SmartContract, assert, hash160, method, prop } from 'scrypt-ts'
import { OracleLib } from '../oracleLib'
import {
OracleTimestampState,
OracleTimestampStateProto,
} from './timestampProto'

export class DexUseTimestamp extends SmartContract {
@prop()
oracleKey: PubKey

constructor(oracleKey: PubKey) {
super(...arguments)
this.oracleKey = oracleKey
}

@method()
public unlock(
timestampData: OracleTimestampState,
publickey: PubKey,
oracleInputIndex: bigint,
shPreimage: SHPreimage,
spentScriptsCtx: SpentScriptsCtx
) {
// Check sighash preimage.
assert(
this.checkSig(
SigHashUtils.checkSHPreimage(shPreimage),
SigHashUtils.Gx
),
'preimage check error'
)
SigHashUtils.checkSpentScriptsCtx(
spentScriptsCtx,
shPreimage.hashSpentScripts
)
const oracleLocking = OracleLib.buildOracleP2wsh(
hash160(OracleTimestampStateProto.toByteString(timestampData)),
this.oracleKey,
publickey
)
assert(
spentScriptsCtx[Number(oracleInputIndex)] == oracleLocking,
'oracle script mismatch'
)
}
}

DexUsePrice

https://oracle.scrypt.io/v1/price

Contract invocation script link

import {
SHPreimage,
SigHashUtils,
SpentScriptsCtx,
} from '@cat-protocol/cat-sdk'
import { PubKey, SmartContract, assert, hash160, method, prop } from 'scrypt-ts'
import { OracleLib } from '../oracleLib'
import { OraclePriceState, OraclePriceStateProto } from './priceProto'

export class DexUsePrice extends SmartContract {
@prop()
oracleKey: PubKey

constructor(oracleKey: PubKey) {
super(...arguments)
this.oracleKey = oracleKey
}

@method()
public unlock(
priceData: OraclePriceState,
publickey: PubKey,
oracleInputIndex: bigint,
shPreimage: SHPreimage,
spentScriptsCtx: SpentScriptsCtx
) {
// Check sighash preimage.
assert(
this.checkSig(
SigHashUtils.checkSHPreimage(shPreimage),
SigHashUtils.Gx
),
'preimage check error'
)
SigHashUtils.checkSpentScriptsCtx(
spentScriptsCtx,
shPreimage.hashSpentScripts
)
const oracleLocking = OracleLib.buildOracleP2wsh(
hash160(OraclePriceStateProto.toByteString(priceData)),
this.oracleKey,
publickey
)
assert(
spentScriptsCtx[Number(oracleInputIndex)] == oracleLocking,
'oracle script mismatch'
)
}
}