ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

fuels-ts 中的 Asset ID 机制:getMintedAssetId 与 createAssetId 原理及实战

fuels-ts 中的 Asset ID 机制:getMintedAssetId 与 createAssetId 原理及实战 fuels-ts 中的 Asset ID 机制getMintedAssetId 与 createAssetId 原理及实战【免费下载链接】fuels-tsFuel Network Typescript SDK项目地址: https://gitcode.com/GitHub_Trending/fu/fuels-ts在 Fuel 网络中每种资产都由一个唯一的 Asset ID 标识而资产发行Mint合约在铸造代币时必须先搞清楚这个新资产的 ID 到底是什么本文基于 fuels-ts 官方文档 Minted Token Asset ID完整讲解 Asset ID 的推导规则、getMintedAssetId与createAssetId两个核心工具函数并结合仓库源码剖析其底层哈希实现与在交易回执Receipt处理中的实际调用位置帮助你在部署代币合约后正确计算、使用铸造出的资产 ID。Asset ID 由什么决定Fuel 网络上一个代币的 Asset ID 由两个因素共同决定铸造该代币的合约 IDContract ID子标识符Sub ID。两者都是 B256 字符串32 字节64 个十六进制字符加0x前缀。推导过程是把 Contract ID 与 Sub ID 拼接后对其应用 SHA-256 哈希算法得到的哈希值即为该资产的 Asset ID。这意味着Contract ID 是动态的——每次部署合约生成的合约 ID 都不同因此同一份合约代码部署两次会产生两种不同的资产Sub ID 可以是固定的——它只是合约 ABI 方法里的一个普通b256参数开发者可以约定一个常量值。这一特性让合约天然支持多资产发行同一个合约用不同的 Sub ID 铸造就会得到互不冲突的多个 Asset ID。一个简化的 Token 合约先看文档中给出的这个简化版代币合约token/src/main.sw它是理解后续操作的上下文contract; use std::asset::{burn, mint, transfer}; abi Token { fn transfer_to_address(target: Address, asset_id: AssetId, coins: u64); fn transfer_to_contract(recipient: ContractId, asset_id: AssetId, coins: u64); fn mint_coins(sub_id: b256, mint_amount: u64); fn burn_coins(sub_id: b256, burn_amount: u64); } impl Token for Contract { fn transfer_to_address(recipient: Address, asset_id: AssetId, amount: u64) { transfer(Identity::Address(recipient), asset_id, amount); } fn transfer_to_contract(target: ContractId, asset_id: AssetId, amount: u64) { transfer(Identity::ContractId(target), asset_id, amount); } fn mint_coins(sub_id: b256, mint_amount: u64) { mint(sub_id, mint_amount); } fn burn_coins(sub_id: b256, burn_amount: u64) { burn(sub_id, burn_amount); } }合约中真正执行铸造的是 Sway 标准库的mint(sub_id, amount)内建函数。注意sub_id是每次调用时传入的参数而不是合约常量——这决定了 Asset ID 只有在合约部署完成后、选定 Sub ID 之后才能被计算出来。部署合约并铸造代币假设上述合约已经通过 typegen 生成了TokenFactory文档给出的铸造流程如下minted-token-asset-id.tsimport { bn, getMintedAssetId, Provider, Wallet } from fuels; import { LOCAL_NETWORK_URL, WALLET_PVT_KEY } from ../../../../env; import { TokenFactory } from ../../../../typegend; const provider new Provider(LOCAL_NETWORK_URL); const deployer Wallet.fromPrivateKey(WALLET_PVT_KEY, provider); const deployContract await TokenFactory.deploy(deployer); const { contract } await deployContract.waitForResult(); // Any valid B256 string can be used as a sub ID const subID 0xc7fd1d987ada439fc085cfa3c49416cf2b504ac50151e3c2335d60595cb90745; const mintAmount bn(1000); const { waitForResult } await contract.functions .mint_coins(subID, mintAmount) .call(); await waitForResult(); // Get the minted const mintedAssetId getMintedAssetId(contract.id.toB256(), subID); console.log(Minted asset ID should be defined, mintedAssetId); const { transactionResult } await waitForResult(); console.log( Transaction should be successful, transactionResult.isStatusSuccess );几个关键点Sub ID 可以是任意合法的 B256 字符串。示例中用一个写死的 B256 值演示生产中常见做法是把 Sub ID 设为合约代码中约定的常量便于团队统一。contract.id.toB256()返回的是部署后动态生成的合约 ID 的 B256 字符串形式这正是 Asset ID 推导中动态的那一半。getMintedAssetId是一个纯本地计算它不访问节点、不消耗 gas任何时候只要知道 Contract ID 和 Sub ID就能在客户端直接算出 Asset ID。这一点在部署后立即转账或预估手续费等场景中非常有用——你甚至可以在 mint 交易上链之前就拿到未来的 Asset ID。getMintedAssetId 的源码实现getMintedAssetId定义在 receipt.tsfuel-ts/transactions包经由fuels聚合包导出export const getMintedAssetId (contractId: string, subId: string): string { const contractIdBytes arrayify(contractId); const subIdBytes arrayify(subId); return sha256(concat([contractIdBytes, subIdBytes])); };实现非常直白arrayify来自fuel-ts/utils把两个 B256 十六进制字符串各自转成 32 字节的Uint8Arrayconcat将 Contract ID 的 32 字节拼在 Sub ID 的 32 字节前面得到 64 字节输入最后用noble/hashes的sha256求哈希返回 32 字节结果的十六进制字符串。字节拼接顺序Contract ID 在前、Sub ID 在后是协议层面的规定顺序颠倒会得到完全不同的 Asset ID。从源码结构看这个函数没有任何输入校验因此调用方有责任保证传入的是合法的 B256 字符串否则arrayify会因非法十六进制而抛出异常。由于 Asset ID 取决于动态的 Contract ID而 Sub ID 可以固定这个辅助函数就是文档推荐用来给定合约 ID 和 Sub ID 快速求得 Asset ID的官方入口。createAssetId直接获得 Sway 原生的 AssetId 参数如果你要在调用 Sway 方法时把 Asset ID 作为参数传入例如transfer_to_address(recipient, asset_id, amount)中的asset_id需要的是 Sway 原生类型AssetId对应的 JS 对象而不是普通字符串。SDK 提供的createAssetId就是为此设计的它内部直接复用getMintedAssetIdreceipt.tsexport const createAssetId (contractId: string, subId: string): AssetId ({ bits: getMintedAssetId(contractId, subId), });AssetId是fuel-ts/address包中的类型别名本质是形如{ bits: string }的 B256 包装对象与 Sway 端的AssetId结构体一一对应可直接作为合约调用参数。文档中的使用示例create-asset-id.tsimport type { AssetId, B256Address } from fuels; import { createAssetId } from fuels; const contractId: B256Address 0x67eb6a384151a30e162c26d2f3e81ca2023dfa1041000210caed42ead32d63c0; const subID: B256Address 0xc7fd1d987ada439fc085cfa3c49416cf2b504ac50151e3c2335d60595cb90745; const assetId: AssetId createAssetId(contractId, subID); // { // bits: 0x16c1cb95e999d0c74806f97643af158e821a0063a0c8ea61183bad2497b57478 // }对同一对(contractId, subID)createAssetId与getMintedAssetId的哈希结果完全一致区别只在于返回值类型前者返回可直接喂给合约调用的AssetId对象后者返回裸的 B256 字符串适合日志输出、比较或存储。它不只是工具函数SDK 内部也在用它从源码结构看getMintedAssetId除了供开发者手动计算 Asset ID 外还被 SDK 内部用于解析交易回执。在 serialization.tsfuel-ts/account包的 providers 工具模块中SDK 在把节点返回的ReceiptMint/ReceiptBurn回执序列化为强类型对象时会用getMintedAssetId(contractId, subId)由回执中携带的合约 ID 和 Sub ID 还原出对应的 Asset ID。这解释了为什么文档示例里 mint 交易完成后、无需额外查询即可拿到本次铸造的 Asset ID——它与节点侧的推导逻辑是同一个公式天然一致。小结与适用边界公式Asset ID SHA256(Contract ID ‖ Sub ID)两个输入均为 B256 字符串Contract ID 在前。getMintedAssetId(contractId, subId)返回 B256 字符串纯本地计算适合任何需要提前知道资产 ID 的场合。createAssetId(contractId, subId)返回 Sway 原生AssetId对象{ bits }用于合约方法调用传参。两个函数均要求传入合法 B256 字符串不做格式校验Contract ID 必须由实际部署结果取得不能凭空假设。参考实现位置packages/transactions/src/receipt.ts、packages/account/src/providers/utils/serialization.ts文档原文见 apps/docs/src/guide/contracts/minted-token-asset-id.md。【免费下载链接】fuels-tsFuel Network Typescript SDK项目地址: https://gitcode.com/GitHub_Trending/fu/fuels-ts创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表