@alephium/web3 0.2.0-rc.8 → 0.2.0-test.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +2 -2
- package/.eslintrc.json +21 -0
- package/LICENSE +165 -0
- package/README.md +135 -2
- package/contracts/add/add.ral +13 -0
- package/contracts/greeter_main.ral +1 -1
- package/contracts/main.ral +4 -0
- package/contracts/sub/sub.ral +10 -0
- package/contracts/test/metadata.ral +18 -0
- package/contracts/test/warnings.ral +8 -0
- package/dist/alephium-web3.min.js +1 -1
- package/dist/alephium-web3.min.js.LICENSE.txt +17 -0
- package/dist/alephium-web3.min.js.map +1 -1
- package/dist/scripts/create-project.js +1 -1
- package/dist/src/api/api-alephium.d.ts +6 -19
- package/dist/src/api/api-explorer.d.ts +16 -16
- package/dist/src/api/index.js +1 -5
- package/dist/src/contract/contract.d.ts +16 -31
- package/dist/src/contract/contract.js +96 -123
- package/dist/src/contract/index.js +1 -5
- package/dist/src/index.d.ts +0 -1
- package/dist/src/index.js +1 -19
- package/dist/src/signer/index.d.ts +1 -0
- package/dist/src/signer/index.js +2 -5
- package/dist/src/signer/node-wallet.d.ts +11 -0
- package/dist/src/signer/node-wallet.js +57 -0
- package/dist/src/signer/signer.js +1 -5
- package/dist/src/test/index.d.ts +6 -0
- package/dist/src/test/index.js +41 -0
- package/dist/src/test/privatekey-wallet.d.ts +11 -0
- package/dist/src/test/privatekey-wallet.js +68 -0
- package/dist/src/transaction/index.d.ts +1 -0
- package/dist/src/transaction/index.js +2 -5
- package/dist/src/transaction/sign-verify.d.ts +2 -0
- package/dist/src/transaction/sign-verify.js +58 -0
- package/dist/src/utils/index.d.ts +1 -0
- package/dist/src/utils/index.js +2 -5
- package/dist/src/utils/password-crypto.d.ts +2 -0
- package/dist/src/utils/password-crypto.js +69 -0
- package/dist/src/utils/utils.d.ts +2 -3
- package/dist/src/utils/utils.js +15 -16
- package/gitignore +9 -0
- package/package.json +32 -6
- package/scripts/create-project.ts +1 -1
- package/src/api/api-alephium.ts +0 -14
- package/src/contract/contract.ts +102 -176
- package/src/contract/ralph.test.ts +178 -0
- package/src/fixtures/address.json +36 -0
- package/src/fixtures/balance.json +9 -0
- package/src/fixtures/self-clique.json +19 -0
- package/src/fixtures/transaction.json +13 -0
- package/src/fixtures/transactions.json +179 -0
- package/src/index.ts +0 -2
- package/src/signer/fixtures/genesis.json +26 -0
- package/src/signer/fixtures/wallets.json +26 -0
- package/src/signer/index.ts +1 -0
- package/src/signer/node-wallet.ts +65 -0
- package/src/test/index.ts +31 -0
- package/src/test/privatekey-wallet.ts +57 -0
- package/src/transaction/index.ts +1 -0
- package/src/transaction/sign-verify.test.ts +50 -0
- package/src/transaction/sign-verify.ts +39 -0
- package/src/utils/address.test.ts +47 -0
- package/src/utils/djb2.test.ts +35 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/password-crypto.test.ts +27 -0
- package/src/utils/password-crypto.ts +77 -0
- package/src/utils/utils.test.ts +161 -0
- package/src/utils/utils.ts +7 -7
- package/templates/base/package.json +1 -1
- package/templates/react/package.json +1 -1
- package/test/contract.test.ts +213 -0
- package/test/events.test.ts +141 -0
- package/test/transaction.test.ts +73 -0
- package/jest-config.json +0 -11
package/src/contract/contract.ts
CHANGED
|
@@ -17,7 +17,8 @@ along with the library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { Buffer } from 'buffer/'
|
|
20
|
-
import
|
|
20
|
+
import * as cryptojs from 'crypto-js'
|
|
21
|
+
import * as crypto from 'crypto'
|
|
21
22
|
import fs from 'fs'
|
|
22
23
|
import { promises as fsPromises } from 'fs'
|
|
23
24
|
import { node, NodeProvider } from '../api'
|
|
@@ -38,38 +39,39 @@ enum SourceType {
|
|
|
38
39
|
Interface = 3
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
export type CompilerOptions =
|
|
42
|
+
export type CompilerOptions = {
|
|
42
43
|
errorOnWarnings: boolean
|
|
44
|
+
ignoreUnusedConstantsWarnings: boolean
|
|
43
45
|
}
|
|
44
46
|
|
|
45
|
-
export const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
ignoreUnusedFieldsWarnings: false,
|
|
49
|
-
ignoreUnusedPrivateFunctionsWarnings: false,
|
|
50
|
-
ignoreReadonlyCheckWarnings: false,
|
|
51
|
-
ignoreExternalCallCheckWarnings: false
|
|
47
|
+
export const DEFAULT_COMPILER_OPTIONS: CompilerOptions = {
|
|
48
|
+
errorOnWarnings: true,
|
|
49
|
+
ignoreUnusedConstantsWarnings: true
|
|
52
50
|
}
|
|
53
51
|
|
|
54
|
-
export const DEFAULT_COMPILER_OPTIONS: CompilerOptions = { errorOnWarnings: true, ...DEFAULT_NODE_COMPILER_OPTIONS }
|
|
55
|
-
|
|
56
52
|
class TypedMatcher<T extends SourceType> {
|
|
57
53
|
matcher: RegExp
|
|
58
54
|
type: T
|
|
55
|
+
name: string | undefined
|
|
59
56
|
|
|
60
57
|
constructor(pattern: string, type: T) {
|
|
61
58
|
this.matcher = new RegExp(pattern, 'mg')
|
|
62
59
|
this.type = type
|
|
60
|
+
this.name = undefined
|
|
63
61
|
}
|
|
64
62
|
|
|
65
63
|
match(str: string): number {
|
|
66
|
-
const results = str.
|
|
67
|
-
|
|
64
|
+
const results = [...str.matchAll(this.matcher)]
|
|
65
|
+
if (results.length > 0) {
|
|
66
|
+
this.name = results[0][1]
|
|
67
|
+
}
|
|
68
|
+
return results.length
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
class SourceFile {
|
|
72
73
|
type: SourceType
|
|
74
|
+
typeId: string
|
|
73
75
|
contractPath: string
|
|
74
76
|
sourceCode: string
|
|
75
77
|
sourceCodeHash: string
|
|
@@ -78,17 +80,13 @@ class SourceFile {
|
|
|
78
80
|
return artifactsRootPath + this.contractPath.slice(this.contractPath.indexOf('/')) + '.json'
|
|
79
81
|
}
|
|
80
82
|
|
|
81
|
-
constructor(type: SourceType,
|
|
83
|
+
constructor(type: SourceType, typeId: string, sourceCode: string, contractPath: string) {
|
|
82
84
|
this.type = type
|
|
85
|
+
this.typeId = typeId
|
|
83
86
|
this.sourceCode = sourceCode
|
|
84
|
-
this.sourceCodeHash =
|
|
87
|
+
this.sourceCodeHash = cryptojs.SHA256(sourceCode).toString()
|
|
85
88
|
this.contractPath = contractPath
|
|
86
89
|
}
|
|
87
|
-
|
|
88
|
-
static async from(type: SourceType, sourceCode: string, contractPath: string): Promise<SourceFile> {
|
|
89
|
-
const sourceCodeHash = await crypto.subtle.digest('SHA-256', Buffer.from(sourceCode))
|
|
90
|
-
return new SourceFile(type, sourceCode, Buffer.from(sourceCodeHash).toString('hex'), contractPath)
|
|
91
|
-
}
|
|
92
90
|
}
|
|
93
91
|
|
|
94
92
|
class Compiled<T extends Artifact> {
|
|
@@ -106,47 +104,19 @@ class Compiled<T extends Artifact> {
|
|
|
106
104
|
class ProjectArtifact {
|
|
107
105
|
static readonly artifactFileName = '.project.json'
|
|
108
106
|
|
|
109
|
-
compilerOptionsUsed: node.CompilerOptions
|
|
110
107
|
infos: Map<string, { sourceCodeHash: string; warnings: string[] }>
|
|
111
108
|
|
|
112
|
-
|
|
113
|
-
if (Object.keys(compilerOptions).length != Object.keys(DEFAULT_NODE_COMPILER_OPTIONS).length) {
|
|
114
|
-
throw Error(`Not all compiler options are set: ${compilerOptions}`)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const combined = { ...compilerOptions, ...DEFAULT_NODE_COMPILER_OPTIONS }
|
|
118
|
-
if (Object.keys(combined).length !== Object.keys(DEFAULT_NODE_COMPILER_OPTIONS).length) {
|
|
119
|
-
throw Error(`There are unknown compiler options: ${compilerOptions}`)
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
constructor(
|
|
124
|
-
compilerOptionsUsed: node.CompilerOptions,
|
|
125
|
-
infos: Map<string, { sourceCodeHash: string; warnings: string[] }>
|
|
126
|
-
) {
|
|
127
|
-
ProjectArtifact.checkCompilerOptionsParameter(compilerOptionsUsed)
|
|
128
|
-
this.compilerOptionsUsed = compilerOptionsUsed
|
|
109
|
+
constructor(infos: Map<string, { sourceCodeHash: string; warnings: string[] }>) {
|
|
129
110
|
this.infos = infos
|
|
130
111
|
}
|
|
131
112
|
|
|
132
113
|
async saveToFile(rootPath: string): Promise<void> {
|
|
133
114
|
const filepath = rootPath + '/' + ProjectArtifact.artifactFileName
|
|
134
|
-
const
|
|
135
|
-
const content = JSON.stringify(artifact, null, 2)
|
|
115
|
+
const content = JSON.stringify(Object.fromEntries(this.infos), null, 2)
|
|
136
116
|
return fsPromises.writeFile(filepath, content)
|
|
137
117
|
}
|
|
138
118
|
|
|
139
|
-
|
|
140
|
-
ProjectArtifact.checkCompilerOptionsParameter(compilerOptions)
|
|
141
|
-
|
|
142
|
-
const optionsMatched = Object.entries(compilerOptions).every(([key, inputOption]) => {
|
|
143
|
-
const usedOption = this.compilerOptionsUsed[`${key}`]
|
|
144
|
-
return usedOption === inputOption
|
|
145
|
-
})
|
|
146
|
-
if (!optionsMatched) {
|
|
147
|
-
return true
|
|
148
|
-
}
|
|
149
|
-
|
|
119
|
+
sourceHasChanged(files: SourceFile[]): boolean {
|
|
150
120
|
if (files.length !== this.infos.size) {
|
|
151
121
|
return true
|
|
152
122
|
}
|
|
@@ -156,7 +126,6 @@ class ProjectArtifact {
|
|
|
156
126
|
return true
|
|
157
127
|
}
|
|
158
128
|
}
|
|
159
|
-
|
|
160
129
|
return false
|
|
161
130
|
}
|
|
162
131
|
|
|
@@ -166,10 +135,10 @@ class ProjectArtifact {
|
|
|
166
135
|
return undefined
|
|
167
136
|
}
|
|
168
137
|
const content = await fsPromises.readFile(filepath)
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return new ProjectArtifact(
|
|
138
|
+
const files = new Map(
|
|
139
|
+
Object.entries<{ sourceCodeHash: string; warnings: string[] }>(JSON.parse(content.toString()))
|
|
140
|
+
)
|
|
141
|
+
return new ProjectArtifact(files)
|
|
173
142
|
}
|
|
174
143
|
}
|
|
175
144
|
|
|
@@ -177,7 +146,6 @@ export class Project {
|
|
|
177
146
|
sourceFiles: SourceFile[]
|
|
178
147
|
contracts: Compiled<Contract>[]
|
|
179
148
|
scripts: Compiled<Script>[]
|
|
180
|
-
projectArtifact: ProjectArtifact
|
|
181
149
|
|
|
182
150
|
readonly contractsRootPath: string
|
|
183
151
|
readonly artifactsRootPath: string
|
|
@@ -186,12 +154,12 @@ export class Project {
|
|
|
186
154
|
static currentProject: Project
|
|
187
155
|
|
|
188
156
|
static readonly abstractContractMatcher = new TypedMatcher<SourceType>(
|
|
189
|
-
'^Abstract Contract [A-Z][a-zA-Z0-9]*',
|
|
157
|
+
'^Abstract Contract ([A-Z][a-zA-Z0-9]*)\\(*',
|
|
190
158
|
SourceType.AbstractContract
|
|
191
159
|
)
|
|
192
|
-
static readonly contractMatcher = new TypedMatcher('^Contract [A-Z][a-zA-Z0-9]*', SourceType.Contract)
|
|
193
|
-
static readonly interfaceMatcher = new TypedMatcher('^Interface [A-Z][a-zA-Z0-9]* \\{', SourceType.Interface)
|
|
194
|
-
static readonly scriptMatcher = new TypedMatcher('^TxScript [A-Z][a-zA-Z0-9]*', SourceType.Script)
|
|
160
|
+
static readonly contractMatcher = new TypedMatcher('^Contract ([A-Z][a-zA-Z0-9]*)\\(*', SourceType.Contract)
|
|
161
|
+
static readonly interfaceMatcher = new TypedMatcher('^Interface ([A-Z][a-zA-Z0-9]*) \\{', SourceType.Interface)
|
|
162
|
+
static readonly scriptMatcher = new TypedMatcher('^TxScript ([A-Z][a-zA-Z0-9]*)( \\{*|\\(*)', SourceType.Script)
|
|
195
163
|
static readonly matchers = [
|
|
196
164
|
Project.abstractContractMatcher,
|
|
197
165
|
Project.contractMatcher,
|
|
@@ -199,44 +167,13 @@ export class Project {
|
|
|
199
167
|
Project.scriptMatcher
|
|
200
168
|
]
|
|
201
169
|
|
|
202
|
-
static buildProjectArtifact(
|
|
203
|
-
sourceFiles: SourceFile[],
|
|
204
|
-
contracts: Compiled<Contract>[],
|
|
205
|
-
scripts: Compiled<Script>[],
|
|
206
|
-
compilerOptions: node.CompilerOptions
|
|
207
|
-
): ProjectArtifact {
|
|
208
|
-
const files: Map<string, { sourceCodeHash: string; warnings: string[] }> = new Map()
|
|
209
|
-
contracts.forEach((c) => {
|
|
210
|
-
files.set(c.sourceFile.contractPath, {
|
|
211
|
-
sourceCodeHash: c.sourceFile.sourceCodeHash,
|
|
212
|
-
warnings: c.warnings
|
|
213
|
-
})
|
|
214
|
-
})
|
|
215
|
-
scripts.forEach((s) => {
|
|
216
|
-
files.set(s.sourceFile.contractPath, {
|
|
217
|
-
sourceCodeHash: s.sourceFile.sourceCodeHash,
|
|
218
|
-
warnings: s.warnings
|
|
219
|
-
})
|
|
220
|
-
})
|
|
221
|
-
const compiledSize = contracts.length + scripts.length
|
|
222
|
-
sourceFiles.slice(compiledSize).forEach((c) => {
|
|
223
|
-
files.set(c.contractPath, {
|
|
224
|
-
sourceCodeHash: c.sourceCodeHash,
|
|
225
|
-
warnings: []
|
|
226
|
-
})
|
|
227
|
-
})
|
|
228
|
-
return new ProjectArtifact(compilerOptions, files)
|
|
229
|
-
}
|
|
230
|
-
|
|
231
170
|
private constructor(
|
|
232
171
|
provider: NodeProvider,
|
|
233
172
|
contractsRootPath: string,
|
|
234
173
|
artifactsRootPath: string,
|
|
235
174
|
sourceFiles: SourceFile[],
|
|
236
175
|
contracts: Compiled<Contract>[],
|
|
237
|
-
scripts: Compiled<Script>[]
|
|
238
|
-
errorOnWarnings: boolean,
|
|
239
|
-
projectArtifact: ProjectArtifact
|
|
176
|
+
scripts: Compiled<Script>[]
|
|
240
177
|
) {
|
|
241
178
|
this.nodeProvider = provider
|
|
242
179
|
this.contractsRootPath = contractsRootPath
|
|
@@ -244,14 +181,6 @@ export class Project {
|
|
|
244
181
|
this.sourceFiles = sourceFiles
|
|
245
182
|
this.contracts = contracts
|
|
246
183
|
this.scripts = scripts
|
|
247
|
-
this.projectArtifact = projectArtifact
|
|
248
|
-
|
|
249
|
-
if (errorOnWarnings) {
|
|
250
|
-
Project.checkCompilerWarnings(
|
|
251
|
-
[...contracts.map((c) => c.warnings).flat(), ...scripts.map((s) => s.warnings).flat()],
|
|
252
|
-
errorOnWarnings
|
|
253
|
-
)
|
|
254
|
-
}
|
|
255
184
|
}
|
|
256
185
|
|
|
257
186
|
private getContractPath(path: string): string {
|
|
@@ -262,12 +191,15 @@ export class Project {
|
|
|
262
191
|
: this.contractsRootPath + '/' + path
|
|
263
192
|
}
|
|
264
193
|
|
|
265
|
-
static checkCompilerWarnings(warnings: string[],
|
|
266
|
-
|
|
194
|
+
private static checkCompilerWarnings(warnings: string[], compilerOptions: CompilerOptions): void {
|
|
195
|
+
const remains = compilerOptions.ignoreUnusedConstantsWarnings
|
|
196
|
+
? warnings.filter((s) => !s.includes('unused constants'))
|
|
197
|
+
: warnings
|
|
198
|
+
if (remains.length !== 0) {
|
|
267
199
|
const prefixPerWarning = ' - '
|
|
268
|
-
const warningString = prefixPerWarning +
|
|
269
|
-
const output =
|
|
270
|
-
if (errorOnWarnings) {
|
|
200
|
+
const warningString = prefixPerWarning + remains.join('\n' + prefixPerWarning)
|
|
201
|
+
const output = 'Compilation warnings:\n' + warningString + '\n'
|
|
202
|
+
if (compilerOptions.errorOnWarnings) {
|
|
271
203
|
throw new Error(output)
|
|
272
204
|
} else {
|
|
273
205
|
console.log(output)
|
|
@@ -275,21 +207,23 @@ export class Project {
|
|
|
275
207
|
}
|
|
276
208
|
}
|
|
277
209
|
|
|
278
|
-
static contract(path: string): Contract {
|
|
210
|
+
static contract(path: string, compilerOptions?: Partial<CompilerOptions>): Contract {
|
|
279
211
|
const contractPath = Project.currentProject.getContractPath(path)
|
|
280
212
|
const contract = Project.currentProject.contracts.find((c) => c.sourceFile.contractPath === contractPath)
|
|
281
213
|
if (typeof contract === 'undefined') {
|
|
282
214
|
throw new Error(`Contract ${contractPath} does not exist`)
|
|
283
215
|
}
|
|
216
|
+
Project.checkCompilerWarnings(contract.warnings, { ...DEFAULT_COMPILER_OPTIONS, ...compilerOptions })
|
|
284
217
|
return contract.artifact
|
|
285
218
|
}
|
|
286
219
|
|
|
287
|
-
static script(path: string): Script {
|
|
220
|
+
static script(path: string, compilerOptions?: Partial<CompilerOptions>): Script {
|
|
288
221
|
const contractPath = Project.currentProject.getContractPath(path)
|
|
289
222
|
const script = Project.currentProject.scripts.find((c) => c.sourceFile.contractPath === contractPath)
|
|
290
223
|
if (typeof script === 'undefined') {
|
|
291
224
|
throw new Error(`Script ${contractPath} does not exist`)
|
|
292
225
|
}
|
|
226
|
+
Project.checkCompilerWarnings(script.warnings, { ...DEFAULT_COMPILER_OPTIONS, ...compilerOptions })
|
|
293
227
|
return script.artifact
|
|
294
228
|
}
|
|
295
229
|
|
|
@@ -309,7 +243,6 @@ export class Project {
|
|
|
309
243
|
for (const script of this.scripts) {
|
|
310
244
|
await saveToFile(script)
|
|
311
245
|
}
|
|
312
|
-
await this.projectArtifact.saveToFile(this.artifactsRootPath)
|
|
313
246
|
}
|
|
314
247
|
|
|
315
248
|
contractByCodeHash(codeHash: string): Contract {
|
|
@@ -320,43 +253,56 @@ export class Project {
|
|
|
320
253
|
return contract.artifact
|
|
321
254
|
}
|
|
322
255
|
|
|
256
|
+
private async saveProjectArtifactToFile(): Promise<void> {
|
|
257
|
+
const files: Map<string, { sourceCodeHash: string; warnings: string[] }> = new Map()
|
|
258
|
+
this.contracts.forEach((c) => {
|
|
259
|
+
files.set(c.sourceFile.contractPath, {
|
|
260
|
+
sourceCodeHash: c.sourceFile.sourceCodeHash,
|
|
261
|
+
warnings: c.warnings
|
|
262
|
+
})
|
|
263
|
+
})
|
|
264
|
+
this.scripts.forEach((s) => {
|
|
265
|
+
files.set(s.sourceFile.contractPath, {
|
|
266
|
+
sourceCodeHash: s.sourceFile.sourceCodeHash,
|
|
267
|
+
warnings: s.warnings
|
|
268
|
+
})
|
|
269
|
+
})
|
|
270
|
+
const compiledSize = this.contracts.length + this.scripts.length
|
|
271
|
+
this.sourceFiles.slice(compiledSize).forEach((c) => {
|
|
272
|
+
files.set(c.contractPath, {
|
|
273
|
+
sourceCodeHash: c.sourceCodeHash,
|
|
274
|
+
warnings: []
|
|
275
|
+
})
|
|
276
|
+
})
|
|
277
|
+
const projectArtifact = new ProjectArtifact(files)
|
|
278
|
+
await projectArtifact.saveToFile(this.artifactsRootPath)
|
|
279
|
+
}
|
|
280
|
+
|
|
323
281
|
private static async compile(
|
|
324
282
|
provider: NodeProvider,
|
|
325
283
|
files: SourceFile[],
|
|
326
284
|
contractsRootPath: string,
|
|
327
|
-
artifactsRootPath: string
|
|
328
|
-
errorOnWarnings: boolean,
|
|
329
|
-
compilerOptions: node.CompilerOptions
|
|
285
|
+
artifactsRootPath: string
|
|
330
286
|
): Promise<Project> {
|
|
331
287
|
const sourceStr = files.map((f) => f.sourceCode).join('\n')
|
|
332
288
|
const result = await provider.contracts.postContractsCompileProject({
|
|
333
|
-
code: sourceStr
|
|
334
|
-
compilerOptions: compilerOptions
|
|
289
|
+
code: sourceStr
|
|
335
290
|
})
|
|
336
291
|
const contracts: Compiled<Contract>[] = []
|
|
337
292
|
const scripts: Compiled<Script>[] = []
|
|
338
293
|
result.contracts.forEach((contractResult, index) => {
|
|
339
294
|
const sourceFile = files[`${index}`]
|
|
340
|
-
const contract = Contract.fromCompileResult(contractResult)
|
|
295
|
+
const contract = Contract.fromCompileResult(sourceFile.typeId, contractResult)
|
|
341
296
|
contracts.push(new Compiled(sourceFile, contract, contractResult.warnings))
|
|
342
297
|
})
|
|
343
298
|
result.scripts.forEach((scriptResult, index) => {
|
|
344
299
|
const sourceFile = files[index + contracts.length]
|
|
345
|
-
const script = Script.fromCompileResult(scriptResult)
|
|
300
|
+
const script = Script.fromCompileResult(sourceFile.typeId, scriptResult)
|
|
346
301
|
scripts.push(new Compiled(sourceFile, script, scriptResult.warnings))
|
|
347
302
|
})
|
|
348
|
-
const
|
|
349
|
-
const project = new Project(
|
|
350
|
-
provider,
|
|
351
|
-
contractsRootPath,
|
|
352
|
-
artifactsRootPath,
|
|
353
|
-
files,
|
|
354
|
-
contracts,
|
|
355
|
-
scripts,
|
|
356
|
-
errorOnWarnings,
|
|
357
|
-
projectArtifact
|
|
358
|
-
)
|
|
303
|
+
const project = new Project(provider, contractsRootPath, artifactsRootPath, files, contracts, scripts)
|
|
359
304
|
await project.saveArtifactsToFile()
|
|
305
|
+
await project.saveProjectArtifactToFile()
|
|
360
306
|
return project
|
|
361
307
|
}
|
|
362
308
|
|
|
@@ -365,9 +311,7 @@ export class Project {
|
|
|
365
311
|
files: SourceFile[],
|
|
366
312
|
projectArtifact: ProjectArtifact,
|
|
367
313
|
contractsRootPath: string,
|
|
368
|
-
artifactsRootPath: string
|
|
369
|
-
errorOnWarnings: boolean,
|
|
370
|
-
compilerOptions: node.CompilerOptions
|
|
314
|
+
artifactsRootPath: string
|
|
371
315
|
): Promise<Project> {
|
|
372
316
|
try {
|
|
373
317
|
const contracts: Compiled<Contract>[] = []
|
|
@@ -387,20 +331,10 @@ export class Project {
|
|
|
387
331
|
scripts.push(new Compiled(file, artifact, warnings))
|
|
388
332
|
}
|
|
389
333
|
}
|
|
390
|
-
|
|
391
|
-
return new Project(
|
|
392
|
-
provider,
|
|
393
|
-
contractsRootPath,
|
|
394
|
-
artifactsRootPath,
|
|
395
|
-
files,
|
|
396
|
-
contracts,
|
|
397
|
-
scripts,
|
|
398
|
-
errorOnWarnings,
|
|
399
|
-
projectArtifact
|
|
400
|
-
)
|
|
334
|
+
return new Project(provider, contractsRootPath, artifactsRootPath, files, contracts, scripts)
|
|
401
335
|
} catch (error) {
|
|
402
336
|
console.log(`Failed to load artifacts, error: ${error}, try to re-compile contracts...`)
|
|
403
|
-
return Project.compile(provider, files, contractsRootPath, artifactsRootPath
|
|
337
|
+
return Project.compile(provider, files, contractsRootPath, artifactsRootPath)
|
|
404
338
|
}
|
|
405
339
|
}
|
|
406
340
|
|
|
@@ -421,8 +355,12 @@ export class Project {
|
|
|
421
355
|
throw new Error(`Multiple definitions in file: ${contractPath}`)
|
|
422
356
|
}
|
|
423
357
|
const matcherIndex = results.indexOf(1)
|
|
424
|
-
const
|
|
425
|
-
|
|
358
|
+
const matcher = this.matchers[`${matcherIndex}`]
|
|
359
|
+
const type = matcher.type
|
|
360
|
+
if (matcher.name === undefined) {
|
|
361
|
+
throw new Error(`Invalid definition in file: ${contractPath}`)
|
|
362
|
+
}
|
|
363
|
+
return new SourceFile(type, matcher.name, sourceStr, contractPath)
|
|
426
364
|
}
|
|
427
365
|
|
|
428
366
|
private static async loadSourceFiles(contractsRootPath: string): Promise<SourceFile[]> {
|
|
@@ -449,44 +387,30 @@ export class Project {
|
|
|
449
387
|
return sourceFiles.sort((a, b) => a.type - b.type)
|
|
450
388
|
}
|
|
451
389
|
|
|
452
|
-
static async build(
|
|
453
|
-
compilerOptionsPartial: Partial<CompilerOptions> = {},
|
|
454
|
-
contractsRootPath = 'contracts',
|
|
455
|
-
artifactsRootPath = 'artifacts'
|
|
456
|
-
): Promise<void> {
|
|
390
|
+
static async build(contractsRootPath = 'contracts', artifactsRootPath = 'artifacts'): Promise<void> {
|
|
457
391
|
const provider = getCurrentNodeProvider()
|
|
458
392
|
const sourceFiles = await Project.loadSourceFiles(contractsRootPath)
|
|
459
|
-
const { errorOnWarnings, ...nodeCompilerOptions } = { ...DEFAULT_COMPILER_OPTIONS, ...compilerOptionsPartial }
|
|
460
393
|
const projectArtifact = await ProjectArtifact.from(artifactsRootPath)
|
|
461
|
-
if (typeof projectArtifact === 'undefined' || projectArtifact.
|
|
462
|
-
|
|
463
|
-
Project.currentProject = await Project.compile(
|
|
464
|
-
provider,
|
|
465
|
-
sourceFiles,
|
|
466
|
-
contractsRootPath,
|
|
467
|
-
artifactsRootPath,
|
|
468
|
-
errorOnWarnings,
|
|
469
|
-
nodeCompilerOptions
|
|
470
|
-
)
|
|
394
|
+
if (typeof projectArtifact === 'undefined' || projectArtifact.sourceHasChanged(sourceFiles)) {
|
|
395
|
+
Project.currentProject = await Project.compile(provider, sourceFiles, contractsRootPath, artifactsRootPath)
|
|
471
396
|
} else {
|
|
472
|
-
console.log(`Load compiled contracts from folder "${artifactsRootPath}"`)
|
|
473
397
|
Project.currentProject = await Project.loadArtifacts(
|
|
474
398
|
provider,
|
|
475
399
|
sourceFiles,
|
|
476
400
|
projectArtifact,
|
|
477
401
|
contractsRootPath,
|
|
478
|
-
artifactsRootPath
|
|
479
|
-
errorOnWarnings,
|
|
480
|
-
nodeCompilerOptions
|
|
402
|
+
artifactsRootPath
|
|
481
403
|
)
|
|
482
404
|
}
|
|
483
405
|
}
|
|
484
406
|
}
|
|
485
407
|
|
|
486
408
|
export abstract class Artifact {
|
|
409
|
+
readonly typeId: string
|
|
487
410
|
readonly functions: FunctionSig[]
|
|
488
411
|
|
|
489
|
-
constructor(functions: FunctionSig[]) {
|
|
412
|
+
constructor(typeId: string, functions: FunctionSig[]) {
|
|
413
|
+
this.typeId = typeId
|
|
490
414
|
this.functions = functions
|
|
491
415
|
}
|
|
492
416
|
|
|
@@ -512,13 +436,14 @@ export class Contract extends Artifact {
|
|
|
512
436
|
readonly eventsSig: EventSig[]
|
|
513
437
|
|
|
514
438
|
constructor(
|
|
439
|
+
typeId: string,
|
|
515
440
|
bytecode: string,
|
|
516
441
|
codeHash: string,
|
|
517
442
|
fieldsSig: FieldsSig,
|
|
518
443
|
eventsSig: EventSig[],
|
|
519
444
|
functions: FunctionSig[]
|
|
520
445
|
) {
|
|
521
|
-
super(functions)
|
|
446
|
+
super(typeId, functions)
|
|
522
447
|
this.bytecode = bytecode
|
|
523
448
|
this.codeHash = codeHash
|
|
524
449
|
this.fieldsSig = fieldsSig
|
|
@@ -537,6 +462,7 @@ export class Contract extends Artifact {
|
|
|
537
462
|
throw Error('The artifact JSON for contract is incomplete')
|
|
538
463
|
}
|
|
539
464
|
const contract = new Contract(
|
|
465
|
+
artifact.typeId,
|
|
540
466
|
artifact.bytecode,
|
|
541
467
|
artifact.codeHash,
|
|
542
468
|
artifact.fieldsSig,
|
|
@@ -546,8 +472,8 @@ export class Contract extends Artifact {
|
|
|
546
472
|
return contract
|
|
547
473
|
}
|
|
548
474
|
|
|
549
|
-
static fromCompileResult(result: CompileContractResult): Contract {
|
|
550
|
-
return new Contract(result.bytecode, result.codeHash, result.fields, result.events, result.functions)
|
|
475
|
+
static fromCompileResult(typeId: string, result: CompileContractResult): Contract {
|
|
476
|
+
return new Contract(typeId, result.bytecode, result.codeHash, result.fields, result.events, result.functions)
|
|
551
477
|
}
|
|
552
478
|
|
|
553
479
|
// support both 'code.ral' and 'code.ral.json'
|
|
@@ -566,6 +492,7 @@ export class Contract extends Artifact {
|
|
|
566
492
|
|
|
567
493
|
override toString(): string {
|
|
568
494
|
const object = {
|
|
495
|
+
typeId: this.typeId,
|
|
569
496
|
bytecode: this.bytecode,
|
|
570
497
|
codeHash: this.codeHash,
|
|
571
498
|
fieldsSig: this.fieldsSig,
|
|
@@ -588,10 +515,8 @@ export class Contract extends Artifact {
|
|
|
588
515
|
}
|
|
589
516
|
}
|
|
590
517
|
|
|
591
|
-
// no need to be cryptographically strong random
|
|
592
518
|
static randomAddress(): string {
|
|
593
|
-
const bytes =
|
|
594
|
-
crypto.getRandomValues(bytes)
|
|
519
|
+
const bytes = crypto.randomBytes(33)
|
|
595
520
|
bytes[0] = 3
|
|
596
521
|
return bs58.encode(bytes)
|
|
597
522
|
}
|
|
@@ -776,14 +701,14 @@ export class Script extends Artifact {
|
|
|
776
701
|
readonly bytecodeTemplate: string
|
|
777
702
|
readonly fieldsSig: FieldsSig
|
|
778
703
|
|
|
779
|
-
constructor(bytecodeTemplate: string, fieldsSig: FieldsSig, functions: FunctionSig[]) {
|
|
780
|
-
super(functions)
|
|
704
|
+
constructor(typeId: string, bytecodeTemplate: string, fieldsSig: FieldsSig, functions: FunctionSig[]) {
|
|
705
|
+
super(typeId, functions)
|
|
781
706
|
this.bytecodeTemplate = bytecodeTemplate
|
|
782
707
|
this.fieldsSig = fieldsSig
|
|
783
708
|
}
|
|
784
709
|
|
|
785
|
-
static fromCompileResult(result: CompileScriptResult): Script {
|
|
786
|
-
return new Script(result.bytecodeTemplate, result.fields, result.functions)
|
|
710
|
+
static fromCompileResult(typeId: string, result: CompileScriptResult): Script {
|
|
711
|
+
return new Script(typeId, result.bytecodeTemplate, result.fields, result.functions)
|
|
787
712
|
}
|
|
788
713
|
|
|
789
714
|
// TODO: safely parse json
|
|
@@ -791,7 +716,7 @@ export class Script extends Artifact {
|
|
|
791
716
|
if (artifact.bytecodeTemplate == null || artifact.fieldsSig == null || artifact.functions == null) {
|
|
792
717
|
throw Error('The artifact JSON for script is incomplete')
|
|
793
718
|
}
|
|
794
|
-
return new Script(artifact.bytecodeTemplate, artifact.fieldsSig, artifact.functions)
|
|
719
|
+
return new Script(artifact.typeId, artifact.bytecodeTemplate, artifact.fieldsSig, artifact.functions)
|
|
795
720
|
}
|
|
796
721
|
|
|
797
722
|
static async fromArtifactFile(path: string): Promise<Script> {
|
|
@@ -802,6 +727,7 @@ export class Script extends Artifact {
|
|
|
802
727
|
|
|
803
728
|
override toString(): string {
|
|
804
729
|
const object = {
|
|
730
|
+
typeId: this.typeId,
|
|
805
731
|
bytecodeTemplate: this.bytecodeTemplate,
|
|
806
732
|
fieldsSig: this.fieldsSig,
|
|
807
733
|
functions: this.functions
|