Deployment Guide¶
This guide covers the signing flow, deploy payload format, contract upgrades, and how to verify a deployment.
Signing Flow¶
All state-changing operations (deploy, upgrade, call) require a signed transaction. Dilithia uses ML-DSA-65 (a post-quantum digital signature algorithm) for transaction signing. Here is the step-by-step flow:
- Load the secret key -- the hex-encoded ML-DSA-65 secret key is read from
--secret-keyor theDILITHIA_SECRET_KEYenvironment variable - Derive the public key -- the public key is extracted from the last
MLDSA65_PK_LENbytes of the secret key - Derive the sender address --
address_from_pk(pk_bytes)computes the on-chain address - Fetch the nonce -- unless
--nonceis provided, the CLI fetches the current nonce viaGET <RPC>/nonce/<address> - Build the canonical payload -- a JSON object with alphabetically sorted keys (see below)
- Sign the payload --
sign_mldsa65(payload_bytes, sk_bytes)produces the signature - Submit the transaction -- the full request body (including bytecode/args, signature, public key) is POSTed to the appropriate RPC endpoint
Canonical Payload Format¶
The canonical payload is the exact byte sequence that gets signed. Keys are always sorted alphabetically to ensure deterministic serialization.
Deploy / Upgrade Payload¶
{
"bytecode_hash": "<hex hash of the hex-encoded WASM bytes>",
"chain_id": "dilithia",
"from": "<sender address>",
"name": "<contract name>",
"nonce": 0
}
Note
The bytecode_hash is computed over the hex-encoded string of the WASM bytes, not the raw binary. This matches the hash_hex() function from dilithia_core.
Call Payload¶
{
"args": { ... },
"chain_id": "dilithia",
"contract": "<contract name>",
"from": "<sender address>",
"method": "<method name>",
"nonce": 0
}
Full Deploy Request Body¶
The complete request body built by the CLI for deploy and upgrade operations:
{
"name": "<contract name>",
"bytecode": "<hex-encoded WASM bytes>",
"from": "<sender address>",
"alg": "mldsa65",
"pk": "<hex-encoded public key>",
"sig": "<hex-encoded signature>",
"nonce": 0,
"chain_id": "dilithia",
"version": 1
}
Deploying with the CLI¶
dilithia-contract deploy \
--name my_token \
--wasm target/wasm32-unknown-unknown/release/my_token.wasm \
--rpc http://localhost:8000/rpc \
--secret-key $DILITHIA_SECRET_KEY
On success, the CLI returns the raw response body from the target node. The exact fields depend on the node version and endpoint behavior.
Deploying with the SDK¶
You can also deploy contracts programmatically using the Dilithia SDKs. The CLI itself delegates request-building to dilithia-sdk-rust, so canonical payload construction and endpoint selection stay aligned with that SDK.
Upgrading Contracts¶
The upgrade command replaces the on-chain WASM bytecode for an already-deployed contract:
dilithia-contract upgrade \
--name my_token \
--wasm target/wasm32-unknown-unknown/release/my_token.wasm \
--rpc http://localhost:8000/rpc \
--secret-key $DILITHIA_SECRET_KEY
Key points about upgrades:
- Admin-only -- only the original deployer (the address that submitted the initial
deploytransaction) can upgrade a contract - State preserved -- the contract's storage is not cleared during an upgrade; the new WASM code operates on the existing state
- Same signing flow -- the canonical payload format is identical to
deploy; the CLI swaps in the SDK upgrade request builder instead of the deploy request builder
Breaking storage changes
If your new contract code changes how it reads or writes storage keys, existing data may become unreadable or misinterpreted. Plan storage migrations carefully.
Verifying a Deployment¶
After deploying or upgrading, verify that the contract is live and functioning:
Inspect the extracted ABI¶
dilithia-contract extract-abi \
--wasm target/wasm32-unknown-unknown/release/my_token.wasm \
--output json
This returns the method list embedded into the compiled WASM by the vendored contract SDK macro.
Call a Method¶
dilithia-contract call \
--contract my_token \
--method init \
--args '{"total_supply":1000000,"deployer":"0xabc..."}' \
--rpc http://localhost:8000/rpc \
--secret-key $DILITHIA_SECRET_KEY \
--wait
Query State¶
dilithia-contract query \
--contract my_token \
--method total_supply \
--rpc http://localhost:8000/rpc
If ABI extraction, a state-changing call, and a read-only query all return the expected results, your contract is successfully deployed and operational.