Hi everyone,
I’m working on a React form component to collect data and create a new asset on the Sui blockchain. The process includes two steps:
- Creating the asset** using the
new_asset
function from my backend. - Minting tokens** for the asset using the
mint
function.
When I trigger the process, the wallet prompts me to approve the transaction, but it fails after approval. I suspect the issue might be related to how the data is formatted or passed as arguments.
Below is the relevant code for your reference:
const handleSubmit = async (e) => {
e.preventDefault();
try {
const tx = new Transaction();
// Form data
const assetName = createTokenForm.asset_name || "";
const metadata = createTokenForm.metadata || {};
const supplyCap = createTokenForm.supply_cap[0];
const keys = [
"property_name",
"location",
"size_sqm",
"year_acquired",
"owner_name",
"plot_number",
];
const values = [
metadata.property_name || "",
metadata.location || "",
metadata.size_sqm?.toString() || "",
metadata.year_acquired?.toString() || "",
metadata.owner_name || "",
metadata.plot_number || "",
];
if (supplyCap <= 0) {
alert("Supply cap must be greater than zero.");
return;
}
// Serialize arguments
const serializedAssetName = bcs.string().serialize(assetName).toBytes();
const serializedSupplyCap = bcs.u64().serialize(BigInt(supplyCap)).toBytes();
const serializedKeys = bcs.vector(bcs.string()).serialize(keys).toBytes();
const serializedValues = bcs.vector(bcs.string()).serialize(values).toBytes();
// Create the asset
tx.moveCall({
target: `${packageId}::sui_land::tokenized_asset::new_asset`,
arguments: [
tx.pure(serializedSupplyCap),
tx.pure(serializedAssetName),
tx.pure(serializedKeys),
tx.pure(serializedValues),
],
});
const result = await signAndExecuteTransaction({ transaction: tx });
const assetCapId = result.effects?.events?.[0]?.data?.asset_cap_id;
if (!assetCapId) {
alert("Asset creation failed. No asset cap ID returned.");
return;
}
// Mint tokens
const mintTx = new Transaction();
mintTx.moveCall({
target: `${packageId}::sui_land::tokenized_asset::mint`,
arguments: [
tx.object(assetCapId),
tx.pure(serializedKeys),
tx.pure(serializedValues),
tx.pure(serializedSupplyCap),
],
});
const mintResult = await signAndExecuteTransaction({
transaction: mintTx,
});
if (mintResult.effects?.status === "success") {
alert("Token minted successfully!");
} else {
alert("Minting failed.");
}
} catch (error) {
console.error("Error creating and minting token:", error);
alert("An error occurred while creating and minting the token.");
}
};
The backend implementation of the new_asset
function can be found in the [MystenLabs Asset Tokenization GitHub repository
public fun new_asset<T: drop>(
witness: T,
total_supply: u64,
symbol: ascii::String,
name: String,
description: String,
icon_url: Option<Url>,
burnable: bool,
ctx: &mut TxContext
): (AssetCap<T>, AssetMetadata<T>) {
assert!(sui::types::is_one_time_witness(&witness), EBadWitness);
assert!(total_supply > 0, EInsufficientTotalSupply);
let asset_cap = AssetCap {
id: object::new(ctx),
supply: balance::create_supply(witness),
total_supply,
burnable
};
let asset_metadata = AssetMetadata {
id: object::new(ctx),
name,
total_supply,
symbol,
description,
icon_url
};
emit(AssetCreated {
asset_metadata: object::id(&asset_metadata),
name: type_name::into_string(type_name::get<T>())
});
(asset_cap, asset_metadata)
}
I’ll appreciate any help i can get regards this