Skip to main content

Aptos Examples

ERC20 example

Code

当然,下面是增加了注释的 Move 代码示例,解释了每个部分的作用:

address 0x1 {
module MyToken {
// 定义 Token 结构体,包含总供应量和一个映射每个地址到其余额的字典
struct Token {
total_supply: u64,
balances: map<address, u64>,
}

// 初始化函数,设置代币的初始供应量,并将其全部分配给创建者
public fun initialize(account: &signer, initial_supply: u64) {
// 创建一个新的 Token 实例
let token = Token {
total_supply: initial_supply,
balances: map::empty(),
};
// 将初始供应量分配给合约创建者的地址
map::add(&mut token.balances, Signer::address_of(account), initial_supply);
// 将 Token 资源移动到创建者的账户下
move_to(account, token);
}

// 转账函数,允许代币的持有者将一定数量的代币转移到另一个地址
public fun transfer(from: &signer, to: address, amount: u64) acquires Token {
// 获取代币持有者的 Token 资源引用
let token = borrow_global_mut<Token>(Signer::address_of(from));
// 获取转出账户的余额
let from_balance = *map::get<&u64>(&token.balances, Signer::address_of(from)).unwrap();
// 获取或插入转入账户的余额(如果不存在则初始化为0)
let to_balance = map::get_or_insert(&mut token.balances, to, 0);

// 确保转出账户有足够的余额
assert!(from_balance >= amount, 1); // 抛出错误码 1
// 更新转出和转入账户的余额
map::add(&mut token.balances, Signer::address_of(from), from_balance - amount);
map::add(&mut token.balances, to, *to_balance + amount);
}

// 查询指定账户余额的函数
public fun balance_of(account: address): u64 acquires Token {
// 获取全局 Token 资源引用
let token = borrow_global<Token>(0x1);
// 返回指定账户的余额,如果没有记录,则返回0
match map::get<&u64>(&token.balances, account) {
Some(balance) => *balance,
None => 0,
}
}

// 查询代币总供应量的函数
public fun total_supply(): u64 acquires Token {
// 获取全局 Token 资源引用
let token = borrow_global<Token>(0x1);
// 返回总供应量
token.total_supply
}
}
}

在这段代码中,我们使用了 Move 语言的一些核心概念,如资源(struct Token),全局存储(move_to,borrow_global,borrow_global_mut),以及签名者(&signer)来验证交易发起者的权限。每个函数前的注释解释了它的功能和如何操作这些概念。

请记住,这只是一个概念验证示例,实际上,你可能需要考虑更多的安全措施,比如审计、测试、错误处理等。在部署任何区块链代码之前,都应该进行彻底的检查和测试。

为什么是 address 0x1

在 Move 语言中,address 0x1 是一个特殊的地址,通常用于部署核心模块和标准库。这个地址具有特殊权限,因为在某些区块链平台上,如 Libra(现在称为 Diem)和 Aptos,只有特定的地址(通常是预定义的或由区块链的创始实体控制的地址)才被允许部署模块。

在 Move 中,当你看到 address 0x1,它通常指的是一个预留的、有高级权限的地址,用于存放系统级的代码。在实际开发中,你会使用你自己的账户地址来部署你的模块。每个账户地址都是唯一的,并且可以用来部署用户定义的模块。

因此,在实际情况中,你应该用你自己的账户地址替换 address 0x1。例如,如果你的账户地址是 0x123,那么你会这样开始你的模块定义:

address 0x123 {
module MyToken {
// ...
}
}

在这种情况下,模块 MyToken 将会被部署在地址 0x123 下。这是你自己的地址,你有权限在此地址下部署和更新模块。

在开发和测试时,你通常会在本地或测试网络上拥有一个或多个账户地址,这些地址不受上述限制,你可以在这些地址上自由地部署和测试你的 Move 代码。在主网上部署时,你需要确保你使用的是你拥有正确权限的地址。

如何申请我自己的地址

在 Move 语言和与之相关的区块链平台(如 Diem 或 Aptos)中,地址通常是通过生成密钥对(公钥和私钥)来创建的。私钥用于签署交易,而公钥用于生成区块链地址。以下是通常的步骤,用于生成新的区块链地址:

  1. 生成密钥对:你需要使用加密库来生成一个新的密钥对。在 Move 相关的区块链上,通常使用 ED25519 签名算法。

  2. 派生地址:从公钥派生出一个地址。在某些区块链上,地址可能是公钥的哈希或者是公钥的一部分。

  3. 创建账户:在区块链上创建一个与该地址关联的账户。这通常需要一个已存在的账户来支付一些初始费用,因为大多数区块链都需要交易费用来防止垃圾交易。

以下是一个简化的例子,说明如何在 Rust 语言中使用 libra-crypto 库来生成一个新的 Move 地址:

use libra_crypto::ed25519::*;
use libra_crypto::traits::Uniform;
use libra_types::account_address::AccountAddress;

fn main() {
// 生成一个新的 ED25519 密钥对
let mut rng = rand::thread_rng();
let (private_key, public_key) = Ed25519PrivateKey::generate_for_testing(&mut rng).into_keys();

// 从公钥派生出一个地址
let address = AccountAddress::from(&public_key);

println!("Private Key: {:?}", private_key);
println!("Public Key: {:?}", public_key);
println!("Address: {:?}", address);
}

请注意,这段代码是基于 Diem(原 Libra)项目的库的,如果你使用的是不同的区块链,可能需要使用不同的库和方法。

在实际操作中,你可能需要使用区块链提供的钱包软件或命令行工具来生成地址和密钥对。例如,Aptos CLI 提供了创建账户和管理密钥的功能。始终确保你的私钥安全,不要与任何人分享。如果你丢失了私钥,你将无法访问与之关联的地址上的资产。如果你的私钥被盗,攻击者可以完全控制你的地址和资产。