Rust NEAR协议代币库near-token的使用,NEAR生态中代币创建与管理的Rust解决方案

Rust NEAR协议代币库near-token的使用,NEAR生态中代币创建与管理的Rust解决方案

near-token是一个用于在NEAR协议中处理代币的Rust库。该库提供了NearToken类型以及各种单位转换和构造方法,使得在NEAR生态系统中处理代币变得简单高效。

基础用法

首先需要将near-token添加为项目依赖:

cargo add near-token

基础使用示例展示了如何创建NearToken对象并进行单位转换:

use near_token::NearToken;

fn main() {
    // 从NEAR单位创建代币对象
    const TEN_NEAR: NearToken = NearToken::from_near(10);

    // 验证各种单位转换
    assert_eq!(TEN_NEAR.to_string(), "10.00 NEAR");
    assert_eq!(TEN_NEAR.as_near(), 10);
    assert_eq!(TEN_NEAR.as_millinear(), 10000);
    assert_eq!(TEN_NEAR.as_yoctonear(), 10000000000000000000000000);

    // 从字符串解析代币金额
    let input_str = "0.123456 NEAR";
    let input_near: NearToken = input_str.parse().unwrap();
    assert_eq!(
        input_near,
        NearToken::from_yoctonear(123456000000000000000000)
    );
}

serde序列化支持

要启用serde序列化功能,需要添加对应特性:

cargo add near-token --features serde

序列化示例展示了如何将NearToken用于可序列化结构:

// 可序列化的转账详情结构
#[derive(serde::Serialize)]
struct TransferDetails {
    amount: NearToken,
}

fn main() {
    const TEN_NEAR: NearToken = NearToken::from_near(10);

    let details = TransferDetails { amount: TEN_NEAR };
    assert_eq!(
        serde_json::to_string(&details).unwrap(),
        r#"{"amount":"10000000000000000000000000"}"#
    );
}

borsh序列化支持

要启用borsh序列化功能,需要添加对应特性:

cargo add near-token --features borsh

borsh序列化示例:

use borsh::{to_vec, BorshSerialize};
use near_token::NearToken;

// 支持borsh序列化的结构
#[derive(BorshSerialize)]
struct TransferDetails {
    amount: NearToken,
}

fn main() {
    const TEN_NEAR: NearToken = NearToken::from_near(10);

    let details = TransferDetails { amount: TEN_NEAR };
    assert_eq!(
        to_vec(&details).unwrap(),
        vec![0, 0, 0, 74, 72, 1, 20, 22, 149, 69, 8, 0, 0, 0, 0, 0]
    );
}

NEAR代币基础

NEAR代币是NEAR区块链网络的原生资产,用于支付网络交易费用和存储租金。所有智能合约的执行和状态存储都需要消耗NEAR代币。

完整代币合约示例

以下是一个完整的代币合约实现,展示了代币的创建、转移和序列化操作:

use near_token::NearToken;
use serde::{Serialize, Deserialize};
use borsh::{BorshSerialize, BorshDeserialize};

// 代币转移结构体,支持多种序列化方式
#[derive(Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
pub struct TokenTransfer {
    pub sender: String,       // 发送方账户
    pub receiver: String,     // 接收方账户
    pub amount: NearToken,    // 转账金额
    pub memo: Option<String>, // 可选备注
}

impl TokenTransfer {
    // 创建新的转账
    pub fn new(sender: &str, receiver: &str, amount: NearToken) -> Self {
        Self {
            sender: sender.to_string(),
            receiver: receiver.to_string(),
            amount,
            memo: None,
        }
    }

    // 添加备注
    pub fn with_memo(mut self, memo: &str) -> Self {
        self.memo = Some(memo.to_string());
        self
    }
}

// 代币合约实现
#[derive(Debug, Default, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
pub struct TokenContract {
    pub name: String,                          // 代币名称
    pub symbol: String,                        // 代币符号
    pub total_supply: NearToken,               // 总供应量
    pub balances: std::collections::HashMap<String, NearToken>, // 账户余额
}

impl TokenContract {
    // 创建新代币合约
    pub fn new(name: &str, symbol: &str, total_supply: NearToken) -> Self {
        let mut contract = Self {
            name: name.to_string(),
            symbol: symbol.to_string(),
            total_supply,
            balances: std::collections::HashMap::new(),
        };
        
        // 初始化合约创建者拥有全部代币
        contract.balances.insert("owner".to_string(), total_supply);
        contract
    }

    // 执行转账
    pub fn transfer(&mut self, transfer: &TokenTransfer) -> Result<(), String> {
        // 检查发送方余额
        let sender_balance = self.balances.get(&transfer.sender)
            .ok_or_else(|| format!("Sender {} not found", transfer.sender))?;
        
        // 验证余额是否充足
        if *sender_balance < transfer.amount {
            return Err("Insufficient balance".to_string());
        }

        // 执行转账操作
        *self.balances.entry(transfer.sender.clone()).or_default() -= transfer.amount;
        *self.balances.entry(transfer.receiver.clone()).or_default() += transfer.amount;

        Ok(())
    }
}

fn main() {
    // 创建代币合约,总供应量1000 NEAR
    let total_supply = NearToken::from_near(1000);
    let mut contract = TokenContract::new("My Token", "MTK", total_supply);

    // 创建转账交易
    let transfer = TokenTransfer::new("owner", "alice", NearToken::from_near(100))
        .with_memo("First transfer");
    
    // 执行转账
    match contract.transfer(&transfer) {
        Ok(_) => println!("Transfer successful!"),
        Err(e) => println!("Transfer failed: {}", e),
    }

    // 序列化为JSON
    let json = serde_json::to_string(&transfer).unwrap();
    println!("Serialized transfer: {}", json);

    // 序列化为Borsh
    let borsh_data = borsh::to_vec(&transfer).unwrap();
    println!("Borsh serialized length: {}", borsh_data.len());
}

许可证

near-token库采用MIT和Apache-2.0双重许可证,用户可以根据需要选择其中一种。


1 回复

Rust NEAR协议代币库near-token的使用 - NEAR生态中代币创建与管理的Rust解决方案

概述

near-token是一个用于NEAR协议生态系统的Rust库,它简化了在NEAR区块链上创建和管理代币的过程。这个库为开发者提供了与NEAR代币标准(NEP-141)交互的工具,使得在Rust中实现代币功能变得更加容易。

主要功能

  1. 代币创建和初始化
  2. 代币转账功能
  3. 余额查询
  4. 元数据管理
  5. 跨合约调用支持

完整示例代码

以下是基于near-token库创建完整代币合约的示例:

use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::collections::LazyOption;
use near_sdk::json_types::U128;
use near_sdk::{env, near_bindgen, AccountId, Balance, PanicOnDefault, Promise};
use near_token::Token;

// 代币元数据结构
#[derive(BorshDeserialize, BorshSerialize)]
pub struct TokenMetadata {
    pub spec: String,
    pub name: String,
    pub symbol: String,
    pub icon: Option<String>,
    pub reference: Option<String>,
    pub reference_hash: Option<[u8; 32]>,
    pub decimals: u8,
}

// 主合约结构
#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize, PanicOnDefault)]
pub struct MyToken {
    token: Token,
    metadata: LazyOption<TokenMetadata>,
}

#[near_bindgen]
impl MyToken {
    // 初始化合约
    #[init]
    pub fn new(
        owner_id: AccountId,
        name: String,
        symbol: String,
        decimals: u8,
        icon: Option<String>,
        reference: Option<String>,
        reference_hash: Option<String>,
    ) -> Self {
        // 初始化代币
        let mut token = Token::new(
            name.clone(),
            symbol.clone(),
            decimals,
            owner_id.clone(),
        );
        
        // 设置初始元数据
        let metadata = TokenMetadata {
            spec: "nep-141".to_string(),
            name,
            symbol,
            icon,
            reference,
            reference_hash: reference_hash.map(|s| {
                let mut hash = [0u8; 32];
                hex::decode_to_slice(s, &mut hash).unwrap();
                hash
            }),
            decimals,
        };
        
        Self {
            token,
            metadata: LazyOption::new(b"m", Some(metadata)),
        }
    }

    // 转账功能
    pub fn transfer(&mut self, receiver_id: AccountId, amount: U128) {
        self.token.transfer(
            &env::predecessor_account_id(),
            &receiver_id,
            amount.into(),
        );
    }

    // 带消息的转账(用于跨合约调用)
    pub fn transfer_call(
        &mut self,
        receiver_id: AccountId,
        amount: U128,
        msg: String,
    ) -> Promise {
        self.token.transfer_call(
            &env::predecessor_account_id(),
            &receiver_id,
            amount.into(),
            msg,
        )
    }

    // 查询余额
    pub fn ft_balance_of(&self, account_id: AccountId) -> U128 {
        self.token.balance_of(&account_id).into()
    }

    // 铸造新代币(仅所有者可调用)
    pub fn mint(&mut self, account_id: AccountId, amount: U128) {
        assert_eq!(
            env::predecessor_account_id(),
            self.token.owner_id(),
            "Only owner can mint"
        );
        self.token.mint(&account_id, amount.into());
    }

    // 销毁代币
    pub fn burn(&mut self, amount: U128) {
        self.token.burn(&env::predecessor_account_id(), amount.into());
    }

    // 获取元数据
    pub fn ft_metadata(&self) -> TokenMetadata {
        self.metadata.get().unwrap()
    }

    // 更改所有者(仅当前所有者可调用)
    pub fn change_owner(&mut self, new_owner: AccountId) {
        assert_eq!(
            env::predecessor_account_id(),
            self.token.owner_id(),
            "Only owner can change owner"
        );
        self.token.change_owner(new_owner);
    }
}

// 实现NEP-141标准的方法
impl MyToken {
    pub fn ft_transfer(&mut self, receiver_id: AccountId, amount: U128, memo: Option<String>) {
        self.transfer(receiver_id, amount);
        if let Some(memo) = memo {
            env::log_str(&format!("Memo: {}", memo));
        }
    }

    pub fn ft_transfer_call(
        &mut self,
        receiver_id: AccountId,
        amount: U128,
        memo: Option<String>,
        msg: String,
    ) -> Promise {
        if let Some(memo) = memo {
            env::log_str(&format!("Memo: {}", memo));
        }
        self.transfer_call(receiver_id, amount, msg)
    }

    pub fn ft_total_supply(&self) -> U128 {
        self.token.total_supply().into()
    }
}

部署和测试

使用near-cli部署和测试合约:

# 编译合约
RUSTFLAGS='-C link-arg=-s' cargo build --target wasm32-unknown-unknown --release

# 创建子账户
near create-account token.myaccount.testnet --masterAccount myaccount.testnet

# 部署合约
near deploy --wasmFile target/wasm32-unknown-unknown/release/my_token.wasm --accountId token.myaccount.testnet

# 初始化合约
near call token.myaccount.testnet new '{
  "owner_id": "myaccount.testnet",
  "name": "My Token",
  "symbol": "MTK",
  "decimals": 24,
  "icon": null,
  "reference": null,
  "reference_hash": null
}' --accountId myaccount.testnet

# 铸造代币
near call token.myaccount.testnet mint '{
  "account_id": "myaccount.testnet",
  "amount": "1000000"
}' --accountId myaccount.testnet

# 查询余额
near view token.myaccount.testnet ft_balance_of '{"account_id": "myaccount.testnet"}'

总结

这个完整示例展示了如何使用near-token库实现一个符合NEP-141标准的代币合约,包括:

  • 代币创建和初始化
  • 转账功能实现
  • 余额查询
  • 元数据管理
  • 跨合约调用支持
  • 权限控制

near-token库提供了构建NEAR生态代币所需的核心功能,开发者可以在此基础上进一步扩展业务逻辑。

回到顶部