Getting Started with Panda
Panda is a blockchain with native Python smart contracts for data science. The fastest way to get started is through the Contract Playground -- a browser-based IDE where you can write, deploy, and interact with contracts in seconds.
Using the Contract Playground
The Playground is available at explorer.pandachain.io/playground. No installation needed.
1. Open the Playground
Navigate to the Contract Playground. You'll see:
- Editor -- A full-featured code editor with Python syntax highlighting
- Template Picker -- Pre-built contract templates to start from
- Deploy Panel -- Connect your wallet and deploy to the chain
- Interact Panel -- Call and query methods on deployed contracts
2. Choose a Template
Click a template to load it into the editor:
- Hello World -- Simple greeting contract with state and events
- PRC-20 Token -- Fungible token with transfers, approvals, and minting
- PRC-721 NFT -- Non-fungible token collection with ownership and metadata
- Counter -- Minimal stateful contract
- Voting -- On-chain governance
- ML Model -- Train and serve machine learning models on-chain
3. Write Your Contract
All Panda contracts follow the same pattern. Here is the full Counter contract (contracts/examples/counter.py), which demonstrates every core concept:
from panda import contract, constructor, call, query, event
@contract
class Counter:
"""A simple counter that tracks a value and who last modified it."""
class State:
count: int = 0
owner: str = ""
last_caller: str = ""
@constructor
def deploy(self, ctx, initial_count: int = 0):
"""Set the initial count and owner on deployment."""
self.state.owner = ctx.sender
self.state.count = initial_count
@call
def increment(self, ctx):
"""Add 1 to the counter."""
self.state.count = self.state.count + 1
self.state.last_caller = ctx.sender
self.emit(event.CountChanged(
new_count=self.state.count,
changed_by=ctx.sender,
))
@call
def decrement(self, ctx):
"""Subtract 1 from the counter. Rejects if count would go below 0."""
if self.state.count <= 0:
raise ValueError("Counter cannot go below zero")
self.state.count = self.state.count - 1
self.state.last_caller = ctx.sender
self.emit(event.CountChanged(
new_count=self.state.count,
changed_by=ctx.sender,
))
@call
def add(self, ctx, value: int):
"""Add an arbitrary positive value to the counter."""
if value <= 0:
raise ValueError("Value must be positive")
self.state.count = self.state.count + value
self.state.last_caller = ctx.sender
self.emit(event.CountChanged(
new_count=self.state.count,
changed_by=ctx.sender,
))
@call
def reset(self, ctx):
"""Reset the counter to 0. Only the owner can reset."""
if ctx.sender != self.state.owner:
raise ValueError("Only the owner can reset")
self.state.count = 0
self.state.last_caller = ctx.sender
self.emit(event.CountReset(reset_by=ctx.sender))
@query
def get_count(self) -> int:
"""Return the current count."""
return self.state.count
@query
def info(self) -> dict:
"""Return contract metadata."""
return {
"count": self.state.count,
"owner": self.state.owner,
"last_caller": self.state.last_caller,
}
Key concepts:
@contract-- Marks the class as a deployable contractclass State-- Defines on-chain state with typed fields and defaults@constructor-- Runs once at deploy time to initialize state@call-- Methods that modify state (require a transaction and gas)@query-- Read-only methods (free, no transaction)self.emit(event.Name(...))-- Emits indexable event logsctx.sender-- The address of the account calling the method
4. Connect Your Wallet
Click Connect Wallet in the Deploy panel. The Playground supports MetaMask and other Web3 wallets.
5. Deploy
Click Deploy to send your contract to the chain. The Playground will:
- Encode your Python source as a deploy transaction
- Send it to the Panda precompile via your wallet
- Show the contract address once mined
6. Interact
Once deployed, the Interact panel shows all @call and @query methods parsed from your contract. Fill in parameters and click to execute.
Using the Panda SDK
For programmatic access, use the Panda SDK:
TypeScript
npm install @panda-sdk/client
import { PandaProvider, Contract } from "@panda-sdk/client";
const provider = new PandaProvider({ rpcUrl: "http://localhost:8545" });
await provider.discoverSender();
// Deploy a contract (using the Counter from contracts/examples/counter.py)
const code = `
from panda import contract, constructor, call, query, event
@contract
class Counter:
class State:
count: int = 0
owner: str = ""
last_caller: str = ""
@constructor
def deploy(self, ctx, initial_count: int = 0):
self.state.owner = ctx.sender
self.state.count = initial_count
@call
def increment(self, ctx):
self.state.count = self.state.count + 1
self.state.last_caller = ctx.sender
self.emit(event.CountChanged(
new_count=self.state.count,
changed_by=ctx.sender,
))
@query
def get_count(self) -> int:
return self.state.count
`;
const result = await provider.deploy(code);
console.log("Deployed at:", result.contractAddress);
// Call and query
await provider.call(result.contractAddress, "increment");
const count = await provider.query(result.contractAddress, "get_count");
console.log("Count:", count); // 1
Python
pip install panda-sdk-client
from panda_client import PandaProvider
provider = PandaProvider(rpc_url="http://localhost:8545")
provider.discover_sender()
code = open("counter.py").read()
result = provider.deploy(code)
print(f"Deployed at: {result.contract_address}")
provider.call(result.contract_address, "increment")
count = provider.query(result.contract_address, "get_count")
print(f"Count: {count}") # 1
Data Science Example
Panda supports on-chain machine learning via panda.ml. Here is the PricePredictor contract (contracts/examples/price_predictor.py), which trains a linear regression model on-chain and serves predictions:
from panda import contract, constructor, call, query, event
from panda.ml import LinearRegression, save_model, load_model, r2_score
@contract
class PricePredictor:
"""Linear regression model for on-chain price prediction."""
class State:
owner: str = ""
asset_name: str = ""
model: dict = {}
is_trained: bool = False
sample_count: int = 0
last_r2: float = 0.0
@constructor
def deploy(self, ctx, asset_name: str = "ETH"):
self.state.owner = ctx.sender
self.state.asset_name = asset_name
@call
def train(self, ctx, features: list, prices: list):
if len(features) != len(prices):
raise ValueError("features and prices must have same length")
if len(features) < 2:
raise ValueError("Need at least 2 data points")
model = LinearRegression()
model.fit(features, prices)
preds = model.predict(features)
r2 = r2_score(prices, preds)
self.state.model = save_model(model)
self.state.is_trained = True
self.state.sample_count = self.state.sample_count + len(features)
self.state.last_r2 = round(r2, 6)
self.emit(event.ModelTrained(
asset=self.state.asset_name,
samples=len(features),
r2_score=self.state.last_r2,
trainer=ctx.sender,
))
@query
def predict(self, features: list) -> list:
if not self.state.is_trained:
raise ValueError("Model not trained yet")
model = load_model(self.state.model)
predictions = model.predict(features)
return [round(p, 2) for p in predictions]
@query
def info(self) -> dict:
return {
"asset_name": self.state.asset_name,
"owner": self.state.owner,
"is_trained": self.state.is_trained,
"sample_count": self.state.sample_count,
"last_r2": self.state.last_r2,
}
The panda.ml module provides deterministic wrappers around scikit-learn models (LinearRegression, LogisticRegression, DecisionTreeClassifier, KMeans, RandomForest, and more). Models are serialized to JSON dicts via save_model() and reconstructed with load_model(), so they can be stored directly in contract state.
Cross-Chain Capabilities
Panda contracts can communicate across chains -- Ethereum, Solana, and between Panda layers. The BridgeV2 contract (contracts/examples/cross_chain_bridge_v2.py) demonstrates async cross-chain calls, fire-and-forget messages, and chain-whitelisted receivers:
from panda import contract, constructor, call, query, receiver, event, Chain
@contract
class BridgeV2:
class State:
owner: str = ""
total_bridged: int = 0
total_received: int = 0
pending_bridges: dict = {}
bridge_count: int = 0
@constructor
def deploy(self, ctx):
self.state.owner = ctx.sender
@call
async def bridge_tokens(self, ctx, amount: int, recipient: str = ""):
"""Bridge tokens to Ethereum. Awaits confirmation from Ethereum side."""
if amount <= 0:
raise ValueError("Amount must be positive")
target = recipient or ctx.sender
eth = Chain.ethereum()
# Lock tokens on this side
bridge_id = self.state.bridge_count
self.state.pending_bridges[str(bridge_id)] = {
"sender": ctx.sender,
"amount": amount,
"recipient": target,
"status": "pending",
}
self.state.bridge_count += 1
# Send cross-chain call and await confirmation
_result = await eth.call(
"0xEthBridge", "lock_and_mint",
amount=amount, recipient=target,
)
# This code runs when the cross-chain response arrives
self.state.pending_bridges[str(bridge_id)]["status"] = "confirmed"
self.state.total_bridged += amount
self.emit(event.BridgeConfirmed(bridge_id=bridge_id, amount=amount))
@receiver(chains=["ethereum"])
def on_tokens_locked(self, ctx, amount: int, sender: str):
"""Receive notification that tokens were locked on Ethereum."""
self.state.total_received += amount
self.emit(
event.TokensReceived(
amount=amount,
sender=sender,
source_chain=ctx.source_chain,
message_id=ctx.message_id,
)
)
@query
def get_stats(self) -> dict:
return {
"total_bridged": self.state.total_bridged,
"total_received": self.state.total_received,
"bridge_count": self.state.bridge_count,
}
Key cross-chain concepts:
Chain.ethereum()-- Creates a handle to the Ethereum chainawait eth.call(...)-- Async cross-chain call that waits for confirmation@receiver(chains=["ethereum"])-- Receives inbound messages from whitelisted chainsctx.source_chain,ctx.message_id-- Cross-chain execution context fields
Learn more in the Cross-Chain Messaging guide.
Next Steps
- Explore the Contract Development Guide for the full decorator reference and advanced patterns
- Read the SDK Reference for all decorators, classes, and testing utilities
- Learn about Cross-Chain Messaging for multi-chain contracts
- Open a Notebook to query contracts interactively from Python
- Learn about Visualizations to render charts and graphics from contracts
- Read the ML Contracts Guide for data science on-chain
- Understand ZK Proofs for verifiable computation
- See the Rollup Architecture for how Panda scales
- Check the API Reference for the full JSON-RPC API
- Browse the PRC-20 and PRC-721 token standards
- See all Ecosystem Apps available in the explorer