Token-, NFT- und Smart-Contract-Flüsse · Lektion 2 von 6
NFTs und Multi-Token-Standards
8 Min. Lesezeit
Nicht-fungible Token sind der Bereich, in dem On-Chain-Daten in der Öffentlichkeit am häufigsten falsch interpretiert werden. Eine einzelne NFT-Übertragung sagt nichts über den Preis aus, ein „Rekordverkauf“ kann ein Kredit sein, der in derselben Transaktion zurückgezahlt wurde, und Angaben zu Lizenzgebühren hängen von den Richtlinien des Marktplatzes ab, nicht vom Token. Analysten müssen einfache Übertragungen von Verkäufen unterscheiden, die eigenen Ereignisse des Marktplatzes entschlüsseln, um Preis und Gebührenaufteilung zu ermitteln, und Anzeichen für Wash-Trading erkennen.
ERC-721-Ereignisse
Ein ERC-721-Token (EIP-721) gibt jeder Token-ID genau einen Eigentümer. Der Standard definiert drei Ereignisse:
| Ereignis | Topics | Daten |
|---|---|---|
Transfer(address indexed from, address indexed to, uint256 indexed tokenId) | topic0, from, to, tokenId | leer |
Approval(address indexed owner, address indexed approved, uint256 indexed tokenId) | topic0, owner, approved, tokenId | leer |
ApprovalForAll(address indexed owner, address indexed operator, bool approved) | topic0, owner, operator | approved-Flag |
Da die kanonische Signatur Transfer(address,address,uint256) mit der von ERC-20 identisch ist, ist auch topic0 derselbe Wert (0xddf252ad…b3ef). Das Schlüsselwort indexed ist nicht Teil der Signatur und ändert deshalb den Hash nicht; es ändert nur, wo der Wert gespeichert wird. Ein ERC-721-Transfer hat vier Topics und leere Daten; ein ERC-20-Transfer hat drei Topics und den Betrag in den Daten. Ein Decoder, der nur nach topic0 unterscheidet, liest Token-IDs als Beträge. So haben manche Dashboards „Übertragungen“ von Milliarden Einheiten einer Kunstsammlung gemeldet.
Beim Minting gilt die ERC-20-Konvention: from ist die Nulladresse. ApprovalForAll ist das NFT-Äquivalent einer unbegrenzten ERC-20-Freigabe: Sie ermöglicht einem Operator, üblicherweise einem Marktplatz-Contract, jeden Token zu übertragen, den der Eigentümer in dieser Sammlung hält. Phishing-Kampagnen, die eine ApprovalForAll-Signatur erlangen, können eine Sammlung aus einer Wallet mit einer einzigen Transaktion leeren. Deshalb ist dieses Ereignis das Erste, was geprüft werden sollte, wenn ein Opfer gestohlene NFTs meldet.
Um zu bestätigen, welchen Standard ein Contract zu implementieren vorgibt, rufe supportsInterface (ERC-165) auf: Die Interface-ID für ERC-721 lautet 0x80ac58cd, für ERC-1155 0xd9b67a26 und für den Lizenzgebührenstandard ERC-2981 0x2a55205a. Einige frühe Sammlungen gab es bereits vor den Standards. CryptoPunks (2017) verwenden ihren eigenen Contract mit benutzerdefinierten Ereignissen wie PunkTransfer und PunkBought; ihre Trades sind für einen Decoder, der nur ERC-721-Transfers liest, nicht sichtbar.
ERC-1155-Multi-Token
ERC-1155 (EIP-1155) vereint viele Token-Typen in einem Contract. Jeder Typ hat eine id, und jeder Inhaber hält eine bestimmte Menge dieser ID. So kann derselbe Contract eine fungible Spielwährung (ID 1, Millionen Einheiten) und einzigartige Einzelstücke (Menge 1) halten. Die Übertragungsereignisse sind:
TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value)TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values)
Der Operator ist das Konto, das zur Durchführung der Übertragung berechtigt ist, und sollte der Aufrufer sein. Bei einem Marktplatzverkauf wird daher der Marktplatz-Contract als Operator und der Verkäufer als from angezeigt. Wie bei den anderen Standards wird beim Minting from auf die Nulladresse und beim Burnen to auf die Nulladresse gesetzt. Die topic0-Werte sind 0xc3d58168…0f62 für TransferSingle und 0x4a39dc06…f7fb für TransferBatch.
Batch-Ereignisse enthalten zwei dynamische Arrays in data, die mit Offsets kodiert sind. Ein Batch, der drei Einheiten der ID 7 und eine Einheit der ID 12 überträgt, wird folgendermaßen dekodiert:
Wort 0: 0x…40 Offset des ids-Arrays (64 Bytes ab Beginn der Daten)
Wort 1: 0x…a0 Offset des values-Arrays (160 Bytes)
Wort 2: 0x…02 Länge von ids = 2
Wort 3: 0x…07 ids[0] = 7
Wort 4: 0x…0c ids[1] = 12
Wort 5: 0x…02 Länge von values = 2
Wort 6: 0x…03 values[0] = 3
Wort 7: 0x…01 values[1] = 1
Die ersten beiden Wörter zeigen auf den Beginn der jeweiligen Arrays; jedes Array beginnt dann mit seiner Länge. Die Paare werden nach Position gelesen: (ID 7, 3 Einheiten) und (ID 12, 1 Einheit). In einer flachen Tabelle wird aus einem TransferBatch so viele Zeilen, wie IDs vorhanden sind. Werden die Arrays nicht in einzelne Zeilen aufgeteilt, geht der Großteil des Volumens von Contracts mit vielen Batch-Übertragungen unbemerkt verloren. ERC-1155 definiert außerdem ApprovalForAll und URI(string value, uint256 indexed id), wobei Letzteres Metadatenänderungen ankündigt.
Verkäufe und einfache Übertragungen
Ein Transfer-Ereignis enthält allein keinen Preis. Eigentümer übertragen NFTs zwischen ihren eigenen Wallets, verleihen sie, verschenken sie per Airdrop oder verkaufen sie gegen Zahlungen außerhalb der Chain. Ein Verkauf lässt sich aus weiteren Belegen in derselben Transaktion ableiten: einem Zahlungsfluss (native Coins in den Traces oder ein ERC-20-Transfer wie WETH) und idealerweise einem eigenen Abwicklungsereignis des Marktplatzes.
Seaport, das von OpenSea und anderen verwendete Open-Source-Protokoll, gibt OrderFulfilled mit einem Angebot (was der Ersteller der Order gibt) und einer Gegenleistung (was der Ersteller und etwaige Gebührenempfänger erhalten müssen) aus. Ein vereinfachtes dekodiertes Beispiel für ein Listing, das für 10 ETH verkauft wurde:
{
"event": "OrderFulfilled",
"offerer": "0x5e11…a7b3",
"recipient": "0xb7e2…19cd",
"offer": [
{"itemType": 2, "token": "0xc011…77ab", "identifier": "4321", "amount": "1"}
],
"consideration": [
{"itemType": 0, "amount": "9450000000000000000", "recipient": "0x5e11…a7b3"},
{"itemType": 0, "amount": "50000000000000000", "recipient": "0xfee0…2c1d"},
{"itemType": 0, "amount": "500000000000000000", "recipient": "0xc4ea…b0b1"}
]
}
Elementtyp 2 ist ein ERC-721-Token, Elementtyp 0 ist die native Coin. Der Ersteller des Angebots (der Verkäufer) gibt Token 4321 ab; die Gegenleistung zahlt 9,45 ETH an den Verkäufer, 0,05 ETH (0,5 %) an eine Gebührenadresse und 0,5 ETH (5 %) an den Ersteller. Der Verkaufspreis ist die Summe: 10 ETH. Die Ausrichtung ist wichtig: Wenn ein Verkäufer ein Gebot annimmt, ist der Ersteller des Angebots der Käufer, das Angebot besteht aus WETH und der NFT befindet sich in der Gegenleistung. Weitere Komplikationen:
- Bundles: eine Zahlung für mehrere NFTs; jeder Einzelpreis ist eine Zuteilung und sollte als solche gekennzeichnet werden.
- Aggregator-Dienste: Ein Router kauft in einer Transaktion bei mehreren Marktplätzen; ordne jedes Element der Order zu, die ausgeführt wurde.
- Zahlungstoken: Preise in WETH, Stablecoins oder anderen Token müssen anhand des Preises zum Blockzeitpunkt umgerechnet werden.
| Was du in der Transaktion siehst | Wahrscheinliche Bedeutung |
|---|---|
| Nur NFT-Transfer | Wallet-Übertragung, Geschenk oder Verkauf außerhalb der Chain; kein Preis |
NFT-Transfer und eine Zahlung an die Adresse from | Wahrscheinlicher Verkauf; mit einem Marktplatzereignis bestätigen |
| Abwicklungsereignis des Marktplatzes | Verkauf mit Preis und Gebührenaufteilung |
| Minting (von der Nulladresse) mit Zahlung an den Contract | Primärverkauf zum Minting-Preis |
Lizenzgebühren
ERC-2981 standardisiert eine Abfrage, royaltyInfo(tokenId, salePrice), die einen Empfänger und einen Betrag zurückgibt. Sie dient nur der Information: Nichts im Token zwingt einen Marktplatz zur Zahlung. Einige Sammlungen versuchten, die Zahlung durch eine Sperre für Transfers über nicht zahlende Marktplätze durchzusetzen, doch die Durchsetzung ließ nach. OpenSea beispielsweise deaktivierte sein On-Chain-Durchsetzungstool und machte die Gebühren für Ersteller bei neuen Sammlungen ab dem 31. August 2023 und bei älteren Sammlungen, die auf die Durchsetzung gesetzt hatten, nach dem 29. Februar 2024 optional. Für Analysen solltest du die tatsächlich gezahlten Lizenzgebühren messen (Gegenleistungsposten, die an den Empfänger der Lizenzgebühren gesendet wurden), statt den vom Token angegebenen Satz, und davon ausgehen, dass der effektive Satz je nach Marktplatz und im Zeitverlauf variiert.
Anzeichen für Wash-Trading
Wash-Trading bedeutet, mit sich selbst oder mit kolludierenden Konten zu handeln, um das Volumen vorzutäuschen, einen Preis aufzublähen oder Prämien abzugreifen. Das bekannteste Beispiel ist CryptoPunk 9998 vom 28. Oktober 2021: ein „Verkauf“ für rund 124.457 ETH (damals etwa 532 Millionen US-Dollar), bei dem der Käufer den Punk, wie die Ersteller der Sammlung erklärten, mit geliehenem Geld von sich selbst kaufte und den Kredit in derselben Transaktion zurückzahlte. Volumenprämien schaffen anhaltende Anreize: Eine begutachtete Studie zu NFT-Märkten auf Ethereum (La Morgia et al., IEEE ICDCS 2023) ergab, dass Wash-Trading etwa 85 % des Volumens auf LooksRare ausmachte, einem Marktplatz, der Token-Prämien proportional zum Handelsvolumen auszahlte.
Zu den von Forschern und Analysten verwendeten Anzeichen gehören:
- Geschlossene Kreisläufe: Derselbe Token wandert von A → B → A oder durch einen kleinen Ring von Konten.
- Gemeinsame Finanzierungsquelle: Käufer und Verkäufer wurden kurz vor dem Handel aus derselben Quelle finanziert.
- Gemeinsamer Abfluss: Die Erlöse beider Seiten landen an derselben Adresse.
- Risikofreie Position: Die kolludierenden Konten haben zusammengenommen denselben Kontostand wie zuvor, abzüglich der Gebühren.
- Selbstfinanzierung: Flash Loans oder Zahlungen innerhalb derselben Transaktion, die an den Zahler zurückfließen.
- Preise weit über der jüngsten Spanne der Sammlung sowie schnelle wiederholte Trades desselben Tokens.
Ein einfacher Round-Trip-Filter für eine dekodierte nft_sales-Tabelle:
-- Token, die innerhalb von 30 Tagen von ihrem früheren Verkäufer zurückgekauft wurden
SELECT a.collection, a.token_id, a.seller, a.buyer,
a.price_eth AS first_price, b.price_eth AS return_price
FROM nft_sales a
JOIN nft_sales b
ON b.collection = a.collection
AND b.token_id = a.token_id
AND b.seller = a.buyer
AND b.buyer = a.seller
AND b.block_time > a.block_time
AND b.block_time <= a.block_time + INTERVAL '30' DAY
ORDER BY a.price_eth DESC;
Der Self-Join ordnet jeden Verkauf einem späteren Verkauf desselben Tokens zu, bei dem die Rollen vertauscht sind. Die Intervallsyntax unterscheidet sich je nach Datenbank-Engine. Ein Treffer ist ein Hinweis, kein Beweis: Sammler kaufen gelegentlich ein Stück zurück, das sie verkauft haben. Die Aussagekraft steigt, wenn mehrere unabhängige Anzeichen zusammenkommen, etwa eine gemeinsame Finanzierungsquelle, ein Round-Trip und das Einfordern einer Prämie. Zur Analyse der Finanzierung siehe die Lektion Heuristiken zum Kontomodell.
Prüfungsschwerpunkt: ERC-721 Transfer, Approval und ApprovalForAll und warum ein ERC-721-Transfer vier Topics und leere Daten hat; ERC-1155 TransferSingle und TransferBatch, das Operator-Feld und das Aufteilen von Batch-Arrays; Minting und Burnen über die Nulladresse; warum eine Übertragung keinen Preis enthält und wie ein Marktplatzereignis (Angebot und Gegenleistung) Preis und Gebührenaufteilung liefert; Bundles und die Ausrichtung bei Geboten; ERC-2981 als Information und der Wechsel zu optionalen Gebühren für Ersteller; Anzeichen für Wash-Trading (geschlossene Kreisläufe, gemeinsame Finanzierungsquelle, gemeinsamer Abfluss, risikofreie Position) und der Fall CryptoPunk 9998.