Deploying Contracts
This guide covers the complete workflow for deploying smart contracts to Ashen, from building to verification.
Quick Start
Section titled “Quick Start”# 1. Build the contractnode contract build --manifest-path contracts/my_contract/Cargo.toml
# 2. Bundle with IDLnode contract bundle \ --elf target/riscv64imac-unknown-none-elf/release/my_contract \ --idl contracts/my_contract/my_contract.idl \ --out ./my_contract.bundle
# 3. Deploynode contract deploy \ --bundle ./my_contract.bundle \ --key $ASHEN_PRIVATE_KEY \ --waitPrerequisites
Section titled “Prerequisites”- Rust with the
riscv64imac-unknown-none-elftarget - A funded account for deployment gas fees
- Your private key (ed25519 hex or keystore reference)
# Install RISC-V targetrustup target add riscv64imac-unknown-none-elf
# Generate a keypair if needednode keygen > ./dev.key.jsonexport ASHEN_PRIVATE_KEY=@./dev.key.jsonStep 1: Build the Contract
Section titled “Step 1: Build the Contract”Rust Contracts
Section titled “Rust Contracts”node contract build --manifest-path contracts/my_contract/Cargo.toml
# With custom output pathnode contract build \ --manifest-path contracts/my_contract/Cargo.toml \ --out-elf ./my_contract.elf
# With debug info (for tracing)node contract build \ --manifest-path contracts/my_contract/Cargo.toml \ --debuginfo
# Verbose outputnode contract build \ --manifest-path contracts/my_contract/Cargo.toml \ --verboseOutput: target/riscv64imac-unknown-none-elf/release/<contract_name>
Zig Contracts
Section titled “Zig Contracts”Zig contracts use the Ashen SDK and compile via zig build:
cd contracts/my_zig_contractzig build -Doptimize=ReleaseSmallOutput: zig-out/bin/<contract_name>
Build Options
Section titled “Build Options”| Option | Description |
|---|---|
--manifest-path | Path to Cargo.toml |
--target | Target triple (default: riscv64imac-unknown-none-elf) |
--release | Release build (default: true) |
--debuginfo | Preserve DWARF debug info for tracing |
--bin | Binary name (if multiple in workspace) |
--out-elf | Custom output path |
--verbose | Show build commands |
Step 2: Create IDL
Section titled “Step 2: Create IDL”Every contract needs an IDL (Interface Definition Language) file describing its methods, types, and events.
IDL Structure
Section titled “IDL Structure”interface MyContract { // View method (read-only) fn balance_of(account: Address) -> u128;
// Mutating method fn transfer(to: Address, amount: u128) -> ();
// Events event Transfer { from: Address indexed, to: Address indexed, amount: u128, }}Generate IDL from Rust
Section titled “Generate IDL from Rust”If using the Rust SDK with #[contract] macros:
cargo run -p idl-abi-gen -- \ --idl contracts/my_contract/my_contract.idl \ --out-dir contracts/my_contract/src \ --rust-contractValidate IDL
Section titled “Validate IDL”ashen idl validate ./my_contract.idlStep 3: Bundle Contract
Section titled “Step 3: Bundle Contract”Bundle the compiled ELF with its IDL for deployment:
node contract bundle \ --elf target/riscv64imac-unknown-none-elf/release/my_contract \ --idl contracts/my_contract/my_contract.idl \ --out ./my_contract.bundleUpgrade Policy
Section titled “Upgrade Policy”Specify upgrade policy at bundle time:
# Immutable (cannot be upgraded)node contract bundle ... --upgrade-policy immutable
# Owner-upgradeable (default)node contract bundle ... --upgrade-policy owner
# Governance-upgradeablenode contract bundle ... --upgrade-policy governanceStep 4: Deploy
Section titled “Step 4: Deploy”Basic Deployment
Section titled “Basic Deployment”node contract deploy \ --bundle ./my_contract.bundle \ --key $ASHEN_PRIVATE_KEYDeploy and Wait for Confirmation
Section titled “Deploy and Wait for Confirmation”node contract deploy \ --bundle ./my_contract.bundle \ --key $ASHEN_PRIVATE_KEY \ --wait \ --wait-timeout-s 120Deploy with Custom Parameters
Section titled “Deploy with Custom Parameters”node contract deploy \ --bundle ./my_contract.bundle \ --key $ASHEN_PRIVATE_KEY \ --max-fee 5000000 \ --gas-limit 2000000 \ --rpc-url http://custom-node:3030 \ --waitDeploy Options
Section titled “Deploy Options”| Option | Default | Description |
|---|---|---|
--bundle | — | Path to contract bundle |
--elf | — | Alternative: path to ELF (without bundle) |
--idl | — | Alternative: path to IDL (with —elf) |
--key | $ASHEN_PRIVATE_KEY | Signing key |
--max-fee | 1000000 | Maximum fee to pay |
--gas-limit | 1000000 | Gas limit for deployment |
--rpc-url | http://127.0.0.1:3030 | RPC endpoint |
--auth-token | — | Optional auth token |
--wait | false | Wait for inclusion |
--wait-timeout-s | 60 | Timeout when waiting |
--upgrade-policy | owner | Upgrade policy |
Using the TUI for Deployment
Section titled “Using the TUI for Deployment”The interactive TUI provides a visual deployment experience:
# Launch TUIashen
# Navigate to Deploy screen (press 'd')# Select bundle file# Review deployment parameters# Submit and monitor progressTUI Deploy Features
Section titled “TUI Deploy Features”- Bundle Selection — Browse and select bundle files
- Parameter Editor — Adjust gas, fees, upgrade policy
- Simulation — Preview deployment before submission
- Progress Tracking — Watch deployment confirmation in real-time
- History — Track all your deployments
Scripted Deployment (Agent Automation)
Section titled “Scripted Deployment (Agent Automation)”For CI/CD pipelines and agent automation, use the CLI with structured output.
Basic Script
Section titled “Basic Script”#!/bin/bashset -e
CONTRACT_PATH="contracts/my_contract"BUNDLE_PATH="./my_contract.bundle"
# Buildecho "Building contract..."node contract build --manifest-path "$CONTRACT_PATH/Cargo.toml"
# Bundleecho "Creating bundle..."node contract bundle \ --elf "target/riscv64imac-unknown-none-elf/release/my_contract" \ --idl "$CONTRACT_PATH/my_contract.idl" \ --out "$BUNDLE_PATH"
# Deployecho "Deploying..."RESULT=$(node contract deploy \ --bundle "$BUNDLE_PATH" \ --key "$ASHEN_PRIVATE_KEY" \ --wait 2>&1)
# Extract contract address from outputCONTRACT_ADDR=$(echo "$RESULT" | grep -oP 'Contract deployed at: \K0x[a-fA-F0-9]+')echo "Contract deployed at: $CONTRACT_ADDR"
# Verify deploymentashen abi "$CONTRACT_ADDR"Agent Workflow with JSON Output
Section titled “Agent Workflow with JSON Output”#!/bin/bash# Deployment workflow using robot mode for structured output
# 1. Deploy and capture resultecho "Deploying contract..."DEPLOY_RESULT=$(node contract deploy \ --bundle ./my_contract.bundle \ --key "$ASHEN_PRIVATE_KEY" \ --wait 2>&1)
# Parse deployment output for contract addressCONTRACT_ADDR=$(echo "$DEPLOY_RESULT" | grep -oP '0x[a-fA-F0-9]{64}' | head -1)
if [ -z "$CONTRACT_ADDR" ]; then echo "Deployment failed" exit 1fi
echo "Deployed to: $CONTRACT_ADDR"
# 2. Verify the contract has codeACCOUNT=$(ashen tui account "$CONTRACT_ADDR" --json)if ! echo "$ACCOUNT" | jq -e '.ok' > /dev/null; then echo "Failed to query contract account" exit 1fi
# 3. Test a view callVIEW_RESULT=$(ashen tui view \ --contract "$CONTRACT_ADDR" \ --method total_supply \ --json)
if echo "$VIEW_RESULT" | jq -e '.ok' > /dev/null; then SUPPLY=$(echo "$VIEW_RESULT" | jq -r '.data.result') echo "Initial total supply: $SUPPLY"else echo "View call failed: $(echo "$VIEW_RESULT" | jq -r '.message')" exit 1fi
# 4. Execute initialization (if needed)INIT_RESULT=$(ashen tui call \ --contract "$CONTRACT_ADDR" \ --method initialize \ --args '["MyToken", "MTK", 18]' \ --key "$ASHEN_PRIVATE_KEY" \ --submit --wait --json)
if echo "$INIT_RESULT" | jq -e '.ok' > /dev/null; then TX_HASH=$(echo "$INIT_RESULT" | jq -r '.data.tx_hash') echo "Initialized: $TX_HASH"else echo "Initialization failed: $(echo "$INIT_RESULT" | jq -r '.message')" exit 1fi
echo "Deployment complete!"echo "Contract: $CONTRACT_ADDR"Multi-Contract Deployment
Section titled “Multi-Contract Deployment”#!/bin/bash# Deploy multiple contracts with dependencies
declare -A CONTRACTSCONTRACTS=( ["token"]="contracts/token" ["pool"]="contracts/amm_pool" ["router"]="contracts/dex_router")
declare -A ADDRESSES
for name in token pool router; do path="${CONTRACTS[$name]}" echo "Deploying $name..."
# Build node contract build --manifest-path "$path/Cargo.toml"
# Bundle node contract bundle \ --elf "target/riscv64imac-unknown-none-elf/release/$name" \ --idl "$path/$name.idl" \ --out "./$name.bundle"
# Deploy RESULT=$(node contract deploy \ --bundle "./$name.bundle" \ --key "$ASHEN_PRIVATE_KEY" \ --wait 2>&1)
ADDR=$(echo "$RESULT" | grep -oP '0x[a-fA-F0-9]{64}' | head -1) ADDRESSES[$name]="$ADDR" echo "$name deployed at: $ADDR"done
# Initialize router with token and pool addressesashen tui call \ --contract "${ADDRESSES[router]}" \ --method set_addresses \ --args "[\"${ADDRESSES[token]}\", \"${ADDRESSES[pool]}\"]" \ --key "$ASHEN_PRIVATE_KEY" \ --submit --wait --json
echo "Deployment complete!"for name in "${!ADDRESSES[@]}"; do echo " $name: ${ADDRESSES[$name]}"donePost-Deployment Verification
Section titled “Post-Deployment Verification”Verify Contract Code
Section titled “Verify Contract Code”# Check that contract has codeashen account --address $CONTRACT_ADDR
# Fetch and inspect IDLashen abi $CONTRACT_ADDRashen abi $CONTRACT_ADDR --raw > deployed.idl
# Compare with source IDLashen idl diff ./my_contract.idl ./deployed.idlTest Contract Methods
Section titled “Test Contract Methods”# View call (read-only)ashen view $CONTRACT_ADDR total_supply
# With JSON output for automationashen tui view --contract $CONTRACT_ADDR --method total_supply --jsonMonitor Transactions
Section titled “Monitor Transactions”# Get deployment tx detailsashen tx by-hash --tx-hash $DEPLOY_TX_HASH
# List recent transactions to the contractashen tui tx list --contract $CONTRACT_ADDR --jsonTroubleshooting
Section titled “Troubleshooting”Common Issues
Section titled “Common Issues”“insufficient balance”
- Fund your account before deployment
- Check:
ashen account --address $YOUR_ADDRESS
“gas limit exceeded”
- Increase
--gas-limit(default: 1,000,000) - Complex contracts may need 2-5 million gas
“max fee exceeded”
- Increase
--max-fee - Check current gas prices:
ashen status
“contract already exists”
- Contract addresses are deterministic (sender + nonce)
- Use a different nonce lane or wait for previous tx
“invalid IDL”
- Validate:
ashen idl validate ./my_contract.idl - Check for syntax errors and type mismatches
Debug Failed Deployments
Section titled “Debug Failed Deployments”# Trace the deployment transactionashen debug trace --tx-hash $FAILED_TX_HASH
# Check execution logsashen tx by-hash --tx-hash $FAILED_TX_HASH --waitBest Practices
Section titled “Best Practices”-
Always test locally first
Terminal window just devnet-node init --alloc "$ADDR=1000000000000"just node# Deploy to local node before testnet/mainnet -
Use
--waitfor reliable scripting- Without
--wait, you only get the tx hash - With
--wait, you confirm inclusion and get the contract address
- Without
-
Version your IDLs
- Commit IDL files alongside contract source
- Use
ashen idl diffto track breaking changes
-
Set appropriate gas limits
- Start with 1M gas, increase if deployment fails
- Large contracts may need 5-10M gas
-
Consider upgrade policy carefully
immutable: Most secure, no upgrades possibleowner: Flexible, owner can upgradegovernance: Requires on-chain governance approval
Related
Section titled “Related”- Ashen SDK — Write contracts in Zig
- IDL & ABI — Interface definitions
- Using the CLI — Full CLI reference
- Configuration — Node configuration