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