Xây dựng một ứng dụng DeFi đòi hỏi truy cập đáng tin cậy vào dữ liệu blockchain. Dù bạn đang truy vấn số dư token, thực hiện các giao dịch hoặc theo dõi các vị trí cho vay, lớp API nằm giữa mã của bạn và blockchain. Bản tham khảo này bao gồm các nhà cung cấp API DeFi chính, các mẫu xác thực, chiến lược giới hạn tốc độ và các thực tiễn tích hợp tốt nhất.
Hiểu về môi trường API DeFi
API của DeFi thuộc ba loại, mỗi loại phục vụ cho nhu cầu khác nhau:
Các nhà cung cấp RPC (Alchemy, Infura, QuickNode) cung cấp truy cập trực tiếp vào blockchain thông qua JSON-RPC. Đây là nền tảng – tất cả các loại API khác cuối cùng đều phụ thuộc vào các nút RPC. Các nhà cung cấp này chạy các nút lưu trữ và xác minh trên nhiều chuỗi, vì vậy bạn không cần phải làm điều đó.
API nâng cao (Alchemy Enhanced APIs, Moralis, Covalent) tổng hợp các mẫu chung: số dư token, dữ liệu mô tả NFT, lịch sử giao dịch. Thay vì viết eth_call cho mỗi số dư ERC-20, bạn chỉ cần gọi một endpoint.
API Indexing & Query (The Graph, Goldsky, SubQuery) cho phép bạn định nghĩa các mô hình GraphQL tùy chỉnh cho các truy vấn phức tạp. Đây là các công cụ cần thiết cho bảng điều khiển phân tích và phân tích lịch sử khi RPC nguyên liệu sẽ quá chậm.
So sánh các nhà cung cấp chính
| Nhà cung cấp | Loại | Dây đai | Bộ cấp miễn phí | WebSocket | Tốt nhất cho |
|---|---|---|---|---|---|
| Kim loại học | RPC + nâng cao | 15+ | 330 cốc | ✓ | Chiều sâu Ethereum/L2, thời gian thực |
| Infura | RPC + nâng cao | 15+ | 100K yêu cầu/ngày | ✓ | Tính tin cậy của doanh nghiệp, IPFS |
| QuickNode | RPC + Stream | 100+ | 10M yêu cầu/tháng | ✓ | Chiều rộng đa chuỗi, độ trễ thấp |
| Biểu đồ | Liên kết | 40+ | Miễn phí (công cộng) | ✗ | Complex historical queries |
| Covalent | REST được nâng cao | 100+ | 1M req/mo | ✗ | Dữ liệu đa chuỗi thống nhất |
| Moralis | Tăng cường + Dòng | 30+ | 25K yêu cầu/tháng | ✓ | DeFi thời gian thực, xác thực Web3 |
Chọn bộ phần mềm nhà cung cấp của bạn
Hầu hết các ứng dụng sản xuất sử dụng nhiều nhà cung cấp cho các mục đích khác nhau:
- RPC chính: Alchemy hoặc Infura cho mainnet/L2s của Ethereum (tích hợp hỗ trợ tốt nhất)
- Lựa chọn thay thế đa chuỗi: QuickNode cho các chuỗi mà RPC chính không hỗ trợ tốt
- Phân tích/ lịch sử: The Graph cho các truy vấn phức tạp, Covalent cho các truy xuất đa chuỗi đơn giản
Điều này giúp bảo vệ chống lại sự ngừng hoạt động của nhà cung cấp và sự cạn kiệt giới hạn tốc độ.
Các mẫu xác thực
API của DeFi sử dụng ba phương thức xác thực chính. Hiểu rõ từng phương thức sẽ giúp bạn thực hiện các tích hợp an toàn và dễ bảo trì.
Xác thực bằng khóa API (cộng đồng)
Mẫu đơn giản và phổ biến nhất. Thêm khóa trong một header:
`javascript // Alchemy, Infura, QuickNode, Covalent, Moralis const headers = { 'Authorization': Bearer ${API_KEY}, 'Content-Type': 'application/json' };
// Or as query parameter (less secure, avoid in production) // https://eth-mainnet.alchemyapi.io/v2/${API_KEY} `
Các phương pháp bảo mật tốt nhất:
- Không bao giờ lưu các khóa API vào hệ thống kiểm soát phiên bản
Xác thực JWT (Infura)
Infura hỗ trợ token JWT để tăng cường bảo mật:
`javascript // 1. Generate JWT with project ID and secret const jwt = generateJWT({ projectId: INFURA_PROJECT_ID, projectSecret: INFURA_PROJECT_SECRET, expiresIn: '1h' });
// 2. Use in Authorization header const headers = { 'Authorization': Bearer ${jwt}, 'Content-Type': 'application/json' }; `
JWT có hạn sử dụng, hạn chế khả năng bị rò rỉ. Hãy thực hiện tự động cập nhật trước khi hết hạn.
Yêu cầu ký (QuickNode HMAC)
QuickNode cung cấp việc ký bằng HMAC-SHA256 cho các yêu cầu:
`javascript const crypto = require('crypto');
function signRequest(method, path, body, timestamp, secret) { const payload = ${timestamp}${method}${path}${body || ''}; return crypto.createHmac('sha256', secret).update(payload).digest('hex'); }
const timestamp = Date.now().toString(); const signature = signRequest('POST', '/', JSON.stringify(rpcRequest), timestamp, QUICKNODE_SECRET);
const headers = { 'Content-Type': 'application/json', 'X-QN-Signature': signature, 'X-QN-Timestamp': timestamp }; `
Điều này chứng minh tính toàn vẹn của yêu cầu mà không gửi các bí mật qua đường dây.
Các chiến lược hạn chế tốc độ
Các giới hạn mức phí là ràng buộc chính trong phát triển DeFi. Mỗi nhà cung cấp có cách mô hình hóa giới hạn khác nhau.
Hiểu về mô hình giới hạn
Đơn vị tính toán (Alchemy): Mỗi phương thức RPC có một chi phí CU. eth_blockNumber = 10 CU, eth_call = 26 CU + chi phí thực thi. Bậc miễn phí: 330 CUPS (Đơn vị tính toán mỗi giây).
`javascript // Estimate CU cost before sending const CU_COSTS = { 'eth_blockNumber': 10, 'eth_getBalance': 19, 'eth_call': 26, // + execution gas / 100000 'eth_getLogs': 75, // + topics/data size };
function estimateCU(method, params = []) { return CU_COSTS[method] || 100; // Default conservative estimate } `
Số yêu cầu (Infura, QuickNode, Covalent, Moralis): Tính số yêu cầu đơn giản. Tính dễ dự đoán hơn nhưng không phản ánh tải thực tế của các node.
`javascript // Track your own rate limit state class RateLimiter { constructor(limitPerWindow, windowMs) { this.limit = limitPerWindow; this.window = windowMs; this.requests = []; }
async acquire() { const now = Date.now(); this.requests = this.requests.filter(t => now - t < this.window);
if (this.requests.length >= this.limit) { const oldest = this.requests[0]; const waitMs = this.window - (now - oldest); await new Promise(r => setTimeout(r, waitMs)); return this.acquire(); }
this.requests.push(now); } }
// Usage: 100 requests per second const limiter = new RateLimiter(100, 1000); await limiter.acquire(); await fetch(rpcUrl, { method: 'POST', body: JSON.stringify(payload) }); `
Các mẫu phân trang
Các tập dữ liệu lớn cần có trang phân trang. Có hai mẫu phổ biến:
Giữa các điểm nhấn (được khuyến nghị): Token không thông qua chỉ vào trang tiếp theo. Thường xuyên được sử dụng trong các tác vụ ghi đồng thời.
`javascript // Alchemy, Moralis, The Graph async function fetchAllPages(initialParams) { const allResults = []; let cursor = null;
do { const params = { ...initialParams, pageKey: cursor }; const response = await apiCall(params); allResults.push(...response.data); cursor = response.pageKey; // null when done } while (cursor);
return allResults; } `
Giới hạn dựa trên offset: đơn giản là page + limit hoặc offset + limit. Có thể bỏ qua/ lặp lại các mục trong quá trình ghi đồng thời.
`javascript // Covalent, some REST APIs async function fetchAllPages(offset = 0, limit = 100) { const allResults = [];
while (true) { const response = await apiCall({ offset, limit }); if (response.data.length === 0) break; allResults.push(...response.data); offset += limit; }
return allResults; } `
Quản lý lỗi và logic tái thử
API của DeFi trả về các mã HTTP tiêu chuẩn cùng các định dạng lỗi đặc trưng của nhà cung cấp.
Các mã lỗi phổ biến
| Mã HTTP | Ý nghĩa | Hoạt động |
|---|---|---|
| 400 | Yêu cầu không hợp lệ (thông số không hợp lệ) | Khắc phục yêu cầu, không thử lại |
| 401 | Auth không hợp lệ/không có | Kiểm tra thông tin xác thực, cập nhật JWT |
| 403 | Được cấm (kiểu hạn chế domain/IP) | Kiểm tra các thiết lập bảng điều khiển nhà cung cấp |
| 429 | Tốc độ giới hạn | Hãy rút lui, tôn trọng header "Retry-After" |
| 500 | Provider internal error | Lặp lại với thời gian chờ theo hàm số |
| 502/503/504 | Gateway/upstream không có sẵn | Lặp lại, xem xét nhà cung cấp dự phòng |
Các định dạng lỗi riêng của nhà cung cấp
`javascript // Alchemy error response { "jsonrpc": "2.0", "id": 1, "error": { "code": -32005, "message": "request rate limit exceeded", "data": { "retryAfter": 1000 } } }
// Infura error response { "error": { "code": "RATE_LIMIT_EXCEEDED", "message": "Daily request limit exceeded", "retryAfter": 86400 } }
// QuickNode error response { "error": "Rate limit exceeded", "code": "RATE_LIMIT", "retryAfterMs": 500 } `
Cách thực hiện thử lại mạnh mẽ
`javascript class DeFiAPIClient { constructor(baseUrl, apiKey, options = {}) { this.baseUrl = baseUrl; this.apiKey = apiKey; this.maxRetries = options.maxRetries || 3; this.baseDelay = options.baseDelay || 1000; this.maxDelay = options.maxDelay || 30000; this.fallbackProviders = options.fallbackProviders || []; }
async request(method, params, attempt = 0) { try { const response = await fetch(this.baseUrl, { method: 'POST', headers: this.getHeaders(), body: JSON.stringify({ jsonrpc: '2.0', method, params, id: Date.now() }) });
if (response.status === 429) { const retryAfter = this.parseRetryAfter(response); await this.sleep(retryAfter); return this.request(method, params, attempt); // Don't count against maxRetries }
if (response.status >= 500 && attempt < this.maxRetries) { const delay = Math.min( this.baseDelay Math.pow(2, attempt) + Math.random() 1000, this.maxDelay ); await this.sleep(delay); return this.request(method, params, attempt + 1); }
if (!response.ok) { throw new Error(HTTP ${response.status}: ${await response.text()}); }
const data = await response.json(); if (data.error) throw new RPCError(data.error); return data.result;
} catch (error) { // Try fallback providers on network errors or 5xx if (this.isRetriable(error) && this.fallbackProviders.length > 0) { const fallback = this.fallbackProviders.shift(); return fallback.request(method, params); } throw error; } }
parseRetryAfter(response) { const header = response.headers.get('Retry-After'); if (header) return parseInt(header) * 1000; const data = await response.json().catch(() => ({})); return data.retryAfter || data.retryAfterMs || 1000; }
isRetriable(error) { return error instanceof TypeError || // Network error (error.response && error.response.status >= 500); }
sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } } `
Dữ liệu thời gian thực: WebSockets và Webhooks
Xử lý các điểm kết thúc RPC để cập nhật khối là không hiệu quả. Hãy sử dụng các mô hình dựa trên push thay thế.
Đăng ký WebSocket (Alchemy, Infura, QuickNode, Moralis)
`javascript const WebSocket = require('ws');
class BlockSubscriber { constructor(rpcWsUrl) { this.ws = new WebSocket(rpcWsUrl); this.subscriptions = new Map(); this.ws.on('message', this.handleMessage.bind(this)); }
subscribe(event, params, callback) { const id = sub_${Date.now()}_${Math.random()}; this.subscriptions.set(id, callback);
this.ws.send(JSON.stringify({ jsonrpc: '2.0', id, method: 'eth_subscribe', params: [event, ...params] }));
return id; // Use to unsubscribe later }
handleMessage(data) { const msg = JSON.parse(data);
// Subscription confirmation if (msg.id && msg.result && this.subscriptions.has(msg.id)) { const subId = msg.result; // Actual subscription ID this.subscriptions.set(subId, this.subscriptions.get(msg.id)); this.subscriptions.delete(msg.id); return; }
// Event notification if (msg.method === 'eth_subscription' && msg.params) { const { subscription, result } = msg.params; const callback = this.subscriptions.get(subscription); if (callback) callback(result); } }
unsubscribe(id) { this.ws.send(JSON.stringify({ jsonrpc: '2.0', id: Date.now(), method: 'eth_unsubscribe', params: [id] })); this.subscriptions.delete(id); } }
// Usage: Track new blocks const subscriber = new BlockSubscriber('wss://eth-mainnet.g.alchemy.com/v2/YOUR_KEY'); subscriber.subscribe('newHeads', [], (block) => { console.log('New block:', block.number); });
// Track pending transactions to a specific address subscriber.subscribe('alchemy_pendingTransactions', [{ toAddress: '0xUniswapRouterAddress' }], (tx) => { console.log('Pending swap:', tx.hash); }); `
Webhook / Trình phát sóng sự kiện (Alchemy Notify, Moralis Streams, QuickNode Streams)
Webhooks đẩy các sự kiện đến điểm kết thúc HTTP của bạn - phù hợp cho các triển khai không cần server và nhiều khung.
`javascript // Alchemy Notify webhook registration async function registerAlchemyWebhook(webhookUrl, addresses, events) { const response = await fetch('https://dashboard.alchemy.com/api/create-webhook', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': Bearer ${ALCHEMY_API_KEY} }, body: JSON.stringify({ webhook_url: webhookUrl, addresses, event_types: events // ['ADDRESS_ACTIVITY', 'MINED_TRANSACTION', 'DROPPED_TRANSACTION'] }) }); return response.json(); }
// Moralis Streams webhook registration async function registerMoralisStream(webhookUrl, chain, abi, events) { const response = await fetch('https://deep-index.moralis.io/api/v2/streams/evm', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-API-Key': MORALIS_API_KEY }, body: JSON.stringify({ name: 'DeFi Swap Monitor', chain, description: 'Track Uniswap V3 swaps', webhookUrl, advancedOptions: { includeNativeTxs: false }, abi, includeContractLogs: true, allAddresses: false, topic0: events.map(e => ethers.id(e)) // Event signatures }) }); return response.json(); }
// Webhook handler (Express.js example) app.post('/webhook/alchemy', express.raw({ type: 'application/json' }), (req, res) => { // Verify signature (Alchemy signs payloads) const signature = req.headers['x-alchemy-signature']; const expected = crypto .createHmac('sha256', ALCHEMY_WEBHOOK_SECRET) .update(req.body) .digest('hex');
if (signature !== expected) { return res.status(401).send('Invalid signature'); }
const events = JSON.parse(req.body); events.forEach(event => processEvent(event)); res.status(200).send('OK'); }); `
Các mẫu API đặc trưng cho DeFi
Các API dữ liệu token
`javascript // Alchemy Token API - Get all ERC-20 balances for an address async function getTokenBalances(address) { const response = await fetch(https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}/getTokenBalances, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ owner: address, contractAddresses: [] }) // [] = all tokens }); return response.json(); }
// Moralis Token API - Get token price, metadata, holders async function getTokenData(chain, address) { const [metadata, price, holders] = await Promise.all([ fetch(https://deep-index.moralis.io/api/v2/erc20/metadata?chain=${chain}&addresses=${address}, { headers: { 'X-API-Key': MORALIS_KEY } }).then(r => r.json()), fetch(https://deep-index.moralis.io/api/v2/erc20/${address}/price?chain=${chain}, { headers: { 'X-API-Key': MORALIS_KEY } }).then(r => r.json()), fetch(https://deep-index.moralis.io/api/v2/erc20/${address}/holders?chain=${chain}&limit=10, { headers: { 'X-API-Key': MORALIS_KEY } }).then(r => r.json()) ]); return { metadata, price, holders }; }
// Covalent - Unified token balances across chains async function getCrossChainBalances(address) { const response = await fetch( https://api.covalenthq.com/v1/${address}/balances_v2/?key=${COVALENT_KEY}&nft=false ); return response.json(); // Returns balances for ALL supported chains } `
API DEX và Swap
`javascript // 1inch Aggregation API - Best swap routes across DEXs async function getSwapQuote(fromToken, toToken, amount, chain = 1) { const response = await fetch( https://api.1inch.dev/swap/v5.2/${chain}/quote?src=${fromToken}&dst=${toToken}&amount=${amount}, { headers: { 'Authorization': Bearer ${ONEINCH_KEY} } } ); return response.json(); // { dstAmount, protocols, gas, ... } }
// 0x Swap API - Professional market making async function getZeroXQuote(sellToken, buyToken, sellAmount, takerAddress) { const response = await fetch( https://api.0x.org/swap/v1/quote?sellToken=${sellToken}&buyToken=${buyToken}&sellAmount=${sellAmount}&takerAddress=${takerAddress}, { headers: { '0x-api-key': ZEROX_KEY } } ); return response.json(); }
// Uniswap V3 Subgraph (The Graph) - Pool data, ticks, positions const UNISWAP_V3_QUERY = query Pools($feeTier: Int!, $token0: String!, $token1: String!) { pools(where: { feeTier: $feeTier, token0: $token0, token1: $token1 }) { id token0 { symbol decimals } token1 { symbol decimals } feeTier liquidity sqrtPrice tick volumeUSD txCount } } ; `
Các API của Protokol vay
`javascript // Aave V3 GraphQL (The Graph) - User positions, reserves, rates const AAVE_QUERY = query UserReserves($user: String!) { user(id: $user) { reserves { reserve { symbol decimals liquidityRate variableBorrowRate stableBorrowRate utilizationRate } currentATokenBalance currentVariableDebt currentStableDebt } } } ;
// Compound V3 REST (via Alchemy Enhanced API or direct RPC) // Requires reading Comet contract storage — use Alchemy's getAssetTransfers // with category: ['erc20'] to track cToken balances
// Morpho Blue (new lending primitive) - Subgraph const MORPHO_QUERY = query Market($marketId: String!) { market(id: $marketId) { totalSupplyAssets totalBorrowAssets supplyApy borrowApy utilization lltv } } ; `
API Oracle & Price Feed
`javascript // Chainlink Price Feeds - Direct RPC reads (no API key needed for view calls) const PRICE_FEED_ABI = [ 'function latestRoundData() view returns (uint80, int256, uint256, uint256, uint80)', 'function decimals() view returns (uint8)' ];
async function getChainlinkPrice(feedAddress, provider) { const contract = new ethers.Contract(feedAddress, PRICE_FEED_ABI, provider); const [, answer, , updatedAt] = await contract.latestRoundData(); const decimals = await contract.decimals(); return { price: Number(answer) / 10**decimals, timestamp: Number(updatedAt) }; }
// Pyth Network - Pull-based price feeds (Solana/EVM) // Requires Wormhole bridge for cross-chain — use Pyth SDK
// CoinGecko/CoinMarketCap - REST APIs for reference prices async function getReferencePrice(tokenId, vsCurrency = 'usd') { const response = await fetch( https://api.coingecko.com/api/v3/simple/price?ids=${tokenId}&vs_currencies=${vsCurrency} ); return response.json(); } `
Các phương pháp thực hành tốt nhất về tích hợp
1. Bức tách cung cấp (Provider Abstraction Layer)
Đừng kết hợp logic kinh doanh với SDK của một nhà cung cấp duy nhất. Tạo một lớp trừu tượng:
`typescript // types.ts interface RPCProvider { request(method: string, params: unknown[]): Promise
interface EnhancedAPI { getTokenBalances(address: string): Promise
// providers/alchemy.ts class AlchemyProvider implements RPCProvider, EnhancedAPI { // ... implementation }
// providers/quicknode.ts class QuickNodeProvider implements RPCProvider, EnhancedAPI { // ... implementation }
// factory.ts function createProvider(config: ProviderConfig): RPCProvider & EnhancedAPI { switch (config.primary) { case 'alchemy': return new AlchemyProvider(config); case 'quicknode': return new QuickNodeProvider(config); case 'infura': return new InfuraProvider(config); default: throw new Error(Unknown provider: ${config.primary}); } }
// Usage — swap providers by changing config const provider = createProvider({ primary: 'alchemy', apiKey: process.env.ALCHEMY_KEY }); const balances = await provider.getTokenBalances('0x...'); `
2. Kiểm tra sức khỏe và chuyển đổi khi xảy ra sự cố
`javascript class ProviderPool { constructor(providers) { this.providers = providers.map(p => ({ ...p, healthy: true, lastCheck: 0 })); this.currentIndex = 0; }
async getHealthyProvider() { // Check health periodically for (let i = 0; i < this.providers.length; i++) { const idx = (this.currentIndex + i) % this.providers.length; const provider = this.providers[idx];
if (Date.now() - provider.lastCheck > 30000) { // Check every 30s provider.healthy = await this.checkHealth(provider); provider.lastCheck = Date.now(); }
if (provider.healthy) { this.currentIndex = idx; return provider.instance; } } throw new Error('No healthy providers available'); }
async checkHealth(provider) { try { await provider.instance.request('eth_blockNumber', []); return true; } catch { return false; } } } `
3. Chiến lược lưu trữ
Tự động lưu trữ dữ liệu một cách mạnh mẽ nhưng hủy bỏ đúng cách:
`javascript class DeFiCache { constructor(redisClient) { this.redis = redisClient; this.ttl = { tokenMetadata: 86400, // 24h — rarely changes tokenPrice: 60, // 1min — volatile userBalances: 30, // 30s — changes per block poolReserves: 12, // 12s — ~1 block historicalData: 3600 // 1h — immutable }; }
async get(key, fetcher, type = 'tokenPrice') { const cached = await this.redis.get(key); if (cached) return JSON.parse(cached);
const fresh = await fetcher(); await this.redis.setex(key, this.ttl[type], JSON.stringify(fresh)); return fresh; }
// Invalidate on relevant events async invalidateOnBlock(blockNumber) { // Clear balance/pool caches — they change every block const keys = await this.redis.keys('balance:*'); keys.forEach(k => this.redis.del(k)); } } `
4. Những điều cần cân nhắc của nhà phát triển Việt Nam
Những nhà phát triển DeFi Việt Nam phải đối mặt với những hạn chế cụ thể:
Tối ưu hóa độ trễ:
- Node QuickNode Singapore: ~40ms từ Thành phố Hồ Chí Minh
- Alchemy Singapore: ~45ms
- Infura Singapore: ~50ms
- Thực hiện kiểm tra trạng thái từ các mạng VN (Viettel, VNPT, FPT) để đo độ trễ thực tế
Quản lý chi phí:
- Các cấp miễn phí thường được chia sẻ giữa các thành viên trong nhóm
- Thực hiện loại bỏ trùng lặp yêu cầu ở cấp ứng dụng
Tuân thủ quy định:
- Nghị định 53/2022/ND-CP: Các yêu cầu về địa phương hóa dữ liệu cho dữ liệu tài chính
- Đề xuất lưu trữ lớp đệm trong Việt Nam (AWS Việt Nam, Viettel IDC)
- Đồng tiền ổn định VND (VNDC, VNM) yêu cầu tích hợp KYC/AML địa phương
Các nguồn cộng đồng:
- Discord của các nhà phát triển Blockchain Việt Nam: ~5.000 thành viên
- Telegram của Web3 Việt Nam: các cuộc thảo luận kỹ thuật hoạt động
Hỏi đáp
Câu hỏi: Tôi nên sử dụng Alchemy hay Infura cho mainnet Ethereum không? A: Alchemy có các API nâng cao và webhooks thông báo tốt hơn. Infura có các SLA doanh nghiệp và tích hợp IPFS tốt hơn. Đối với hầu hết các ứng dụng DeFi, trải nghiệm của nhà phát triển của Alchemy là tốt nhất.
Câu hỏi: Làm thế nào để xử lý giới hạn tốc độ trong các sự kiện có lưu lượng truy cập cao (IDO, airdrop)?
Câu hỏi: Tôi có thể sử dụng The Graph để lấy dữ liệu giao dịch thời gian thực không? A: Không. The Graph có độ trễ của chỉ mục (từ vài giây đến vài phút). Hãy sử dụng Alchemy/Infura/QuickNode WebSocket để lấy dữ liệu thời gian thực, và The Graph để phân tích dữ liệu lịch sử.
Câu hỏi: Sự khác biệt giữa giới hạn CUPS và giới hạn dựa trên yêu cầu của Alchemy là gì?
Câu hỏi: Làm thế nào để xác minh chữ ký webhook một cách an toàn?
Câu hỏi: Nhà cung cấp nào có hỗ trợ ngôn ngữ Việt Nam tốt nhất?
Danh sách kiểm tra tổng quan
- [ ] Chọn các nhà cung cấp chính + dự phòng cho mỗi chuỗi
- [ ] Thực hiện xác thực với việc thay đổi khóa
- [ ] Tạo giới hạn tốc độ với các mô hình riêng của nhà cung cấp
- [ ] Thêm thử lại giảm dần với dự phòng
- [ ] Sử dụng WebSocket cho thời gian thực, webhooks cho không cần server
Tham khảo này được duy trì như một tài liệu sống. Các nhà cung cấp API thường xuyên cập nhật – hãy kiểm tra tài liệu chính thức để biết các điểm kết thúc, giới hạn tốc độ và các tính năng mới nhất.
