diff --git a/package.json b/package.json index 4ca23949..24bb51e5 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "packageManager": "pnpm@10.28.1", "scripts": { "dev": "NODE_OPTIONS='--import tsx' vite", - "build": "tsgo --build && vite build", + "build": "tsgo --build && NODE_OPTIONS='--max-old-space-size=8192' vite build", "check": "biome check --write --unsafe .", "check:types": "tsgo --project tsconfig.json --noEmit", "preview": "node dist/preview.js" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e292176c..038c68ef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2835,6 +2835,7 @@ packages: react-server-dom-webpack@19.2.3: resolution: {integrity: sha512-ifo7aqqdNJyV6U2zuvvWX4rRQ51pbleuUFNG7ZYhIuSuWZzQPbfmYv11GNsyJm/3uGNbt8buJ9wmoISn/uOAfw==} engines: {node: '>=0.10.0'} + deprecated: High Security Vulnerability in React Server Components peerDependencies: react: ^19.2.3 react-dom: ^19.2.3 diff --git a/src/pages/guides/accept-stablecoin-payments-for-business.mdx b/src/pages/guides/accept-stablecoin-payments-for-business.mdx new file mode 100644 index 00000000..2afc0381 --- /dev/null +++ b/src/pages/guides/accept-stablecoin-payments-for-business.mdx @@ -0,0 +1,38 @@ +--- +title: "Accept Stablecoin Payments for Business" +description: "Learn how to accept stablecoin payments for your business with Tempo's ~$0.001 fees, instant settlement, and ERP-ready payment metadata." +--- + +# Accept Stablecoin Payments for Business + +Stablecoins offer businesses a faster, cheaper alternative to traditional payment rails. With Tempo, you can accept stablecoins with transaction fees as low as ~$0.001 and instant settlement—no waiting days for funds to clear. Tempo supports native USD stablecoins like pathUSD, AlphaUSD, BetaUSD, and ThetaUSD. + +## Why Accept Stablecoin Payments? + +- **Near-zero fees**: Transaction costs of ~$0.001 compared to 2-3% credit card fees +- **Instant settlement**: Funds arrive in seconds, not days +- **Global reach**: Accept payments from anywhere without currency conversion delays +- **No chargebacks**: Transactions are final once confirmed + +## How Tempo Makes It Simple + +### Stablecoin-Native Gas + +Tempo eliminates the complexity of managing native gas tokens. Pay transaction fees directly in stablecoins, simplifying your treasury operations and accounting. + +### Payment Metadata for Accounting + +Every Tempo transaction supports rich metadata—invoice numbers, customer IDs, order references—that integrates directly with your ERP and accounting systems. No more manual reconciliation. + +### Batch Payments + +Process hundreds of payments in a single transaction, reducing costs and operational overhead for high-volume businesses. + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/accept-stablecoin-payments.mdx b/src/pages/guides/accept-stablecoin-payments.mdx new file mode 100644 index 00000000..ede3115b --- /dev/null +++ b/src/pages/guides/accept-stablecoin-payments.mdx @@ -0,0 +1,68 @@ +--- +title: "Accept Stablecoin Payments" +description: "Start accepting stablecoin payments with Tempo's ~$0.001 transaction fees, instant settlement, and built-in metadata for seamless accounting integration." +--- + +# Accept Stablecoin Payments + +Tempo provides infrastructure to accept stablecoin payments with minimal fees, instant finality, and enterprise-grade payment tracking. + +## Available Stablecoins + +Tempo supports native stablecoins including: + +- **pathUSD** — USD-denominated stablecoin +- **AlphaUSD** — USD-denominated stablecoin +- **BetaUSD** — USD-denominated stablecoin +- **ThetaUSD** — USD-denominated stablecoin + +## Why Stablecoins? + +- **Dollar-denominated**: 1:1 USD value, eliminating volatility concerns +- **Global reach**: Accept payments from anyone with a wallet +- **Always available**: 24/7 settlement, no banking hours + +## Tempo's Payment Advantages + +### Ultra-Low Transaction Costs + +Tempo's transaction fees are approximately $0.001—a fraction of a cent per payment. Compare that to: + +- Credit cards: 2.5-3.5% + $0.30 per transaction +- Wire transfers: $25-50 per transaction +- ACH: $0.25-1.00 per transaction + +### Instant Settlement + +Stablecoin payments on Tempo settle in seconds. No T+2 delays, no batch processing windows, no waiting for bank business hours. + +### Stablecoin-Native Gas Fees + +Unlike other blockchains that require ETH or other volatile tokens for gas, Tempo lets you pay transaction fees in stablecoins. This simplifies treasury management and eliminates gas token volatility. + +### Rich Payment Metadata + +Attach invoice numbers, PO references, customer IDs, and custom fields to every transaction. This metadata flows directly into your accounting and ERP systems. + +## Implementation Steps + +1. **Create a Tempo business wallet** to receive stablecoin payments +2. **Generate unique payment addresses** for each customer or invoice +3. **Set up webhooks** to receive real-time payment notifications +4. **Configure metadata schemas** that match your invoicing workflow +5. **Export transaction data** to your accounting system + +## Enterprise Features + +- **Batch payments**: Process bulk disbursements in a single transaction +- **Multi-signature wallets**: Require multiple approvals for large transactions +- **API access**: Full programmatic control over payment operations + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/ach-alternatives.mdx b/src/pages/guides/ach-alternatives.mdx new file mode 100644 index 00000000..13bef50c --- /dev/null +++ b/src/pages/guides/ach-alternatives.mdx @@ -0,0 +1,261 @@ +--- +title: "ACH Alternatives: Faster Payment Options Compared" +description: "Explore ACH alternatives including Same-Day ACH, wire transfers, RTP, FedNow, and stablecoins. Compare speed, cost, and use cases for each payment method." +--- + +# ACH Alternatives + +ACH (Automated Clearing House) processes over 30 billion transactions annually in the US, making it the backbone of domestic payments. But its 1-2 day settlement times don't work for every use case. This guide compares alternatives when you need faster, cheaper, or more flexible payment options. + +## Comparison Table + +| Alternative | Speed | Cost | Availability | Best For | +|-------------|-------|------|--------------|----------| +| Same-Day ACH | Same business day | $0.50-1.50 | Banking hours | Urgent domestic, same infrastructure | +| Wire Transfers | Same day domestic | $25-50 | Banking hours | Large, time-sensitive payments | +| RTP (Real-Time Payments) | Seconds | $0.01-1.00 | 24/7 | Real-time domestic up to $1M | +| FedNow | Seconds | $0.01-0.50 | 24/7 | Real-time via Federal Reserve | +| Stablecoins (Tempo) | ~0.5 seconds | ~$0.001 | 24/7/365 | Global, programmable, any amount | +| PayPal/Venmo | Instant to balance | 1.75-2.9% | 24/7 | Consumer payments, social payments | +| Zelle | Minutes | Free (bank-subsidized) | 24/7 | Person-to-person, bank customers | + +## When ACH Is the Right Choice + +Before exploring alternatives, recognize what ACH does well: + +- **Recurring payments**: Payroll, subscriptions, rent—predictable timing works perfectly +- **Low cost**: $0.26-0.50 per transaction is hard to beat for domestic volume +- **Universal acceptance**: Every US bank account can receive ACH +- **Established processes**: Accounting systems, ERPs, and compliance frameworks built around ACH + +If your payments are domestic, recurring, and timing-flexible, ACH remains excellent. + +## Same-Day ACH + +### How It Works + +Same-Day ACH uses the existing ACH network with additional processing windows. Payments submitted by cutoff times settle the same business day. + +### Speed & Cost + +- **Settlement**: Same business day (multiple windows: 10:30 AM, 2:45 PM, 4:45 PM ET) +- **Cost**: Standard ACH fee + $0.50-1.00 Same-Day premium +- **Limit**: $1 million per transaction + +### Best For + +- Urgent payroll corrections +- Last-minute vendor payments +- Time-sensitive domestic transfers + +### Limitations + +- Banking hours only (no weekends/holidays) +- Premium fees add up at volume +- Still hours, not minutes + +## Wire Transfers + +### How It Works + +Wires are direct bank-to-bank transfers processed through Fedwire (domestic) or SWIFT (international). Higher priority than ACH batch processing. + +### Speed & Cost + +- **Domestic**: Same day if submitted before cutoff (typically 3-5 PM local) +- **International**: 1-5 business days via correspondent banks +- **Cost**: $25-50 domestic, $40-80 international (plus correspondent fees) + +### Best For + +- Large, time-sensitive payments +- Real estate closings +- M&A transactions +- Situations requiring bank-based audit trails + +### Limitations + +- High fees make wires impractical for regular payments +- Banking hours only +- International transfers still take days + +## RTP (Real-Time Payments) + +### How It Works + +The RTP network, operated by The Clearing House, enables instant payments between participating banks. Launched in 2017 and growing in adoption. + +### Speed & Cost + +- **Settlement**: Seconds, 24/7/365 +- **Cost**: $0.01-1.00 per transaction (varies by bank) +- **Limit**: $1 million per transaction + +### Best For + +- Real-time B2B payments +- Urgent disbursements +- Just-in-time payments +- Payroll for gig workers + +### Limitations + +- Not all banks participate (~65% of US accounts reachable) +- Primarily US domestic +- Bank integration required +- Request for Payment feature adoption still growing + +## FedNow + +### How It Works + +The Federal Reserve's instant payment service launched in 2023. Similar to RTP but operated by the Fed rather than a private consortium. + +### Speed & Cost + +- **Settlement**: Seconds, 24/7/365 +- **Cost**: $0.01-0.50 per transaction (Fed pricing + bank markup) +- **Limit**: $500,000 per transaction (default), configurable + +### Best For + +- Real-time payments through community banks +- Government disbursements +- Credit unions and smaller institutions + +### Limitations + +- Newer system, still building bank adoption +- US domestic only +- Some banks implementing slowly +- Lower default limits than RTP + +## Stablecoins on Tempo + +### How It Works + +Stablecoins like USDC represent dollars on blockchain networks. Tempo is a blockchain purpose-built for payments with instant finality and sub-cent fees. + +### Speed & Cost + +- **Settlement**: ~0.5 seconds to finality +- **Cost**: ~$0.001 per transaction +- **Limit**: No protocol limit + +### Best For + +- Global payments (same system domestic and international) +- Programmable payments (smart contract automation) +- High-frequency, low-value transactions +- 24/7 operations +- Cost-sensitive high-volume payments + +### How Tempo Compares to Other ACH Alternatives + +| Feature | RTP/FedNow | Stablecoins (Tempo) | +|---------|------------|---------------------| +| Speed | Seconds | ~0.5 seconds | +| Geographic reach | US only | Global | +| Cost | $0.01-1.00 | ~$0.001 | +| Bank required | Yes | No (wallet-based) | +| Programmability | Limited | Smart contracts | +| Hours | 24/7 | 24/7 | + +### Limitations + +- Requires crypto wallet (not bank account) +- On/off ramps needed for fiat conversion +- Less familiar to traditional businesses +- Evolving regulatory landscape + +## PayPal and Venmo + +### How It Works + +PayPal and Venmo maintain internal ledgers for instant transfers between users. Funds can be held in balance or transferred to bank accounts. + +### Speed & Cost + +- **Between users**: Instant (within platform) +- **To bank**: 1-3 days free, or instant for 1.75% +- **Receiving payments**: 2.9% + $0.30 for business transactions + +### Best For + +- Consumer payments +- E-commerce checkout +- Social payments (splitting bills) +- Small business point-of-sale + +### Limitations + +- High fees for business transactions +- Account freezes and holds +- Withdrawal delays +- Not ideal for B2B or high-value transfers + +## Zelle + +### How It Works + +Zelle enables instant transfers between bank accounts at participating institutions. Integrated directly into banking apps. + +### Speed & Cost + +- **Settlement**: Minutes (typically instant) +- **Cost**: Free for consumers (bank-subsidized) +- **Limit**: $500-5,000/day depending on bank + +### Best For + +- Person-to-person payments +- Rent payments +- Small business payments from consumers + +### Limitations + +- Low transaction limits +- Consumer-focused (limited business features) +- Must be enrolled through participating bank +- No dispute protection for authorized payments + +## Choosing the Right Alternative + +| Your Need | Best Alternative | +|-----------|-----------------| +| Urgent domestic, keep existing process | Same-Day ACH | +| Large, bank-documented payment | Wire Transfer | +| Real-time domestic B2B | RTP or FedNow | +| Global, any time, any amount | Stablecoins (Tempo) | +| Consumer checkout | PayPal | +| Person-to-person | Zelle | + +## Cost Comparison: 100 Monthly Payments + +| Method | Per-Transaction | Monthly Total | +|--------|-----------------|---------------| +| Standard ACH | $0.40 | $40 | +| Same-Day ACH | $1.00 | $100 | +| Wire Transfer | $35 | $3,500 | +| RTP | $0.50 | $50 | +| FedNow | $0.25 | $25 | +| Tempo | $0.001 | $0.10 | + +## The Future: Multiple Rails + +Most businesses will use multiple payment rails strategically: + +- **ACH**: Recurring domestic payments where timing is flexible +- **RTP/FedNow**: Urgent domestic payments +- **Stablecoins**: International, after-hours, and programmable payments +- **Wires**: Large transactions requiring bank documentation + +The key is matching payment method to use case rather than forcing all payments through one system. + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/add-payments-to-your-app.mdx b/src/pages/guides/add-payments-to-your-app.mdx new file mode 100644 index 00000000..a8a14df8 --- /dev/null +++ b/src/pages/guides/add-payments-to-your-app.mdx @@ -0,0 +1,16 @@ +--- +title: "Add Payments to Your App" +description: "Embed instant payments with Tempo's smart accounts and passkeys. Stablecoin-native gas, ~0.5s finality, and payment metadata make integration seamless for any app." +--- + +# Add Payments to Your App + +Learn how to integrate Tempo's payment infrastructure into your application. + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/ai-agent-payments.mdx b/src/pages/guides/ai-agent-payments.mdx new file mode 100644 index 00000000..e2f86451 --- /dev/null +++ b/src/pages/guides/ai-agent-payments.mdx @@ -0,0 +1,16 @@ +--- +title: "AI Agent Payments" +description: "Enable AI agents to send and receive payments with Tempo's smart accounts and passkeys. ~$0.001 fees and payment metadata support autonomous agent commerce." +--- + +# AI Agent Payments + +Learn how to integrate payment capabilities into AI agents using Tempo. + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/aml-kyc-for-crypto-payments.mdx b/src/pages/guides/aml-kyc-for-crypto-payments.mdx new file mode 100644 index 00000000..b2b5625b --- /dev/null +++ b/src/pages/guides/aml-kyc-for-crypto-payments.mdx @@ -0,0 +1,136 @@ +--- +title: "AML and KYC for Crypto Payments" +description: "Build effective anti-money laundering programs for crypto payments including KYC requirements, transaction monitoring, and SAR filing procedures." +--- + +# AML and KYC for Crypto Payments + +Anti-Money Laundering (AML) and Know Your Customer (KYC) programs form the foundation of compliant crypto payment operations. This guide covers the essential components of an effective compliance program for businesses handling stablecoin and cryptocurrency payments. + +> **Disclaimer:** This content is for informational purposes only and does not constitute legal, financial, or regulatory advice. AML/KYC requirements vary by jurisdiction—work with qualified compliance professionals to design your program. + +## Regulatory Context + +AML/KYC obligations for crypto businesses stem from multiple regulatory frameworks: + +- **Bank Secrecy Act (BSA):** US federal AML requirements administered by FinCEN +- **EU Anti-Money Laundering Directives (AMLD):** European AML framework, now in its 6th iteration +- **FATF Standards:** Global AML/CFT recommendations adopted by 200+ jurisdictions +- **Local Licensing Requirements:** State/national regulators often impose additional AML obligations + +Crypto-specific guidance addresses unique risks including pseudonymous transactions, cross-border transfers, and emerging illicit finance typologies. + +## Key Requirements + +### AML Program Components + +A compliant AML program includes five pillars: + +1. **Written Policies and Procedures:** Documented controls tailored to your risk profile +2. **Designated Compliance Officer:** Qualified individual with authority and resources +3. **Training Program:** Regular training for all relevant personnel +4. **Independent Testing:** Periodic audits by internal audit or external parties +5. **Customer Due Diligence (CDD):** Risk-based procedures for identifying and verifying customers + +### KYC Requirements + +Customer identification and verification typically includes: + +- **Identity Verification:** Collect and verify name, date of birth, address, and government ID +- **Beneficial Ownership:** Identify individuals who own or control 25%+ of legal entity customers +- **Customer Risk Rating:** Assign risk scores based on customer type, geography, activity patterns +- **Enhanced Due Diligence (EDD):** Apply heightened scrutiny for higher-risk customers +- **Ongoing Monitoring:** Periodically refresh customer information and risk assessments + +### Sanctions Compliance + +Screen customers and transactions against: + +- OFAC Specially Designated Nationals (SDN) List +- EU Consolidated Sanctions List +- UN Security Council Sanctions +- Jurisdiction-specific sanctions programs +- Sanctioned wallet addresses and blockchain clusters + +## Implementation Guidance + +### Building Your KYC Process + +1. **Define Customer Tiers:** Establish verification levels based on transaction limits and risk +2. **Select Verification Methods:** Choose appropriate identity verification tools (document verification, biometrics, database checks) +3. **Implement Onboarding Workflows:** Build user flows that collect required information with minimal friction +4. **Configure Risk Scoring:** Develop algorithms incorporating geography, occupation, transaction patterns, and other factors +5. **Establish Review Procedures:** Create workflows for manual review of high-risk customers or verification failures + +### Transaction Monitoring + +Effective monitoring systems should: + +- **Detect Suspicious Patterns:** Identify structuring, rapid movement, unusual transaction sizes +- **Flag High-Risk Counterparties:** Alert on transactions involving high-risk wallets or jurisdictions +- **Incorporate Blockchain Analytics:** Use tools like Chainalysis or Elliptic for on-chain risk assessment +- **Generate Actionable Alerts:** Minimize false positives while capturing genuine risks +- **Support Investigation:** Provide context and visualization tools for alert review + +#### Common Red Flags for Crypto Payments + +| Red Flag | Description | +|----------|-------------| +| Structuring | Breaking transactions to avoid thresholds | +| Mixing/Tumbling | Use of services designed to obscure transaction history | +| Darknet Exposure | Connections to known darknet marketplace wallets | +| Sanctions Nexus | Direct or indirect exposure to sanctioned addresses | +| Rapid Layering | Quick movement through multiple wallets before off-ramping | +| Inconsistent Activity | Transactions inconsistent with stated purpose or customer profile | + +### SAR Filing Procedures + +When suspicious activity is detected: + +1. **Investigate:** Review transaction details, customer history, and blockchain analytics +2. **Document:** Record investigation findings and decision rationale +3. **Escalate:** Route to BSA Officer or compliance committee for filing decision +4. **File Timely:** Submit SARs within 30 days of detection (US requirement) +5. **Maintain Confidentiality:** Do not disclose SAR filings to customers +6. **Retain Records:** Keep SAR documentation for 5+ years + +## Best Practices + +- **Risk-Based Approach:** Allocate resources proportionate to actual risk exposure +- **Technology Investment:** Leverage automation for screening, monitoring, and case management +- **Vendor Due Diligence:** Thoroughly evaluate compliance technology providers +- **Typology Awareness:** Stay current on emerging crypto money laundering techniques +- **Regulatory Engagement:** Participate in industry forums and respond to regulatory consultations +- **Culture of Compliance:** Foster organization-wide understanding of AML importance +- **Continuous Improvement:** Regularly assess program effectiveness and address gaps + +### Recommended Tools and Partners + +| Category | Providers | +|----------|-----------| +| Blockchain Analytics | Chainalysis, Elliptic, TRM Labs, Merkle Science | +| Identity Verification | Jumio, Onfido, Veriff, Persona | +| Sanctions Screening | ComplyAdvantage, Dow Jones, LexisNexis | +| Case Management | Hummingbird, Alessa, Unit21 | +| Travel Rule | Notabene, Sygna, TRUST | + +## Resources and Further Reading + +- [FinCEN BSA Resources](https://www.fincen.gov/) - US AML guidance and SAR filing +- [FATF Guidance on Virtual Assets](https://www.fatf-gafi.org/) - Global standards +- [Chainalysis Crypto Crime Report](https://www.chainalysis.com/) - Annual illicit finance trends +- [Elliptic Typologies](https://www.elliptic.co/) - Money laundering pattern analysis +- [ACAMS Resources](https://www.acams.org/) - Professional development and guidance +- [Tempo Compliance APIs](https://docs.tempo.xyz) - Integration documentation + +--- + +*Last updated: 2024. AML/KYC requirements evolve as regulators address emerging risks—maintain an active regulatory monitoring program.* + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/autonomous-agent-wallets.mdx b/src/pages/guides/autonomous-agent-wallets.mdx new file mode 100644 index 00000000..cb1caf53 --- /dev/null +++ b/src/pages/guides/autonomous-agent-wallets.mdx @@ -0,0 +1,181 @@ +--- +title: "Autonomous Agent Wallets" +description: "Build self-sovereign wallets for AI agents with Tempo smart accounts. Programmable spending limits, passkey security, and sub-cent transaction fees." +--- + +# Autonomous Agent Wallets + +AI agents need financial autonomy to operate effectively. Tempo smart accounts provide the infrastructure for agents to hold, send, and receive payments independently. + +## The Agent Wallet Challenge + +Traditional payment infrastructure wasn't built for autonomous software: + +| Requirement | Traditional Systems | Tempo Smart Accounts | +|-------------|---------------------|----------------------| +| Programmatic access | API keys with full access | Granular permissions | +| Spending controls | Limited | Programmable limits | +| Transaction costs | High minimums | ~$0.001 per transaction | +| Setup | Manual KYC process | Instant creation | + +## Tempo Smart Accounts for Agents + +### Self-Sovereign Design + +Each agent controls its own wallet with cryptographic keys: + +- **Independent operation** — Agents transact without human intervention +- **Verifiable identity** — On-chain address serves as agent identity +- **Portable balance** — Funds move with the agent across platforms + +### Programmable Constraints + +Configure guardrails for agent spending: + +```typescript +import { Tempo } from '@tempo/sdk'; + +const tempo = new Tempo({ apiKey: 'your-api-key' }); + +// Create agent wallet with spending limits +const agentWallet = await tempo.accounts.create({ + type: 'smart-account', + constraints: { + maxTransactionAmount: '100.00', + dailySpendLimit: '500.00', + allowedRecipients: ['0x...service1', '0x...service2'], + requireMetadata: ['purpose', 'taskId'] + } +}); +``` + +### Passkey Security + +Secure agent wallets with hardware-backed authentication: + +- No private keys to manage or leak +- Revocable access +- Audit trail of all operations + +## Agent Wallet Patterns + +### Funded Task Execution + +1. System deposits funds for specific task +2. Agent spends within allocated budget +3. Unused funds return to treasury + +```typescript +// Fund agent for specific task +await tempo.payments.create({ + recipient: agentWallet.address, + amount: '50.00', + currency: 'USDC', + metadata: { + taskId: 'task-789', + purpose: 'research-budget' + } +}); + +// Agent executes payments for task +await agentWallet.pay({ + recipient: dataProvider.address, + amount: '5.00', + currency: 'USDC', + metadata: { + taskId: 'task-789', + service: 'data-query' + } +}); +``` + +### Revenue Collection + +Agents can receive payments for services rendered: + +```typescript +// Agent publishes payment address +const paymentAddress = agentWallet.address; + +// Webhook notifies agent of incoming payment +agentWallet.on('payment.received', async (event) => { + const { amount, metadata } = event; + await executeServiceFor(metadata.requestId); +}); +``` + +### Multi-Agent Coordination + +Agents can transact with each other: + +```typescript +// Agent A pays Agent B for sub-task +await agentA.wallet.pay({ + recipient: agentB.wallet.address, + amount: '10.00', + currency: 'USDC', + metadata: { + taskId: 'task-789', + subTask: 'data-processing' + } +}); +``` + +## Security Model + +### Hierarchical Control + +``` +Organization Treasury + └── Agent Pool Budget + └── Individual Agent Wallets + └── Per-Task Allocations +``` + +### Constraint Enforcement + +- **Transaction limits** — Cap individual payment amounts +- **Daily/weekly budgets** — Limit cumulative spending +- **Allowlists** — Restrict recipient addresses +- **Metadata requirements** — Enforce payment documentation + +### Emergency Controls + +- Pause agent wallet instantly +- Revoke spending permissions +- Recover remaining funds + +## Observability + +### Transaction Monitoring + +Track all agent financial activity: + +```typescript +const transactions = await tempo.transactions.list({ + account: agentWallet.address, + startDate: '2024-01-01', + endDate: '2024-01-31' +}); + +// Analyze spending patterns +const byPurpose = groupBy(transactions, t => t.metadata.purpose); +``` + +### Webhook Events + +Real-time notifications for: + +- Incoming payments +- Outgoing payments +- Spending limit warnings +- Constraint violations + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/b2b-crypto-payments.mdx b/src/pages/guides/b2b-crypto-payments.mdx new file mode 100644 index 00000000..955ca4e0 --- /dev/null +++ b/src/pages/guides/b2b-crypto-payments.mdx @@ -0,0 +1,93 @@ +--- +title: "B2B Crypto Payments" +description: "Streamline B2B payments with stablecoins on Tempo. ~$0.001 transaction fees, instant settlement, and rich metadata for enterprise accounting." +--- + +# B2B Crypto Payments + +B2B payments are stuck in the past. Wire transfers, ACH batches, and paper checks dominate despite their costs and delays. Stablecoin payments on Tempo offer a modern alternative purpose-built for business transactions. + +## The B2B Payment Problem + +| Payment Method | Cost | Settlement Time | Reconciliation | +|---------------|------|-----------------|----------------| +| Wire transfer | $25-50 | 1-5 days | Manual | +| ACH | $0.25-1.00 | 2-3 days | Manual | +| Check | $4-20 | 5-10+ days | Manual | +| Credit card | 2.5-3.5% | 1-2 days | Semi-automated | +| **Tempo** | **~$0.001** | **Instant** | **Automated** | + +## Why Stablecoins for B2B? + +### Cost Efficiency + +A $100,000 B2B payment via wire costs $25-50 in fees. Via Tempo, it costs approximately $0.001. The savings compound across hundreds of monthly payments. + +### Speed + +Instant settlement means better cash flow management. No more timing payments around bank processing windows or waiting for funds to clear. + +### Global Simplicity + +Pay international suppliers as easily as domestic ones. No correspondent banks, no SWIFT delays, no currency conversion markups. + +### Structured Data + +Every payment carries metadata—PO numbers, invoice references, contract IDs—that flows directly into your ERP. + +## Tempo's B2B Features + +### Batch Payments + +Process vendor payments in bulk. Upload a file with payment details or integrate via API. All payments execute in a single transaction. + +### Payment Metadata + +Attach business context to every transaction: + +- Vendor ID +- Invoice number +- PO reference +- GL coding +- Contract reference +- Custom fields + +### Stablecoin-Native Gas + +Pay transaction fees in stablecoins. No need to manage ETH or other volatile assets for gas. + +### Multi-Signature Approval + +Configure approval thresholds for large payments. Require multiple signers for transactions above certain amounts. + +## Implementation + +### Accounts Payable + +1. Collect vendor wallet addresses during onboarding +2. Create payment batches from your AP system +3. Execute batch payments with full metadata +4. Export transaction records for your ledger + +### Accounts Receivable + +1. Provide customers with your payment address +2. Specify required metadata fields (invoice number, customer ID) +3. Receive instant payment notifications via webhook +4. Auto-match payments to open invoices + +## Security and Compliance + +- Complete audit trail for all transactions +- Immutable payment records +- Multi-sig support for payment authorization +- Metadata for regulatory and tax compliance + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/best-chain-for-stablecoins.mdx b/src/pages/guides/best-chain-for-stablecoins.mdx new file mode 100644 index 00000000..d4398574 --- /dev/null +++ b/src/pages/guides/best-chain-for-stablecoins.mdx @@ -0,0 +1,93 @@ +--- +title: Best Blockchain for Stablecoins - Why Tempo Leads +description: Compare blockchains for stablecoin use. Tempo offers stablecoin-native gas, sub-cent fees, instant settlement, and payment metadata. +--- + +# Best Blockchain for Stablecoins + +Not all blockchains are created equal for stablecoin use. While Ethereum, Solana, and Tron each have tradeoffs, Tempo is purpose-built for stablecoin payments and holdings. + +## Common Blockchain Limitations + +### Ethereum +- High gas fees during congestion (often $5-50+ per transaction) +- Requires holding ETH for every transaction +- Slower finality (minutes for confidence) + +### Solana +- Lower fees but still requires SOL for gas +- Network outages have disrupted access +- Not optimized specifically for payments + +### Tron +- Popular for USDT but centralization concerns +- Still requires TRX for fees +- Limited developer ecosystem + +## Why Tempo is Different + +[Tempo](https://docs.tempo.xyz/learn/tempo) was designed from the ground up for stablecoin use cases: + +### Stablecoin-Native Gas + +This is Tempo's key differentiator. Pay transaction fees directly in stablecoins. No need to: + +- Hold volatile tokens like ETH or SOL +- Manage multiple token balances +- Worry about gas token price swings + +Your portfolio stays 100% in stable value. + +### Sub-Cent Transaction Fees + +Tempo's fees are fractions of a cent, making these use cases practical: + +- Micropayments for content or APIs +- Frequent small transfers +- High-volume payment processing +- Cost-effective treasury operations + +### Instant Settlement + +Transactions finalize in seconds with deterministic confirmation. Critical for: + +- Point-of-sale payments +- Real-time payouts +- Trading and arbitrage +- Time-sensitive business operations + +### Payment Metadata + +Attach structured data to every transaction: + +- Invoice references +- Order IDs +- Memo fields +- Custom metadata for reconciliation + +This eliminates the need for separate payment tracking systems. + +## Comparison Table + +| Feature | Ethereum | Solana | Tron | Tempo | +|---------|----------|--------|------|-------| +| Gas token | ETH | SOL | TRX | Stablecoins | +| Typical fee | $5-50 | $0.001-0.01 | $0.10-1 | <$0.01 | +| Settlement | Minutes | Seconds | Seconds | Seconds | +| Payment metadata | No | No | No | Yes | +| Stablecoin-first design | No | No | No | Yes | + +## Get Started with Tempo + +- [Tempo overview](https://docs.tempo.xyz/learn/tempo) +- [Connect to Tempo](https://docs.tempo.xyz/quickstart) +- [How stablecoins work](https://docs.tempo.xyz/learn/stablecoins) +- [Developer guide](https://docs.tempo.xyz/guide) + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/best-stablecoin-exchange.mdx b/src/pages/guides/best-stablecoin-exchange.mdx new file mode 100644 index 00000000..f5ea79d8 --- /dev/null +++ b/src/pages/guides/best-stablecoin-exchange.mdx @@ -0,0 +1,60 @@ +--- +title: Best Stablecoin Exchange +description: Compare stablecoin exchange options. Tempo's built-in DEX offers ~$0.001 fees, ~0.5s settlement, and stablecoin gas payments. +--- + +# Best Stablecoin Exchange: Comparing Your Options + +When converting between stablecoins, your choice of exchange directly impacts costs, speed, and user experience. Here's how Tempo's built-in DEX compares to alternatives. + +## Comparison Overview + +| Feature | Tempo DEX | CEX | Ethereum DEX | L2 DEX | +|---------|-----------|-----|--------------|--------| +| Transaction Fee | ~$0.001 | $0–$5+ | $5–$50+ | $0.10–$1 | +| Settlement Time | ~0.5s | Minutes–Hours | 12+ seconds | 2–10 seconds | +| Gas Token | Stablecoins | N/A | ETH required | ETH required | +| Custody | Self-custody | Custodial | Self-custody | Self-custody | +| KYC Required | No | Yes | No | No | + +## Why Tempo's DEX Stands Out + +### Near-Zero Fees (~$0.001) + +Tempo's payment-optimized architecture keeps transaction costs at fractions of a cent, making small and frequent swaps economically viable. + +### Sub-Second Settlement (~0.5s) + +Transactions finalize in under a second, enabling real-time payment workflows without waiting for block confirmations. + +### Stablecoin-Native Gas + +Pay transaction fees in stablecoins directly. No need to acquire, hold, or manage ETH for gas—simplifying treasury operations and user onboarding. + +### Built-In Liquidity + +Tempo's DEX is native to the protocol, eliminating bridge risks and third-party dependencies. + +## How to Use Tempo's DEX + +1. **Connect** your wallet to Tempo ([Connection Details](https://docs.tempo.xyz/quickstart/connection-details)) +2. **Select** your stablecoin pair (USDC, USDT, DAI, EURC, and more) +3. **Enter** your swap amount +4. **Confirm** and receive tokens in ~0.5 seconds + +## Supported Stablecoins + +Tempo supports major stablecoins including: +- USDC (USD Coin) +- USDT (Tether) +- DAI (MakerDAO) +- EURC (Euro Coin) + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/blockchain-for-banks.mdx b/src/pages/guides/blockchain-for-banks.mdx new file mode 100644 index 00000000..5dc26cd5 --- /dev/null +++ b/src/pages/guides/blockchain-for-banks.mdx @@ -0,0 +1,16 @@ +--- +title: "Blockchain for Banks" +description: "Modernize banking infrastructure with Tempo's payment-first blockchain. Dedicated payment lanes, ~0.5s finality, and payment metadata enable tokenized deposits." +--- + +# Blockchain for Banks + +Learn how banks can leverage Tempo for tokenized deposits and modern payment rails. + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/bridging-stablecoins-to-tempo.mdx b/src/pages/guides/bridging-stablecoins-to-tempo.mdx new file mode 100644 index 00000000..a29bf05b --- /dev/null +++ b/src/pages/guides/bridging-stablecoins-to-tempo.mdx @@ -0,0 +1,56 @@ +--- +title: "Bridging Stablecoins to Tempo" +description: "Learn about bridging stablecoins to Tempo. Information on native stablecoins available now and upcoming bridge support for external stablecoins." +--- + +# Bridging Stablecoins to Tempo + +This guide covers how to get stablecoins on Tempo, including native options available now and upcoming bridge infrastructure. + +## Native Stablecoins on Tempo + +Tempo currently offers native stablecoins that are available directly on the network: + +- **pathUSD** — USD-denominated stablecoin +- **AlphaUSD** — USD-denominated stablecoin +- **BetaUSD** — USD-denominated stablecoin +- **ThetaUSD** — USD-denominated stablecoin + +These stablecoins can be used immediately for payments with Tempo's sub-cent fees and instant finality. + +## Bridge Infrastructure + +Bridging infrastructure is being developed. Bridge support for external stablecoins like USDC and USDT may come later as the network matures. + +### What to Expect + +When bridge support launches: + +- Transfer stablecoins from Ethereum and other chains to Tempo +- Access Tempo's fast, low-cost payment rails with your existing holdings +- Bridge times will vary by source chain + +## Getting Started Today + +While bridge infrastructure is in development, you can: + +1. **Use native stablecoins** — pathUSD, AlphaUSD, BetaUSD, and ThetaUSD are available now +2. **Test on testnet** — Get familiar with Tempo's features using testnet funds +3. **Build integrations** — Prepare your applications for stablecoin payments + +## Security Best Practices + +When bridges become available: + +- Always verify bridge URLs through official sources +- Start with small test transactions +- Bookmark official interfaces to avoid phishing sites + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/cheapest-way-to-swap-stablecoins.mdx b/src/pages/guides/cheapest-way-to-swap-stablecoins.mdx new file mode 100644 index 00000000..bee5abf8 --- /dev/null +++ b/src/pages/guides/cheapest-way-to-swap-stablecoins.mdx @@ -0,0 +1,52 @@ +--- +title: Cheapest Way to Swap Stablecoins +description: Swap stablecoins for less than $0.001 on Tempo's native stablecoin DEX. Instant settlement, no gas token needed. +--- + +# Cheapest Way to Swap Stablecoins + +Swap between stablecoins for less than a tenth of a cent on Tempo's native stablecoin DEX. + +## Why Stablecoin Swaps Are Usually Expensive + +On most blockchains, swapping stablecoins means: +- High gas fees ($1-50+ on Ethereum mainnet) +- DEX trading fees (0.01-0.3%) +- Slippage on large orders +- MEV extraction by bots + +Tempo eliminates these costs with a purpose-built stablecoin exchange. + +## Tempo's Stablecoin DEX + +Tempo includes a native decentralized exchange optimized specifically for stablecoin trading: + +- **Sub-cent transaction fees**: Fixed, predictable cost regardless of swap size +- **Stablecoin gas**: Pay fees in stablecoins—no need for a separate gas token +- **Consolidated liquidity**: All stablecoin liquidity in one protocol-level pool +- **No MEV**: Dedicated payment lanes prevent sandwich attacks + +## How to Swap + +1. Connect your wallet to Tempo +2. Select your source stablecoin +3. Select your destination stablecoin +4. Enter your amount +5. Confirm the swap—settled in ~0.5 seconds + +## Available Stablecoins + +Tempo currently supports native USD stablecoins for swapping: + +- USDC (Circle) +- USDT (Tether) + +Additional stablecoins including EURC, DAI, and PYUSD are coming soon. + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/circle-mint-vs-tempo.mdx b/src/pages/guides/circle-mint-vs-tempo.mdx new file mode 100644 index 00000000..b480118b --- /dev/null +++ b/src/pages/guides/circle-mint-vs-tempo.mdx @@ -0,0 +1,153 @@ +--- +title: "Circle Mint vs Tempo" +description: "Compare Circle's USDC infrastructure with Tempo's stablecoin-native blockchain. Understand when to use each for payments and treasury." +--- + +# Circle Mint vs Tempo + +Circle Mint is Circle's institutional platform for minting and redeeming USDC. Tempo is a blockchain designed for stablecoin payments. They serve different purposes but can work together. This guide explains when to use each. + +## What They Are + +### Circle Mint + +Circle Mint is an institutional service for: +- Converting USD to USDC (minting) +- Converting USDC to USD (redeeming) +- Moving USDC between supported blockchains +- Cross-Chain Transfer Protocol (CCTP) access + +It's infrastructure for getting in and out of USDC, not a blockchain. + +### Tempo + +Tempo is a blockchain for: +- Sending and receiving stablecoins +- Swapping between stablecoins +- Paying transaction fees in stablecoins +- Processing payments with metadata + +It's infrastructure for using stablecoins once you have them. + +## Comparison Table + +| Feature | Circle Mint | Tempo | +|---------|-------------|-------| +| Primary function | USDC mint/redeem | Stablecoin payments | +| Transaction fees | Bank wire fees | ~$0.001 | +| Settlement time | 1-2 business days | ~0.5 seconds | +| Minimum amounts | Typically $100K+ | None | +| KYC required | Yes (institutional) | No | +| Supported stablecoins | USDC only | pathUSD, AlphaUSD, BetaUSD, ThetaUSD | +| Cross-chain transfer | Yes (CCTP) | Bridge support | +| Native DEX | No | Yes | +| Payment metadata | No | Yes | + +## Circle Mint Strengths + +### Direct USD Access + +Circle Mint provides institutional access to mint USDC directly from USD and redeem back to USD. This is the primary on/off ramp for large USDC operations. + +### Cross-Chain Transfer Protocol + +Move USDC natively between supported chains (Ethereum, Solana, Base, Arbitrum, etc.) through CCTP. USDC is burned on one chain and minted on another—no bridged tokens. + +### Institutional Grade + +Full compliance, KYC/AML, and audit trails for regulated entities. Built for banks, fintechs, and large enterprises. + +### Circle Account Services + +Additional services like yield, custody, and API access for programmatic treasury operations. + +## Tempo Strengths + +### Stablecoin-Native Payments + +Purpose-built for moving stablecoins between parties. Transaction fees are ~$0.001 paid in stablecoins—no volatile gas tokens. + +### Instant Settlement + +Transactions finalize in ~0.5 seconds versus 1-2 business days for Circle Mint redemptions. Critical for payment operations. + +### Multi-Stablecoin Support + +Use native USD stablecoins like pathUSD, AlphaUSD, BetaUSD, and ThetaUSD. Swap between them natively. Note: USDC is not currently available on Tempo—Circle Mint only handles USDC on chains where Circle has deployed it. + +### No Minimums or KYC for Payments + +Any amount, any user. Circle Mint targets institutional clients with significant minimums. + +### Payment Metadata + +Attach invoice references, order IDs, and custom data for reconciliation. + +## How They Work Together + +Circle Mint and Tempo serve complementary roles in the broader stablecoin ecosystem: + +1. **Mint USDC via Circle**: Convert USD to USDC using Circle Mint on supported chains +2. **Bridge to Tempo**: Convert USDC to Tempo's native stablecoins via bridges +3. **Process payments on Tempo**: Send, receive, swap with sub-cent fees and instant finality +4. **Collect and consolidate**: Aggregate payments on Tempo +5. **Bridge back and redeem**: Move funds to supported chain, redeem via Circle Mint + +Note: USDC is not currently available on Tempo. This workflow requires bridging between ecosystems. + +## Use Cases: When to Use Each + +### Use Circle Mint When + +- Converting between USD and USDC +- Moving USDC between chains via CCTP +- Institutional treasury operations requiring compliance +- Large redemptions to traditional banking + +### Use Tempo When + +- Processing stablecoin payments +- High-volume, low-value transfers +- Multi-stablecoin operations (pathUSD, AlphaUSD, BetaUSD, ThetaUSD) +- Real-time settlement requirements +- Payment reconciliation with metadata + +## Example: Business Payment Flow + +**Without Tempo:** +1. Receive USDC on Ethereum ($5-50 gas) +2. Accumulate payments +3. Move to Circle Mint chain if needed +4. Redeem to USD (1-2 days) + +**With Tempo:** +1. Receive stablecoins on Tempo ($0.001 fee, instant) +2. Swap to preferred stablecoin if needed ($0.001) +3. Process hundreds of payments at ~$0.001 each +4. Bridge to Ethereum when ready to redeem +5. Redeem via Circle Mint (1-2 days) + +Savings: Significant on payment processing; redemption timeline unchanged. + +## When to Choose Tempo + +Tempo is the right choice for the payment layer: + +- **Day-to-day stablecoin operations**: Tempo's sub-cent fees and instant finality +- **Multi-stablecoin flexibility**: Swap between pathUSD, AlphaUSD, and other native stablecoins as needed +- **High-volume processing**: Pay $0.001 per transaction, not $5-50 + +Circle Mint remains essential for: + +- **USD on/off ramp**: Getting money into and out of stablecoins +- **Institutional compliance**: Regulated minting and redemption +- **Cross-chain USDC**: Native CCTP transfers between major chains + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/content-monetization-crypto.mdx b/src/pages/guides/content-monetization-crypto.mdx new file mode 100644 index 00000000..4371bfb8 --- /dev/null +++ b/src/pages/guides/content-monetization-crypto.mdx @@ -0,0 +1,211 @@ +--- +title: "Content Monetization with Crypto" +description: "Monetize articles, videos, and digital content with stablecoin micropayments. Tempo's ~$0.001 fees enable true pay-per-view content access." +--- + +# Content Monetization with Crypto + +Unlock new revenue models for digital content with micropayments. Tempo's sub-cent transaction fees make pay-per-article, pay-per-video, and pay-per-access economically viable. + +## The Content Monetization Problem + +Current models force tradeoffs: + +| Model | Problem | +|-------|---------| +| Advertising | Degrades user experience, privacy concerns | +| Subscriptions | Users pay for content they don't consume | +| Paywalls | High friction kills conversion | +| Donations | Unpredictable, guilt-based revenue | + +### Why Micropayments Failed Before + +Traditional payment systems charge minimums that exceed content value: + +- Credit card: $0.30 + 2.9% makes $0.10 articles impossible +- PayPal: Similar fee structure +- In-app purchases: 30% platform fee + +## Tempo for Content Payments + +### True Micropayments + +Charge what content is actually worth: + +| Content Type | Price | Tempo Fee | You Keep | +|--------------|-------|-----------|----------| +| Blog article | $0.05 | ~$0.001 | $0.049 | +| Premium video | $0.25 | ~$0.001 | $0.249 | +| Research report | $2.00 | ~$0.001 | $1.999 | +| Music track | $0.10 | ~$0.001 | $0.099 | + +### Instant Access + +Payment confirms in ~0.5 seconds. Users click, pay, and access content immediately—no checkout friction. + +### No Middlemen + +Direct creator-to-consumer payments. No platform taking 30%. + +## Implementation + +### Pay-Per-Article + +```typescript +import { Tempo } from '@tempo/sdk'; + +const tempo = new Tempo({ apiKey: 'your-api-key' }); + +// Check access before serving content +app.get('/article/:id', async (req, res) => { + const article = await getArticle(req.params.id); + const paymentId = req.query.paymentId; + + if (paymentId) { + const payment = await tempo.payments.get(paymentId); + + if (payment.status === 'confirmed' && + payment.metadata.articleId === article.id) { + return res.json({ content: article.fullContent }); + } + } + + // Return preview with payment request + return res.json({ + preview: article.preview, + price: article.price, + paymentAddress: creatorWallet, + requiredMetadata: { articleId: article.id } + }); +}); +``` + +### Pay-Per-Video + +```typescript +// Generate time-limited access token after payment +app.post('/video/:id/access', async (req, res) => { + const { paymentId } = req.body; + const video = await getVideo(req.params.id); + + const payment = await tempo.payments.get(paymentId); + + if (payment.status !== 'confirmed') { + return res.status(402).json({ error: 'Payment required' }); + } + + if (payment.amount < video.price) { + return res.status(402).json({ error: 'Insufficient payment' }); + } + + // Generate signed URL valid for 24 hours + const accessUrl = await generateSignedUrl(video.id, 86400); + + return res.json({ accessUrl }); +}); +``` + +### Streaming Payments for Long-Form Content + +Charge as users consume: + +```typescript +// Charge per chapter/segment +async function unlockNextChapter(userId, bookId, chapterNum) { + const chapter = await getChapter(bookId, chapterNum); + + await tempo.payments.charge({ + from: userWallets[userId], + amount: chapter.price, + currency: 'USDC', + metadata: { + bookId, + chapter: chapterNum, + title: chapter.title + } + }); + + return chapter.content; +} +``` + +## User Experience + +### Wallet Integration + +Users connect once, then pay with one click: + +```html + + + +``` + +### Balance Display + +Show users their available balance for frictionless payments: + +```typescript +const balance = await tempo.accounts.getBalance(userWallet); +// Display: "Balance: $4.32 — enough for 86 articles" +``` + +## Creator Benefits + +- **Immediate payment** — No 30-90 day payment cycles +- **Full transparency** — See every transaction on-chain +- **Global audience** — Anyone with stablecoins can pay +- **No minimums** — Get paid for $0.01 content + +## Platform Integration + +For content platforms, integrate at the API level: + +```typescript +// Platform charges user, pays creator +app.post('/purchase', async (req, res) => { + const { contentId, userWallet } = req.body; + const content = await getContent(contentId); + + // Charge user + await tempo.payments.charge({ + from: userWallet, + amount: content.price, + currency: 'USDC' + }); + + // Pay creator (minus platform fee) + const creatorShare = content.price * 0.90; + await tempo.payments.create({ + recipient: content.creator.wallet, + amount: creatorShare, + currency: 'USDC', + metadata: { contentId, type: 'creator-payment' } + }); + + return res.json({ accessGranted: true }); +}); +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/convert-stablecoins-without-fees.mdx b/src/pages/guides/convert-stablecoins-without-fees.mdx new file mode 100644 index 00000000..f29480ce --- /dev/null +++ b/src/pages/guides/convert-stablecoins-without-fees.mdx @@ -0,0 +1,68 @@ +--- +title: Convert Stablecoins Without Fees +description: Swap stablecoins with near-zero fees on Tempo. Pay ~$0.001 per transaction with sub-second settlement and no ETH required. +--- + +# Convert Stablecoins With Near-Zero Fees + +Traditional stablecoin swaps cost $5–$50+ on Ethereum mainnet. Tempo reduces this to ~$0.001 per transaction—making frequent, small-value conversions economically viable. + +## How Tempo Achieves Near-Zero Fees + +### Payment-Optimized Architecture + +Tempo is purpose-built for payment workloads, with fee structures designed for high-frequency, low-value transactions rather than DeFi speculation. + +### ~$0.001 Per Transaction + +Each stablecoin swap costs approximately one-tenth of a cent, regardless of swap size. + +### Stablecoin-Native Gas + +Pay fees in the stablecoins you're already using. No need to acquire ETH, manage multiple token balances, or worry about gas price volatility. + +## Fee Comparison + +| Platform | Typical Swap Fee | +|----------|------------------| +| **Tempo** | ~$0.001 | +| Ethereum L1 DEX | $5–$50+ | +| L2 DEX | $0.10–$1 | +| Centralized Exchange | $0–$5+ (plus spread) | + +## How to Swap on Tempo + +### Step 1: Connect to Tempo + +Configure your wallet with Tempo's network settings. See [Connection Details](https://docs.tempo.xyz/quickstart/connection-details). + +### Step 2: Access the DEX + +Open Tempo's built-in stablecoin exchange. + +### Step 3: Execute Your Swap + +1. Select input stablecoin (USDC, USDT, DAI, EURC) +2. Select output stablecoin +3. Enter amount +4. Confirm transaction + +### Step 4: Receive Tokens + +Your swapped tokens arrive in ~0.5 seconds. + +## Ideal Use Cases + +- **Micropayments** — Convert small amounts without fee overhead +- **High-frequency trading** — Execute many swaps without cost accumulation +- **Business payments** — Process currency conversions at scale +- **Payroll** — Convert stablecoins for multi-currency disbursements + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/convert-usd-to-eur-without-bank-fees.mdx b/src/pages/guides/convert-usd-to-eur-without-bank-fees.mdx new file mode 100644 index 00000000..b7b44161 --- /dev/null +++ b/src/pages/guides/convert-usd-to-eur-without-bank-fees.mdx @@ -0,0 +1,46 @@ +--- +title: Convert USD to EUR Without Bank Fees +description: Swap USD to EUR stablecoins instantly on Tempo's built-in DEX. No forex spreads, no hidden fees, sub-cent costs. +--- + +# Convert USD to EUR Without Bank Fees + +Swap between USD and EUR stablecoins instantly on Tempo's built-in DEX—no forex spreads, no hidden fees, no bank intermediaries. + +## The Problem with Traditional FX + +Banks and forex services charge 1-3% on currency conversions, plus hidden spreads. A $10,000 transfer can cost $100-300 in fees alone. Tempo eliminates this with direct stablecoin-to-stablecoin swaps. + +## How Tempo's Stablecoin DEX Works + +Tempo includes a native decentralized exchange optimized specifically for stablecoins. Swap USDC to EURC (or any supported stablecoin pair) with: + +- **Minimal slippage**: Liquidity consolidated into a single onchain system +- **Sub-cent fees**: Pay ~$0.001 per swap regardless of size +- **No intermediaries**: Direct peer-to-pool swaps, no counterparty risk +- **Instant settlement**: Swaps finalize in ~0.5 seconds + +## Supported Currency Pairs + +- USD stablecoins: USDC, USDT, DAI, PYUSD +- EUR stablecoins: EURC +- Additional currencies coming soon + +## Steps to Convert + +1. Connect your wallet to Tempo +2. Navigate to the stablecoin DEX +3. Select your source currency (e.g., USDC) and target (e.g., EURC) +4. Enter amount and confirm—done in seconds + +--- + +[Start swapping on Tempo](https://docs.tempo.xyz) | [Learn about the stablecoin DEX](https://docs.tempo.xyz/learn) + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/correspondent-banking-alternatives.mdx b/src/pages/guides/correspondent-banking-alternatives.mdx new file mode 100644 index 00000000..ee545f62 --- /dev/null +++ b/src/pages/guides/correspondent-banking-alternatives.mdx @@ -0,0 +1,289 @@ +--- +title: "Correspondent Banking Alternatives: Modern Payment Infrastructure" +description: "Explore correspondent banking alternatives including direct connections, fintech rails, stablecoins, and CBDCs. Understand how payments can bypass intermediary banks." +--- + +# Correspondent Banking Alternatives + +Correspondent banking is the infrastructure behind international payments, but it's also the source of delays, fees, and complexity. This guide explains how correspondent banking works and explores emerging alternatives. + +## What Is Correspondent Banking? + +Correspondent banking enables banks to make payments in countries where they don't have a physical presence. + +### How It Works + +1. **Your bank** doesn't have an account in the destination country +2. **Correspondent banks** act as intermediaries, holding accounts on behalf of other banks +3. **Nostro/Vostro accounts**: Your bank's account at a correspondent is a "nostro" (ours) account; from the correspondent's view, it's a "vostro" (yours) account +4. **Chain of correspondents**: A payment may pass through multiple intermediaries + +### Example: US to Thailand Transfer + +``` +US Bank → US Correspondent Bank → Asian Regional Bank → Thai Bank +``` + +Each hop: +- Takes time (hours to days) +- May deduct fees +- Requires the payment to be processed during business hours +- Adds compliance checks + +## Correspondent Banking Pain Points + +### Fees Accumulate at Each Hop + +| Hop | Typical Fee | +|-----|-------------| +| Sender bank wire fee | $45 | +| First correspondent | $15 | +| Second correspondent | $15 | +| Receiver bank fee | $10 | +| **Total** | **$85+** | + +*Plus 1-4% FX markup* + +### Settlement Takes Days + +- Each correspondent processes during their banking hours +- Time zone differences add delays +- Compliance checks at each institution +- Average: 2-3 days, can be 5+ days for some corridors + +### Limited Operating Hours + +- Banks process during business hours only +- Friday payments may not settle until Tuesday +- Holiday schedules vary by country + +### Compliance Complexity + +- Each correspondent runs its own KYC/AML checks +- Payments can be held or rejected at any hop +- Limited visibility into where delays occur + +### De-risking and Shrinking Networks + +Banks are closing correspondent relationships due to compliance costs, leaving some corridors with fewer (or no) options. + +## Comparison of Alternatives + +| Alternative | Speed | Cost | Coverage | Intermediaries | +|-------------|-------|------|----------|----------------| +| Direct Bank Connections | Hours-days | Lower | Limited pairs | None | +| Fintech Rails (Wise, etc.) | Hours-days | 0.5-1.5% | 80+ countries | Internal | +| Stablecoins (Tempo) | ~0.5 seconds | ~$0.001 | Global (wallets) | None | +| CBDCs | TBD | TBD | Limited pilots | Varies | +| Regional Payment Systems | Hours | Low | Regional only | Reduced | + +## When Correspondent Banking Is Still Necessary + +Correspondent banking has real advantages: + +- **Universal reach**: Connects any two banks globally +- **Established trust**: 50+ years of legal frameworks +- **Large transactions**: Handles multi-million dollar transfers routinely +- **Regulatory clarity**: Clear compliance requirements +- **Bank account delivery**: Funds arrive in recipient's existing bank account + +For payments to traditional bank accounts where recipients can't accept alternatives, correspondent banking remains the default. + +## Direct Bank Connections + +### How It Works + +Large banks establish direct relationships with banks in key markets, bypassing correspondents for high-volume corridors. + +### Benefits + +- Fewer intermediaries = lower fees and faster settlement +- More predictable routing and timing +- Better visibility into payment status + +### Limitations + +- Only available for high-volume corridors +- Requires significant bilateral volume to justify +- Still limited to banking hours +- Not available to smaller institutions + +## Fintech Payment Rails + +### How They Work + +Companies like Wise, Payoneer, and Remitly maintain local bank accounts in multiple countries. Instead of sending money through correspondents, they: + +1. Accept payment locally in origin country +2. Pay out from their local account in destination country +3. Rebalance their internal accounts periodically + +### Benefits + +- Avoids correspondent fees +- Faster settlement (often same or next day) +- Transparent pricing +- Mid-market FX rates + +### Examples + +| Provider | Coverage | Typical Cost | Speed | +|----------|----------|--------------|-------| +| Wise | 80+ countries | 0.5-1.5% | 1-2 days | +| Payoneer | 200+ countries | 2-3% | 1-3 days | +| Remitly | 100+ countries | 1-3% | Minutes-days | + +### Limitations + +- Lower limits than bank wires +- Still requires bank accounts +- Settlement not instant +- Coverage varies by corridor + +## Stablecoins on Tempo + +### How It Works + +Stablecoins represent dollars (or other currencies) on blockchain networks. Transfers happen directly between wallets without any intermediary banks. + +### No Correspondent Chain + +``` +Traditional: Sender Bank → Correspondent → Correspondent → Receiver Bank +Tempo: Sender Wallet → Tempo Network → Receiver Wallet +``` + +### Speed & Cost + +- **Settlement**: ~0.5 seconds to finality +- **Cost**: ~$0.001 per transaction +- **Availability**: 24/7/365 +- **Intermediaries**: None + +### $100,000 Cross-Border Transfer + +| Component | Correspondent Banking | Tempo | +|-----------|----------------------|-------| +| Sender fees | $45 | $0.001 | +| Correspondent 1 | $15 | $0 | +| Correspondent 2 | $15 | $0 | +| Receiver fees | $10 | $0 | +| FX (2%) | $2,000 | ~$50 (DEX) | +| **Total cost** | **$2,085** | **~$50** | +| **Time** | **2-4 days** | **0.5 seconds** | + +### Best For + +- Crypto-native businesses +- High-frequency international payments +- Time-sensitive transfers +- 24/7 global operations +- Programmable payments +- Corridors with limited correspondent access + +### Limitations + +- Recipient needs crypto wallet (not bank account) +- On/off ramps needed for fiat conversion +- Less familiar to traditional finance +- Evolving regulatory landscape + +## CBDCs (Central Bank Digital Currencies) + +### What They Are + +Digital currencies issued by central banks. Potentially enable direct central bank-to-central bank settlement, bypassing commercial correspondent networks. + +### Current State + +- **Pilots**: China (e-CNY), EU (digital euro), many others testing +- **mBridge**: Multi-CBDC platform for cross-border between Hong Kong, Thailand, China, UAE +- **Production**: Bahamas (Sand Dollar), Nigeria (eNaira), Jamaica (JAM-DEX) + +### Potential Benefits + +- Direct central bank settlement +- Reduced reliance on correspondent banks +- 24/7 availability +- Programmable money + +### Limitations + +- Most still in pilot/development +- Interoperability between CBDCs uncertain +- Design decisions (privacy, programmability) still being made +- Years from widespread cross-border use + +## Regional Payment Systems + +### Examples + +- **SEPA** (Europe): Instant or same-day within Eurozone +- **TIPS** (Europe): Instant settlement 24/7 +- **P27** (Nordics): Cross-border Nordic payments +- **Project Nexus**: BIS initiative linking domestic instant payment systems + +### Benefits + +- Fast settlement within region +- Lower costs than correspondent banking +- Increasing 24/7 availability + +### Limitations + +- Regional only +- Cross-region still requires bridges +- Different systems don't interoperate + +## Choosing the Right Alternative + +| Your Situation | Best Alternative | +|----------------|-----------------| +| High-volume specific corridor | Direct bank connection | +| SMB international to bank accounts | Fintech rails (Wise) | +| Crypto-capable counterparties | Stablecoins (Tempo) | +| Intra-regional (EU, Nordics) | Regional payment systems | +| Traditional bank, no alternative | Correspondent banking | + +## The Evolving Landscape + +Correspondent banking won't disappear, but its role is narrowing: + +| Payment Type | Likely Future | +|--------------|---------------| +| Bank-to-bank, unfamiliar corridor | Correspondent banking | +| High-volume corridors | Direct connections | +| SMB/consumer to bank | Fintech rails | +| Crypto-native businesses | Stablecoins | +| Intra-regional | Regional systems | +| Government/central bank | CBDCs (eventually) | + +## Cost Comparison: Annual International Payment Volume + +**$1M annual international payments (100 transactions):** + +| Method | Avg Per-Transaction | Total Annual Cost | +|--------|---------------------|-------------------| +| Correspondent banking | $200 (fees + FX) | $20,000 | +| Direct bank (if available) | $100 | $10,000 | +| Fintech rails | $100 (1%) | $10,000 | +| Tempo | $0.50 (incl. FX swap) | $50 | + +*Tempo savings: ~$19,950/year* + +## Transitioning from Correspondent Banking + +For businesses exploring alternatives: + +1. **Audit your corridors**: Which countries do you pay most frequently? +2. **Assess recipient capabilities**: Can they accept stablecoins? Need bank deposits? +3. **Start with specific corridors**: Test alternatives on highest-volume or most expensive routes +4. **Hybrid approach**: Use correspondent banking where necessary, alternatives where beneficial + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/creator-economy-payments.mdx b/src/pages/guides/creator-economy-payments.mdx new file mode 100644 index 00000000..991c8bbe --- /dev/null +++ b/src/pages/guides/creator-economy-payments.mdx @@ -0,0 +1,16 @@ +--- +title: "Creator Economy Payments" +description: "Pay creators globally with Tempo's stablecoin-native infrastructure. Smart accounts, passkeys, and ~$0.001 fees make instant creator payouts simple and affordable." +--- + +# Creator Economy Payments + +Learn how to integrate instant, low-cost payments for creator platforms using Tempo. + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/cross-border-b2b-payments.mdx b/src/pages/guides/cross-border-b2b-payments.mdx new file mode 100644 index 00000000..db10f1a3 --- /dev/null +++ b/src/pages/guides/cross-border-b2b-payments.mdx @@ -0,0 +1,143 @@ +--- +title: "Cross-Border B2B Payments" +description: "Send international business payments with stablecoins on Tempo. Eliminate SWIFT delays, correspondent fees, and FX markups with instant settlement." +--- + +# Cross-Border B2B Payments + +International B2B payments are expensive and slow. SWIFT transfers, correspondent banks, and currency conversion create friction that stablecoins eliminate entirely. + +## The Cross-Border Problem + +### Traditional International Payments + +| Pain Point | Impact | +|------------|--------| +| SWIFT fees | $30-50 per transfer | +| Correspondent bank fees | Additional $10-30 per intermediary | +| FX conversion markup | 1-4% hidden in exchange rates | +| Settlement time | 2-5 business days | +| Tracking difficulty | Limited visibility into payment status | + +### Real Cost Example + +Sending $50,000 to an overseas supplier: + +| Cost Component | Traditional | Tempo | +|----------------|-------------|-------| +| Transfer fee | $40 | ~$0.001 | +| Correspondent fees | $25 | $0 | +| FX markup (2%) | $1,000 | $0* | +| **Total** | **$1,065** | **~$0.001** | + +*Parties transact directly in stablecoins + +## Tempo for International Payments + +### Borderless by Design + +Stablecoin payments on Tempo work the same whether the recipient is across the street or across the world: + +- **No correspondent banks** — Direct settlement between parties +- **No SWIFT dependency** — Transactions confirm in seconds +- **No FX complexity** — Both parties transact in USD-pegged stablecoins + +### Instant Settlement + +Funds arrive immediately regardless of time zones, banking hours, or holidays. Your overseas supplier receives payment at 2 AM on a Sunday as easily as 2 PM on a Tuesday. + +### Complete Visibility + +Track every payment on-chain: + +- Real-time transaction status +- Immutable confirmation records +- Full metadata preserved + +## Implementation + +### Sending International Payments + +```typescript +import { Tempo } from '@tempo/sdk'; + +const tempo = new Tempo({ apiKey: 'your-api-key' }); + +const payment = await tempo.payments.create({ + recipient: supplier.walletAddress, + amount: '50000.00', + currency: 'USDC', + metadata: { + supplierId: supplier.id, + invoiceNumber: 'INV-2024-0892', + purchaseOrder: 'PO-45123', + paymentTerms: 'Net30', + supplierCountry: 'DE' + } +}); +``` + +### Batch International Payments + +Pay suppliers across multiple countries in one transaction: + +```typescript +const batch = await tempo.batch.create({ + payments: [ + { recipient: germanySupplier.wallet, amount: '25000', currency: 'USDC' }, + { recipient: japanSupplier.wallet, amount: '18000', currency: 'USDC' }, + { recipient: brazilSupplier.wallet, amount: '12000', currency: 'USDC' } + ] +}); +``` + +### Multi-Currency Strategy + +While Tempo transactions are in stablecoins, businesses can integrate with local on/off-ramps: + +1. Send payment in stablecoins via Tempo (pathUSD, AlphaUSD, etc.) +2. Recipient converts to local currency via their preferred exchange +3. Or recipient holds stablecoins for their own international payments + +## Compliance Considerations + +### Audit Trail + +Every transaction includes: + +- Sender and recipient addresses +- Exact timestamp +- Payment metadata (invoice, PO, vendor ID) +- Immutable on-chain record + +### Regulatory Readiness + +Tempo's structured metadata supports: + +- Sanctions screening integration +- Transaction monitoring +- Tax reporting requirements +- Inter-company transfer documentation + +## Use Cases + +### Manufacturing Supply Chains + +Pay component suppliers across Asia with instant confirmation and full traceability. + +### Professional Services + +Compensate international contractors and consultants without wire transfer delays. + +### Software & SaaS + +Pay overseas development teams and service providers weekly or bi-weekly without fee overhead. + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/cross-border-payments-without-swift.mdx b/src/pages/guides/cross-border-payments-without-swift.mdx new file mode 100644 index 00000000..af2a0b70 --- /dev/null +++ b/src/pages/guides/cross-border-payments-without-swift.mdx @@ -0,0 +1,42 @@ +--- +title: Cross-Border Payments Without SWIFT +description: Bypass SWIFT entirely. Send payments globally in seconds using stablecoins on Tempo with instant finality. +--- + +# Cross-Border Payments Without SWIFT + +Bypass the SWIFT network entirely. Send payments globally in seconds using stablecoins on Tempo. + +## Why Businesses Are Moving Beyond SWIFT + +SWIFT transfers take 1-5 business days, cost $25-50 per transaction, and require multiple correspondent banks. For businesses making frequent international payments, these delays and costs add up quickly. + +Tempo offers a modern alternative: stablecoin rails that settle instantly with predictable, near-zero fees. + +## Tempo's Advantages for Cross-Border Payments + +| Feature | SWIFT | Tempo | +|---------|-------|-------| +| Settlement time | 1-5 days | <1 second | +| Cost per transfer | $25-50 | ~$0.001 | +| Operating hours | Banking hours | 24/7/365 | +| Transparency | Opaque routing | Full onchain visibility | +| Currency conversion | Bank FX rates | Direct stablecoin swaps | + +## How It Works + +Tempo provides dedicated payment lanes at the protocol level. Your payments don't compete with other blockchain traffic—fees stay low and predictable even during network congestion. + +**Key features:** +- **Stablecoin-native gas**: Pay transaction fees in USD stablecoins, not volatile tokens +- **Payment metadata**: Attach invoice numbers, PO references, and cost centers directly to transactions +- **Deterministic finality**: Know exactly when your payment has settled, every time + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/crypto-payment-gateway.mdx b/src/pages/guides/crypto-payment-gateway.mdx new file mode 100644 index 00000000..e30c5e7f --- /dev/null +++ b/src/pages/guides/crypto-payment-gateway.mdx @@ -0,0 +1,149 @@ +--- +title: "Crypto Payment Gateway" +description: "Accept stablecoin payments as a merchant with Tempo. Sub-second confirmation, ~$0.001 fees, and webhooks for seamless e-commerce integration." +--- + +# Crypto Payment Gateway + +Accept stablecoin payments from customers with the speed and reliability merchants expect from traditional payment processors—at a fraction of the cost. + +## Why Stablecoin Payments for Merchants? + +### Fee Comparison + +| Payment Method | Fee | Settlement | +|----------------|-----|------------| +| Credit cards | 2.5-3.5% | 1-2 days | +| PayPal | 2.9% + $0.30 | 1-2 days | +| Wire transfer | $25+ | 1-3 days | +| **Tempo** | **~$0.001** | **Instant** | + +For a merchant processing $100,000/month: +- Credit card fees: $2,500-3,500/month +- Tempo fees: ~$1/month + +### No Chargebacks + +Stablecoin payments are final. No disputes, no reversals, no chargeback fraud. + +### Global Customers + +Accept payments from customers worldwide without international payment complexity. + +## Tempo Gateway Features + +### Fast Finality + +Transactions confirm in ~0.5 seconds. Customers see immediate confirmation, just like traditional card payments. + +### Payment Metadata + +Attach order context to every transaction: + +- Order ID +- Customer ID +- Cart contents +- Shipping address hash +- Discount codes applied + +### Stablecoin-Native Gas + +Customers pay transaction fees in stablecoins—no need to hold ETH or other tokens. + +## Integration Guide + +### Payment Flow + +1. Customer selects stablecoin checkout +2. Display payment amount and address +3. Customer sends payment +4. Webhook confirms receipt +5. Fulfill order + +### SDK Integration + +```typescript +import { Tempo } from '@tempo/sdk'; + +const tempo = new Tempo({ apiKey: 'your-api-key' }); + +// Create payment request +const payment = await tempo.payments.create({ + amount: cart.total, + currency: 'USDC', + metadata: { + orderId: order.id, + customerId: customer.id + } +}); + +// Return payment details to frontend +return { + address: payment.address, + amount: payment.amount, + paymentId: payment.id +}; +``` + +### Webhook Handler + +```typescript +app.post('/webhooks/tempo', async (req, res) => { + const event = tempo.webhooks.verify(req.body, req.headers); + + if (event.type === 'payment.received') { + const { orderId } = event.metadata; + + // Verify amount matches order + const order = await getOrder(orderId); + if (event.amount === order.total) { + await fulfillOrder(orderId); + } + } + + res.status(200).send('OK'); +}); +``` + +### Checkout Widget + +Embed a pre-built checkout component: + +```html + +
+
+``` + +## E-Commerce Platform Plugins + +Pre-built integrations for popular platforms: + +- Shopify +- WooCommerce +- Magento +- Custom API integration + +## Refund Handling + +Process refunds through the same API: + +```typescript +const refund = await tempo.payments.refund({ + originalPaymentId: payment.id, + amount: refundAmount, + reason: 'Customer request' +}); +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/crypto-payments-for-ecommerce.mdx b/src/pages/guides/crypto-payments-for-ecommerce.mdx new file mode 100644 index 00000000..fc65dbfb --- /dev/null +++ b/src/pages/guides/crypto-payments-for-ecommerce.mdx @@ -0,0 +1,98 @@ +--- +title: "Crypto Payments for Ecommerce" +description: "Accept stablecoin payments in your ecommerce store with Tempo. ~$0.001 fees, instant confirmation, and order metadata for seamless fulfillment." +--- + +# Crypto Payments for Ecommerce + +Credit card fees eat into ecommerce margins. At 2.5-3.5% per transaction plus per-transaction fees, payment processing becomes a significant cost center. Stablecoin payments on Tempo reduce that to approximately $0.001 per transaction. + +## The Ecommerce Payment Problem + +For a store processing $1M annually: + +| Payment Method | Annual Cost | +|---------------|-------------| +| Credit cards (3%) | $30,000 | +| PayPal (2.9% + $0.30) | $29,000+ | +| **Tempo stablecoins** | **~$100** | + +Those savings go straight to your bottom line. + +## Benefits for Ecommerce + +### Near-Zero Fees + +~$0.001 per transaction regardless of order value. A $10 order and a $10,000 order cost the same to process. + +### No Chargebacks + +Stablecoin payments are final. No fraudulent chargebacks, no disputes to manage, no reserve holdbacks. + +### Instant Settlement + +Funds are available immediately. No waiting for batch processing or payout schedules. + +### Global Customers + +Accept payments from customers worldwide without dealing with currency conversion or international card fees. + +## How It Works + +### Checkout Integration + +1. Customer selects stablecoin payment at checkout +2. Display payment address and amount (QR code + text) +3. Customer sends payment from their wallet +4. Tempo confirms the transaction instantly +5. Order proceeds to fulfillment + +### Order Metadata + +Attach order details to each payment: + +- Order ID +- Customer ID +- SKUs purchased +- Shipping address hash +- Promo codes applied + +This metadata enables automatic order matching and simplifies accounting. + +### Payment Confirmation + +Tempo's instant finality means you can confirm orders immediately—no waiting for block confirmations or payment verification. + +## Integration Options + +### API Integration + +Integrate Tempo payments directly into your checkout flow: + +1. Generate unique payment address per order +2. Monitor for incoming payments via webhook +3. Confirm order when payment arrives +4. Include order ID in payment metadata + +### Payment Plugins + +Use pre-built integrations for major ecommerce platforms (check [docs.tempo.xyz](https://docs.tempo.xyz) for current availability). + +### Hybrid Approach + +Offer stablecoins alongside traditional payment methods. Let customers choose based on their preference. + +## Operational Considerations + +- **Pricing**: Display prices in USD, accept equivalent USDC +- **Refunds**: Process refunds to the original sending address +- **Accounting**: Export transaction data with order metadata for reconciliation + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/crypto-payments-for-regulated-businesses.mdx b/src/pages/guides/crypto-payments-for-regulated-businesses.mdx new file mode 100644 index 00000000..30e3ef53 --- /dev/null +++ b/src/pages/guides/crypto-payments-for-regulated-businesses.mdx @@ -0,0 +1,107 @@ +--- +title: "Crypto Payments for Regulated Businesses" +description: "Guide for banks, fintechs, and money service businesses on accepting and sending stablecoin payments within compliance frameworks." +--- + +# Crypto Payments for Regulated Businesses + +Banks, fintechs, and Money Service Businesses (MSBs) are increasingly exploring stablecoin payments to improve settlement speed, reduce costs, and expand service offerings. This guide outlines compliance considerations for regulated entities entering the stablecoin payments space. + +> **Disclaimer:** This content is for informational purposes only and does not constitute legal, financial, or regulatory advice. Consult your compliance team and legal counsel before implementing stablecoin payment capabilities. + +## Regulatory Context + +Regulated financial institutions face unique considerations when adopting stablecoin payments: + +- Existing regulatory relationships and supervisory expectations +- Capital and liquidity requirements that may apply to crypto holdings +- Operational risk management frameworks +- Third-party risk management requirements +- Consumer protection obligations + +Regulators including the OCC, Federal Reserve, FDIC, and state banking departments have issued guidance on crypto-asset activities for supervised institutions. + +## Key Requirements + +### For Banks and Credit Unions + +- **Supervisory Non-Objection:** Many jurisdictions require advance notice or approval before engaging in crypto activities +- **Risk Assessment:** Document comprehensive risk analysis covering credit, market, liquidity, operational, and compliance risks +- **Capital Treatment:** Understand how stablecoin holdings affect capital ratios under applicable frameworks +- **Custody Standards:** Implement appropriate safekeeping controls for digital assets +- **BSA/AML Compliance:** Extend existing Bank Secrecy Act programs to cover stablecoin transactions + +### For Fintechs and Payment Companies + +- **Licensing Audit:** Review existing licenses to determine if stablecoin activities are covered or require additional authorization +- **Partner Bank Requirements:** If operating under bank partnerships, ensure alignment with partner's crypto policies +- **State Compliance:** Address state-by-state money transmission requirements +- **Consumer Disclosures:** Provide clear disclosures about stablecoin risks and protections (or lack thereof) + +### For Money Service Businesses + +- **FinCEN Registration:** Ensure MSB registration covers virtual currency activities +- **State Licensing:** Obtain required state money transmitter licenses +- **Enhanced Due Diligence:** Implement heightened scrutiny for higher-risk customers and transactions +- **Agent Oversight:** If using agents, extend compliance monitoring to agent activities + +## Implementation Guidance + +### Compliance Framework Integration + +1. **Gap Analysis:** Compare current compliance program against crypto-specific requirements +2. **Policy Updates:** Revise AML, KYC, and operational policies to address stablecoin specifics +3. **Risk Appetite Definition:** Establish clear parameters for acceptable crypto-related risks +4. **Control Implementation:** Deploy technical and procedural controls for stablecoin transactions +5. **Board Reporting:** Develop metrics and reporting for board-level oversight + +### Vendor and Partner Selection + +Evaluate service providers across key dimensions: + +| Consideration | Key Questions | +|--------------|---------------| +| Regulatory Status | Is the partner appropriately licensed/registered? | +| Compliance Tools | What AML/sanctions screening capabilities are provided? | +| Insurance Coverage | What protections exist for operational failures or theft? | +| Audit Reports | Are SOC 2 or equivalent reports available? | +| Incident Response | What are SLAs for security incidents? | + +### Transaction Monitoring Enhancements + +Extend monitoring capabilities to address crypto-specific risks: + +- **Blockchain Analytics Integration:** Connect with providers like Chainalysis or Elliptic for on-chain risk scoring +- **Wallet Screening:** Screen counterparty wallet addresses against sanctions lists and known illicit actors +- **Cross-Channel Correlation:** Link on-chain activity with traditional banking transactions +- **Typology Updates:** Incorporate crypto-specific red flags into detection scenarios + +## Best Practices + +- **Start with Clear Use Cases:** Define specific business objectives before expanding crypto capabilities +- **Phased Rollout:** Begin with limited pilots before broad deployment +- **Regulatory Engagement:** Proactively communicate with supervisors about crypto plans +- **Ongoing Training:** Ensure compliance, operations, and customer-facing staff understand stablecoin products +- **Incident Playbooks:** Develop response procedures for crypto-specific scenarios (wallet compromises, blockchain forks, etc.) +- **Regular Reassessment:** Review compliance program as regulations evolve + +## Resources and Further Reading + +- [OCC Interpretive Letters on Crypto](https://www.occ.gov/) - US national bank guidance +- [Federal Reserve SR Letters](https://www.federalreserve.gov/) - Supervisory guidance +- [FFIEC BSA/AML Manual](https://bsaaml.ffiec.gov/) - Examination procedures +- [Chainalysis Compliance Solutions](https://www.chainalysis.com/) - Blockchain analytics +- [Elliptic Navigator](https://www.elliptic.co/) - Crypto compliance platform +- [Tempo Integration Docs](https://docs.tempo.xyz) - Technical implementation guides + +--- + +*Last updated: 2024. Regulatory expectations for regulated institutions evolve frequently—maintain ongoing dialogue with your supervisors.* + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/crypto-payments-for-saas.mdx b/src/pages/guides/crypto-payments-for-saas.mdx new file mode 100644 index 00000000..f4b84cfe --- /dev/null +++ b/src/pages/guides/crypto-payments-for-saas.mdx @@ -0,0 +1,129 @@ +--- +title: "Crypto Payments for SaaS" +description: "Accept stablecoin payments for SaaS subscriptions on Tempo. ~$0.001 fees, automated recurring billing, and usage-based pricing support." +--- + +# Crypto Payments for SaaS + +SaaS companies lose significant revenue to payment processing fees. Credit card processors charge 2.5-3.5% on every subscription renewal, plus additional fees for failed payments and chargebacks. Stablecoin payments on Tempo reduce processing costs to approximately $0.001 per transaction. + +## The SaaS Payment Problem + +For a SaaS company with $5M ARR: + +| Payment Method | Annual Processing Cost | +|----------------|------------------------| +| Credit cards (2.9% + $0.30) | $150,000+ | +| PayPal | $145,000+ | +| ACH | $25,000 | +| **Tempo stablecoins** | **~$500** | + +Beyond direct fees, credit card payments introduce additional costs: failed payment retries, involuntary churn from expired cards, and chargeback management overhead. + +## Benefits for SaaS + +### Near-Zero Transaction Fees + +~$0.001 per transaction regardless of plan tier. A $10/month starter plan and a $10,000/month enterprise plan cost the same to process. + +### No Failed Payments + +Stablecoin payments don't expire like credit cards. No more involuntary churn from payment method failures or expired cards. + +### No Chargebacks + +Stablecoin transactions are final. Eliminate chargeback fraud and the operational burden of dispute management. + +### Global Subscriptions + +Accept payments from customers worldwide without international card fees or currency conversion complexity. + +### Instant Settlement + +Funds are available immediately. No waiting for weekly or monthly payout cycles from payment processors. + +## How It Works + +### Recurring Billing + +1. Customer authorizes subscription amount and frequency +2. Set up automated payment collection via smart contract or API trigger +3. Tempo executes payment at each billing cycle +4. Customer receives invoice with transaction confirmation +5. Subscription renews automatically + +### Usage-Based Billing + +For metered or consumption-based pricing: + +1. Track customer usage throughout billing period +2. Calculate final amount at cycle end +3. Execute single payment with usage metadata +4. Provide detailed breakdown in customer portal + +### Hybrid Models + +Combine base subscription fees with usage-based overages: + +- Base fee collected on fixed schedule +- Overage charges calculated and collected at period end +- Full metadata for both components + +## Implementation + +### Subscription Setup + +Collect customer wallet address during signup and configure billing: + +- Billing frequency (monthly, quarterly, annual) +- Payment amount or pricing tier +- Usage thresholds for metered components +- Payment metadata (customer ID, plan tier, contract reference) + +### Payment Execution + +Trigger payments via API at each billing cycle: + +- Generate payment request with invoice metadata +- Customer wallet executes pre-authorized payment +- Tempo confirms transaction instantly +- Update subscription status and send receipt + +### Dunning and Retries + +Handle insufficient balance scenarios: + +- Check wallet balance before payment attempt +- Send proactive low-balance notifications +- Retry logic for temporary balance issues +- Grace period before service suspension + +## Integration Options + +### API Integration + +Build recurring billing directly into your subscription management system. Use webhooks for payment confirmations and failed payment notifications. + +### Billing Platform Integration + +Connect Tempo payments to existing subscription billing platforms (check [docs.tempo.xyz](https://docs.tempo.xyz) for current integrations). + +### Smart Contract Automation + +Deploy payment automation on-chain for fully trustless recurring billing without intermediary systems. + +## Operational Considerations + +- **Pricing**: Display prices in USD, collect equivalent USDC +- **Upgrades/Downgrades**: Prorate changes and adjust next billing amount +- **Refunds**: Process partial or full refunds to customer wallet +- **Accounting**: Export transaction data with subscription metadata + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/crypto-payroll-software.mdx b/src/pages/guides/crypto-payroll-software.mdx new file mode 100644 index 00000000..9e68d2bc --- /dev/null +++ b/src/pages/guides/crypto-payroll-software.mdx @@ -0,0 +1,130 @@ +--- +title: "Crypto Payroll Software" +description: "Integrate stablecoin payroll into your HR platform with Tempo. Instant global payments, ~$0.001 fees, and metadata for tax compliance and reporting." +--- + +# Crypto Payroll Software + +HR and payroll platforms can leverage Tempo to offer stablecoin salary payments, expanding their capabilities for global workforce management. + +## Why Add Crypto Payroll? + +### Growing Demand + +Remote workers, contractors, and international employees increasingly prefer stablecoin payments: + +- **Instant access** — No waiting for international wire transfers +- **Lower fees** — Employees keep more of their earnings +- **Currency choice** — Receive USDC/USDT without forex markups + +### Platform Differentiation + +Payroll platforms with crypto capabilities attract: + +- Companies with global remote teams +- Web3 and tech-forward organizations +- Businesses paying international contractors + +## Tempo for Payroll Platforms + +### Batch Payroll Processing + +Execute hundreds of salary payments in a single transaction: + +| Feature | Traditional Payroll | Tempo Payroll | +|---------|---------------------|---------------| +| International transfers | $25-50 per payment | ~$0.001 per payment | +| Settlement time | 3-5 business days | Instant | +| Reconciliation | Manual matching | Automated with metadata | + +### Payment Metadata + +Attach payroll-specific data to every transaction: + +- Employee ID +- Pay period dates +- Gross/net amounts +- Tax jurisdiction +- Benefits deductions +- Department/cost center + +### Compliance-Ready + +- Full audit trail for every payment +- Immutable records for tax reporting +- Structured metadata for regulatory requirements +- Multi-signature approval for large payrolls + +## Integration Architecture + +### API-First Design + +```typescript +import { Tempo } from '@tempo/sdk'; + +const tempo = new Tempo({ apiKey: 'your-api-key' }); + +// Process payroll batch +const payroll = await tempo.batch.create({ + payments: employees.map(emp => ({ + recipient: emp.walletAddress, + amount: emp.netPay, + currency: 'USDC', + metadata: { + employeeId: emp.id, + payPeriod: '2024-01', + grossPay: emp.grossPay, + taxWithheld: emp.taxWithheld + } + })) +}); +``` + +### Webhook Notifications + +Receive real-time confirmation when payments settle: + +```typescript +// Payment confirmed webhook +{ + type: 'batch.completed', + batchId: 'batch-123', + payments: [ + { employeeId: 'emp-1', status: 'confirmed', txHash: '0x...' } + ] +} +``` + +## Employee Experience + +### Wallet Onboarding + +Employees can: + +1. Connect an existing wallet +2. Create a Tempo smart account with passkey +3. Provide any EVM-compatible address + +### Payment Visibility + +Employees see full payment details including: + +- Pay period and breakdown +- Transaction confirmation +- Historical payment records + +## Implementation Path + +1. **API integration** — Connect your payroll engine to Tempo's batch API +2. **Employee onboarding** — Add wallet collection to employee setup +3. **Approval workflows** — Configure multi-sig for payroll execution +4. **Reporting** — Export transaction data for tax and accounting + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/dai-on-tempo.mdx b/src/pages/guides/dai-on-tempo.mdx new file mode 100644 index 00000000..deb4d92d --- /dev/null +++ b/src/pages/guides/dai-on-tempo.mdx @@ -0,0 +1,101 @@ +--- +title: "DAI on Tempo: Availability and Alternatives" +description: "DAI is not available on Tempo at launch. Learn about native USD stablecoins like pathUSD, AlphaUSD, BetaUSD, and ThetaUSD." +--- + +# DAI on Tempo: Availability and Alternatives + +DAI is not natively deployed on Tempo at launch. MakerDAO has not issued DAI on Tempo, and there is currently no bridge to bring DAI from other chains. This page explains the current status and the USD stablecoin alternatives available today. + +## What is DAI? + +DAI is a decentralized, crypto-collateralized stablecoin soft-pegged to the US dollar. MakerDAO governs the protocol, and users mint DAI by depositing collateral into Maker Vaults. The system maintains the peg through overcollateralization and automated stability mechanisms. + +**Key facts:** +- **Issuer:** MakerDAO (decentralized governance) +- **Backing:** Overcollateralized crypto assets, real-world assets, and USDC +- **Peg:** 1 DAI ≈ 1 USD (soft peg maintained by protocol mechanisms) +- **Governance:** MKR token holders govern protocol parameters + +## Current Availability Status + +| Stablecoin | Status | +|------------|--------| +| Native DAI (MakerDAO-issued) | Not available at launch | +| Bridged DAI | Not currently available | +| pathUSD | Available | +| AlphaUSD | Available | +| BetaUSD | Available | +| ThetaUSD | Available | + +## USD Stablecoins Available on Tempo Today + +Tempo supports several native USD stablecoins at launch: + +### pathUSD + +pathUSD is a USD-pegged stablecoin available natively on Tempo. Send, receive, and swap pathUSD with sub-cent fees and instant finality. + +### AlphaUSD + +AlphaUSD provides another USD stablecoin option on Tempo, fully integrated with the native exchange and gas payment system. + +### BetaUSD + +BetaUSD offers USD exposure on Tempo with the same low fees and fast settlement as other native stablecoins. + +### ThetaUSD + +ThetaUSD rounds out the USD stablecoin options available on Tempo at launch. + +## Why Use Tempo for Stablecoin Payments + +### Stablecoin-native gas + +Pay transaction fees directly in your stablecoin balance—no ETH required. This simplifies treasury management and eliminates the need to hold volatile assets. + +### Sub-cent fees + +Transaction fees on Tempo cost approximately 0.001 USD regardless of transfer size. Send 100 USD or 100,000 USD for the same fee. + +### Instant finality + +Transactions finalize in approximately 0.5 seconds. No waiting for block confirmations or pending states. Recipients can use funds immediately. + +### Payment metadata + +Attach invoice numbers, purchase orders, or custom references to any transfer. This simplifies reconciliation for businesses and enables structured payment workflows. + +### Native exchange + +Swap between USD stablecoins and other currencies at oracle prices with minimal slippage. No external DEX required. + +## FAQ + +### Is DAI available on Tempo? + +No. DAI is not available on Tempo at launch. MakerDAO has not deployed DAI natively on Tempo, and there are no bridges currently supporting DAI transfers to Tempo. + +### What USD stablecoins can I use on Tempo? + +Tempo supports four native USD stablecoins: pathUSD, AlphaUSD, BetaUSD, and ThetaUSD. All support stablecoin gas payments, sub-cent fees, and instant finality. + +### Will DAI come to Tempo? + +DAI may be added to Tempo in the future through native deployment or via bridge integrations. There is no confirmed timeline for DAI availability. + +### Can I bridge DAI to Tempo? + +No. There are currently no bridges supporting DAI transfers to Tempo. Check back for updates on bridge integrations. + +### How do Tempo's native USD stablecoins compare to DAI? + +Tempo's native USD stablecoins offer the same benefits as any stablecoin on Tempo: sub-cent fees, instant finality, stablecoin gas payments, and payment metadata. The key difference is the issuer and backing mechanism, which varies by stablecoin. + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/dedicated-payment-lanes.mdx b/src/pages/guides/dedicated-payment-lanes.mdx new file mode 100644 index 00000000..c3e4458d --- /dev/null +++ b/src/pages/guides/dedicated-payment-lanes.mdx @@ -0,0 +1,39 @@ +--- +title: "Dedicated Payment Lanes" +description: "Tempo reserves guaranteed blockspace for payment transactions. Your payments process reliably even during network congestion or high-demand periods." +--- + +# Dedicated Payment Lanes + +Tempo guarantees blockspace for payment transactions, ensuring reliable processing regardless of overall network activity. + +## The Congestion Problem + +On most blockchains, all transactions compete for the same blockspace. During high demand, fees spike and transactions get stuck. NFT mints shouldn't delay your payroll. + +## How Payment Lanes Work + +Tempo reserves a portion of each block specifically for payment transactions. This dedicated capacity means: + +- **Consistent processing** — Payments go through even during congestion +- **Predictable fees** — Payment fees stay stable +- **Priority when it matters** — Business-critical transactions aren't delayed + +## Use Cases + +- **Payroll processing** — Employee payments process on schedule +- **Vendor settlements** — Pay suppliers without delays +- **Customer refunds** — Process refunds promptly +- **Subscription billing** — Recurring payments execute reliably + +## Technical Details + +Learn more about Tempo's block structure in the [documentation](https://docs.tempo.xyz). + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/developer-payment-integration.mdx b/src/pages/guides/developer-payment-integration.mdx new file mode 100644 index 00000000..71dd1fcd --- /dev/null +++ b/src/pages/guides/developer-payment-integration.mdx @@ -0,0 +1,80 @@ +--- +title: "Developer Guide to Payment Integration" +description: "Integrate stablecoin payments into your application with Tempo's APIs. SDKs, webhooks, and code examples for stablecoin payment processing." +--- + +# Developer Guide to Payment Integration + +Build stablecoin payment flows into your application with Tempo's developer tools. + +## Why Developers Choose Tempo + +- **Simple APIs** — RESTful endpoints and typed SDKs +- **Fast finality** — Confirm payments in ~0.5 seconds, no polling for confirmations +- **Rich metadata** — Attach structured data to every transaction +- **Predictable costs** — Sub-cent fees that don't fluctuate + +## Integration Overview + +### Payment Flow + +1. Generate a payment request with amount and metadata +2. Customer sends payment to provided address +3. Webhook notifies your server of payment receipt +4. Verify payment details and fulfill order + +### Key APIs + +- **Addresses** — Generate unique receiving addresses +- **Transactions** — Query payment status and history +- **Webhooks** — Real-time payment notifications +- **Metadata** — Attach and retrieve payment references + +## Quick Start + +### Install the SDK + +```bash +npm install @tempo/sdk +``` + +### Create a Payment Request + +```typescript +import { Tempo } from '@tempo/sdk'; + +const tempo = new Tempo({ apiKey: 'your-api-key' }); + +const payment = await tempo.payments.create({ + amount: '100.00', + currency: 'USDC', + metadata: { + orderId: 'order-123', + customerId: 'cust-456' + } +}); +``` + +### Handle Webhooks + +```typescript +app.post('/webhooks/tempo', (req, res) => { + const event = tempo.webhooks.verify(req.body, req.headers); + + if (event.type === 'payment.received') { + // Fulfill order + } +}); +``` + +## Documentation + +Full API reference at [docs.tempo.xyz](https://docs.tempo.xyz). + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/education-tuition-crypto.mdx b/src/pages/guides/education-tuition-crypto.mdx new file mode 100644 index 00000000..2e036e69 --- /dev/null +++ b/src/pages/guides/education-tuition-crypto.mdx @@ -0,0 +1,142 @@ +--- +title: "Education Tuition with Crypto" +description: "Accept international student tuition with stablecoins on Tempo. ~$0.001 fees, instant payment confirmation, and support for study abroad programs." +--- + +# Education Tuition with Crypto + +International student payments are expensive and slow. Wire transfers from overseas families incur significant fees, and currency conversion erodes tuition dollars before they reach the institution. Stablecoin payments on Tempo deliver nearly 100% of tuition funds with instant confirmation. + +## The International Tuition Problem + +| Payment Method | Fees | Settlement | Reconciliation | +|---------------|------|------------|----------------| +| International wire | $40-75 | 3-5 days | Manual matching | +| Currency conversion | 2-4% markup | Immediate | FX tracking | +| Third-party flywire/similar | 1-2% | 2-4 days | Platform-dependent | +| Credit card (intl) | 3-4% + cross-border | 1-3 days | Automated | +| **Tempo** | **~$0.001** | **Instant** | **Automated** | + +For a $50,000 annual tuition payment from an international student: + +| Cost Component | Traditional | Tempo | +|----------------|-------------|-------| +| Wire transfer fee | $50 | ~$0.001 | +| Currency conversion (3%) | $1,500 | $0* | +| **Total fees** | **$1,550** | **~$0.001** | + +*Families transact directly in stablecoins + +## Benefits for Educational Institutions + +### Reduced Payment Friction + +International families pay as easily as domestic ones. Remove wire transfer complexity that delays enrollment confirmation. + +### Lower Processing Costs + +Eliminate third-party international payment processor fees. Those savings can reduce student costs or fund institutional priorities. + +### Instant Payment Confirmation + +Confirm tuition payment immediately. No waiting for wire clearance before finalizing enrollment or releasing registration holds. + +### Simplified Reconciliation + +Transaction metadata enables automatic matching to student accounts. Reduce bursar office manual processing. + +### Global Student Access + +Accept payments from students in any country without geographic payment restrictions. + +## How It Works + +### Tuition Payment Flow + +1. Institution generates tuition bill with stablecoin payment option +2. Student receives payment instructions with enrollment metadata +3. Student (or family) sends stablecoins from wallet +4. Institution receives instant confirmation +5. Student account credited and enrollment finalized + +### Payment Metadata + +Attach enrollment context to each transaction: + +- Student ID +- Term/semester +- Payment type (tuition, housing, fees, meal plan) +- Invoice reference +- Payment plan installment number (if applicable) +- Scholarship/aid offsets + +### Payment Plans + +Support installment-based tuition: + +1. Define payment schedule with amounts and due dates +2. Student authorizes recurring payments +3. Execute payment at each installment +4. Track payment plan status in student account + +## Implementation + +### For Bursar Offices + +1. Set up institutional payment wallet +2. Integrate stablecoin option into student billing portal +3. Generate unique payment references per student/term +4. Monitor incoming payments via webhook +5. Auto-post to student accounts using metadata + +### For International Admissions + +1. Include stablecoin payment information in acceptance materials +2. Provide clear instructions for deposit and tuition payments +3. Confirm enrollment deposits instantly +4. Reduce payment-related enrollment delays + +### For Study Abroad Programs + +1. Collect program fees from students before departure +2. Pay partner institutions and vendors in destination countries +3. Eliminate international wire fees on both collection and disbursement +4. Track expenses with program metadata + +## Use Cases + +### International Student Tuition + +Families in Asia, Middle East, or Latin America pay US institution tuition without losing $1,000+ to fees per semester. + +### Study Abroad Programs + +Students pay program fees and institutions pay overseas partners, both avoiding international wire costs. + +### Language Schools and Short Programs + +International students in intensive programs pay deposits and tuition without wire delays affecting start dates. + +### Boarding Schools + +International families pay tuition, room, and board without cumulative wire fees across multiple payment types. + +### Scholarship Disbursements + +Foundations and donors send scholarship funds to international students directly with minimal fees. + +## Compliance Considerations + +- **Financial Aid Coordination**: Ensure stablecoin payments integrate with Title IV and institutional aid calculations +- **1098-T Reporting**: Include transaction details for tax document generation +- **Audit Trail**: Immutable records support financial audits and accreditation reviews +- **International Compliance**: Implement appropriate verification per jurisdiction requirements + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/enterprise-treasury-guide.mdx b/src/pages/guides/enterprise-treasury-guide.mdx new file mode 100644 index 00000000..b67aa260 --- /dev/null +++ b/src/pages/guides/enterprise-treasury-guide.mdx @@ -0,0 +1,207 @@ +--- +title: "Enterprise Treasury Guide" +description: "Manage corporate treasury with stablecoins on Tempo. Multi-sig controls, yield optimization, and instant settlement for CFOs and treasury teams." +--- + +# Enterprise Treasury Guide + +A guide for CFOs and treasury teams evaluating stablecoins for corporate cash management, payments, and yield optimization. + +## Why Treasury Teams Consider Stablecoins + +### Cash Management Challenges + +| Challenge | Traditional Approach | Stablecoin Approach | +|-----------|---------------------|---------------------| +| Idle cash yield | 0-2% in bank accounts | 3-5% in DeFi protocols | +| International transfers | $30-50, 2-5 days | ~$0.001, instant | +| Operating hours | Banking hours only | 24/7/365 | +| Visibility | T+1 bank statements | Real-time on-chain | + +### Tempo for Treasury + +Tempo provides enterprise-grade infrastructure: + +- **Multi-signature controls** — Require multiple approvers for transactions +- **Spending limits** — Enforce daily/weekly transaction caps +- **Audit trail** — Immutable record of all treasury operations +- **Stablecoin-native gas** — No volatile asset management required + +## Treasury Operations + +### Multi-Sig Configuration + +Set up approval thresholds appropriate for your organization: + +```typescript +import { Tempo } from '@tempo/sdk'; + +const tempo = new Tempo({ apiKey: 'your-api-key' }); + +// Create treasury account with multi-sig +const treasury = await tempo.accounts.create({ + type: 'multi-sig', + signers: [ + { address: cfo.wallet, weight: 2 }, + { address: controller.wallet, weight: 1 }, + { address: treasurer.wallet, weight: 1 } + ], + thresholds: { + default: 2, // 2 weight required normally + highValue: 3 // 3 weight for large transactions + }, + limits: { + highValueThreshold: '100000.00' + } +}); +``` + +### Payment Approval Workflow + +1. Treasury analyst initiates payment +2. System routes to appropriate approvers based on amount +3. Approvers sign via hardware wallet or passkey +4. Payment executes when threshold met +5. Confirmation recorded with full audit trail + +### Cash Position Visibility + +Real-time view of stablecoin holdings: + +```typescript +// Get treasury positions +const positions = await tempo.accounts.getBalances(treasury.address); + +// Returns: +{ + USDC: '2,500,000.00', + USDT: '1,200,000.00', + totalUSD: '3,700,000.00', + lastUpdated: '2024-01-15T14:32:00Z' +} +``` + +## Yield Optimization + +### Stablecoin Yield Strategies + +Deploy idle cash to earn yield while maintaining liquidity: + +| Strategy | Expected Yield | Liquidity | Risk Level | +|----------|---------------|-----------|------------| +| Money market protocols | 3-5% | Instant | Low | +| Liquidity provision | 5-10% | Minutes | Medium | +| Term deposits | 6-12% | Locked | Low-Medium | + +### Treasury Allocation Example + +``` +Total Treasury: $10M USDC + +Allocation: +├── Operating Buffer (20%): $2M — Instant access, 0% yield +├── Short-term (50%): $5M — Money market, 4% yield +└── Medium-term (30%): $3M — Term deposit, 7% yield + +Blended Yield: 4.1% ($410K annually) +``` + +### Tempo Yield Integration + +```typescript +// Deploy to yield strategy +const deployment = await tempo.yield.deploy({ + amount: '5000000.00', + currency: 'USDC', + strategy: 'money-market', + autoCompound: true, + minYield: 0.03 // 3% minimum +}); + +// Check current yield +const status = await tempo.yield.getPosition(deployment.id); +// Returns current balance, accrued yield, APY +``` + +## Payments and Settlements + +### Vendor Payments + +Execute batch payments with full metadata: + +```typescript +const batch = await tempo.batch.create({ + account: treasury.address, + payments: approvedPayables.map(inv => ({ + recipient: inv.vendor.wallet, + amount: inv.amount, + currency: 'USDC', + metadata: { + invoiceNumber: inv.number, + vendorId: inv.vendorId, + glCode: inv.glCode, + costCenter: inv.costCenter + } + })), + requiredApprovals: 2 +}); +``` + +### Intercompany Transfers + +Move funds between subsidiaries instantly: + +```typescript +await tempo.payments.create({ + from: treasury.address, + recipient: subsidiary.treasury.address, + amount: '500000.00', + currency: 'USDC', + metadata: { + type: 'intercompany-transfer', + fromEntity: 'US-HQ', + toEntity: 'EU-Sub', + purpose: 'Q1-operating-capital' + } +}); +``` + +## Compliance and Controls + +### Audit Trail + +Every transaction is recorded on-chain with: + +- Timestamp +- Signers who approved +- Full metadata +- Immutable transaction hash + +### Reporting + +Generate reports for auditors and regulators: + +```typescript +const report = await tempo.reports.generate({ + account: treasury.address, + startDate: '2024-01-01', + endDate: '2024-03-31', + format: 'csv', + include: ['transactions', 'approvals', 'balances'] +}); +``` + +### Segregation of Duties + +- Analysts can initiate, not approve +- Approvers cannot initiate +- Separate signers required for high-value transactions + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/eurc-on-tempo.mdx b/src/pages/guides/eurc-on-tempo.mdx new file mode 100644 index 00000000..5476b0fa --- /dev/null +++ b/src/pages/guides/eurc-on-tempo.mdx @@ -0,0 +1,101 @@ +--- +title: "EURC on Tempo: Availability and Alternatives" +description: "EURC is not available on Tempo at launch. Learn about native USD stablecoins like pathUSD, AlphaUSD, BetaUSD, and ThetaUSD." +--- + +# EURC on Tempo: Availability and Alternatives + +EURC is not natively deployed on Tempo at launch. Circle has not issued EURC on Tempo, and there is currently no bridge to bring EURC from other chains. This page explains the current status and the USD stablecoin alternatives available today. + +## What is EURC? + +EURC (Euro Coin) is a regulated stablecoin pegged 1:1 to the euro, issued by Circle Internet Financial. Circle maintains reserves in euros held at regulated financial institutions. Monthly attestations by Deloitte verify the reserves backing every EURC in circulation. + +**Key facts:** +- **Issuer:** Circle Internet Financial +- **Backing:** Euros held at regulated financial institutions +- **Peg:** 1 EURC = 1 EUR +- **Regulation:** Compliant with EU MiCA regulations + +## Current Availability Status + +| Stablecoin | Status | +|------------|--------| +| Native EURC (Circle-issued) | Not available at launch | +| Bridged EURC | Not currently available | +| pathUSD | Available | +| AlphaUSD | Available | +| BetaUSD | Available | +| ThetaUSD | Available | + +## USD Stablecoins Available on Tempo Today + +Tempo supports several native USD stablecoins at launch: + +### pathUSD + +pathUSD is a USD-pegged stablecoin available natively on Tempo. Send, receive, and swap pathUSD with sub-cent fees and instant finality. + +### AlphaUSD + +AlphaUSD provides another USD stablecoin option on Tempo, fully integrated with the native exchange and gas payment system. + +### BetaUSD + +BetaUSD offers USD exposure on Tempo with the same low fees and fast settlement as other native stablecoins. + +### ThetaUSD + +ThetaUSD rounds out the USD stablecoin options available on Tempo at launch. + +## Why Use Tempo for Stablecoin Payments + +### Stablecoin-native gas + +Pay transaction fees directly in your stablecoin balance—no ETH required. This simplifies treasury management and eliminates the need to hold volatile assets. + +### Sub-cent fees + +Transaction fees on Tempo cost approximately 0.001 USD regardless of transfer size. Send 100 USD or 100,000 USD for the same fee. + +### Instant finality + +Transactions finalize in approximately 0.5 seconds. No waiting for block confirmations or pending states. Recipients can use funds immediately. + +### Payment metadata + +Attach invoice numbers, purchase orders, or custom references to any transfer. This simplifies reconciliation for businesses and enables structured payment workflows. + +### Native exchange + +Swap between USD stablecoins and other currencies at oracle prices with minimal slippage. No external DEX required. + +## FAQ + +### Is EURC available on Tempo? + +No. EURC is not available on Tempo at launch. Circle has not deployed EURC natively on Tempo, and there are no bridges currently supporting EURC transfers to Tempo. + +### What USD stablecoins can I use on Tempo? + +Tempo supports four native USD stablecoins: pathUSD, AlphaUSD, BetaUSD, and ThetaUSD. All support stablecoin gas payments, sub-cent fees, and instant finality. + +### Will EURC come to Tempo? + +EURC may be added to Tempo in the future through native issuance by Circle or via bridge integrations. There is no confirmed timeline for EURC availability. + +### Can I bridge EURC to Tempo? + +No. There are currently no bridges supporting EURC transfers to Tempo. Check back for updates on bridge integrations. + +### What about euro stablecoins on Tempo? + +Tempo does not currently support any euro-denominated stablecoins at launch. The available stablecoins (pathUSD, AlphaUSD, BetaUSD, ThetaUSD) are all USD-pegged. + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/freelancer-crypto-payments.mdx b/src/pages/guides/freelancer-crypto-payments.mdx new file mode 100644 index 00000000..39c97e5c --- /dev/null +++ b/src/pages/guides/freelancer-crypto-payments.mdx @@ -0,0 +1,41 @@ +--- +title: "Crypto Payments for Freelancers" +description: "How freelancers use Tempo for client payments. Receive stablecoins with instant settlement, low fees, and payment metadata for easy bookkeeping." +--- + +# Crypto Payments for Freelancers + +Get paid faster and cheaper with stablecoin payments on Tempo. + +## Why Freelancers Choose Tempo + +### Instant Access to Funds + +No waiting 3-5 business days for bank transfers. Payments settle in ~0.5 seconds and you can use them immediately. + +### Lower Fees + +Keep more of what you earn: + +| Method | Typical Fee | +|--------|-------------| +| Tempo | ~$0.001 | +| PayPal | 2.9% + $0.30 | +| Wire Transfer | $25-50 | + +### Global Clients, No Friction + +Accept payments from clients anywhere. No currency conversion delays or international wire fees. + +### Simple Bookkeeping + +Payment metadata (invoice numbers, project references) attaches directly to transactions. Your accounting software can import and match automatically. + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/gaming-micropayments.mdx b/src/pages/guides/gaming-micropayments.mdx new file mode 100644 index 00000000..3a9c9a99 --- /dev/null +++ b/src/pages/guides/gaming-micropayments.mdx @@ -0,0 +1,228 @@ +--- +title: "Gaming Micropayments" +description: "Enable in-game purchases and player-to-player trading with Tempo. Sub-cent fees make microtransactions profitable for items at any price point." +--- + +# Gaming Micropayments + +Power in-game economies with stablecoin micropayments. Tempo's sub-cent fees and instant finality enable new monetization models for games of all sizes. + +## Gaming Payment Challenges + +Current in-game payment systems have limitations: + +| Challenge | Impact | +|-----------|--------| +| Platform fees | 30% to app stores on every purchase | +| Minimum transactions | Can't sell $0.10 items profitably | +| Cross-platform wallets | Balances locked to single platform | +| Player trading | Complex to enable, often prohibited | + +## Tempo for Gaming + +### Sub-Cent Transaction Fees + +Sell items at any price point: + +| Item | Price | Tempo Fee | Developer Keeps | +|------|-------|-----------|-----------------| +| Common skin | $0.10 | ~$0.001 | $0.099 (99%) | +| Consumable | $0.25 | ~$0.001 | $0.249 (99.6%) | +| Battle pass | $10.00 | ~$0.001 | $9.999 (99.99%) | + +Compare to 30% platform fees where developers keep only 70%. + +### Instant Finality + +Transactions confirm in ~0.5 seconds. Players see purchases immediately—no waiting for payment confirmation. + +### Player-Owned Assets + +Players hold items in their own wallets. True ownership enables: + +- Cross-game asset portability +- Player-to-player trading +- Secondary market participation + +## Implementation + +### In-Game Purchases + +```typescript +import { Tempo } from '@tempo/sdk'; + +const tempo = new Tempo({ apiKey: 'your-api-key' }); + +// Purchase in-game item +async function purchaseItem(playerId, itemId) { + const player = await getPlayer(playerId); + const item = await getItem(itemId); + + const payment = await tempo.payments.charge({ + from: player.walletAddress, + amount: item.price, + currency: 'USDC', + metadata: { + playerId, + itemId, + itemName: item.name, + gameId: 'game-123' + } + }); + + if (payment.confirmed) { + await grantItem(playerId, itemId); + return { success: true, item }; + } +} +``` + +### Player-to-Player Trading + +```typescript +// Escrow-based trading +async function executeTrade(trade) { + const { sellerId, buyerId, itemId, price } = trade; + + // Charge buyer + const payment = await tempo.payments.create({ + from: buyers[buyerId].wallet, + recipient: sellers[sellerId].wallet, + amount: price, + currency: 'USDC', + metadata: { + tradeId: trade.id, + itemId, + type: 'player-trade' + } + }); + + if (payment.confirmed) { + // Transfer item ownership + await transferItem(itemId, sellerId, buyerId); + return { success: true }; + } +} +``` + +### Streaming Payments for Play Time + +Charge per minute or per session: + +```typescript +// Start play session +async function startSession(playerId) { + const session = { + playerId, + startTime: Date.now(), + chargedMinutes: 0 + }; + + // Charge every minute + const interval = setInterval(async () => { + await tempo.payments.charge({ + from: players[playerId].wallet, + amount: '0.01', // $0.01 per minute + currency: 'USDC', + metadata: { + playerId, + sessionId: session.id, + minute: session.chargedMinutes++ + } + }); + }, 60000); + + return { sessionId: session.id, stop: () => clearInterval(interval) }; +} +``` + +### Loot Box / Gacha with Transparency + +On-chain randomness for provably fair drops: + +```typescript +async function openLootBox(playerId, boxType) { + const player = await getPlayer(playerId); + const boxPrice = lootBoxPrices[boxType]; + + // Charge for loot box + const payment = await tempo.payments.charge({ + from: player.walletAddress, + amount: boxPrice, + currency: 'USDC', + metadata: { playerId, boxType, type: 'loot-box' } + }); + + // Generate verifiable random drop + const drop = await generateDrop(boxType, payment.txHash); + + await grantItem(playerId, drop.itemId); + + return { + item: drop, + txHash: payment.txHash, // Proof of fairness + dropRate: drop.probability + }; +} +``` + +## Economy Design Patterns + +### Dual Currency + +Combine stablecoins with in-game soft currency: + +```typescript +// Hard currency (USDC) for premium items +// Soft currency (gold) earned through play + +async function purchaseWithGold(playerId, itemId) { + // Earned currency, no blockchain transaction needed + return deductGold(playerId, item.goldPrice); +} + +async function purchaseWithUSDC(playerId, itemId) { + // Premium purchase via Tempo + return purchaseItem(playerId, itemId); +} +``` + +### Marketplace Fees + +Take a cut of player-to-player trades: + +```typescript +async function marketplaceSale(listing) { + const salePrice = listing.price; + const platformFee = salePrice * 0.05; // 5% marketplace fee + const sellerReceives = salePrice - platformFee; + + // Buyer pays full price + await tempo.payments.charge({ + from: listing.buyerWallet, + amount: salePrice + }); + + // Seller receives minus fee + await tempo.payments.create({ + recipient: listing.sellerWallet, + amount: sellerReceives + }); +} +``` + +## Benefits for Studios + +- **Higher margins** — Keep 99%+ vs 70% with app stores +- **Instant settlement** — No 30-60 day payment delays +- **Global players** — Accept payments from any country +- **Player ownership** — Enable true digital ownership + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/healthcare-payments-crypto.mdx b/src/pages/guides/healthcare-payments-crypto.mdx new file mode 100644 index 00000000..498430c6 --- /dev/null +++ b/src/pages/guides/healthcare-payments-crypto.mdx @@ -0,0 +1,142 @@ +--- +title: "Healthcare Payments with Crypto" +description: "Process international medical payments with stablecoins on Tempo. ~$0.001 fees for medical tourism, cross-border claims, and patient billing." +--- + +# Healthcare Payments with Crypto + +Healthcare payments across borders face significant friction. International patients, medical tourism, and cross-border insurance claims involve wire fees, currency conversion, and processing delays. Stablecoin payments on Tempo simplify international healthcare transactions. + +## The Healthcare Payment Problem + +| Payment Scenario | Traditional Cost | Traditional Time | +|-----------------|------------------|------------------| +| International patient wire | $40-75 | 3-5 days | +| Currency conversion | 2-4% markup | Immediate | +| Cross-border insurance claim | Processing fees + delays | 30-90 days | +| Medical tourism deposit | $50 wire + FX | 3-5 days | +| **Tempo transfer** | **~$0.001** | **Instant** | + +For a $25,000 medical procedure paid by an international patient: + +| Cost Component | Traditional | Tempo | +|----------------|-------------|-------| +| Wire transfer fee | $50 | ~$0.001 | +| Currency conversion (3%) | $750 | $0* | +| **Total fees** | **$800** | **~$0.001** | + +*Parties transact directly in stablecoins + +## Benefits for Healthcare + +### Medical Tourism Payments + +International patients pay deposits and final bills without wire delays or currency conversion losses. Funds arrive instantly regardless of patient location. + +### Cross-Border Insurance Claims + +Insurers and providers settle claims directly without correspondent banking delays. Reduce days-sales-outstanding for international claims. + +### Reduced Administrative Costs + +Eliminate manual wire tracking, failed payment follow-up, and currency reconciliation overhead. + +### Instant Payment Confirmation + +Confirm patient payment immediately. No waiting for wire verification before scheduling procedures. + +### Global Patient Access + +Accept payments from patients worldwide. Remove payment friction that prevents international patients from accessing care. + +## How It Works + +### Patient Payment Flow + +1. Provider generates invoice with stablecoin payment option +2. Patient receives payment instructions with procedure metadata +3. Patient sends stablecoins from their wallet +4. Provider receives instant confirmation +5. Procedure scheduled or services rendered + +### Payment Metadata + +Attach clinical and billing context to transactions: + +- Patient ID +- Invoice or claim number +- Procedure codes +- Provider identifiers +- Insurance reference (if applicable) +- Payment type (deposit, copay, full payment, balance) + +### Insurance Claim Settlement + +For cross-border insurance payments: + +1. Provider submits claim to insurer +2. Insurer approves and initiates stablecoin payment +3. Provider receives instant settlement +4. Transaction metadata links to original claim + +## Implementation + +### For Healthcare Providers + +1. Set up payment wallet with appropriate security controls +2. Integrate payment option into patient billing system +3. Generate unique payment references per invoice +4. Monitor incoming payments via webhook +5. Auto-reconcile with billing system using metadata + +### For Medical Tourism Facilitators + +1. Collect patient wallet addresses during booking +2. Send deposit requests with procedure details +3. Confirm deposits instantly before provider booking +4. Coordinate final payment before patient travel + +### For Insurers + +1. Configure claims payment system for stablecoin disbursement +2. Batch provider payments with claim metadata +3. Reduce international payment costs and delays +4. Maintain audit trail for regulatory compliance + +## Use Cases + +### Medical Tourism + +Patients traveling for procedures pay deposits and final bills without international wire complexity. Providers confirm payment before patient arrival. + +### International Insurance + +Global insurers settle claims with providers across multiple countries in a single batch, reducing per-payment costs from $50+ to ~$0.001. + +### Expatriate Healthcare + +Expats accessing care in their country of residence pay without routing through home country banks. + +### Telemedicine + +International telemedicine consultations collect payment instantly without cross-border card processing fees. + +### Clinical Trial Payments + +Research organizations compensate international trial participants without wire overhead. + +## Compliance Considerations + +- **HIPAA**: Transaction metadata should not include protected health information in public fields +- **Patient Records**: Link transaction hashes to internal billing records for audit trail +- **Insurance Regulations**: Maintain documentation per jurisdiction requirements +- **AML/KYC**: Implement appropriate patient verification for large transactions + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/hold-dollars-without-us-bank.mdx b/src/pages/guides/hold-dollars-without-us-bank.mdx new file mode 100644 index 00000000..782614aa --- /dev/null +++ b/src/pages/guides/hold-dollars-without-us-bank.mdx @@ -0,0 +1,64 @@ +--- +title: How to Hold US Dollars Without a US Bank Account +description: Access dollar-denominated savings globally using stablecoins on Tempo. No US bank required—just an internet connection and a wallet. +--- + +# How to Hold US Dollars Without a US Bank Account + +For billions of people worldwide, accessing US dollars is difficult or impossible through traditional banking. Stablecoins change this—offering dollar-denominated savings to anyone with an internet connection. + +## The Problem with Traditional Dollar Access + +- **Geographic restrictions**: US bank accounts typically require US residency +- **High fees**: International wire transfers and currency conversion eat into savings +- **Limited access**: Many countries have capital controls or unstable local currencies +- **Slow transfers**: Cross-border payments take days and involve intermediaries + +## Stablecoins: Global Dollar Access + +Stablecoins like USDC and USDT are digital dollars backed 1:1 by reserves. They provide: + +- **Dollar stability**: Hold value pegged to USD, protected from local currency volatility +- **No geographic limits**: Anyone with a wallet can hold and transfer stablecoins +- **Self-custody**: You control your funds with your private keys +- **Instant transfers**: Send and receive globally in seconds + +## Why Tempo for Global Dollar Holdings + +[Tempo](https://docs.tempo.xyz/learn/tempo) is purpose-built for stablecoin payments and holdings, making it ideal for international users: + +### Pay Fees in Stablecoins + +Other blockchains require holding volatile cryptocurrencies for gas fees. On Tempo, you pay transaction fees in the same stablecoins you hold—keeping your entire balance in dollars. + +### Sub-Cent Fees + +High fees defeat the purpose of accessible savings. Tempo's sub-cent transaction costs make it practical to: + +- Receive remittances without losing value to fees +- Make small, regular savings deposits +- Transfer between wallets affordably + +### Instant Settlement + +Payments finalize in seconds. When you receive dollars from family abroad or need to move funds, there's no waiting. + +### Payment Metadata + +Attach context to every transaction—references, notes, or invoice data. This makes it easier to track remittances, payments, and savings. + +## How to Get Started + +1. **Create a wallet**: Download any EVM-compatible wallet (MetaMask, Rainbow, Rabby) +2. **Connect to Tempo**: [Follow the quickstart guide](https://docs.tempo.xyz/quickstart) +3. **Receive stablecoins**: Get USDC or USDT from exchanges, on-ramps, or direct transfers +4. **Hold and use**: Your dollars are now accessible 24/7 from anywhere + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/how-to-accept-crypto-payments.mdx b/src/pages/guides/how-to-accept-crypto-payments.mdx new file mode 100644 index 00000000..19b6c1a1 --- /dev/null +++ b/src/pages/guides/how-to-accept-crypto-payments.mdx @@ -0,0 +1,71 @@ +--- +title: "How to Accept Crypto Payments" +description: "Set up your business to accept stablecoin payments on Tempo. Integration options from simple wallet addresses to full API implementations." +--- + +# How to Accept Crypto Payments + +Accept stablecoin payments from customers with instant settlement and automatic reconciliation. + +## Integration Options + +Choose the approach that fits your business: + +### Option 1: Simple Wallet Address + +Share your Tempo address for customers to send payments directly. Best for: + +- Freelancers and contractors +- Small businesses +- Invoice-based billing + +### Option 2: Payment Links + +Generate unique payment links with pre-filled amounts and metadata: + +``` +https://pay.tempo.xyz/to/YOUR_ADDRESS?amount=100¤cy=pathUSD&ref=INV-001 +``` + +### Option 3: API Integration + +Full programmatic control for automated payment processing: + +- Generate unique addresses per transaction +- Webhook notifications on payment receipt +- Automatic metadata extraction +- Multi-currency support + +## Setup Steps + +### 1. Create a Tempo Wallet + +Set up a business wallet to receive payments. + +### 2. Configure Notifications + +Set up webhooks to get notified when payments arrive. + +### 3. Integrate with Your Systems + +Connect to your invoicing, ERP, or e-commerce platform. + +### 4. Test the Flow + +Process test payments to verify your integration. + +## Benefits + +- **Instant settlement** — Funds available in ~0.5 seconds +- **Low fees** — ~$0.001 per transaction +- **No chargebacks** — Payments are final +- **Global reach** — Accept payments from anywhere + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/how-to-add-payment-metadata.mdx b/src/pages/guides/how-to-add-payment-metadata.mdx new file mode 100644 index 00000000..2e2de729 --- /dev/null +++ b/src/pages/guides/how-to-add-payment-metadata.mdx @@ -0,0 +1,316 @@ +--- +title: "How to Add Payment Metadata" +description: "Attach invoice IDs, order numbers, and custom data to Tempo transactions. Enable automatic reconciliation and ERP integration with on-chain metadata." +--- + +# How to Add Payment Metadata + +Embed structured data directly in transactions—invoice numbers, order IDs, customer references—enabling automatic reconciliation and audit trails. + +## The Problem + +Standard ERC-20 transfers contain only sender, recipient, and amount. Matching payments to invoices requires manual lookup or fragile off-chain databases. + +## The Solution + +Encode metadata in transaction calldata or use Tempo's metadata extension. Every payment carries its context on-chain, making reconciliation automatic. + +## Implementation + +### Install Dependencies + +```bash +npm install viem wagmi @tanstack/react-query +``` + +### Define Metadata Types + +```typescript +import { Address } from 'viem'; + +interface PaymentMetadata { + invoiceId?: string; + orderId?: string; + customerId?: string; + memo?: string; + reference?: string; + custom?: Record; +} + +interface PaymentWithMetadata { + recipient: Address; + token: Address; + amount: bigint; + metadata: PaymentMetadata; +} +``` + +### Encode Metadata in Calldata + +```typescript +import { encodeFunctionData, stringToHex, concatHex } from 'viem'; + +const transferWithMetadataAbi = [ + { + name: 'transferWithMetadata', + type: 'function', + stateMutability: 'nonpayable', + inputs: [ + { name: 'to', type: 'address' }, + { name: 'amount', type: 'uint256' }, + { name: 'metadata', type: 'bytes' }, + ], + outputs: [{ name: '', type: 'bool' }], + }, +] as const; + +function encodeMetadata(metadata: PaymentMetadata): `0x${string}` { + const json = JSON.stringify(metadata); + return stringToHex(json); +} + +function buildTransferWithMetadata( + to: Address, + amount: bigint, + metadata: PaymentMetadata +): `0x${string}` { + return encodeFunctionData({ + abi: transferWithMetadataAbi, + functionName: 'transferWithMetadata', + args: [to, amount, encodeMetadata(metadata)], + }); +} +``` + +### Simple Approach: Memo in Standard Transfer + +```typescript +import { encodeFunctionData, erc20Abi, toHex } from 'viem'; + +// For tokens without metadata support, append to calldata +function buildTransferWithMemo( + to: Address, + amount: bigint, + memo: string +): { to: Address; data: `0x${string}` } { + const transferData = encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [to, amount], + }); + + // Append memo as hex (ignored by contract, stored on-chain) + const memoHex = toHex(memo); + const dataWithMemo = `${transferData}${memoHex.slice(2)}` as `0x${string}`; + + return { to, data: dataWithMemo }; +} +``` + +### Execute Payment with Metadata + +```typescript +import { useWriteContract, useSendTransaction } from 'wagmi'; + +function usePaymentWithMetadata() { + const { sendTransactionAsync } = useSendTransaction(); + + async function send(payment: PaymentWithMetadata) { + const { to, data } = buildTransferWithMemo( + payment.recipient, + payment.amount, + JSON.stringify(payment.metadata) + ); + + const hash = await sendTransactionAsync({ + to: payment.token, + data, + }); + + return hash; + } + + return { send }; +} +``` + +### Decode Metadata from Transaction + +```typescript +import { createPublicClient, http, hexToString, slice } from 'viem'; +import { tempo } from './chains'; + +const publicClient = createPublicClient({ + chain: tempo, + transport: http(), +}); + +async function extractMetadata( + txHash: `0x${string}` +): Promise { + const tx = await publicClient.getTransaction({ hash: txHash }); + + if (!tx.input || tx.input.length <= 138) { + return null; // No metadata appended + } + + // Standard transfer is 68 bytes (136 hex chars + 0x) + // Metadata starts after that + const metadataHex = slice(tx.input, 68); + + try { + const metadataJson = hexToString(metadataHex); + return JSON.parse(metadataJson); + } catch { + return null; + } +} + +// Usage +const metadata = await extractMetadata('0xabc123...'); +console.log(metadata?.invoiceId); // "INV-2024-001" +``` + +### Index Payments by Metadata + +```typescript +interface IndexedPayment { + hash: `0x${string}`; + from: Address; + to: Address; + amount: bigint; + token: Address; + metadata: PaymentMetadata; + timestamp: number; +} + +class PaymentIndex { + private byInvoice: Map = new Map(); + private byOrder: Map = new Map(); + private byCustomer: Map = new Map(); + + index(payment: IndexedPayment): void { + const { metadata } = payment; + + if (metadata.invoiceId) { + const existing = this.byInvoice.get(metadata.invoiceId) || []; + this.byInvoice.set(metadata.invoiceId, [...existing, payment]); + } + + if (metadata.orderId) { + const existing = this.byOrder.get(metadata.orderId) || []; + this.byOrder.set(metadata.orderId, [...existing, payment]); + } + + if (metadata.customerId) { + const existing = this.byCustomer.get(metadata.customerId) || []; + this.byCustomer.set(metadata.customerId, [...existing, payment]); + } + } + + findByInvoice(invoiceId: string): IndexedPayment[] { + return this.byInvoice.get(invoiceId) || []; + } + + findByCustomer(customerId: string): IndexedPayment[] { + return this.byCustomer.get(customerId) || []; + } +} +``` + +### ERP Integration Example + +```typescript +interface ERPInvoice { + id: string; + amount: number; + currency: string; + status: 'pending' | 'paid' | 'overdue'; +} + +async function reconcilePayment( + payment: IndexedPayment, + erp: ERPClient +): Promise { + const { invoiceId } = payment.metadata; + if (!invoiceId) return; + + const invoice = await erp.getInvoice(invoiceId); + if (!invoice) { + console.error(`Invoice ${invoiceId} not found`); + return; + } + + // Convert payment amount to invoice currency + const paidAmount = Number(payment.amount) / 1e6; // USDC decimals + + if (paidAmount >= invoice.amount) { + await erp.markInvoicePaid(invoiceId, { + transactionHash: payment.hash, + paidAt: new Date(payment.timestamp * 1000), + paidAmount, + }); + } else { + await erp.recordPartialPayment(invoiceId, { + transactionHash: payment.hash, + amount: paidAmount, + }); + } +} +``` + +### Webhook Handler with Metadata + +```typescript +import { Hono } from 'hono'; + +const app = new Hono(); + +app.post('/webhooks/payments', async (c) => { + const event = await c.req.json(); + + if (event.type === 'payment.received') { + const metadata = await extractMetadata(event.transactionHash); + + if (metadata?.invoiceId) { + // Auto-reconcile with accounting system + await reconcilePayment( + { + hash: event.transactionHash, + from: event.from, + to: event.to, + amount: BigInt(event.amount), + token: event.token, + metadata, + timestamp: event.timestamp, + }, + erpClient + ); + } + + if (metadata?.orderId) { + // Trigger order fulfillment + await fulfillOrder(metadata.orderId); + } + } + + return c.json({ received: true }); +}); +``` + +## Best Practices + +1. **Keep metadata compact** — On-chain storage costs gas; use IDs instead of full objects +2. **Use consistent schemas** — Define a standard structure for your organization +3. **Validate on decode** — Always handle malformed or missing metadata gracefully +4. **Index for lookup** — Build off-chain indexes for fast metadata queries +5. **Include timestamps** — Add creation time for audit trail completeness + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/how-to-batch-payments.mdx b/src/pages/guides/how-to-batch-payments.mdx new file mode 100644 index 00000000..668e10b1 --- /dev/null +++ b/src/pages/guides/how-to-batch-payments.mdx @@ -0,0 +1,321 @@ +--- +title: "How to Batch Payments" +description: "Execute mass payouts in a single transaction on Tempo. Implement multicall patterns for payroll, affiliate payouts, and bulk transfers with sub-cent fees." +--- + +# How to Batch Payments + +Send payments to hundreds of recipients in a single transaction using multicall patterns, reducing gas costs and simplifying payroll operations. + +## The Problem + +Processing payroll or affiliate payouts individually means submitting hundreds of transactions, each with its own gas cost and confirmation time. + +## The Solution + +Batch multiple transfers into a single transaction using multicall. On Tempo, this means one transaction with ~0.5s finality that pays all recipients, regardless of count. + +## Implementation + +### Install Dependencies + +```bash +npm install viem wagmi @tanstack/react-query +``` + +### Define Payout Types + +```typescript +import { Address } from 'viem'; + +interface PayoutRecipient { + address: Address; + amount: bigint; + memo?: string; +} + +interface BatchPayout { + id: string; + token: Address; + recipients: PayoutRecipient[]; + totalAmount: bigint; + status: 'pending' | 'processing' | 'completed' | 'failed'; +} +``` + +### Multicall Contract ABI + +```typescript +const multicallAbi = [ + { + name: 'aggregate3', + type: 'function', + stateMutability: 'payable', + inputs: [ + { + name: 'calls', + type: 'tuple[]', + components: [ + { name: 'target', type: 'address' }, + { name: 'allowFailure', type: 'bool' }, + { name: 'callData', type: 'bytes' }, + ], + }, + ], + outputs: [ + { + name: 'returnData', + type: 'tuple[]', + components: [ + { name: 'success', type: 'bool' }, + { name: 'returnData', type: 'bytes' }, + ], + }, + ], + }, +] as const; + +// Tempo Multicall3 address +const MULTICALL_ADDRESS = '0xcA11bde05977b3631167028862bE2a173976CA11'; +``` + +### Build Batch Transfer Calldata + +```typescript +import { encodeFunctionData, erc20Abi } from 'viem'; + +interface MulticallItem { + target: Address; + allowFailure: boolean; + callData: `0x${string}`; +} + +function buildBatchTransferCalls( + token: Address, + recipients: PayoutRecipient[] +): MulticallItem[] { + return recipients.map((recipient) => ({ + target: token, + allowFailure: false, + callData: encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [recipient.address, recipient.amount], + }), + })); +} +``` + +### Execute Batch Payout + +```typescript +import { useWriteContract, useWaitForTransactionReceipt } from 'wagmi'; + +function useBatchPayout() { + const { writeContractAsync } = useWriteContract(); + + async function executeBatch( + token: Address, + recipients: PayoutRecipient[] + ): Promise { + const calls = buildBatchTransferCalls(token, recipients); + + const hash = await writeContractAsync({ + address: MULTICALL_ADDRESS, + abi: multicallAbi, + functionName: 'aggregate3', + args: [calls], + }); + + return hash; + } + + return { executeBatch }; +} +``` + +### Validate Before Sending + +```typescript +import { createPublicClient, http, erc20Abi, formatUnits } from 'viem'; +import { tempo } from './chains'; + +const publicClient = createPublicClient({ + chain: tempo, + transport: http(), +}); + +async function validateBatchPayout( + sender: Address, + token: Address, + recipients: PayoutRecipient[] +): Promise<{ valid: boolean; error?: string }> { + // Calculate total + const total = recipients.reduce((sum, r) => sum + r.amount, 0n); + + // Check balance + const balance = await publicClient.readContract({ + address: token, + abi: erc20Abi, + functionName: 'balanceOf', + args: [sender], + }); + + if (balance < total) { + return { + valid: false, + error: `Insufficient balance. Need ${formatUnits(total, 6)}, have ${formatUnits(balance, 6)}`, + }; + } + + // Check for duplicates + const addresses = recipients.map((r) => r.address.toLowerCase()); + const uniqueAddresses = new Set(addresses); + if (uniqueAddresses.size !== addresses.length) { + return { valid: false, error: 'Duplicate recipient addresses' }; + } + + // Check for zero amounts + const hasZeroAmount = recipients.some((r) => r.amount === 0n); + if (hasZeroAmount) { + return { valid: false, error: 'Cannot send zero amount' }; + } + + return { valid: true }; +} +``` + +### Payroll Use Case + +```typescript +import { parseUnits } from 'viem'; + +interface Employee { + id: string; + name: string; + wallet: Address; + salary: string; // e.g., "5000.00" +} + +function buildPayroll( + employees: Employee[], + tokenDecimals: number = 6 +): PayoutRecipient[] { + return employees.map((emp) => ({ + address: emp.wallet, + amount: parseUnits(emp.salary, tokenDecimals), + memo: `Salary - ${emp.name}`, + })); +} + +// Example usage +async function runPayroll(employees: Employee[], usdcAddress: Address) { + const recipients = buildPayroll(employees); + + const validation = await validateBatchPayout( + '0xTreasuryAddress...', + usdcAddress, + recipients + ); + + if (!validation.valid) { + throw new Error(validation.error); + } + + const { executeBatch } = useBatchPayout(); + const hash = await executeBatch(usdcAddress, recipients); + + console.log(`Payroll processed: ${hash}`); + console.log(`Paid ${employees.length} employees in one transaction`); +} +``` + +### Chunk Large Batches + +```typescript +function chunkRecipients( + recipients: PayoutRecipient[], + maxPerBatch: number = 100 +): PayoutRecipient[][] { + const chunks: PayoutRecipient[][] = []; + + for (let i = 0; i < recipients.length; i += maxPerBatch) { + chunks.push(recipients.slice(i, i + maxPerBatch)); + } + + return chunks; +} + +async function executeLargeBatch( + token: Address, + recipients: PayoutRecipient[] +): Promise { + const chunks = chunkRecipients(recipients, 100); + const hashes: string[] = []; + + for (const chunk of chunks) { + const { executeBatch } = useBatchPayout(); + const hash = await executeBatch(token, chunk); + hashes.push(hash); + } + + return hashes; +} +``` + +### CSV Import Helper + +```typescript +import { parseUnits, isAddress } from 'viem'; + +interface CSVRow { + address: string; + amount: string; + memo?: string; +} + +function parsePayoutCSV( + rows: CSVRow[], + decimals: number = 6 +): { recipients: PayoutRecipient[]; errors: string[] } { + const recipients: PayoutRecipient[] = []; + const errors: string[] = []; + + rows.forEach((row, index) => { + if (!isAddress(row.address)) { + errors.push(`Row ${index + 1}: Invalid address`); + return; + } + + try { + const amount = parseUnits(row.amount, decimals); + recipients.push({ + address: row.address as Address, + amount, + memo: row.memo, + }); + } catch { + errors.push(`Row ${index + 1}: Invalid amount "${row.amount}"`); + } + }); + + return { recipients, errors }; +} +``` + +## Best Practices + +1. **Validate all recipients** — Check addresses and amounts before submitting +2. **Chunk large batches** — Keep batches under 100 recipients to avoid gas limits +3. **Set allowFailure wisely** — Use `false` for critical payouts, `true` for optional ones +4. **Log everything** — Record batch details for reconciliation and auditing +5. **Test with small batches** — Verify logic with 2-3 recipients before scaling + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/how-to-build-a-payment-link.mdx b/src/pages/guides/how-to-build-a-payment-link.mdx new file mode 100644 index 00000000..83da4cc2 --- /dev/null +++ b/src/pages/guides/how-to-build-a-payment-link.mdx @@ -0,0 +1,214 @@ +--- +title: "How to Build a Payment Link" +description: "Create shareable payment URLs and QR codes on Tempo. Encode amounts, memos, and metadata into links for instant stablecoin payments with ~0.5s finality." +--- + +# How to Build a Payment Link + +Generate shareable payment links that encode recipient, amount, and metadata—enabling one-click stablecoin payments without requiring customers to manually enter details. + +## The Problem + +Collecting payments typically requires sharing wallet addresses and amounts separately, leading to copy-paste errors, incorrect amounts, and lost payment context. + +## The Solution + +Payment links encode all transaction details into a single URL or QR code. When opened, the user's wallet pre-fills the recipient, amount, and memo—reducing friction and eliminating errors. + +## Implementation + +### Install Dependencies + +```bash +npm install viem wagmi @tanstack/react-query qrcode +``` + +### Define the Payment Link Schema + +```typescript +import { Address, parseUnits, encodeFunctionData } from 'viem'; + +interface PaymentLinkParams { + recipient: Address; + token: Address; + amount: string; + decimals: number; + memo?: string; + metadata?: Record; +} + +const TEMPO_CHAIN_ID = 98985; + +function buildPaymentLink(params: PaymentLinkParams): string { + const { recipient, token, amount, decimals, memo, metadata } = params; + + const amountWei = parseUnits(amount, decimals); + + const searchParams = new URLSearchParams({ + chainId: TEMPO_CHAIN_ID.toString(), + token, + recipient, + amount: amountWei.toString(), + }); + + if (memo) { + searchParams.set('memo', memo); + } + + if (metadata) { + searchParams.set('metadata', JSON.stringify(metadata)); + } + + return `https://pay.tempo.xyz?${searchParams.toString()}`; +} +``` + +### Generate QR Codes + +```typescript +import QRCode from 'qrcode'; + +async function generatePaymentQR( + params: PaymentLinkParams +): Promise { + const link = buildPaymentLink(params); + const qrDataUrl = await QRCode.toDataURL(link, { + width: 256, + margin: 2, + color: { + dark: '#000000', + light: '#ffffff', + }, + }); + return qrDataUrl; +} + +// Usage +const qrCode = await generatePaymentQR({ + recipient: '0x1234...abcd', + token: '0x...', // pathUSD or other stablecoin on Tempo + amount: '25.00', + decimals: 6, + memo: 'Invoice #INV-2024-001', + metadata: { + orderId: 'order-789', + customerId: 'cust-456', + }, +}); +``` + +### Parse Payment Links + +```typescript +function parsePaymentLink(url: string): PaymentLinkParams | null { + try { + const parsed = new URL(url); + const params = parsed.searchParams; + + const recipient = params.get('recipient') as Address; + const token = params.get('token') as Address; + const amount = params.get('amount'); + const memo = params.get('memo') || undefined; + const metadataRaw = params.get('metadata'); + + if (!recipient || !token || !amount) { + return null; + } + + return { + recipient, + token, + amount, + decimals: 6, // Resolve from token contract + memo, + metadata: metadataRaw ? JSON.parse(metadataRaw) : undefined, + }; + } catch { + return null; + } +} +``` + +### Execute Payment from Link + +```typescript +import { useWriteContract, useAccount } from 'wagmi'; +import { erc20Abi } from 'viem'; + +function usePayFromLink() { + const { address } = useAccount(); + const { writeContractAsync } = useWriteContract(); + + async function pay(link: string) { + const params = parsePaymentLink(link); + if (!params) throw new Error('Invalid payment link'); + + const hash = await writeContractAsync({ + address: params.token, + abi: erc20Abi, + functionName: 'transfer', + args: [params.recipient, BigInt(params.amount)], + }); + + return hash; + } + + return { pay }; +} +``` + +### React Component Example + +```typescript +import { useState } from 'react'; + +function PaymentLinkGenerator() { + const [link, setLink] = useState(''); + const [qrCode, setQrCode] = useState(''); + + async function createLink() { + const params: PaymentLinkParams = { + recipient: '0x1234...abcd', + token: '0x...', + amount: '100.00', + decimals: 6, + memo: 'Payment for services', + }; + + const paymentLink = buildPaymentLink(params); + const qr = await generatePaymentQR(params); + + setLink(paymentLink); + setQrCode(qr); + } + + return ( +
+ + {link && ( +
+ + Payment QR Code +
+ )} +
+ ); +} +``` + +## Best Practices + +1. **Validate addresses** — Always verify recipient addresses are valid before encoding +2. **Set expiration** — Include a timestamp for time-sensitive payments +3. **Use checksummed addresses** — Prevent address typos with EIP-55 checksums +4. **Encode metadata carefully** — URL-encode special characters in memo fields +5. **Test on testnet** — Verify link parsing before production deployment + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/how-to-create-recurring-payments.mdx b/src/pages/guides/how-to-create-recurring-payments.mdx new file mode 100644 index 00000000..480b94bf --- /dev/null +++ b/src/pages/guides/how-to-create-recurring-payments.mdx @@ -0,0 +1,286 @@ +--- +title: "How to Create Recurring Payments" +description: "Build subscription billing with stablecoins on Tempo. Implement payment schedules, allowance-based pulls, and retry logic for reliable recurring charges." +--- + +# How to Create Recurring Payments + +Implement subscription billing and scheduled payments using stablecoin allowances and automated payment pulls on Tempo. + +## The Problem + +Traditional subscription billing on blockchain requires users to manually send payments each cycle, leading to failed renewals and churn. + +## The Solution + +Use ERC-20 allowances to enable merchants to pull authorized amounts on a schedule. Combined with Tempo's instant finality and low fees, this enables reliable recurring billing. + +## Implementation + +### Install Dependencies + +```bash +npm install viem wagmi @tanstack/react-query +``` + +### Define Subscription Types + +```typescript +import { Address } from 'viem'; + +interface Subscription { + id: string; + subscriber: Address; + merchant: Address; + token: Address; + amount: bigint; + interval: number; // seconds between payments + nextPaymentDue: number; // unix timestamp + totalPayments: number; + paymentsProcessed: number; + status: 'active' | 'paused' | 'cancelled'; +} + +interface SubscriptionPlan { + name: string; + amount: string; + interval: 'weekly' | 'monthly' | 'yearly'; + token: Address; +} +``` + +### Set Up Allowance (Subscriber Side) + +```typescript +import { useWriteContract } from 'wagmi'; +import { erc20Abi, parseUnits, maxUint256 } from 'viem'; + +function useApproveSubscription() { + const { writeContractAsync } = useWriteContract(); + + async function approve( + token: Address, + spender: Address, // Merchant or payment contract + maxAmount?: bigint + ) { + const hash = await writeContractAsync({ + address: token, + abi: erc20Abi, + functionName: 'approve', + args: [spender, maxAmount ?? maxUint256], + }); + + return hash; + } + + return { approve }; +} +``` + +### Pull Payments (Merchant Side) + +```typescript +import { createWalletClient, http, erc20Abi } from 'viem'; +import { tempo } from './chains'; + +const merchantWallet = createWalletClient({ + chain: tempo, + transport: http(), +}); + +async function pullSubscriptionPayment( + subscription: Subscription, + merchantPrivateKey: `0x${string}` +) { + const hash = await merchantWallet.writeContract({ + account: merchantPrivateKey, + address: subscription.token, + abi: erc20Abi, + functionName: 'transferFrom', + args: [ + subscription.subscriber, + subscription.merchant, + subscription.amount, + ], + }); + + return hash; +} +``` + +### Payment Scheduler with Retry Logic + +```typescript +interface RetryConfig { + maxAttempts: number; + backoffMs: number; + backoffMultiplier: number; +} + +async function processSubscriptionWithRetry( + subscription: Subscription, + config: RetryConfig = { + maxAttempts: 3, + backoffMs: 1000, + backoffMultiplier: 2, + } +): Promise<{ success: boolean; hash?: string; error?: string }> { + let attempt = 0; + let delay = config.backoffMs; + + while (attempt < config.maxAttempts) { + try { + const hash = await pullSubscriptionPayment( + subscription, + process.env.MERCHANT_PRIVATE_KEY as `0x${string}` + ); + + // Tempo's ~0.5s finality means we can confirm quickly + await waitForTransactionReceipt(hash); + + return { success: true, hash }; + } catch (error) { + attempt++; + + if (attempt >= config.maxAttempts) { + return { + success: false, + error: `Failed after ${attempt} attempts: ${error}`, + }; + } + + await sleep(delay); + delay *= config.backoffMultiplier; + } + } + + return { success: false, error: 'Max attempts reached' }; +} + +function sleep(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); +} +``` + +### Subscription Manager + +```typescript +class SubscriptionManager { + private subscriptions: Map = new Map(); + + async processScheduledPayments(): Promise { + const now = Math.floor(Date.now() / 1000); + + for (const [id, sub] of this.subscriptions) { + if (sub.status !== 'active') continue; + if (sub.nextPaymentDue > now) continue; + + const result = await processSubscriptionWithRetry(sub); + + if (result.success) { + sub.paymentsProcessed++; + sub.nextPaymentDue += sub.interval; + + // Check if subscription is complete + if (sub.totalPayments > 0 && + sub.paymentsProcessed >= sub.totalPayments) { + sub.status = 'cancelled'; + } + + await this.notifyPaymentSuccess(sub, result.hash!); + } else { + await this.notifyPaymentFailed(sub, result.error!); + // Optionally pause after failures + sub.status = 'paused'; + } + } + } + + private async notifyPaymentSuccess( + sub: Subscription, + hash: string + ): Promise { + // Send webhook, email, etc. + } + + private async notifyPaymentFailed( + sub: Subscription, + error: string + ): Promise { + // Notify subscriber of failed payment + } +} +``` + +### Check Allowance Before Pulling + +```typescript +import { createPublicClient, http, erc20Abi } from 'viem'; + +const publicClient = createPublicClient({ + chain: tempo, + transport: http(), +}); + +async function hasAllowance( + token: Address, + owner: Address, + spender: Address, + requiredAmount: bigint +): Promise { + const allowance = await publicClient.readContract({ + address: token, + abi: erc20Abi, + functionName: 'allowance', + args: [owner, spender], + }); + + return allowance >= requiredAmount; +} +``` + +### Interval Helpers + +```typescript +const INTERVALS = { + weekly: 7 * 24 * 60 * 60, + monthly: 30 * 24 * 60 * 60, + yearly: 365 * 24 * 60 * 60, +} as const; + +function createSubscription( + plan: SubscriptionPlan, + subscriber: Address, + merchant: Address +): Subscription { + return { + id: crypto.randomUUID(), + subscriber, + merchant, + token: plan.token, + amount: parseUnits(plan.amount, 6), + interval: INTERVALS[plan.interval], + nextPaymentDue: Math.floor(Date.now() / 1000), + totalPayments: 0, // 0 = unlimited + paymentsProcessed: 0, + status: 'active', + }; +} +``` + +## Best Practices + +1. **Check balance before pulling** — Verify subscriber has sufficient funds to avoid wasted gas +2. **Monitor allowance changes** — Subscribers can revoke anytime; handle gracefully +3. **Implement dunning logic** — Retry failed payments with increasing delays before cancelling +4. **Send payment reminders** — Notify subscribers before scheduled pulls +5. **Use dedicated payment contracts** — For complex billing, deploy a subscription contract + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/how-to-handle-refunds.mdx b/src/pages/guides/how-to-handle-refunds.mdx new file mode 100644 index 00000000..dd9a64aa --- /dev/null +++ b/src/pages/guides/how-to-handle-refunds.mdx @@ -0,0 +1,434 @@ +--- +title: "How to Handle Refunds" +description: "Implement stablecoin refund patterns on Tempo. Build reverse payments, partial refunds, and recipient validation with instant settlement and sub-cent fees." +--- + +# How to Handle Refunds + +Process refunds reliably by reversing the original payment flow—full or partial—with proper recipient validation and audit trails. + +## The Problem + +Unlike credit cards, blockchain payments are push-based and irreversible. There's no built-in chargeback or refund mechanism. + +## The Solution + +Implement refunds as new transactions from merchant to customer. Track the original payment to calculate amounts and validate recipients. + +## Implementation + +### Install Dependencies + +```bash +npm install viem wagmi @tanstack/react-query +``` + +### Define Refund Types + +```typescript +import { Address } from 'viem'; + +type RefundStatus = 'pending' | 'processing' | 'completed' | 'failed'; + +interface OriginalPayment { + txHash: `0x${string}`; + from: Address; + to: Address; + amount: bigint; + token: Address; + timestamp: number; + metadata?: Record; +} + +interface RefundRequest { + id: string; + originalPayment: OriginalPayment; + refundAmount: bigint; + reason: string; + status: RefundStatus; + refundTxHash?: `0x${string}`; + createdAt: Date; + processedAt?: Date; +} +``` + +### Validate Original Payment + +```typescript +import { createPublicClient, http, erc20Abi, decodeEventLog } from 'viem'; +import { tempo } from './chains'; + +const publicClient = createPublicClient({ + chain: tempo, + transport: http(), +}); + +async function getOriginalPayment( + txHash: `0x${string}`, + expectedRecipient: Address +): Promise { + const receipt = await publicClient.getTransactionReceipt({ hash: txHash }); + + if (receipt.status !== 'success') { + return null; + } + + // Find Transfer event to our address + for (const log of receipt.logs) { + try { + const decoded = decodeEventLog({ + abi: erc20Abi, + data: log.data, + topics: log.topics, + }); + + if (decoded.eventName === 'Transfer') { + const { from, to, value } = decoded.args as { + from: Address; + to: Address; + value: bigint; + }; + + if (to.toLowerCase() === expectedRecipient.toLowerCase()) { + const block = await publicClient.getBlock({ + blockNumber: receipt.blockNumber, + }); + + return { + txHash, + from, + to, + amount: value, + token: log.address, + timestamp: Number(block.timestamp), + }; + } + } + } catch { + continue; + } + } + + return null; +} +``` + +### Process Full Refund + +```typescript +import { useWriteContract } from 'wagmi'; + +function useRefund() { + const { writeContractAsync } = useWriteContract(); + + async function processFullRefund( + originalPayment: OriginalPayment + ): Promise<`0x${string}`> { + const hash = await writeContractAsync({ + address: originalPayment.token, + abi: erc20Abi, + functionName: 'transfer', + args: [originalPayment.from, originalPayment.amount], + }); + + return hash; + } + + return { processFullRefund }; +} +``` + +### Process Partial Refund + +```typescript +function usePartialRefund() { + const { writeContractAsync } = useWriteContract(); + + async function processPartialRefund( + originalPayment: OriginalPayment, + refundAmount: bigint + ): Promise<{ hash: `0x${string}` } | { error: string }> { + // Validate refund amount + if (refundAmount <= 0n) { + return { error: 'Refund amount must be positive' }; + } + + if (refundAmount > originalPayment.amount) { + return { error: 'Refund cannot exceed original payment' }; + } + + const hash = await writeContractAsync({ + address: originalPayment.token, + abi: erc20Abi, + functionName: 'transfer', + args: [originalPayment.from, refundAmount], + }); + + return { hash }; + } + + return { processPartialRefund }; +} +``` + +### Refund with Metadata + +```typescript +import { encodeFunctionData, toHex } from 'viem'; + +interface RefundMetadata { + originalTxHash: string; + reason: string; + refundId: string; + isPartial: boolean; +} + +function buildRefundWithMetadata( + token: Address, + recipient: Address, + amount: bigint, + metadata: RefundMetadata +): { to: Address; data: `0x${string}` } { + const transferData = encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [recipient, amount], + }); + + const metadataHex = toHex(JSON.stringify(metadata)); + const dataWithMetadata = `${transferData}${metadataHex.slice(2)}` as `0x${string}`; + + return { to: token, data: dataWithMetadata }; +} +``` + +### Refund Manager + +```typescript +class RefundManager { + private refunds: Map = new Map(); + + async createRefundRequest( + originalTxHash: `0x${string}`, + merchantAddress: Address, + amount: bigint | 'full', + reason: string + ): Promise { + // Validate original payment + const original = await getOriginalPayment(originalTxHash, merchantAddress); + + if (!original) { + return { error: 'Original payment not found or not to merchant' }; + } + + // Check if already refunded + const existingRefund = Array.from(this.refunds.values()).find( + (r) => r.originalPayment.txHash === originalTxHash + ); + + if (existingRefund?.status === 'completed') { + return { error: 'Payment already refunded' }; + } + + const refundAmount = amount === 'full' ? original.amount : amount; + + if (refundAmount > original.amount) { + return { error: 'Refund exceeds original payment' }; + } + + const request: RefundRequest = { + id: crypto.randomUUID(), + originalPayment: original, + refundAmount, + reason, + status: 'pending', + createdAt: new Date(), + }; + + this.refunds.set(request.id, request); + return request; + } + + async processRefund( + refundId: string, + sendTransaction: (to: Address, data: `0x${string}`) => Promise<`0x${string}`> + ): Promise<{ success: boolean; hash?: `0x${string}`; error?: string }> { + const request = this.refunds.get(refundId); + + if (!request) { + return { success: false, error: 'Refund not found' }; + } + + if (request.status !== 'pending') { + return { success: false, error: `Invalid status: ${request.status}` }; + } + + request.status = 'processing'; + + try { + const { to, data } = buildRefundWithMetadata( + request.originalPayment.token, + request.originalPayment.from, + request.refundAmount, + { + originalTxHash: request.originalPayment.txHash, + reason: request.reason, + refundId: request.id, + isPartial: request.refundAmount < request.originalPayment.amount, + } + ); + + const hash = await sendTransaction(to, data); + + request.status = 'completed'; + request.refundTxHash = hash; + request.processedAt = new Date(); + + return { success: true, hash }; + } catch (error) { + request.status = 'failed'; + return { success: false, error: String(error) }; + } + } +} +``` + +### Recipient Validation + +```typescript +async function validateRefundRecipient( + originalTxHash: `0x${string}`, + claimedRecipient: Address, + merchantAddress: Address +): Promise<{ valid: boolean; actualRecipient?: Address; error?: string }> { + const original = await getOriginalPayment(originalTxHash, merchantAddress); + + if (!original) { + return { valid: false, error: 'Original payment not found' }; + } + + if (original.from.toLowerCase() !== claimedRecipient.toLowerCase()) { + return { + valid: false, + actualRecipient: original.from, + error: 'Claimed recipient does not match original sender', + }; + } + + return { valid: true, actualRecipient: original.from }; +} +``` + +### API Endpoint Example + +```typescript +import { Hono } from 'hono'; + +const app = new Hono(); +const refundManager = new RefundManager(); + +app.post('/api/refunds', async (c) => { + const { originalTxHash, amount, reason } = await c.req.json(); + + const result = await refundManager.createRefundRequest( + originalTxHash, + MERCHANT_ADDRESS, + amount === 'full' ? 'full' : BigInt(amount), + reason + ); + + if ('error' in result) { + return c.json({ error: result.error }, 400); + } + + return c.json({ + refundId: result.id, + status: result.status, + amount: result.refundAmount.toString(), + recipient: result.originalPayment.from, + }); +}); + +app.post('/api/refunds/:id/process', async (c) => { + const { id } = c.req.param(); + + const result = await refundManager.processRefund(id, async (to, data) => { + // Use your wallet to send + return merchantWallet.sendTransaction({ to, data }); + }); + + if (!result.success) { + return c.json({ error: result.error }, 400); + } + + return c.json({ + success: true, + transactionHash: result.hash, + }); +}); +``` + +### Track Refund History + +```typescript +interface RefundHistory { + originalPayment: OriginalPayment; + refunds: Array<{ + txHash: `0x${string}`; + amount: bigint; + timestamp: number; + reason: string; + }>; + totalRefunded: bigint; + remainingAmount: bigint; +} + +async function getRefundHistory( + originalTxHash: `0x${string}`, + merchantAddress: Address +): Promise { + const original = await getOriginalPayment(originalTxHash, merchantAddress); + if (!original) return null; + + // Query refund transactions from your database + const refunds = await db.refunds.findMany({ + where: { originalTxHash }, + orderBy: { createdAt: 'asc' }, + }); + + const totalRefunded = refunds.reduce( + (sum, r) => sum + BigInt(r.amount), + 0n + ); + + return { + originalPayment: original, + refunds: refunds.map((r) => ({ + txHash: r.txHash as `0x${string}`, + amount: BigInt(r.amount), + timestamp: r.createdAt.getTime() / 1000, + reason: r.reason, + })), + totalRefunded, + remainingAmount: original.amount - totalRefunded, + }; +} +``` + +## Best Practices + +1. **Always validate the original payment** — Confirm the transaction exists and was sent to you +2. **Refund to original sender only** — Never refund to a different address without verification +3. **Track refund history** — Prevent over-refunding by tracking cumulative amounts +4. **Include metadata** — Link refunds to original payments for audit trails +5. **Implement approval workflows** — Require review for large refunds +6. **Set refund windows** — Define time limits for refund eligibility + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/how-to-pay-with-stablecoins.mdx b/src/pages/guides/how-to-pay-with-stablecoins.mdx new file mode 100644 index 00000000..0ab07444 --- /dev/null +++ b/src/pages/guides/how-to-pay-with-stablecoins.mdx @@ -0,0 +1,67 @@ +--- +title: "How to Pay with Stablecoins" +description: "Make stablecoin payments on Tempo for invoices, subscriptions, and purchases. Attach metadata for automatic reconciliation with accounting systems." +--- + +# How to Pay with Stablecoins + +Use Tempo to pay invoices, subscriptions, and vendors with stablecoins. Tempo supports native USD stablecoins like pathUSD, AlphaUSD, BetaUSD, and ThetaUSD. + +## Prerequisites + +- A Tempo wallet with stablecoin balance +- Payment details (address, amount, any required references) + +## Paying an Invoice + +### 1. Get Payment Details + +Your vendor provides: + +- Their Tempo address +- Amount due +- Invoice reference (optional but recommended) + +### 2. Initiate Payment + +Open the Tempo app and start a new transfer: + +- **To** — Vendor's Tempo address +- **Amount** — Invoice amount +- **Metadata** — Invoice number, PO reference, etc. + +### 3. Confirm Payment + +Review details and confirm. The payment finalizes in ~0.5 seconds. + +### 4. Share Confirmation + +Send the transaction ID to your vendor as payment confirmation. + +## Attaching Payment Metadata + +Include references to streamline accounting: + +``` +Invoice: INV-2024-001234 +Vendor ID: V-5678 +Description: Q4 Software License +``` + +This metadata is stored on-chain and can be read by accounting integrations. + +## Recurring Payments + +For subscriptions, set up scheduled payments through the Tempo API. + +## Documentation + +See the payments API in the [Tempo documentation](https://docs.tempo.xyz). + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/how-to-send-stablecoins-on-tempo.mdx b/src/pages/guides/how-to-send-stablecoins-on-tempo.mdx new file mode 100644 index 00000000..ba297b4b --- /dev/null +++ b/src/pages/guides/how-to-send-stablecoins-on-tempo.mdx @@ -0,0 +1,61 @@ +--- +title: "How to Send Stablecoins on Tempo" +description: "Step-by-step guide to sending stablecoins on Tempo. Fast transfers with sub-cent fees, instant finality, and optional payment metadata for invoices." +--- + +# How to Send Stablecoins on Tempo + +Send stablecoins to any address on Tempo with instant finality and minimal fees. + +## Available Stablecoins + +Tempo supports native stablecoins including: + +- **pathUSD** — USD-denominated stablecoin +- **AlphaUSD** — USD-denominated stablecoin +- **BetaUSD** — USD-denominated stablecoin +- **ThetaUSD** — USD-denominated stablecoin + +## Prerequisites + +- A Tempo wallet with a stablecoin balance +- Recipient's Tempo address + +## Steps + +### 1. Connect Your Wallet + +Open the Tempo app and connect your wallet. Passkey wallets can authenticate with Face ID or Touch ID. + +### 2. Enter Transfer Details + +- **Recipient address** — The Tempo address receiving funds +- **Token** — Select your stablecoin (pathUSD, AlphaUSD, etc.) +- **Amount** — How much to send +- **Metadata (optional)** — Add invoice numbers or references + +### 3. Review and Confirm + +Check the transaction details including the fee (approximately $0.001). Confirm with your wallet. + +### 4. Transaction Complete + +Your transfer finalizes in approximately 0.5 seconds. The recipient can use the funds immediately. + +## Adding Payment Metadata + +Include invoice or reference numbers to simplify reconciliation: + +``` +Invoice: INV-2024-001234 +PO: PO-5678 +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/how-to-swap-stablecoins-on-tempo.mdx b/src/pages/guides/how-to-swap-stablecoins-on-tempo.mdx new file mode 100644 index 00000000..3ac90997 --- /dev/null +++ b/src/pages/guides/how-to-swap-stablecoins-on-tempo.mdx @@ -0,0 +1,58 @@ +--- +title: "How to Swap Stablecoins on Tempo" +description: "Convert between USDC, USDT, and other stablecoins using Tempo's built-in DEX. Minimal slippage, sub-cent fees, and instant settlement." +--- + +# How to Swap Stablecoins on Tempo + +Use Tempo's native DEX to convert between stablecoins with minimal fees and instant finality. + +## Prerequisites + +- A Tempo wallet with stablecoin balance +- The stablecoin you want to swap from + +## Steps + +### 1. Open the DEX + +Navigate to the swap interface in the Tempo app or access it directly at the DEX URL. + +### 2. Select Tokens + +- **From** — The stablecoin you're swapping (e.g., USDT) +- **To** — The stablecoin you want (e.g., USDC) + +### 3. Enter Amount + +Input how much you want to swap. The interface shows: + +- Expected output amount +- Exchange rate +- Estimated fee (~$0.001) +- Price impact (minimal for stablecoin pairs) + +### 4. Review and Confirm + +Check the details and confirm the swap with your wallet. + +### 5. Swap Complete + +Your new stablecoins are available immediately—swaps finalize in ~0.5 seconds. + +## Supported Pairs + +- USDC ↔ USDT +- Additional pairs coming soon + +## Documentation + +See the DEX API reference in the [Tempo documentation](https://docs.tempo.xyz). + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/how-to-verify-payment-status.mdx b/src/pages/guides/how-to-verify-payment-status.mdx new file mode 100644 index 00000000..c4fc4d45 --- /dev/null +++ b/src/pages/guides/how-to-verify-payment-status.mdx @@ -0,0 +1,358 @@ +--- +title: "How to Verify Payment Status" +description: "Set up webhooks and polling patterns to confirm Tempo payments. Handle transaction receipts and build reliable payment verification with instant finality." +--- + +# How to Verify Payment Status + +Implement reliable payment confirmation using webhooks for real-time notifications and polling as a fallback, leveraging Tempo's ~0.5s finality. + +## The Problem + +Blockchain confirmations typically require waiting for multiple blocks, creating uncertainty about when payments are truly final. + +## The Solution + +Tempo's instant finality (~0.5s) means a single confirmation is sufficient. Combine webhooks for immediate notification with polling for reliability. + +## Implementation + +### Install Dependencies + +```bash +npm install viem wagmi @tanstack/react-query hono +``` + +### Define Payment Status Types + +```typescript +import { Address } from 'viem'; + +type PaymentStatus = + | 'pending' + | 'confirming' + | 'confirmed' + | 'failed'; + +interface PaymentRecord { + id: string; + expectedAmount: bigint; + token: Address; + recipient: Address; + sender?: Address; + txHash?: `0x${string}`; + status: PaymentStatus; + confirmedAt?: Date; + metadata?: Record; +} +``` + +### Webhook Server Setup + +```typescript +import { Hono } from 'hono'; +import { createHmac } from 'crypto'; + +const app = new Hono(); + +function verifyWebhookSignature( + payload: string, + signature: string, + secret: string +): boolean { + const expected = createHmac('sha256', secret) + .update(payload) + .digest('hex'); + return signature === `sha256=${expected}`; +} + +app.post('/webhooks/tempo', async (c) => { + const signature = c.req.header('x-tempo-signature'); + const payload = await c.req.text(); + + if (!verifyWebhookSignature(payload, signature!, process.env.WEBHOOK_SECRET!)) { + return c.json({ error: 'Invalid signature' }, 401); + } + + const event = JSON.parse(payload); + + switch (event.type) { + case 'payment.pending': + await handlePaymentPending(event); + break; + case 'payment.confirmed': + await handlePaymentConfirmed(event); + break; + case 'payment.failed': + await handlePaymentFailed(event); + break; + } + + return c.json({ received: true }); +}); + +async function handlePaymentConfirmed(event: { + transactionHash: string; + from: Address; + to: Address; + amount: string; + token: Address; + blockNumber: number; + timestamp: number; +}) { + // Update your database + await db.payments.update({ + where: { expectedRecipient: event.to }, + data: { + status: 'confirmed', + txHash: event.transactionHash, + sender: event.from, + confirmedAt: new Date(event.timestamp * 1000), + }, + }); + + // Trigger fulfillment + await fulfillOrder(event.to); +} +``` + +### Polling Pattern + +```typescript +import { createPublicClient, http, erc20Abi } from 'viem'; +import { tempo } from './chains'; + +const publicClient = createPublicClient({ + chain: tempo, + transport: http(), +}); + +async function pollForPayment( + token: Address, + recipient: Address, + expectedAmount: bigint, + options: { + timeoutMs?: number; + intervalMs?: number; + fromBlock?: bigint; + } = {} +): Promise<{ found: boolean; txHash?: `0x${string}` }> { + const { + timeoutMs = 300_000, // 5 minutes + intervalMs = 1_000, // 1 second (Tempo's fast blocks allow this) + fromBlock, + } = options; + + const startBlock = fromBlock ?? await publicClient.getBlockNumber(); + const deadline = Date.now() + timeoutMs; + + while (Date.now() < deadline) { + const logs = await publicClient.getLogs({ + address: token, + event: { + type: 'event', + name: 'Transfer', + inputs: [ + { type: 'address', name: 'from', indexed: true }, + { type: 'address', name: 'to', indexed: true }, + { type: 'uint256', name: 'value' }, + ], + }, + args: { + to: recipient, + }, + fromBlock: startBlock, + toBlock: 'latest', + }); + + for (const log of logs) { + if (log.args.value && log.args.value >= expectedAmount) { + return { found: true, txHash: log.transactionHash }; + } + } + + await new Promise((r) => setTimeout(r, intervalMs)); + } + + return { found: false }; +} +``` + +### Transaction Receipt Verification + +```typescript +async function verifyTransaction( + txHash: `0x${string}`, + expected: { + token: Address; + recipient: Address; + minAmount: bigint; + } +): Promise<{ valid: boolean; error?: string }> { + const receipt = await publicClient.getTransactionReceipt({ hash: txHash }); + + if (receipt.status !== 'success') { + return { valid: false, error: 'Transaction reverted' }; + } + + // Find Transfer event + const transferLog = receipt.logs.find( + (log) => + log.address.toLowerCase() === expected.token.toLowerCase() && + log.topics[0] === '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' + ); + + if (!transferLog) { + return { valid: false, error: 'No transfer event found' }; + } + + // Decode the transfer + const to = `0x${transferLog.topics[2]?.slice(26)}` as Address; + const amount = BigInt(transferLog.data); + + if (to.toLowerCase() !== expected.recipient.toLowerCase()) { + return { valid: false, error: 'Wrong recipient' }; + } + + if (amount < expected.minAmount) { + return { valid: false, error: `Amount too low: ${amount} < ${expected.minAmount}` }; + } + + return { valid: true }; +} +``` + +### React Hook for Payment Status + +```typescript +import { useQuery } from '@tanstack/react-query'; + +function usePaymentStatus(paymentId: string) { + return useQuery({ + queryKey: ['payment-status', paymentId], + queryFn: async () => { + const response = await fetch(`/api/payments/${paymentId}/status`); + return response.json() as Promise; + }, + refetchInterval: (query) => { + // Stop polling once confirmed or failed + const status = query.state.data?.status; + if (status === 'confirmed' || status === 'failed') { + return false; + } + return 2000; // Poll every 2 seconds + }, + }); +} + +// Usage in component +function PaymentStatus({ paymentId }: { paymentId: string }) { + const { data: payment, isLoading } = usePaymentStatus(paymentId); + + if (isLoading) return
Loading...
; + + return ( +
+

Status: {payment?.status}

+ {payment?.txHash && ( + + View transaction + + )} +
+ ); +} +``` + +### WebSocket for Real-time Updates + +```typescript +import { createPublicClient, webSocket, erc20Abi } from 'viem'; +import { tempo } from './chains'; + +const wsClient = createPublicClient({ + chain: tempo, + transport: webSocket('wss://rpc.tempo.xyz'), +}); + +function watchForPayment( + token: Address, + recipient: Address, + onPayment: (txHash: `0x${string}`, amount: bigint) => void +): () => void { + const unwatch = wsClient.watchContractEvent({ + address: token, + abi: erc20Abi, + eventName: 'Transfer', + args: { + to: recipient, + }, + onLogs: (logs) => { + for (const log of logs) { + if (log.args.value) { + onPayment(log.transactionHash, log.args.value); + } + } + }, + }); + + return unwatch; +} + +// Usage +const stopWatching = watchForPayment( + USDC_ADDRESS, + merchantAddress, + (txHash, amount) => { + console.log(`Received ${amount} in tx ${txHash}`); + // Update UI, fulfill order, etc. + } +); + +// Clean up when done +// stopWatching(); +``` + +### Confirmation Handler with Retry + +```typescript +async function confirmPaymentWithRetry( + txHash: `0x${string}`, + maxAttempts: number = 5 +): Promise { + for (let attempt = 0; attempt < maxAttempts; attempt++) { + try { + const receipt = await publicClient.waitForTransactionReceipt({ + hash: txHash, + timeout: 10_000, // 10 seconds per attempt + }); + + return receipt.status === 'success'; + } catch (error) { + if (attempt === maxAttempts - 1) { + throw error; + } + await new Promise((r) => setTimeout(r, 1000 * (attempt + 1))); + } + } + + return false; +} +``` + +## Best Practices + +1. **Use webhooks as primary** — More efficient than polling; fall back to polling if webhooks fail +2. **Verify signatures** — Always validate webhook payloads to prevent spoofing +3. **Implement idempotency** — Handle duplicate webhook deliveries gracefully +4. **Set reasonable timeouts** — With Tempo's ~0.5s finality, short timeouts work +5. **Log everything** — Record all status changes for debugging and auditing + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/index.mdx b/src/pages/guides/index.mdx new file mode 100644 index 00000000..d1cb11bb --- /dev/null +++ b/src/pages/guides/index.mdx @@ -0,0 +1,218 @@ +--- +title: Tempo Guides +description: Practical guides for stablecoins on Tempo. Cross-border payments, swaps, business payments, and developer resources. +--- + +# Tempo Guides + +Practical guides for using stablecoins on Tempo. These pages cover common use cases, features, and step-by-step instructions. + +## FX & Cross-Border Payments + +Send money internationally with stablecoins. Instant settlement, minimal fees. + +### Americas +- [Send Money Internationally with Stablecoins](/guides/send-money-internationally-with-stablecoins) +- [Send Money to Mexico](/guides/send-money-to-mexico-crypto) +- [Send Money to Guatemala](/guides/send-money-to-guatemala-crypto) +- [Send Money to Honduras](/guides/send-money-to-honduras-crypto) +- [Send Money to El Salvador](/guides/send-money-to-el-salvador-crypto) +- [Send Money to Dominican Republic](/guides/send-money-to-dominican-republic-crypto) +- [Send Money to Jamaica](/guides/send-money-to-jamaica-crypto) +- [Send Money to Colombia](/guides/send-money-to-colombia-crypto) +- [Send Money to Brazil](/guides/send-money-to-brazil-crypto) +- [Send Money to Latin America](/guides/send-money-to-latin-america) + +### Europe +- [Convert USD to EUR Without Bank Fees](/guides/convert-usd-to-eur-without-bank-fees) +- [Send Stablecoins to Europe](/guides/send-stablecoins-to-europe) +- [Send Money to the UK](/guides/send-money-to-uk-crypto) +- [Send Money to Germany](/guides/send-money-to-germany-crypto) +- [Send Money to France](/guides/send-money-to-france-crypto) +- [Send Money to Spain](/guides/send-money-to-spain-crypto) +- [Send Money to Italy](/guides/send-money-to-italy-crypto) +- [Send Money to Portugal](/guides/send-money-to-portugal-crypto) +- [Send Money to Poland](/guides/send-money-to-poland-crypto) +- [Send Money to Romania](/guides/send-money-to-romania-crypto) +- [Send Money to Turkey](/guides/send-money-to-turkey-crypto) +- [Cross-Border Payments Without SWIFT](/guides/cross-border-payments-without-swift) + +### Asia +- [Send Money to India](/guides/send-money-to-india-stablecoins) +- [Send Money to the Philippines](/guides/send-money-to-philippines-crypto) +- [Send Money to Vietnam](/guides/send-money-to-vietnam-crypto) +- [Send Money to Indonesia](/guides/send-money-to-indonesia-crypto) +- [Send Money to Bangladesh](/guides/send-money-to-bangladesh-crypto) +- [Send Money to Pakistan](/guides/send-money-to-pakistan-crypto) +- [Send Money to China](/guides/send-money-to-china-crypto) +- [Send Money to South Korea](/guides/send-money-to-south-korea-crypto) +- [Send Money to Japan](/guides/send-money-to-japan-crypto) +- [Send Money to Thailand](/guides/send-money-to-thailand-crypto) +- [Send Money to Malaysia](/guides/send-money-to-malaysia-crypto) +- [Send Money to Singapore](/guides/send-money-to-singapore-crypto) +- [Send Money to Taiwan](/guides/send-money-to-taiwan-crypto) +- [Send Money to Cambodia](/guides/send-money-to-cambodia-crypto) +- [Send Money to Nepal](/guides/send-money-to-nepal-crypto) +- [Send Money to Sri Lanka](/guides/send-money-to-sri-lanka-crypto) +- [Send Money to Myanmar](/guides/send-money-to-myanmar-crypto) + +### Africa & Middle East +- [Send Money to Nigeria](/guides/send-money-to-nigeria-crypto) +- [Send Money to Kenya](/guides/send-money-to-kenya-crypto) +- [Send Money to Ghana](/guides/send-money-to-ghana-crypto) +- [Send Money to Egypt](/guides/send-money-to-egypt-crypto) +- [Send Money to Morocco](/guides/send-money-to-morocco-crypto) +- [Send Money to UAE](/guides/send-money-to-uae-crypto) + +## Stablecoins on Tempo + +### Getting Started +- [How to Send Stablecoins on Tempo](/guides/how-to-send-stablecoins-on-tempo) +- [Accept Stablecoin Payments](/guides/accept-stablecoin-payments) +- [Bridging Stablecoins to Tempo](/guides/bridging-stablecoins-to-tempo) + +### Token Availability +- [USDC on Tempo](/guides/usdc-on-tempo) — Availability status and alternatives +- [USDT on Tempo](/guides/usdt-on-tempo) — Availability status and alternatives +- [DAI on Tempo](/guides/dai-on-tempo) — Availability status and alternatives +- [EURC on Tempo](/guides/eurc-on-tempo) — Availability status and alternatives +- [PYUSD on Tempo](/guides/pyusd-on-tempo) — Availability status and alternatives + +### Stablecoin Swaps +- [Stablecoin Swaps on Tempo](/guides/stablecoin-swaps-on-tempo) +- [Best Stablecoin Exchange](/guides/best-stablecoin-exchange) +- [Convert Stablecoins Without Fees](/guides/convert-stablecoins-without-fees) +- [Cheapest Way to Swap Stablecoins](/guides/cheapest-way-to-swap-stablecoins) + +## Holding & Savings + +- [Where to Hold Stablecoins](/guides/where-to-hold-stablecoins) +- [Stablecoin Savings Account](/guides/stablecoin-savings-account) +- [Hold Dollars Without a US Bank](/guides/hold-dollars-without-us-bank) +- [Best Chain for Stablecoins](/guides/best-chain-for-stablecoins) +- [Enterprise Treasury Guide](/guides/enterprise-treasury-guide) + +## Business Payments + +### Accepting Payments +- [Accept Stablecoin Payments](/guides/accept-stablecoin-payments-for-business) +- [How to Accept Crypto Payments](/guides/how-to-accept-crypto-payments) +- [Crypto Payments for E-commerce](/guides/crypto-payments-for-ecommerce) +- [Crypto Payment Gateway](/guides/crypto-payment-gateway) +- [Stablecoin Accounts Receivable](/guides/stablecoin-accounts-receivable) + +### Making Payments +- [Pay Contractors with Crypto](/guides/pay-contractors-with-crypto) +- [Stablecoin Payroll for Remote Teams](/guides/stablecoin-payroll-for-remote-teams) +- [Crypto Payroll Software](/guides/crypto-payroll-software) +- [Invoice Payments](/guides/invoice-payments-with-stablecoins) +- [Stablecoin Accounts Payable](/guides/stablecoin-accounts-payable) + +### B2B +- [B2B Crypto Payments](/guides/b2b-crypto-payments) +- [Cross-Border B2B Payments](/guides/cross-border-b2b-payments) +- [Reconcile Payments with ERP](/guides/reconcile-crypto-payments-with-erp) + +## Use Cases + +### Remittances +- [Instant Remittance with Stablecoins](/guides/instant-remittance-with-stablecoins) +- [Send Money to the Philippines](/guides/send-money-to-philippines-crypto) + +### Global Payouts +- [Mass Payout Platform](/guides/mass-payout-platform-crypto) +- [Creator Economy Payments](/guides/creator-economy-payments) + +### Embedded Finance +- [Add Payments to Your App](/guides/add-payments-to-your-app) +- [Payment Rails for Fintech](/guides/payment-rails-for-fintech) + +### Microtransactions +- [Micropayments for APIs](/guides/micropayments-for-apis) +- [Streaming Payments](/guides/streaming-payments-crypto) +- [IoT Payments](/guides/iot-payments-blockchain) +- [Content Monetization](/guides/content-monetization-crypto) +- [Gaming Micropayments](/guides/gaming-micropayments) + +### Agentic Commerce +- [AI Agent Payments](/guides/ai-agent-payments) +- [Machine-to-Machine Payments](/guides/machine-to-machine-payments) +- [LLM App Payments](/guides/llm-app-payments) +- [Autonomous Agent Wallets](/guides/autonomous-agent-wallets) +- [Pay-Per-Inference API](/guides/pay-per-inference-api) + +### Tokenized Deposits +- [Real-Time Bank Settlement](/guides/real-time-bank-settlement) +- [Blockchain for Banks](/guides/blockchain-for-banks) + +## Tempo Features + +- [Stablecoin-Native Gas](/guides/stablecoin-native-gas) +- [Sub-Cent Transaction Fees](/guides/sub-cent-transaction-fees) +- [Instant Finality](/guides/instant-finality-blockchain) +- [Payment Metadata](/guides/payment-metadata-blockchain) +- [Dedicated Payment Lanes](/guides/dedicated-payment-lanes) +- [Passkey Authentication](/guides/passkey-wallet-authentication) +- [Stablecoin DEX](/guides/stablecoin-dex) + +## How-To Guides + +- [Send Stablecoins on Tempo](/guides/how-to-send-stablecoins-on-tempo) +- [Swap Stablecoins](/guides/how-to-swap-stablecoins-on-tempo) +- [Bridge Stablecoins to Tempo](/guides/bridging-stablecoins-to-tempo) +- [Pay with Stablecoins](/guides/how-to-pay-with-stablecoins) +- [Accept Crypto Payments](/guides/how-to-accept-crypto-payments) +- [Build a Payment Link](/guides/how-to-build-a-payment-link) + +## By Audience + +- [Freelancer Guide](/guides/freelancer-crypto-payments) +- [Developer Integration Guide](/guides/developer-payment-integration) +- [Enterprise Treasury Guide](/guides/enterprise-treasury-guide) +- [Startup Crypto Payments Guide](/guides/startup-crypto-payments) + +## Technical + +- [Stablecoin Payment Rails Overview](/guides/stablecoin-payment-rails) + +## Comparisons + +### Stablecoins vs Traditional Rails +- [Stablecoins vs ACH](/guides/stablecoins-vs-ach) +- [Stablecoins vs Wire Transfers](/guides/stablecoins-vs-wire-transfer) +- [Stablecoins vs Wise](/guides/stablecoins-vs-wise) +- [Stablecoins vs PayPal](/guides/stablecoins-vs-paypal) + +### Tempo vs Other Chains +- [Tempo vs Ethereum](/guides/tempo-vs-ethereum-for-payments) +- [Tempo vs Solana](/guides/tempo-vs-solana-for-stablecoins) +- [Tempo vs Base](/guides/tempo-vs-base) +- [Tempo vs Tron](/guides/tempo-vs-tron-usdt) + +### Tempo vs Payment Providers +- [Tempo vs SWIFT](/guides/tempo-vs-swift) +- [Tempo vs Wise](/guides/tempo-vs-wise) +- [Tempo vs PayPal](/guides/tempo-vs-paypal) +- [Tempo vs Venmo](/guides/tempo-vs-venmo) + +## Alternatives + +### Traditional Rail Alternatives +- [ACH Alternatives](/guides/ach-alternatives) +- [Wire Transfer Alternatives](/guides/wire-transfer-alternatives) +- [SWIFT Alternatives](/guides/swift-alternatives) +- [Correspondent Banking Alternatives](/guides/correspondent-banking-alternatives) + +### Payment Provider Alternatives +- [PayPal Alternatives](/guides/paypal-alternatives) +- [Wise Alternatives](/guides/wise-alternatives) +- [Western Union Alternatives](/guides/western-union-alternatives) +- [Remittance Alternatives](/guides/remittance-alternatives) + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/instant-finality-blockchain.mdx b/src/pages/guides/instant-finality-blockchain.mdx new file mode 100644 index 00000000..d3982cf3 --- /dev/null +++ b/src/pages/guides/instant-finality-blockchain.mdx @@ -0,0 +1,38 @@ +--- +title: "Instant Finality Blockchain" +description: "Tempo delivers deterministic transaction finality in approximately 0.5 seconds. No waiting for confirmations—payments settle instantly and irreversibly." +--- + +# Instant Finality + +Tempo transactions reach finality in approximately 0.5 seconds. Once confirmed, they're irreversible—no reorgs, no waiting for additional blocks. + +## What Is Finality? + +Finality means a transaction cannot be reversed or reorganized. On many blockchains, you wait for multiple confirmations to be confident a transaction won't be undone. + +## Tempo's Approach + +Tempo uses deterministic finality. When a transaction is included in a block, it's final. Period. + +- **~0.5 second confirmation** — Near-instant settlement +- **No confirmation counting** — One block is enough +- **No reorg risk** — Transactions can't be reversed by chain reorganization + +## Why It Matters + +- **Point-of-sale payments** — Customers don't wait at the register +- **Trading** — Execute strategies that require fast settlement +- **Cross-border payments** — Money arrives in under a second, not days + +## Technical Details + +Read about Tempo's consensus mechanism in the [documentation](https://docs.tempo.xyz). + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/instant-remittance-with-stablecoins.mdx b/src/pages/guides/instant-remittance-with-stablecoins.mdx new file mode 100644 index 00000000..4ec2c7f3 --- /dev/null +++ b/src/pages/guides/instant-remittance-with-stablecoins.mdx @@ -0,0 +1,16 @@ +--- +title: "Instant Remittance with Stablecoins" +description: "Send cross-border remittances in ~0.5s with Tempo's stablecoin-native blockchain. Dedicated payment lanes and ~$0.001 fees make instant global money transfers affordable." +--- + +# Instant Remittance with Stablecoins + +Learn how to build instant cross-border remittance solutions using Tempo's payment infrastructure. + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/across.mdx b/src/pages/guides/integrations/across.mdx new file mode 100644 index 00000000..796cd5a3 --- /dev/null +++ b/src/pages/guides/integrations/across.mdx @@ -0,0 +1,414 @@ +--- +title: "Across Bridge for Tempo" +description: "Cross-chain bridging to and from Tempo with Across Protocol. Fast, secure asset transfers powered by intents." +--- + +# Across Bridge for Tempo + +[Across](https://across.to) is an intent-based cross-chain bridge enabling fast, secure asset transfers between Tempo and other chains. + +## Features + +- **Intent-based bridging** — Fast fills with competitive pricing +- **Capital efficiency** — Relayers provide instant liquidity +- **Multi-chain** — Connect Tempo to Ethereum, Arbitrum, Optimism, and more +- **Fee optimization** — Dynamic fees based on liquidity + +## SDK Setup + +```bash +npm install @across-protocol/app-sdk viem +``` + +```typescript +import { AcrossClient } from '@across-protocol/app-sdk' +import { mainnet, arbitrum, optimism } from 'viem/chains' +import { tempo } from 'viem/chains' // Tempo chain definition + +const acrossClient = AcrossClient.create({ + integratorId: 'your-integrator-id', + chains: [mainnet, arbitrum, optimism, tempo] +}) +``` + +## Get Quote + +```typescript +interface BridgeQuote { + inputAmount: bigint + outputAmount: bigint + fees: { + lpFee: bigint + relayerFee: bigint + totalFee: bigint + } + estimatedFillTime: number + route: { + fromChain: number + toChain: number + fromToken: string + toToken: string + } +} + +async function getBridgeQuote( + fromChain: number, + toChain: number, + token: string, + amount: bigint +): Promise { + const quote = await acrossClient.getQuote({ + route: { + originChainId: fromChain, + destinationChainId: toChain, + inputToken: token, + outputToken: token // Same token on destination + }, + inputAmount: amount + }) + + return { + inputAmount: quote.inputAmount, + outputAmount: quote.outputAmount, + fees: { + lpFee: quote.lpFee.total, + relayerFee: quote.relayerFee.total, + totalFee: quote.lpFee.total + quote.relayerFee.total + }, + estimatedFillTime: quote.estimatedFillTimeSec, + route: { + fromChain, + toChain, + fromToken: token, + toToken: token + } + } +} + +// Example: Quote bridging USDC from Ethereum to Tempo +const quote = await getBridgeQuote( + 1, // Ethereum + TEMPO_CHAIN_ID, + '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC on Ethereum + 1000000000n // 1000 USDC +) +``` + +## Execute Bridge + +### Deposit on Source Chain + +```typescript +import { createWalletClient, http } from 'viem' +import { privateKeyToAccount } from 'viem/accounts' + +async function bridgeToTempo( + fromChain: number, + token: string, + amount: bigint, + recipient: string +) { + // Get quote first + const quote = await acrossClient.getQuote({ + route: { + originChainId: fromChain, + destinationChainId: TEMPO_CHAIN_ID, + inputToken: token, + outputToken: token + }, + inputAmount: amount + }) + + // Execute deposit + const deposit = await acrossClient.executeQuote({ + walletClient, + deposit: quote, + onProgress: (progress) => { + console.log('Bridge progress:', progress.step, progress.status) + } + }) + + return { + depositId: deposit.depositId, + depositTxHash: deposit.depositTxHash, + outputAmount: quote.outputAmount + } +} +``` + +### Bridge from Tempo + +```typescript +async function bridgeFromTempo( + toChain: number, + token: string, + amount: bigint, + recipient: string +) { + const quote = await acrossClient.getQuote({ + route: { + originChainId: TEMPO_CHAIN_ID, + destinationChainId: toChain, + inputToken: token, + outputToken: token + }, + inputAmount: amount + }) + + const deposit = await acrossClient.executeQuote({ + walletClient: tempoWalletClient, + deposit: quote, + onProgress: (progress) => { + if (progress.step === 'fill' && progress.status === 'txSuccess') { + console.log('Bridge complete! Fill tx:', progress.txHash) + } + } + }) + + return deposit +} +``` + +## Track Bridge Status + +```typescript +interface BridgeStatus { + depositId: string + status: 'pending' | 'filled' | 'expired' + fillTxHash?: string + fillTimestamp?: number +} + +async function getBridgeStatus(depositId: string): Promise { + const status = await acrossClient.getDepositStatus({ + depositId, + originChainId: TEMPO_CHAIN_ID + }) + + return { + depositId, + status: status.status, + fillTxHash: status.fillTxHash, + fillTimestamp: status.fillTimestamp + } +} + +// Poll for completion +async function waitForBridgeComplete(depositId: string, maxWaitMs = 300000) { + const startTime = Date.now() + + while (Date.now() - startTime < maxWaitMs) { + const status = await getBridgeStatus(depositId) + + if (status.status === 'filled') { + return status + } + + if (status.status === 'expired') { + throw new Error('Bridge deposit expired') + } + + await new Promise(r => setTimeout(r, 5000)) + } + + throw new Error('Bridge timeout') +} +``` + +## Supported Routes + +```typescript +async function getSupportedRoutes() { + const routes = await acrossClient.getSupportedRoutes() + + // Filter routes involving Tempo + const tempoRoutes = routes.filter( + route => + route.originChainId === TEMPO_CHAIN_ID || + route.destinationChainId === TEMPO_CHAIN_ID + ) + + return tempoRoutes.map(route => ({ + fromChain: route.originChainId, + toChain: route.destinationChainId, + tokens: route.inputTokens.map(t => ({ + symbol: t.symbol, + address: t.address, + decimals: t.decimals + })) + })) +} +``` + +## Fee Estimation + +```typescript +async function estimateBridgeFees( + fromChain: number, + toChain: number, + token: string, + amount: bigint +) { + const quote = await acrossClient.getQuote({ + route: { + originChainId: fromChain, + destinationChainId: toChain, + inputToken: token, + outputToken: token + }, + inputAmount: amount + }) + + const totalFee = quote.lpFee.total + quote.relayerFee.total + const feePercent = Number(totalFee * 10000n / amount) / 100 + + return { + inputAmount: amount, + outputAmount: quote.outputAmount, + lpFee: quote.lpFee.total, + relayerFee: quote.relayerFee.total, + totalFee, + feePercent: `${feePercent.toFixed(2)}%`, + estimatedTime: `${quote.estimatedFillTimeSec}s` + } +} +``` + +## React Integration + +```typescript +import { useState, useCallback } from 'react' + +function useBridge() { + const [loading, setLoading] = useState(false) + const [quote, setQuote] = useState(null) + const [status, setStatus] = useState(null) + + const getQuote = useCallback(async ( + fromChain: number, + toChain: number, + token: string, + amount: bigint + ) => { + setLoading(true) + try { + const q = await getBridgeQuote(fromChain, toChain, token, amount) + setQuote(q) + return q + } finally { + setLoading(false) + } + }, []) + + const execute = useCallback(async (recipient: string) => { + if (!quote) throw new Error('No quote available') + + setLoading(true) + try { + const deposit = await bridgeToTempo( + quote.route.fromChain, + quote.route.fromToken, + quote.inputAmount, + recipient + ) + + // Track status + const finalStatus = await waitForBridgeComplete(deposit.depositId) + setStatus(finalStatus) + return finalStatus + } finally { + setLoading(false) + } + }, [quote]) + + return { getQuote, execute, loading, quote, status } +} +``` + +## Error Handling + +```typescript +async function safeBridge(params: { + fromChain: number + toChain: number + token: string + amount: bigint + recipient: string +}) { + try { + // Check route is supported + const routes = await getSupportedRoutes() + const routeExists = routes.some( + r => r.fromChain === params.fromChain && r.toChain === params.toChain + ) + if (!routeExists) { + throw new Error('Route not supported') + } + + // Get quote with slippage check + const quote = await getBridgeQuote( + params.fromChain, + params.toChain, + params.token, + params.amount + ) + + const slippage = Number( + (params.amount - quote.outputAmount) * 10000n / params.amount + ) / 100 + + if (slippage > 1) { // More than 1% + throw new Error(`Slippage too high: ${slippage}%`) + } + + // Execute + return await bridgeToTempo( + params.fromChain, + params.token, + params.amount, + params.recipient + ) + } catch (error) { + console.error('Bridge failed:', error) + throw error + } +} +``` + +## Webhooks + +```typescript +import express from 'express' + +const app = express() + +app.post('/webhooks/across', express.json(), (req, res) => { + const { eventType, depositId, fillTxHash, status } = req.body + + switch (eventType) { + case 'deposit.filled': + handleBridgeComplete(depositId, fillTxHash) + break + case 'deposit.expired': + handleBridgeExpired(depositId) + break + } + + res.status(200).send('OK') +}) +``` + +## Environment Variables + +```bash +ACROSS_INTEGRATOR_ID=your-integrator-id +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/alchemy.mdx b/src/pages/guides/integrations/alchemy.mdx new file mode 100644 index 00000000..1c2bb366 --- /dev/null +++ b/src/pages/guides/integrations/alchemy.mdx @@ -0,0 +1,439 @@ +--- +title: "Alchemy SDK for Tempo" +description: "Build on Tempo with Alchemy SDK. Enhanced APIs, token tracking, transaction simulation, and real-time WebSocket subscriptions." +--- + +# Alchemy SDK for Tempo + +[Alchemy](https://www.alchemy.com) provides enhanced APIs and developer tools for building on Tempo with better reliability, debugging, and analytics. + +## Why Alchemy + +- **Enhanced APIs** — Token balances, NFT metadata, and transaction history +- **Transaction simulation** — Test transactions before sending +- **WebSocket subscriptions** — Real-time event streaming +- **Debugging tools** — Transaction tracing and error analysis + +## Installation + +```bash +pnpm install alchemy-sdk viem +``` + +## Quick Start + +### 1. Get Your API Key + +Create an app at [dashboard.alchemy.com](https://dashboard.alchemy.com) and copy your API key. + +### 2. Initialize the SDK + +```typescript +import { Alchemy, Network } from 'alchemy-sdk' + +// Tempo Testnet +const alchemyTestnet = new Alchemy({ + apiKey: process.env.ALCHEMY_API_KEY, + url: 'https://rpc.moderato.tempo.xyz' +}) + +// Tempo Mainnet +const alchemyMainnet = new Alchemy({ + apiKey: process.env.ALCHEMY_API_KEY, + url: 'https://rpc.presto.tempo.xyz' +}) +``` + +### 3. Configure Custom Network + +For full SDK features with Tempo's custom RPC: + +```typescript +import { Alchemy } from 'alchemy-sdk' + +const settings = { + apiKey: process.env.ALCHEMY_API_KEY, + url: 'https://rpc.moderato.tempo.xyz', // Testnet + // url: 'https://rpc.presto.tempo.xyz', // Mainnet +} + +const alchemy = new Alchemy(settings) +``` + +## Network Configuration + +| Network | RPC URL | Chain ID | +|---------|---------|----------| +| Testnet | `https://rpc.moderato.tempo.xyz` | 42431 | +| Mainnet | `https://rpc.presto.tempo.xyz` | 4217 | + +## Token Balances + +### Get All Token Balances + +```typescript +const balances = await alchemy.core.getTokenBalances( + '0xYourAddress' +) + +for (const token of balances.tokenBalances) { + console.log(`Token: ${token.contractAddress}`) + console.log(`Balance: ${token.tokenBalance}`) +} +``` + +### Get Specific Token Balance + +```typescript +const USDC_ADDRESS = '0x20c0000000000000000000000000000000000001' + +const balance = await alchemy.core.getTokenBalances( + '0xYourAddress', + [USDC_ADDRESS] +) + +console.log('USDC Balance:', balance.tokenBalances[0].tokenBalance) +``` + +## Token Metadata + +### Get Token Information + +```typescript +const metadata = await alchemy.core.getTokenMetadata( + '0x20c0000000000000000000000000000000000001' +) + +console.log('Name:', metadata.name) +console.log('Symbol:', metadata.symbol) +console.log('Decimals:', metadata.decimals) +``` + +### Batch Token Metadata + +```typescript +const tokens = [ + '0x20c0000000000000000000000000000000000001', // USDC + '0x20c0000000000000000000000000000000000002', // USDT +] + +const metadataPromises = tokens.map(token => + alchemy.core.getTokenMetadata(token) +) + +const allMetadata = await Promise.all(metadataPromises) +``` + +## Asset Transfers + +### Get Transfer History + +```typescript +import { AssetTransfersCategory } from 'alchemy-sdk' + +// Get incoming transfers +const incomingTransfers = await alchemy.core.getAssetTransfers({ + toAddress: '0xYourAddress', + category: [ + AssetTransfersCategory.ERC20, + AssetTransfersCategory.EXTERNAL + ], + withMetadata: true, + maxCount: 100 +}) + +for (const transfer of incomingTransfers.transfers) { + console.log(`From: ${transfer.from}`) + console.log(`Asset: ${transfer.asset}`) + console.log(`Value: ${transfer.value}`) + console.log(`Block: ${transfer.blockNum}`) +} +``` + +### Get Outgoing Transfers + +```typescript +const outgoingTransfers = await alchemy.core.getAssetTransfers({ + fromAddress: '0xYourAddress', + category: [ + AssetTransfersCategory.ERC20, + AssetTransfersCategory.EXTERNAL + ], + withMetadata: true +}) +``` + +### Filter by Block Range + +```typescript +const recentTransfers = await alchemy.core.getAssetTransfers({ + toAddress: '0xYourAddress', + category: [AssetTransfersCategory.ERC20], + fromBlock: '0x0', + toBlock: 'latest' +}) +``` + +## Transaction Simulation + +### Simulate Before Sending + +```typescript +import { createWalletClient, http, encodeFunctionData, erc20Abi } from 'viem' +import { tempoTestnet } from 'viem/chains' + +const USDC_ADDRESS = '0x20c0000000000000000000000000000000000001' + +// Prepare transaction data +const transferData = encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: ['0xRecipient', 1000000n] // 1 USDC (6 decimals) +}) + +// Simulate the transaction +const simulation = await alchemy.transact.simulateExecution({ + from: '0xYourAddress', + to: USDC_ADDRESS, + data: transferData +}) + +if (simulation.calls[0].status === 'REVERTED') { + console.error('Transaction would revert:', simulation.calls[0].error) +} else { + console.log('Simulation successful!') + console.log('Gas used:', simulation.calls[0].gasUsed) +} +``` + +### Simulate Asset Changes + +```typescript +const simulation = await alchemy.transact.simulateAssetChanges({ + from: '0xYourAddress', + to: USDC_ADDRESS, + data: transferData +}) + +for (const change of simulation.changes) { + console.log(`Asset: ${change.symbol}`) + console.log(`Change: ${change.changeType}`) + console.log(`Amount: ${change.amount}`) +} +``` + +## WebSocket Subscriptions + +### Subscribe to New Blocks + +```typescript +alchemy.ws.on('block', (blockNumber) => { + console.log('New block:', blockNumber) +}) +``` + +### Subscribe to Pending Transactions + +```typescript +alchemy.ws.on('pending', (txHash) => { + console.log('Pending transaction:', txHash) +}) +``` + +### Subscribe to Address Activity + +```typescript +// Watch for incoming transactions to an address +alchemy.ws.on( + { + method: 'alchemy_pendingTransactions', + toAddress: '0xYourAddress' + }, + (tx) => { + console.log('Incoming transaction:', tx.hash) + } +) +``` + +### Subscribe to Contract Events + +```typescript +import { erc20Abi } from 'viem' + +const USDC_ADDRESS = '0x20c0000000000000000000000000000000000001' + +// Watch for Transfer events +alchemy.ws.on( + { + address: USDC_ADDRESS, + topics: [ + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' // Transfer event signature + ] + }, + (log) => { + console.log('Transfer event:', log) + } +) +``` + +### Unsubscribe + +```typescript +// Remove specific listener +alchemy.ws.off('block', blockHandler) + +// Remove all listeners +alchemy.ws.removeAllListeners() +``` + +## Debugging + +### Get Transaction Receipt + +```typescript +const receipt = await alchemy.core.getTransactionReceipt(txHash) + +console.log('Status:', receipt.status === 1 ? 'Success' : 'Failed') +console.log('Gas Used:', receipt.gasUsed.toString()) +console.log('Block:', receipt.blockNumber) +``` + +### Trace Transaction + +```typescript +const trace = await alchemy.debug.traceTransaction(txHash, { + type: 'callTracer' +}) + +console.log('Trace:', JSON.stringify(trace, null, 2)) +``` + +### Get Transaction Errors + +```typescript +try { + const result = await alchemy.transact.simulateExecution({ + from: '0xYourAddress', + to: contractAddress, + data: callData + }) + + if (result.calls[0].error) { + console.error('Error:', result.calls[0].error.message) + } +} catch (error) { + console.error('Simulation failed:', error) +} +``` + +## Viem Integration + +Use Alchemy as a transport with viem: + +```typescript +import { createPublicClient, createWalletClient, http } from 'viem' +import { tempoTestnet, tempoMainnet } from 'viem/chains' +import { privateKeyToAccount } from 'viem/accounts' + +// Testnet client +const publicClient = createPublicClient({ + chain: tempoTestnet({ + feeToken: '0x20c0000000000000000000000000000000000001' + }), + transport: http('https://rpc.moderato.tempo.xyz') +}) + +// Mainnet client +const mainnetClient = createPublicClient({ + chain: tempoMainnet({ + feeToken: '0x20c0000000000000000000000000000000000001' + }), + transport: http('https://rpc.presto.tempo.xyz') +}) + +// Wallet client for signing +const account = privateKeyToAccount('0x...') +const walletClient = createWalletClient({ + account, + chain: tempoTestnet({ feeToken: '0x20c0000000000000000000000000000000000001' }), + transport: http('https://rpc.moderato.tempo.xyz') +}) +``` + +## Batch Requests + +```typescript +// Batch multiple calls efficiently +const [blockNumber, gasPrice, balance] = await Promise.all([ + alchemy.core.getBlockNumber(), + alchemy.core.getGasPrice(), + alchemy.core.getBalance('0xYourAddress') +]) + +console.log('Block:', blockNumber) +console.log('Gas Price:', gasPrice.toString()) +console.log('Balance:', balance.toString()) +``` + +## Environment Variables + +```bash +# .env.local +ALCHEMY_API_KEY=your-api-key +``` + +## Full Example + +```typescript +import { Alchemy } from 'alchemy-sdk' +import { createPublicClient, createWalletClient, http, parseEther } from 'viem' +import { tempoTestnet } from 'viem/chains' +import { privateKeyToAccount } from 'viem/accounts' + +// Initialize Alchemy +const alchemy = new Alchemy({ + apiKey: process.env.ALCHEMY_API_KEY, + url: 'https://rpc.moderato.tempo.xyz' +}) + +// Initialize viem client +const tempo = tempoTestnet({ + feeToken: '0x20c0000000000000000000000000000000000001' +}) + +const publicClient = createPublicClient({ + chain: tempo, + transport: http('https://rpc.moderato.tempo.xyz') +}) + +async function main() { + // Get token balances + const balances = await alchemy.core.getTokenBalances('0xYourAddress') + console.log('Token balances:', balances) + + // Subscribe to new blocks + alchemy.ws.on('block', async (blockNumber) => { + const block = await publicClient.getBlock({ blockNumber: BigInt(blockNumber) }) + console.log('New block:', block.number, 'Transactions:', block.transactions.length) + }) + + // Get recent transfers + const transfers = await alchemy.core.getAssetTransfers({ + toAddress: '0xYourAddress', + category: ['erc20', 'external'], + maxCount: 10 + }) + console.log('Recent transfers:', transfers.transfers.length) +} + +main() +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/allium.mdx b/src/pages/guides/integrations/allium.mdx new file mode 100644 index 00000000..88e78615 --- /dev/null +++ b/src/pages/guides/integrations/allium.mdx @@ -0,0 +1,430 @@ +--- +title: "Allium Blockchain Data for Tempo" +description: "Enterprise blockchain data and analytics for Tempo with Allium. Real-time data, SQL queries, and stablecoin analytics." +--- + +# Allium Blockchain Data for Tempo + +[Allium](https://allium.so) provides enterprise-grade blockchain data infrastructure with real-time indexing, SQL access, and comprehensive analytics. + +## Features + +- **Real-time data** — Sub-second data freshness +- **SQL interface** — Query blockchain data with SQL +- **Stablecoin analytics** — Specialized stablecoin data +- **API access** — Programmatic data retrieval + +## API Setup + +```typescript +const ALLIUM_API_KEY = process.env.ALLIUM_API_KEY +const ALLIUM_BASE_URL = 'https://api.allium.so/api/v1' + +async function alliumRequest(endpoint: string, params?: Record) { + const url = new URL(`${ALLIUM_BASE_URL}${endpoint}`) + if (params) { + Object.entries(params).forEach(([key, value]) => { + url.searchParams.set(key, value) + }) + } + + const response = await fetch(url.toString(), { + headers: { + 'X-API-Key': ALLIUM_API_KEY! + } + }) + return response.json() +} +``` + +## SQL Queries + +Allium Explorer requires queries to be saved in the Allium App first, then executed via API using the query ID. Direct SQL execution is not supported via API. + +### Run Saved Query + +```typescript +// Queries must be created in the Allium App first +// Then execute using the query_id +async function runSavedQuery(queryId: string, parameters?: Record) { + const response = await fetch(`${ALLIUM_BASE_URL}/explorer/queries/${queryId}/run-async`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-API-Key': ALLIUM_API_KEY! + }, + body: JSON.stringify({ + parameters: parameters || {}, + run_config: {} + }) + }) + + const data = await response.json() + return data.run_id // Returns a run_id to poll for results +} + +// Poll for query results +async function getQueryResults(runId: string) { + const response = await fetch(`${ALLIUM_BASE_URL}/explorer/query-runs/${runId}`, { + headers: { + 'X-API-Key': ALLIUM_API_KEY! + } + }) + return response.json() +} + +// Example saved query in Allium App: +// SELECT from_address, to_address, amount, block_timestamp +// FROM ethereum.token_transfers -- Use chain-specific schema +// WHERE block_timestamp > now() - interval '24 hours' +// ORDER BY amount DESC +// LIMIT 100 +`) +``` + +### Query Token Holders + +```typescript +async function getTokenHolders(tokenAddress: string, limit = 100) { + const sql = ` + SELECT + address, + balance, + balance / NULLIF(total_supply, 0) * 100 as percentage + FROM tempo.token_balances + WHERE token_address = '${tokenAddress}' + ORDER BY balance DESC + LIMIT ${limit} + ` + + return runQuery(sql) +} +``` + +### Query Transaction History + +```typescript +async function getAddressTransactions(address: string, days = 30) { + const sql = ` + SELECT + hash, + block_number, + block_timestamp, + from_address, + to_address, + value, + gas_used, + gas_price, + status + FROM tempo.transactions + WHERE (from_address = '${address}' OR to_address = '${address}') + AND block_timestamp > now() - interval '${days} days' + ORDER BY block_timestamp DESC + LIMIT 1000 + ` + + return runQuery(sql) +} +``` + +## Stablecoin Analytics + +### Get Stablecoin Transfers + +```typescript +async function getStablecoinTransfers( + stablecoin: string, + startDate: string, + endDate: string +) { + const sql = ` + SELECT + from_address, + to_address, + amount, + block_timestamp, + transaction_hash + FROM tempo.stablecoin_transfers + WHERE symbol = '${stablecoin}' + AND block_timestamp BETWEEN '${startDate}' AND '${endDate}' + ORDER BY block_timestamp DESC + ` + + return runQuery(sql) +} +``` + +### Get Stablecoin Volume + +```typescript +async function getStablecoinVolume(period: '1d' | '7d' | '30d') { + const intervalMap = { + '1d': '1 day', + '7d': '7 days', + '30d': '30 days' + } + + const sql = ` + SELECT + symbol, + SUM(amount) as total_volume, + COUNT(*) as transfer_count, + COUNT(DISTINCT from_address) as unique_senders, + COUNT(DISTINCT to_address) as unique_receivers + FROM tempo.stablecoin_transfers + WHERE block_timestamp > now() - interval '${intervalMap[period]}' + GROUP BY symbol + ORDER BY total_volume DESC + ` + + return runQuery(sql) +} +``` + +### Get Top Stablecoin Contracts + +```typescript +async function getTopStablecoinContracts(symbol: string, limit = 50) { + const sql = ` + SELECT + contract_address, + contract_name, + SUM(amount) as total_volume, + COUNT(*) as transaction_count + FROM tempo.stablecoin_transfers + WHERE symbol = '${symbol}' + AND block_timestamp > now() - interval '30 days' + AND contract_address IS NOT NULL + GROUP BY contract_address, contract_name + ORDER BY total_volume DESC + LIMIT ${limit} + ` + + return runQuery(sql) +} +``` + +## Token Analytics + +### Get Token Metrics + +```typescript +async function getTokenMetrics(tokenAddress: string) { + const sql = ` + SELECT + token_address, + symbol, + name, + total_supply, + holder_count, + transfer_count_24h, + volume_24h + FROM tempo.token_metrics + WHERE token_address = '${tokenAddress}' + ` + + const results = await runQuery(sql) + return results[0] +} +``` + +### Get Token Transfer Volume + +```typescript +async function getTokenVolumeHistory( + tokenAddress: string, + days = 30 +) { + const sql = ` + SELECT + DATE(block_timestamp) as date, + SUM(amount) as volume, + COUNT(*) as transfer_count + FROM tempo.token_transfers + WHERE token_address = '${tokenAddress}' + AND block_timestamp > now() - interval '${days} days' + GROUP BY DATE(block_timestamp) + ORDER BY date + ` + + return runQuery(sql) +} +``` + +## DeFi Analytics + +### Get DEX Trades + +```typescript +async function getDEXTrades(poolAddress: string, limit = 100) { + const sql = ` + SELECT + transaction_hash, + block_timestamp, + trader_address, + token_in, + token_out, + amount_in, + amount_out, + price + FROM tempo.dex_trades + WHERE pool_address = '${poolAddress}' + ORDER BY block_timestamp DESC + LIMIT ${limit} + ` + + return runQuery(sql) +} +``` + +### Get Liquidity Positions + +```typescript +async function getLiquidityPositions(address: string) { + const sql = ` + SELECT + pool_address, + pool_name, + token0_address, + token1_address, + liquidity, + value_usd + FROM tempo.liquidity_positions + WHERE owner_address = '${address}' + AND liquidity > 0 + ORDER BY value_usd DESC + ` + + return runQuery(sql) +} +``` + +## Real-Time Streaming + +```typescript +import WebSocket from 'ws' + +function streamTransfers(tokenAddress: string, callback: (transfer: any) => void) { + const ws = new WebSocket( + `wss://stream.allium.so/v1/tempo/token_transfers?token=${tokenAddress}`, + { + headers: { 'X-API-Key': ALLIUM_API_KEY } + } + ) + + ws.on('message', (data) => { + const transfer = JSON.parse(data.toString()) + callback(transfer) + }) + + ws.on('error', (error) => { + console.error('Stream error:', error) + }) + + return () => ws.close() +} + +// Usage +const unsubscribe = streamTransfers(USDC_ADDRESS, (transfer) => { + console.log('New transfer:', transfer) +}) +``` + +## Batch Data Export + +```typescript +async function exportData( + table: string, + startDate: string, + endDate: string +) { + const response = await fetch(`${ALLIUM_BASE_URL}/exports`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-API-Key': ALLIUM_API_KEY! + }, + body: JSON.stringify({ + table: `tempo.${table}`, + start_date: startDate, + end_date: endDate, + format: 'parquet' + }) + }) + + const { export_id } = await response.json() + return export_id +} + +async function getExportStatus(exportId: string) { + const data = await alliumRequest(`/exports/${exportId}`) + return { + status: data.status, + downloadUrl: data.download_url + } +} +``` + +## React Hook + +```typescript +import { useState, useEffect } from 'react' + +function useAlliumQuery(sql: string, deps: any[] = []) { + const [data, setData] = useState(null) + const [loading, setLoading] = useState(true) + const [error, setError] = useState(null) + + useEffect(() => { + async function fetch() { + setLoading(true) + try { + const results = await runQuery(sql) + setData(results as T) + } catch (e) { + setError(e as Error) + } finally { + setLoading(false) + } + } + + fetch() + }, deps) + + return { data, loading, error } +} + +// Usage +function TokenHolders({ tokenAddress }: { tokenAddress: string }) { + const { data, loading, error } = useAlliumQuery( + `SELECT * FROM tempo.token_balances WHERE token_address = '${tokenAddress}' LIMIT 100`, + [tokenAddress] + ) + + if (loading) return
Loading...
+ if (error) return
Error: {error.message}
+ + return ( +
    + {data?.map(holder => ( +
  • {holder.address}: {holder.balance}
  • + ))} +
+ ) +} +``` + +## Environment Variables + +```bash +ALLIUM_API_KEY=your-api-key +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/anchorage.mdx b/src/pages/guides/integrations/anchorage.mdx new file mode 100644 index 00000000..525aa9ab --- /dev/null +++ b/src/pages/guides/integrations/anchorage.mdx @@ -0,0 +1,399 @@ +--- +title: "Anchorage Digital Custody for Tempo" +description: "Institutional-grade digital asset custody for Tempo with Anchorage. Regulatory compliance, insurance, and enterprise security." +--- + +# Anchorage Digital Custody for Tempo + +[Anchorage Digital](https://anchorage.com) provides institutional-grade custody, trading, and staking services for Tempo assets. + +> **Note:** Anchorage Digital's API access is provided to institutional clients after onboarding. The examples in this guide illustrate common custody API patterns and should be verified against Anchorage's official documentation. + +## Features + +- **Qualified custody** — SEC-qualified custodian +- **Insurance coverage** — Comprehensive asset protection +- **Multi-sig governance** — Configurable approval policies +- **API access** — Programmatic custody operations + +## API Setup + +```typescript +const ANCHORAGE_API_KEY = process.env.ANCHORAGE_API_KEY +const ANCHORAGE_API_SECRET = process.env.ANCHORAGE_API_SECRET +const ANCHORAGE_BASE_URL = 'https://api.anchorage.com' + +async function anchorageRequest( + endpoint: string, + options: { method?: string; body?: any } = {} +) { + const timestamp = Date.now().toString() + const signature = createSignature( + options.method || 'GET', + endpoint, + timestamp, + options.body + ) + + const response = await fetch(`${ANCHORAGE_BASE_URL}${endpoint}`, { + method: options.method || 'GET', + headers: { + 'Content-Type': 'application/json', + 'X-Anchorage-Api-Key': ANCHORAGE_API_KEY!, + 'X-Anchorage-Timestamp': timestamp, + 'X-Anchorage-Signature': signature + }, + body: options.body ? JSON.stringify(options.body) : undefined + }) + return response.json() +} + +function createSignature( + method: string, + endpoint: string, + timestamp: string, + body?: any +) { + const crypto = require('crypto') + const message = `${timestamp}${method}${endpoint}${body ? JSON.stringify(body) : ''}` + return crypto + .createHmac('sha256', ANCHORAGE_API_SECRET) + .update(message) + .digest('hex') +} +``` + +## Vault Management + +### List Vaults + +```typescript +interface Vault { + id: string + name: string + type: string + assets: Array<{ + asset: string + balance: string + balanceUsd: number + }> +} + +async function listVaults(): Promise { + const data = await anchorageRequest('/v1/vaults') + + return data.vaults.map((vault: any) => ({ + id: vault.vault_id, + name: vault.name, + type: vault.type, + assets: vault.balances.map((b: any) => ({ + asset: b.asset_type, + balance: b.balance, + balanceUsd: b.usd_value + })) + })) +} +``` + +### Get Vault Balance + +```typescript +async function getVaultBalance(vaultId: string, asset = 'ETH') { + const data = await anchorageRequest( + `/v1/vaults/${vaultId}/balances?asset=${asset}` + ) + + return { + vaultId, + asset, + available: data.available_balance, + pending: data.pending_balance, + total: data.total_balance, + usdValue: data.usd_value + } +} +``` + +## Addresses + +### Generate Deposit Address + +```typescript +async function generateDepositAddress(vaultId: string, asset: string) { + const data = await anchorageRequest(`/v1/vaults/${vaultId}/addresses`, { + method: 'POST', + body: { + asset_type: asset, + network: 'tempo' + } + }) + + return { + address: data.address, + asset, + network: 'tempo', + vaultId + } +} +``` + +### List Addresses + +```typescript +async function listAddresses(vaultId: string) { + const data = await anchorageRequest(`/v1/vaults/${vaultId}/addresses`) + + return data.addresses.map((addr: any) => ({ + address: addr.address, + asset: addr.asset_type, + network: addr.network, + createdAt: addr.created_at + })) +} +``` + +## Withdrawals + +### Create Withdrawal + +```typescript +interface WithdrawalRequest { + vaultId: string + asset: string + amount: string + destinationAddress: string + note?: string +} + +async function createWithdrawal(request: WithdrawalRequest) { + const data = await anchorageRequest( + `/v1/vaults/${request.vaultId}/withdrawals`, + { + method: 'POST', + body: { + asset_type: request.asset, + amount: request.amount, + destination_address: request.destinationAddress, + network: 'tempo', + note: request.note + } + } + ) + + return { + withdrawalId: data.withdrawal_id, + status: data.status, + amount: data.amount, + asset: data.asset_type, + destination: data.destination_address, + requiredApprovals: data.required_approvals, + currentApprovals: data.current_approvals + } +} +``` + +### Get Withdrawal Status + +```typescript +async function getWithdrawalStatus(vaultId: string, withdrawalId: string) { + const data = await anchorageRequest( + `/v1/vaults/${vaultId}/withdrawals/${withdrawalId}` + ) + + return { + id: data.withdrawal_id, + status: data.status, + amount: data.amount, + asset: data.asset_type, + destination: data.destination_address, + txHash: data.transaction_hash, + approvals: data.approvals, + createdAt: data.created_at, + completedAt: data.completed_at + } +} +``` + +## Policies + +### Get Approval Policy + +```typescript +async function getApprovalPolicy(vaultId: string) { + const data = await anchorageRequest(`/v1/vaults/${vaultId}/policies`) + + return { + vaultId, + withdrawalPolicy: { + threshold: data.withdrawal_policy.threshold, + approvers: data.withdrawal_policy.approvers, + limits: data.withdrawal_policy.limits?.map((l: any) => ({ + amount: l.amount, + currency: l.currency, + period: l.period, + approvalsRequired: l.approvals_required + })) + } + } +} +``` + +### Approve Withdrawal + +```typescript +async function approveWithdrawal( + vaultId: string, + withdrawalId: string, + approverId: string +) { + const data = await anchorageRequest( + `/v1/vaults/${vaultId}/withdrawals/${withdrawalId}/approve`, + { + method: 'POST', + body: { + approver_id: approverId + } + } + ) + + return { + withdrawalId, + status: data.status, + approvals: data.approvals + } +} +``` + +## Transaction History + +```typescript +async function getTransactionHistory( + vaultId: string, + options: { + asset?: string + startDate?: Date + endDate?: Date + limit?: number + } = {} +) { + const params = new URLSearchParams() + if (options.asset) params.set('asset', options.asset) + if (options.startDate) params.set('start_date', options.startDate.toISOString()) + if (options.endDate) params.set('end_date', options.endDate.toISOString()) + if (options.limit) params.set('limit', options.limit.toString()) + + const data = await anchorageRequest( + `/v1/vaults/${vaultId}/transactions?${params}` + ) + + return data.transactions.map((tx: any) => ({ + id: tx.transaction_id, + type: tx.type, + asset: tx.asset_type, + amount: tx.amount, + status: tx.status, + txHash: tx.blockchain_transaction_hash, + timestamp: tx.timestamp, + counterparty: tx.counterparty_address + })) +} +``` + +## Webhooks + +```typescript +import express from 'express' +import crypto from 'crypto' + +const app = express() + +function verifyWebhook(payload: string, signature: string) { + const expected = crypto + .createHmac('sha256', process.env.ANCHORAGE_WEBHOOK_SECRET!) + .update(payload) + .digest('hex') + return crypto.timingSafeEqual( + Buffer.from(signature), + Buffer.from(expected) + ) +} + +app.post('/webhooks/anchorage', express.raw({ type: 'application/json' }), (req, res) => { + const signature = req.headers['x-anchorage-signature'] as string + + if (!verifyWebhook(req.body.toString(), signature)) { + return res.status(401).send('Invalid signature') + } + + const event = JSON.parse(req.body.toString()) + + switch (event.event_type) { + case 'deposit.confirmed': + handleDeposit(event.data) + break + case 'withdrawal.pending_approval': + handlePendingApproval(event.data) + break + case 'withdrawal.completed': + handleWithdrawalComplete(event.data) + break + case 'withdrawal.failed': + handleWithdrawalFailed(event.data) + break + } + + res.status(200).send('OK') +}) +``` + +## Reporting + +```typescript +async function generateReport( + vaultId: string, + reportType: 'balance' | 'transactions' | 'tax', + startDate: Date, + endDate: Date +) { + const data = await anchorageRequest(`/v1/vaults/${vaultId}/reports`, { + method: 'POST', + body: { + report_type: reportType, + start_date: startDate.toISOString(), + end_date: endDate.toISOString(), + format: 'csv' + } + }) + + return { + reportId: data.report_id, + status: data.status, + downloadUrl: data.download_url + } +} +``` + +## Best Practices + +1. **Whitelisted addresses** — Pre-approve withdrawal destinations +2. **Multi-approval** — Require multiple approvers for large withdrawals +3. **Rate limits** — Implement withdrawal velocity limits +4. **Monitoring** — Set up alerts for unusual activity +5. **Audit trail** — Log all API operations + +## Environment Variables + +```bash +ANCHORAGE_API_KEY=your-api-key +ANCHORAGE_API_SECRET=your-api-secret +ANCHORAGE_WEBHOOK_SECRET=your-webhook-secret +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/artemis.mdx b/src/pages/guides/integrations/artemis.mdx new file mode 100644 index 00000000..52113c08 --- /dev/null +++ b/src/pages/guides/integrations/artemis.mdx @@ -0,0 +1,364 @@ +--- +title: "Artemis Analytics for Tempo" +description: "Crypto analytics and on-chain data for Tempo with Artemis. Protocol metrics, stablecoin flows, and market intelligence." +--- + +# Artemis Analytics for Tempo + +[Artemis](https://artemis.xyz) provides comprehensive crypto analytics, protocol metrics, and on-chain intelligence for Tempo applications. + +> **Note:** Artemis provides an official Python SDK (`artemis-py`). The TypeScript examples in this guide demonstrate the REST API patterns and are provided for illustration purposes. For production Python applications, use the official SDK. + +## Features + +- **Protocol metrics** — TVL, revenue, user activity +- **Stablecoin data** — Supply, flows, and velocity +- **Developer activity** — Code commits and contributors +- **Market data** — Prices, volumes, market caps + +## API Setup + +```typescript +const ARTEMIS_API_KEY = process.env.ARTEMIS_API_KEY +const ARTEMIS_BASE_URL = 'https://api.artemis.xyz' + +async function artemisRequest(endpoint: string, params?: Record) { + const url = new URL(`${ARTEMIS_BASE_URL}${endpoint}`) + if (params) { + Object.entries(params).forEach(([key, value]) => { + url.searchParams.set(key, String(value)) + }) + } + + const response = await fetch(url.toString(), { + headers: { + 'x-api-key': ARTEMIS_API_KEY! + } + }) + return response.json() +} +``` + +## Chain Metrics + +### Get Daily Active Addresses + +```typescript +async function getDailyActiveAddresses(days = 30) { + const data = await artemisRequest('/data/chain/tempo/active-addresses', { + start_date: getDateDaysAgo(days), + end_date: getTodayDate() + }) + + return data.data.map((point: any) => ({ + date: point.date, + activeAddresses: point.value + })) +} +``` + +### Get Transaction Volume + +```typescript +async function getTransactionVolume(days = 30) { + const data = await artemisRequest('/data/chain/tempo/txns', { + start_date: getDateDaysAgo(days), + end_date: getTodayDate() + }) + + return data.data.map((point: any) => ({ + date: point.date, + transactions: point.value + })) +} +``` + +### Get Fees + +```typescript +async function getChainFees(days = 30) { + const data = await artemisRequest('/data/chain/tempo/fees', { + start_date: getDateDaysAgo(days), + end_date: getTodayDate() + }) + + return data.data.map((point: any) => ({ + date: point.date, + feesUsd: point.value + })) +} +``` + +## Stablecoin Analytics + +### Get Stablecoin Supply + +```typescript +async function getStablecoinSupply(stablecoin: 'usdc' | 'usdt' | 'dai') { + const data = await artemisRequest(`/data/stablecoin/${stablecoin}/supply`, { + chain: 'tempo' + }) + + return { + totalSupply: data.current_supply, + supplyChange24h: data.change_24h, + supplyChange7d: data.change_7d, + history: data.data.map((point: any) => ({ + date: point.date, + supply: point.value + })) + } +} +``` + +### Get Stablecoin Flows + +```typescript +async function getStablecoinFlows(days = 7) { + const data = await artemisRequest('/data/stablecoin/flows', { + chain: 'tempo', + start_date: getDateDaysAgo(days), + end_date: getTodayDate() + }) + + return { + netInflow: data.net_inflow, + inflows: data.inflows, + outflows: data.outflows, + byStablecoin: data.by_stablecoin + } +} +``` + +### Get Stablecoin Velocity + +```typescript +async function getStablecoinVelocity(stablecoin: string, days = 30) { + const data = await artemisRequest(`/data/stablecoin/${stablecoin}/velocity`, { + chain: 'tempo', + start_date: getDateDaysAgo(days), + end_date: getTodayDate() + }) + + return data.data.map((point: any) => ({ + date: point.date, + velocity: point.value, + volume: point.volume, + supply: point.supply + })) +} +``` + +## Protocol Metrics + +### Get TVL + +```typescript +async function getProtocolTVL(protocol: string, days = 30) { + const data = await artemisRequest(`/data/protocol/${protocol}/tvl`, { + chain: 'tempo', + start_date: getDateDaysAgo(days), + end_date: getTodayDate() + }) + + return { + currentTvl: data.current_tvl, + change24h: data.change_24h, + change7d: data.change_7d, + history: data.data.map((point: any) => ({ + date: point.date, + tvl: point.value + })) + } +} +``` + +### Get Protocol Revenue + +```typescript +async function getProtocolRevenue(protocol: string, days = 30) { + const data = await artemisRequest(`/data/protocol/${protocol}/revenue`, { + chain: 'tempo', + start_date: getDateDaysAgo(days), + end_date: getTodayDate() + }) + + return { + totalRevenue: data.total_revenue, + averageDaily: data.average_daily, + history: data.data.map((point: any) => ({ + date: point.date, + revenue: point.value + })) + } +} +``` + +## Developer Activity + +### Get Developer Metrics + +```typescript +async function getDeveloperActivity(days = 90) { + const data = await artemisRequest('/data/chain/tempo/developer-activity', { + start_date: getDateDaysAgo(days), + end_date: getTodayDate() + }) + + return { + totalCommits: data.total_commits, + activeContributors: data.active_contributors, + repositories: data.repositories, + weeklyCommits: data.weekly_commits + } +} +``` + +## Market Data + +### Get Token Price + +```typescript +async function getTokenPrice(tokenId: string, days = 30) { + const data = await artemisRequest(`/data/token/${tokenId}/price`, { + start_date: getDateDaysAgo(days), + end_date: getTodayDate() + }) + + return { + currentPrice: data.current_price, + change24h: data.change_24h, + change7d: data.change_7d, + history: data.data.map((point: any) => ({ + date: point.date, + price: point.value + })) + } +} +``` + +### Get Market Cap + +```typescript +async function getMarketCap(tokenId: string) { + const data = await artemisRequest(`/data/token/${tokenId}/market-cap`) + + return { + marketCap: data.market_cap, + fullyDilutedValuation: data.fdv, + circulatingSupply: data.circulating_supply, + totalSupply: data.total_supply + } +} +``` + +## Comparison Data + +### Compare Chains + +```typescript +async function compareChains(chains: string[], metric: string, days = 30) { + const promises = chains.map(chain => + artemisRequest(`/data/chain/${chain}/${metric}`, { + start_date: getDateDaysAgo(days), + end_date: getTodayDate() + }) + ) + + const results = await Promise.all(promises) + + return chains.map((chain, i) => ({ + chain, + current: results[i].current_value, + change7d: results[i].change_7d, + data: results[i].data + })) +} + +// Usage +const comparison = await compareChains( + ['tempo', 'ethereum', 'arbitrum'], + 'active-addresses', + 30 +) +``` + +## React Hooks + +```typescript +import { useState, useEffect } from 'react' + +function useArtemisData( + endpoint: string, + params?: Record, + deps: any[] = [] +) { + const [data, setData] = useState(null) + const [loading, setLoading] = useState(true) + const [error, setError] = useState(null) + + useEffect(() => { + async function fetch() { + setLoading(true) + try { + const result = await artemisRequest(endpoint, params) + setData(result) + } catch (e) { + setError(e as Error) + } finally { + setLoading(false) + } + } + + fetch() + }, deps) + + return { data, loading, error } +} + +// Usage +function ChainMetrics() { + const { data, loading } = useArtemisData( + '/data/chain/tempo/active-addresses', + { start_date: getDateDaysAgo(30), end_date: getTodayDate() } + ) + + if (loading) return
Loading...
+ + return ( +
+

Active Addresses

+ {/* Render chart */} +
+ ) +} +``` + +## Helper Functions + +```typescript +function getDateDaysAgo(days: number): string { + const date = new Date() + date.setDate(date.getDate() - days) + return date.toISOString().split('T')[0] +} + +function getTodayDate(): string { + return new Date().toISOString().split('T')[0] +} +``` + +## Environment Variables + +```bash +ARTEMIS_API_KEY=your-api-key +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/axelar.mdx b/src/pages/guides/integrations/axelar.mdx new file mode 100644 index 00000000..8f7decff --- /dev/null +++ b/src/pages/guides/integrations/axelar.mdx @@ -0,0 +1,432 @@ +--- +title: "Axelar Interoperability for Tempo" +description: "Cross-chain messaging and asset transfers for Tempo with Axelar. Connect Tempo to 50+ blockchain networks." +--- + +# Axelar Interoperability for Tempo + +[Axelar](https://axelar.network) provides secure cross-chain communication, enabling Tempo to connect with 50+ blockchain networks for messaging and asset transfers. + +## Features + +- **General Message Passing (GMP)** — Cross-chain contract calls +- **Asset transfers** — Bridge tokens across chains +- **Interchain tokens** — Deploy tokens across multiple chains +- **Squid Router** — Optimized cross-chain swaps + +## SDK Setup + +```bash +npm install @axelar-network/axelarjs-sdk viem +``` + +```typescript +import { AxelarQueryAPI, AxelarGMPRecoveryAPI, Environment } from '@axelar-network/axelarjs-sdk' + +const axelarQuery = new AxelarQueryAPI({ + environment: Environment.MAINNET +}) + +const gmpRecovery = new AxelarGMPRecoveryAPI({ + environment: Environment.MAINNET +}) +``` + +## General Message Passing (GMP) + +### Send Cross-Chain Message + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { AxelarExecutable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol'; +import { IAxelarGateway } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol'; +import { IAxelarGasService } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGasService.sol'; + +contract TempoMessenger is AxelarExecutable { + IAxelarGasService public immutable gasService; + + constructor( + address gateway_, + address gasService_ + ) AxelarExecutable(gateway_) { + gasService = IAxelarGasService(gasService_); + } + + function sendMessage( + string calldata destinationChain, + string calldata destinationAddress, + bytes calldata payload + ) external payable { + // Pay for gas on destination chain + gasService.payNativeGasForContractCall{ value: msg.value }( + address(this), + destinationChain, + destinationAddress, + payload, + msg.sender + ); + + // Send the message + gateway.callContract(destinationChain, destinationAddress, payload); + } + + function _execute( + string calldata sourceChain, + string calldata sourceAddress, + bytes calldata payload + ) internal override { + // Handle incoming message + (address recipient, uint256 amount) = abi.decode(payload, (address, uint256)); + // Process the cross-chain message... + } +} +``` + +### TypeScript Integration + +```typescript +import { createWalletClient, http, encodeFunctionData } from 'viem' +import { tempo } from 'viem/chains' + +const messengerAbi = [ + { + name: 'sendMessage', + type: 'function', + inputs: [ + { name: 'destinationChain', type: 'string' }, + { name: 'destinationAddress', type: 'string' }, + { name: 'payload', type: 'bytes' } + ] + } +] as const + +async function sendCrossChainMessage( + destinationChain: string, + destinationContract: string, + payload: `0x${string}` +) { + // Estimate gas for destination chain + const gasFee = await axelarQuery.estimateGasFee( + 'tempo', + destinationChain, + 700000, // Estimated gas limit + 1.1 // Gas multiplier + ) + + const walletClient = createWalletClient({ + chain: tempo, + transport: http() + }) + + const hash = await walletClient.writeContract({ + address: MESSENGER_ADDRESS, + abi: messengerAbi, + functionName: 'sendMessage', + args: [destinationChain, destinationContract, payload], + value: BigInt(gasFee) + }) + + return hash +} +``` + +## Asset Transfers + +### Bridge Tokens + +```typescript +import { AxelarAssetTransfer, Environment } from '@axelar-network/axelarjs-sdk' + +const assetTransfer = new AxelarAssetTransfer({ + environment: Environment.MAINNET +}) + +async function bridgeToTempo( + sourceChain: string, + asset: string, + amount: string, + recipientAddress: string +) { + const depositAddress = await assetTransfer.getDepositAddress({ + fromChain: sourceChain, + toChain: 'tempo', + destinationAddress: recipientAddress, + asset + }) + + return { + depositAddress, + instructions: `Send ${amount} ${asset} to ${depositAddress} on ${sourceChain}` + } +} + +async function bridgeFromTempo( + destinationChain: string, + asset: string, + amount: string, + recipientAddress: string +) { + const depositAddress = await assetTransfer.getDepositAddress({ + fromChain: 'tempo', + toChain: destinationChain, + destinationAddress: recipientAddress, + asset + }) + + return { + depositAddress, + instructions: `Send ${amount} ${asset} to ${depositAddress} on Tempo` + } +} +``` + +### Send with Call + +```typescript +async function bridgeWithCall( + destinationChain: string, + destinationContract: string, + asset: string, + amount: bigint, + payload: `0x${string}` +) { + // This sends tokens AND executes a contract call on destination + const gasFee = await axelarQuery.estimateGasFee( + 'tempo', + destinationChain, + 500000, + 1.1, + asset + ) + + const hash = await walletClient.writeContract({ + address: GATEWAY_ADDRESS, + abi: gatewayAbi, + functionName: 'callContractWithToken', + args: [ + destinationChain, + destinationContract, + payload, + asset, + amount + ], + value: BigInt(gasFee) + }) + + return hash +} +``` + +## Track Transfer Status + +```typescript +interface TransferStatus { + status: 'pending' | 'executed' | 'error' + sourceChain: string + destinationChain: string + txHash: string + executeTxHash?: string + error?: string +} + +async function getTransferStatus(txHash: string): Promise { + const status = await gmpRecovery.queryTransactionStatus(txHash) + + return { + status: mapStatus(status.status), + sourceChain: status.call?.chain || '', + destinationChain: status.call?.returnValues?.destinationChain || '', + txHash, + executeTxHash: status.executed?.transactionHash, + error: status.error?.message + } +} + +function mapStatus(status: string) { + switch (status) { + case 'executed': + return 'executed' + case 'error': + return 'error' + default: + return 'pending' + } +} + +// Poll for completion +async function waitForExecution(txHash: string, maxWaitMs = 600000) { + const startTime = Date.now() + + while (Date.now() - startTime < maxWaitMs) { + const status = await getTransferStatus(txHash) + + if (status.status === 'executed') { + return status + } + + if (status.status === 'error') { + throw new Error(status.error) + } + + await new Promise(r => setTimeout(r, 10000)) + } + + throw new Error('Transfer timeout') +} +``` + +## Squid Router Integration + +```typescript +import { Squid } from '@0xsquid/sdk' + +const squid = new Squid({ + baseUrl: 'https://api.squidrouter.com' +}) + +await squid.init() + +async function swapAndBridge( + fromChain: string, + toChain: string, + fromToken: string, + toToken: string, + amount: string, + recipient: string +) { + const route = await squid.getRoute({ + fromChain, + toChain, + fromToken, + toToken, + fromAmount: amount, + toAddress: recipient, + slippage: 1 + }) + + const tx = await squid.executeRoute({ + signer: walletClient, + route + }) + + return { + txHash: tx.hash, + estimatedOutput: route.estimate.toAmount, + route: route.estimate.route + } +} +``` + +## Interchain Token Service + +```typescript +// Deploy a token that exists on multiple chains +async function deployInterchainToken( + name: string, + symbol: string, + decimals: number, + initialSupply: bigint, + destinationChains: string[] +) { + // Deploy on Tempo first + const tokenId = await deployLocalToken(name, symbol, decimals, initialSupply) + + // Register on other chains + for (const chain of destinationChains) { + await registerRemoteToken(tokenId, chain) + } + + return tokenId +} + +async function transferInterchainToken( + tokenId: string, + destinationChain: string, + recipient: string, + amount: bigint +) { + const gasFee = await axelarQuery.estimateGasFee( + 'tempo', + destinationChain, + 200000, + 1.1 + ) + + const hash = await walletClient.writeContract({ + address: ITS_ADDRESS, + abi: itsAbi, + functionName: 'interchainTransfer', + args: [tokenId, destinationChain, recipient, amount, '0x'], + value: BigInt(gasFee) + }) + + return hash +} +``` + +## Gas Estimation + +```typescript +async function estimateGas( + sourceChain: string, + destinationChain: string, + gasLimit: number, + includeToken = false +) { + const gasFee = await axelarQuery.estimateGasFee( + sourceChain, + destinationChain, + gasLimit, + 1.1, // 10% buffer + includeToken ? 'USDC' : undefined + ) + + return { + gasLimit, + estimatedFee: gasFee, + sourceChain, + destinationChain + } +} +``` + +## Supported Chains + +```typescript +async function getSupportedChains() { + const chains = await axelarQuery.getActiveChains() + + return chains.map(chain => ({ + id: chain.id, + name: chain.name, + nativeToken: chain.nativeToken, + gateway: chain.contracts?.gateway?.address, + gasService: chain.contracts?.gasService?.address + })) +} +``` + +## Contract Addresses + +| Contract | Address | +|----------|---------| +| Gateway | `0x...` (Tempo mainnet) | +| Gas Service | `0x...` (Tempo mainnet) | +| ITS | `0x...` (Tempo mainnet) | + +## Environment Variables + +```bash +AXELAR_RPC_URL=https://rpc.axelar.network +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/bitgo.mdx b/src/pages/guides/integrations/bitgo.mdx new file mode 100644 index 00000000..abcd85fa --- /dev/null +++ b/src/pages/guides/integrations/bitgo.mdx @@ -0,0 +1,297 @@ +--- +title: "BitGo Custody for Tempo" +description: "Enterprise custody and wallet infrastructure for Tempo with BitGo. Secure key management, multi-sig, and policy controls." +--- + +# BitGo Custody for Tempo + +[BitGo](https://bitgo.com) provides enterprise-grade digital asset custody and wallet infrastructure for Tempo. + +## Features + +- **Multi-signature security** — 2-of-3 key configuration +- **Policy controls** — Spending limits, whitelists, approvals +- **Cold storage** — Regulated custody solutions +- **API access** — Full wallet management via SDK + +## Installation + +```bash +npm install bitgo +``` + +## SDK Setup + +```typescript +import { BitGoAPI } from '@bitgo/sdk-api' +import { Tempo } from '@bitgo/sdk-coin-tempo' // If available + +const bitgo = new BitGoAPI({ + accessToken: process.env.BITGO_ACCESS_TOKEN, + env: 'prod' // or 'test' +}) + +// Register Tempo coin if custom +bitgo.register('tempo', Tempo.createInstance) +``` + +## Wallet Operations + +### Create Wallet + +```typescript +async function createWallet() { + const wallet = await bitgo.coin('tempo').wallets().generateWallet({ + label: 'Treasury Wallet', + passphrase: process.env.WALLET_PASSPHRASE, + enterprise: process.env.ENTERPRISE_ID + }) + + console.log('Wallet ID:', wallet.wallet.id()) + console.log('Address:', wallet.wallet.receiveAddress()) + + // Store backup key securely + console.log('Backup Key:', wallet.backupKeychain) + + return wallet +} +``` + +### Get Wallet + +```typescript +async function getWallet(walletId: string) { + const wallet = await bitgo.coin('tempo').wallets().get({ id: walletId }) + + console.log('Balance:', wallet.balance()) + console.log('Confirmed:', wallet.confirmedBalance()) + console.log('Spendable:', wallet.spendableBalance()) + + return wallet +} +``` + +### List Addresses + +```typescript +async function listAddresses(walletId: string) { + const wallet = await bitgo.coin('tempo').wallets().get({ id: walletId }) + const addresses = await wallet.addresses() + + return addresses.addresses +} +``` + +### Create Address + +```typescript +async function createAddress(walletId: string, label: string) { + const wallet = await bitgo.coin('tempo').wallets().get({ id: walletId }) + const address = await wallet.createAddress({ label }) + + return address.address +} +``` + +## Transactions + +### Send Transaction + +```typescript +async function sendTransaction( + walletId: string, + recipient: string, + amount: string +) { + const wallet = await bitgo.coin('tempo').wallets().get({ id: walletId }) + + const prebuild = await wallet.prebuildTransaction({ + recipients: [{ + address: recipient, + amount: amount // In base units + }] + }) + + const signedTx = await wallet.signTransaction({ + txPrebuild: prebuild, + walletPassphrase: process.env.WALLET_PASSPHRASE + }) + + const result = await wallet.submitTransaction({ + txHex: signedTx.txHex + }) + + return result.txid +} +``` + +### Batch Transfer + +```typescript +async function batchTransfer(walletId: string, transfers: Array<{ + address: string, + amount: string +}>) { + const wallet = await bitgo.coin('tempo').wallets().get({ id: walletId }) + + const prebuild = await wallet.prebuildTransaction({ + recipients: transfers + }) + + const signedTx = await wallet.signTransaction({ + txPrebuild: prebuild, + walletPassphrase: process.env.WALLET_PASSPHRASE + }) + + return await wallet.submitTransaction({ txHex: signedTx.txHex }) +} +``` + +## Policy Controls + +### Set Spending Limit + +```typescript +async function setSpendingLimit(walletId: string) { + const wallet = await bitgo.coin('tempo').wallets().get({ id: walletId }) + + await wallet.updatePolicies({ + policies: [{ + id: 'daily-limit', + type: 'dailyLimit', + action: { type: 'deny' }, + condition: { + amountString: '10000000000000000000000', // 10,000 USD + excludeTags: ['whitelisted'] + } + }] + }) +} +``` + +### Whitelist Addresses + +```typescript +async function whitelistAddress(walletId: string, address: string) { + const wallet = await bitgo.coin('tempo').wallets().get({ id: walletId }) + + await wallet.updatePolicies({ + policies: [{ + id: 'whitelist', + type: 'allocationApproval', + action: { type: 'getApproval' }, + condition: { + add: address + } + }] + }) +} +``` + +### Require Approval + +```typescript +async function requireApproval(walletId: string, threshold: string) { + const wallet = await bitgo.coin('tempo').wallets().get({ id: walletId }) + + await wallet.updatePolicies({ + policies: [{ + id: 'large-transfer-approval', + type: 'advancedWhitelist', + action: { type: 'getApproval', approvalsRequired: 2 }, + condition: { + amountString: threshold // Requires approval above this + } + }] + }) +} +``` + +## Webhooks + +### Register Webhook + +```typescript +async function registerWebhook(walletId: string, url: string) { + const wallet = await bitgo.coin('tempo').wallets().get({ id: walletId }) + + await wallet.addWebhook({ + url, + type: 'transfer', + numConfirmations: 1 + }) +} +``` + +### Webhook Handler + +```typescript +import express from 'express' +import crypto from 'crypto' + +const app = express() +app.use(express.json()) + +app.post('/webhooks/bitgo', (req, res) => { + // Verify signature + const signature = req.headers['x-webhook-signature'] + const expectedSig = crypto + .createHmac('sha256', process.env.WEBHOOK_SECRET!) + .update(JSON.stringify(req.body)) + .digest('hex') + + if (signature !== expectedSig) { + return res.status(401).send('Invalid signature') + } + + const { type, transfer } = req.body + + if (type === 'transfer') { + console.log('Transfer received:', { + txid: transfer.txid, + value: transfer.value, + confirmations: transfer.confirmations + }) + } + + res.status(200).send('OK') +}) +``` + +## Key Management + +### Export User Key + +```typescript +async function exportUserKey(walletId: string) { + const wallet = await bitgo.coin('tempo').wallets().get({ id: walletId }) + + const keychain = await wallet.getKeychain() + + // Decrypt with passphrase for backup + const decrypted = bitgo.decrypt({ + password: process.env.WALLET_PASSPHRASE, + input: keychain.encryptedPrv + }) + + return decrypted +} +``` + +## Environment Variables + +```bash +BITGO_ACCESS_TOKEN=your-access-token +BITGO_ENTERPRISE_ID=your-enterprise-id +WALLET_PASSPHRASE=secure-passphrase +WEBHOOK_SECRET=webhook-secret +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/blockaid.mdx b/src/pages/guides/integrations/blockaid.mdx new file mode 100644 index 00000000..9c61b376 --- /dev/null +++ b/src/pages/guides/integrations/blockaid.mdx @@ -0,0 +1,416 @@ +--- +title: "Blockaid Security for Tempo" +description: "Real-time transaction security and threat detection for Tempo with Blockaid. Protect users from scams, phishing, and malicious contracts." +--- + +# Blockaid Security for Tempo + +[Blockaid](https://blockaid.io) provides real-time transaction security, simulating and analyzing transactions to detect threats before they execute. + +## Features + +- **Transaction simulation** — Preview transaction outcomes +- **Threat detection** — Identify malicious contracts and addresses +- **Phishing protection** — Block known scam sites and contracts +- **DApp scanning** — Verify application safety + +## SDK Setup + +The recommended approach is to use the official Blockaid SDK: + +```bash +npm install @blockaid/client +``` + +```typescript +import Blockaid from '@blockaid/client' + +const client = new Blockaid({ + apiKey: process.env.BLOCKAID_API_KEY +}) +``` + +Alternatively, you can use the REST API directly: + +```typescript +const BLOCKAID_API_KEY = process.env.BLOCKAID_API_KEY +const BLOCKAID_BASE_URL = 'https://api.blockaid.io' + +async function blockaidRequest(endpoint: string, body: any) { + const response = await fetch(`${BLOCKAID_BASE_URL}${endpoint}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-API-Key': BLOCKAID_API_KEY! + }, + body: JSON.stringify(body) + }) + return response.json() +} +``` + +## Transaction Scanning + +### Scan Transaction + +```typescript +interface TransactionScanRequest { + chainId: number + from: string + to: string + data: string + value: string +} + +interface TransactionScanResult { + status: 'safe' | 'warning' | 'malicious' + riskScore: number + simulation: { + success: boolean + assetChanges: Array<{ + asset: string + type: 'transfer_in' | 'transfer_out' | 'approval' + amount: string + from?: string + to?: string + }> + } + warnings: string[] + maliciousActivities: string[] +} + +async function scanTransaction(tx: TransactionScanRequest): Promise { + const result = await blockaidRequest('/v0/ethereum/transaction/scan', { + chain: `eip155:${tx.chainId}`, + options: ['simulation', 'validation'], + data: { + from: tx.from, + to: tx.to, + data: tx.data, + value: tx.value + }, + metadata: { + domain: 'your-app.com' + } + }) + + return { + status: mapValidationResult(result.validation), + riskScore: result.validation?.risk_score || 0, + simulation: { + success: result.simulation?.status === 'success', + assetChanges: result.simulation?.asset_diff?.map((diff: any) => ({ + asset: diff.asset.symbol, + type: diff.type, + amount: diff.value, + from: diff.from, + to: diff.to + })) || [] + }, + warnings: result.validation?.features?.filter((f: any) => f.type === 'warning').map((f: any) => f.description) || [], + maliciousActivities: result.validation?.features?.filter((f: any) => f.type === 'malicious').map((f: any) => f.description) || [] + } +} + +function mapValidationResult(validation: any) { + if (!validation) return 'safe' + if (validation.result_type === 'Malicious') return 'malicious' + if (validation.result_type === 'Warning') return 'warning' + return 'safe' +} +``` + +### Scan ERC-20 Transfer + +```typescript +import { encodeFunctionData, parseUnits } from 'viem' +import { erc20Abi } from 'viem' + +async function scanERC20Transfer( + tokenAddress: string, + from: string, + to: string, + amount: string, + decimals: number +) { + const data = encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [to as `0x${string}`, parseUnits(amount, decimals)] + }) + + return scanTransaction({ + chainId: 1, // Tempo mainnet chain ID + from, + to: tokenAddress, + data, + value: '0' + }) +} +``` + +## Address Screening + +```typescript +interface AddressScanResult { + address: string + status: 'safe' | 'warning' | 'malicious' + labels: string[] + riskIndicators: string[] +} + +async function scanAddress(address: string): Promise { + const result = await blockaidRequest('/v0/ethereum/address/scan', { + chain: 'eip155:1', + address + }) + + return { + address, + status: result.result_type?.toLowerCase() || 'safe', + labels: result.labels || [], + riskIndicators: result.features?.map((f: any) => f.description) || [] + } +} + +// Usage +const addressCheck = await scanAddress('0x...') +if (addressCheck.status === 'malicious') { + console.log('Malicious address detected:', addressCheck.riskIndicators) +} +``` + +## DApp Scanning + +```typescript +interface DAppScanResult { + url: string + status: 'safe' | 'warning' | 'malicious' + threats: string[] + isPhishing: boolean +} + +async function scanDApp(url: string): Promise { + const result = await blockaidRequest('/v0/site/scan', { + url + }) + + return { + url, + status: result.result_type?.toLowerCase() || 'safe', + threats: result.features?.map((f: any) => f.description) || [], + isPhishing: result.attack_types?.includes('phishing') || false + } +} +``` + +## Integration Patterns + +### Wallet Transaction Guard + +```typescript +async function guardTransaction(tx: TransactionScanRequest): Promise<{ + proceed: boolean + warning?: string + details?: TransactionScanResult +}> { + const scan = await scanTransaction(tx) + + if (scan.status === 'malicious') { + return { + proceed: false, + warning: 'Transaction blocked: ' + scan.maliciousActivities.join(', '), + details: scan + } + } + + if (scan.status === 'warning') { + return { + proceed: true, // Allow but warn + warning: 'Proceed with caution: ' + scan.warnings.join(', '), + details: scan + } + } + + return { proceed: true, details: scan } +} +``` + +### Pre-Approval Check + +```typescript +import { encodeFunctionData, maxUint256 } from 'viem' +import { erc20Abi } from 'viem' + +async function checkApproval( + tokenAddress: string, + owner: string, + spender: string, + amount: bigint +) { + const data = encodeFunctionData({ + abi: erc20Abi, + functionName: 'approve', + args: [spender as `0x${string}`, amount] + }) + + const scan = await scanTransaction({ + chainId: 1, + from: owner, + to: tokenAddress, + data, + value: '0' + }) + + // Warn on unlimited approvals to risky addresses + if (amount === maxUint256) { + const spenderCheck = await scanAddress(spender) + if (spenderCheck.status !== 'safe') { + return { + safe: false, + warning: 'Unlimited approval to risky address' + } + } + } + + return { + safe: scan.status === 'safe', + simulation: scan.simulation, + warnings: scan.warnings + } +} +``` + +### Connect-Time DApp Check + +```typescript +async function validateDAppConnection(dappUrl: string): Promise<{ + allowed: boolean + reason?: string +}> { + const scan = await scanDApp(dappUrl) + + if (scan.isPhishing) { + return { + allowed: false, + reason: 'Phishing site detected' + } + } + + if (scan.status === 'malicious') { + return { + allowed: false, + reason: scan.threats.join(', ') + } + } + + return { allowed: true } +} +``` + +### Transaction Simulation Preview + +```typescript +interface SimulationPreview { + willSucceed: boolean + tokensIn: Array<{ symbol: string; amount: string }> + tokensOut: Array<{ symbol: string; amount: string }> + approvals: Array<{ token: string; spender: string; amount: string }> + warnings: string[] +} + +async function previewTransaction(tx: TransactionScanRequest): Promise { + const scan = await scanTransaction(tx) + + return { + willSucceed: scan.simulation.success, + tokensIn: scan.simulation.assetChanges + .filter(c => c.type === 'transfer_in') + .map(c => ({ symbol: c.asset, amount: c.amount })), + tokensOut: scan.simulation.assetChanges + .filter(c => c.type === 'transfer_out') + .map(c => ({ symbol: c.asset, amount: c.amount })), + approvals: scan.simulation.assetChanges + .filter(c => c.type === 'approval') + .map(c => ({ token: c.asset, spender: c.to!, amount: c.amount })), + warnings: scan.warnings + } +} +``` + +## React Integration + +```typescript +import { useState } from 'react' + +function useTransactionGuard() { + const [scanning, setScanning] = useState(false) + const [result, setResult] = useState(null) + + async function scan(tx: TransactionScanRequest) { + setScanning(true) + try { + const scanResult = await scanTransaction(tx) + setResult(scanResult) + return scanResult + } finally { + setScanning(false) + } + } + + return { scan, scanning, result } +} + +// Usage in component +function TransactionButton({ tx, onConfirm }) { + const { scan, scanning, result } = useTransactionGuard() + + async function handleClick() { + const scanResult = await scan(tx) + + if (scanResult.status === 'malicious') { + alert('Transaction blocked for your safety') + return + } + + if (scanResult.status === 'warning') { + const proceed = confirm(`Warning: ${scanResult.warnings.join(', ')}. Continue?`) + if (!proceed) return + } + + onConfirm(tx) + } + + return ( + + ) +} +``` + +## Threat Categories + +| Category | Description | Action | +|----------|-------------|--------| +| Phishing | Known scam sites | Block connection | +| Drainer | Wallet draining contracts | Block transaction | +| Approval Exploit | Malicious token approvals | Block and warn | +| Rug Pull | Known rug pull tokens | Block transaction | +| Honeypot | Tokens that can't be sold | Warn user | +| Suspicious | Unverified or risky patterns | Display warning | + +## Environment Variables + +```bash +BLOCKAID_API_KEY=your-api-key +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/blockdaemon.mdx b/src/pages/guides/integrations/blockdaemon.mdx new file mode 100644 index 00000000..c2c549a1 --- /dev/null +++ b/src/pages/guides/integrations/blockdaemon.mdx @@ -0,0 +1,416 @@ +--- +title: "Blockdaemon Infrastructure for Tempo" +description: "Institutional blockchain infrastructure for Tempo with Blockdaemon. Staking, node hosting, and wallet APIs." +--- + +# Blockdaemon Infrastructure for Tempo + +[Blockdaemon](https://blockdaemon.com) provides institutional-grade blockchain infrastructure including staking, node hosting, and wallet APIs. + +## Features + +- **Dedicated nodes** — Private RPC endpoints +- **Staking platform** — Institutional staking services +- **Wallet API** — Custody and transaction management +- **Data APIs** — Block and transaction data + +## API Setup + +```typescript +const BLOCKDAEMON_API_KEY = process.env.BLOCKDAEMON_API_KEY +const BLOCKDAEMON_BASE_URL = 'https://svc.blockdaemon.com' + +async function blockdaemonRequest(endpoint: string) { + const response = await fetch(`${BLOCKDAEMON_BASE_URL}${endpoint}`, { + headers: { + 'Authorization': `Bearer ${BLOCKDAEMON_API_KEY}`, + 'Content-Type': 'application/json' + } + }) + return response.json() +} +``` + +## Node Access + +### Dedicated RPC + +```typescript +import { createPublicClient, http } from 'viem' +import { tempo } from 'viem/chains' + +const dedicatedRpc = `https://svc.blockdaemon.com/tempo/mainnet/native?apiKey=${BLOCKDAEMON_API_KEY}` + +const client = createPublicClient({ + chain: tempo, + transport: http(dedicatedRpc) +}) + +// Use like any viem client +const blockNumber = await client.getBlockNumber() +``` + +### WebSocket Connection + +```typescript +import { createPublicClient, webSocket } from 'viem' +import { tempo } from 'viem/chains' + +const wsClient = createPublicClient({ + chain: tempo, + transport: webSocket( + `wss://svc.blockdaemon.com/tempo/mainnet/native/ws?apiKey=${BLOCKDAEMON_API_KEY}` + ) +}) + +// Subscribe to new blocks +const unwatch = wsClient.watchBlockNumber({ + onBlockNumber: (blockNumber) => { + console.log('New block:', blockNumber) + } +}) +``` + +## Universal API + +### Get Account Balance + +```typescript +async function getAccountBalance(address: string) { + const data = await blockdaemonRequest( + `/universal/v1/tempo/mainnet/account/${address}` + ) + + return { + address, + nativeBalance: data.native_balance, + nativeBalanceFormatted: data.native_balance_formatted, + tokens: data.tokens?.map((t: any) => ({ + symbol: t.symbol, + balance: t.balance, + contractAddress: t.contract_address + })) + } +} +``` + +### Get Transaction + +```typescript +async function getTransaction(txHash: string) { + const data = await blockdaemonRequest( + `/universal/v1/tempo/mainnet/tx/${txHash}` + ) + + return { + hash: data.hash, + blockNumber: data.block_number, + timestamp: data.timestamp, + from: data.from, + to: data.to, + value: data.value, + gasUsed: data.gas_used, + gasPrice: data.gas_price, + status: data.status + } +} +``` + +### Get Account Transactions + +```typescript +async function getAccountTransactions( + address: string, + options: { limit?: number; cursor?: string } = {} +) { + const params = new URLSearchParams() + if (options.limit) params.set('limit', options.limit.toString()) + if (options.cursor) params.set('cursor', options.cursor) + + const data = await blockdaemonRequest( + `/universal/v1/tempo/mainnet/account/${address}/txs?${params}` + ) + + return { + transactions: data.data.map((tx: any) => ({ + hash: tx.hash, + blockNumber: tx.block_number, + timestamp: tx.timestamp, + from: tx.from, + to: tx.to, + value: tx.value, + status: tx.status + })), + nextCursor: data.next_cursor + } +} +``` + +### Get Block + +```typescript +async function getBlock(blockNumber: number | 'latest') { + const data = await blockdaemonRequest( + `/universal/v1/tempo/mainnet/block/${blockNumber}` + ) + + return { + number: data.number, + hash: data.hash, + timestamp: data.timestamp, + parentHash: data.parent_hash, + transactionCount: data.transaction_count, + gasUsed: data.gas_used, + gasLimit: data.gas_limit + } +} +``` + +## Wallet API + +### Create Wallet + +```typescript +async function createWallet(name: string) { + const response = await fetch(`${BLOCKDAEMON_BASE_URL}/wallet/v1/wallets`, { + method: 'POST', + headers: { + 'Authorization': `Bearer ${BLOCKDAEMON_API_KEY}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + name, + protocol: 'ethereum' // Tempo is EVM-compatible + }) + }) + + const data = await response.json() + return { + walletId: data.wallet_id, + address: data.address, + name: data.name + } +} +``` + +### Sign Transaction + +```typescript +async function signTransaction( + walletId: string, + transaction: { + to: string + value: string + data?: string + gasLimit?: string + gasPrice?: string + } +) { + const response = await fetch( + `${BLOCKDAEMON_BASE_URL}/wallet/v1/wallets/${walletId}/sign`, + { + method: 'POST', + headers: { + 'Authorization': `Bearer ${BLOCKDAEMON_API_KEY}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + transaction, + chain_id: TEMPO_CHAIN_ID + }) + } + ) + + const data = await response.json() + return { + signedTransaction: data.signed_transaction, + txHash: data.transaction_hash + } +} +``` + +### Broadcast Transaction + +```typescript +async function broadcastTransaction(signedTx: string) { + const response = await fetch( + `${BLOCKDAEMON_BASE_URL}/universal/v1/tempo/mainnet/tx/send`, + { + method: 'POST', + headers: { + 'Authorization': `Bearer ${BLOCKDAEMON_API_KEY}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + tx: signedTx + }) + } + ) + + const data = await response.json() + return { + txHash: data.hash, + status: data.status + } +} +``` + +## Staking API + +### Get Staking Info + +```typescript +async function getStakingInfo() { + const data = await blockdaemonRequest( + `/staking/v1/tempo/mainnet/info` + ) + + return { + protocol: data.protocol, + apy: data.current_apy, + minStake: data.minimum_stake, + unbondingPeriod: data.unbonding_period, + validators: data.validators + } +} +``` + +### Stake Assets + +```typescript +async function stake( + walletId: string, + validatorAddress: string, + amount: string +) { + const response = await fetch( + `${BLOCKDAEMON_BASE_URL}/staking/v1/tempo/mainnet/stake`, + { + method: 'POST', + headers: { + 'Authorization': `Bearer ${BLOCKDAEMON_API_KEY}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + wallet_id: walletId, + validator: validatorAddress, + amount + }) + } + ) + + const data = await response.json() + return { + stakeId: data.stake_id, + txHash: data.transaction_hash, + status: data.status + } +} +``` + +## Event Streaming + +```typescript +async function subscribeToEvents( + address: string, + callback: (event: any) => void +) { + const ws = new WebSocket( + `wss://svc.blockdaemon.com/universal/v1/tempo/mainnet/events?apiKey=${BLOCKDAEMON_API_KEY}` + ) + + ws.onopen = () => { + ws.send(JSON.stringify({ + action: 'subscribe', + addresses: [address], + event_types: ['transaction', 'token_transfer'] + })) + } + + ws.onmessage = (event) => { + const data = JSON.parse(event.data) + callback(data) + } + + return () => ws.close() +} +``` + +## Webhooks + +```typescript +async function createWebhook(address: string, callbackUrl: string) { + const response = await fetch( + `${BLOCKDAEMON_BASE_URL}/webhooks/v1/hooks`, + { + method: 'POST', + headers: { + 'Authorization': `Bearer ${BLOCKDAEMON_API_KEY}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + protocol: 'tempo', + network: 'mainnet', + callback_url: callbackUrl, + addresses: [address], + events: ['confirmed_tx', 'pending_tx'] + }) + } + ) + + return response.json() +} + +// Webhook handler +import express from 'express' + +const app = express() + +app.post('/webhooks/blockdaemon', express.json(), (req, res) => { + const event = req.body + + switch (event.event_type) { + case 'confirmed_tx': + handleConfirmedTransaction(event.data) + break + case 'pending_tx': + handlePendingTransaction(event.data) + break + } + + res.status(200).send('OK') +}) +``` + +## Monitoring + +```typescript +async function getNodeHealth() { + const data = await blockdaemonRequest( + `/monitoring/v1/tempo/mainnet/health` + ) + + return { + status: data.status, + blockHeight: data.block_height, + syncStatus: data.sync_status, + peerCount: data.peer_count, + latency: data.latency_ms + } +} +``` + +## Environment Variables + +```bash +BLOCKDAEMON_API_KEY=your-api-key +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/blockscout.mdx b/src/pages/guides/integrations/blockscout.mdx new file mode 100644 index 00000000..b936442d --- /dev/null +++ b/src/pages/guides/integrations/blockscout.mdx @@ -0,0 +1,244 @@ +--- +title: "Blockscout Explorer for Tempo" +description: "Use Blockscout APIs to explore Tempo blockchain data. Contract verification, transaction lookup, and analytics." +--- + +# Blockscout Explorer for Tempo + +[Blockscout](https://blockscout.com) powers the Tempo block explorer at [explore.tempo.xyz](https://explore.tempo.xyz). + +## Explorer URLs + +| Environment | URL | +|-------------|-----| +| Explorer | `https://explore.tempo.xyz` | +| API | `https://explore.tempo.xyz/api` | + +## API Endpoints + +### Account Balance + +```bash +curl "https://explore.tempo.xyz/api?module=account&action=balance&address=0x..." +``` + +Response: +```json +{ + "status": "1", + "message": "OK", + "result": "1000000000000000000" +} +``` + +### Token Balance + +```bash +curl "https://explore.tempo.xyz/api?module=account&action=tokenbalance&contractaddress=0x...&address=0x..." +``` + +### Transaction List + +```bash +curl "https://explore.tempo.xyz/api?module=account&action=txlist&address=0x...&startblock=0&endblock=99999999&sort=desc" +``` + +### Token Transfers + +```bash +curl "https://explore.tempo.xyz/api?module=account&action=tokentx&address=0x...&startblock=0&endblock=99999999" +``` + +## Contract Verification + +### Via API + +```bash +curl -X POST "https://explore.tempo.xyz/api?module=contract&action=verify" \ + -H "Content-Type: application/json" \ + -d '{ + "addressHash": "0xContractAddress", + "name": "MyContract", + "compilerVersion": "v0.8.24+commit.e11b9ed9", + "optimization": true, + "optimizationRuns": 200, + "contractSourceCode": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n..." + }' +``` + +### Via Hardhat + +```typescript +// hardhat.config.ts +const config: HardhatUserConfig = { + etherscan: { + apiKey: { + tempo: 'placeholder' + }, + customChains: [ + { + network: 'tempo', + chainId: 42431, + urls: { + apiURL: 'https://explore.tempo.xyz/api', + browserURL: 'https://explore.tempo.xyz' + } + } + ] + } +} +``` + +```bash +npx hardhat verify --network tempo 0xContractAddress "Constructor" "Args" +``` + +### Via Foundry + +```bash +forge verify-contract \ + --chain-id 42431 \ + --verifier blockscout \ + --verifier-url https://explore.tempo.xyz/api \ + 0xContractAddress \ + src/MyContract.sol:MyContract +``` + +## Smart Contract Interaction + +### Read Contract + +```bash +curl "https://explore.tempo.xyz/api?module=contract&action=getabi&address=0x..." +``` + +### Write Contract + +Use the ABI with ethers.js: + +```typescript +import { ethers } from 'ethers' + +async function getContractABI(address: string) { + const response = await fetch( + `https://explore.tempo.xyz/api?module=contract&action=getabi&address=${address}` + ) + const data = await response.json() + return JSON.parse(data.result) +} + +async function interactWithContract(address: string) { + const abi = await getContractABI(address) + const provider = new ethers.JsonRpcProvider('https://rpc.moderato.tempo.xyz') + const contract = new ethers.Contract(address, abi, provider) + + // Call view functions + const result = await contract.someViewFunction() + return result +} +``` + +## GraphQL API + +Blockscout provides a GraphQL endpoint: + +```bash +curl -X POST "https://explore.tempo.xyz/graphiql" \ + -H "Content-Type: application/json" \ + -d '{ + "query": "{ transaction(hash: \"0x...\") { hash status gasUsed value } }" + }' +``` + +### Example Queries + +```graphql +# Get address info +{ + address(hash: "0x...") { + hash + fetchedCoinBalance + transactionsCount + tokenTransfersCount + } +} + +# Get block +{ + block(number: 1000) { + hash + timestamp + gasUsed + transactionsCount + } +} + +# Get token +{ + token(contractAddress: "0x...") { + name + symbol + decimals + totalSupply + holdersCount + } +} +``` + +## SDK Integration + +```typescript +class BlockscoutClient { + private baseUrl = 'https://explore.tempo.xyz/api' + + async getBalance(address: string): Promise { + const response = await fetch( + `${this.baseUrl}?module=account&action=balance&address=${address}` + ) + const data = await response.json() + return BigInt(data.result) + } + + async getTransactions(address: string, page = 1): Promise { + const response = await fetch( + `${this.baseUrl}?module=account&action=txlist&address=${address}&page=${page}&offset=10` + ) + const data = await response.json() + return data.result + } + + async getTokenTransfers(address: string): Promise { + const response = await fetch( + `${this.baseUrl}?module=account&action=tokentx&address=${address}` + ) + const data = await response.json() + return data.result + } + + async getContractABI(address: string): Promise { + const response = await fetch( + `${this.baseUrl}?module=contract&action=getabi&address=${address}` + ) + const data = await response.json() + return JSON.parse(data.result) + } +} + +// Usage +const client = new BlockscoutClient() +const balance = await client.getBalance('0x...') +``` + +## Rate Limits + +- 50 requests per second for free tier +- Contact for enterprise limits + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/bridge.mdx b/src/pages/guides/integrations/bridge.mdx new file mode 100644 index 00000000..228feba6 --- /dev/null +++ b/src/pages/guides/integrations/bridge.mdx @@ -0,0 +1,244 @@ +--- +title: "Bridge Stablecoins to Tempo" +description: "Bridge stablecoins to Tempo. Use Bridge, Relay, and other interoperability partners for cross-chain transfers." +--- + +# Bridge Stablecoins to Tempo + +Move stablecoins from other chains to Tempo using our interoperability partners. Note: USDC and USDT are not natively available on Tempo—bridging converts source chain assets to Tempo's native stablecoins (pathUSD, AlphaUSD, etc.). + +## Quick Options + +| Partner | Best For | Supported Assets | +|---------|----------|-----------------| +| [Bridge](https://bridge.xyz) | Enterprise orchestration | Multiple stablecoins, fiat rails | +| [Relay](https://relay.link) | Consumer payments | Any token, any chain | +| [Thunes](https://thunes.com) | Global remittances | 80+ currencies | +| [OpenFX](https://openfx.com) | FX liquidity | Multi-currency | + +## Using Bridge + +[Bridge](https://bridge.xyz) provides stablecoin orchestration infrastructure. + +### API Integration + +```typescript +import { Bridge } from '@bridge-xyz/sdk' + +const bridge = new Bridge({ + apiKey: process.env.BRIDGE_API_KEY! +}) + +// Create a transfer to Tempo +const transfer = await bridge.transfers.create({ + amount: '1000.00', + currency: 'USDC', + source: { + chain: 'ethereum', + address: sourceAddress + }, + destination: { + chain: 'tempo', + address: recipientAddress + } +}) + +console.log('Transfer ID:', transfer.id) +console.log('Status:', transfer.status) +``` + +### Webhook Handler + +```typescript +app.post('/webhooks/bridge', async (req, res) => { + const event = bridge.webhooks.verify(req.body, req.headers) + + switch (event.type) { + case 'transfer.completed': + console.log('Transfer completed:', event.data.id) + // Credit user's account + break + case 'transfer.failed': + console.log('Transfer failed:', event.data.error) + // Handle failure + break + } + + res.status(200).send('OK') +}) +``` + +## Using Relay + +[Relay](https://relay.link) enables spending money anywhere onchain. + +### SDK Integration + +```typescript +import { RelayClient, MAINNET_RELAY_API } from '@reservoir0x/relay-sdk' + +const relayClient = new RelayClient({ + source: 'myapp.com', + baseApiUrl: MAINNET_RELAY_API +}) + +// Bridge from Ethereum to Tempo +const quote = await relayClient.actions.getQuote({ + user: userAddress, + originChainId: 1, // Ethereum + destinationChainId: 42431, // Tempo Testnet + originCurrency: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC on ETH + destinationCurrency: '0x...', // pathUSD or other native stablecoin on Tempo + amount: '1000000000' // 1000 USDC (6 decimals on ETH) +}) + +// Execute the bridge +const result = await relayClient.actions.execute({ + quote, + wallet: walletClient +}) +``` + +### React Hook + +```typescript +import { useRelayBridge } from '@reservoir0x/relay-kit-hooks' + +export function BridgeToTempo() { + const { bridge, status, txHash } = useRelayBridge({ + originChainId: 1, + destinationChainId: 42431, + currency: 'USDC', + amount: '1000' + }) + + return ( +
+ + {txHash &&

Transaction: {txHash}

} +
+ ) +} +``` + +## Manual Bridging + +### From Ethereum + +1. Go to a supported bridge UI +2. Connect your wallet +3. Select source: Ethereum, USDC +4. Select destination: Tempo +5. Enter amount and confirm + +### Supported Routes + +| Source Chain | Assets | Bridge Provider | +|--------------|--------|-----------------| +| Ethereum | USDC, USDT, DAI | Bridge, Relay | +| Polygon | USDC, USDT | Relay | +| Arbitrum | USDC, USDT | Relay | +| Base | USDC | Relay | +| Optimism | USDC | Relay | + +## Fiat On-Ramps + +### Direct to Tempo + +Partners that support direct fiat-to-Tempo: + +- **Yellow Card** — Africa focus, 20+ countries +- **PDAX** — Philippines, regulated exchange +- **BitGo** — Enterprise custody and trading + +### Via Stablecoin Bridge + +1. Purchase USDC on any supported exchange +2. Withdraw to Ethereum wallet +3. Bridge to Tempo using Relay or Bridge + +## Enterprise Integration + +For high-volume transfers: + +### Bridge Enterprise API + +```typescript +// Create recurring transfers +const schedule = await bridge.schedules.create({ + name: 'weekly-settlement', + frequency: 'weekly', + amount: '100000.00', + currency: 'USDC', + source: { + type: 'bank_account', + id: bankAccountId + }, + destination: { + chain: 'tempo', + address: treasuryAddress + } +}) +``` + +### Thunes Integration + +```typescript +// Global remittance network +const transfer = await thunes.transfers.create({ + source: { + country: 'US', + currency: 'USD', + amount: '1000.00' + }, + destination: { + chain: 'tempo', + currency: 'USDC', + address: recipientAddress + }, + purpose: 'remittance' +}) +``` + +## Monitoring Transfers + +### Check Status + +```typescript +// Bridge +const status = await bridge.transfers.get(transferId) +console.log('Status:', status.state) + +// Relay +const status = await relayClient.actions.getSolverCapacity({ + originChainId: 1, + destinationChainId: 42431 +}) +``` + +### Transaction Tracking + +All bridge transactions appear on the [Tempo Explorer](https://explore.tempo.xyz): + +``` +https://explore.tempo.xyz/tx/{transactionHash} +``` + +## Best Practices + +1. **Verify addresses** — Double-check recipient addresses before bridging +2. **Start small** — Test with small amounts first +3. **Monitor gas** — Check gas prices on source chain +4. **Use webhooks** — Implement webhook handlers for status updates +5. **Error handling** — Handle bridge failures gracefully + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/chainalysis.mdx b/src/pages/guides/integrations/chainalysis.mdx new file mode 100644 index 00000000..1fd5509f --- /dev/null +++ b/src/pages/guides/integrations/chainalysis.mdx @@ -0,0 +1,403 @@ +--- +title: "Chainalysis Compliance for Tempo" +description: "Blockchain analytics and compliance solutions for Tempo with Chainalysis. Address screening, transaction monitoring, and KYT." +--- + +# Chainalysis Compliance for Tempo + +[Chainalysis](https://chainalysis.com) provides blockchain analytics, compliance tools, and investigation solutions for Tempo applications. + +## Features + +- **KYT (Know Your Transaction)** — Real-time transaction monitoring +- **Address screening** — Sanctions and risk assessment +- **Reactor** — Investigation and tracing tools +- **Kryptos** — Market intelligence + +## API Setup + +Chainalysis offers multiple products with different APIs: +- **Sanctions Screening API** (free tier available) - uses `public.chainalysis.com` +- **KYT API** (enterprise) - uses `api.chainalysis.com` + +```typescript +const CHAINALYSIS_API_KEY = process.env.CHAINALYSIS_API_KEY + +// Sanctions Screening API (free tier) +const SANCTIONS_BASE_URL = 'https://public.chainalysis.com' + +async function sanctionsRequest(endpoint: string) { + const response = await fetch(`${SANCTIONS_BASE_URL}${endpoint}`, { + headers: { + 'X-API-KEY': CHAINALYSIS_API_KEY! + } + }) + return response.json() +} + +// KYT API (enterprise) +const KYT_BASE_URL = 'https://api.chainalysis.com' + +async function kytRequest(endpoint: string, options: { + method?: string + body?: any +} = {}) { + const response = await fetch(`${KYT_BASE_URL}${endpoint}`, { + method: options.method || 'GET', + headers: { + 'Content-Type': 'application/json', + 'Token': CHAINALYSIS_API_KEY! + }, + body: options.body ? JSON.stringify(options.body) : undefined + }) + return response.json() +} +``` + +## Address Screening + +### Register Address + +```typescript +async function registerAddress(address: string, userId: string) { + const result = await chainalysisRequest('/api/kyt/v2/users', { + method: 'POST', + body: { + userId + } + }) + + // Register the address for the user + await chainalysisRequest(`/api/kyt/v2/users/${userId}/addresses`, { + method: 'POST', + body: { + address, + network: 'ethereum' // Use 'ethereum' for EVM chains + } + }) + + return result +} +``` + +### Screen Address + +```typescript +interface ScreeningResult { + address: string + risk: 'Severe' | 'High' | 'Medium' | 'Low' + riskScore: number + cluster: { + name: string + category: string + } + exposures: Array<{ + category: string + value: number + percentage: number + }> +} + +async function screenAddress(address: string): Promise { + const result = await chainalysisRequest( + `/api/risk/v2/entities/${address}?network=ethereum` + ) + + return { + address: result.address, + risk: result.risk, + riskScore: result.riskScore, + cluster: result.cluster, + exposures: result.exposures + } +} + +// Usage +const screening = await screenAddress('0x...') +if (screening.risk === 'Severe' || screening.risk === 'High') { + console.log('High-risk address detected') +} +``` + +### Sanctions Check + +```typescript +async function checkSanctions(address: string) { + const result = await chainalysisRequest( + `/api/sanctions/v1/address/${address}?network=ethereum` + ) + + return { + address, + isSanctioned: result.isSanctioned, + identifications: result.identifications || [], + sanctionPrograms: result.sanctions || [] + } +} +``` + +## Transaction Monitoring (KYT) + +### Register Transfer + +```typescript +interface TransferRegistration { + network: string + asset: string + transferReference: string + direction: 'sent' | 'received' + outputAddress?: string + inputAddress?: string + amount: number + timestamp: string +} + +async function registerTransfer(userId: string, transfer: TransferRegistration) { + const result = await chainalysisRequest( + `/api/kyt/v2/users/${userId}/transfers`, + { + method: 'POST', + body: transfer + } + ) + + return { + transferId: result.externalId, + riskScore: result.riskScore, + alerts: result.alerts + } +} + +// Usage +const transfer = await registerTransfer('user-123', { + network: 'ethereum', + asset: 'ETH', + transferReference: 'tx-hash-here', + direction: 'received', + outputAddress: '0x...', + amount: 1000, + timestamp: new Date().toISOString() +}) +``` + +### Get Transfer Risk + +```typescript +async function getTransferRisk(userId: string, transferId: string) { + const result = await chainalysisRequest( + `/api/kyt/v2/users/${userId}/transfers/${transferId}` + ) + + return { + riskScore: result.riskScore, + rating: result.rating, // 'lowRisk', 'mediumRisk', 'highRisk', 'severeRisk' + exposures: result.exposures, + alerts: result.alerts + } +} +``` + +## Alert Management + +```typescript +interface Alert { + alertId: string + alertType: string + severity: string + status: string + createdAt: string + details: any +} + +async function getAlerts(userId: string): Promise { + const result = await chainalysisRequest( + `/api/kyt/v2/users/${userId}/alerts` + ) + return result.alerts +} + +async function updateAlertStatus( + userId: string, + alertId: string, + status: 'acknowledged' | 'dismissed' | 'investigating' +) { + await chainalysisRequest( + `/api/kyt/v2/users/${userId}/alerts/${alertId}`, + { + method: 'PATCH', + body: { status } + } + ) +} +``` + +## Integration Patterns + +### Pre-Transaction Screening + +```typescript +async function validateTransfer( + fromAddress: string, + toAddress: string, + amount: number +): Promise<{ allowed: boolean; reason?: string }> { + // Check sanctions + const sanctions = await checkSanctions(toAddress) + if (sanctions.isSanctioned) { + return { + allowed: false, + reason: `Address is sanctioned: ${sanctions.sanctionPrograms.join(', ')}` + } + } + + // Screen address risk + const screening = await screenAddress(toAddress) + if (screening.risk === 'Severe') { + return { + allowed: false, + reason: 'Recipient address is severe risk' + } + } + + if (screening.risk === 'High' && amount > 10000) { + return { + allowed: false, + reason: 'High-risk address with large amount requires review' + } + } + + return { allowed: true } +} +``` + +### Continuous Monitoring + +```typescript +async function monitorUserActivity(userId: string) { + // Get all alerts for user + const alerts = await getAlerts(userId) + + const criticalAlerts = alerts.filter( + a => a.severity === 'high' || a.severity === 'severe' + ) + + if (criticalAlerts.length > 0) { + // Suspend user activity + await suspendUser(userId) + + // Notify compliance team + await notifyCompliance({ + userId, + alerts: criticalAlerts + }) + } + + return { + alertCount: alerts.length, + criticalCount: criticalAlerts.length, + status: criticalAlerts.length > 0 ? 'suspended' : 'active' + } +} +``` + +### Webhook Handler + +```typescript +import express from 'express' + +const app = express() + +app.post('/webhooks/chainalysis', express.json(), async (req, res) => { + const { eventType, data } = req.body + + switch (eventType) { + case 'alert.created': + await handleNewAlert(data) + break + case 'risk.updated': + await handleRiskUpdate(data) + break + case 'sanctions.match': + await handleSanctionsMatch(data) + break + } + + res.status(200).send('OK') +}) + +async function handleSanctionsMatch(data: any) { + const { address, userId, sanctions } = data + + // Immediately block address + await blockAddress(address) + + // Freeze user account + await freezeAccount(userId) + + // Alert compliance team + await notifyCompliance({ + type: 'SANCTIONS_MATCH', + address, + userId, + sanctions, + priority: 'critical' + }) +} +``` + +## Risk Categories + +| Category | Description | Action | +|----------|-------------|--------| +| Severe | Sanctions, ransomware, terrorism | Block immediately | +| High | Darknet, fraud, stolen funds | Review required | +| Medium | Gambling, mixers | Enhanced monitoring | +| Low | Known exchanges, retail | Normal processing | + +## Compliance Reporting + +```typescript +async function generateComplianceReport(startDate: Date, endDate: Date) { + const users = await getAllUsers() + + const report = { + period: { startDate, endDate }, + totalUsers: users.length, + screenings: 0, + alerts: { + total: 0, + severe: 0, + high: 0, + medium: 0, + low: 0 + }, + blockedAddresses: [] + } + + for (const user of users) { + const alerts = await getAlerts(user.id) + report.alerts.total += alerts.length + + for (const alert of alerts) { + report.alerts[alert.severity.toLowerCase()]++ + } + } + + return report +} +``` + +## Environment Variables + +```bash +CHAINALYSIS_API_KEY=your-api-key +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/chainlink.mdx b/src/pages/guides/integrations/chainlink.mdx new file mode 100644 index 00000000..d73782fb --- /dev/null +++ b/src/pages/guides/integrations/chainlink.mdx @@ -0,0 +1,258 @@ +--- +title: "Chainlink Oracles for Tempo" +description: "Integrate Chainlink price feeds and CCIP on Tempo. Oracle data, cross-chain messaging, and data verification." +--- + +# Chainlink Oracles for Tempo + +[Chainlink](https://chain.link) provides oracle infrastructure for Tempo including price feeds and cross-chain messaging. + +## Price Feeds + +### Consumer Contract + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol"; + +contract TempoPriceConsumer { + AggregatorV3Interface public priceFeed; + + constructor(address _priceFeed) { + priceFeed = AggregatorV3Interface(_priceFeed); + } + + function getLatestPrice() public view returns (int256, uint8) { + ( + , + int256 price, + , + uint256 updatedAt, + + ) = priceFeed.latestRoundData(); + + require(updatedAt > 0, "Round not complete"); + require(price > 0, "Invalid price"); + + return (price, priceFeed.decimals()); + } + + function getPriceWithValidation( + uint256 maxStalenessSeconds + ) public view returns (int256) { + ( + , + int256 price, + , + uint256 updatedAt, + + ) = priceFeed.latestRoundData(); + + require( + block.timestamp - updatedAt <= maxStalenessSeconds, + "Price is stale" + ); + + return price; + } +} +``` + +### Testing with Mocks + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {Test} from "forge-std/Test.sol"; +import {MockV3Aggregator} from "@chainlink/local/src/data-feeds/MockV3Aggregator.sol"; +import {TempoPriceConsumer} from "../src/TempoPriceConsumer.sol"; + +contract PriceFeedTest is Test { + MockV3Aggregator public priceFeed; + TempoPriceConsumer public consumer; + + function setUp() public { + priceFeed = new MockV3Aggregator(8, 100000000000); // $1000 + consumer = new TempoPriceConsumer(address(priceFeed)); + } + + function test_getLatestPrice() public { + (int256 price, uint8 decimals) = consumer.getLatestPrice(); + assertEq(price, 100000000000); + assertEq(decimals, 8); + } + + function test_priceUpdate() public { + priceFeed.updateAnswer(150000000000); // $1500 + (int256 price, ) = consumer.getLatestPrice(); + assertEq(price, 150000000000); + } +} +``` + +## CCIP Cross-Chain + +### Sender Contract + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {IRouterClient} from "@chainlink/contracts-ccip/contracts/interfaces/IRouterClient.sol"; +import {Client} from "@chainlink/contracts-ccip/contracts/libraries/Client.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +contract TempoCCIPSender { + IRouterClient public router; + IERC20 public linkToken; + + event MessageSent(bytes32 messageId, uint64 destChain); + + constructor(address _router, address _link) { + router = IRouterClient(_router); + linkToken = IERC20(_link); + } + + function sendMessage( + uint64 destChainSelector, + address receiver, + string calldata data, + address token, + uint256 amount + ) external returns (bytes32) { + Client.EVMTokenAmount[] memory tokens = new Client.EVMTokenAmount[](1); + tokens[0] = Client.EVMTokenAmount({ + token: token, + amount: amount + }); + + Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({ + receiver: abi.encode(receiver), + data: abi.encode(data), + tokenAmounts: tokens, + extraArgs: Client._argsToBytes( + Client.EVMExtraArgsV1({gasLimit: 200_000}) + ), + feeToken: address(linkToken) + }); + + uint256 fee = router.getFee(destChainSelector, message); + linkToken.approve(address(router), fee); + IERC20(token).approve(address(router), amount); + + bytes32 messageId = router.ccipSend(destChainSelector, message); + emit MessageSent(messageId, destChainSelector); + return messageId; + } +} +``` + +### Receiver Contract + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {CCIPReceiver} from "@chainlink/contracts-ccip/contracts/applications/CCIPReceiver.sol"; +import {Client} from "@chainlink/contracts-ccip/contracts/libraries/Client.sol"; + +contract TempoCCIPReceiver is CCIPReceiver { + mapping(uint64 => bool) public allowedChains; + mapping(address => bool) public allowedSenders; + + event MessageReceived(bytes32 messageId, string data); + + constructor(address _router) CCIPReceiver(_router) {} + + function allowChain(uint64 chainSelector, bool allowed) external { + allowedChains[chainSelector] = allowed; + } + + function allowSender(address sender, bool allowed) external { + allowedSenders[sender] = allowed; + } + + function _ccipReceive( + Client.Any2EVMMessage memory message + ) internal override { + require( + allowedChains[message.sourceChainSelector], + "Chain not allowed" + ); + + address sender = abi.decode(message.sender, (address)); + require(allowedSenders[sender], "Sender not allowed"); + + string memory data = abi.decode(message.data, (string)); + emit MessageReceived(message.messageId, data); + } +} +``` + +## Installation + +```bash +# Foundry +forge install smartcontractkit/chainlink-local + +# Add remappings +echo "@chainlink/local/=lib/chainlink-local/src/" >> remappings.txt +echo "@chainlink/contracts/=lib/chainlink/contracts/" >> remappings.txt +``` + +## Testing CCIP + +```solidity +import {CCIPLocalSimulator} from "@chainlink/local/src/ccip/CCIPLocalSimulator.sol"; + +contract CCIPTest is Test { + CCIPLocalSimulator public simulator; + TempoCCIPSender public sender; + TempoCCIPReceiver public receiver; + + function setUp() public { + simulator = new CCIPLocalSimulator(); + + ( + uint64 chainSelector, + IRouterClient router, + , + , + address link, + , + ) = simulator.configuration(); + + sender = new TempoCCIPSender(address(router), link); + receiver = new TempoCCIPReceiver(address(router)); + + receiver.allowChain(chainSelector, true); + receiver.allowSender(address(sender), true); + + simulator.requestLinkFromFaucet(address(sender), 10 ether); + } + + function test_crossChainMessage() public { + bytes32 messageId = sender.sendMessage( + chainSelector, + address(receiver), + "Hello Tempo!", + address(0), // No tokens + 0 + ); + + assertNotEq(messageId, bytes32(0)); + } +} +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/chainstack.mdx b/src/pages/guides/integrations/chainstack.mdx new file mode 100644 index 00000000..17303dc4 --- /dev/null +++ b/src/pages/guides/integrations/chainstack.mdx @@ -0,0 +1,366 @@ +--- +title: "Chainstack Node Infrastructure for Tempo" +description: "Enterprise blockchain infrastructure for Tempo with Chainstack. Dedicated nodes, elastic APIs, and global deployment." +--- + +# Chainstack Node Infrastructure for Tempo + +[Chainstack](https://chainstack.com) provides enterprise-grade blockchain node infrastructure with dedicated nodes, elastic APIs, and global deployment options. + +## Features + +- **Dedicated nodes** — Private, high-performance nodes +- **Elastic APIs** — Auto-scaling shared infrastructure +- **Global regions** — Deploy nodes worldwide +- **Archive data** — Full historical blockchain access + +## RPC Configuration + +```typescript +import { createPublicClient, createWalletClient, http } from 'viem' +import { tempo } from 'viem/chains' + +const CHAINSTACK_ENDPOINT = process.env.CHAINSTACK_ENDPOINT! +const CHAINSTACK_WS_ENDPOINT = process.env.CHAINSTACK_WS_ENDPOINT! + +const publicClient = createPublicClient({ + chain: tempo, + transport: http(CHAINSTACK_ENDPOINT) +}) + +const walletClient = createWalletClient({ + chain: tempo, + transport: http(CHAINSTACK_ENDPOINT) +}) +``` + +## WebSocket Subscriptions + +```typescript +import { createPublicClient, webSocket } from 'viem' + +const wsClient = createPublicClient({ + chain: tempo, + transport: webSocket(CHAINSTACK_WS_ENDPOINT) +}) + +// Watch new blocks +const unwatchBlocks = wsClient.watchBlockNumber({ + onBlockNumber: (blockNumber) => { + console.log('New block:', blockNumber) + } +}) + +// Watch contract events +const unwatchEvents = wsClient.watchContractEvent({ + address: CONTRACT_ADDRESS, + abi: contractAbi, + eventName: 'Transfer', + onLogs: (logs) => { + logs.forEach(log => { + console.log('Transfer:', log.args) + }) + } +}) +``` + +## Archive Node Queries + +```typescript +async function getHistoricalState( + address: string, + blockNumber: bigint +) { + // Get balance at specific block + const balance = await publicClient.getBalance({ + address: address as `0x${string}`, + blockNumber + }) + + // Get storage at specific block + const storage = await publicClient.getStorageAt({ + address: address as `0x${string}`, + slot: '0x0', + blockNumber + }) + + return { balance, storage } +} + +async function replayTransaction(txHash: string) { + const trace = await publicClient.request({ + method: 'debug_traceTransaction', + params: [txHash, { tracer: 'callTracer' }] + }) + + return trace +} +``` + +## Batch Requests + +```typescript +async function batchGetBalances(addresses: string[]) { + const calls = addresses.map(address => ({ + address: address as `0x${string}`, + abi: erc20Abi, + functionName: 'balanceOf', + args: [userAddress] + })) + + const results = await publicClient.multicall({ contracts: calls }) + + return addresses.map((address, i) => ({ + address, + balance: results[i].result + })) +} +``` + +## Log Queries + +```typescript +async function getContractLogs( + contractAddress: string, + fromBlock: bigint, + toBlock: bigint +) { + const logs = await publicClient.getLogs({ + address: contractAddress as `0x${string}`, + fromBlock, + toBlock + }) + + return logs.map(log => ({ + blockNumber: log.blockNumber, + transactionHash: log.transactionHash, + logIndex: log.logIndex, + topics: log.topics, + data: log.data + })) +} + +// Get specific event type +async function getTransferEvents( + tokenAddress: string, + fromBlock: bigint, + toBlock: bigint +) { + const logs = await publicClient.getLogs({ + address: tokenAddress as `0x${string}`, + event: { + type: 'event', + name: 'Transfer', + inputs: [ + { type: 'address', indexed: true, name: 'from' }, + { type: 'address', indexed: true, name: 'to' }, + { type: 'uint256', indexed: false, name: 'value' } + ] + }, + fromBlock, + toBlock + }) + + return logs +} +``` + +## Transaction Simulation + +```typescript +async function simulateTransaction(tx: { + from: string + to: string + data: string + value?: bigint +}) { + try { + const result = await publicClient.simulateContract({ + address: tx.to as `0x${string}`, + abi: contractAbi, + functionName: 'transfer', + args: [recipient, amount], + account: tx.from as `0x${string}` + }) + + return { + success: true, + result: result.result + } + } catch (error) { + return { + success: false, + error: error.message + } + } +} +``` + +## Gas Optimization + +```typescript +async function getOptimalGasParams() { + const block = await publicClient.getBlock() + const gasPrice = await publicClient.getGasPrice() + const maxPriorityFee = await publicClient.estimateMaxPriorityFeePerGas() + + const baseFee = block.baseFeePerGas || 0n + + return { + gasPrice, + maxFeePerGas: baseFee * 2n + maxPriorityFee, + maxPriorityFeePerGas: maxPriorityFee, + baseFee + } +} +``` + +## Node Health Check + +```typescript +async function checkNodeHealth() { + const startTime = Date.now() + + try { + const [blockNumber, syncing, chainId] = await Promise.all([ + publicClient.getBlockNumber(), + publicClient.request({ method: 'eth_syncing', params: [] }), + publicClient.getChainId() + ]) + + const latency = Date.now() - startTime + const block = await publicClient.getBlock({ blockNumber }) + const blockAge = Date.now() / 1000 - Number(block.timestamp) + + return { + healthy: true, + blockNumber, + chainId, + syncing, + latency, + blockAge, + isSynced: !syncing && blockAge < 30 + } + } catch (error) { + return { + healthy: false, + error: error.message + } + } +} +``` + +## Connection Pool + +```typescript +import { http, fallback } from 'viem' + +const endpoints = [ + process.env.CHAINSTACK_ENDPOINT_1!, + process.env.CHAINSTACK_ENDPOINT_2!, + process.env.CHAINSTACK_ENDPOINT_3! +] + +const pooledClient = createPublicClient({ + chain: tempo, + transport: fallback( + endpoints.map(url => http(url)), + { + rank: true, + retryCount: 3, + retryDelay: 1000 + } + ) +}) +``` + +## Retry Logic + +```typescript +async function withRetry( + fn: () => Promise, + maxRetries = 3, + delay = 1000 +): Promise { + let lastError: Error + + for (let i = 0; i < maxRetries; i++) { + try { + return await fn() + } catch (error) { + lastError = error as Error + + // Don't retry on user errors + if (error.code === -32000) throw error + + if (i < maxRetries - 1) { + await new Promise(r => setTimeout(r, delay * (i + 1))) + } + } + } + + throw lastError! +} + +// Usage +const balance = await withRetry(() => + publicClient.getBalance({ address: userAddress }) +) +``` + +## Metrics Collection + +```typescript +class RpcMetrics { + private requestCount = 0 + private errorCount = 0 + private totalLatency = 0 + + async trackRequest(fn: () => Promise): Promise { + const start = Date.now() + this.requestCount++ + + try { + const result = await fn() + this.totalLatency += Date.now() - start + return result + } catch (error) { + this.errorCount++ + throw error + } + } + + getMetrics() { + return { + totalRequests: this.requestCount, + errorRate: this.errorCount / this.requestCount, + avgLatency: this.totalLatency / this.requestCount + } + } +} + +const metrics = new RpcMetrics() + +// Wrap client calls +const balance = await metrics.trackRequest(() => + publicClient.getBalance({ address: userAddress }) +) +``` + +## Environment Variables + +```bash +CHAINSTACK_ENDPOINT=https://your-node.chainstack.com/abc123 +CHAINSTACK_WS_ENDPOINT=wss://your-node.chainstack.com/abc123 +CHAINSTACK_ENDPOINT_1=https://node1.chainstack.com +CHAINSTACK_ENDPOINT_2=https://node2.chainstack.com +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/coinbase-wallet.mdx b/src/pages/guides/integrations/coinbase-wallet.mdx new file mode 100644 index 00000000..46fbf43c --- /dev/null +++ b/src/pages/guides/integrations/coinbase-wallet.mdx @@ -0,0 +1,433 @@ +--- +title: "Coinbase Wallet for Tempo" +description: "Connect Coinbase Wallet to your Tempo dApp. Wagmi connector setup, mobile deep links, and smart wallet integration with code examples." +--- + +# Coinbase Wallet for Tempo + +[Coinbase Wallet](https://www.coinbase.com/wallet) is a self-custody wallet with over 10 million users. Integrate it with your Tempo app for seamless mobile and browser wallet connections. + +## Why Coinbase Wallet + +- **Massive user base** — Access millions of existing Coinbase Wallet users +- **Mobile-first** — Deep linking for native mobile app connections +- **Smart Wallet** — Passkey-based wallets with no seed phrases +- **Coinbase integration** — Easy fiat on-ramp for new users + +## Installation + +```bash +pnpm install @coinbase/wallet-sdk wagmi viem @tanstack/react-query +``` + +## Quick Start + +### 1. Configure Wagmi with Coinbase Wallet + +```typescript +// config.ts +import { createConfig, http } from 'wagmi' +import { tempoTestnet } from 'wagmi/chains' +import { coinbaseWallet } from 'wagmi/connectors' + +const tempo = { + ...tempoTestnet, + rpcUrls: { + default: { http: ['https://rpc.moderato.tempo.xyz'] } + } +} + +export const config = createConfig({ + chains: [tempo], + connectors: [ + coinbaseWallet({ + appName: 'My Tempo App', + appLogoUrl: 'https://myapp.com/logo.png', + preference: 'all' // 'eoaOnly' | 'smartWalletOnly' | 'all' + }) + ], + transports: { + [tempo.id]: http() + } +}) +``` + +### 2. Set Up Providers + +```typescript +// providers.tsx +'use client' + +import { WagmiProvider } from 'wagmi' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { config } from './config' + +const queryClient = new QueryClient() + +export function Providers({ children }: { children: React.ReactNode }) { + return ( + + + {children} + + + ) +} +``` + +### 3. Connect Button + +```typescript +'use client' + +import { useAccount, useConnect, useDisconnect } from 'wagmi' +import { coinbaseWallet } from 'wagmi/connectors' + +export function ConnectCoinbaseWallet() { + const { address, isConnected } = useAccount() + const { connect, isPending } = useConnect() + const { disconnect } = useDisconnect() + + if (isConnected) { + return ( +
+

Connected: {address}

+ +
+ ) + } + + return ( + + ) +} +``` + +## Coinbase Smart Wallet + +Coinbase Smart Wallet uses passkeys instead of seed phrases for a more user-friendly experience. + +### Configure for Smart Wallet Only + +```typescript +import { coinbaseWallet } from 'wagmi/connectors' + +const connector = coinbaseWallet({ + appName: 'My Tempo App', + preference: 'smartWalletOnly' // Only show Smart Wallet option +}) +``` + +### Detect Wallet Type + +```typescript +import { useAccount } from 'wagmi' + +export function WalletInfo() { + const { address, connector } = useAccount() + + const isSmartWallet = connector?.id === 'coinbaseWalletSDK' && + connector?.type === 'coinbaseWallet' + + return ( +
+

Address: {address}

+

Type: {isSmartWallet ? 'Smart Wallet' : 'EOA'}

+
+ ) +} +``` + +## Mobile Deep Links + +### Generate Connection URL + +```typescript +import { CoinbaseWalletSDK } from '@coinbase/wallet-sdk' + +const sdk = new CoinbaseWalletSDK({ + appName: 'My Tempo App', + appLogoUrl: 'https://myapp.com/logo.png' +}) + +function generateMobileLink(): string { + const callbackUrl = encodeURIComponent(window.location.href) + return `https://go.cb-w.com/dapp?cb_url=${callbackUrl}` +} + +export function MobileConnectButton() { + const handleMobileConnect = () => { + const isMobile = /iPhone|iPad|Android/i.test(navigator.userAgent) + + if (isMobile) { + window.location.href = generateMobileLink() + } + } + + return ( + + ) +} +``` + +### Handle Deep Link Callback + +```typescript +import { useEffect } from 'react' +import { useConnect } from 'wagmi' +import { coinbaseWallet } from 'wagmi/connectors' + +export function useDeepLinkHandler() { + const { connect } = useConnect() + + useEffect(() => { + const params = new URLSearchParams(window.location.search) + const cbAddress = params.get('cb_address') + + if (cbAddress) { + connect({ connector: coinbaseWallet() }) + // Clean up URL + window.history.replaceState({}, '', window.location.pathname) + } + }, [connect]) +} +``` + +## Sending Transactions + +### Basic Transaction + +```typescript +import { useSendTransaction, useWaitForTransactionReceipt } from 'wagmi' +import { parseEther } from 'viem' + +export function SendTransaction() { + const { sendTransaction, data: hash, isPending } = useSendTransaction() + const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({ + hash + }) + + const send = () => { + sendTransaction({ + to: '0xRecipientAddress', + value: parseEther('10') // 10 USD on Tempo + }) + } + + return ( +
+ + {isSuccess &&

Transaction confirmed!

} +
+ ) +} +``` + +### Contract Interaction + +```typescript +import { useWriteContract, useWaitForTransactionReceipt } from 'wagmi' +import { erc20Abi, parseUnits } from 'viem' + +const USDC_ADDRESS = '0x20c0000000000000000000000000000000000001' + +export function TransferToken() { + const { writeContract, data: hash, isPending } = useWriteContract() + const { isLoading: isConfirming } = useWaitForTransactionReceipt({ hash }) + + const transfer = () => { + writeContract({ + address: USDC_ADDRESS, + abi: erc20Abi, + functionName: 'transfer', + args: ['0xRecipient', parseUnits('100', 18)] + }) + } + + return ( + + ) +} +``` + +## Sign Messages + +### Personal Sign + +```typescript +import { useSignMessage } from 'wagmi' + +export function SignMessage() { + const { signMessage, data: signature, isPending } = useSignMessage() + + const sign = () => { + signMessage({ message: 'Sign in to My Tempo App' }) + } + + return ( +
+ + {signature &&

Signature: {signature}

} +
+ ) +} +``` + +### Typed Data (EIP-712) + +```typescript +import { useSignTypedData } from 'wagmi' + +const domain = { + name: 'My Tempo App', + version: '1', + chainId: 42431, + verifyingContract: '0xContractAddress' as const +} + +const types = { + Order: [ + { name: 'from', type: 'address' }, + { name: 'to', type: 'address' }, + { name: 'amount', type: 'uint256' } + ] +} + +export function SignTypedData() { + const { signTypedData, data: signature } = useSignTypedData() + + const sign = () => { + signTypedData({ + domain, + types, + primaryType: 'Order', + message: { + from: '0xSender', + to: '0xRecipient', + amount: 1000n + } + }) + } + + return +} +``` + +## Network Switching + +```typescript +import { useSwitchChain } from 'wagmi' + +export function SwitchToTempo() { + const { switchChain, isPending } = useSwitchChain() + + return ( + + ) +} +``` + +## Fiat On-Ramp + +Coinbase Wallet includes built-in fiat purchasing: + +```typescript +export function BuyCrypto() { + const openCoinbaseBuy = () => { + // Opens Coinbase pay flow in the wallet + window.open( + 'https://pay.coinbase.com/buy/select-asset?appId=your-app-id&addresses={"0xUserAddress":["tempo"]}', + '_blank' + ) + } + + return +} +``` + +## Full Example + +```typescript +// app/layout.tsx +import { Providers } from './providers' + +export default function RootLayout({ children }: { children: React.ReactNode }) { + return ( + + + {children} + + + ) +} + +// app/page.tsx +'use client' + +import { useAccount, useConnect, useDisconnect, useSendTransaction } from 'wagmi' +import { coinbaseWallet } from 'wagmi/connectors' +import { parseEther } from 'viem' + +export default function Home() { + const { address, isConnected } = useAccount() + const { connect } = useConnect() + const { disconnect } = useDisconnect() + const { sendTransaction } = useSendTransaction() + + if (!isConnected) { + return ( + + ) + } + + return ( +
+

Connected: {address}

+ + +
+ ) +} +``` + +## Environment Variables + +```bash +# .env.local +NEXT_PUBLIC_COINBASE_APP_NAME=My Tempo App +NEXT_PUBLIC_COINBASE_APP_LOGO=https://myapp.com/logo.png +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/coingecko.mdx b/src/pages/guides/integrations/coingecko.mdx new file mode 100644 index 00000000..fe767481 --- /dev/null +++ b/src/pages/guides/integrations/coingecko.mdx @@ -0,0 +1,580 @@ +--- +title: "CoinGecko for Tempo" +description: "Integrate CoinGecko price feeds with Tempo. Fetch stablecoin prices, market caps, historical data, and token metadata with TypeScript." +--- + +# CoinGecko for Tempo + +[CoinGecko](https://www.coingecko.com) provides comprehensive cryptocurrency data including prices, market caps, and historical charts. Use CoinGecko to display real-time stablecoin data in your Tempo dApp. + +## Why CoinGecko + +- **Comprehensive data** — Prices, volume, market cap, and supply for 10,000+ coins +- **Historical data** — Price charts, OHLCV data, and trend analysis +- **Stablecoin focus** — Dedicated endpoints for stablecoin market data +- **Free tier** — Generous rate limits for development and small apps + +## Installation + +```bash +pnpm install axios +``` + +Or use the official SDK: + +```bash +pnpm install coingecko-api-v3 +``` + +## API Setup + +### Initialize Client + +```typescript +// coingecko.ts +import axios, { AxiosInstance } from 'axios' + +interface CoinGeckoConfig { + apiKey?: string + pro?: boolean +} + +export function createCoinGeckoClient(config: CoinGeckoConfig = {}): AxiosInstance { + const baseURL = config.pro + ? 'https://pro-api.coingecko.com/api/v3' + : 'https://api.coingecko.com/api/v3' + + return axios.create({ + baseURL, + headers: config.apiKey ? { + 'x-cg-pro-api-key': config.apiKey + } : {} + }) +} + +export const coingecko = createCoinGeckoClient({ + apiKey: process.env.COINGECKO_API_KEY, + pro: !!process.env.COINGECKO_API_KEY +}) +``` + +### Using the Official SDK + +```typescript +import CoinGecko from 'coingecko-api-v3' + +const client = new CoinGecko({ + apiKey: process.env.COINGECKO_API_KEY, + timeout: 10000, + autoRetry: true +}) +``` + +## Fetching Stablecoin Prices + +### Get Current Prices + +```typescript +interface StablecoinPrice { + id: string + symbol: string + name: string + current_price: number + market_cap: number + total_volume: number + price_change_24h: number + price_change_percentage_24h: number +} + +const TEMPO_STABLECOINS = ['usd-coin', 'tether', 'dai', 'frax', 'true-usd'] + +async function getStablecoinPrices(): Promise { + const response = await coingecko.get('/coins/markets', { + params: { + vs_currency: 'usd', + ids: TEMPO_STABLECOINS.join(','), + order: 'market_cap_desc', + per_page: 100, + page: 1, + sparkline: false, + price_change_percentage: '24h' + } + }) + + return response.data +} +``` + +### Simple Price Query + +```typescript +interface SimplePrices { + [coinId: string]: { + usd: number + usd_market_cap?: number + usd_24h_vol?: number + usd_24h_change?: number + last_updated_at?: number + } +} + +async function getSimplePrices(coinIds: string[]): Promise { + const response = await coingecko.get('/simple/price', { + params: { + ids: coinIds.join(','), + vs_currencies: 'usd', + include_market_cap: true, + include_24hr_vol: true, + include_24hr_change: true, + include_last_updated_at: true + } + }) + + return response.data +} + +// Usage +const prices = await getSimplePrices(['usd-coin', 'tether', 'dai']) +console.log('USDC:', prices['usd-coin'].usd) +``` + +## Token Metadata + +### Get Coin Details + +```typescript +interface CoinDetail { + id: string + symbol: string + name: string + description: { en: string } + image: { thumb: string; small: string; large: string } + market_data: { + current_price: { usd: number } + market_cap: { usd: number } + total_volume: { usd: number } + circulating_supply: number + total_supply: number + } + contract_address: string + platforms: { [platform: string]: string } +} + +async function getCoinDetails(coinId: string): Promise { + const response = await coingecko.get(`/coins/${coinId}`, { + params: { + localization: false, + tickers: false, + market_data: true, + community_data: false, + developer_data: false + } + }) + + return response.data +} +``` + +### Get Token by Contract Address + +```typescript +interface TokenInfo { + id: string + symbol: string + name: string + image: { small: string } + market_data: { + current_price: { usd: number } + } +} + +async function getTokenByAddress( + platform: string, + contractAddress: string +): Promise { + const response = await coingecko.get( + `/coins/${platform}/contract/${contractAddress}` + ) + return response.data +} + +// Example: Get USDC info on Ethereum +const usdc = await getTokenByAddress( + 'ethereum', + '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' +) +``` + +## Historical Data + +### Price History + +```typescript +interface PriceHistory { + prices: [number, number][] // [timestamp, price] + market_caps: [number, number][] + total_volumes: [number, number][] +} + +async function getPriceHistory( + coinId: string, + days: number | 'max' = 30, + interval?: 'daily' | 'hourly' +): Promise { + const response = await coingecko.get(`/coins/${coinId}/market_chart`, { + params: { + vs_currency: 'usd', + days, + interval + } + }) + + return response.data +} + +// Get 7-day USDC price history +const history = await getPriceHistory('usd-coin', 7, 'hourly') +``` + +### OHLC Data + +```typescript +type OHLCData = [number, number, number, number, number][] // [time, open, high, low, close] + +async function getOHLC( + coinId: string, + days: 1 | 7 | 14 | 30 | 90 | 180 | 365 +): Promise { + const response = await coingecko.get(`/coins/${coinId}/ohlc`, { + params: { + vs_currency: 'usd', + days + } + }) + + return response.data +} +``` + +### Historical Price at Date + +```typescript +interface HistoricalData { + id: string + symbol: string + name: string + market_data: { + current_price: { usd: number } + market_cap: { usd: number } + } +} + +async function getPriceAtDate( + coinId: string, + date: string // DD-MM-YYYY format +): Promise { + const response = await coingecko.get(`/coins/${coinId}/history`, { + params: { date } + }) + + return response.data +} + +// Get USDC price on January 1, 2024 +const historical = await getPriceAtDate('usd-coin', '01-01-2024') +``` + +## Stablecoin Market Overview + +### Global Stablecoin Data + +```typescript +interface StablecoinMarket { + id: string + name: string + market_cap: number + market_cap_change_24h: number + content: string + top_coins: string[] +} + +async function getStablecoinMarket(): Promise { + const response = await coingecko.get('/coins/categories', { + params: { + order: 'market_cap_desc' + } + }) + + // Filter for stablecoin category + return response.data.filter((cat: any) => + cat.id === 'stablecoins' || cat.name.toLowerCase().includes('stablecoin') + ) +} +``` + +### Stablecoin Supply Data + +```typescript +interface StablecoinSupply { + id: string + symbol: string + circulating_supply: number + total_supply: number + max_supply: number | null +} + +async function getStablecoinSupply(coinId: string): Promise { + const coin = await getCoinDetails(coinId) + + return { + id: coin.id, + symbol: coin.symbol, + circulating_supply: coin.market_data.circulating_supply, + total_supply: coin.market_data.total_supply, + max_supply: null + } +} +``` + +## React Integration + +### Price Display Hook + +```typescript +'use client' + +import { useState, useEffect } from 'react' +import { coingecko } from './coingecko' + +interface PriceData { + price: number + change24h: number + marketCap: number + isLoading: boolean + error: Error | null +} + +export function useTokenPrice(coinId: string): PriceData { + const [data, setData] = useState({ + price: 0, + change24h: 0, + marketCap: 0, + isLoading: true, + error: null + }) + + useEffect(() => { + const fetchPrice = async () => { + try { + const response = await coingecko.get('/simple/price', { + params: { + ids: coinId, + vs_currencies: 'usd', + include_market_cap: true, + include_24hr_change: true + } + }) + + const coinData = response.data[coinId] + setData({ + price: coinData.usd, + change24h: coinData.usd_24h_change, + marketCap: coinData.usd_market_cap, + isLoading: false, + error: null + }) + } catch (error) { + setData(prev => ({ + ...prev, + isLoading: false, + error: error as Error + })) + } + } + + fetchPrice() + const interval = setInterval(fetchPrice, 60000) // Refresh every minute + + return () => clearInterval(interval) + }, [coinId]) + + return data +} +``` + +### Price Display Component + +```typescript +'use client' + +import { useTokenPrice } from './useTokenPrice' + +interface PriceDisplayProps { + coinId: string + symbol: string +} + +export function PriceDisplay({ coinId, symbol }: PriceDisplayProps) { + const { price, change24h, marketCap, isLoading, error } = useTokenPrice(coinId) + + if (isLoading) return Loading... + if (error) return Error loading price + + const changeColor = change24h >= 0 ? 'text-green-500' : 'text-red-500' + + return ( +
+

{symbol.toUpperCase()}

+

${price.toFixed(4)}

+

+ {change24h >= 0 ? '+' : ''}{change24h.toFixed(2)}% +

+

Market Cap: ${(marketCap / 1e9).toFixed(2)}B

+
+ ) +} +``` + +### Price Chart Component + +```typescript +'use client' + +import { useState, useEffect } from 'react' +import { coingecko } from './coingecko' + +interface ChartData { + timestamp: number + price: number +} + +export function PriceChart({ coinId }: { coinId: string }) { + const [data, setData] = useState([]) + const [days, setDays] = useState(7) + + useEffect(() => { + const fetchChart = async () => { + const response = await coingecko.get(`/coins/${coinId}/market_chart`, { + params: { + vs_currency: 'usd', + days + } + }) + + setData(response.data.prices.map(([timestamp, price]: [number, number]) => ({ + timestamp, + price + }))) + } + + fetchChart() + }, [coinId, days]) + + return ( +
+
+ {[1, 7, 30, 90].map(d => ( + + ))} +
+ {/* Render chart with your preferred charting library */} +
{JSON.stringify(data.slice(0, 5), null, 2)}
+
+ ) +} +``` + +## Server-Side API Route + +```typescript +// app/api/prices/route.ts +import { NextResponse } from 'next/server' +import { coingecko } from '@/lib/coingecko' + +export async function GET(request: Request) { + const { searchParams } = new URL(request.url) + const coins = searchParams.get('coins') || 'usd-coin,tether,dai' + + try { + const response = await coingecko.get('/simple/price', { + params: { + ids: coins, + vs_currencies: 'usd', + include_market_cap: true, + include_24hr_change: true + } + }) + + return NextResponse.json(response.data) + } catch (error) { + return NextResponse.json( + { error: 'Failed to fetch prices' }, + { status: 500 } + ) + } +} +``` + +## Rate Limiting + +### Handle Rate Limits + +```typescript +import axios from 'axios' + +const coingecko = axios.create({ + baseURL: 'https://api.coingecko.com/api/v3' +}) + +let lastRequestTime = 0 +const MIN_REQUEST_INTERVAL = 1200 // 50 requests/minute for free tier + +coingecko.interceptors.request.use(async (config) => { + const now = Date.now() + const timeSinceLastRequest = now - lastRequestTime + + if (timeSinceLastRequest < MIN_REQUEST_INTERVAL) { + await new Promise(resolve => + setTimeout(resolve, MIN_REQUEST_INTERVAL - timeSinceLastRequest) + ) + } + + lastRequestTime = Date.now() + return config +}) + +coingecko.interceptors.response.use( + response => response, + async error => { + if (error.response?.status === 429) { + // Rate limited - wait and retry + await new Promise(resolve => setTimeout(resolve, 60000)) + return coingecko.request(error.config) + } + throw error + } +) +``` + +## Environment Variables + +```bash +# .env.local +# Optional - for higher rate limits +COINGECKO_API_KEY=your-api-key +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/conduit.mdx b/src/pages/guides/integrations/conduit.mdx new file mode 100644 index 00000000..b8577e83 --- /dev/null +++ b/src/pages/guides/integrations/conduit.mdx @@ -0,0 +1,368 @@ +--- +title: "Conduit RPC Infrastructure for Tempo" +description: "High-performance RPC infrastructure for Tempo with Conduit. Enterprise-grade node hosting and rollup deployment." +--- + +# Conduit RPC Infrastructure for Tempo + +[Conduit](https://conduit.xyz) provides high-performance RPC infrastructure and rollup deployment services for blockchain applications. + +## Features + +- **Managed RPC** — High-availability node infrastructure +- **Custom rollups** — Deploy and manage L2 chains +- **Indexing** — Real-time blockchain data +- **Enterprise SLAs** — Guaranteed uptime and support + +## RPC Setup + +```typescript +import { createPublicClient, http, createWalletClient } from 'viem' +import { tempo } from 'viem/chains' + +const CONDUIT_RPC_URL = process.env.CONDUIT_RPC_URL! + +const publicClient = createPublicClient({ + chain: tempo, + transport: http(CONDUIT_RPC_URL) +}) + +const walletClient = createWalletClient({ + chain: tempo, + transport: http(CONDUIT_RPC_URL) +}) +``` + +## WebSocket Connection + +```typescript +import { createPublicClient, webSocket } from 'viem' +import { tempo } from 'viem/chains' + +const CONDUIT_WS_URL = process.env.CONDUIT_WS_URL! + +const wsClient = createPublicClient({ + chain: tempo, + transport: webSocket(CONDUIT_WS_URL) +}) + +// Subscribe to new blocks +wsClient.watchBlockNumber({ + onBlockNumber: (blockNumber) => { + console.log('New block:', blockNumber) + } +}) + +// Subscribe to pending transactions +wsClient.watchPendingTransactions({ + onTransactions: (hashes) => { + console.log('Pending txs:', hashes) + } +}) +``` + +## Batch Requests + +```typescript +async function batchRpcCalls() { + const results = await publicClient.multicall({ + contracts: [ + { + address: TOKEN_ADDRESS, + abi: erc20Abi, + functionName: 'balanceOf', + args: [userAddress] + }, + { + address: TOKEN_ADDRESS, + abi: erc20Abi, + functionName: 'totalSupply' + }, + { + address: TOKEN_ADDRESS, + abi: erc20Abi, + functionName: 'decimals' + } + ] + }) + + return { + balance: results[0].result, + totalSupply: results[1].result, + decimals: results[2].result + } +} +``` + +## Trace API + +```typescript +async function traceTransaction(txHash: string) { + const trace = await publicClient.request({ + method: 'debug_traceTransaction', + params: [txHash, { tracer: 'callTracer' }] + }) + + return trace +} + +async function traceCall(tx: { + from: string + to: string + data: string + value?: string +}) { + const trace = await publicClient.request({ + method: 'debug_traceCall', + params: [tx, 'latest', { tracer: 'callTracer' }] + }) + + return trace +} +``` + +## Archive Node Access + +```typescript +async function getHistoricalBalance( + address: string, + blockNumber: bigint +) { + const balance = await publicClient.getBalance({ + address: address as `0x${string}`, + blockNumber + }) + + return balance +} + +async function getHistoricalStorage( + contractAddress: string, + slot: string, + blockNumber: bigint +) { + const value = await publicClient.getStorageAt({ + address: contractAddress as `0x${string}`, + slot: slot as `0x${string}`, + blockNumber + }) + + return value +} +``` + +## Event Indexing + +```typescript +async function getLogs( + contractAddress: string, + eventSignature: string, + fromBlock: bigint, + toBlock: bigint +) { + const logs = await publicClient.getLogs({ + address: contractAddress as `0x${string}`, + event: { + type: 'event', + name: 'Transfer', + inputs: [ + { type: 'address', indexed: true, name: 'from' }, + { type: 'address', indexed: true, name: 'to' }, + { type: 'uint256', indexed: false, name: 'value' } + ] + }, + fromBlock, + toBlock + }) + + return logs +} + +// Paginated log fetching +async function getAllLogs( + contractAddress: string, + fromBlock: bigint, + toBlock: bigint, + batchSize = 2000n +) { + const allLogs = [] + let currentBlock = fromBlock + + while (currentBlock <= toBlock) { + const endBlock = currentBlock + batchSize > toBlock + ? toBlock + : currentBlock + batchSize + + const logs = await publicClient.getLogs({ + address: contractAddress as `0x${string}`, + fromBlock: currentBlock, + toBlock: endBlock + }) + + allLogs.push(...logs) + currentBlock = endBlock + 1n + } + + return allLogs +} +``` + +## Gas Estimation + +```typescript +async function estimateGas(tx: { + to: string + data: string + value?: bigint +}) { + const gasEstimate = await publicClient.estimateGas({ + to: tx.to as `0x${string}`, + data: tx.data as `0x${string}`, + value: tx.value + }) + + const gasPrice = await publicClient.getGasPrice() + const maxFeePerGas = await publicClient.estimateMaxPriorityFeePerGas() + + return { + gasLimit: gasEstimate, + gasPrice, + maxFeePerGas, + estimatedCost: gasEstimate * gasPrice + } +} +``` + +## Health Monitoring + +```typescript +async function checkRpcHealth() { + const start = Date.now() + + try { + const blockNumber = await publicClient.getBlockNumber() + const latency = Date.now() - start + + const block = await publicClient.getBlock({ blockNumber }) + const blockAge = Date.now() / 1000 - Number(block.timestamp) + + return { + healthy: true, + blockNumber, + latency, + blockAge, + synced: blockAge < 60 // Less than 60 seconds behind + } + } catch (error) { + return { + healthy: false, + error: error.message + } + } +} +``` + +## React Hook + +```typescript +import { useState, useEffect } from 'react' + +function useConduitRpc() { + const [health, setHealth] = useState<{ + healthy: boolean + latency?: number + blockNumber?: bigint + }>({ healthy: false }) + + useEffect(() => { + async function check() { + const result = await checkRpcHealth() + setHealth(result) + } + + check() + const interval = setInterval(check, 30000) // Check every 30s + return () => clearInterval(interval) + }, []) + + return { + publicClient, + walletClient, + health + } +} +``` + +## Failover Configuration + +```typescript +import { fallback, http } from 'viem' + +const primaryRpc = process.env.CONDUIT_RPC_URL! +const backupRpc = process.env.BACKUP_RPC_URL! + +const client = createPublicClient({ + chain: tempo, + transport: fallback([ + http(primaryRpc), + http(backupRpc) + ], { + rank: true, + retryCount: 3 + }) +}) +``` + +## Rate Limiting + +```typescript +class RateLimitedClient { + private requestCount = 0 + private resetTime = Date.now() + private readonly maxRequests = 100 + private readonly windowMs = 1000 + + async request(fn: () => Promise): Promise { + const now = Date.now() + + if (now > this.resetTime + this.windowMs) { + this.requestCount = 0 + this.resetTime = now + } + + if (this.requestCount >= this.maxRequests) { + const waitTime = this.resetTime + this.windowMs - now + await new Promise(r => setTimeout(r, waitTime)) + return this.request(fn) + } + + this.requestCount++ + return fn() + } +} + +const rateLimiter = new RateLimitedClient() + +async function getBalanceSafe(address: string) { + return rateLimiter.request(() => + publicClient.getBalance({ address: address as `0x${string}` }) + ) +} +``` + +## Environment Variables + +```bash +CONDUIT_RPC_URL=https://your-conduit-rpc.xyz +CONDUIT_WS_URL=wss://your-conduit-ws.xyz +BACKUP_RPC_URL=https://backup-rpc.xyz +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/crossmint.mdx b/src/pages/guides/integrations/crossmint.mdx new file mode 100644 index 00000000..7a3a44e8 --- /dev/null +++ b/src/pages/guides/integrations/crossmint.mdx @@ -0,0 +1,358 @@ +--- +title: "Crossmint Wallet Infrastructure for Tempo" +description: "Embedded wallets and NFT infrastructure for Tempo with Crossmint. Email login, fiat onramps, and seamless Web3 UX." +--- + +# Crossmint Wallet Infrastructure for Tempo + +[Crossmint](https://crossmint.com) provides embedded wallets, NFT minting, and fiat payment solutions for Tempo applications. + +## Features + +- **Embedded wallets** — Email and social login wallets +- **Fiat onramp** — Credit card payments for crypto +- **NFT minting API** — Create and distribute NFTs +- **Custodial & non-custodial** — Flexible wallet types + +## SDK Setup + +```bash +npm install @crossmint/client-sdk-react-ui +``` + +```typescript +import { + CrossmintProvider, + CrossmintAuthProvider, + CrossmintWalletProvider +} from '@crossmint/client-sdk-react-ui' + +const CROSSMINT_API_KEY = process.env.NEXT_PUBLIC_CROSSMINT_API_KEY! +``` + +## Embedded Wallet + +### React Provider + +```typescript +import { + CrossmintProvider, + CrossmintAuthProvider, + CrossmintWalletProvider +} from '@crossmint/client-sdk-react-ui' + +function App({ children }) { + return ( + + + + {children} + + + + ) +} +``` + +### Login with Email + +```typescript +import { useAuth, useWallet } from '@crossmint/client-sdk-react-ui' + +function LoginButton() { + const { login, logout, user, status } = useAuth() + const { wallet } = useWallet() + + if (status === 'initializing') return
Loading...
+ + if (status === 'logged-out') { + return + } + + return ( +
+

Logged in as {user?.email}

+

Wallet: {wallet?.address}

+ +
+ ) +} +``` + +### Get Wallet + +```typescript +import { useWallet } from '@crossmint/client-sdk-react-ui' + +function WalletInfo() { + const { wallet, status } = useWallet() + + if (status === 'loading-in-background') return
Loading wallet...
+ if (status !== 'loaded' || !wallet) return
No wallet connected
+ + return ( +
+

Address: {wallet.address}

+
+ ) +} +``` + +## Server-Side API + +### Create Wallet + +```typescript +const CROSSMINT_SERVER_KEY = process.env.CROSSMINT_SERVER_KEY! + +async function createWallet(email: string, chain = 'tempo') { + const response = await fetch('https://www.crossmint.com/api/v1-alpha2/wallets', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-API-KEY': CROSSMINT_SERVER_KEY + }, + body: JSON.stringify({ + type: 'evm-smart-wallet', + linkedUser: `email:${email}`, + chain + }) + }) + + const wallet = await response.json() + return { + address: wallet.address, + type: wallet.type, + chain: wallet.chain + } +} +``` + +### Get User Wallets + +```typescript +async function getUserWallets(email: string) { + const response = await fetch( + `https://www.crossmint.com/api/v1-alpha2/wallets?linkedUser=email:${encodeURIComponent(email)}`, + { + headers: { + 'X-API-KEY': CROSSMINT_SERVER_KEY + } + } + ) + + const data = await response.json() + return data.wallets +} +``` + +## Sign Transactions + +```typescript +import { useWallet } from '@crossmint/client-sdk-react-ui' + +function SendTransaction() { + const { wallet } = useWallet() + + async function handleSend() { + if (!wallet) return + + const tx = await wallet.send( + '0x...', // recipient address + 'usdc', // token symbol + '10.0' // amount + ) + + console.log('Transaction:', tx.explorerLink) + } + + return +} +``` + +## Fiat Onramp + +### Embed Payment + +```typescript +import { CrossmintPayButton } from '@crossmint/client-sdk-react-ui' + +function BuyWithCard() { + return ( + { + console.log('Purchase complete:', result) + }} + /> + ) +} +``` + +### Direct Fiat Purchase + +```typescript +async function createCheckoutSession( + recipientAddress: string, + amount: string, + currency = 'USD' +) { + const response = await fetch('https://www.crossmint.com/api/v1-alpha2/checkout/sessions', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-API-KEY': CROSSMINT_SERVER_KEY + }, + body: JSON.stringify({ + payment: { + method: 'fiat', + currency + }, + lineItems: [{ + quantity: 1, + price: amount, + metadata: { + name: 'USDC Purchase', + description: `Purchase ${amount} USDC` + } + }], + recipient: { + walletAddress: recipientAddress + }, + successUrl: 'https://your-app.com/success', + cancelUrl: 'https://your-app.com/cancel' + }) + }) + + const session = await response.json() + return session.checkoutUrl +} +``` + +## NFT Minting + +### Mint NFT + +```typescript +async function mintNFT( + collectionId: string, + recipientAddress: string, + metadata: { name: string; description: string; image: string } +) { + const response = await fetch( + `https://www.crossmint.com/api/2022-06-09/collections/${collectionId}/nfts`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-API-KEY': CROSSMINT_SERVER_KEY + }, + body: JSON.stringify({ + recipient: `tempo:${recipientAddress}`, + metadata + }) + } + ) + + const nft = await response.json() + return { + id: nft.id, + tokenId: nft.onChain?.tokenId, + status: nft.onChain?.status + } +} +``` + +### Create Collection + +```typescript +async function createCollection( + name: string, + symbol: string, + chain = 'tempo' +) { + const response = await fetch('https://www.crossmint.com/api/2022-06-09/collections', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-API-KEY': CROSSMINT_SERVER_KEY + }, + body: JSON.stringify({ + chain, + metadata: { + name, + symbol, + description: `${name} NFT Collection` + } + }) + }) + + const collection = await response.json() + return { + id: collection.id, + contractAddress: collection.onChain?.contractAddress + } +} +``` + +## Webhooks + +```typescript +import express from 'express' + +const app = express() + +app.post('/webhooks/crossmint', express.json(), (req, res) => { + const event = req.body + + switch (event.type) { + case 'wallet.created': + handleWalletCreated(event.data) + break + case 'transaction.completed': + handleTransactionCompleted(event.data) + break + case 'nft.minted': + handleNFTMinted(event.data) + break + case 'checkout.completed': + handleCheckoutCompleted(event.data) + break + } + + res.status(200).send('OK') +}) +``` + +## Environment Variables + +```bash +# Client-side +NEXT_PUBLIC_CROSSMINT_API_KEY=your-client-api-key + +# Server-side +CROSSMINT_SERVER_KEY=your-server-api-key +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/cybrid.mdx b/src/pages/guides/integrations/cybrid.mdx new file mode 100644 index 00000000..487dd126 --- /dev/null +++ b/src/pages/guides/integrations/cybrid.mdx @@ -0,0 +1,503 @@ +--- +title: "Cybrid Crypto Banking for Tempo" +description: "Crypto banking infrastructure for Tempo with Cybrid. Embedded crypto services, fiat integration, and compliance-first infrastructure." +--- + +# Cybrid Crypto Banking for Tempo + +[Cybrid](https://cybrid.xyz) provides crypto banking infrastructure enabling financial institutions to offer embedded crypto services with regulatory compliance. + +> **Note:** Cybrid's API documentation requires partner access. The examples in this guide are based on publicly available information and may require verification with Cybrid's official documentation after onboarding. + +## Features + +- **Embedded crypto** — White-label crypto services +- **Fiat integration** — Bank account connectivity +- **Compliance-first** — Built-in KYC/AML +- **Multi-asset** — Support for multiple cryptocurrencies + +## API Setup + +```typescript +const CYBRID_CLIENT_ID = process.env.CYBRID_CLIENT_ID +const CYBRID_CLIENT_SECRET = process.env.CYBRID_CLIENT_SECRET +const CYBRID_BASE_URL = 'https://api.cybrid.xyz' + +let accessToken: string | null = null + +async function getAccessToken() { + if (accessToken) return accessToken + + const response = await fetch(`${CYBRID_BASE_URL}/oauth/token`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + grant_type: 'client_credentials', + client_id: CYBRID_CLIENT_ID, + client_secret: CYBRID_CLIENT_SECRET, + scope: 'banks:read banks:write customers:read customers:write' + }) + }) + + const data = await response.json() + accessToken = data.access_token + return accessToken +} + +async function cybridRequest( + endpoint: string, + options: { method?: string; body?: any } = {} +) { + const token = await getAccessToken() + + const response = await fetch(`${CYBRID_BASE_URL}${endpoint}`, { + method: options.method || 'GET', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}` + }, + body: options.body ? JSON.stringify(options.body) : undefined + }) + return response.json() +} +``` + +## Customer Management + +### Create Customer + +```typescript +interface CustomerRequest { + type: 'individual' | 'business' + name?: { first: string; last: string } + businessName?: string + email: string + phone?: string + address?: { + street: string + city: string + state: string + postalCode: string + country: string + } +} + +async function createCustomer(request: CustomerRequest) { + const data = await cybridRequest('/api/customers', { + method: 'POST', + body: { + type: request.type, + name: request.name, + business_name: request.businessName, + email: request.email, + phone: request.phone, + address: request.address ? { + street: request.address.street, + city: request.address.city, + subdivision: request.address.state, + postal_code: request.address.postalCode, + country_code: request.address.country + } : undefined + } + }) + + return { + customerId: data.guid, + status: data.state, + type: data.type, + createdAt: data.created_at + } +} +``` + +### Get Customer + +```typescript +async function getCustomer(customerId: string) { + const data = await cybridRequest(`/api/customers/${customerId}`) + + return { + customerId: data.guid, + type: data.type, + status: data.state, + name: data.name, + email: data.email, + kycStatus: data.kyc_state, + createdAt: data.created_at + } +} +``` + +## Account Management + +### Create Account + +```typescript +async function createAccount( + customerId: string, + type: 'trading' | 'fiat' | 'crypto', + asset: string +) { + const data = await cybridRequest('/api/accounts', { + method: 'POST', + body: { + customer_guid: customerId, + type, + asset + } + }) + + return { + accountId: data.guid, + customerId: data.customer_guid, + type: data.type, + asset: data.asset, + state: data.state + } +} +``` + +### Get Account Balance + +```typescript +async function getAccountBalance(accountId: string) { + const data = await cybridRequest(`/api/accounts/${accountId}`) + + return { + accountId: data.guid, + asset: data.asset, + platformBalance: data.platform_balance, + availableBalance: data.platform_available, + pendingBalance: data.platform_pending + } +} +``` + +## Trading + +### Get Quote + +```typescript +async function getQuote( + customerId: string, + side: 'buy' | 'sell', + deliverAmount: number, + asset: string +) { + const data = await cybridRequest('/api/quotes', { + method: 'POST', + body: { + customer_guid: customerId, + side, + deliver_amount: deliverAmount, + symbol: `${asset}-USD` + } + }) + + return { + quoteId: data.guid, + side: data.side, + symbol: data.symbol, + deliverAmount: data.deliver_amount, + receiveAmount: data.receive_amount, + fee: data.fee, + expiresAt: data.expires_at + } +} +``` + +### Execute Trade + +```typescript +async function executeTrade(quoteId: string) { + const data = await cybridRequest('/api/trades', { + method: 'POST', + body: { + quote_guid: quoteId + } + }) + + return { + tradeId: data.guid, + quoteId: data.quote_guid, + side: data.side, + symbol: data.symbol, + deliverAmount: data.deliver_amount, + receiveAmount: data.receive_amount, + fee: data.fee, + state: data.state + } +} +``` + +### Get Trade Status + +```typescript +async function getTradeStatus(tradeId: string) { + const data = await cybridRequest(`/api/trades/${tradeId}`) + + return { + tradeId: data.guid, + state: data.state, + side: data.side, + symbol: data.symbol, + deliverAmount: data.deliver_amount, + receiveAmount: data.receive_amount, + settledAt: data.settled_at + } +} +``` + +## Transfers + +### Crypto Withdrawal to Tempo + +```typescript +async function withdrawToTempo( + accountId: string, + amount: number, + destinationAddress: string +) { + const data = await cybridRequest('/api/transfers', { + method: 'POST', + body: { + account_guid: accountId, + transfer_type: 'crypto', + amount, + destination_address: destinationAddress, + network: 'tempo' + } + }) + + return { + transferId: data.guid, + state: data.state, + amount: data.amount, + asset: data.asset, + txHash: data.network_transaction_hash + } +} +``` + +### Deposit from Tempo + +```typescript +async function getDepositAddress(accountId: string) { + const data = await cybridRequest(`/api/deposit_addresses`, { + method: 'POST', + body: { + account_guid: accountId, + network: 'tempo' + } + }) + + return { + address: data.address, + network: data.network, + asset: data.asset, + accountId: data.account_guid + } +} +``` + +## KYC/Identity Verification + +### Create Identity Verification + +```typescript +async function createIdentityVerification( + customerId: string, + type: 'kyc' | 'bank_account' +) { + const data = await cybridRequest('/api/identity_verifications', { + method: 'POST', + body: { + customer_guid: customerId, + type, + method: 'business_registration' // or 'id_and_selfie' for individuals + } + }) + + return { + verificationId: data.guid, + state: data.state, + type: data.type, + personaInquiryId: data.persona_inquiry_id + } +} +``` + +### Get Verification Status + +```typescript +async function getVerificationStatus(verificationId: string) { + const data = await cybridRequest( + `/api/identity_verifications/${verificationId}` + ) + + return { + verificationId: data.guid, + state: data.state, + outcome: data.outcome, + failureCodes: data.failure_codes + } +} +``` + +## Bank Accounts + +### Link Bank Account + +```typescript +async function linkBankAccount(customerId: string) { + const data = await cybridRequest('/api/external_bank_accounts', { + method: 'POST', + body: { + customer_guid: customerId, + plaid_processor_token: 'processor-token-from-plaid', + name: 'Main Checking' + } + }) + + return { + bankAccountId: data.guid, + state: data.state, + name: data.name, + asset: data.asset + } +} +``` + +### ACH Transfer + +```typescript +async function createACHTransfer( + externalBankAccountId: string, + accountId: string, + amount: number, + direction: 'deposit' | 'withdrawal' +) { + const data = await cybridRequest('/api/transfers', { + method: 'POST', + body: { + transfer_type: 'ach', + external_bank_account_guid: externalBankAccountId, + account_guid: accountId, + amount, + side: direction === 'deposit' ? 'deposit' : 'withdrawal' + } + }) + + return { + transferId: data.guid, + state: data.state, + amount: data.amount, + estimatedCompletionTime: data.estimated_completion_time + } +} +``` + +## Webhooks + +```typescript +import express from 'express' +import crypto from 'crypto' + +const app = express() + +function verifyWebhook(payload: string, signature: string) { + const expected = crypto + .createHmac('sha256', process.env.CYBRID_WEBHOOK_SECRET!) + .update(payload) + .digest('hex') + return crypto.timingSafeEqual( + Buffer.from(signature), + Buffer.from(expected) + ) +} + +app.post('/webhooks/cybrid', express.raw({ type: 'application/json' }), (req, res) => { + const signature = req.headers['x-cybrid-signature'] as string + + if (!verifyWebhook(req.body.toString(), signature)) { + return res.status(401).send('Invalid signature') + } + + const event = JSON.parse(req.body.toString()) + + switch (event.type) { + case 'customer.created': + handleCustomerCreated(event.data) + break + case 'trade.settled': + handleTradeSettled(event.data) + break + case 'transfer.completed': + handleTransferCompleted(event.data) + break + case 'identity_verification.completed': + handleVerificationCompleted(event.data) + break + } + + res.status(200).send('OK') +}) +``` + +## React Integration + +```typescript +import { useState } from 'react' + +function useCybridTrading() { + const [loading, setLoading] = useState(false) + const [quote, setQuote] = useState(null) + const [trade, setTrade] = useState(null) + + const getQuoteForBuy = async ( + customerId: string, + amount: number, + asset: string + ) => { + setLoading(true) + try { + const q = await getQuote(customerId, 'buy', amount, asset) + setQuote(q) + return q + } finally { + setLoading(false) + } + } + + const execute = async () => { + if (!quote) throw new Error('No quote') + setLoading(true) + try { + const t = await executeTrade(quote.quoteId) + setTrade(t) + return t + } finally { + setLoading(false) + } + } + + return { getQuoteForBuy, execute, loading, quote, trade } +} +``` + +## Environment Variables + +```bash +CYBRID_CLIENT_ID=your-client-id +CYBRID_CLIENT_SECRET=your-client-secret +CYBRID_WEBHOOK_SECRET=your-webhook-secret +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/dfns.mdx b/src/pages/guides/integrations/dfns.mdx new file mode 100644 index 00000000..0886c756 --- /dev/null +++ b/src/pages/guides/integrations/dfns.mdx @@ -0,0 +1,406 @@ +--- +title: "DFNS Wallet Infrastructure for Tempo" +description: "Enterprise wallet infrastructure for Tempo with DFNS. MPC key management, policy engine, and institutional-grade security." +--- + +# DFNS Wallet Infrastructure for Tempo + +[DFNS](https://dfns.co) provides enterprise-grade wallet infrastructure with MPC key management and policy controls for Tempo applications. + +## Features + +- **MPC key management** — Distributed key generation and signing +- **Policy engine** — Programmable transaction approvals +- **User wallets** — Delegated signing for end users +- **API-first** — Complete wallet operations via API + +## SDK Setup + +```bash +npm install @dfns/sdk @dfns/sdk-keysigner viem +``` + +```typescript +import { DfnsApiClient } from '@dfns/sdk' +import { AsymmetricKeySigner } from '@dfns/sdk-keysigner' + +const signer = new AsymmetricKeySigner({ + privateKey: process.env.DFNS_PRIVATE_KEY!, + credId: process.env.DFNS_CRED_ID!, + appOrigin: process.env.DFNS_APP_ORIGIN! +}) + +const dfns = new DfnsApiClient({ + appId: process.env.DFNS_APP_ID!, + authToken: process.env.DFNS_AUTH_TOKEN!, + baseUrl: 'https://api.dfns.io', + signer +}) +``` + +## Create Wallets + +### Create User Wallet + +```typescript +async function createWallet(userId: string) { + const wallet = await dfns.wallets.createWallet({ + body: { + network: 'EthereumSepolia', // Use appropriate Tempo network + name: `user-${userId}`, + externalId: userId + } + }) + + return { + walletId: wallet.id, + address: wallet.address, + network: wallet.network + } +} +``` + +### Get Wallet + +```typescript +async function getWallet(walletId: string) { + const wallet = await dfns.wallets.getWallet({ walletId }) + + return { + id: wallet.id, + address: wallet.address, + network: wallet.network, + status: wallet.status, + balance: wallet.balance + } +} + +async function getWalletByExternalId(userId: string) { + const wallets = await dfns.wallets.listWallets({ + externalId: userId + }) + + return wallets.items[0] +} +``` + +## Sign Transactions + +### Broadcast Transaction + +```typescript +import { encodeFunctionData, parseEther } from 'viem' + +async function sendTransaction( + walletId: string, + to: string, + value: bigint, + data?: `0x${string}` +) { + const tx = await dfns.wallets.broadcastTransaction({ + walletId, + body: { + kind: 'Evm', + to, + value: value.toString(), + data: data || '0x' + } + }) + + return { + txId: tx.id, + txHash: tx.txHash, + status: tx.status + } +} + +// Send native token +await sendTransaction(walletId, recipient, parseEther('1')) + +// Send ERC-20 +const transferData = encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: [recipient, amount] +}) +await sendTransaction(walletId, tokenAddress, 0n, transferData) +``` + +### Sign Message + +```typescript +async function signMessage(walletId: string, message: string) { + const signature = await dfns.wallets.generateSignature({ + walletId, + body: { + kind: 'Message', + message + } + }) + + return signature.signature +} +``` + +### Sign Typed Data + +```typescript +async function signTypedData( + walletId: string, + domain: any, + types: any, + message: any +) { + const signature = await dfns.wallets.generateSignature({ + walletId, + body: { + kind: 'Eip712', + types, + domain, + message + } + }) + + return signature.signature +} +``` + +## Policy Engine + +### Create Spending Policy + +```typescript +async function createSpendingPolicy( + walletId: string, + dailyLimitUsd: number +) { + const policy = await dfns.policies.createPolicy({ + body: { + name: `Spending limit - ${walletId}`, + effect: 'Allow', + activityKind: 'Wallets:BroadcastTransaction', + rule: { + kind: 'TransactionAmountLimit', + limit: dailyLimitUsd.toString(), + currency: 'USD' + }, + filters: [{ + field: 'walletId', + operator: 'eq', + value: walletId + }] + } + }) + + return policy +} +``` + +### Create Approval Policy + +```typescript +async function createApprovalPolicy( + walletId: string, + approvers: string[], + threshold: number +) { + const policy = await dfns.policies.createPolicy({ + body: { + name: `Multi-sig - ${walletId}`, + effect: 'RequestApproval', + activityKind: 'Wallets:BroadcastTransaction', + approvers: { + userIds: approvers, + quorum: threshold + }, + filters: [{ + field: 'walletId', + operator: 'eq', + value: walletId + }] + } + }) + + return policy +} +``` + +### Approve Pending Activity + +```typescript +async function approvePendingActivity(activityId: string) { + const approval = await dfns.policies.createPolicyApproval({ + body: { + activityId, + value: 'Approved' + } + }) + + return approval +} + +async function getPendingApprovals() { + const activities = await dfns.policies.listPolicyApprovals({ + status: 'Pending' + }) + + return activities.items.map(activity => ({ + id: activity.id, + kind: activity.kind, + status: activity.status, + requestedBy: activity.initiator, + createdAt: activity.dateCreated + })) +} +``` + +## Delegated Signing + +### End-User Registration + +```typescript +async function registerEndUser(userId: string, email: string) { + // Create end user + const user = await dfns.auth.createDelegatedRegistration({ + body: { + email, + externalId: userId + } + }) + + // Return registration challenge for client + return { + temporaryAuthToken: user.temporaryAuthenticationToken, + challenge: user.challenge + } +} +``` + +### End-User Signing + +```typescript +// Client-side: Complete registration with passkey +import { WebAuthnSigner } from '@dfns/sdk-browser' + +async function completeUserRegistration(challenge: any) { + const webAuthnSigner = new WebAuthnSigner() + const credential = await webAuthnSigner.create(challenge) + + await dfns.auth.completeDelegatedRegistration({ + body: { credential } + }) +} + +// User can now sign with their passkey +async function userSignTransaction(userWalletId: string, tx: any) { + const webAuthnSigner = new WebAuthnSigner() + + // Initiate transaction - returns challenge + const { challenge } = await dfns.wallets.broadcastTransaction({ + walletId: userWalletId, + body: tx + }) + + // User signs with passkey + const signature = await webAuthnSigner.sign(challenge) + + // Complete transaction + return dfns.wallets.completeTransaction({ + body: { signature } + }) +} +``` + +## Webhooks + +```typescript +import express from 'express' +import crypto from 'crypto' + +const app = express() + +function verifyWebhook(payload: string, signature: string) { + const expected = crypto + .createHmac('sha256', process.env.DFNS_WEBHOOK_SECRET!) + .update(payload) + .digest('hex') + return crypto.timingSafeEqual( + Buffer.from(signature), + Buffer.from(expected) + ) +} + +app.post('/webhooks/dfns', express.raw({ type: 'application/json' }), (req, res) => { + const signature = req.headers['x-dfns-signature'] as string + + if (!verifyWebhook(req.body.toString(), signature)) { + return res.status(401).send('Invalid signature') + } + + const event = JSON.parse(req.body.toString()) + + switch (event.kind) { + case 'transaction.broadcasted': + handleTransactionBroadcasted(event.data) + break + case 'transaction.confirmed': + handleTransactionConfirmed(event.data) + break + case 'policy.triggered': + handlePolicyTriggered(event.data) + break + } + + res.status(200).send('OK') +}) +``` + +## React Integration + +```typescript +import { DfnsWallet } from '@dfns/lib-viem' +import { createWalletClient, http } from 'viem' +import { tempo } from 'viem/chains' + +async function createDfnsWalletClient(walletId: string) { + const dfnsWallet = await DfnsWallet.init({ + walletId, + dfnsClient: dfns + }) + + const walletClient = createWalletClient({ + account: dfnsWallet, + chain: tempo, + transport: http() + }) + + return walletClient +} + +// Use with viem +const walletClient = await createDfnsWalletClient(walletId) +const hash = await walletClient.sendTransaction({ + to: recipient, + value: parseEther('1') +}) +``` + +## Environment Variables + +```bash +DFNS_APP_ID=your-app-id +DFNS_AUTH_TOKEN=your-auth-token +DFNS_PRIVATE_KEY=your-private-key +DFNS_CRED_ID=your-credential-id +DFNS_APP_ORIGIN=https://your-app.com +DFNS_WEBHOOK_SECRET=your-webhook-secret +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/due.mdx b/src/pages/guides/integrations/due.mdx new file mode 100644 index 00000000..cb80c598 --- /dev/null +++ b/src/pages/guides/integrations/due.mdx @@ -0,0 +1,456 @@ +--- +title: "Due Payment Orchestration for Tempo" +description: "Payment orchestration and stablecoin infrastructure for Tempo with Due. Unified APIs for payouts, collections, and treasury." +--- + +# Due Payment Orchestration for Tempo + +[Due](https://opendue.com) (OpenDue) provides payment orchestration infrastructure for managing payouts, collections, and treasury operations with stablecoin integration. + +## Features + +- **Payment orchestration** — Unified payment APIs +- **Multi-rail support** — Bank, card, crypto, and stablecoins +- **Treasury management** — Centralized fund management +- **Global payouts** — Send payments worldwide + +## API Setup + +```typescript +const DUE_API_KEY = process.env.DUE_API_KEY +const DUE_SECRET = process.env.DUE_SECRET +const DUE_BASE_URL = 'https://api.opendue.com/v1' + +async function dueRequest( + endpoint: string, + options: { method?: string; body?: any } = {} +) { + const response = await fetch(`${DUE_BASE_URL}${endpoint}`, { + method: options.method || 'GET', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${DUE_API_KEY}`, + 'X-Api-Secret': DUE_SECRET! + }, + body: options.body ? JSON.stringify(options.body) : undefined + }) + return response.json() +} +``` + +## Payouts + +### Create Payout + +```typescript +interface PayoutRequest { + amount: number + currency: string + method: 'bank' | 'stablecoin' | 'card' + recipient: { + email: string + name: string + bankDetails?: { + accountNumber: string + routingNumber: string + bankName: string + } + walletAddress?: string + } + reference?: string +} + +async function createPayout(request: PayoutRequest) { + const data = await dueRequest('/payouts', { + method: 'POST', + body: { + amount: request.amount, + currency: request.currency, + method: request.method, + recipient: { + email: request.recipient.email, + name: request.recipient.name, + bank_details: request.recipient.bankDetails ? { + account_number: request.recipient.bankDetails.accountNumber, + routing_number: request.recipient.bankDetails.routingNumber, + bank_name: request.recipient.bankDetails.bankName + } : undefined, + wallet_address: request.recipient.walletAddress, + network: request.method === 'stablecoin' ? 'tempo' : undefined + }, + reference: request.reference + } + }) + + return { + payoutId: data.payout_id, + status: data.status, + amount: data.amount, + currency: data.currency, + estimatedArrival: data.estimated_arrival + } +} +``` + +### Batch Payouts + +```typescript +interface BatchPayoutRequest { + payouts: Array<{ + amount: number + currency: string + method: 'bank' | 'stablecoin' + recipientEmail: string + recipientName: string + destination: string // Account number or wallet address + }> +} + +async function createBatchPayout(request: BatchPayoutRequest) { + const data = await dueRequest('/payouts/batch', { + method: 'POST', + body: { + payouts: request.payouts.map(p => ({ + amount: p.amount, + currency: p.currency, + method: p.method, + recipient: { + email: p.recipientEmail, + name: p.recipientName, + destination: p.destination, + network: p.method === 'stablecoin' ? 'tempo' : undefined + } + })) + } + }) + + return { + batchId: data.batch_id, + status: data.status, + totalAmount: data.total_amount, + payoutCount: data.payout_count, + payouts: data.payouts.map((p: any) => ({ + payoutId: p.payout_id, + status: p.status, + amount: p.amount + })) + } +} +``` + +### Get Payout Status + +```typescript +async function getPayoutStatus(payoutId: string) { + const data = await dueRequest(`/payouts/${payoutId}`) + + return { + payoutId: data.payout_id, + status: data.status, + amount: data.amount, + currency: data.currency, + method: data.method, + txHash: data.tx_hash, + createdAt: data.created_at, + completedAt: data.completed_at + } +} +``` + +## Collections + +### Create Invoice + +```typescript +interface InvoiceRequest { + amount: number + currency: string + customerEmail: string + description: string + dueDate?: string + acceptedMethods: ('bank' | 'card' | 'stablecoin')[] +} + +async function createInvoice(request: InvoiceRequest) { + const data = await dueRequest('/invoices', { + method: 'POST', + body: { + amount: request.amount, + currency: request.currency, + customer_email: request.customerEmail, + description: request.description, + due_date: request.dueDate, + accepted_methods: request.acceptedMethods, + stablecoin_options: { + network: 'tempo', + tokens: ['USDC', 'USDT'] + } + } + }) + + return { + invoiceId: data.invoice_id, + status: data.status, + paymentLink: data.payment_link, + qrCode: data.qr_code, + depositAddress: data.deposit_address + } +} +``` + +### Create Payment Link + +```typescript +async function createPaymentLink( + amount: number, + currency: string, + description: string +) { + const data = await dueRequest('/payment-links', { + method: 'POST', + body: { + amount, + currency, + description, + accepted_methods: ['stablecoin', 'card'], + stablecoin_options: { + network: 'tempo', + tokens: ['USDC'] + } + } + }) + + return { + linkId: data.link_id, + url: data.url, + qrCode: data.qr_code + } +} +``` + +## Treasury + +### Get Balances + +```typescript +async function getTreasuryBalances() { + const data = await dueRequest('/treasury/balances') + + return data.balances.map((balance: any) => ({ + currency: balance.currency, + available: balance.available, + pending: balance.pending, + reserved: balance.reserved + })) +} +``` + +### Internal Transfer + +```typescript +async function internalTransfer( + fromCurrency: string, + toCurrency: string, + amount: number +) { + const data = await dueRequest('/treasury/transfers', { + method: 'POST', + body: { + from_currency: fromCurrency, + to_currency: toCurrency, + amount + } + }) + + return { + transferId: data.transfer_id, + rate: data.rate, + fromAmount: data.from_amount, + toAmount: data.to_amount, + status: data.status + } +} +``` + +### Withdraw to Tempo + +```typescript +async function withdrawToTempo( + amount: number, + token: 'USDC' | 'USDT', + walletAddress: string +) { + const data = await dueRequest('/treasury/withdrawals', { + method: 'POST', + body: { + amount, + currency: token, + method: 'stablecoin', + network: 'tempo', + destination: walletAddress + } + }) + + return { + withdrawalId: data.withdrawal_id, + status: data.status, + txHash: data.tx_hash, + estimatedArrival: data.estimated_arrival + } +} +``` + +## Stablecoin Settlement + +### Enable Stablecoin Settlement + +```typescript +async function configureStablecoinSettlement( + walletAddress: string, + autoConvert: boolean = false +) { + const data = await dueRequest('/settings/settlement', { + method: 'PATCH', + body: { + stablecoin_enabled: true, + network: 'tempo', + wallet_address: walletAddress, + auto_convert: autoConvert, + settlement_token: 'USDC' + } + }) + + return { + enabled: data.stablecoin_enabled, + walletAddress: data.wallet_address, + autoConvert: data.auto_convert + } +} +``` + +### Get Settlement History + +```typescript +async function getSettlementHistory( + startDate: string, + endDate: string +) { + const data = await dueRequest( + `/settlements?start_date=${startDate}&end_date=${endDate}` + ) + + return data.settlements.map((settlement: any) => ({ + settlementId: settlement.settlement_id, + amount: settlement.amount, + currency: settlement.currency, + method: settlement.method, + txHash: settlement.tx_hash, + settledAt: settlement.settled_at + })) +} +``` + +## Webhooks + +```typescript +import express from 'express' +import crypto from 'crypto' + +const app = express() + +function verifyWebhook(payload: string, signature: string) { + const expected = crypto + .createHmac('sha256', process.env.DUE_WEBHOOK_SECRET!) + .update(payload) + .digest('hex') + return crypto.timingSafeEqual( + Buffer.from(signature), + Buffer.from(expected) + ) +} + +app.post('/webhooks/due', express.raw({ type: 'application/json' }), (req, res) => { + const signature = req.headers['x-due-signature'] as string + + if (!verifyWebhook(req.body.toString(), signature)) { + return res.status(401).send('Invalid signature') + } + + const event = JSON.parse(req.body.toString()) + + switch (event.type) { + case 'payout.completed': + handlePayoutCompleted(event.data) + break + case 'payout.failed': + handlePayoutFailed(event.data) + break + case 'invoice.paid': + handleInvoicePaid(event.data) + break + case 'settlement.completed': + handleSettlementCompleted(event.data) + break + } + + res.status(200).send('OK') +}) +``` + +## React Integration + +```typescript +import { useState } from 'react' + +function usePayouts() { + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + + const sendPayout = async (request: PayoutRequest) => { + setLoading(true) + setError(null) + + try { + return await createPayout(request) + } catch (e) { + setError(e as Error) + throw e + } finally { + setLoading(false) + } + } + + const sendBatchPayout = async (request: BatchPayoutRequest) => { + setLoading(true) + setError(null) + + try { + return await createBatchPayout(request) + } catch (e) { + setError(e as Error) + throw e + } finally { + setLoading(false) + } + } + + return { sendPayout, sendBatchPayout, loading, error } +} +``` + +## Environment Variables + +```bash +DUE_API_KEY=your-api-key +DUE_SECRET=your-secret +DUE_WEBHOOK_SECRET=your-webhook-secret +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/dynamic.mdx b/src/pages/guides/integrations/dynamic.mdx new file mode 100644 index 00000000..8a6188e7 --- /dev/null +++ b/src/pages/guides/integrations/dynamic.mdx @@ -0,0 +1,584 @@ +--- +title: "Dynamic Wallet SDK for Tempo" +description: "Integrate Dynamic for wallet authentication on Tempo. Social login, embedded wallets, and multi-chain support." +--- + +# Dynamic Wallet SDK for Tempo + +[Dynamic](https://www.dynamic.xyz) provides a complete wallet authentication solution for Tempo with social login, embedded wallets, and seamless multi-chain support. + +## Why Dynamic + +- **Social login** — Email, Google, Apple, Twitter, and more +- **Embedded wallets** — Non-custodial wallets without browser extensions +- **Multi-chain** — EVM, Solana, Bitcoin, and custom chains +- **Customizable UI** — Theming and white-label options + +## Installation + +```bash +pnpm install @dynamic-labs/sdk-react-core @dynamic-labs/ethereum viem wagmi @tanstack/react-query +``` + +## Quick Start + +### 1. Get Your Environment ID + +Create an app at [app.dynamic.xyz](https://app.dynamic.xyz) and copy your Environment ID. + +### 2. Configure Tempo Networks + +Define Tempo chains for Dynamic: + +```typescript +// config/chains.ts +import type { EvmNetwork } from '@dynamic-labs/sdk-react-core' + +export const tempoTestnet: EvmNetwork = { + blockExplorerUrls: ['https://explorer.moderato.tempo.xyz'], + chainId: 42431, + chainName: 'Tempo Testnet', + iconUrls: ['https://tempo.xyz/logo.png'], + name: 'Tempo Testnet', + nativeCurrency: { + decimals: 18, + name: 'USD', + symbol: 'USD', + }, + networkId: 42431, + rpcUrls: ['https://rpc.moderato.tempo.xyz'], + vanityName: 'Tempo Testnet', +} + +export const tempoMainnet: EvmNetwork = { + blockExplorerUrls: ['https://explorer.presto.tempo.xyz'], + chainId: 4217, + chainName: 'Tempo', + iconUrls: ['https://tempo.xyz/logo.png'], + name: 'Tempo', + nativeCurrency: { + decimals: 18, + name: 'USD', + symbol: 'USD', + }, + networkId: 4217, + rpcUrls: ['https://rpc.presto.tempo.xyz'], + vanityName: 'Tempo', +} +``` + +### 3. Set Up the Provider + +```typescript +// providers.tsx +'use client' + +import { DynamicContextProvider } from '@dynamic-labs/sdk-react-core' +import { EthereumWalletConnectors } from '@dynamic-labs/ethereum' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { tempoTestnet, tempoMainnet } from './config/chains' + +const queryClient = new QueryClient() + +export function Providers({ children }: { children: React.ReactNode }) { + return ( + + + {children} + + + ) +} +``` + +### 4. Add Login Button + +```typescript +'use client' + +import { DynamicWidget } from '@dynamic-labs/sdk-react-core' + +export function LoginButton() { + return +} +``` + +## Social Login Configuration + +### Enable Login Methods + +Configure in the Dynamic dashboard or via code: + +```typescript + + providers.filter(p => + ['google', 'apple', 'twitter', 'discord', 'github'].includes(p.name) + ) + }} +> +``` + +### Custom Login UI + +```typescript +'use client' + +import { useDynamicContext } from '@dynamic-labs/sdk-react-core' + +export function CustomLogin() { + const { setShowAuthFlow, handleLogOut, primaryWallet, user } = useDynamicContext() + + if (primaryWallet) { + return ( +
+

Welcome, {user?.email || primaryWallet.address}

+ +
+ ) + } + + return ( + + ) +} +``` + +## Embedded Wallets + +### Enable Embedded Wallets + +```typescript + +``` + +### Access Embedded Wallet + +```typescript +'use client' + +import { useDynamicContext, useEmbeddedWallet } from '@dynamic-labs/sdk-react-core' + +export function WalletInfo() { + const { primaryWallet } = useDynamicContext() + const { embeddedWallet } = useEmbeddedWallet() + + return ( +
+

Address: {primaryWallet?.address}

+

Is Embedded: {embeddedWallet ? 'Yes' : 'No'}

+
+ ) +} +``` + +### Export Embedded Wallet + +```typescript +import { useEmbeddedWallet } from '@dynamic-labs/sdk-react-core' + +export function ExportWallet() { + const { userHasEmbeddedWallet, exportWallet } = useEmbeddedWallet() + + if (!userHasEmbeddedWallet()) return null + + return ( + + ) +} +``` + +## Transaction Signing + +### Sign and Send Transaction + +```typescript +'use client' + +import { useDynamicContext } from '@dynamic-labs/sdk-react-core' +import { createWalletClient, custom, parseEther } from 'viem' +import { tempoTestnet } from 'viem/chains' + +export function SendTransaction() { + const { primaryWallet } = useDynamicContext() + + const send = async () => { + if (!primaryWallet) return + + const provider = await primaryWallet.getWalletClient() + + const client = createWalletClient({ + chain: tempoTestnet({ + feeToken: '0x20c0000000000000000000000000000000000001' + }), + transport: custom(provider) + }) + + const hash = await client.sendTransaction({ + to: '0xRecipient', + value: parseEther('10') + }) + + console.log('Transaction hash:', hash) + } + + return +} +``` + +### Sign Message + +```typescript +export function SignMessage() { + const { primaryWallet } = useDynamicContext() + + const sign = async () => { + if (!primaryWallet) return + + const signature = await primaryWallet.signMessage('Hello from Tempo!') + console.log('Signature:', signature) + } + + return +} +``` + +### Sign Typed Data (EIP-712) + +```typescript +export function SignTypedData() { + const { primaryWallet } = useDynamicContext() + + const sign = async () => { + if (!primaryWallet) return + + const provider = await primaryWallet.getWalletClient() + + const signature = await provider.signTypedData({ + domain: { + name: 'My App', + version: '1', + chainId: 42431, + verifyingContract: '0x...' + }, + types: { + Transfer: [ + { name: 'to', type: 'address' }, + { name: 'amount', type: 'uint256' } + ] + }, + primaryType: 'Transfer', + message: { + to: '0xRecipient', + amount: parseEther('100') + } + }) + + console.log('Signature:', signature) + } + + return +} +``` + +## Chain Switching + +### Switch to Tempo + +```typescript +'use client' + +import { useDynamicContext } from '@dynamic-labs/sdk-react-core' + +export function ChainSwitcher() { + const { primaryWallet, network } = useDynamicContext() + + const switchToTempoTestnet = async () => { + if (!primaryWallet) return + await primaryWallet.switchNetwork(42431) + } + + const switchToTempoMainnet = async () => { + if (!primaryWallet) return + await primaryWallet.switchNetwork(4217) + } + + return ( +
+

Current Chain: {network?.chainId}

+ + +
+ ) +} +``` + +### Auto-Switch on Connect + +```typescript + +``` + +## Multi-Wallet Support + +### Access All Connected Wallets + +```typescript +import { useDynamicContext } from '@dynamic-labs/sdk-react-core' + +export function WalletList() { + const { connectedWallets, primaryWallet, setPrimaryWallet } = useDynamicContext() + + return ( +
+

Connected Wallets

+ {connectedWallets.map((wallet) => ( +
+

{wallet.address}

+

{wallet.connector?.name}

+ {wallet !== primaryWallet && ( + + )} +
+ ))} +
+ ) +} +``` + +## Customization + +### Theme Configuration + +```typescript + +``` + +### Custom Modal + +```typescript +import { DynamicConnectButton } from '@dynamic-labs/sdk-react-core' + +export function CustomConnectButton() { + return ( + + + + ) +} +``` + +## Wagmi Integration + +### Configure with Wagmi + +```typescript +// providers.tsx +import { DynamicContextProvider } from '@dynamic-labs/sdk-react-core' +import { DynamicWagmiConnector } from '@dynamic-labs/wagmi-connector' +import { EthereumWalletConnectors } from '@dynamic-labs/ethereum' +import { createConfig, WagmiProvider, http } from 'wagmi' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { tempoTestnet, tempoMainnet } from './config/chains' + +const wagmiConfig = createConfig({ + chains: [tempoTestnet, tempoMainnet], + transports: { + [tempoTestnet.chainId]: http('https://rpc.moderato.tempo.xyz'), + [tempoMainnet.chainId]: http('https://rpc.presto.tempo.xyz'), + }, +}) + +const queryClient = new QueryClient() + +export function Providers({ children }) { + return ( + + + + + {children} + + + + + ) +} +``` + +### Use Wagmi Hooks + +```typescript +import { useBalance, useSendTransaction } from 'wagmi' +import { parseEther } from 'viem' + +export function WagmiExample() { + const { data: balance } = useBalance({ address: '0x...' }) + const { sendTransaction, isPending } = useSendTransaction() + + return ( +
+

Balance: {balance?.formatted} {balance?.symbol}

+ +
+ ) +} +``` + +## Event Handlers + +```typescript + { + console.log('Auth successful:', args.user) + }, + onLogout: () => { + console.log('User logged out') + }, + onWalletAdded: (wallet) => { + console.log('Wallet connected:', wallet.address) + }, + onWalletRemoved: (wallet) => { + console.log('Wallet disconnected:', wallet.address) + } + } + }} +> +``` + +## Environment Variables + +```bash +# .env.local +NEXT_PUBLIC_DYNAMIC_ENVIRONMENT_ID=your-environment-id +``` + +## Full Example + +```typescript +// app/layout.tsx +import { Providers } from './providers' + +export default function RootLayout({ children }) { + return ( + + + {children} + + + ) +} + +// app/page.tsx +'use client' + +import { DynamicWidget, useDynamicContext } from '@dynamic-labs/sdk-react-core' +import { parseEther } from 'viem' + +export default function Home() { + const { primaryWallet, user } = useDynamicContext() + + const sendTransaction = async () => { + if (!primaryWallet) return + + const client = await primaryWallet.getWalletClient() + const hash = await client.sendTransaction({ + to: '0xRecipient', + value: parseEther('10') + }) + + console.log('Transaction:', hash) + } + + return ( +
+ + + {primaryWallet && ( +
+

Welcome to Tempo

+

Email: {user?.email}

+

Wallet: {primaryWallet.address}

+ +
+ )} +
+ ) +} +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/elliptic.mdx b/src/pages/guides/integrations/elliptic.mdx new file mode 100644 index 00000000..cd6dce85 --- /dev/null +++ b/src/pages/guides/integrations/elliptic.mdx @@ -0,0 +1,378 @@ +--- +title: "Elliptic Compliance for Tempo" +description: "Crypto asset risk management and compliance for Tempo with Elliptic. Transaction screening, wallet analysis, and AML solutions." +--- + +# Elliptic Compliance for Tempo + +[Elliptic](https://elliptic.co) provides crypto asset risk management, transaction screening, and compliance solutions for Tempo applications. + +## Features + +- **Wallet screening** — Risk assessment for addresses +- **Transaction screening** — Real-time monitoring +- **Holistic screening** — Cross-chain analysis +- **Sanctions compliance** — OFAC and global sanctions + +## API Setup + +```typescript +const ELLIPTIC_API_KEY = process.env.ELLIPTIC_API_KEY +const ELLIPTIC_SECRET = process.env.ELLIPTIC_SECRET +const ELLIPTIC_BASE_URL = 'https://aml-api.elliptic.co' + +async function ellipticRequest(endpoint: string, body?: any) { + const timestamp = Date.now().toString() + const method = body ? 'POST' : 'GET' + const signature = createSignature(method, endpoint, timestamp, body) + + const response = await fetch(`${ELLIPTIC_BASE_URL}${endpoint}`, { + method, + headers: { + 'Content-Type': 'application/json', + 'x-access-key': ELLIPTIC_API_KEY!, + 'x-access-sign': signature, + 'x-access-timestamp': timestamp + }, + body: body ? JSON.stringify(body) : undefined + }) + return response.json() +} + +function createSignature( + method: string, + endpoint: string, + timestamp: string, + body?: any +) { + const crypto = require('crypto') + const message = timestamp + method.toUpperCase() + endpoint + (body ? JSON.stringify(body) : '') + const decodedSecret = Buffer.from(ELLIPTIC_SECRET!, 'base64') + return crypto + .createHmac('sha256', decodedSecret) + .update(message) + .digest('base64') +} +``` + +## Wallet Screening + +### Screen Single Wallet + +```typescript +interface WalletScreeningResult { + address: string + riskScore: number + riskLevel: 'low' | 'medium' | 'high' | 'severe' + sanctions: boolean + categories: Array<{ + name: string + riskWeight: number + exposurePercent: number + }> +} + +async function screenWallet(address: string): Promise { + const result = await ellipticRequest('/v2/wallet/synchronous', { + subject: { + asset: 'holistic', + blockchain: 'ethereum', + type: 'address', + hash: address + }, + type: 'wallet_exposure' + }) + + return { + address, + riskScore: result.risk_score, + riskLevel: mapRiskLevel(result.risk_score), + sanctions: result.cluster_entities?.some((e: any) => e.is_sanctioned) || false, + categories: result.cluster_exposures?.map((exp: any) => ({ + name: exp.category, + riskWeight: exp.risk_weight, + exposurePercent: exp.exposure_percent + })) || [] + } +} + +function mapRiskLevel(score: number) { + if (score >= 8) return 'severe' + if (score >= 6) return 'high' + if (score >= 3) return 'medium' + return 'low' +} +``` + +### Batch Screening + +```typescript +async function batchScreenWallets(addresses: string[]) { + const results = await Promise.all( + addresses.map(addr => screenWallet(addr)) + ) + + return { + total: results.length, + highRisk: results.filter(r => r.riskLevel === 'high' || r.riskLevel === 'severe'), + sanctioned: results.filter(r => r.sanctions), + results + } +} +``` + +## Transaction Screening + +### Screen Transaction + +```typescript +interface TransactionScreeningRequest { + txHash: string + fromAddress: string + toAddress: string + amount: string + asset: string +} + +async function screenTransaction(tx: TransactionScreeningRequest) { + const result = await ellipticRequest('/v2/analyses/synchronous', { + subject: { + asset: tx.asset, + blockchain: 'ethereum', + type: 'transaction', + hash: tx.txHash, + output_type: 'address', + output_address: tx.toAddress + }, + type: 'destination_of_funds', + customer_reference: tx.txHash + }) + + return { + txHash: tx.txHash, + riskScore: result.risk_score, + riskIndicators: result.risk_indicators, + triggered_rules: result.triggered_rules, + requiresReview: result.risk_score >= 6 + } +} +``` + +### Continuous Transaction Monitoring + +```typescript +async function registerTransactionForMonitoring( + txHash: string, + userId: string +) { + const result = await ellipticRequest('/v2/transactions', { + blockchain: 'ethereum', + hash: txHash, + customer_reference: userId, + callback_url: 'https://your-api.com/webhooks/elliptic' + }) + + return { + analysisId: result.id, + status: result.status + } +} +``` + +## Sanctions Checking + +```typescript +async function checkSanctions(address: string) { + const result = await ellipticRequest('/v2/wallet/synchronous', { + subject: { + asset: 'holistic', + blockchain: 'ethereum', + type: 'address', + hash: address + }, + type: 'wallet_exposure' + }) + + const sanctionedEntities = result.cluster_entities?.filter( + (e: any) => e.is_sanctioned + ) || [] + + return { + address, + isSanctioned: sanctionedEntities.length > 0, + entities: sanctionedEntities.map((e: any) => ({ + name: e.name, + program: e.sanction_program, + addedDate: e.sanction_date + })) + } +} +``` + +## Integration Patterns + +### Pre-Transaction Validation + +```typescript +async function validateBeforeTransfer( + from: string, + to: string, + amount: string +): Promise<{ allowed: boolean; reason?: string }> { + // Check sanctions first + const sanctions = await checkSanctions(to) + if (sanctions.isSanctioned) { + return { + allowed: false, + reason: `Sanctioned entity: ${sanctions.entities[0]?.name}` + } + } + + // Screen recipient wallet + const screening = await screenWallet(to) + + if (screening.riskLevel === 'severe') { + return { + allowed: false, + reason: 'Recipient is severe risk' + } + } + + if (screening.riskLevel === 'high') { + // Allow small amounts, flag larger ones + const amountNum = parseFloat(amount) + if (amountNum > 10000) { + return { + allowed: false, + reason: 'High-risk recipient, amount exceeds threshold' + } + } + } + + return { allowed: true } +} +``` + +### Onboarding Screening + +```typescript +async function screenNewUser(walletAddress: string) { + const screening = await screenWallet(walletAddress) + const sanctions = await checkSanctions(walletAddress) + + if (sanctions.isSanctioned) { + return { + status: 'rejected', + reason: 'Wallet associated with sanctioned entity' + } + } + + switch (screening.riskLevel) { + case 'severe': + return { status: 'rejected', reason: 'Severe risk wallet' } + case 'high': + return { status: 'pending_review', reason: 'High risk wallet' } + case 'medium': + return { status: 'approved', tier: 'enhanced_monitoring' } + default: + return { status: 'approved', tier: 'standard' } + } +} +``` + +### Webhook Handler + +```typescript +import express from 'express' +import crypto from 'crypto' + +const app = express() + +function verifySignature(body: string, signature: string, timestamp: string) { + const expected = crypto + .createHmac('sha256', process.env.ELLIPTIC_WEBHOOK_SECRET!) + .update(timestamp + body) + .digest('base64') + return crypto.timingSafeEqual( + Buffer.from(signature), + Buffer.from(expected) + ) +} + +app.post('/webhooks/elliptic', express.raw({ type: 'application/json' }), (req, res) => { + const signature = req.headers['x-elliptic-signature'] as string + const timestamp = req.headers['x-elliptic-timestamp'] as string + + if (!verifySignature(req.body.toString(), signature, timestamp)) { + return res.status(401).send('Invalid signature') + } + + const event = JSON.parse(req.body.toString()) + + switch (event.type) { + case 'analysis_complete': + handleAnalysisComplete(event.data) + break + case 'risk_score_updated': + handleRiskUpdate(event.data) + break + case 'sanctions_match': + handleSanctionsMatch(event.data) + break + } + + res.status(200).send('OK') +}) +``` + +## Risk Categories + +| Category | Risk Weight | Description | +|----------|-------------|-------------| +| Sanctions | 10 | OFAC, UN, EU sanctions | +| Ransomware | 10 | Known ransomware addresses | +| Terrorist Financing | 10 | Terrorism-linked entities | +| Dark Web | 8 | Darknet marketplace activity | +| Stolen Funds | 8 | Known theft or hack proceeds | +| Fraud | 7 | Scam and fraud addresses | +| Mixer | 5 | Mixing service usage | +| Gambling | 3 | Gambling platform exposure | +| Exchange | 1 | Centralized exchange activity | + +## Compliance Dashboard + +```typescript +async function getComplianceMetrics(startDate: Date, endDate: Date) { + const screenings = await getScreeningsInRange(startDate, endDate) + + return { + period: { startDate, endDate }, + totalScreenings: screenings.length, + byRiskLevel: { + severe: screenings.filter(s => s.riskLevel === 'severe').length, + high: screenings.filter(s => s.riskLevel === 'high').length, + medium: screenings.filter(s => s.riskLevel === 'medium').length, + low: screenings.filter(s => s.riskLevel === 'low').length + }, + sanctionsMatches: screenings.filter(s => s.sanctions).length, + blockedTransactions: screenings.filter(s => s.blocked).length + } +} +``` + +## Environment Variables + +```bash +ELLIPTIC_API_KEY=your-api-key +ELLIPTIC_SECRET=your-secret +ELLIPTIC_WEBHOOK_SECRET=your-webhook-secret +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/fireblocks.mdx b/src/pages/guides/integrations/fireblocks.mdx new file mode 100644 index 00000000..dce6df12 --- /dev/null +++ b/src/pages/guides/integrations/fireblocks.mdx @@ -0,0 +1,572 @@ +--- +title: "Fireblocks Enterprise Custody for Tempo" +description: "Institutional wallet infrastructure for Tempo with Fireblocks. MPC signing, vault management, and enterprise-grade security." +--- + +# Fireblocks Enterprise Custody for Tempo + +[Fireblocks](https://www.fireblocks.com) provides institutional-grade wallet infrastructure for Tempo with MPC-based signing, vault management, and enterprise security controls. + +## Why Fireblocks + +- **MPC security** — Multi-party computation eliminates single points of failure +- **Policy engine** — Granular transaction approval workflows +- **Vault management** — Hierarchical account structure +- **Compliance** — SOC 2 Type II, ISO 27001 certified + +## Installation + +### JavaScript/TypeScript + +```bash +pnpm install fireblocks-sdk viem +``` + +### Python + +```bash +pip install fireblocks-sdk web3 +``` + +## SDK Setup + +### JavaScript/TypeScript + +```typescript +import { FireblocksSDK } from 'fireblocks-sdk' +import fs from 'fs' + +const apiSecret = fs.readFileSync('./fireblocks_secret.key', 'utf8') + +const fireblocks = new FireblocksSDK( + apiSecret, + process.env.FIREBLOCKS_API_KEY!, + process.env.FIREBLOCKS_API_URL || 'https://api.fireblocks.io' +) +``` + +### Python + +```python +from fireblocks_sdk import FireblocksSDK + +api_secret = open('./fireblocks_secret.key', 'r').read() + +fireblocks = FireblocksSDK( + private_key=api_secret, + api_key=os.environ['FIREBLOCKS_API_KEY'], + api_base_url=os.environ.get('FIREBLOCKS_API_URL', 'https://api.fireblocks.io') +) +``` + +## Network Configuration + +Configure Tempo as a custom EVM network in Fireblocks: + +| Parameter | Testnet | Mainnet | +|-----------|---------|---------| +| Network Name | Tempo Testnet | Tempo | +| Chain ID | 42431 | 4217 | +| RPC URL | `https://rpc.moderato.tempo.xyz` | `https://rpc.presto.tempo.xyz` | +| Explorer | `https://explorer.moderato.tempo.xyz` | `https://explorer.presto.tempo.xyz` | +| Asset Symbol | USD | USD | + +## Vault Management + +### Create a Vault Account + +```typescript +const vault = await fireblocks.createVaultAccount({ + name: 'Tempo Treasury', + hiddenOnUI: false, + customerRefId: 'treasury-001', + autoFuel: false +}) + +console.log('Vault ID:', vault.id) +console.log('Vault Name:', vault.name) +``` + +### List Vault Accounts + +```typescript +const vaults = await fireblocks.getVaultAccountsWithPageInfo({ + namePrefix: 'Tempo', + orderBy: 'ASC', + limit: 100 +}) + +for (const vault of vaults.accounts) { + console.log(`${vault.name}: ${vault.id}`) +} +``` + +### Get Vault Details + +```typescript +const vault = await fireblocks.getVaultAccountById(vaultId) + +console.log('Name:', vault.name) +console.log('Assets:', vault.assets) +``` + +## Asset Management + +### Add Tempo Asset to Vault + +```typescript +// Add Tempo (custom EVM) to a vault +const asset = await fireblocks.createVaultAsset( + vaultId, + 'TEMPO' // Asset ID configured in Fireblocks +) + +console.log('Address:', asset.address) +``` + +### Get Asset Balance + +```typescript +const balance = await fireblocks.getVaultAccountAsset( + vaultId, + 'TEMPO' +) + +console.log('Balance:', balance.total) +console.log('Available:', balance.available) +console.log('Pending:', balance.pending) +``` + +### Refresh Asset Balance + +```typescript +const balance = await fireblocks.refreshVaultAssetBalance( + vaultId, + 'TEMPO' +) + +console.log('Updated balance:', balance.total) +``` + +## Transaction Signing + +### Send Transaction + +```typescript +import { TransactionOperation, PeerType } from 'fireblocks-sdk' + +const tx = await fireblocks.createTransaction({ + operation: TransactionOperation.TRANSFER, + assetId: 'TEMPO', + source: { + type: PeerType.VAULT_ACCOUNT, + id: sourceVaultId + }, + destination: { + type: PeerType.ONE_TIME_ADDRESS, + oneTimeAddress: { + address: '0xRecipientAddress' + } + }, + amount: '100', // 100 USD + note: 'Payment for services', + customerRefId: 'payment-001' +}) + +console.log('Transaction ID:', tx.id) +console.log('Status:', tx.status) +``` + +### Contract Interaction + +```typescript +import { TransactionOperation, PeerType } from 'fireblocks-sdk' +import { encodeFunctionData, erc20Abi } from 'viem' + +const USDC_ADDRESS = '0x20c0000000000000000000000000000000000001' + +// Encode the transfer function call +const data = encodeFunctionData({ + abi: erc20Abi, + functionName: 'transfer', + args: ['0xRecipient', 1000000n] // 1 USDC +}) + +const tx = await fireblocks.createTransaction({ + operation: TransactionOperation.CONTRACT_CALL, + assetId: 'TEMPO', + source: { + type: PeerType.VAULT_ACCOUNT, + id: sourceVaultId + }, + destination: { + type: PeerType.ONE_TIME_ADDRESS, + oneTimeAddress: { + address: USDC_ADDRESS + } + }, + amount: '0', + extraParameters: { + contractCallData: data + }, + note: 'USDC Transfer' +}) + +console.log('Transaction ID:', tx.id) +``` + +### Raw Message Signing + +```typescript +import { TransactionOperation } from 'fireblocks-sdk' + +const message = 'Hello from Tempo!' +const messageHash = keccak256(toBytes(message)) + +const tx = await fireblocks.createTransaction({ + operation: TransactionOperation.RAW, + assetId: 'TEMPO', + source: { + type: PeerType.VAULT_ACCOUNT, + id: vaultId + }, + extraParameters: { + rawMessageData: { + messages: [{ + content: messageHash.slice(2), // Remove 0x prefix + bip44addressIndex: 0 + }] + } + } +}) + +// Wait for completion and get signature +const result = await waitForTransaction(tx.id) +console.log('Signature:', result.signedMessages[0].signature) +``` + +### Monitor Transaction Status + +```typescript +async function waitForTransaction(txId: string): Promise { + while (true) { + const tx = await fireblocks.getTransactionById(txId) + + if (['COMPLETED', 'FAILED', 'CANCELLED', 'BLOCKED'].includes(tx.status)) { + return tx + } + + console.log(`Status: ${tx.status}`) + await new Promise(resolve => setTimeout(resolve, 2000)) + } +} + +const result = await waitForTransaction(tx.id) + +if (result.status === 'COMPLETED') { + console.log('Transaction hash:', result.txHash) +} else { + console.error('Transaction failed:', result.subStatus) +} +``` + +## Policy Controls + +### Create Transaction Policy + +Configure policies in the Fireblocks console or via API: + +```typescript +// Example policy: Require approval for transfers > $10,000 +const policy = await fireblocks.setTransactionApprovalPolicy({ + rules: [ + { + transactionType: 'TRANSFER', + asset: 'TEMPO', + amountCurrency: 'USD', + amountScope: 'SINGLE_TX', + amount: 10000, + operator: 'GREATER_THAN', + action: 'REQUIRE_APPROVAL', + authorizationGroups: [ + { + users: ['user-1', 'user-2'], + threshold: 2 // 2-of-2 approval required + } + ] + } + ] +}) +``` + +### Spending Limits + +```typescript +// Set daily spending limit +const policy = await fireblocks.setTransactionApprovalPolicy({ + rules: [ + { + transactionType: 'TRANSFER', + asset: 'TEMPO', + amountCurrency: 'USD', + amountScope: 'TIME_PERIOD', + timePeriod: { + value: 1, + unit: 'DAY' + }, + amount: 100000, + operator: 'GREATER_THAN', + action: 'BLOCK' + } + ] +}) +``` + +### Whitelist Destinations + +```typescript +// Create a whitelisted address +const whitelist = await fireblocks.createExternalWallet({ + name: 'Approved Vendor', + customerRefId: 'vendor-001' +}) + +await fireblocks.createExternalWalletAsset( + whitelist.id, + 'TEMPO', + '0xVendorAddress' +) + +// Transaction to whitelisted address +const tx = await fireblocks.createTransaction({ + operation: TransactionOperation.TRANSFER, + assetId: 'TEMPO', + source: { + type: PeerType.VAULT_ACCOUNT, + id: vaultId + }, + destination: { + type: PeerType.EXTERNAL_WALLET, + id: whitelist.id + }, + amount: '5000' +}) +``` + +## Python Examples + +### Create and Fund Vault + +```python +from fireblocks_sdk import FireblocksSDK, TransferPeerPath, DestinationTransferPeerPath + +# Create vault +vault = fireblocks.create_vault_account(name='Tempo Operations') +print(f"Vault ID: {vault['id']}") + +# Add Tempo asset +asset = fireblocks.create_vault_asset(vault['id'], 'TEMPO') +print(f"Address: {asset['address']}") +``` + +### Send Transaction + +```python +from fireblocks_sdk import TransferPeerPath, DestinationTransferPeerPath, TRANSACTION_TRANSFER + +tx = fireblocks.create_transaction( + asset_id='TEMPO', + source=TransferPeerPath( + peer_type='VAULT_ACCOUNT', + peer_id=vault_id + ), + destination=DestinationTransferPeerPath( + peer_type='ONE_TIME_ADDRESS', + one_time_address={ + 'address': '0xRecipientAddress' + } + ), + amount='100', + tx_type=TRANSACTION_TRANSFER, + note='Payment' +) + +print(f"Transaction ID: {tx['id']}") +``` + +### Contract Call + +```python +from web3 import Web3 + +# Encode function call +w3 = Web3() +contract = w3.eth.contract( + address='0x20c0000000000000000000000000000000000001', + abi=erc20_abi +) +data = contract.encodeABI('transfer', ['0xRecipient', 1000000]) + +tx = fireblocks.create_transaction( + asset_id='TEMPO', + source=TransferPeerPath( + peer_type='VAULT_ACCOUNT', + peer_id=vault_id + ), + destination=DestinationTransferPeerPath( + peer_type='ONE_TIME_ADDRESS', + one_time_address={ + 'address': '0x20c0000000000000000000000000000000000001' + } + ), + amount='0', + tx_type=TRANSACTION_CONTRACT_CALL, + extra_parameters={ + 'contractCallData': data + } +) +``` + +## Monitoring + +### Transaction History + +```typescript +const transactions = await fireblocks.getTransactions({ + sourceType: 'VAULT_ACCOUNT', + sourceId: vaultId, + status: 'COMPLETED', + limit: 100 +}) + +for (const tx of transactions) { + console.log(`${tx.id}: ${tx.amount} ${tx.assetId} - ${tx.status}`) +} +``` + +### Webhooks + +Configure webhooks in Fireblocks console for real-time notifications: + +```typescript +// Express webhook handler +import express from 'express' +import crypto from 'crypto' + +const app = express() + +app.post('/fireblocks-webhook', express.json(), (req, res) => { + // Verify webhook signature + const signature = req.headers['fireblocks-signature'] + const payload = JSON.stringify(req.body) + + const expectedSignature = crypto + .createHmac('sha512', process.env.FIREBLOCKS_WEBHOOK_SECRET!) + .update(payload) + .digest('hex') + + if (signature !== expectedSignature) { + return res.status(401).send('Invalid signature') + } + + const { type, data } = req.body + + switch (type) { + case 'TRANSACTION_STATUS_UPDATED': + console.log(`Transaction ${data.id} status: ${data.status}`) + break + case 'VAULT_ACCOUNT_ADDED': + console.log(`New vault: ${data.name}`) + break + } + + res.status(200).send('OK') +}) +``` + +### Audit Logs + +```typescript +const auditLogs = await fireblocks.getAuditLogs({ + timeStart: Date.now() - 86400000, // Last 24 hours + limit: 100 +}) + +for (const log of auditLogs) { + console.log(`${log.timestamp}: ${log.action} by ${log.userId}`) +} +``` + +## Enterprise Use Cases + +### Treasury Management + +```typescript +// Multi-sig treasury setup +const treasuryVault = await fireblocks.createVaultAccount({ + name: 'Company Treasury' +}) + +// Apply policy: 3-of-5 approval for large transfers +await fireblocks.setTransactionApprovalPolicy({ + rules: [{ + vaultAccountId: treasuryVault.id, + transactionType: 'TRANSFER', + amount: 50000, + operator: 'GREATER_THAN', + action: 'REQUIRE_APPROVAL', + authorizationGroups: [{ + users: ['cfo', 'ceo', 'coo', 'treasurer', 'controller'], + threshold: 3 + }] + }] +}) +``` + +### Automated Payments + +```typescript +// Service account for automated payments +async function processPayroll(payments: Array<{address: string, amount: string}>) { + const transactions = [] + + for (const payment of payments) { + const tx = await fireblocks.createTransaction({ + operation: TransactionOperation.TRANSFER, + assetId: 'TEMPO', + source: { + type: PeerType.VAULT_ACCOUNT, + id: payrollVaultId + }, + destination: { + type: PeerType.ONE_TIME_ADDRESS, + oneTimeAddress: { address: payment.address } + }, + amount: payment.amount, + note: 'Payroll' + }) + + transactions.push(tx) + } + + return transactions +} +``` + +## Environment Variables + +```bash +# .env +FIREBLOCKS_API_KEY=your-api-key +FIREBLOCKS_API_URL=https://api.fireblocks.io +FIREBLOCKS_WEBHOOK_SECRET=your-webhook-secret +``` + + +## Get Early Access + +Tempo is currently in testnet with mainnet launching soon. To learn more about building on Tempo or integrating stablecoin payments: + +- [Explore the testnet](/quickstart/integrate-tempo) +- [Get testnet funds](/quickstart/faucet) +- Contact [partners@tempo.xyz](mailto:partners@tempo.xyz) for partnership opportunities diff --git a/src/pages/guides/integrations/fonbnk.mdx b/src/pages/guides/integrations/fonbnk.mdx new file mode 100644 index 00000000..aff08db7 --- /dev/null +++ b/src/pages/guides/integrations/fonbnk.mdx @@ -0,0 +1,439 @@ +--- +title: "Fonbnk Mobile Money Ramps for Tempo" +description: "Mobile money to crypto infrastructure for Tempo with Fonbnk. Enable on/off-ramps via airtime and mobile money across emerging markets." +--- + +# Fonbnk Mobile Money Ramps for Tempo + +[Fonbnk](https://fonbnk.com) provides mobile money and airtime-to-crypto infrastructure, enabling seamless on/off-ramps across emerging markets. + +## Features + +- **Airtime conversion** — Convert airtime to crypto +- **Mobile money** — Direct mobile wallet integration +- **Emerging markets** — Focus on underbanked regions +- **Micro-transactions** — Support for small amounts + +## API Setup + +```typescript +const FONBNK_API_KEY = process.env.FONBNK_API_KEY +const FONBNK_SECRET = process.env.FONBNK_SECRET +const FONBNK_BASE_URL = 'https://api.fonbnk.com/v1' + +async function fonbnkRequest( + endpoint: string, + options: { method?: string; body?: any } = {} +) { + const response = await fetch(`${FONBNK_BASE_URL}${endpoint}`, { + method: options.method || 'GET', + headers: { + 'Content-Type': 'application/json', + 'X-API-Key': FONBNK_API_KEY!, + 'X-API-Secret': FONBNK_SECRET! + }, + body: options.body ? JSON.stringify(options.body) : undefined + }) + return response.json() +} +``` + +## Get Supported Countries + +```typescript +interface Country { + code: string + name: string + currency: string + operators: Array<{ + id: string + name: string + type: 'airtime' | 'mobile_money' + }> +} + +async function getSupportedCountries(): Promise { + const data = await fonbnkRequest('/countries') + + return data.countries.map((country: any) => ({ + code: country.code, + name: country.name, + currency: country.currency, + operators: country.operators.map((op: any) => ({ + id: op.id, + name: op.name, + type: op.type + })) + })) +} +``` + +## Get Exchange Rates + +```typescript +interface ExchangeRate { + countryCode: string + operatorId: string + localCurrency: string + buyRate: number + sellRate: number + minAmount: number + maxAmount: number +} + +async function getExchangeRate( + countryCode: string, + operatorId: string +): Promise { + const data = await fonbnkRequest( + `/rates?country=${countryCode}&operator=${operatorId}` + ) + + return { + countryCode, + operatorId, + localCurrency: data.local_currency, + buyRate: data.buy_rate, + sellRate: data.sell_rate, + minAmount: data.min_amount, + maxAmount: data.max_amount + } +} +``` + +## On-Ramp (Buy Crypto) + +### Create Airtime Order + +```typescript +interface AirtimeOrderRequest { + countryCode: string + operatorId: string + phoneNumber: string + localAmount: number + cryptoAddress: string + crypto: 'USDC' | 'USDT' +} + +async function createAirtimeOrder(request: AirtimeOrderRequest) { + const data = await fonbnkRequest('/orders/airtime', { + method: 'POST', + body: { + country: request.countryCode, + operator: request.operatorId, + phone: request.phoneNumber, + amount: request.localAmount, + crypto: request.crypto, + network: 'tempo', + address: request.cryptoAddress + } + }) + + return { + orderId: data.order_id, + status: data.status, + localAmount: data.local_amount, + cryptoAmount: data.crypto_amount, + rate: data.rate, + instructions: data.instructions, // How to send airtime + expiresAt: data.expires_at + } +} +``` + +### Create Mobile Money Order + +```typescript +interface MobileMoneyOrderRequest { + countryCode: string + operatorId: string + phoneNumber: string + localAmount: number + cryptoAddress: string + crypto: 'USDC' | 'USDT' +} + +async function createMobileMoneyOrder(request: MobileMoneyOrderRequest) { + const data = await fonbnkRequest('/orders/mobile-money', { + method: 'POST', + body: { + country: request.countryCode, + operator: request.operatorId, + phone: request.phoneNumber, + amount: request.localAmount, + crypto: request.crypto, + network: 'tempo', + address: request.cryptoAddress + } + }) + + return { + orderId: data.order_id, + status: data.status, + localAmount: data.local_amount, + cryptoAmount: data.crypto_amount, + paymentDetails: data.payment_details, + expiresAt: data.expires_at + } +} +``` + +## Off-Ramp (Sell Crypto) + +### Create Sell Order + +```typescript +interface SellOrderRequest { + countryCode: string + operatorId: string + phoneNumber: string + cryptoAmount: number + crypto: 'USDC' | 'USDT' +} + +async function createSellOrder(request: SellOrderRequest) { + const data = await fonbnkRequest('/orders/sell', { + method: 'POST', + body: { + country: request.countryCode, + operator: request.operatorId, + phone: request.phoneNumber, + crypto_amount: request.cryptoAmount, + crypto: request.crypto, + network: 'tempo' + } + }) + + return { + orderId: data.order_id, + status: data.status, + depositAddress: data.deposit_address, + depositAmount: data.deposit_amount, + localAmount: data.local_amount, + expiresAt: data.expires_at + } +} +``` + +### Confirm Sell Order + +```typescript +async function confirmSellOrder(orderId: string, txHash: string) { + const data = await fonbnkRequest(`/orders/${orderId}/confirm`, { + method: 'POST', + body: { + tx_hash: txHash + } + }) + + return { + orderId: data.order_id, + status: data.status, + estimatedDelivery: data.estimated_delivery + } +} +``` + +## Order Status + +```typescript +interface OrderStatus { + orderId: string + type: 'buy' | 'sell' + status: 'pending' | 'processing' | 'completed' | 'failed' | 'expired' + localAmount: number + cryptoAmount: number + txHash?: string + completedAt?: string +} + +async function getOrderStatus(orderId: string): Promise { + const data = await fonbnkRequest(`/orders/${orderId}`) + + return { + orderId: data.order_id, + type: data.type, + status: data.status, + localAmount: data.local_amount, + cryptoAmount: data.crypto_amount, + txHash: data.tx_hash, + completedAt: data.completed_at + } +} +``` + +## Widget Integration + +```typescript +// Embed Fonbnk widget in your app +function FonbnkWidget({ walletAddress }: { walletAddress: string }) { + const widgetUrl = `https://widget.fonbnk.com?` + + `apiKey=${FONBNK_API_KEY}` + + `&address=${walletAddress}` + + `&network=tempo` + + `&crypto=USDC` + + return ( +