@alephium/web3 0.2.0-test.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +152 -24
- package/dist/src/api/api-alephium.js +163 -82
- package/dist/src/api/api-explorer.d.ts +192 -49
- package/dist/src/api/api-explorer.js +195 -34
- 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 +127 -80
- package/dist/src/contract/contract.js +425 -467
- 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 +7 -0
- package/dist/src/global.js +54 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +23 -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 +59 -60
- package/dist/src/signer/signer.js +99 -69
- 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 -3
- package/dist/src/utils/subscription.js +0 -1
- package/dist/src/utils/utils.d.ts +6 -11
- package/dist/src/utils/utils.js +22 -26
- package/jest-config.json +11 -0
- package/package.json +11 -47
- package/src/api/api-alephium.ts +219 -33
- package/src/api/api-explorer.ts +275 -52
- 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 +663 -581
- package/src/contract/events.ts +8 -7
- package/src/contract/ralph.ts +29 -4
- package/src/global.ts +56 -0
- package/src/index.ts +7 -0
- package/src/signer/index.ts +0 -1
- package/src/signer/signer.ts +165 -134
- package/src/transaction/index.ts +0 -1
- package/src/transaction/status.ts +6 -3
- package/src/utils/bs58.ts +11 -0
- package/src/utils/index.ts +0 -1
- package/src/utils/subscription.ts +1 -5
- package/src/utils/utils.ts +15 -23
- package/webpack.config.js +3 -0
- package/.eslintrc.json +0 -21
- package/LICENSE +0 -165
- package/contracts/add/add.ral +0 -16
- package/contracts/greeter/greeter.ral +0 -7
- package/contracts/greeter/greeter_interface.ral +0 -3
- package/contracts/greeter_main.ral +0 -9
- package/contracts/main.ral +0 -6
- package/contracts/sub/sub.ral +0 -9
- package/dev/user.conf +0 -29
- package/dist/scripts/create-project.d.ts +0 -2
- package/dist/scripts/create-project.js +0 -124
- 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 -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/scripts/create-project.ts +0 -136
- 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 -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/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 -41
- 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 -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,178 +43,369 @@ 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.
|
|
46
|
+
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");
|
|
51
|
+
const api_1 = require("../api");
|
|
48
52
|
const ralph = __importStar(require("./ralph"));
|
|
49
53
|
const utils_1 = require("../utils");
|
|
54
|
+
const global_1 = require("../global");
|
|
55
|
+
const __1 = require("..");
|
|
56
|
+
var SourceType;
|
|
57
|
+
(function (SourceType) {
|
|
58
|
+
SourceType[SourceType["Contract"] = 0] = "Contract";
|
|
59
|
+
SourceType[SourceType["Script"] = 1] = "Script";
|
|
60
|
+
SourceType[SourceType["AbstractContract"] = 2] = "AbstractContract";
|
|
61
|
+
SourceType[SourceType["Interface"] = 3] = "Interface";
|
|
62
|
+
})(SourceType || (SourceType = {}));
|
|
63
|
+
exports.DEFAULT_NODE_COMPILER_OPTIONS = {
|
|
64
|
+
ignoreUnusedConstantsWarnings: false,
|
|
65
|
+
ignoreUnusedVariablesWarnings: false,
|
|
66
|
+
ignoreUnusedFieldsWarnings: false,
|
|
67
|
+
ignoreUnusedPrivateFunctionsWarnings: false,
|
|
68
|
+
ignoreReadonlyCheckWarnings: false,
|
|
69
|
+
ignoreExternalCallCheckWarnings: false
|
|
70
|
+
};
|
|
71
|
+
exports.DEFAULT_COMPILER_OPTIONS = { errorOnWarnings: true, ...exports.DEFAULT_NODE_COMPILER_OPTIONS };
|
|
72
|
+
class TypedMatcher {
|
|
73
|
+
constructor(pattern, type) {
|
|
74
|
+
this.matcher = new RegExp(pattern, 'mg');
|
|
75
|
+
this.type = type;
|
|
76
|
+
}
|
|
77
|
+
match(str) {
|
|
78
|
+
const results = str.match(this.matcher);
|
|
79
|
+
return results === null ? 0 : results.length;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
50
82
|
class SourceFile {
|
|
51
|
-
constructor(
|
|
52
|
-
this.
|
|
53
|
-
this.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
83
|
+
constructor(type, sourceCode, sourceCodeHash, contractPath) {
|
|
84
|
+
this.type = type;
|
|
85
|
+
this.sourceCode = sourceCode;
|
|
86
|
+
this.sourceCodeHash = sourceCodeHash;
|
|
87
|
+
this.contractPath = contractPath;
|
|
88
|
+
}
|
|
89
|
+
getArtifactPath(artifactsRootDir) {
|
|
90
|
+
return artifactsRootDir + this.contractPath.slice(this.contractPath.indexOf('/')) + '.json';
|
|
91
|
+
}
|
|
92
|
+
static async from(type, sourceCode, contractPath) {
|
|
93
|
+
const sourceCodeHash = await crypto_1.webcrypto.subtle.digest('SHA-256', buffer_1.Buffer.from(sourceCode));
|
|
94
|
+
return new SourceFile(type, sourceCode, buffer_1.Buffer.from(sourceCodeHash).toString('hex'), contractPath);
|
|
62
95
|
}
|
|
63
96
|
}
|
|
64
|
-
class
|
|
65
|
-
constructor(
|
|
66
|
-
this.
|
|
67
|
-
this.
|
|
97
|
+
class Compiled {
|
|
98
|
+
constructor(sourceFile, artifact, warnings) {
|
|
99
|
+
this.sourceFile = sourceFile;
|
|
100
|
+
this.artifact = artifact;
|
|
101
|
+
this.warnings = warnings;
|
|
68
102
|
}
|
|
69
|
-
|
|
70
|
-
|
|
103
|
+
}
|
|
104
|
+
class ProjectArtifact {
|
|
105
|
+
constructor(compilerOptionsUsed, infos) {
|
|
106
|
+
ProjectArtifact.checkCompilerOptionsParameter(compilerOptionsUsed);
|
|
107
|
+
this.compilerOptionsUsed = compilerOptionsUsed;
|
|
108
|
+
this.infos = infos;
|
|
71
109
|
}
|
|
72
|
-
static
|
|
73
|
-
if (
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
110
|
+
static checkCompilerOptionsParameter(compilerOptions) {
|
|
111
|
+
if (Object.keys(compilerOptions).length != Object.keys(exports.DEFAULT_NODE_COMPILER_OPTIONS).length) {
|
|
112
|
+
throw Error(`Not all compiler options are set: ${compilerOptions}`);
|
|
113
|
+
}
|
|
114
|
+
const combined = { ...compilerOptions, ...exports.DEFAULT_NODE_COMPILER_OPTIONS };
|
|
115
|
+
if (Object.keys(combined).length !== Object.keys(exports.DEFAULT_NODE_COMPILER_OPTIONS).length) {
|
|
116
|
+
throw Error(`There are unknown compiler options: ${compilerOptions}`);
|
|
79
117
|
}
|
|
80
118
|
}
|
|
81
|
-
|
|
82
|
-
|
|
119
|
+
async saveToFile(rootPath) {
|
|
120
|
+
const filepath = rootPath + '/' + ProjectArtifact.artifactFileName;
|
|
121
|
+
const artifact = { compilerOptionsUsed: this.compilerOptionsUsed, infos: Object.fromEntries(this.infos) };
|
|
122
|
+
const content = JSON.stringify(artifact, null, 2);
|
|
123
|
+
return fs_2.promises.writeFile(filepath, content);
|
|
83
124
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
return
|
|
125
|
+
needToReCompile(compilerOptions, files) {
|
|
126
|
+
ProjectArtifact.checkCompilerOptionsParameter(compilerOptions);
|
|
127
|
+
const optionsMatched = Object.entries(compilerOptions).every(([key, inputOption]) => {
|
|
128
|
+
const usedOption = this.compilerOptionsUsed[`${key}`];
|
|
129
|
+
return usedOption === inputOption;
|
|
130
|
+
});
|
|
131
|
+
if (!optionsMatched) {
|
|
132
|
+
return true;
|
|
89
133
|
}
|
|
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
|
-
}
|
|
134
|
+
if (files.length !== this.infos.size) {
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
for (const file of files) {
|
|
138
|
+
const info = this.infos.get(file.contractPath);
|
|
139
|
+
if (typeof info === 'undefined' || info.sourceCodeHash !== file.sourceCodeHash) {
|
|
140
|
+
return true;
|
|
105
141
|
}
|
|
142
|
+
}
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
static async from(rootPath) {
|
|
146
|
+
const filepath = rootPath + '/' + ProjectArtifact.artifactFileName;
|
|
147
|
+
if (!fs_1.default.existsSync(filepath)) {
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
const content = await fs_2.promises.readFile(filepath);
|
|
151
|
+
const json = JSON.parse(content.toString());
|
|
152
|
+
const compilerOptionsUsed = json.compilerOptionsUsed;
|
|
153
|
+
const files = new Map(Object.entries(json.infos));
|
|
154
|
+
return new ProjectArtifact(compilerOptionsUsed, files);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
ProjectArtifact.artifactFileName = '.project.json';
|
|
158
|
+
class Project {
|
|
159
|
+
constructor(contractsRootDir, artifactsRootDir, sourceFiles, contracts, scripts, errorOnWarnings, projectArtifact) {
|
|
160
|
+
this.contractsRootDir = contractsRootDir;
|
|
161
|
+
this.artifactsRootDir = artifactsRootDir;
|
|
162
|
+
this.sourceFiles = sourceFiles;
|
|
163
|
+
this.contracts = contracts;
|
|
164
|
+
this.scripts = scripts;
|
|
165
|
+
this.projectArtifact = projectArtifact;
|
|
166
|
+
if (errorOnWarnings) {
|
|
167
|
+
Project.checkCompilerWarnings([...contracts.map((c) => c.warnings).flat(), ...scripts.map((s) => s.warnings).flat()], errorOnWarnings);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
static buildProjectArtifact(sourceFiles, contracts, scripts, compilerOptions) {
|
|
171
|
+
const files = new Map();
|
|
172
|
+
contracts.forEach((c) => {
|
|
173
|
+
files.set(c.sourceFile.contractPath, {
|
|
174
|
+
sourceCodeHash: c.sourceFile.sourceCodeHash,
|
|
175
|
+
bytecodeDebugPatch: c.artifact.bytecodeDebugPatch,
|
|
176
|
+
codeHashDebug: c.artifact.codeHashDebug,
|
|
177
|
+
warnings: c.warnings
|
|
178
|
+
});
|
|
106
179
|
});
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
180
|
+
scripts.forEach((s) => {
|
|
181
|
+
files.set(s.sourceFile.contractPath, {
|
|
182
|
+
sourceCodeHash: s.sourceFile.sourceCodeHash,
|
|
183
|
+
bytecodeDebugPatch: s.artifact.bytecodeDebugPatch,
|
|
184
|
+
codeHashDebug: '',
|
|
185
|
+
warnings: s.warnings
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
const compiledSize = contracts.length + scripts.length;
|
|
189
|
+
sourceFiles.slice(compiledSize).forEach((c) => {
|
|
190
|
+
files.set(c.contractPath, {
|
|
191
|
+
sourceCodeHash: c.sourceCodeHash,
|
|
192
|
+
bytecodeDebugPatch: '',
|
|
193
|
+
codeHashDebug: '',
|
|
194
|
+
warnings: []
|
|
195
|
+
});
|
|
114
196
|
});
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
197
|
+
return new ProjectArtifact(compilerOptions, files);
|
|
198
|
+
}
|
|
199
|
+
getContractPath(path) {
|
|
200
|
+
return path.startsWith(`./${this.contractsRootDir}`)
|
|
201
|
+
? path.slice(2)
|
|
202
|
+
: path.startsWith(this.contractsRootDir)
|
|
203
|
+
? path
|
|
204
|
+
: this.contractsRootDir + '/' + path;
|
|
205
|
+
}
|
|
206
|
+
static checkCompilerWarnings(warnings, errorOnWarnings) {
|
|
207
|
+
if (warnings.length !== 0) {
|
|
208
|
+
const prefixPerWarning = ' - ';
|
|
209
|
+
const warningString = prefixPerWarning + warnings.join('\n' + prefixPerWarning);
|
|
210
|
+
const output = `Compilation warnings:\n` + warningString + '\n';
|
|
211
|
+
if (errorOnWarnings) {
|
|
212
|
+
throw new Error(output);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
console.log(output);
|
|
122
216
|
}
|
|
123
217
|
}
|
|
124
|
-
return result;
|
|
125
218
|
}
|
|
126
|
-
static
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
return
|
|
219
|
+
static contract(name) {
|
|
220
|
+
const contract = Project.currentProject.contracts.find((c) => c.artifact.name === name);
|
|
221
|
+
if (typeof contract === 'undefined') {
|
|
222
|
+
throw new Error(`Contract "${name}" does not exist`);
|
|
223
|
+
}
|
|
224
|
+
return contract.artifact;
|
|
132
225
|
}
|
|
133
|
-
static
|
|
134
|
-
|
|
135
|
-
|
|
226
|
+
static script(name) {
|
|
227
|
+
const script = Project.currentProject.scripts.find((c) => c.artifact.name === name);
|
|
228
|
+
if (typeof script === 'undefined') {
|
|
229
|
+
throw new Error(`Script "${name}" does not exist`);
|
|
136
230
|
}
|
|
231
|
+
return script.artifact;
|
|
137
232
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
233
|
+
async saveArtifactsToFile() {
|
|
234
|
+
const artifactsRootDir = this.artifactsRootDir;
|
|
235
|
+
const saveToFile = async function (compiled) {
|
|
236
|
+
const artifactDir = compiled.sourceFile.getArtifactPath(artifactsRootDir);
|
|
237
|
+
const folder = artifactDir.slice(0, artifactDir.lastIndexOf('/'));
|
|
238
|
+
if (!fs_1.default.existsSync(folder)) {
|
|
239
|
+
fs_1.default.mkdirSync(folder, { recursive: true });
|
|
240
|
+
}
|
|
241
|
+
return fs_2.promises.writeFile(artifactDir, compiled.artifact.toString());
|
|
242
|
+
};
|
|
243
|
+
for (const contract of this.contracts) {
|
|
244
|
+
saveToFile(contract);
|
|
145
245
|
}
|
|
146
|
-
|
|
147
|
-
|
|
246
|
+
for (const script of this.scripts) {
|
|
247
|
+
await saveToFile(script);
|
|
148
248
|
}
|
|
249
|
+
await this.projectArtifact.saveToFile(this.artifactsRootDir);
|
|
149
250
|
}
|
|
150
|
-
|
|
151
|
-
const
|
|
152
|
-
if (
|
|
153
|
-
|
|
251
|
+
contractByCodeHash(codeHash) {
|
|
252
|
+
const contract = this.contracts.find((c) => c.artifact.codeHash === codeHash || c.artifact.codeHashDebug == codeHash);
|
|
253
|
+
if (typeof contract === 'undefined') {
|
|
254
|
+
throw new Error(`Unknown code with code hash: ${codeHash}`);
|
|
154
255
|
}
|
|
155
|
-
return
|
|
256
|
+
return contract.artifact;
|
|
156
257
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
258
|
+
static async compile(provider, files, contractsRootDir, artifactsRootDir, errorOnWarnings, compilerOptions) {
|
|
259
|
+
const sourceStr = files.map((f) => f.sourceCode).join('\n');
|
|
260
|
+
const result = await provider.contracts.postContractsCompileProject({
|
|
261
|
+
code: sourceStr,
|
|
262
|
+
compilerOptions: compilerOptions
|
|
263
|
+
});
|
|
264
|
+
const contracts = [];
|
|
265
|
+
const scripts = [];
|
|
266
|
+
result.contracts.forEach((contractResult, index) => {
|
|
267
|
+
const sourceFile = files[`${index}`];
|
|
268
|
+
const contract = Contract.fromCompileResult(contractResult);
|
|
269
|
+
contracts.push(new Compiled(sourceFile, contract, contractResult.warnings));
|
|
270
|
+
});
|
|
271
|
+
result.scripts.forEach((scriptResult, index) => {
|
|
272
|
+
const sourceFile = files[index + contracts.length];
|
|
273
|
+
const script = Script.fromCompileResult(scriptResult);
|
|
274
|
+
scripts.push(new Compiled(sourceFile, script, scriptResult.warnings));
|
|
275
|
+
});
|
|
276
|
+
const projectArtifact = Project.buildProjectArtifact(files, contracts, scripts, compilerOptions);
|
|
277
|
+
const project = new Project(contractsRootDir, artifactsRootDir, files, contracts, scripts, errorOnWarnings, projectArtifact);
|
|
278
|
+
await project.saveArtifactsToFile();
|
|
279
|
+
return project;
|
|
172
280
|
}
|
|
173
|
-
static
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
281
|
+
static async loadArtifacts(provider, files, projectArtifact, contractsRootDir, artifactsRootDir, errorOnWarnings, compilerOptions) {
|
|
282
|
+
try {
|
|
283
|
+
const contracts = [];
|
|
284
|
+
const scripts = [];
|
|
285
|
+
for (const file of files) {
|
|
286
|
+
const info = projectArtifact.infos.get(file.contractPath);
|
|
287
|
+
if (typeof info === 'undefined') {
|
|
288
|
+
throw Error(`Unable to find project info for ${file.contractPath}, please rebuild the project`);
|
|
289
|
+
}
|
|
290
|
+
const warnings = info.warnings;
|
|
291
|
+
const artifactDir = file.getArtifactPath(artifactsRootDir);
|
|
292
|
+
if (file.type === SourceType.Contract) {
|
|
293
|
+
const artifact = await Contract.fromArtifactFile(artifactDir, info.bytecodeDebugPatch, info.codeHashDebug);
|
|
294
|
+
contracts.push(new Compiled(file, artifact, warnings));
|
|
295
|
+
}
|
|
296
|
+
else if (file.type === SourceType.Script) {
|
|
297
|
+
const artifact = await Script.fromArtifactFile(artifactDir, info.bytecodeDebugPatch);
|
|
298
|
+
scripts.push(new Compiled(file, artifact, warnings));
|
|
299
|
+
}
|
|
185
300
|
}
|
|
301
|
+
return new Project(contractsRootDir, artifactsRootDir, files, contracts, scripts, errorOnWarnings, projectArtifact);
|
|
186
302
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
303
|
+
catch (error) {
|
|
304
|
+
console.log(`Failed to load artifacts, error: ${error}, try to re-compile contracts...`);
|
|
305
|
+
return Project.compile(provider, files, contractsRootDir, artifactsRootDir, errorOnWarnings, compilerOptions);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
static async loadSourceFile(dirPath, filename) {
|
|
309
|
+
const contractPath = dirPath + '/' + filename;
|
|
310
|
+
if (!filename.endsWith('.ral')) {
|
|
311
|
+
throw new Error(`Invalid filename: ${contractPath}, smart contract file name should end with ".ral"`);
|
|
312
|
+
}
|
|
313
|
+
const sourceBuffer = await fs_2.promises.readFile(contractPath);
|
|
314
|
+
const sourceStr = sourceBuffer.toString();
|
|
315
|
+
const results = this.matchers.map((m) => m.match(sourceStr));
|
|
316
|
+
const matchNumber = results.reduce((a, b) => a + b, 0);
|
|
317
|
+
if (matchNumber === 0) {
|
|
318
|
+
throw new Error(`No contract defined in file: ${contractPath}`);
|
|
319
|
+
}
|
|
320
|
+
if (matchNumber > 1) {
|
|
321
|
+
throw new Error(`Multiple definitions in file: ${contractPath}`);
|
|
322
|
+
}
|
|
323
|
+
const matcherIndex = results.indexOf(1);
|
|
324
|
+
const type = this.matchers[`${matcherIndex}`].type;
|
|
325
|
+
return SourceFile.from(type, sourceStr, contractPath);
|
|
326
|
+
}
|
|
327
|
+
static async loadSourceFiles(contractsRootDir) {
|
|
328
|
+
const loadDir = async function (dirPath, results) {
|
|
329
|
+
const dirents = await fs_2.promises.readdir(dirPath, { withFileTypes: true });
|
|
330
|
+
for (const dirent of dirents) {
|
|
331
|
+
if (dirent.isFile()) {
|
|
332
|
+
const file = await Project.loadSourceFile(dirPath, dirent.name);
|
|
333
|
+
results.push(file);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
const newPath = dirPath + '/' + dirent.name;
|
|
337
|
+
await loadDir(newPath, results);
|
|
338
|
+
}
|
|
190
339
|
}
|
|
340
|
+
};
|
|
341
|
+
const sourceFiles = [];
|
|
342
|
+
await loadDir(contractsRootDir, sourceFiles);
|
|
343
|
+
const contractAndScriptSize = sourceFiles.filter((f) => f.type === SourceType.Contract || f.type === SourceType.Script).length;
|
|
344
|
+
if (sourceFiles.length === 0 || contractAndScriptSize === 0) {
|
|
345
|
+
throw new Error('Project have no source files');
|
|
346
|
+
}
|
|
347
|
+
return sourceFiles.sort((a, b) => a.type - b.type);
|
|
348
|
+
}
|
|
349
|
+
static async build(compilerOptionsPartial = {}, contractsRootDir = Project.DEFAULT_CONTRACTS_DIR, artifactsRootDir = Project.DEFAULT_ARTIFACTS_DIR) {
|
|
350
|
+
const provider = (0, global_1.getCurrentNodeProvider)();
|
|
351
|
+
const sourceFiles = await Project.loadSourceFiles(contractsRootDir);
|
|
352
|
+
const { errorOnWarnings, ...nodeCompilerOptions } = { ...exports.DEFAULT_COMPILER_OPTIONS, ...compilerOptionsPartial };
|
|
353
|
+
const projectArtifact = await ProjectArtifact.from(artifactsRootDir);
|
|
354
|
+
if (typeof projectArtifact === 'undefined' || projectArtifact.needToReCompile(nodeCompilerOptions, sourceFiles)) {
|
|
355
|
+
console.log(`Compiling contracts in folder "${contractsRootDir}"`);
|
|
356
|
+
Project.currentProject = await Project.compile(provider, sourceFiles, contractsRootDir, artifactsRootDir, errorOnWarnings, nodeCompilerOptions);
|
|
191
357
|
}
|
|
358
|
+
else {
|
|
359
|
+
console.log(`Contracts are compiled already. Loading them from folder "${artifactsRootDir}"`);
|
|
360
|
+
Project.currentProject = await Project.loadArtifacts(provider, sourceFiles, projectArtifact, contractsRootDir, artifactsRootDir, errorOnWarnings, nodeCompilerOptions);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
exports.Project = Project;
|
|
365
|
+
Project.abstractContractMatcher = new TypedMatcher('^Abstract Contract [A-Z][a-zA-Z0-9]*', SourceType.AbstractContract);
|
|
366
|
+
Project.contractMatcher = new TypedMatcher('^Contract [A-Z][a-zA-Z0-9]*', SourceType.Contract);
|
|
367
|
+
Project.interfaceMatcher = new TypedMatcher('^Interface [A-Z][a-zA-Z0-9]* \\{', SourceType.Interface);
|
|
368
|
+
Project.scriptMatcher = new TypedMatcher('^TxScript [A-Z][a-zA-Z0-9]*', SourceType.Script);
|
|
369
|
+
Project.matchers = [
|
|
370
|
+
Project.abstractContractMatcher,
|
|
371
|
+
Project.contractMatcher,
|
|
372
|
+
Project.interfaceMatcher,
|
|
373
|
+
Project.scriptMatcher
|
|
374
|
+
];
|
|
375
|
+
Project.DEFAULT_CONTRACTS_DIR = 'contracts';
|
|
376
|
+
Project.DEFAULT_ARTIFACTS_DIR = 'artifacts';
|
|
377
|
+
class Artifact {
|
|
378
|
+
constructor(version, name, functions) {
|
|
379
|
+
this.version = version;
|
|
380
|
+
this.name = name;
|
|
381
|
+
this.functions = functions;
|
|
192
382
|
}
|
|
193
|
-
|
|
194
|
-
return
|
|
383
|
+
publicFunctions() {
|
|
384
|
+
return this.functions.filter((func) => func.isPublic).map((func) => func.name);
|
|
195
385
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const contract = await Common._from(provider, sourceFile, (sourceFile) => Contract.loadContractStr(sourceFile), Contract.compile);
|
|
202
|
-
this._putArtifactToCache(contract);
|
|
203
|
-
return contract;
|
|
386
|
+
usingPreapprovedAssetsFunctions() {
|
|
387
|
+
return this.functions.filter((func) => func.usePreapprovedAssets).map((func) => func.name);
|
|
388
|
+
}
|
|
389
|
+
usingAssetsInContractFunctions() {
|
|
390
|
+
return this.functions.filter((func) => func.useAssetsInContract).map((func) => func.name);
|
|
204
391
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
392
|
+
}
|
|
393
|
+
exports.Artifact = Artifact;
|
|
394
|
+
class Contract extends Artifact {
|
|
395
|
+
constructor(version, name, bytecode, bytecodeDebugPatch, codeHash, codeHashDebug, fieldsSig, eventsSig, functions) {
|
|
396
|
+
super(version, name, functions);
|
|
397
|
+
this.bytecode = bytecode;
|
|
398
|
+
this.bytecodeDebugPatch = bytecodeDebugPatch;
|
|
399
|
+
this.codeHash = codeHash;
|
|
400
|
+
this.fieldsSig = fieldsSig;
|
|
401
|
+
this.eventsSig = eventsSig;
|
|
402
|
+
this.bytecodeDebug = ralph.buildDebugBytecode(this.bytecode, this.bytecodeDebugPatch);
|
|
403
|
+
this.codeHashDebug = codeHashDebug;
|
|
210
404
|
}
|
|
211
405
|
// TODO: safely parse json
|
|
212
|
-
static fromJson(artifact) {
|
|
213
|
-
if (artifact.
|
|
406
|
+
static fromJson(artifact, bytecodeDebugPatch = '', codeHashDebug = '') {
|
|
407
|
+
if (artifact.version == null ||
|
|
408
|
+
artifact.name == null ||
|
|
214
409
|
artifact.bytecode == null ||
|
|
215
410
|
artifact.codeHash == null ||
|
|
216
411
|
artifact.fieldsSig == null ||
|
|
@@ -218,31 +413,35 @@ class Contract extends Common {
|
|
|
218
413
|
artifact.functions == null) {
|
|
219
414
|
throw Error('The artifact JSON for contract is incomplete');
|
|
220
415
|
}
|
|
221
|
-
const contract = new Contract(artifact.
|
|
222
|
-
this._putArtifactToCache(contract);
|
|
416
|
+
const contract = new Contract(artifact.version, artifact.name, artifact.bytecode, bytecodeDebugPatch, artifact.codeHash, codeHashDebug ? codeHashDebug : artifact.codeHash, artifact.fieldsSig, artifact.eventsSig, artifact.functions);
|
|
223
417
|
return contract;
|
|
224
418
|
}
|
|
419
|
+
static fromCompileResult(result) {
|
|
420
|
+
return new Contract(result.version, result.name, result.bytecode, result.bytecodeDebugPatch, result.codeHash, result.codeHashDebug, result.fields, result.events, result.functions);
|
|
421
|
+
}
|
|
225
422
|
// support both 'code.ral' and 'code.ral.json'
|
|
226
|
-
static async fromArtifactFile(path) {
|
|
227
|
-
const
|
|
228
|
-
const artifactPath = sourceFile.artifactPath;
|
|
229
|
-
const content = await fs_2.promises.readFile(artifactPath);
|
|
423
|
+
static async fromArtifactFile(path, bytecodeDebugPatch, codeHashDebug) {
|
|
424
|
+
const content = await fs_2.promises.readFile(path);
|
|
230
425
|
const artifact = JSON.parse(content.toString());
|
|
231
|
-
return Contract.fromJson(artifact);
|
|
426
|
+
return Contract.fromJson(artifact, bytecodeDebugPatch, codeHashDebug);
|
|
232
427
|
}
|
|
233
|
-
async fetchState(
|
|
234
|
-
const state = await
|
|
428
|
+
async fetchState(address, group) {
|
|
429
|
+
const state = await __1.web3.getCurrentNodeProvider().contracts.getContractsAddressState(address, {
|
|
430
|
+
group: group
|
|
431
|
+
});
|
|
235
432
|
return this.fromApiContractState(state);
|
|
236
433
|
}
|
|
237
434
|
toString() {
|
|
238
|
-
|
|
239
|
-
|
|
435
|
+
const object = {
|
|
436
|
+
version: this.version,
|
|
437
|
+
name: this.name,
|
|
240
438
|
bytecode: this.bytecode,
|
|
241
439
|
codeHash: this.codeHash,
|
|
242
440
|
fieldsSig: this.fieldsSig,
|
|
243
441
|
eventsSig: this.eventsSig,
|
|
244
442
|
functions: this.functions
|
|
245
|
-
}
|
|
443
|
+
};
|
|
444
|
+
return JSON.stringify(object, null, 2);
|
|
246
445
|
}
|
|
247
446
|
toState(fields, asset, address) {
|
|
248
447
|
const addressDef = typeof address !== 'undefined' ? address : Contract.randomAddress();
|
|
@@ -256,16 +455,27 @@ class Contract extends Common {
|
|
|
256
455
|
asset: asset
|
|
257
456
|
};
|
|
258
457
|
}
|
|
458
|
+
// no need to be cryptographically strong random
|
|
259
459
|
static randomAddress() {
|
|
260
|
-
const bytes =
|
|
460
|
+
const bytes = new Uint8Array(33);
|
|
461
|
+
crypto_1.webcrypto.getRandomValues(bytes);
|
|
261
462
|
bytes[0] = 3;
|
|
262
463
|
return utils_1.bs58.encode(bytes);
|
|
263
464
|
}
|
|
264
|
-
|
|
465
|
+
_printDebugMessages(funcName, messages) {
|
|
466
|
+
if (messages.length != 0) {
|
|
467
|
+
console.log(`Testing ${this.name}.${funcName}:`);
|
|
468
|
+
messages.forEach((m) => console.log(`Debug - ${m.contractAddress} - ${m.message}`));
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
async _test(funcName, params, expectPublic, accessType, printDebugMessages) {
|
|
265
472
|
const apiParams = this.toTestContract(funcName, params);
|
|
266
|
-
const apiResult = await
|
|
473
|
+
const apiResult = await __1.web3.getCurrentNodeProvider().contracts.postContractsTestContract(apiParams);
|
|
267
474
|
const methodIndex = typeof params.testMethodIndex !== 'undefined' ? params.testMethodIndex : this.getMethodIndex(funcName);
|
|
268
|
-
const isPublic = this.functions[`${methodIndex}`].
|
|
475
|
+
const isPublic = this.functions[`${methodIndex}`].isPublic;
|
|
476
|
+
if (printDebugMessages) {
|
|
477
|
+
this._printDebugMessages(funcName, apiResult.debugMessages);
|
|
478
|
+
}
|
|
269
479
|
if (isPublic === expectPublic) {
|
|
270
480
|
const result = await this.fromTestContractResult(methodIndex, apiResult);
|
|
271
481
|
return result;
|
|
@@ -274,11 +484,11 @@ class Contract extends Common {
|
|
|
274
484
|
throw new Error(`The test method ${funcName} is not ${accessType}`);
|
|
275
485
|
}
|
|
276
486
|
}
|
|
277
|
-
async testPublicMethod(
|
|
278
|
-
return this._test(
|
|
487
|
+
async testPublicMethod(funcName, params, printDebugMessages = true) {
|
|
488
|
+
return this._test(funcName, params, true, 'public', printDebugMessages);
|
|
279
489
|
}
|
|
280
|
-
async testPrivateMethod(
|
|
281
|
-
return this._test(
|
|
490
|
+
async testPrivateMethod(funcName, params, printDebugMessages = true) {
|
|
491
|
+
return this._test(funcName, params, false, 'private', printDebugMessages);
|
|
282
492
|
}
|
|
283
493
|
toApiFields(fields) {
|
|
284
494
|
if (typeof fields === 'undefined') {
|
|
@@ -310,7 +520,7 @@ class Contract extends Common {
|
|
|
310
520
|
return {
|
|
311
521
|
group: params.group,
|
|
312
522
|
address: params.address,
|
|
313
|
-
bytecode: this.
|
|
523
|
+
bytecode: this.bytecodeDebug,
|
|
314
524
|
initialFields: this.toApiFields(params.initialFields),
|
|
315
525
|
initialAsset: typeof params.initialAsset !== 'undefined' ? toApiAsset(params.initialAsset) : undefined,
|
|
316
526
|
methodIndex: this.getMethodIndex(funcName),
|
|
@@ -319,30 +529,8 @@ class Contract extends Common {
|
|
|
319
529
|
inputAssets: toApiInputAssets(params.inputAssets)
|
|
320
530
|
};
|
|
321
531
|
}
|
|
322
|
-
|
|
323
|
-
const
|
|
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
|
-
async fromApiContractState(state) {
|
|
345
|
-
const contract = await Contract.fromCodeHash(state.codeHash);
|
|
532
|
+
fromApiContractState(state) {
|
|
533
|
+
const contract = Project.currentProject.contractByCodeHash(state.codeHash);
|
|
346
534
|
return {
|
|
347
535
|
address: state.address,
|
|
348
536
|
contractId: (0, utils_1.binToHex)((0, utils_1.contractIdFromAddress)(state.address)),
|
|
@@ -350,11 +538,11 @@ class Contract extends Common {
|
|
|
350
538
|
initialStateHash: state.initialStateHash,
|
|
351
539
|
codeHash: state.codeHash,
|
|
352
540
|
fields: fromApiFields(state.fields, contract.fieldsSig),
|
|
353
|
-
fieldsSig:
|
|
541
|
+
fieldsSig: contract.fieldsSig,
|
|
354
542
|
asset: fromApiAsset(state.asset)
|
|
355
543
|
};
|
|
356
544
|
}
|
|
357
|
-
static
|
|
545
|
+
static fromApiEvent(event, codeHash) {
|
|
358
546
|
let eventSig;
|
|
359
547
|
if (event.eventIndex == -1) {
|
|
360
548
|
eventSig = this.ContractCreatedEvent;
|
|
@@ -363,7 +551,7 @@ class Contract extends Common {
|
|
|
363
551
|
eventSig = this.ContractDestroyedEvent;
|
|
364
552
|
}
|
|
365
553
|
else {
|
|
366
|
-
const contract =
|
|
554
|
+
const contract = Project.currentProject.contractByCodeHash(codeHash);
|
|
367
555
|
eventSig = contract.eventsSig[event.eventIndex];
|
|
368
556
|
}
|
|
369
557
|
return {
|
|
@@ -373,18 +561,18 @@ class Contract extends Common {
|
|
|
373
561
|
fields: fromApiEventFields(event.fields, eventSig)
|
|
374
562
|
};
|
|
375
563
|
}
|
|
376
|
-
|
|
564
|
+
fromTestContractResult(methodIndex, result) {
|
|
377
565
|
const addressToCodeHash = new Map();
|
|
378
566
|
addressToCodeHash.set(result.address, result.codeHash);
|
|
379
567
|
result.contracts.forEach((contract) => addressToCodeHash.set(contract.address, contract.codeHash));
|
|
380
568
|
return {
|
|
381
|
-
address: result.address,
|
|
382
569
|
contractId: (0, utils_1.binToHex)((0, utils_1.contractIdFromAddress)(result.address)),
|
|
383
|
-
|
|
570
|
+
contractAddress: result.address,
|
|
571
|
+
returns: (0, api_1.fromApiArray)(result.returns, this.functions[`${methodIndex}`].returnTypes),
|
|
384
572
|
gasUsed: result.gasUsed,
|
|
385
|
-
contracts:
|
|
573
|
+
contracts: result.contracts.map((contract) => this.fromApiContractState(contract)),
|
|
386
574
|
txOutputs: result.txOutputs.map(fromApiOutput),
|
|
387
|
-
events:
|
|
575
|
+
events: result.events.map((event) => {
|
|
388
576
|
const contractAddress = event.contractAddress;
|
|
389
577
|
const codeHash = addressToCodeHash.get(contractAddress);
|
|
390
578
|
if (typeof codeHash !== 'undefined' || event.eventIndex < 0) {
|
|
@@ -393,29 +581,26 @@ class Contract extends Common {
|
|
|
393
581
|
else {
|
|
394
582
|
throw Error(`Cannot find codeHash for the contract address: ${contractAddress}`);
|
|
395
583
|
}
|
|
396
|
-
})
|
|
584
|
+
}),
|
|
585
|
+
debugMessages: result.debugMessages
|
|
397
586
|
};
|
|
398
587
|
}
|
|
399
|
-
async
|
|
588
|
+
async txParamsForDeployment(signer, params) {
|
|
400
589
|
const bytecode = this.buildByteCodeToDeploy(params.initialFields ? params.initialFields : {});
|
|
401
590
|
const signerParams = {
|
|
402
|
-
signerAddress:
|
|
591
|
+
signerAddress: (await signer.getSelectedAccount()).address,
|
|
403
592
|
bytecode: bytecode,
|
|
404
|
-
initialAttoAlphAmount:
|
|
405
|
-
issueTokenAmount:
|
|
406
|
-
initialTokenAmounts: params.initialTokenAmounts
|
|
593
|
+
initialAttoAlphAmount: params.initialAttoAlphAmount,
|
|
594
|
+
issueTokenAmount: params.issueTokenAmount,
|
|
595
|
+
initialTokenAmounts: params.initialTokenAmounts,
|
|
407
596
|
gasAmount: params.gasAmount,
|
|
408
|
-
gasPrice:
|
|
597
|
+
gasPrice: params.gasPrice
|
|
409
598
|
};
|
|
410
599
|
return signerParams;
|
|
411
600
|
}
|
|
412
|
-
async
|
|
413
|
-
const signerParams = await this.
|
|
414
|
-
|
|
415
|
-
signerAddress: (await signer.getAccounts())[0].address
|
|
416
|
-
});
|
|
417
|
-
const response = await signer.buildContractCreationTx(signerParams);
|
|
418
|
-
return fromApiDeployContractUnsignedTx(response);
|
|
601
|
+
async deploy(signer, params) {
|
|
602
|
+
const signerParams = await this.txParamsForDeployment(signer, params);
|
|
603
|
+
return signer.signAndSubmitDeployContractTx(signerParams);
|
|
419
604
|
}
|
|
420
605
|
buildByteCodeToDeploy(initialFields) {
|
|
421
606
|
return ralph.buildContractByteCode(this.bytecode, initialFields, this.fieldsSig);
|
|
@@ -424,310 +609,86 @@ class Contract extends Common {
|
|
|
424
609
|
exports.Contract = Contract;
|
|
425
610
|
Contract.ContractCreatedEvent = {
|
|
426
611
|
name: 'ContractCreated',
|
|
427
|
-
signature: 'event ContractCreated(address:Address)',
|
|
428
612
|
fieldNames: ['address'],
|
|
429
613
|
fieldTypes: ['Address']
|
|
430
614
|
};
|
|
431
615
|
Contract.ContractDestroyedEvent = {
|
|
432
616
|
name: 'ContractDestroyed',
|
|
433
|
-
signature: 'event ContractDestroyed(address:Address)',
|
|
434
617
|
fieldNames: ['address'],
|
|
435
618
|
fieldTypes: ['Address']
|
|
436
619
|
};
|
|
437
|
-
class Script extends
|
|
438
|
-
constructor(
|
|
439
|
-
super(
|
|
620
|
+
class Script extends Artifact {
|
|
621
|
+
constructor(version, name, bytecodeTemplate, bytecodeDebugPatch, fieldsSig, functions) {
|
|
622
|
+
super(version, name, functions);
|
|
440
623
|
this.bytecodeTemplate = bytecodeTemplate;
|
|
624
|
+
this.bytecodeDebugPatch = bytecodeDebugPatch;
|
|
441
625
|
this.fieldsSig = fieldsSig;
|
|
442
626
|
}
|
|
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;
|
|
627
|
+
static fromCompileResult(result) {
|
|
628
|
+
return new Script(result.version, result.name, result.bytecodeTemplate, result.bytecodeDebugPatch, result.fields, result.functions);
|
|
467
629
|
}
|
|
468
630
|
// TODO: safely parse json
|
|
469
|
-
static fromJson(artifact) {
|
|
470
|
-
if (artifact.
|
|
631
|
+
static fromJson(artifact, bytecodeDebugPatch = '') {
|
|
632
|
+
if (artifact.version == null ||
|
|
633
|
+
artifact.name == null ||
|
|
471
634
|
artifact.bytecodeTemplate == null ||
|
|
472
635
|
artifact.fieldsSig == null ||
|
|
473
636
|
artifact.functions == null) {
|
|
474
637
|
throw Error('The artifact JSON for script is incomplete');
|
|
475
638
|
}
|
|
476
|
-
return new Script(artifact.
|
|
639
|
+
return new Script(artifact.version, artifact.name, artifact.bytecodeTemplate, bytecodeDebugPatch, artifact.fieldsSig, artifact.functions);
|
|
477
640
|
}
|
|
478
|
-
static async fromArtifactFile(path) {
|
|
479
|
-
const
|
|
480
|
-
const artifactPath = sourceFile.artifactPath;
|
|
481
|
-
const content = await fs_2.promises.readFile(artifactPath);
|
|
641
|
+
static async fromArtifactFile(path, bytecodeDebugPatch) {
|
|
642
|
+
const content = await fs_2.promises.readFile(path);
|
|
482
643
|
const artifact = JSON.parse(content.toString());
|
|
483
|
-
return this.fromJson(artifact);
|
|
644
|
+
return this.fromJson(artifact, bytecodeDebugPatch);
|
|
484
645
|
}
|
|
485
646
|
toString() {
|
|
486
|
-
|
|
487
|
-
|
|
647
|
+
const object = {
|
|
648
|
+
version: this.version,
|
|
649
|
+
name: this.name,
|
|
488
650
|
bytecodeTemplate: this.bytecodeTemplate,
|
|
489
651
|
fieldsSig: this.fieldsSig,
|
|
490
652
|
functions: this.functions
|
|
491
|
-
}
|
|
653
|
+
};
|
|
654
|
+
return JSON.stringify(object, null, 2);
|
|
492
655
|
}
|
|
493
|
-
async
|
|
656
|
+
async txParamsForExecution(signer, params) {
|
|
494
657
|
const signerParams = {
|
|
495
|
-
signerAddress:
|
|
658
|
+
signerAddress: (await signer.getSelectedAccount()).address,
|
|
496
659
|
bytecode: this.buildByteCodeToDeploy(params.initialFields ? params.initialFields : {}),
|
|
497
|
-
attoAlphAmount:
|
|
498
|
-
tokens:
|
|
660
|
+
attoAlphAmount: params.attoAlphAmount,
|
|
661
|
+
tokens: params.tokens,
|
|
499
662
|
gasAmount: params.gasAmount,
|
|
500
|
-
gasPrice:
|
|
663
|
+
gasPrice: params.gasPrice
|
|
501
664
|
};
|
|
502
665
|
return signerParams;
|
|
503
666
|
}
|
|
504
|
-
async
|
|
505
|
-
const signerParams = await this.
|
|
506
|
-
|
|
507
|
-
signerAddress: (await signer.getAccounts())[0].address
|
|
508
|
-
});
|
|
509
|
-
return await signer.buildScriptTx(signerParams);
|
|
667
|
+
async execute(signer, params) {
|
|
668
|
+
const signerParams = await this.txParamsForExecution(signer, params);
|
|
669
|
+
return await signer.signAndSubmitExecuteScriptTx(signerParams);
|
|
510
670
|
}
|
|
511
671
|
buildByteCodeToDeploy(initialFields) {
|
|
512
672
|
return ralph.buildScriptByteCode(this.bytecodeTemplate, initialFields, this.fieldsSig);
|
|
513
673
|
}
|
|
514
674
|
}
|
|
515
675
|
exports.Script = Script;
|
|
516
|
-
function extractBoolean(v) {
|
|
517
|
-
if (typeof v === 'boolean') {
|
|
518
|
-
return v;
|
|
519
|
-
}
|
|
520
|
-
else {
|
|
521
|
-
throw new Error(`Invalid boolean value: ${v}`);
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
// TODO: check integer bounds
|
|
525
|
-
function extractNumber256(v) {
|
|
526
|
-
if ((typeof v === 'number' && Number.isInteger(v)) || typeof v === 'bigint') {
|
|
527
|
-
return v.toString();
|
|
528
|
-
}
|
|
529
|
-
else if (typeof v === 'string') {
|
|
530
|
-
return v;
|
|
531
|
-
}
|
|
532
|
-
else {
|
|
533
|
-
throw new Error(`Invalid 256 bit number: ${v}`);
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
function extractOptionalNumber256(v) {
|
|
537
|
-
return typeof v !== 'undefined' ? extractNumber256(v) : undefined;
|
|
538
|
-
}
|
|
539
|
-
// TODO: check hex string
|
|
540
|
-
function extractByteVec(v) {
|
|
541
|
-
if (typeof v === 'string') {
|
|
542
|
-
// try to convert from address to contract id
|
|
543
|
-
try {
|
|
544
|
-
const address = utils_1.bs58.decode(v);
|
|
545
|
-
if (address.length == 33 && address[0] == 3) {
|
|
546
|
-
return buffer_1.Buffer.from(address.slice(1)).toString('hex');
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
catch (_) {
|
|
550
|
-
return v;
|
|
551
|
-
}
|
|
552
|
-
return v;
|
|
553
|
-
}
|
|
554
|
-
else {
|
|
555
|
-
throw new Error(`Invalid string: ${v}`);
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
function extractBs58(v) {
|
|
559
|
-
if (typeof v === 'string') {
|
|
560
|
-
try {
|
|
561
|
-
utils_1.bs58.decode(v);
|
|
562
|
-
return v;
|
|
563
|
-
}
|
|
564
|
-
catch (error) {
|
|
565
|
-
throw new Error(`Invalid base58 string: ${v}`);
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
else {
|
|
569
|
-
throw new Error(`Invalid string: ${v}`);
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
function decodeNumber256(n) {
|
|
573
|
-
if (Number.isSafeInteger(Number.parseInt(n))) {
|
|
574
|
-
return Number(n);
|
|
575
|
-
}
|
|
576
|
-
else {
|
|
577
|
-
return BigInt(n);
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
function extractArray(tpe, v) {
|
|
581
|
-
if (!Array.isArray(v)) {
|
|
582
|
-
throw new Error(`Expected array, got ${v}`);
|
|
583
|
-
}
|
|
584
|
-
const semiColonIndex = tpe.lastIndexOf(';');
|
|
585
|
-
if (semiColonIndex == -1) {
|
|
586
|
-
throw new Error(`Invalid Val type: ${tpe}`);
|
|
587
|
-
}
|
|
588
|
-
const subType = tpe.slice(1, semiColonIndex);
|
|
589
|
-
const dim = parseInt(tpe.slice(semiColonIndex + 1, -1));
|
|
590
|
-
if (v.length != dim) {
|
|
591
|
-
throw new Error(`Invalid val dimension: ${v}`);
|
|
592
|
-
}
|
|
593
|
-
else {
|
|
594
|
-
return { value: v.map((v) => toApiVal(v, subType)), type: 'Array' };
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
exports.extractArray = extractArray;
|
|
598
|
-
function toApiVal(v, tpe) {
|
|
599
|
-
if (tpe === 'Bool') {
|
|
600
|
-
return { value: extractBoolean(v), type: tpe };
|
|
601
|
-
}
|
|
602
|
-
else if (tpe === 'U256' || tpe === 'I256') {
|
|
603
|
-
return { value: extractNumber256(v), type: tpe };
|
|
604
|
-
}
|
|
605
|
-
else if (tpe === 'ByteVec') {
|
|
606
|
-
return { value: extractByteVec(v), type: tpe };
|
|
607
|
-
}
|
|
608
|
-
else if (tpe === 'Address') {
|
|
609
|
-
return { value: extractBs58(v), type: tpe };
|
|
610
|
-
}
|
|
611
|
-
else {
|
|
612
|
-
return extractArray(tpe, v);
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
exports.toApiVal = toApiVal;
|
|
616
|
-
function decodeArrayType(tpe) {
|
|
617
|
-
const semiColonIndex = tpe.lastIndexOf(';');
|
|
618
|
-
if (semiColonIndex === -1) {
|
|
619
|
-
throw new Error(`Invalid Val type: ${tpe}`);
|
|
620
|
-
}
|
|
621
|
-
const subType = tpe.slice(1, semiColonIndex);
|
|
622
|
-
const dim = parseInt(tpe.slice(semiColonIndex + 1, -1));
|
|
623
|
-
if (subType[0] == '[') {
|
|
624
|
-
const [baseType, subDim] = decodeArrayType(subType);
|
|
625
|
-
return [baseType, (subDim.unshift(dim), subDim)];
|
|
626
|
-
}
|
|
627
|
-
else {
|
|
628
|
-
return [subType, [dim]];
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
function foldVals(vals, dims) {
|
|
632
|
-
if (dims.length == 1) {
|
|
633
|
-
return vals;
|
|
634
|
-
}
|
|
635
|
-
else {
|
|
636
|
-
const result = [];
|
|
637
|
-
const chunkSize = vals.length / dims[0];
|
|
638
|
-
const chunkDims = dims.slice(1);
|
|
639
|
-
for (let i = 0; i < vals.length; i += chunkSize) {
|
|
640
|
-
const chunk = vals.slice(i, i + chunkSize);
|
|
641
|
-
result.push(foldVals(chunk, chunkDims));
|
|
642
|
-
}
|
|
643
|
-
return result;
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
function _fromApiVal(vals, valIndex, tpe) {
|
|
647
|
-
if (vals.length === 0) {
|
|
648
|
-
throw new Error('Not enough Vals');
|
|
649
|
-
}
|
|
650
|
-
const firstVal = vals[`${valIndex}`];
|
|
651
|
-
if (tpe === 'Bool' && firstVal.type === tpe) {
|
|
652
|
-
return [firstVal.value, valIndex + 1];
|
|
653
|
-
}
|
|
654
|
-
else if ((tpe === 'U256' || tpe === 'I256') && firstVal.type === tpe) {
|
|
655
|
-
return [decodeNumber256(firstVal.value), valIndex + 1];
|
|
656
|
-
}
|
|
657
|
-
else if ((tpe === 'ByteVec' || tpe === 'Address') && firstVal.type === tpe) {
|
|
658
|
-
return [firstVal.value, valIndex + 1];
|
|
659
|
-
}
|
|
660
|
-
else {
|
|
661
|
-
const [baseType, dims] = decodeArrayType(tpe);
|
|
662
|
-
const arraySize = dims.reduce((a, b) => a * b);
|
|
663
|
-
const nextIndex = valIndex + arraySize;
|
|
664
|
-
const valsToUse = vals.slice(valIndex, nextIndex);
|
|
665
|
-
if (valsToUse.length == arraySize && valsToUse.every((val) => val.type === baseType)) {
|
|
666
|
-
const localVals = valsToUse.map((val) => fromApiVal(val, baseType));
|
|
667
|
-
return [foldVals(localVals, dims), nextIndex];
|
|
668
|
-
}
|
|
669
|
-
else {
|
|
670
|
-
throw new Error(`Invalid array Val type: ${valsToUse}, ${tpe}`);
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
676
|
function fromApiFields(vals, fieldsSig) {
|
|
675
|
-
return fromApiVals(vals, fieldsSig.names, fieldsSig.types);
|
|
677
|
+
return (0, api_1.fromApiVals)(vals, fieldsSig.names, fieldsSig.types);
|
|
676
678
|
}
|
|
677
679
|
function fromApiEventFields(vals, eventSig) {
|
|
678
|
-
return fromApiVals(vals, eventSig.fieldNames, eventSig.fieldTypes);
|
|
679
|
-
}
|
|
680
|
-
function fromApiVals(vals, names, types) {
|
|
681
|
-
let valIndex = 0;
|
|
682
|
-
const result = {};
|
|
683
|
-
types.forEach((currentType, index) => {
|
|
684
|
-
const currentName = names[`${index}`];
|
|
685
|
-
const [val, nextIndex] = _fromApiVal(vals, valIndex, currentType);
|
|
686
|
-
valIndex = nextIndex;
|
|
687
|
-
result[`${currentName}`] = val;
|
|
688
|
-
});
|
|
689
|
-
return result;
|
|
690
|
-
}
|
|
691
|
-
function fromApiArray(vals, types) {
|
|
692
|
-
let valIndex = 0;
|
|
693
|
-
const result = [];
|
|
694
|
-
for (const currentType of types) {
|
|
695
|
-
const [val, nextIndex] = _fromApiVal(vals, valIndex, currentType);
|
|
696
|
-
result.push(val);
|
|
697
|
-
valIndex = nextIndex;
|
|
698
|
-
}
|
|
699
|
-
return result;
|
|
700
|
-
}
|
|
701
|
-
function fromApiVal(v, tpe) {
|
|
702
|
-
if (v.type === 'Bool' && v.type === tpe) {
|
|
703
|
-
return v.value;
|
|
704
|
-
}
|
|
705
|
-
else if ((v.type === 'U256' || v.type === 'I256') && v.type === tpe) {
|
|
706
|
-
return decodeNumber256(v.value);
|
|
707
|
-
}
|
|
708
|
-
else if ((v.type === 'ByteVec' || v.type === 'Address') && v.type === tpe) {
|
|
709
|
-
return v.value;
|
|
710
|
-
}
|
|
711
|
-
else {
|
|
712
|
-
throw new Error(`Invalid node.Val type: ${v}`);
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
function toApiToken(token) {
|
|
716
|
-
return { id: token.id, amount: extractNumber256(token.amount) };
|
|
717
|
-
}
|
|
718
|
-
function fromApiToken(token) {
|
|
719
|
-
return { id: token.id, amount: decodeNumber256(token.amount) };
|
|
680
|
+
return (0, api_1.fromApiVals)(vals, eventSig.fieldNames, eventSig.fieldTypes);
|
|
720
681
|
}
|
|
721
682
|
function toApiAsset(asset) {
|
|
722
683
|
return {
|
|
723
|
-
attoAlphAmount:
|
|
724
|
-
tokens: typeof asset.tokens !== 'undefined' ? asset.tokens.map(toApiToken) : []
|
|
684
|
+
attoAlphAmount: (0, api_1.toApiNumber256)(asset.alphAmount),
|
|
685
|
+
tokens: typeof asset.tokens !== 'undefined' ? asset.tokens.map(api_1.toApiToken) : []
|
|
725
686
|
};
|
|
726
687
|
}
|
|
727
688
|
function fromApiAsset(asset) {
|
|
728
689
|
return {
|
|
729
|
-
alphAmount:
|
|
730
|
-
tokens:
|
|
690
|
+
alphAmount: (0, api_1.fromApiNumber256)(asset.attoAlphAmount),
|
|
691
|
+
tokens: (0, api_1.fromApiTokens)(asset.tokens)
|
|
731
692
|
};
|
|
732
693
|
}
|
|
733
694
|
function getVal(vals, name) {
|
|
@@ -752,13 +713,13 @@ function toApiFields(fields, fieldsSig) {
|
|
|
752
713
|
return toApiVals(fields, fieldsSig.names, fieldsSig.types);
|
|
753
714
|
}
|
|
754
715
|
function toApiArgs(args, funcSig) {
|
|
755
|
-
return toApiVals(args, funcSig.
|
|
716
|
+
return toApiVals(args, funcSig.paramNames, funcSig.paramTypes);
|
|
756
717
|
}
|
|
757
718
|
function toApiVals(fields, names, types) {
|
|
758
719
|
return names.map((name, index) => {
|
|
759
720
|
const val = getVal(fields, name);
|
|
760
721
|
const tpe = types[`${index}`];
|
|
761
|
-
return toApiVal(val, tpe);
|
|
722
|
+
return (0, api_1.toApiVal)(val, tpe);
|
|
762
723
|
});
|
|
763
724
|
}
|
|
764
725
|
function toApiInputAsset(inputAsset) {
|
|
@@ -773,8 +734,8 @@ function fromApiOutput(output) {
|
|
|
773
734
|
return {
|
|
774
735
|
type: 'AssetOutput',
|
|
775
736
|
address: asset.address,
|
|
776
|
-
alphAmount:
|
|
777
|
-
tokens: asset.tokens
|
|
737
|
+
alphAmount: (0, api_1.fromApiNumber256)(asset.attoAlphAmount),
|
|
738
|
+
tokens: (0, api_1.fromApiTokens)(asset.tokens),
|
|
778
739
|
lockTime: asset.lockTime,
|
|
779
740
|
message: asset.message
|
|
780
741
|
};
|
|
@@ -784,16 +745,13 @@ function fromApiOutput(output) {
|
|
|
784
745
|
return {
|
|
785
746
|
type: 'ContractOutput',
|
|
786
747
|
address: asset.address,
|
|
787
|
-
alphAmount:
|
|
788
|
-
tokens: asset.tokens
|
|
748
|
+
alphAmount: (0, api_1.fromApiNumber256)(asset.attoAlphAmount),
|
|
749
|
+
tokens: (0, api_1.fromApiTokens)(asset.tokens)
|
|
789
750
|
};
|
|
790
751
|
}
|
|
791
752
|
else {
|
|
792
753
|
throw new Error(`Unknown output type: ${output}`);
|
|
793
754
|
}
|
|
794
755
|
}
|
|
795
|
-
function fromApiDeployContractUnsignedTx(result) {
|
|
796
|
-
return { ...result, contractId: (0, utils_1.binToHex)((0, utils_1.contractIdFromAddress)(result.contractAddress)) };
|
|
797
|
-
}
|
|
798
756
|
(0, utils_1.assertType)();
|
|
799
757
|
(0, utils_1.assertType)();
|