Verifizierte Verträge, Proxys und der Upgrade-Schlüssel, den niemand erwähnt

·7 Min. Lesezeit·Von SSP Editorial Team
SSP-Academy-Titelbild: verifizierte Smart Contracts, Proxys und Upgrade-Schlüssel

Verifizierte Verträge, Proxys und der Upgrade-Schlüssel, den niemand erwähnt

Auf dem Block-Explorer steht ein grüner Haken mit der Aufschrift Contract Source Code Verified, und sehr viele Menschen lesen ihn als „dieser Vertrag ist sicher“.

Das bedeutet er nicht. Er bedeutet etwas viel Engeres und viel Nützlicheres, und das eine mit dem anderen zu verwechseln ist der Weg, auf dem sorgfältige Menschen am Ende Dinge freigeben, denen sie nie zugestimmt hätten.

Was „verifiziert“ tatsächlich bescheinigt

Verträge werden als Bytecode ausgerollt — Maschinenbefehle, in der Praxis unlesbar. Verifizierung ist der Vorgang, den originalen Quelltext hochzuladen und den Explorer bestätigen zu lassen, dass dessen Kompilierung, mit der angegebenen Compilerversion und den angegebenen Einstellungen, exakt den Bytecode ergibt, der bereits an dieser Adresse liegt.

Das ist die gesamte Behauptung: der Quelltext, den du liest, ist wirklich der Quelltext, der läuft.

Das ist eine echte und wertvolle Zusage. Ohne sie hättest du keine Möglichkeit zu wissen, ob der hübsch aussehende Code auf dem GitHub eines Projekts irgendetwas mit dem zu tun hat, was deine Transaktion gleich berührt.

Aber achte darauf, was er alles nicht sagt. Verifizierung ist keine Prüfung. Niemand hat beurteilt, ob der Code korrekt ist, ob er Fehler hat oder ob er irgendetwas tut, was seine Funktionsnamen nahelegen. Ein Vertrag mit einer Funktion namens claimRewards, die dein gesamtes Guthaben an den Bereitsteller überweist, kann verifiziert sein — und die Verifizierung wäre völlig ehrlich: Sie bescheinigte wahrheitsgemäß, dass der Diebstahl genau das ist, was der Code sagt.

Verifiziert heißt lesbar, nicht vertrauenswürdig. Es verschiebt die Frage von „was ist dieses Ding?“ zu „verstehe ich, was ich gerade gelesen habe?“, was Fortschritt ist, dir die zweite Frage aber nicht beantwortet.

Auch die Umkehrung zählt. Ein unverifizierter Vertrag ist kein Beweis für Bosheit — viele legitime Bereitstellungen kommen nie zur Verifizierung. Er bedeutet aber, dass niemand — kein Werkzeug, das du benutzt, und kein Forscher, der dich hätte warnen können — lesen kann, womit du gleich interagierst. Dabei vorsichtig zu sein ist vernünftig.

Und dann machen Proxys es schlimmer

Hier verschiebt sich der Boden, und das ist der Teil, der meist unerwähnt bleibt.

Die meisten nicht trivialen Verträge, mit denen du zu tun hast, sind keine einzelnen Verträge. Sie sind Proxys. Der Proxy ist die Adresse, die du siehst, und er hält alle Daten — Guthaben, Freigaben, Zustand. Aber er enthält so gut wie keine Logik. Stattdessen reicht er jeden Aufruf an einen separaten Implementierungsvertrag weiter und führt schlicht aus, was dieser sagt.

Der Grund ist Aufrüstbarkeit. Unveränderliche Verträge lassen sich nicht flicken, also ist ein Fehler dauerhaft und eine fehlende Funktion für immer fort. Einen Proxy auf eine neue Implementierung zeigen zu lassen erlaubt einem Team, Fehler zu beheben und Verbesserungen auszuliefern, ohne jeden Nutzer zur Migration zu bitten. Angesichts dessen, wie viel Wert durch unbehebbare Fehler verloren ging, ist das eine vertretbare Entwurfsentscheidung.

Sie hat eine leicht zu übersehende Folge. Wenn du einen Proxy im Explorer nachschlägst und ihn verifiziert siehst, hast du die Weiterleitungslogik verifiziert, nicht das Verhalten. Der Code, der tatsächlich entscheidet, was mit deinem Geld geschieht, liegt an der Implementierungsadresse, die der Explorer prominent zeigen mag oder auch nicht, und die ersetzt werden kann.

Die eigentliche Frage lautete also nie „ist dieser Vertrag verifiziert?“. Sie lautet:

Wer kann das Verhalten dieses Vertrags ändern, und wie schnell?

Der Admin-Schlüssel ist das eigentliche Sicherheitsmodell

Jeder aufrüstbare Vertrag hat jemanden, der die Aufrüstung durchführen kann. Diese Befugnis ist das Sicherheitsmodell, gleichgültig wie gut der gegenwärtige Code ist.

Die Bandbreite reicht von alarmierend bis vernünftig:

Ein einzelnes extern besessenes Konto. Ein privater Schlüssel, auf irgendjemandes Rechner, kann die Logik des Vertrags austauschen, der dein Geld hält. Wird er erphisht, gestohlen oder sein Besitzer genötigt, wird der Vertrag zu dem, was der Angreifer will. Diese Anordnung ist häufiger, als sie sein sollte.

Ein Multisig. Mehrere Unterzeichner müssen zustimmen. Deutlich besser — der einzelne Ausfallpunkt fällt weg —, wobei es sich lohnt zu wissen, wie viele Unterzeichner es sind und ob es wirklich unabhängige Menschen sind oder vier Laptops desselben Teams.

Ein Multisig hinter einer Zeitsperre. Eine Aufrüstung wird on-chain angekündigt und kann erst nach einer festen Verzögerung ausgeführt werden, oft 24 bis 72 Stunden. Das ist die bedeutsame Variante, denn sie verändert deine Lage vollständig: Du bekommst Vorwarnung und ein Fenster, um abzuziehen, bevor die Änderung greift. Eine Zeitsperre verhindert keine bösartige Aufrüstung. Sie macht sie überlebbar.

Gar kein Aufrüstungspfad. Der Vertrag ist unveränderlich. Höchste Vorhersagbarkeit, null Abhilfe, wenn ein Fehler gefunden wird. Eine legitime Wahl, meist getroffen von Protokollen, die lange genug im Feld erprobt sind, um darauf zu setzen.

Keine dieser Varianten ist automatisch richtig. Aber der Unterschied zwischen „ein Schlüssel“ und „Multisig plus zwei Tage Verzögerung“ ist der Unterschied zwischen darauf hoffen, dass niemand einen Fehler macht, und Zeit haben, zu reagieren, wenn es doch geschieht.

Warum das gerade bei Freigaben zubeißt

Das ist der Teil, der mit etwas zusammenhängt, das du tatsächlich regelmäßig tust.

Wenn du eine Token-Freigabe erteilst, ermächtigst du eine Adresse, deine Token zu bewegen. Kein Stück Code — eine Adresse. Die Freigabe liegt im Speicher des Token-Vertrags und bleibt unbefristet bestehen.

Ist diese Adresse ein aufrüstbarer Proxy, dann kann die Logik, die deine Token bewegen darf, nach deiner Freigabe ersetzt werden — ohne dein Zutun und ohne jede neue Signatur von dir. Du hast das eine geprüft und bleibst dem anderen ausgesetzt.

Deshalb wiegt der stehende Rat, nicht mehr genutzte Freigaben zu widerrufen, schwerer, als er zunächst wirkt. Es geht nicht nur darum, dass ein Vertrag sich als fehlerhaft herausstellt. Es geht darum, dass eine unbegrenzte Freigabe an einen aufrüstbaren Vertrag eine Erlaubnis an denjenigen ist, der den Upgrade-Schlüssel kontrolliert — so lange du sie offen lässt.

Es ist außerdem die schärfste Grenze der Transaktionssimulation. Vor dem Signieren zu simulieren sagt dir, was eine Transaktion gegen den gegenwärtigen Zustand und die gegenwärtige Implementierung tut. Das ist wirklich nützlich, und es kann dir nicht sagen, was dieselbe Freigabe nächsten Monat erlauben wird.

Was SSP dir zeigt und wo es aufhört

Wenn SSP Key eine Freigabe darstellt, dekodiert es die Aufrufdaten, statt dir rohes Hex zu zeigen. Es erkennt die üblichen ERC-20-Selektoren — approve, transfer, transferFrom, increaseAllowance, setApprovalForAll — und gibt sie in klarer Sprache wieder, samt Kennzeichnung unbegrenzter Freigaben, im Code definiert als jeder Betrag ab 2^255.

Der Dekodierer ist bewusst zurückhaltend. Sein eigener Kopfkommentar beschreibt ihn als reine Darstellungsschicht: Er ändert nie, was signiert wird, und er scheitert geschlossen. Ein unbekannter Selektor, eine falsche Länge, fehlerhaftes Hex oder nicht standardkonforme Adressauffüllung führen dazu, dass er nichts zurückgibt und auf eine generische Aktion mit rohem Hex hinter einer „Erweitert“-Ansicht zurückfällt. Lieber gibt er zu, es nicht zu wissen, als selbstsicher zu raten und falsch zu liegen. Token-Symbole und -Dezimalstellen werden nur angehängt, wenn sie aus dem Verzeichnis auf dem Gerät bekannt sind, nie erschlossen.

Nun die ehrliche Grenze. Der Dekodierer kennt den Begriff Proxy nicht. Ein Implementierungsvertrag kommt darin nirgends vor. Er kann dir korrekt und klar sagen: „du erteilst eine unbegrenzte USDC-Freigabe an 0xABC…“ — und er kann dir nicht sagen, dass 0xABC ein Proxy ist, wer dessen Upgrade-Schlüssel hält oder dass dessen Verhalten nächste Woche völlig anders sein kann.

Das ist weniger ein Versäumnis als eine Grenze, die kein Wallet-Dekodierer überschreiten kann. Dekodieren beschreibt den Aufruf vor dir. Ob die Gegenstelle aufrüstbar ist und wer sie regiert, ist eine Eigenschaft der weiteren Welt, die gesondert geprüft werden muss. Wir nennen die Grenze lieber, als einen selbstsicher aussehenden Freigabebildschirm eine Vollständigkeit andeuten zu lassen, die er nicht hat.

Eine praktische Prüfung, bevor du etwas Bedeutendes freigibst

Ist er verifiziert? Wenn nicht, sei dir bewusst, dass du allein dem Ruf vertraust.

Ist es ein Proxy? Explorer kennzeichnen das — achte auf einen Proxy-Hinweis oder eine Option „Read as Proxy“. Wenn sie da ist, ist die Implementierung der Code, auf den es ankommt.

Wer kann ihn aufrüsten, und gibt es eine Verzögerung? Das ist die wertvollste Frage der Liste und die, die fast niemand stellt. Ein Projekt, das darüber nachgedacht hat, dokumentiert es. Eines, das es nicht getan hat oder nichts sagt, hat dir etwas mitgeteilt.

Muss die Freigabe unbegrenzt sein? Meist nicht. Den Betrag freizugeben, den du tatsächlich ausgeben willst, begrenzt dein Risiko genau darauf, ganz gleich, was aus dem Vertrag später wird.

Widerrufe, wenn du fertig bist. Eine offene Freigabe ist eine stehende Erlaubnis, und sie überlebt deine Aufmerksamkeit.

Die lohnende gedankliche Verschiebung ist klein und ändert viel. Verifizierung sagt dir, welcher Code gerade jetzt läuft. Aufrüstbarkeit sagt dir, wer entscheidet, was morgen läuft. Fast das gesamte Risiko wohnt in der zweiten Frage, und fast die gesamte angebotene Beruhigung betrifft nur die erste.

Diesen Artikel teilen

Verwandte Artikel