-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmod.ts
159 lines (147 loc) Β· 4.12 KB
/
mod.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import {
CompilationError,
download,
ensureDir,
Input,
InputSettings,
Output,
walk,
Wrapper,
} from './deps.ts'
export class BuildError extends Error implements CompilationError {
formattedMessage: string
component: string
errorCode: string
severity: 'error' | 'warning'
sourceLocation: { end: number; file: string; start: number }
type: string
constructor(err: CompilationError) {
super(err.message)
this.name = 'CompilationError'
this.message = err.message
this.formattedMessage = err.formattedMessage
this.component = err.component
this.errorCode = err.errorCode
this.severity = err.severity
this.sourceLocation = err.sourceLocation
this.type = err.type
}
}
const HelloWorld = `// SPDX-License-Identifier: MIT
pragma solidity >=0.8;
contract HelloWorld {
string public greet = "Hello World!";
}`
function findImports(importPath: string) {
try {
return { contents: Deno.readTextFileSync(importPath) }
} catch (e) {
return { error: e.message }
}
}
/**
* Initialize a new Solidity project
* @param name project name
* @param version compiler version
*/
export const initProject = async (name: string, version: string) => {
await Deno.mkdir(name)
Deno.chdir(name)
await Deno.mkdir('contracts')
await download('.solc.js', version)
try {
const gitignore = await Deno.readTextFile('.gitignore')
if (!gitignore.includes('.solc.js')) {
await Deno.writeTextFile('.gitignore', '.solc.js\n', { append: true })
}
} catch (e) {
if (e instanceof Deno.errors.NotFound) {
await Deno.writeTextFile('.gitignore', '.solc.js')
} else throw e
}
await Deno.writeTextFile('contracts/hello.sol', HelloWorld)
}
/**
* Compile files and return compilation result
* @param solc Solidity compiler API
* @param sources source list
* @param settings compiler settings
*/
export const compile = async (
solc: Wrapper,
sources: Record<string, { content: string }>,
settings: InputSettings,
): Promise<Output> => {
const result = JSON.parse(
solc.compile(
JSON.stringify({
sources,
language: 'Solidity',
settings: {
...settings,
outputSelection: {
'*': {
'*': ['evm.bytecode', 'evm.deployedBytecode', 'abi'],
},
...settings.outputSelection, // to be able to override outputs
},
},
} as Input),
{ import: findImports },
),
)
return result
}
/**
* Compile contracts in a current directory and save outputs to the `artifacts` folder.
* @param solc Solidity compiler API
* @param settings Compiler settings
*/
export const compileToFs = async (
solc: Wrapper,
settings: InputSettings,
) => {
const files: Record<string, { content: string }> = {}
for await (const entry of walk('.')) {
if (entry.isFile && entry.name.endsWith('.sol')) {
files[entry.path] = { content: await Deno.readTextFile(entry.path) }
}
}
const result = await compile(solc, files, settings)
if (result.errors) {
throw new BuildError(result.errors[0])
}
const compiled = Object.entries(result.contracts).map(([sourceName, c]) => {
return {
sourceName,
contracts: Object.entries(c).map(([contractName, contract]) => {
const linkReferences = contract.evm?.bytecode?.linkReferences
const deployedLinkReferences = contract.evm?.deployedBytecode
?.linkReferences
const bytecode = contract.evm?.bytecode?.object
return ({
contractName,
sourceName,
bytecode: bytecode ? `0x${bytecode}` : undefined,
abi: contract.abi,
linkReferences,
deployedLinkReferences,
})
}),
}
})
try {
await Deno.remove('artifacts', { recursive: true })
} catch {}
await Deno.mkdir('artifacts')
for (const { contracts, sourceName } of compiled) {
await ensureDir(`artifacts/${sourceName}`)
for (const contract of contracts) {
await Deno.writeTextFile(
`artifacts/${sourceName}/${contract.contractName}.json`,
JSON.stringify(contract, null, 2),
)
}
}
return Object.keys(files).length
}