This integration enables seamless fiat-to-crypto on-ramp for PayDrip drip creation using the Base Pay API. Users can create drips with fiat payments, generate shareable payment links, and get real-time fiat conversion quotes.
Purpose: Bridge between Base Pay fiat on-ramp and drip creation
Key Features:
- Initiate drip creation with fiat payment
- Handle payment confirmation callbacks from Base Pay oracle
- Finalize drip creation after payment confirmation
- Track pending drips awaiting payment
Key Functions:
initiateDripWithFiat(receiver, amountPerStep, totalSteps, interval, returnUrl)
confirmPayment(paymentId, token) // Called by oracle
failPayment(paymentId, reason) // Called by oracle
finalizeDrip(paymentId) // Creates actual drip after payment confirmedPayment Flow:
- User calls
initiateDripWithFiat() - Contract generates paymentId and checkout URL
- User completes fiat payment via Base Pay
- Oracle calls
confirmPayment()after verification - User calls
finalizeDrip()to create the drip in PayDrip contract
Purpose: Generate shareable payment links for drip creation
Key Features:
- Create single-use or multi-use payment links
- Support both crypto and fiat payments
- Link expiry and validation
- Track link usage and associated drips
Key Functions:
createPaymentLink(receiver, amountPerStep, totalSteps, interval, expiry, memo, token, multiUse)
payViaLink(linkId) // Pay with crypto
payViaLinkWithFiat(linkId, returnUrl) // Pay with fiat via Base Pay
cancelLink(linkId)
isLinkValid(linkId)Use Cases:
- Subscription payment links
- Invoice payment links
- Donation links
- Recurring payment requests
Purpose: Provide real-time fiat to crypto conversion quotes
Key Features:
- Support multiple fiat currencies (USD, EUR, GBP)
- Oracle-based rate updates
- Quote validity periods
- Fee calculation
- Stale rate detection
Key Functions:
getQuote(usdcAmount, fiatCurrency) // Get simple quote
estimateDripCost(amountPerStep, totalSteps, fiatCurrency) // Estimate total drip cost
getDetailedQuote(usdcAmount, fiatCurrency) // Get detailed quote with metadata
updateRate(currency, newRate) // Oracle updates rate- PayDrip proxy deployed
- USDC contract address on Base
- Oracle address for payment confirmation
- Base Pay processor address
- Deploy BasePayDrip
BasePayDrip implementation = new BasePayDrip();
bytes memory initData = abi.encodeWithSelector(
BasePayDrip.initialize.selector,
payDripAddress,
oracleAddress,
basePayProcessorAddress
);
PaymentStreamProxy proxy = new PaymentStreamProxy(address(implementation), initData);- Deploy PaymentLinkFactory
PaymentLinkFactory implementation = new PaymentLinkFactory();
bytes memory initData = abi.encodeWithSelector(
PaymentLinkFactory.initialize.selector,
payDripAddress,
basePayDripAddress
);
PaymentStreamProxy proxy = new PaymentStreamProxy(address(implementation), initData);- Deploy FiatQuoter
FiatQuoter implementation = new FiatQuoter();
bytes memory initData = abi.encodeWithSelector(
FiatQuoter.initialize.selector,
oracleAddress
);
PaymentStreamProxy proxy = new PaymentStreamProxy(address(implementation), initData);// 1. Initiate fiat payment
const { paymentId, checkoutUrl } = await basePayDrip.initiateDripWithFiat(
receiverAddress,
amountPerStep,
totalSteps,
interval,
returnUrl
);
// 2. Redirect user to checkoutUrl
window.location.href = checkoutUrl;
// 3. After payment, oracle confirms (backend)
await basePayDrip.confirmPayment(paymentId, usdcAddress);
// 4. Finalize drip creation
const dripId = await basePayDrip.finalizeDrip(paymentId);// Create link
const linkId = await linkFactory.createPaymentLink(
receiverAddress,
amountPerStep,
totalSteps,
interval,
expiryTimestamp,
"Monthly subscription",
usdcAddress,
true // multiUse
);
// Share link URL
const linkUrl = `https://paydrip.app/pay/${linkId}`;
// Pay via link (user perspective)
const dripId = await linkFactory.payViaLink(linkId);// Get quote for drip cost
const fiatAmount = await fiatQuoter.estimateDripCost(
amountPerStep,
totalSteps,
"USD"
);
console.log(`Total cost: ${fiatAmount / 1e6} USD`);
// Get detailed quote
const quote = await fiatQuoter.getDetailedQuote(totalAmount, "USD");
console.log(`Rate: ${quote.rate}`);
console.log(`Valid until: ${quote.validUntil}`);The oracle monitors Base Pay payment events and calls confirmation functions:
// Listen for Base Pay payment success
basePayAPI.on('payment.success', async (event) => {
const { paymentId, amount, token } = event;
// Verify payment on-chain
const verified = await verifyPayment(paymentId);
if (verified) {
// Confirm payment in BasePayDrip contract
await basePayDrip.confirmPayment(paymentId, token);
} else {
await basePayDrip.failPayment(paymentId, "Verification failed");
}
});Updates fiat exchange rates periodically:
// Update rates every 5 minutes
setInterval(async () => {
const rates = await fetchRatesFromAPI(['USD', 'EUR', 'GBP']);
await fiatQuoter.batchUpdateRates(
['USD', 'EUR', 'GBP'],
[rates.USD, rates.EUR, rates.GBP]
);
}, 5 * 60 * 1000);- Oracle Trust: Oracle must be trusted to confirm payments correctly
- Payment Timeout: Pending payments expire after 24 hours
- Rate Staleness: Quotes become stale after 5 minutes
- Authorization: Only oracle can confirm/fail payments
- Reentrancy: All external calls protected with ReentrancyGuard
- Upgradeability: All contracts are UUPS upgradeable
# Run all Base Pay integration tests
forge test --match-contract BasePayDripTest -vv
# Run payment link tests
forge test --match-contract PaymentLinkFactoryTest -vv
# Run all integration tests
forge test --match-path "test/BasePayDrip.t.sol" --match-path "test/PaymentLinkFactory.t.sol" -vv- PayDrip Proxy:
0x6f2bd18433b0aea1a10be7af88d3a6bbdd0f8b1e - USDC:
0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 - BasePayDrip: TBD
- PaymentLinkFactory: TBD
- FiatQuoter: TBD
- Payment confirmation timeout: 24 hours
- Quote validity: 5 minutes
- Rate validity: 1 hour
- Default fee: 0.5% (50 basis points)
- Multi-token support: Support tokens beyond USDC
- Custom fee structures: Per-link or per-user fee configurations
- Subscription templates: Pre-configured payment link templates
- Analytics dashboard: Track payment volumes and conversion rates
- Webhook integration: Direct Base Pay webhook callbacks
- Gasless transactions: Meta-transactions for better UX