Deployment Guide

Deploy a Push Oracle network on Cardano using the SDK with optional multisig governance for continuous data feed operations.

Prerequisites

  • SDK installed and configured (Setup Guide)
  • Configuration files prepared:
    • oracle_deploy.yml for deployment
    • oracle-owner-actions.yml for management
  • Funded wallet with sufficient ADA:
    • Testnet: ~200 ADA
    • Mainnet: ~300 ADA
  • C3 payment tokens
  • For multisig: All party signing keys and verification keys

ADA Breakdown:

  • Oracle NFT minting: ~5 ADA
  • Reference script: ~66 ADA (locked, recoverable)
  • Initial oracle UTXOs: ~50-100 ADA (locked, recoverable)
  • Transaction fees: ~10-20 ADA
  • Buffer: ~50 ADA

Deployment Overview

Push Oracle deployment involves several steps:

  1. Deploy Oracle Contracts
  2. Create Reference Script (optional but recommended)
  3. Initialize Oracle Datum (if needed)
  4. Add Initial Funding (C3 tokens to oracle)

Step 1: Deploy Oracle Contracts

Automatic Deployment (Single Signature)

Command:

python scripts/oracle_deploy.py mk-start-oracle

Interactive prompts:

Enter a platform pkh or 'q' to quit: 1a550d57572584e1add125b5712f709ac3b9828ad86581a4759022ba
Enter a platform pkh or 'q' to quit: q

Created start oracle tx id: <tx_id>
Tx written to file start_oracle.cbor

The SDK automatically:

  1. Reads oracle_deploy.yml configuration
  2. Generates or loads oracle Plutus script
  3. Calculates oracle script address
  4. Creates oracle UTXOs:
    • CoreSettings (C3CS NFT) - holds oracle configuration
    • AggState (C3AS NFT) - tracks aggregation state
    • RewardState (C3RA NFT) - manages reward distribution
    • OracleFeed (C3OF NFT) - stores latest aggregated price
    • NodeFeed (C3NF NFTs) - one per node operator
  5. Mints oracle NFTs
  6. Funds oracle with initial C3 tokens
  7. Builds and signs transaction
  8. Submits to blockchain

What happens:

  • Transaction is built and saved to start_oracle.cbor
  • If single signature (threshold = 1), transaction is auto-submitted
  • Oracle script address is displayed
  • Transaction ID is shown for tracking

Multisig Deployment

Step 1: Party 1 builds transaction

python scripts/oracle_deploy.py mk-start-oracle
# Output: start_oracle.cbor

Step 2: Additional parties sign

Each party runs:

python scripts/oracle_deploy.py sign-tx
# Prompts:
# Enter filename containing tx cbor: start_oracle.cbor
# Were you the one who created and balanced this tx with your own inputs? y/n: n
# (Reviews transaction)
# Do you want to sign this tx? y/n: y
 
# Output: start_oracle.cbor (updated with signature)

Important: Share the .cbor file between parties securely.

Step 3: Final party submits

When threshold signatures collected:

python scripts/oracle_deploy.py sign-and-submit-tx
# Prompts:
# Enter filename containing tx cbor: start_oracle.cbor
# Were you the one who created and balanced this tx with your own inputs? y/n: n
# (Reviews transaction)
# Do you want to sign and submit this tx? y/n: y
 
# Submits transaction

Coordination tips:

  • Use secure channel for sharing .cbor files
  • Each party should verify transaction contents before signing
  • Track who has signed: cardano-cli transaction view --tx-file start_oracle.cbor

Deployment with Local Oracle Script

If you have a pre-compiled oracle script:

python scripts/oracle_deploy.py --script-path ./tmp/OracleV3.plutus mk-start-oracle

Deployment with Docker Image

Use Charli3’s oracle compiler image:

# Pulls latest oracle compiler
python scripts/oracle_deploy.py mk-start-oracle
 
# Or use local image
python scripts/oracle_deploy.py --local-image --image-name myregistry/oracle-compiler:latest mk-start-oracle

The SDK will:

  1. Pull/use Docker image
  2. Generate validator arguments (NFT policies, token policies)
  3. Compile oracle script with parameters
  4. Save to tmp/OracleV3.plutus
  5. Proceed with deployment

Step 2: Create Reference Script

Reference scripts reduce transaction costs significantly by allowing validators to be referenced rather than included.

Automatic Creation

If enabled in deployment:

# In oracle_deploy.yml (not applicable to Push Oracle - feature of Pull Oracle)
# Push Oracle creates reference script separately

Manual Creation

After deployment, create reference script:

Using oracle-owner-actions.yml:

python scripts/oracle_owner_actions.py create-reference-script --script-path ./tmp/OracleV3.plutus

This command:

  1. Loads oracle script from file
  2. Creates reference script UTXO at oracle address
  3. Locks ~66 ADA (recoverable when oracle is removed)
  4. Submits transaction

Multisig workflow:

# Build transaction
python scripts/oracle_owner_actions.py create-reference-script --script-path ./tmp/OracleV3.plutus
# (SDK builds but doesn't submit for multisig)
 
# Sign and submit (similar to other multisig operations)

Verify reference script:

cardano-cli query utxo --address <oracle_address> --testnet-magic 1
# Look for UTXO with script hash matching oracle script

Step 3: Initialize Oracle Datum

Some oracle configurations require datum initialization.

Check if needed:

# Query oracle UTXOs
cardano-cli query utxo --address <oracle_address> --testnet-magic 1
 
# Check OracleFeed UTxO datum
# If price_data is None/null, initialization is needed

Initialize:

# This is typically done automatically during deployment
# If manual initialization needed:
await oracle_owner.initialize_oracle_datum()

What it does:

  • Sets initial price_data in OracleFeed datum
  • Allows first aggregation to proceed
  • Usually price = 0, timestamp = 0, expiry = 0

Step 4: Add Initial Funding

Fund the oracle with C3 tokens to pay node operators.

Command:

python scripts/oracle_owner_actions.py add-funds <amount>

Example:

# Add 1000 C3 tokens (1000000000 lovelace if 6 decimals)
python scripts/oracle_owner_actions.py add-funds 1000000000

This transaction:

  • Moves C3 tokens from your wallet to AggState UTXO
  • Increases oracle’s payment capacity
  • Enables node operators to be paid for updates

Verify funding:

# Query AggState UTXO
cardano-cli query utxo --address <oracle_address> --testnet-magic 1
# Check C3 token amount in AggState UTXO

Step 5: Verify Deployment

Check Transaction Confirmation

Using Blockfrost:

curl "https://cardano-preprod.blockfrost.io/api/v0/txs/<tx_id>" \
  -H "project_id: <project_id>"

Look for block_height to confirm inclusion.

Query Oracle UTXOs

Using Blockfrost:

curl "https://cardano-preprod.blockfrost.io/api/v0/addresses/<oracle_address>/utxos" \
  -H "project_id: <project_id>"

Using Kupo:

curl "http://localhost:1442/matches/<oracle_address>/*"

Expected UTXOs:

NFTToken NamePurposeCount
CoreSettingsC3CSOracle configuration1
AggStateC3ASAggregation state1
RewardStateC3RAReward distribution1
OracleFeedC3OFLatest price data1
NodeFeedC3NFNode operator statesN (one per node)

Verification script:

# Count NodeFeed NFTs (should equal number of nodes)
curl "<oracle_utxos_endpoint>" | jq '[.[] | select(.amount[] | .unit | contains("NodeFeed"))] | length'

Inspect Transaction Details

View transaction:

cardano-cli transaction view --tx-file start_oracle.cbor

Verify:

  • Correct number of outputs (1 + 1 + 1 + 1 + N nodes = 4 + N)
  • Each output has appropriate NFT
  • ADA amounts are reasonable (~2-3 ADA per UTXO)
  • C3 tokens in AggState UTXO match initial_c3_amount
  • Datums are properly structured

Check datums:

# Python script to inspect datums
from pycardano import Transaction
tx = Transaction.from_cbor(open('start_oracle.cbor', 'rb').read())
for output in tx.transaction_body.outputs:
    if output.datum:
        print(output.datum)

Understanding Oracle Architecture

UTXO Structure

CoreSettings UTXO:

  • NFT: C3CS (single)
  • Purpose: Immutable oracle configuration
  • Datum: OracleSettings (nodes, fees, timing, consensus params)
  • Never updated after deployment

AggState UTXO:

  • NFT: C3AS (single)
  • Purpose: Mutable aggregation state
  • Datum: AggDatum (same settings as CoreSettings but mutable)
  • Updated: When settings change or nodes added/removed
  • Holds: C3 tokens for paying fees

RewardState UTXO:

  • NFT: C3RA (single)
  • Purpose: Track and distribute rewards
  • Datum: RewardDatum (node rewards, platform rewards)
  • Updated: After each aggregation (fees allocated)

OracleFeed UTXO:

  • NFT: C3OF (single)
  • Purpose: Latest aggregated price
  • Datum: OracleDatum (price, timestamp, expiry)
  • Updated: After each aggregation

NodeFeed UTXOs:

  • NFT: C3NF (one per node)
  • Purpose: Individual node states
  • Datum: NodeDatum (operator VKH, latest feed)
  • Updated: When node submits update

NFT Minting

All oracle NFTs are minted using a native script:

  • Script type: InvalidBefore (time-locked)
  • Parameters: script_start_slot from config
  • Uniqueness: Time-lock ensures unique policy ID
  • Burning: NFTs can be burned during oracle removal

Policy ID: Derived from native script hash

Fee Flow

  1. Funding: Platform adds C3 tokens to AggState
  2. Node Update: Node operator submits price feed
  3. Aggregation: Aggregator collects updates, calculates consensus
  4. Fee Allocation:
    • Node fee → each participating node (in RewardState)
    • Aggregate fee → aggregator (in RewardState)
    • Platform fee → platform (in RewardState)
  5. Collection: Operators/platform collect from RewardState

Post-Deployment Checklist

  • Oracle transaction confirmed (block height > 0)
  • All expected UTXOs created (4 + N nodes)
  • CoreSettings UTXO has correct configuration
  • AggState UTXO has initial C3 funding
  • RewardState UTXO initialized with zero rewards
  • OracleFeed UTXO datum initialized
  • NodeFeed UTXOs created for all nodes
  • Reference script created (if applicable)
  • Oracle script address documented
  • NFT policy ID documented
  • Node operators notified of deployment

Advanced Deployment Options

Custom Oracle Parameters

Generate oracle script with specific parameters:

  1. Create validator-argument.yml:
oracle_mp: "<minting_nft_hash>"
aggState_tn: "AggState"
reward_tn: "Reward"
oracleFeed_tn: "OracleFeed"
nodeFeed_tn: "NodeFeed"
payment_mp: "<c3_token_hash>"
payment_tn: "<c3_token_name>"
rate_tn: "<exchange_rate_token_name>"  # Optional
rate_mp: "<exchange_rate_token_hash>"   # Optional
  1. Compile using Docker:
docker run -v $(pwd)/tmp:/mnt \
  ghcr.io/charli3-official/serialized:latest \
  /app/serialized \
  --argument-path /mnt/validator-argument.yml \
  --script-path /mnt/OracleV3.plutus \
  -a -v
  1. Use generated script:
python scripts/oracle_deploy.py --script-path ./tmp/OracleV3.plutus mk-start-oracle

Multisig Oracle Deployment

For production oracles with multisig governance:

  1. Create multisig native script:
# In oracle_deploy.yml
oracle_settings:
  os_platform:
    pmultisig_pkhs:
      - "party1_vkh"
      - "party2_vkh"
      - "party3_vkh"
    pmultisig_threshold: 2  # 2-of-3 multisig
  1. Generate multisig-enabled oracle script:
# Uses multisig parameters from config
python scripts/oracle_deploy.py mk-start-oracle
  1. Coordinate multisig signing:
  • Party 1 builds transaction
  • Parties 2-N sign sequentially
  • Final party submits

Troubleshooting

“Platform auth NFT not found” (Pull Oracle concept - not applicable)

  • Push Oracle doesn’t use platform auth NFT concept
  • Ignore if seeing in logs from copied configurations

“Insufficient C3 tokens”

  • Cause: Wallet doesn’t have initial_c3_amount C3 tokens
  • Solution:
    1. Check wallet balance: Query address for C3 tokens
    2. Mint more C3 tokens if needed
    3. Or reduce initial_c3_amount in config

“Script start slot in the past”

  • Cause: script_start_slot ≤ current blockchain slot
  • Solution:
    1. Query current slot: cardano-cli query tip --testnet-magic 1
    2. Update config: script_start_slot = current_slot + 1000
    3. Rebuild transaction

“Invalid oracle script hash”

  • Cause: Script compilation parameters mismatch
  • Solution:
    1. Verify all parameters in validator-argument.yml
    2. Ensure NFT policy ID is correct (from native script)
    3. Recompile oracle script
    4. Verify hash: cardano-cli transaction policyid --script-file OracleV3.plutus

“Transaction too large”

  • Cause: Too many nodes or complex datums
  • Solution:
    1. Deploy with fewer nodes initially
    2. Add more nodes after deployment using add-nodes
    3. Use reference script to reduce tx size

“Reference script creation failed”

  • Cause: Insufficient ADA or network issue
  • Solution:
    1. Ensure wallet has ≥66 ADA available
    2. Check network connectivity
    3. Retry: python scripts/oracle_owner_actions.py create-reference-script

“Multisig threshold not met”

  • Cause: Insufficient signatures
  • Solution:
    1. Count signatures: cardano-cli transaction view --tx-file start_oracle.cbor
    2. Ensure threshold parties have signed
    3. No duplicate signatures
    4. Each party uses their own signing key

“Node VKH format invalid”

  • Cause: Using bech32 instead of hex
  • Solution:
    # Wrong: addr_vkh1abc...
    # Correct: abc123... (hex only)
    cardano-cli address key-hash --payment-verification-key-file node.vkey

“Wallet address mismatch”

  • Cause: Mnemonic derives to different address
  • Solution:
    1. Verify derivation path (m/1852’/1815’/0’/0/0)
    2. Check network (testnet vs mainnet)
    3. Ensure correct mnemonic

Next Steps