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 }