How It Works
Use transaction sponsorship to let your users sign transactions while your developer-controlled wallet covers the network fees. This guide explains the concepts, the end-to-end flow, and how the SDK coordinates UTXO management and transaction rewriting under the hood.
TL;DR:
- Create and fund a developer-controlled wallet (pays fees).
- Build your transaction with a “static” sponsorship UTXO and change address from the SDK.
- Ask the sponsorship SDK to swap in a real UTXO and sign on the server.
- Let the user sign and submit the final sponsored transaction.
- UTXOS automatically manages UTXO creation and chains prep transactions when needed, so you don’t have to worry about UTXO contention.
Key Concepts
- Developer-controlled wallet: The wallet you control and fund. It pays the fees and manages a pool of UTXOs for sponsorship.
- Static sponsorship info: A fixed “template” input and change address you use while building the transaction. The SDK later swaps this template with a real UTXO.
- Sponsorship UTXO: An actual UTXO selected from your wallet’s pool to replace the static input.
- Collateral UTXO (optional): A designated UTXO that can serve as collateral if your chain or script requires it.
- CBOR transaction: The serialized transaction produced by your builder, which the SDK parses and rewrites.
- UTXOS automatic UTXO management: UTXOS keeps your sponsorship UTXO pool healthy by creating, consolidating, and refreshing UTXOs automatically. When the pool is low or stale, UTXOS chains a preparatory transaction to mint new sponsorship-sized UTXOs—minimizing contention without manual intervention.
Step 1: Create and fund the developer-controlled wallet
This wallet pays transaction fees. Fund it by sending cryptocurrency to its address.
Ensure that your sponsorship configuration is set to include enough UTXOs to satisfy your concurrency needs.
Step 2: Build the transaction with static sponsorship info
Use the static info from the SDK as a placeholder:
- Set the change address to the static change address.
- Add the static UTXO as an input.
- Optionally add the provided collateral UTXO.
Example:
// 1) Get the static information
const staticInfo = sdk.sponsorship.getStaticInfo();
// 2) Build your transaction with your preferred builder
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
)
// Optional: Add static collateral if needed
.txInCollateral(
staticInfo.collateral.input.txHash,
staticInfo.collateral.input.outputIndex,
staticInfo.collateral.output.amount,
staticInfo.collateral.output.address
);
const transaction = txBuilder.complete(); // CBORNotes:
- The “static” inputs and change are only placeholders. The SDK replaces them later with real UTXOs.
- Keep your business logic (mints, script interactions, etc.) as usual—only the sponsorship-specific pieces use the static info.
Step 3: Request sponsorship
Send the built CBOR transaction to the sponsorship SDK. The SDK will:
- Verify and prepare the UTXO pool.
- Swap the static placeholder with a selected UTXO from your wallet.
- Sign the transaction with the developer-controlled wallet.
- Return a new CBOR transaction ready for the user to co-sign (if needed) and submit.
const sponsorTxResult = await sdk.sponsorship.sponsorTx({
sponsorshipId: "your_sponsorship_id",
tx: transaction, // CBOR from Step 2
});The result contains a sponsored transaction in CBOR form.
Note: UTXOS handles UTXO preparation automatically. If the pool is below your configured target, it may chain a preparatory transaction before or alongside sponsorship. No manual fragmentation or consolidation is required.
What happens under the hood
- UTXO availability check
- Fetch all available UTXOs from the developer-controlled wallet.
- Exclude UTXOs that are pending in the mempool to avoid double-spends.
- The remaining set forms the “available” pool.
- UTXO pool maintenance (automated by UTXOS)
- Fetch all UTXOs again from the wallet.
- Identify inputs to consolidate:
- Any UTXOs that are not the standard sponsorship amount.
- Any sponsorship-sized UTXOs that have been pending longer than a configured threshold (consume/refresh them).
- Build a “prepare UTXO” transaction:
- Consolidate selected inputs.
- Create new UTXOs per your configured count/amount.
- Submit this transaction and include its hash in the sponsorship response metadata when chaining is needed. UTXOS performs this automatically and chains preparation with sponsorship to avoid UTXO contention.
- UTXO selection
- Randomly select an eligible UTXO from the available pool for this sponsorship.
- Transaction rewrite
- Parse the provided CBOR with a transaction parser (e.g., TxParser).
- Remove the static input(s) and the static change output.
- Rebuild the transaction with:
- Original non-static inputs and outputs intact.
- The selected real sponsorship UTXO added as input.
- Change set to the developer-controlled wallet address.
- Return the rewritten transaction in CBOR.
- Developer-controlled wallet signature
- The developer wallet signs the rewritten transaction using its private key (server-side).
- Return the sponsored transaction
- The final CBOR includes the sponsorship UTXO and signatures from the developer-controlled wallet.
- This CBOR is ready for the user to sign (if required by your flow) and submit.
Step 4: User signs and submits
Finally, the user signs and submits the sponsored transaction.
const signedTx = await userWallet.signTx(sponsoredTx.data, true);
const txHash = await provider.submitTx(signedTx);Notes:
- Depending on your policy, the developer’s signature might already be present. The user adds their signature(s) before submission.
- Ensure you submit to the correct network/provider.
API Notes
-
sdk.sponsorship.getStaticInfo()- Returns:
- changeAddress: string
- utxo:
{ input: { txHash: string, outputIndex: number }, output: { amount: string | bigint, address: string } } - collateral: same shape as utxo (optional if your flow requires collateral)
- Usage: Only for building the placeholder transaction in Step 2.
- Returns:
-
sdk.sponsorship.sponsorTx({ sponsorshipId, tx })- Input:
- sponsorshipId: string (issued by your system)
- tx: string (CBOR-encoded transaction)
- Output:
- data: string (CBOR-encoded sponsored transaction ready for user signature/submission)
- Optionally, metadata indicating a chained “prepare UTXO” transaction if the pool needed maintenance.
- Input:
Error Handling and Retries
- Insufficient UTXOs: UTXOS automatically builds and submits a prepare UTXO transaction and chains it with the sponsorship flow. You may see a chained response; usually no action is needed, but if your policy requires confirmation before spending, retry sponsorship after the prep confirms.
- Pending UTXOs: If many UTXOs are pending, sponsorship may delay or return an error; consider increasing your UTXO buffer or fragmentation.
- CBOR/Parsing errors: Ensure your transaction is valid CBOR and includes the static input and change address exactly as provided by getStaticInfo().
- Timeout or provider errors: Implement retries with backoff and surface actionable messages to clients.
Security Considerations
- Keep the developer-controlled wallet’s private keys on a secure server. Never ship them to the client.
- Rate-limit sponsorship requests to prevent abuse and accidental UTXO exhaustion.
- Monitor the UTXO pool:
- Minimum sponsorship UTXO count.
- Standard sponsorship UTXO size.
- Pending vs. confirmed ratio.
- Use dedicated addresses for change to simplify accounting and auditing.
Best Practices
- Choose a standard sponsorship UTXO size that comfortably covers typical fees plus a buffer.
- Maintain a target UTXO count based on peak concurrency (e.g., 2–3× your expected parallel sponsorships).
- Fund the wallet periodically and automate UTXO maintenance via the SDK’s consolidation flow.
FAQ
- Can I use any transaction builder?
- Yes. As long as you can set the change address and add the static input(s), and produce a CBOR transaction.
- What format must I send to sponsorTx?
- CBOR-encoded transaction as a string.
- Does the SDK always create a consolidation transaction?
- Only when your available UTXO pool is below the configured target or includes stale/pending UTXOs that should be refreshed.
- Who signs what?
- The developer-controlled wallet signs to cover fees and provide the sponsorship input. The user signs their parts (e.g., spending inputs, mints, scripts) per your app’s policy before submission.
- How many confirmations do I need before new sponsorship UTXOs are usable?
- Follow your environment’s recommended confirmation policy; pending UTXOs are excluded until safely usable.