API Reference

Panda extends the standard Ethereum JSON-RPC and Solana JSON-RPC APIs with custom methods for Python smart contract management. This document covers all Panda-specific API extensions.

Ethereum JSON-RPC Extensions

These methods are available on panda-geth RPC endpoints (default port 8545). They supplement the standard eth_*, net_*, and web3_* methods.

panda_deployContract

Deploy a Python smart contract to the Panda-enabled Ethereum chain.

Parameters:

NameTypeDescription
codestringPython source code of the contract
constructorArgsobjectArguments to pass to the initialize() method (optional)
fromstringAddress of the deployer
gasstringGas limit (hex-encoded)
gasPricestringGas price in wei (hex-encoded, optional for EIP-1559)

Returns: Transaction hash (string)

Example:

// Request
{
  "jsonrpc": "2.0",
  "method": "panda_deployContract",
  "params": [{
    "code": "from panda import contract, call, query\n\n@contract\nclass Counter:\n    class State:\n        count: int = 0\n\n    @call\n    def increment(self, ctx, amount: int = 1):\n        self.state.count += amount\n\n    @query\n    def get_count(self) -> int:\n        return self.state.count",
    "constructorArgs": {},
    "from": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
    "gas": "0x2DC6C0"
  }],
  "id": 1
}

// Response
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xabc123def456789012345678901234567890123456789012345678901234abcd"
}

panda_callContract

Call a state-mutating (@call) method on a deployed contract. Produces a transaction.

Parameters:

NameTypeDescription
addressstringContract address
methodstringMethod name to call
argsobjectMethod arguments as key-value pairs
fromstringCaller address
gasstringGas limit (hex-encoded)

Returns: Transaction hash (string)

Example:

// Request
{
  "jsonrpc": "2.0",
  "method": "panda_callContract",
  "params": [{
    "address": "0x1234567890abcdef1234567890abcdef12345678",
    "method": "increment",
    "args": {"amount": 5},
    "from": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
    "gas": "0x100000"
  }],
  "id": 2
}

// Response
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": "0xdef456789012345678901234567890123456789012345678901234567890abcd"
}

panda_queryContract

Call a read-only (@query) method on a deployed contract. Does not produce a transaction. No gas cost.

Parameters:

NameTypeDescription
addressstringContract address
methodstringMethod name to query
argsobjectMethod arguments (optional)
blockNumberstringBlock number to query at (default: "latest")

Returns: The method's return value (JSON-encoded)

Example:

// Request
{
  "jsonrpc": "2.0",
  "method": "panda_queryContract",
  "params": [{
    "address": "0x1234567890abcdef1234567890abcdef12345678",
    "method": "get_count",
    "args": {}
  }],
  "id": 3
}

// Response
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": 5
}

panda_getContractState

Retrieve the full state of a deployed contract.

Parameters:

NameTypeDescription
addressstringContract address
blockNumberstringBlock number (default: "latest")

Returns: Object containing all state fields and their current values.

Example:

// Request
{
  "jsonrpc": "2.0",
  "method": "panda_getContractState",
  "params": ["0x1234567890abcdef1234567890abcdef12345678", "latest"],
  "id": 4
}

// Response
{
  "jsonrpc": "2.0",
  "id": 4,
  "result": {
    "count": 5,
    "owner": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18"
  }
}

panda_getContractCode

Retrieve the Python source code of a deployed contract.

Parameters:

NameTypeDescription
addressstringContract address

Returns: Python source code (string)

Example:

// Request
{
  "jsonrpc": "2.0",
  "method": "panda_getContractCode",
  "params": ["0x1234567890abcdef1234567890abcdef12345678"],
  "id": 5
}

// Response
{
  "jsonrpc": "2.0",
  "id": 5,
  "result": "from panda import contract, call, query\n\n@contract\nclass Counter:\n    class State:\n        count: int = 0\n..."
}

panda_lintContract

Lint a Python smart contract without deploying it. Returns detailed analysis results.

Parameters:

NameTypeDescription
codestringPython source code to lint

Returns: Lint result object

Example:

// Request
{
  "jsonrpc": "2.0",
  "method": "panda_lintContract",
  "params": ["from panda import contract, call\nimport os\n\n@contract\nclass Bad:\n    class State:\n        x: int = 0\n    @call\n    def hack(self, ctx):\n        os.system('whoami')"],
  "id": 6
}

// Response
{
  "jsonrpc": "2.0",
  "id": 6,
  "result": {
    "valid": false,
    "errors": [
      {
        "line": 2,
        "column": 0,
        "severity": "error",
        "code": "E001",
        "message": "Forbidden import: 'os' is not allowed in Panda contracts"
      },
      {
        "line": 10,
        "column": 8,
        "severity": "error",
        "code": "E002",
        "message": "Forbidden function call: 'os.system' is not allowed"
      }
    ],
    "warnings": [],
    "contract_info": {
      "name": "Bad",
      "state_fields": [{"name": "x", "type": "int", "default": "0"}],
      "call_methods": ["hack"],
      "query_methods": []
    }
  }
}

panda_estimateGas

Estimate the gas cost of calling a contract method.

Parameters:

NameTypeDescription
addressstringContract address
methodstringMethod name
argsobjectMethod arguments
fromstringCaller address (optional)

Returns: Estimated gas object

Example:

// Request
{
  "jsonrpc": "2.0",
  "method": "panda_estimateGas",
  "params": [{
    "address": "0x1234567890abcdef1234567890abcdef12345678",
    "method": "train",
    "args": {
      "features": [[1.0, 2.0], [3.0, 4.0]],
      "labels": [1.0, 2.0]
    }
  }],
  "id": 7
}

// Response
{
  "jsonrpc": "2.0",
  "id": 7,
  "result": {
    "pandaComputeUnits": 142857,
    "evmGasEquivalent": "0x15F391",
    "breakdown": {
      "bytecodeInstructions": 98432,
      "numpyOperations": 34210,
      "stateReads": 5120,
      "stateWrites": 5095
    }
  }
}

panda_getProof

Retrieve the ZK proof for a transaction that required one.

Parameters:

NameTypeDescription
txHashstringTransaction hash

Returns: ZK proof object

Example:

// Request
{
  "jsonrpc": "2.0",
  "method": "panda_getProof",
  "params": ["0xabc123..."],
  "id": 8
}

// Response
{
  "jsonrpc": "2.0",
  "id": 8,
  "result": {
    "proofType": "validity",
    "backend": "risc_zero",
    "proof": "0x...",
    "publicInputs": {
      "contractHash": "0x...",
      "inputStateRoot": "0x...",
      "outputStateRoot": "0x...",
      "callDataHash": "0x..."
    },
    "verified": true,
    "generationTimeMs": 45230,
    "proofSizeBytes": 1024
  }
}

panda_verifyProof

Verify a ZK proof on-chain.

Parameters:

NameTypeDescription
proofobjectProof object (as returned by panda_getProof)

Returns: boolean -- true if the proof is valid

Example:

// Request
{
  "jsonrpc": "2.0",
  "method": "panda_verifyProof",
  "params": [{"proofType": "validity", "proof": "0x...", "publicInputs": {}}],
  "id": 9
}

// Response
{
  "jsonrpc": "2.0",
  "id": 9,
  "result": true
}

Solana RPC Extensions

These methods are available on panda-solana RPC endpoints (default port 8899). They supplement the standard Solana RPC methods.

pandaDeployProgram

Deploy a Python smart contract as a Solana program.

Parameters:

NameTypeDescription
codestringPython source code
configobjectDeployment configuration (optional)
payerstringBase58-encoded payer public key

Returns: Transaction signature (string)

Example:

// Request
{
  "jsonrpc": "2.0",
  "method": "pandaDeployProgram",
  "params": [{
    "code": "from panda import contract, call, query\n\n@contract\nclass Counter:\n    class State:\n        count: int = 0\n\n    @call\n    def increment(self, ctx, amount: int = 1):\n        self.state.count += amount\n\n    @query\n    def get_count(self) -> int:\n        return self.state.count",
    "payer": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM"
  }],
  "id": 1
}

// Response
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "5VERv8NMhRYqCq2U7HDj2cyPNUNbqNpKEjYaA8QR3JcNXEQMpfGzNxsK3rbPY7u8XbUxfJ4S8WT2aNzNKwSzqAmp"
}

pandaCallProgram

Call a state-mutating method on a deployed Panda program.

Parameters:

NameTypeDescription
programIdstringBase58-encoded program public key
methodstringMethod name
argsobjectMethod arguments
payerstringBase58-encoded payer public key

Returns: Transaction signature (string)

Example:

// Request
{
  "jsonrpc": "2.0",
  "method": "pandaCallProgram",
  "params": [{
    "programId": "PNDAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "method": "increment",
    "args": {"amount": 10},
    "payer": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM"
  }],
  "id": 2
}

// Response
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": "2xNweLHLqrbx4zo1waDvgWNdFC25MHHB9BfAENMPYYBA1vKn5wLJ2dYBHXZbcm4c6U5xNXV3t4B7gJhVmhx2W8Q"
}

pandaQueryProgram

Query a read-only method on a deployed Panda program. Uses transaction simulation -- no transaction is submitted.

Parameters:

NameTypeDescription
programIdstringBase58-encoded program public key
methodstringMethod name
argsobjectMethod arguments (optional)

Returns: The method's return value (JSON-encoded)

Example:

// Request
{
  "jsonrpc": "2.0",
  "method": "pandaQueryProgram",
  "params": [{
    "programId": "PNDAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "method": "get_count"
  }],
  "id": 3
}

// Response
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": 10
}

pandaGetProgramState

Retrieve the full state of a deployed Panda program by reading its state PDA.

Parameters:

NameTypeDescription
programIdstringBase58-encoded program public key

Returns: Object with all state fields

Example:

// Request
{
  "jsonrpc": "2.0",
  "method": "pandaGetProgramState",
  "params": ["PNDAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"],
  "id": 4
}

// Response
{
  "jsonrpc": "2.0",
  "id": 4,
  "result": {
    "count": 10,
    "owner": "9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM"
  }
}

pandaGetProgramCode

Retrieve the Python source code of a deployed Panda program.

Parameters:

NameTypeDescription
programIdstringBase58-encoded program public key

Returns: Python source code (string)

Example:

// Request
{
  "jsonrpc": "2.0",
  "method": "pandaGetProgramCode",
  "params": ["PNDAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"],
  "id": 5
}

// Response
{
  "jsonrpc": "2.0",
  "id": 5,
  "result": "from panda import contract, call, query\n\n@contract\nclass Counter:\n..."
}

pandaLintContract

Lint a contract on the Solana side. Identical behavior to the Ethereum variant.

Parameters:

NameTypeDescription
codestringPython source code

Returns: Lint result object (same format as panda_lintContract)

Error Codes

Both Ethereum and Solana RPC extensions use consistent error codes:

CodeNameDescription
-32000EXECUTION_ERRORContract execution failed (Python exception)
-32001LINT_ERRORContract failed linting/validation
-32002OUT_OF_GASExecution exceeded gas limit
-32003TIMEOUTExecution exceeded wall-clock timeout
-32004SANDBOX_VIOLATIONContract attempted forbidden operation
-32005STATE_ERRORState read/write failure
-32006NOT_A_PANDA_CONTRACTAddress is not a Panda contract
-32007METHOD_NOT_FOUNDSpecified method does not exist on contract
-32008PROOF_ERRORZK proof generation or verification failed
-32009DEPLOYMENT_ERRORContract deployment failed
-32010DETERMINISM_ERRORNon-deterministic execution detected

Example error response:

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32000,
    "message": "Contract execution failed",
    "data": {
      "type": "AssertionError",
      "message": "Insufficient balance",
      "traceback": "  File \"contract.py\", line 15, in transfer\n    assert balance >= amount, \"Insufficient balance\"",
      "gasUsed": 12345
    }
  }
}

WebSocket Subscriptions

Ethereum WebSocket (port 8546)

Subscribe to Panda-specific events via WebSocket:

// Subscribe to all Panda contract events
{
  "jsonrpc": "2.0",
  "method": "eth_subscribe",
  "params": ["logs", {
    "topics": ["0xPANDA_EVENT_TOPIC"]
  }],
  "id": 1
}

// Subscribe to specific contract events
{
  "jsonrpc": "2.0",
  "method": "eth_subscribe",
  "params": ["logs", {
    "address": "0x1234567890abcdef1234567890abcdef12345678",
    "topics": ["0xPANDA_EVENT_TOPIC"]
  }],
  "id": 2
}

Solana WebSocket (port 8900)

Use standard Solana WebSocket subscriptions to watch Panda program activity:

// Subscribe to program account changes
{
  "jsonrpc": "2.0",
  "method": "programSubscribe",
  "params": [
    "PNDAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    {"encoding": "jsonParsed"}
  ],
  "id": 1
}

Rate Limits

Default rate limits (configurable per deployment):

Endpoint TypeLimit
Query methods (panda_queryContract, pandaQueryProgram)100 req/sec
Transaction methods (panda_callContract, pandaCallProgram)20 req/sec
Lint (panda_lintContract)10 req/sec
Gas estimation50 req/sec
State queries100 req/sec
WebSocket subscriptions50 concurrent per connection

SDK Integration

Python

import requests
import json

class PandaClient:
    def __init__(self, rpc_url="http://localhost:8545"):
        self.rpc_url = rpc_url
        self._id = 0

    def _call(self, method, params):
        self._id += 1
        response = requests.post(self.rpc_url, json={
            "jsonrpc": "2.0",
            "method": method,
            "params": [params] if isinstance(params, dict) else params,
            "id": self._id,
        })
        result = response.json()
        if "error" in result:
            raise Exception(f"RPC Error: {result['error']['message']}")
        return result["result"]

    def deploy(self, code, from_addr, gas="0x2DC6C0"):
        return self._call("panda_deployContract", {
            "code": code,
            "from": from_addr,
            "gas": gas,
        })

    def call(self, address, method, args=None, from_addr=None, gas="0x100000"):
        return self._call("panda_callContract", {
            "address": address,
            "method": method,
            "args": args or {},
            "from": from_addr,
            "gas": gas,
        })

    def query(self, address, method, args=None):
        return self._call("panda_queryContract", {
            "address": address,
            "method": method,
            "args": args or {},
        })

    def get_state(self, address):
        return self._call("panda_getContractState", [address, "latest"])

    def lint(self, code):
        return self._call("panda_lintContract", [code])


# Usage
client = PandaClient("http://localhost:30545")
tx = client.deploy(open("counter.py").read(), "0x742d35Cc...")
state = client.get_state("0x1234...")
result = client.query("0x1234...", "get_count")

JavaScript / TypeScript

import { ethers } from "ethers";

class PandaProvider {
  private provider: ethers.JsonRpcProvider;

  constructor(rpcUrl: string = "http://localhost:8545") {
    this.provider = new ethers.JsonRpcProvider(rpcUrl);
  }

  async deploy(code: string, from: string): Promise<string> {
    return this.provider.send("panda_deployContract", [{
      code,
      from,
      gas: "0x2DC6C0",
    }]);
  }

  async call(address: string, method: string, args: object = {}): Promise<string> {
    return this.provider.send("panda_callContract", [{
      address,
      method,
      args,
      from: await this.provider.getSigner().then(s => s.getAddress()),
      gas: "0x100000",
    }]);
  }

  async query(address: string, method: string, args: object = {}): Promise<any> {
    return this.provider.send("panda_queryContract", [{
      address,
      method,
      args,
    }]);
  }

  async getState(address: string): Promise<object> {
    return this.provider.send("panda_getContractState", [address, "latest"]);
  }

  async getCode(address: string): Promise<string> {
    return this.provider.send("panda_getContractCode", [address]);
  }

  async lint(code: string): Promise<object> {
    return this.provider.send("panda_lintContract", [code]);
  }
}