Platform Operations

Ongoing management operations for Push Oracle networks including governance actions, node management, funding, and reward collection.

Prerequisites

  • Deployed oracle (Deployment Guide)
  • oracle-owner-actions.yml configured correctly
  • Access to oracle owner wallet (or multisig parties)
  • Reference script created (recommended for lower fees)

Configuration File

All operations use oracle-owner-actions.yml. Ensure it contains:

# Network and connectivity
network: "testnet"
chain_query:
  blockfrost:
    api_url: "https://cardano-preprod.blockfrost.io/api"
    project_id: "your_project_id"
 
# Oracle details
oracle_owner:
  oracle_addr: "addr_test1wp..."
  minting_nft_hash: "1f2d9f..."
  c3_token_hash: "436941..."
  c3_token_name: "C3"
  script_start_slot: 28585322
  reference_script_input: "tx_hash#index"  # Optional
  oracle_platform:
    multisig_pkhs: ["vkh1", "vkh2"]
    multisig_threshold: 1

Governance Operations

All governance operations require platform authorization. For multisig (threshold > 1), transactions must be signed by required parties.

Update Oracle Settings

Modify oracle parameters after deployment. Settings are stored in AggState UTXO datum.

Command:

python scripts/oracle_owner_actions.py mk-edit-settings

Interactive workflow:

Current settings: OracleSettings(...)

0: os_minimum_deposit
1: os_updated_nodes
2: os_updated_node_time
3: os_aggregate_time
4: os_aggregate_change
5: os_node_fee_price.node_fee
6: os_node_fee_price.aggregate_fee
7: os_node_fee_price.platform_fee
8: os_iqr_multiplier
9: os_divergence
10: os_aggregate_valid_range

Please enter the setting number or 'q' to finish: 1
Enter a new value for os_updated_nodes: 7000

Please enter the setting number or 'q' to finish: q

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

Created edit settings tx id: <tx_id>
Tx written to file edit_settings.cbor

What you can update:

SettingDescriptionConstraints
os_minimum_depositMinimum C3 in oracle> 0
os_updated_nodesRequired nodes %≤ 10000 (100%)
os_updated_node_timeNode update validity> 0 ms
os_aggregate_timeMin aggregation interval> 0 ms
os_aggregate_changeMin price change %≤ 10000 (100%)
os_node_fee_price.*Fee structure≥ 0
os_iqr_multiplierOutlier detection> 0
os_divergenceMax divergence %≤ 10000 (100%)
os_aggregate_valid_rangeAggregation validity> 0 ms

Important: Cannot update os_node_list using this command. Use mk-add-nodes or mk-remove-nodes instead.

Single signature workflow:

# Build, sign, and submit automatically
python scripts/oracle_owner_actions.py mk-edit-settings

Multisig workflow:

# Party 1: Build transaction
python scripts/oracle_owner_actions.py mk-edit-settings
# Output: edit_settings.cbor
 
# Party 2-N: Sign
python scripts/oracle_owner_actions.py sign-tx
# Enter filename: edit_settings.cbor
# Do you want to sign? y
 
# Final party: Submit
python scripts/oracle_owner_actions.py sign-and-submit-tx
# Enter filename: edit_settings.cbor
# Do you want to sign and submit? y

Add Nodes

Add new node operators to the oracle network.

Command:

python scripts/oracle_owner_actions.py mk-add-nodes

Interactive workflow:

Enter a node to add or 'q' to quit: 018ab1dd5f33ca2e0ae6ccb694ea379d841bf5f4d2d5756452a2117d
Enter a node to add or 'q' to quit: f3a8e5c9b2d4a7e6c1f8d3b5a9e2c7f4d1a8b3e5c2f7d4a1b8e3c5f2
Enter a node to add or 'q' to quit: q

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

Created add nodes tx id: <tx_id>
Tx written to file add_nodes.cbor

The SDK:

  1. Validates node VKHs (hex format, not already in oracle)
  2. Creates new NodeFeed UTXOs for each node
  3. Mints NodeFeed NFTs (C3NF tokens)
  4. Updates AggState datum with new node list
  5. Updates RewardState datum (adds reward entries with 0 balance)
  6. Builds transaction

Node VKH format:

  • Must be hex-encoded verification key hash
  • NOT bech32 format (no addr_vkh1 prefix)
  • Get from: cardano-cli address key-hash --payment-verification-key-file node.vkey

Multisig workflow:

# Party 1: Build
python scripts/oracle_owner_actions.py mk-add-nodes
# Output: add_nodes.cbor
 
# Parties 2-N: Sign and submit
python scripts/oracle_owner_actions.py sign-tx
python scripts/oracle_owner_actions.py sign-and-submit-tx

Verify nodes added:

# Count NodeFeed NFTs
curl "<oracle_address_utxos>" | jq '[.[] | select(.amount[] | .unit | contains("NodeFeed"))] | length'

Remove Nodes

Remove node operators from the oracle network. Accumulated rewards are paid out before removal.

Command:

python scripts/oracle_owner_actions.py mk-remove-nodes

Interactive workflow:

Enter a node to remove or 'q' to quit: 018ab1dd5f33ca2e0ae6ccb694ea379d841bf5f4d2d5756452a2117d
Enter a node to remove or 'q' to quit: q

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

Created remove nodes tx id: <tx_id>
Tx written to file remove_nodes.cbor

The SDK:

  1. Validates nodes exist in oracle
  2. Calculates accumulated rewards for each node
  3. Creates payout outputs (if rewards > 0)
  4. Burns NodeFeed NFTs
  5. Updates AggState datum (removes from node list)
  6. Updates RewardState datum (removes reward entries)
  7. Builds transaction

Important: If a node has accumulated rewards, they will be automatically paid to the node’s address before removal. The node does NOT need to manually collect first.

Multisig workflow:

# Party 1: Build
python scripts/oracle_owner_actions.py mk-remove-nodes
# Output: remove_nodes.cbor
 
# Parties 2-N: Sign and submit

Verify nodes removed:

# Count NodeFeed NFTs (should decrease)
curl "<oracle_address_utxos>" | jq '[.[] | select(.amount[] | .unit | contains("NodeFeed"))] | length'

Funding Operations

Add Funds

Add C3 tokens to the oracle to pay for future node updates and aggregations.

Command:

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

Example:

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

The transaction:

  • Consumes AggState UTXO
  • Adds C3 tokens from your wallet
  • Outputs updated AggState UTXO with increased C3 balance
  • Requires only platform wallet signature (no multisig needed)

Verify funding:

# Query AggState UTXO
curl "<oracle_address_utxos>" | \
  jq '.[] | select(.amount[] | .unit | contains("AggState"))'
# Check C3 token amount

When to add funds:

  • Before deploying new nodes (to ensure fees can be paid)
  • When C3 balance is running low
  • To support higher aggregation frequency

Estimate required funding:

Funds needed = (expected_aggregations × total_fees_per_aggregation)

Where:
total_fees = (node_fee × avg_participating_nodes) + aggregate_fee + platform_fee

Reward Operations

Platform Collect

Collect accumulated platform fees from the oracle’s RewardState.

Command:

python scripts/oracle_owner_actions.py mk-platform-collect

Interactive workflow:

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

Enter withdrawal address: addr_test1vr...

Created platform collect tx id: <tx_id>
Tx written to file platform_collect.cbor

The SDK:

  1. Queries RewardState UTXO
  2. Checks platform_reward balance
  3. Creates output sending platform fees to withdrawal address
  4. Updates RewardState (sets platform_reward = 0)
  5. Requires AggState UTXO as reference input
  6. Builds transaction

Multisig workflow:

# Party 1: Build
python scripts/oracle_owner_actions.py mk-platform-collect
# Output: platform_collect.cbor
 
# Parties 2-N: Sign and submit

When to collect:

  • Periodically as platform fees accumulate
  • Before oracle removal (to claim final fees)
  • When needing C3 tokens for other purposes

Node Collect (Node Operator Operation)

Node operators collect their accumulated rewards. This is NOT a platform operation but is included for completeness.

How it works:

  1. Node operator queries their accumulated rewards in RewardState
  2. Calls node.collect(reward_address)
  3. Receives C3 tokens to specified address
  4. RewardState updated (operator’s reward set to 0)

Example (from node operator perspective):

from charli3_offchain_core.node import Node
 
# Initialize node instance
node = Node(
    network=network,
    chain_query=chain_query,
    signing_key=node_signing_key,
    verification_key=node_verification_key,
    # ... other parameters
)
 
# Collect rewards to node operator's address
await node.collect(node.address)

Platform operators don’t typically run this command, but may assist node operators if needed.

Oracle Lifecycle Management

Pause Oracle (Not implemented in Push Oracle)

Push Oracle doesn’t have a native pause mechanism. To halt operations:

  1. Coordinate with node operators to stop submitting updates
  2. Stop collecting platform fees (don’t run aggregations)
  3. Wait for pending aggregations to complete
  4. Don’t add new funding

This is an operational pause, not an on-chain mechanism.

Close Oracle

Permanently remove the oracle and recover locked ADA and remaining C3 tokens.

Command:

python scripts/oracle_owner_actions.py mk-oracle-close

Interactive workflow:

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

Enter the withdrawal address for the C3 tokens: addr_test1vr...

Select an option:
TO_NODES: Pay unclaimed C3 tokens to node operators and collect the network remainder
TO_ONE_ADDRESS: Collect all C3 tokens in the network, including unclaimed C3 tokens
Option [TO_NODES]: TO_NODES

Created oracle close tx id: <tx_id>
Tx written to file oracle_close.cbor

Disbursement options:

TO_NODES:

  • Pays each node operator their accumulated rewards
  • Collects remaining C3 from AggState, OracleFeed
  • Sends platform fees to withdrawal address
  • Fair distribution to all parties

TO_ONE_ADDRESS:

  • Collects ALL C3 tokens from oracle (including unclaimed node rewards)
  • Sends to single withdrawal address
  • Use with caution - nodes lose their rewards

The transaction:

  1. Consumes all oracle UTXOs (AggState, OracleFeed, RewardState, all NodeFeeds)
  2. Burns all oracle NFTs
  3. Distributes C3 tokens according to option
  4. Returns locked ADA to platform wallet
  5. Oracle becomes permanently non-functional

Important: This operation is irreversible. Ensure all parties have been notified and rewards collected if using TO_NODES option.

Multisig workflow:

# Party 1: Build
python scripts/oracle_owner_actions.py mk-oracle-close
# Output: oracle_close.cbor
 
# Parties 2-N: Sign and submit

Verify oracle removed:

# Query oracle address (should have no UTXOs with oracle NFTs)
curl "<oracle_address_utxos>" | \
  jq '[.[] | select(.amount[] | .unit | contains("C3"))]'
# Should return empty or only non-NFT UTXOs

Reference Script Management

Create Reference Script

Creates a reference script UTXO to reduce transaction costs.

Command:

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

The transaction:

  • Creates UTXO at oracle address with oracle script attached
  • Locks ~66 ADA (recoverable on oracle close)
  • Allows validators to be referenced (not included) in txs
  • Significantly reduces transaction fees

When to create:

  • After oracle deployment (if not created during deployment)
  • If reference script UTXO was accidentally spent
  • When upgrading to new oracle script version

Verify reference script:

cardano-cli query utxo --address <oracle_address> --testnet-magic 1
# Look for UTXO with large size and script hash

Transaction Management (Multisig)

Sign Transaction

Add your signature to a pending multisig transaction.

Command:

python scripts/oracle_owner_actions.py sign-tx

Interactive workflow:

Enter filename containing tx cbor: platform_collect.cbor

Were you the one who created and balanced this tx with your own inputs? y/n: n

Transaction{
  body: TransactionBody{...}
  witness_set: TransactionWitnessSet{
    vkey_witnesses: [VKeyWitness(...), ...]
  }
}

Please review contents of the above tx once again manually before signing

Do you want to sign this tx? y/n: y

Tx signed
Tx written to file platform_collect.cbor

Important:

  • Answer ‘n’ to “Were you the one who created…” unless you built the transaction yourself
  • Carefully review transaction contents before signing
  • SDK validates transaction structure and prevents invalid operations
  • Transaction file is updated with your signature

Submit Transaction

Submit a fully-signed multisig transaction to the blockchain.

Command:

python scripts/oracle_owner_actions.py sign-and-submit-tx

Interactive workflow:

Enter filename containing tx cbor: platform_collect.cbor

Were you the one who created and balanced this tx with your own inputs? y/n: n

Transaction{...}

Please review contents of the above tx once again manually before signing

Do you want to sign and submit this tx? y/n: y

Tx signed
Submitting transaction: <tx_id>
Transaction submitted with tx_id: <tx_id>
Tx signed and submitted

Validation:

  • SDK checks threshold is met before submitting
  • Validates all signatures are correct
  • Ensures transaction hasn’t expired
  • Monitors confirmation status

Transaction fails if:

  • Insufficient signatures (< threshold)
  • Any signature is invalid
  • Transaction validity window expired
  • On-chain validation fails

Monitoring & Validation

Query Oracle State

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>/*"

What to check:

AggState UTXO:

  • C3 token balance (funding level)
  • Node list (current operators)
  • Oracle settings

RewardState UTXO:

  • Platform reward balance
  • Each node’s accumulated rewards
  • Total rewards outstanding

OracleFeed UTXO:

  • Latest aggregated price
  • Timestamp of last aggregation
  • Expiry time

NodeFeed UTXOs:

  • Count (should equal number of nodes)
  • Each node’s latest feed value
  • Last update timestamp

Validate Transaction Before Signing

View transaction details:

cardano-cli transaction view --tx-file <operation>.cbor

Check for:

  • Correct inputs (oracle UTXOs being consumed)
  • Expected outputs (updated UTXOs, payouts)
  • Reasonable fees (typically 0.2-0.5 ADA)
  • Correct datums (settings, rewards, prices)
  • No unexpected outputs or withdrawals

Parse transaction in Python:

from pycardano import Transaction
 
tx = Transaction.from_cbor(open('platform_collect.cbor', 'rb').read())
 
print("Inputs:", tx.transaction_body.inputs)
print("Outputs:", tx.transaction_body.outputs)
print("Fee:", tx.transaction_body.fee)
print("Signatures:", len(tx.transaction_witness_set.vkey_witnesses or []))

Monitor Oracle Health

Key metrics to track:

  1. C3 Balance: Ensure sufficient funding

    # Query AggState C3 balance
    curl "<oracle_utxos>" | jq '.[] | select(...) | .amount[] | select(.unit | contains("<c3_policy>"))'
  2. Node Activity: Check recent updates

    # Query NodeFeed timestamps
    # Parse datums to see last update times
  3. Reward Balances: Track accumulated fees

    # Query RewardState datum
    # Check platform_reward and node rewards
  4. Aggregation Frequency: Monitor oracle feeds

    # Query OracleFeed timestamps
    # Calculate time between aggregations
  5. Transaction Success Rate: Track failed txs

    # Monitor blockchain for failed transactions
    # Check validation errors

Best Practices

Multisig Coordination

  1. Establish communication channel - Secure method for sharing transaction files
  2. Define roles - Who builds, who signs, who submits
  3. Version control configs - All parties use identical configuration
  4. Test on testnet - Validate operations before mainnet
  5. Backup transaction files - Store signed transactions securely
  6. Document signing order - Clear process for each operation type

Security

  1. Protect signing keys - Use hardware wallets for mainnet
  2. Verify transactions - Always review before signing
  3. Separate wallets - Different wallets for platform and personal funds
  4. Regular audits - Review access controls periodically
  5. Incident response - Prepare for key compromise scenarios
  6. Monitor operations - Regular health checks and anomaly detection

Operations

  1. Regular funding - Maintain adequate C3 balance
  2. Periodic collection - Collect platform fees regularly
  3. Node coordination - Keep operators informed of changes
  4. Monitor health - Track key metrics continuously
  5. Document changes - Log all governance actions
  6. Plan maintenance - Schedule updates during low activity
  7. Test upgrades - Validate changes on testnet first

Cost Management

  1. Use reference scripts - Significantly reduces tx fees
  2. Batch operations - Combine multiple node additions when possible
  3. Optimize timing - Perform operations during low network congestion
  4. Monitor C3 usage - Track fee burn rate
  5. Budget appropriately - Plan for ongoing funding needs

Troubleshooting

Transaction Building Issues

“AggState UTxO not found”

  • Cause: Oracle address incorrect or oracle not deployed
  • Solution:
    1. Verify oracle_addr in config matches deployed oracle
    2. Query oracle address for UTXOs
    3. Check AggState NFT (C3AS) exists

“Platform auth NFT not found”

  • Cause: Minting NFT hash incorrect
  • Solution:
    1. Verify minting_nft_hash matches oracle NFT policy
    2. Check native script hash calculation
    3. Query platform address for NFT

“Insufficient C3 tokens”

  • Cause: Oracle C3 balance too low
  • Solution:
    1. Check AggState C3 balance
    2. Add funds: python scripts/oracle_owner_actions.py add-funds <amount>
    3. Ensure wallet has C3 tokens

“Node VKH not found in oracle”

  • Cause: Trying to remove node that doesn’t exist
  • Solution:
    1. Query oracle state for current node list
    2. Verify VKH is correct hex format
    3. Check node was added successfully

“Cannot modify osNodeList”

  • Cause: Trying to update os_node_list via mk-edit-settings
  • Solution:
    • Use mk-add-nodes to add nodes
    • Use mk-remove-nodes to remove nodes
    • Settings update only for other parameters

Multisig Issues

“Insufficient signatures”

  • Cause: Transaction threshold not met
  • Solution:
    1. Count current signatures
    2. Ensure all required parties have signed
    3. Check for duplicate signatures
    4. Verify each party uses their own key

“Signature verification failed”

  • Cause: Invalid signature or wrong signing key
  • Solution:
    1. Verify party is using correct signing key file
    2. Check key matches VKH in pmultisig_pkhs
    3. Ensure key file is not corrupted
    4. Regenerate signature if needed

“Transaction already signed by this party”

  • Cause: Duplicate signature attempt
  • Solution:
    1. Check transaction file for existing signatures
    2. Coordinate with other parties to avoid duplicates
    3. If error, skip this party and continue

On-Chain Validation Failures

“Script execution failed”

  • Cause: On-chain validator rejected transaction
  • Solution:
    1. Review transaction with cardano-cli transaction view
    2. Check datum structure matches expected format
    3. Verify redeemer is correct for operation
    4. Ensure all prerequisites met (e.g., nodes exist)
    5. Check logs for specific validation error

“Datum mismatch”

  • Cause: On-chain datum doesn’t match expected structure
  • Solution:
    1. Re-query oracle UTXOs to get current datums
    2. Rebuild transaction with fresh data
    3. Verify datum types match (AggDatum, RewardDatum, etc.)

“Invalid redeemer”

  • Cause: Wrong redeemer type for operation
  • Solution:
    1. Verify operation type (AddNodes, RemoveNodes, etc.)
    2. Check redeemer construction in code
    3. Ensure redeemer matches validator expectations

“Timing constraints violated”

  • Cause: Transaction validity window expired
  • Solution:
    1. Rebuild transaction (creates new validity range)
    2. Sign and submit more quickly
    3. Coordinate multisig parties better
    4. Check system clock accuracy

Reward Collection Issues

“No platform reward available”

  • Cause: Platform fees haven’t accumulated yet
  • Solution:
    1. Wait for aggregations to occur (fees allocated after each aggregation)
    2. Query RewardState to see platform_reward value
    3. Collect only when balance > 0

“Node collection failed”

  • Cause: Node signature doesn’t match registered VKH
  • Solution:
    1. Verify node operator is using correct signing key
    2. Check VKH matches entry in os_node_list
    3. Ensure node was properly added to oracle

Oracle Removal Issues

“Cannot remove oracle - pending rewards”

  • Cause: Nodes have unclaimed rewards
  • Solution:
    • Option 1: Use TO_NODES disbursement (automatically pays out)
    • Option 2: Manually collect all node rewards first, then use TO_ONE_ADDRESS

“Oracle close transaction too large”

  • Cause: Many nodes with many outputs
  • Solution:
    1. Remove some nodes first to reduce transaction size
    2. Collect node rewards before closing (reduces outputs)
    3. Use TO_ONE_ADDRESS if acceptable (fewer outputs)