Cardano Transaction Sponsorship
Transaction sponsorship allows you to pay for users’ transaction fees, improving user experience by removing the need for users to hold native tokens for gas fees.
Step-by-Step Guide
Create A Sponsorship
- Navigate to the UTXOS dashboard and log into your account
- Create a new sponsorship campaign
- Configure your sponsorship settings and policies
- Copy the
Sponsorship IDfrom the sponsorship settings for use in your code
Fund the wallet
- In the Sponsorships table, you will find your wallet address. Copy this address.
- Use the copied address to transfer funds from your wallet to this developer-controlled wallet.
Initialize The SDK
Initialize the Web3Sdk with your project credentials and network configuration:
import { Web3Sdk } from "@meshsdk/web3-sdk";
const sdk = new Web3Sdk({
projectId: process.env.NEXT_PUBLIC_UTXOS_PROJECT_ID, // https://utxos.dev/dashboard
apiKey: process.env.UTXOS_API_KEY,
network: "preprod",
privateKey: process.env.UTXOS_PRIVATE_KEY,
fetcher: provider,
submitter: provider,
});Never expose your private key in client-side code. Use environment variables or secure key management in production.
Build The Transaction
The SDK provides static UTXO information that must be included in your transaction:
// Get the required static information
const staticInfo = sdk.sponsorship.getStaticInfo();
// Build your transaction with the required fields
const txBuilder = your_preferred_transaction_builder
.
.
// Required: Set the change address from static info
.changeAddress(staticInfo.changeAddress)
// Required: Add the static UTXO as an input
.txIn(
staticInfo.utxo.input.txHash,
staticInfo.utxo.input.outputIndex,
staticInfo.utxo.output.amount,
staticInfo.utxo.output.address,
0,
)
// If required: Add the static UTXO as collateral
.txInCollateral(
staticInfo.collateral.input.txHash,
staticInfo.collateral.input.outputIndex,
staticInfo.collateral.output.amount,
staticInfo.collateral.output.address,
);
const transaction = txBuilder.complete();Sponsor The Transaction
Once your transaction is built, sponsor it and submit to the network:
try {
// Step 1: Request sponsorship for your transaction
const sponsorTxResult = await sdk.sponsorship.sponsorTx({
sponsorshipId: "your_sponsorship_id", // Replace with your actual sponsorship ID
tx: transaction, // Your built transaction
});
if (sponsorTxResult.success === false) {
throw new Error(sponsorTxResult.error);
}
// Step 2: User signs the sponsored transaction
const signedTx = await userWallet.cardano.signTx(sponsoredTx.data, true);
// Step 3: Submit the signed transaction to the network
const txHash = await provider.submitTx(signedTx);
console.log(`Transaction submitted successfully! Hash: ${txHash}`);
} catch (error) {
console.error("Sponsorship failed:", error);
// Handle sponsorship errors (insufficient funds, policy violations, etc.)
}Complete Example
Here’s a complete working example:
const provider = BlockfrostProvider("...");
const sponsorshipId = "your_sponsorship_id"; // Replace with your actual sponsorship ID
const sdk = new Web3Sdk({
projectId: "11111111-2222-3333-YOUR-PROJECTID", // Your project ID from dashboard
apiKey: "YOUR_API_KEY", // Your API key from dashboard
network: "testnet", // Use "testnet" for testing, "mainnet" for production
privateKey: "YOUR_PRIVATE_KEY", // Developer's wallet private key (keep secure!)
fetcher: provider, // Your Cardano provider for fetching data
submitter: provider, // Your Cardano provider for submitting transactions
});
async function developerCreateTx(receivingAddress: string) {
const txBuilder = new MeshTxBuilder({
fetcher: provider,
});
const forgingScript = ForgeScript.withOneSignature(receivingAddress);
const demoAssetMetadata = {
name: "Mesh Token",
image: "ipfs://QmRzicpReutwCkM6aotuKjErFCUD213DpwPq6ByuzMJaua",
mediaType: "image/jpg",
description: "This NFT was minted by Mesh (https://meshjs.dev/).",
};
const policyId = resolveScriptHash(forgingScript);
const tokenName = "MeshToken";
const tokenNameHex = stringToHex(tokenName);
const metadata = { [policyId]: { [tokenName]: { ...demoAssetMetadata } } };
const staticInfo = sdk.sponsorship.getStaticInfo();
txBuilder
.mint("1", policyId, tokenNameHex)
.mintingScript(forgingScript)
.metadataValue(721, metadata)
.txOut(receivingAddress, [{ unit: policyId + tokenNameHex, quantity: "1" }])
.changeAddress(staticInfo.changeAddress)
.txIn(
staticInfo.utxo.input.txHash,
staticInfo.utxo.input.outputIndex,
staticInfo.utxo.output.amount,
staticInfo.utxo.output.address,
0,
)
.txInCollateral(
staticInfo.collateral.input.txHash,
staticInfo.collateral.input.outputIndex,
staticInfo.collateral.output.amount,
staticInfo.collateral.output.address,
);
const unsignedTx = await txBuilder.complete();
return unsignedTx;
}
async function runFullDemo() {
const staticInfo = sdk.sponsorship.getStaticInfo();
const userWallet = await getUserWallet(); // this can be UTXOS user controlled wallet or CIP-30 browser wallet
const userAddress = await userWallet.cardano.getChangeAddress();
const tx = await developerCreateTx(userAddress);
const tx2 = await sdk.sponsorship.sponsorTx({
sponsorshipId: sponsorshipId,
tx: tx,
});
const signedTx = await userWallet.cardano.signTx(tx2, true);
const txHash = await provider.submitTx(signedTx);
console.log("txHash", txHash);
}Additional Information
Configuration Options
A developer account can have multiple sponsorships configurations. Each sponsorship can have a different configuration.
numUtxosTriggerPrepare: the number of UTXOs that trigger the prepare phasenumUtxosPrepare: the number of UTXOs that are prepared during the prepare phaseutxoAmount: the amount of balance to prepare for each UTXO
getStaticInfo() Method
The getStaticInfo() method provides essential static information required for building sponsored transactions. It returns the change address and a predefined UTXO that must be included in the transaction inputs.
You can specify the sponsorship amount (“5” or “99”) to get the corresponding UTXO. “99” is useful for higher fee transactions or batch airdrops.
For example, to get the static info for sponsoring transactions with 99 ADA:
const staticInfo = sdk.sponsorship.getStaticInfo("99");