Tracing und Transaktionsgraphen · Lektion 5 von 6
Tracing im Kontomodell sowie von Token und NFTs
14 Min. Lesezeit
Auf Ethereum und anderen Chains mit Kontomodell erscheint ein Großteil der Werte bei einem typischen Betrug oder Diebstahl niemals als einfache Übertragung zwischen zwei Adressen. Die Werte bewegen sich innerhalb von Contract-Aufrufen, in Form von Token-Events, deren ausgegebenen Inhalt der Contract selbst bestimmt hat, oder über eine Signatur, die das Opfer bereits Tage zuvor preisgegeben hat. Ein Prüfer, der nur den Reiter „Transaktionen“ eines Explorers verfolgt, übersieht Hops, stellt falsch dar, wer Gelder bewegt hat, und meldet Beträge, die die Gegenseite anhand derselben Chain widerlegen kann – mitunter um den Faktor einer Billion.
Vier Stellen, an denen sich Werte bewegen
Jeder Kanal wird an einer anderen Stelle aufgezeichnet. Deshalb muss ein Hop-Datensatz angeben, woher seine Belege stammen.
| Kanal | Aufzeichnungsort | Forensische Fallstricke |
|---|---|---|
| Wert auf oberster Ebene: natives ETH, das durch eine Transaktion gesendet wird | In der Transaktion selbst | Eine fehlgeschlagene Transaktion bewegt keine Werte, verursacht aber dennoch Gasgebühren |
| Interne Übertragungen: ETH, das ein Contract während der Ausführung sendet | Nur in Ausführungs-Traces | In Receipts und Logs nicht enthalten; manche Explorer zeigen sie an, andere nicht |
| Token-Übertragungen: ERC-20, ERC-721, ERC-1155 | Transfer-Events in den Receipt-Logs | Die Contract-Adresse des Events identifiziert den Token, nicht sein Symbol |
| Zustandsänderungen ohne Standard-Events: Rebasing, Fee-on-Transfer, nicht standardkonforme Token | Im Contract-Speicher | Event-Summen stimmen nicht mit Guthaben überein; Abgleich mit Zustandsabfragen an einem bestimmten Block erforderlich |
Interne Übertragungen sind die häufigste Ursache für übersehene Hops: Ein Swap mit Auszahlung in nativem ETH, ein Weiterleitungs-Contract oder ein Wallet-Contract zur gebündelten Ausführung bewegt ETH durch Aufrufe, die kein Log hinterlassen. Um diese Übertragungen zu erhalten, ist ein tracingfähiger Knoten erforderlich, in der Regel ein Archivknoten. Die Methodennamen unterscheiden sich je nach Client (debug_traceTransaction mit einem Call-Tracer bei einigen, trace_transaction bei anderen). Dokumentieren Sie für jeden Trace den verwendeten Client, die Version und die Methode, denn zwei Tracer können dieselbe Ausführung unterschiedlich darstellen (die Lektionen 2.4, 2.9 und 5.1 behandeln die Dekodierung).
ERC-20-Übertragungen lesen
Ein ERC-20-Token (EIP-20) ist ein Contract, der eine Zuordnung von Adressen zu Guthaben verwaltet. Wenn jemand „USDC sendet“, ist das to der Transaktion der Token-Contract (oder ein Router), ihr nativer value beträgt meist 0, und der Empfänger erscheint nur in den Aufrufdaten und Logs. Guthabenänderungen geben Transfer(address indexed _from, address indexed _to, uint256 _value) aus, mit topic0 0xddf252ad…b3ef auf jeder EVM-Chain, Absender und Empfänger in den Topics 1 und 2 sowie dem Rohbetrag in data.
Die Identität des Tokens ist die Contract-Adresse, die das Log ausgegeben hat, niemals sein Name oder Symbol: Jeder kann einen Contract namens „USDC“ bereitstellen, der formal einwandfreie Transfer-Events ausgibt. Events werden außerdem vom Code des Contracts selbst geschrieben. Ein bösartiger Contract kann daher Transfer-Events ausgeben, denen keine Guthabenänderung entspricht. Filtern oder kennzeichnen Sie vor der Analyse Übertragungen mit dem Wert null und Übertragungen nicht gelisteter Token.
Dezimalstellen und Einheiten
Das Log speichert eine Ganzzahl in Basiseinheiten. Der Dezimalstellenwert, mit dem sie in menschenlesbare Einheiten umgerechnet wird, ist nicht im Event enthalten. Lesen Sie ihn einmal pro Contract mit decimals() aus und speichern Sie ihn zusammen mit seiner Quelle.
| Token (Ethereum-Mainnet) | Dezimalstellen | Rohwert für 1 Einheit |
|---|---|---|
| USDC, USDT | 6 | 1.000.000 |
| WBTC | 8 | 100.000.000 |
| DAI, WETH, die meisten Token | 18 | 1.000.000.000.000.000.000 |
Werden auf einen Token mit 6 Dezimalstellen 18 Dezimalstellen angewendet, werden die Beträge um den Faktor 10^12 zu niedrig angegeben; umgekehrt werden sie um denselben Faktor zu hoch angegeben. Derselbe Vermögenswert kann auf verschiedenen Chains unterschiedliche Dezimalstellen verwenden, da über Bridges übertragene und neu ausgegebene Versionen eigenständige Contracts sind. Rohwerte sind 256-Bit-Ganzzahlen (bis zu 78 Ziffern). Speichern Sie sie deshalb als Zeichenfolgen oder hochpräzise Dezimalzahlen und dividieren Sie erst bei der Darstellung.
Minting, Burning und Token, die vom Modell abweichen
Minting-Vorgänge sind Transfers von der Nulladresse, und die meisten Burning-Vorgänge sind Transfers an sie. Das Senden von Token an eine „tote“ Adresse wie 0x…dEaD ist kein Burning, da das Guthaben weiterhin existiert. Manche Token weichen mit benutzerdefinierten Mint- und Burn-Events von dieser Konvention ab. Der ursprüngliche WETH-Contract (WETH9) gibt Deposit und Withdrawal ohne Transfer aus. Ein allein aus Transfer-Logs rekonstruiertes WETH-Guthaben ist daher für jede Adresse falsch, die Wrapping oder Unwrapping durchführt.
Auch die Regel „Guthaben = eingehende minus ausgehende Transfer-Werte“ versagt bei:
| Design | Was geschieht | Was zu tun ist |
|---|---|---|
| Fee-on-Transfer | Bei einer Übertragung von 100 kommen beispielsweise 98 an; 2 gehen an eine Gebühren-Wallet oder werden verbrannt, häufig als zweites Transfer-Event | Verwenden Sie den Betrag im Transfer an den Empfänger, nicht den Betrag aus den Aufrufdaten |
| Rebasing | Guthaben ändern sich ohne jegliches Transfer-Event | Lesen Sie balanceOf an bestimmten Blockhöhen aus; modellieren Sie das Rebase |
| Anteilsbasiert | Der Contract verwaltet Anteile; angezeigte Guthaben werden um einige Basiseinheiten abgerundet | Verfolgen Sie die Anteils-Events, sofern vorhanden |
| Einfrierbar oder pausierbar | Der Emittent kann eine Adresse sperren oder ihr Guthaben über benutzerdefinierte Funktionen verbrennen | Dekodieren Sie auch die administrativen Events des Emittenten |
Lidos stETH ist ein bekanntes Beispiel für Rebasing: Guthaben steigen, wenn das Oracle des Protokolls Erträge meldet, ohne dass ein Transfer ausgegeben wird. Aufgrund der Rundung von Anteilen können bei Übertragungen 1–2 wei zurückbleiben. Sein Wrapper wstETH verhält sich wie ein gewöhnlicher ERC-20-Token.
Führen Sie vor der Berichterstattung über Token-Flüsse einen Abgleich durch: Legen Sie den Token anhand von Contract-Adresse und Chain-ID eindeutig fest; rekonstruieren Sie die relevanten Guthaben aus Transfer-Logs bis zum Stichtagsblock; vergleichen Sie sie mit balanceOf sowie Minting minus Burning mit totalSupply() an diesem Block; und erklären Sie jede Abweichung oder weisen Sie sie als Einschränkung aus. Token-Events sind Aussagen des Contract-Codes; Zustandsabfragen überprüfen sie.
Freigaben, transferFrom und Drainer
ERC-20 ermöglicht es einem Eigentümer, einen Verfügungsberechtigten mit approve(spender, amount) zu autorisieren, wodurch Approval(owner, spender, value) ausgegeben wird. Der Verfügungsberechtigte, üblicherweise ein DEX-Router oder Kreditpool, ruft später transferFrom(owner, recipient, amount) auf. Im daraus resultierenden Transfer ist from der Eigentümer, dessen Token bewegt wurden, nicht das Konto, das die Transaktion gesendet hat. Unbegrenzte Freigaben (2^256 − 1, 64 Hexadezimalziffern f) ermöglichen es dem Verfügungsberechtigten, jederzeit das gesamte Guthaben des Eigentümers zu bewegen. Verfügungsrahmen lassen sich nicht immer aus Events rekonstruieren (die weitverbreitete Bibliothek von OpenZeppelin gibt seit Version 5.0 kein neues Approval mehr aus, wenn transferFrom einen Verfügungsrahmen nutzt). Lesen Sie deshalb allowance(owner, spender) am relevanten Block aus.
Ein Drainer ist ein Phishing-Kit, das ein Opfer dazu bringt, ein Verfügungsrecht einzuräumen, und dieses anschließend nutzt. Die Handlung des Opfers ist eine der folgenden:
- eine On-Chain-Freigabetransaktion, häufig unbegrenzt, die vom Opfer signiert und gesendet wird;
- eine Off-Chain-Permit-Signatur (EIP-2612), die der Angreifer einreicht und für die er Gas bezahlt; laut Spezifikation kann jede Adresse ein gültiges Permit einreichen. Ein erfolgreiches Permit setzt den Verfügungsrahmen und gibt ein
Approval-Event in einer Transaktion aus, die das Opfer nie gesendet hat; - eine Signatur für einen gemeinsam genutzten Freigabe-Contract, dem das Opfer bereits eine Freigabe erteilt hatte und der daraufhin die Übertragung autorisiert.
Der Drainer-Contract ruft anschließend transferFrom auf und teilt die Erlöse auf. Eine Studie von He und Kollegen an der Zhejiang University und der Mohamed bin Zayed University of Artificial Intelligence (Die Schattenwirtschaft entlarven: eine eingehende Untersuchung von Drainer-as-a-Service-Phishing auf Ethereum, 2025), die den Zeitraum von März 2023 bis April 2025 abdeckt, stellte fest, dass die häufigste Aufteilung 20 % für den Kit-Betreiber und 80 % für den Affiliate betrug, der die Phishing-Kampagne durchführte. Eine feste Aufteilung, die sich bei vielen Opfern wiederholt, ist ein starkes Muster. Sie bleibt jedoch eine Schlussfolgerung über die Rollen, bis andere Belege sie bestätigen.
Ein Teil der Belege liegt daher off-chain vor. Bei entsprechender rechtlicher Befugnis können auf dem Gerät des Opfers der Browserverlauf der Phishing-Website und die Aufzeichnungen der Wallet zu Signaturanfragen vorliegen, die zusammen die Handlung des Opfers zeitlich einordnen (Lektion 7.3). Off-Chain-Signaturen hinterlassen bis zu ihrer Verwendung keine Spuren auf der Chain. Zwischen Signatur und Abschöpfung kann deshalb viel Zeit vergehen.
Durchgeführtes Tracing-Beispiel: ein Permit-Drainer
Ein Opfer meldet den Verlust von 25.000 USDC. Der Prüfer dekodiert die relevanten Transaktionen anhand eines Tracing-Knotens:
Tx 0x3b9e…a417 Block 24,598,331 Status 1 Absender 0xD7c4…19
Aufruf 0xD7c4…19 -> 0x8f2A…c3 (Contract, nicht verifiziert)
Log 41 Token 0xA0b8…eB48 Approval Eigentümer 0x5e1C…2e Verfügungsberechtigter 0x8f2A…c3 Wert 25000000000
Log 42 Token 0xA0b8…eB48 Transfer von 0x5e1C…2e an 0x0dE3…7a Wert 5000000000
Log 43 Token 0xA0b8…eB48 Transfer von 0x5e1C…2e an 0xAf10…d0 Wert 20000000000
Tx 0x77c0…5b12 Block 24,598,402 Status 1 Absender 0xAf10…d0
Log 7 Token 0xA0b8…eB48 Transfer von 0xAf10…d0 an 0x9c3B…e1 (Pool) Wert 20000000000
Log 9 Token WETH Transfer von 0x9c3B…e1 an 0x4d1F…80 (Router) Wert 7.9e18
Trace [0,3] CALL 0x4d1F…80 -> 0xF5a9…31 Wert 7.9 ETH
Tx 0x1e44…c9a0 Block 24,598,460 Status 1 Absender 0xF5a9…31
Wert auf oberster Ebene 0xF5a9…31 -> 0x2bD1…f6 7.89 ETH
Die erste Transaktion wurde nicht vom Opfer gesendet. Ihr Absender rief einen nicht verifizierten Contract auf, der das Permit des Opfers einreichte (Log 41, ein Verfügungsrahmen von 25.000 USDC bei 6 Dezimalstellen) und in derselben Transaktion 5.000 und 20.000 USDC von der Adresse des Opfers wegbewegte (Logs 42 und 43). Die Beträge stimmen überein: 5.000 + 20.000 = 25.000, eine Aufteilung von 20/80. Ein Bericht mit der Aussage „Das Opfer hat 25.000 USDC gesendet“ würde einen Vorgang falsch beschreiben, den der Schlüssel des Opfers nie signiert hat. In der zweiten Transaktion tauschte der Empfänger des größeren Anteils seine 20.000 USDC über einen Pool; der Router führte ein Unwrapping von 7,9 WETH durch und sendete 7,9 ETH an eine neue Adresse. Dieser Hop erscheint nur im Trace an Position [0,3]: Ein Prüfer, der ausschließlich Logs liest, würde hier die Spur der Gelder verlieren. In der dritten Transaktion sendete die neue Adresse 7,89 ETH an 0x2bD1…f6 und behielt etwa 0,01 ETH zurück, aus denen sie die Gasgebühren bezahlte. Diese Zieladresse leitet ihre Einzahlungen an eine Hot Wallet einer Börse weiter.
Jeder hier dargestellte Fluss hat die Einstufung A: Er ist auf der Chain aufgezeichnet und über einen Knoten überprüfbar. Die Rollen von Betreiber und Affiliate sind Schlussfolgerungen aus der Aufteilung. Die Kennzeichnung als Börseneinzahlungsadresse beruht auf einer einzelnen Heuristik, bis die Börse sie bestätigt. Von dort wird das Tracing wie in Lektion 3.4 beschrieben fortgesetzt.
Einen durch einen Contract vermittelten Hop dokumentieren
Der Hop-Datensatz aus Lektion 3.2 benötigt auf Chains mit Kontomodell zusätzliche Felder: den Log-Index oder die Trace-Position, da eine Transaktion Dutzende Übertragungen enthalten kann; die Token-Contract-Adresse, ihre Dezimalstellen und den ganzzahligen Rohwert; den Absender der Transaktion sowie from und to der Übertragung, da es sich häufig um unterschiedliche Parteien handelt; und den Status der Transaktion, da rückgängig gemachte Transaktionen Traces, aber keine dauerhaften Übertragungen hinterlassen.
Zwei Identitätsfallen sind tokenspezifisch. Gefälschte Token kopieren den Namen und das Symbol eines echten Stablecoins; nur die Contract-Adresse zeigt, welcher echt ist. Address Poisoning sendet Nullwert-, Kleinstbetrags- oder gefälschte Übertragungen von einer Adresse, die einer vom Opfer verwendeten Adresse ähnelt, in der Hoffnung, dass das Opfer sie aus dem Verlauf kopiert. Vergleichen Sie immer vollständige Adressen, niemals nur die ersten und letzten Zeichen.
Stablecoins und Einblicksmöglichkeiten des Emittenten
Stablecoin-Übertragungen sind gewöhnliche Token-Events und lassen sich deterministisch verfolgen, mit zwei zusätzlichen Merkmalen. Erstens verfügen die wichtigsten durch Fiatgeld gedeckten Stablecoin-Contracts über eine Einfrierfunktion (Sperrliste) für den Emittenten. Ein Guthaben, das noch nicht bewegt wurde, kann daher manchmal schneller gestoppt werden als durch eine gerichtliche Anordnung (Lektion 10.1). Zweitens sieht der Emittent dieselbe Chain wie alle anderen und besitzt Identitätsdaten nur für seine direkten Kunden, typischerweise diejenigen, die Token prägen und einlösen: Er kann bestätigen, welche Adressen er eingefroren hat und wer Token geprägt oder eingelöst hat, nicht aber, wer die Adresse eines gewöhnlichen Inhabers kontrolliert. Dokumentieren Sie bei jedem Stablecoin-Hop die Chain und die Contract-Adresse: Dasselbe Kürzel existiert auf vielen Chains, und eine über eine Bridge übertragene Version ist ein eigenständiger Contract, den die Einfrierfunktion des ursprünglichen Emittenten möglicherweise nicht erreicht. Große Stablecoin-Flüsse auf Tron werden in Lektion 5.4 behandelt.
NFTs und Multi-Token-Standards
Ein ERC-721-Token weist jeder Token-ID genau einen Eigentümer zu. Sein Transfer(address,address,uint256) hat denselben topic0 wie ERC-20, da indexed nicht Teil der Signatur ist. Die Token-ID ist jedoch indiziert: Ein ERC-721-Transfer hat vier Topics und leere Daten, ein ERC-20-Transfer drei Topics mit dem Betrag in den Daten. Ein Decoder, der nur topic0 als Zuordnungsschlüssel verwendet, liest Token-IDs als Beträge. ApprovalForAll erlaubt einem Operator, üblicherweise einem Marktplatz-Contract, sämtliche Token zu bewegen, die der Eigentümer in einer Kollektion hält. Phishing, das diese Freigabe erlangt, kann eine Kollektion in einer einzigen Transaktion leeren: Es ist das erste Event, das Sie prüfen sollten, wenn ein Opfer gestohlene NFTs meldet. Um festzustellen, welchen Standard ein Contract nach eigener Angabe unterstützt, rufen Sie supportsInterface (ERC-165) auf: 0x80ac58cd für ERC-721, 0xd9b67a26 für ERC-1155, 0x2a55205a für den Lizenzgebührenstandard ERC-2981. Frühe Kollektionen können älter als die Standards sein: CryptoPunks (2017) verwenden benutzerdefinierte Events wie PunkTransfer und PunkBought, die für einen reinen ERC-721-Decoder unsichtbar sind.
ERC-1155 fasst viele Token-Typen in einem Contract zusammen, jeweils mit einer id und einer Menge pro Inhaber. Seine Events TransferSingle (topic0 0xc3d58168…0f62) und TransferBatch (0x4a39dc06…f7fb) enthalten einen Operator, also das Konto, das die Übertragung durchführt. Bei einem Marktplatzverkauf erscheint daher der Marktplatz als Operator und der Verkäufer als from. Minting und Burning verwenden die Nulladresse. Batch-Events enthalten Arrays von IDs und Werten. Aus einem TransferBatch muss eine Zeile pro ID entstehen, andernfalls verschwindet der Großteil des Volumens eines Contracts mit vielen Batch-Vorgängen unbemerkt.
Verkäufe, Lizenzgebühren und Wash-Flüsse
Ein Transfer-Event enthält keinen Preis: Eigentümer bewegen NFTs zwischen eigenen Wallets, verleihen sie, verteilen sie per Airdrop und verkaufen sie gegen Off-Chain-Zahlungen. Ein Verkauf ist eine Schlussfolgerung aus einer Zahlung in derselben Transaktion und idealerweise dem Abwicklungs-Event des Marktplatzes. Seaport, das von OpenSea und anderen verwendet wird, gibt OrderFulfilled mit einem Angebot (was der Ersteller des Auftrags gibt) und einer Gegenleistung (was der Ersteller und die Gebührenempfänger erhalten) aus: Bei einem für 10 ETH verkauften Angebot zahlt die Gegenleistung 9,45 ETH an den Verkäufer, 0,05 ETH (0,5 %) an eine Gebührenadresse und 0,5 ETH (5 %) an den Urheber. Wenn ein Verkäufer ein Gebot annimmt, ist der Anbieter der Käufer, der WETH anbietet. Der Preis pro Einzelobjekt eines Bündels ist eine rechnerische Zuordnung und sollte als solche gekennzeichnet werden. ERC-2981-Lizenzgebühren haben informativen Charakter (OpenSea machte beispielsweise Urhebergebühren für neue Kollektionen ab dem 31. August 2023 optional). Messen Sie deshalb die tatsächlich gezahlten Lizenzgebühren, nicht den angegebenen Satz.
NFTs können eine Wertübertragung als Verkauf tarnen: Ein Geldwäscher kauft mit illegalen Geldern ein NFT von einer Wallet, die er ebenfalls kontrolliert, und die Erlöse erscheinen als Handelseinkünfte. Der Zahlungsfluss trägt den Wert: Verfolgen Sie die an den Verkäufer gezahlten ETH oder Stablecoins und behandeln Sie die NFT-Bewegung als Kontext. Zu den Wash-Trading-Indizien gehören geschlossene Kreisläufe (A → B → A), ein gemeinsamer Geldgeber von Käufer und Verkäufer, ein gemeinsamer Abflussweg für Erlöse, eine risikofreie Gesamtposition, Eigenfinanzierung über Flash Loans oder Zahlungen innerhalb derselben Transaktion sowie Preise weit oberhalb der üblichen Spanne der Kollektion. CryptoPunk 9998 ist das bekannte Beispiel: Am 28. Oktober 2021 wurde er für etwa 124.457 ETH (rund 532 Millionen US-Dollar) „verkauft“, wobei der Käufer ihn, wie die Schöpfer der Kollektion erklärten, mit geliehenem Geld von sich selbst kaufte und dieses Geld in derselben Transaktion zurückzahlte. Eine begutachtete Studie (La Morgia et al., IEEE ICDCS 2023) stellte fest, dass Wash-Trading etwa 85 % des Volumens auf LooksRare ausmachte, das Handelsvolumen mit Token belohnte. Eine Abfrage nach Token, die von ihrem früheren Verkäufer zurückgekauft wurden, liefert Ermittlungsansätze, keine Feststellungen. Die Sicherheit steigt, wenn unabhängige Indizien übereinstimmen (Lektion 6.5).
Prüfungsschwerpunkt: die vier Kanäle, in denen sich Werte auf Chains mit Kontomodell bewegen, und ihre jeweiligen Aufzeichnungsorte; warum interne Übertragungen einen tracingfähigen Knoten benötigen und warum Client, Version und Methode dokumentiert werden; Identifizierung von Token anhand der Contract-Adresse, Umrechnung mit den richtigen Dezimalstellen sowie die Fallstricke gefälschter Token und des Address Poisoning; Minting- und Burning-Konventionen und Token, die davon abweichen (WETH, Fee-on-Transfer, Rebasing), mit Abgleich gegenbalanceOfundtotalSupply; approve,transferFrom, EIP-2612-Permit und Drainer-Aufteilungen als Schlussfolgerung über Rollen; Lesen und Abgleichen eines dekodierten Drainer-Traces; zusätzliche Felder im Hop-Datensatz; Einfrieren von Stablecoins und die Grenzen der Einblicksmöglichkeiten des Emittenten; ERC-721- gegenüber ERC-20-Topics, ApprovalForAll, ERC-1155-Operator und Batches; dass eine Übertragung keinen Preis hat; Verfolgen des Zahlungsflusses bei NFT-Wash-Flüssen.