canopy Documentation

The official go implementation of the Canopy Network protocol

RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy canopy on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name canopy --restart always canopy-network/canopy:latest

File: README.md

Official golang implementation of the Canopy Network Protocol




Overview




⫸ **Welcome to the Network that Powers the Peer-to-Peer Launchpad for New Chains**

Built on a recursive architecture, chains bootstrap each other into independence —
forming an unstoppable web of utility and security.

Here you'll find:

➪ A recursive framework to build blockchains.

➪ The seed chain that started the recursive cycle.

For more information on the Canopy Network Protocol visit https://canopynetwork.org

Standard

➪ Canopy is an Ethereum-RPC compatible L1 for native transfers, so it can plug into existing Ethereum exchange, wallet, and indexer tooling,
including MetaMask. Use the /v1/eth endpoint as a custom Ethereum RPC and review the compatibility notes in the eth-spec

RPC

➪ Full RPC Specification

Protocol Documentation

➪ Check out the Canopy Network wiki: https://canopy-network.gitbook.io/docs

Repository Documentation

Welcome to the Canopy Network reference implementation. This repository can be well understood reading about the core modules:

  • Controller: Coordinates communication between all the major parts of the Canopy blockchain, like a central hub or "bus" that connects the system together.
  • Finite State Machine (FSM): Defines the logic for how transactions change the blockchain's state — it decides what’s valid and how state transitions happen from one block to the next.
  • Byzantine Fault Tolerant (BFT) Consensus: A consensus mechanism that allows the network to agree on new blocks even if some nodes are unreliable or malicious.
  • Peer-to-Peer Networking: A secure and encrypted communication system that lets nodes talk directly to each other without needing a central server.
  • Persistence: Manages the blockchain’s storage — it saves the current state (ledger), indexes past transactions, and ensures fast and reliable data verification.

How to Run It

➪ To run the Canopy binary, use the following commands:

bash
make build/canopy-full
canopy start

How to Run It with 🐳 Docker

➪ To run a Canopy Localnet in a containerized environment, use the following commands:

bash
make docker/build
make docker/up-fast
make docker/logs

or simply

make docker/up && make docker/logs

Running Tests

➪ To run Canopy unit tests, use the Go testing tools:

bash
make test

How to Contribute

➪ Canopy is an open-source project, and we welcome contributions from the community. Here's how to get involved:

  1. Fork the repository and clone it locally.
  2. Code your improvements or fixes.
  3. Submit a Pull Request (PR) for review.

➣ Please follow these guidelines to maintain high-quality contributions:

High Impact or Architectural Changes

➪ Before making large changes, discuss them with the Canopy team on Discord to ensure alignment.

Coding Style

  • Code must adhere to official Go formatting (use gofmt).
  • (Optional) Use EditorConfig for consistent formatting.
  • All code should follow Go documentation/commentary guidelines.
  • PRs should be opened against the development branch.



Contact



File: bft/README.md

Byzantine Fault Tolerant (BFT) Package

What is BFT?

Byzantine Fault Tolerance (BFT) refers to a system's ability to continue operating correctly even when some components fail or act maliciously. The term originates from the Byzantine Generals Problem, a logical dilemma illustrating the challenges of reaching consensus in a distributed system where components may fail or provide misleading information.

In blockchain networks, BFT algorithms enable validators to reach agreement on the state of the ledger despite potential failures or malicious actors. These algorithms ensure that as long as a certain threshold of participants (typically more than two-thirds) behave honestly, the network can maintain both safety (all honest nodes agree on the same values) and liveness (the system continues to make progress).

What is unique about NestBFT?

NestBFT is an innovative consensus algorithm designed specifically for the Canopy Network's multi-layered architecture. Unlike traditional BFT algorithms, NestBFT is engineered to operate in unreliable peer-to-peer environments, addressing challenges that many modern consensus protocols overlook by assuming network messages arrive without delay. Canopy employs NestBFT for both the base-chain and nested chain layers, creating a hierarchical consensus structure that enables efficient validation across nested chains.

Unlike many modern consensus protocols that assume peer-to-peer network messages arrive without delay, NestBFT is designed for unreliable peer-to-peer environments. It incorporates a novel pacemaker mechanism to address validator coordination challenges while offering immediate safety and finality.

NestBFT utilizes a star communication pattern where validators primarily communicate through a designated leader rather than directly with each other. This approach significantly reduces the number of messages that need to be exchanged during consensus, resulting in improved scalability. In traditional BFT algorithms with all-to-all communication, the number of messages grows quadratically with the number of validators (O(n²)). With NestBFT's star pattern, message complexity is reduced to linear (O(n)), allowing the system to support larger validator sets without communication overhead becoming prohibitive.

The Role of NestBFT in the Canopy Blockchain

NestBFT serves as the core consensus engine for the Canopy Network, enabling secure and efficient agreement on the state of both the base chain and nested chains. By providing a unified consensus layer, NestBFT allows validators to participate in multiple chains while reusing the same staked collateral, significantly improving capital efficiency.

The algorithm's design supports Canopy's plugin-based architecture, where validators interact with nested chain nodes through bilateral APIs. This approach offloads state machine operation and block storage to the nested chain software while managing the consensus and peer-to-peer layers at the base-chain level.

NestBFT's resilience against grinding attacks, DDoS, and long-range attacks makes it particularly well-suited for Canopy's multi-chain environment. The protocol's immediate finality property ensures that once transactions are confirmed, they cannot be reversed, providing strong security guarantees for nested chains.

This architecture also facilitates a predefined path for nested chains to eventually graduate to independence, providing flexibility for projects as they mature.

Processes

Consensus Phases

NestBFT implements a comprehensive consensus process consisting of eight core phases and two recovery phases. The process begins with leader election using a Verifiable Random Function (VRF) to select candidates, followed by voting to determine the leader. The elected leader then proposes a block, which undergoes multiple rounds of validation and voting by replicas.

The consensus progresses through propose, precommit, and commit phases, each requiring supermajority agreement from validators. This multi-phase approach ensures both safety and liveness of the network. If errors occur during consensus, the recovery phases—Round Interrupt and Pacemaker—allow replicas to synchronize their state and restart the process, maintaining the network's resilience against failures.

The design prioritizes safety during network partitions and includes mechanisms to prevent malicious leaders from stalling consensus indefinitely. This structured approach enables NestBFT to achieve immediate finality while maintaining robustness in unreliable network conditions.

mermaid
graph TD
    A[Start New Height] --> B[Election Phase]
    B --> C[ElectionVote Phase]
    C --> D[Propose Phase]
    D --> E[ProposeVote Phase]
    E --> F[Precommit Phase]
    F --> G[PrecommitVote Phase]
    G --> H[Commit Phase]
    H --> I[CommitProcess Phase]
    I --> J[Block Committed]
    J --> A

    E -- Failure --> K[Round Interrupt]
    F -- Failure --> K
    G -- Failure --> K
    H -- Failure --> K

    K --> L[Pacemaker Phase]
    L --> B

Consensus Engine

The NestBFT consensus engine is the central component that orchestrates the entire consensus process. It manages the state machine that transitions through the various consensus phases and coordinates the actions of validators during block production and validation.

The engine maintains the current view of the consensus state, including the current height, round, and phase. It processes incoming messages from other validators, verifies their validity, and updates the consensus state accordingly. When conditions for transitioning to the next phase are met (such as receiving a sufficient number of votes), the engine triggers the appropriate actions.

For leaders, the engine handles proposal creation, vote collection, and quorum certificate generation. For replicas, it manages proposal validation, vote generation, and block commitment. The engine also implements the timeout mechanisms that ensure liveness by allowing the system to progress even when some validators are unresponsive.

BLS Signatures

BLS (Boneh-Lynn-Shacham) signatures are a cryptographic innovation that NestBFT leverages to achieve significant efficiency improvements over traditional digital signature schemes. Unlike earlier signature algorithms like ECDSA or Ed25519, BLS signatures can be aggregated, allowing multiple signatures to be combined into a single, compact signature that can be verified against the corresponding public keys. This property is particularly valuable in consensus protocols where collecting signatures from many validators is a common operation.

In NestBFT, BLS signatures enable O(1) space complexity for quorum certificates by aggregating individual validator signatures into a single multisignature. This dramatically reduces the size of consensus messages and blockchain storage requirements. The verification process is also more efficient, as a single verification operation can validate the participation of multiple validators. NestBFT implements BLS signature aggregation for all voting phases, allowing the leader to collect individual signatures from validators and combine them into compact proofs of supermajority support.

Key aspects of BLS Signatures:

  • Signature aggregation reduces message size and storage requirements
  • Enables efficient verification of supermajority support
  • Provides non-interactive aggregation without requiring signer coordination
  • Maintains cryptographic security while improving performance
  • Supports threshold signatures for distributed key generation
  • Reduces bandwidth consumption in consensus message exchange

The [Election](election.md) Process

The Election Process in NestBFT combines Verifiable Random Functions (VRFs) with sortition to achieve a fair, unpredictable, and Sybil-resistant leader selection mechanism. Validators use VRFs to generate provably random values based on their private keys and consensus state. These values serve as lottery tickets, where lower values increase the chance of becoming a leader candidate. The VRF outputs are verifiable by other validators, ensuring that the randomness cannot be manipulated while maintaining deterministic verification.

Sortition in NestBFT refers to the stake-weighted selection process that ensures validators' influence in the leader election is proportional to their staked CNPY tokens. This approach prevents Sybil attacks by making it impossible to gain additional influence by splitting stake across multiple validator identities. If no VRF candidates emerge, the protocol falls back to a stake-weighted pseudorandom selection mechanism that maintains fairness while ensuring liveness. This sophisticated election process provides both unpredictability to prevent targeted attacks and fairness to maintain validator incentives.

Key aspects of the Election Process:

  • VRFs provide verifiable, unpredictable randomness for candidate selection
  • Stake-weighted sortition ensures influence proportional to economic commitment
  • Fallback mechanisms guarantee liveness even when VRF candidates are absent
  • Resistance to grinding attacks through unpredictable leader selection
  • Efficient verification of election results through cryptographic proofs
  • Balance between randomness and determinism for security and predictability
  • Sybil resistance through stake-weighted influence

Quorum Certificates

Quorum Certificates (QCs) in NestBFT are cryptographic proofs that a supermajority of validators has endorsed a specific consensus message. These certificates contain the original message along with an aggregated BLS signature representing more than 2/3 of the total voting power. QCs serve as irrefutable evidence that consensus has been reached at a particular phase, enabling validators to safely progress to subsequent phases.

NestBFT uses QCs at multiple points in the consensus process, including after proposal validation, precommit, and commit phases. Each QC builds upon previous ones, creating a chain of cryptographic evidence that ensures both safety and liveness. When a validator receives a valid QC, it can immediately verify the supermajority support without needing to communicate with other validators. This property enables efficient consensus progression and provides the foundation for NestBFT's immediate finality guarantees.

Key aspects of Quorum Certificates:

  • Cryptographic proof of supermajority validator support
  • Enables immediate verification of consensus progress
  • Chained structure creates auditable consensus history
  • Compact representation through BLS signature aggregation
  • Prevents conflicting decisions through supermajority requirements
  • Facilitates safe view changes during recovery phases
  • Provides the foundation for immediate transaction finality

The Voting Mechanism

The Voting Mechanism in NestBFT enables validators to express their support for proposals through cryptographic signatures. Each vote represents a validator's endorsement of a specific message, with the validator's voting power determined by their staked CNPY tokens. The protocol organizes votes by height, round, phase, and payload hash, ensuring that validators only vote on identical proposals. This structure prevents equivocation and maintains consensus integrity.

NestBFT implements a star communication pattern for voting, where validators send their votes to the current leader rather than broadcasting to all participants. The leader aggregates these votes and, upon collecting a supermajority (more than 2/3 of voting power), creates a quorum certificate that proves sufficient support. This certificate is then broadcast to all validators as evidence of consensus progress. This approach significantly reduces network communication overhead while maintaining Byzantine fault tolerance guarantees.

Key aspects of the Voting Mechanism:

  • Stake-weighted voting power ensures economic alignment with security
  • Cryptographic signatures provide non-repudiable proof of validator support
  • Structured vote organization prevents equivocation
  • Clear supermajority thresholds for consensus progress
  • Efficient verification of voting results through BLS signature aggregation

Safety and Liveness Mechanisms

NestBFT incorporates sophisticated safety and liveness mechanisms to ensure the protocol maintains correct operation even in challenging network conditions or when facing Byzantine behavior. Safety guarantees that honest validators will never commit conflicting blocks at the same height, preserving the integrity of the blockchain. This is achieved through the locking mechanism, where validators become "locked" on blocks that have received sufficient support, preventing them from voting for conflicting proposals.

Liveness mechanisms ensure that the protocol continues to make progress despite temporary failures or network issues. NestBFT implements timeout-based round changes that prevent a malicious or faulty leader from stalling consensus indefinitely. The Pacemaker phase synchronizes validators to the highest observed round, enabling the protocol to recover from failures and continue making progress. These mechanisms work together to provide a robust consensus system that prioritizes safety while maintaining practical liveness under realistic network conditions.

Key aspects of Safety and Liveness Mechanisms:

  • Locking mechanism prevents conflicting commits at the same height
  • Timeout-based round changes prevent indefinite stalling
  • Pacemaker synchronization aligns validators after failures
  • View change protocol enables recovery from leader failures
  • Prioritization of safety during network partitions
  • Practical liveness guarantees under realistic network conditions
  • Resistance to various Byzantine attack vectors

Security Mechanisms

Canopy employs innovative security mechanisms to ensure the reliability and stability of its nested chains. The NestBFT consensus algorithm provides robust protection against various attack vectors through its carefully designed phases and cryptographic techniques.

Byzantine Fault Tolerance

NestBFT can tolerate up to one-third of validators being Byzantine (malicious or faulty). This means that as long as more than two-thirds of the validators follow the protocol correctly, the system will maintain both safety and liveness.

Sybil Resistance

The stake-weighted leader election process prevents Sybil attacks by ensuring that influence in the consensus process is proportional to economic stake rather than node count.

[Double-Signing Prevention](evidence.md)

The protocol includes mechanisms to detect and punish validators who sign conflicting blocks at the same height, protecting against equivocation attacks.

Fork Prevention

The locking mechanism and quorum certificates ensure that once a block has been certified by a supermajority, no conflicting block can be certified at the same height, preventing blockchain forks.

DDoS Mitigation

The star communication pattern reduces the attack surface for DDoS attacks by limiting the number of connections each validator needs to maintain.

[Accountability](evidence.md)

All messages in NestBFT are signed, creating an audit trail that can be used to identify and punish misbehaving validators.

Timing Attack Resistance

The protocol includes timeouts and view changes to prevent malicious leaders from stalling consensus indefinitely.

Network Partition Handling

NestBFT prioritizes safety during network partitions, ensuring that conflicting blocks cannot be committed even if the network is temporarily split.

Long-Range Attack Prevention

The finality provided by NestBFT prevents long-range attacks that attempt to rewrite history from a point far in the past.

These security features work together to create a robust consensus system that can withstand various attacks while maintaining the integrity and availability of the Canopy blockchain and its nested chains.


File: cmd/rpc/web/wallet/docs/declarative-actions-and-chain.md

Declarative Actions and Chain Configuration

This wallet follows a config-first architecture: behavior is defined in configuration files, and the runtime executes that configuration.

The two core files are:

  • public/plugin/canopy/chain.json
  • public/plugin/canopy/manifest.json

Why This Exists

The goal is to avoid hardcoded blockchain behavior in UI components.

With this model, you can:

  • Change RPC endpoints without rewriting app code.
  • Add or modify wallet actions (send, stake, governance, etc.) without creating new React forms manually.
  • Keep business rules in a single, auditable configuration layer.
  • Reuse the same runtime engine across different chains or environments.

`chain.json`: Network and Data Contract

chain.json defines chain-level and API-level behavior:

  • RPC base URLs (rpc, admin)
  • denomination metadata (base, symbol, decimals)
  • explorers and links
  • data sources (ds) used by hooks and dynamic forms
  • fee providers and session settings

Think of chain.json as the integration contract with the blockchain.

`manifest.json`: Declarative UI + Action Contract

manifest.json defines what the app can do and how forms behave:

  • actions[]: each user operation (send, stake, edit stake, governance vote, etc.)
  • dynamic fields, validation, and conditional visibility
  • wizard steps and confirmation summaries
  • payload mapping and coercion
  • submit endpoint (base, path, method)
  • success/error notifications

Think of manifest.json as the interaction contract between user intent and transaction payloads.

End-to-End Runtime Flow

  1. User opens an action.
  2. Runtime loads action definition from manifest.json.
  3. Runtime resolves DS dependencies from chain.json (ds.* calls).
  4. Form is rendered dynamically from field config.
  5. Values are validated/coerced according to manifest rules.
  6. Payload is built declaratively.
  7. Request is submitted to the configured endpoint.
  8. Notifications and UI state are resolved from action config.

Runtime Layers in Practice

In this wallet, declarative actions are executed by a runtime pipeline:

  • ActionModalProvider / ActionsModal: opens and hosts action UI.
  • ActionRunner: orchestrates DS fetch, form state, payload build, submit, and notifications.
  • FormRenderer + field registry: resolves and renders each field type.
  • usePopulateController: controls initialization/autopopulate phases and DS readiness.

This separation is intentional:

  • UI shell remains generic.
  • business behavior lives in config.
  • dynamic data and validation are resolved centrally.

Example: Stake / Edit Stake

The stake action can route to different endpoints based on current state:

  • New validator -> /v1/admin/tx-stake
  • Existing validator -> /v1/admin/tx-edit-stake

This is defined in manifest submit config, not in component code.

The same action can also adapt:

  • field requirements
  • labels/help text
  • payload normalization

based on whether ds.validator exists.

Field Types (Manifest-Driven)

Field rendering is mapped through a field registry. Current types include:

  • text, textarea
  • amount, number, address
  • select, advancedSelect
  • switch, option, optionCard
  • tableSelect
  • dynamicHtml
  • layout/structure: section, divider, spacer, heading, collapsibleGroup

Why this matters:

  • new flows can be created by reusing existing field types in manifest.
  • runtime does not need action-specific React forms.
  • unsupported types fail safely and are visible during integration.

When opening a dynamic action modal, data can come from multiple sources:

  1. action defaults (field.value)
  2. DS results (ds.*)
  3. runtime/session context (account, chain, fees, session)
  4. explicit prefilledData passed when opening the action (for edit flows)

Population phases

Population is not a single step. It follows phases:

  • waiting: critical DS is not ready, form can show loading/skeleton behavior.
  • initializing: first safe population pass from templates/defaults.
  • ready: form becomes interactive; only explicit autoPopulate: "always" keeps updating from DS.

Precedence and safety

  • prefilledData is treated as authoritative for those fields during init.
  • default templates do not overwrite prefilled fields.
  • after initialization, DS updates do not blindly overwrite user input unless field explicitly opts in with autoPopulate: "always".

This avoids race conditions and accidental input loss when DS refreshes.

Responsive Behavior (Declarative + Runtime)

Responsive form layout is controlled through field span config and runtime helpers.

Grid model

  • Forms render in a 12-column grid.
  • Each field can define span (or ui.grid.colSpan) with breakpoints:
    • base, sm, md, lg, xl

Example:

json
{
  "id": "fee",
  "name": "fee",
  "type": "amount",
  "span": { "base": 12, "md": 6 }
}

Runtime behavior:

  • mobile-first: defaults to full width on small screens.
  • breakpoints progressively apply wider multi-column layouts.
  • tabs and modal content regions are scroll-safe to prevent overflow.

Dynamic action modals are designed to:

  • keep viewport constraints (dvh-based max height).
  • maintain internal scrolling in content region.
  • preserve close controls and headers.
  • avoid sidebar/topbar overlap through controlled overlay stacking.

Data Source (DS) Interaction Pattern

DS definitions live in chain.json. Action DS blocks reference them declaratively.

Typical usage:

  • action declares DS dependencies (account, validator, keystore, etc.).
  • DS options control staleness/refetch behavior (staleTimeMs, refetchIntervalMs, watch, critical).
  • templates consume DS via {{ ds.someKey.someValue }}.

This provides consistent data-fetch semantics for all actions.

Template and Coercion Model

Templates are resolved at runtime using context objects:

  • form
  • ds
  • account
  • chain
  • fees
  • params
  • session

Payload fields can define coercion:

  • string
  • number
  • boolean
  • raw objects where needed

For blockchain payloads, this is critical for safe numeric conversions
(e.g., display denom -> micro denom) and type correctness.

Design Rules for New Actions

When adding a new action, keep these rules:

  • Put business behavior in manifest, not React components.
  • Keep payload transformations explicit (coerce, conversion helpers, guards).
  • Fetch external state via DS, never inline endpoint strings in UI components.
  • Prefer conditional config (showIf, dynamic required, templated values) over branching UI code.
  • Keep confirmation summaries and notifications in config so users can review intent before submit.

Additional rules for dynamic modals/forms:

  • Use prefilledData for edit workflows instead of hardcoding edit components.
  • Use critical DS keys when form correctness depends on external data.
  • Use autoPopulate: "once" for default suggestions and "always" only when continuous sync is required.
  • Keep long help text and labels concise to preserve mobile readability.

Benefits and Tradeoffs

Benefits:

  • Faster iteration for product/business rules.
  • Lower risk of UI/backend drift.
  • Easier portability to new chains.

Tradeoffs:

  • More responsibility on config quality.
  • Requires strict validation and review of manifest changes.
  • Debugging often means inspecting resolved templates and DS outputs.

Before shipping manifest or chain changes:

  • Validate JSON syntax.
  • Verify DS endpoints, methods, and selectors.
  • Confirm numeric conversions (micro/base denom) are correct.
  • Confirm submit.path and payload align with RPC contract.
  • Test both success and failure toasts/messages.
  • Test responsive behavior for long labels/help/validation messages.

File: cmd/rpc/web/wallet/src/app/providers/README_ACTION_MODAL.md

Action Modal Integration

Overview

The ActionModalProvider provides a global modal system for running actions (like send, stake, etc.) from anywhere in the application.

Setup

The provider is already integrated in src/app/App.tsx:

tsx
<ActionModalProvider>
  
    <RouterProvider router={router}/>
  
</ActionModalProvider>

Usage

1. Import the hook

tsx
import { useActionModal } from '@/app/providers/ActionModalProvider';

2. Use in your component

tsx
export const YourComponent = () => {
  const { openAction } = useActionModal();

  const handleSend = () => {
    openAction('send', {
      onFinish: () => {
        console.log('Send completed!');
        // Refresh data, show toast, etc.
      },
      onClose: () => {
        console.log('Modal closed');
      }
    });
  };

  return (
    
      Send Tokens
    
  );
};

3. Available Actions

Actions are defined in public/plugin/canopy/manifest.json. Common actions include:

  • send - Send tokens to another address
  • stake - Stake tokens
  • unstake - Unstake tokens
  • editStake - Edit stake amount
  • receive - Show receive address

4. Setting the Selected Account

Before opening an action, make sure to set the correct account:

tsx
import { useAccounts } from '@/hooks/useAccounts';
import { useActionModal } from '@/app/providers/ActionModalProvider';

export const AccountList = () => {
  const { accounts, setSelectedAccount } = useAccounts();
  const { openAction } = useActionModal();

  const handleSendFromAccount = (accountAddress: string) => {
    // Find and set the account
    const account = accounts.find(a => a.address === accountAddress);
    if (account && setSelectedAccount) {
      setSelectedAccount(account);
    }

    // Open the send action
    openAction('send', {
      onFinish: () => {
        // Refresh balances, show success message, etc.
      }
    });
  };

  return (
    
      {accounts.map(account => (
         handleSendFromAccount(account.address)}>
          Send from {account.nickname}
        
      ))}
    
  );
};

Example: Complete Integration

See src/app/pages/Accounts.tsx for a complete example of how to:

  1. Import and use the hook
  2. Set the selected account before opening an action
  3. Handle callbacks (onFinish, onClose)
  4. Integrate with existing UI components

API Reference

`useActionModal()`

Returns an object with:

  • openAction(actionId: string, options?: ActionModalOptions) - Opens an action modal
  • closeAction() - Closes the current action modal
  • isOpen: boolean - Whether a modal is currently open
  • currentActionId: string | null - The ID of the currently open action

`ActionModalOptions`

typescript
interface ActionModalOptions {
  onFinish?: () => void;  // Called when action completes successfully
  onClose?: () => void;   // Called when modal is closed (any reason)
}

Styling

The modal uses the following classes from your theme:

  • bg-bg-secondary - Modal background
  • bg-bg-tertiary - Button backgrounds
  • border-bg-accent - Borders
  • text-text-muted - Icon colors

You can customize the modal appearance by editing src/app/providers/ActionModalProvider.tsx.


File: cmd/rpc/web/wallet/README.md

Canopy Wallet

A modern, config-first blockchain wallet built with React, TypeScript, and Tailwind CSS. The wallet features a dynamic, configuration-driven architecture where blockchain interactions, UI forms, and data sources are defined through JSON configuration files rather than hardcoded application logic.

🌟 Features

Core Functionality

  • Multi-Account Management: Create, import, and manage multiple blockchain accounts
  • Transaction Management: Send, receive, and track transactions with real-time status updates
  • Staking Operations: Stake, unstake, pause/unpause validators with comprehensive management tools
  • Governance Participation: Vote on proposals and create new governance proposals
  • Real-time Monitoring: Monitor node performance, network peers, system resources, and logs

Architecture Highlights

  • Config-First Approach: All blockchain interactions defined in chain.json and manifest.json
  • Data Source (DS) Pattern: Centralized API configuration and caching
  • Dynamic Form Generation: Transaction forms generated from JSON configuration
  • Real-time Updates: Live data updates using React Query with configurable intervals
  • Responsive Design: Modern UI with dark theme and responsive layouts

🏗️ Architecture Overview

Config-First Design

The wallet operates on a config-first principle where blockchain-specific configurations are externalized into JSON files:

text
public/plugin/canopy/
├── chain.json          # RPC endpoints, data sources, parameters
└── manifest.json       # Transaction forms, UI definitions, actions

Data Source (DS) Pattern

All API calls use a centralized DS system defined in chain.json:

json
{
  "ds": {
    "height": {
      "source": { "base": "rpc", "path": "/v1/query/height", "method": "POST" },
      "selector": "",
      "coerce": { "response": { "": "int" } }
    },
    "admin": {
      "consensusInfo": {
        "source": { "base": "admin", "path": "/v1/admin/consensus-info", "method": "GET" }
      }
    }
  }
}

Component Structure

text
src/
├── app/
│   ├── pages/           # Main application pages
│   └── providers/       # React context providers
├── components/
│   ├── dashboard/       # Dashboard widgets
│   ├── monitoring/      # Node monitoring components
│   ├── staking/         # Staking management UI
│   └── ui/              # Reusable UI components
├── hooks/               # Custom React hooks
├── core/                # Core utilities and DS system
└── manifest/            # Manifest parsing and types

🚀 Getting Started

Prerequisites

  • Node.js 18+ and npm/pnpm
  • A running Canopy node with RPC and Admin endpoints

Installation

  1. Clone the repository

    bash
    git clone <repository-url>
    cd canopy-wallet
  2. Install dependencies

    bash
    npm install
    # or
    pnpm install
  3. Configure your node connection

    Edit public/plugin/canopy/chain.json:

    json
    {
      "rpc": {
        "base": "http://your-node-ip:50002",
        "admin": "http://your-node-ip:50003"
      }
    }
  4. Copy environment file:

    bash
    cp .env.example .env
  5. Start the development server

    bash
    npm run dev
  6. Open your browser

    text
    http://localhost:5173

📁 Configuration Files

chain.json

Defines blockchain-specific configuration:

  • RPC Endpoints: Base and admin API URLs
  • Data Sources: API endpoint definitions with caching strategies
  • Fee Configuration: Transaction fee parameters and providers
  • Network Parameters: Chain ID, denomination, explorer URLs
  • Session Settings: Unlock timeouts and security preferences

manifest.json

Defines dynamic UI and transaction forms:

  • Actions: Transaction templates (send, stake, governance)
  • Form Fields: Dynamic form generation with validation
  • UI Mapping: Icons, labels, and transaction categorization
  • Payload Construction: Data transformation for API calls

Declarative Architecture Docs

  • Declarative Actions + Chain Guide: docs/declarative-actions-and-chain.md
  • Covers the config-first runtime flow, purpose of chain.json and manifest.json, and implementation guidelines.

🖥️ Main Features

Dashboard

  • Account balance overview with 24h change tracking
  • Recent transaction history with status indicators
  • Quick action buttons for common operations
  • Network status and validator information

Account Management

  • Create new accounts with secure key generation
  • Import existing accounts from private keys
  • Export account information and QR codes
  • Multi-account switching and management

Staking

  • Comprehensive validator management
  • Real-time staking statistics and rewards tracking
  • Bulk operations for multiple validators
  • Performance metrics and chain participation

Governance

  • View active proposals with voting status
  • Cast votes with detailed proposal information
  • Create new governance proposals
  • Track voting history and participation

Monitoring

  • Real-time Node Status: Sync status, block height, consensus information
  • Network Peers: Connected peers, network topology
  • System Resources: CPU, memory, disk usage monitoring
  • Live Logs: Real-time log streaming with export functionality
  • Performance Metrics: Block production, network I/O, system health

🔧 Development

Project Structure

  • React 18: Modern React with hooks and concurrent features
  • TypeScript: Full type safety throughout the application
  • Tailwind CSS: Utility-first styling with custom design system
  • React Router: Client-side routing with protected routes
  • React Query: Server state management with caching
  • Framer Motion: Smooth animations and transitions
  • Zustand: Lightweight state management

Key Development Patterns

Data Fetching

All data fetching uses the DS pattern through custom hooks:

typescript
const dsFetch = useDSFetcher();
const data = await dsFetch('admin.consensusInfo');

Form Handling

Forms are generated dynamically from manifest configuration:

typescript
const { openAction } = useActionModal();
openAction('send'); // Opens send transaction form

Error Handling

Consistent error handling with user-friendly messages:

typescript
const { data, error, isLoading } = useQuery({
  queryKey: ['nodeData'],
  queryFn: () => dsFetch('admin.consensusInfo'),
  retry: 2,
  retryDelay: 1000,
});

Adding New Features

  1. Define Data Sources: Add new DS endpoints in chain.json
  2. Create Hooks: Build custom hooks for data fetching
  3. Build Components: Create UI components using design system
  4. Add Actions: Define new transaction types in manifest.json

Environment Variables

bash
VITE_DEFAULT_CHAIN=canopy
VITE_CONFIG_MODE=embedded
VITE_NODE_ENV=development

🛠️ Deployment

Production Build

bash
npm run build

Configuration for Production

  1. Update chain.json with production RPC endpoints
  2. Configure proper CORS settings on your node
  3. Set appropriate session timeouts and security parameters
  4. Ensure SSL/TLS is configured for secure connections

Docker Deployment

The wallet can be deployed alongside Canopy nodes:

bash
# Build the application
npm run build

# Serve with any static file server
npx serve -s dist -p 3000

🔐 Security

Key Management

  • Private keys are encrypted with user passwords
  • Keys stored locally in browser secure storage
  • Session-based key unlocking with configurable timeouts

Network Security

  • All API calls over HTTPS in production
  • CORS configuration required on node endpoints
  • Session timeout and re-authentication for sensitive operations

Best Practices

  • Regular password changes recommended
  • Backup recovery phrases securely
  • Use hardware wallets for large amounts
  • Verify transaction details before signing

📚 API Reference

Core Hooks

  • useAccountData(): Account balances and information
  • useNodeData(): Node status and monitoring data
  • useValidators(): Validator information and staking data
  • useTransactions(): Transaction history and status

DS Endpoints

All API endpoints are defined in chain.json under the ds section:

  • Query endpoints: Height, accounts, validators, transactions
  • Admin endpoints: Consensus info, peer info, logs, resources
  • Transaction endpoints: Send, stake, governance operations

🤝 Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes following the existing patterns
  4. Add appropriate tests and documentation
  5. Commit your changes (git commit -m 'Add amazing feature')
  6. Push to the branch (git push origin feature/amazing-feature)
  7. Open a Pull Request

Code Style

  • Use TypeScript for all new code
  • Follow existing naming conventions
  • Add JSDoc comments for complex functions
  • Use the established DS pattern for API calls
  • Maintain responsive design principles

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🆘 Support

For support and questions:

  • Check the documentation in /docs
  • Review existing issues on GitHub
  • Join our community discussions
  • Contact the development team

🗂️ Configuration Examples

Basic Node Configuration

json
{
  "chainId": "1",
  "displayName": "Canopy",
  "rpc": {
    "base": "http://localhost:50002",
    "admin": "http://localhost:50003"
  },
  "denom": {
    "base": "ucnpy",
    "symbol": "CNPY",
    "decimals": 6
  }
}

Simple Transaction Action

json
{
  "id": "send",
  "title": "Send",
  "icon": "Send",
  "form": {
    "fields": [
      {
        "id": "output",
        "name": "output",
        "type": "text",
        "label": "Recipient Address",
        "required": true
      }
    ]
  },
  "submit": {
    "base": "admin",
    "path": "/v1/admin/tx-send",
    "method": "POST"
  }
}

Building for Production

Environment Configuration

The build process uses the VITE_BASE_PATH environment variable to configure the deployment path.

Default production path: /wallet/

To customize the base path, create a .env file:

bash
# For deployment at https://example.com/wallet/
VITE_BASE_PATH=/wallet/

# For deployment at root domain https://wallet.example.com/
VITE_BASE_PATH=/

# For custom subdirectory
VITE_BASE_PATH=/my-custom-path/

Build Commands

bash
# Production build (uses /wallet/ by default)
npm run build

# Build with custom base path
VITE_BASE_PATH=/custom/ npm run build

# Preview production build
npm run preview

The build output will be in the out/ directory.

Deployment

Docker Build

The wallet is automatically built during the Docker image build process via the Makefile:

bash
# From project root
make build/wallet

This is automatically called by the Dockerfile.

Manual Deployment

  1. Build the wallet:

    bash
    npm run build
  2. The compiled assets will be embedded in the Go binary during the build process via //go:embed directives.

Reverse Proxy Configuration

When deploying behind a reverse proxy (like Traefik), ensure the proxy is configured to strip the path prefix:

Example Traefik Configuration:

yaml
http:
  middlewares:
    strip-wallet-prefix:
      stripPrefix:
        prefixes:
          - "/wallet"
        forceSlash: false

  routers:
    wallet:
      rule: "Host(`example.com`) && PathPrefix(`/wallet`)"
      service: wallet
      middlewares:
        - strip-wallet-prefix

This ensures that requests to /wallet/assets/file.js are forwarded to the Go server as /assets/file.js.

Troubleshooting

Assets not loading in production

Problem: CSS and JS files return 404 or wrong MIME type.

Solution:

  1. Verify VITE_BASE_PATH matches your deployment path
  2. Ensure reverse proxy is configured to strip the path prefix
  3. Rebuild the Docker image after changing the base path

Built with ❤️ for the Canopy ecosystem


File: cmd/rpc/web/explorer/README.md

Explorer

A modern React application built with Vite, TypeScript, Tailwind CSS, React Hook Form, Framer Motion, and React Query for efficient data fetching and state management.

Features

  • ⚡ Vite - Fast build tool and dev server
  • ⚛️ React 18 - Latest React features
  • 🔷 TypeScript - Type safety and better developer experience
  • 🎨 Tailwind CSS - Utility-first CSS framework
  • 📝 React Hook Form - Performant forms with easy validation
  • ✨ Framer Motion - Production-ready motion library for React
  • 🔄 React Query - Powerful data fetching and caching library

Getting Started

Prerequisites

  • Node.js (version 18 or higher)
  • npm or yarn
  • Canopy blockchain node running on port 50001

Installation

  1. Clone the repository and navigate to the project directory:
bash
cd cmd/rpc/web/explorer
  1. Install dependencies:
bash
npm install
  1. Ensure your Canopy blockchain node is running on port 50001:
bash
# Your Canopy node should be accessible at:
# http://localhost:50001
  1. Start the development server:
bash
npm run dev
  1. Open your browser and navigate to http://localhost:5173

Quick Setup

The application will automatically connect to your Canopy node at http://localhost:50001. If your node is running on a different port, you can configure it by setting window.__CONFIG__ in your HTML or modifying the API configuration.

Available Scripts

  • npm run dev - Start development server
  • npm run build - Build for production
  • npm run preview - Preview production build
  • npm run lint - Run ESLint
  • npm run type-check - Run TypeScript type checking

Project Structure

text
/* Detailed source-code truncated for AI context efficiency. */

Component Mapping

Component Purpose Location
Analytics Dashboard with network metrics and charts /analytics
Blocks Block explorer with filtering and pagination /blocks
Transactions Transaction history and details /transactions
Validators Validator information and ranking /validators
Token Swaps Token swap orders and trading /token-swaps
Home Main dashboard with overview tables /

API Integration

This project includes a complete API integration system with React Query:

API Functions (`src/lib/api.ts`)

  • All backend API calls from the original explorer project
  • TypeScript support for better type safety
  • Error handling and response processing

React Query Hooks (`src/hooks/useApi.ts`)

  • Custom hooks for each API endpoint
  • Automatic caching and background updates
  • Loading and error states
  • Optimistic updates support

Available Hooks

  • useBlocks(page) - Fetch blocks data
  • useTransactions(page, height) - Fetch transactions
  • useAccounts(page) - Fetch accounts
  • useValidators(page) - Fetch validators
  • useCommittee(page, chainId) - Fetch committee data
  • useDAO(height) - Fetch DAO data
  • useAccount(height, address) - Fetch account details
  • useParams(height) - Fetch parameters
  • useSupply(height) - Fetch supply data
  • useCardData() - Fetch dashboard card data
  • useTableData(page, category, committee) - Fetch table data
  • And many more...

Usage Example

typescript
import { useBlocks, useValidators } from './hooks/useApi'

function MyComponent() {
  const { data: blocks, isLoading, error } = useBlocks(1)
  const { data: validators } = useValidators(1)

  if (isLoading) return Loading...
  if (error) return Error: {error.message}

  return (
    
      <h2>Blocks: {blocks?.totalCount}</h2>
      <h2>Validators: {validators?.totalCount}</h2>
    
  )
}

Technologies Used

  • Vite - Build tool and dev server
  • React - UI library
  • TypeScript - Type safety
  • Tailwind CSS - Styling
  • React Hook Form - Form handling
  • Framer Motion - Animations
  • React Query - Data fetching and caching

Development

This project uses:

  • ESLint for code linting
  • Prettier for code formatting
  • TypeScript for type checking
  • React Query DevTools for debugging queries

API Configuration

The application automatically configures API endpoints based on the environment:

  • Default RPC URL: http://localhost:50002
  • Default Admin RPC URL: http://localhost:50002
  • Default Chain ID: 1

You can override these settings by setting window.__CONFIG__ in your HTML.

License

MIT


File: cmd/rpc/README.md

JSON-RPC API Methods


RPC Routes Reference

  • /v1/
  • /v1/tx
  • /v1/txs
  • /v1/query/height
  • /v1/query/indexer-blobs
  • /v1/query/account
  • /v1/query/accounts
  • /v1/query/pool
  • /v1/query/pools
  • /v1/query/validator
  • /v1/query/validators
  • /v1/query/committee-data
  • /v1/query/committees-data
  • /v1/query/subsidized-committees
  • /v1/query/retired-committees
  • /v1/query/non-signers
  • /v1/query/params
  • /v1/query/supply
  • /v1/query/fee-params
  • /v1/query/gov-params
  • /v1/query/con-params
  • /v1/query/val-params
  • /v1/query/eco-params
  • /v1/query/state
  • /v1/query/state-diff
  • /v1/query/state-diff
  • /v1/query/cert-by-height
  • /v1/query/block-by-height
  • /v1/query/blocks
  • /v1/query/block-by-hash
  • /v1/query/txs-by-height
  • /v1/query/txs-by-sender
  • /v1/query/txs-by-rec
  • /v1/query/tx-by-hash
  • /v1/query/events-by-height
  • /v1/query/events-by-address
  • /v1/query/events-by-chain
  • /v1/query/order
  • /v1/query/orders
  • /v1/query/dex-batch
  • /v1/query/next-dex-batch
  • /v1/query/dex-price
  • /v1/query/last-proposers
  • /v1/query/valid-double-signer
  • /v1/query/double-signers
  • /v1/query/minimum-evidence-height
  • /v1/query/lottery
  • /v1/query/pending
  • /v1/query/failed-txs
  • /v1/gov/proposals
  • /v1/gov/poll
  • /v1/query/root-chain-info
  • /v1/query/validator-set
  • /v1/query/checkpoint
  • /v1/subscribe-rc-info
  • /debug/pprof
  • /debug/pprof/*name
  • /v1/eth
  • /v1/admin/keystore
  • /v1/admin/keystore-new-key
  • /v1/admin/keystore-import
  • /v1/admin/keystore-import-raw
  • /v1/admin/keystore-delete
  • /v1/admin/keystore-get
  • /v1/admin/tx-send
  • /v1/admin/tx-stake
  • /v1/admin/tx-edit-stake
  • /v1/admin/tx-unstake
  • /v1/admin/tx-pause
  • /v1/admin/tx-unpause
  • /v1/admin/tx-change-param
  • /v1/admin/tx-dao-transfer
  • /v1/admin/tx-create-order
  • /v1/admin/tx-edit-order
  • /v1/admin/tx-delete-order
  • /v1/admin/tx-dex-limit-order
  • /v1/admin/tx-dex-liquidity-deposit
  • /v1/admin/tx-dex-liquidity-withdraw
  • /v1/admin/tx-lock-order
  • /v1/admin/tx-close-order
  • /v1/admin/tx-subsidy
  • /v1/admin/tx-start-poll
  • /v1/admin/tx-vote-poll
  • /v1/admin/resource-usage
  • /v1/admin/peer-info
  • /v1/admin/consensus-info
  • /v1/admin/peer-book
  • /v1/admin/config
  • /v1/admin/log
  • /v1/gov/add-vote
  • /v1/gov/del-vote

Standard

Version

Route: /v1/

Description: responds with the software version

HTTP Method: GET

Request: null

Response: string - the protocol version

Example:

text
$ curl -H "Content-Type: application/json" -X GET --data '{}' localhost:50002/v1/

> "0.0.0-alpha"

Tx

Route: /v1/tx

Description: submits a transaction

HTTP Method: POST

Request:

  • type: string - the message name ("send", "stake", "edit-stake", ...)
  • msg: Message - the payload of the transaction (MessageSend, MessageStake, ...)
  • signature: Signature - the authorization (public key and signature) of the transaction
  • time: uint64 - the creation time of the transaction for replay protection (unix micro)
  • createdHeight: uint64 - the height the transaction was created +/- 4320 accepted
  • fee: uint64 the network fee for sending the transaction (minimum is parameterized)
  • memo: string - an embedded message in the transaction (optional)
  • networkID: uint64 - the unique identifier of the network (1 for mainnet, 2 for testnet, ...)
  • chainID: uint64 - the unique identifier of the committee (1 for canopy, 2 for canary, ...)

Response: hex string - the hash of the transaction

Example:

text
$ curl -X POST localhost:50002/v1/tx \
  -H "Content-Type: application/json" \
  -d '{
    "type": "send",
    "msg": {
      "fromAddress": "b8bc466953be5f6f31954108f683d2b02b8b7453",
      "toAddress": "08c18a0e3ef3727b42eab9eef51494f8f7f83bd0",
      "amount": 1000000
    },
    "signature": {
      "publicKey": "a5b97c05cb26c9bc118b3e2258f03101a9a427317dccd80abd4f3a82a42afc6c27ae5f63a04aaef180558b0176282f1c78a51af474036316b1c2ae826bf8c23a",
      "signature": "89ce883843a4ebfc763e0fd377718e659063bdfee492f3fff1cfe055b9cbc1f67da580e3ad638c32d520c3db4baf94a0c4f605cb73b0ee021a330a23a93ffe99"
    },
    "time": 1747865418150488,
    "createdHeight": 1,
    "fee": 10000,
    "memo": "hello world",
    "networkID": 1,
    "chainID": 1
  }'

> "25c7216b7523fdfdb60b989b38c4b9d83a546a63029d56f2ce6f2be6bd255aa4"

Txs

Route: /v1/txs

Description: submits multiple transactions in a single request

HTTP Method: POST

Request: array of transactions, each with the same structure as the /v1/tx request:

  • type: string - the message name ("send", "stake", "edit-stake", ...)
  • msg: Message - the payload of the transaction (MessageSend, MessageStake, ...)
  • signature: Signature - the authorization (public key and signature) of the transaction
  • time: uint64 - the creation time of the transaction for replay protection (unix micro)
  • createdHeight: uint64 - the height the transaction was created +/- 4320 accepted
  • fee: uint64 the network fee for sending the transaction (minimum is parameterized)
  • memo: string - an embedded message in the transaction (optional)
  • networkID: uint64 - the unique identifier of the network (1 for mainnet, 2 for testnet, ...)
  • chainID: uint64 - the unique identifier of the committee (1 for canopy, 2 for canary, ...)

Response: array of hex strings - the hashes of the submitted transactions

Example:

text
$ curl -X POST localhost:50002/v1/txs \
  -H "Content-Type: application/json" \
  -d '[
    {
      "type": "send",
      "msg": {
        "fromAddress": "b8bc466953be5f6f31954108f683d2b02b8b7453",
        "toAddress": "08c18a0e3ef3727b42eab9eef51494f8f7f83bd0",
        "amount": 1000000
      },
      "signature": {
        "publicKey": "a5b97c05cb26c9bc118b3e2258f03101a9a427317dccd80abd4f3a82a42afc6c27ae5f63a04aaef180558b0176282f1c78a51af474036316b1c2ae826bf8c23a",
        "signature": "89ce883843a4ebfc763e0fd377718e659063bdfee492f3fff1cfe055b9cbc1f67da580e3ad638c32d520c3db4baf94a0c4f605cb73b0ee021a330a23a93ffe99"
      },
      "time": 1747865418150488,
      "createdHeight": 1,
      "fee": 10000,
      "memo": "hello world",
      "networkID": 1,
      "chainID": 1
    }
  ]'

> ["25c7216b7523fdfdb60b989b38c4b9d83a546a63029d56f2ce6f2be6bd255aa4"]

Height

Route: /v1/query/height

Description: responds with the next block version

HTTP Method: POST

Request: null

Response:

  • height: uint64 - the number of the next block

Example::

text
$ curl -H "Content-Type: application/json" -X POST --data '{}' localhost:50002/v1/query/height

> 9157

Indexer Blobs

Route: /v1/query/indexer-blobs

Description: responds with the current and previous indexer blobs as protobuf bytes. The indexer blob is a snapshot of the blockchain state at a given height, containing blocks, accounts, pools, validators, orders, params, supply, dex data, committee data, and signer information. Accounts, pools, and validators are returned as deltas between the current and previous blobs.

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)

Response: raw protobuf bytes (application/x-protobuf) representing an IndexerBlobs message containing:

  • current: IndexerBlob - the indexer blob at the requested height
    • block: bytes - the block data
    • accounts: []bytes - the account entries
    • pools: []bytes - the pool entries
    • validators: []bytes - the validator entries
    • dexPrices: []bytes - the DEX price entries
    • nonSigners: []bytes - the non-signer entries
    • doubleSigners: []bytes - the double-signer entries
    • orders: bytes - the order book data
    • params: bytes - the protocol parameters
    • dexBatches: []bytes - the DEX batch entries
    • nextDexBatches: []bytes - the next DEX batch entries
    • committeesData: bytes - the committees data
    • subsidizedCommittees: []uint64 - the subsidized committee IDs
    • retiredCommittees: []uint64 - the retired committee IDs
    • supply: bytes - the token supply data
    • totalValidatorsActive: uint32 - count of active validators
    • totalValidatorsPaused: uint32 - count of paused validators
    • totalValidatorsUnstaking: uint32 - count of unstaking validators
    • validatorsDelta: bool - whether validators are returned as a delta
    • totalDelegatesActive: uint32 - count of active delegates
    • totalDelegatesPaused: uint32 - count of paused delegates
    • totalDelegatesUnstaking: uint32 - count of unstaking delegates
  • previous: IndexerBlob - the indexer blob at the previous height (same structure as current, absent for heights ≤ 2)

Example:

text
$ curl -X POST localhost:50002/v1/query/indexer-blobs \
  -H "Content-Type: application/json" \
  -d '{
        "height": 100
      }'

>

Account

Route: /v1/query/account

Description: responds with an account for the specified address

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)
  • address: hex string - the 20 byte identifier of the account

Response:

  • address: hex string - the 20 byte identifier
  • amount: uint64 - the spendable balance of funds the account can currently withdraw
  • totalAmount: uint64 - the total balance recorded for the account before vesting locks are applied
  • vestedAmount: uint64 - the portion of vestingAmount that has vested at the queried height
  • lockedAmount: uint64 - the portion of vestingAmount that is still locked at the queried height
  • vestingAmount: uint64 - the total amount governed by the vesting schedule (omitted when zero)
  • vestingStartHeight: uint64 - the block height where vesting begins (omitted when zero)
  • vestingCliffHeight: uint64 - the block height where vesting first becomes spendable (omitted when zero)
  • vestingEndHeight: uint64 - the block height where vesting fully completes (omitted when zero)

Example:

text
$ curl -X POST localhost:50002/v1/query/account \
  -H "Content-Type: application/json" \
  -d '{
        "address": "0971d5d96f1533479ab1a6472fe0260df6ae732d",
        "height": 1000
      }'

> {
    "address": "0971d5d96f1533479ab1a6472fe0260df6ae732d",
    "amount": 99990000,
    "totalAmount": 100000000,
    "vestedAmount": 500000,
    "lockedAmount": 10000,
    "vestingAmount": 510000,
    "vestingStartHeight": 900,
    "vestingCliffHeight": 950,
    "vestingEndHeight": 1200
  }

Accounts

Route: /v1/query/accounts

Description: responds with a list of accounts based on the page parameters

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)
  • perPage: int - the number of elements per page (the default is 10 and max is 5,000)
  • pageNumber: int - the number of the page (the default is 1)

Response:

  • perPage: int - the number of elements per page
  • pageNumber: int - the number of the page
  • results: array - the list of result objects
    • address: - hex string the 20 byte unique identifier of the account
    • amount: - uint64 the spendable balance in micro denomination
    • totalAmount: - uint64 the total recorded balance before vesting locks are applied
    • vestedAmount: - uint64 the vested portion of the vesting tranche at the queried height
    • lockedAmount: - uint64 the still-locked portion of the vesting tranche at the queried height
    • vestingAmount: - uint64 the total amount on the vesting schedule, omitted when zero
    • vestingStartHeight: - uint64 the height where vesting begins, omitted when zero
    • vestingCliffHeight: - uint64 the height where vesting first becomes spendable, omitted when zero
    • vestingEndHeight: - uint64 the height where vesting fully completes, omitted when zero
  • type: string - the type of results
  • count: int - length of results
  • totalPages: int - number of pages
  • totalCount: int - total number of items that exist in all pages

Example:

text
$ curl -X POST localhost:50002/v1/query/accounts \
  -H "Content-Type: application/json" \
  -d '{
        "perPage": 10,
        "page": 1,
        "height": 1000
      }'

> {
    "pageNumber": 1,
    "perPage": 10,
    "results": [
      {
        "address": "180c9d067ce4275612896dc7ce01390329e7f101",
        "amount": 969901,
        "totalAmount": 969901,
        "vestedAmount": 0,
        "lockedAmount": 0
      },
      {
        "address": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
        "amount": 18239045002,
        "totalAmount": 18239045002,
        "vestedAmount": 0,
        "lockedAmount": 0
      },
      {
        "address": "551f21e333012027b81701a35023efc88b864975",
        "amount": 130,
        "totalAmount": 1000,
        "vestedAmount": 30,
        "lockedAmount": 870,
        "vestingAmount": 900,
        "vestingStartHeight": 900,
        "vestingCliffHeight": 950,
        "vestingEndHeight": 1200
      }
    ],
    "type": "accounts",
    "count": 3,
    "totalPages": 1,
    "totalCount": 3
  }

Pool

Route: /v1/query/pool

Description: responds with a Pool structure for a specific ID

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)
  • id: uint64 - the unique identifier

Response:

  • id: string - the unique identifier
  • amount:uint64 - the balance of funds the pool has in micro denomination
  • poolPoints: array - a list of pool points
    • address: hex-string - the recipient address of the points
    • points: uint64 the amount of points owned
  • totalPoolPoints: uint64 - the sum of all pool points
    Example:
text
$ curl -X POST localhost:50002/v1/query/pool \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000
        "id": 1,
      }'

> {
  "id": "1",
  "amount": 969,
  "poolPoints": [
    {
      "address": "551f21e333012027b81701a35023efc88b864975",
      "points": 100
    }
  ],
  "totalPoolPoints": 100
}

Pools

Route: /v1/query/pools

Description: responds with a list of pools based on the page parameters

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)
  • perPage: int - the number of elements per page (the default is 10 and max is 5,000)
  • pageNumber: int - the number of the page (the default is 1)

Response:

  • perPage: int - the number of elements per page
  • pageNumber: int - the number of the page
  • results: array - the list of result objects
    • id: - string the unique identifier of the pool
    • amount: - uint64 the balance of funds the pool has in micro denomination
    • poolPoints: array - a list of pool points
      • address: hex-string - the recipient address of the points
      • points: uint64 the amount of points owned
  • totalPoolPoints: uint64 - the sum of all pool points
  • type: string - the type of results
  • count: int - length of results
  • totalPages: int - number of pages
  • totalCount: int - total number of items that exist in all pages

Example:

text
$ curl -X POST localhost:50002/v1/query/pools \
  -H "Content-Type: application/json" \
  -d '{
        "perPage": 10,
        "page": 1,
        "height": 1000
      }'

> {
    "pageNumber": 1,
    "perPage": 10,
    "results": [
      {
        "id": "1",
        "amount": 969,
        "poolPoints": [
          {
            "address": "551f21e333012027b81701a35023efc88b864975",
            "points": 100
          }
        ],
        "totalPoolPoints": 100
      }
    ],
    "type": "pools",
    "count": 1,
    "totalPages": 1,
    "totalCount": 1
  }

Validator

Route: /v1/query/validator

Description: responds with a Validator structure for a specific address

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)
  • address: hex string - the 20 byte identifier

Response:

  • address: hex-string - the 20 byte identifier
  • publicKey: hex string - the unique public identifier of the validator that is used to validate digital signatures
  • stakedAmount: uint64 - the locked balance of funds the address has in micro denomination
  • committees: []uint64 - list of chain ids the validator is staked on behalf
  • netAddress: url - the public peer-to-peer address of the validator
  • maxPausedHeight: uint64 - the height the validator will be automatically begin unstaking if not unpaused (0 is not paused)
  • unstakingHeight: uint64 - the height the validator's locked funds are returned (0 is not unstaking)
  • output: hex string - the 20 byte unique identifier of the account where rewards and locked funds are distributed
  • delegate: bool - is the validator a delegate only
  • compound: bool - is the validator automatically compounding their rewards

Example:

text
$ curl -X POST localhost:50002/v1/query/validator \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000
        "address": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
      }'

> {
      "address": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
      "publicKey": "b2947db37385bb43c46244cef15f2451a446cea011fc1a2e1d52b1cecc7a50a8924e0e062555793bbd55a91a685017ee",
      "committees": [
        1
      ],
      "netAddress": "tcp://localhost",
      "stakedAmount": 2000,
      "maxPausedHeight": 0,
      "unstakingHeight": 0,
      "output": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
      "delegate": false,
      "compound": false
  }

Validators

Route: /v1/query/validators

Description: responds with a page of filtered validators

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)
  • perPage: int - the number of elements per page (the default is 10 and max is 5,000)
  • pageNumber: int - the number of the page (the default is 1)
  • unstaking: int - only validators are currently unstaking (optional: 0=Off, 1=MustBe, 2=Exclude)
  • paused: int - only validators are currently paused (optional: 0=Off, 1=MustBe, 2=Exclude)
  • delegate: int only validators are set as delegates (optional: 0=Off, 1=MustBe, 2=Exclude)
  • committee: uint64 - validators are staked for this chain id (optional: 0=Any)

Response:

  • perPage: int - the number of elements per page
  • pageNumber: int - the number of the page
  • results: array - the list of result objects
    • address: uint64 - the 20 byte identifier
    • publicKey: hex string - the unique public identifier of the validator that is used to validate digital signatures
    • stakedAmount: uint64 - the locked balance of funds the address has in micro denomination
    • committees: []uint64 - list of chain ids the validator is staked on behalf
    • netAddress: url - the public peer-to-peer address of the validator
    • maxPausedHeight: uint64 - the height the validator will be automatically begin unstaking if not unpaused (0 is not paused)
    • unstakingHeight: uint64 - the height the validator's locked funds are returned (0 is not unstaking)
    • output: hex string - the 20 byte unique identifier of the account where rewards and locked funds are distributed
    • delegate: bool - is the validator a delegate only
    • compound: bool - is the validator automatically compounding their rewards
  • type: string - the type of results
  • count: int - length of results
  • totalPages: int - number of pages
  • totalCount: int - total number of items that exist in all pages

Example:

text
$ curl -X POST localhost:50002/v1/query/validators \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000
      }'

> {
    "pageNumber": 1,
    "perPage": 10,
    "results": [
      {
        "address": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
        "publicKey": "b2947db37385bb43c46244cef15f2451a446cea011fc1a2e1d52b1cecc7a50a8924e0e062555793bbd55a91a685017ee",
        "committees": [
          1
        ],
        "netAddress": "tcp://localhost",
        "stakedAmount": 2000,
        "maxPausedHeight": 0,
        "unstakingHeight": 0,
        "output": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
        "delegate": false,
        "compound": false
      },
      {
        "address": "551f21e333012027b81701a35023efc88b864975",
        "publicKey": "904d1f2b856eaab5f44c16d1fd2d77b469b2d080f31fdb78354d021c1ff47ebb44af30a2ce5f389f6bc6d07946aa86d421a05c31c72927678b540d76bf112649",
        "committees": [
          1,
          2,
          3
        ],
        "netAddress": "",
        "stakedAmount": 23344689106,
        "maxPausedHeight": 0,
        "unstakingHeight": 0,
        "output": "551f21e333012027b81701a35023efc88b864975",
        "delegate": true,
        "compound": true
      }
    ],
    "type": "validators",
    "count": 2,
    "totalPages": 1,
    "totalCount": 2
  }

Validator-Set

Route: /v1/query/validator-set

Description: responds with the exact list of non-delegate validators for a specific committee id (non-paginated, currently in consensus)

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)
  • id: uint64 – the unique identifier of the committee

Response:

  • validatorSet array - the list of result objects
    • publicKey: hex string - the unique public identifier of the validator that is used to validate digital signatures
    • votingPower: uint64 - the locked balance of funds the address has in micro denomination
    • netAddress: url - the public peer-to-peer address of the validator

Example:

text
$ curl -X POST localhost:50002/v1/query/validator-set \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000,
        "id": 1
      }'

> {
  "validatorSet": [
    {
      "publicKey": "b2947db37385bb43c46244cef15f2451a446cea011fc1a2e1d52b1cecc7a50a8924e0e062555793bbd55a91a685017ee",
      "votingPower": 2000,
      "netAddress": "tcp://localhost"
    }
  ]
}

Committee-Data

Route: /v1/query/committee-data

Description: responds with information about the current status of the Committee

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)
  • id: uint64 – the unique identifier of the committee

Response:

  • chainID: uint64 - the unique identifier of the committee
  • lastRootHeightUpdated: uint64 - the most recent root-chain height the committee reported in their certificate results transaction
  • lastChainHeightUpdated: uint64 - the most recent chain height the committee reported in their certificate results transaction
  • paymentPercents: array - a list of recipients and the percentage of rewards they will receive, distributed at the end of the block
    • address: hex string - the address where the tokens will be received
    • percents: uint64 - the dilutable share of the committee treasury pool
    • chainId: uint64 - the committee pool from which the payment is distributed
  • numberOfSamples: uint64 - the total count of processed Certificate Result Transactions, used to normalize reward percentages accurately

Example:

text
$ curl -X POST localhost:50002/v1/query/committee-data \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000,
        "id": 1
      }'

> {
  "chainID": 1,
  "lastRootHeightUpdated": 998,
  "lastChainHeightUpdated": 998,
  "paymentPercents": [
    {
      "address": "551f21e333012027b81701a35023efc88b864975",
      "percents": 10,
      "chainId": 1
    },
    {
      "address": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
      "percents": 90,
      "chainId": 1
    }
  ],
  "numberOfSamples": 1
}

Committees-Data

Route: /v1/query/committees-data

Description: responds with the master list of subsidized committee data

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)

Response:

  • list: array - a list of result objects
    • chainID: uint64 - the unique identifier of the committee
    • lastRootHeightUpdated: uint64 - the most recent root-chain height the committee reported in their certificate results transaction
    • lastChainHeightUpdated: uint64 - the most recent chain height the committee reported in their certificate results transaction
    • paymentPercents: array - a list of recipients and the percentage of rewards they will receive, distributed at the end of the block
      • address: hex string - the address where the tokens will be received
      • percent: uint64 - the dilutable share of the committee treasury pool
      • chainId: uint64 - the committee pool from which the payment is distributed
    • numberOfSamples: uint64 - the total count of processed Certificate Result Transactions, used to normalize reward percentages accurately

Example:

text
$ curl -X POST localhost:50002/v1/query/committees-data \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000
      }'

> {
  "list": [
    {
      "chainID": 1,
      "lastRootHeightUpdated": 998,
      "lastChainHeightUpdated": 998,
      "paymentPercents": null,
      "numberOfSamples": 0
    }
  ]
}

Subsidized-Committees

Route: /v1/query/subsidized-committees

Description: responds with a list of chainIds that receive a portion of the 'block reward'

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)

Response: uint64 array - a list of subsidized chain ids

Example:

text
$ curl -X POST localhost:50002/v1/query/subsidized-committees \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000
      }'

> [1, 2, 3]

Retired-Committees

Route: /v1/query/retired-committees

Description: responds with a list of the retired chain ids

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)

Response: uint64 array - a list of retired chain ids

Example:

text
$ curl -X POST localhost:50002/v1/query/retired-committees \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000
      }'

> [1, 2, 3]

Non-Signers

Route: /v1/query/non-signers

Description: responds with data on validators who did not sign recent blocks

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)

Response:

  • array - a list of non-signer data
    • address: 20 byte identifier of non-signer
    • counter: increments when a validator doesn't sign a block and resets every non-sign-window

Example:

text
$ curl -X POST localhost:50002/v1/query/non-signers \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000
      }'

> [{
  "address": "551f21e333012027b81701a35023efc88b864975",
  "counter": 1,
}]

Params

Route: /v1/query/params

Description: responds with parameters from all categories in a single object

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)

Response:

  • consensus: object - the governance parameters listed under the consensus params space
    • blockSize: uint64 - the maximum block size in bytes
    • protocolVersion: string - the protocol version and height when the version updated separated by delimiter: / (2/100 is version=2 height=100)
    • rootChainID: uint64 - the committee id of the root chain (may be self chain id)
  • validator: object - the governance parameters listed under the validator params space
    • unstakingBlocks: uint64 - the number of blocks a validator is 'unstaking' before it is unstaked and the bonded funds are returned
    • maxPauseBlocks: uint64 - the number of blocks a non-delegate validator may be consecutively paused for before automatically it begins 'unstaking'
    • doubleSignSlashPercentage: uint64 - the percent of stake that is burned for a validator when a double sign is proved with evidence
    • maxNonSign: uint64 - the number of blocks a validator may not sign within a nonSignWindow before being slashed
    • nonSignWindow: uint64 - the number of blocks the validator non-sign counter is reset
    • maxCommittees: uint64 - the maximum count of committees a validator may be simultaneously staked for
    • maxCommitteeSize: uint64 - the maximum count of validators simulatneously active in BFT for any 1 committee (sorted highest stake to lowest, above the limit is non-active and non-rewarded)
    • earlyWithdrawalPenalty: uint64 - the percent of the reward that is burned when it is directly withdrawn instead of compounded to a validator's stake
    • delegateUnstakingBlocks: uint64 - the number of blocks a delegate validator is 'unstaking' before it is unstaked and the bonded funds are returned
    • minimumOrderSize: uint64 - the minimum sell order amount in micro denomination
    • stakePercentForSubsidizedCommittee: uint64 — minimum percentage of total stake that must be committed to a committee for it to be considered subsidized
    • maxSlashPerCommittee: uint64 - the maximum slash per block a committee may penalize a validator - if exceeded the validator is auto-ejected from the committee and the slash is limited
    • delegateRewardPercentage: uint64 - the percent of the block reward a pseudo-randomly chosen delegate validator, nested-validator, and nested-delegate receives
    • buyDeadlineBlocks: uint64 - the deadline in blocks before a 'locked' sell order is released on the root-chain - (applies only to the 'buyer-side' of token swaps)
    • lockOrderFeeMultiplier: uint64 - the multiplier to a sendFee required to lock a sell order on the root-chain - (applies only to the 'buyer-side' of token swaps)
  • fee: object - the governance parameters listed under the fee params space
    • sendFee: uint64 - the minimum fee in micro denomination needed to execute a send transaction
    • stakeFee: uint64 - the minimum fee in micro denomination needed to execute a stake transaction
    • editStakeFee: uint64 - the minimum fee in micro denomination needed to execute a editStake transaction
    • pauseFee: uint64 - the minimum fee in micro denomination needed to execute a pause transaction
    • unpauseFee: uint64 - the minimum fee in micro denomination needed to execute a unpause transaction
    • changeParameterFee: uint64 - the minimum fee in micro denomination needed to execute a changeParameter transaction
    • daoTransferFee: uint64 - the minimum fee in micro denomination needed to execute a daoTransfer transaction
    • certificateResultsFee: uint64 - the minimum fee in micro denomination needed to execute a certificateResults transaction
    • subsidyFee: uint64 - the minimum fee in micro denomination needed to execute a subsidy transaction
    • createOrderFee: uint64 - the minimum fee in micro denomination needed to execute a createOrder transaction
    • editOrderFee: uint64 - the minimum fee in micro denomination needed to execute a editOrder transaction
    • deleteOrderFee: uint64 - the minimum fee in micro denomination needed to execute a deleteOrder transaction
  • governance: object - the governance parameters listed under the governance params space
    • daoRewardPercentage: uint64 - the percent of the block reward that is awarded to the DAO treasury pool

Example:

text
$ curl -X POST localhost:50002/v1/query/params \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000
      }'

> {
  "consensus": {
    "blockSize": 1000000,
    "protocolVersion": "1/0",
    "rootChainID": 1
  },
  "validator": {
    "unstakingBlocks": 200000,
    "maxPauseBlocks": 4380,
    "doubleSignSlashPercentage": 10,
    "nonSignSlashPercentage": 1,
    "maxNonSign": 3,
    "nonSignWindow": 5,
    "maxCommittees": 15,
    "maxCommitteeSize": 100,
    "earlyWithdrawalPenalty": 20,
    "delegateUnstakingBlocks": 2,
    "minimumOrderSize": 1000000000,
    "stakePercentForSubsidizedCommittee": 33,
    "maxSlashPerCommittee": 15,
    "delegateRewardPercentage": 10,
    "buyDeadlineBlocks": 60,
    "lockOrderFeeMultiplier": 2
  },
  "fee": {
    "sendFee": 10000,
    "stakeFee": 10000,
    "editStakeFee": 10000,
    "unstakeFee": 10000,
    "pauseFee": 10000,
    "unpauseFee": 10000,
    "changeParameterFee": 10000,
    "daoTransferFee": 10000,
    "certificateResultsFee": 0,
    "subsidyFee": 10000,
    "createOrderFee": 10000,
    "editOrderFee": 10000,
    "deleteOrderFee": 10000
  },
  "governance": {
    "daoRewardPercentage": 5
  }
}

Supply

Route: /v1/query/supply

Description: responds with the token supply information for the blockchain

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)

Response:

  • total: uint64 - the total tokens existing in the system (minted tokens are added, burned tokens are removed)
  • staked: uint64 - the total locked tokens in the protocol (includes delegated)
  • delegatedOnly: uint64 - the total locked tokens that are delegated only
  • committeeStaked: array - a list of committees and their committed (staked + delegated) tokens, sorted by stake
    • id: uint64 - the unique identifier of the committee
    • amount: uint64 - the total amount of tokens committed to this committee
    • poolPoints: array - the list of pool share holders and their respective points
    • totalPoolPoints: uint64 - the total number of pool points for this committee
  • committeeDelegatedOnly: array - a list of committees and their delegated only tokens, sorted by stake
    • id: uint64 - the unique identifier of the committee
    • amount: uint64 - the total amount of delegated tokens to this committee
    • poolPoints: array - the list of pool share holders and their respective points
    • totalPoolPoints: uint64 - the total number of pool points for this committee

Example:

text
$ curl -X POST localhost:50002/v1/query/supply \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000
      }'

> {
  "total": 1000000000000,
  "staked": 500000000000,
  "delegatedOnly": 100000000000,
  "committeeStaked": [
    {
      "id": 1,
      "amount": 150000000000,
      "poolPoints": [],
      "totalPoolPoints": 0
    }
  ],
  "committeeDelegatedOnly": [
    {
      "id": 1,
      "amount": 100000000000,
      "poolPoints": [],
      "totalPoolPoints": 0
    }
  ]
}

Fee Params

Route: /v1/query/fee-params

Description: responds with a fee parameters object

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)

Response:

  • sendFee: uint64 - the minimum fee in micro denomination needed to execute a send transaction
  • stakeFee: uint64 - the minimum fee in micro denomination needed to execute a stake transaction
  • editStakeFee: uint64 - the minimum fee in micro denomination needed to execute a editStake transaction
  • pauseFee: uint64 - the minimum fee in micro denomination needed to execute a pause transaction
  • unpauseFee: uint64 - the minimum fee in micro denomination needed to execute a unpause transaction
  • changeParameterFee: uint64 - the minimum fee in micro denomination needed to execute a changeParameter transaction
  • daoTransferFee: uint64 - the minimum fee in micro denomination needed to execute a daoTransfer transaction
  • certificateResultsFee: uint64 - the minimum fee in micro denomination needed to execute a certificateResults transaction
  • subsidyFee: uint64 - the minimum fee in micro denomination needed to execute a subsidy transaction
  • createOrderFee: uint64 - the minimum fee in micro denomination needed to execute a createOrder transaction
  • editOrderFee: uint64 - the minimum fee in micro denomination needed to execute a editOrder transaction
  • deleteOrderFee: uint64 - the minimum fee in micro denomination needed to execute a deleteOrder transaction

Example:

text
$ curl -X POST localhost:50002/v1/query/fee-params \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000
      }'

> {
    "sendFee": 10000,
    "stakeFee": 10000,
    "editStakeFee": 10000,
    "unstakeFee": 10000,
    "pauseFee": 10000,
    "unpauseFee": 10000,
    "changeParameterFee": 10000,
    "daoTransferFee": 10000,
    "certificateResultsFee": 0,
    "subsidyFee": 10000,
    "createOrderFee": 10000,
    "editOrderFee": 10000,
    "deleteOrderFee": 10000
  }

Consensus Params

Route: /v1/query/con-params

Description: responds with a consensus parameters object

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)

Response:

  • blockSize: uint64 - the maximum block size in bytes
  • protocolVersion: string - the protocol version and height when the version updated separated by delimiter: / (2/100 is version=2 height=100)
  • rootChainID: uint64 - the committee id of the root chain (may be self chain id)

Example:

text
$ curl -X POST localhost:50002/v1/query/con-params \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000
      }'

> {
    "blockSize": 1000000,
    "protocolVersion": "1/0",
    "rootChainID": 1
  }

Validator Params

Route: /v1/query/val-params

Description: responds with a validator parameters object

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)

Response:

  • unstakingBlocks: uint64 - the number of blocks a validator is 'unstaking' before it is unstaked and the bonded funds are returned
  • maxPauseBlocks: uint64 - the number of blocks a non-delegate validator may be consecutively paused for before automatically it begins 'unstaking'
  • doubleSignSlashPercentage: uint64 - the percent of stake that is burned for a validator when a double sign is proved with evidence
  • maxNonSign: uint64 - the number of blocks a validator may not sign within a nonSignWindow before being slashed
  • nonSignWindow: uint64 - the number of blocks the validator non-sign counter is reset
  • maxCommittees: uint64 - the maximum count of committees a validator may be simultaneously staked for
  • maxCommitteeSize: uint64 - the maximum count of validators simultaneously active in BFT for any 1 committee (sorted highest stake to lowest, above the limit is non-active and non-rewarded)
  • earlyWithdrawalPenalty: uint64 - the percent of the reward that is burned when it is directly withdrawaled instead of compounded to a validator's stake
  • delegateUnstakingBlocks: uint64 - the number of blocks a delegate validator is 'unstaking' before it is unstaked and the bonded funds are returned
  • minimumOrderSize: uint64 - the minimum sell order amount in micro denomination
  • stakePercentForSubsidizedCommittee: uint64 — minimum percentage of total stake that must be committed to a committee for it to be considered subsidized
  • maxSlashPerCommittee: uint64 - the maximum slash per block a committee may penalize a validator - if exceeded the validator is auto-ejected from the committee and the slash is limited
  • delegateRewardPercentage: uint64 - the percent of the block reward a pseudo-randomly chosen delegate validator, nested-validator, and nested-delegate receives
  • buyDeadlineBlocks: uint64 - the deadline in blocks before a 'locked' sell order is released on the root-chain - (applies only to the 'buyer-side' of token swaps)
  • lockOrderFeeMultiplier: uint64 - the multiplier to a sendFee required to lock a sell order on the root-chain - (applies only to the 'buyer-side' of token swaps)

Example:

text
$ curl -X POST localhost:50002/v1/query/val-params \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000
      }'

> {
    "unstakingBlocks": 200000,
    "maxPauseBlocks": 4380,
    "doubleSignSlashPercentage": 10,
    "nonSignSlashPercentage": 1,
    "maxNonSign": 3,
    "nonSignWindow": 5,
    "maxCommittees": 15,
    "maxCommitteeSize": 100,
    "earlyWithdrawalPenalty": 20,
    "delegateUnstakingBlocks": 2,
    "minimumOrderSize": 1000000000,
    "stakePercentForSubsidizedCommittee": 33,
    "maxSlashPerCommittee": 15,
    "delegateRewardPercentage": 10,
    "buyDeadlineBlocks": 60,
    "lockOrderFeeMultiplier": 2
  }

Governance Params

Route: /v1/query/gov-params

Description: responds with a governance parameters object

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)

Response:

  • daoRewardPercentage: uint64 - the percent of the block reward that is awarded to the DAO treasury pool

Example:

text
$ curl -X POST localhost:50002/v1/query/gov-params \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000
      }'

> {
    "daoRewardPercentage": 5
  }

Economics Params

Route: /v1/query/eco-params

Description: responds with a economic parameters object

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)

Response:

  • mintPerBlock: uint64 - the amount minted per block in micro denominiation
  • mintPerCommittee: uint64 - the amount of mint distributed to each committee reward pool
  • daoCut: uint64 - the amount of mint distributed to the DAO treasury pool
  • proposerCut: uint64 - the percent of the mint in this chain's committee pool that is distributed to the block proposer
  • delegateCut: uint64 - the percent of the mint in this chain's committee pool that is distributed to the delegate, nested proposer (if applicable), and nested delegate (if applicable)

Example:

text
$ curl -X POST localhost:50002/v1/query/eco-params \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000
      }'

> {
  "MintPerBlock": 80000000,
  "MintPerCommittee": 19000000,
  "DAOCut": 4000000,
  "ProposerCut": 70,
  "DelegateCut": 10
}

State

Route: /v1/query/state

Description: responds with the state ledger export in genesis.json format

HTTP Method: GET

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)

Response:

  • pools: array - see Pools response
  • accounts: array - see Accounts response
  • nonSigners: object - see Non-Signers response
  • validators: array - see Validator-Set response
  • params: object - see Params response
  • supply: object - see Supply response
  • orderBooks: array - see order-books response

Example:

text
$ curl -X GET "localhost:50002/v1/query/state?height=1000"

> {
  "pools": [
    ...
  ],
  "accounts": [
    ...
  ],
  "validators": [
    ...
  ],
  "params": {
    ...
  },
  "supply": {
    ...
  },
  "orderBooks": [...]
}

State Diff (Browser View)

Route: /v1/query/state-diff

Description: view the differences in state (ledger) between two heights

HTTP Method: GET

Request:

  • height: uint64 – the block height to act as the end to calculate the state deltas (optional: use 0 to read from the latest block)
  • start-height: uint64 – the start height to act as the 'base' (optional: will auto-use height-1)

Response:

  • state: object - see State but with diff highlights (ex. "amount": 25257333001 <- 25206666335)

Example:
VIEW IN BROWSER: http://localhost:50002/v1/query/state-diff?height=1000&startHeight=998

text
{
  "pools": [
        {
            "amount": 25257333001 <- 25206666335,
            "id": 2
        },
    ...
  ]
  "accounts": [
    ...
  ],
  "validators": [
    ...
  ],
  "params": {
    ...
  },
  "supply": {
    ...
  },
  "orderBooks": [...]
}

State Diff

Route: /v1/query/state-diff

Description: view the differences in state (ledger) between two heights

HTTP Method: POST

Request:

  • height: uint64 – the block height to act as the end to calculate the state deltas (optional: use 0 to read from the latest block)
  • start-height: uint64 – the start height to act as the 'base' (optional: will auto-use height-1)

Response:

  • state: object - see State but with diff highlights (ex. "amount": 18239045002 => 18202565004)
text
$ curl -X POST localhost:50002/v1/query/state-diff \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000,
        "startHeight": 998
      }'

> {
  "pools": [
    ...
  ]
  "accounts": [
      {
          "address": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
          "amount": 18239045002 => 18202565004
      },
  ],
  "validators": [
    ...
  ],
  "params": {
    ...
  },
  "supply": {
    ...
  },
  "orderBooks": [...]
}

Quorum Certificate By Height

Route: /v1/query/cert-by-height

Description: view a quorum certificate for a specific block height

HTTP Method: POST

Request:

  • height: uint64 – the block height to act as the end to calculate the state deltas (optional: use 0 to read from the latest block)

Response:

  • header: object - the view of the certificate
    • height: uint64 - the block height of the certificate
    • committeeHeight: uint64 - the block height of the root-chain that corresponds to the committee that signed this block
    • round: uint64 - the 0-indexed iteration count of BFT that finalized this block
    • phase: string - the phase identifier of the view for this certificate
    • networkID: uint64 - the unique identifier of the network (ex. 1=mainnet, 2=testnet)
    • chainID: uint64 - the unique identifier of the chain this QC corresponds to (ex. 1=Canopy, 2=Canary)
  • block: hex string - the protobuf encoded bytes of the block
  • blockHash: hex string - the SHA256 hash of the block protobuf bytes
  • resultsHash: hex string - the SHA256 hash of the proposal results structure (see below)
  • results: object - the quorum certificate results summary
    • rewardRecipients: object - the recipients who are rewarded based on the quorum certificate, specifically who the committee agreed to reward from the committee treasury
      • paymentPercents: array - the percentage of rewards allocated to each recipient
        • address: hex string - the 20 byte unique identifier of the reward recipient
        • percent: uint64 - the dilutable share of the committee treasury pool
        • chainID: uint64 - the chain_id where the payment is distributed
      • slashRecipients: object - the recipients who are penalized (slashed) based on the quorum certificate specifically who the committee agreed to slash due to evidence of bad behavior
        • doubleSigners: array - a list of actors who the committee agreed double-signed based on evidence
          • id: hex string - the identifier of the malicious validator
          • heights: uint64 array - the list of heights when the infractions occurred
      • orders: object - contains information regarding the 'buying side' of sell orders including actions like 'buy/reserve order' or 'close/complete order'
        • lockOrders: array - a list of actions where a buyer expresses an intent to purchase an order, often referred to as 'claiming' the order
          • orderId: hex string - is the id that is unique to this committee to identify the order
          • chainId: uint64 - is the id of the committee
          • buyerReceiveAddress: hex string - the address where the sold may be received
          • buyerSendAddress: hex string - the 'counter asset' address where the tokens will be sent from
          • buyerChainDeadline: uint64 - the 'counter asset' chain height at which the buyer must send the 'counter asset' by or the 'intent to buy' will be voided
        • resetOrders: uint64 array - a list of orders where no funds were sent before the deadline
        • closeOrders: uint64 array - list of orders where funds were sent, signaling the committee to transfer escrowed tokens to the buyer's receive address
      • checkpoint: object - contains information from the 3rd party chain in order for Canopy to provide Checkpoint-as-a-Service
        • height: uint64 - the height of the third party chain
        • blockHash: hex string - the cryptographic hash of the third party chain block for the height
      • retired: boolean - signals if the committee wants to shut down and mark itself as 'forever unsubsidized' on the root-chain
  • proposerKey: hex string - the public key of the proposer
  • signature: object - the BLS aggregate signature of the committee
    • signature: hex string - the bytes of the BLS signature
    • bitmap: hex string - bitmask of the BLS signature
text
/* Detailed source-code truncated for AI context efficiency. */

Blocks

Route: /v1/query/blocks

Description: view a page of blocks

HTTP Method: POST

Request:

  • perPage: int - the number of elements per page (the default is 10 and max is 5,000)
  • pageNumber: int - the number of the page (the default is 1)

Response:

  • perPage: int - the number of elements per page
  • pageNumber: int - the number of the page
  • results: array - the list of result objects
    • blockHeader: object - the summary of the block
      • height: uint64 - the number of blocks in the blockchain before a specific block, indicating its position in the chain and representing the blockchain's length
      • hash: hex string - a unique identifier for a block, generated by applying a cryptographic hash function to the block's contents, ensuring its integrity and connecting it to the previous block in the chain
      • networkID: uint64 - a unique identifier used to distinguish different canopy blockchain networks, ensuring that transactions and blocks are only processed within the correct network
      • time: unix micro timestamp - specific time recorded in a block when it is created by the proposer, indicating when the block was proposed
      • numTxs: uint64 - the number of transactions in the block
      • totalTxs: uint64 - the total transactions in the blockchain
      • totalVDFIterations: uint64 - the total number of verifiable random delay function iterations in the blockchain
      • lastBlockHash: hex string - the unique identifier of the previous block, chaining this block to the previous
      • stateRoot: hex string - the merkle root of the 'state commit store' representing the entire state of the blockchain at this height
      • transactionRoot: hex string - the merkle root of the 'transactions' included in this block
      • validatorRoot: hex string - the merkle root of the validators that signed the quorum certificate for this height
      • nextValidatorRoot: hex string - the merkle root of the validators who are responsible for proposing and validating the next block
      • proposerAddress: hex string - is the short version of the public key of the Validator who proposed this block
      • vdf: object - the verifiable delay proof for this block. The VDF serves as a protection mechanism against historical forking attacks
        • proof: hex string - a proof of function completion given a specific seed
        • output: hex string - the final output of the calculated 'squarings'
        • iterations: uint64 - number of serial executions (proxy for time)
      • lastQuorumCertificate: object - the quorum certificate from the previous block is included in the block header to ensure all nodes have the same record of blockchain certificates (See cert-by-height response above)
    • transactions: array - list of transactions in the block (see tx-by-hash)
  • type: string - the type of results
  • count: int - length of results
  • totalPages: int - number of pages
  • totalCount: int - total number of items that exist in all pages
text
/* Detailed source-code truncated for AI context efficiency. */

Block By Height

Route: /v1/query/block-by-height

Description: view a block by its height

HTTP Method: POST

Request:

  • height: uint64 – the block height to act as the end to calculate the state deltas (optional: use 0 to read from the latest block)

Response:

  • blockHeader: object - the summary of the block
    • height: uint64 - the number of blocks in the blockchain before a specific block, indicating its position in the chain and representing the blockchain's length
    • hash: hex string - a unique identifier for a block, generated by applying a cryptographic hash function to the block's contents, ensuring its integrity and connecting it to the previous block in the chain
    • networkID: uint64 - a unique identifier used to distinguish different canopy blockchain networks, ensuring that transactions and blocks are only processed within the correct network
    • time: unix micro timestamp - specific time recorded in a block when it is created by the proposer, indicating when the block was proposed
    • numTxs: uint64 - the number of transactions in the block
    • totalTxs: uint64 - the total transactions in the blockchain
    • totalVDFIterations: uint64 - the total number of verifiable random delay function iterations in the blockchain
    • lastBlockHash: hex string - the unique identifier of the previous block, chaining this block to the previous
    • stateRoot: hex string - the merkle root of the 'state commit store' representing the entire state of the blockchain at this height
    • transactionRoot: hex string - the merkle root of the 'transactions' included in this block
    • validatorRoot: hex string - the merkle root of the validators that signed the quorum certificate for this height
    • nextValidatorRoot: hex string - the merkle root of the validators who are responsible for proposing and validating the next block
    • proposerAddress: hex string - is the short version of the public key of the Validator who proposed this block
    • vdf: object - the verifiable delay proof for this block. The VDF serves as a protection mechanism against historical forking attacks
      • proof: hex string - a proof of function completion given a specific seed
      • output: hex string - the final output of the calculated 'squarings'
      • iterations: uint64 - number of serial executions (proxy for time)
    • lastQuorumCertificate: object - the quorum certificate from the previous block is included in the block header to ensure all nodes have the same record of blockchain certificates (See cert-by-height response above)
  • transactions: array - list of transactions in the block (see tx-by-hash)
text
/* Detailed source-code truncated for AI context efficiency. */

Block By Hash

Route: /v1/query/block-by-hash

Description: view a block by its hash

HTTP Method: POST

Request:

  • hash: hex string – the 32 byte unique identifier of the block

Response:

  • blockHeader: object - the summary of the block
    • height: uint64 - the number of blocks in the blockchain before a specific block, indicating its position in the chain and representing the blockchain's length
    • hash: hex string - a unique identifier for a block, generated by applying a cryptographic hash function to the block's contents, ensuring its integrity and connecting it to the previous block in the chain
    • networkID: uint64 - a unique identifier used to distinguish different canopy blockchain networks, ensuring that transactions and blocks are only processed within the correct network
    • time: unix micro timestamp - specific time recorded in a block when it is created by the proposer, indicating when the block was proposed
    • numTxs: uint64 - the number of transactions in the block
    • totalTxs: uint64 - the total transactions in the blockchain
    • totalVDFIterations: uint64 - the total number of verifiable random delay function iterations in the blockchain
    • lastBlockHash: hex string - the unique identifier of the previous block, chaining this block to the previous
    • stateRoot: hex string - the merkle root of the 'state commit store' representing the entire state of the blockchain at this height
    • transactionRoot: hex string - the merkle root of the 'transactions' included in this block
    • validatorRoot: hex string - the merkle root of the validators that signed the quorum certificate for this height
    • nextValidatorRoot: hex string - the merkle root of the validators who are responsible for proposing and validating the next block
    • proposerAddress: hex string - is the short version of the public key of the Validator who proposed this block
    • vdf: object - the verifiable delay proof for this block. The VDF serves as a protection mechanism against historical forking attacks
      • proof: hex string - a proof of function completion given a specific seed
      • output: hex string - the final output of the calculated 'squarings'
      • iterations: uint64 - number of serial executions (proxy for time)
    • lastQuorumCertificate: object - the quorum certificate from the previous block is included in the block header to ensure all nodes have the same record of blockchain certificates (See cert-by-height response above)
  • transactions: array - list of transactions in the block (see tx-by-hash)
text
/* Detailed source-code truncated for AI context efficiency. */

Events By Height

Route: /v1/query/events-by-height

Description: view the events at a specific block height

HTTP Method: POST

Request:

  • height: uint64 – the block height to query events for (optional: use 0 to read from the latest block)
  • perPage: int - the number of elements per page (the default is 10 and max is 5,000)
  • pageNumber: int - the number of the page (the default is 1)

Response:

  • perPage: int - the number of elements per page
  • pageNumber: int - the number of the page
  • results: array - the list of result objects
    • eventType: string - the type of the event: 'reward', 'slash', 'dex-liquidity-deposit', 'dex-liquidity-withdraw', 'dex-swap', 'order-book-swap', 'automatic-pause', 'automatic-begin-unstaking', or 'automatic-finish-unstaking'
    • msg: object - the actual event message payload, which varies by event type:
      • reward: { "amount": uint64 } - amount of reward
      • slash: { "amount": uint64 } - amount of slash
      • dex-liquidity-deposit: { "amount": uint64, "localOrigin": bool, "orderId": hex string, "points": uint64 } - deposit amount, whether it was made on this chain or the counter, unique order identifier, and amount of points created
      • dex-liquidity-withdraw: { "localAmount": uint64, "remoteAmount": uint64, "orderId": hex string, "pointsBurned": uint64 } - amount of liquidity received on local and remote chains, unique order identifier, and amount of points burned
      • dex-swap: { "soldAmount": uint64, "boughtAmount": uint64, "localOrigin": bool, "success": bool, "orderId": hex string } - amounts sold/bought, direction, success status, and unique order identifier
      • order-book-swap: { "soldAmount": uint64, "boughtAmount": uint64, "data": hex string, "sellerReceiveAddress": hex string, "buyerReceiveAddress": hex string, "sellersSendAddress": hex string, "orderId": hex string } - order book swap details including addresses and order information
      • automatic-pause: {} - empty object
      • automatic-begin-unstaking: {} - empty object
      • automatic-finish-unstaking: {} - empty object
    • height: uint64 - the block height at which the event occurred
    • reference: string - the reference for the event: 'begin_block', transaction hash, or 'end_block'
    • chainId: uint64 - the chain id associated with the event
    • address: hex string - the address the event is indexed for
  • type: string - the type of results
  • count: int - length of results
  • totalPages: int - number of pages
  • totalCount: int - total number of items that exist in all pages
text
$ curl -X POST localhost:50002/v1/query/events-by-height \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000
      }'

> {
  "pageNumber": 1,
  "perPage": 10,
  "results": [
    {
      "eventType": "reward",
      "msg": {
        "amount": 10000
      },
      "height": 1000,
      "reference": "end_block",
      "chainId": 1,
      "address": "551f21e333012027b81701a35023efc88b864975"
    },
    {
      "eventType": "dex-swap",
      "msg": {
        "soldAmount": 1000000,
        "boughtAmount": 950000,
        "localOrigin": true,
        "success": true,
        "orderId": "ff22f214f5f300d315a5"
      },
      "height": 1000,
      "reference": "ff22f214f5f300d315a56581ccb0f10fe1665f90c8f09666f7c58abcabfbcedb",
      "chainId": 1,
      "address": "551f21e333012027b81701a35023efc88b864975"
    },
    {
      "eventType": "order-book-swap",
      "msg": {
        "soldAmount": 500000,
        "boughtAmount": 475000,
        "data": "",
        "sellerReceiveAddress": "551f21e333012027b81701a35023efc88b864975",
        "sellerReceiveAddress": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
        "sellersSendAddress": "551f21e333012027b81701a35023efc88b864975",
        "orderId": "a1b2c3d4e5f6"
      },
      "height": 1000,
      "reference": "a1b2c3d4e5f67890123456789abcdef0123456789abcdef0123456789abcdef0",
      "chainId": 1,
      "address": "551f21e333012027b81701a35023efc88b864975"
    }
  ],
  "type": "event-results-page",
  "count": 3,
  "totalPages": 1,
  "totalCount": 3
}

Events By Address

Route: /v1/query/events-by-address

Description: view the events for a specific address

HTTP Method: POST

Request:

  • address: hex string – the address to query events for
  • perPage: int - the number of elements per page (the default is 10 and max is 5,000)
  • pageNumber: int - the number of the page (the default is 1)

Response:

  • perPage: int - the number of elements per page
  • pageNumber: int - the number of the page
  • results: array - the list of result objects
    • eventType: string - the type of the event: 'reward', 'slash', 'dex-liquidity-deposit', 'dex-liquidity-withdraw', 'dex-swap', 'order-book-swap', 'automatic-pause', 'automatic-begin-unstaking', or 'automatic-finish-unstaking'
    • msg: object - the actual event message payload, which varies by event type:
      • reward: { "amount": uint64 } - amount of reward
      • slash: { "amount": uint64 } - amount of slash
      • dex-liquidity-deposit: { "amount": uint64, "localOrigin": bool, "orderId": hex string, "points": uint64 } - deposit amount, whether it was made on this chain or the counter, unique order identifier, and amount of points created
      • dex-liquidity-withdraw: { "localAmount": uint64, "remoteAmount": uint64, "orderId": hex string, "pointsBurned": uint64 } - amount of liquidity received on local and remote chains, unique order identifier, and amount of points burned
      • dex-swap: { "soldAmount": uint64, "boughtAmount": uint64, "localOrigin": bool, "success": bool, "orderId": hex string } - amounts sold/bought, direction, success status, and unique order identifier
      • order-book-swap: { "soldAmount": uint64, "boughtAmount": uint64, "data": hex string, "sellerReceiveAddress": hex string, "buyerReceiveAddress": hex string, "sellersSendAddress": hex string, "orderId": hex string } - order book swap details including addresses and order information
      • automatic-pause: {} - empty object
      • automatic-begin-unstaking: {} - empty object
      • automatic-finish-unstaking: {} - empty object
    • height: uint64 - the block height at which the event occurred
    • reference: string - the reference for the event: 'begin_block', transaction hash, or 'end_block'
    • chainId: uint64 - the chain id associated with the event
    • address: hex string - the address the event is indexed for
  • type: string - the type of results
  • count: int - length of results
  • totalPages: int - number of pages
  • totalCount: int - total number of items that exist in all pages
text
$ curl -X POST localhost:50002/v1/query/events-by-address \
  -H "Content-Type: application/json" \
  -d '{
        "address": "551f21e333012027b81701a35023efc88b864975"
      }'

> {
  "pageNumber": 1,
  "perPage": 10,
  "results": [
    {
      "eventType": "reward",
      "msg": {
        "amount": 10000
      },
      "height": 1000,
      "reference": "end_block",
      "chainId": 1,
      "address": "551f21e333012027b81701a35023efc88b864975"
    },
    {
      "eventType": "dex-swap",
      "msg": {
        "soldAmount": 1000000,
        "boughtAmount": 950000,
        "localOrigin": true,
        "success": true,
        "orderId": "ff22f214f5f300d315a5"
      },
      "height": 1000,
      "reference": "ff22f214f5f300d315a56581ccb0f10fe1665f90c8f09666f7c58abcabfbcedb",
      "chainId": 1,
      "address": "551f21e333012027b81701a35023efc88b864975"
    },
    {
      "eventType": "order-book-swap",
      "msg": {
        "soldAmount": 500000,
        "boughtAmount": 475000,
        "data": "0x",
        "sellerReceiveAddress": "551f21e333012027b81701a35023efc88b864975",
        "sellerReceiveAddress": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
        "sellersSendAddress": "551f21e333012027b81701a35023efc88b864975",
        "orderId": "a1b2c3d4e5f6"
      },
      "height": 1000,
      "reference": "a1b2c3d4e5f67890123456789abcdef0123456789abcdef0123456789abcdef0",
      "chainId": 1,
      "address": "551f21e333012027b81701a35023efc88b864975"
    }
  ],
  "type": "event-results-page",
  "count": 3,
  "totalPages": 1,
  "totalCount": 3
}

Events By Chain

Route: /v1/query/events-by-chain

Description: view the events for a specific chain id

HTTP Method: POST

Request:

  • chainId: uint64 – the chain id to query events for
  • perPage: int - the number of elements per page (the default is 10 and max is 5,000)
  • pageNumber: int - the number of the page (the default is 1)

Response:

  • perPage: int - the number of elements per page
  • pageNumber: int - the number of the page
  • results: array - the list of result objects
    • eventType: string - the type of the event: 'reward', 'slash', 'dex-liquidity-deposit', 'dex-liquidity-withdraw', 'dex-swap', 'order-book-swap', 'automatic-pause', 'automatic-begin-unstaking', or 'automatic-finish-unstaking'
    • msg: object - the actual event message payload, which varies by event type:
      • reward: { "amount": uint64 } - amount of reward
      • slash: { "amount": uint64 } - amount of slash
      • dex-liquidity-deposit: { "amount": uint64, "localOrigin": bool, "orderId": hex string, "points": uint64 } - deposit amount, whether it was made on this chain or the counter, unique order identifier, and amount of points created
      • dex-liquidity-withdraw: { "localAmount": uint64, "remoteAmount": uint64, "orderId": hex string, "pointsBurned": uint64 } - amount of liquidity received on local and remote chains, unique order identifier, and amount of points burned
      • dex-swap: { "soldAmount": uint64, "boughtAmount": uint64, "localOrigin": bool, "success": bool, "orderId": hex string } - amounts sold/bought, direction, success status, and unique order identifier
      • order-book-swap: { "soldAmount": uint64, "boughtAmount": uint64, "data": hex string, "sellerReceiveAddress": hex string, "buyerReceiveAddress": hex string, "sellersSendAddress": hex string, "orderId": hex string } - order book swap details including addresses and order information
      • automatic-pause: {} - empty object
      • automatic-begin-unstaking: {} - empty object
      • automatic-finish-unstaking: {} - empty object
    • height: uint64 - the block height at which the event occurred
    • reference: string - the reference for the event: 'begin_block', transaction hash, or 'end_block'
    • chainId: uint64 - the chain id associated with the event
    • address: hex string - the address the event is indexed for
  • type: string - the type of results
  • count: int - length of results
  • totalPages: int - number of pages
  • totalCount: int - total number of items that exist in all pages
text
$ curl -X POST localhost:50002/v1/query/events-by-chain \
  -H "Content-Type: application/json" \
  -d '{
        "chainId": 1
      }'

> {
  "pageNumber": 1,
  "perPage": 10,
  "results": [
    {
      "eventType": "reward",
      "msg": {
        "amount": 10000
      },
      "height": 1000,
      "reference": "end_block",
      "chainId": 1,
      "address": "551f21e333012027b81701a35023efc88b864975"
    },
    {
      "eventType": "dex-swap",
      "msg": {
        "soldAmount": 1000000,
        "boughtAmount": 950000,
        "localOrigin": true,
        "success": true,
        "orderId": "ff22f214f5f300d315a5"
      },
      "height": 1000,
      "reference": "ff22f214f5f300d315a56581ccb0f10fe1665f90c8f09666f7c58abcabfbcedb",
      "chainId": 1,
      "address": "551f21e333012027b81701a35023efc88b864975"
    },
    {
      "eventType": "order-book-swap",
      "msg": {
        "soldAmount": 500000,
        "boughtAmount": 475000,
        "data": "",
        "sellerReceiveAddress": "551f21e333012027b81701a35023efc88b864975",
        "sellerReceiveAddress": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
        "sellersSendAddress": "551f21e333012027b81701a35023efc88b864975",
        "orderId": "a1b2c3d4e5f6"
      },
      "height": 1000,
      "reference": "a1b2c3d4e5f67890123456789abcdef0123456789abcdef0123456789abcdef0",
      "chainId": 1,
      "address": "551f21e333012027b81701a35023efc88b864975"
    }
  ],
  "type": "event-results-page",
  "count": 3,
  "totalPages": 1,
  "totalCount": 3
}

Transactions By Height

Route: /v1/query/txs-by-height

Description: view the transactions included in a block at a specific height

HTTP Method: POST

Request:

  • height: uint64 – the block height to act as the end to calculate the state deltas (optional: use 0 to read from the latest block)
  • perPage: int - the number of elements per page (the default is 10 and max is 5,000)
  • pageNumber: int - the number of the page (the default is 1)

Response:

  • perPage: int - the number of elements per page
  • pageNumber: int - the number of the page
  • results: array - the list of result objects
    • blockHeader: object - the summary of the block
    • transactions: array - list of transactions in the block
      • sender: hex-string - the address of the user sending the transaction
      • recipient: hex-string - the address of the user receiving the transaction
      • messageType: string - the name of the of the message like 'send' or 'stake'
      • height: uint64 - the block height at which the transaction was included
      • index: uint64 - the position of the transaction within the block
      • transaction: object - original transaction object
        • messageType: string - type of the transaction like 'send' or 'stake'
        • msg: object - the actual transaction message payload, which is encapsulated in a generic message format. (See tx-by-hash)
        • signature: object - the cryptographic signature used to verify the authenticity of the transaction
        • createdHeight: uint64 - the height when the transaction was created - allows 'safe pruning'
        • time: unix micro timestamp - timestamp when the transaction was created - used as temporal entropy to prevent hash collisions in txs
        • fee: uint64 - fee associated with processing the transaction in micro denomination
        • memo: string - an optional message or note attached to the transaction
        • networkId: uint64 - the identity of the network the transaction is intended for
        • chainId: uint64 - the identity of the committee the transaction is intended for
      • txHash: hex-string - the unique hash that identifies the transaction
  • type: string - the type of results
  • count: int - length of results
  • totalPages: int - number of pages
  • totalCount: int - total number of items that exist in all pages
text
$ curl -X POST localhost:50002/v1/query/txs-by-height \
  -H "Content-Type: application/json" \
  -d '{
        "height": 17585
      }'

>{
  "pageNumber": 1,
  "perPage": 10,
  "results": [
    {
      "sender": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
      "recipient": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
      "messageType": "send",
      "height": 17585,
      "transaction": {
        "type": "send",
        "msg": {
          "fromAddress": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
          "toAddress": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
          "amount": 100000
        },
        "signature": {
          "publicKey": "b2947db37385bb43c46244cef15f2451a446cea011fc1a2e1d52b1cecc7a50a8924e0e062555793bbd55a91a685017ee",
          "signature": "8a427223eae305e0816d66c7940320f7fa17b3a084c1a27130fd4cd0e6fe68eae2edecf1ec197cac1ac049899cdf9e0e10ae7855b2b2aacd213950eb4856dd10b6bc0b77eb34bc3e49e82cabb21aaf85f588876b0568f1b4981961c3e9c525a9"
        },
        "time": 1749070106734452,
        "createdHeight": 17584,
        "fee": 10000,
        "networkID": 1,
        "chainID": 1
      },
      "txHash": "ff22f214f5f300d315a56581ccb0f10fe1665f90c8f09666f7c58abcabfbcedb"
    }
  ],
  "type": "tx-results-page",
  "count": 1,
  "totalPages": 1,
  "totalCount": 1
}

Transactions By Sender

Route: /v1/query/txs-by-sender

Description: view the transactions sent by an address

HTTP Method: POST

Request:

  • address: hex-string – the address of the user sending the transaction
  • perPage: int - the number of elements per page (the default is 10 and max is 5,000)
  • pageNumber: int - the number of the page (the default is 1)

Response:

  • perPage: int - the number of elements per page
  • pageNumber: int - the number of the page
  • results: array - the list of result objects
    • blockHeader: object - the summary of the block
    • transactions: array - list of transactions in the block
      • sender: hex-string - the address of the user sending the transaction
      • recipient: hex-string - the address of the user receiving the transaction
      • messageType: string - the name of the of the message like 'send' or 'stake'
      • height: uint64 - the block height at which the transaction was included
      • index: uint64 - the position of the transaction within the block
      • transaction: object - original transaction object
        • messageType: string - type of the transaction like 'send' or 'stake'
        • msg: object - the actual transaction message payload, which is encapsulated in a generic message format. (See tx-by-hash)
        • signature: object - the cryptographic signature used to verify the authenticity of the transaction
        • createdHeight: uint64 - the height when the transaction was created - allows 'safe pruning'
        • time: unix micro timestamp - timestamp when the transaction was created - used as temporal entropy to prevent hash collisions in txs
        • fee: uint64 - fee associated with processing the transaction in micro denomination
        • memo: string - an optional message or note attached to the transaction
        • networkId: uint64 - the identity of the network the transaction is intended for
        • chainId: uint64 - the identity of the committee the transaction is intended for
      • txHash: hex-string - the unique hash that identifies the transaction
  • type: string - the type of results
  • count: int - length of results
  • totalPages: int - number of pages
  • totalCount: int - total number of items that exist in all pages
text
$ curl -X POST localhost:50002/v1/query/txs-by-sender \
  -H "Content-Type: application/json" \
  -d '{
        "address": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711"
      }'

>{
  "pageNumber": 1,
  "perPage": 10,
  "results": [
    {
      "sender": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
      "recipient": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
      "messageType": "send",
      "height": 17585,
      "transaction": {
        "type": "send",
        "msg": {
          "fromAddress": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
          "toAddress": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
          "amount": 100000
        },
        "signature": {
          "publicKey": "b2947db37385bb43c46244cef15f2451a446cea011fc1a2e1d52b1cecc7a50a8924e0e062555793bbd55a91a685017ee",
          "signature": "8a427223eae305e0816d66c7940320f7fa17b3a084c1a27130fd4cd0e6fe68eae2edecf1ec197cac1ac049899cdf9e0e10ae7855b2b2aacd213950eb4856dd10b6bc0b77eb34bc3e49e82cabb21aaf85f588876b0568f1b4981961c3e9c525a9"
        },
        "time": 1749070106734452,
        "createdHeight": 17584,
        "fee": 10000,
        "networkID": 1,
        "chainID": 1
      },
      "txHash": "ff22f214f5f300d315a56581ccb0f10fe1665f90c8f09666f7c58abcabfbcedb"
    }
  ],
  "type": "tx-results-page",
  "count": 1,
  "totalPages": 1,
  "totalCount": 1
}

Transactions By Recipient

Route: /v1/query/txs-by-rec

Description: view the transactions received by an address

HTTP Method: POST

Request:

  • address: hex-string – the address of the user sending the transaction
  • perPage: int - the number of elements per page (the default is 10 and max is 5,000)
  • pageNumber: int - the number of the page (the default is 1)

Response:

  • perPage: int - the number of elements per page
  • pageNumber: int - the number of the page
  • results: array - the list of result objects
    • blockHeader: object - the summary of the block
    • transactions: array - list of transactions in the block
      • sender: hex-string - the address of the user sending the transaction
      • recipient: hex-string - the address of the user receiving the transaction
      • messageType: string - the name of the of the message like 'send' or 'stake'
      • height: uint64 - the block height at which the transaction was included
      • index: uint64 - the position of the transaction within the block
      • transaction: object - original transaction object
        • messageType: string - type of the transaction like 'send' or 'stake'
        • msg: object - the actual transaction message payload, which is encapsulated in a generic message format. (See tx-by-hash)
        • signature: object - the cryptographic signature used to verify the authenticity of the transaction
        • createdHeight: uint64 - the height when the transaction was created - allows 'safe pruning'
        • time: unix micro timestamp - timestamp when the transaction was created - used as temporal entropy to prevent hash collisions in txs
        • fee: uint64 - fee associated with processing the transaction in micro denomination
        • memo: string - an optional message or note attached to the transaction
        • networkId: uint64 - the identity of the network the transaction is intended for
        • chainId: uint64 - the identity of the committee the transaction is intended for
      • txHash: hex-string - the unique hash that identifies the transaction
  • type: string - the type of results
  • count: int - length of results
  • totalPages: int - number of pages
  • totalCount: int - total number of items that exist in all pages
text
$ curl -X POST localhost:50002/v1/query/txs-by-rec \
  -H "Content-Type: application/json" \
  -d '{
        "address": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711"
      }'

>{
  "pageNumber": 1,
  "perPage": 10,
  "results": [
    {
      "sender": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
      "recipient": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
      "messageType": "send",
      "height": 17585,
      "transaction": {
        "type": "send",
        "msg": {
          "fromAddress": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
          "toAddress": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
          "amount": 100000
        },
        "signature": {
          "publicKey": "b2947db37385bb43c46244cef15f2451a446cea011fc1a2e1d52b1cecc7a50a8924e0e062555793bbd55a91a685017ee",
          "signature": "8a427223eae305e0816d66c7940320f7fa17b3a084c1a27130fd4cd0e6fe68eae2edecf1ec197cac1ac049899cdf9e0e10ae7855b2b2aacd213950eb4856dd10b6bc0b77eb34bc3e49e82cabb21aaf85f588876b0568f1b4981961c3e9c525a9"
        },
        "time": 1749070106734452,
        "createdHeight": 17584,
        "fee": 10000,
        "networkID": 1,
        "chainID": 1
      },
      "txHash": "ff22f214f5f300d315a56581ccb0f10fe1665f90c8f09666f7c58abcabfbcedb"
    }
  ],
  "type": "tx-results-page",
  "count": 1,
  "totalPages": 1,
  "totalCount": 1
}

Transaction By Hash

Route: /v1/query/tx-by-hash

Description: view a transaction by its hash

HTTP Method: POST

Request:

  • hash: hex-string – the 32 byte unique id of the transaction

Response:

  • sender: hex-string - the address of the user sending the transaction
  • recipient: hex-string - the address of the user receiving the transaction
  • messageType: string - the name of the of the message like 'send' or 'stake'
  • committed: bool - true when the transaction has been included in a block or false when it is still in the mempool
  • height: uint64 - the committed block height, or the candidate block height when committed is false
  • index: uint64 - the committed transaction position, or the candidate position when committed is false
  • transaction: object - original transaction object
    • messageType: string - type of the transaction like 'send' or 'stake'
    • msg: object - the actual transaction message payload, which is encapsulated in a generic message format.
      Oneof:
      • messageSend:
        • fromAddress: hex string - the sender of the funds
        • toAddress: hex string - the recipient of the funds
        • amount: uint64 - the amount of tokens in micro-denomination (uCNPY)
      • messageStake:
        • publicKey: hex string - the public cryptographic identity of the Validator operator
        • amount: uint64 - the amount of tokens to be locked as a surety bond
        • committees: repeated uint64 - the list of committees the validator is staking towards
        • netAddress: string - the tcp peer-to-peer address of the peer
        • outputAddress: hex string - the reward/unstaking address
        • delegate: bool - indicates if the validator is a delegate
        • compound: bool - indicates if the validator is auto-compounding
        • signer: hex string - the authorized signer of the transaction
      • messageEditStake:
        • address: hex string - the identifier linked to the Validator structure
        • amount: uint64 - updated amount of tokens being staked
        • committees: repeated uint64 - updated list of committees
        • netAddress: string - updated tcp peer-to-peer address
        • outputAddress: hex string - updated reward address
        • compound: bool - updated auto-compounding status
        • signer: hex string - identifies the signer authorized to edit output
      • messageUnstake:
        • address: hex string - the identifier linked to the Validator structure
      • messagePause:
        • address: hex string - the identifier linked to the Validator structure
      • messageUnpause:
        • address: hex string - the identifier linked to the Validator structure
      • messageChangeParameter:
        • parameterSpace: string - the path where the parameter is located (val, cons, fee, gov)
        • parameterKey: string - the name of the parameter
        • parameterValue: Any - the value of the parameter (uint64 or string)
        • startHeight: uint64 - start block height for proposal validity
        • endHeight: uint64 - end block height for proposal validity
        • signer: hex string - the sender/creator of the proposal
        • proposalHash: string - internal hash to track the proposal
      • messageDAOTransfer:
        • address: hex string - recipient address and sender of the message
        • amount: uint64 - amount of tokens
        • startHeight: uint64 - start block height for vote window
        • endHeight: uint64 - end block height for vote window
        • proposalHash: string - internal hash to track the proposal
      • messageSubsidy:
        • address: hex string - sender of the funds
        • chainID: uint64 - id of the committee receiving the funds
        • amount: uint64 - amount of tokens transferred to recipient pool
        • opcode: hex string - code designating fund instructions
      • messageCertificateResult:
        • qc: object - see cert-by-height
      • messageCreateOrder:
        • chainID: uint64 - id of the committee handling the counter asset
        • data: hex string - generic data for swap logic
        • amountForSale: uint64 - uCNPY listed for sale and moved to escrow
        • requestedAmount: uint64 - counter asset required for swap completion
        • sellerReceiveAddress: hex string - address to receive counter asset
        • sellersSendAddress: hex string - Canopy address from which seller signs
        • orderId: hex string - unique identifier auto-populated by state machine
      • messageEditOrder:
        • orderID: hex string - unique identifier for the order
        • chainID: uint64 - committee responsible for the counter asset
        • data: hex string - updated swap logic data
        • amountForSale: uint64 - updated uCNPY for sale
        • requestedAmount: uint64 - updated counter asset amount
        • sellerReceiveAddress: hex string - updated recipient address for counter asset
      • messageDeleteOrder:
        • orderID: hex string - identifier of the order to delete
        • chainID: uint64 - committee responsible for the order
    • signature: object - the cryptographic signature used to verify the authenticity of the transaction
    • createdHeight: uint64 - the height when the transaction was created - allows 'safe pruning'
    • time: unix micro timestamp - timestamp when the transaction was created - used as temporal entropy to prevent hash collisions in txs
    • fee: uint64 - fee associated with processing the transaction in micro denomination
    • memo: string - an optional message or note attached to the transaction
    • networkId: uint64 - the identity of the network the transaction is intended for
    • chainId: uint64 - the identity of the committee the transaction is intended for
  • txHash: hex-string - the unique hash that identifies the transaction
text
$ curl -X POST localhost:50002/v1/query/tx-by-hash \
  -H "Content-Type: application/json" \
  -d '{
        "hash": "ff22f214f5f300d315a56581ccb0f10fe1665f90c8f09666f7c58abcabfbcedb"
      }'

>{
  "sender": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
  "recipient": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
  "messageType": "send",
  "committed": true,
  "height": 17585,
  "transaction": {
    "type": "send",
    "msg": {
      "fromAddress": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
      "toAddress": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
      "amount": 100000
    },
    "signature": {
      "publicKey": "b2947db37385bb43c46244cef15f2451a446cea011fc1a2e1d52b1cecc7a50a8924e0e062555793bbd55a91a685017ee",
      "signature": "8a427223eae305e0816d66c7940320f7fa17b3a084c1a27130fd4cd0e6fe68eae2edecf1ec197cac1ac049899cdf9e0e10ae7855b2b2aacd213950eb4856dd10b6bc0b77eb34bc3e49e82cabb21aaf85f588876b0568f1b4981961c3e9c525a9"
    },
    "time": 1749070106734452,
    "createdHeight": 17584,
    "fee": 10000,
    "networkID": 1,
    "chainID": 1
  },
  "txHash": "ff22f214f5f300d315a56581ccb0f10fe1665f90c8f09666f7c58abcabfbcedb"
}

Order

Route: /v1/query/order

Description: view a sell order by its unique identifier

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)
  • committee: uint64 – the unique identifier of the committee
  • orderId: hex-string – the unique identifier of the order

Response:

  • id: hex-string - the unique identifier of the order
  • committee: uint64 - the id of the committee that is in-charge of escrow for the swap
  • data: hex-string - a generic data field which can allow a committee to execute specific functionality for the swap
  • amountForSale: uint64 - amount of 'root-chain-asset' for sale in smallest unit
  • requestedAmount: uint64 - amount of 'counter-asset' the seller of the 'root-chain-asset' receives
  • sellerReceiveAddress: hex-string - the external chain address to receive the 'counter-asset' in smallest unit
  • buyerSendAddress: hex-string - if reserved (locked): the address the buyer will be transferring the funds from
  • buyerChainDeadline: hex-string - the external chain height deadline to send the 'tokens' to SellerReceiveAddress
  • sellersSendAddress: hex-string - the signing address of seller who is selling the CNPY
text
$ curl -X POST localhost:50002/v1/query/order \
  -H "Content-Type: application/json" \
  -d '{
        "committee": 1,
        "orderId": "abb1f314f5f300d315a56581ccb0f10fe1665f90c8f09666f7c58abcabfbcedb",
        "height": 1000
      }'

>{
  "id": "abb1f314f5f300d315a56581ccb0f10fe1665f90c8f09666f7c58abcabfbcedb",
  "committee": "1",
  "data": "",
  "amountForSale": 1000000000000,
  "requestedAmount": 2000000000000,
  "sellersReceiveAddress": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
  "buyerSendAddress": "aaac0b3d64c12c6f164545545b2ba2ab4d80deff",
  "buyerChainDeadline": 17585,
  "sellersSendAddress": "bb43c46244cef15f2451a446cea011fc1a2eddfe"
}

Orders

Route: /v1/query/orders

Description: view all sell orders for a counter-asset pair with optional filters and pagination

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)
  • committee: uint64 – the unique identifier of the committee to filter by (optional: use 0 to get all committees)
  • pageNumber: int – the page number to retrieve (optional: starts at 1)
  • perPage: int – the number of orders per page (optional: defaults to system default)

Response:

  • pageNumber: int - the current page number
  • perPage: int - the number of items per page
  • results: sell order array - the paginated list of sell orders
    • id: hex string - the 20 byte identifier of the order
    • committee: uint64 - the id of the committee that is in-charge of escrow for the swap
    • data: hex-string - a generic data field which can allow a committee to execute specific functionality for the swap
    • amountForSale: uint64 - amount of 'root-chain-asset' for sale
    • requestedAmount: uint64 - amount of 'counter-asset' the seller of the 'root-chain-asset' receives
    • sellerReceiveAddress: hex-string - the external chain address to receive the 'counter-asset'
    • buyerSendAddress: hex-string - if reserved (locked): the address the buyer will be transferring the funds from
    • buyerChainDeadline: hex-string - the external chain height deadline to send the 'tokens' to SellerReceiveAddress
    • sellersSendAddress: hex-string - the signing address of seller who is selling the CNPY
  • type: string - the type of paginated results ("orders")
  • count: int - the number of items in this page
  • totalPages: int - the total number of pages available
  • totalCount: int - the total number of orders matching the filters

Example 1: Basic pagination

text
$ curl -X POST localhost:50002/v1/query/orders \
  -H "Content-Type: application/json" \
  -d '{
        "pageNumber": 1,
        "perPage": 10
      }'

> {
    "pageNumber": 1,
    "perPage": 10,
    "results": [
        {
            "id": "abb1f314f5f300d315a56581ccb0f10fe1665f90c8f09666f7c58abcabfbcedb",
            "committee": 1,
            "amountForSale": 1000000000000,
            "requestedAmount": 2000000000000,
            "sellerReceiveAddress": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
            "sellersSendAddress": "bb43c46244cef15f2451a446cea011fc1a2eddfe"
        },
        {
            "id": "ccd2f425f6f411e426b67692ddc1f21gf2776ga1d9g1a777g8d69bcdbacddfec",
            "committee": 1,
            "amountForSale": 500000000000,
            "requestedAmount": 1000000000000,
            "sellerReceiveAddress": "613d1c4e7dde2d7g275bb6647c3cb3dc0f91d822",
            "buyerSendAddress": "aaac0b3d64c12c6f164545545b2ba2ab4d80deff",
            "buyerChainDeadline": 17585,
            "sellersSendAddress": "cc54d57355dfg26g3562b557dfb122gd2b3feegh"
        }
    ],
    "type": "orders",
    "count": 2,
    "totalPages": 1,
    "totalCount": 2
}

Example 2: Filter by committee with pagination

text
$ curl -X POST localhost:50002/v1/query/orders \
  -H "Content-Type: application/json" \
  -d '{
        "committee": 1,
        "pageNumber": 1,
        "perPage": 20
      }'

Dex Batch

Route: /v1/query/dex-batch
Description: view the locked dex batch for a committee or all dex batches
HTTP Method: POST
Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)
  • id: uint64 – the unique identifier of the committee (optional: use 0 to get all committees)
  • points: bool - return all point holders for the liquidity pool and total points
    Response:
  • committee: uint64 - the id of the 'counter asset'
  • receiptHash: hex-string - the hash of the counter batch this locked batch corresponds to
  • orders: dex limit order array - the list of dex limit orders
    • amountForSale: uint64 - amount of asset for sale
    • requestedAmount: uint64 - the minimum requested amount of 'counter-asset' to receive
    • address: hex string - the address where the funds are transferred from and to
    • orderId: hex string - unique identifier for the order (20 bytes, derived from transaction hash)
  • deposits: dex deposit array - the list of dex limit orders
    • amount: uint64 - amount of asset being deposited
    • address: hex string - the address where the funds are transferred from
    • orderId: hex string - unique identifier for the deposit (20 bytes, derived from transaction hash)
  • withdraws: dex withdraw array - the list of dex limit orders
    • percent: uint64 - the percent of liquidity being withdrawn
    • address: hex string - the address where the funds are transferred from
    • orderId: hex string - unique identifier for the withdrawal (20 bytes, derived from transaction hash)
  • poolPoints: array - a list of pool points
    • address: hex-string - the recipient address of the points
    • points: uint64 the amount of points owned
  • totalPoolPoints: uint64 - the sum of all pool points
  • poolSize: uint64 - contains the current balance of the liquidity pool
  • counterPoolSize: uint64 - the last computed 'counter pool' size of the liquidity pool on the counter chain
  • receipts: uint64 array - the amount distributed (dY) for each order
text
$ curl -X POST localhost:50002/v1/query/dex-batch \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000,
        "id": 1
      }'
> {
    "committee": 1,
    "receiptHash": "b5d54c39e66671c9731b9f471e585d8262cd4f54963f0c93082d8dcf334d4c78",
    "orders": [
        {
            "amountForSale": 1000000000000,
            "requestedAmount": 2000000000000,
            "address": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
            "orderId": "a1b2c3d4e5f67890abcd"
        }
    ],
    "deposits": [
        {
            "amount": 1000000000000,
            "address": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
            "orderId": "1234567890abcdef1234"
        }
    ],
    "withdraws": [
        {
            "amount": 100,
            "address": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
            "orderId": "fedcba0987654321fedc"
        }
    ],
    "poolPoints": [
      {
        "address": "551f21e333012027b81701a35023efc88b864975",
        "points": 100
      }
    ],
    "totalPoolPoints": 100,
    "poolSize": 5000000000000,
    "counterPoolSize": 3000000000000,
    "receipts": [1000000, 0, 950000]
}

Next Dex Batch

Route: /v1/query/next-dex-batch
Description: view the up-next dex batch for a committee or all upcoming dex batches
HTTP Method: POST
Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)
  • id: uint64 – the unique identifier of the committee (optional: use 0 to get all committees)
    Response:
  • committee: uint64 - the id of the 'counter asset'
  • receiptHash: hex-string - the hash of the counter batch this locked batch corresponds to
  • orders: dex limit order array - the list of dex limit orders
    • amountForSale: uint64 - amount of asset for sale
    • requestedAmount: uint64 - the minimum requested amount of 'counter-asset' to receive
    • address: hex string - the address where the funds are transferred from and to
    • orderId: hex string - unique identifier for the order (20 bytes, derived from transaction hash)
  • deposits: dex deposit array - the list of dex limit orders
    • amount: uint64 - amount of asset being deposited
    • address: hex string - the address where the funds are transferred from
    • orderId: hex string - unique identifier for the deposit (20 bytes, derived from transaction hash)
  • withdraws: dex withdraw array - the list of dex limit orders
    • percent: uint64 - the percent of liquidity being withdrawn
    • address: hex string - the address where the funds are transferred from
    • orderId: hex string - unique identifier for the withdrawal (20 bytes, derived from transaction hash)
  • poolPoints: array - a list of pool points
    • address: hex-string - the recipient address of the points
    • points: uint64 the amount of points owned
  • totalPoolPoints: uint64 - the sum of all pool points
  • poolSize: uint64 - contains the current balance of the liquidity pool
  • counterPoolSize: uint64 - the last computed 'counter pool' size of the liquidity pool on the counter chain
  • receipts: uint64 array - the amount distributed (dY) for each order
text
$ curl -X POST localhost:50002/v1/query/next-dex-batch \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000,
        "id": 1
      }'
> {
    "committee": 1,
    "receiptHash": "b5d54c39e66671c9731b9f471e585d8262cd4f54963f0c93082d8dcf334d4c78",
    "orders": [
        {
            "amountForSale": 1000000000000,
            "requestedAmount": 2000000000000,
            "address": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
            "orderId": "a1b2c3d4e5f67890abcd"
        }
    ],
    "deposits": [
        {
            "amount": 1000000000000,
            "address": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
            "orderId": "1234567890abcdef1234"
        }
    ],
    "withdraws": [
        {
            "amount": 100,
            "address": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
            "orderId": "fedcba0987654321fedc"
        }
    ],
    "poolPoints": [
      {
        "address": "551f21e333012027b81701a35023efc88b864975",
        "points": 100
      }
    ],
    "totalPoolPoints": 100,
    "poolSize": 5000000000000,
    "counterPoolSize": 3000000000000,
    "receipts": [1000000, 0, 950000]
}

Dex Price

Route: /v1/query/dex-price
Description: retrieves the latest dex price for a committee or all dex prices
HTTP Method: POST
Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)
  • id: uint64 – the unique identifier of the committee (optional: use 0 to get all committees)
    Response:
  • chainId: uint64 - the id of the local chain
  • remoteChainId: uint64 - the id of the remote chain
  • localPool: uint64 - the current balance of the local liquidity pool
  • remotePool: uint64 - the current balance of the remote liquidity pool
  • e6ScaledPrice: uint64 - the price scaled by 1e6 (1,000,000)
text
$ curl -X POST localhost:50002/v1/query/dex-price \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000,
        "id": 1
      }'
> {
    "chainId": 1,
    "remoteChainId": 2,
    "localPool": 5000000000000,
    "remotePool": 3000000000000,
    "e6ScaledPrice": 600000
}

Pending Transactions (Mempool)

Route: /v1/query/pending

Description: view the transactions not yet confirmed in a block

HTTP Method: POST

Request:

  • perPage: int - the number of elements per page (the default is 10 and max is 5,000)
  • pageNumber: int - the number of the page (the default is 1)

Response:

  • perPage: int - the number of elements per page
  • pageNumber: int - the number of the page
  • results: array - the list of result objects
    • blockHeader: object - the summary of the block
    • transactions: array - list of transactions in the block
      • sender: hex-string - the address of the user sending the transaction
      • recipient: hex-string - the address of the user receiving the transaction
      • messageType: string - the name of the of the message like 'send' or 'stake'
      • height: uint64 - the block height at which the transaction was included (n/a)
      • index: uint64 - the position of the transaction within the block
      • transaction: object - original transaction object
        • messageType: string - type of the transaction like 'send' or 'stake'
        • msg: object - the actual transaction message payload, which is encapsulated in a generic message format. (See tx-by-hash)
        • signature: object - the cryptographic signature used to verify the authenticity of the transaction
        • createdHeight: uint64 - the height when the transaction was created - allows 'safe pruning'
        • time: unix micro timestamp - timestamp when the transaction was created - used as temporal entropy to prevent hash collisions in txs
        • fee: uint64 - fee associated with processing the transaction in micro denomination
        • memo: string - an optional message or note attached to the transaction
        • networkId: uint64 - the identity of the network the transaction is intended for
        • chainId: uint64 - the identity of the committee the transaction is intended for
      • txHash: hex-string - the unique hash that identifies the transaction
  • type: string - the type of results
  • count: int - length of results
  • totalPages: int - number of pages
  • totalCount: int - total number of items that exist in all pages
text
$ curl -X POST localhost:50002/v1/query/pending \
  -H "Content-Type: application/json" \
  -d '{}'

>{
  "pageNumber": 1,
  "perPage": 10,
  "results": [
    {
      "sender": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
      "recipient": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
      "messageType": "send",
      "height": 0,
      "transaction": {
        "type": "send",
        "msg": {
          "fromAddress": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
          "toAddress": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
          "amount": 100000
        },
        "signature": {
          "publicKey": "b2947db37385bb43c46244cef15f2451a446cea011fc1a2e1d52b1cecc7a50a8924e0e062555793bbd55a91a685017ee",
          "signature": "8a427223eae305e0816d66c7940320f7fa17b3a084c1a27130fd4cd0e6fe68eae2edecf1ec197cac1ac049899cdf9e0e10ae7855b2b2aacd213950eb4856dd10b6bc0b77eb34bc3e49e82cabb21aaf85f588876b0568f1b4981961c3e9c525a9"
        },
        "time": 1749070106734452,
        "createdHeight": 17584,
        "fee": 10000,
        "networkID": 1,
        "chainID": 1
      },
      "txHash": "ff22f214f5f300d315a56581ccb0f10fe1665f90c8f09666f7c58abcabfbcedb"
    }
  ],
  "type": "pending-results-page",
  "count": 1,
  "totalPages": 1,
  "totalCount": 1
}

Failed Transactions

Route: /v1/query/failed-txs

Description: view the transactions that failed locally - note: there is no global index of failed transactions because Canopy does not include failed transactions in blocks

HTTP Method: POST

Request:

  • address: hex-string - the address of the sender of the failed transactions
  • perPage: int - the number of elements per page (the default is 10 and max is 5,000)
  • pageNumber: int - the number of the page (the default is 1)

Response:

  • perPage: int - the number of elements per page
  • pageNumber: int - the number of the page
  • results: array - the list of result objects
    • blockHeader: object - the summary of the block
    • transactions: array - list of transactions in the block
      • sender: hex-string - the address of the user sending the transaction
      • recipient: hex-string - the address of the user receiving the transaction
      • messageType: string - the name of the of the message like 'send' or 'stake'
      • height: uint64 - the block height at which the transaction was included (n/a)
      • index: uint64 - the position of the transaction within the block
      • transaction: object - original transaction object
        • messageType: string - type of the transaction like 'send' or 'stake'
        • msg: object - the actual transaction message payload, which is encapsulated in a generic message format. (See tx-by-hash)
        • signature: object - the cryptographic signature used to verify the authenticity of the transaction
        • createdHeight: uint64 - the height when the transaction was created - allows 'safe pruning'
        • time: unix micro timestamp - timestamp when the transaction was created - used as temporal entropy to prevent hash collisions in txs
        • fee: uint64 - fee associated with processing the transaction in micro denomination
        • memo: string - an optional message or note attached to the transaction
        • networkId: uint64 - the identity of the network the transaction is intended for
        • chainId: uint64 - the identity of the committee the transaction is intended for
      • txHash: hex-string - the unique hash that identifies the transaction
    • address: hex-string - the sender of the transaction
    • error: object - the failure reason
      • code: uint64 - the softare code of the failure
      • module: string - the software module of the failure
      • msg: string - the failure message
  • type: string - the type of results
  • count: int - length of results
  • totalPages: int - number of pages
  • totalCount: int - total number of items that exist in all pages
text
$ curl -X POST localhost:50002/v1/query/failed-txs \
  -H "Content-Type: application/json" \
  -d '{
    "address":"502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711"
  }'

>{
  "pageNumber": 1,
  "perPage": 10,
  "results": [
    {
      "transaction": {
        "type": "send",
        "msg": {
          "fromAddress": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
          "toAddress": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
          "amount": 341230502138
        },
        "signature": {
          "publicKey": "b2947db37385bb43c46244cef15f2451a446cea011fc1a2e1d52b1cecc7a50a8924e0e062555793bbd55a91a685017ee",
          "signature": "892b2467b96f82c986eddd584852713bddb49910e8f8b4fcce49713722c6fed3441271e329c275f6994e0ba02cfefda50cf13ade98c22fd140a2f5e2b27db527b11aaa013fb7422db479c61ba9fd95098975701f7f692fb1c9b633f03a15e979"
        },
        "time": 1749075548254250,
        "createdHeight": 18666,
        "fee": 10000,
        "networkID": 1,
        "chainID": 1
      },
      "txHash": "dd94d433b9da628444fb790515ddfc0434934ed7da9aca6793995f87691e8439",
      "address": "502c0b3d6ccd1c6f164aa5536b2ba2cb9e80c711",
      "error": {
        "code": 28,
        "module": "state_machine",
        "msg": "insufficient funds"
      }
    }
  ],
  "type": "failed-txs-page",
  "count": 1,
  "totalPages": 1,
  "totalCount": 1
}

Governance Proposals

Route: /v1/gov/proposals

Description: view how your validator is voting for governance parameters changes and token distributions from the DAO Treasury Fund

HTTP Method: GET

Request: None

Response:

  • map[proposalHashHex] -> object
    • proposal: object - the governance proposal structure in the form of a Transaction with a payload that is oneOf: MessageChangeParameter or MessageDAOTransfer see (see tx-by-hash)
    • approve: bool - is the local Validator voting yes or no on the proposal
text
$ curl -X GET localhost:50002/v1/gov/proposals

>{
  "93ba7a69f9be05257822c61be59bd80c1d5c5c9f56d6320f94a36d84c4c781f9": {
    "proposal": {
      "type": "changeParameter",
      "msg": {
        "parameterSpace": "cons|fee|val|gov",
        "parameterKey": "protocolVersion",
        "parameterValue": "example",
        "startHeight": 1,
        "endHeight": 1000,
        "signer": "4646464646464646464646464646464646464646"
      },
      "signature": {
        "publicKey": "a10665940f6dd5f8c5ca858b562afee13794a5055ffc289596b4fe9230aae83bd7e8b4dc1c9611793936d6dfd725e592",
        "signature": "8c586257852296498c056d9ea8090f69207d938d67375ea34fbc2af4fa06e97404588d3f67237c3bf847fe8c6d7a670d03680622aba6b3b7e72d3bc93f871bf98ba8a2e94d1ab6e52437746a0449bc2fbd9ccf42e8256f5ab541b95435f6c202"
      },
      "time": 1744837549307074,
      "createdHeight": 1,
      "fee": 10000,
      "memo": "example",
      "networkID": 1,
      "chainID": 1
    },
    "approve": true
  }
}

Governance Poll

Route: /v1/gov/poll

Description: view community sentiment by on-chain votes of Accounts and Validators. This data is recalculated and updated periodically

HTTP Method: GET

Request: None

Response:

  • map[proposalHashHex] -> object
    • proposalHash: hex-string - the SHA256 hash of the proposal that is voted on
    • proposalURL: url-string - the URL of the proposal information
    • accounts: object - the accounts voting data
      • approveTokens: uint64 - approve count represented by liquid token balance
      • rejectTokens: uint64 - reject count reprented by liquid token balance
      • totalTokens: uint64 - total liquid tokens that voted
      • approvePercent: uint64 - the percent of voters in this category who approve
      • rejectPercent: uint64 - the percent of voters in this category who disapprove
      • votedPercent: uint64 - the percent of voters in this category who voted
    • validators: object - the validators voting data
      • approveTokens: uint64 - approve count represented by liquid token balance
      • rejectTokens: uint64 - reject count reprented by liquid token balance
      • totalTokens: uint64 - total liquid tokens that voted
      • approvePercent: uint64 - the percent of voters in this category who approve
      • rejectPercent: uint64 - the percent of voters in this category who disapprove
      • votedPercent: uint64 - the percent of voters in this category who voted
    • approve: bool - is the local Validator voting yes or no on the proposal
text
$ curl -X GET localhost:50002/v1/gov/poll

>{
  "50d858e0985ecc7f60418aaf0cc5ab587f42c2570a884095a9e8ccacd0f6545c": {
    "proposalHash": "50d858e0985ecc7f60418aaf0cc5ab587f42c2570a884095a9e8ccacd0f6545c",
    "proposalURL": "https://forum.cnpy.network/something",
    "accounts": {
      "approveTokens": 0,
      "rejectTokens": 0,
      "totalVotedTokens": 0,
      "totalTokens": 12556191411824,
      "approvedPercent": 0,
      "rejectPercent": 0,
      "votedPercent": 0
    },
    "validators": {
      "approveTokens": 0,
      "rejectTokens": 0,
      "totalVotedTokens": 0,
      "totalTokens": 2223557946105,
      "approvedPercent": 0,
      "rejectPercent": 0,
      "votedPercent": 0
    }
  }
}

Root Chain Info

Route: /v1/gov/root-chain-info

Description: responds with root-chain data needed for nested-chain consensus

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)
  • id: uint64 – the unique identifier of the committee

Response:

  • rootChainid: uint64 - the unique identifier of the chain responsible for the validator set
  • height: uint64 - the height of the query
  • validatorSet: object - the consensus validators currently active according to the root-chain
    • validatorSet: object array - the list of consensus validators
      • publicKey: hex-string - the BLS public key of the validator
      • votingPower: uint64 - the voting power of the validator (typically amount of staked tokens)
      • netAddress: url string - the TCP peer-to-peer address of the validator
  • lastValidatorSet: object - the consensus validators active for the last root-chain height (see validatorSet)
  • lotteryWinner: object - the selected delegate/pseudo-validator who receives rewards
    • winner: hex-string - the 20 byte address of the selected actor
    • cut: uint64 - the percent cut of the rewards before normalization
  • orders: object - the swap order book from the 'root chain' for the 'nested chain'
    • chainId: uint64 - the unique identifier of the committee
    • orders: sell order array - the actual list of sell orders
      • id: hex string - the 20 byte identifier of the order
      • committee: uint64 - the id of the committee that is in-charge of escrow for the swap
      • data: hex-string - a generic data field which can allow a committee to execute specific functionality for the swap
      • amountForSale: uint64 - amount of 'root-chain-asset' for sale
      • requestedAmount: uint64 - amount of 'counter-asset' the seller of the 'root-chain-asset' receives
      • sellerReceiveAddress: hex-string - the external chain address to receive the 'counter-asset'
      • buyerSendAddress: hex-string - if reserved (locked): the address the buyer will be transferring the funds from
      • buyerChainDeadline: hex-string - the external chain height deadline to send the 'tokens' to SellerReceiveAddress
      • sellersSendAddress: hex-string - the signing address of seller who is selling the CNPY
text
$ curl -X POST localhost:50002/v1/query/root-chain-info \
  -H "Content-Type: application/json" \
  -d '{
        "height": 17585,
        "id": 1
      }'

>{
  "rootChainId": 1,
  "height": 17585,
  "validatorSet": {
    "validatorSet": [
      {
        "publicKey": "b17d4eb3938957e710bacc9f09d2a9aa79a568fcdf1f8fc565bdb5de3f334295e929e4b086b9c8e9610654155fb0452b",
        "votingPower": 1,
        "netAddress": "tcp://canopyrocks.xyz"
      }
    ]
  },
  "lastValidatorSet": {
    "validatorSet": [
      {
        "publicKey": "b17d4eb3938957e710bacc9f09d2a9aa79a568fcdf1f8fc565bdb5de3f334295e929e4b086b9c8e9610654155fb0452b",
        "votingPower": 1,
        "netAddress": "tcp://canopyrocks.xyz"
      }
    ]
  },
  "lotteryWinner": {
    "winner": "",
    "cut": 0
  },
  "orders": {
    "chainID": 1
  }
}

Last Proposers

Route: /v1/query/last-proposers

Description: responds with the last Proposer addresses saved in the state

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)

Response:

  • addresses: hex-string array - a list of addresses of the most recent previous proposers in fixed modulo order
text
$ curl -X POST localhost:50002/v1/query/last-proposers \
  -H "Content-Type: application/json" \
  -d '{
        "height": 17585
      }'

>{
  "addresses": [
    "fc5cdb5c0b6a6df41b92976bbdf2b6832855446f",
    "ac2c2eb9aa04b99ec9a523b09ca844a77826c291",
    "b9c6c2dfa9d049e480c8cec9c29463abf078a594",
    "b9c6c2dfa9d049e480c8cec9c29463abf078a594",
    "33e14ef6b87fb688b829c5e29618bb549dc7b4cd"
  ]
}

Is Valid Double Signer

Route: /v1/query/valid-double-signer

Description: responds if the DoubleSigner is NOT already set for a height - this is useful to determine if byzantine evidence is stale.

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)
  • address: hex-string - the address of the potential double signer

Response: bool - may be set as a double signer

text
$ curl -X POST localhost:50002/v1/query/valid-double-signer \
  -H "Content-Type: application/json" \
  -d '{
        "height": 17585,
        "address": "b9c6c2dfa9d049e480c8cec9c29463abf078a594"
      }'

>true

Double Signer

Route: /v1/query/double-signers

Description: responds with all double signers in the indexer

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)

Response:

  • array - list of all double signers as of the query height
    • id: uint64 - the address identifier of the malicious actor
    • heights: array
text
$ curl -X POST localhost:50002/v1/query/double-signers \
  -H "Content-Type: application/json" \
  -d '{
        "height": 17585
      }'

>[{
  "id": "b9c6c2dfa9d049e480c8cec9c29463abf078a594",
  "heights": [1000, 17585]
}]

Minimum Evidence Height

Route: /v1/query/minimum-evidence-height

Description: responds with the minimum height the evidence must be to still be usable

HTTP Method: POST

Request: None

Response: uint64 - the minimum evidence height

text
$ curl -X POST localhost:50002/v1/query/minimum-evidence-height \
  -H "Content-Type: application/json" \
  -d '{}'

> 165453

Lottery

Route: /v1/query/lottery

Description: responds with the selected winner (nested-validator/nested-delegate/delegate) chosen pseudo-randomly based on their stake weight within a committee

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)
  • id: uint64 - the unique identifier of the committee

Response:

  • winner: hex-string - the 20 byte address of the selected actor
  • cut: uint64 - the percent cut of the rewards before normalization
text
$ curl -X POST localhost:50002/v1/query/lottery \
  -H "Content-Type: application/json" \
  -d '{
        "height": 17585,
        "id" : 1
      }'

>{
  "winner": "b9c6c2dfa9d049e480c8cec9c29463abf078a594",
  "cut": 10
}

Checkpoint

Route: /v1/query/checkpoint

Description: responds with the checkpoint block hash for a certain committee and height combination

HTTP Method: POST

Request:

  • height: uint64 – the block height to read data from (optional: use 0 to read from the latest block)
  • id: uint64 - the unique identifier of the committee / chain

Response: hex-string - the block hash of the committee / chain

text
$ curl -X POST localhost:50002/v1/query/checkpoint \
  -H "Content-Type: application/json" \
  -d '{
        "height": 1000,
        "id" : 1
      }'

> "cd9d3e487bce2918e306364fca286f473bd8cc92f150b3d97f9063b570a2b801"

Subscribe Root Chain Info

Route: /v1/query/subscribe-rc-info

Description: ws: upgrades a http request to a websockets connection. Subscribes to the root chain info for when the root-chain publishes it.

HTTP Method: WS

Request:

  • chainId: uint64 - the unique identifier of the committee / chain

Response: Periodic updates with Root-Chain-Info sent over the WebSocket

text
$ websocat "ws://localhost:50002/v1/subscribe-rc-info?chainId=123"

Ethereum

Route: /v1/eth

Description: implements Ethereum JSON-RPC interface. For more details see the Canopy Ethereum Wrapper specification.

HTTP Method: POST

Request: (See Ethereum Specification)

Response: (See Ethereum Specification)

text
$ curl -X POST http://localhost:50002/v1/eth \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc":"2.0",
    "method":"eth_blockNumber",
    "params":[],
    "id":1
  }'

> {
  "id": 1,
  "jsonrpc": "2.0",
  "result": "0x2fc6c"
}

Admin

🚨Important: All admin commands assume secure https connection

Keystore

Route: /v1/admin/keystore

Description: responds with the local keystore

HTTP Method: GET

Request: None

Response:

  • addressMap: object - the map of addresses to keystore entry [hex-address] -> keystoreEntry
    • publicKey: hex-string - the public code that can cryptographically verify signatures from the private key
    • salt: hex-string - random 16 bytes salt
    • encrypted: hex-string - the private key encrypted with AES-GCM
    • keyAddress: hex-string - the address of the key
    • keyNickname: string - the nickname of the key
  • nicknameMap: object the map of nicknames to address [nickname] -> hex-address
text
$ curl -X GET http://localhost:50003/v1/admin/keystore \
  -H "Content-Type: application/json" \
  -d '{}'

> {
  "addressMap": {
    "b0b4a45ca70104ecc943a49e4553f0e7e1135b01": {
      "publicKey": "8cb57bdcc0f90c36aea48a6edab31996400af55f623f676a3c64c04b826454aea227f14d1b70c150d5fa9fe5f6790f60",
      "salt": "aff12414025b261cc56fbeaeb5dcf5f4",
      "encrypted": "eb3d900e781a2de743bcc804737753cbe7440bffab18419409517db0a2bf98b8028f69aba271f482b838c6de8e8b8292",
      "keyAddress": "b0b4a45ca70104ecc943a49e4553f0e7e1135b01",
      "keyNickname": "my_key"
    }
  },
  "nicknameMap": {
    "my_key": "b0b4a45ca70104ecc943a49e4553f0e7e1135b01",
  }
}

Keystore New Key

Route: /v1/admin/keystore-new-key

Description: create a new BLS key in the keystore

HTTP Method: POST

Request:

  • nickname: string - the nickname associated with the key
  • password: string - the plaintext password used to encrypt the key

Response: hex-string - the 20 byte address of the newly created key

text
$ curl -X POST http://localhost:50003/v1/admin/keystore-new-key \
  -H "Content-Type: application/json" \
  -d '{"nickname":"my_key_", "password":"plain-text"}'

> "7cd2a86894f4a23ea956dee1722c6776230bf552"

Keystore Import

Route: /v1/admin/keystore-import

Description: import an encrypted private key to the node's keystore

HTTP Method: POST

Request:

  • nickname: string - the nickname associated with the key
  • address: hex-string - the address associated with the encrypted key
  • publicKey: hex-string - the public code that can cryptographically verify signatures from the private key
  • salt: hex-string - random 16 bytes salt
  • encrypted: hex-string - the private key encrypted with AES-GCM

Response: hex-string - the 20 byte address of the newly imported key

text
$ curl -X POST http://localhost:50003/v1/admin/keystore-import \
  -H "Content-Type: application/json" \
  -d '{
    "nickname":"my_key_", 
    "addresss":"b0b4a45ca70104ecc943a49e4553f0e7e1135b01",
    "publicKey": "8cb57bdcc0f90c36aea48a6edab31996400af55f623f676a3c64c04b826454aea227f14d1b70c150d5fa9fe5f6790f60",
      "salt": "aff12414025b261cc56fbeaeb5dcf5f4",
      "encrypted": "eb3d900e781a2de743bcc804737753cbe7440bffab18419409517db0a2bf98b8028f69aba271f482b838c6de8e8b8292"
    }'

> "b0b4a45ca70104ecc943a49e4553f0e7e1135b01"

Keystore Import Raw

Route: /v1/admin/keystore-import-raw

Description: import a raw private key to the node's keystore

HTTP Method: POST

Request:

  • nickname: string - the nickname associated with the key
  • password: string - the plain-text password to encrypt the private key with
  • privateKey: hex-string - the secret code that is capable of producing digital signatures

Response: hex-string - the 20 byte address of the newly imported key

text
$ curl -X POST http://localhost:50003/v1/admin/keystore-import-raw \
  -H "Content-Type: application/json" \
  -d '{
    "nickname":"my_key_2", 
    "password":"plain-text",
    "privateKey": "ee62bbab22a26e34e5489bdb3a751533c34084975fadac4b5b23e15dbd0cff70"
    }'

> "b0b4a45ca70104ecc943a49e4553f0e7e1135b01"

Keystore Delete

Route: /v1/admin/keystore-delete

Description: removes a key from the keystore using either the address or nickname after validating the password

HTTP Method: POST

Request:

  • nickname: string - the nickname associated with the key
  • address: string - the address associated with the key
  • password: string - (required) the plain-text password used to encrypt the key

Response: hex-string - the 20 byte address of the newly imported key

text
$ curl -X POST http://localhost:50003/v1/admin/keystore-delete \
  -H "Content-Type: application/json" \
  -d '{
    "nickname":"my_key_2",
    "password":"my_password"
    }'

> "b0b4a45ca70104ecc943a49e4553f0e7e1135b01"

Keystore Get

Route: /v1/admin/keystore-get

Description: responds with the key group associated with an address or nickname

HTTP Method: POST

Request:

  • nickname: string - the nickname associated with the key
  • address: hex-string - address associated with the key
  • password: hex-string - the plain-text password to get the private key with

Response:

  • address: hex-string - the 20 byte address of the newly imported key
  • publicKey: hex-string - a cryptographic code shared openly, used to verify digital signatures of its paired private key
  • privateKey: hex-string - a secret cryptographic code that is used to produce digital signatures
text
$ curl -X POST http://localhost:50003/v1/admin/keystore-get \
  -H "Content-Type: application/json" \
  -d '{
    "nickname":"my_key",
    "password":"test"
    }'

> {
  "address": "b0b4a45ca70104ecc943a49e4553f0e7e1135b01",
  "publicKey": "acb57b23c0f90c16aea48a6edbb31996400af55f623f676a3c64c04b826454aea227f14d1b70c151d5fa9fe536790f6d",
  "privateKey": "ed3c9acd8fffa374756ba1c175af5228f9e4e96c0ecdfda0a9fd9afa09472e12"
}

Txn Send

Route: /v1/admin/tx-send

Description: generates/submits a send transaction

HTTP Method: POST

Request:

  • address: hex-string - the from address
  • output: hex-string - the recipient address
  • fee: uint64 - the transaction fee in micro denomination (optional - minimum fee filled if 0)
  • memo: string - an arbitrary message encoded in the transaction
  • submit: bool - submit this transaction or not (returns the tx-hash if true)
  • password: string - the password associated to decrypt the private key to sign the transaction

Response: (See tx-by-hash and MessageSend)

text
$ curl -X POST http://localhost:50003/v1/admin/tx-send \
  -H "Content-Type: application/json" \
  -d '{
    "address":"b0b4a45ca70104ecc943a49e4553f0e7e1135b01",
    "output":"271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5",
    "amount": 1000000,
    "memo": "hello world",
    "submit": false,
    "password": "test"
    }'

> {
  "type": "send",
  "msg": {
  "fromAddress": "b0b4a45ca70104ecc943a49e4553f0e7e1135b01",
  "toAddress": "271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5",
  "amount": 1000000
  },
  "signature": {
  "publicKey": "8cb57bdcc0f90c36aea48a6edab31996400af55f623f676a3c64c04b826454aea227f14d1b70c150d5fa9fe5f6790f60",
  "signature": "8b33f205f3cfeae277ac9b363a442114117d67dfa2722c9396bd1f67f289a977b0495c252db9a693c8e4c659667461ea0e9928533f69376622572808b10a17bd9c005ccea3f798a138719f896b1d27e981d88ef0cb025a761f6e37a5a6fd6e49"
  },
  "time": 1749415924948935,
  "createdHeight": 196596,
  "fee": 10000,
  "memo": "hello world",
  "networkID": 1,
  "chainID": 1
}

Txn Stake

Route: /v1/admin/tx-stake

Description: generates/submits a stake transaction

HTTP Method: POST

Request:

  • address: hex-string - the operator address associated with the validator
  • amount: uint64 - the amount of tokens to stake in smallest (micro) denomination
  • pubKey: hex-string - the operator public key (must be BLS if non-delegate)
  • netAddress: url string - the p2p url of the validator (n/a for delegate)
  • committees: string - a comma separated list of committee ids
  • delegate: bool - is this validator active (false) or delegating (true)
  • earlyWithdrawal: bool - is this validator withdrawing its rewards early for a penalty (true) or auto-compounding (false)
  • output: hex-string - the address where rewards and returned bonded tokens outputs to
  • fee: uint64 - the transaction fee in micro denomination (optional - minimum fee filled if 0)
  • memo: string - an arbitrary message encoded in the transaction
  • submit: bool - submit this transaction or not (returns the tx-hash if true)
  • password: string - the password associated to decrypt the private key to sign the transaction
  • signer: hex-string - the address associated with the key that is signing the transaction

Response: (See tx-by-hash and MessageStake)

text
$ curl -X POST http://localhost:50003/v1/admin/tx-stake \
  -H "Content-Type: application/json" \
  -d '{
    "address": "abb4a45ca70104ecc943a49e4553f0e7e1135b01",
    "netAddress": "tcp://cnpyrocks.com",
    "committees": "1,2,3",
    "amount": 1000000,
    "delegate": false,
    "earlyWithdrawal": false,
    "output": "ab1e0120ac7f11a6f60baa24b2b187eaf1e2e6f5",
    "signer": "b0b4a45ca70104ecc943a49e4553f0e7e1135b01",
    "memo": "hello world",
    "fee": 10000,
    "submit": false,
    "password": "test"
  }'

> {
  "type": "stake",
  "msg": {
    "publickey": "8cb57bdcc0f90c36aea48a6edab31996400af55f623f676a3c64c04b826454aea227f14d1b70c150d5fa9fe5f6790f60",
    "amount": 1000000,
    "committees": [
      1,2,3
    ],
    "netAddress": "tcp://cnpyrocks.com",
    "outputAddress": "ab1e0120ac7f11a6f60baa24b2b187eaf1e2e6f5",
    "delegate": false,
    "compound": true
  },
  "signature": {
    "publicKey": "8cb57bdcc0f90c36aea48a6edab31996400af55f623f676a3c64c04b826454aea227f14d1b70c150d5fa9fe5f6790f60",
    "signature": "a0473e839b23abc7d8448de5c58141827d86157263deaa79db0d9a1d1f0ffa9f7503c9ff52be7645b3ca0de50482651c1857d2af39c6953a68e386ca0901f668ef61dd706e4ed753548b5cb6737aceb06307e5894fbe49668fa2a1ff9036e971"
  },
  "time": 1749416582662716,
  "createdHeight": 196596,
  "fee": 10000,
  "memo": "hello world",
  "networkID": 1,
  "chainID": 1
}

Txn Edit Stake

Route: /v1/admin/tx-edit-stake

Description: generates/submits an edit stake transaction

HTTP Method: POST

Request:

  • address: hex-string - the operator address associated with the validator
  • amount: uint64 - the amount of tokens to stake in smallest (micro) denomination - (cannot decrease amount, lower defaults to current stake amount)
  • netAddress: url string - the p2p url of the validator (n/a for delegate)
  • committees: string - a comma separated list of committee ids
  • earlyWithdrawal: bool - is this validator withdrawing its rewards early for a penalty (true) or auto-compounding (false)
  • output: hex-string - the address where rewards and returned bonded tokens outputs to (only the output address can change this)
  • fee: uint64 - the transaction fee in micro denomination (optional - minimum fee filled if 0)
  • memo: string - an arbitrary message encoded in the transaction
  • submit: bool - submit this transaction or not (returns the tx-hash if true)
  • password: string - the password associated to decrypt the private key to sign the transaction
  • signer: hex-string - the address associated with the key that is signing the transaction

Response: (See tx-by-hash and MessageEditStake)

text
$ curl -X POST http://localhost:50003/v1/admin/tx-edit-stake \
  -H "Content-Type: application/json" \
  -d '{
    "address": "abb4a45ca70104ecc943a49e4553f0e7e1135b01",
    "netAddress": "tcp://cnpyrocks.com",
    "committees": "1,2,3",
    "amount": 1000000,
    "earlyWithdrawal": false,
    "output": "ab1e0120ac7f11a6f60baa24b2b187eaf1e2e6f5",
    "signer": "b0b4a45ca70104ecc943a49e4553f0e7e1135b01",
    "memo": "hello world",
    "fee": 10000,
    "submit": false,
    "password": "test"
  }'

> {
  "type": "edit-stake",
  "msg": {
    "addresss": "abb4a45ca70104ecc943a49e4553f0e7e1135b01",
    "amount": 1000000,
    "committees": [
      1,2,3
    ],
    "netAddress": "tcp://cnpyrocks.com",
    "outputAddress": "ab1e0120ac7f11a6f60baa24b2b187eaf1e2e6f5",
    "compound": true
  },
  "signature": {
    "publicKey": "8cb57bdcc0f90c36aea48a6edab31996400af55f623f676a3c64c04b826454aea227f14d1b70c150d5fa9fe5f6790f60",
    "signature": "a0473e839b23abc7d8448de5c58141827d86157263deaa79db0d9a1d1f0ffa9f7503c9ff52be7645b3ca0de50482651c1857d2af39c6953a68e386ca0901f668ef61dd706e4ed753548b5cb6737aceb06307e5894fbe49668fa2a1ff9036e971"
  },
  "time": 1749416582662716,
  "createdHeight": 196596,
  "fee": 10000,
  "memo": "hello world",
  "networkID": 1,
  "chainID": 1
}

Txn Pause

Route: /v1/admin/tx-pause

Description: generates/submits a pause transaction

HTTP Method: POST

Request:

  • address: hex-string - the operator address associated with the validator
  • fee: uint64 - the transaction fee in micro denomination (optional - minimum fee filled if 0)
  • memo: string - an arbitrary message encoded in the transaction
  • submit: bool - submit this transaction or not (returns the tx-hash if true)
  • password: string - the password associated to decrypt the private key to sign the transaction
  • signer: hex-string - the address associated with the key that is signing the transaction

Response: (See tx-by-hash and MessagePause)

text
$ curl -X POST http://localhost:50003/v1/admin/tx-pause \
  -H "Content-Type: application/json" \
  -d '{
    "address": "abb4a45ca70104ecc943a49e4553f0e7e1135b01",
    "signer": "b0b4a45ca70104ecc943a49e4553f0e7e1135b01",
    "memo": "hello world",
    "fee": 10000,
    "submit": false,
    "password": "test"
  }'

> {
  "type": "pause",
  "msg": {
    "addresss": "abb4a45ca70104ecc943a49e4553f0e7e1135b01",
  "signature": {
    "publicKey": "8cb57bdcc0f90c36aea48a6edab31996400af55f623f676a3c64c04b826454aea227f14d1b70c150d5fa9fe5f6790f60",
    "signature": "a0473e839b23abc7d8448de5c58141827d86157263deaa79db0d9a1d1f0ffa9f7503c9ff52be7645b3ca0de50482651c1857d2af39c6953a68e386ca0901f668ef61dd706e4ed753548b5cb6737aceb06307e5894fbe49668fa2a1ff9036e971"
  },
  "time": 1749416582662716,
  "createdHeight": 196596,
  "fee": 10000,
  "memo": "hello world",
  "networkID": 1,
  "chainID": 1
}

Txn Unpause

Route: /v1/admin/tx-unpause

Description: generates/submits an unpause transaction

HTTP Method: POST

Request:

  • address: hex-string - the operator address associated with the validator
  • fee: uint64 - the transaction fee in micro denomination (optional - minimum fee filled if 0)
  • memo: string - an arbitrary message encoded in the transaction
  • submit: bool - submit this transaction or not (returns the tx-hash if true)
  • password: string - the password associated to decrypt the private key to sign the transaction
  • signer: hex-string - the address associated with the key that is signing the transaction

Response: (See tx-by-hash and MessageUnpause)

text
$ curl -X POST http://localhost:50003/v1/admin/tx-unpause \
  -H "Content-Type: application/json" \
  -d '{
    "address": "abb4a45ca70104ecc943a49e4553f0e7e1135b01",
    "signer": "b0b4a45ca70104ecc943a49e4553f0e7e1135b01",
    "memo": "hello world",
    "fee": 10000,
    "submit": false,
    "password": "test"
  }'

> {
  "type": "unpause",
  "msg": {
    "addresss": "abb4a45ca70104ecc943a49e4553f0e7e1135b01",
  "signature": {
    "publicKey": "8cb57bdcc0f90c36aea48a6edab31996400af55f623f676a3c64c04b826454aea227f14d1b70c150d5fa9fe5f6790f60",
    "signature": "a0473e839b23abc7d8448de5c58141827d86157263deaa79db0d9a1d1f0ffa9f7503c9ff52be7645b3ca0de50482651c1857d2af39c6953a68e386ca0901f668ef61dd706e4ed753548b5cb6737aceb06307e5894fbe49668fa2a1ff9036e971"
  },
  "time": 1749416582662716,
  "createdHeight": 196596,
  "fee": 10000,
  "memo": "hello world",
  "networkID": 1,
  "chainID": 1
}

Txn Unstake

Route: /v1/admin/tx-unstake

Description: generates/submits an unstake transaction

HTTP Method: POST

Request:

  • address: hex-string - the operator address associated with the validator
  • fee: uint64 - the transaction fee in micro denomination (optional - minimum fee filled if 0)
  • memo: string - an arbitrary message encoded in the transaction
  • submit: bool - submit this transaction or not (returns the tx-hash if true)
  • password: string - the password associated to decrypt the private key to sign the transaction
  • signer: hex-string - the address associated with the key that is signing the transaction

Response: (See tx-by-hash and MessageUnstake)

text
$ curl -X POST http://localhost:50003/v1/admin/tx-unstake \
  -H "Content-Type: application/json" \
  -d '{
    "address": "abb4a45ca70104ecc943a49e4553f0e7e1135b01",
    "signer": "b0b4a45ca70104ecc943a49e4553f0e7e1135b01",
    "memo": "hello world",
    "fee": 10000,
    "submit": false,
    "password": "test"
  }'

> {
  "type": "unstake",
  "msg": {
    "addresss": "abb4a45ca70104ecc943a49e4553f0e7e1135b01",
  "signature": {
    "publicKey": "8cb57bdcc0f90c36aea48a6edab31996400af55f623f676a3c64c04b826454aea227f14d1b70c150d5fa9fe5f6790f60",
    "signature": "a0473e839b23abc7d8448de5c58141827d86157263deaa79db0d9a1d1f0ffa9f7503c9ff52be7645b3ca0de50482651c1857d2af39c6953a68e386ca0901f668ef61dd706e4ed753548b5cb6737aceb06307e5894fbe49668fa2a1ff9036e971"
  },
  "time": 1749416582662716,
  "createdHeight": 196596,
  "fee": 10000,
  "memo": "hello world",
  "networkID": 1,
  "chainID": 1
}

Txn Create Order

Route: /v1/admin/tx-create-order

Description: generates/submits a create (sell) order transaction

HTTP Method: POST

Request:

  • address: hex-string - the address that is sending the 'root-chain' funds
  • receiveAddress: hex-string - the address that is receiving the 'counter-asset' funds
  • committees: string - the id of the committee that is responsible for the 'counter asset'
  • amount: uint64 - the amount of 'root-chain-asset' to lock in escrow to be swapped in smallest denomination
  • receiveAmount: uint64 - the amount of 'counter-asset' to receive in smallest denomination
  • data: hex-string - an arbitrary string code associated with the order (can be used for sub-asset contract address)
  • fee: uint64 - the transaction fee in micro denomination (optional - minimum fee filled if 0)
  • memo: string - an arbitrary message encoded in the transaction
  • submit: bool - submit this transaction or not (returns the tx-hash if true)
  • password: string - the password associated to decrypt the private key to sign the transaction

Response: (See tx-by-hash and MessageCreateOrder)

text
$ curl -X POST http://localhost:50003/v1/admin/tx-create-order \
  -H "Content-Type: application/json" \
  -d '{
    "address":"abb4a45ca70104ecc943a49e4553f0e7e1135b01",
    "committees":"1",
    "amount":100000000,
    "receiveAmount":100000000,
    "data": "0x...",
    "receiveAddress":"271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5",
    "memo":"",
    "fee":10000,
    "submit":false,
    "password":"test"
    }'

> {
  "type": "createOrder",
  "msg": {
    "chainId": 1,
    "amountForSale": 100000000,
    "data": "0x...",
    "requestedAmount": 100000000,
    "sellerReceiveAddress": "271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5",
    "sellersSendAddress": "abb4a45ca70104ecc943a49e4553f0e7e1135b01"
  },
  "signature": {
    "publicKey": "83e91c8cf692365efd9a99a5efbd0afcc3d93a1e88e9bfe7d5219f9f5cf50cb785dd8c9727a1618a92100e28d47f7bf1",
    "signature": "b4aaccade020f47abef8b3513bb2967aadf5a0b7a5bdfb238d91a6c56c01d6911c1dcc1c0158e58eca6cc006a3f3e3750f3ddc9a3fa8a5091c9e3a5a7cd02e40d632d57747c8fca3f2b46b8c1415e54d4bc8e367e4b78ad5a25403571f3e8a6f"
  },
  "time": 1749643857253846,
  "createdHeight": 196596,
  "fee": 10000,
  "networkID": 1,
  "chainID": 1
}

Txn Edit Order

Route: /v1/admin/tx-edit-order

Description: generates/submits an edit (sell) order transaction. Note: can only go through. if order is not yet 'locked' by a buyer

HTTP Method: POST

Request:

  • address: hex-string - the address that originally created the sell order
  • receiveAddress: hex-string - the address that is receiving the 'counter-asset' funds
  • committees: string - the id of the committee that is responsible for the 'counter asset'
  • orderId: hex-string - the unique id of the sell-order
  • amount: uint64 - the amount of 'root-chain-asset' to lock in escrow to be swapped in smallest denomination
  • receiveAmount: uint64 - the amount of 'counter-asset' to receive in smallest denomination
  • data: hex-string - an arbitrary string code associated with the order (can be used for sub-asset contract address)
  • fee: uint64 - the transaction fee in micro denomination (optional - minimum fee filled if 0)
  • memo: string - an arbitrary message encoded in the transaction
  • submit: bool - submit this transaction or not (returns the tx-hash if true)
  • password: string - the password associated to decrypt the private key to sign the transaction

Response: (See tx-by-hash and MessageEditOrder)

text
$ curl -X POST http://localhost:50003/v1/admin/tx-edit-order \
  -H "Content-Type: application/json" \
  -d '{
    "address":"abb4a45ca70104ecc943a49e4553f0e7e1135b01",
    "committees":"1",
    "orderId":"1516f1cdd23f7e9f89e13a96ddf86351775f130f",
    "amount":100000000,
    "data": "0x...",
    "receiveAmount":101000000,
    "receiveAddress":"271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5",
    "memo":"",
    "fee":10000,
    "submit":false,
    "password":"test"
    }'

> {
  "type": "editOrder",
  "msg": {
    "orderID": "1516f1cdd23f7e9f89e13a96ddf86351775f130f",
    "chainID": 1,
    "data": "0x...",
    "amountForSale": 100000000,
    "requestedAmount": 101000000,
    "sellerReceiveAddress": "271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5"
  },
  "signature": {
    "publicKey": "83e91c8cf692365efd9a99a5efbd0afcc3d93a1e88e9bfe7d5219f9f5cf50cb785dd8c9727a1618a92100e28d47f7bf1",
    "signature": "a2e993ba9d1516f1cdd23f7e9f89e13a96ddf86351775f130f179495a0c15116c3aa786f513c4efe9471412865c93541089dd330c8064be5c34772140e46672b8d58df086b908cfa6847bdb6efe37dae3e3ed7872ddd28fc9e20b1f2dd7edb70"
  },
  "time": 1749644414876391,
  "createdHeight": 196596,
  "fee": 10000,
  "networkID": 1,
  "chainID": 1
}

Txn Delete Order

Route: /v1/admin/tx-delete-order

Description: generates/submits a delete (sell) order transaction. Note: can only go through. if order is not yet 'locked' by a buyer

HTTP Method: POST

Request:

  • address: hex-string - the address that originally created the sell order
  • committees: string - the id of the committee that is responsible for the 'counter asset'
  • orderId: hex-string - the unique id of the sell-order
  • fee: uint64 - the transaction fee in micro denomination (optional - minimum fee filled if 0)
  • memo: string - an arbitrary message encoded in the transaction
  • submit: bool - submit this transaction or not (returns the tx-hash if true)
  • password: string - the password associated to decrypt the private key to sign the transaction

Response: (See tx-by-hash and MessageDeleteOrder)

text
$ curl -X POST http://localhost:50003/v1/admin/tx-delete-order \
  -H "Content-Type: application/json" \
  -d '{
    "address":"abb4a45ca70104ecc943a49e4553f0e7e1135b01",
    "committees":"1",
    "orderId":"1516f1cdd23f7e9f89e13a96ddf86351775f130f",
    "memo":"",
    "fee":10000,
    "submit":false,
    "password":"test"
    }'

> {
  "type": "deleteOrder",
  "msg": {
    "orderID": "1516f1cdd23f7e9f89e13a96ddf86351775f130f",
    "chainID": 1
  },
  "signature": {
    "publicKey": "83e91c8cf692365efd9a99a5efbd0afcc3d93a1e88e9bfe7d5219f9f5cf50cb785dd8c9727a1618a92100e28d47f7bf1",
    "signature": "8043f0c6827aea8449a238811af800dec35cc78222cd3f3b0c830323c22902920f7b19d963d6ff76165bf3754f6dfb6504ddd20368b32169720880fd928e7ccbbfd628cd4c2c065c280fa51bc2d4b0b23d88fe9ffa6088b5d19e1b3e80463783"
  },
  "time": 1749644810582870,
  "createdHeight": 196596,
  "fee": 10000,
  "networkID": 1,
  "chainID": 1
}

Txn Dex Limit Order

Route: /v1/admin/tx-dex-limit-order

Description: generates/submits a DEX limit order transaction

HTTP Method: POST

Request:

  • address: hex-string - the from address
  • amount: uint64 - the amount to sell in smallest denomination
  • receiveAmount: uint64 - the amount to receive in smallest denomination
  • committees: string - the committee id of the counter asset
  • fee: uint64 - the transaction fee in micro denomination (optional - minimum fee filled if 0)
  • memo: string - an arbitrary message encoded in the transaction
  • submit: bool - submit this transaction or not (returns the tx-hash if true)
  • password: string - the password associated to decrypt the private key to sign the transaction

Response: (See tx-by-hash and MessageDexLimitOrder)

text
$ curl -X POST http://localhost:50003/v1/admin/tx-dex-limit-order \
  -H "Content-Type: application/json" \
  -d '{
    "address":"b0b4a45ca70104ecc943a49e4553f0e7e1135b01",
    "amount": 1000000,
    "receiveAmount": 2000000,
    "committees":"1",
    "fee":0,
    "submit":false,
    "password":"test"
    }'
  
> {
  "type": "dexLimitOrder",
  "msg": {
    "chainID": 1,
    "amountForSale": 1000000,
    "requestedAmount": 2000000,
    "sellerReceiveAddress": "b0b4a45ca70104ecc943a49e4553f0e7e1135b01"
  },
  "signature": {
    "publicKey": "83e91c8cf692365efd9a99a5efbd0afcc3d93a1e88e9bfe7d5219f9f5cf50cb785dd8c9727a1618a92100e28d47f7bf1",
    "signature": "835dfa9e5a370233369d1e955620a1512f9a5c31702e718e52d6cc60f40a91a0f142ae8e35c1dadd3213b17f881fbe6413c64103e27a7336296d963daf9a6e91cc9625d470248db009a9cde63c55cb6f4282f96b936bde547756e85e9ed84bb5"
  },
  "time": 1749644810582870,
  "createdHeight": 196596,
  "fee": 10000,
  "networkID": 1,
  "chainID": 1
}

Txn Dex Liquidity Deposit

Route: /v1/admin/tx-dex-liquidity-deposit

Description: generates/submits a DEX liquidity deposit transaction

HTTP Method: POST

Request:

  • address: hex-string - the from address
  • amount: uint64 - the amount to deposit in smallest denomination
  • committees: string - the committee id of the counter asset
  • fee: uint64 - the transaction fee in micro denomination (optional - minimum fee filled if 0)
  • memo: string - an arbitrary message encoded in the transaction
  • submit: bool - submit this transaction or not (returns the tx-hash if true)
  • password: string - the password associated to decrypt the private key to sign the transaction

Response: (See tx-by-hash and MessageDexLiquidityDeposit)

text
$ curl -X POST http://localhost:50003/v1/admin/tx-dex-liquidity-deposit \
  -H "Content-Type: application/json" \
  -d '{
    "address":"b0b4a45ca70104ecc943a49e4553f0e7e1135b01",
    "amount": 1000000,
    "committees":"1",
    "fee":0,
    "submit":false,
    "password":"test"
    }'
  
> {
  "type": "dexLiquidityDeposit",
  "msg": {
    "chainID": 1,
    "amount": 1000000,
    "address": "b0b4a45ca70104ecc943a49e4553f0e7e1135b01"
  },
  "signature": {
    "publicKey": "83e91c8cf692365efd9a99a5efbd0afcc3d93a1e88e9bfe7d5219f9f5cf50cb785dd8c9727a1618a92100e28d47f7bf1",
    "signature": "835dfa9e5a370233369d1e955620a1512f9a5c31702e718e52d6cc60f40a91a0f142ae8e35c1dadd3213b17f881fbe6413c64103e27a7336296d963daf9a6e91cc9625d470248db009a9cde63c55cb6f4282f96b936bde547756e85e9ed84bb5"
  },
  "time": 1749644810582870,
  "createdHeight": 196596,
  "fee": 10000,
  "networkID": 1,
  "chainID": 1
}

Txn Dex Liquidity Withdraw

Route: /v1/admin/tx-dex-liquidity-withdraw

Description: generates/submits a DEX liquidity withdraw transaction

HTTP Method: POST

Request:

  • address: hex-string - the from address
  • percent: int - the percentage of liquidity to withdraw (1-100)
  • committees: string - the committee id of the counter asset
  • fee: uint64 - the transaction fee in micro denomination (optional - minimum fee filled if 0)
  • memo: string - an arbitrary message encoded in the transaction
  • submit: bool - submit this transaction or not (returns the tx-hash if true)
  • password: string - the password associated to decrypt the private key to sign the transaction

Response: (See tx-by-hash and MessageDexLiquidityWithdraw)

text
$ curl -X POST http://localhost:50003/v1/admin/tx-dex-liquidity-withdraw \
  -H "Content-Type: application/json" \
  -d '{
    "address":"b0b4a45ca70104ecc943a49e4553f0e7e1135b01",
    "percent": 50,
    "committees":"1",
    "fee":0,
    "submit":false,
    "password":"test"
    }'
  
> {
  "type": "dexLiquidityWithdraw",
  "msg": {
    "chainID": 1,
    "percent": 50,
    "address": "b0b4a45ca70104ecc943a49e4553f0e7e1135b01"
  },
  "signature": {
    "publicKey": "83e91c8cf692365efd9a99a5efbd0afcc3d93a1e88e9bfe7d5219f9f5cf50cb785dd8c9727a1618a92100e28d47f7bf1",
    "signature": "835dfa9e5a370233369d1e955620a1512f9a5c31702e718e52d6cc60f40a91a0f142ae8e35c1dadd3213b17f881fbe6413c64103e27a7336296d963daf9a6e91cc9625d470248db009a9cde63c55cb6f4282f96b936bde547756e85e9ed84bb5"
  },
  "time": 1749644810582870,
  "createdHeight": 196596,
  "fee": 10000,
  "networkID": 1,
  "chainID": 1
}

Txn Lock Order (Nested-Chain Only)

Route: /v1/admin/tx-lock-order

Description: generates/submits a lock (sell) order transaction.

Notes:

  1. Can only go through if order is not yet 'locked' by a buyer.
  2. This transaction is executed on the nested-chain but is reported back to the root-chain by the committee
  3. This is only for nested chains trying to lock an order based on the root-chain
  4. Embeds a 'lock order' command in a standard self-send transaction - this is a good model of how this could work in most chains like Ethereum or Bitcoin but can be Nested-Chain specific.
  5. The default for Canopy chains carries a fee of 2x the Send Fee for extra spam protection on locks

HTTP Method: POST

Request:

  • address: hex-string - the address that is sending the nested-chain 'counter-asset'
  • receiveAddress: hex-string - the address on the root-chain that is receiving the sell order funds
  • orderId: hex-string - the unique id of the sell-order on the root-chain
  • fee: uint64 - the transaction fee in micro denomination (optional - minimum fee filled if 0)
  • submit: bool - submit this transaction or not (returns the tx-hash if true)
  • password: string - the password associated to decrypt the private key to sign the transaction

Response: (See tx-by-hash and MessageSend)

text
$ curl -X POST http://localhost:50003/v1/admin/tx-lock-order \
  -H "Content-Type: application/json" \
  -d '{
    "address":"271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5","receiveAddress":"abb4a45ca70104ecc943a49e4553f0e7e1135b01","orderId":"1516f1cdd23f7e9f89e13a96ddf86351775f130f",
    "fee":0,
    "submit":false,
    "password":"test"
    }'
  
> {
  "type": "send",
  "msg": {
    "fromAddress": "271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5",
    "toAddress": "271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5",
    "amount": 1
  },
  "signature": {
    "publicKey": "83e91c8cf692365efd9a99a5efbd0afcc3d93a1e88e9bfe7d5219f9f5cf50cb785dd8c9727a1618a92100e28d47f7bf1",
    "signature": "835dfa9e5a370233369d1e955620a1512f9a5c31702e718e52d6cc60f40a91a0f142ae8e35c1dadd3213b17f881fbe6413c64103e27a7336296d963daf9a6e91cc9625d470248db009a9cde63c55cb6f4282f96b936bde547756e85e9ed84bb5"
  },
  "time": 1749645076176475,
  "createdHeight": 196596,
  "fee": 20000,
  "memo": "{\"orderId\":\"1516f1cdd23f7e9f89e13a96ddf86351775f130f\",\"chain_id\":2,\"buyerSendAddress\":\"271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5\",\"buyerReceiveAddress\":\"abb4a45ca70104ecc943a49e4553f0e7e1135b01\"}",
  "networkID": 1,
  "chainID": 2
}

Txn Close Order (Nested-Chain Only)

Route: /v1/admin/tx-close-order

Description: generates/submits a close (sell) order transaction.

Notes:

  1. Can only go through if order is already 'locked' by this sender as the buyer.
  2. This transaction is executed on the nested-chain but is reported back to the root-chain by the committee
  3. This is only for nested chains trying to lock an order based on the root-chain
  4. Embeds a 'lock order' command in a standard self-send transaction - this is a good model of how this could work in most chains like Ethereum or Bitcoin but can be Nested-Chain specific.
  5. The default for Canopy chains carries a fee of 2x the Send Fee for extra spam protection on closes

HTTP Method: POST

Request:

  • address: hex-string - the address that is sending the nested-chain 'counter-asset'
  • orderId: hex-string - the unique id of the sell-order on the root-chain
  • fee: uint64 - the transaction fee in micro denomination (optional - minimum fee filled if 0)
  • submit: bool - submit this transaction or not (returns the tx-hash if true)
  • password: string - the password associated to decrypt the private key to sign the transaction

Response: (See tx-by-hash and MessageSend)

text
$ curl -X POST http://localhost:50003/v1/admin/tx-close-order \
  -H "Content-Type: application/json" \
  -d '{
    "address":"271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5","orderId":"1516f1cdd23f7e9f89e13a96ddf86351775f130f",
    "fee":0,
    "submit":false,
    "password":"test"
  }'
  
> {
  "type": "send",
  "msg": {
    "fromAddress": "271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5",
    "toAddress": "271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5",
    "amount": 1
  },
  "signature": {
    "publicKey": "83e91c8cf692365efd9a99a5efbd0afcc3d93a1e88e9bfe7d5219f9f5cf50cb785dd8c9727a1618a92100e28d47f7bf1",
    "signature": "835dfa9e5a370233369d1e955620a1512f9a5c31702e718e52d6cc60f40a91a0f142ae8e35c1dadd3213b17f881fbe6413c64103e27a7336296d963daf9a6e91cc9625d470248db009a9cde63c55cb6f4282f96b936bde547756e85e9ed84bb5"
  },
  "time": 1749645076176475,
  "createdHeight": 196596,
  "fee": 20000,
  "memo": "{\"orderId\":\"1516f1cdd23f7e9f89e13a96ddf86351775f130f\",\"chain_id\":2,\"closeOrder\":\true"}",
  "networkID": 1,
  "chainID": 2
}

Txn Subsidy

Route: /v1/admin/tx-subsidy

Description: generates/submits a subsidy transaction.

HTTP Method: POST

Request:

  • address: hex-string - the address that is sending the funds
  • id: uint64 - the id of the pool being subsidized
  • amount: hex-string - the amount being sent in micro denominiation
  • opcode: hex-string - an arbitrary instruction code that may be embedded in the message
  • fee: uint64 - the transaction fee in micro denomination (optional - minimum fee filled if 0)
  • submit: bool - submit this transaction or not (returns the tx-hash if true)
  • password: string - the password associated to decrypt the private key to sign the transaction

Response: (See tx-by-hash and MessageSubsidy)

text
$ curl -X POST http://localhost:50003/v1/admin/tx-subsidy \
  -H "Content-Type: application/json" \
  -d '{
    "address":"271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5",
    "amount": 1000,
    "id":"1",
    "fee":0,
    "submit":false,
    "password":"test"
  }'
  
> {
  "type": "subsidy",
  "msg": {
    "address": "271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5",
    "chainID": 0,
    "amount": 1000,
    "opcode": ""
  },
  "signature": {
    "publicKey": "83e91c8cf692365efd9a99a5efbd0afcc3d93a1e88e9bfe7d5219f9f5cf50cb785dd8c9727a1618a92100e28d47f7bf1",
    "signature": "b4d2793972505d56381c407a99c4d2bd05848ec433c4ce53f558ea8a2ad4014c657b46c056e5519a43fe4c322aaa227011f2199c314b0c8a4e29f850e092449ebbf5d9ee94984d96266b8b2246b2eaa1b720a046eff16e97636196bf707074ce"
  },
  "time": 1749647821374907,
  "createdHeight": 65,
  "fee": 10000,
  "networkID": 1,
  "chainID": 1
}

Txn Start Poll

Route: /v1/admin/tx-start-poll

Description: generates/submits a start on-chain poll transaction.

Note: Embeds a 'start-poll' command in a standard self-send transaction - this is a good model of how this could work in most chains like Ethereum or Bitcoin but can be Nested-Chain specific.

HTTP Method: POST

Request:

  • address: hex-string - the address that is initiating the poll
  • pollJSON: json string - the poll json object (proposal, endBlock, url)
  • fee: uint64 - the transaction fee in micro denomination (optional - minimum fee filled if 0)
  • submit: bool - submit this transaction or not (returns the tx-hash if true)
  • password: string - the password associated to decrypt the private key to sign the transaction

Response: (See tx-by-hash and MessageSend) with poll embedded in the memo

text
$ curl -X POST http://localhost:50003/v1/admin/tx-start-poll \
  -H "Content-Type: application/json" \
  -d '{
    "address":"271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5",
    "pollJSON":{"proposal":"canopy network is the best","endBlock":100,"URL":"https://discord.com/link-to-thread"},
    "password":"test",
    "submit":false
    }'
  
> {
  "type": "send",
  "msg": {
    "fromAddress": "271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5",
    "toAddress": "271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5",
    "amount": 1
  },
  "signature": {
    "publicKey": "83e91c8cf692365efd9a99a5efbd0afcc3d93a1e88e9bfe7d5219f9f5cf50cb785dd8c9727a1618a92100e28d47f7bf1",
    "signature": "8e154daa1909ec4b3a60df1f0b7f222c226be0b9057d243eb7ba6979447832b78535980324b564cd880086109db4e09c0c24b04a6aa2ebd883f78a4e05412334fe5f45652a0405e613c7d71a4118e2e4e865c19f47f06177fc1773c9410e0dac"
  },
  "time": 1749646707973281,
  "createdHeight": 10,
  "fee": 10000,
  "memo": "{\"startPoll\":\"04729495295b8fb37cd82562d0876afc838637daf2024670bc49a8b241926661\",\"url\":\"https://discord.com/link-to-thread\",\"endHeight\":100}",
  "networkID": 1,
  "chainID": 1
}

Txn Vote Poll

Route: /v1/admin/tx-vote-poll

Description: generates/submits a vote on-chain poll transaction.

Note: Embeds a 'vote-poll' command in a standard self-send transaction - this is a good model of how this could work in most chains like Ethereum or Bitcoin but can be Nested-Chain specific.

HTTP Method: POST

Request:

  • address: hex-string - the address that is initiating the poll
  • pollJSON: json string - the poll json object (proposal, endBlock, url)
  • pollApprove: bool - vote yes or not on the poll
  • fee: uint64 - the transaction fee in micro denomination (optional - minimum fee filled if 0)
  • submit: bool - submit this transaction or not (returns the tx-hash if true)
  • password: string - the password associated to decrypt the private key to sign the transaction

Response: (See tx-by-hash and MessageSend) with poll vote embedded in the memo

text
$ curl -X POST http://localhost:50003/v1/admin/tx-vote-poll \
  -H "Content-Type: application/json" \
  -d '{
    "address":"271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5",
    "pollJSON":{"proposal":"canopy network is the best","endBlock":100,"URL":"https://discord.com/link-to-thread"},
    "pollApprove":true,
    "password":"test",
    "submit":false
    }'
  
> {
  "type": "send",
  "msg": {
    "fromAddress": "271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5",
    "toAddress": "271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5",
    "amount": 1
  },
  "signature": {
    "publicKey": "83e91c8cf692365efd9a99a5efbd0afcc3d93a1e88e9bfe7d5219f9f5cf50cb785dd8c9727a1618a92100e28d47f7bf1",
    "signature": "8b21bce5c260e556107647cc085174bc3353f022116005972655a7c3c2484a5b5b379bf949e4ef464fac3c8659090c5e188db778d29790612be91e537567725ebfad9e7257757e4a116f46bc21da404eed8910e965edc79679f87d6e93292d5d"
  },
  "time": 1749646925994608,
  "createdHeight": 21,
  "fee": 10000,
  "memo": "{\"votePoll\":\"04729495295b8fb37cd82562d0876afc838637daf2024670bc49a8b241926661\",\"approve\":true}",
  "networkID": 1,
  "chainID": 1

Txn DAO Transfer

Route: /v1/admin/tx-dao-transfer

Description: generates/submits a dao transfer transaction. Note: this transaction type is a proposal and requires approval from +2/3rds of the validator stake

HTTP Method: POST

Request:

  • address: hex-string - the address where the funds will be received
  • amount: uint64 - the amount requested from the DAO
  • fee: uint64 - the transaction fee in micro denomination (optional - minimum fee filled if 0)
  • startHeight: uint64 - is the beginning height where the transaction must. be sent, this field locks in a block-range when it's converted to JSON, allowing Validators a deadline to vote, and creating a valid window when this transaction may be submitted
  • endHeight: uint64 - is the ending height counterpart to startHeight
  • memo: string - an arbitrary message encoded in the transaction
  • submit: bool - submit this transaction or not (returns the tx-hash if true)
  • password: string - the password associated to decrypt the private key to sign the transaction
  • signer: hex-string - the address associated with the key that is signing the transaction

Response: (See tx-by-hash and MessageDAOTransfer)

text
$ curl -X POST http://localhost:50003/v1/admin/tx-dao-transfer \
  -H "Content-Type: application/json" \
  -d '{
    "address":"abb4a45ca70104ecc943a49e4553f0e7e1135b01",
    "amount":100000000,
    "startBlock":1,
    "endBlock":100,
    "memo":"hello world",
    "fee":0,
    "submit":false,
    "password":"test"
    }'

> {
  "type": "daoTransfer",
  "msg": {
  "address": "abb4a45ca70104ecc943a49e4553f0e7e1135b01",
  "amount": 1000000000,
  "startHeight": 1,
  "endHeight": 100
  },
  "signature": {
  "publicKey": "8cb57bdcc0f90c36aea48a6edab31996400af55f623f676a3c64c04b826454aea227f14d1b70c150d5fa9fe5f6790f60",
  "signature": "a0473e839b23abc7d8448de5c58141827d86157263deaa79db0d9a1d1f0ffa9f7503c9ff52be7645b3ca0de50482651c1857d2af39c6953a68e386ca0901f668ef61dd706e4ed753548b5cb6737aceb06307e5894fbe49668fa2a1ff9036e971"
  },
  "time": 1749642868861970,
  "createdHeight": 196596,
  "fee": 10000,
  "memo": "hello world",
  "networkID": 1,
  "chainID": 1
}

Txn Change Parameter

Route: /v1/admin/tx-change-param

Description: generates/submits a change parameter transaction. Note: this transaction type is a proposal and requires approval from +2/3rds of the validator stake

HTTP Method: POST

Request:

  • address: hex-string - the address where the funds will be received
  • paramSpace: string - the sub-space where the parameter exists (fee, val, cons, gov)
  • paramKey: string - the unique name of the parameter
  • paramValue: uint64/string - the updated value of the parameter
  • startHeight: uint64 - is the beginning height where the transaction must. be sent, this field locks in a block-range when it's converted to JSON, allowing Validators a deadline to vote, and creating a valid window when this transaction may be submitted
  • endHeight: uint64 - is the ending height counterpart to startHeight
  • fee: uint64 - the transaction fee in micro denomination (optional - minimum fee filled if 0)
  • memo: string - an arbitrary message encoded in the transaction
  • submit: bool - submit this transaction or not (returns the tx-hash if true)
  • password: string - the password associated to decrypt the private key to sign the transaction
  • signer: hex-string - the address associated with the key that is signing the transaction

Response: (See tx-by-hash and MessageChangeParameter)

text
$ curl -X POST http://localhost:50003/v1/admin/tx-change-param \
  -H "Content-Type: application/json" \
  -d '{
    "address":"abb4a45ca70104ecc943a49e4553f0e7e1135b01",
    "paramSpace":"fee",
    "paramKey":"sendFee",
    "paramValue":"20000",
    "startBlock":1,
    "endBlock":100,
    "memo":"hello world",
    "fee":10000,
    "submit":false,
    "password":"test"
    }'

> {
  "type": "changeParameter",
  "msg": {
    "parameterSpace": "fee",
    "parameterKey": "sendFee",
    "parameterValue": 20000,
    "startHeight": 1,
    "endHeight": 100,
    "signer": "abb4a45ca70104ecc943a49e4553f0e7e1135b01"
  },
  "signature": {
    "publicKey": "8cb57bdcc0f90c36aea48a6edab31996400af55f623f676a3c64c04b826454aea227f14d1b70c150d5fa9fe5f6790f60",
    "signature": "882b6b3ede14a6ca6cc1a228c21f73ece1db2e4b28b51d10b3d2c3bac8bade80342a358cff65f496127803469438f9dd0d1c49c7231f0a4861ab45c6a9941e0724eba59afc8210dfd64acf05770375957a85a98ccecd798b349dc26125d6472b"
  },
  "time": 1749643492341200,
  "createdHeight": 196596,
  "fee": 10000,
  "memo": "hello world",
  "networkID": 1,
  "chainID": 1
}

Add Proposal Vote

Route: /v1/gov/add-vote

Description: configures local validator to vote yes or no on a proposal transaction when included in a block

HTTP Method: POST

Request:

  • approve: bool - approve the proposal or not
  • proposal: object - the proposal transaction

Response: Echo back the request

text
$ curl -X POST http://localhost:50003/v1/gov/add-vote \
  -H "Content-Type: application/json" \
  -d '{
  "approve": true,
  "proposal": {
    "type": "changeParameter",
    "msg": {
      "parameterSpace": "fee",
      "parameterKey": "sendFee",
      "parameterValue": 1000,
      "startHeight": 1,
      "endHeight": 100,
      "signer": "271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5"
    },
    "signature": {
      "publicKey": "83e91c8cf692365efd9a99a5efbd0afcc3d93a1e88e9bfe7d5219f9f5cf50cb785dd8c9727a1618a92100e28d47f7bf1",
      "signature": "b3ed9ba4988a1209af9871ebf086ff7d8ae81efc968144e65d9f37abecf51070c53e6d2bbbb9c91e79ea8de9ee4a1cda1611b908ecf6dd63625ef5fa6d048cb618d871cdf83cc93000b5126c3aa7fe658af8e3f71eb1e2860aa32fed6892dd7b"
    },
    "time": 1749647127495605,
    "createdHeight": 31,
    "fee": 10000,
    "networkID": 1,
    "chainID": 1
  }
}'
  
> {
  "approve": true,
  "proposal": {
    "type": "changeParameter",
    "msg": {
      "parameterSpace": "fee",
      "parameterKey": "sendFee",
      "parameterValue": 1000,
      "startHeight": 1,
      "endHeight": 100,
      "signer": "271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5"
    },
    "signature": {
      "publicKey": "83e91c8cf692365efd9a99a5efbd0afcc3d93a1e88e9bfe7d5219f9f5cf50cb785dd8c9727a1618a92100e28d47f7bf1",
      "signature": "b3ed9ba4988a1209af9871ebf086ff7d8ae81efc968144e65d9f37abecf51070c53e6d2bbbb9c91e79ea8de9ee4a1cda1611b908ecf6dd63625ef5fa6d048cb618d871cdf83cc93000b5126c3aa7fe658af8e3f71eb1e2860aa32fed6892dd7b"
    },
    "time": 1749647127495605,
    "createdHeight": 31,
    "fee": 10000,
    "networkID": 1,
    "chainID": 1
  }
}

Remove Proposal Vote

Route: /v1/gov/del-vote

Description: removes a proposal vote from a local validator

HTTP Method: POST

Request:

  • proposal: object - the proposal transaction

Response: Echo back the request

text
$ curl -X POST http://localhost:50003/v1/gov/del-vote \
  -H "Content-Type: application/json" \
  -d '{
  "proposal": {
    "type": "changeParameter",
    "msg": {
      "parameterSpace": "fee",
      "parameterKey": "sendFee",
      "parameterValue": 1000,
      "startHeight": 1,
      "endHeight": 100,
      "signer": "271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5"
    },
    "signature": {
      "publicKey": "83e91c8cf692365efd9a99a5efbd0afcc3d93a1e88e9bfe7d5219f9f5cf50cb785dd8c9727a1618a92100e28d47f7bf1",
      "signature": "b3ed9ba4988a1209af9871ebf086ff7d8ae81efc968144e65d9f37abecf51070c53e6d2bbbb9c91e79ea8de9ee4a1cda1611b908ecf6dd63625ef5fa6d048cb618d871cdf83cc93000b5126c3aa7fe658af8e3f71eb1e2860aa32fed6892dd7b"
    },
    "time": 1749647127495605,
    "createdHeight": 31,
    "fee": 10000,
    "networkID": 1,
    "chainID": 1
  }
}'
  
> {
  "approve": false,
  "proposal": {
    "type": "changeParameter",
    "msg": {
      "parameterSpace": "fee",
      "parameterKey": "sendFee",
      "parameterValue": 1000,
      "startHeight": 1,
      "endHeight": 100,
      "signer": "271e0120ac7f11a6f60ba124b2b187eaf1e2e6f5"
    },
    "signature": {
      "publicKey": "83e91c8cf692365efd9a99a5efbd0afcc3d93a1e88e9bfe7d5219f9f5cf50cb785dd8c9727a1618a92100e28d47f7bf1",
      "signature": "b3ed9ba4988a1209af9871ebf086ff7d8ae81efc968144e65d9f37abecf51070c53e6d2bbbb9c91e79ea8de9ee4a1cda1611b908ecf6dd63625ef5fa6d048cb618d871cdf83cc93000b5126c3aa7fe658af8e3f71eb1e2860aa32fed6892dd7b"
    },
    "time": 1749647127495605,
    "createdHeight": 31,
    "fee": 10000,
    "networkID": 1,
    "chainID": 1
  }
}

Peer Info

Route: /v1/admin/peer-info

Description: gets the resource usage for the node

HTTP Method: GET

Request: none

Response:

  • id: object - the id of the this node as seen by peers
    • publicKey: hex-string - the peer-to-peer public key
    • netAddress: hex-string - the external net address as configured
    • peerMeta: object - the meta data about the peer
      • networkID: uint64 - the identifier of the network (1=mainnet, 2=testnet)
      • chainID: uint64 - the identifier of the chain (1=Canopy, 2=Canary)
  • numPeers: uint64 - the total number of peers
  • numInbound: uint64 - the total number of peers that dialed this node and connected
  • numOutbound: uint64 - the total number of peers that this node dialed and connected to
  • peers: array - the list of peers
    • address: object - the identifier of the peer
      • publicKey: hex-string - the peer-to-peer public key
      • netAddress: hex-string - the external net address as configured
      • peerMeta: object - the meta data about the peer
      • networkID: uint64 - the identifier of the network (1=mainnet, 2=testnet)
      • chainID: uint64 - the identifier of the chain (1=Canopy, 2=Canary)
    • isOutbound: bool - was this peer dialed or did this peer dial our node?
    • isValidator: bool - is this peer an active validator for our chainId?
    • isMustConnect: bool - must this node connect to this peer?
    • isTrusted: bool - is this peer trusted by configuration?
    • reputation: int - what is the reputation of this peer according to our node?
text
$ curl http://localhost:50003/v1/admin/peer-info
  
> {
  "id": {
    "publicKey": "b88a5928e54cbf0a36e0b98f5bcf02de9a9a1deba6994739f9160181a609f516eb702936a0cbf4c1f2e7e6be5b8272f2",
    "netAddress": "127.125.17.207",
    "peerMeta": {
      "networkID": 2,
      "chainID": 1
    }
  },
  "numPeers": 1,
  "numInbound": 0,
  "numOutbound": 1,
  "peers": [
    {
      "address": {
        "publicKey": "98d45087a99bcbfde91993502e77dde869d4485c3778fe46513958320da560823d56a0108f4cf3513393f4d561bc489b",
        "netAddress": "159.89.181.58:9001",
        "peerMeta": {
          "networkID": 2,
          "chainID": 1,
        }
      },
      "isOutbound": true,
      "isValidator": true,
      "isMustConnect": true,
      "isTrusted": false,
      "reputation": 10
    }
  ]
}

Peer Book

Route: /v1/admin/peer-book

Description: gets the peer address book for this local node

HTTP Method: GET

Request: none

Response: array - the list of peers in the book

  • address: object - the identifier of the peer
    • publicKey: hex-string - the peer-to-peer public key
    • netAddress: hex-string - the external net address as configured
    • peerMeta: object - the meta data about the peer
    • networkID: uint64 - the identifier of the network (1=mainnet, 2=testnet)
    • chainID: uint64 - the identifier of the chain (1=Canopy, 2=Canary)
  • consecutiveFailedDial: uint64 - how many consecutive failed dial attempts are there in churn management process?
text
$ curl http://localhost:50003/v1/admin/peer-book
  
> [
  {
    "address": {
      "publicKey": "abd45087acdbcbfde91993502e77dde869d4485c3778fe46513958320da56082fd56a0108f4cf3513393f4d561bf48eb",
      "netAddress": "132.23.81.38:9001",
      "peerMeta": {
        "networkID": 2,
        "chainID": 1,
      }
    },
    "consecutiveFailedDial": 0
  },
]

Consensus Info

Route: /v1/admin/consensus-info

Description: gets the consensus dump from this node (if a validator)

HTTP Method: GET

Request: none

Response:

  • isSyncing: bool - is the node syncing or not?
  • view: object - the current view of BFT
  • blockHash: hex-string - the hash of the proposal block (if any)
  • resultsHash: hex-string - the hash of the proposal results (if any)
  • locked: bool - is the node 'locked' on a proposal
  • address: hex-string - the address of this validator
  • publicKey: hex-string - the pubKey of this validator
  • proposerAddress: hex-string - the address of the current proposer
  • proposer: hex-string - the pubKey of the proposer
  • proposals: object - map[round] -> 'proposals' received from the Leader Validator(s)
  • partialQcs: object - double sign evidence
  • pacemakerVotes: object - view messages from the current ValidatorSet allowing the node to synchronize to the highest +2/3 seen Round
  • minimumPowerFor23Maj: uint64 - minimum amount of voting power needed to acheive a +2/3rds majority
  • votes: object - map[round] -> 'votes' received from Replica (non-leader) Validators
  • status: string - useful message about the current BFT status of the node
text
/* Detailed source-code truncated for AI context efficiency. */

Resource Usage

Route: /v1/admin/resource-usage

Description: gets the resource usage for the node

HTTP Method: GET

Request: none

Response: See below

text
$ curl http://localhost:50003/v1/admin/resource-usage
  
> {
  "process": {
    "name": "___go_build_github_com_canopy_network_canopy_cmd_cli",
    "status": "S",
    "createTime": "18 Feb 14 05:40 AST",
    "fdCount": 46,
    "threadCount": 22,
    "usedMemoryPercent": 4.719185829162598,
    "usedCPUPercent": 55.01593610361968
  },
  "system": {
    "totalRAM": 17179869184,
    "availableRAM": 5899804672,
    "usedRAM": 11280064512,
    "usedRAMPercent": 65.65861701965332,
    "freeRAM": 205660160,
    "usedCPUPercent": 7.31242895399022,
    "userCPU": 369023.99,
    "systemCPU": 140800.73,
    "idleCPU": 6470812.52,
    "totalDisk": 1000240963584,
    "usedDisk": 641660645376,
    "usedDiskPercent": 64.1506065775233,
    "freeDisk": 358580318208,
    "ReceivedBytesIO": 38328565621,
    "WrittenBytesIO": 9078489286
  }
}

Logs Stream

Route: /v1/admin/logs

Description: gets the stream of node logs (up to last log rotation)

HTTP Method: GET

Request: none

Response: See below

text
$ curl http://localhost:50003/v1/admin/log
  
> 
Jun 11 09:47:15.533 INFO: Self is the proposer
Jun 11 09:47:15.532 INFO: (rH:155, H:155, R:0, P:PROPOSE)
Jun 11 09:47:13.538 INFO: Voting SELF as the proposer
Jun 11 09:47:13.532 INFO: (rH:155, H:155, R:0, P:ELECTION_VOTE)
Jun 11 09:47:11.537 INFO: Self is a leader candidate 🗳️
Jun 11 09:47:11.531 INFO: (rH:155, H:155, R:0, P:ELECTION)
Jun 11 09:47:09.525 INFO: Reset BFT (NEW_COMMITTEE)
Jun 11 09:47:09.521 INFO: Reset BFT (NEW_HEIGHT)
...

Golang Profiling Debug

Route:

  • /debug/pprof
  • /debug/pprof/*name

Description: serves the Go pprof index and named pprof handlers. These routes are exposed on the profiling server bound to ProfilingPort, not the main RPC port. Available profiles can be found in net/http/pprof. See https://pkg.go.dev/net/http/pprof

HTTP Method: GET


File: cmd/auto-update/README.md

Canopy Auto-Update Package

This package implements an automatic update mechanism for the Canopy CLI application. It periodically checks for new releases and automatically updates the binary when available, ensuring users always have the latest version of the software.

Overview

The auto-update package provides a robust mechanism to:

  • Check for new releases on GitHub
  • Download and install updates automatically
  • Manage the running CLI process
  • Handle graceful updates without disrupting the user experience

Architecture

Flow of Operation

  1. Initialization and Configuration

    • The system starts by checking if auto-update is enabled in the configuration
    • Sets up necessary data directories and binary paths
    • Initializes thread-safe state management mechanisms
    • Creates communication channels for process coordination
  2. Version Check and Update Detection

    • Every 30 minutes, the system queries GitHub's API for the latest release
    • Compares the current version with the latest release
    • If a new version is found, sets a flag to prevent concurrent updates
    • The system identifies the appropriate platform-specific binary for the current OS/architecture
  3. Update Process

    • When a new version is detected, the system:
      1. Downloads the new binary while maintaining exclusive access
      2. Replaces the existing binary with proper permissions
      3. Adds a random delay (1-30 minutes) to prevent update storms
      4. Sets an update-in-progress flag to manage the update state
  4. Process Management

    • The system maintains two main goroutines:
      1. Process Manager: Handles the CLI process lifecycle
      2. Update Checker: Periodically checks for new versions
    • When an update is ready:
      1. Sends termination signal to the current process
      2. Waits for process termination
      3. Starts the new version
      4. Maintains process state and handles errors
  5. Thread Safety and Coordination

    • Uses atomic flags for state management:
      • Update-in-progress flag: Prevents process exit during updates
      • Update-detection flag: Prevents concurrent update handling
    • Implements mutex for binary file access
    • Uses buffered channels for process coordination:
      • Start signal channel: Signals process start
      • End signal channel: Signals process end

How It Works

  1. Initialization

    • Creates necessary data directories
    • Loads configuration
    • Sets up binary path
  2. Update Check Loop

    • Runs every 30 minutes
    • Fetches latest release from GitHub
    • Compares versions
    • Triggers update if needed
  3. Update Process

    • Downloads new binary
    • Adds random delay (1-30 minutes)
    • Gracefully terminates current process
    • Starts new version
    • Maintains process state
  4. Error Handling

    • Manages download failures
    • Handles process termination errors
    • Recovers from failed updates
    • Logs error conditions

Configuration

The auto-update mechanism can be enabled/disabled through the Canopy configuration:

json
{
    "autoUpdate": true
}

Environment Variables

  • BIN_PATH: Specifies the path to the CLI binary (defaults to "./cli")

Binary persistence

BIN_PATH is only ever read, never written to. It points at the binary shipped with the
build, which in a container lives on the ephemeral filesystem and is discarded whenever
the container is recreated.

Updates are downloaded to <data-dir>/canopy_updated instead, since the data directory
is the volume that persists across restarts. On every start, and on every restart after
an update, the coordinator runs <data-dir>/canopy_updated when it exists and is
executable, and falls back to BIN_PATH when it does not. Removing that file rolls the
node back to the version shipped with the image.

Plugin persistence

For the same reason, plugin artifacts are stored under the data directory rather than in
the image. The coordinator downloads (and pluginctl.sh extracts and runs) the plugin
from <data-dir>/plugin/<lang>, which is exported to the launcher as CANOPY_PLUGIN_HOME.
Only pluginctl.sh ships in the image; the downloaded binary/tarball live on the
persistent volume, so a restart reuses the already-downloaded plugin instead of
re-fetching it from GitHub. Removing that directory forces a fresh download on next start.

Dependencies

  • Go standard library
  • GitHub API for release information
  • Canopy core packages

Usage

For deployment examples, refer to the Dockerfile in the root of the repository. The Dockerfile demonstrates:

  • How to build the auto-update enabled binary
  • Proper environment setup
  • Required permissions
  • Volume mounting for persistence
  • Process management in a containerized environment

Example Dockerfile usage:

bash
# Build the image
docker build --build-arg BIN_PATH=./cli -t canopy .

# Run the container
docker run -it --env-file=.env -p 50000:50000 -p 50001:50001 -p 50002:50002 -p 50003:50003 -p 9001:9001 --name canopy canopy

File: controller/README.md


Package Controller

The Controller package serves as the central coordination hub for a Canopy blockchain node. It
orchestrates the interactions between various system components and manages the node's lifecycle
from initialization through operation to shutdown.

Overview

The Controller acts as a "bus" between the core modules of the Canopy blockchain:

  • Blockchain state management (FSM)
  • Transaction processing and mempool
  • Byzantine Fault Tolerant (BFT) consensus
  • Peer-to-peer networking
  • Root chain interactions

This package is responsible for ensuring these components work together seamlessly to maintain
blockchain consensus, process transactions, and communicate with peers and parent chains.

Core Components

[Controller Structure](controller.md)

The Controller contains references to all major subsystems and coordinates their interactions:

  • Node identity (address, keys)
  • Configuration settings
  • Core blockchain components (FSM, Mempool, Consensus, P2P)
  • Root chain management
  • Synchronization status
mermaid
graph TD
    Controller --> FSM[State Machine]
    Controller --> Mempool
    Controller --> Consensus
    Controller --> P2P
    Controller --> RootChain[Root Chain Info]

    P2P -- Messages --> Controller
    Consensus -- State Updates --> FSM
    Mempool -- Transactions --> Consensus
    RootChain -- Validator Info --> Consensus
    FSM -- Blockchain State --> Controller

[Block Processing System](block.md)

The block processing system handles how blocks are:

  • Received and validated from the network
  • Created during the proposal phase
  • Committed to the blockchain
  • Distributed to other nodes

This system ensures all nodes maintain consensus on the blockchain state through BFT consensus.

[Consensus Management](consensus.md)

The consensus management system:

  • Synchronizes nodes with the current blockchain state
  • Routes consensus messages between validators
  • Manages validator committees
  • Handles block requests and responses
  • Reports on consensus status

[Transaction System](tx.md)

The transaction system:

  • Processes locally generated transactions
  • Validates incoming transactions from peers
  • Maintains the mempool of pending transactions
  • Gossips valid transactions to peers
  • Tracks failed transactions for reporting

[Certificate Result System](result.md)

The Certificate Result system handles the post-consensus outcomes:

  • Calculates reward distributions to network participants
  • Processes cross-chain swap orders
  • Manages slashes for Byzantine behavior
  • Creates checkpoints for cross-chain verification
  • Tracks chain lifecycle status

Security Features

The Controller implements several security measures:

  • Thread safety through mutex locks and atomic operations
  • Byzantine Fault Tolerance for consensus security
  • Reputation system to penalize malicious or faulty peers
  • Rate limiting to prevent DoS attacks
  • Message signing and verification
  • VDF iteration verification to prevent unsafe forks
  • Cross-chain checkpointing for long-range attack prevention

Usage

The Controller is the primary entry point when initializing a Canopy blockchain node. After
configuration and initialization of the core components (FSM, P2P, etc.), the Controller's
Start() method begins node operation, which continues until Stop() is called.

The Controller interacts closely with several other major Canopy components which in turn interact
with each other at various levels:

  • FSM (Finite State Machine): Maintains blockchain state and processes transactions
  • BFT (Byzantine Fault Tolerance): Manages consensus between validators
  • P2P (Peer to Peer): Handles network communication between nodes
  • Crypto: Provides cryptographic primitives for security operations
  • Store: Persists blockchain data to disk storage

Together, these components form a complete blockchain node capable of participating in the Canopy network.