Skip to content

Commit 9cfaa50

Browse files
Add script to extract methods (#475)
Signed-off-by: Alberto Molina <[email protected]> Signed-off-by: Miguel_LZPF <[email protected]> Co-authored-by: Miguel_LZPF <[email protected]>
1 parent 244eab2 commit 9cfaa50

File tree

11 files changed

+182
-7
lines changed

11 files changed

+182
-7
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,6 @@ asset-tokenization-studio.iml
132132

133133
# IntelliJ Idea
134134
/.idea/
135+
136+
# Extracted methods from contracts
137+
contracts/extracted-methods.txt

contracts/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ node_modules
2828
coverage
2929
coverage.json
3030
gas-report.txt
31+
extracted-methods.txt
3132

3233
#Hardhat files
3334
cache

contracts/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@hashgraph/asset-tokenization-contracts",
3-
"version": "1.14.1",
3+
"version": "1.14.2",
44
"main": "./build/typechain-types/index.js",
55
"module": "./build/typechain-types/index.js",
66
"files": [
@@ -87,7 +87,8 @@
8787
"slither": "npm run slither:summary && npm run slither:storageLayout && npm run slither:inheritance && npm run slither:analysis",
8888
"prettierCheck": "prettier --check",
8989
"prepack": "npm run compile:force",
90-
"doc": "npx hardhat dodoc"
90+
"doc": "npx hardhat dodoc",
91+
"extractMethods": "npx -y tsx scripts/extractMethods.ts"
9192
},
9293
"keywords": [],
9394
"author": "",

contracts/scripts/constants.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,11 @@ export const EQUITY_CONFIG_ID =
221221
export const BOND_CONFIG_ID =
222222
'0x0000000000000000000000000000000000000000000000000000000000000002'
223223

224+
// Extract Methods // TODO: Use OUTPUT_FILE as input parameter (CONTRACTS_DIR?)
225+
export const CONTRACTS_DIR = 'contracts'
226+
export const OUTPUT_FILE = 'extracted-methods.txt'
227+
export const REGEX_SELECTOR = /function\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)/g
228+
224229
// * Roles
225230
export const DEFAULT_ADMIN_ROLE =
226231
'0x0000000000000000000000000000000000000000000000000000000000000000'
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import { readdirSync, readFileSync, statSync, writeFileSync } from 'fs'
2+
import { join, extname } from 'path'
3+
import { CONTRACTS_DIR, OUTPUT_FILE, REGEX_SELECTOR } from '@scripts'
4+
5+
function getSolidityFiles(dir: string): string[] {
6+
const entries = readdirSync(dir)
7+
let files: string[] = []
8+
9+
for (const entry of entries) {
10+
const fullPath = join(dir, entry)
11+
const stats = statSync(fullPath)
12+
13+
if (stats.isDirectory()) {
14+
files = files.concat(getSolidityFiles(fullPath))
15+
} else if (extname(entry) === '.sol') {
16+
files.push(fullPath)
17+
}
18+
}
19+
20+
return files
21+
}
22+
23+
function extractFunctions(content: string) {
24+
const regex =
25+
/function\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s+(public|external)((?:\s+\w+)*)\s*(returns\s*\(.*?\))?/g
26+
27+
const normalFns = new Set<string>()
28+
const viewFns = new Set<string>()
29+
const pureFns = new Set<string>()
30+
31+
const normalFnsSelector = new Set<string>()
32+
const viewFnsSelector = new Set<string>()
33+
const pureFnsSelector = new Set<string>()
34+
35+
let match: RegExpExecArray | null
36+
37+
while ((match = regex.exec(content)) !== null) {
38+
const [
39+
fullMatch,
40+
name,
41+
args,
42+
visibility,
43+
modifiers = '',
44+
returns = '',
45+
] = match
46+
47+
const normalized =
48+
`function ${name}(${args.trim()}) ${visibility}${modifiers}${returns ? ' ' + returns.trim() : ''}`
49+
.replace(/\s+/g, ' ')
50+
.trim()
51+
52+
const lower = modifiers.toLowerCase()
53+
const selector = REGEX_SELECTOR.exec(fullMatch)
54+
55+
if (selector === null) continue
56+
57+
const [fullMatchSelector] = selector
58+
59+
if (lower.includes('pure')) {
60+
if (pureFnsSelector.has(fullMatchSelector)) continue
61+
pureFnsSelector.add(fullMatchSelector)
62+
pureFns.add(normalized)
63+
} else if (lower.includes('view')) {
64+
if (viewFnsSelector.has(fullMatchSelector)) continue
65+
viewFnsSelector.add(fullMatchSelector)
66+
viewFns.add(normalized)
67+
} else {
68+
if (normalFnsSelector.has(fullMatchSelector)) continue
69+
normalFnsSelector.add(fullMatchSelector)
70+
normalFns.add(normalized)
71+
}
72+
}
73+
74+
return { normalFns, viewFns, pureFns }
75+
}
76+
77+
export function main() {
78+
const files = getSolidityFiles(CONTRACTS_DIR)
79+
80+
const normalSet = new Set<string>()
81+
const viewSet = new Set<string>()
82+
const pureSet = new Set<string>()
83+
84+
const normalSetSelectors = new Set<string>()
85+
const viewSetSelectors = new Set<string>()
86+
const pureSetSelectors = new Set<string>()
87+
88+
for (const file of files) {
89+
const content = readFileSync(file, 'utf8')
90+
const { normalFns, viewFns, pureFns } = extractFunctions(content)
91+
92+
normalFns.forEach((fn) => {
93+
const selector = REGEX_SELECTOR.exec(fn)
94+
95+
if (selector === null) return
96+
97+
const [fullMatchSelector] = selector
98+
99+
if (normalSetSelectors.has(fullMatchSelector)) return
100+
normalSetSelectors.add(fullMatchSelector)
101+
normalSet.add(fn)
102+
})
103+
104+
viewFns.forEach((fn) => {
105+
const selector = REGEX_SELECTOR.exec(fn)
106+
107+
if (selector === null) return
108+
109+
const [fullMatchSelector] = selector
110+
111+
if (viewSetSelectors.has(fullMatchSelector)) return
112+
viewSetSelectors.add(fullMatchSelector)
113+
viewSet.add(fn)
114+
})
115+
116+
pureFns.forEach((fn) => {
117+
const selector = REGEX_SELECTOR.exec(fn)
118+
119+
if (selector === null) return
120+
121+
const [fullMatchSelector] = selector
122+
123+
if (pureSetSelectors.has(fullMatchSelector)) return
124+
pureSetSelectors.add(fullMatchSelector)
125+
pureSet.add(fn)
126+
})
127+
}
128+
129+
const output = [
130+
'====== ✅ Non-view/pure external/public methods ======\n',
131+
...Array.from(normalSet).sort(),
132+
'\n====== 👁️ View functions ======\n',
133+
...Array.from(viewSet).sort(),
134+
'\n====== 🧪 Pure functions ======\n',
135+
...Array.from(pureSet).sort(),
136+
]
137+
138+
writeFileSync(OUTPUT_FILE, output.join('\n'), 'utf8')
139+
console.log(`✅ Methods extracted to ${OUTPUT_FILE}`)
140+
}
141+
142+
main()

contracts/scripts/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,3 +278,6 @@ export * from './resolverDiamondCut'
278278

279279
// * Factory
280280
export * from './factory'
281+
282+
// * Extract methods
283+
export * from './extractMethods'

contracts/tasks/utils.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,3 +322,23 @@ task('createVC', 'Prints the VC for a given issuer and holder')
322322
const vcString = JSON.stringify(vc)
323323
console.log(`The VC for the holder is: '${vcString}'`)
324324
})
325+
326+
task(
327+
'extract-methods',
328+
'Extracts all public and external function signatures from contracts'
329+
).setAction(async () => {
330+
try {
331+
const { main } = await import('@scripts')
332+
// Redirect output so it is not logged
333+
const originalConsoleLog = console.log
334+
console.log = () => {}
335+
try {
336+
main() // ! Called when importing the script directly
337+
} finally {
338+
console.log = originalConsoleLog
339+
}
340+
} catch (error) {
341+
console.error('❌ An error occurred while extracting methods:')
342+
console.error(error)
343+
}
344+
})

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@hashgraph/hedera-asset-tokenization",
3-
"version": "1.14.1",
3+
"version": "1.14.2",
44
"license": "Apache-2.0",
55
"description": "asset tokenization",
66
"scripts": {

sdk/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@hashgraph/asset-tokenization-sdk",
3-
"version": "1.14.1",
3+
"version": "1.14.2",
44
"description": "Testing to MASTER",
55
"main": "./build/cjs/src/index.js",
66
"module": "./build/esm/src/index.js",

0 commit comments

Comments
 (0)