Your TriviaBattle contract is 100% compatible with paymasters (Base Account Paymaster, CDP Paymaster, etc.). All security improvements (SafeERC20, CEI pattern, ReentrancyGuard) work seamlessly with paymaster sponsorship.
These functions are called by users and should be sponsored by paymaster:
Contract: USDC Token Address
- approve(address spender, uint256 amount)
Contract: Your TriviaBattle Contract Address
- joinBattle() // Paid players join (uses USDC transferFrom)
- joinTrialBattle(string) // Trial players join (no USDC, but can be gasless)
- submitScore(uint256) // Submit game score
- submitTrialScore(string, uint256) // Submit trial score
- claimWinnings() // Claim prize winnings (uses USDC transfer)
These functions are called by the contract owner and should NOT be in the allowlist:
- startSession(uint256) // Owner only
- distributePrizes() // Owner/Chainlink only
- updatePlatformFeeRecipient(address) // Owner only
- setChainlinkForwarder(address) // Owner only
- emergencyWithdraw() // Owner only
- setTimeLockDelay(uint256) // Owner only
Add these to your paymaster allowlist in the CDP Dashboard:
-
USDC Token Contract
- Address:
0x833589fcd6edb6e08f4c7c32d4f71b54bda02913(Base Mainnet) - Function:
approve(address,uint256)
- Address:
-
TriviaBattle Contract
- Address:
YOUR_DEPLOYED_CONTRACT_ADDRESS - Functions:
joinBattle()joinTrialBattle(string)submitScore(uint256)submitTrialScore(string,uint256)claimWinnings()
- Address:
- Go to CDP Dashboard
- Navigate to Paymaster → Contract Allowlist
- Add each contract address and function signature
- Save changes
The contract uses SafeERC20 which is fully compatible with paymasters:
- ✅ Handles non-standard ERC20 tokens (like USDC)
- ✅ Detects paused tokens and reverts appropriately
- ✅ Works with paymaster-sponsored transactions
The nonReentrant modifier works correctly with paymasters:
- ✅ Prevents reentrancy attacks
- ✅ Compatible with paymaster transaction flow
- ✅ No conflicts with paymaster execution
The Checks-Effects-Interactions pattern is maintained:
- ✅ State updates happen before external calls
- ✅ Paymaster transactions follow the same pattern
- ✅ No issues with paymaster sponsorship
// User calls joinBattle() - paymaster sponsors gas
const tx = await contract.joinBattle({
// Paymaster automatically sponsors if:
// 1. Contract is in allowlist
// 2. Function is in allowlist
// 3. Paymaster has sufficient balance
});
// Transaction flow:
// 1. User signs transaction
// 2. Paymaster validates (checks allowlist)
// 3. Paymaster sponsors gas fees
// 4. Contract executes:
// - Updates state (prizePool, playerCount, etc.)
// - Calls usdcToken.safeTransferFrom() (also in allowlist)
// 5. User pays 1 USDC entry fee (not gas!)// User claims winnings - paymaster sponsors gas
const tx = await contract.claimWinnings({
// Paymaster sponsors the gas
// User receives USDC winnings
// No gas cost to user!
});Both the USDC contract's approve() and the TriviaBattle contract's functions that use safeTransferFrom() need to be in the allowlist:
- ✅ USDC:
approve(address,uint256) - ✅ TriviaBattle:
joinBattle()(callssafeTransferFrominternally) - ✅ TriviaBattle:
claimWinnings()(callssafeTransferinternally)
Ensure your paymaster has sufficient balance to sponsor transactions:
- Monitor in CDP Dashboard
- Top up as needed
- Set spending limits if desired
The contract functions have reasonable gas limits:
joinBattle(): ~100,000 gas (typical)submitScore(): ~50,000 gas (typical)claimWinnings(): ~80,000 gas (typical)
Ensure your paymaster can handle these gas costs.
You can batch multiple operations in a single paymaster-sponsored transaction:
// Batch: approve + joinBattle
const calls = [
{
to: USDC_ADDRESS,
data: encodeFunctionData({
abi: usdcAbi,
functionName: 'approve',
args: [CONTRACT_ADDRESS, ENTRY_FEE]
})
},
{
to: CONTRACT_ADDRESS,
data: encodeFunctionData({
abi: triviaAbi,
functionName: 'joinBattle'
})
}
];
// Single paymaster-sponsored transaction
await wallet.sendCalls({ calls });// Check if contract is in allowlist
const isAllowed = await paymaster.isContractAllowed(CONTRACT_ADDRESS);
console.log('Contract in allowlist:', isAllowed);// Try joining battle with paymaster
try {
const tx = await contract.joinBattle();
console.log('✅ Paymaster sponsored transaction:', tx.hash);
} catch (error) {
if (error.message.includes('paymaster')) {
console.error('❌ Paymaster issue - check allowlist');
}
}- Check CDP Dashboard for sponsored transactions
- Monitor gas costs
- Track paymaster balance
The contract's security features work correctly with paymasters:
- ReentrancyGuard: Prevents attacks even with paymaster
- SafeERC20: Handles USDC transfers safely
- CEI Pattern: Maintains state consistency
- Access Control: Owner functions remain protected
Remember that paymaster sponsorship requires trust in the paymaster service:
- Paymaster can see transaction details
- Paymaster controls gas sponsorship
- Use reputable paymaster services (Coinbase CDP, etc.)
✅ Your contract is fully paymaster-compatible!
To enable paymaster:
- Add USDC
approve()to allowlist - Add TriviaBattle user functions to allowlist
- Ensure paymaster has sufficient balance
- Test with a small transaction first
Functions that benefit from paymaster:
joinBattle()- Users join games gaslesslyjoinTrialBattle()- Trial players join gaslesslysubmitScore()- Score submissions gaslessclaimWinnings()- Prize claims gasless
Functions that DON'T need paymaster:
- Owner/admin functions (owner pays gas)
- Chainlink automation (sponsored separately)
Your contract is ready for production with paymaster support! 🚀