AttestationBeacon is the oracle output contract. Copy it below. Asset as Contract ID explains the asset.
A sample is a price and a time that the signers sign. A fixing is the price that the output stores in a slot. The slot key names the slot. The binding on this page uses one key. Multi-Oracle Aggregation is the same contract with more signers, and the consumers that take a median.
Source
Copy the contract without changes. A change to the code changes the address of the output. Compile the file witharkadec (Compiler). Constructor lists the arguments that you bind.
contracts/attestation_beacon.ark @ 9fc10ef
attestation_beacon.ark in arkade-options 9fc10ef.
Constructor
The ticker is not a parameter. The contract fixes it as
BTCUSD (0x425443555344).
Binding
The SDK flattens arrays. The constructor arguments aresigners.0 to signers.4. The call arguments are sigs.0 to sigs.4. The artifact also declares server. The SDK client binds server to the operator key.
State packet
The packet has type 32 and 329 bytes. Integers usenum2bin: little-endian sign-magnitude.
The genesis state is round 0 with eight zero slots.
attest stores the price in the value as a 32-byte number. A consumer reads the first 8 bytes of the value to get the price.
Functions
attest spends the output at input 0. The sample digest is the SHA-256 hash of the asset id, the ticker, the price (8 bytes), and the time (8 bytes).
Slot i of sigs belongs to signer i. A slot below signersN holds a valid signature or an empty signature. Any other value fails the spend. The spend needs at least threshold valid signatures.
The next packet has the round plus 1. Slot 0 holds the slot key and the price. Slots 1 to 7 hold the old slots 0 to 6. The slot key must not be in a current slot.
read keeps the packet of the output the same. It checks that output 0 gains readFee. It has no signature check.
Output 0 carries the oracle output’s own script, because it is the oracle’s continuation. A contract that also continues on output 0, like the pool templates (Lending, Automated Market Maker), cannot spend in the same transaction as a read: one output 0 cannot carry two scripts. A vault that settles without continuing can share the transaction and pays readFee from its locked funds. Any other reader spends the oracle in a separate transaction.
migrate spends the output at input 0. adminPk signs the SHA-256 hash of the domain, the text migrate, the asset id, the group index (4 bytes), the round (8 bytes), and next. The round comes from the current packet. Output 0 pays the 32-byte program next with the unit and the same packet.
unilateral is the exit if the operator is unavailable. It is a tapscript leaf that needs the CSV exit and a signature from adminPk.
The emulator runs each function except unilateral.
Set up one key
One key means one signer (signersN), a threshold of 1, and an admin key (adminPk) that equals the signer key. The contract checks only the first signersN signer slots. Repeat the signer key in the other four slots.
Build exit as a BIP68 sequence (CSV sequences). Use the issuance txid in reverse byte order for ctrlTxid (Asset as Contract ID).
oracle.ts
current. It holds the unit and a genesis state packet (round 0, eight zero slots). The function genesisOutputs in protocol/beacon.ts builds the outputs. The wallet submits them as an offchain transaction.
The deployed oracle uses keyLag 60. The emulator clock must be 60 seconds past the slot key before attest writes it. A negative keyLag removes that clock gate: attest then checks only that the sample time is not later than the slot key plus keyLag, so a fixing can land at any time. Deploy a negative lag only when the signers’ own process is the liveness guarantee, because the emulator no longer stops an early fixing. The deployed oracle uses readFee 1000, which is more than the dust limit of 330 sats.
The output
Each cooperative spend creates the output again on output 0 with its identity unit. Onlymigrate changes the script.
Publish a price
Anyone who has the signatures of the quorum can write a sample into the output. With one key, the quorum is one signature. The output is the only input. It returns on output 0 with the new state:num2bin writes a number as little-endian sign-magnitude bytes. The top bit of the last byte must stay clear.
protocol/beacon.ts @ 9fc10ef
OptionVault uses its expiry time in unix seconds. attest verifies the signature, the clock, and the change of state. The excerpt omits the check of the signer set and the checks of the packet size and version:
contracts/attestation_beacon.ark @ 9fc10ef
The contract limits
time from above only, and the slot does not store time. See Limits. The function buildAttest builds the transaction that oracle/service.ts sends:
protocol/cospend.ts @ 9fc10ef
Consume the price
A consumer spends the oracle output as an input of its own transaction.read has no signature check, so anyone can build this transaction. In OptionVault, the consumer is input 0 and the oracle output is input 1. read takes the index of its own input. The payouts come from the output of the consumer, minus readFee:
read keeps the state and charges the fee:
contracts/attestation_beacon.ark @ 9fc10ef
expiry:
contracts/option_vault.ark @ 9fc10ef
The function
buildSettle builds the settlement transaction. The builder of the SDK spends one covenant output. cospend.ts assembles two:
protocol/cospend.ts @ 9fc10ef
Replace the key
The admin replaces the script of the output, for example with a script that has a new signer key. The contracts that read the output do not change, because they look for the same asset id.migrate takes the 32-byte program of the new script and a signature from adminPk:
contracts/attestation_beacon.ark @ 9fc10ef
- Bind the new script with the same arguments and the new key in
signers. The 32-byte program of this script isnext. - Read
roundfrom bytes 1 to 8 of the state packet of the output. - Compute the digest
msgas the functionmigratecomputes it. Sign the digest with the key ofadminPk. The signature isopSig. - Spend the output at input 0 with the function
migrate. PassnextandopSig. - Pay output 0 to the new script with the unit and at least the input value. Keep the state packet the same.
arkade-options has no builder for migrate and no test that spends it. Steps 2 to 5 follow the contract. Use buildAttest as a template for the transaction.
Exit
contracts/attestation_beacon.ark @ 9fc10ef
adminPk alone can claim the output onchain: unroll it, wait for the exit delay, and sign. The unit then leaves Arkade, and contracts that read this oracle can no longer settle against it.
Limits
Source files at
9fc10ef: attestation_beacon.ark, option_vault.ark, protocol/beacon.ts, protocol/cospend.ts, and the reference service oracle/service.ts.