Webhooks ve RPC ile USDT / USDC Ödemelerini İzleme
Bir ödeme alıcısı ve yoklama imleci (polling cursor) oluşturun. Token sözleşmelerini, alıcıları ve tam sayı tutarları doğrulayın, olayları tekilleştirin ve eksik veya değiştirilen blokları uzlaştırın.
Stablecoin ödeme izleme veya borsa yatırma tespiti için, Webhook'lar, WebSocket log'ları veya HTTP polling kullanarak EVM zincirlerinde gelen ERC-20 USDT / USDC transferlerini izleyin. Geliştiriciler ve yapay zeka ajanları (AI Agent) aynı API'leri kullanır; ödemeleri işlemeden önce zinciri, token sözleşmesini, alıcıyı ve onay derinliğini seçin. USDT / USDC transfer izleme çözümü sayfasında yatırma, satıcı bildirimi veya çıkış ödemesi (payout) iş akışlarından birini seçin.
- İlk adım: Bir API key ve HTTPS alıcınızla başlayarak bir abonelik oluşturun ve alıcıyı izleyin.
- Tamamlanma koşulu: Eşleşen bir transfer imza, zincir, token, alıcı ve tam sayı tutar kontrollerini geçer, ödeme adayı olarak bir kez saklanır ve alıcı HTTP
204döndürür; bakiyeyi hesaba geçirmeden önce onay politikanız kapsamında zincir üzerinde doğrulayın.
Temel transfer izleme kullanılabilir. Tutar ve token filtreleme alıcınızda çalışır. Sunucu tarafı koşullar, çok aşamalı onaylar ve IM uyarıları yakında sunulacak.
Geliştiriciler ve Yapay Zeka Ajanları için: Bir API key ve kendi HTTPS alıcınızla başlayın; token sözleşmelerini ve tutarları uygulamanızda filtreleyin. Webhook kurulumunu kopyalayın.
Bu rehberin tamamlamanıza yardımcı olduğu görevler
- Seçilen zincir için Push desteğini kontrol ettikten sonra HTTPS uç noktanızda USDT / USDC ödeme bildirimleri alın.
- Zincir üstü doğrulama ve onay politikanızı uygulamadan önce zincirini, token sözleşmesini, alıcısını ve tam sayı tutarını kontrol ederek bir transfer adayını doğrulayın.
- Sınırlı
eth_getLogssorguları ve kaydedilmiş bir imleç ile eksik transfer log'larını geriye dönük doldurun.
Webhook, WebSocket veya polling seçimi
| Yöntem | Ne için kullanılır | Kurtarma |
|---|---|---|
| Webhook | Gelen token transferleri dahil olmak üzere HTTPS alıcınıza gönderilen adres etkinliği | İmzaları doğrulayın, olay kimliklerini tekilleştirin ve subscription.gap / chain.reorg durumlarını yönetin; saklanan eşleşmeleri yeniden oynatın |
| WebSocket | Kalıcı bir bağlantı üzerinden filtrelenmiş logs | Yeniden bağlanın, yeniden abone olun ve kaçırılan blokları geriye dönük doldurun |
| HTTP polling | Kendi imlecinizle zamanlanmış izleme veya geçmiş log'ları geriye dönük doldurma | Sınırlı eth_getLogs aralıklarını sorgulayın ve ilerlemeyi kalıcı hale getirin |
WebSocket'i seçmeden önce genel GET /v1/chains yanıtındaki ws ve subscriptions alanlarını okuyun. Push desteği ayrı bir kontroldür: API key'inizle GET /v1/push/chains okuyun. WebSocket desteği olmayan bir zincir, orada listeleniyorsa adres Webhook'larını kullanabilir. Daha önceki blokları taramanız gerektiğinde veya kalıcı bir bağlantı olmadan çalışırken polling kullanın.
Webhook'lar ile ödeme alma
Abonelik oluşturun ve alıcıyı izleyin
Bir API key alın ve 443 portunda bir HTTPS alıcısı dağıtın. Kimlik doğrulamalı Push zincir listesinden CHAIN seçin, RECIPIENT değerini yatırma adresinize ve RECEIVER_URL değerini alıcı URL'nize ayarlayın. Bu kabuk örneği jq gerektirir; {} zincirin varsayılan onay sayısını kullanır. Farklı bir sayı seçmeden önce min_confirmations, default_confirmations ve max_confirmations değerlerini inceleyin. Push OpenAPI bu istekleri tanımlar.
set -eu
umask 077
: "${BLOCKVECTRA_API_KEY:?Set your API key}"
: "${CHAIN:?Select a chain from the Push chain list}"
: "${RECIPIENT:?Set the watched EVM recipient address}"
: "${RECEIVER_URL:?Set your HTTPS receiver URL}"
PUSH_URL='https://api.blockvectra.com/v1/push'
curl --fail-with-body -sS "$PUSH_URL/chains" \
-H "x-api-key: $BLOCKVECTRA_API_KEY" > push-chains.json
jq -e --arg chain "$CHAIN" 'any(.chains[]; .chain == $chain)' push-chains.json
jq -n --arg url "$RECEIVER_URL" --arg chain "$CHAIN" \
'{url: $url, chains: {($chain): {}}}' > create.json
curl --fail-with-body -sS "$PUSH_URL/subscriptions" \
-H "x-api-key: $BLOCKVECTRA_API_KEY" \
-H 'Content-Type: application/json' -d @create.json > subscription.json
SUBSCRIPTION_ID=$(jq -er '.id' subscription.json)
jq -n --arg recipient "$RECIPIENT" '{addresses: [$recipient]}' > addresses.json
curl --fail-with-body -sS "$PUSH_URL/subscriptions/$SUBSCRIPTION_ID/addresses/add" \
-H "x-api-key: $BLOCKVECTRA_API_KEY" \
-H 'Content-Type: application/json' -d @addresses.json > address-change.json
curl --fail-with-body -sS "$PUSH_URL/subscriptions/$SUBSCRIPTION_ID" \
-H "x-api-key: $BLOCKVECTRA_API_KEY"Oluşturma işlemi id ve secret döndürür. Secret değerini alıcı için güvenli bir şekilde saklayın; subscription.json bir kimlik bilgisi içerir. address-change.json dosyasındaki applied_version >= change_version olana kadar aboneliği yoklayın, ardından chains[CHAIN].applied_from_block değerini kaydedin. Yeni adresler bu bloktan itibaren eşleşir, bu nedenle daha önceki ödeme aralıkları için yoklamaya devam edin.
Ödemeleri doğrulayın, tekilleştirin ve geçerleyin
Ham gövde imza işlevini verify-push.js olarak kaydedin. Aşağıdaki alıcı, Node.js'de bir Web API Request kabul eder ve JSON ayrıştırmasından önce orijinal baytlarını okur. secrets nesnesini, abonelik kimliği dizelerinden saklanan secret'lara eşleyen bir Map olarak oluşturun. Güvenilir expected yapılandırmasını { chain, token, recipient, amountUnits } olarak ayarlayın: token, o zincirdeki doğrulanmış stablecoin sözleşmesidir ve amountUnits, en küçük birimlerindeki beklenen pozitif tam sayı tutarıdır. Tutarları asla kayan noktalı sayılarla veya token sembolüyle değil, BigInt ile karşılaştırın.
import { verifyPush } from './verify-push.js';
export function selectPayment(data, event, expected) {
if (data.chain !== expected.chain || event.type !== 'token.transfer' ||
event.standard !== 'erc20') return null;
const address = value => typeof value === 'string' && /^0x[0-9a-fA-F]{40}$/.test(value);
if (![event.token, event.to, expected.token, expected.recipient].every(address)) return null;
if (event.token.toLowerCase() !== expected.token.toLowerCase() ||
event.to.toLowerCase() !== expected.recipient.toLowerCase()) return null;
const integer = value => typeof value === 'string' && /^[1-9][0-9]{0,77}$/.test(value);
if (!integer(event.amount) || !integer(expected.amountUnits)) return null;
const amount = BigInt(event.amount);
if (amount >= (1n << 256n) || amount !== BigInt(expected.amountUnits)) return null;
if (typeof event.id !== 'string' || typeof event.ref !== 'string' ||
!/^0x[0-9a-f]{64}$/.test(event.tx_hash) ||
!/^0x[0-9a-f]{64}$/.test(event.block_hash) ||
!Number.isSafeInteger(event.log_index) || event.log_index < 0 ||
!Number.isSafeInteger(event.block_number) || event.block_number < 0) return null;
return {
eventId: event.id, ref: event.ref, chain: data.chain,
token: event.token, recipient: event.to, amountUnits: event.amount,
txHash: event.tx_hash, logIndex: event.log_index,
blockHash: event.block_hash, blockNumber: event.block_number,
};
}
export async function receivePayments(request, expected, secrets, store) {
const rawBody = Buffer.from(await request.arrayBuffer());
const headers = Object.fromEntries(request.headers);
if (!verifyPush(rawBody, headers, secrets)) return new Response(null, { status: 401 });
let message;
try { message = JSON.parse(rawBody.toString('utf8')); }
catch { return new Response(null, { status: 400 }); }
const data = message?.data;
if (message?.type !== 'push.events' ||
!Number.isSafeInteger(data?.subscription_id) || data.subscription_id <= 0 ||
String(data.subscription_id) !== headers['bv-subscription-id'] ||
data.chain !== expected.chain || !Array.isArray(data.events)) {
return new Response(null, { status: 400 });
}
try {
await store.transaction(async tx => {
for (const event of data.events) {
if (!event || typeof event.id !== 'string') continue;
const recovery = event.type === 'subscription.gap' || event.type === 'chain.reorg';
const payment = selectPayment(data, event, expected);
if (!recovery && !payment) continue;
if (!await tx.insertEventOnce(data.subscription_id, event)) continue;
if (recovery) await tx.enqueueRecovery(data.chain, event);
else await tx.recordPaymentCandidate(payment);
}
});
} catch {
return new Response(null, { status: 503 });
}
return new Response(null, { status: 204 });
}Dayanıklı depolama ile store.transaction uygulayın. Tek bir işlem içinde insertEventOnce, benzersiz bir (subscription_id, event.id) anahtarı altında bir olay ekler ve yinelenenler için false döndürür; bunu recordPaymentCandidate veya enqueueRecovery ile birlikte commit edin. Bir yeniden denemenin olayı işleyebilmesi için başarısızlık durumunda tüm yazmaları geri alın. Kurtarma işleri de idempotent olmalıdır. Yalnızca commit ettikten sonra 10 saniye içinde 2xx döndürün; HTTP sunucunuzda 1 MiB gövde sınırını uygulayın.
Bu örnek, beklenen tek bir ödeme tutarını kontrol eder. Birden fazla sipariş için, zincir, token ve alıcıya göre güvenilir ödeme yapılandırmasını arayın ve kendi kurallarınız altında kısmi veya fazla ödemeleri uzlaştırın. Bir adayın hesaba geçirilmeden önce hala zincir üstü doğrulamaya ve onay politikanıza ihtiyacı vardır. Abonelikler ve yoklama arasında, iki teslimat yolunun aynı transferi iki kez hesaba geçirmemesi için transferi zincir, işlem karması ve log dizini ile uzlaştırın; değiştirilen blokları izlemek için blok karmasını saklayın.
Eksik veya değiştirilen blokları kurtarın
subscription.gap için, aşağıdaki yoklama yolunu veya mevcut Data API veri kümelerini kullanarak from_block ile to_block arasını tarayan bir kuyruk işi ekleyin. chain.reorg, teslim edilen blokların değiştirildiğine dair ücretsiz bir bildirimdir, bir teslimat boşluğu değildir. Bu aralıktaki eski olayları ref ile işaretleyin veya atın; yeni kimliklerle otomatik olarak yeniden teslim edilen kanonik olayları işlemeden önce ödeme kayıtlarını ref ve tx_hash ile kanonik zincire göre uzlaştırın. Bu olayları id ile tekilleştirin. Yeniden düzenleme bildirimi tamamlanan ilerlemeyi ilerletmez; zincir başına complete_through_block kaydedin, tamamlanmayı asla en büyük olay blok numarasından çıkarmayın.
Replay, mevcut replayable_from_block sınırı içindeki chain ve from_block parametrelerini kabul eder. Yalnızca saklanan eşleşmeleri yeniden gönderir; adres veya zincir eklenmeden önceki dönemleri veya aboneliğin çevrimdışı olduğu dönemleri taramaz. Bu aralıkları ve süresi dolmuş boşlukları karşılamak için bir yoklama imleci tutun. İstek hataları ve geçersiz yeniden oynatma aralıkları hata referansı sayfasında ele alınmıştır; teslimat, geçmiş ve adres-gün ücretleri faturalandırma kuralları sayfasında açıklanmaktadır.
Kalan bölümler, izleme ve kurtarma için ERC-20 log filtreleme ve imleç tabanlı yoklamayı uygular.
Transfer Olayı ve Filtre Parametreleri
Standart ERC-20 token sözleşmeleri, her transferde aşağıdaki olayı yayar:
event Transfer(address indexed from, address indexed to, uint256 value);eth_getLogs çağırırken, eşleşen log'ları filtrelemek için token sözleşme adresini ve topics dizisini iletin:
| Parametre | Değer | Açıklama |
|---|---|---|
address | Token sözleşme adresi (veya adres dizisi) | Hedef stablecoin sözleşme adresi. Tek bir adres belirtebilir (örneğin BSC USDT 0x55d398326f99059fF775485246999027B3197955, Base USDC 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913) veya birden fazla token'ı aynı anda izlemek için bir adres dizisi iletebilirsiniz |
topics[0] | 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef | Olay imza karması: keccak256("Transfer(address,address,uint256)") |
topics[1] | null | Gönderici adresi (from). Yatırma izleme herhangi bir kullanıcı cüzdanından gelen fonları kabul ettiğinden, herhangi bir göndericiyle eşleştirmek için null iletin |
topics[2] | 32 baytlık sıfır dolgulu alıcı adresi | Hedef adresi (to). EVM log belirtimleri uyarınca indexed adres parametreleri 32 bayt (64 onaltılık karakter) yer kaplar. 32 baytlık bir topic oluşturmak için 20 baytlık alıcı adresinin solunu 12 sıfır baytıyla (24 onaltılık sıfır karakteri) doldurun. |
fromBlock | Başlangıç bloğu (onaltılık) | Sorgu blok aralığının başlangıcı (dahil) |
toBlock | Bitiş bloğu (onaltılık) | Sorgu blok aralığının sonu (dahil) |
İndekslenmemiş value (transfer tutarı), log nesnesinin data alanında 32 baytlık onaltılık bir uint256 olarak kodlanır. İnsan tarafından okunabilir token tutarını elde etmek için bu ham tutarı 10^decimals değerine bölün (örneğin BSC USDT için 18 ondalık; Base ve Ethereum USDC için 6 ondalık).
İmleç Yoklaması ve Blok Aralığı Sınırları
Bir yoklama servisi, düzenli aralıklarla (örneğin her 3 ila 5 saniyede bir) yeni blokları sorgular.
İmleci İlerletme
Veritabanınızda kalıcı bir imleç olan last_polled_block (işlenen ve commit edilen en yüksek blok) saklayın:
- Her yoklama döngüsü için
fromBlock = last_polled_block + 1olarak ayarlayın. eth_blockNumberaracılığıyla geçerli zincir başlığını sorgulayın ve onay derinliğinize göre güvenli hedef yükseklik olansafe_headdeğerini hesaplayın.fromBlock <= safe_headise,safe_headdeğerine kadar olan parçalar halinde log'ları sorgulayın. Her parçayı başarıyla işledikten sonra imleci ilerletin.
Blok Aralığı Sınırı
Tek bir eth_getLogs çağrısının blok aralığı toBlock − fromBlock + 1 olarak hesaplanır. Bu değer, GET /v1/chains içinde o zincir için yayınlanan max_logs_block_range değerini aşmamalıdır.
Bir istek bu aralığı aşarsa, hizmet çağrıyı -32602 hata koduyla reddeder:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32602,
"message": "eth_getLogs block range too large: max 1000 blocks",
"data": {
"reason": "logs_range_too_large",
"docs_url": "https://docs.blockvectra.com/en/errors/#logs_range_too_large",
"retryable": false
}
}
}Blok aralığını aşan istekler -32602 JSON-RPC hatası döndürür (faturalandırılmaz). Uygulama mantığınızda GET /v1/chains üzerinden max_logs_block_range değerini okuyun ve her yoklama dilimini sınırlayın: chunk_end = min(fromBlock + max_logs_block_range - 1, safe_head).
Blok Yeniden Düzenlemelerini (Reorg) ve Onay Derinliğini Yönetme
Blokzincirin uç noktasına yakın yerlerde geçici blok yeniden düzenlemeleri (reorg) meydana gelebilir. Onay derinliği olmadan ödemeleri latest üzerinden hesaba geçirmek, sonradan atılan yetim bir koldaki işlemleri hesaba geçirme riski taşır.
Ödeme işlemeyi korumak için aşağıdaki önlemleri uygulayın:
Onay Derinliği
latest seviyesine kadar sorgulamak yerine güvenli bir hedef blok yüksekliğine kadar sorgulayın:
safe_head = current_head - CONFIRMATION_DEPTH
CONFIRMATION_DEPTH değerini uygulamanızın risk toleransına göre ayarlayın. Yalnızca safe_head seviyesine kadar sorgulama yapmak, yalnızca yeterli onaya sahip blokların işlenmesini sağlar.
Yoklama Sırasında Yeniden Düzenlemeler
Standart EVM JSON-RPC, yalnızca zincir reorg nedeniyle daha önce yayınlanan bir olay geri alındığında WebSocket logs abonelik akışlarındaki log nesnelerinde removed: true ayarlar. HTTP üzerinden eth_getLogs ile yoklama yaparken, sorgular kanonik zincirdeki log'ları döndürür; yeniden düzenlenen log'lar sonraki sorgularda görünmez. safe_head içinde yoklama yapmak, ödemelerin yalnızca yeterince onaylanmış bloklarda işlenmesini sağlar.
(transactionHash, logIndex) ile Tekilleştirme
Ödeme dinleyicileri katı bir idempotentlik (idempotency) uygulamalıdır:
- Tek Bir İşlemde Birden Fazla Transfer: Tek bir işlem, aynı yatırma adresine birden fazla
Transferolayı içerebilir (örneğin takasları bölen token yönlendiricileri veya çoklu ödeme sözleşmeleri). Önemli:transactionHashtek başına ödeme başına benzersiz değildir. - Çakışan Yoklama ve Yeniden Denemeler: Yoklama servisleri yeniden başladığında, geçici ağ hatalarından kurtulduğunda veya sığ reorg'ları işlemek için birkaç blok geri sarıldığında, aynı blok aralığındaki log'lar birden çok kez sorgulanır.
- Log İndeksi Benzersizliği:
logIndex, olay log'unun blok içindeki göreceli konumunu tanımlar. EVM belirtimleri uyarınca, bir olay için kanonik bileşik benzersiz tanımlayıcı(transactionHash, logIndex)şeklindedir.
İlişkisel veritabanı şemalarında, yatırma kayıtları tablonuzda bileşik bir benzersiz indeks bildirin:
CREATE UNIQUE INDEX idx_transfers_tx_log ON deposit_records (transaction_hash, log_index);Bir yatırma işlemini işlemeden önce, her bir zincir üstü transferin tam olarak bir kez hesaba geçmesini garanti etmek için mevcut (transactionHash, logIndex) kayıtlarını kontrol edin.
Eksiksiz Kod Örnekleri
Aşağıdaki örnekler, /v1/chains üzerinden ağ yeteneklerinin alınmasını, güvenli blok aralıklarının hesaplanmasını, aralık limitlerine uygun olarak stablecoin Transfer log'larının yoklanmasını ve olayların tekilleştirilmesini göstermektedir.
import { createPublicClient, formatUnits, http, parseAbiItem } from "viem";
const apiKey = process.env.BLOCKVECTRA_API_KEY;
if (!apiKey) {
throw new Error("BLOCKVECTRA_API_KEY environment variable is not set");
}
const CHAIN = "bsc_mainnet";
const RPC_URL = "https://api.blockvectra.com/v1/bsc_mainnet";
const CHAINS_URL = "https://api.blockvectra.com/v1/chains";
// Target stablecoin contract address (BSC USDT used in this example)
const TOKEN_CONTRACT = "0x55d398326f99059fF775485246999027B3197955" as const;
const TOKEN_DECIMALS = 18;
// Monitored deposit address
const RECIPIENT_ADDRESS = "0xdded13D555B6DA811103cC1794D3d4330F69632C" as const;
// Confirmation depth to guard against chain reorgs
const CONFIRMATION_DEPTH = 15n;
// 1. Fetch chain capabilities from public metadata endpoint (unauthenticated, unbilled)
const chainsRes = await fetch(CHAINS_URL);
const { chains } = (await chainsRes.json()) as {
chains: Array<{
chain: string;
ws: boolean;
subscriptions: string[];
max_logs_block_range: number;
}>;
};
const chainConfig = chains.find((c) => c.chain === CHAIN);
if (!chainConfig) {
throw new Error(`Chain ${CHAIN} not found in /v1/chains`);
}
const maxLogsRange = BigInt(chainConfig.max_logs_block_range || 1000);
console.log(`Chain: ${CHAIN} | WebSocket supported: ${chainConfig.ws} | Max logs range: ${maxLogsRange}`);
// 2. Initialize viem client with x-api-key header
const client = createPublicClient({
transport: http(RPC_URL, {
fetchOptions: {
headers: { "x-api-key": apiKey },
},
}),
});
// Set to track processed events by composite key: (transactionHash, logIndex)
const processedLogs = new Set<string>();
// 3. Compute query range: subtract confirmation depth from current head
const currentHead = await client.getBlockNumber();
const safeHead = currentHead - CONFIRMATION_DEPTH;
// For demonstration, start cursor 10 blocks before safeHead
let cursor = safeHead > 10n ? safeHead - 10n : 0n;
console.log(`Current head: ${currentHead} | Safe head: ${safeHead} | Polling cursor: ${cursor}`);
while (cursor <= safeHead) {
const chunkEnd = cursor + maxLogsRange - 1n < safeHead ? cursor + maxLogsRange - 1n : safeHead;
const logs = await client.getLogs({
address: TOKEN_CONTRACT,
event: parseAbiItem(
"event Transfer(address indexed from, address indexed to, uint256 value)"
),
args: {
to: RECIPIENT_ADDRESS,
},
fromBlock: cursor,
toBlock: chunkEnd,
});
for (const log of logs) {
const dedupKey = `${log.transactionHash}-${log.logIndex}`;
if (processedLogs.has(dedupKey)) {
continue;
}
processedLogs.add(dedupKey);
const tokenAmount = formatUnits(log.args.value ?? 0n, TOKEN_DECIMALS);
console.log(
`[Payment Received] Amount: ${tokenAmount} | ` +
`Tx: ${log.transactionHash} | Log: ${log.logIndex} | Block: ${log.blockNumber}`
);
}
cursor = chunkEnd + 1n;
}
// Run with: npx tsx example.mtsFaturalandırma Kuralları ve İlgili Rehberler
- İstek ölçümü, CU ağırlıkları ve hata kodu faturalandırma belirlemeleri hakkında ayrıntılar için Faturalandırma Kuralları: Hatalar ve Faturalandırılmayan İstekler sayfasına bakın.
eth_getLogsblok aralığı limitleri ve parçalama mantığı hakkında ayrıntılı rehberlik için eth_getLogs Blok Aralığı Limitleri ve Parçalı Sorgular sayfasına bakın.- Gerçek zamanlı RPC düğüm sorguları ile indekslenmiş geçmiş transfer API'leri arasındaki farklar için Zincir Başı ile İndekslenmiş Geçmiş: eth_getLogs ile Transfers Ne Zaman Kullanılır sayfasına bakın.
Sonraki adımlar
- BlockVectra'nın indekslediği her veri kümesini görmek için veri kümeleri dizinine göz atın.
- Hesabınızın neleri içerdiğini kontrol etmek için ücretsiz planı ve fiyatlandırmayı inceleyin.
- Bir API key oluşturmak için konsolda oturum açın.
Son güncelleme:
İşlemleri Simüle Etme
eth_simulateV1 kullanarak zincir üzerinde göndermeden önce birden fazla işlemi test edin ve durum değişikliklerini inceleyin. Desteklenen zincir yöntemi politikalarını, yürütme belirtimi istek yüklerini, CU fiyatlandırma ağırlıklarını ve AI Agent MCP entegrasyonunu öğrenin.
Hisse senedi token çarpanı
Robinhood Chain hisse senedi token çarpanını anlayın, bakiyeleri hisseye dönüştürün, eth_call ile uiMultiplier okuyun ve Data API aracılığıyla sahipleri ile günlük etkinliği takip edin.