Releases: devel0x/electronero
Electronero Network: Release "Opcode Origin" v0.1.0
🚀 Electronero Network – Token Subsystem Release (XRC20) "Opcode Origin"
🔧 Overview
This release introduces the XRC20 Token Subsystem, enabling fungible tokens directly on the Electronero network — without compromising the core privacy model.
Built into the core protocol, this system provides:
- ⚙️ On-chain token creation, minting, burning, and transfer
- 🔐 Private sender/receiver identities via stealth addresses
- 🔍 Public token balances and transaction history for auditability
- 🧩 Seamless integration with simplewallet and new RPC endpoints
Electronero introduces a comprehensive XRC‑20 token system accessible from both the CLI and RPC. Deploy new tokens with token_create, pay a deployment fee to governance, and manage balances privately as each operation rides on standard ring‑signature transactions. Transfers apply a small governance fee and optional creator fee while commands like token_balance and token_allowance reveal holdings and approved spenders.
Creators may mint or burn supply, transfer ownership, and pause or unpause transfers. Accounts can be frozen with governance approval, and token_transfer_from enables delegated spending much like ERC‑20. History and discovery tools such as token_history, tokens_deployed, and my_tokens help track every asset. Tokens reside in <data-dir>/tokens.bin so wallets stay in sync after rescanning the chain. Together these features empower a rich token ecosystem right within Electronero.
✨ New Features
✅ Token Subsystem (XRC20)
- Create and manage fungible tokens.
- Supports token-level metadata: name, symbol, supply, decimals.
- Protocol-level
TOKEN_OPERATIONtransaction type. - All token state (balances, total supply, tx log) is stored on-chain.
🔐 Hybrid Privacy Model
- Balances and transfers are publicly visible.
- User identities remain private via stealth address mechanisms.
- No RingCT/decoys for token operations — enabling lightweight auditability.
🔒 Address Model
- Only base wallets (primary account, index 0) can create tokens.
- Integrated addresses and subaddresses are fully supported as token holders.
- All transfer and balance functions work with standard and subaddresses.
🖥️ RPC + CLI Enhancements
🎯 Core RPC Methods
token_transfertoken_approvetoken_transfer_fromtoken_burntoken_minttoken_set_feetoken_lock_feetoken_pause/token_unpausetoken_freeze/token_unfreezetoken_allowancetoken_infotoken_balancetoken_historytoken_history_addrtokens_deployedmy_tokensall_tokens
All token RPC calls support account_index (AINDEX) to select source subaddress. Defaults to base address if not provided.
🧪 Simplewallet Commands
token_create <name> <symbol> <supply> [creator_fee]
token_balance <token_address> [owner]
token_transfer <token_address> <to> <amount>
token_approve <token_address> <spender> <amount>
token_transfer_from <token_address> <from> <to> <amount>
token_burn <token_address> <amount>
token_mint <token_address> <amount>
token_set_fee <token_address> <creator_fee>
token_lock_fee <token_address>
token_pause <token_address>
token_unpause <token_address>
token_freeze <token_address> <account>
token_unfreeze <token_address> <account>
token_info <token_address>
token_allowance <token_address> <owner> <spender>
token_history <token_address>
token_history_addr <address>
all_tokens
tokens_deployed [address]
my_tokens [address]
🧪 Code Examples
The all_tokens command lists every token known to the wallet:
bool simple_wallet::all_tokens(const std::vector<std::string> &args) {
if (!m_tokens_path.empty())
m_tokens.load(m_tokens_path);
std::vector<token_info> list;
m_tokens.list_all(list);
for (const auto &t : list)
message_writer() << t.name << " (" << t.symbol << ") " << t.address;
return true;
}If your wallet ever falls out of sync you can rebuild the local token data with
rescan_token_operations <start_height> which replays every token transaction
from the given height.
void t_cryptonote_protocol_handler<t_core>::rescan_token_operations(uint64_t from_height) {
m_tokens = token_store();
auto& bc = m_core.get_blockchain_storage();
uint64_t top = bc.get_current_blockchain_height();
for (uint64_t h = from_height; h < top; ++h) {
bc.for_all_transactions(h, [this, h](const cryptonote::transaction &tx) {
process_token_tx(tx, h);
});
}
if (!m_tokens_path.empty())
m_tokens.save(m_tokens_path);
}Token transactions embed opcode data in the transaction tx_extra field. The protocol extracts this information via process_token_tx, which calls parse_token_extra to decode the operation and parameters. Once verified, the handler updates the local token store and persists the result:
void t_cryptonote_protocol_handler<t_core>::process_token_tx(const cryptonote::transaction &tx,
uint64_t height) {
std::vector<cryptonote::tx_extra_field> fields;
if (!cryptonote::parse_tx_extra(tx.extra, fields))
return;
cryptonote::tx_extra_token_data tdata;
if (!find_tx_extra_field_by_type(fields, tdata))
return;
token_op_type op;
std::vector<std::string> parts;
crypto::signature sig;
bool has_sig;
if (!parse_token_extra(tdata.data, op, parts, sig, has_sig))
return;
// ...verify signer and execute operation...
if (op == token_op_type::transfer)
m_tokens.transfer_by_address(parts[0], parts[1], parts[2], std::stoull(parts[3]));
if (!m_tokens_path.empty())
m_tokens.save(m_tokens_path);
}Token metadata lives in <data-dir>/tokens.bin and is managed by the wallet's token_store class. The loader restores token balances and history:
bool token_store::load(const std::string &file) {
std::ifstream ifs(file, std::ios::binary);
if (!ifs) {
MERROR("Failed to open token store " << file);
return false;
}
try {
boost::archive::binary_iarchive ia(ifs);
token_store_data data;
ia >> data;
tokens = std::move(data.tokens);
transfer_history = std::move(data.transfers);
rebuild_indexes();
} catch(const std::exception &e) {
MERROR("Failed to load token store " << file << ": " << e.what());
return false;
}
return true;
}🧠 Design Notes
- Subaddress-aware: all wallet and RPC operations support subaddress accounts.
- Token IDs are 64-bit identifiers (
token_id) mapped to human-readable names. - Built on top of LMDB, integrated with consensus and mempool validation layer.
⚠️ Known Limitations / Notes
- Tokens do not use RingCT or decoy outputs.
- Only the amount and token ID are visible — sender and recipient are concealed.
- This is a semi-public system designed for hybrid use cases (compliance + privacy).
- Only base wallet addresses can create tokens.
🧰 Developer Tips
- Use
get_subaddress_as_str({account, index})to fetch subaddress strings. - Token creation and ownership is restricted to account index
0. - All token operations are broadcast through the P2P network and mined in blocks.
📅 What's Next
- ✅ Launching on-chain marketplace for token distribution
- 🧪 Semi-Fungible Tokens (SFT) with functionality similar to ERC-1155
- 📜 Open-source release of token subsystem for third-party audit
- 🧩 UI integrations
- 🔐 zkProof + ring signature research for private token metadata (Phase 2)
Modules
Electronero ships language-specific RPC wrappers in the modules/ directory. modules/NodeJs.md shows using electronero.js to access wallet and daemon RPCs from Node.js. modules/PHP.md demonstrates a cURL-based PHP wrapper, while modules/go.md documents a typed Go client. The Python helpers in modules/python.md offer simple DaemonRPC and WalletRPC classes with usage examples.
Merged Pull Requests
- 1d39dbb Fix owner address selection in on_token_burn (#292)
- b448ddd Use account index in token RPC operations (#291)
- 722aaa9 Add RPC validation for token_transfer_ownership (#290)
- 0e3e5b1 Fix token info RPC response (#286)
- dbf30a1 Handle account address defaults for token commands (#284)
- 3793a16 Add creator fee lock feature (#281)
- 150235f Fix serialization signature (#280)
- daa8c30 Add token pause feature (#271)
- e991598 Add token allowance command (#269)
- c7367d0 Add tokens path messages (#260)
- bbdbc75 Add data-dir option to wallet tools (#258)
- 36f95f5 Initialize tokens path after parsing options (#257)
- e6efd3d Fix missing arg_data_dir declaration by including cryptonote_core (#256)
- ea9567b Fix tokens path to respect data-dir (#255)
- 039d892 Reduce tx meta error verbosity (#254)
- 0785ed5 log: print tx meta error once (#253)
- 4043baa fix fee assignment when finalizing split transactions (#252)
- 80d2f15 Add token listing improvements (#244)
- 456a472 Fix token rescan duplication (#243)
- 6178ec3 Ksl7ca codex/create basic mobile app with react native or flutter (#235)
- 22d4381 Add Flutter app alongside React Native (#234)
- a4dd2cc Add Flutter app alongside React Native (#233)
- 75257e5 Allow integrated addresses in token transfers (#217)
- a886f63 Avoid double application of token transactions (#232)
- 41d6448 Add signature enforcement for token ops after activation height (#227)
- b6656a0 Enhance sign-in flow with keypad PIN (#230)
- 14dcdcc Fix expo entry and dependencies (#229)
- 6762dc1 Add Sign In flow with PIN code (#228)
- 5036aa9 Load token data on RPC init (#223)
- 8bc13b7 Fix token address index when rescanning (#210)
- fcc81e7 Fix token rescan to handle...