Mint Assets

Create a Minting Policy

First, we need to create a minting policy for the assets we want to mint. In this example, we'll use a native script time-locking policy with our wallet as the required signer:

const address = await lucid.wallet().address();
 
const mintingPolicy = scriptFromNative({
  type: "all",
  scripts: [
    { type: "sig", keyHash: paymentCredentialOf(address).hash },
    {
      type: "before",
      slot: unixTimeToSlot(lucid.config().network, Date.now() + 1000000),
    },
  ],
});

Next we derive the policy id from the minting policy script:

const policyId = mintingPolicyToId(mintingPolicy);

Mint Assets

Now we can mint our desired tokens:

const tx = await lucid
  .newTx()
  .mintAssets({
    [policyId + fromText("MyToken")]: 1n,
    [policyId + fromText("MyOtherToken")]: 1n,
  })
  .pay.ToAddress(address, { [policyId + fromText("MyToken")]: 1n })
  .validTo(Date.now() + 900000)
  .attach.MintingPolicy(mintingPolicy)
  .complete();
 
const signed = await tx.sign.withWallet().complete();
const txHash = await signed.submit();
ℹ️

When working with script parameters (involving nested structures or custom data types):

const scriptWithParams = applyParamsToScript(
  yourCompiledScript,
  [param1, param2, ...]
);
  • Minting tokens creates them, but it doesn't automatically assign them to any address. After minting, the tokens are technically "owned" by the transaction itself.
  • Purpose of pay.ToAddress() is to send the newly minted tokens to a specific address

CIP-0068 Token Standard

CIP-0068 (opens in a new tab) is a token standard that extends CIP-0025 (opens in a new tab) to provide richer metadata functionality.

const tokenName = "Your Token Name";
const tokenImage = "ipfs://QmV0CID...";
 
const metadata = Data.fromJson({
  name: tokenName,
  image: tokenImage,
  otherFields,
});
const version = BigInt(1);
const extra: Data[] = []; // Custom user defined plutus data. Setting data is optional, but the field is required and needs to be at least Unit/Void: #6.121([])
const cip68 = new Constr(0, [metadata, version, extra]);
 
const datum = Data.to(cip68);
const redeemer = Data.void(); // Your CIP-0068 Script Redeemer
 
const spendingValidator: SpendingValidator = { type: "PlutusV3", script: YourCip0068Script };
const validatorAddress = validatorToAddress(network, spendingValidator);
 
const mintingPolicy: MintingPolicy = { type: "PlutusV3", script: YourCip0068Script }; // might be the same as the spending validator if it's multi-purpose
const policyID = mintingPolicyToId(mintingPolicy);
 
const assetName = fromText(tokenName);
 
const refUnit = toUnit(policyID, assetName, 100); // the reference token
const usrUnit = toUnit(policyID, assetName, label); // label: 222 | 333 | 444
 
const tx = await lucid
  .newTx()
  .mintAssets(
    {
      [refUnit]: 1n,
      [usrUnit]: BigInt(qty),
    },
    redeemer
  )
  .attach.MintingPolicy(mintingPolicy)
  .pay.ToContract(
    validatorAddress,
    {
      kind: "inline",
      value: datum,
    },
    {
      [refUnit]: 1n,
    }
  )
  .complete();
💡

An alternative way to define the metadata is to use an object:

const metadataObject = {
  [fromText("myKey")]: Data.to(fromText("myValue")),
};
 
const metadataCBOR = Data.to({ metadata: new Map(Object.entries(metadataObject)), version: 0n }, CIP68Datum);

Burn

To burn tokens, we use a similar process to minting, but with negative values for the assets we want to burn:

const tx = await lucid
  .newTx()
  .mintAssets({
    [policyId + fromText("MyToken")]: -1n,
    [policyId + fromText("MyOtherToken")]: -1n,
  })
  .validTo(Date.now() + 900000)
  .attach.MintingPolicy(mintingPolicy)
  .complete();
 
const signed = await tx.sign.withWallet().complete();
const txHash = await signed.submit();
💡
  • All assets minted in a single mintAssets call should be of the same policy id. You can chain multiple mintAssets calls if you need to mint assets with different policy ids - The minting policy must be attached to the transaction using attach.MintingPolicy - Lucid Evolution supports Native, PlutusV1 / V2 / V3 minting policies. The appropriate script type will be used based on the policy you attach. - When using Plutus scripts (V1 / V2 / V3), make sure to provide an appropriate redeemer. - The validTo field is important for time-locked minting policies to ensure the transaction is submitted within the valid time range