Subcurrency

The following is a simple example of a subcurrency which implements functionality to mint and send a token. It is a ledger-based token, i.e. the contract maintains a ledger of user account balances.

Being a ledger-based token, this example does not use Fuel's native asset system. It is not recommended to actually use ledger-based tokens in production; this example is here purely for illustrative purposes.

contract; use std::hash::sha256; //////////////////////////////////////// // Event declarations //////////////////////////////////////// // // Events allow clients to react to changes in the contract. // Unlike Solidity, events are simply structs. // /// Emitted when a token is sent. struct Sent { from: Address, to: Address, amount: u64, } //////////////////////////////////////// // ABI method declarations //////////////////////////////////////// /// ABI for a subcurrency. abi Token { // Mint new tokens and send to an address. // Can only be called by the contract creator. #[storage(read, write)] fn mint(receiver: Address, amount: u64); // Sends an amount of an existing token. // Can be called from any address. #[storage(read, write)] fn send(receiver: Address, amount: u64); } //////////////////////////////////////// // Constants //////////////////////////////////////// /// Address of contract creator. const MINTER = Address::from(0x9299da6c73e6dc03eeabcce242bb347de3f5f56cd1c70926d76526d7ed199b8b); //////////////////////////////////////// // Contract storage //////////////////////////////////////// // Contract storage persists across transactions. storage { balances: StorageMap<Address, u64> = StorageMap {}, } //////////////////////////////////////// // ABI definitions //////////////////////////////////////// /// Contract implements the `Token` ABI. impl Token for Contract { #[storage(read, write)] fn mint(receiver: Address, amount: u64) { let sender = msg_sender().unwrap(); let sender: Address = match sender { Identity::Address(addr) => { assert(addr == MINTER); addr }, _ => revert(0), }; // Increase the balance of receiver storage.balances.insert(receiver, storage.balances.get(receiver).try_read().unwrap_or(0) + amount); } #[storage(read, write)] fn send(receiver: Address, amount: u64) { let sender = msg_sender().unwrap(); let sender = match sender { Identity::Address(addr) => addr, _ => revert(0), }; // Reduce the balance of sender let sender_amount = storage.balances.get(sender).try_read().unwrap_or(0); assert(sender_amount > amount); storage.balances.insert(sender, sender_amount - amount); // Increase the balance of receiver storage.balances.insert(receiver, storage.balances.get(receiver).try_read().unwrap_or(0) + amount); log(Sent { from: sender, to: receiver, amount: amount, }); } }