Documentation
How the DAML VM works, what it supports, what's different from Canton, and the complete JSON-RPC API reference.
ava-labs/avalanche-canton(private)How the VM Works
This is a custom AvalancheGo Virtual Machine that implements the block.ChainVM interface (Snowman linear-chain consensus). It runs as an rpcchainvmplugin — a separate process that communicates with AvalancheGo over gRPC. The VM is written entirely in Go.
The VM has two execution paths for DAML contracts:
JSON Templates
Templates defined as JSON objects with typed fields, signatory/observer declarations, and declarative choice effects. Write DAML-like syntax in the browser editor, compile client-side, deploy via registerTemplate. Choice bodies use field mappings (this.field, arg.param) to create new contracts.
DAML-LF Bytecode
Upload .dar files compiled by the official damlc compiler (DAML SDK 3.4+). The VM parses the protobuf archive, extracts DAML-LF v1 and v2 packages, and registers templates with their full choice expressions. A Go-based DAML-LF interpreter evaluates choice bodies at runtime.
Blocks are produced through Avalanche's Snowman consensus. The VM implements WaitForEvent to notify the engine when transactions arrive, BuildBlock to assemble transactions into blocks, and Verify/Accept/Rejectfor the full block lifecycle. State is persisted to LevelDB via AvalancheGo's database interface.
DAML Compatibility
The VM implements the core DAML ledger model. Here's what's supported and what's not:
What works
- ✓Templates — with typed fields, signatories, observers
- ✓Choices — consuming and non-consuming, with controllers and parameters
- ✓Authorization model — signatory/controller checks, authority expansion through choice bodies
- ✓DAML-LF parsing — v1 and v2 protobuf archives from damlc build
- ✓Expression evaluator — variables, records, lists, lambdas, let bindings, case/match, 20+ builtins
- ✓Update monad — Create, Exercise, Fetch, Pure, Block/Bind, GetTime
- ✓Party-scoped queries — need-to-know privacy at the API layer via asParty
- ✓Ed25519 signatures — optional transaction signing with registered keys
- ✓Template versioning — upgrade templates with version suffixes
- ✓Contract pruning — GDPR-style deletion of archived contracts
What's missing
- ✗Sub-transaction privacy — Canton decomposes transactions into per-party views. All our validators see all data.
- ✗Contract keys — DAML key-based lookups and exercise-by-key
- ✗Interfaces — DAML interface definitions (LF 1.15+)
- ✗Try/catch — DAML exception handling
- ✗Full stdlib — some stdlib functions referenced by complex contracts may not evaluate
- ✗Scenario/Script testing — only ledger operations, not test harness
Why the Gaps Don't Matter
Sub-transaction privacy? Avalanche L1s are sovereign chains with their own validator sets. On a permissioned L1, only approved validators sync the chain — the data never leaves the validator set. Put different data classes on different L1s (public, institutional, private) and you get infrastructure-level isolation without Canton's complex per-view encryption. For data-level encryption within a single L1, FHE (EncryptedERC20) is available on EVM L1s.
Contract keys and interfaces? These are convenience features in the DAML language, not fundamental ledger primitives. The core contract lifecycle (create, exercise, archive) and the authorization model (signatories, controllers, authority expansion) are fully implemented. Keys and interfaces can be added incrementally without architectural changes.
What Avalanche adds that Canton doesn't have: Sub-second finality via Snowman consensus. Full DeFi composability on the C-Chain. Standard Solidity tooling (Foundry, Hardhat, MetaMask) for EVM L1s in the same network. Cross-L1 atomic settlement via ICM. 300K+ Solidity developers. No vendor lock-in — your validators, your rules.
Architecture
AvalancheGo Node (v1.14.2)
├── P-Chain (platform, validators)
├── C-Chain (EVM, DeFi)
└── DAML L1 (custom VM)
├── rpcchainvm plugin (Go, 22MB binary)
│ ├── vm.go → block.ChainVM interface
│ ├── block.go → Snowman block lifecycle
│ ├── engine.go → DAML execution engine
│ ├── api.go → JSON-RPC handler
│ └── daml/lf/ → DAML-LF protobuf parser + interpreter
├── Consensus: Snowman (single-slot finality)
├── State: LevelDB via AvalancheGo database interface
└── Networking: AppGossip for mempool propagationAPI Reference
All RPC methods follow the JSON-RPC 2.0 specification.
Base Endpoint
https://rpc.damlonavalanche.com
All JSON-RPC requests are POST to this URL. REST endpoints use the same origin.
Methods
JSON-RPC Methods
daml.getParties
Returns the list of all parties currently registered on the ledger. Parties are the fundamental identity primitive in DAML — every contract is visible to its signatories and observers.
Request
curl -X POST https://rpc.damlonavalanche.com \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "daml.getParties",
"params": {},
"id": 1
}'Response
{
"jsonrpc": "2.0",
"result": ["Alice", "Bob", "Acme"],
"id": 1
}daml.getTemplates
Returns all registered DAML templates. Each template defines a contract type with fields, signatories, observers, and choices. Templates are the schema layer of the DAML ledger.
Request
curl -X POST https://rpc.damlonavalanche.com \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "daml.getTemplates",
"params": {},
"id": 1
}'Response
{
"jsonrpc": "2.0",
"result": [
{
"module": "Bond",
"name": "Bond",
"fields": {
"issuer": "Party",
"owner": "Party",
"amount": "Int64",
"currency": "Text"
},
"signatories": ["issuer"],
"observers": ["owner"],
"choices": {
"Transfer": {
"consuming": true,
"controllers": ["owner"],
"params": { "newOwner": "Party" }
}
},
"source": "template Bond with ..."
}
],
"id": 1
}daml.getActiveContracts
Returns all active (non-archived) contracts on the ledger. Supports optional filtering by template ID and party visibility. The asParty filter demonstrates Canton's privacy model — each party only sees contracts they are a signatory or observer of.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| templateId | string | optional | Filter by template, e.g. "Bond:Bond" |
| asParty | string | optional | Only return contracts visible to this party (privacy filter) |
Request
curl -X POST https://rpc.damlonavalanche.com \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "daml.getActiveContracts",
"params": {
"templateId": "Bond:Bond",
"asParty": "Alice"
},
"id": 1
}'Response
{
"jsonrpc": "2.0",
"result": [
{
"id": "00a1b2c3d4...",
"templateId": "Bond:Bond",
"payload": {
"issuer": "Alice",
"owner": "Bob",
"amount": 1000000,
"currency": "USD"
},
"signatories": ["Alice"],
"observers": ["Bob"],
"active": true,
"createdAt": 1711929600
}
],
"id": 1
}daml.getContract
Fetches a single contract by its ID. Optionally scoped to a party for privacy-aware lookups.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| contractId | string | required | The contract ID to look up |
| asParty | string | optional | Only return if visible to this party |
Request
curl -X POST https://rpc.damlonavalanche.com \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "daml.getContract",
"params": {
"contractId": "00a1b2c3d4..."
},
"id": 1
}'Response
{
"jsonrpc": "2.0",
"result": {
"id": "00a1b2c3d4...",
"templateId": "Bond:Bond",
"payload": {
"issuer": "Alice",
"owner": "Bob",
"amount": 1000000,
"currency": "USD"
},
"signatories": ["Alice"],
"observers": ["Bob"],
"active": true,
"createdAt": 1711929600
},
"id": 1
}daml.getTemplate
Returns a single template definition by its qualified ID (module:name).
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| templateId | string | required | Qualified template ID, e.g. "Bond:Bond" |
Request
curl -X POST https://rpc.damlonavalanche.com \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "daml.getTemplate",
"params": {
"templateId": "Bond:Bond"
},
"id": 1
}'Response
{
"jsonrpc": "2.0",
"result": {
"module": "Bond",
"name": "Bond",
"fields": {
"issuer": "Party",
"owner": "Party",
"amount": "Int64",
"currency": "Text"
},
"signatories": ["issuer"],
"observers": ["owner"],
"choices": {
"Transfer": {
"consuming": true,
"controllers": ["owner"],
"params": { "newOwner": "Party" }
},
"Settle": {
"consuming": true,
"controllers": ["issuer"],
"params": {}
}
},
"source": "template Bond with ..."
},
"id": 1
}daml.submit
Submits a transaction to the ledger. A transaction consists of one or more commands executed atomically by a submitter party. Supported command types: create, exercise, allocateParty, registerTemplate. An optional Ed25519 signature can be attached for authenticated submissions.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| transaction.submitter | string | required | The party submitting the transaction |
| transaction.commands | Command[] | required | Array of commands: {type, templateId?, arguments?, contractId?, choice?, party?, template?} |
| transaction.signature | string | optional | Hex-encoded Ed25519 signature over SHA-256(submitter + JSON(commands)) |
Request
curl -X POST https://rpc.damlonavalanche.com \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "daml.submit",
"params": {
"transaction": {
"submitter": "Alice",
"commands": [
{
"type": "create",
"templateId": "Bond:Bond",
"arguments": {
"issuer": "Alice",
"owner": "Bob",
"amount": 1000000,
"currency": "USD"
}
}
]
}
},
"id": 1
}'Response
{
"jsonrpc": "2.0",
"result": {
"accepted": true,
"message": "Transaction committed. 1 contract(s) created."
},
"id": 1
}daml.uploadDar
Uploads a compiled DAML Archive (.dar) to register its templates on the ledger. The file must be base64-encoded.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| darFile | string | required | Base64-encoded contents of the .dar file |
Request
curl -X POST https://rpc.damlonavalanche.com \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "daml.uploadDar",
"params": {
"darFile": "UEsDBBQAAAAI..."
},
"id": 1
}'Response
{
"jsonrpc": "2.0",
"result": {
"accepted": true,
"message": "DAR uploaded. 3 template(s) registered."
},
"id": 1
}REST Endpoints
/api/compile
Compiles DAML source code into Canton template definitions. Accepts raw DAML text and returns structured template objects ready for deployment.
Request Body
{
"source": "module Bond where\n\ntemplate Bond\n with\n issuer : Party\n where\n signatory issuer"
}Response
{
"templates": [
{
"module": "Bond",
"name": "Bond",
"fields": { "issuer": "Party" },
"signatories": ["issuer"],
"observers": [],
"choices": {},
"source": "template Bond with ..."
}
]
}/api/benchmark
Runs a throughput benchmark by submitting a batch of transactions to the ledger and measuring TPS and latency.
Request Body
{
"txCount": 1000
}Response
{
"tps": 196420,
"totalMs": 5.09,
"txCount": 1000,
"successCount": 1000,
"failCount": 0
}Type Definitions
Template
interface Template {
module: string; // DAML module name
name: string; // Template name
version?: string; // Optional version
fields: Record<string, string> | null;
// Field name -> DAML type (Party, Text, Int64, etc.)
signatories: string[] | string;
observers: string[] | string;
choices: Record<string, Choice> | string[];
source: string; // Original DAML source
}Choice
interface Choice {
consuming: boolean; // Whether exercising archives the contract
controllers: string[]; // Parties allowed to exercise
params: Record<string, string>;
// Parameter name -> DAML type
effects?: unknown; // Optional effect definitions
}Contract
interface Contract {
id: string; // Unique contract ID
templateId: string; // Qualified template ID (module:name)
payload: Record<string, unknown>;
// Contract field values
signatories: string[]; // Signatory parties
observers: string[]; // Observer parties
active: boolean; // Whether the contract is active
createdAt: number; // Unix timestamp
archivedAt?: number; // Unix timestamp (if archived)
}Command
interface Command {
type: string; // "create" | "exercise" | "allocateParty" | "registerTemplate"
templateId?: string; // For create commands
arguments?: Record<string, unknown>;
// For create/exercise commands
contractId?: string; // For exercise commands
choice?: string; // For exercise commands
template?: Template; // For registerTemplate commands
party?: string; // For allocateParty commands
}Canton-on-Avalanche // DAML smart contracts running natively on Avalanche L1
build.avax.network