@alephium/web3 0.2.0-test.1 → 0.2.2
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 +116 -18
- package/dist/src/api/api-alephium.js +146 -81
- 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 +69 -55
- package/dist/src/contract/contract.js +241 -387
- 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 +163 -26
- 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 +405 -432
- 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
|
+
ignoreUpdateFieldsCheckWarnings: 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,20 +745,24 @@ export class Contract extends Artifact {
|
|
|
592
745
|
}
|
|
593
746
|
}
|
|
594
747
|
|
|
595
|
-
|
|
596
|
-
const contract = Project.currentProject.contractByCodeHash(state.codeHash)
|
|
748
|
+
fromApiContractState(state: node.ContractState): ContractState {
|
|
597
749
|
return {
|
|
598
750
|
address: state.address,
|
|
599
751
|
contractId: binToHex(contractIdFromAddress(state.address)),
|
|
600
752
|
bytecode: state.bytecode,
|
|
601
753
|
initialStateHash: state.initialStateHash,
|
|
602
754
|
codeHash: state.codeHash,
|
|
603
|
-
fields: fromApiFields(state.fields,
|
|
604
|
-
fieldsSig:
|
|
755
|
+
fields: fromApiFields(state.fields, this.fieldsSig),
|
|
756
|
+
fieldsSig: this.fieldsSig,
|
|
605
757
|
asset: fromApiAsset(state.asset)
|
|
606
758
|
}
|
|
607
759
|
}
|
|
608
760
|
|
|
761
|
+
static fromApiContractState(state: node.ContractState): ContractState {
|
|
762
|
+
const contract = Project.currentProject.contractByCodeHash(state.codeHash)
|
|
763
|
+
return contract.fromApiContractState(state)
|
|
764
|
+
}
|
|
765
|
+
|
|
609
766
|
static ContractCreatedEvent: EventSig = {
|
|
610
767
|
name: 'ContractCreated',
|
|
611
768
|
fieldNames: ['address'],
|
|
@@ -618,10 +775,7 @@ export class Contract extends Artifact {
|
|
|
618
775
|
fieldTypes: ['Address']
|
|
619
776
|
}
|
|
620
777
|
|
|
621
|
-
static
|
|
622
|
-
event: node.ContractEventByTxId,
|
|
623
|
-
codeHash: string | undefined
|
|
624
|
-
): Promise<ContractEventByTxId> {
|
|
778
|
+
static fromApiEvent(event: node.ContractEventByTxId, codeHash: string | undefined): ContractEventByTxId {
|
|
625
779
|
let eventSig: EventSig
|
|
626
780
|
|
|
627
781
|
if (event.eventIndex == -1) {
|
|
@@ -641,55 +795,53 @@ export class Contract extends Artifact {
|
|
|
641
795
|
}
|
|
642
796
|
}
|
|
643
797
|
|
|
644
|
-
|
|
798
|
+
fromTestContractResult(methodIndex: number, result: node.TestContractResult): TestContractResult {
|
|
645
799
|
const addressToCodeHash = new Map<string, string>()
|
|
646
800
|
addressToCodeHash.set(result.address, result.codeHash)
|
|
647
801
|
result.contracts.forEach((contract) => addressToCodeHash.set(contract.address, contract.codeHash))
|
|
648
802
|
return {
|
|
649
|
-
address: result.address,
|
|
650
803
|
contractId: binToHex(contractIdFromAddress(result.address)),
|
|
804
|
+
contractAddress: result.address,
|
|
651
805
|
returns: fromApiArray(result.returns, this.functions[`${methodIndex}`].returnTypes),
|
|
652
806
|
gasUsed: result.gasUsed,
|
|
653
|
-
contracts:
|
|
807
|
+
contracts: result.contracts.map((contract) => Contract.fromApiContractState(contract)),
|
|
654
808
|
txOutputs: result.txOutputs.map(fromApiOutput),
|
|
655
|
-
events:
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
)
|
|
809
|
+
events: result.events.map((event) => {
|
|
810
|
+
const contractAddress = event.contractAddress
|
|
811
|
+
const codeHash = addressToCodeHash.get(contractAddress)
|
|
812
|
+
if (typeof codeHash !== 'undefined' || event.eventIndex < 0) {
|
|
813
|
+
return Contract.fromApiEvent(event, codeHash)
|
|
814
|
+
} else {
|
|
815
|
+
throw Error(`Cannot find codeHash for the contract address: ${contractAddress}`)
|
|
816
|
+
}
|
|
817
|
+
}),
|
|
818
|
+
debugMessages: result.debugMessages
|
|
666
819
|
}
|
|
667
820
|
}
|
|
668
821
|
|
|
669
|
-
async
|
|
822
|
+
async txParamsForDeployment(
|
|
823
|
+
signer: SignerProvider,
|
|
824
|
+
params: Omit<BuildDeployContractTx, 'signerAddress'>
|
|
825
|
+
): Promise<SignDeployContractTxParams> {
|
|
670
826
|
const bytecode = this.buildByteCodeToDeploy(params.initialFields ? params.initialFields : {})
|
|
671
827
|
const signerParams: SignDeployContractTxParams = {
|
|
672
|
-
signerAddress:
|
|
828
|
+
signerAddress: (await signer.getSelectedAccount()).address,
|
|
673
829
|
bytecode: bytecode,
|
|
674
|
-
initialAttoAlphAmount:
|
|
675
|
-
issueTokenAmount:
|
|
676
|
-
initialTokenAmounts: params.initialTokenAmounts
|
|
830
|
+
initialAttoAlphAmount: params.initialAttoAlphAmount,
|
|
831
|
+
issueTokenAmount: params.issueTokenAmount,
|
|
832
|
+
initialTokenAmounts: params.initialTokenAmounts,
|
|
677
833
|
gasAmount: params.gasAmount,
|
|
678
|
-
gasPrice:
|
|
834
|
+
gasPrice: params.gasPrice
|
|
679
835
|
}
|
|
680
836
|
return signerParams
|
|
681
837
|
}
|
|
682
838
|
|
|
683
|
-
async
|
|
684
|
-
signer:
|
|
839
|
+
async deploy(
|
|
840
|
+
signer: SignerProvider,
|
|
685
841
|
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)
|
|
842
|
+
): Promise<SignDeployContractTxResult> {
|
|
843
|
+
const signerParams = await this.txParamsForDeployment(signer, params)
|
|
844
|
+
return signer.signAndSubmitDeployContractTx(signerParams)
|
|
693
845
|
}
|
|
694
846
|
|
|
695
847
|
buildByteCodeToDeploy(initialFields: Fields): string {
|
|
@@ -699,35 +851,65 @@ export class Contract extends Artifact {
|
|
|
699
851
|
|
|
700
852
|
export class Script extends Artifact {
|
|
701
853
|
readonly bytecodeTemplate: string
|
|
854
|
+
readonly bytecodeDebugPatch: string
|
|
702
855
|
readonly fieldsSig: FieldsSig
|
|
703
856
|
|
|
704
|
-
constructor(
|
|
705
|
-
|
|
857
|
+
constructor(
|
|
858
|
+
version: string,
|
|
859
|
+
name: string,
|
|
860
|
+
bytecodeTemplate: string,
|
|
861
|
+
bytecodeDebugPatch: string,
|
|
862
|
+
fieldsSig: FieldsSig,
|
|
863
|
+
functions: FunctionSig[]
|
|
864
|
+
) {
|
|
865
|
+
super(version, name, functions)
|
|
706
866
|
this.bytecodeTemplate = bytecodeTemplate
|
|
867
|
+
this.bytecodeDebugPatch = bytecodeDebugPatch
|
|
707
868
|
this.fieldsSig = fieldsSig
|
|
708
869
|
}
|
|
709
870
|
|
|
710
|
-
static fromCompileResult(
|
|
711
|
-
return new Script(
|
|
871
|
+
static fromCompileResult(result: node.CompileScriptResult): Script {
|
|
872
|
+
return new Script(
|
|
873
|
+
result.version,
|
|
874
|
+
result.name,
|
|
875
|
+
result.bytecodeTemplate,
|
|
876
|
+
result.bytecodeDebugPatch,
|
|
877
|
+
result.fields,
|
|
878
|
+
result.functions
|
|
879
|
+
)
|
|
712
880
|
}
|
|
713
881
|
|
|
714
882
|
// TODO: safely parse json
|
|
715
|
-
static fromJson(artifact: any): Script {
|
|
716
|
-
if (
|
|
883
|
+
static fromJson(artifact: any, bytecodeDebugPatch = ''): Script {
|
|
884
|
+
if (
|
|
885
|
+
artifact.version == null ||
|
|
886
|
+
artifact.name == null ||
|
|
887
|
+
artifact.bytecodeTemplate == null ||
|
|
888
|
+
artifact.fieldsSig == null ||
|
|
889
|
+
artifact.functions == null
|
|
890
|
+
) {
|
|
717
891
|
throw Error('The artifact JSON for script is incomplete')
|
|
718
892
|
}
|
|
719
|
-
return new Script(
|
|
893
|
+
return new Script(
|
|
894
|
+
artifact.version,
|
|
895
|
+
artifact.name,
|
|
896
|
+
artifact.bytecodeTemplate,
|
|
897
|
+
bytecodeDebugPatch,
|
|
898
|
+
artifact.fieldsSig,
|
|
899
|
+
artifact.functions
|
|
900
|
+
)
|
|
720
901
|
}
|
|
721
902
|
|
|
722
|
-
static async fromArtifactFile(path: string): Promise<Script> {
|
|
903
|
+
static async fromArtifactFile(path: string, bytecodeDebugPatch: string): Promise<Script> {
|
|
723
904
|
const content = await fsPromises.readFile(path)
|
|
724
905
|
const artifact = JSON.parse(content.toString())
|
|
725
|
-
return this.fromJson(artifact)
|
|
906
|
+
return this.fromJson(artifact, bytecodeDebugPatch)
|
|
726
907
|
}
|
|
727
908
|
|
|
728
909
|
override toString(): string {
|
|
729
910
|
const object = {
|
|
730
|
-
|
|
911
|
+
version: this.version,
|
|
912
|
+
name: this.name,
|
|
731
913
|
bytecodeTemplate: this.bytecodeTemplate,
|
|
732
914
|
fieldsSig: this.fieldsSig,
|
|
733
915
|
functions: this.functions
|
|
@@ -735,27 +917,27 @@ export class Script extends Artifact {
|
|
|
735
917
|
return JSON.stringify(object, null, 2)
|
|
736
918
|
}
|
|
737
919
|
|
|
738
|
-
async
|
|
920
|
+
async txParamsForExecution(
|
|
921
|
+
signer: SignerProvider,
|
|
922
|
+
params: Omit<BuildExecuteScriptTx, 'signerAddress'>
|
|
923
|
+
): Promise<SignExecuteScriptTxParams> {
|
|
739
924
|
const signerParams: SignExecuteScriptTxParams = {
|
|
740
|
-
signerAddress:
|
|
925
|
+
signerAddress: (await signer.getSelectedAccount()).address,
|
|
741
926
|
bytecode: this.buildByteCodeToDeploy(params.initialFields ? params.initialFields : {}),
|
|
742
|
-
attoAlphAmount:
|
|
743
|
-
tokens:
|
|
927
|
+
attoAlphAmount: params.attoAlphAmount,
|
|
928
|
+
tokens: params.tokens,
|
|
744
929
|
gasAmount: params.gasAmount,
|
|
745
|
-
gasPrice:
|
|
930
|
+
gasPrice: params.gasPrice
|
|
746
931
|
}
|
|
747
932
|
return signerParams
|
|
748
933
|
}
|
|
749
934
|
|
|
750
|
-
async
|
|
751
|
-
signer:
|
|
935
|
+
async execute(
|
|
936
|
+
signer: SignerProvider,
|
|
752
937
|
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)
|
|
938
|
+
): Promise<SignExecuteScriptTxResult> {
|
|
939
|
+
const signerParams = await this.txParamsForExecution(signer, params)
|
|
940
|
+
return await signer.signAndSubmitExecuteScriptTx(signerParams)
|
|
759
941
|
}
|
|
760
942
|
|
|
761
943
|
buildByteCodeToDeploy(initialFields: Fields): string {
|
|
@@ -763,164 +945,6 @@ export class Script extends Artifact {
|
|
|
763
945
|
}
|
|
764
946
|
}
|
|
765
947
|
|
|
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
948
|
function fromApiFields(vals: node.Val[], fieldsSig: node.FieldsSig): Fields {
|
|
925
949
|
return fromApiVals(vals, fieldsSig.names, fieldsSig.types)
|
|
926
950
|
}
|
|
@@ -929,70 +953,22 @@ function fromApiEventFields(vals: node.Val[], eventSig: node.EventSig): Fields {
|
|
|
929
953
|
return fromApiVals(vals, eventSig.fieldNames, eventSig.fieldTypes)
|
|
930
954
|
}
|
|
931
955
|
|
|
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
956
|
export interface Asset {
|
|
968
957
|
alphAmount: Number256
|
|
969
958
|
tokens?: Token[]
|
|
970
959
|
}
|
|
971
960
|
|
|
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
961
|
function toApiAsset(asset: Asset): node.AssetState {
|
|
986
962
|
return {
|
|
987
|
-
attoAlphAmount:
|
|
963
|
+
attoAlphAmount: toApiNumber256(asset.alphAmount),
|
|
988
964
|
tokens: typeof asset.tokens !== 'undefined' ? asset.tokens.map(toApiToken) : []
|
|
989
965
|
}
|
|
990
966
|
}
|
|
991
967
|
|
|
992
968
|
function fromApiAsset(asset: node.AssetState): Asset {
|
|
993
969
|
return {
|
|
994
|
-
alphAmount:
|
|
995
|
-
tokens:
|
|
970
|
+
alphAmount: fromApiNumber256(asset.attoAlphAmount),
|
|
971
|
+
tokens: fromApiTokens(asset.tokens)
|
|
996
972
|
}
|
|
997
973
|
}
|
|
998
974
|
|
|
@@ -1080,14 +1056,17 @@ export interface ContractEventByTxId {
|
|
|
1080
1056
|
fields: Fields
|
|
1081
1057
|
}
|
|
1082
1058
|
|
|
1059
|
+
export type DebugMessage = node.DebugMessage
|
|
1060
|
+
|
|
1083
1061
|
export interface TestContractResult {
|
|
1084
|
-
address: string
|
|
1085
1062
|
contractId: string
|
|
1063
|
+
contractAddress: string
|
|
1086
1064
|
returns: Val[]
|
|
1087
1065
|
gasUsed: number
|
|
1088
1066
|
contracts: ContractState[]
|
|
1089
1067
|
txOutputs: Output[]
|
|
1090
1068
|
events: ContractEventByTxId[]
|
|
1069
|
+
debugMessages: DebugMessage[]
|
|
1091
1070
|
}
|
|
1092
1071
|
export declare type Output = AssetOutput | ContractOutput
|
|
1093
1072
|
export interface AssetOutput extends Asset {
|
|
@@ -1100,7 +1079,7 @@ export interface ContractOutput {
|
|
|
1100
1079
|
type: string
|
|
1101
1080
|
address: string
|
|
1102
1081
|
alphAmount: Number256
|
|
1103
|
-
tokens
|
|
1082
|
+
tokens?: Token[]
|
|
1104
1083
|
}
|
|
1105
1084
|
|
|
1106
1085
|
function fromApiOutput(output: node.Output): Output {
|
|
@@ -1109,8 +1088,8 @@ function fromApiOutput(output: node.Output): Output {
|
|
|
1109
1088
|
return {
|
|
1110
1089
|
type: 'AssetOutput',
|
|
1111
1090
|
address: asset.address,
|
|
1112
|
-
alphAmount:
|
|
1113
|
-
tokens: asset.tokens
|
|
1091
|
+
alphAmount: fromApiNumber256(asset.attoAlphAmount),
|
|
1092
|
+
tokens: fromApiTokens(asset.tokens),
|
|
1114
1093
|
lockTime: asset.lockTime,
|
|
1115
1094
|
message: asset.message
|
|
1116
1095
|
}
|
|
@@ -1119,8 +1098,8 @@ function fromApiOutput(output: node.Output): Output {
|
|
|
1119
1098
|
return {
|
|
1120
1099
|
type: 'ContractOutput',
|
|
1121
1100
|
address: asset.address,
|
|
1122
|
-
alphAmount:
|
|
1123
|
-
tokens: asset.tokens
|
|
1101
|
+
alphAmount: fromApiNumber256(asset.attoAlphAmount),
|
|
1102
|
+
tokens: fromApiTokens(asset.tokens)
|
|
1124
1103
|
}
|
|
1125
1104
|
} else {
|
|
1126
1105
|
throw new Error(`Unknown output type: ${output}`)
|
|
@@ -1136,21 +1115,16 @@ export interface DeployContractTransaction {
|
|
|
1136
1115
|
contractId: string
|
|
1137
1116
|
}
|
|
1138
1117
|
|
|
1139
|
-
function fromApiDeployContractUnsignedTx(result: node.BuildDeployContractTxResult): DeployContractTransaction {
|
|
1140
|
-
return { ...result, contractId: binToHex(contractIdFromAddress(result.contractAddress)) }
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
1118
|
type BuildTxParams<T> = Omit<T, 'bytecode'> & { initialFields?: Val[] }
|
|
1144
1119
|
|
|
1145
1120
|
export interface BuildDeployContractTx {
|
|
1146
1121
|
signerAddress: string
|
|
1147
1122
|
initialFields?: Fields
|
|
1148
|
-
initialAttoAlphAmount?:
|
|
1123
|
+
initialAttoAlphAmount?: Number256
|
|
1149
1124
|
initialTokenAmounts?: Token[]
|
|
1150
1125
|
issueTokenAmount?: Number256
|
|
1151
1126
|
gasAmount?: number
|
|
1152
1127
|
gasPrice?: Number256
|
|
1153
|
-
submitTx?: boolean
|
|
1154
1128
|
}
|
|
1155
1129
|
assertType<Eq<keyof BuildDeployContractTx, keyof BuildTxParams<SignDeployContractTxParams>>>()
|
|
1156
1130
|
|
|
@@ -1161,7 +1135,6 @@ export interface BuildExecuteScriptTx {
|
|
|
1161
1135
|
tokens?: Token[]
|
|
1162
1136
|
gasAmount?: number
|
|
1163
1137
|
gasPrice?: Number256
|
|
1164
|
-
submitTx?: boolean
|
|
1165
1138
|
}
|
|
1166
1139
|
assertType<Eq<keyof BuildExecuteScriptTx, keyof BuildTxParams<SignExecuteScriptTxParams>>>()
|
|
1167
1140
|
|