@alephium/web3 0.2.0-rc.1 → 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 +2 -2
- package/contracts/greeter/greeter_interface.ral +1 -0
- package/contracts/greeter_main.ral +0 -2
- 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 +44 -11
- package/dist/src/api/api-alephium.js +16 -0
- package/dist/src/api/api-explorer.d.ts +16 -16
- package/dist/src/api/index.d.ts +2 -2
- package/dist/src/api/index.js +18 -3
- package/dist/src/contract/contract.d.ts +101 -52
- package/dist/src/contract/contract.js +353 -219
- 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 +2 -0
- package/dist/src/index.js +20 -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 +0 -1
- package/dist/src/transaction/index.js +5 -2
- 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 -1
- package/dist/src/utils/subscription.js +2 -1
- package/dist/src/utils/utils.d.ts +5 -4
- package/dist/src/utils/utils.js +17 -16
- package/jest-config.json +11 -0
- package/package.json +6 -34
- package/scripts/create-project.ts +3 -2
- package/src/api/api-alephium.ts +53 -5
- package/src/api/index.ts +13 -3
- package/src/contract/contract.ts +505 -318
- package/src/contract/events.ts +2 -2
- package/src/{transaction/sign-verify.ts → global.ts} +14 -15
- package/src/index.ts +3 -0
- package/src/signer/index.ts +0 -1
- package/src/signer/signer.ts +3 -2
- package/src/transaction/index.ts +0 -1
- package/src/transaction/status.ts +1 -1
- package/src/utils/index.ts +0 -1
- package/src/utils/subscription.ts +3 -3
- package/src/utils/utils.ts +10 -10
- 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/add.ral +0 -16
- package/contracts/main.ral +0 -6
- package/contracts/sub/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/index.js +0 -41
- package/dist/src/test/privatekey-wallet.d.ts +0 -12
- 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 -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/transaction/sign-verify.test.ts +0 -50
- 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/test/contract.test.ts +0 -178
- package/test/events.test.ts +0 -138
- package/test/transaction.test.ts +0 -72
|
@@ -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,210 +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");
|
|
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;
|
|
74
|
+
}
|
|
75
|
+
match(str) {
|
|
76
|
+
const results = str.match(this.matcher);
|
|
77
|
+
return results === null ? 0 : results.length;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
50
80
|
class SourceFile {
|
|
51
|
-
constructor(
|
|
52
|
-
this.
|
|
53
|
-
this.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
81
|
+
constructor(type, sourceCode, sourceCodeHash, contractPath) {
|
|
82
|
+
this.type = type;
|
|
83
|
+
this.sourceCode = sourceCode;
|
|
84
|
+
this.sourceCodeHash = sourceCodeHash;
|
|
85
|
+
this.contractPath = contractPath;
|
|
86
|
+
}
|
|
87
|
+
getArtifactPath(artifactsRootPath) {
|
|
88
|
+
return artifactsRootPath + this.contractPath.slice(this.contractPath.indexOf('/')) + '.json';
|
|
89
|
+
}
|
|
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);
|
|
62
93
|
}
|
|
63
94
|
}
|
|
64
|
-
class
|
|
65
|
-
constructor(
|
|
66
|
-
this.
|
|
67
|
-
this.
|
|
95
|
+
class Compiled {
|
|
96
|
+
constructor(sourceFile, artifact, warnings) {
|
|
97
|
+
this.sourceFile = sourceFile;
|
|
98
|
+
this.artifact = artifact;
|
|
99
|
+
this.warnings = warnings;
|
|
68
100
|
}
|
|
69
|
-
|
|
70
|
-
|
|
101
|
+
}
|
|
102
|
+
class ProjectArtifact {
|
|
103
|
+
constructor(compilerOptionsUsed, infos) {
|
|
104
|
+
ProjectArtifact.checkCompilerOptionsParameter(compilerOptionsUsed);
|
|
105
|
+
this.compilerOptionsUsed = compilerOptionsUsed;
|
|
106
|
+
this.infos = infos;
|
|
71
107
|
}
|
|
72
|
-
static
|
|
73
|
-
if (
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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}`);
|
|
111
|
+
}
|
|
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}`);
|
|
79
115
|
}
|
|
80
116
|
}
|
|
81
|
-
|
|
82
|
-
|
|
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);
|
|
83
122
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
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;
|
|
128
|
+
});
|
|
129
|
+
if (!optionsMatched) {
|
|
130
|
+
return true;
|
|
89
131
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
throw new Error('Invalid file path: ' + path);
|
|
98
|
-
}
|
|
99
|
-
dirs.pop();
|
|
100
|
-
break;
|
|
101
|
-
}
|
|
102
|
-
default: {
|
|
103
|
-
dirs.push(part);
|
|
104
|
-
}
|
|
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;
|
|
105
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
|
+
});
|
|
106
176
|
});
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
+
});
|
|
114
189
|
});
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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);
|
|
122
209
|
}
|
|
123
210
|
}
|
|
124
|
-
return result;
|
|
125
211
|
}
|
|
126
|
-
static
|
|
127
|
-
const contractPath =
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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;
|
|
132
219
|
}
|
|
133
|
-
static
|
|
134
|
-
|
|
135
|
-
|
|
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`);
|
|
136
225
|
}
|
|
226
|
+
return script.artifact;
|
|
137
227
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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);
|
|
145
240
|
}
|
|
146
|
-
|
|
147
|
-
|
|
241
|
+
for (const script of this.scripts) {
|
|
242
|
+
await saveToFile(script);
|
|
148
243
|
}
|
|
244
|
+
await this.projectArtifact.saveToFile(this.artifactsRootPath);
|
|
149
245
|
}
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
if (
|
|
153
|
-
|
|
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}`);
|
|
154
250
|
}
|
|
155
|
-
return
|
|
251
|
+
return contract.artifact;
|
|
156
252
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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;
|
|
172
275
|
}
|
|
173
|
-
static
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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
|
+
}
|
|
185
295
|
}
|
|
296
|
+
return new Project(provider, contractsRootPath, artifactsRootPath, files, contracts, scripts, errorOnWarnings, projectArtifact);
|
|
186
297
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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
|
+
}
|
|
190
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);
|
|
191
352
|
}
|
|
353
|
+
else {
|
|
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;
|
|
192
373
|
}
|
|
193
|
-
|
|
194
|
-
return
|
|
374
|
+
publicFunctions() {
|
|
375
|
+
return this.functions.filter((func) => func.isPublic).map((func) => func.name);
|
|
195
376
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
fs_1.default.mkdirSync(Common._artifactsFolder(), { recursive: true });
|
|
199
|
-
}
|
|
200
|
-
const sourceFile = this.getSourceFile(path, []);
|
|
201
|
-
const contract = await Common._from(provider, sourceFile, (sourceFile) => Contract.loadContractStr(sourceFile), Contract.compile);
|
|
202
|
-
this._putArtifactToCache(contract);
|
|
203
|
-
return contract;
|
|
377
|
+
usingPreapprovedAssetsFunctions() {
|
|
378
|
+
return this.functions.filter((func) => func.usePreapprovedAssets).map((func) => func.name);
|
|
204
379
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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;
|
|
210
392
|
}
|
|
211
393
|
// TODO: safely parse json
|
|
212
394
|
static fromJson(artifact) {
|
|
213
|
-
if (artifact.
|
|
214
|
-
artifact.bytecode == null ||
|
|
395
|
+
if (artifact.bytecode == null ||
|
|
215
396
|
artifact.codeHash == null ||
|
|
216
397
|
artifact.fieldsSig == null ||
|
|
217
398
|
artifact.eventsSig == null ||
|
|
218
399
|
artifact.functions == null) {
|
|
219
400
|
throw Error('The artifact JSON for contract is incomplete');
|
|
220
401
|
}
|
|
221
|
-
const contract = new Contract(artifact.
|
|
222
|
-
this._putArtifactToCache(contract);
|
|
402
|
+
const contract = new Contract(artifact.bytecode, artifact.codeHash, artifact.fieldsSig, artifact.eventsSig, artifact.functions);
|
|
223
403
|
return contract;
|
|
224
404
|
}
|
|
405
|
+
static fromCompileResult(result) {
|
|
406
|
+
return new Contract(result.bytecode, result.codeHash, result.fields, result.events, result.functions);
|
|
407
|
+
}
|
|
225
408
|
// support both 'code.ral' and 'code.ral.json'
|
|
226
409
|
static async fromArtifactFile(path) {
|
|
227
|
-
const
|
|
228
|
-
const artifactPath = sourceFile.artifactPath;
|
|
229
|
-
const content = await fs_2.promises.readFile(artifactPath);
|
|
410
|
+
const content = await fs_2.promises.readFile(path);
|
|
230
411
|
const artifact = JSON.parse(content.toString());
|
|
231
412
|
return Contract.fromJson(artifact);
|
|
232
413
|
}
|
|
233
|
-
async fetchState(
|
|
234
|
-
const state = await
|
|
414
|
+
async fetchState(address, group) {
|
|
415
|
+
const state = await Project.currentProject.nodeProvider.contracts.getContractsAddressState(address, {
|
|
416
|
+
group: group
|
|
417
|
+
});
|
|
235
418
|
return this.fromApiContractState(state);
|
|
236
419
|
}
|
|
237
420
|
toString() {
|
|
238
|
-
|
|
239
|
-
sourceCodeSha256: this.sourceCodeSha256,
|
|
421
|
+
const object = {
|
|
240
422
|
bytecode: this.bytecode,
|
|
241
423
|
codeHash: this.codeHash,
|
|
242
424
|
fieldsSig: this.fieldsSig,
|
|
243
425
|
eventsSig: this.eventsSig,
|
|
244
426
|
functions: this.functions
|
|
245
|
-
}
|
|
427
|
+
};
|
|
428
|
+
return JSON.stringify(object, null, 2);
|
|
246
429
|
}
|
|
247
430
|
toState(fields, asset, address) {
|
|
248
431
|
const addressDef = typeof address !== 'undefined' ? address : Contract.randomAddress();
|
|
@@ -256,16 +439,18 @@ class Contract extends Common {
|
|
|
256
439
|
asset: asset
|
|
257
440
|
};
|
|
258
441
|
}
|
|
442
|
+
// no need to be cryptographically strong random
|
|
259
443
|
static randomAddress() {
|
|
260
|
-
const bytes =
|
|
444
|
+
const bytes = new Uint8Array(33);
|
|
445
|
+
crypto_1.webcrypto.getRandomValues(bytes);
|
|
261
446
|
bytes[0] = 3;
|
|
262
447
|
return utils_1.bs58.encode(bytes);
|
|
263
448
|
}
|
|
264
|
-
async _test(
|
|
449
|
+
async _test(funcName, params, expectPublic, accessType) {
|
|
265
450
|
const apiParams = this.toTestContract(funcName, params);
|
|
266
|
-
const apiResult = await
|
|
451
|
+
const apiResult = await Project.currentProject.nodeProvider.contracts.postContractsTestContract(apiParams);
|
|
267
452
|
const methodIndex = typeof params.testMethodIndex !== 'undefined' ? params.testMethodIndex : this.getMethodIndex(funcName);
|
|
268
|
-
const isPublic = this.functions[`${methodIndex}`].
|
|
453
|
+
const isPublic = this.functions[`${methodIndex}`].isPublic;
|
|
269
454
|
if (isPublic === expectPublic) {
|
|
270
455
|
const result = await this.fromTestContractResult(methodIndex, apiResult);
|
|
271
456
|
return result;
|
|
@@ -274,11 +459,11 @@ class Contract extends Common {
|
|
|
274
459
|
throw new Error(`The test method ${funcName} is not ${accessType}`);
|
|
275
460
|
}
|
|
276
461
|
}
|
|
277
|
-
async testPublicMethod(
|
|
278
|
-
return this._test(
|
|
462
|
+
async testPublicMethod(funcName, params) {
|
|
463
|
+
return this._test(funcName, params, true, 'public');
|
|
279
464
|
}
|
|
280
|
-
async testPrivateMethod(
|
|
281
|
-
return this._test(
|
|
465
|
+
async testPrivateMethod(funcName, params) {
|
|
466
|
+
return this._test(funcName, params, false, 'private');
|
|
282
467
|
}
|
|
283
468
|
toApiFields(fields) {
|
|
284
469
|
if (typeof fields === 'undefined') {
|
|
@@ -319,30 +504,8 @@ class Contract extends Common {
|
|
|
319
504
|
inputAssets: toApiInputAssets(params.inputAssets)
|
|
320
505
|
};
|
|
321
506
|
}
|
|
322
|
-
static async fromCodeHash(codeHash) {
|
|
323
|
-
const cached = this._getArtifactFromCache(codeHash);
|
|
324
|
-
if (typeof cached !== 'undefined') {
|
|
325
|
-
return cached;
|
|
326
|
-
}
|
|
327
|
-
const files = await fs_2.promises.readdir(Common._artifactsFolder());
|
|
328
|
-
for (const file of files) {
|
|
329
|
-
if (file.endsWith('.ral.json')) {
|
|
330
|
-
try {
|
|
331
|
-
const contract = await Contract.fromArtifactFile(file);
|
|
332
|
-
if (contract.codeHash === codeHash) {
|
|
333
|
-
return contract;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
catch (_) { }
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
throw new Error(`Unknown code with code hash: ${codeHash}`);
|
|
340
|
-
}
|
|
341
|
-
static async getFieldsSig(state) {
|
|
342
|
-
return Contract.fromCodeHash(state.codeHash).then((contract) => contract.fieldsSig);
|
|
343
|
-
}
|
|
344
507
|
async fromApiContractState(state) {
|
|
345
|
-
const contract =
|
|
508
|
+
const contract = Project.currentProject.contractByCodeHash(state.codeHash);
|
|
346
509
|
return {
|
|
347
510
|
address: state.address,
|
|
348
511
|
contractId: (0, utils_1.binToHex)((0, utils_1.contractIdFromAddress)(state.address)),
|
|
@@ -350,7 +513,7 @@ class Contract extends Common {
|
|
|
350
513
|
initialStateHash: state.initialStateHash,
|
|
351
514
|
codeHash: state.codeHash,
|
|
352
515
|
fields: fromApiFields(state.fields, contract.fieldsSig),
|
|
353
|
-
fieldsSig:
|
|
516
|
+
fieldsSig: contract.fieldsSig,
|
|
354
517
|
asset: fromApiAsset(state.asset)
|
|
355
518
|
};
|
|
356
519
|
}
|
|
@@ -363,7 +526,7 @@ class Contract extends Common {
|
|
|
363
526
|
eventSig = this.ContractDestroyedEvent;
|
|
364
527
|
}
|
|
365
528
|
else {
|
|
366
|
-
const contract =
|
|
529
|
+
const contract = Project.currentProject.contractByCodeHash(codeHash);
|
|
367
530
|
eventSig = contract.eventsSig[event.eventIndex];
|
|
368
531
|
}
|
|
369
532
|
return {
|
|
@@ -424,71 +587,42 @@ class Contract extends Common {
|
|
|
424
587
|
exports.Contract = Contract;
|
|
425
588
|
Contract.ContractCreatedEvent = {
|
|
426
589
|
name: 'ContractCreated',
|
|
427
|
-
signature: 'event ContractCreated(address:Address)',
|
|
428
590
|
fieldNames: ['address'],
|
|
429
591
|
fieldTypes: ['Address']
|
|
430
592
|
};
|
|
431
593
|
Contract.ContractDestroyedEvent = {
|
|
432
594
|
name: 'ContractDestroyed',
|
|
433
|
-
signature: 'event ContractDestroyed(address:Address)',
|
|
434
595
|
fieldNames: ['address'],
|
|
435
596
|
fieldTypes: ['Address']
|
|
436
597
|
};
|
|
437
|
-
class Script extends
|
|
438
|
-
constructor(
|
|
439
|
-
super(
|
|
598
|
+
class Script extends Artifact {
|
|
599
|
+
constructor(bytecodeTemplate, fieldsSig, functions) {
|
|
600
|
+
super(functions);
|
|
440
601
|
this.bytecodeTemplate = bytecodeTemplate;
|
|
441
602
|
this.fieldsSig = fieldsSig;
|
|
442
603
|
}
|
|
443
|
-
static
|
|
444
|
-
|
|
445
|
-
if (scriptMatches === null) {
|
|
446
|
-
throw new Error(`No script found in: ${fileName}`);
|
|
447
|
-
}
|
|
448
|
-
else if (scriptMatches.length > 1) {
|
|
449
|
-
throw new Error(`Multiple scripts in: ${fileName}`);
|
|
450
|
-
}
|
|
451
|
-
else {
|
|
452
|
-
return;
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
static async loadContractStr(sourceFile) {
|
|
456
|
-
return Common._loadContractStr(sourceFile, [], (code) => Script.checkCodeType(sourceFile.contractPath, code));
|
|
457
|
-
}
|
|
458
|
-
static async fromSource(provider, path) {
|
|
459
|
-
const sourceFile = this.getSourceFile(path, []);
|
|
460
|
-
return Common._from(provider, sourceFile, (sourceFile) => Script.loadContractStr(sourceFile), Script.compile);
|
|
461
|
-
}
|
|
462
|
-
static async compile(provider, sourceFile, scriptStr, contractHash) {
|
|
463
|
-
const compiled = await provider.contracts.postContractsCompileScript({ code: scriptStr });
|
|
464
|
-
const artifact = new Script(contractHash, compiled.bytecodeTemplate, compiled.fields, compiled.functions);
|
|
465
|
-
await artifact._saveToFile(sourceFile);
|
|
466
|
-
return artifact;
|
|
604
|
+
static fromCompileResult(result) {
|
|
605
|
+
return new Script(result.bytecodeTemplate, result.fields, result.functions);
|
|
467
606
|
}
|
|
468
607
|
// TODO: safely parse json
|
|
469
608
|
static fromJson(artifact) {
|
|
470
|
-
if (artifact.
|
|
471
|
-
artifact.bytecodeTemplate == null ||
|
|
472
|
-
artifact.fieldsSig == null ||
|
|
473
|
-
artifact.functions == null) {
|
|
609
|
+
if (artifact.bytecodeTemplate == null || artifact.fieldsSig == null || artifact.functions == null) {
|
|
474
610
|
throw Error('The artifact JSON for script is incomplete');
|
|
475
611
|
}
|
|
476
|
-
return new Script(artifact.
|
|
612
|
+
return new Script(artifact.bytecodeTemplate, artifact.fieldsSig, artifact.functions);
|
|
477
613
|
}
|
|
478
614
|
static async fromArtifactFile(path) {
|
|
479
|
-
const
|
|
480
|
-
const artifactPath = sourceFile.artifactPath;
|
|
481
|
-
const content = await fs_2.promises.readFile(artifactPath);
|
|
615
|
+
const content = await fs_2.promises.readFile(path);
|
|
482
616
|
const artifact = JSON.parse(content.toString());
|
|
483
617
|
return this.fromJson(artifact);
|
|
484
618
|
}
|
|
485
619
|
toString() {
|
|
486
|
-
|
|
487
|
-
sourceCodeSha256: this.sourceCodeSha256,
|
|
620
|
+
const object = {
|
|
488
621
|
bytecodeTemplate: this.bytecodeTemplate,
|
|
489
622
|
fieldsSig: this.fieldsSig,
|
|
490
623
|
functions: this.functions
|
|
491
|
-
}
|
|
624
|
+
};
|
|
625
|
+
return JSON.stringify(object, null, 2);
|
|
492
626
|
}
|
|
493
627
|
async paramsForDeployment(params) {
|
|
494
628
|
const signerParams = {
|
|
@@ -752,7 +886,7 @@ function toApiFields(fields, fieldsSig) {
|
|
|
752
886
|
return toApiVals(fields, fieldsSig.names, fieldsSig.types);
|
|
753
887
|
}
|
|
754
888
|
function toApiArgs(args, funcSig) {
|
|
755
|
-
return toApiVals(args, funcSig.
|
|
889
|
+
return toApiVals(args, funcSig.paramNames, funcSig.paramTypes);
|
|
756
890
|
}
|
|
757
891
|
function toApiVals(fields, names, types) {
|
|
758
892
|
return names.map((name, index) => {
|