Ana içeriğe geç

Ethereum ve BNB Smart Chain entegrasyonu

Bu kılavuz, Volet.com ödeme akıllı sözleşmeleri ve ethers v6 ile Ethereum ve BNB Smart Chain'de emanetçi olmayan kripto ödemelerin nasıl kabul edileceğini açıklar.

Müşteriler cüzdanlarını bağlar, işlemleri onaylar ve bir akıllı sözleşme aracılığıyla doğrudan alıcı cüzdanınıza öder. Fonlar bir Volet.com hesabına yatırılmaz.

Devam etmeden önce ödeme akışına genel bakış için Akıllı sözleşme entegrasyonu sayfasını inceleyin.

Bir bakışta entegrasyon​

  1. Müşterinin cüzdanını bağlayın ve seçilen blokzincir ağını doğrulayın.
  2. Ödeme sözleşmelerini ve alıcı cüzdanınızı yapılandırın.
  3. Ödemeyi başlatmadan önce arka uçta bir sipariş oluşturun.
  4. Toplam ödeme tutarını hesaplamak için previewPayment() fonksiyonunu çağırın.
  5. Ödemeyi başlatmak için transfer() fonksiyonunu çağırın. USDT için token harcama iznini (allowance) kontrol edin ve gerekirse onay isteyin.
  6. Ödeme işleminin hash'ini (txid) siparişe kaydedin.
  7. Siparişi ödendi olarak işaretlemeden önce işlemi arka uçta doğrulayın.

Başlamadan önce​

İhtiyacınız olanlar:

  • Müşteri cüzdanı: Tarayıcıda ödeme için MetaMask veya EIP-1193 uyumlu başka bir cüzdan.
  • Kütüphane: Cüzdanlarla ve akıllı sözleşmelerle etkileşim için ethers sürüm 6.
  • Üye işyeri cüzdanı: Ödemeleri almak için kontrolünüzde olan Ethereum biçiminde bir cüzdan adresi.
  • Arka uç ve veritabanı: Sipariş oluşturmak, işlem ayrıntılarını saklamak ve ödemeleri doğrulamak için.
  • RPC sağlayıcısı: Blokzincirdeki işlemleri almak ve yürütülmelerini doğrulamak için.

Mobil cüzdan bağlantıları için ayrıca bir Reown/WalletConnect Project ID gerekir.

Desteklenen ağlar ve varlıklar​

AğChain IDDesteklenen varlıklar
Ethereum Mainnet1ETH, USDT (ERC-20)
BNB Smart Chain56BNB, USDT (BEP-20)

Her varlık ilgili ödeme işlemcisi sözleşmesini kullanır. Aşağıdaki kod örnekleri, entegrasyon yapılandırmasındaki işlemci ve token adreslerini içerir.

Sözleşme adresleri, token ondalık basamakları ve fonksiyon parametreleri için Akıllı sözleşme referansı sayfasına bakın.

Örnekleri üretimde kullanmadan önce dağıtılmış işlemci adreslerini ve sözleşme arayüzünü Volet.com ile teyit edin.

Adım 1. Müşterinin cüzdanını bağlayın​

Müşterinin tarayıcı cüzdanını bağlamak için ethers v6 kullanın.

<script src="https://cdn.jsdelivr.net/npm/ethers@6/dist/ethers.umd.min.js"></script>

<button id="connect-wallet">Connect wallet</button>

<script>
let provider;
let signer;

document.getElementById('connect-wallet').addEventListener('click', async () => {
if (!window.ethereum) {
alert('Install a compatible wallet, such as MetaMask.');
return;
}

provider = new ethers.BrowserProvider(window.ethereum);
await provider.send('eth_requestAccounts', []);
signer = await provider.getSigner();

document.getElementById('connect-wallet').textContent =
await signer.getAddress();
});
</script>

Müşteri, ödeme sayfanızda seçilen ağa bağlanmalıdır:

  • Ethereum Mainnet (chainId: 1)
  • BNB Smart Chain (chainId: 56)

Cüzdan başka bir ağdaysa ağ değişikliği isteyin veya müşteriden ağı elle değiştirmesini isteyin.

Müşteriler cüzdanlarında ağ değiştirebildiği için ödemeyi göndermeden hemen önce etkin chain ID'yi her zaman doğrulayın.

Adım 2. Ödeme sözleşmelerini yapılandırın​

Ödeme işlemcisinin ABI'sini ve token fonksiyonlarını uygulamanıza ekleyin.

const PROCESSOR_ABI = [
'function previewPayment(uint256 amount, bool buyerPaysCommission) view returns (uint256 commission, uint256 totalPay)',
'function transfer(address seller, uint256 amount, bool buyerPaysCommission, address optionalCommissionWallet) payable',
];

const ERC20_ABI = [
'function balanceOf(address owner) view returns (uint256)',
'function allowance(address owner, address spender) view returns (uint256)',
'function approve(address spender, uint256 value) returns (bool)',
];

const PROCESSORS = {
native: '0x2fceE245109Cf3c535489a6F52fe11b3BBd644FF',
usdt: '0xe4083ED0A1101615b9092E8cD2164e2f42B4571E',
};

const USDT_BY_CHAIN = {
1: {
address: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
decimals: 6,
},
56: {
address: '0x55d398326f99059fF775485246999027B3197955',
decimals: 18,
},
};

Ödeme işlemcisi iki ana fonksiyon sunar:

  • previewPayment(amount, buyerPaysCommission) işlem komisyonunu ve müşterinin ödemesi gereken toplam tutarı hesaplar.
  • transfer(seller, amount, buyerPaysCommission, optionalCommissionWallet) ödemeyi gerçekleştirir ve fonları sözleşmenin komisyon ayarlarına göre dağıtır.

amount parametresi varlığın en küçük birimlerini kullanır. ETH ve BNB için ethers.parseEther(), USDT için doğru token ondalık basamağıyla ethers.parseUnits() kullanın.

buyerPaysCommission parametresi işlem komisyonunu kimin karşılayacağını belirler:

  • true: Komisyon müşterinin ödemesine eklenir.
  • false: Komisyon üye işyerinin alacağı tutardan düşülür.

İş ortağı komisyon cüzdanı yoksa optionalCommissionWallet için ethers.ZeroAddress kullanın.

Toplam ödeme tutarını her zaman previewPayment() fonksiyonundan alın. İşlem komisyonunu elle hesaplamayın.

Parametrelerin eksiksiz tanımları için Akıllı sözleşme referansı sayfasına bakın.

Adım 3. ETH veya BNB kabul edin​

Yerel ETH ve BNB ödemeleri tek bir cüzdan işlemi gerektirir.

Müşteri doğru blokzincire bağlı olduğunda aynı fonksiyon her iki ağda da çalışır.

async function payNative(signer, seller, humanAmount, buyerPaysCommission = true) {
if (!ethers.isAddress(seller)) {
throw new Error('Invalid merchant wallet');
}

const network = await signer.provider.getNetwork();

if (![1n, 56n].includes(network.chainId)) {
throw new Error('Unsupported network');
}

const processor = new ethers.Contract(
PROCESSORS.native,
PROCESSOR_ABI,
signer
);

const amount = ethers.parseEther(humanAmount);

const [, totalPay] = await processor.previewPayment(
amount,
buyerPaysCommission
);

const tx = await processor.transfer(
seller,
amount,
buyerPaysCommission,
ethers.ZeroAddress,
{ value: totalPay }
);

return tx.hash;
}

İşlemin value değeri, previewPayment() tarafından döndürülen totalPay değerine eşit olmalıdır.

Müşterinin blokzincir ağ ücretini karşılayacak kadar ETH veya BNB'si de olmalıdır.

Fonksiyon, ödeme işleminin hash'ini (txid) döndürür. Bu değeri mevcut siparişe kaydedin ve siparişi teslim etmeden önce ödemeyi doğrulayın.

Adım 4. USDT kabul edin​

USDT ödemeleri bir ERC-20 veya BEP-20 token sözleşmesi kullanır ve ek bir onay işlemi gerektirebilir.

Ödeme yapmadan önce uygulamanız şunları yapmalıdır:

  1. Müşterinin USDT bakiyesini balanceOf() ile kontrol etmek.
  2. İşlemcinin harcama iznini allowance() ile kontrol etmek.
  3. İzin yetersizse approve() ile onay istemek.
  4. Ödemeyi gerçekleştirmek için transfer() fonksiyonunu çağırmak.
async function payUsdt(signer, seller, humanAmount, buyerPaysCommission = true) {
if (!ethers.isAddress(seller)) {
throw new Error('Invalid merchant wallet');
}

const chainId = Number((await signer.provider.getNetwork()).chainId);
const tokenConfig = USDT_BY_CHAIN[chainId];

if (!tokenConfig) {
throw new Error('Unsupported network');
}

const processor = new ethers.Contract(
PROCESSORS.usdt,
PROCESSOR_ABI,
signer
);

const token = new ethers.Contract(
tokenConfig.address,
ERC20_ABI,
signer
);

const amount = ethers.parseUnits(humanAmount, tokenConfig.decimals);

const [, totalPay] = await processor.previewPayment(
amount,
buyerPaysCommission
);

const buyer = await signer.getAddress();
const balance = await token.balanceOf(buyer);

if (balance < totalPay) {
throw new Error('Insufficient USDT');
}

const currentAllowance = await token.allowance(
buyer,
PROCESSORS.usdt
);

if (currentAllowance < totalPay) {
// Ethereum USDT may require resetting an existing allowance.
if (chainId === 1 && currentAllowance > 0n) {
const resetTx = await token.approve(PROCESSORS.usdt, 0n);
await resetTx.wait();
}

const approvalTx = await token.approve(
PROCESSORS.usdt,
totalPay
);

await approvalTx.wait();
}

const tx = await processor.transfer(
seller,
amount,
buyerPaysCommission,
ethers.ZeroAddress
);

return tx.hash;
}

USDT onay gereksinimleri​

Mevcut izne bağlı olarak bir USDT ödemesi şunları gerektirebilir:

Mevcut izinGereken işlemler
YeterliYalnızca ödeme
Sıfır veya yetersizOnay + ödeme
Ethereum USDT'de sıfır olmayan mevcut izinİzni sıfırlama + onay + ödeme

Ethereum USDT, sıfır olmayan bir iznin doğrudan sıfır olmayan başka bir değere değiştirilmesini reddedebilir. Örnek, gerektiğinde önce izni sıfırlayarak bu durumu ele alır.

Bir sonraki işleme geçmeden önce her onayın doğrulanması gerekir.

Önemli:

  • approve() işlemi bir ödeme değildir.
  • Müşteri USDT ile ödese bile ağ ücretlerini karşılayacak kadar ETH veya BNB'ye ihtiyaç duyar.
  • ethers.parseUnits() ile hesaplanan tam sayı token tutarları kullanın. Finansal tutarlar için kayan noktalı aritmetik kullanmayın.
  • Onay işlemlerini son ödeme işleminden ayrı olarak takip edin.

Adım 5. Ödeme işlemini kaydedin​

Arka ucunuz, müşteri ödeme göndermeden önce bir sipariş oluşturmalıdır.

Her sipariş şu beklenen değerleri içermelidir:

  • Sipariş kimliği
  • Blokzincir ağı ve chain ID
  • Varlık ve tutar
  • Üye işyerinin alıcı cüzdanı (seller)
  • Onaylı ödeme işlemcisi sözleşmesi
  • Ödeme sayfanız gerektiriyorsa alıcının cüzdanı
  • İşlem komisyonu ayarı (buyerPaysCommission)

Müşteri ödemeyi gönderdikten sonra:

  1. Cüzdanın döndürdüğü ödeme işlemi hash'ini (txid) alın.
  2. Hash'i arka ucunuza gönderin.
  3. Sipariş kimliği ve chain ID ile birlikte saklayın.
  4. Sunucu tarafında ödeme doğrulamasını başlatın.

Her ödeme işlemi en fazla bir siparişle ilişkilendirilmelidir. Bunu veritabanınızda benzersiz bir (chainId, txid) kısıtlamasıyla zorunlu kılın.

Akıllı sözleşmenin transfer() fonksiyonu sipariş kimliği kabul etmez. Sipariş ile ödeme işlemi arasındaki ilişki uygulamanızda tutulmalıdır.

Müşteri ödemeyi yeniden denerse hâlâ beklemede olabilecek işlem kayıtlarının üzerine yazmak yerine ödeme denemelerini ayrı tutun.

Adım 6. Ödemeyi doğrulayın​

Siparişi tamamlamadan önce ödeme doğrulaması zorunludur.

Döndürülen bir işlem hash'i yalnızca işlemin gönderildiğini gösterir. Üye işyerinin doğru ödemeyi aldığını kanıtlamaz.

Arka ucunuz bağımsız olarak şunları yapmalıdır:

  1. İşlemi ve yürütme makbuzunu blokzincirden almak.
  2. Başarılı yürütmeyi ve blokzincirde gereken kesinliği doğrulamak.
  3. İşlemin beklenen ağı ve ödeme işlemcisini kullandığını doğrulamak.
  4. Varlığı, üye işyeri cüzdanını, tutarı ve sözleşme çağrısını siparişle karşılaştırmak.
  5. Üye işyerinin beklenen fonları aldığını doğrulamak.
  6. İşlemin daha önce başka bir sipariş için kullanılmadığından emin olmak.
  7. Siparişi ödendi olarak işaretlemek ve yalnızca bir kez teslim etmek.

Başarılı bir işlem makbuzu tek başına yeterli değildir. Bir işlem, doğru üye işyerine veya doğru tutarı ödemeden de başarıyla yürütülebilir.

Arka uç uygulaması, sipariş yaşam döngüsü, kesinlik gereksinimleri ve üretim kontrol listesi için Ödeme doğrulama ve sipariş takibi sayfasını izleyin.

İsteğe bağlı: Mobil cüzdanları destekleyin​

Mobil cüzdanları WalletConnect ile desteklemek için @walletconnect/ethereum-provider paketini entegre edin ve Reown Cloud üzerinden aldığınız bir Project ID ile yapılandırın.

EVM HTML örneği, ağ seçimi ve ağ değiştirme dahil WalletConnect entegrasyonunu gösterir.

WalletConnect Project ID uygulamanızı tanımlar. Özel anahtar değildir. Mümkünse uygulamanın izin verilen alan adlarını veya kaynaklarını (origin) kısıtlayın.

Entegrasyon örneği​

example-evm.html örneği şunları gösterir:

  • MetaMask ve WalletConnect uyumlu cüzdanları bağlama.
  • Ethereum veya BNB Smart Chain seçme.
  • previewPayment() ile ödeme tutarlarını hesaplama.
  • ETH, BNB ve USDT ödemeleri gönderme.
  • İşlem hash'lerini gösterme ve blokzincir onaylarını takip etme.

Kodu incelemek ve uyarlamak için örneği tarayıcınızda açabilir veya HTML dosyasını indirebilirsiniz:

  • Canlı örneği açın — etkileşimli demoyu açar. Demo Ethereum ve BNB Smart Chain ana ağını kullanır; bu nedenle onayladığınız bir ödeme gerçek fon aktarır.
  • example-evm.html dosyasını indirin — HTML dosyasını yerelde çalıştırmak veya uygulamanıza uyarlamak için indirir.

MetaMask gibi tarayıcı cüzdan uzantıları, doğrudan diskten açılan sayfalarla (file://) düzgün çalışmayabilir. İndirdiğiniz dosyayı bunun yerine yerel bir web sunucusu üzerinden açın. Örneğin dosyanın bulunduğu klasörde npx serve komutunu çalıştırın ve gösterilen localhost adresini açın.

Örneği deneyin​

  1. Canlı örneği açın veya indirdiğiniz dosyayı MetaMask yüklü bir tarayıcıda yerel sunucu üzerinden açın.
  2. Ethereum Mainnet veya BNB Smart Chain seçin ve Connect Wallet (MetaMask) düğmesine tıklayın. Mobil cüzdanlar için WalletConnect Project ID'nizi girin ve WalletConnect (QR) seçeneğini belirleyin.
  3. Ödeme yöntemini seçin: ETH, BNB veya USDT.
  4. Alıcı cüzdanı Seller address alanına girin.
  5. Ödeme tutarını girin ve işlem komisyonunu kimin ödeyeceğini seçin.
  6. İşlem komisyonunu ve toplam ödeme tutarını görmek için Preview düğmesine tıklayın. Ardından Pay düğmesine tıklayın ve işlemi cüzdanınızda onaylayın. USDT ödemeleri önce ayrı bir onay gerektirebilir.
  7. Sipariş ve işlem hash'i Orders tablosunda görünür. Demo en fazla 15 blokzincir onayını takip eder.

Ödemeden önce:

  • İki farklı cüzdan kullanın. Satıcı adresi, ödeme yapan cüzdandan farklı olmalıdır. Aksi takdirde sözleşme ödemeyi SellerIsBuyer hatasıyla reddeder.
  • İşlemler gerçek fon kullanır. Örnekte 0.001 ETH veya BNB önceden doldurulmuştur. Onaylamadan önce tutarı, işlem komisyonunu ve ağ ücretini kontrol edin.

Demo sınırlamaları: Bu örnek işlem geçmişini tarayıcının localStorage alanında saklar ve üretime hazır bir ödeme sayfası değildir. 15 onayı takip etmek Ethereum kesinliğini sağlamaz ve arka uçtaki ödeme doğrulamasının yerini tutmaz. Müşteri siparişlerini kabul etmeden önce ödeme doğrulama sürecinin tamamını uygulayın.