@alephium/web3 0.1.0 → 0.2.0-rc.10
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/contracts/greeter/greeter.ral +7 -0
- package/contracts/{greeter_interface.ral → greeter/greeter_interface.ral} +1 -0
- package/contracts/greeter_main.ral +2 -4
- 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/scripts/create-project.js +3 -2
- package/dist/src/api/api-alephium.d.ts +58 -13
- package/dist/src/api/api-alephium.js +19 -3
- package/dist/src/api/api-explorer.d.ts +32 -16
- package/dist/src/api/api-explorer.js +26 -0
- package/dist/src/api/index.d.ts +2 -2
- package/dist/src/api/index.js +18 -3
- package/dist/src/contract/contract.d.ts +105 -48
- package/dist/src/contract/contract.js +362 -189
- package/dist/src/contract/events.d.ts +7 -25
- package/dist/src/contract/events.js +18 -31
- package/dist/src/contract/index.js +5 -1
- package/dist/src/global.d.ts +4 -0
- package/dist/src/global.js +38 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +21 -1
- package/dist/src/signer/index.d.ts +0 -1
- package/dist/src/signer/index.js +5 -2
- package/dist/src/signer/signer.d.ts +1 -1
- package/dist/src/signer/signer.js +8 -3
- package/dist/src/transaction/index.d.ts +1 -0
- package/dist/src/{test → transaction}/index.js +6 -13
- package/dist/src/transaction/status.d.ts +10 -0
- package/dist/src/transaction/status.js +48 -0
- package/dist/src/utils/index.d.ts +1 -2
- package/dist/src/utils/index.js +6 -3
- package/dist/src/utils/subscription.d.ts +23 -0
- package/dist/src/utils/subscription.js +53 -0
- package/dist/src/utils/utils.d.ts +5 -2
- package/dist/src/utils/utils.js +25 -16
- package/jest-config.json +11 -0
- package/package.json +7 -35
- package/scripts/create-project.ts +3 -2
- package/src/api/api-alephium.ts +73 -8
- package/src/api/api-explorer.ts +30 -0
- package/src/api/index.ts +13 -3
- package/src/contract/contract.ts +512 -279
- package/src/contract/events.ts +21 -48
- package/src/{utils/transaction.ts → global.ts} +14 -15
- package/src/index.ts +4 -0
- package/src/signer/index.ts +0 -1
- package/src/signer/signer.ts +4 -3
- package/src/{utils/password-crypto.test.ts → transaction/index.ts} +1 -9
- package/src/transaction/status.ts +58 -0
- package/src/utils/index.ts +1 -2
- package/src/utils/subscription.ts +72 -0
- package/src/utils/utils.ts +16 -8
- package/templates/base/package.json +2 -2
- package/templates/base/src/greeter.ts +8 -7
- package/templates/react/package.json +2 -2
- package/templates/react/src/App.tsx +2 -2
- package/.eslintrc.json +0 -21
- package/LICENSE +0 -165
- package/contracts/add.ral +0 -16
- package/contracts/greeter.ral +0 -7
- package/contracts/main.ral +0 -6
- package/contracts/sub.ral +0 -9
- package/dist/src/signer/node-wallet.d.ts +0 -13
- package/dist/src/signer/node-wallet.js +0 -60
- package/dist/src/test/index.d.ts +0 -7
- package/dist/src/test/privatekey-wallet.d.ts +0 -12
- package/dist/src/test/privatekey-wallet.js +0 -68
- package/dist/src/utils/password-crypto.d.ts +0 -2
- package/dist/src/utils/password-crypto.js +0 -69
- package/dist/src/utils/transaction.d.ts +0 -2
- package/dist/src/utils/transaction.js +0 -58
- package/gitignore +0 -10
- 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 -74
- package/src/test/index.ts +0 -32
- package/src/test/privatekey-wallet.ts +0 -58
- package/src/utils/address.test.ts +0 -47
- package/src/utils/djb2.test.ts +0 -35
- package/src/utils/password-crypto.ts +0 -77
- package/src/utils/transaction.test.ts +0 -50
- package/src/utils/utils.test.ts +0 -160
- package/test/contract.test.ts +0 -161
- package/test/events.test.ts +0 -139
|
@@ -18,7 +18,11 @@ along with the library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
18
18
|
*/
|
|
19
19
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
20
20
|
if (k2 === undefined) k2 = k;
|
|
21
|
-
Object.
|
|
21
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
22
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
23
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
24
|
+
}
|
|
25
|
+
Object.defineProperty(o, k2, desc);
|
|
22
26
|
}) : (function(o, m, k, k2) {
|
|
23
27
|
if (k2 === undefined) k2 = k;
|
|
24
28
|
o[k2] = m[k];
|
|
@@ -39,173 +43,389 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
39
43
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
44
|
};
|
|
41
45
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
-
exports.toApiVal = exports.extractArray = exports.Script = exports.Contract = exports.
|
|
46
|
+
exports.toApiVal = exports.extractArray = exports.Script = exports.Contract = exports.Artifact = exports.Project = exports.DEFAULT_COMPILER_OPTIONS = exports.DEFAULT_NODE_COMPILER_OPTIONS = void 0;
|
|
43
47
|
const buffer_1 = require("buffer/");
|
|
44
|
-
const
|
|
45
|
-
const crypto = __importStar(require("crypto"));
|
|
48
|
+
const crypto_1 = require("crypto");
|
|
46
49
|
const fs_1 = __importDefault(require("fs"));
|
|
47
50
|
const fs_2 = require("fs");
|
|
48
51
|
const ralph = __importStar(require("./ralph"));
|
|
49
52
|
const utils_1 = require("../utils");
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
const global_1 = require("../global");
|
|
54
|
+
var SourceType;
|
|
55
|
+
(function (SourceType) {
|
|
56
|
+
SourceType[SourceType["Contract"] = 0] = "Contract";
|
|
57
|
+
SourceType[SourceType["Script"] = 1] = "Script";
|
|
58
|
+
SourceType[SourceType["AbstractContract"] = 2] = "AbstractContract";
|
|
59
|
+
SourceType[SourceType["Interface"] = 3] = "Interface";
|
|
60
|
+
})(SourceType || (SourceType = {}));
|
|
61
|
+
exports.DEFAULT_NODE_COMPILER_OPTIONS = {
|
|
62
|
+
ignoreUnusedConstantsWarnings: false,
|
|
63
|
+
ignoreUnusedVariablesWarnings: false,
|
|
64
|
+
ignoreUnusedFieldsWarnings: false,
|
|
65
|
+
ignoreUnusedPrivateFunctionsWarnings: false,
|
|
66
|
+
ignoreReadonlyCheckWarnings: false,
|
|
67
|
+
ignoreExternalCallCheckWarnings: false
|
|
68
|
+
};
|
|
69
|
+
exports.DEFAULT_COMPILER_OPTIONS = { errorOnWarnings: true, ...exports.DEFAULT_NODE_COMPILER_OPTIONS };
|
|
70
|
+
class TypedMatcher {
|
|
71
|
+
constructor(pattern, type) {
|
|
72
|
+
this.matcher = new RegExp(pattern, 'mg');
|
|
73
|
+
this.type = type;
|
|
54
74
|
}
|
|
55
|
-
|
|
56
|
-
|
|
75
|
+
match(str) {
|
|
76
|
+
const results = str.match(this.matcher);
|
|
77
|
+
return results === null ? 0 : results.length;
|
|
57
78
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
79
|
+
}
|
|
80
|
+
class SourceFile {
|
|
81
|
+
constructor(type, sourceCode, sourceCodeHash, contractPath) {
|
|
82
|
+
this.type = type;
|
|
83
|
+
this.sourceCode = sourceCode;
|
|
84
|
+
this.sourceCodeHash = sourceCodeHash;
|
|
85
|
+
this.contractPath = contractPath;
|
|
66
86
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
return `./contracts/${fileName.slice(0, -5)}`;
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
return `./contracts/${fileName}`;
|
|
73
|
-
}
|
|
87
|
+
getArtifactPath(artifactsRootPath) {
|
|
88
|
+
return artifactsRootPath + this.contractPath.slice(this.contractPath.indexOf('/')) + '.json';
|
|
74
89
|
}
|
|
75
|
-
static
|
|
76
|
-
|
|
77
|
-
|
|
90
|
+
static async from(type, sourceCode, contractPath) {
|
|
91
|
+
const sourceCodeHash = await crypto_1.webcrypto.subtle.digest('SHA-256', buffer_1.Buffer.from(sourceCode));
|
|
92
|
+
return new SourceFile(type, sourceCode, buffer_1.Buffer.from(sourceCodeHash).toString('hex'), contractPath);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
class Compiled {
|
|
96
|
+
constructor(sourceFile, artifact, warnings) {
|
|
97
|
+
this.sourceFile = sourceFile;
|
|
98
|
+
this.artifact = artifact;
|
|
99
|
+
this.warnings = warnings;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
class ProjectArtifact {
|
|
103
|
+
constructor(compilerOptionsUsed, infos) {
|
|
104
|
+
ProjectArtifact.checkCompilerOptionsParameter(compilerOptionsUsed);
|
|
105
|
+
this.compilerOptionsUsed = compilerOptionsUsed;
|
|
106
|
+
this.infos = infos;
|
|
107
|
+
}
|
|
108
|
+
static checkCompilerOptionsParameter(compilerOptions) {
|
|
109
|
+
if (Object.keys(compilerOptions).length != Object.keys(exports.DEFAULT_NODE_COMPILER_OPTIONS).length) {
|
|
110
|
+
throw Error(`Not all compiler options are set: ${compilerOptions}`);
|
|
78
111
|
}
|
|
79
|
-
|
|
80
|
-
|
|
112
|
+
const combined = { ...compilerOptions, ...exports.DEFAULT_NODE_COMPILER_OPTIONS };
|
|
113
|
+
if (Object.keys(combined).length !== Object.keys(exports.DEFAULT_NODE_COMPILER_OPTIONS).length) {
|
|
114
|
+
throw Error(`There are unknown compiler options: ${compilerOptions}`);
|
|
81
115
|
}
|
|
82
116
|
}
|
|
83
|
-
|
|
84
|
-
|
|
117
|
+
async saveToFile(rootPath) {
|
|
118
|
+
const filepath = rootPath + '/' + ProjectArtifact.artifactFileName;
|
|
119
|
+
const artifact = { compilerOptionsUsed: this.compilerOptionsUsed, infos: Object.fromEntries(this.infos) };
|
|
120
|
+
const content = JSON.stringify(artifact, null, 2);
|
|
121
|
+
return fs_2.promises.writeFile(filepath, content);
|
|
85
122
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
return
|
|
123
|
+
needToReCompile(compilerOptions, files) {
|
|
124
|
+
ProjectArtifact.checkCompilerOptionsParameter(compilerOptions);
|
|
125
|
+
const optionsMatched = Object.entries(compilerOptions).every(([key, inputOption]) => {
|
|
126
|
+
const usedOption = this.compilerOptionsUsed[`${key}`];
|
|
127
|
+
return usedOption === inputOption;
|
|
91
128
|
});
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
129
|
+
if (!optionsMatched) {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
if (files.length !== this.infos.size) {
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
for (const file of files) {
|
|
136
|
+
const info = this.infos.get(file.contractPath);
|
|
137
|
+
if (typeof info === 'undefined' || info.sourceCodeHash !== file.sourceCodeHash) {
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
static async from(rootPath) {
|
|
144
|
+
const filepath = rootPath + '/' + ProjectArtifact.artifactFileName;
|
|
145
|
+
if (!fs_1.default.existsSync(filepath)) {
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
const content = await fs_2.promises.readFile(filepath);
|
|
149
|
+
const json = JSON.parse(content.toString());
|
|
150
|
+
const compilerOptionsUsed = json.compilerOptionsUsed;
|
|
151
|
+
const files = new Map(Object.entries(json.infos));
|
|
152
|
+
return new ProjectArtifact(compilerOptionsUsed, files);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
ProjectArtifact.artifactFileName = '.project.json';
|
|
156
|
+
class Project {
|
|
157
|
+
constructor(provider, contractsRootPath, artifactsRootPath, sourceFiles, contracts, scripts, errorOnWarnings, projectArtifact) {
|
|
158
|
+
this.nodeProvider = provider;
|
|
159
|
+
this.contractsRootPath = contractsRootPath;
|
|
160
|
+
this.artifactsRootPath = artifactsRootPath;
|
|
161
|
+
this.sourceFiles = sourceFiles;
|
|
162
|
+
this.contracts = contracts;
|
|
163
|
+
this.scripts = scripts;
|
|
164
|
+
this.projectArtifact = projectArtifact;
|
|
165
|
+
if (errorOnWarnings) {
|
|
166
|
+
Project.checkCompilerWarnings([...contracts.map((c) => c.warnings).flat(), ...scripts.map((s) => s.warnings).flat()], errorOnWarnings);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
static buildProjectArtifact(sourceFiles, contracts, scripts, compilerOptions) {
|
|
170
|
+
const files = new Map();
|
|
171
|
+
contracts.forEach((c) => {
|
|
172
|
+
files.set(c.sourceFile.contractPath, {
|
|
173
|
+
sourceCodeHash: c.sourceFile.sourceCodeHash,
|
|
174
|
+
warnings: c.warnings
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
scripts.forEach((s) => {
|
|
178
|
+
files.set(s.sourceFile.contractPath, {
|
|
179
|
+
sourceCodeHash: s.sourceFile.sourceCodeHash,
|
|
180
|
+
warnings: s.warnings
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
const compiledSize = contracts.length + scripts.length;
|
|
184
|
+
sourceFiles.slice(compiledSize).forEach((c) => {
|
|
185
|
+
files.set(c.contractPath, {
|
|
186
|
+
sourceCodeHash: c.sourceCodeHash,
|
|
187
|
+
warnings: []
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
return new ProjectArtifact(compilerOptions, files);
|
|
191
|
+
}
|
|
192
|
+
getContractPath(path) {
|
|
193
|
+
return path.startsWith(`./${this.contractsRootPath}`)
|
|
194
|
+
? path.slice(2)
|
|
195
|
+
: path.startsWith(this.contractsRootPath)
|
|
196
|
+
? path
|
|
197
|
+
: this.contractsRootPath + '/' + path;
|
|
198
|
+
}
|
|
199
|
+
static checkCompilerWarnings(warnings, errorOnWarnings) {
|
|
200
|
+
if (warnings.length !== 0) {
|
|
201
|
+
const prefixPerWarning = ' - ';
|
|
202
|
+
const warningString = prefixPerWarning + warnings.join('\n' + prefixPerWarning);
|
|
203
|
+
const output = `Compilation warnings:\n` + warningString + '\n';
|
|
204
|
+
if (errorOnWarnings) {
|
|
205
|
+
throw new Error(output);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
console.log(output);
|
|
98
209
|
}
|
|
99
210
|
}
|
|
100
|
-
return result;
|
|
101
211
|
}
|
|
102
|
-
static
|
|
103
|
-
const contractPath =
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
212
|
+
static contract(path) {
|
|
213
|
+
const contractPath = Project.currentProject.getContractPath(path);
|
|
214
|
+
const contract = Project.currentProject.contracts.find((c) => c.sourceFile.contractPath === contractPath);
|
|
215
|
+
if (typeof contract === 'undefined') {
|
|
216
|
+
throw new Error(`Contract ${contractPath} does not exist`);
|
|
217
|
+
}
|
|
218
|
+
return contract.artifact;
|
|
108
219
|
}
|
|
109
|
-
static
|
|
110
|
-
|
|
111
|
-
|
|
220
|
+
static script(path) {
|
|
221
|
+
const contractPath = Project.currentProject.getContractPath(path);
|
|
222
|
+
const script = Project.currentProject.scripts.find((c) => c.sourceFile.contractPath === contractPath);
|
|
223
|
+
if (typeof script === 'undefined') {
|
|
224
|
+
throw new Error(`Script ${contractPath} does not exist`);
|
|
112
225
|
}
|
|
226
|
+
return script.artifact;
|
|
113
227
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
228
|
+
async saveArtifactsToFile() {
|
|
229
|
+
const artifactsRootPath = this.artifactsRootPath;
|
|
230
|
+
const saveToFile = async function (compiled) {
|
|
231
|
+
const artifactPath = compiled.sourceFile.getArtifactPath(artifactsRootPath);
|
|
232
|
+
const folder = artifactPath.slice(0, artifactPath.lastIndexOf('/'));
|
|
233
|
+
if (!fs_1.default.existsSync(folder)) {
|
|
234
|
+
fs_1.default.mkdirSync(folder, { recursive: true });
|
|
235
|
+
}
|
|
236
|
+
return fs_2.promises.writeFile(artifactPath, compiled.artifact.toString());
|
|
237
|
+
};
|
|
238
|
+
for (const contract of this.contracts) {
|
|
239
|
+
await saveToFile(contract);
|
|
121
240
|
}
|
|
122
|
-
|
|
123
|
-
|
|
241
|
+
for (const script of this.scripts) {
|
|
242
|
+
await saveToFile(script);
|
|
124
243
|
}
|
|
244
|
+
await this.projectArtifact.saveToFile(this.artifactsRootPath);
|
|
125
245
|
}
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
|
|
246
|
+
contractByCodeHash(codeHash) {
|
|
247
|
+
const contract = this.contracts.find((c) => c.artifact.codeHash === codeHash);
|
|
248
|
+
if (typeof contract === 'undefined') {
|
|
249
|
+
throw new Error(`Unknown code with code hash: ${codeHash}`);
|
|
250
|
+
}
|
|
251
|
+
return contract.artifact;
|
|
129
252
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
253
|
+
static async compile(provider, files, contractsRootPath, artifactsRootPath, errorOnWarnings, compilerOptions) {
|
|
254
|
+
const sourceStr = files.map((f) => f.sourceCode).join('\n');
|
|
255
|
+
const result = await provider.contracts.postContractsCompileProject({
|
|
256
|
+
code: sourceStr,
|
|
257
|
+
compilerOptions: compilerOptions
|
|
258
|
+
});
|
|
259
|
+
const contracts = [];
|
|
260
|
+
const scripts = [];
|
|
261
|
+
result.contracts.forEach((contractResult, index) => {
|
|
262
|
+
const sourceFile = files[`${index}`];
|
|
263
|
+
const contract = Contract.fromCompileResult(contractResult);
|
|
264
|
+
contracts.push(new Compiled(sourceFile, contract, contractResult.warnings));
|
|
265
|
+
});
|
|
266
|
+
result.scripts.forEach((scriptResult, index) => {
|
|
267
|
+
const sourceFile = files[index + contracts.length];
|
|
268
|
+
const script = Script.fromCompileResult(scriptResult);
|
|
269
|
+
scripts.push(new Compiled(sourceFile, script, scriptResult.warnings));
|
|
270
|
+
});
|
|
271
|
+
const projectArtifact = Project.buildProjectArtifact(files, contracts, scripts, compilerOptions);
|
|
272
|
+
const project = new Project(provider, contractsRootPath, artifactsRootPath, files, contracts, scripts, errorOnWarnings, projectArtifact);
|
|
273
|
+
await project.saveArtifactsToFile();
|
|
274
|
+
return project;
|
|
145
275
|
}
|
|
146
|
-
static
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
276
|
+
static async loadArtifacts(provider, files, projectArtifact, contractsRootPath, artifactsRootPath, errorOnWarnings, compilerOptions) {
|
|
277
|
+
try {
|
|
278
|
+
const contracts = [];
|
|
279
|
+
const scripts = [];
|
|
280
|
+
for (const file of files) {
|
|
281
|
+
const info = projectArtifact.infos.get(file.contractPath);
|
|
282
|
+
if (typeof info === 'undefined') {
|
|
283
|
+
throw Error(`Unable to find project info for ${file.contractPath}, please rebuild the project`);
|
|
284
|
+
}
|
|
285
|
+
const warnings = info.warnings;
|
|
286
|
+
const artifactPath = file.getArtifactPath(artifactsRootPath);
|
|
287
|
+
if (file.type === SourceType.Contract) {
|
|
288
|
+
const artifact = await Contract.fromArtifactFile(artifactPath);
|
|
289
|
+
contracts.push(new Compiled(file, artifact, warnings));
|
|
290
|
+
}
|
|
291
|
+
else if (file.type === SourceType.Script) {
|
|
292
|
+
const artifact = await Script.fromArtifactFile(artifactPath);
|
|
293
|
+
scripts.push(new Compiled(file, artifact, warnings));
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return new Project(provider, contractsRootPath, artifactsRootPath, files, contracts, scripts, errorOnWarnings, projectArtifact);
|
|
154
297
|
}
|
|
155
|
-
|
|
156
|
-
|
|
298
|
+
catch (error) {
|
|
299
|
+
console.log(`Failed to load artifacts, error: ${error}, try to re-compile contracts...`);
|
|
300
|
+
return Project.compile(provider, files, contractsRootPath, artifactsRootPath, errorOnWarnings, compilerOptions);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
static async loadSourceFile(dirPath, filename) {
|
|
304
|
+
const contractPath = dirPath + '/' + filename;
|
|
305
|
+
if (!filename.endsWith('.ral')) {
|
|
306
|
+
throw new Error(`Invalid filename: ${contractPath}, smart contract file name should end with ".ral"`);
|
|
307
|
+
}
|
|
308
|
+
const sourceBuffer = await fs_2.promises.readFile(contractPath);
|
|
309
|
+
const sourceStr = sourceBuffer.toString();
|
|
310
|
+
const results = this.matchers.map((m) => m.match(sourceStr));
|
|
311
|
+
const matchNumber = results.reduce((a, b) => a + b, 0);
|
|
312
|
+
if (matchNumber === 0) {
|
|
313
|
+
throw new Error(`No contract defined in file: ${contractPath}`);
|
|
314
|
+
}
|
|
315
|
+
if (matchNumber > 1) {
|
|
316
|
+
throw new Error(`Multiple definitions in file: ${contractPath}`);
|
|
317
|
+
}
|
|
318
|
+
const matcherIndex = results.indexOf(1);
|
|
319
|
+
const type = this.matchers[`${matcherIndex}`].type;
|
|
320
|
+
return SourceFile.from(type, sourceStr, contractPath);
|
|
321
|
+
}
|
|
322
|
+
static async loadSourceFiles(contractsRootPath) {
|
|
323
|
+
const loadDir = async function (dirPath, results) {
|
|
324
|
+
const dirents = await fs_2.promises.readdir(dirPath, { withFileTypes: true });
|
|
325
|
+
for (const dirent of dirents) {
|
|
326
|
+
if (dirent.isFile()) {
|
|
327
|
+
const file = await Project.loadSourceFile(dirPath, dirent.name);
|
|
328
|
+
results.push(file);
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
const newPath = dirPath + '/' + dirent.name;
|
|
332
|
+
await loadDir(newPath, results);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
const sourceFiles = [];
|
|
337
|
+
await loadDir(contractsRootPath, sourceFiles);
|
|
338
|
+
const contractAndScriptSize = sourceFiles.filter((f) => f.type === SourceType.Contract || f.type === SourceType.Script).length;
|
|
339
|
+
if (sourceFiles.length === 0 || contractAndScriptSize === 0) {
|
|
340
|
+
throw new Error('Project have no source files');
|
|
341
|
+
}
|
|
342
|
+
return sourceFiles.sort((a, b) => a.type - b.type);
|
|
343
|
+
}
|
|
344
|
+
static async build(compilerOptionsPartial = {}, contractsRootPath = 'contracts', artifactsRootPath = 'artifacts') {
|
|
345
|
+
const provider = (0, global_1.getCurrentNodeProvider)();
|
|
346
|
+
const sourceFiles = await Project.loadSourceFiles(contractsRootPath);
|
|
347
|
+
const { errorOnWarnings, ...nodeCompilerOptions } = { ...exports.DEFAULT_COMPILER_OPTIONS, ...compilerOptionsPartial };
|
|
348
|
+
const projectArtifact = await ProjectArtifact.from(artifactsRootPath);
|
|
349
|
+
if (typeof projectArtifact === 'undefined' || projectArtifact.needToReCompile(nodeCompilerOptions, sourceFiles)) {
|
|
350
|
+
console.log(`Compile contracts in folder "${contractsRootPath}"`);
|
|
351
|
+
Project.currentProject = await Project.compile(provider, sourceFiles, contractsRootPath, artifactsRootPath, errorOnWarnings, nodeCompilerOptions);
|
|
157
352
|
}
|
|
158
353
|
else {
|
|
159
|
-
|
|
160
|
-
|
|
354
|
+
console.log(`Load compiled contracts from folder "${artifactsRootPath}"`);
|
|
355
|
+
Project.currentProject = await Project.loadArtifacts(provider, sourceFiles, projectArtifact, contractsRootPath, artifactsRootPath, errorOnWarnings, nodeCompilerOptions);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
exports.Project = Project;
|
|
360
|
+
Project.abstractContractMatcher = new TypedMatcher('^Abstract Contract [A-Z][a-zA-Z0-9]*', SourceType.AbstractContract);
|
|
361
|
+
Project.contractMatcher = new TypedMatcher('^Contract [A-Z][a-zA-Z0-9]*', SourceType.Contract);
|
|
362
|
+
Project.interfaceMatcher = new TypedMatcher('^Interface [A-Z][a-zA-Z0-9]* \\{', SourceType.Interface);
|
|
363
|
+
Project.scriptMatcher = new TypedMatcher('^TxScript [A-Z][a-zA-Z0-9]*', SourceType.Script);
|
|
364
|
+
Project.matchers = [
|
|
365
|
+
Project.abstractContractMatcher,
|
|
366
|
+
Project.contractMatcher,
|
|
367
|
+
Project.interfaceMatcher,
|
|
368
|
+
Project.scriptMatcher
|
|
369
|
+
];
|
|
370
|
+
class Artifact {
|
|
371
|
+
constructor(functions) {
|
|
372
|
+
this.functions = functions;
|
|
161
373
|
}
|
|
162
|
-
|
|
163
|
-
return
|
|
374
|
+
publicFunctions() {
|
|
375
|
+
return this.functions.filter((func) => func.isPublic).map((func) => func.name);
|
|
164
376
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
fs_1.default.mkdirSync(Common._artifactsFolder(), { recursive: true });
|
|
168
|
-
}
|
|
169
|
-
const contract = await Common._from(provider, fileName, (fileName, importCaches) => Contract.loadContractStr(fileName, importCaches), Contract.compile);
|
|
170
|
-
this._putArtifactToCache(contract);
|
|
171
|
-
return contract;
|
|
377
|
+
usingPreapprovedAssetsFunctions() {
|
|
378
|
+
return this.functions.filter((func) => func.usePreapprovedAssets).map((func) => func.name);
|
|
172
379
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
380
|
+
usingAssetsInContractFunctions() {
|
|
381
|
+
return this.functions.filter((func) => func.useAssetsInContract).map((func) => func.name);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
exports.Artifact = Artifact;
|
|
385
|
+
class Contract extends Artifact {
|
|
386
|
+
constructor(bytecode, codeHash, fieldsSig, eventsSig, functions) {
|
|
387
|
+
super(functions);
|
|
388
|
+
this.bytecode = bytecode;
|
|
389
|
+
this.codeHash = codeHash;
|
|
390
|
+
this.fieldsSig = fieldsSig;
|
|
391
|
+
this.eventsSig = eventsSig;
|
|
178
392
|
}
|
|
179
393
|
// TODO: safely parse json
|
|
180
394
|
static fromJson(artifact) {
|
|
181
|
-
if (artifact.
|
|
182
|
-
artifact.bytecode == null ||
|
|
395
|
+
if (artifact.bytecode == null ||
|
|
183
396
|
artifact.codeHash == null ||
|
|
184
397
|
artifact.fieldsSig == null ||
|
|
185
398
|
artifact.eventsSig == null ||
|
|
186
399
|
artifact.functions == null) {
|
|
187
400
|
throw Error('The artifact JSON for contract is incomplete');
|
|
188
401
|
}
|
|
189
|
-
const contract = new Contract(artifact.
|
|
190
|
-
this._putArtifactToCache(contract);
|
|
402
|
+
const contract = new Contract(artifact.bytecode, artifact.codeHash, artifact.fieldsSig, artifact.eventsSig, artifact.functions);
|
|
191
403
|
return contract;
|
|
192
404
|
}
|
|
405
|
+
static fromCompileResult(result) {
|
|
406
|
+
return new Contract(result.bytecode, result.codeHash, result.fields, result.events, result.functions);
|
|
407
|
+
}
|
|
193
408
|
// support both 'code.ral' and 'code.ral.json'
|
|
194
|
-
static async fromArtifactFile(
|
|
195
|
-
const
|
|
196
|
-
const content = await fs_2.promises.readFile(artifactPath);
|
|
409
|
+
static async fromArtifactFile(path) {
|
|
410
|
+
const content = await fs_2.promises.readFile(path);
|
|
197
411
|
const artifact = JSON.parse(content.toString());
|
|
198
412
|
return Contract.fromJson(artifact);
|
|
199
413
|
}
|
|
414
|
+
async fetchState(address, group) {
|
|
415
|
+
const state = await Project.currentProject.nodeProvider.contracts.getContractsAddressState(address, {
|
|
416
|
+
group: group
|
|
417
|
+
});
|
|
418
|
+
return this.fromApiContractState(state);
|
|
419
|
+
}
|
|
200
420
|
toString() {
|
|
201
|
-
|
|
202
|
-
sourceCodeSha256: this.sourceCodeSha256,
|
|
421
|
+
const object = {
|
|
203
422
|
bytecode: this.bytecode,
|
|
204
423
|
codeHash: this.codeHash,
|
|
205
424
|
fieldsSig: this.fieldsSig,
|
|
206
425
|
eventsSig: this.eventsSig,
|
|
207
426
|
functions: this.functions
|
|
208
|
-
}
|
|
427
|
+
};
|
|
428
|
+
return JSON.stringify(object, null, 2);
|
|
209
429
|
}
|
|
210
430
|
toState(fields, asset, address) {
|
|
211
431
|
const addressDef = typeof address !== 'undefined' ? address : Contract.randomAddress();
|
|
@@ -219,16 +439,18 @@ class Contract extends Common {
|
|
|
219
439
|
asset: asset
|
|
220
440
|
};
|
|
221
441
|
}
|
|
442
|
+
// no need to be cryptographically strong random
|
|
222
443
|
static randomAddress() {
|
|
223
|
-
const bytes =
|
|
444
|
+
const bytes = new Uint8Array(33);
|
|
445
|
+
crypto_1.webcrypto.getRandomValues(bytes);
|
|
224
446
|
bytes[0] = 3;
|
|
225
447
|
return utils_1.bs58.encode(bytes);
|
|
226
448
|
}
|
|
227
|
-
async _test(
|
|
449
|
+
async _test(funcName, params, expectPublic, accessType) {
|
|
228
450
|
const apiParams = this.toTestContract(funcName, params);
|
|
229
|
-
const apiResult = await
|
|
451
|
+
const apiResult = await Project.currentProject.nodeProvider.contracts.postContractsTestContract(apiParams);
|
|
230
452
|
const methodIndex = typeof params.testMethodIndex !== 'undefined' ? params.testMethodIndex : this.getMethodIndex(funcName);
|
|
231
|
-
const isPublic = this.functions[`${methodIndex}`].
|
|
453
|
+
const isPublic = this.functions[`${methodIndex}`].isPublic;
|
|
232
454
|
if (isPublic === expectPublic) {
|
|
233
455
|
const result = await this.fromTestContractResult(methodIndex, apiResult);
|
|
234
456
|
return result;
|
|
@@ -237,11 +459,11 @@ class Contract extends Common {
|
|
|
237
459
|
throw new Error(`The test method ${funcName} is not ${accessType}`);
|
|
238
460
|
}
|
|
239
461
|
}
|
|
240
|
-
async testPublicMethod(
|
|
241
|
-
return this._test(
|
|
462
|
+
async testPublicMethod(funcName, params) {
|
|
463
|
+
return this._test(funcName, params, true, 'public');
|
|
242
464
|
}
|
|
243
|
-
async testPrivateMethod(
|
|
244
|
-
return this._test(
|
|
465
|
+
async testPrivateMethod(funcName, params) {
|
|
466
|
+
return this._test(funcName, params, false, 'private');
|
|
245
467
|
}
|
|
246
468
|
toApiFields(fields) {
|
|
247
469
|
if (typeof fields === 'undefined') {
|
|
@@ -282,30 +504,8 @@ class Contract extends Common {
|
|
|
282
504
|
inputAssets: toApiInputAssets(params.inputAssets)
|
|
283
505
|
};
|
|
284
506
|
}
|
|
285
|
-
static async fromCodeHash(codeHash) {
|
|
286
|
-
const cached = this._getArtifactFromCache(codeHash);
|
|
287
|
-
if (typeof cached !== 'undefined') {
|
|
288
|
-
return cached;
|
|
289
|
-
}
|
|
290
|
-
const files = await fs_2.promises.readdir(Common._artifactsFolder());
|
|
291
|
-
for (const file of files) {
|
|
292
|
-
if (file.endsWith('.ral.json')) {
|
|
293
|
-
try {
|
|
294
|
-
const contract = await Contract.fromArtifactFile(file);
|
|
295
|
-
if (contract.codeHash === codeHash) {
|
|
296
|
-
return contract;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
catch (_) { }
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
throw new Error(`Unknown code with code hash: ${codeHash}`);
|
|
303
|
-
}
|
|
304
|
-
static async getFieldsSig(state) {
|
|
305
|
-
return Contract.fromCodeHash(state.codeHash).then((contract) => contract.fieldsSig);
|
|
306
|
-
}
|
|
307
507
|
async fromApiContractState(state) {
|
|
308
|
-
const contract =
|
|
508
|
+
const contract = Project.currentProject.contractByCodeHash(state.codeHash);
|
|
309
509
|
return {
|
|
310
510
|
address: state.address,
|
|
311
511
|
contractId: (0, utils_1.binToHex)((0, utils_1.contractIdFromAddress)(state.address)),
|
|
@@ -313,7 +513,7 @@ class Contract extends Common {
|
|
|
313
513
|
initialStateHash: state.initialStateHash,
|
|
314
514
|
codeHash: state.codeHash,
|
|
315
515
|
fields: fromApiFields(state.fields, contract.fieldsSig),
|
|
316
|
-
fieldsSig:
|
|
516
|
+
fieldsSig: contract.fieldsSig,
|
|
317
517
|
asset: fromApiAsset(state.asset)
|
|
318
518
|
};
|
|
319
519
|
}
|
|
@@ -326,7 +526,7 @@ class Contract extends Common {
|
|
|
326
526
|
eventSig = this.ContractDestroyedEvent;
|
|
327
527
|
}
|
|
328
528
|
else {
|
|
329
|
-
const contract =
|
|
529
|
+
const contract = Project.currentProject.contractByCodeHash(codeHash);
|
|
330
530
|
eventSig = contract.eventsSig[event.eventIndex];
|
|
331
531
|
}
|
|
332
532
|
return {
|
|
@@ -387,69 +587,42 @@ class Contract extends Common {
|
|
|
387
587
|
exports.Contract = Contract;
|
|
388
588
|
Contract.ContractCreatedEvent = {
|
|
389
589
|
name: 'ContractCreated',
|
|
390
|
-
signature: 'event ContractCreated(address:Address)',
|
|
391
590
|
fieldNames: ['address'],
|
|
392
591
|
fieldTypes: ['Address']
|
|
393
592
|
};
|
|
394
593
|
Contract.ContractDestroyedEvent = {
|
|
395
594
|
name: 'ContractDestroyed',
|
|
396
|
-
signature: 'event ContractDestroyed(address:Address)',
|
|
397
595
|
fieldNames: ['address'],
|
|
398
596
|
fieldTypes: ['Address']
|
|
399
597
|
};
|
|
400
|
-
class Script extends
|
|
401
|
-
constructor(
|
|
402
|
-
super(
|
|
598
|
+
class Script extends Artifact {
|
|
599
|
+
constructor(bytecodeTemplate, fieldsSig, functions) {
|
|
600
|
+
super(functions);
|
|
403
601
|
this.bytecodeTemplate = bytecodeTemplate;
|
|
404
602
|
this.fieldsSig = fieldsSig;
|
|
405
603
|
}
|
|
406
|
-
static
|
|
407
|
-
|
|
408
|
-
if (scriptMatches === null) {
|
|
409
|
-
throw new Error(`No script found in: ${fileName}`);
|
|
410
|
-
}
|
|
411
|
-
else if (scriptMatches.length > 1) {
|
|
412
|
-
throw new Error(`Multiple scripts in: ${fileName}`);
|
|
413
|
-
}
|
|
414
|
-
else {
|
|
415
|
-
return;
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
static async loadContractStr(fileName, importsCache) {
|
|
419
|
-
return Common._loadContractStr(fileName, importsCache, (code) => Script.checkCodeType(fileName, code));
|
|
420
|
-
}
|
|
421
|
-
static async fromSource(provider, fileName) {
|
|
422
|
-
return Common._from(provider, fileName, (fileName, importsCache) => Script.loadContractStr(fileName, importsCache), Script.compile);
|
|
423
|
-
}
|
|
424
|
-
static async compile(provider, fileName, scriptStr, contractHash) {
|
|
425
|
-
const compiled = await provider.contracts.postContractsCompileScript({ code: scriptStr });
|
|
426
|
-
const artifact = new Script(contractHash, compiled.bytecodeTemplate, compiled.fields, compiled.functions);
|
|
427
|
-
await artifact._saveToFile(fileName);
|
|
428
|
-
return artifact;
|
|
604
|
+
static fromCompileResult(result) {
|
|
605
|
+
return new Script(result.bytecodeTemplate, result.fields, result.functions);
|
|
429
606
|
}
|
|
430
607
|
// TODO: safely parse json
|
|
431
608
|
static fromJson(artifact) {
|
|
432
|
-
if (artifact.
|
|
433
|
-
artifact.bytecodeTemplate == null ||
|
|
434
|
-
artifact.fieldsSig == null ||
|
|
435
|
-
artifact.functions == null) {
|
|
609
|
+
if (artifact.bytecodeTemplate == null || artifact.fieldsSig == null || artifact.functions == null) {
|
|
436
610
|
throw Error('The artifact JSON for script is incomplete');
|
|
437
611
|
}
|
|
438
|
-
return new Script(artifact.
|
|
612
|
+
return new Script(artifact.bytecodeTemplate, artifact.fieldsSig, artifact.functions);
|
|
439
613
|
}
|
|
440
|
-
static async fromArtifactFile(
|
|
441
|
-
const
|
|
442
|
-
const content = await fs_2.promises.readFile(artifactPath);
|
|
614
|
+
static async fromArtifactFile(path) {
|
|
615
|
+
const content = await fs_2.promises.readFile(path);
|
|
443
616
|
const artifact = JSON.parse(content.toString());
|
|
444
617
|
return this.fromJson(artifact);
|
|
445
618
|
}
|
|
446
619
|
toString() {
|
|
447
|
-
|
|
448
|
-
sourceCodeSha256: this.sourceCodeSha256,
|
|
620
|
+
const object = {
|
|
449
621
|
bytecodeTemplate: this.bytecodeTemplate,
|
|
450
622
|
fieldsSig: this.fieldsSig,
|
|
451
623
|
functions: this.functions
|
|
452
|
-
}
|
|
624
|
+
};
|
|
625
|
+
return JSON.stringify(object, null, 2);
|
|
453
626
|
}
|
|
454
627
|
async paramsForDeployment(params) {
|
|
455
628
|
const signerParams = {
|
|
@@ -713,7 +886,7 @@ function toApiFields(fields, fieldsSig) {
|
|
|
713
886
|
return toApiVals(fields, fieldsSig.names, fieldsSig.types);
|
|
714
887
|
}
|
|
715
888
|
function toApiArgs(args, funcSig) {
|
|
716
|
-
return toApiVals(args, funcSig.
|
|
889
|
+
return toApiVals(args, funcSig.paramNames, funcSig.paramTypes);
|
|
717
890
|
}
|
|
718
891
|
function toApiVals(fields, names, types) {
|
|
719
892
|
return names.map((name, index) => {
|