/** * HTTP API: WP_Http_Curl class * * @package WordPress * @subpackage HTTP * @since 4.4.0 */ /** * Core class used to integrate Curl as an HTTP transport. * * HTTP request method uses Curl extension to retrieve the url. * * Requires the Curl extension to be installed. * * @since 2.7.0 * @deprecated 6.4.0 Use WP_Http * @see WP_Http */ #[AllowDynamicProperties] class WP_Http_Curl { /** * Temporary header storage for during requests. * * @since 3.2.0 * @var string */ private $headers = ''; /** * Temporary body storage for during requests. * * @since 3.6.0 * @var string */ private $body = ''; /** * The maximum amount of data to receive from the remote server. * * @since 3.6.0 * @var int|false */ private $max_body_length = false; /** * The file resource used for streaming to file. * * @since 3.6.0 * @var resource|false */ private $stream_handle = false; /** * The total bytes written in the current request. * * @since 4.1.0 * @var int */ private $bytes_written_total = 0; /** * Send a HTTP request to a URI using cURL extension. * * @since 2.7.0 * * @param string $url The request URL. * @param string|array $args Optional. Override the defaults. * @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'. A WP_Error instance upon error */ public function request( $url, $args = array() ) { $defaults = array( 'method' => 'GET', 'timeout' => 5, 'redirection' => 5, 'httpversion' => '1.0', 'blocking' => true, 'headers' => array(), 'body' => null, 'cookies' => array(), 'decompress' => false, 'stream' => false, 'filename' => null, ); $parsed_args = wp_parse_args( $args, $defaults ); if ( isset( $parsed_args['headers']['User-Agent'] ) ) { $parsed_args['user-agent'] = $parsed_args['headers']['User-Agent']; unset( $parsed_args['headers']['User-Agent'] ); } elseif ( isset( $parsed_args['headers']['user-agent'] ) ) { $parsed_args['user-agent'] = $parsed_args['headers']['user-agent']; unset( $parsed_args['headers']['user-agent'] ); } // Construct Cookie: header if any cookies are set. WP_Http::buildCookieHeader( $parsed_args ); $handle = curl_init(); // cURL offers really easy proxy support. $proxy = new WP_HTTP_Proxy(); if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) { curl_setopt( $handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP ); curl_setopt( $handle, CURLOPT_PROXY, $proxy->host() ); curl_setopt( $handle, CURLOPT_PROXYPORT, $proxy->port() ); if ( $proxy->use_authentication() ) { curl_setopt( $handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY ); curl_setopt( $handle, CURLOPT_PROXYUSERPWD, $proxy->authentication() ); } } $is_local = isset( $parsed_args['local'] ) && $parsed_args['local']; $ssl_verify = isset( $parsed_args['sslverify'] ) && $parsed_args['sslverify']; if ( $is_local ) { /** This filter is documented in wp-includes/class-wp-http-streams.php */ $ssl_verify = apply_filters( 'https_local_ssl_verify', $ssl_verify, $url ); } elseif ( ! $is_local ) { /** This filter is documented in wp-includes/class-wp-http.php */ $ssl_verify = apply_filters( 'https_ssl_verify', $ssl_verify, $url ); } /* * CURLOPT_TIMEOUT and CURLOPT_CONNECTTIMEOUT expect integers. Have to use ceil since. * a value of 0 will allow an unlimited timeout. */ $timeout = (int) ceil( $parsed_args['timeout'] ); curl_setopt( $handle, CURLOPT_CONNECTTIMEOUT, $timeout ); curl_setopt( $handle, CURLOPT_TIMEOUT, $timeout ); curl_setopt( $handle, CURLOPT_URL, $url ); curl_setopt( $handle, CURLOPT_RETURNTRANSFER, true ); curl_setopt( $handle, CURLOPT_SSL_VERIFYHOST, ( true === $ssl_verify ) ? 2 : false ); curl_setopt( $handle, CURLOPT_SSL_VERIFYPEER, $ssl_verify ); if ( $ssl_verify ) { curl_setopt( $handle, CURLOPT_CAINFO, $parsed_args['sslcertificates'] ); } curl_setopt( $handle, CURLOPT_USERAGENT, $parsed_args['user-agent'] ); /* * The option doesn't work with safe mode or when open_basedir is set, and there's * a bug #17490 with redirected POST requests, so handle redirections outside Curl. */ curl_setopt( $handle, CURLOPT_FOLLOWLOCATION, false ); curl_setopt( $handle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS ); switch ( $parsed_args['method'] ) { case 'HEAD': curl_setopt( $handle, CURLOPT_NOBODY, true ); break; case 'POST': curl_setopt( $handle, CURLOPT_POST, true ); curl_setopt( $handle, CURLOPT_POSTFIELDS, $parsed_args['body'] ); break; case 'PUT': curl_setopt( $handle, CURLOPT_CUSTOMREQUEST, 'PUT' ); curl_setopt( $handle, CURLOPT_POSTFIELDS, $parsed_args['body'] ); break; default: curl_setopt( $handle, CURLOPT_CUSTOMREQUEST, $parsed_args['method'] ); if ( ! is_null( $parsed_args['body'] ) ) { curl_setopt( $handle, CURLOPT_POSTFIELDS, $parsed_args['body'] ); } break; } if ( true === $parsed_args['blocking'] ) { curl_setopt( $handle, CURLOPT_HEADERFUNCTION, array( $this, 'stream_headers' ) ); curl_setopt( $handle, CURLOPT_WRITEFUNCTION, array( $this, 'stream_body' ) ); } curl_setopt( $handle, CURLOPT_HEADER, false ); if ( isset( $parsed_args['limit_response_size'] ) ) { $this->max_body_length = (int) $parsed_args['limit_response_size']; } else { $this->max_body_length = false; } // If streaming to a file open a file handle, and setup our curl streaming handler. if ( $parsed_args['stream'] ) { if ( ! WP_DEBUG ) { $this->stream_handle = @fopen( $parsed_args['filename'], 'w+' ); } else { $this->stream_handle = fopen( $parsed_args['filename'], 'w+' ); } if ( ! $this->stream_handle ) { return new WP_Error( 'http_request_failed', sprintf( /* translators: 1: fopen(), 2: File name. */ __( 'Could not open handle for %1$s to %2$s.' ), 'fopen()', $parsed_args['filename'] ) ); } } else { $this->stream_handle = false; } if ( ! empty( $parsed_args['headers'] ) ) { // cURL expects full header strings in each element. $headers = array(); foreach ( $parsed_args['headers'] as $name => $value ) { $headers[] = "{$name}: $value"; } curl_setopt( $handle, CURLOPT_HTTPHEADER, $headers ); } if ( '1.0' === $parsed_args['httpversion'] ) { curl_setopt( $handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0 ); } else { curl_setopt( $handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1 ); } /** * Fires before the cURL request is executed. * * Cookies are not currently handled by the HTTP API. This action allows * plugins to handle cookies themselves. * * @since 2.8.0 * * @param resource $handle The cURL handle returned by curl_init() (passed by reference). * @param array $parsed_args The HTTP request arguments. * @param string $url The request URL. */ do_action_ref_array( 'http_api_curl', array( &$handle, $parsed_args, $url ) ); // We don't need to return the body, so don't. Just execute request and return. if ( ! $parsed_args['blocking'] ) { curl_exec( $handle ); $curl_error = curl_error( $handle ); if ( $curl_error ) { if ( PHP_VERSION_ID < 80000 ) { // curl_close() has no effect as of PHP 8.0. curl_close( $handle ); } return new WP_Error( 'http_request_failed', $curl_error ); } if ( in_array( curl_getinfo( $handle, CURLINFO_HTTP_CODE ), array( 301, 302 ), true ) ) { if ( PHP_VERSION_ID < 80000 ) { // curl_close() has no effect as of PHP 8.0. curl_close( $handle ); } return new WP_Error( 'http_request_failed', __( 'Too many redirects.' ) ); } if ( PHP_VERSION_ID < 80000 ) { // curl_close() has no effect as of PHP 8.0. curl_close( $handle ); } return array( 'headers' => array(), 'body' => '', 'response' => array( 'code' => false, 'message' => false, ), 'cookies' => array(), ); } curl_exec( $handle ); $processed_headers = WP_Http::processHeaders( $this->headers, $url ); $body = $this->body; $bytes_written_total = $this->bytes_written_total; $this->headers = ''; $this->body = ''; $this->bytes_written_total = 0; $curl_error = curl_errno( $handle ); // If an error occurred, or, no response. if ( $curl_error || ( 0 === strlen( $body ) && empty( $processed_headers['headers'] ) ) ) { if ( CURLE_WRITE_ERROR /* 23 */ === $curl_error ) { if ( ! $this->max_body_length || $this->max_body_length !== $bytes_written_total ) { if ( $parsed_args['stream'] ) { if ( PHP_VERSION_ID < 80000 ) { // curl_close() has no effect as of PHP 8.0. curl_close( $handle ); } fclose( $this->stream_handle ); return new WP_Error( 'http_request_failed', __( 'Failed to write request to temporary file.' ) ); } else { if ( PHP_VERSION_ID < 80000 ) { // curl_close() has no effect as of PHP 8.0. curl_close( $handle ); } return new WP_Error( 'http_request_failed', curl_error( $handle ) ); } } } else { $curl_error = curl_error( $handle ); if ( $curl_error ) { if ( PHP_VERSION_ID < 80000 ) { // curl_close() has no effect as of PHP 8.0. curl_close( $handle ); } return new WP_Error( 'http_request_failed', $curl_error ); } } if ( in_array( curl_getinfo( $handle, CURLINFO_HTTP_CODE ), array( 301, 302 ), true ) ) { if ( PHP_VERSION_ID < 80000 ) { // curl_close() has no effect as of PHP 8.0. curl_close( $handle ); } return new WP_Error( 'http_request_failed', __( 'Too many redirects.' ) ); } } if ( PHP_VERSION_ID < 80000 ) { // curl_close() has no effect as of PHP 8.0. curl_close( $handle ); } if ( $parsed_args['stream'] ) { fclose( $this->stream_handle ); } $response = array( 'headers' => $processed_headers['headers'], 'body' => null, 'response' => $processed_headers['response'], 'cookies' => $processed_headers['cookies'], 'filename' => $parsed_args['filename'], ); // Handle redirects. $redirect_response = WP_Http::handle_redirects( $url, $parsed_args, $response ); if ( false !== $redirect_response ) { return $redirect_response; } if ( true === $parsed_args['decompress'] && true === WP_Http_Encoding::should_decode( $processed_headers['headers'] ) ) { $body = WP_Http_Encoding::decompress( $body ); } $response['body'] = $body; return $response; } /** * Grabs the headers of the cURL request. * * Each header is sent individually to this callback, and is appended to the `$header` property * for temporary storage. * * @since 3.2.0 * * @param resource $handle cURL handle. * @param string $headers cURL request headers. * @return int Length of the request headers. */ private function stream_headers( $handle, $headers ) { $this->headers .= $headers; return strlen( $headers ); } /** * Grabs the body of the cURL request. * * The contents of the document are passed in chunks, and are appended to the `$body` * property for temporary storage. Returning a length shorter than the length of * `$data` passed in will cause cURL to abort the request with `CURLE_WRITE_ERROR`. * * @since 3.6.0 * * @param resource $handle cURL handle. * @param string $data cURL request body. * @return int Total bytes of data written. */ private function stream_body( $handle, $data ) { $data_length = strlen( $data ); if ( $this->max_body_length && ( $this->bytes_written_total + $data_length ) > $this->max_body_length ) { $data_length = ( $this->max_body_length - $this->bytes_written_total ); $data = substr( $data, 0, $data_length ); } if ( $this->stream_handle ) { $bytes_written = fwrite( $this->stream_handle, $data ); } else { $this->body .= $data; $bytes_written = $data_length; } $this->bytes_written_total += $bytes_written; // Upon event of this function returning less than strlen( $data ) curl will error with CURLE_WRITE_ERROR. return $bytes_written; } /** * Determines whether this class can be used for retrieving a URL. * * @since 2.7.0 * * @param array $args Optional. Array of request arguments. Default empty array. * @return bool False means this class can not be used, true means it can. */ public static function test( $args = array() ) { if ( ! function_exists( 'curl_init' ) || ! function_exists( 'curl_exec' ) ) { return false; } $is_ssl = isset( $args['ssl'] ) && $args['ssl']; if ( $is_ssl ) { $curl_version = curl_version(); // Check whether this cURL version support SSL requests. if ( ! ( CURL_VERSION_SSL & $curl_version['features'] ) ) { return false; } } /** * Filters whether cURL can be used as a transport for retrieving a URL. * * @since 2.7.0 * * @param bool $use_class Whether the class can be used. Default true. * @param array $args An array of request arguments. */ return apply_filters( 'use_curl_transport', true, $args ); } } Wie Transaktionssimulationen Multi‑Chain‑DeFi sicherer machen — und wo sie an Grenzen stoßen – Shweta Poddar Weddings Photography

Warum sehen viele DeFi‑Nutzer die Transaktionssimulation als die wichtigste Neuerung in Wallet‑UX seit Jahren? Die kurze Antwort: weil sie aus einem unsichtbaren Prüfmechanismus eine unmittelbar nutzbare Sicherheitsinformation macht. Für deutschsprachige Nutzer, die mehrere Chains parallel bedienen müssen, verändert eine zuverlässige Simulation nicht nur die Bedienung — sie reduziert Angriffsflächen, erhöht Vorhersehbarkeit und erlaubt bewusste Risikokontrolle. Gleichzeitig ist Simulation kein Allheilmittel: ihre Wirksamkeit hängt von Datenqualität, Modellgrenzen und Nutzungsverhalten ab.

Dieser Artikel erklärt mechanisch, warum Simulationen funktionieren, welche Annahmen sie treffen, wie sie in Multi‑Chain‑Wallets eingebettet werden können, und welche praktischen Entscheidungen Anwender in Deutschland und dem übrigen DACH‑Raum treffen sollten, um Kapital sicherer zu bewegen. Am Ende steht eine handhabbare Heuristik: wann man einer Simulation vertrauen kann — und wann man manuell tiefer prüfen sollte.

Illustration einer Wallet‑Benutzeroberfläche mit Multi‑Chain‑Übersicht und Simulationsergebnissen, die Änderungen von Token‑Guthaben vor Signatur zeigt

Wie Transaktionssimulation technisch funktioniert — ein Mechanismusblick

Transaktionssimulationen replizieren vor der Signatur die erwarteten Zustandsänderungen einer Blockchain‑Transaktion in einer sicheren Umgebung. Mechanisch heißt das: die Wallet nimmt die Transaktionsdaten (Zieladresse, Betrag, Gasparameter, ggf. Smart‑Contract‑Aufrufe), führt sie in einem lokalen oder serverseitigen EVM‑Interpreter aus und rechnet das Resultat auf Token‑Salden, Contract‑State und Gasverbrauch hoch. Ergebnis: der Nutzer sieht konkret, wie sich sein Kontostand ändern würde, bevor er den Kryptoschlüssel benutzt.

Wesentliche Wirkungspunkte: 1) Sichtbarkeit von Slippage, Gebühren und eventuellen Rückläufern; 2) Erkennung offener Approvals (z. B. Infinite Approvals) bevor sie bestätigt werden; 3) Plausibilitätsprüfungen gegen Phishing‑ oder Front‑running‑Muster. In der Praxis reduziert das die Unsicherheit bei komplexen Multi‑Hop‑Swaps oder beim Interagieren mit unbekannten Contracts.

Designentscheidungen in Multi‑Chain‑Wallets und ihre Sicherheitsfolgen

Multi‑Chain heißt: viele EVM‑Kompatible Chains mit unterschiedlichen Gas‑Tokens, Bridges und Liquiditätsmustern. Das erzeugt drei konkrete Herausforderungen für Simulationen: Datenfrische (Mempool und State), Cross‑Chain‑Effekte (Brücken‑Zustände, nicht atomare Operationen) und Nutzer‑Erwartungen (z. B. Gebührenabrechnung in Stablecoins statt nativen Tokens).

Wallet‑Designs lösen das unterschiedlich. Eine robuste Architektur trennt Signatur‑Pfad von Zusatzdiensten: die Wallet bleibt grundlegend offline‑fähig für Signaturen, während Simulation, Swap‑Aggregation oder Sicherheitsscans als Prüf‑Layer hinzutreten. Das ist das Modell einer Non‑Custodial‑Wallet wie der rabby wallet, die ausdrücklich Transaktionssimulation als Vor‑Signatur‑Prüfung implementiert und gleichzeitig erklärt, dass Kernfunktionen bei Ausfall der Dienste lokal weiterlaufen.

Trade‑off: Serverseitige Simulationen können schneller und vollständiger (z. B. mit aktuellen Indexern) sein, erhöhen aber die Abhängigkeit vom Backend und damit das Risiko bei Manipulationen. Lokale Simulationen sind unabhängig, aber limitiert durch lokale Node‑Synchronität und Speicher/CPU. Die praktische Lösung in guten Wallets ist eine hybride Architektur: lokale Signatur‑Unabhängigkeit plus verifizierbare, offene Simulationstools.

Was Simulationen nicht leisten — die Grenzen und Fallstricke

Wichtig ist, die Grenzen zu benennen. Simulationen liefern eine deterministische Prognose basierend auf einem Snapshot des States und der angenommenen Mempool‑Reihenfolge. Sie sagen nicht zuverlässig voraus, wie Miner/Proposer, Front‑Runner oder Relayer in den Sekunden zwischen Simulation und On‑Chain‑Einschluss reagieren. Bei stark volatilen Märkten, sehr knappen Liquiditätspools oder bei Transaktionen, die externe Oracles triggern, kann das tatsächliche Outcome deutlich abweichen.

Weitere Grenzen: Inter‑Chain‑Bridges arbeiten oft nicht atomar. Eine Wallet‑Simulation kann die lokale Auswirkung auf einer Chain korrekt anzeigen, aber nicht die Wahrscheinlichkeit eines Parts failing auf der Gegenkette. Solche Fälle erfordern zusätzliche Risikoindikatoren (z. B. Bridge‑Finality, Gebührenpuffer, Split‑Tx‑Timeouts), die manche Wallets als ergänzende Metadaten anzeigen sollten.

Praktische Sicherheitsfunktionen, die Simulation ergänzen

Simulationen sind Teil eines Sicherheits‑Stacks, nicht dessen Ersatz. Wichtige ergänzende Mechanismen sind:

  • Integraler Sicherheits‑Scanner: Vertrags‑Checks gegen bekannte Exploits, Phishing‑Hitlists und ungewöhnliche Approval‑Patterns.
  • Hardware‑Wallet‑Signing: lokale Schlüssel bleiben gesichert und die Signatur erfolgt auf einem separaten Gerät.
  • Gas Account und Gebührenmanagement: besonders in DE nützlich, wenn Nutzer stablecoins für Gebühren bevorzugen und nicht permanent native Chain‑Tokens halten.
  • Swap‑Aggregator mit Slippage‑Kontrolle: reduziert unerwartete Ausführungsraten und macht Simulationsergebnisse mit Markt‑Quotes vergleichbar.

Ein Wallet, das diese Funktionen kombiniert, erhöht die Robustheit: Simulation erklärt, Scanner warnt, Hardware‑Wallet bietet letzte Schutzbarriere.

Regionaler Kontext: Warum deutsche DeFi‑Nutzer spezifisch profitieren — und was sie beachten sollten

In Deutschland ist regulatorische Vorsicht und steuerliche Rechenschaftspflicht stärker ausgeprägt als in einigen anderen Regionen. Simulationen, die vorab präzise Token‑Saldoänderungen anzeigen, erleichtern korrekte Aufzeichnungen — etwa beim Realisieren von Gewinnen oder steuerpflichtigen Ereignissen. Ebenfalls wichtig: die Open‑Source‑Basis vieler moderner Wallets erlaubt unabhängige Prüfer aus der DACH‑Community Codeaudits durchzuführen, was Vertrauen schafft.

Gleichzeitig sollten Nutzer in Deutschland die Komplexität von Brücken und Kettenübergreifenden Swaps besonders beachten: Bankähnliche Erwartungen an Transaktionsfinalität passen hier oft nicht. Eine klare Heuristik hilft: beschränke große Beträge auf mindestens zwei unabhängige Checks (Simulation + Hardware‑Signatur + Scanner), reduziere Approvals und nutze Gas‑Accounts, um Missing‑Native‑Token‑Risiken zu vermeiden.

Eine wiederverwendbare Entscheidungsheuristik für DeFi‑Aktionen

Vor jeder riskanteren Aktion (Large Swap, Bridge, Approve All) empfiehlt sich die folgende vereinfachte Prüfung: 1) Simulation ansehen: passen erwartete Saldoänderungen zur Absicht? 2) Scanner prüfen: gibt es Warnungen oder Infinite Approvals? 3) Quellen validieren: ist das Ziel‑Contract‑Address bekannt/verifiziert? 4) Signing‑Level: Hardware‑Wallet für hohe Beträge; Seed‑Check bei neuen Geräten. Diese Kette reduziert Bedienfehler und angriffsbedingte Verluste.

Wenn eine Simulation widersprüchliche Ergebnisse liefert (z. B. niedriger erwarteter Gasverbrauch als früher angezeigt), ist Zurückhaltung angezeigt: entweder ist der State veraltet oder ein dynamischer Mechanismus (Oracle, Relayer) beeinflusst das Ergebnis.

Was man in den nächsten Monaten beobachten sollte

Signale, die die Nützlichkeit von Simulationen beeinflussen: 1) Verbesserte öffentliche Indexer, die konsistentere Mempool‑Snapshots liefern; 2) breitere Hardware‑Wallet‑Integration in Browser‑Wallets; 3) Standardisierte Machine‑Readable‑Risk‑Metadaten für Contracts, die Simulationsergebnisse automatisch annotieren könnten. Wenn diese Trends zusammenkommen, steigen Erwartung und Verlässlichkeit von Simulationen. Umgekehrt bleibt Automation ohne Transparenz riskant — daher ist Open‑Source‑Nachprüfbarkeit ein Schlüsselindikator für vertrauenswürdige Wallets.

FAQ — Häufige Fragen zur Transaktionssimulation und Multi‑Chain‑Wallets

Was ist der Unterschied zwischen Simulation und einer reinen Gas‑Schätzung?

Eine Gas‑Schätzung sagt lediglich, wie viel Rechenaufwand (Gas) eine Transaktion ungefähr verbrauchen wird. Eine Transaktionssimulation führt die Operationen durch und zeigt konkrete Auswirkungen auf Token‑Salden, Contract‑State und erlaubnisbezogene Änderungen (z. B. Allowances). Sie ist dadurch informativer, weil sie das erwartete Endergebnis visualisiert.

Kann ich Simulationen blind vertrauen, um große Summen ohne zusätzliche Vorsicht zu transferieren?

Nein. Simulationen reduzieren Unsicherheit, ersetzen aber nicht mechanische Risiken wie Front‑running, Miner‑Manipulation oder Bridge‑Failure. Für große Summen bleiben zusätzliche Maßnahmen nötig: Hardware‑Signing, schrittweise Transfers, und das Vermeiden von One‑Click‑Infinite Approvals.

Wie hilft die lokale Schlüsselspeicherung bei der Sicherheit?

Lokale Schlüsselverarbeitung bedeutet, dass die Wallet die privaten Schlüssel nicht an Server sendet — Signaturoperationen bleiben lokal. Das senkt das Risiko eines Serverleaks, verlangt aber sichere Endgeräte und Disziplin beim Backup (Seed‑Phrase). Verwendet man zusätzlich Hardware‑Wallets, erhöht sich die physische Sicherheit signifikant.

Welche Rolle spielen Swap‑Aggregator in Verbindung mit Simulationen?

Aggregator suchen optimale Routen über DEXes. In Kombination mit Simulationen erlauben sie, vorab die tatsächliche Ausführungsweise eines Multi‑Hop‑Swaps zu prüfen und Slippage‑Risiken abzuschätzen. Wichtig ist, dass der Aggregator transparent über die verwendeten Liquidity‑Quellen informiert.

Uncategorized

Leave a Comment

Your email address will not be published. Required fields are marked *