# VisitorBook lib.rs ```rust #![cfg_attr(not(feature = "export-abi"), no_main)] extern crate alloc; use stylus_sdk::{ alloy_primitives::{Address, U256}, msg, prelude::*, }; sol_storage! { #[entrypoint] pub struct VisitorBook { address[] visitors; mapping(address => bool) has_visited; } } #[public] impl VisitorBook { // Function to record a new visitor pub fn sign_guestbook(&mut self) { let visitor = msg::sender(); // Check if the address has already visited if !self.has_visited.get(visitor) { // Add to visitors array self.visitors.push(visitor); // Mark as visited self.has_visited.setter(visitor).set(true); } } // Get total number of unique visitors pub fn get_total_visitors(&self) -> U256 { U256::from(self.visitors.len()) } // Get visitor at specific index pub fn get_visitor_at_index(&self, index: U256) -> Address { self.visitors.get(index).unwrap() } // Check if an address has visited pub fn has_address_visited(&self, address: Address) -> bool { self.has_visited.get(address) } } ``` # Fancy VisitorBook Cargo.toml ```toml [dependencies] stylus-sdk = "0.6.0" alloy-primitives = { version = "=0.7.6", default-features = false } alloy-sol-types = { version = "=0.7.6", default-features = false } alloy-sol-macro = { version = "=0.7.6", default-features = false } alloy-sol-macro-expander = { version = "=0.7.6", default-features = false } alloy-sol-macro-input = { version = "=0.7.6", default-features = false } ``` lib.rs ```rust #![cfg_attr(not(feature = "export-abi"), no_main)] extern crate alloc; use stylus_sdk::{ alloy_primitives::{Address, U256}, alloy_sol_types::sol, call::transfer_eth, contract, evm, msg, prelude::*, }; sol! { event Visit(address indexed sender, string message); error InsufficientPayment(address visitor, uint256 payment); error TransferFailed(address recipient, uint256 amount); error AlreadyVisited(); error IndexOutOfBounds(); } sol_storage! { #[entrypoint] pub struct VisitorBook { uint256 fee; address[] visitors; mapping(address => bool) has_visited; } } #[derive(SolidityError)] pub enum VisitorBookErrors { InsufficientPayment(InsufficientPayment), TransferFailed(TransferFailed), AlreadyVisited(AlreadyVisited), IndexOutOfBounds(IndexOutOfBounds), } #[public] impl VisitorBook { pub fn initialize(&mut self) { // Initialize constants self.fee.set(U256::from(100)); } // Function to record a new visitor pub fn sign_guestbook(&mut self, message: String) -> Result<(), VisitorBookErrors> { let visitor = msg::sender(); let value = msg::value(); // Require a payment of 100 wei if value < self.fee.get() { return Err(VisitorBookErrors::InsufficientPayment( InsufficientPayment { visitor, payment: value, }, )); } // Check if the address has already visited if self.has_visited.get(visitor) { return Err(VisitorBookErrors::AlreadyVisited(AlreadyVisited {})); } // Add to visitors array self.visitors.push(visitor); // Mark as visited self.has_visited.setter(visitor).set(true); // Emit event evm::log(Visit { sender: visitor, message, }); // Transfer reward if contract::balance() >= self.fee.get() { if let Err(_) = transfer_eth(visitor, self.fee.get()) { return Err(VisitorBookErrors::TransferFailed(TransferFailed { recipient: visitor, amount: self.fee.get(), })); } } Ok(()) } // Get total number of unique visitors pub fn get_total_visitors(&self) -> U256 { U256::from(self.visitors.len()) } // Get visitor at specific index pub fn get_visitor_at_index(&self, index: U256) -> Result<Address, VisitorBookErrors> { self.visitors .get(index) .ok_or(VisitorBookErrors::IndexOutOfBounds(IndexOutOfBounds {})) } // Check if an address has visited pub fn has_address_visited(&self, address: Address) -> bool { self.has_visited.get(address) } } ```