_FuelError: Only one field must be provided

Error:

  • Run $ fuelup show and add the output below

Default host: x86_64-unknown-linux-gnu
fuelup home: /home/manav/.fuelup

installed toolchains

latest-x86_64-unknown-linux-gnu (default)
nightly-2024-01-24-x86_64-unknown-linux-gnu
nightly-2024-04-12-x86_64-unknown-linux-gnu

active toolchain

latest-x86_64-unknown-linux-gnu (default)
forc : 0.49.3
- forc-client
- forc-deploy : 0.49.3
- forc-run : 0.49.3
- forc-crypto : 0.49.3
- forc-debug : Could not parse version (empty string, expected a semver version)
- forc-doc : 0.49.3
- forc-explore : 0.28.1
- forc-fmt : 0.49.3
- forc-lsp : 0.49.3
- forc-tx : 0.49.3
- forc-wallet : 0.4.3
fuel-core : 0.22.4
fuel-core-keygen : 0.22.4

fuels versions

forc : 0.54.0
forc-wallet : 0.54.0

  • Detailed steps to recreate issue
    → Calling mint function on a custom Token Contract using Typescript SDK
  • Link full scope of the codebase pertaining to your issue

Code that calls the mint function on a POST Request.

import { Provider, Wallet, Contract } from "fuels";
import { NextRequest, NextResponse } from "next/server";
import { abi } from "@/abi";

export async function POST(req: NextRequest, res: NextResponse) {
    const requestData = await req.json();
    const receiverAddress = requestData.receiverAddress;

    const provider = await Provider.create('https://beta-5.fuel.network/graphql');
    const wallet = Wallet.fromPrivateKey(process.env.NEXT_WALLET_PRIVATE_KEY || '', provider);
    const contractId = process.env.NEXT_CONTRACT_ID || '';

    const contract = new Contract(contractId, abi, wallet);
    const value = await contract.functions.mint(receiverAddress, 0x0000000000000000000000000000000000000000000000000000000000000000, 100).call();
    console.log(value);

    return NextResponse.json({ result: receiverAddress });
}

The Token Contract Code:

contract;

mod errors;

use errors::{MintError};

use src20::SRC20;
use src3::SRC3;
use asset::{
    base::{
        _decimals,
        _name,
        _set_decimals,
        _set_name,
        _set_symbol,
        _symbol,
        _total_assets,
        _total_supply,
        SetAssetAttributes,
    },
    mint::{
        _burn,
        _mint,
    },
};
use std::{call_frames::contract_id, hash::Hash, storage::storage_string::*, string::String};

storage {
    /// The total number of unique assets minted by this contract.
    total_assets: u64 = 0,
    /// The total number of coins minted for a particular asset.
    total_supply: StorageMap<AssetId, u64> = StorageMap {},
}

configurable {
    /// The total supply of coins for the asset minted by this contract.
    TOTAL_SUPPLY: u64 = 100_000_000,
    /// The decimals of the asset minted by this contract.
    DECIMALS: u8 = 9u8,
    /// The name of the asset minted by this contract.
    NAME: str[7] = __to_str_array("Vadapav"),
    /// The symbol of the asset minted by this contract.
    SYMBOL: str[5] = __to_str_array("VDPAV"),
}

impl SRC20 for Contract {
    /// Returns the total number of individual assets minted by a contract.
    ///
    /// # Additional Information
    ///
    /// For this single asset contract, this is always one.
    ///
    /// # Returns
    ///
    /// * [u64] - The number of assets that this contract has minted.
    ///
    /// # Examples
    ///
    /// ```sway
    /// use src20::SRC20;
    ///
    /// fn foo(contract_id: ContractId) {
    ///     let src_20_abi = abi(SRC20, contract_id);
    ///     let assets = src_20_abi.total_assets();
    ///     assert(assets == 1);
    /// }
    /// ```
    #[storage(read)]
    fn total_assets() -> u64 {
        1
    }

    /// Returns the total supply of coins for the asset.
    ///
    /// # Arguments
    ///
    /// * `asset`: [AssetId] - The asset of which to query the total supply, this should be the default `SubId`.
    ///
    /// # Returns
    ///
    /// * [Option<u64>] - The total supply of an `asset`.
    ///
    /// # Examples
    ///
    /// ```sway
    /// use src20::SRC20;
    /// use std::constants::DEFAULT_SUB_ID;
    ///
    /// fn foo(contract_id: ContractId) {
    ///     let src_20_abi = abi(SRC20, contract_id);
    ///     let supply = src_20_abi.total_supply(DEFAULT_SUB_ID);
    ///     assert(supply.unwrap() != 0);
    /// }
    /// ```
    #[storage(read)]
    fn total_supply(asset: AssetId) -> Option<u64> {
        if asset == AssetId::default() {
            Some(TOTAL_SUPPLY)
        } else {
            None
        }
    }

    /// Returns the name of the asset.
    ///
    /// # Arguments
    ///
    /// * `asset`: [AssetId] - The asset of which to query the name, this should be the default `SubId`.
    ///
    /// # Returns
    ///
    /// * [Option<String>] - The name of `asset`.
    ///
    /// # Examples
    ///
    /// ```sway
    /// use src20::SRC20;
    /// use std::constants::DEFAULT_SUB_ID;
    ///
    /// fn foo(contract_id: ContractId) {
    ///     let src_20_abi = abi(SRC20, contract_id);
    ///     let name = src_20_abi.name(DEFAULT_SUB_ID);
    ///     assert(name.is_some());
    /// }
    /// ```
    #[storage(read)]
    fn name(asset: AssetId) -> Option<String> {
        if asset == AssetId::default() {
            Some(String::from_ascii_str(from_str_array(NAME)))
        } else {
            None
        }
    }

    /// Returns the symbol of the asset.
    ///
    /// # Arguments
    ///
    /// * `asset`: [AssetId] - The asset of which to query the symbol, this should be the default `SubId`.
    ///
    /// # Returns
    ///
    /// * [Option<String>] - The symbol of `asset`.
    ///
    /// # Examples
    ///
    /// ```sway
    /// use src20::SRC20;
    /// use std::constants::DEFAULT_SUB_ID;
    ///
    /// fn foo(contract_id: ContractId) {
    ///     let src_20_abi = abi(SRC20, contract_id);
    ///     let symbol = src_20_abi.symbol(DEFAULT_SUB_ID);
    ///     assert(symbol.is_some());
    /// }
    /// ```
    #[storage(read)]
    fn symbol(asset: AssetId) -> Option<String> {
        if asset == AssetId::default() {
            Some(String::from_ascii_str(from_str_array(SYMBOL)))
        } else {
            None
        }
    }

    /// Returns the number of decimals the asset uses.
    ///
    /// # Arguments
    ///
    /// * `asset`: [AssetId] - The asset of which to query the decimals, this should be the default `SubId`.
    ///
    /// # Returns
    ///
    /// * [Option<u8>] - The decimal precision used by `asset`.
    ///
    /// # Examples
    ///
    /// ```sway
    /// use src20::SRC20;
    /// use std::constants::DEFAULT_SUB_ID;
    ///
    /// fn foo(contract_id: ContractId) {
    ///     let src_20_abi = abi(SRC20, contract_id);
    ///     let decimals = src_20_abi.decimals(DEFAULT_SUB_ID);
    ///     assert(decimals.unwrap() == 9u8);
    /// }
    /// ```
    #[storage(read)]
    fn decimals(asset: AssetId) -> Option<u8> {
        if asset == AssetId::default() {
            Some(DECIMALS)
        } else {
            None
        }
    }
}

impl SRC3 for Contract {
    /// Mints new assets using the `sub_id` sub-identifier.
    ///
    /// # Arguments
    ///
    /// * `recipient`: [Identity] - The user to which the newly minted assets are transferred to.
    /// * `sub_id`: [SubId] - The sub-identifier of the newly minted asset.
    /// * `amount`: [u64] - The quantity of coins to mint.
    ///
    /// # Reverts
    ///
    /// * When more than 100,000,000 coins have been minted.
    ///
    /// # Number of Storage Accesses
    ///
    /// * Reads: `3`
    /// * Writes: `2`
    ///
    /// # Examples
    ///
    /// ```sway
    /// use src3::SRC3;
    ///
    /// fn foo(contract: ContractId) {
    ///     let contract_abi = abi(SR3, contract);
    ///     contract_abi.mint(Identity::ContractId(this_contract()), ZERO_B256, 100);
    /// }
    /// ```
    #[storage(read, write)]
    fn mint(recipient: Identity, sub_id: SubId, amount: u64) {
        let asset = AssetId::new(contract_id(), sub_id);
        require(
            storage
                .total_supply
                .get(asset)
                .try_read()
                .unwrap_or(0) + amount < 100_000_000,
            MintError::MaxMinted,
        );
        let _ = _mint(
            storage
                .total_assets,
            storage
                .total_supply,
            recipient,
            sub_id,
            amount,
        );
    }
    /// Burns assets sent with the given `sub_id`.
    ///
    /// # Additional Information
    ///
    /// NOTE: The sha-256 hash of `(ContractId, SubId)` must match the `AssetId` where `ContractId` is the id of
    /// the implementing contract and `SubId` is the given `sub_id` argument.
    ///
    /// # Arguments
    ///
    /// * `sub_id`: [SubId] - The sub-identifier of the asset to burn.
    /// * `amount`: [u64] - The quantity of coins to burn.
    ///
    /// # Number of Storage Accesses
    ///
    /// * Reads: `1`
    /// * Writes: `1`
    ///
    /// # Examples
    ///
    /// ```sway
    /// use src3::SRC3;
    ///
    /// fn foo(contract: ContractId, asset_id: AssetId) {
    ///     let contract_abi = abi(SR3, contract);
    ///     contract_abi {
    ///         gas: 10000,
    ///         coins: 100,
    ///         asset_id: AssetId,
    ///     }.burn(ZERO_B256, 100);
    /// }
    /// ```
    #[storage(read, write)]
    fn burn(sub_id: SubId, amount: u64) {
        _burn(storage.total_supply, sub_id, amount);
    }
}

Being thrown when encoding an enum value, expecting one key but looks like you are passing 2.

From the look of the contract, we are expecting an Identity as the enum parameter to the mint function. I’d be expecting you to pass { Address: '0x...' } or { ContractId: '0x...'}

Please can you log out the value of the first parameter, receiverAddress?

receiverAddress:

Screenshot 2024-05-03 135315

okay, so I would expect you to call the contract function like so:

const value = await contract.functions.mint({Address: receiverAddress}, 0x0000000000000000000000000000000000000000000000000000000000000000, 100).call();
console.log(value);

Okay, but now I’m getting this error. Am I doing something wrong?

Also, if i type contractId instead of Address, i get a different error

const value = await contract.functions.mint({contractId: receiverAddress}, 0x0000000000000000000000000000000000000000000000000000000000000000, 100).call();
console.log(value);

Error:

Ah apologies it is an enum containing a struct. This documentation around Identity will help.

But I expect it to work with:

const identityInput = { Address: { bits: receiverAddress } };
const value = await contract.functions.mint(identityInput, 0x0000000000000000000000000000000000000000000000000000000000000000, 100).call();

Potentially your address is in the wrong format, for that you can use our address helper.

I changed it to b256 Address but now I’m getting an error that says that it’s invalid b256. I don’t understand what’s wrong here.

Code:

import { Provider, Wallet, Contract, Address } from "fuels";
import { NextRequest, NextResponse } from "next/server";
import { abi } from "@/abi";

export async function POST(req: NextRequest, res: NextResponse) {
    const requestData = await req.json();
    const receiverAddress = new Address(requestData.receiverAddress);
    console.log("User Address: ", receiverAddress);

    const provider = await Provider.create('https://beta-5.fuel.network/graphql');
    const wallet = Wallet.fromPrivateKey(process.env.NEXT_WALLET_PRIVATE_KEY || '', provider);
    const contractId = process.env.NEXT_CONTRACT_ID || '';

    try {
        const contract = new Contract(contractId, abi, wallet);
        const identityInput = { Address: { value: receiverAddress.toB256() } };
        console.log("B256: ", identityInput);
        const value = await contract.functions.mint(identityInput, 0x0000000000000000000000000000000000000000000000000000000000000000, 100).call();
        console.log(value);
        return NextResponse.json({ result: receiverAddress });
    } catch (error) {
        console.log(error);
        return NextResponse.json({ result: "There was an Error" });
    }

}

Error:

Would you be able to share the full code / repo and I will replicate it?

Here’s the Repository Link:

It uses Farcaster Frames (Frog Framework) to Mint a Token.

1 Like

Please could you provide the contract ID you are using and a .env.example so I can replicate it fully.

my env.example

NEXT_WALLET_PRIVATE_KEY=private_key
NEXT_CONTRACT_ID=0xea59858d3736e22b548b72735096217e19c2fc0e1301ebfb64e00e3a8a0b5234
1 Like

Ah, the Identity is now set correctly. The error is now being thrown for the sub_id, we expect a b256 to be a string. Change the contract call to be like so:

const value = await contract.functions.mint(identityInput, '0x0000000000000000000000000000000000000000000000000000000000000000', 100).call();
2 Likes

Yes! It worked. Thank you so much!!

1 Like