Overview
Create a fungible token using the NEP-20 standard with the NEXUS SDK.Step 1: Scaffold Token
Copy
nexus dev scaffold my_token --template nep20
cd my_token
Step 2: Token Implementation
The NEP-20 template uses the production SDK with Solidity-compatible types:Copy
use nexus_sdk::{
solidity::{*, SafeMath},
contract_api::{ez::prelude::*, ez::ret},
require,
};
use nexus_sdk::solidity::uint256 as U256;
// State Variables
pub static BALANCES: Mapping<Address, U256> = Mapping::new(b"bal");
pub static ALLOWANCES: DoubleMapping<Address, Address, U256> = DoubleMapping::new(b"allow");
pub static TOTAL_SUPPLY: Mapping<&[u8], U256> = Mapping::new(b"supply");
pub static OWNER: Mapping<&[u8], Address> = Mapping::new(b"owner");
pub const NAME_KEY: &[u8] = b"name";
pub const SYMBOL_KEY: &[u8] = b"symbol";
pub const DECIMALS_KEY: &[u8] = b"decimals";
/// Internal module for reusable logic
pub mod internal {
use super::*;
pub fn init(name: String, symbol: String, decimals: u8, supply: U256) {
nexus_sdk::contract_api::storage::set(NAME_KEY, name.as_bytes());
nexus_sdk::contract_api::storage::set(SYMBOL_KEY, symbol.as_bytes());
nexus_sdk::contract_api::storage::set(DECIMALS_KEY, &[decimals]);
let sender = Blockchain::msg.sender();
OWNER.set(&b"val".as_slice(), sender.clone());
if supply > U256::zero() {
mint(sender, supply);
}
}
pub fn mint(to: Address, amount: U256) {
let current_supply = TOTAL_SUPPLY.get(&b"total".as_slice());
TOTAL_SUPPLY.set(&b"total".as_slice(), current_supply.add(amount));
let current_bal = BALANCES.get(&to);
BALANCES.set(&to, current_bal.add(amount));
emit("Transfer", &[]);
}
pub fn transfer(sender: Address, to: Address, amount: U256) -> bool {
let sender_bal = BALANCES.get(&sender);
if sender_bal < amount {
return false;
}
BALANCES.set(&sender, sender_bal.sub(amount));
let to_bal = BALANCES.get(&to);
BALANCES.set(&to, to_bal.add(amount));
emit("Transfer", &[]);
true
}
}
// ABI Entry Points
nexus_fn! {
fn init_token(name: String, symbol: String, decimals: u64, supply: U256) {
internal::init(name, symbol, decimals as u8, supply);
ret::u32(1)
}
}
nexus_fn! {
fn mint(to: Address, amount: U256) {
let sender = Blockchain::msg.sender();
let owner = OWNER.get(&b"val".as_slice());
require!(sender == owner, "Not owner");
internal::mint(to, amount);
ret::u32(1)
}
}
nexus_fn! {
fn transfer(to: Address, amount: U256) {
let _guard = ReentrancyGuard::new();
let sender = Blockchain::msg.sender();
let success = internal::transfer(sender, to, amount);
if success { ret::u32(1) } else { ret::u32(0) }
}
}
nexus_fn! {
fn balanceOf(addr: Address) {
let bal = BALANCES.get(&addr);
let mut out = [0u8; 32];
bal.to_little_endian(&mut out);
ret::u256(&out)
}
}
Step 3: Compile
Copy
cargo build --target wasm32-unknown-unknown --release
Step 4: Deploy
Copy
nexus contract deploy \
--wasm ./target/wasm32-unknown-unknown/release/my_token.wasm \
--name my_token \
--from my-wallet \
--init-args '["MyToken","MTK","18","1000000000000000000"]'
[name, symbol, decimals, initial_supply]
Step 5: Verify
Copy
# Check name
nexus contract call --contract <ID> --function name --from my-wallet
# Check balance
nexus contract call --contract <ID> --function balanceOf \
--args '["0x<YOUR_PUBKEY>"]' --from my-wallet
Step 6: Transfer
Copy
nexus contract call --contract <ID> --function transfer \
--args '["0x<RECIPIENT>","1000000"]' --from my-wallet --commit
Using SDK
Copy
const token = new TokenContract(client, contractId);
// Check balance
const { balanceDecimal } = await token.balanceOf(address);
// Transfer
await token.transfer(recipient, '1000000');
// Approve spender
await token.approve(spenderAddress, '5000000');
// Transfer from (requires approval)
await token.transferFrom(ownerAddress, recipientAddress, '2000000');
Key SDK Features
Mapping Types
Copy
// Single-key mapping (like Solidity mapping(address => uint256))
static BALANCES: Mapping<Address, U256> = Mapping::new(b"bal");
// Double-key mapping (like mapping(address => mapping(address => uint256)))
static ALLOWANCES: DoubleMapping<Address, Address, U256> = DoubleMapping::new(b"allow");
SafeMath
Copy
// Safe arithmetic - reverts on overflow
let sum = a.add(b);
let diff = a.sub(b);
let product = a.mul(b);
Reentrancy Protection
Copy
nexus_fn! {
fn transfer(to: Address, amount: U256) {
let _guard = ReentrancyGuard::new(); // Auto-releases on drop
// ... transfer logic
}
}
nexus_fn! Macro
Thenexus_fn! macro handles ABI encoding/decoding automatically:
Copy
nexus_fn! {
fn myFunction(arg1: Address, arg2: U256) {
// Arguments are automatically decoded
// Use ret::* functions to return values
ret::u32(1)
}
}