Ethereum- und BNB-Smart-Chain-Integration
Diese Anleitung erklärt, wie Sie Non-Custodial-Krypto-Zahlungen auf Ethereum und BNB Smart Chain mit den Zahlungs-Smart-Contracts von Volet.com und ethers v6 annehmen.
Kunden verbinden ihre Wallets, bestätigen Transaktionen und zahlen über einen Smart Contract direkt auf Ihr Empfangs-Wallet. Die Gelder werden keinem Volet.com-Konto gutgeschrieben.
Bevor Sie fortfahren, lesen Sie den Überblick über den Zahlungsablauf unter Smart-Contract-Integration.
Integration im Überblick
- Wallet des Kunden verbinden und das gewählte Blockchain-Netzwerk bestätigen.
- Zahlungs-Contracts und Ihr Empfangs-Wallet konfigurieren.
- Vor der Zahlung eine Bestellung im Backend erstellen.
previewPayment()aufrufen, um den Gesamtbetrag der Zahlung zu berechnen.transfer()aufrufen, um die Zahlung auszulösen. Bei USDT die Allowance des Tokens prüfen und bei Bedarf eine Freigabe anfordern.- Den Hash der Zahlungstransaktion (
txid) bei der Bestellung speichern. - Die Transaktion im Backend prüfen, bevor die Bestellung als bezahlt markiert wird.
Bevor Sie beginnen
Sie benötigen:
- Wallet des Kunden: MetaMask oder ein anderes EIP-1193-kompatibles Wallet für Zahlungen im Browser.
- Bibliothek:
ethersVersion 6 für die Interaktion mit Wallets und Smart Contracts. - Händler-Wallet: eine Wallet-Adresse im Ethereum-Format unter Ihrer Kontrolle, um Zahlungen zu empfangen.
- Backend und Datenbank: um Bestellungen zu erstellen, Transaktionsdaten zu speichern und Zahlungen zu prüfen.
- RPC-Anbieter: um Blockchain-Transaktionen abzurufen und ihre Ausführung zu prüfen.
Für die Verbindung mobiler Wallets benötigen Sie außerdem eine Reown/WalletConnect Project ID.
Unterstützte Netzwerke und Assets
| Netzwerk | Chain ID | Unterstützte Assets |
|---|---|---|
| Ethereum Mainnet | 1 | ETH, USDT (ERC-20) |
| BNB Smart Chain | 56 | BNB, USDT (BEP-20) |
Jedes Asset verwendet den zugehörigen Prozessor-Contract. Die Codebeispiele unten enthalten die Prozessor- und Token-Adressen aus der Integrationskonfiguration.
Contract-Adressen, Token-Decimals und Funktionsparameter finden Sie in der Smart-Contract-Referenz.
Bestätigen Sie die Adressen der bereitgestellten Prozessoren und die Contract-Schnittstelle mit Volet.com, bevor Sie die Beispiele produktiv einsetzen.
Schritt 1. Wallet des Kunden verbinden
Verbinden Sie das Browser-Wallet des Kunden mit ethers v6.
<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>
Der Kunde muss sich mit dem Netzwerk verbinden, das in Ihrem Checkout gewählt ist:
- Ethereum Mainnet (
chainId: 1) - BNB Smart Chain (
chainId: 56)
Ist das Wallet mit einem anderen Netzwerk verbunden, fordern Sie einen Netzwerkwechsel an oder bitten Sie den Kunden, manuell zu wechseln.
Prüfen Sie die aktive Chain ID immer unmittelbar vor dem Senden einer Zahlung, da Kunden das Netzwerk im Wallet wechseln können.
Schritt 2. Zahlungs-Contracts konfigurieren
Fügen Sie Ihrer Anwendung die ABI des Zahlungsprozessors und die Token-Funktionen hinzu.
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,
},
};
Der Zahlungsprozessor bietet zwei Hauptfunktionen:
previewPayment(amount, buyerPaysCommission)berechnet die Bearbeitungsgebühr und den Gesamtbetrag, den der Kunde zahlen muss.transfer(seller, amount, buyerPaysCommission, optionalCommissionWallet)führt die Zahlung aus und verteilt die Gelder gemäß den Gebühreneinstellungen des Contracts.
Der Parameter amount wird in den kleinsten Einheiten des Assets angegeben. Verwenden Sie ethers.parseEther() für ETH und BNB und ethers.parseUnits() mit den korrekten Token-Decimals für USDT.
Der Parameter buyerPaysCommission legt fest, wer die Bearbeitungsgebühr trägt:
true: Die Gebühr wird zur Zahlung des Kunden addiert.false: Die Gebühr wird vom Betrag abgezogen, den der Händler erhält.
Verwenden Sie ethers.ZeroAddress für optionalCommissionWallet, wenn kein Provisions-Wallet eines Partners vorgesehen ist.
Übernehmen Sie den Gesamtbetrag der Zahlung immer aus previewPayment(). Berechnen Sie die Bearbeitungsgebühr nicht selbst.
Vollständige Parameterdefinitionen finden Sie in der Smart-Contract-Referenz.
Schritt 3. ETH oder BNB annehmen
Zahlungen in nativem ETH und BNB erfordern eine einzige Wallet-Transaktion.
Dieselbe Funktion funktioniert in beiden Netzwerken, sofern der Kunde mit der richtigen Blockchain verbunden ist.
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;
}
Der value der Transaktion muss dem totalPay entsprechen, den previewPayment() zurückgibt.
Der Kunde braucht außerdem genug ETH oder BNB für die Netzwerkgebühr der Blockchain.
Die Funktion gibt den Hash der Zahlungstransaktion (txid) zurück. Speichern Sie ihn bei der bestehenden Bestellung und prüfen Sie die Zahlung, bevor Sie die Bestellung ausführen.
Schritt 4. USDT annehmen
USDT-Zahlungen laufen über einen ERC-20- oder BEP-20-Token-Contract und können eine zusätzliche Freigabetransaktion erfordern.
Vor einer Zahlung muss Ihre Anwendung:
- Das USDT-Guthaben des Kunden mit
balanceOf()prüfen. - Die Allowance des Prozessors mit
allowance()prüfen. - Bei unzureichender Allowance eine Freigabe mit
approve()anfordern. transfer()aufrufen, um die Zahlung auszuführen.
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;
}
Anforderungen an die USDT-Freigabe
Je nach bestehender Allowance kann eine USDT-Zahlung Folgendes erfordern:
| Bestehende Allowance | Erforderliche Transaktionen |
|---|---|
| Ausreichend | Nur die Zahlung |
| Null oder unzureichend | Freigabe + Zahlung |
| Bestehende Allowance ungleich null bei Ethereum-USDT | Allowance auf null zurücksetzen + Freigabe + Zahlung |
Ethereum-USDT kann es ablehnen, eine Allowance ungleich null direkt auf einen anderen Wert ungleich null zu ändern. Das Beispiel löst das, indem es die Allowance bei Bedarf zuerst zurücksetzt.
Jede Freigabe muss bestätigt sein, bevor Sie mit der nächsten Transaktion fortfahren.
Wichtig:
- Eine
approve()-Transaktion ist keine Zahlung. - Der Kunde braucht genug ETH oder BNB für die Netzwerkgebühren, auch wenn er in USDT zahlt.
- Verwenden Sie ganzzahlige Token-Beträge, die mit
ethers.parseUnits()berechnet werden. Verwenden Sie für Geldbeträge keine Gleitkommaarithmetik. - Verfolgen Sie Freigabetransaktionen getrennt von der abschließenden Zahlungstransaktion.
Schritt 5. Zahlungstransaktion speichern
Ihr Backend muss eine Bestellung erstellen, bevor der Kunde eine Zahlung sendet.
Jede Bestellung sollte die erwarteten Werte enthalten für:
- Bestell-ID
- Blockchain-Netzwerk und Chain ID
- Asset und Betrag
- Empfangs-Wallet des Händlers (
seller) - Freigegebenen Prozessor-Contract
- Wallet des Käufers, falls Ihr Checkout es verlangt
- Einstellung der Bearbeitungsgebühr (
buyerPaysCommission)
Nachdem der Kunde die Zahlung gesendet hat:
- Den vom Wallet zurückgegebenen Hash der Zahlungstransaktion (
txid) übernehmen. - Den Hash an Ihr Backend senden.
- Ihn zusammen mit Bestell-ID und Chain ID speichern.
- Die serverseitige Zahlungsprüfung starten.
Jede Zahlungstransaktion darf höchstens einer Bestellung zugeordnet sein. Setzen Sie das mit einer eindeutigen Einschränkung (chainId, txid) in Ihrer Datenbank durch.
Die Funktion transfer() des Smart Contracts akzeptiert keine Bestell-ID. Die Verknüpfung zwischen Bestellung und Zahlungstransaktion muss Ihre Anwendung herstellen.
Wiederholt ein Kunde eine Zahlung, legen Sie getrennte Zahlungsversuche an, statt Transaktionsdatensätze zu überschreiben, die möglicherweise noch ausstehen.
Schritt 6. Zahlung prüfen
Vor dem Abschluss einer Bestellung ist eine Zahlungsprüfung erforderlich.
Ein zurückgegebener Transaktions-Hash zeigt nur, dass eine Transaktion gesendet wurde. Er belegt nicht, dass der Händler die richtige Zahlung erhalten hat.
Ihr Backend muss unabhängig:
- Transaktion und Ausführungs-Receipt von der Blockchain abrufen.
- Erfolgreiche Ausführung und die erforderliche Finalität auf der Blockchain bestätigen.
- Prüfen, ob die Transaktion das erwartete Netzwerk und den erwarteten Zahlungsprozessor verwendet hat.
- Asset, Händler-Wallet, Betrag und Contract-Aufruf mit der Bestellung abgleichen.
- Bestätigen, dass der Händler die erwarteten Gelder erhalten hat.
- Sicherstellen, dass die Transaktion nicht bereits für eine andere Bestellung verwendet wurde.
- Die Bestellung als bezahlt markieren und nur einmal ausführen.
Ein erfolgreiches Transaktions-Receipt allein reicht nicht aus. Eine Transaktion kann erfolgreich ausgeführt worden sein, ohne den richtigen Händler oder den richtigen Betrag zu bezahlen.
Folgen Sie Zahlungsprüfung und Bestellverfolgung für die Backend-Implementierung, den Lebenszyklus von Bestellungen, die Anforderungen an die Finalität und die Checkliste für den Produktivbetrieb.
Optional: mobile Wallets unterstützen
Um mobile Wallets über WalletConnect zu unterstützen, integrieren Sie @walletconnect/ethereum-provider und konfigurieren es mit einer Project ID aus Reown Cloud.
Das EVM-HTML-Beispiel zeigt die WalletConnect-Integration einschließlich Netzwerkauswahl und Netzwerkwechsel.
Eine WalletConnect Project ID identifiziert Ihre Anwendung. Sie ist kein privater Schlüssel. Beschränken Sie, wo möglich, die zulässigen Domains oder Origins der Anwendung.
Integrationsbeispiel
Das Beispiel example-evm.html zeigt:
- Verbindung von MetaMask und WalletConnect-kompatiblen Wallets.
- Auswahl von Ethereum oder BNB Smart Chain.
- Berechnung der Zahlungsbeträge mit
previewPayment(). - Senden von Zahlungen in ETH, BNB und USDT.
- Anzeige von Transaktions-Hashes und Verfolgung von Blockchain-Bestätigungen.
Sie können das Beispiel im Browser öffnen oder die HTML-Datei herunterladen, um den Code zu studieren und anzupassen:
- Live-Beispiel öffnen – öffnet die interaktive Demo. Sie nutzt das Mainnet von Ethereum und BNB Smart Chain, eine bestätigte Zahlung überträgt also echtes Geld.
- example-evm.html herunterladen – lädt die HTML-Datei herunter, um sie lokal auszuführen oder für Ihre Anwendung anzupassen.
Browser-Wallet-Erweiterungen wie MetaMask funktionieren mit direkt von der Festplatte geöffneten Seiten (file://) möglicherweise nicht korrekt. Stellen Sie die heruntergeladene Datei stattdessen über einen lokalen Webserver bereit. Führen Sie zum Beispiel npx serve im Ordner mit der Datei aus und öffnen Sie die angezeigte localhost-URL.
Beispiel ausprobieren
- Öffnen Sie das Live-Beispiel oder stellen Sie die heruntergeladene Datei lokal bereit – in einem Browser mit installiertem MetaMask.
- Wählen Sie Ethereum Mainnet oder BNB Smart Chain und klicken Sie auf Connect Wallet (MetaMask). Für mobile Wallets geben Sie Ihre WalletConnect Project ID ein und wählen WalletConnect (QR).
- Wählen Sie die Zahlungsmethode: ETH, BNB oder USDT.
- Geben Sie das Empfangs-Wallet unter Seller address ein.
- Geben Sie den Zahlungsbetrag ein und legen Sie fest, wer die Bearbeitungsgebühr zahlt.
- Klicken Sie auf Preview, um Bearbeitungsgebühr und Gesamtbetrag der Zahlung zu sehen. Klicken Sie dann auf Pay und bestätigen Sie die Transaktion im Wallet. Für USDT-Zahlungen kann vorher eine separate Freigabe nötig sein.
- Bestellung und Transaktions-Hash erscheinen in der Tabelle Orders. Die Demo verfolgt bis zu 15 Blockchain-Bestätigungen.
Bevor Sie zahlen:
- Verwenden Sie zwei verschiedene Wallets. Die Verkäuferadresse muss sich vom zahlenden Wallet unterscheiden. Andernfalls lehnt der Contract die Zahlung mit
SellerIsBuyerab.- Transaktionen bewegen echtes Geld. Das Beispiel ist mit
0.001ETH oder BNB vorausgefüllt. Prüfen Sie Betrag, Bearbeitungsgebühr und Netzwerkgebühr, bevor Sie bestätigen.
Grenzen der Demo: Dieses Beispiel speichert den Transaktionsverlauf im
localStoragedes Browsers und ist kein produktiver Checkout. Das Verfolgen von 15 Bestätigungen stellt keine Ethereum-Finalität her und ersetzt keine Zahlungsprüfung im Backend. Setzen Sie den vollständigen Prozess der Zahlungsprüfung um, bevor Sie Kundenbestellungen annehmen.
Siehe auch
- Smart-Contract-Integration – Überblick über den Non-Custodial-Zahlungsablauf.
- TRON-Integration – TRX und USDT TRC-20 annehmen.
- Smart-Contract-Referenz – Prozessor-Adressen, Token-Decimals und Contract-Parameter.
- Fehlerbehebung – häufige Wallet- und Transaktionsfehler.