Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.canton.network/llms.txt

Use this file to discover all available pages before exploring further.

Use this checklist when planning and executing a migration from Ethereum to Canton. Each section covers a key area with specific action items.

Before You Start

  • Identify state model dependencies: Does your app rely on global state queries?
  • Map multi-party relationships: Who are the parties in your contracts?
  • Evaluate privacy requirements: Do you need sub-transaction privacy?
  • Review integration points: What systems connect to your smart contracts?
If your app heavily relies on global state queries (e.g., “show all NFTs”), you’ll need to redesign this functionality using party-scoped queries or off-ledger indexing.
AreaEthereum AssumptionCanton Reality
StateGlobal, queryableDistributed, party-scoped
ContractsMutableImmutable (archive + create)
AuthorizationRuntime msg.senderCompile-time signatories
PrivacyPublic by defaultPrivate by default
IdentityAnonymous addressesNamed parties
  • Install the Daml SDK
  • Install VS Code with the Daml extension
  • Clone the CN Quickstart repository
  • Run make setup && make build && make start to verify your setup works

Smart Contract Migration

Phase 1: Model Your Parties

1

Identify all actors

List everyone who interacts with your contracts and map them to Canton parties:
  • Contract owneradmin : Party (signatory for admin contracts)
  • Usersuser : Party (each user is a distinct party)
  • Operatorsoperator : Party (may be signatory or controller)
2

Define party relationships

For each contract, determine:
  • Who must agree to create it? → Signatories
  • Who should see it? → Observers
  • Who can act on it? → Controllers (per choice)
3

Plan party hosting

Decide where parties will be hosted:
  • User parties: Often on the application provider’s validator
  • Admin parties: On your organization’s validator
  • External parties: On their own validators

Phase 2: Translate Contracts

// Solidity
struct Asset {
    address owner;
    uint256 value;
    bool locked;
}
-- Daml
data Asset = Asset with
  owner : Party
  value : Decimal
  locked : Bool
  deriving (Eq, Show)
// Solidity: Global mapping
mapping(address => uint256) public balances;
-- Daml: Individual contracts per holding
template TokenHolding
  with
    owner : Party
    issuer : Party
    amount : Decimal
  where
    signatory issuer
    observer owner
The key insight: Instead of one contract with a mapping, you have many contracts—one per holding.
// Solidity
function transfer(address to, uint256 amount) public {
    require(balances[msg.sender] >= amount);
    balances[msg.sender] -= amount;
    balances[to] += amount;
}
-- Daml
choice Transfer : ContractId TokenHolding
  with
    newOwner : Party
  controller owner
  do
    create this with owner = newOwner
// Solidity
modifier onlyOwner() {
    require(msg.sender == owner);
    _;
}
-- Daml: No modifier needed
choice AdminAction : ()
  controller admin  -- Only admin can exercise
  do
    -- Protocol enforces this
    pure ()

Phase 3: Handle State Differently

  • Replace global queries: Design party-scoped query patterns
  • Plan for contract keys: Use keys for lookups instead of addresses
  • Accept contract ID changes: IDs change on every update; use keys for stable references
Canton has no equivalent to Ethereum’s eth_getLogs or event filtering across all contracts. Plan your indexing strategy early.

Integration Migration

API Changes

EthereumCantonNotes
JSON-RPCLedger API (gRPC or JSON API)Different protocol
Web3.js / ethers.jsLedger API client or dApp SDKLanguage-specific clients
Event logsTransaction streamsSubscribe to party’s transactions
eth_callExercise non-consuming choiceRead-only operations

Authentication Changes

Ethereum authenticates via private key signatures and derives identity from msg.sender. In Canton, identity comes from party authentication with JWT tokens. Where Ethereum allows anyone to call a public function, Canton restricts access to authenticated parties only.

Indexing Strategy

Since there’s no global state query:
  • Use the Participant Query Store (PQS) for SQL-based querying
  • Stream transactions to your own database
  • Design contracts with query-friendly keys

Testing Migration

Unit Tests

  • Replace Hardhat/Foundry tests with Daml Script tests
  • Test authorization rules (who can exercise what)
  • Test multi-party workflows (propose-accept patterns)
-- Daml Script test
testTransfer = script do
  alice <- allocateParty "Alice"
  bob <- allocateParty "Bob"

  -- Alice creates a token
  tokenId <- submit alice do
    createCmd Token with owner = alice, issuer = alice, amount = 100.0

  -- Alice transfers to Bob
  newTokenId <- submit alice do
    exerciseCmd tokenId Transfer with newOwner = bob

  -- Verify Bob owns it
  Some token <- queryContractId bob newTokenId
  assert (token.owner == bob)

Integration Tests

  • Test against LocalNet (CN Quickstart provides this)
  • Verify API integration works
  • Test error scenarios and rollback behavior

Deployment Migration

Network Selection

  • LocalNet — development and testing
  • DevNet — integration testing
  • TestNet — pre-production validation
  • MainNet — production

Deployment Checklist

  • Package your Daml code: dpm build
  • Upload to validator: Via admin or LAPI APIs
  • Allocate parties: Create party identities
  • Initialize contracts: Create initial state
  • Configure applications: Point to Ledger API

Operational Changes

Monitoring

Where Ethereum has block explorers, Canton uses validator logs and metrics. Transaction hash lookups become transaction ID queries. Gas tracking maps to traffic unit tracking.

Key Management

Ethereum EOA private keys correspond to Canton party keys, which can live on the validator or be held externally. Hardware wallets map to HSM and KMS integrations. Multisig wallets are replaced by multi-signatory contracts, where authorization is enforced at the Daml level.

Common Migration Pitfalls

Avoid these common mistakes when migrating from Ethereum.
PitfallWhy It HappensHow to Avoid
Building global state viewsExpecting Ethereum-like queriesDesign for party-scoped data from start
Overusing partiesTreating parties like addressesParties have hosting costs; design deliberately
Ignoring propose-acceptExpecting unilateral contract creationMulti-party contracts need workflow
Expecting event logsUsing Ethereum event patternsUse transaction streams and indexing
Contract ID as identifierTreating IDs like addressesUse contract keys for stable references

Migration Phases

PhaseFocusCompletion Criteria
1. LearningUnderstand Canton modelTeam comfortable with Daml basics
2. DesignRedesign for CantonParty model and contracts designed
3. DevelopmentImplement in DamlContracts and tests complete
4. IntegrationConnect applicationsAPIs working on LocalNet
5. TestingValidate on test networksPassed DevNet/TestNet testing
6. DeploymentGo to productionRunning on MainNet

Next Steps

Module 3: Daml Development

Start building with Daml.

CN Quickstart

Get hands-on with a working example.