Deploy contracts
A deploy is an ordinary signed transaction to neuro:system.deploy. Every validator audits the bytecode with VMGuardian in consensus; a contract that fails the audit is never created anywhere.
1. Build
Contracts are no_std Rust compiled to wasm32-unknown-unknown as a cdylib, importing host functions from the env module — declare them with #[link(wasm_import_module = "env")] so they link with current Rust. See NeuroWASM for the interface and a complete example.
[lib]
crate-type = ["cdylib"]
[profile.release]
opt-level = "z"
lto = true
codegen-units = 1cargo build --release --target wasm32-unknown-unknown
od -An -tx1 -v target/wasm32-unknown-unknown/release/my_contract.wasm | tr -d ' \n' > my_contract.hexThe hex must start with 0061736d (the WASM magic). Maximum size: 512 KiB of bytecode (MAX_BYTECODE_SIZE).
Working examples in the repository: neurochain/contracts/nrc20 (fungible token), ncert (security certificates, NRC-721 style), dao and gov_dao.
2. Check before you send optional
| Endpoint | What you get |
|---|---|
POST /api/v1/contracts/analyze { "bytecode_hex": "…" } | risk_score, security_score, ml_score, model, violations — the same analysis the gate runs |
POST /api/v1/contracts/attest { "bytecode_hex": "…" } | The same result signed by the node with ML-DSA-65, verifiable in the browser |
The web app's deploy page runs the analysis in the browser first, then asks the node for a signed attestation.
3. Send the deploy
With the SDK (recommended):
await nc.deployContract({
wallet,
bytecodeHex,
name: 'MyToken', // unique contract name, optional
description: '…',
template: 'nrc20', // registered template id, optional
initArgs: { … }, // passed to initialize, optional; decimals as a number
gasPrice,
})By hand — POST /api/v1/transactions with to: "neuro:system.deploy", value: 0, and data set to this JSON string:
{ "bytecode_hex": "0061736d…", "name": "MyToken", "description": "", "template": "", "init_args": { } }signed like any transaction (nc-tx-v2|from|neuro:system.deploy|0|nonce).
The node also exposes POST /api/v1/contracts/deploy (owner, bytecode_hex or base64_wasm, plus a signed operation for neuro:system.deploy); it builds the same transaction for you.
4. What every validator does
- Gate. Decode the bytecode and look up its SHA3-256 hash:
- whitelisted (official templates such as NRC-20) → security score 100, no analysis;
- gate switched off by governance (
deploy_security_enabled = 0) → neutral score 70; - otherwise run VMGuardian
analyze_v2. Ifrisk_score ≥ deploy_risk_threshold(default 0.80), the transaction fails with no fee charged, the rejection is logged with its rule violations, and thenc_deploy_rejected_totalmetric counts it.
- Charge 10 000 gas units ×
gas_price. - Create the contract at
neuro:<10 hex>.app— the first 5 bytes ofSHA3-256(owner ‖ nonce). A contract name already taken by another contract fails the deploy. - Constructor. If the module exports
init, it runs once with the deploy's storage. - Initialize. If
init_argsis present, the contract is called with{"function": "initialize", …init_args}— the arguments are flattened to the top level of the JSON — with you as the caller. - Template fee. If
templatenames a registered template with a fee, that fee goes from you to the template's author.
The resulting security score is 100 − risk_score × 100 and is stored with the contract.
Fees
| Item | Cost |
|---|---|
| Deploy | 10 000 gas units × gas_price (at 1 uNRO: 0.01 NRO) |
| Rejected by the gate | Nothing |
| Template | The template's own fee, if any |
After deploy: continuous monitoring
Each node re-audits deployed contracts every 20 seconds (MONITOR_INTERVAL_SECS). When a contract's score moves by 10 points or more (MONITOR_SCORE_THRESHOLD) — for example after the model is updated — a certificate update transaction is issued through consensus. Certificates are readable at GET /api/v1/certificates/contract/:address. See VMGuardian.
Troubleshooting
| Error | Cause |
|---|---|
Deploy rejected by VMGuardian: risk_score … >= threshold … | The audit found risky patterns; analyze lists them. |
gas_price … below block base_fee … | Raise gasPrice above the current base fee. |
Contract name '…' is already taken | Choose another name, or leave it empty. |
| Size error | Bytecode over 512 KiB — build with opt-level = "z" and LTO. |