Sway 智能合约 Mint to Address:向地址铸造资产的完整指南
2026/9/12 20:24:46 网站建设 项目流程

Sway 智能合约 Mint to Address:向地址铸造资产的完整指南

【免费下载链接】sway🌴 Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/sway

铸造(Mint)是 Sway 智能合约中最核心的资产操作之一。本文以官方参考文档 Mint to Address 为骨架,讲解如何在 Fuel 链上使用标准库std::asset::mint_to铸造指定数量的资产并将其直接转移给一个Address(账户地址)。读完本文,你将掌握mint_to的导入方式、参数语义、Address/Identity/SubId三个关键类型的用法,以及该函数在 sway-lib-std/src/asset.sw 中从mint指令到transfer转移的完整底层调用链,并了解铸造到地址时的回滚(revert)条件与安全注意事项。

一、核心概念:Address、Identity 与 SubId

在讲解具体代码之前,需要先理清三个与铸造地址密切相关的类型。

1.Address:UTXO 模型中的输出地址

在 Fuel 的 UTXO 模型中,每一个输出(output)都对应一个地址。Address是一个包含b256值的结构体,其官方定义如下(见 namespace 代码锚点):

pub struct Address { bits: b256, }

Address的值是对以下二者之一的哈希:

  • 一个公钥(public key)
  • 一个 Predicate(谓词脚本)

需要注意:AddressContractId是完全分离的两种类型,不应Address来表示一个已部署合约的地址。

Addressb256之间可以互相转换:

let variable1 = 0x000000000000000000000000000000000000000000000000000000000000002A; let my_address = Address::from(variable1); let variable2: b256 = my_address.into(); // variable1 == variable2

2.Identity:统一处理地址与合约的统一枚举

mint_to的接收方参数类型是Identity,而不是AddressIdentity是一个枚举,其定义见 sway-lib-std/src/identity.sw:

pub enum Identity { Address: Address, ContractId: ContractId, }

Identity的作用是让开发者能够以统一的方式处理"转移给地址"与"转移给合约"两类场景。当我们要铸造给某个Address时,就用Identity::Address(user)将其包装起来。

3.SubId:子标识符

SubId(sub identifier)用于在同一合约下区分不同的资产。同一合约通过ContractId::this()与不同的SubId组合,可以派生出不同的AssetId。铸造时通常使用SubId::zero()表示默认子标识。

二、导入mint_to函数

mint_to位于标准库的资产模块中。使用前需要显式导入:

use std::asset::mint_to;

此导入语句与文档中的mint_to_import锚点一致,见 asset_operations 示例代码。

三、铸造到地址:完整示例

铸造资产并发送到指定Address时,需要指定两个关键参数:

  • amount:希望铸造的数量;
  • 接收方:封装为Identity::Address的目标地址。

以下是文档与示例代码(asset_operations 示例代码)中的完整写法:

fn minting_to_address() { let amount = 10; let address = 0x0000000000000000000000000000000000000000000000000000000000000001; let user = Address::from(address); mint_to(Identity::Address(user), SubId::zero(), amount); }

逐行解读:

  1. let amount = 10;—— 定义铸造数量为 10。
  2. let address = 0x...0001;—— 定义一个b256字面量作为目标地址。
  3. let user = Address::from(address);—— 将b256转换为Address类型。
  4. mint_to(Identity::Address(user), SubId::zero(), amount);—— 以Identity::Address包装user,以SubId::zero()作为子标识,铸造amount数量的资产并转移给该地址。

参数签名与含义

根据 sway-lib-std/src/asset.sw 中的定义,mint_to的完整签名为:

pub fn mint_to(to: Identity, sub_id: SubId, amount: u64)
参数类型含义
toIdentity接收资产的账户身份,可以是Identity::Address(addr)Identity::ContractId(id)
sub_idSubId要铸造的资产的子标识符
amountu64铸造的币数量

四、底层实现剖析:从minttransfer的两步调用链

mint_to之所以能做到"铸造并转移",是因为它在内部执行了两次操作。源码实现如下(sway-lib-std/src/asset.sw):

pub fn mint_to(to: Identity, sub_id: SubId, amount: u64) { mint(sub_id, amount); transfer(to, AssetId::new(ContractId::this(), sub_id), amount); }

第一步:mint—— 通过 Sway 汇编指令铸造

mint将资产铸造到当前合约自身的余额中,其实现直接调用了 Fuel 虚拟机(VM)的mint指令(sway-lib-std/src/asset.sw):

pub fn mint(sub_id: SubId, amount: u64) { asm(r1: amount, r2: sub_id) { mint r1 r2; } }

即把amount放入寄存器r1sub_id放入r2,执行mint r1 r2指令。此时新铸造的资产由当前合约持有。

第二步:transfer—— 将资产转移给目标地址

紧接着,mint_to构造资产 IDAssetId::new(ContractId::this(), sub_id)并调用transfer把刚刚铸造出的资产从合约余额转移给目标Identitytransfer内部按接收方类型分派(sway-lib-std/src/asset.sw):

pub fn transfer(to: Identity, asset_id: AssetId, amount: u64) { match to { Identity::Address(addr) => transfer_to_address(addr, asset_id, amount), Identity::ContractId(id) => force_transfer_to_contract(id, asset_id, amount), }; }

当目标是Address时,走transfer_to_address分支:该函数会遍历当前交易的所有输出(outputs),寻找一个金额为 0 的未使用OutputVariable,找到后通过tro指令完成转移(sway-lib-std/src/asset.sw):

fn transfer_to_address(to: Address, asset_id: AssetId, amount: u64) { let mut index = 0; let number_of_outputs = output_count().as_u64(); while index < number_of_outputs { if let Some(Output::Variable) = output_type(index) { if let Some(0) = output_amount(index) { asm(r1: to.bits(), r2: index, r3: amount, r4: asset_id) { tro r1 r2 r3 r4; }; return; } } index += 1; } revert(FAILED_TRANSFER_TO_ADDRESS_SIGNAL); }

由此可见:铸造到地址的本质是"先铸造到合约,再通过tro指令转账到地址"。这也解释了为何"铸造到合约"(Identity::ContractId)与"铸造到地址"在底层走的是不同的转移路径。

五、回滚(Revert)条件与安全注意事项

从源码文档(doc comments)与实现中可以确认以下回滚条件:

  • transfer到地址时(sway-lib-std/src/asset.sw):

    • amount大于合约中asset_id对应余额时回滚;
    • amount等于 0 时回滚;
    • 当交易中没有可用的空闲可变输出(free variable output)时回滚(即上面transfer_to_address中遍历后未找到未使用输出,调用revert(FAILED_TRANSFER_TO_ADDRESS_SIGNAL))。
  • transfer到合约时force_transfer_to_contract,sway-lib-std/src/asset.sw):当amount大于合约余额或等于 0 时回滚。

⚠️ 特别警示:永久丢失资产的风险

mint_to的文档注释明确警告(sway-lib-std/src/asset.sw):

如果to是一个合约,即使接收合约没有任何可取回资金的机制(例如没有提款功能),资产也会被转移过去,若使用不当可能导致资产的永久丢失(PERMANENT LOSS OF COINS)

虽然本文主题是铸造到Address(账户地址),但在使用mint_to设计业务逻辑时,务必意识到同一函数也支持Identity::ContractId,需要根据接收方类型谨慎设计。

六、与其他铸造方式的关系

在 铸造总览文档 中,标准库sway-lib-std/src/asset.sw提供了两种铸造函数:

  • mint():只铸造,资产留在当前合约余额中,不进行转移:
    use std::asset::mint; let amount = 10; mint(SubId::zero(), amount);
  • mint_to():铸造并转移,可指定Identity::Address(本文场景)或Identity::ContractId

完整的铸造到地址示例代码还包含铸造到合约(minting_to_contract)与同时铸造到两类目标(minting_to)的写法,均可参考 asset_operations 示例代码。

七、实践建议

  1. 明确目标类型:向账户地址铸造时使用Identity::Address(Address::from(b256));向合约铸造时使用Identity::ContractId,不要混用AddressContractId
  2. 留意 SubId 与资产 IDmint_to中使用的sub_id与最终资产 ID 的关系是AssetId::new(ContractId::this(), sub_id),同一合约可借助不同SubId铸造多种资产。
  3. 预留可变输出:由于铸造到地址依赖tro指令写入可变输出,交易必须包含足够的可变输出数量,否则会以FAILED_TRANSFER_TO_ADDRESS_SIGNAL回滚。
  4. 金额与余额校验:确保amount大于 0 且不超过合约在该资产上的余额,避免触发回滚。

如需深入了解Address的底层定义、ContractId以及Identity的其他辅助方法,可继续阅读 Address 参考文档、ContractId 参考文档 与 Identity 源码。

【免费下载链接】sway🌴 Empowering everyone to build reliable and efficient smart contracts.项目地址: https://gitcode.com/GitHub_Trending/sw/sway

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询