@alephium/web3 0.2.0-test.0 → 0.2.0

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.
Files changed (126) hide show
  1. package/.eslintignore +2 -2
  2. package/README.md +2 -135
  3. package/dist/alephium-web3.min.js +1 -1
  4. package/dist/alephium-web3.min.js.LICENSE.txt +0 -17
  5. package/dist/alephium-web3.min.js.map +1 -1
  6. package/dist/src/api/api-alephium.d.ts +152 -24
  7. package/dist/src/api/api-alephium.js +163 -82
  8. package/dist/src/api/api-explorer.d.ts +192 -49
  9. package/dist/src/api/api-explorer.js +195 -34
  10. package/dist/src/api/index.d.ts +40 -5
  11. package/dist/src/api/index.js +115 -7
  12. package/dist/src/api/types.d.ts +23 -0
  13. package/dist/src/api/types.js +235 -0
  14. package/dist/src/api/utils.d.ts +6 -0
  15. package/dist/{scripts/rename-gitignore.js → src/api/utils.js} +11 -6
  16. package/dist/src/contract/contract.d.ts +127 -80
  17. package/dist/src/contract/contract.js +425 -467
  18. package/dist/src/contract/events.d.ts +4 -4
  19. package/dist/src/contract/events.js +2 -1
  20. package/dist/src/contract/index.js +5 -1
  21. package/dist/src/contract/ralph.d.ts +5 -4
  22. package/dist/src/contract/ralph.js +27 -1
  23. package/dist/src/global.d.ts +7 -0
  24. package/dist/src/global.js +54 -0
  25. package/dist/src/index.d.ts +2 -0
  26. package/dist/src/index.js +23 -1
  27. package/dist/src/signer/index.d.ts +0 -1
  28. package/dist/src/signer/index.js +5 -2
  29. package/dist/src/signer/signer.d.ts +59 -60
  30. package/dist/src/signer/signer.js +99 -69
  31. package/dist/src/transaction/index.d.ts +0 -1
  32. package/dist/src/transaction/index.js +5 -2
  33. package/dist/src/transaction/status.d.ts +2 -1
  34. package/dist/src/transaction/status.js +2 -1
  35. package/dist/src/utils/bs58.d.ts +1 -0
  36. package/dist/src/utils/bs58.js +13 -1
  37. package/dist/src/utils/index.d.ts +0 -1
  38. package/dist/src/utils/index.js +5 -2
  39. package/dist/src/utils/subscription.d.ts +0 -3
  40. package/dist/src/utils/subscription.js +0 -1
  41. package/dist/src/utils/utils.d.ts +6 -11
  42. package/dist/src/utils/utils.js +22 -26
  43. package/jest-config.json +11 -0
  44. package/package.json +11 -47
  45. package/src/api/api-alephium.ts +219 -33
  46. package/src/api/api-explorer.ts +275 -52
  47. package/src/api/index.ts +140 -6
  48. package/src/api/types.ts +229 -0
  49. package/{scripts/rename-gitignore.js → src/api/utils.ts} +7 -6
  50. package/src/contract/contract.ts +663 -581
  51. package/src/contract/events.ts +8 -7
  52. package/src/contract/ralph.ts +29 -4
  53. package/src/global.ts +56 -0
  54. package/src/index.ts +7 -0
  55. package/src/signer/index.ts +0 -1
  56. package/src/signer/signer.ts +165 -134
  57. package/src/transaction/index.ts +0 -1
  58. package/src/transaction/status.ts +6 -3
  59. package/src/utils/bs58.ts +11 -0
  60. package/src/utils/index.ts +0 -1
  61. package/src/utils/subscription.ts +1 -5
  62. package/src/utils/utils.ts +15 -23
  63. package/webpack.config.js +3 -0
  64. package/.eslintrc.json +0 -21
  65. package/LICENSE +0 -165
  66. package/contracts/add/add.ral +0 -16
  67. package/contracts/greeter/greeter.ral +0 -7
  68. package/contracts/greeter/greeter_interface.ral +0 -3
  69. package/contracts/greeter_main.ral +0 -9
  70. package/contracts/main.ral +0 -6
  71. package/contracts/sub/sub.ral +0 -9
  72. package/dev/user.conf +0 -29
  73. package/dist/scripts/create-project.d.ts +0 -2
  74. package/dist/scripts/create-project.js +0 -124
  75. package/dist/scripts/rename-gitignore.d.ts +0 -1
  76. package/dist/scripts/start-devnet.d.ts +0 -1
  77. package/dist/scripts/start-devnet.js +0 -131
  78. package/dist/scripts/stop-devnet.d.ts +0 -1
  79. package/dist/scripts/stop-devnet.js +0 -32
  80. package/dist/src/signer/node-wallet.d.ts +0 -13
  81. package/dist/src/signer/node-wallet.js +0 -60
  82. package/dist/src/test/index.d.ts +0 -7
  83. package/dist/src/test/index.js +0 -41
  84. package/dist/src/test/privatekey-wallet.d.ts +0 -12
  85. package/dist/src/test/privatekey-wallet.js +0 -68
  86. package/dist/src/transaction/sign-verify.d.ts +0 -2
  87. package/dist/src/transaction/sign-verify.js +0 -58
  88. package/dist/src/utils/password-crypto.d.ts +0 -2
  89. package/dist/src/utils/password-crypto.js +0 -69
  90. package/gitignore +0 -10
  91. package/scripts/create-project.ts +0 -136
  92. package/scripts/start-devnet.js +0 -141
  93. package/scripts/stop-devnet.js +0 -32
  94. package/src/contract/ralph.test.ts +0 -178
  95. package/src/fixtures/address.json +0 -36
  96. package/src/fixtures/balance.json +0 -9
  97. package/src/fixtures/self-clique.json +0 -19
  98. package/src/fixtures/transaction.json +0 -13
  99. package/src/fixtures/transactions.json +0 -179
  100. package/src/signer/fixtures/genesis.json +0 -26
  101. package/src/signer/fixtures/wallets.json +0 -26
  102. package/src/signer/node-wallet.ts +0 -74
  103. package/src/test/index.ts +0 -32
  104. package/src/test/privatekey-wallet.ts +0 -58
  105. package/src/transaction/sign-verify.test.ts +0 -50
  106. package/src/transaction/sign-verify.ts +0 -39
  107. package/src/utils/address.test.ts +0 -47
  108. package/src/utils/djb2.test.ts +0 -35
  109. package/src/utils/password-crypto.test.ts +0 -27
  110. package/src/utils/password-crypto.ts +0 -77
  111. package/src/utils/utils.test.ts +0 -161
  112. package/templates/base/README.md +0 -34
  113. package/templates/base/package.json +0 -35
  114. package/templates/base/src/greeter.ts +0 -41
  115. package/templates/base/tsconfig.json +0 -19
  116. package/templates/react/README.md +0 -34
  117. package/templates/react/config-overrides.js +0 -18
  118. package/templates/react/package.json +0 -66
  119. package/templates/react/src/App.tsx +0 -42
  120. package/templates/react/src/artifacts/greeter.ral.json +0 -26
  121. package/templates/react/src/artifacts/greeter_main.ral.json +0 -22
  122. package/templates/shared/.eslintrc.json +0 -12
  123. package/templates/shared/scripts/header.js +0 -0
  124. package/test/contract.test.ts +0 -178
  125. package/test/events.test.ts +0 -138
  126. package/test/transaction.test.ts +0 -72
@@ -17,250 +17,560 @@ along with the library. If not, see <http://www.gnu.org/licenses/>.
17
17
  */
18
18
 
19
19
  import { Buffer } from 'buffer/'
20
- import * as cryptojs from 'crypto-js'
21
- import * as crypto from 'crypto'
20
+ import { webcrypto as crypto } from 'crypto'
22
21
  import fs from 'fs'
23
22
  import { promises as fsPromises } from 'fs'
24
- import { NodeProvider } from '../api'
25
- import { node } from '../api'
26
- import { SignDeployContractTxParams, SignExecuteScriptTxParams, SignerWithNodeProvider } from '../signer'
23
+ import {
24
+ fromApiArray,
25
+ fromApiNumber256,
26
+ toApiNumber256,
27
+ NamedVals,
28
+ node,
29
+ NodeProvider,
30
+ Number256,
31
+ toApiToken,
32
+ toApiVal,
33
+ Token,
34
+ Val,
35
+ fromApiTokens,
36
+ fromApiVals
37
+ } from '../api'
38
+ import {
39
+ SignDeployContractTxParams,
40
+ SignExecuteScriptTxParams,
41
+ SignerProvider,
42
+ SignExecuteScriptTxResult,
43
+ SignDeployContractTxResult
44
+ } from '../signer'
27
45
  import * as ralph from './ralph'
28
46
  import { bs58, binToHex, contractIdFromAddress, assertType, Eq } from '../utils'
47
+ import { getCurrentNodeProvider } from '../global'
48
+ import { web3 } from '..'
49
+
50
+ export type FieldsSig = node.FieldsSig
51
+ export type EventSig = node.EventSig
52
+ export type FunctionSig = node.FunctionSig
53
+ export type Fields = NamedVals
54
+ export type Arguments = NamedVals
55
+
56
+ enum SourceType {
57
+ Contract = 0,
58
+ Script = 1,
59
+ AbstractContract = 2,
60
+ Interface = 3
61
+ }
62
+
63
+ export type CompilerOptions = node.CompilerOptions & {
64
+ errorOnWarnings: boolean
65
+ }
66
+
67
+ export const DEFAULT_NODE_COMPILER_OPTIONS: node.CompilerOptions = {
68
+ ignoreUnusedConstantsWarnings: false,
69
+ ignoreUnusedVariablesWarnings: false,
70
+ ignoreUnusedFieldsWarnings: false,
71
+ ignoreUnusedPrivateFunctionsWarnings: false,
72
+ ignoreReadonlyCheckWarnings: false,
73
+ ignoreExternalCallCheckWarnings: false
74
+ }
75
+
76
+ export const DEFAULT_COMPILER_OPTIONS: CompilerOptions = { errorOnWarnings: true, ...DEFAULT_NODE_COMPILER_OPTIONS }
77
+
78
+ class TypedMatcher<T extends SourceType> {
79
+ matcher: RegExp
80
+ type: T
81
+
82
+ constructor(pattern: string, type: T) {
83
+ this.matcher = new RegExp(pattern, 'mg')
84
+ this.type = type
85
+ }
86
+
87
+ match(str: string): number {
88
+ const results = str.match(this.matcher)
89
+ return results === null ? 0 : results.length
90
+ }
91
+ }
29
92
 
30
93
  class SourceFile {
31
- readonly dirs: string[]
32
- readonly dirPath: string
33
- readonly contractPath: string
34
- readonly artifactPath: string
35
-
36
- constructor(dirs: string[], fileName: string) {
37
- this.dirs = dirs
38
- this.dirPath = dirs.length === 0 ? '' : dirs.join('/') + '/'
39
- if (fileName.endsWith('.json')) {
40
- this.contractPath = './contracts/' + this.dirPath + fileName.slice(0, -5)
41
- this.artifactPath = './artifacts/' + this.dirPath + fileName
42
- } else {
43
- this.contractPath = './contracts/' + this.dirPath + fileName
44
- this.artifactPath = './artifacts/' + this.dirPath + fileName + '.json'
45
- }
94
+ type: SourceType
95
+ contractPath: string
96
+ sourceCode: string
97
+ sourceCodeHash: string
98
+
99
+ getArtifactPath(artifactsRootDir: string): string {
100
+ return artifactsRootDir + this.contractPath.slice(this.contractPath.indexOf('/')) + '.json'
101
+ }
102
+
103
+ constructor(type: SourceType, sourceCode: string, sourceCodeHash: string, contractPath: string) {
104
+ this.type = type
105
+ this.sourceCode = sourceCode
106
+ this.sourceCodeHash = sourceCodeHash
107
+ this.contractPath = contractPath
108
+ }
109
+
110
+ static async from(type: SourceType, sourceCode: string, contractPath: string): Promise<SourceFile> {
111
+ const sourceCodeHash = await crypto.subtle.digest('SHA-256', Buffer.from(sourceCode))
112
+ return new SourceFile(type, sourceCode, Buffer.from(sourceCodeHash).toString('hex'), contractPath)
46
113
  }
47
114
  }
48
115
 
49
- export abstract class Common {
50
- readonly sourceCodeSha256: string
51
- readonly functions: node.FunctionSig[]
52
-
53
- static readonly importRegex = new RegExp('^import "([^"/]+/(([^"]+)/)?)?[a-z][a-z_0-9]*.ral"', 'mg')
54
- static readonly contractRegex = new RegExp('^TxContract [A-Z][a-zA-Z0-9]*', 'mg')
55
- static readonly interfaceRegex = new RegExp('^Interface [A-Z][a-zA-Z0-9]* \\{', 'mg')
56
- static readonly scriptRegex = new RegExp('^TxScript [A-Z][a-zA-Z0-9]*', 'mg')
57
-
58
- private static _artifactCache: Map<string, Contract | Script> = new Map<string, Contract | Script>()
59
- static artifactCacheCapacity = 20
60
- protected static _getArtifactFromCache(codeHash: string): Contract | Script | undefined {
61
- return this._artifactCache.get(codeHash)
62
- }
63
- protected static _putArtifactToCache(contract: Contract): void {
64
- if (!this._artifactCache.has(contract.codeHash)) {
65
- if (this._artifactCache.size >= this.artifactCacheCapacity) {
66
- const keyToDelete = this._artifactCache.keys().next().value
67
- this._artifactCache.delete(keyToDelete)
68
- }
69
- this._artifactCache.set(contract.codeHash, contract)
116
+ class Compiled<T extends Artifact> {
117
+ sourceFile: SourceFile
118
+ artifact: T
119
+ warnings: string[]
120
+
121
+ constructor(sourceFile: SourceFile, artifact: T, warnings: string[]) {
122
+ this.sourceFile = sourceFile
123
+ this.artifact = artifact
124
+ this.warnings = warnings
125
+ }
126
+ }
127
+
128
+ type CodeInfo = { sourceCodeHash: string; bytecodeDebugPatch: string; codeHashDebug: string; warnings: string[] }
129
+
130
+ class ProjectArtifact {
131
+ static readonly artifactFileName = '.project.json'
132
+
133
+ compilerOptionsUsed: node.CompilerOptions
134
+ infos: Map<string, CodeInfo>
135
+
136
+ static checkCompilerOptionsParameter(compilerOptions: node.CompilerOptions): void {
137
+ if (Object.keys(compilerOptions).length != Object.keys(DEFAULT_NODE_COMPILER_OPTIONS).length) {
138
+ throw Error(`Not all compiler options are set: ${compilerOptions}`)
139
+ }
140
+
141
+ const combined = { ...compilerOptions, ...DEFAULT_NODE_COMPILER_OPTIONS }
142
+ if (Object.keys(combined).length !== Object.keys(DEFAULT_NODE_COMPILER_OPTIONS).length) {
143
+ throw Error(`There are unknown compiler options: ${compilerOptions}`)
70
144
  }
71
145
  }
72
146
 
73
- constructor(sourceCodeSha256: string, functions: node.FunctionSig[]) {
74
- this.sourceCodeSha256 = sourceCodeSha256
75
- this.functions = functions
147
+ constructor(compilerOptionsUsed: node.CompilerOptions, infos: Map<string, CodeInfo>) {
148
+ ProjectArtifact.checkCompilerOptionsParameter(compilerOptionsUsed)
149
+ this.compilerOptionsUsed = compilerOptionsUsed
150
+ this.infos = infos
76
151
  }
77
152
 
78
- protected static _artifactsFolder(): string {
79
- return './artifacts/'
153
+ async saveToFile(rootPath: string): Promise<void> {
154
+ const filepath = rootPath + '/' + ProjectArtifact.artifactFileName
155
+ const artifact = { compilerOptionsUsed: this.compilerOptionsUsed, infos: Object.fromEntries(this.infos) }
156
+ const content = JSON.stringify(artifact, null, 2)
157
+ return fsPromises.writeFile(filepath, content)
80
158
  }
81
159
 
82
- static getSourceFile(path: string, _dirs: string[]): SourceFile {
83
- const parts = path.split('/')
84
- const dirs = Array.from(_dirs)
85
- if (parts.length === 1) {
86
- return new SourceFile(dirs, path)
160
+ needToReCompile(compilerOptions: node.CompilerOptions, files: SourceFile[]): boolean {
161
+ ProjectArtifact.checkCompilerOptionsParameter(compilerOptions)
162
+
163
+ const optionsMatched = Object.entries(compilerOptions).every(([key, inputOption]) => {
164
+ const usedOption = this.compilerOptionsUsed[`${key}`]
165
+ return usedOption === inputOption
166
+ })
167
+ if (!optionsMatched) {
168
+ return true
87
169
  }
88
- parts.slice(0, parts.length - 1).forEach((part) => {
89
- switch (part) {
90
- case '.': {
91
- break
92
- }
93
- case '..': {
94
- if (dirs.length === 0) {
95
- throw new Error('Invalid file path: ' + path)
96
- }
97
- dirs.pop()
98
- break
99
- }
100
- default: {
101
- dirs.push(part)
102
- }
170
+
171
+ if (files.length !== this.infos.size) {
172
+ return true
173
+ }
174
+ for (const file of files) {
175
+ const info = this.infos.get(file.contractPath)
176
+ if (typeof info === 'undefined' || info.sourceCodeHash !== file.sourceCodeHash) {
177
+ return true
103
178
  }
179
+ }
180
+
181
+ return false
182
+ }
183
+
184
+ static async from(rootPath: string): Promise<ProjectArtifact | undefined> {
185
+ const filepath = rootPath + '/' + ProjectArtifact.artifactFileName
186
+ if (!fs.existsSync(filepath)) {
187
+ return undefined
188
+ }
189
+ const content = await fsPromises.readFile(filepath)
190
+ const json = JSON.parse(content.toString())
191
+ const compilerOptionsUsed = json.compilerOptionsUsed as node.CompilerOptions
192
+ const files = new Map(Object.entries<CodeInfo>(json.infos))
193
+ return new ProjectArtifact(compilerOptionsUsed, files)
194
+ }
195
+ }
196
+
197
+ export class Project {
198
+ sourceFiles: SourceFile[]
199
+ contracts: Compiled<Contract>[]
200
+ scripts: Compiled<Script>[]
201
+ projectArtifact: ProjectArtifact
202
+
203
+ readonly contractsRootDir: string
204
+ readonly artifactsRootDir: string
205
+
206
+ static currentProject: Project
207
+
208
+ static readonly abstractContractMatcher = new TypedMatcher<SourceType>(
209
+ '^Abstract Contract [A-Z][a-zA-Z0-9]*',
210
+ SourceType.AbstractContract
211
+ )
212
+ static readonly contractMatcher = new TypedMatcher('^Contract [A-Z][a-zA-Z0-9]*', SourceType.Contract)
213
+ static readonly interfaceMatcher = new TypedMatcher('^Interface [A-Z][a-zA-Z0-9]* \\{', SourceType.Interface)
214
+ static readonly scriptMatcher = new TypedMatcher('^TxScript [A-Z][a-zA-Z0-9]*', SourceType.Script)
215
+ static readonly matchers = [
216
+ Project.abstractContractMatcher,
217
+ Project.contractMatcher,
218
+ Project.interfaceMatcher,
219
+ Project.scriptMatcher
220
+ ]
221
+
222
+ static buildProjectArtifact(
223
+ sourceFiles: SourceFile[],
224
+ contracts: Compiled<Contract>[],
225
+ scripts: Compiled<Script>[],
226
+ compilerOptions: node.CompilerOptions
227
+ ): ProjectArtifact {
228
+ const files: Map<string, CodeInfo> = new Map()
229
+ contracts.forEach((c) => {
230
+ files.set(c.sourceFile.contractPath, {
231
+ sourceCodeHash: c.sourceFile.sourceCodeHash,
232
+ bytecodeDebugPatch: c.artifact.bytecodeDebugPatch,
233
+ codeHashDebug: c.artifact.codeHashDebug,
234
+ warnings: c.warnings
235
+ })
104
236
  })
105
- return new SourceFile(dirs, parts[parts.length - 1])
106
- }
107
-
108
- protected static async _handleImports(
109
- pathes: string[],
110
- contractStr: string,
111
- importsCache: string[]
112
- ): Promise<string> {
113
- const localImportsCache: string[] = []
114
- let result = contractStr.replace(Common.importRegex, (match) => {
115
- localImportsCache.push(match)
116
- return ''
237
+ scripts.forEach((s) => {
238
+ files.set(s.sourceFile.contractPath, {
239
+ sourceCodeHash: s.sourceFile.sourceCodeHash,
240
+ bytecodeDebugPatch: s.artifact.bytecodeDebugPatch,
241
+ codeHashDebug: '',
242
+ warnings: s.warnings
243
+ })
117
244
  })
118
- for (const myImport of localImportsCache) {
119
- const relativePath = myImport.slice(8, -1)
120
- const importSourceFile = this.getSourceFile(relativePath, pathes)
121
- if (!importsCache.includes(importSourceFile.contractPath)) {
122
- importsCache.push(importSourceFile.contractPath)
123
- const importContractStr = await Common._loadContractStr(importSourceFile, importsCache, (code) =>
124
- Contract.checkCodeType(importSourceFile.contractPath, code)
125
- )
126
- result = result.concat('\n', importContractStr)
245
+ const compiledSize = contracts.length + scripts.length
246
+ sourceFiles.slice(compiledSize).forEach((c) => {
247
+ files.set(c.contractPath, {
248
+ sourceCodeHash: c.sourceCodeHash,
249
+ bytecodeDebugPatch: '',
250
+ codeHashDebug: '',
251
+ warnings: []
252
+ })
253
+ })
254
+ return new ProjectArtifact(compilerOptions, files)
255
+ }
256
+
257
+ private constructor(
258
+ contractsRootDir: string,
259
+ artifactsRootDir: string,
260
+ sourceFiles: SourceFile[],
261
+ contracts: Compiled<Contract>[],
262
+ scripts: Compiled<Script>[],
263
+ errorOnWarnings: boolean,
264
+ projectArtifact: ProjectArtifact
265
+ ) {
266
+ this.contractsRootDir = contractsRootDir
267
+ this.artifactsRootDir = artifactsRootDir
268
+ this.sourceFiles = sourceFiles
269
+ this.contracts = contracts
270
+ this.scripts = scripts
271
+ this.projectArtifact = projectArtifact
272
+
273
+ if (errorOnWarnings) {
274
+ Project.checkCompilerWarnings(
275
+ [...contracts.map((c) => c.warnings).flat(), ...scripts.map((s) => s.warnings).flat()],
276
+ errorOnWarnings
277
+ )
278
+ }
279
+ }
280
+
281
+ private getContractPath(path: string): string {
282
+ return path.startsWith(`./${this.contractsRootDir}`)
283
+ ? path.slice(2)
284
+ : path.startsWith(this.contractsRootDir)
285
+ ? path
286
+ : this.contractsRootDir + '/' + path
287
+ }
288
+
289
+ static checkCompilerWarnings(warnings: string[], errorOnWarnings: boolean): void {
290
+ if (warnings.length !== 0) {
291
+ const prefixPerWarning = ' - '
292
+ const warningString = prefixPerWarning + warnings.join('\n' + prefixPerWarning)
293
+ const output = `Compilation warnings:\n` + warningString + '\n'
294
+ if (errorOnWarnings) {
295
+ throw new Error(output)
296
+ } else {
297
+ console.log(output)
127
298
  }
128
299
  }
129
- return result
130
300
  }
131
301
 
132
- protected static async _loadContractStr(
133
- sourceFile: SourceFile,
134
- importsCache: string[],
135
- validate: (code: string) => void
136
- ): Promise<string> {
137
- const contractPath = sourceFile.contractPath
138
- const contractBuffer = await fsPromises.readFile(contractPath)
139
- const contractStr = contractBuffer.toString()
302
+ static contract(name: string): Contract {
303
+ const contract = Project.currentProject.contracts.find((c) => c.artifact.name === name)
304
+ if (typeof contract === 'undefined') {
305
+ throw new Error(`Contract "${name}" does not exist`)
306
+ }
307
+ return contract.artifact
308
+ }
309
+
310
+ static script(name: string): Script {
311
+ const script = Project.currentProject.scripts.find((c) => c.artifact.name === name)
312
+ if (typeof script === 'undefined') {
313
+ throw new Error(`Script "${name}" does not exist`)
314
+ }
315
+ return script.artifact
316
+ }
140
317
 
141
- validate(contractStr)
142
- return Common._handleImports(sourceFile.dirs, contractStr, importsCache)
318
+ private async saveArtifactsToFile(): Promise<void> {
319
+ const artifactsRootDir = this.artifactsRootDir
320
+ const saveToFile = async function (compiled: Compiled<Artifact>): Promise<void> {
321
+ const artifactDir = compiled.sourceFile.getArtifactPath(artifactsRootDir)
322
+ const folder = artifactDir.slice(0, artifactDir.lastIndexOf('/'))
323
+ if (!fs.existsSync(folder)) {
324
+ fs.mkdirSync(folder, { recursive: true })
325
+ }
326
+ return fsPromises.writeFile(artifactDir, compiled.artifact.toString())
327
+ }
328
+ for (const contract of this.contracts) {
329
+ saveToFile(contract)
330
+ }
331
+ for (const script of this.scripts) {
332
+ await saveToFile(script)
333
+ }
334
+ await this.projectArtifact.saveToFile(this.artifactsRootDir)
143
335
  }
144
336
 
145
- static checkFileNameExtension(fileName: string): void {
146
- if (!fileName.endsWith('.ral')) {
147
- throw new Error('Smart contract file name should end with ".ral"')
337
+ contractByCodeHash(codeHash: string): Contract {
338
+ const contract = this.contracts.find(
339
+ (c) => c.artifact.codeHash === codeHash || c.artifact.codeHashDebug == codeHash
340
+ )
341
+ if (typeof contract === 'undefined') {
342
+ throw new Error(`Unknown code with code hash: ${codeHash}`)
148
343
  }
344
+ return contract.artifact
149
345
  }
150
346
 
151
- protected static async _from<T extends { sourceCodeSha256: string }>(
347
+ private static async compile(
152
348
  provider: NodeProvider,
153
- sourceFile: SourceFile,
154
- loadContractStr: (sourceFile: SourceFile, importsCache: string[]) => Promise<string>,
155
- compile: (provider: NodeProvider, sourceFile: SourceFile, contractStr: string, contractHash: string) => Promise<T>
156
- ): Promise<T> {
157
- Common.checkFileNameExtension(sourceFile.contractPath)
158
-
159
- const contractStr = await loadContractStr(sourceFile, [])
160
- const contractHash = cryptojs.SHA256(contractStr).toString()
161
- const existingContract = this._getArtifactFromCache(contractHash)
162
- if (typeof existingContract !== 'undefined') {
163
- return existingContract as unknown as T
164
- } else {
165
- return compile(provider, sourceFile, contractStr, contractHash)
349
+ files: SourceFile[],
350
+ contractsRootDir: string,
351
+ artifactsRootDir: string,
352
+ errorOnWarnings: boolean,
353
+ compilerOptions: node.CompilerOptions
354
+ ): Promise<Project> {
355
+ const sourceStr = files.map((f) => f.sourceCode).join('\n')
356
+ const result = await provider.contracts.postContractsCompileProject({
357
+ code: sourceStr,
358
+ compilerOptions: compilerOptions
359
+ })
360
+ const contracts: Compiled<Contract>[] = []
361
+ const scripts: Compiled<Script>[] = []
362
+ result.contracts.forEach((contractResult, index) => {
363
+ const sourceFile = files[`${index}`]
364
+ const contract = Contract.fromCompileResult(contractResult)
365
+ contracts.push(new Compiled(sourceFile, contract, contractResult.warnings))
366
+ })
367
+ result.scripts.forEach((scriptResult, index) => {
368
+ const sourceFile = files[index + contracts.length]
369
+ const script = Script.fromCompileResult(scriptResult)
370
+ scripts.push(new Compiled(sourceFile, script, scriptResult.warnings))
371
+ })
372
+ const projectArtifact = Project.buildProjectArtifact(files, contracts, scripts, compilerOptions)
373
+ const project = new Project(
374
+ contractsRootDir,
375
+ artifactsRootDir,
376
+ files,
377
+ contracts,
378
+ scripts,
379
+ errorOnWarnings,
380
+ projectArtifact
381
+ )
382
+ await project.saveArtifactsToFile()
383
+ return project
384
+ }
385
+
386
+ private static async loadArtifacts(
387
+ provider: NodeProvider,
388
+ files: SourceFile[],
389
+ projectArtifact: ProjectArtifact,
390
+ contractsRootDir: string,
391
+ artifactsRootDir: string,
392
+ errorOnWarnings: boolean,
393
+ compilerOptions: node.CompilerOptions
394
+ ): Promise<Project> {
395
+ try {
396
+ const contracts: Compiled<Contract>[] = []
397
+ const scripts: Compiled<Script>[] = []
398
+ for (const file of files) {
399
+ const info = projectArtifact.infos.get(file.contractPath)
400
+ if (typeof info === 'undefined') {
401
+ throw Error(`Unable to find project info for ${file.contractPath}, please rebuild the project`)
402
+ }
403
+ const warnings = info.warnings
404
+ const artifactDir = file.getArtifactPath(artifactsRootDir)
405
+ if (file.type === SourceType.Contract) {
406
+ const artifact = await Contract.fromArtifactFile(artifactDir, info.bytecodeDebugPatch, info.codeHashDebug)
407
+ contracts.push(new Compiled(file, artifact, warnings))
408
+ } else if (file.type === SourceType.Script) {
409
+ const artifact = await Script.fromArtifactFile(artifactDir, info.bytecodeDebugPatch)
410
+ scripts.push(new Compiled(file, artifact, warnings))
411
+ }
412
+ }
413
+
414
+ return new Project(
415
+ contractsRootDir,
416
+ artifactsRootDir,
417
+ files,
418
+ contracts,
419
+ scripts,
420
+ errorOnWarnings,
421
+ projectArtifact
422
+ )
423
+ } catch (error) {
424
+ console.log(`Failed to load artifacts, error: ${error}, try to re-compile contracts...`)
425
+ return Project.compile(provider, files, contractsRootDir, artifactsRootDir, errorOnWarnings, compilerOptions)
166
426
  }
167
427
  }
168
428
 
169
- protected _saveToFile(sourceFile: SourceFile): Promise<void> {
170
- const folder = Common._artifactsFolder() + sourceFile.dirPath
171
- if (!fs.existsSync(folder)) {
172
- fs.mkdirSync(folder, { recursive: true })
429
+ private static async loadSourceFile(dirPath: string, filename: string): Promise<SourceFile> {
430
+ const contractPath = dirPath + '/' + filename
431
+ if (!filename.endsWith('.ral')) {
432
+ throw new Error(`Invalid filename: ${contractPath}, smart contract file name should end with ".ral"`)
433
+ }
434
+
435
+ const sourceBuffer = await fsPromises.readFile(contractPath)
436
+ const sourceStr = sourceBuffer.toString()
437
+ const results = this.matchers.map((m) => m.match(sourceStr))
438
+ const matchNumber = results.reduce((a, b) => a + b, 0)
439
+ if (matchNumber === 0) {
440
+ throw new Error(`No contract defined in file: ${contractPath}`)
441
+ }
442
+ if (matchNumber > 1) {
443
+ throw new Error(`Multiple definitions in file: ${contractPath}`)
444
+ }
445
+ const matcherIndex = results.indexOf(1)
446
+ const type = this.matchers[`${matcherIndex}`].type
447
+ return SourceFile.from(type, sourceStr, contractPath)
448
+ }
449
+
450
+ private static async loadSourceFiles(contractsRootDir: string): Promise<SourceFile[]> {
451
+ const loadDir = async function (dirPath: string, results: SourceFile[]): Promise<void> {
452
+ const dirents = await fsPromises.readdir(dirPath, { withFileTypes: true })
453
+ for (const dirent of dirents) {
454
+ if (dirent.isFile()) {
455
+ const file = await Project.loadSourceFile(dirPath, dirent.name)
456
+ results.push(file)
457
+ } else {
458
+ const newPath = dirPath + '/' + dirent.name
459
+ await loadDir(newPath, results)
460
+ }
461
+ }
462
+ }
463
+ const sourceFiles: SourceFile[] = []
464
+ await loadDir(contractsRootDir, sourceFiles)
465
+ const contractAndScriptSize = sourceFiles.filter(
466
+ (f) => f.type === SourceType.Contract || f.type === SourceType.Script
467
+ ).length
468
+ if (sourceFiles.length === 0 || contractAndScriptSize === 0) {
469
+ throw new Error('Project have no source files')
470
+ }
471
+ return sourceFiles.sort((a, b) => a.type - b.type)
472
+ }
473
+
474
+ static readonly DEFAULT_CONTRACTS_DIR = 'contracts'
475
+ static readonly DEFAULT_ARTIFACTS_DIR = 'artifacts'
476
+
477
+ static async build(
478
+ compilerOptionsPartial: Partial<CompilerOptions> = {},
479
+ contractsRootDir = Project.DEFAULT_CONTRACTS_DIR,
480
+ artifactsRootDir = Project.DEFAULT_ARTIFACTS_DIR
481
+ ): Promise<void> {
482
+ const provider = getCurrentNodeProvider()
483
+ const sourceFiles = await Project.loadSourceFiles(contractsRootDir)
484
+ const { errorOnWarnings, ...nodeCompilerOptions } = { ...DEFAULT_COMPILER_OPTIONS, ...compilerOptionsPartial }
485
+ const projectArtifact = await ProjectArtifact.from(artifactsRootDir)
486
+ if (typeof projectArtifact === 'undefined' || projectArtifact.needToReCompile(nodeCompilerOptions, sourceFiles)) {
487
+ console.log(`Compiling contracts in folder "${contractsRootDir}"`)
488
+ Project.currentProject = await Project.compile(
489
+ provider,
490
+ sourceFiles,
491
+ contractsRootDir,
492
+ artifactsRootDir,
493
+ errorOnWarnings,
494
+ nodeCompilerOptions
495
+ )
496
+ } else {
497
+ console.log(`Contracts are compiled already. Loading them from folder "${artifactsRootDir}"`)
498
+ Project.currentProject = await Project.loadArtifacts(
499
+ provider,
500
+ sourceFiles,
501
+ projectArtifact,
502
+ contractsRootDir,
503
+ artifactsRootDir,
504
+ errorOnWarnings,
505
+ nodeCompilerOptions
506
+ )
173
507
  }
174
- return fsPromises.writeFile(sourceFile.artifactPath, this.toString())
508
+ }
509
+ }
510
+
511
+ export abstract class Artifact {
512
+ readonly version: string
513
+ readonly name: string
514
+ readonly functions: FunctionSig[]
515
+
516
+ constructor(version: string, name: string, functions: FunctionSig[]) {
517
+ this.version = version
518
+ this.name = name
519
+ this.functions = functions
175
520
  }
176
521
 
177
522
  abstract buildByteCodeToDeploy(initialFields?: Fields): string
523
+
524
+ publicFunctions(): string[] {
525
+ return this.functions.filter((func) => func.isPublic).map((func) => func.name)
526
+ }
527
+
528
+ usingPreapprovedAssetsFunctions(): string[] {
529
+ return this.functions.filter((func) => func.usePreapprovedAssets).map((func) => func.name)
530
+ }
531
+
532
+ usingAssetsInContractFunctions(): string[] {
533
+ return this.functions.filter((func) => func.useAssetsInContract).map((func) => func.name)
534
+ }
178
535
  }
179
536
 
180
- export class Contract extends Common {
537
+ export class Contract extends Artifact {
181
538
  readonly bytecode: string
539
+ readonly bytecodeDebugPatch: string
182
540
  readonly codeHash: string
183
- readonly fieldsSig: node.FieldsSig
184
- readonly eventsSig: node.EventSig[]
541
+ readonly fieldsSig: FieldsSig
542
+ readonly eventsSig: EventSig[]
543
+
544
+ readonly bytecodeDebug: string
545
+ readonly codeHashDebug: string
185
546
 
186
547
  constructor(
187
- sourceCodeSha256: string,
548
+ version: string,
549
+ name: string,
188
550
  bytecode: string,
551
+ bytecodeDebugPatch: string,
189
552
  codeHash: string,
190
- fieldsSig: node.FieldsSig,
191
- eventsSig: node.EventSig[],
192
- functions: node.FunctionSig[]
553
+ codeHashDebug: string,
554
+ fieldsSig: FieldsSig,
555
+ eventsSig: EventSig[],
556
+ functions: FunctionSig[]
193
557
  ) {
194
- super(sourceCodeSha256, functions)
558
+ super(version, name, functions)
195
559
  this.bytecode = bytecode
560
+ this.bytecodeDebugPatch = bytecodeDebugPatch
196
561
  this.codeHash = codeHash
197
562
  this.fieldsSig = fieldsSig
198
563
  this.eventsSig = eventsSig
199
- }
200
564
 
201
- static checkCodeType(fileName: string, contractStr: string): void {
202
- const interfaceMatches = contractStr.match(Contract.interfaceRegex)
203
- const contractMatches = contractStr.match(Contract.contractRegex)
204
- if (interfaceMatches === null && contractMatches === null) {
205
- throw new Error(`No contract found in: ${fileName}`)
206
- }
207
- if (interfaceMatches && contractMatches) {
208
- throw new Error(`Multiple contracts and interfaces in: ${fileName}`)
209
- }
210
- if (interfaceMatches === null) {
211
- if (contractMatches !== null && contractMatches.length > 1) {
212
- throw new Error(`Multiple contracts in: ${fileName}`)
213
- }
214
- }
215
- if (contractMatches === null) {
216
- if (interfaceMatches !== null && interfaceMatches.length > 1) {
217
- throw new Error(`Multiple interfaces in: ${fileName}`)
218
- }
219
- }
220
- }
221
-
222
- private static async loadContractStr(sourceFile: SourceFile): Promise<string> {
223
- return Common._loadContractStr(sourceFile, [], (code) => Contract.checkCodeType(sourceFile.contractPath, code))
224
- }
225
-
226
- static async fromSource(provider: NodeProvider, path: string): Promise<Contract> {
227
- if (!fs.existsSync(Common._artifactsFolder())) {
228
- fs.mkdirSync(Common._artifactsFolder(), { recursive: true })
229
- }
230
- const sourceFile = this.getSourceFile(path, [])
231
- const contract = await Common._from(
232
- provider,
233
- sourceFile,
234
- (sourceFile) => Contract.loadContractStr(sourceFile),
235
- Contract.compile
236
- )
237
- this._putArtifactToCache(contract)
238
- return contract
239
- }
240
-
241
- private static async compile(
242
- provider: NodeProvider,
243
- sourceFile: SourceFile,
244
- contractStr: string,
245
- contractHash: string
246
- ): Promise<Contract> {
247
- const compiled = await provider.contracts.postContractsCompileContract({ code: contractStr })
248
- const artifact = new Contract(
249
- contractHash,
250
- compiled.bytecode,
251
- compiled.codeHash,
252
- compiled.fields,
253
- compiled.events,
254
- compiled.functions
255
- )
256
- await artifact._saveToFile(sourceFile)
257
- return artifact
565
+ this.bytecodeDebug = ralph.buildDebugBytecode(this.bytecode, this.bytecodeDebugPatch)
566
+ this.codeHashDebug = codeHashDebug
258
567
  }
259
568
 
260
569
  // TODO: safely parse json
261
- static fromJson(artifact: any): Contract {
570
+ static fromJson(artifact: any, bytecodeDebugPatch = '', codeHashDebug = ''): Contract {
262
571
  if (
263
- artifact.sourceCodeSha256 == null ||
572
+ artifact.version == null ||
573
+ artifact.name == null ||
264
574
  artifact.bytecode == null ||
265
575
  artifact.codeHash == null ||
266
576
  artifact.fieldsSig == null ||
@@ -270,44 +580,58 @@ export class Contract extends Common {
270
580
  throw Error('The artifact JSON for contract is incomplete')
271
581
  }
272
582
  const contract = new Contract(
273
- artifact.sourceCodeSha256,
583
+ artifact.version,
584
+ artifact.name,
274
585
  artifact.bytecode,
586
+ bytecodeDebugPatch,
275
587
  artifact.codeHash,
588
+ codeHashDebug ? codeHashDebug : artifact.codeHash,
276
589
  artifact.fieldsSig,
277
590
  artifact.eventsSig,
278
591
  artifact.functions
279
592
  )
280
- this._putArtifactToCache(contract)
281
593
  return contract
282
594
  }
283
595
 
596
+ static fromCompileResult(result: node.CompileContractResult): Contract {
597
+ return new Contract(
598
+ result.version,
599
+ result.name,
600
+ result.bytecode,
601
+ result.bytecodeDebugPatch,
602
+ result.codeHash,
603
+ result.codeHashDebug,
604
+ result.fields,
605
+ result.events,
606
+ result.functions
607
+ )
608
+ }
609
+
284
610
  // support both 'code.ral' and 'code.ral.json'
285
- static async fromArtifactFile(path: string): Promise<Contract> {
286
- const sourceFile = this.getSourceFile(path, [])
287
- const artifactPath = sourceFile.artifactPath
288
- const content = await fsPromises.readFile(artifactPath)
611
+ static async fromArtifactFile(path: string, bytecodeDebugPatch: string, codeHashDebug: string): Promise<Contract> {
612
+ const content = await fsPromises.readFile(path)
289
613
  const artifact = JSON.parse(content.toString())
290
- return Contract.fromJson(artifact)
614
+ return Contract.fromJson(artifact, bytecodeDebugPatch, codeHashDebug)
291
615
  }
292
616
 
293
- async fetchState(provider: NodeProvider, address: string, group: number): Promise<ContractState> {
294
- const state = await provider.contracts.getContractsAddressState(address, { group: group })
617
+ async fetchState(address: string, group: number): Promise<ContractState> {
618
+ const state = await web3.getCurrentNodeProvider().contracts.getContractsAddressState(address, {
619
+ group: group
620
+ })
295
621
  return this.fromApiContractState(state)
296
622
  }
297
623
 
298
624
  override toString(): string {
299
- return JSON.stringify(
300
- {
301
- sourceCodeSha256: this.sourceCodeSha256,
302
- bytecode: this.bytecode,
303
- codeHash: this.codeHash,
304
- fieldsSig: this.fieldsSig,
305
- eventsSig: this.eventsSig,
306
- functions: this.functions
307
- },
308
- null,
309
- 2
310
- )
625
+ const object = {
626
+ version: this.version,
627
+ name: this.name,
628
+ bytecode: this.bytecode,
629
+ codeHash: this.codeHash,
630
+ fieldsSig: this.fieldsSig,
631
+ eventsSig: this.eventsSig,
632
+ functions: this.functions
633
+ }
634
+ return JSON.stringify(object, null, 2)
311
635
  }
312
636
 
313
637
  toState(fields: Fields, asset: Asset, address?: string): ContractState {
@@ -323,25 +647,37 @@ export class Contract extends Common {
323
647
  }
324
648
  }
325
649
 
650
+ // no need to be cryptographically strong random
326
651
  static randomAddress(): string {
327
- const bytes = crypto.randomBytes(33)
652
+ const bytes = new Uint8Array(33)
653
+ crypto.getRandomValues(bytes)
328
654
  bytes[0] = 3
329
655
  return bs58.encode(bytes)
330
656
  }
331
657
 
658
+ private _printDebugMessages(funcName: string, messages: DebugMessage[]) {
659
+ if (messages.length != 0) {
660
+ console.log(`Testing ${this.name}.${funcName}:`)
661
+ messages.forEach((m) => console.log(`Debug - ${m.contractAddress} - ${m.message}`))
662
+ }
663
+ }
664
+
332
665
  private async _test(
333
- provider: NodeProvider,
334
666
  funcName: string,
335
667
  params: TestContractParams,
336
668
  expectPublic: boolean,
337
- accessType: string
669
+ accessType: string,
670
+ printDebugMessages: boolean
338
671
  ): Promise<TestContractResult> {
339
672
  const apiParams: node.TestContract = this.toTestContract(funcName, params)
340
- const apiResult = await provider.contracts.postContractsTestContract(apiParams)
673
+ const apiResult = await web3.getCurrentNodeProvider().contracts.postContractsTestContract(apiParams)
341
674
 
342
675
  const methodIndex =
343
676
  typeof params.testMethodIndex !== 'undefined' ? params.testMethodIndex : this.getMethodIndex(funcName)
344
- const isPublic = this.functions[`${methodIndex}`].signature.indexOf('pub ') !== -1
677
+ const isPublic = this.functions[`${methodIndex}`].isPublic
678
+ if (printDebugMessages) {
679
+ this._printDebugMessages(funcName, apiResult.debugMessages)
680
+ }
345
681
  if (isPublic === expectPublic) {
346
682
  const result = await this.fromTestContractResult(methodIndex, apiResult)
347
683
  return result
@@ -351,19 +687,19 @@ export class Contract extends Common {
351
687
  }
352
688
 
353
689
  async testPublicMethod(
354
- provider: NodeProvider,
355
690
  funcName: string,
356
- params: TestContractParams
691
+ params: TestContractParams,
692
+ printDebugMessages = true
357
693
  ): Promise<TestContractResult> {
358
- return this._test(provider, funcName, params, true, 'public')
694
+ return this._test(funcName, params, true, 'public', printDebugMessages)
359
695
  }
360
696
 
361
697
  async testPrivateMethod(
362
- provider: NodeProvider,
363
698
  funcName: string,
364
- params: TestContractParams
699
+ params: TestContractParams,
700
+ printDebugMessages = true
365
701
  ): Promise<TestContractResult> {
366
- return this._test(provider, funcName, params, false, 'private')
702
+ return this._test(funcName, params, false, 'private', printDebugMessages)
367
703
  }
368
704
 
369
705
  toApiFields(fields?: Fields): node.Val[] {
@@ -399,7 +735,7 @@ export class Contract extends Common {
399
735
  return {
400
736
  group: params.group,
401
737
  address: params.address,
402
- bytecode: this.bytecode,
738
+ bytecode: this.bytecodeDebug,
403
739
  initialFields: this.toApiFields(params.initialFields),
404
740
  initialAsset: typeof params.initialAsset !== 'undefined' ? toApiAsset(params.initialAsset) : undefined,
405
741
  methodIndex: this.getMethodIndex(funcName),
@@ -409,33 +745,8 @@ export class Contract extends Common {
409
745
  }
410
746
  }
411
747
 
412
- static async fromCodeHash(codeHash: string): Promise<Contract> {
413
- const cached = this._getArtifactFromCache(codeHash)
414
- if (typeof cached !== 'undefined') {
415
- return cached as Contract
416
- }
417
-
418
- const files = await fsPromises.readdir(Common._artifactsFolder())
419
- for (const file of files) {
420
- if (file.endsWith('.ral.json')) {
421
- try {
422
- const contract = await Contract.fromArtifactFile(file)
423
- if (contract.codeHash === codeHash) {
424
- return contract as Contract
425
- }
426
- } catch (_) {}
427
- }
428
- }
429
-
430
- throw new Error(`Unknown code with code hash: ${codeHash}`)
431
- }
432
-
433
- static async getFieldsSig(state: node.ContractState): Promise<node.FieldsSig> {
434
- return Contract.fromCodeHash(state.codeHash).then((contract) => contract.fieldsSig)
435
- }
436
-
437
- async fromApiContractState(state: node.ContractState): Promise<ContractState> {
438
- const contract = await Contract.fromCodeHash(state.codeHash)
748
+ fromApiContractState(state: node.ContractState): ContractState {
749
+ const contract = Project.currentProject.contractByCodeHash(state.codeHash)
439
750
  return {
440
751
  address: state.address,
441
752
  contractId: binToHex(contractIdFromAddress(state.address)),
@@ -443,37 +754,32 @@ export class Contract extends Common {
443
754
  initialStateHash: state.initialStateHash,
444
755
  codeHash: state.codeHash,
445
756
  fields: fromApiFields(state.fields, contract.fieldsSig),
446
- fieldsSig: await Contract.getFieldsSig(state),
757
+ fieldsSig: contract.fieldsSig,
447
758
  asset: fromApiAsset(state.asset)
448
759
  }
449
760
  }
450
761
 
451
- static ContractCreatedEvent: node.EventSig = {
762
+ static ContractCreatedEvent: EventSig = {
452
763
  name: 'ContractCreated',
453
- signature: 'event ContractCreated(address:Address)',
454
764
  fieldNames: ['address'],
455
765
  fieldTypes: ['Address']
456
766
  }
457
767
 
458
- static ContractDestroyedEvent: node.EventSig = {
768
+ static ContractDestroyedEvent: EventSig = {
459
769
  name: 'ContractDestroyed',
460
- signature: 'event ContractDestroyed(address:Address)',
461
770
  fieldNames: ['address'],
462
771
  fieldTypes: ['Address']
463
772
  }
464
773
 
465
- static async fromApiEvent(
466
- event: node.ContractEventByTxId,
467
- codeHash: string | undefined
468
- ): Promise<ContractEventByTxId> {
469
- let eventSig: node.EventSig
774
+ static fromApiEvent(event: node.ContractEventByTxId, codeHash: string | undefined): ContractEventByTxId {
775
+ let eventSig: EventSig
470
776
 
471
777
  if (event.eventIndex == -1) {
472
778
  eventSig = this.ContractCreatedEvent
473
779
  } else if (event.eventIndex == -2) {
474
780
  eventSig = this.ContractDestroyedEvent
475
781
  } else {
476
- const contract = await Contract.fromCodeHash(codeHash!)
782
+ const contract = Project.currentProject.contractByCodeHash(codeHash!)
477
783
  eventSig = contract.eventsSig[event.eventIndex]
478
784
  }
479
785
 
@@ -485,55 +791,53 @@ export class Contract extends Common {
485
791
  }
486
792
  }
487
793
 
488
- async fromTestContractResult(methodIndex: number, result: node.TestContractResult): Promise<TestContractResult> {
794
+ fromTestContractResult(methodIndex: number, result: node.TestContractResult): TestContractResult {
489
795
  const addressToCodeHash = new Map<string, string>()
490
796
  addressToCodeHash.set(result.address, result.codeHash)
491
797
  result.contracts.forEach((contract) => addressToCodeHash.set(contract.address, contract.codeHash))
492
798
  return {
493
- address: result.address,
494
799
  contractId: binToHex(contractIdFromAddress(result.address)),
800
+ contractAddress: result.address,
495
801
  returns: fromApiArray(result.returns, this.functions[`${methodIndex}`].returnTypes),
496
802
  gasUsed: result.gasUsed,
497
- contracts: await Promise.all(result.contracts.map((contract) => this.fromApiContractState(contract))),
803
+ contracts: result.contracts.map((contract) => this.fromApiContractState(contract)),
498
804
  txOutputs: result.txOutputs.map(fromApiOutput),
499
- events: await Promise.all(
500
- result.events.map((event) => {
501
- const contractAddress = event.contractAddress
502
- const codeHash = addressToCodeHash.get(contractAddress)
503
- if (typeof codeHash !== 'undefined' || event.eventIndex < 0) {
504
- return Contract.fromApiEvent(event, codeHash)
505
- } else {
506
- throw Error(`Cannot find codeHash for the contract address: ${contractAddress}`)
507
- }
508
- })
509
- )
805
+ events: result.events.map((event) => {
806
+ const contractAddress = event.contractAddress
807
+ const codeHash = addressToCodeHash.get(contractAddress)
808
+ if (typeof codeHash !== 'undefined' || event.eventIndex < 0) {
809
+ return Contract.fromApiEvent(event, codeHash)
810
+ } else {
811
+ throw Error(`Cannot find codeHash for the contract address: ${contractAddress}`)
812
+ }
813
+ }),
814
+ debugMessages: result.debugMessages
510
815
  }
511
816
  }
512
817
 
513
- async paramsForDeployment(params: BuildDeployContractTx): Promise<SignDeployContractTxParams> {
818
+ async txParamsForDeployment(
819
+ signer: SignerProvider,
820
+ params: Omit<BuildDeployContractTx, 'signerAddress'>
821
+ ): Promise<SignDeployContractTxParams> {
514
822
  const bytecode = this.buildByteCodeToDeploy(params.initialFields ? params.initialFields : {})
515
823
  const signerParams: SignDeployContractTxParams = {
516
- signerAddress: params.signerAddress,
824
+ signerAddress: (await signer.getSelectedAccount()).address,
517
825
  bytecode: bytecode,
518
- initialAttoAlphAmount: extractOptionalNumber256(params.initialAttoAlphAmount),
519
- issueTokenAmount: extractOptionalNumber256(params.issueTokenAmount),
520
- initialTokenAmounts: params.initialTokenAmounts?.map(toApiToken),
826
+ initialAttoAlphAmount: params.initialAttoAlphAmount,
827
+ issueTokenAmount: params.issueTokenAmount,
828
+ initialTokenAmounts: params.initialTokenAmounts,
521
829
  gasAmount: params.gasAmount,
522
- gasPrice: extractOptionalNumber256(params.gasPrice)
830
+ gasPrice: params.gasPrice
523
831
  }
524
832
  return signerParams
525
833
  }
526
834
 
527
- async transactionForDeployment(
528
- signer: SignerWithNodeProvider,
835
+ async deploy(
836
+ signer: SignerProvider,
529
837
  params: Omit<BuildDeployContractTx, 'signerAddress'>
530
- ): Promise<DeployContractTransaction> {
531
- const signerParams = await this.paramsForDeployment({
532
- ...params,
533
- signerAddress: (await signer.getAccounts())[0].address
534
- })
535
- const response = await signer.buildContractCreationTx(signerParams)
536
- return fromApiDeployContractUnsignedTx(response)
838
+ ): Promise<SignDeployContractTxResult> {
839
+ const signerParams = await this.txParamsForDeployment(signer, params)
840
+ return signer.signAndSubmitDeployContractTx(signerParams)
537
841
  }
538
842
 
539
843
  buildByteCodeToDeploy(initialFields: Fields): string {
@@ -541,108 +845,95 @@ export class Contract extends Common {
541
845
  }
542
846
  }
543
847
 
544
- export class Script extends Common {
848
+ export class Script extends Artifact {
545
849
  readonly bytecodeTemplate: string
546
- readonly fieldsSig: node.FieldsSig
850
+ readonly bytecodeDebugPatch: string
851
+ readonly fieldsSig: FieldsSig
547
852
 
548
853
  constructor(
549
- sourceCodeSha256: string,
854
+ version: string,
855
+ name: string,
550
856
  bytecodeTemplate: string,
551
- fieldsSig: node.FieldsSig,
552
- functions: node.FunctionSig[]
857
+ bytecodeDebugPatch: string,
858
+ fieldsSig: FieldsSig,
859
+ functions: FunctionSig[]
553
860
  ) {
554
- super(sourceCodeSha256, functions)
861
+ super(version, name, functions)
555
862
  this.bytecodeTemplate = bytecodeTemplate
863
+ this.bytecodeDebugPatch = bytecodeDebugPatch
556
864
  this.fieldsSig = fieldsSig
557
865
  }
558
866
 
559
- static checkCodeType(fileName: string, contractStr: string): void {
560
- const scriptMatches = contractStr.match(this.scriptRegex)
561
- if (scriptMatches === null) {
562
- throw new Error(`No script found in: ${fileName}`)
563
- } else if (scriptMatches.length > 1) {
564
- throw new Error(`Multiple scripts in: ${fileName}`)
565
- } else {
566
- return
567
- }
568
- }
569
-
570
- private static async loadContractStr(sourceFile: SourceFile): Promise<string> {
571
- return Common._loadContractStr(sourceFile, [], (code) => Script.checkCodeType(sourceFile.contractPath, code))
572
- }
573
-
574
- static async fromSource(provider: NodeProvider, path: string): Promise<Script> {
575
- const sourceFile = this.getSourceFile(path, [])
576
- return Common._from(provider, sourceFile, (sourceFile) => Script.loadContractStr(sourceFile), Script.compile)
577
- }
578
-
579
- private static async compile(
580
- provider: NodeProvider,
581
- sourceFile: SourceFile,
582
- scriptStr: string,
583
- contractHash: string
584
- ): Promise<Script> {
585
- const compiled = await provider.contracts.postContractsCompileScript({ code: scriptStr })
586
- const artifact = new Script(contractHash, compiled.bytecodeTemplate, compiled.fields, compiled.functions)
587
- await artifact._saveToFile(sourceFile)
588
- return artifact
867
+ static fromCompileResult(result: node.CompileScriptResult): Script {
868
+ return new Script(
869
+ result.version,
870
+ result.name,
871
+ result.bytecodeTemplate,
872
+ result.bytecodeDebugPatch,
873
+ result.fields,
874
+ result.functions
875
+ )
589
876
  }
590
877
 
591
878
  // TODO: safely parse json
592
- static fromJson(artifact: any): Script {
879
+ static fromJson(artifact: any, bytecodeDebugPatch = ''): Script {
593
880
  if (
594
- artifact.sourceCodeSha256 == null ||
881
+ artifact.version == null ||
882
+ artifact.name == null ||
595
883
  artifact.bytecodeTemplate == null ||
596
884
  artifact.fieldsSig == null ||
597
885
  artifact.functions == null
598
886
  ) {
599
887
  throw Error('The artifact JSON for script is incomplete')
600
888
  }
601
- return new Script(artifact.sourceCodeSha256, artifact.bytecodeTemplate, artifact.fieldsSig, artifact.functions)
889
+ return new Script(
890
+ artifact.version,
891
+ artifact.name,
892
+ artifact.bytecodeTemplate,
893
+ bytecodeDebugPatch,
894
+ artifact.fieldsSig,
895
+ artifact.functions
896
+ )
602
897
  }
603
898
 
604
- static async fromArtifactFile(path: string): Promise<Script> {
605
- const sourceFile = this.getSourceFile(path, [])
606
- const artifactPath = sourceFile.artifactPath
607
- const content = await fsPromises.readFile(artifactPath)
899
+ static async fromArtifactFile(path: string, bytecodeDebugPatch: string): Promise<Script> {
900
+ const content = await fsPromises.readFile(path)
608
901
  const artifact = JSON.parse(content.toString())
609
- return this.fromJson(artifact)
902
+ return this.fromJson(artifact, bytecodeDebugPatch)
610
903
  }
611
904
 
612
905
  override toString(): string {
613
- return JSON.stringify(
614
- {
615
- sourceCodeSha256: this.sourceCodeSha256,
616
- bytecodeTemplate: this.bytecodeTemplate,
617
- fieldsSig: this.fieldsSig,
618
- functions: this.functions
619
- },
620
- null,
621
- 2
622
- )
906
+ const object = {
907
+ version: this.version,
908
+ name: this.name,
909
+ bytecodeTemplate: this.bytecodeTemplate,
910
+ fieldsSig: this.fieldsSig,
911
+ functions: this.functions
912
+ }
913
+ return JSON.stringify(object, null, 2)
623
914
  }
624
915
 
625
- async paramsForDeployment(params: BuildExecuteScriptTx): Promise<SignExecuteScriptTxParams> {
916
+ async txParamsForExecution(
917
+ signer: SignerProvider,
918
+ params: Omit<BuildExecuteScriptTx, 'signerAddress'>
919
+ ): Promise<SignExecuteScriptTxParams> {
626
920
  const signerParams: SignExecuteScriptTxParams = {
627
- signerAddress: params.signerAddress,
921
+ signerAddress: (await signer.getSelectedAccount()).address,
628
922
  bytecode: this.buildByteCodeToDeploy(params.initialFields ? params.initialFields : {}),
629
- attoAlphAmount: extractOptionalNumber256(params.attoAlphAmount),
630
- tokens: typeof params.tokens !== 'undefined' ? params.tokens.map(toApiToken) : undefined,
923
+ attoAlphAmount: params.attoAlphAmount,
924
+ tokens: params.tokens,
631
925
  gasAmount: params.gasAmount,
632
- gasPrice: extractOptionalNumber256(params.gasPrice)
926
+ gasPrice: params.gasPrice
633
927
  }
634
928
  return signerParams
635
929
  }
636
930
 
637
- async transactionForDeployment(
638
- signer: SignerWithNodeProvider,
931
+ async execute(
932
+ signer: SignerProvider,
639
933
  params: Omit<BuildExecuteScriptTx, 'signerAddress'>
640
- ): Promise<BuildScriptTxResult> {
641
- const signerParams = await this.paramsForDeployment({
642
- ...params,
643
- signerAddress: (await signer.getAccounts())[0].address
644
- })
645
- return await signer.buildScriptTx(signerParams)
934
+ ): Promise<SignExecuteScriptTxResult> {
935
+ const signerParams = await this.txParamsForExecution(signer, params)
936
+ return await signer.signAndSubmitExecuteScriptTx(signerParams)
646
937
  }
647
938
 
648
939
  buildByteCodeToDeploy(initialFields: Fields): string {
@@ -650,164 +941,6 @@ export class Script extends Common {
650
941
  }
651
942
  }
652
943
 
653
- export type Number256 = number | bigint | string
654
- export type Val = Number256 | boolean | string | Val[]
655
- export type NamedVals = Record<string, Val>
656
- export type Fields = NamedVals
657
- export type Arguments = NamedVals
658
-
659
- function extractBoolean(v: Val): boolean {
660
- if (typeof v === 'boolean') {
661
- return v
662
- } else {
663
- throw new Error(`Invalid boolean value: ${v}`)
664
- }
665
- }
666
-
667
- // TODO: check integer bounds
668
- function extractNumber256(v: Val): string {
669
- if ((typeof v === 'number' && Number.isInteger(v)) || typeof v === 'bigint') {
670
- return v.toString()
671
- } else if (typeof v === 'string') {
672
- return v
673
- } else {
674
- throw new Error(`Invalid 256 bit number: ${v}`)
675
- }
676
- }
677
-
678
- function extractOptionalNumber256(v?: Val): string | undefined {
679
- return typeof v !== 'undefined' ? extractNumber256(v) : undefined
680
- }
681
-
682
- // TODO: check hex string
683
- function extractByteVec(v: Val): string {
684
- if (typeof v === 'string') {
685
- // try to convert from address to contract id
686
- try {
687
- const address = bs58.decode(v)
688
- if (address.length == 33 && address[0] == 3) {
689
- return Buffer.from(address.slice(1)).toString('hex')
690
- }
691
- } catch (_) {
692
- return v as string
693
- }
694
- return v as string
695
- } else {
696
- throw new Error(`Invalid string: ${v}`)
697
- }
698
- }
699
-
700
- function extractBs58(v: Val): string {
701
- if (typeof v === 'string') {
702
- try {
703
- bs58.decode(v)
704
- return v as string
705
- } catch (error) {
706
- throw new Error(`Invalid base58 string: ${v}`)
707
- }
708
- } else {
709
- throw new Error(`Invalid string: ${v}`)
710
- }
711
- }
712
-
713
- function decodeNumber256(n: string): Number256 {
714
- if (Number.isSafeInteger(Number.parseInt(n))) {
715
- return Number(n)
716
- } else {
717
- return BigInt(n)
718
- }
719
- }
720
-
721
- export function extractArray(tpe: string, v: Val): node.Val {
722
- if (!Array.isArray(v)) {
723
- throw new Error(`Expected array, got ${v}`)
724
- }
725
-
726
- const semiColonIndex = tpe.lastIndexOf(';')
727
- if (semiColonIndex == -1) {
728
- throw new Error(`Invalid Val type: ${tpe}`)
729
- }
730
-
731
- const subType = tpe.slice(1, semiColonIndex)
732
- const dim = parseInt(tpe.slice(semiColonIndex + 1, -1))
733
- if ((v as Val[]).length != dim) {
734
- throw new Error(`Invalid val dimension: ${v}`)
735
- } else {
736
- return { value: (v as Val[]).map((v) => toApiVal(v, subType)), type: 'Array' }
737
- }
738
- }
739
-
740
- export function toApiVal(v: Val, tpe: string): node.Val {
741
- if (tpe === 'Bool') {
742
- return { value: extractBoolean(v), type: tpe }
743
- } else if (tpe === 'U256' || tpe === 'I256') {
744
- return { value: extractNumber256(v), type: tpe }
745
- } else if (tpe === 'ByteVec') {
746
- return { value: extractByteVec(v), type: tpe }
747
- } else if (tpe === 'Address') {
748
- return { value: extractBs58(v), type: tpe }
749
- } else {
750
- return extractArray(tpe, v)
751
- }
752
- }
753
-
754
- function decodeArrayType(tpe: string): [baseType: string, dims: number[]] {
755
- const semiColonIndex = tpe.lastIndexOf(';')
756
- if (semiColonIndex === -1) {
757
- throw new Error(`Invalid Val type: ${tpe}`)
758
- }
759
-
760
- const subType = tpe.slice(1, semiColonIndex)
761
- const dim = parseInt(tpe.slice(semiColonIndex + 1, -1))
762
- if (subType[0] == '[') {
763
- const [baseType, subDim] = decodeArrayType(subType)
764
- return [baseType, (subDim.unshift(dim), subDim)]
765
- } else {
766
- return [subType, [dim]]
767
- }
768
- }
769
-
770
- function foldVals(vals: Val[], dims: number[]): Val {
771
- if (dims.length == 1) {
772
- return vals
773
- } else {
774
- const result: Val[] = []
775
- const chunkSize = vals.length / dims[0]
776
- const chunkDims = dims.slice(1)
777
- for (let i = 0; i < vals.length; i += chunkSize) {
778
- const chunk = vals.slice(i, i + chunkSize)
779
- result.push(foldVals(chunk, chunkDims))
780
- }
781
- return result
782
- }
783
- }
784
-
785
- function _fromApiVal(vals: node.Val[], valIndex: number, tpe: string): [result: Val, nextIndex: number] {
786
- if (vals.length === 0) {
787
- throw new Error('Not enough Vals')
788
- }
789
-
790
- const firstVal = vals[`${valIndex}`]
791
- if (tpe === 'Bool' && firstVal.type === tpe) {
792
- return [firstVal.value as boolean, valIndex + 1]
793
- } else if ((tpe === 'U256' || tpe === 'I256') && firstVal.type === tpe) {
794
- return [decodeNumber256(firstVal.value as string), valIndex + 1]
795
- } else if ((tpe === 'ByteVec' || tpe === 'Address') && firstVal.type === tpe) {
796
- return [firstVal.value as string, valIndex + 1]
797
- } else {
798
- const [baseType, dims] = decodeArrayType(tpe)
799
- const arraySize = dims.reduce((a, b) => a * b)
800
- const nextIndex = valIndex + arraySize
801
- const valsToUse = vals.slice(valIndex, nextIndex)
802
- if (valsToUse.length == arraySize && valsToUse.every((val) => val.type === baseType)) {
803
- const localVals = valsToUse.map((val) => fromApiVal(val, baseType))
804
- return [foldVals(localVals, dims), nextIndex]
805
- } else {
806
- throw new Error(`Invalid array Val type: ${valsToUse}, ${tpe}`)
807
- }
808
- }
809
- }
810
-
811
944
  function fromApiFields(vals: node.Val[], fieldsSig: node.FieldsSig): Fields {
812
945
  return fromApiVals(vals, fieldsSig.names, fieldsSig.types)
813
946
  }
@@ -816,70 +949,22 @@ function fromApiEventFields(vals: node.Val[], eventSig: node.EventSig): Fields {
816
949
  return fromApiVals(vals, eventSig.fieldNames, eventSig.fieldTypes)
817
950
  }
818
951
 
819
- function fromApiVals(vals: node.Val[], names: string[], types: string[]): Fields {
820
- let valIndex = 0
821
- const result: Fields = {}
822
- types.forEach((currentType, index) => {
823
- const currentName = names[`${index}`]
824
- const [val, nextIndex] = _fromApiVal(vals, valIndex, currentType)
825
- valIndex = nextIndex
826
- result[`${currentName}`] = val
827
- })
828
- return result
829
- }
830
-
831
- function fromApiArray(vals: node.Val[], types: string[]): Val[] {
832
- let valIndex = 0
833
- const result: Val[] = []
834
- for (const currentType of types) {
835
- const [val, nextIndex] = _fromApiVal(vals, valIndex, currentType)
836
- result.push(val)
837
- valIndex = nextIndex
838
- }
839
- return result
840
- }
841
-
842
- function fromApiVal(v: node.Val, tpe: string): Val {
843
- if (v.type === 'Bool' && v.type === tpe) {
844
- return v.value as boolean
845
- } else if ((v.type === 'U256' || v.type === 'I256') && v.type === tpe) {
846
- return decodeNumber256(v.value as string)
847
- } else if ((v.type === 'ByteVec' || v.type === 'Address') && v.type === tpe) {
848
- return v.value as string
849
- } else {
850
- throw new Error(`Invalid node.Val type: ${v}`)
851
- }
852
- }
853
-
854
952
  export interface Asset {
855
953
  alphAmount: Number256
856
954
  tokens?: Token[]
857
955
  }
858
956
 
859
- export interface Token {
860
- id: string
861
- amount: Number256
862
- }
863
-
864
- function toApiToken(token: Token): node.Token {
865
- return { id: token.id, amount: extractNumber256(token.amount) }
866
- }
867
-
868
- function fromApiToken(token: node.Token): Token {
869
- return { id: token.id, amount: decodeNumber256(token.amount) }
870
- }
871
-
872
957
  function toApiAsset(asset: Asset): node.AssetState {
873
958
  return {
874
- attoAlphAmount: extractNumber256(asset.alphAmount),
959
+ attoAlphAmount: toApiNumber256(asset.alphAmount),
875
960
  tokens: typeof asset.tokens !== 'undefined' ? asset.tokens.map(toApiToken) : []
876
961
  }
877
962
  }
878
963
 
879
964
  function fromApiAsset(asset: node.AssetState): Asset {
880
965
  return {
881
- alphAmount: decodeNumber256(asset.attoAlphAmount),
882
- tokens: typeof asset.tokens !== 'undefined' ? asset.tokens.map(fromApiToken) : undefined
966
+ alphAmount: fromApiNumber256(asset.attoAlphAmount),
967
+ tokens: fromApiTokens(asset.tokens)
883
968
  }
884
969
  }
885
970
 
@@ -895,7 +980,7 @@ export interface ContractState {
895
980
  initialStateHash?: string
896
981
  codeHash: string
897
982
  fields: Fields
898
- fieldsSig: node.FieldsSig
983
+ fieldsSig: FieldsSig
899
984
  asset: Asset
900
985
  }
901
986
 
@@ -918,12 +1003,12 @@ function toApiContractState(state: ContractState): node.ContractState {
918
1003
  }
919
1004
  }
920
1005
 
921
- function toApiFields(fields: Fields, fieldsSig: node.FieldsSig): node.Val[] {
1006
+ function toApiFields(fields: Fields, fieldsSig: FieldsSig): node.Val[] {
922
1007
  return toApiVals(fields, fieldsSig.names, fieldsSig.types)
923
1008
  }
924
1009
 
925
- function toApiArgs(args: Arguments, funcSig: node.FunctionSig): node.Val[] {
926
- return toApiVals(args, funcSig.argNames, funcSig.argTypes)
1010
+ function toApiArgs(args: Arguments, funcSig: FunctionSig): node.Val[] {
1011
+ return toApiVals(args, funcSig.paramNames, funcSig.paramTypes)
927
1012
  }
928
1013
 
929
1014
  function toApiVals(fields: Fields, names: string[], types: string[]): node.Val[] {
@@ -967,14 +1052,17 @@ export interface ContractEventByTxId {
967
1052
  fields: Fields
968
1053
  }
969
1054
 
1055
+ export type DebugMessage = node.DebugMessage
1056
+
970
1057
  export interface TestContractResult {
971
- address: string
972
1058
  contractId: string
1059
+ contractAddress: string
973
1060
  returns: Val[]
974
1061
  gasUsed: number
975
1062
  contracts: ContractState[]
976
1063
  txOutputs: Output[]
977
1064
  events: ContractEventByTxId[]
1065
+ debugMessages: DebugMessage[]
978
1066
  }
979
1067
  export declare type Output = AssetOutput | ContractOutput
980
1068
  export interface AssetOutput extends Asset {
@@ -987,7 +1075,7 @@ export interface ContractOutput {
987
1075
  type: string
988
1076
  address: string
989
1077
  alphAmount: Number256
990
- tokens: Token[]
1078
+ tokens?: Token[]
991
1079
  }
992
1080
 
993
1081
  function fromApiOutput(output: node.Output): Output {
@@ -996,8 +1084,8 @@ function fromApiOutput(output: node.Output): Output {
996
1084
  return {
997
1085
  type: 'AssetOutput',
998
1086
  address: asset.address,
999
- alphAmount: decodeNumber256(asset.attoAlphAmount),
1000
- tokens: asset.tokens.map(fromApiToken),
1087
+ alphAmount: fromApiNumber256(asset.attoAlphAmount),
1088
+ tokens: fromApiTokens(asset.tokens),
1001
1089
  lockTime: asset.lockTime,
1002
1090
  message: asset.message
1003
1091
  }
@@ -1006,8 +1094,8 @@ function fromApiOutput(output: node.Output): Output {
1006
1094
  return {
1007
1095
  type: 'ContractOutput',
1008
1096
  address: asset.address,
1009
- alphAmount: decodeNumber256(asset.attoAlphAmount),
1010
- tokens: asset.tokens.map(fromApiToken)
1097
+ alphAmount: fromApiNumber256(asset.attoAlphAmount),
1098
+ tokens: fromApiTokens(asset.tokens)
1011
1099
  }
1012
1100
  } else {
1013
1101
  throw new Error(`Unknown output type: ${output}`)
@@ -1023,21 +1111,16 @@ export interface DeployContractTransaction {
1023
1111
  contractId: string
1024
1112
  }
1025
1113
 
1026
- function fromApiDeployContractUnsignedTx(result: node.BuildDeployContractTxResult): DeployContractTransaction {
1027
- return { ...result, contractId: binToHex(contractIdFromAddress(result.contractAddress)) }
1028
- }
1029
-
1030
1114
  type BuildTxParams<T> = Omit<T, 'bytecode'> & { initialFields?: Val[] }
1031
1115
 
1032
1116
  export interface BuildDeployContractTx {
1033
1117
  signerAddress: string
1034
1118
  initialFields?: Fields
1035
- initialAttoAlphAmount?: string
1119
+ initialAttoAlphAmount?: Number256
1036
1120
  initialTokenAmounts?: Token[]
1037
1121
  issueTokenAmount?: Number256
1038
1122
  gasAmount?: number
1039
1123
  gasPrice?: Number256
1040
- submitTx?: boolean
1041
1124
  }
1042
1125
  assertType<Eq<keyof BuildDeployContractTx, keyof BuildTxParams<SignDeployContractTxParams>>>()
1043
1126
 
@@ -1048,7 +1131,6 @@ export interface BuildExecuteScriptTx {
1048
1131
  tokens?: Token[]
1049
1132
  gasAmount?: number
1050
1133
  gasPrice?: Number256
1051
- submitTx?: boolean
1052
1134
  }
1053
1135
  assertType<Eq<keyof BuildExecuteScriptTx, keyof BuildTxParams<SignExecuteScriptTxParams>>>()
1054
1136