1
- import fs from "fs" ;
1
+ import fs from "node: fs" ;
2
2
3
3
import { keccak256 } from "../src/internal/util/keccak" ;
4
4
@@ -17,7 +17,6 @@ function* genPermutations(elemCount: number, len: number) {
17
17
// from 0 to max number of permutations (elemCount ** len) and convert
18
18
// each number to a list of digits as per the base `elemCount`, see above.
19
19
const numberOfPermutations = elemCount ** len ;
20
- // Pre-compute the base `elemCount` dividers ([1, elemCount, elemCount ** 2, ...])
21
20
const dividers = Array ( elemCount )
22
21
. fill ( 0 )
23
22
. map ( ( _ , i ) => elemCount ** i ) ;
@@ -38,9 +37,9 @@ type TypeName = { type: string; modifier?: "memory" };
38
37
type FnParam = TypeName & { name : string } ;
39
38
40
39
/** Computes the function selector for the given function with simple arguments. */
41
- function selector ( { name = "log " , params = [ ] as TypeName [ ] } ) {
42
- const sig = params . map ( ( p ) => p . type ) . join ( "," ) ;
43
- return keccak256 ( Buffer . from ( `${ name } (${ sig } )` ) ) . slice ( 0 , 4 ) ;
40
+ function selector ( { name = "" , params = [ ] as TypeName [ ] } ) {
41
+ const sigParams = params . map ( ( p ) => p . type ) . join ( "," ) ;
42
+ return keccak256 ( Buffer . from ( `${ name } (${ sigParams } )` ) ) . slice ( 0 , 4 ) ;
44
43
}
45
44
46
45
function toHex ( value : Uint8Array ) {
@@ -67,7 +66,66 @@ const TYPES = [
67
66
{ type : "address" } ,
68
67
] as const ;
69
68
70
- let consoleSolFile = `// SPDX-License-Identifier: MIT
69
+ /** A list of `console.log*` functions that we want to generate. */
70
+ const CONSOLE_LOG_FUNCTIONS =
71
+ // Basic `log()` function
72
+ [ { name : "log" , params : [ ] as FnParam [ ] } ]
73
+ // Generate single parameter functions that are type-suffixed for
74
+ // backwards-compatibility, e.g. logInt, logUint, logString, etc.
75
+ . concat (
76
+ SINGLE_TYPES . map ( ( single ) => {
77
+ const param = { ...single , name : "p0" } as const ;
78
+ const nameSuffix = capitalize ( param . type . replace ( "int256" , "int" ) ) ;
79
+
80
+ return {
81
+ name : `log${ nameSuffix } ` ,
82
+ params : [ param ] ,
83
+ } as const ;
84
+ } )
85
+ )
86
+ // Also generate the function definitions for `log` for permutations of
87
+ // up to 4 parameters using the `types` (uint256, string, bool, address).
88
+ . concat (
89
+ [ ...Array ( 4 ) ] . flatMap ( ( _ , paramCount ) => {
90
+ return Array . from (
91
+ genPermutations ( TYPES . length , paramCount + 1 ) ,
92
+ ( permutation ) => ( {
93
+ name : "log" ,
94
+ params : permutation . map ( ( typeIndex , i ) => ( {
95
+ ...TYPES [ typeIndex ] ,
96
+ name : `p${ i } ` ,
97
+ } ) ) ,
98
+ } )
99
+ ) ;
100
+ } )
101
+ ) ;
102
+
103
+ /** Maps from a 4-byte function selector to a signature (argument types) */
104
+ const CONSOLE_LOG_SIGNATURES : Map < string , string [ ] > =
105
+ CONSOLE_LOG_FUNCTIONS . reduce ( ( acc , { params } ) => {
106
+ // We always use `log` for the selector, even if it's logUint, for example.
107
+ const signature = toHex ( selector ( { name : "log" , params } ) ) ;
108
+ const types = params . map ( ( p ) => p . type ) ;
109
+ acc . set ( signature , types ) ;
110
+
111
+ // For backwards compatibility, we additionally support the (invalid)
112
+ // selectors that contain the `int`/`uint` aliases in the selector calculation.
113
+ if ( params . some ( ( p ) => [ "uint256" , "int256" ] . includes ( p . type ) ) ) {
114
+ const aliased = params . map ( ( p ) => ( {
115
+ ...p ,
116
+ type : p . type . replace ( "int256" , "int" ) ,
117
+ } ) ) ;
118
+
119
+ const signature = toHex ( selector ( { name : "log" , params : aliased } ) ) ;
120
+ acc . set ( signature , types ) ;
121
+ }
122
+
123
+ return acc ;
124
+ } , new Map ( ) ) ;
125
+
126
+ // Finally, render and save the console.sol and logger.ts files
127
+ const consoleSolFile = `\
128
+ // SPDX-License-Identifier: MIT
71
129
pragma solidity >=0.4.22 <0.9.0;
72
130
73
131
library console {
@@ -103,114 +161,46 @@ library console {
103
161
_castToPure(_sendLogPayloadImplementation)(payload);
104
162
}
105
163
106
- function log() internal pure {
107
- _sendLogPayload(abi.encodeWithSignature("log()"));
108
- }
109
- ` ;
110
-
111
- function renderLogFunction ( { name = "log" , params = [ ] as FnParam [ ] } ) : string {
164
+ ${ CONSOLE_LOG_FUNCTIONS . map ( ( { name, params } ) => {
112
165
let fnParams = params
113
166
. map ( ( p ) => `${ p . type } ${ p . modifier ? ` ${ p . modifier } ` : "" } ${ p . name } ` )
114
167
. join ( ", " ) ;
115
168
let sig = params . map ( ( p ) => p . type ) . join ( "," ) ;
116
169
let passed = params . map ( ( p ) => p . name ) . join ( ", " ) ;
170
+ let passedArgs = passed . length > 0 ? `, ${ passed } ` : "" ;
117
171
118
- return ` function ${ name } (${ fnParams } ) internal pure {
119
- _sendLogPayload(abi.encodeWithSignature("log(${ sig } )", ${ passed } ));
172
+ return `\
173
+ function ${ name } (${ fnParams } ) internal pure {
174
+ _sendLogPayload(abi.encodeWithSignature("log(${ sig } )"${ passedArgs } ));
120
175
}
121
-
122
176
` ;
177
+ } ) . join ( "\n" ) } \
123
178
}
179
+ ` ;
124
180
125
- let logger =
126
- "// ------------------------------------\n" +
127
- "// This code was autogenerated using\n" +
128
- "// scripts/console-library-generator.ts\n" +
129
- "// ------------------------------------\n\n" ;
130
-
131
- for ( let i = 0 ; i < SINGLE_TYPES . length ; i ++ ) {
132
- const type = capitalize ( SINGLE_TYPES [ i ] . type ) ;
133
-
134
- logger += `export const ${ type } Ty = "${ type } ";\n` ;
135
- }
181
+ const loggerFile = `\
182
+ // ------------------------------------
183
+ // This code was autogenerated using
184
+ // scripts/console-library-generator.ts
185
+ // ------------------------------------
136
186
137
- logger +=
138
- "\n/** Maps from a 4-byte function selector to a signature (argument types) */\n" +
139
- "export const CONSOLE_LOG_SIGNATURES: Record<number, string[]> = { \n";
187
+ ${ Array . from ( SINGLE_TYPES . map ( ( t ) => capitalize ( t . type ) ) )
188
+ . map ( ( t ) => `export const ${ t } Ty = " ${ t } ";` )
189
+ . join ( " \n") }
140
190
141
191
/** Maps from a 4-byte function selector to a signature (argument types) */
142
- const CONSOLE_LOG_SIGNATURES : Map < string , string [ ] > = new Map ( ) ;
143
-
144
- // Add the empty log() first
145
- const sigInt = toHex ( selector ( { name : "log" , params : [ ] } ) ) ;
146
- CONSOLE_LOG_SIGNATURES . set ( sigInt , [ ] ) ;
147
-
148
- // Generate single parameter functions that are type-suffixed for
149
- // backwards-compatibility, e.g. logInt, logUint, logString, etc.
150
- for ( let i = 0 ; i < SINGLE_TYPES . length ; i ++ ) {
151
- const param = { ...SINGLE_TYPES [ i ] , name : "p0" } as const ;
152
-
153
- const typeAliased = param . type . replace ( "int256" , "int" ) ;
154
- const nameSuffix = capitalize ( typeAliased ) ;
155
-
156
- const signature = toHex ( selector ( { name : "log" , params : [ param ] } ) ) ;
157
- CONSOLE_LOG_SIGNATURES . set ( signature , [ param . type ] ) ;
158
-
159
- // For full backwards compatibility, also support the (invalid) selectors of
160
- // `log(int)` and `log(uint)`. The selector encoding specifies that one has to
161
- // use the canonical type name but it seems that we supported it in the past.
162
- if ( [ "uint256" , "int256" ] . includes ( param . type ) ) {
163
- const signature = toHex (
164
- selector ( { name : "log" , params : [ { type : typeAliased } ] } )
165
- ) ;
166
- CONSOLE_LOG_SIGNATURES . set ( signature , [ param . type ] ) ;
167
- }
168
-
169
- consoleSolFile += renderLogFunction ( {
170
- name : `log${ nameSuffix } ` ,
171
- params : [ param ] ,
172
- } ) ;
173
- }
174
-
175
- // Now generate the function definitions for `log` for permutations of
176
- // up to 4 parameters using the `types` (uint256, string, bool, address).
177
- const MAX_NUMBER_OF_PARAMETERS = 4 ;
178
- for ( let paramCount = 0 ; paramCount < MAX_NUMBER_OF_PARAMETERS ; paramCount ++ ) {
179
- for ( const permutation of genPermutations ( TYPES . length , paramCount + 1 ) ) {
180
- const params = permutation . map (
181
- ( typeIndex , i ) => ( { ...TYPES [ typeIndex ] , name : `p${ i } ` } as const )
182
- ) ;
183
-
184
- consoleSolFile += renderLogFunction ( { params } ) ;
185
-
186
- const types = params . map ( ( p ) => p . type ) ;
187
- const signature = toHex ( selector ( { name : "log" , params } ) ) ;
188
- CONSOLE_LOG_SIGNATURES . set ( signature , types ) ;
189
-
190
- // Again, for full backwards compatibility, also support the (invalid)
191
- // selectors that contain the `int`/`uint` aliases in the selector calculation.
192
- if ( params . some ( ( p ) => [ "uint256" , "int256" ] . includes ( p . type ) ) ) {
193
- const aliased = params . map ( ( p ) => ( {
194
- ...p ,
195
- type : p . type . replace ( "int256" , "int" ) ,
196
- } ) ) ;
197
-
198
- const signature = toHex ( selector ( { name : "log" , params : aliased } ) ) ;
199
- CONSOLE_LOG_SIGNATURES . set ( signature , types ) ;
200
- }
201
- }
202
- }
203
-
204
- for ( const [ sig , types ] of CONSOLE_LOG_SIGNATURES ) {
205
- const typeNames = types . map ( ( t ) => `${ capitalize ( t ) } Ty` ) . join ( ", " ) ;
206
- logger += ` ${ sig } : [${ typeNames } ],\n` ;
207
- }
208
-
209
- consoleSolFile += "}\n" ;
210
- logger += "};\n" ;
192
+ export const CONSOLE_LOG_SIGNATURES: Record<number, string[]> = {
193
+ ${ Array . from ( CONSOLE_LOG_SIGNATURES )
194
+ . map ( ( [ sig , types ] ) => {
195
+ const typeNames = types . map ( ( t ) => `${ capitalize ( t ) } Ty` ) . join ( ", " ) ;
196
+ return ` ${ sig } : [${ typeNames } ],` ;
197
+ } )
198
+ . join ( "\n" ) }
199
+ };
200
+ ` ;
211
201
202
+ fs . writeFileSync ( __dirname + "/../console.sol" , consoleSolFile ) ;
212
203
fs . writeFileSync (
213
204
__dirname + "/../src/internal/hardhat-network/stack-traces/logger.ts" ,
214
- logger
205
+ loggerFile
215
206
) ;
216
- fs . writeFileSync ( __dirname + "/../console.sol" , consoleSolFile ) ;
0 commit comments