LCOV - code coverage report
Current view: top level - crypto/evm/repositories - function_selector_repository.dart (source / functions) Coverage Total Hit
Test: lcov.info Lines: 96.7 % 61 59
Test Date: 2025-01-30 01:10:00 Functions: - 0 0

            Line data    Source code
       1              : import 'dart:async';
       2              : import 'dart:convert';
       3              : 
       4              : import 'package:walletkit_dart/src/common/http_client.dart';
       5              : import 'package:walletkit_dart/walletkit_dart.dart';
       6              : 
       7              : const _openchainEndpoint = "https://api.openchain.xyz/signature-database/v1";
       8              : const _4byteEndpoint = "https://www.4byte.directory/api/v1";
       9              : 
      10              : class FunctionSelectorRepository {
      11              :   final Map<String, Completer<ExternalContractFunction?>> functionCache = {};
      12              : 
      13            2 :   static final FunctionSelectorRepository _instance =
      14            1 :       FunctionSelectorRepository._();
      15              : 
      16            1 :   FunctionSelectorRepository._();
      17              : 
      18            1 :   factory FunctionSelectorRepository() {
      19            1 :     return _instance;
      20              :   }
      21              : 
      22            1 :   Future<ExternalContractFunction?> fetchSelector(
      23              :     String selector, {
      24              :     bool openChain = true,
      25              :     bool fourByte = true,
      26              :   }) async {
      27            1 :     assert(openChain || fourByte, "At least one source must be enabled");
      28              : 
      29              :     if (fourByte) {
      30            1 :       final fourByteFunction = await fetchSelector4Byte(selector);
      31              :       if (fourByteFunction != null) return fourByteFunction;
      32              :     }
      33              : 
      34              :     if (openChain) {
      35            1 :       final openChainFunction = await fetchSelectorOpenChain(selector);
      36              :       if (openChainFunction != null) return openChainFunction;
      37              :     }
      38              : 
      39              :     return null;
      40              :   }
      41              : 
      42            1 :   Future<ExternalContractFunction?> fetchSelector4Byte(
      43              :     String selector,
      44              :   ) async {
      45            2 :     selector = selector.startsWith("0x") ? selector : "0x$selector";
      46              : 
      47            1 :     final endpoint = "$_4byteEndpoint/signatures/?hex_signature=$selector";
      48            1 :     final uri = Uri.parse(endpoint);
      49              : 
      50            2 :     if (functionCache.containsKey(endpoint)) {
      51            3 :       return await functionCache[endpoint]!.future;
      52              :     }
      53              : 
      54            1 :     final future = _4byteRequest(uri, selector);
      55              : 
      56            1 :     final completer = Completer<ExternalContractFunction?>();
      57            2 :     functionCache[endpoint] = completer;
      58              : 
      59              :     try {
      60              :       final function = await future;
      61            1 :       completer.complete(function);
      62              :       return function;
      63              :     } catch (e) {
      64            0 :       completer.complete(null);
      65              :       return null;
      66              :     }
      67              :   }
      68              : 
      69            1 :   Future<ExternalContractFunction?> fetchSelectorOpenChain(
      70              :     String selector,
      71              :   ) async {
      72            2 :     selector = selector.startsWith("0x") ? selector : "0x$selector";
      73              : 
      74              :     final endpoint =
      75            1 :         "$_openchainEndpoint/lookup?function=$selector&filter=true";
      76            1 :     final uri = Uri.parse(endpoint);
      77              : 
      78            2 :     if (functionCache.containsKey(endpoint)) {
      79            3 :       return await functionCache[endpoint]!.future;
      80              :     }
      81              : 
      82            1 :     final future = _openchainRequest(uri, selector);
      83              : 
      84            1 :     final completer = Completer<ExternalContractFunction?>();
      85            2 :     functionCache[endpoint] = completer;
      86              :     try {
      87              :       final function = await future;
      88            1 :       completer.complete(function);
      89              :       return function;
      90              :     } catch (e) {
      91            0 :       completer.complete(null);
      92              :       return null;
      93              :     }
      94              :   }
      95              : 
      96            1 :   Future<ExternalContractFunction?> _openchainRequest(
      97              :     Uri uri,
      98              :     String selector,
      99              :   ) async {
     100            2 :     final response = await HTTPService.client.get(uri);
     101              : 
     102            2 :     if (response.statusCode == 200) {
     103            2 :       final json = jsonDecode(response.body);
     104              : 
     105              :       if (json
     106            1 :           case {
     107            2 :             "ok": true,
     108            2 :             "result": {
     109            2 :               "event": Json _,
     110            2 :               "function": Json function_json,
     111              :             }
     112              :           }) {
     113            1 :         final functions = function_json[selector] as List<dynamic>?;
     114              : 
     115            1 :         if (functions == null || functions.isEmpty) return null;
     116              : 
     117            2 :         final name = functions.first["name"] as String?;
     118              : 
     119              :         if (name == null) return null;
     120              : 
     121              :         final function =
     122            1 :             ContractFunction.fromTextSignature(textSignature: name);
     123              : 
     124              :         if (function == null) return null;
     125              : 
     126              :         return function;
     127              :       }
     128              : 
     129              :       return null;
     130              :     }
     131              : 
     132              :     return null;
     133              :   }
     134              : 
     135            1 :   Future<ExternalContractFunction?> _4byteRequest(
     136              :     Uri uri,
     137              :     String selector,
     138              :   ) async {
     139            2 :     final response = await HTTPService.client.get(uri);
     140            2 :     if (response.statusCode == 200) {
     141            2 :       final contentType = response.headers["content-type"];
     142              : 
     143            1 :       if (contentType != null && !contentType.contains("application/json")) {
     144              :         return null;
     145              :       }
     146              : 
     147            2 :       final responseData = jsonDecode(response.body);
     148              : 
     149              :       // TODO: Maybe return a List of all Functions so that we can display all possible functions
     150            2 :       final function = getLowestIdFunction(responseData["results"]);
     151              : 
     152              :       return function;
     153              :     }
     154              : 
     155              :     return null;
     156              :   }
     157              : 
     158            1 :   static ExternalContractFunction? getLowestIdFunction(List<dynamic> results) {
     159            5 :     results.sort((a, b) => a["id"].compareTo(b["id"]));
     160              : 
     161            1 :     for (final {
     162            2 :           "id": int _,
     163            1 :           "created_at": _,
     164            2 :           "text_signature": String text_signature,
     165            1 :           "hex_signature": _,
     166            1 :           "bytes_signature": _,
     167            2 :         } in results) {
     168            1 :       return ContractFunction.fromTextSignature(
     169              :         textSignature: text_signature,
     170              :       );
     171              :     }
     172              :     return null;
     173              :   }
     174              : }
        

Generated by: LCOV version 2.0-1