@@ -64,4 +64,132 @@ library TWStrings {
64
64
require (value == 0 , "Strings: hex length insufficient " );
65
65
return string (buffer);
66
66
}
67
+
68
+ /// @dev Returns the hexadecimal representation of `value`.
69
+ /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte,
70
+ /// and the alphabets are capitalized conditionally according to
71
+ /// https://eips.ethereum.org/EIPS/eip-55
72
+ function toHexStringChecksummed (address value ) internal pure returns (string memory str ) {
73
+ str = toHexString (value);
74
+ /// @solidity memory-safe-assembly
75
+ assembly {
76
+ let mask := shl (6 , div (not (0 ), 255 )) // `0b010000000100000000 ...`
77
+ let o := add (str, 0x22 )
78
+ let hashed := and (keccak256 (o, 40 ), mul (34 , mask)) // `0b10001000 ... `
79
+ let t := shl (240 , 136 ) // `0b10001000 << 240`
80
+ for {
81
+ let i := 0
82
+ } 1 {
83
+
84
+ } {
85
+ mstore (add (i, i), mul (t, byte (i, hashed)))
86
+ i := add (i, 1 )
87
+ if eq (i, 20 ) {
88
+ break
89
+ }
90
+ }
91
+ mstore (o, xor (mload (o), shr (1 , and (mload (0x00 ), and (mload (o), mask)))))
92
+ o := add (o, 0x20 )
93
+ mstore (o, xor (mload (o), shr (1 , and (mload (0x20 ), and (mload (o), mask)))))
94
+ }
95
+ }
96
+
97
+ /// @dev Returns the hexadecimal representation of `value`.
98
+ /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
99
+ function toHexString (address value ) internal pure returns (string memory str ) {
100
+ str = toHexStringNoPrefix (value);
101
+ /// @solidity memory-safe-assembly
102
+ assembly {
103
+ let strLength := add (mload (str), 2 ) // Compute the length.
104
+ mstore (str, 0x3078 ) // Write the "0x" prefix.
105
+ str := sub (str, 2 ) // Move the pointer.
106
+ mstore (str, strLength) // Write the length.
107
+ }
108
+ }
109
+
110
+ /// @dev Returns the hexadecimal representation of `value`.
111
+ /// The output is encoded using 2 hexadecimal digits per byte.
112
+ function toHexStringNoPrefix (address value ) internal pure returns (string memory str ) {
113
+ /// @solidity memory-safe-assembly
114
+ assembly {
115
+ str := mload (0x40 )
116
+
117
+ // Allocate the memory.
118
+ // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
119
+ // 0x02 bytes for the prefix, and 0x28 bytes for the digits.
120
+ // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.
121
+ mstore (0x40 , add (str, 0x80 ))
122
+
123
+ // Store "0123456789abcdef" in scratch space.
124
+ mstore (0x0f , 0x30313233343536373839616263646566 )
125
+
126
+ str := add (str, 2 )
127
+ mstore (str, 40 )
128
+
129
+ let o := add (str, 0x20 )
130
+ mstore (add (o, 40 ), 0 )
131
+
132
+ value := shl (96 , value)
133
+
134
+ // We write the string from rightmost digit to leftmost digit.
135
+ // The following is essentially a do-while loop that also handles the zero case.
136
+ for {
137
+ let i := 0
138
+ } 1 {
139
+
140
+ } {
141
+ let p := add (o, add (i, i))
142
+ let temp := byte (i, value)
143
+ mstore8 (add (p, 1 ), mload (and (temp, 15 )))
144
+ mstore8 (p, mload (shr (4 , temp)))
145
+ i := add (i, 1 )
146
+ if eq (i, 20 ) {
147
+ break
148
+ }
149
+ }
150
+ }
151
+ }
152
+
153
+ /// @dev Returns the hex encoded string from the raw bytes.
154
+ /// The output is encoded using 2 hexadecimal digits per byte.
155
+ function toHexString (bytes memory raw ) internal pure returns (string memory str ) {
156
+ str = toHexStringNoPrefix (raw);
157
+ /// @solidity memory-safe-assembly
158
+ assembly {
159
+ let strLength := add (mload (str), 2 ) // Compute the length.
160
+ mstore (str, 0x3078 ) // Write the "0x" prefix.
161
+ str := sub (str, 2 ) // Move the pointer.
162
+ mstore (str, strLength) // Write the length.
163
+ }
164
+ }
165
+
166
+ /// @dev Returns the hex encoded string from the raw bytes.
167
+ /// The output is encoded using 2 hexadecimal digits per byte.
168
+ function toHexStringNoPrefix (bytes memory raw ) internal pure returns (string memory str ) {
169
+ /// @solidity memory-safe-assembly
170
+ assembly {
171
+ let length := mload (raw)
172
+ str := add (mload (0x40 ), 2 ) // Skip 2 bytes for the optional prefix.
173
+ mstore (str, add (length, length)) // Store the length of the output.
174
+
175
+ // Store "0123456789abcdef" in scratch space.
176
+ mstore (0x0f , 0x30313233343536373839616263646566 )
177
+
178
+ let o := add (str, 0x20 )
179
+ let end := add (raw, length)
180
+
181
+ for {
182
+
183
+ } iszero (eq (raw, end)) {
184
+
185
+ } {
186
+ raw := add (raw, 1 )
187
+ mstore8 (add (o, 1 ), mload (and (mload (raw), 15 )))
188
+ mstore8 (o, mload (and (shr (4 , mload (raw)), 15 )))
189
+ o := add (o, 2 )
190
+ }
191
+ mstore (o, 0 ) // Zeroize the slot after the string.
192
+ mstore (0x40 , add (o, 0x20 )) // Allocate the memory.
193
+ }
194
+ }
67
195
}
0 commit comments