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

Generated by: LCOV version 2.0-1