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
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:
make build/canopy-full
canopy startHow to Run It with 🐳 Docker
➪ To run a Canopy Localnet in a containerized environment, use the following commands:
make docker/build
make docker/up-fast
make docker/logs
or simply
make docker/up && make docker/logsRunning Tests
➪ To run Canopy unit tests, use the Go testing tools:
make testHow to Contribute
➪ Canopy is an open-source project, and we welcome contributions from the community. Here's how to get involved:
- Fork the repository and clone it locally.
- Code your improvements or fixes.
- 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
developmentbranch.
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.
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 --> BConsensus 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.jsonpublic/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
- User opens an action.
- Runtime loads action definition from
manifest.json. - Runtime resolves DS dependencies from
chain.json(ds.*calls). - Form is rendered dynamically from field config.
- Values are validated/coerced according to manifest rules.
- Payload is built declaratively.
- Request is submitted to the configured endpoint.
- 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,textareaamount,number,addressselect,advancedSelectswitch,option,optionCardtableSelectdynamicHtml- 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.
Modal Data Population and Prefill Model
When opening a dynamic action modal, data can come from multiple sources:
- action defaults (
field.value) - DS results (
ds.*) - runtime/session context (
account,chain,fees,session) - explicit
prefilledDatapassed 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 explicitautoPopulate: "always"keeps updating from DS.
Precedence and safety
prefilledDatais 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(orui.grid.colSpan) with breakpoints:base,sm,md,lg,xl
Example:
{
"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.
Modal responsiveness
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:
formdsaccountchainfeesparamssession
Payload fields can define coercion:
stringnumberboolean- 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, dynamicrequired, 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
prefilledDatafor edit workflows instead of hardcoding edit components. - Use
criticalDS 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.
Recommended Review Checklist
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.pathandpayloadalign 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:
<ActionModalProvider>
<RouterProvider router={router}/>
</ActionModalProvider>Usage
1. Import the hook
import { useActionModal } from '@/app/providers/ActionModalProvider';2. Use in your component
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 addressstake- Stake tokensunstake- Unstake tokenseditStake- Edit stake amountreceive- Show receive address
4. Setting the Selected Account
Before opening an action, make sure to set the correct account:
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:
- Import and use the hook
- Set the selected account before opening an action
- Handle callbacks (onFinish, onClose)
- Integrate with existing UI components
API Reference
`useActionModal()`
Returns an object with:
openAction(actionId: string, options?: ActionModalOptions)- Opens an action modalcloseAction()- Closes the current action modalisOpen: boolean- Whether a modal is currently opencurrentActionId: string | null- The ID of the currently open action
`ActionModalOptions`
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 backgroundbg-bg-tertiary- Button backgroundsborder-bg-accent- Borderstext-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.jsonandmanifest.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:
public/plugin/canopy/
├── chain.json # RPC endpoints, data sources, parameters
└── manifest.json # Transaction forms, UI definitions, actionsData Source (DS) Pattern
All API calls use a centralized DS system defined in chain.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
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
Clone the repository
bashgit clone <repository-url> cd canopy-walletInstall dependencies
bashnpm install # or pnpm installConfigure your node connection
Edit
public/plugin/canopy/chain.json:json{ "rpc": { "base": "http://your-node-ip:50002", "admin": "http://your-node-ip:50003" } }Copy environment file:
bashcp .env.example .envStart the development server
bashnpm run devOpen your browser
texthttp://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.jsonandmanifest.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:
const dsFetch = useDSFetcher();
const data = await dsFetch('admin.consensusInfo');Form Handling
Forms are generated dynamically from manifest configuration:
const { openAction } = useActionModal();
openAction('send'); // Opens send transaction formError Handling
Consistent error handling with user-friendly messages:
const { data, error, isLoading } = useQuery({
queryKey: ['nodeData'],
queryFn: () => dsFetch('admin.consensusInfo'),
retry: 2,
retryDelay: 1000,
});Adding New Features
- Define Data Sources: Add new DS endpoints in
chain.json - Create Hooks: Build custom hooks for data fetching
- Build Components: Create UI components using design system
- Add Actions: Define new transaction types in
manifest.json
Environment Variables
VITE_DEFAULT_CHAIN=canopy
VITE_CONFIG_MODE=embedded
VITE_NODE_ENV=development🛠️ Deployment
Production Build
npm run buildConfiguration for Production
- Update
chain.jsonwith production RPC endpoints - Configure proper CORS settings on your node
- Set appropriate session timeouts and security parameters
- Ensure SSL/TLS is configured for secure connections
Docker Deployment
The wallet can be deployed alongside Canopy nodes:
# 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 informationuseNodeData(): Node status and monitoring datauseValidators(): Validator information and staking datauseTransactions(): 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
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes following the existing patterns
- Add appropriate tests and documentation
- Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - 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
{
"chainId": "1",
"displayName": "Canopy",
"rpc": {
"base": "http://localhost:50002",
"admin": "http://localhost:50003"
},
"denom": {
"base": "ucnpy",
"symbol": "CNPY",
"decimals": 6
}
}Simple Transaction Action
{
"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:
# 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
# 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 previewThe 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:
# From project root
make build/walletThis is automatically called by the Dockerfile.
Manual Deployment
Build the wallet:
bashnpm run buildThe compiled assets will be embedded in the Go binary during the build process via
//go:embeddirectives.
Reverse Proxy Configuration
When deploying behind a reverse proxy (like Traefik), ensure the proxy is configured to strip the path prefix:
Example Traefik Configuration:
http:
middlewares:
strip-wallet-prefix:
stripPrefix:
prefixes:
- "/wallet"
forceSlash: false
routers:
wallet:
rule: "Host(`example.com`) && PathPrefix(`/wallet`)"
service: wallet
middlewares:
- strip-wallet-prefixThis 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:
- Verify
VITE_BASE_PATHmatches your deployment path - Ensure reverse proxy is configured to strip the path prefix
- 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
- Clone the repository and navigate to the project directory:
cd cmd/rpc/web/explorer- Install dependencies:
npm install- Ensure your Canopy blockchain node is running on port 50001:
# Your Canopy node should be accessible at:
# http://localhost:50001- Start the development server:
npm run dev- 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 servernpm run build- Build for productionnpm run preview- Preview production buildnpm run lint- Run ESLintnpm run type-check- Run TypeScript type checking
Project Structure
/* 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 datauseTransactions(page, height)- Fetch transactionsuseAccounts(page)- Fetch accountsuseValidators(page)- Fetch validatorsuseCommittee(page, chainId)- Fetch committee datauseDAO(height)- Fetch DAO datauseAccount(height, address)- Fetch account detailsuseParams(height)- Fetch parametersuseSupply(height)- Fetch supply datauseCardData()- Fetch dashboard card datauseTableData(page, category, committee)- Fetch table data- And many more...
Usage Example
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:
$ 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+/- 4320accepted - fee:
uint64the 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 (1for mainnet,2for testnet, ...) - chainID:
uint64- the unique identifier of the committee (1for canopy,2for canary, ...)
Response: hex string - the hash of the transaction
Example:
$ 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+/- 4320accepted - fee:
uint64the 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 (1for mainnet,2for testnet, ...) - chainID:
uint64- the unique identifier of the committee (1for canopy,2for canary, ...)
Response: array of hex strings - the hashes of the submitted transactions
Example:
$ 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::
$ curl -H "Content-Type: application/json" -X POST --data '{}' localhost:50002/v1/query/height
> 9157Indexer 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
- block:
- previous:
IndexerBlob- the indexer blob at the previous height (same structure as current, absent for heights ≤ 2)
Example:
$ 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 ofvestingAmountthat has vested at the queried height - lockedAmount:
uint64- the portion ofvestingAmountthat 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:
$ 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 stringthe 20 byte unique identifier of the account - amount: -
uint64the spendable balance in micro denomination - totalAmount: -
uint64the total recorded balance before vesting locks are applied - vestedAmount: -
uint64the vested portion of the vesting tranche at the queried height - lockedAmount: -
uint64the still-locked portion of the vesting tranche at the queried height - vestingAmount: -
uint64the total amount on the vesting schedule, omitted when zero - vestingStartHeight: -
uint64the height where vesting begins, omitted when zero - vestingCliffHeight: -
uint64the height where vesting first becomes spendable, omitted when zero - vestingEndHeight: -
uint64the height where vesting fully completes, omitted when zero
- address: -
- 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:
$ 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:
uint64the amount of points owned
- address:
- totalPoolPoints:
uint64- the sum of all pool points
Example:
$ 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: -
stringthe unique identifier of the pool - amount: -
uint64the 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:
uint64the amount of points owned
- address:
- id: -
- 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:
$ 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:
$ 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:
intonly 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
- address:
- 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:
$ 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
- publicKey:
Example:
$ 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
- address:
- numberOfSamples:
uint64- the total count of processed Certificate Result Transactions, used to normalize reward percentages accurately
Example:
$ 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
- address:
- numberOfSamples:
uint64- the total count of processed Certificate Result Transactions, used to normalize reward percentages accurately
- chainID:
Example:
$ 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:
$ 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:
$ 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:
$ 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)
- blockSize:
- 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 anonSignWindowbefore 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 minimumsell order amountin 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 asendFeerequired tolocka sell order on the root-chain - (applies only to the 'buyer-side' of token swaps)
- unstakingBlocks:
- fee:
object- the governance parameters listed under the fee params space- sendFee:
uint64- the minimum fee in micro denomination needed to execute asendtransaction - stakeFee:
uint64- the minimum fee in micro denomination needed to execute astaketransaction - editStakeFee:
uint64- the minimum fee in micro denomination needed to execute aeditStaketransaction - pauseFee:
uint64- the minimum fee in micro denomination needed to execute apausetransaction - unpauseFee:
uint64- the minimum fee in micro denomination needed to execute aunpausetransaction - changeParameterFee:
uint64- the minimum fee in micro denomination needed to execute achangeParametertransaction - daoTransferFee:
uint64- the minimum fee in micro denomination needed to execute adaoTransfertransaction - certificateResultsFee:
uint64- the minimum fee in micro denomination needed to execute acertificateResultstransaction - subsidyFee:
uint64- the minimum fee in micro denomination needed to execute asubsidytransaction - createOrderFee:
uint64- the minimum fee in micro denomination needed to execute acreateOrdertransaction - editOrderFee:
uint64- the minimum fee in micro denomination needed to execute aeditOrdertransaction - deleteOrderFee:
uint64- the minimum fee in micro denomination needed to execute adeleteOrdertransaction
- sendFee:
- 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
- daoRewardPercentage:
Example:
$ 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
- id:
- 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
- id:
Example:
$ 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 asendtransaction - stakeFee:
uint64- the minimum fee in micro denomination needed to execute astaketransaction - editStakeFee:
uint64- the minimum fee in micro denomination needed to execute aeditStaketransaction - pauseFee:
uint64- the minimum fee in micro denomination needed to execute apausetransaction - unpauseFee:
uint64- the minimum fee in micro denomination needed to execute aunpausetransaction - changeParameterFee:
uint64- the minimum fee in micro denomination needed to execute achangeParametertransaction - daoTransferFee:
uint64- the minimum fee in micro denomination needed to execute adaoTransfertransaction - certificateResultsFee:
uint64- the minimum fee in micro denomination needed to execute acertificateResultstransaction - subsidyFee:
uint64- the minimum fee in micro denomination needed to execute asubsidytransaction - createOrderFee:
uint64- the minimum fee in micro denomination needed to execute acreateOrdertransaction - editOrderFee:
uint64- the minimum fee in micro denomination needed to execute aeditOrdertransaction - deleteOrderFee:
uint64- the minimum fee in micro denomination needed to execute adeleteOrdertransaction
Example:
$ 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:
$ 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 anonSignWindowbefore 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 minimumsell order amountin 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 asendFeerequired tolocka sell order on the root-chain - (applies only to the 'buyer-side' of token swaps)
Example:
$ 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:
$ 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:
$ 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- seePoolsresponse - accounts:
array- seeAccountsresponse - nonSigners:
object- seeNon-Signersresponse - validators:
array- seeValidator-Setresponse - params:
object- seeParamsresponse - supply:
object- seeSupplyresponse - orderBooks:
array- seeorder-booksresponse
Example:
$ 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-useheight-1)
Response:
- state:
object- seeStatebut with diff highlights (ex."amount": 25257333001 <- 25206666335)
Example:
VIEW IN BROWSER: http://localhost:50002/v1/query/state-diff?height=1000&startHeight=998
{
"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-useheight-1)
Response:
- state:
object- seeStatebut with diff highlights (ex."amount": 18239045002 => 18202565004)
$ 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)
- height:
- 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
- address:
- 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
- id:
- doubleSigners:
- 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
- orderId:
- 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
- lockOrders:
- 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
- height:
- retired:
boolean- signals if the committee wants to shut down and mark itself as 'forever unsubsidized' on the root-chain
- paymentPercents:
- rewardRecipients:
- 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
- signature:
/* 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)
- proof:
- 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 (Seecert-by-heightresponse above)
- height:
- transactions:
array- list of transactions in the block (seetx-by-hash)
- blockHeader:
- 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
/* 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)
- proof:
- 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 (Seecert-by-heightresponse above)
- height:
- transactions:
array- list of transactions in the block (seetx-by-hash)
/* 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)
- proof:
- 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 (Seecert-by-heightresponse above)
- height:
- transactions:
array- list of transactions in the block (seetx-by-hash)
/* 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
- reward:
- 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
- eventType:
- 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
$ 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
- reward:
- 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
- eventType:
- 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
$ 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
- reward:
- 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
- eventType:
- 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
$ 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. (Seetx-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
- messageType:
- txHash:
hex-string- the unique hash that identifies the transaction
- sender:
- blockHeader:
- 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
$ 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. (Seetx-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
- messageType:
- txHash:
hex-string- the unique hash that identifies the transaction
- sender:
- blockHeader:
- 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
$ 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. (Seetx-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
- messageType:
- txHash:
hex-string- the unique hash that identifies the transaction
- sender:
- blockHeader:
- 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
$ 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-truewhen the transaction has been included in a block orfalsewhen it is still in the mempool - height:
uint64- the committed block height, or the candidate block height whencommittedisfalse - index:
uint64- the committed transaction position, or the candidate position whencommittedisfalse - 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)
- fromAddress:
- 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
- publicKey:
- 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
- address:
- messageUnstake:
- address:
hex string- the identifier linked to the Validator structure
- address:
- messagePause:
- address:
hex string- the identifier linked to the Validator structure
- address:
- messageUnpause:
- address:
hex string- the identifier linked to the Validator structure
- address:
- 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
- parameterSpace:
- 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
- address:
- 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
- address:
- messageCertificateResult:
- qc:
object- seecert-by-height
- qc:
- 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
- chainID:
- 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
- orderID:
- messageDeleteOrder:
- orderID:
hex string- identifier of the order to delete - chainID:
uint64- committee responsible for the order
- orderID:
- messageSend:
- 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
- messageType:
- txHash:
hex-string- the unique hash that identifies the transaction
$ 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
$ 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
- id:
- 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
$ 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
$ 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)
- amountForSale:
- 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)
- amount:
- 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)
- percent:
- poolPoints:
array- a list of pool points- address:
hex-string- the recipient address of the points - points:
uint64the amount of points owned
- address:
- 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
$ 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)
- amountForSale:
- 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)
- amount:
- 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)
- percent:
- poolPoints:
array- a list of pool points- address:
hex-string- the recipient address of the points - points:
uint64the amount of points owned
- address:
- 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
$ 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)
$ 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. (Seetx-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
- messageType:
- txHash:
hex-string- the unique hash that identifies the transaction
- sender:
- blockHeader:
- 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
$ 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. (Seetx-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
- messageType:
- txHash:
hex-string- the unique hash that identifies the transaction
- sender:
- 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
- code:
- blockHeader:
- 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
$ 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 isoneOf:MessageChangeParameterorMessageDAOTransfersee (see tx-by-hash) - approve:
bool- is the local Validator voting yes or no on the proposal
- proposal:
$ 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
- approveTokens:
- 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
- approveTokens:
- approve:
bool- is the local Validator voting yes or no on the proposal
- proposalHash:
$ 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
- publicKey:
- validatorSet:
- 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
- winner:
- 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
- id:
- chainId:
$ 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
$ 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
$ curl -X POST localhost:50002/v1/query/valid-double-signer \
-H "Content-Type: application/json" \
-d '{
"height": 17585,
"address": "b9c6c2dfa9d049e480c8cec9c29463abf078a594"
}'
>trueDouble 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
- id:
$ 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
$ curl -X POST localhost:50002/v1/query/minimum-evidence-height \
-H "Content-Type: application/json" \
-d '{}'
> 165453Lottery
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
$ 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
$ 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
$ 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)
$ 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
- publicKey:
- nicknameMap:
objectthe map of nicknames to address[nickname] -> hex-address
$ 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
$ 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
$ 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
$ 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
$ 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
$ 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)
$ 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)
$ 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)
$ 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)
$ 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)
$ 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)
$ 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)
$ 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)
$ 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)
$ 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)
$ 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)
$ 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)
$ 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:
- Can only go through if order is not yet 'locked' by a buyer.
- This transaction is executed on the nested-chain but is reported back to the root-chain by the committee
- This is only for nested chains trying to lock an order based on the root-chain
- 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-Chainspecific. - 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 thesell orderfunds - 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)
$ 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:
- Can only go through if order is already 'locked' by this sender as the buyer.
- This transaction is executed on the nested-chain but is reported back to the root-chain by the committee
- This is only for nested chains trying to lock an order based on the root-chain
- 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-Chainspecific. - 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)
$ 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)
$ 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
$ 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
$ 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": 1Txn 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 tostartHeight - 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)
$ 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 tostartHeight - 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)
$ 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
$ 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
$ 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)
- networkID:
- publicKey:
- 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)
- publicKey:
- 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?
- address:
$ 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)
- publicKey:
- consecutiveFailedDial:
uint64- how many consecutive failed dial attempts are there in churn management process?
$ 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
/* 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
$ 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
$ 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
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
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
Update Process
- When a new version is detected, the system:
- Downloads the new binary while maintaining exclusive access
- Replaces the existing binary with proper permissions
- Adds a random delay (1-30 minutes) to prevent update storms
- Sets an update-in-progress flag to manage the update state
- When a new version is detected, the system:
Process Management
- The system maintains two main goroutines:
- Process Manager: Handles the CLI process lifecycle
- Update Checker: Periodically checks for new versions
- When an update is ready:
- Sends termination signal to the current process
- Waits for process termination
- Starts the new version
- Maintains process state and handles errors
- The system maintains two main goroutines:
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
- Uses atomic flags for state management:
How It Works
Initialization
- Creates necessary data directories
- Loads configuration
- Sets up binary path
Update Check Loop
- Runs every 30 minutes
- Fetches latest release from GitHub
- Compares versions
- Triggers update if needed
Update Process
- Downloads new binary
- Adds random delay (1-30 minutes)
- Gracefully terminates current process
- Starts new version
- Maintains process state
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:
{
"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:
# 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 canopyFile: 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
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'sStart() method begins node operation, which continues until Stop() is called.
Related Components
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.