Gas Sponsorship Guide
DuckyDux’s gas sponsorship system enables truly gasless experiences for your users by allowing you to pay transaction fees on their behalf with automatic repayment.
Unique Feature: DuckyDux’s sponsorship model automatically handles gas estimation, repayment calculation, and execution - no complex smart contracts required.
How Gas Sponsorship Works
User initiates transaction
User creates a transaction but doesn’t need ETH for gas
Sponsor pays upfront
DuckyDux sponsor contract covers the gas costs
Automatic repayment
User repays sponsor in the same transaction using token proceeds
Sponsorship Flow
Get Quote
// Get sponsorship quote
const sponsorshipQuote = await fetch('https://api.duckydux.com/v1/bundles/quote', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
accounts: ['0x123...abc'], // Users to sponsor
amounts: ['1000000000000000000'] // 1 ETH worth of gas
})
});
const quote = await sponsorshipQuote.json();
Sponsorship Quote Structure
| Field | Description | Example |
|---|---|---|
repaymentAmount | Amount user must repay | 1050000000000000000 |
maxFeePerGas | Maximum gas price used | 20000000000 |
feePercent | Sponsorship fee percentage | 5.0 |
sponsorAddress | Contract handling sponsorship | 0xabc... |
Complete Sponsored Swap Example
Get Swap Quote with Sponsorship
const swapQuote = await fetch('https://api.duckydux.com/v1/swap/quote?' + new URLSearchParams({
sources: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
sinks: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // ETH
supplies: '1000000000', // 1000 USDC
demands: '-1',
slippage: '0.5',
sender: userAddress,
sponsorship: 'true', // Enable sponsorship data
check_approvals: 'true'
}));
const quote = await swapQuote.json();When sponsorship=true, the swap quote includes sponsorship information automatically calculated
based on the transaction requirements.
Sign User Transactions
The API response provides all the necessary transactions with sequential nonces and EIP-1559 gas parameters pre-populated. The user does not need ETH for gas. Sign each transaction as provided.
const signedTxs = []
// Sign approval transaction (if needed)
if (quote.approvals.length > 0) {
const signedApproval = await web3.eth.accounts.signTransaction(
quote.approvals[0].tx,
userPrivateKey
)
signedTxs.push(signedApproval.rawTransaction)
}
// Sign swap transaction(s)
for (const tx of quote.txs) {
const signedSwap = await web3.eth.accounts.signTransaction(tx, userPrivateKey)
signedTxs.push(signedSwap.rawTransaction)
}Submit Sponsored Bundle
const sponsorship = quote.sponsorship // Sponsorship data from the swap quote
const bundleResponse = await fetch('https://api.duckydux.com/v1/bundles/sponsored/send', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
accounts: [userAddress],
amounts: [sponsorship.sponsorAmount],
repayments: [sponsorship.repaymentAmount],
maxFeePerGas: sponsorship.maxFeePerGas,
txs: signedTxs,
}),
})
const result = await bundleResponse.json()
console.log('Sponsored bundle submitted:', result.bundleId)Sponsorship Economics
Fee Structure
Important: Sponsorship fees typically range from 5-10% of the gas cost, covering operational costs and risk premium.
// Example fee calculation
const gasAmount = '1000000000000000000' // 1 ETH worth of gas
const feePercent = 5.0 // 5% fee
const repaymentAmount = gasAmount * (1 + feePercent / 100)
// User repays 1.05 ETH for 1 ETH of sponsored gasRepayment Logic
The sponsorship system automatically handles repayment through these mechanisms:
- Token-to-ETH conversion: If user receives ETH from swap, direct repayment
- Multi-token repayment: System accepts repayment in various tokens
- Slippage protection: Repayment amount accounts for potential slippage
On-Chain Repayment Mechanism
The GasSponsor smart contract facilitates atomic and secure repayments. When a user’s transaction is sponsored, a debt is recorded on-chain. The user can repay this debt by sending ETH directly to the GasSponsor contract.
The contract’s receive() function is designed to handle these payments:
receive() external payable nonReentrant {
Debt memory debt = debts[msg.sender];
if (debt.amount > 0) {
_executeRepayment(msg.sender, debt, msg.value);
}
}This ensures that when ETH is sent to the contract, it automatically checks for an outstanding debt for the sender and processes the repayment. The _executeRepayment function verifies that the paid amount is sufficient, clears the debt, and forwards the funds to the original relayer, making the process transparent and secure.
Risk Management
| Risk | Mitigation | Implementation |
|---|---|---|
| Insufficient repayment | Pre-calculate exact amounts | Use quote system |
| Gas price volatility | Fixed max fee per gas | Set in quote |
| Transaction failure | Atomic bundle execution | All-or-nothing |
| Slippage | Include safety margin | Buffer in repayment |
Integration Patterns
Frontend
// Frontend: Gasless user experience
class DuckyDuxGaslessSwap {
async executeSwap(fromToken, toToken, amount) {
// 1. Get swap quote with sponsorship
const quote = await this.getQuoteWithSponsorship(fromToken, toToken, amount);
// 2. User signs transactions (zero gas)
const signedTxs = await this.signTransactions(quote);
// 3. Submit sponsored bundle
const result = await this.submitSponsoredBundle(signedTxs, quote.sponsorship);
return result;
}
}Common Issues and Solutions
Common Pitfall: Not accounting for gas price fluctuations. Always use the maxFeePerGas from
the sponsorship quote.
Insufficient Repayment
Problem: User doesn’t receive enough tokens to cover repayment
Solution: Add safety margins and slippage buffers
// Add 5% buffer to repayment calculation
const bufferedRepayment = sponsorship.repaymentAmount * 1.05Gas Price Volatility
Problem: Gas prices spike after getting quote
Solution: Use recent quotes and appropriate max fee per gas
// Refresh quotes frequently in volatile conditions
const isVolatile = currentGasPrice > averageGasPrice * 1.5
if (isVolatile) {
// Get fresh quote
const newQuote = await getSponsorshipQuote()
}Bundle Failures
Problem: Sponsored bundle fails to execute
Solution: Implement retry logic with updated parameters
async function submitSponsorshipWithRetry(bundleData, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const result = await submitSponsoredBundle(bundleData)
return result
} catch (error) {
if (i === maxRetries - 1) throw error
// Update gas parameters for retry
bundleData = await updateGasParameters(bundleData)
}
}
}