@@ -117,7 +117,18 @@ contract PoC is Test, Tokens, Log {
117
117
? tokensBalance[_user][_index][j].token.decimals ()
118
118
: 18 ;
119
119
uint256 integer_part = balance / (10 ** d);
120
- uint256 fractional_part = balance % (10 ** d);
120
+ string memory fractional_part_string;
121
+ {
122
+ uint256 fractional_part = balance % (10 ** d);
123
+ string memory fractional_part_leading_zeros;
124
+
125
+ uint256 leading_zeros = d - (log10 (fractional_part) + 1 );
126
+ for (uint256 i = 0 ; i < leading_zeros; i++ ) {
127
+ fractional_part_leading_zeros = string .concat (fractional_part_leading_zeros, "0 " );
128
+ }
129
+
130
+ fractional_part_string = string .concat (fractional_part_leading_zeros, toString (fractional_part));
131
+ }
121
132
122
133
// Get token symbol
123
134
string memory symbol = tokensBalance[_user][_index][j].token != IERC20 (address (0x0 ))
@@ -128,10 +139,10 @@ contract PoC is Test, Tokens, Log {
128
139
string memory template;
129
140
if (logLevel == 1 ) {
130
141
template = string .concat ("%s\t|\t " , symbol, "\t|\t%s.%s " );
131
- _log (template, address (tokensBalance[_user][_index][j].token), integer_part, fractional_part );
142
+ _log (template, address (tokensBalance[_user][_index][j].token), integer_part, fractional_part_string );
132
143
} else if (logLevel == 0 ) {
133
144
template = string .concat ("--- " , symbol, " balance of [%s]:\t%s.%s " , " --- " );
134
- _log (template, resolvedAddress, integer_part, fractional_part );
145
+ _log (template, resolvedAddress, integer_part, fractional_part_string );
135
146
}
136
147
}
137
148
_log ();
@@ -160,7 +171,18 @@ contract PoC is Test, Tokens, Log {
160
171
? tokensBalance[_user][0 ][j].token.decimals ()
161
172
: 18 ;
162
173
uint256 integer_part = abs_profit / (10 ** d);
163
- uint256 fractional_part = abs_profit % (10 ** d);
174
+ string memory fractional_part_string;
175
+ {
176
+ uint256 fractional_part = abs_profit % (10 ** d);
177
+ string memory fractional_part_leading_zeros;
178
+
179
+ uint256 leading_zeros = d - (log10 (fractional_part) + 1 );
180
+ for (uint256 i = 0 ; i < leading_zeros; i++ ) {
181
+ fractional_part_leading_zeros = string .concat (fractional_part_leading_zeros, "0 " );
182
+ }
183
+
184
+ fractional_part_string = string .concat (fractional_part_leading_zeros, toString (fractional_part));
185
+ }
164
186
165
187
// Get token symbol
166
188
string memory symbol = tokensBalance[_user][0 ][j].token != IERC20 (address (0x0 ))
@@ -170,7 +192,7 @@ contract PoC is Test, Tokens, Log {
170
192
// Generate template string
171
193
string memory template = string .concat ("%s\t|\t " , symbol, "\t|\t " , sign, "%s.%s " );
172
194
173
- _log (template, address (tokensBalance[_user][0 ][j].token), integer_part, fractional_part );
195
+ _log (template, address (tokensBalance[_user][0 ][j].token), integer_part, fractional_part_string );
174
196
}
175
197
_log ();
176
198
}
@@ -227,4 +249,70 @@ contract PoC is Test, Tokens, Log {
227
249
if (uint8 (b) < 10 ) return bytes1 (uint8 (b) + 0x30 );
228
250
else return bytes1 (uint8 (b) + 0x57 );
229
251
}
252
+
253
+ /**
254
+ * @dev Converts a `uint256` to its ASCII `string` decimal representation.
255
+ * @notice Pulled from OpenZeppelin 5.0.2 Strings.sol library
256
+ */
257
+ bytes16 private constant HEX_DIGITS = "0123456789abcdef " ;
258
+ function toString (uint256 value ) internal pure returns (string memory ) {
259
+ unchecked {
260
+ uint256 length = log10 (value) + 1 ;
261
+ string memory buffer = new string (length);
262
+ uint256 ptr;
263
+ /// @solidity memory-safe-assembly
264
+ assembly {
265
+ ptr := add (buffer, add (32 , length))
266
+ }
267
+ while (true ) {
268
+ ptr-- ;
269
+ /// @solidity memory-safe-assembly
270
+ assembly {
271
+ mstore8 (ptr, byte (mod (value, 10 ), HEX_DIGITS))
272
+ }
273
+ value /= 10 ;
274
+ if (value == 0 ) break ;
275
+ }
276
+ return buffer;
277
+ }
278
+ }
279
+
280
+ /**
281
+ * @dev Return the log in base 10 of a positive value rounded towards zero.
282
+ * @notice Pulled from OpenZeppelin 5.0.2 Math.sol library
283
+ * Returns 0 if given 0.
284
+ */
285
+ function log10 (uint256 value ) internal pure returns (uint256 ) {
286
+ uint256 result = 0 ;
287
+ unchecked {
288
+ if (value >= 10 ** 64 ) {
289
+ value /= 10 ** 64 ;
290
+ result += 64 ;
291
+ }
292
+ if (value >= 10 ** 32 ) {
293
+ value /= 10 ** 32 ;
294
+ result += 32 ;
295
+ }
296
+ if (value >= 10 ** 16 ) {
297
+ value /= 10 ** 16 ;
298
+ result += 16 ;
299
+ }
300
+ if (value >= 10 ** 8 ) {
301
+ value /= 10 ** 8 ;
302
+ result += 8 ;
303
+ }
304
+ if (value >= 10 ** 4 ) {
305
+ value /= 10 ** 4 ;
306
+ result += 4 ;
307
+ }
308
+ if (value >= 10 ** 2 ) {
309
+ value /= 10 ** 2 ;
310
+ result += 2 ;
311
+ }
312
+ if (value >= 10 ** 1 ) {
313
+ result += 1 ;
314
+ }
315
+ }
316
+ return result;
317
+ }
230
318
}
0 commit comments