当前位置: 首页 > wzjs >正文

凡科做的网站为什么搜不到河南省住建厅网站官网

凡科做的网站为什么搜不到,河南省住建厅网站官网,网络服务商和网络运营商,网站方案书在《Arbitrum Stylus 深入解析与 Rust 合约部署实战》篇中,我们深入探讨了 Arbitrum Stylus 的核心技术架构,包括其 MultiVM 机制、Rust 合约开发环境搭建,以及通过 cargo stylus 实现简单计数器合约的部署与测试。Stylus 作为 Arbitrum Nitr…

在《Arbitrum Stylus 深入解析与 Rust 合约部署实战》篇中,我们深入探讨了 Arbitrum Stylus 的核心技术架构,包括其 MultiVM 机制、Rust 合约开发环境搭建,以及通过 cargo stylus 实现简单计数器合约的部署与测试。Stylus 作为 Arbitrum Nitro 的升级,允许开发者使用 Rust、C++ 等语言编写高效的 WebAssembly(WASM)合约,显著降低了 Gas 成本并提升了性能。本文将更进一步,使用 Rust 在 Stylus 上实现 ERC20  标准合约,并在 Arbitrum Sepolia 上完成部署实战,带您从代码到上链一步到位

1. 前置准备:开发环境与工具链

在开始编写 ERC20  合约之前,确保开发环境已正确配置,在我的《Arbitrum Stylus 深入解析与rust合约部署实战》中,已经有这段内容了,也可以移步到那里先配置好环境:

  • Rust 工具链:安装 Rust 和 Cargo
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/env
  • cargo-stylus 是 Stylus 合约开发的 CLI 工具,用于编译、检查和部署
cargo install --force cargo-stylus
  • WASM (WebAssembly)  设置 WASM 作为 Rust 编译器的构建目标,可以看到这里执行的第三个和第四个命令有重叠的地方,官方文档是只需要执行第四个命令,但是经过我的实践,有可能会报错,提示说需要执行第三个命令,看过我上一篇《Arbitrum Stylus 深入解析与rust合约部署实战》的观众就会知道有这个问题, 所以为了保险起见,这里一并执行了
rustup install 1.81
rustup default 1.81
rustup target add wasm32-unknown-unknown
rustup target add wasm32-unknown-unknown --toolchain 1.81
  • 安装好docker并启动 

2. ERC20 合约:设计与实现

ERC20 是代币标准,支持转账、余额查询等功能,关于ERC协议,我会专门出一期来讲,这里就不展开讲了。这里我们将实现一个简单的 ERC20 代币,我们先来创建项目:

cargo stylus new stylus-tokens

然后在 vscode 中打开项目,我是在 wsl 中,直接执行 code .   就OK。然后,我们修改rust-toolchain.toml 中的版本 为 1.81.0

 接下来我们在src 下面创建 erc20.rs 文件,并复制或者手敲一遍我给的代码,在代码中,每一行我都加上了详细的注释:

// 引入 alloc 模块中的 String 类型,用于动态字符串
use alloc::string::String;
// 引入 alloy_primitives 库中的 Address 和 U256 类型,用于处理以太坊地址和256位无符号整数
use alloy_primitives::{Address, U256};
// 引入 alloy_sol_types 库中的 sol 宏,用于定义 Solidity 风格的数据结构和事件
use alloy_sol_types::sol;
// 引入 PhantomData,用于在泛型中占位,标记类型但不实际存储数据
use core::marker::PhantomData;
// 引入 stylus_sdk 的 msg evm 和 prelude 模块,提供以太坊虚拟机交互和消息处理功能
use stylus_sdk::{evm, msg, prelude::*};// 定义 Erc20Params 特质,用于指定 ERC20 代币的静态参数
pub trait Erc20Params {const NAME: &'static str; // 代币名称,静态字符串const SYMBOL: &'static str; // 代币符号,静态字符串const DECIMALS: u8; // 代币小数位数
}// 使用 sol_storage 宏定义 Solidity 风格的存储结构
sol_storage! {// 定义泛型结构体 Erc20,T 需实现 Erc20Params 特质pub struct Erc20<T> {// 地址到余额的映射,存储每个地址的代币余额mapping(address => uint256) balances;// 地址到授权额度的映射,记录每个地址对其他地址的代币授权mapping(address => mapping(address => uint256)) allowances;// 代币总供应量uint256 total_supply;// 占位符,确保泛型 T 被使用但不占用存储空间PhantomData<T> phantom;}
}// 使用 sol 宏定义 Solidity 风格的事件和错误
sol! {// 定义 Transfer 事件,记录代币转账信息event Transfer(address indexed from, address indexed to, uint256 value);// 定义 Approval 事件,记录代币授权信息event Approval(address indexed owner, address indexed spender, uint256 value);// 定义错误:余额不足error InsufficientBalance(address from, uint256 have, uint256 want);// 定义错误:授权额度不足error InsufficientAllowance(address owner, address spender, uint256 have, uint256 want);
}// 标记 Erc20Error 为 Solidity 风格的错误类型
#[derive(SolidityError)]// 定义 ERC20 错误枚举
pub enum Erc20Error {// 余额不足错误InsufficientBalance(InsufficientBalance),// 授权额度不足错误InsufficientAllowance(InsufficientAllowance),
}// 为 Erc20 结构体实现方法,T 需实现 Erc20Params 特质
impl<T: Erc20Params> Erc20<T> {// 内部转账函数,执行代币转账逻辑pub fn _transfer(&mut self, from: Address, to: Address, value: U256) -> Result<(), Erc20Error> {// 获取发送者余额的 setterlet mut sender_balance = self.balances.setter(from);// 获取发送者的当前余额let old_sender_balance = sender_balance.get();if old_sender_balance < value {// 检查发送者余额是否足够return Err(Erc20Error::InsufficientBalance(InsufficientBalance {// 返回余额不足错误from,                     // 发送者地址have: old_sender_balance, // 当前余额want: value,              // 所需金额}));}// 扣除发送者余额sender_balance.set(old_sender_balance - value);// 获取接收者余额的 setterlet mut to_balance = self.balances.setter(to);// 计算接收者的新余额let new_to_balance = to_balance.get() + value;// 更新接收者余额to_balance.set(new_to_balance);// 记录转账事件到 EVM 日志evm::log(Transfer { from, to, value });Ok(())}// 铸造代币函数pub fn mint(&mut self, address: Address, value: U256) -> Result<(), Erc20Error> {// 获取目标地址余额的 setterlet mut balance = self.balances.setter(address);// 计算新余额let new_balance = balance.get() + value;// 更新目标地址余额balance.set(new_balance);// 增加总供应量self.total_supply.set(self.total_supply.get() + value);// 记录铸造事件(从零地址转账)evm::log(Transfer {from: Address::ZERO, // 零地址表示铸造to: address,         // 目标地址value,               // 铸造数量});Ok(())}// 销毁代币函数pub fn burn(&mut self, address: Address, value: U256) -> Result<(), Erc20Error> {// 获取目标地址余额的 setterlet mut balance = self.balances.setter(address);// 获取当前余额let old_balance = balance.get();if old_balance < value {// 检查余额是否足够销毁return Err(Erc20Error::InsufficientBalance(InsufficientBalance {// 返回余额不足错误from: address,     // 目标地址have: old_balance, // 当前余额want: value,       // 所需销毁金额}));}// 扣除余额balance.set(old_balance - value);// 减少总供应量self.total_supply.set(self.total_supply.get() - value);// 记录销毁事件(转账到零地址)evm::log(Transfer {from: address,     // 目标地址to: Address::ZERO, // 零地址表示销毁value,             // 销毁数量});Ok(())}
}// 标记以下方法为公开,暴露给外部调用
#[public]
// 为 Erc20 实现公开方法
impl<T: Erc20Params> Erc20<T> {// 返回代币名称pub fn name() -> String {// 将静态名称转换为 StringT::NAME.into()}// 返回代币符号pub fn symbol() -> String {// 将静态符号转换为 StringT::SYMBOL.into()}// 返回代币小数位数pub fn decimals() -> u8 {// 返回静态小数位数T::DECIMALS}// 返回代币总供应量pub fn total_supply(&self) -> U256 {// 获取存储中的总供应量self.total_supply.get()}// 查询指定地址的余额pub fn balance_of(&self, owner: Address) -> U256 {// 从映射中获取余额self.balances.get(owner)}// 转账函数pub fn transfer(&mut self, to: Address, value: U256) -> Result<bool, Erc20Error> {// 调用内部转账函数,从调用者转账self._transfer(msg::sender(), to, value)?;Ok(true)}// 授权转账函数,允许 spender 从 from 地址转账pub fn transfer_from(&mut self,from: Address,to: Address,value: U256,) -> Result<bool, Erc20Error> {// 获取 from 地址的授权映射let mut sender_allowances = self.allowances.setter(from);// 获取调用者的授权额度let mut allowance = sender_allowances.setter(msg::sender());// 获取当前授权额度let old_allowance = allowance.get();// 检查授权额度是否足够if old_allowance < value {// 返回授权不足错误return Err(Erc20Error::InsufficientAllowance(InsufficientAllowance {owner: from,            // 拥有者地址spender: msg::sender(), // 花费者地址have: old_allowance,    // 当前授权额度want: value,            // 所需授权额度}));}// 扣除授权额度allowance.set(old_allowance - value);// 执行转账self._transfer(from, to, value)?;Ok(true)}// 授权函数,允许 spender 花费指定金额pub fn approve(&mut self, spender: Address, value: U256) -> bool {// 设置授权额度self.allowances.setter(msg::sender()).insert(spender, value);// 记录授权事件evm::log(Approval {owner: msg::sender(), // 授权者地址spender,              // 被授权者地址value,                // 授权金额});true}// 查询授权额度pub fn allowance(&self, owner: Address, spender: Address) -> U256 {// 从映射中获取指定授权额度self.allowances.getter(owner).get(spender)}
}

接着在 src 文件夹 中创建 lib.rs:

// 条件编译属性:除非启用 export-abi 或 test 功能,否则不生成 main 函数
#![cfg_attr(not(any(feature = "export-abi", test)), no_main)]
// 引入 alloc 模块,支持动态内存分配
extern crate alloc;
// 引入 erc20 模块,包含 ERC20 代币逻辑
mod erc20;// 从 erc20 模块导入 Erc20 结构体、错误类型和参数特质
use crate::erc20::{Erc20, Erc20Error, Erc20Params};
// 引入 Address 和 U256 类型
use alloy_primitives::{Address, U256};
// 引入 stylus_sdk 的消息处理和预定义功能
use stylus_sdk::{msg, prelude::*};// 定义 StylusTokenParams 结构体,用于指定代币参数
struct StylusTokenParams;
// 为 StylusTokenParams 实现 Erc20Params 特质
impl Erc20Params for StylusTokenParams {const NAME: &'static str = "StylusToken";const SYMBOL: &'static str = "STK";// 代币小数位数:18const DECIMALS: u8 = 18;
}// 使用 sol_storage 宏定义存储结构
sol_storage! {// 标记 StylusToken 为合约入口点#[entrypoint]// 定义 StylusToken 结构体struct StylusToken {// 标记 erc20 字段为借用,继承 Erc20 功能#[borrow]// 嵌入 Erc20 结构体,使用 StylusTokenParams 参数Erc20<StylusTokenParams> erc20;}
}// 标记以下方法为公开
#[public]
// 继承 Erc20<StylusTokenParams> 的方法
#[inherit(Erc20<StylusTokenParams>)]
// 为 StylusToken 实现方法
impl StylusToken {// 铸造代币到调用者地址pub fn mint(&mut self, value: U256) -> Result<(), Erc20Error> {// 调用 Erc20 的 mint 方法self.erc20.mint(msg::sender(), value)?;Ok(())}// 铸造代币到指定地址pub fn mint_to(&mut self, to: Address, value: U256) -> Result<(), Erc20Error> {// 调用 Erc20 的 mint 方法self.erc20.mint(to, value)?;Ok(())}// 销毁调用者的代币pub fn burn(&mut self, value: U256) -> Result<(), Erc20Error> {// 调用 Erc20 的 burn 方法self.erc20.burn(msg::sender(), value)?;Ok(())}
}

接着是 main.rs 中的内容:

 // 条件编译属性:除非启用 test 或 export-abi 功能,否则不生成 main 函数
#![cfg_attr(not(any(test, feature = "export-abi")), no_main)]// 条件编译:当 test 和 export-abi 均未启用时
#[cfg(not(any(test, feature = "export-abi")))] // 禁止名称修饰,确保函数名在编译后保持不变
#[no_mangle]
// 定义空的 main 函数,用于合约入口
pub extern "C" fn main() {} // 条件编译:当启用 export-abi 功能时
#[cfg(feature = "export-abi")] 
// 定义 main 函数,用于导出 ABI
fn main() { // 调用 print_abi 函数,生成 Solidity ABI,指定许可证和 Solidity 版本stylus_tokens::print_abi("MIT-OR-APACHE-2.0", "pragma solidity ^0.8.23;"); 
}

Cargo.toml 中的配置:

[package]
name = "stylus_tokens"
version = "0.1.11"
edition = "2021"
license = "MIT OR Apache-2.0"
homepage = "https://github.com/OffchainLabs/stylus-hello-world"
repository = "https://github.com/OffchainLabs/stylus-hello-world"
keywords = ["arbitrum", "ethereum", "stylus", "alloy"]
description = "Stylus tokens example"[dependencies]
alloy-primitives = "=0.8.20"
alloy-sol-types = "=0.8.20"
mini-alloc = "0.4.2"
stylus-sdk = "0.8.0"
hex = "0.4.3"
dotenv = "0.15.0"[dev-dependencies]
tokio = { version = "1.12.0", features = ["full"] }
ethers = "2.0"
eyre = "0.6.8"[features]
export-abi = ["stylus-sdk/export-abi"]
debug = ["stylus-sdk/debug"][[bin]]
name = "stylus_tokens"
path = "src/main.rs"[lib]
crate-type = ["lib", "cdylib"][profile.release]
codegen-units = 1
strip = true
lto = true
panic = "abort"
opt-level = "s"

3. 合约部署上链并mint代币

一切准备就绪之后,我们来编译并且在链上验证我们的代码:

cargo stylus check -e https://sepolia-rollup.arbitrum.io/rpc

我们将一些参数导出成变量

export ARB_RPC_URL=https://sepolia-rollup.arbitrum.io/rpc
export PRIVATE_KEY=你的私钥

然后我们 可以来估算部署合约所需的 gas,这一个步骤不是必需的:

cargo stylus deploy --endpoint=$ARB_RPC_URL --private-key=$PRIVATE_KEY --estimate-gas

OK,开始部署:

cargo stylus deploy --endpoint=$ARB_RPC_URL --private-key=$PRIVATE_KEY

到这里已经部署成功,可以看到合约地址与交易hash,接下来我们开始铸造代币,如果你没有安装 foundry,(foundry 我会出一期详细的教程),请参考我的《Arbitrum Stylus 深入解析与rust合约部署实战》中的方式,导出ABI,然后在 remix 中去操作,这里我使用 foundry cast 命令去mint 代币:

cast send --rpc-url $ARB_RPC_URL --private-key $PRIVATE_KEY 0xb032fb53175b9c24ac157f4a7896ad200fd93468 "mint(uint256)" 100000000000000000000000000

可以看到我成功mint了一亿枚代币,因为有18位小数,所以在你想要mint的数量后面,再加上18个0,0xb032fb53175b9c24ac157f4a7896ad200fd93468  是合约的地址,到时候替换成你们部署成功的合约地址,我们去钱包导入代币,看看代币有没有到账:

可以看到我们代币已经到账了,接下来演示使用命令查看某个地址的代币余额:

OK,如果你走到了这里,恭喜你,你已经完成了 使用 Rust 在 Stylus 上实现 ERC20 合约,重复是最好的老师,希望大家多多练习,后面我也会继续更新系列教程,我是红烧6,关注我,带你上车 web3!

 Arbitrum官方文档:官方文档

stylus 官方示例:stylus-by-example

代码仓库:stylus-tokens

http://www.dtcms.com/wzjs/589275.html

相关文章:

  • 建设项目管理公司网站营销型网站盈利模式
  • 北京效果好的网站推广asp.net学校网站整站系统源码
  • 教育网站建设网站律师事务所咨询免费
  • 用vs2010做网站教程网络营销策划书ppt
  • 手机wap网站特效军事最新消息新闻
  • 移动网站建设厂家网站搭建赚钱吗
  • 一级a做爰片免费网站天天看手机网站建设计
  • 纯静态 网站网站通知模板
  • 个人网站备案核验单织梦做的网站老是被黑
  • 网站建设咨询云尚网络360全景预览wordpress插件
  • 网站框架设计模板做软件界面的网站
  • 开发网站制作自己电脑做服务器搭建网站有域名
  • 做的精美的门户网站推荐华侨城网站开发
  • 桂林广告公司网站建设深圳做英文网站公司
  • 电子商务 网站设计做网站做得好的公司
  • 教做美食网站源码win7 iis 添加网站
  • 阿里云 建网站攻略厦门人才网个人登录
  • 建立一个公司网站大约多少钱免费视频剪辑软件
  • 晋州做网站个人备案网站放什么手续
  • 展厅设计公司logoseo人才网
  • 塘厦东莞网站建设网站模板安装出现预先建设数据库
  • 用php源码如何建设网站自己怎么做网站链接
  • 专门卖化妆品网站建设网页设计素材源文件
  • 项目网站开发上海网站建设聚众网络
  • 深圳医疗网站建设公司网站集约化建设的通知
  • 百度做网站审核要多久wordpress如何修改页脚
  • 驻马店网站建设电话承德教育信息网官网
  • 珠海专业网站建设费用建设银行网站官网
  • 门户网站整改情况报告wordpress转phpcms
  • 网站建设shzanen沈阳品牌设计