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

  1. Navigate to the UTXOS dashboard and log into your account
  2. Create a new sponsorship campaign
  3. Configure your sponsorship settings and policies
  4. Copy the Sponsorship ID from the sponsorship settings for use in your code

Fund the wallet

  1. In the Sponsorships table, you will find your wallet address. Copy this address.
  2. 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();

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 phase
  • numUtxosPrepare: the number of UTXOs that are prepared during the prepare phase
  • utxoAmount: 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");