github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/test/contracts/uniswap/v2/SafeERC20Namer.sol (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  pragma solidity >=0.5.0;
     4  
     5  import './AddressStringUtil.sol';
     6  
     7  // produces token descriptors from inconsistent or absent ERC20 symbol implementations that can return string or bytes32
     8  // this library will always produce a string symbol to represent the token
     9  library SafeERC20Namer {
    10      function bytes32ToString(bytes32 x) private pure returns (string memory) {
    11          bytes memory bytesString = new bytes(32);
    12          uint256 charCount = 0;
    13          for (uint256 j = 0; j < 32; j++) {
    14              bytes1 char = x[j];
    15              if (char != 0) {
    16                  bytesString[charCount] = char;
    17                  charCount++;
    18              }
    19          }
    20          bytes memory bytesStringTrimmed = new bytes(charCount);
    21          for (uint256 j = 0; j < charCount; j++) {
    22              bytesStringTrimmed[j] = bytesString[j];
    23          }
    24          return string(bytesStringTrimmed);
    25      }
    26  
    27      // assumes the data is in position 2
    28      function parseStringData(bytes memory b) private pure returns (string memory) {
    29          uint256 charCount = 0;
    30          // first parse the charCount out of the data
    31          for (uint256 i = 32; i < 64; i++) {
    32              charCount <<= 8;
    33              charCount += uint8(b[i]);
    34          }
    35  
    36          bytes memory bytesStringTrimmed = new bytes(charCount);
    37          for (uint256 i = 0; i < charCount; i++) {
    38              bytesStringTrimmed[i] = b[i + 64];
    39          }
    40  
    41          return string(bytesStringTrimmed);
    42      }
    43  
    44      // uses a heuristic to produce a token name from the address
    45      // the heuristic returns the full hex of the address string in upper case
    46      function addressToName(address token) private pure returns (string memory) {
    47          return AddressStringUtil.toAsciiString(token, 40);
    48      }
    49  
    50      // uses a heuristic to produce a token symbol from the address
    51      // the heuristic returns the first 6 hex of the address string in upper case
    52      function addressToSymbol(address token) private pure returns (string memory) {
    53          return AddressStringUtil.toAsciiString(token, 6);
    54      }
    55  
    56      // calls an external view token contract method that returns a symbol or name, and parses the output into a string
    57      function callAndParseStringReturn(address token, bytes4 selector) private view returns (string memory) {
    58          (bool success, bytes memory data) = token.staticcall(abi.encodeWithSelector(selector));
    59          // if not implemented, or returns empty data, return empty string
    60          if (!success || data.length == 0) {
    61              return '';
    62          }
    63          // bytes32 data always has length 32
    64          if (data.length == 32) {
    65              bytes32 decoded = abi.decode(data, (bytes32));
    66              return bytes32ToString(decoded);
    67          } else if (data.length > 64) {
    68              return abi.decode(data, (string));
    69          }
    70          return '';
    71      }
    72  
    73      // attempts to extract the token symbol. if it does not implement symbol, returns a symbol derived from the address
    74      function tokenSymbol(address token) internal view returns (string memory) {
    75          // 0x95d89b41 = bytes4(keccak256("symbol()"))
    76          string memory symbol = callAndParseStringReturn(token, 0x95d89b41);
    77          if (bytes(symbol).length == 0) {
    78              // fallback to 6 uppercase hex of address
    79              return addressToSymbol(token);
    80          }
    81          return symbol;
    82      }
    83  
    84      // attempts to extract the token name. if it does not implement name, returns a name derived from the address
    85      function tokenName(address token) internal view returns (string memory) {
    86          // 0x06fdde03 = bytes4(keccak256("name()"))
    87          string memory name = callAndParseStringReturn(token, 0x06fdde03);
    88          if (bytes(name).length == 0) {
    89              // fallback to full hex of address
    90              return addressToName(token);
    91          }
    92          return name;
    93      }
    94  }