This guide will walk you through the process of creating and deploying your first token on the Pharos blockchain using Rust and WASM toolchains. By the end of this guide, you will have a fully functional token contract and understand how to interact with it.
Copy cargo install --git https://github.com/PharosNetwork/pharos-cargo-stylus
Copy rustup target add wasm32-unknown-unknown
Copy cargo stylus --help
Cargo subcommand for developing Pharos Stylus projects
Copy git clone https://github.com/PharosNetwork/examples
cd examples/token/rust/contract
Copy // Only run this as a WASM if the export-abi feature is not set.
#![cfg_attr(not(any(feature = "export-abi", test)), no_main)]
extern crate alloc;
// Modules and imports
mod erc20;
use crate::erc20::{Erc20, Erc20Error, Erc20Params};
use alloy_primitives::{Address, U256};
use stylus_sdk::{msg, prelude::*};
/// Immutable definitions
struct StylusTestTokenParams;
impl Erc20Params for StylusTestTokenParams {
const NAME: &'static str = "StylusTestToken";
const SYMBOL: &'static str = "STTK";
const DECIMALS: u8 = 18;
}
// Define the entrypoint as a Solidity storage object. The sol_storage! macro
// will generate Rust-equivalent structs with all fields mapped to Solidity-equivalent
// storage slots and types.
sol_storage! {
#[entrypoint]
struct StylusTestToken {
// Allows erc20 to access StylusTestToken's storage and make calls
#[borrow]
Erc20<StylusTestTokenParams> erc20;
}
}
#[public]
#[inherit(Erc20<StylusTestTokenParams>)]
impl StylusTestToken {
/// Mints tokens
pub fn mint(&mut self, value: U256) -> Result<(), Erc20Error> {
self.erc20.mint(msg::sender(), value)?;
Ok(())
}
/// Mints tokens to another address
pub fn mint_to(&mut self, to: Address, value: U256) -> Result<(), Erc20Error> {
self.erc20.mint(to, value)?;
Ok(())
}
/// Burns tokens
pub fn burn(&mut self, value: U256) -> Result<(), Erc20Error> {
self.erc20.burn(msg::sender(), value)?;
Ok(())
}
}
Copy cargo stylus check --endpoint=<PHAROS_RPC_URL>
Copy cargo stylus deploy --private-key=<YOUR_PRIVATE_KEY> --endpoint=<PHAROS_RPC_URL>
Copy from web3 import Web3
# Replace Pharos RPC URL
RPC_URL = "<Pharos RPC URL>"
# Note: Replace this address to your contract address
CONTRACT_ADDRESS = Web3.to_checksum_address("0x8ca06d75562be39f645b3b1ead98b15ddfd8c06f")
PRIVATE_KEY = "0xfcfc69bd0056a2592e1f46cfba8264d8918fe98ecf5a2ef43aaa4ed1463725e1"
contract_abi = [
{
"inputs": [],
"name": "name",
"outputs": [{"internalType": "string", "name": "", "type": "string"}],
"stateMutability": "pure",
"type": "function",
},
{
"inputs": [],
"name": "symbol",
"outputs": [{"internalType": "string", "name": "", "type": "string"}],
"stateMutability": "pure",
"type": "function",
},
{
"inputs": [],
"name": "decimals",
"outputs": [{"internalType": "uint8", "name": "", "type": "uint8"}],
"stateMutability": "pure",
"type": "function",
},
{
"inputs": [],
"name": "totalSupply",
"outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
"stateMutability": "view",
"type": "function",
},
{
"inputs": [{"internalType": "address", "name": "owner", "type": "address"}],
"name": "balanceOf",
"outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
"stateMutability": "view",
"type": "function",
},
{
"inputs": [{"internalType": "address", "name": "to", "type": "address"}, {"internalType": "uint256", "name": "value", "type": "uint256"}],
"name": "transfer",
"outputs": [{"internalType": "bool", "name": "", "type": "bool"}],
"stateMutability": "nonpayable",
"type": "function",
},
{
"inputs": [{"internalType": "address", "name": "from", "type": "address"}, {"internalType": "address", "name": "to", "type": "address"}, {"internalType": "uint256", "name": "value", "type": "uint256"}],
"name": "transferFrom",
"outputs": [{"internalType": "bool", "name": "", "type": "bool"}],
"stateMutability": "nonpayable",
"type": "function",
},
{
"inputs": [{"internalType": "address", "name": "spender", "type": "address"}, {"internalType": "uint256", "name": "value", "type": "uint256"}],
"name": "approve",
"outputs": [{"internalType": "bool", "name": "", "type": "bool"}],
"stateMutability": "nonpayable",
"type": "function",
},
{
"inputs": [{"internalType": "address", "name": "owner", "type": "address"}, {"internalType": "address", "name": "spender", "type": "address"}],
"name": "allowance",
"outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
"stateMutability": "view",
"type": "function",
},
{
"inputs": [{"internalType": "uint256", "name": "value", "type": "uint256"}],
"name": "mint",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function",
},
{
"inputs": [{"internalType": "address", "name": "to", "type": "address"}, {"internalType": "uint256", "name": "value", "type": "uint256"}],
"name": "mintTo",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function",
},
{
"inputs": [{"internalType": "uint256", "name": "value", "type": "uint256"}],
"name": "burn",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function",
},
]
w3 = Web3(Web3.HTTPProvider(RPC_URL))
print(f"Connected to Ethereum: {w3.is_connected()}")
contract = w3.eth.contract(address=CONTRACT_ADDRESS, abi=contract_abi)
your_address = w3.eth.account.from_key(PRIVATE_KEY).address
print(f"Your Address: {your_address}")
print(f"Your Balance: {contract.functions.balanceOf(your_address).call()}")
Copy python3 -m pip install web3 && python3 scripts/main.py
Now that you’ve created and deployed your first token using Rust. This guide provides a comprehensive introduction to creating and deploying a token on the Pharos blockchain using Rust. If you encounter any issues, refer to the Troubleshooting section or consult the Rust documentation. Happy building! 🚀