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.ymlfor deploymentoracle-owner-actions.ymlfor 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:
- Deploy Oracle Contracts
- Create Reference Script (optional but recommended)
- Initialize Oracle Datum (if needed)
- Add Initial Funding (C3 tokens to oracle)
Step 1: Deploy Oracle Contracts
Automatic Deployment (Single Signature)
Command:
python scripts/oracle_deploy.py mk-start-oracleInteractive 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.cborThe SDK automatically:
- Reads
oracle_deploy.ymlconfiguration - Generates or loads oracle Plutus script
- Calculates oracle script address
- 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
- Mints oracle NFTs
- Funds oracle with initial C3 tokens
- Builds and signs transaction
- 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.cborStep 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 transactionCoordination tips:
- Use secure channel for sharing
.cborfiles - 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-oracleDeployment 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-oracleThe SDK will:
- Pull/use Docker image
- Generate validator arguments (NFT policies, token policies)
- Compile oracle script with parameters
- Save to
tmp/OracleV3.plutus - 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 separatelyManual Creation
After deployment, create reference script:
Using oracle-owner-actions.yml:
python scripts/oracle_owner_actions.py create-reference-script --script-path ./tmp/OracleV3.plutusThis command:
- Loads oracle script from file
- Creates reference script UTXO at oracle address
- Locks ~66 ADA (recoverable when oracle is removed)
- 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 scriptStep 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 neededInitialize:
# 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 1000000000This 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 UTXOStep 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:
| NFT | Token Name | Purpose | Count |
|---|---|---|---|
| CoreSettings | C3CS | Oracle configuration | 1 |
| AggState | C3AS | Aggregation state | 1 |
| RewardState | C3RA | Reward distribution | 1 |
| OracleFeed | C3OF | Latest price data | 1 |
| NodeFeed | C3NF | Node operator states | N (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.cborVerify:
- 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_slotfrom 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
- Funding: Platform adds C3 tokens to AggState
- Node Update: Node operator submits price feed
- Aggregation: Aggregator collects updates, calculates consensus
- Fee Allocation:
- Node fee → each participating node (in RewardState)
- Aggregate fee → aggregator (in RewardState)
- Platform fee → platform (in RewardState)
- 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:
- 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- 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- Use generated script:
python scripts/oracle_deploy.py --script-path ./tmp/OracleV3.plutus mk-start-oracleMultisig Oracle Deployment
For production oracles with multisig governance:
- 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- Generate multisig-enabled oracle script:
# Uses multisig parameters from config
python scripts/oracle_deploy.py mk-start-oracle- 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_amountC3 tokens - Solution:
- Check wallet balance: Query address for C3 tokens
- Mint more C3 tokens if needed
- Or reduce
initial_c3_amountin config
“Script start slot in the past”
- Cause:
script_start_slot≤ current blockchain slot - Solution:
- Query current slot:
cardano-cli query tip --testnet-magic 1 - Update config:
script_start_slot = current_slot + 1000 - Rebuild transaction
- Query current slot:
“Invalid oracle script hash”
- Cause: Script compilation parameters mismatch
- Solution:
- Verify all parameters in validator-argument.yml
- Ensure NFT policy ID is correct (from native script)
- Recompile oracle script
- Verify hash:
cardano-cli transaction policyid --script-file OracleV3.plutus
“Transaction too large”
- Cause: Too many nodes or complex datums
- Solution:
- Deploy with fewer nodes initially
- Add more nodes after deployment using
add-nodes - Use reference script to reduce tx size
“Reference script creation failed”
- Cause: Insufficient ADA or network issue
- Solution:
- Ensure wallet has ≥66 ADA available
- Check network connectivity
- Retry:
python scripts/oracle_owner_actions.py create-reference-script
“Multisig threshold not met”
- Cause: Insufficient signatures
- Solution:
- Count signatures:
cardano-cli transaction view --tx-file start_oracle.cbor - Ensure threshold parties have signed
- No duplicate signatures
- Each party uses their own signing key
- Count signatures:
“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:
- Verify derivation path (m/1852’/1815’/0’/0/0)
- Check network (testnet vs mainnet)
- Ensure correct mnemonic
Next Steps
- Platform Operations - Manage your oracle