Skip to content

原生支持多种资产类型

FuelVM 内置了对多种资产处理的支持。

这在实践中意味着什么?

与 EVM 一样,将 ETH 发送到地址或合约是 FuelVM 内置的操作,这意味着它不依赖某些代币智能合约来更新余额以追踪所有权。

然而,与 EVM 不同的是,发送任何原生资产的过程都是相同的。这意味着,虽然你仍然需要一个智能合约来处理可替代资产的铸造和销毁,但这些资产的发送和接收可以独立于资产合约进行。

流动资金池示例

Fuel 中的所有合约都可以铸造和销毁自己的原生资产。合约还可以接收和转移任何原生资产,包括自己的原生资产。通过调用推送或由合约铸造的所有原生资产的内部余额均由 FuelVM 跟踪,并且可以随时使用库中的 balance_of 函数进行查询 std 。因此,无需使用持久存储手动核算合约的余额。

std 库提供了访问 Fuel 原生资产操作的便捷方法。

在这个例子中,我们展示了一个基本的流动性池合约铸造了自己的原生资产LP资产。

sway
contract;

use std::{
    asset::{
        mint_to_address,
        transfer_to_address,
    },
    call_frames::{
        contract_id,
        msg_asset_id,
    },
    constants::DEFAULT_SUB_ID,
    context::msg_amount,
    hash::*,
};

abi LiquidityPool {
    fn deposit(recipient: Address);
    fn withdraw(recipient: Address);
}

const BASE_ASSET: AssetId = AssetId {
    value: 0x9ae5b658754e096e4d681c548daf46354495a437cc61492599e33fc64dcdc30c,
};

impl LiquidityPool for Contract {
    fn deposit(recipient: Address) {
        assert(msg_asset_id() == BASE_ASSET);
        assert(msg_amount() > 0);

        // Mint two times the amount.
        let amount_to_mint = msg_amount() * 2;

        // Mint some LP assets based upon the amount of the base asset.
        mint_to_address(recipient, DEFAULT_SUB_ID, amount_to_mint);
    }

    fn withdraw(recipient: Address) {
        let asset_id = AssetId::default();
        assert(msg_asset_id() == asset_id);
        assert(msg_amount() > 0);

        // Amount to withdraw.
        let amount_to_transfer = msg_amount() / 2;

        // Transfer base asset to recipient.
        transfer_to_address(recipient, BASE_ASSET, amount_to_transfer);
    }
}

原生资产示例

在这个例子中,我们展示了具有更多铸造、销毁和转移功能的原生资产合约。

sway
contract;

use std::{asset::*, constants::DEFAULT_SUB_ID, context::*};

abi NativeAsset {
    fn mint_coins(mint_amount: u64);
    fn burn_coins(burn_amount: u64);
    fn force_transfer_coins(coins: u64, asset_id: AssetId, target: ContractId);
    fn transfer_coins_to_output(coins: u64, asset_id: AssetId, recipient: Address);
    fn deposit();
    fn get_balance(target: ContractId, asset_id: AssetId) -> u64;
    fn mint_and_send_to_contract(amount: u64, destination: ContractId);
    fn mint_and_send_to_address(amount: u64, recipient: Address);
}

impl NativeAsset for Contract {
    /// Mint an amount of this contracts native asset to the contracts balance.
    fn mint_coins(mint_amount: u64) {
        mint(DEFAULT_SUB_ID, mint_amount);
    }

    /// Burn an amount of this contracts native asset.
    fn burn_coins(burn_amount: u64) {
        burn(DEFAULT_SUB_ID, burn_amount);
    }

    /// Transfer coins to a target contract.
    fn force_transfer_coins(coins: u64, asset_id: AssetId, target: ContractId) {
        force_transfer_to_contract(target, asset_id, coins);
    }

    /// Transfer coins to a transaction output to be spent later.
    fn transfer_coins_to_output(coins: u64, asset_id: AssetId, recipient: Address) {
        transfer_to_address(recipient, asset_id, coins);
    }

    /// Get the internal balance of a specific coin at a specific contract.
    fn get_balance(target: ContractId, asset_id: AssetId) -> u64 {
        balance_of(target, asset_id)
    }

    /// Deposit coins back into the contract.
    fn deposit() {
        assert(msg_amount() > 0);
    }

    /// Mint and send this contracts native asset to a destination contract.
    fn mint_and_send_to_contract(amount: u64, destination: ContractId) {
        mint_to_contract(destination, DEFAULT_SUB_ID, amount);
    }

    /// Mind and send this contracts native asset to a destination address.
    fn mint_and_send_to_address(amount: u64, recipient: Address) {
        mint_to_address(recipient, DEFAULT_SUB_ID, amount);
    }
}