How to Build Multi-Signature Minting Transactions on Cardano
Implement multi-sig NFT minting with the Mesh TypeScript blockchain SDK for Cardano dApp development. Coordinate signatures between browser and server wallets.
Multi-signature (multi-sig) transactions require multiple parties to sign before the transaction can be submitted to the Cardano blockchain. This is essential for NFT minting services where a user pays for minting but the application controls the minting policy in JavaScript Web3 projects.
The multi-sig minting flow:
- Client wallet — User's browser wallet provides payment UTxOs
- Application wallet — Server-side wallet holds the forging script and signs the mint
This guide shows you how to build a complete multi-sig minting system using the Mesh Cardano SDK for dApp development. View the complete source code on GitHub.
Step 1: How Do You Connect the User's Wallet?
Connect the user's browser wallet and get their address and UTxOs:
import { BrowserWallet } from '@meshsdk/core';
const wallet = await BrowserWallet.enable(walletName);Or use the React blockchain CardanoWallet component:
import { CardanoWallet, useWallet } from "@meshsdk/react";
export default function Page() {
const { wallet, connected } = useWallet();
return <CardanoWallet />
}Get the client's address and UTXOs:
const recipientAddress = await wallet.getChangeAddress();
const utxos = await wallet.getUtxos();Select only the UTxOs needed for the minting fee:
const assetMap = new Map<Unit, Quantity>();
assetMap.set("lovelace", mintingFee);
const selectedUtxos = experimentalSelectUtxos(assetMap, utxos, "5000000");Send selectedUtxos and recipientAddress to your backend API.
Step 2: How Do You Build the Transaction on the Server?
On your backend (Next.js API routes, Express, etc.), initialize the provider and application wallet:
const provider = new BlockfrostProvider(
'<blockfrost key here>'
);
const meshWallet = new MeshWallet({
networkId: 0,
fetcher: provider,
submitter: provider,
key: {
type: 'mnemonic',
words: yourMnemonic,
},
});Define the forging script:
const meshWalletAddress = meshWallet.getChangeAddress();
const forgingScript = ForgeScript.withOneSignature(meshWalletAddress);Define the NFT metadata (CIP-25 format):
const assetName = 'MeshToken';
const assetMetadata: AssetMetadata = {
name: 'Mesh Token',
image: 'ipfs://QmRzicpReutwCkM6aotuKjErFCUD213DpwPq6ByuzMJaua',
mediaType: 'image/jpg',
description: 'This NFT was minted by Mesh (https://meshjs.dev/).',
};Build the minting transaction using the user's UTxOs as inputs:
import { MeshTxBuilder, resolveScriptHash, stringToHex } from '@meshsdk/core';
const policyId = resolveScriptHash(forgingScript);
const tokenNameHex = stringToHex(assetName);
const metadata = { [policyId]: { [assetName]: assetMetadata } };
const txBuilder = new MeshTxBuilder({
fetcher: provider,
});
// Add user's UTXOs as inputs
userUtxos.forEach(utxo => {
txBuilder.txIn(utxo.input.txHash, utxo.input.outputIndex, utxo.output.amount, utxo.output.address);
});
const unsignedTx = await txBuilder
.mint("1", policyId, tokenNameHex)
.mintingScript(forgingScript)
.txOut(recipientAddress, [{ unit: policyId + tokenNameHex, quantity: "1" }])
.txOut(bankWalletAddress, [{ unit: "lovelace", quantity: mintingFee }])
.metadataValue(721, metadata)
.changeAddress(recipientAddress)
.complete();Return the unsigned transaction to the client.
Step 3: How Does the User Sign?
The user signs with partial signing enabled (true) since another signature is required:
const signedTx = await wallet.signTx(unsignedTx, true);Send the partially signed transaction back to the server.
Step 4: How Does the Application Sign and Submit?
The backend adds its signature and submits:
const meshWalletSignedTx = await meshWallet.signTx(signedTx, true);
const txHash = await meshWallet.submitTx(meshWalletSignedTx);The transaction is now fully signed and submitted to the Cardano blockchain.
What Security Considerations Apply?
- Never expose mnemonic phrases in client-side code
- Validate user UTxOs before building transactions
- Set reasonable minting fees to cover transaction costs
- Implement rate limiting to prevent abuse
What Should You Explore Next?
- View the complete example code
- Learn about smart contract transactions
- Explore minting transaction options
How to Mint NFTs on Cardano with Node.js
Build a server-side NFT minting application using the Mesh TypeScript blockchain SDK and Node.js for Cardano dApp development.
How to Prove Wallet Ownership with Cardano Message Signing
Implement wallet authentication in your Cardano dApp development using CIP-8 message signing and the Mesh TypeScript blockchain SDK.