NEXUS is live on Zcash. This guide gets you from zero to a deployed contract.
Prerequisites
- Node.js 18+ — for the TypeScript SDK
- Rust + Cargo — for writing and building contracts
- WASM target:
rustup target add wasm32-unknown-unknown
- A running NEXUS node (or access to a hosted endpoint)
Install the SDK
npm install @yattacorp/nexus-sdk
The package name is @yattacorp/nexus-sdk. It exports everything from a single entry point.
Connect to NEXUS
import { NexusClient, Wallet } from '@yattacorp/nexus-sdk';
// Restore wallet from mnemonic — must be mnemonic-based for vault + renewal key support
const wallet = Wallet.fromMnemonic(
process.env.MNEMONIC!,
'mainnet', // 'mainnet' | 'regtest'
undefined, // use default BIP-32 path
'zcash'
);
// Pass wallet directly to NexusClient — no separate connect() call
const client = new NexusClient(
{ rpcUrl: 'https://api.yattacorp.xyz', network: 'mainnet', chain: 'zcash' },
wallet
);
const height = await client.getBlockHeight();
console.log('NEXUS block height:', height);
Deploy Your First Contract
The fastest way to get started is the nexus-contract-template — a pre-configured Cargo workspace with the SDK, build scripts, and tests included. Clone it and skip the manual setup below.
1. Write a Contract
// src/lib.rs
#![no_std]
extern crate alloc;
use nexus_sdk::contract_api::{ez::prelude::*, ez::ret};
pub static COUNTER: Mapping<&[u8], u64> = Mapping::new(b"count");
nexus_fn! {
fn increment() {
let val = COUNTER.get(&b"val".as_slice());
COUNTER.set(&b"val".as_slice(), val + 1);
emit("Incremented", &[]);
ret::u64(val + 1)
}
}
nexus_fn! {
fn get_count() {
ret::u64(COUNTER.get(&b"val".as_slice()))
}
}
2. Build
cargo build --target wasm32-unknown-unknown --release
# Output: target/wasm32-unknown-unknown/release/my_nexus_contract.wasm
3. Deploy
import { readFileSync } from 'fs';
const wasm = readFileSync(
'./target/wasm32-unknown-unknown/release/my_nexus_contract.wasm'
);
const result = await client.deployContract(wasm);
console.log('Contract deployed at:', result.contractId);
4. Call It
// Standard call
await client.callContract(contractId, 'increment', []);
// Stealth call — hides the caller's identity on-chain
await client.stealthCallContract(contractId, 'increment', []);
// Read-only query (free, no gas)
const count = await client.queryContract(contractId, 'get_count', []);
console.log('Count:', count);
stealthCallContract uses the same contract function but wraps the transaction in a stealth address, so on-chain observers cannot link the call to your wallet. See Stealth Addresses.
Deposit ZEC
To use vZEC in contracts, deposit ZEC into your vault:
// Get your Zcash vault address (default timelock: 16,128 blocks = ~2 weeks)
const vault = await client.getVaultAddress();
console.log('Send ZEC to:', vault.vaultAddress);
// e.g. "tmXxx..." on regtest
// After 10 confirmations (~12.5 min), your vZEC balance appears:
const balance = await client.getBalance();
console.log('vZEC balance:', balance);
Then send ZEC to that address:
zcash-cli sendtoaddress <VAULT_ADDRESS> 1.0
zcash-cli sendtoaddress works on regtest only. On mainnet, use any Zcash-compatible wallet to send to the vault address.
Wait 10 confirmations (~12.5 minutes on mainnet). Your vZEC will appear.
Deploy a NEP-20 Token
The fastest way is to clone the nexus-contract-template which includes a production-ready NEP-20 implementation:
git clone https://github.com/yattacorp/nexus-contract-template
cd nexus-contract-template
cargo build --target wasm32-unknown-unknown --release
Then deploy the built WASM:
import { readFileSync } from 'fs';
const wasm = readFileSync(
'./target/wasm32-unknown-unknown/release/my_nexus_contract.wasm'
);
const { contractId } = await client.deployContract(wasm);
await client.callContract(contractId, 'init_token', [
'My Token', // name
'MTK', // symbol
18, // decimals
'1000000000000000000000000', // initial supply (1M tokens)
]);
console.log('Token live at:', contractId);
→ See NEP-20 Token Standard for the full interface and production source.
Next Steps