OPAX-28 Token Standard
Native fungible token standard for ArgusVM and OpenLang - EVM-compatible but optimized for Paxeer
Overview
OPAX-28 is the native fungible token standard for Paxeer Network, designed specifically for ArgusVM's register-based architecture and OpenLang's Rust-inspired syntax. Unlike ERC-20, OPAX-28 provides improved safety, gas efficiency, and native integration with Paxeer's execution environment.
Native Standard: OPAX-28 is part of Paxeer's self-sustainable ecosystem. While compatible with ERC-20 concepts, it's optimized for ArgusVM and OpenLang, providing better performance and safety guarantees.
ArgusVM Optimized
Designed for register-based architecture
Built-in Safety
Automatic overflow protection
OpenLang Native
Rust-inspired syntax
Why OPAX-28?
Part of the Self-Sustainable Ecosystem
OPAX-28 is not just another token standard—it's a fundamental building block of Paxeer's independent infrastructure:
Specification
Interface
All OPAX-28 compliant tokens MUST implement the following interface:
trait OPAX28 {
// Read-only functions
pub view fn name() -> bytes;
pub view fn symbol() -> bytes;
pub view fn decimals() -> u256;
pub view fn total_supply() -> u256;
pub view fn balance_of(owner: address) -> u256;
pub view fn allowance(owner: address, spender: address) -> u256;
// State-changing functions
pub fn transfer(to: address, amount: u256) -> bool;
pub fn transfer_from(from: address, to: address, amount: u256) -> bool;
pub fn approve(spender: address, amount: u256) -> bool;
}Events
OPAX-28 tokens MUST emit the following events:
event Transfer(from: address indexed, to: address indexed, amount: u256);
event Approval(owner: address indexed, spender: address indexed, amount: u256);Function Reference
Read-Only Functions
pub view fn name() -> bytesReturns: Human-readable token name (e.g., "OpenNet Coin")
View: Does not modify state
Example:
let token_name = token.name();
// Returns: b"Paxeer Token"pub view fn symbol() -> bytesReturns: Token ticker symbol (e.g., "OPEN")
View: Does not modify state
Example:
let token_symbol = token.symbol();
// Returns: b"PAX"pub view fn decimals() -> u256Returns: Number of decimal places (typically 6, 8, or 18)
View: Does not modify state
Note: Used for display only; all amounts are stored as base units
Example:
let decimals = token.decimals();
// Returns: 18pub view fn total_supply() -> u256Returns: Total token supply in base units
View: Does not modify state
Example:
let supply = token.total_supply();
// Returns: 1000000000000000000000000 (1M tokens with 18 decimals)pub view fn balance_of(owner: address) -> u256Parameters:
owner- Address to query
Returns: Token balance of owner in base units
Example:
let balance = token.balance_of(0x1234...);
// Returns: 500000000000000000000 (500 tokens with 18 decimals)pub view fn allowance(owner: address, spender: address) -> u256Parameters:
owner- Token owner's addressspender- Authorized spender's address
Returns: Remaining allowance for spender to spend on behalf of owner
Example:
let allowance = token.allowance(owner, spender);
// Returns: 1000000000000000000 (1 token with 18 decimals)State-Changing Functions
pub fn transfer(to: address, amount: u256) -> boolParameters:
to- Recipient addressamount- Amount to transfer in base units
Returns: true on success
Reverts if:
tois zero addressmsg.senderhas insufficient balance- Arithmetic overflow occurs
Emits: Transfer(msg.sender, to, amount)
Example:
token.transfer(recipient, 1000000000000000000); // Transfer 1 tokenpub fn transfer_from(from: address, to: address, amount: u256) -> boolParameters:
from- Source addressto- Recipient addressamount- Amount to transfer in base units
Returns: true on success
Reverts if:
toorfromis zero addressfromhas insufficient balancemsg.senderhas insufficient allowance- Arithmetic overflow occurs
Effects: Decreases msg.sender's allowance by amount
Emits: Transfer(from, to, amount)
Example:
token.transfer_from(owner, recipient, 1000000000000000000);pub fn approve(spender: address, amount: u256) -> boolParameters:
spender- Address authorized to spend tokensamount- Allowance amount in base units
Returns: true on success
Reverts if:
spenderis zero address
Effects: Sets allowance for spender to amount
Emits: Approval(msg.sender, spender, amount)
Security: To prevent front-running attacks, UIs should set allowance to 0 before changing to a new value.
Example:
token.approve(spender, 1000000000000000000); // Approve 1 tokenReference Implementation
Complete OPAX-28 token implementation in OpenLang:
contract OPAX28Token {
state name: bytes;
state symbol: bytes;
state decimals: u256;
state total_supply: u256;
state balances: Map<address, u256>;
state allowances: Map<address, Map<address, u256>>;
event Transfer(from: address indexed, to: address indexed, amount: u256);
event Approval(owner: address indexed, spender: address indexed, amount: u256);
init(name_: bytes, symbol_: bytes, decimals_: u256, initial_supply: u256) {
name = name_;
symbol = symbol_;
decimals = decimals_;
total_supply = initial_supply;
balances[msg.sender] = initial_supply;
emit Transfer(address(0), msg.sender, initial_supply);
}
pub view fn name() -> bytes {
return name;
}
pub view fn symbol() -> bytes {
return symbol;
}
pub view fn decimals() -> u256 {
return decimals;
}
pub view fn total_supply() -> u256 {
return total_supply;
}
pub view fn balance_of(owner: address) -> u256 {
return balances[owner];
}
pub view fn allowance(owner: address, spender: address) -> u256 {
return allowances[owner][spender];
}
pub fn transfer(to: address, amount: u256) -> bool {
require(to != address(0), "transfer to zero address");
require(balances[msg.sender] >= amount, "insufficient balance");
balances[msg.sender] = balances[msg.sender] - amount;
balances[to] = balances[to] + amount;
emit Transfer(msg.sender, to, amount);
return true;
}
pub fn transfer_from(from: address, to: address, amount: u256) -> bool {
require(from != address(0), "transfer from zero address");
require(to != address(0), "transfer to zero address");
require(balances[from] >= amount, "insufficient balance");
require(allowances[from][msg.sender] >= amount, "insufficient allowance");
balances[from] = balances[from] - amount;
balances[to] = balances[to] + amount;
allowances[from][msg.sender] = allowances[from][msg.sender] - amount;
emit Transfer(from, to, amount);
return true;
}
pub fn approve(spender: address, amount: u256) -> bool {
require(spender != address(0), "approve to zero address");
allowances[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
}Differences from ERC-20
Type System
- Explicit
bytestype for name/symbol instead ofstring - Native
u256for all amounts - Map types instead of
mapping
Syntax
- Rust-inspired:
fninstead offunction - Return types:
->syntax - Explicit
emitkeyword for events
Safety
- Built-in overflow protection (no SafeMath needed)
- Explicit
require()statements - Type safety at compile time
Performance
- Optimized for ArgusVM register architecture
- Better gas efficiency
- Native compilation to AVM bytecode
Security Considerations
Overflow Protection
OpenLang provides automatic overflow protection. All arithmetic operations revert on overflow/underflow—no need for SafeMath library!
// Safe by default - no overflow possible
balances[msg.sender] = balances[msg.sender] - amount; // Reverts if underflow
balances[to] = balances[to] + amount; // Reverts if overflowZero Address Checks
The reference implementation prevents transfers to/from the zero address, which would burn tokens unintentionally:
require(to != address(0), "transfer to zero address");
require(from != address(0), "transfer from zero address");Approval Race Condition
To prevent front-running attacks when changing allowances:
- Check current allowance before changing
- Set allowance to 0, then new value (two transactions)
- Or use
increase_allowance()/decrease_allowance()extension (recommended)
Reentrancy Protection
OPAX-28 functions are designed to be reentrancy-safe by following the checks-effects-interactions pattern:
// 1. Checks
require(balances[from] >= amount, "insufficient balance");
// 2. Effects (state changes first)
balances[from] -= amount;
balances[to] += amount;
// 3. Interactions (external calls last, if any)
emit Transfer(from, to, amount);Extensions
OPAX-28 Metadata (OPTIONAL)
Provides additional token metadata:
pub view fn name() -> bytes;
pub view fn symbol() -> bytes;
pub view fn decimals() -> u256;OPAX-28 Capped (OPTIONAL)
Limits total supply:
pub view fn cap() -> u256;Example:
contract CappedToken is OPAX28Token {
state cap: u256;
pub fn mint(to: address, amount: u256) {
require(total_supply + amount <= cap, "cap exceeded");
// ... mint logic
}
}OPAX-28 Burnable (OPTIONAL)
Allows token burning:
pub fn burn(amount: u256);
pub fn burn_from(account: address, amount: u256);Example:
pub fn burn(amount: u256) {
require(balances[msg.sender] >= amount, "insufficient balance");
balances[msg.sender] -= amount;
total_supply -= amount;
emit Transfer(msg.sender, address(0), amount);
}OPAX-28 Mintable (OPTIONAL)
Allows controlled minting:
pub fn mint(to: address, amount: u256);Example:
pub fn mint(to: address, amount: u256) {
require(msg.sender == minter, "only minter");
balances[to] += amount;
total_supply += amount;
emit Transfer(address(0), to, amount);
}Backward Compatibility
OPAX-28 is NOT compatible with ERC-20 at the bytecode level due to different VM architectures (ArgusVM vs EVM).
However, compatibility is maintained at the interface level:
- Function selectors: Use FNV-1a (may upgrade to keccak256)
- Event signatures: Similar for off-chain indexing
- ABI encoding: Follows 32-byte word alignment
Cross-Chain Bridges
Cross-chain bridges must implement explicit translation layers:
Lock OPAX-28 Tokens
Lock tokens on Paxeer Network
Bridge Translation
Bridge translates OPAX-28 to ERC-20 format
Mint on Destination
Mint equivalent ERC-20 tokens on destination chain
Reverse Process
Burn ERC-20, unlock OPAX-28 on Paxeer
Integration Examples
Deploying an OPAX-28 Token
// Deploy with OpenLang
contract MyToken is OPAX28Token {
init() {
super.init(
b"My Token",
b"MTK",
18,
1000000000000000000000000 // 1M tokens
);
}
}Interacting with OPAX-28 Tokens
// Transfer tokens
token.transfer(recipient, 1000000000000000000); // 1 token
// Check balance
let balance = token.balance_of(msg.sender);
// Approve spending
token.approve(spender, 5000000000000000000); // 5 tokens
// Transfer from (by approved spender)
token.transfer_from(owner, recipient, 1000000000000000000);DEX Integration
contract SimpleDEX {
state token: OPAX28Token;
state eth_reserve: u256;
state token_reserve: u256;
pub fn swap_eth_for_tokens() -> u256 {
let eth_amount = msg.value;
let token_amount = (eth_amount * token_reserve) / eth_reserve;
require(token.balance_of(address(this)) >= token_amount, "insufficient liquidity");
eth_reserve += eth_amount;
token_reserve -= token_amount;
token.transfer(msg.sender, token_amount);
return token_amount;
}
}Gas Costs
OPAX-28 operations are optimized for ArgusVM:
| Operation | Gas Cost (Estimated) |
|---|---|
transfer() | ~21,000 gas |
transfer_from() | ~35,000 gas |
approve() | ~46,000 gas |
balance_of() | ~2,100 gas |
allowance() | ~2,100 gas |
Gas costs are lower than ERC-20 due to register-based architecture and optimized bytecode.
Testing
Test Suite
Comprehensive test suite covering:
- ✅ Basic transfers
- ✅ Allowance and
transfer_from - ✅ Edge cases (zero address, insufficient balance)
- ✅ Overflow protection
- ✅ Event emission
- ✅ Reentrancy protection
Example Test
#[test]
fn test_transfer() {
let token = deploy_token();
let alice = address(0x1);
let bob = address(0x2);
// Initial balance
assert_eq(token.balance_of(alice), 1000);
// Transfer
token.transfer(bob, 100);
// Check balances
assert_eq(token.balance_of(alice), 900);
assert_eq(token.balance_of(bob), 100);
}Resources
ArgusVM Documentation
Learn about the execution environment
OpenLang Guide
Master OpenLang syntax
Smart Contracts
Deploy contracts on Paxeer
PaxDex Protocol
Build DEXes with OPAX-28
Status
Standard Status: Draft
Created: 2025-11-04
Category: Token Standard
Network: Paxeer Network & OpenNet
Copyright
Copyright (C) 2025 Paxeer Foundation | OpenLabs LTD. This document is licensed under CC0 1.0 Universal.
Join the Ecosystem: OPAX-28 is part of Paxeer's self-sustainable infrastructure. Build native tokens optimized for ArgusVM and experience the future of blockchain standards!
How is this guide?