diff --git a/README.md b/README.md
index 0145c14..809abc0 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,6 @@
[![npm version](https://badge.fury.io/js/eoslime.svg)](https://badge.fury.io/js/eoslime.svg)
[![codecov](https://codecov.io/gh/LimeChain/eoslime/branch/master/graph/badge.svg)](https://codecov.io/gh/LimeChain/eoslime)
+[![support typescript](https://badgen.net/badge/Support/TypeScript/cyan)](https://badgen.net/badge/Support/TypeScript/cyan)
eoslime.js
============
@@ -23,6 +24,9 @@ Thanks these wonderful people for helping improve EOSLime
Artem
💡
|
+ Pedro Reis Colaço
+ 💻
+ |
@@ -30,6 +34,93 @@ Thanks these wonderful people for helping improve EOSLime
# Change log
+## Version 2.0.0 change log
+## [Typescript support && Codebase code coverage]
+### Breaking changes
+* Rename **Account.addAuthorityKey** to **Account.addOnBehalfKey**
+* Rename **Account.executiveAuth** to **Account.authority**
+* New way to access contract actions and tables
+ **Actions**
+ ```
+ const tokenContract = await eoslime.Contract.at('contract name');
+ // Before
+ tokenContract.issue(params, options)
+ // Now
+ tokenContract.actions.issue([params], options)
+ ```
+ **Tables**
+ ```
+ const tokenContract = await eoslime.Contract.at('contract name');
+ // Before
+ tokenContract.balances()
+ // Now
+ tokenContract.tables.balances()
+ ```
+* Contract.on('deploy')
+ ```
+ // Before
+ Contract.on('deploy', (tx, contract) => {}))
+ // Now
+ Contract.on('deploy', (contract, tx) => {}))
+ ```
+* Remove AuthorityAccount
+* Deprecate **Account.createSubAuthority**
+* Replace **createSubAuthority** with **addAuthority**
+ ```
+ const account = await eoslime.Account.createRandom();
+
+ // ------------ [ Before ] ------------
+
+ // Add subAuthority and return an instance of AuthorityAccount
+ const subAuthorityAccount = await account.createSubAuthority('subauthority');
+
+ // Add what actions the new authority could access
+ await subAuthorityAccount.setAuthorityAbilities([
+ { action: 'produce', contract: faucetContract.name }
+ ]);
+
+ // ------------ [ Now ] ------------
+
+ // Add subAuthority and return tx receipt
+ const tx = await account.addAuthority('subauthority');
+
+ // Add what actions the new authority could access
+ await account.setAuthorityAbilities('subauthority', [
+ { action: 'produce', contract: faucetContract.name }
+ ]);
+
+ const subAuthorityAccount = eoslime.Account.load('name', 'key', 'subauthority');
+ ```
+
+### News
+* Typescript support
+* Refactor CLI commands
+* Fix nodeos pre-loaded accounts to have different keys
+* Unit tests for all CLI commands
+* Return transaction receipts on every chain iteraction
+* Use logger instead console.log
+* Update Kylin network endpoint
+* Add Jungle3 support
+* Remove the check requiring an executor to be provided on contract instantiation. Without executor, one could fetch only the data from the contract tables
+* contract.action.sign(params)
+ ```
+ // Before
+ contract.action.sign(params)
+
+ // Now
+ // Options are the same like the ones for contract.action(params, options)
+ contract.actions.action.sign([params], options)
+ ```
+* contract.action.getRawTransaction(params)
+ ```
+ // Before
+ contract.action.getRawTransaction(params)
+
+ // Now
+ // Options are the same like the ones for contract.action(params, options)
+ contract.actions.action.getRawTransaction([params], options)
+ ```
+
## Version 1.0.4 change log
* **eoslime nodeos**
@@ -91,7 +182,7 @@ EOSLIME was able to be initialized only with pre-configured providers connection
const eoslime = require('eoslime').init('bos', { url: 'Your url', chainId: 'Your chainId' });
// ... any other supported netwok ...
```
-* **Allow read-only contracts** - You are able now to instantiate a contract withouth a signer/executor and read the contract's tables
+* **Allow read-only contracts** - You are able now to instantiate a contract without a signer/executor and read the contract's tables
* **Add Tutorial section in the documentation**
* **Describe how examples in the documentation could be run**
* **Increase the code coverage from 46% to 90+ %**
diff --git a/cli-commands/command-definer.js b/cli-commands/command-definer.js
index 8a0c821..b774242 100644
--- a/cli-commands/command-definer.js
+++ b/cli-commands/command-definer.js
@@ -1,5 +1,5 @@
class CommandDefiner {
- constructor(yargs) {
+ constructor (yargs) {
this.yargs = yargs;
}
@@ -28,8 +28,8 @@ class CommandDefiner {
handle (command) {
return async (args) => {
- const result = await command.execute(args);
- if (!result) {
+ await command.execute(args);
+ if (!command.hasBeenExecuted) {
this.yargs.showHelp();
}
}
diff --git a/cli-commands/commands/command.js b/cli-commands/commands/command.js
index 2aa7277..495a562 100644
--- a/cli-commands/commands/command.js
+++ b/cli-commands/commands/command.js
@@ -1,9 +1,11 @@
class Command {
- constructor(commandDefinition) {
+ constructor (commandDefinition) {
this.subcommands = [];
this.options = commandDefinition.options || [];
this.template = commandDefinition.template || '';
this.description = commandDefinition.description || '';
+
+ this.hasBeenExecuted = true;
}
async processOptions (args) {
@@ -21,8 +23,7 @@ class Command {
return optionResults;
}
- execute (args) { }
-
+ async execute (args) { }
}
module.exports = Command;
diff --git a/cli-commands/commands/compile/index.js b/cli-commands/commands/compile/index.js
index 675a712..b68ef82 100644
--- a/cli-commands/commands/compile/index.js
+++ b/cli-commands/commands/compile/index.js
@@ -1,7 +1,9 @@
const AsyncSoftExec = require('../../helpers/async-soft-exec');
const Command = require('../command');
-const commandMessages = require('./messages');
+const MESSAGE_COMMAND = require('./messages').COMMAND;
+const MESSAGE_CONTRACT = require('./messages').CONTRACT;
+
const compiledDirectories = require('./specific/directories.json');
const compileCommandDefinition = require('./definition');
@@ -11,13 +13,13 @@ const fileSysUtils = require('../../helpers/file-system-util');
class CompileCommand extends Command {
- constructor() {
+ constructor () {
super(compileCommandDefinition);
}
async execute (args) {
try {
- commandMessages.StartCompilation();
+ MESSAGE_COMMAND.Start();
const optionsResults = await super.processOptions(args);
@@ -26,20 +28,25 @@ class CompileCommand extends Command {
for (let i = 0; i < optionsResults.path.length; i++) {
const contractPath = optionsResults.path[i];
- // Todo: Check how to compile without using eosio-cpp
- const asyncSoftExec = new AsyncSoftExec(`eosio-cpp -I . -o ./compiled/${contractPath.fileName}.wasm ${contractPath.fullPath} --abigen`);
- asyncSoftExec.onError((error) => commandMessages.UnsuccessfulCompilationOfContract(error, contractPath.fileName));
- asyncSoftExec.onSuccess(() => commandMessages.SuccessfulCompilationOfContract(contractPath.fileName));
-
- await asyncSoftExec.exec();
+ await processCompilation(contractPath)
}
} else {
- commandMessages.ContractNotExisting();
+ MESSAGE_CONTRACT.NotFound();
}
} catch (error) {
- commandMessages.UnsuccessfulCompilation(error);
+ MESSAGE_COMMAND.Error(error);
}
- return true;
+ }
+}
+
+const processCompilation = async function (contract) {
+ try {
+ const asyncSoftExec = new AsyncSoftExec(`eosio-cpp -I . -o ./compiled/${contract.fileName}.wasm ${contract.fullPath} --abigen`);
+ await asyncSoftExec.exec();
+
+ MESSAGE_CONTRACT.Compiled(contract.fileName);
+ } catch (error) {
+ MESSAGE_CONTRACT.NotCompiled(error, contract.fileName);
}
}
diff --git a/cli-commands/commands/compile/messages.js b/cli-commands/commands/compile/messages.js
index af94aff..f5f04b2 100644
--- a/cli-commands/commands/compile/messages.js
+++ b/cli-commands/commands/compile/messages.js
@@ -1,15 +1,13 @@
-const chalk = require('chalk');
+const logger = require('../../common/logger');
module.exports = {
- 'StartCompilation': () => { console.log(chalk.magentaBright('===== Compilation has started... =====')); },
- 'UnsuccessfulCompilation': (error) => {
- console.log(chalk.redBright(`===== Unsuccessful compilation =====`));
- console.log(error);
+ 'CONTRACT': {
+ 'Compiled': (contract) => { logger.success(`===== ${contract} has been successfully compiled =====`); },
+ 'NotCompiled': (error, file) => { logger.error(`===== Unsuccessful compilation of ${file} =====`, error); },
+ 'NotFound': () => { logger.info(`===== There is not a contract to compile =====`); }
},
- 'SuccessfulCompilationOfContract': (contract) => { console.log(chalk.greenBright(`===== Successfully compilation of ${contract} =====`)); },
- 'UnsuccessfulCompilationOfContract': (error, file) => {
- console.log(chalk.redBright(`===== Unsuccessful compilation of ${file} =====`));
- console.log(error);
- },
- 'ContractNotExisting': () => { console.log(chalk.redBright(`===== There is not a contract to compile =====`)); }
+ 'COMMAND': {
+ 'Start': () => { logger.info('===== Compilation has started... ====='); },
+ 'Error': (error) => { logger.error(`===== Unsuccessful compilation =====`, error); },
+ }
}
\ No newline at end of file
diff --git a/cli-commands/commands/compile/options/path-option.js b/cli-commands/commands/compile/options/path-option.js
index 935a823..1035a88 100644
--- a/cli-commands/commands/compile/options/path-option.js
+++ b/cli-commands/commands/compile/options/path-option.js
@@ -1,10 +1,11 @@
const fileSystemUtil = require('../../../helpers/file-system-util');
+const path = require('path');
const Option = require('../../option');
class PathOption extends Option {
- constructor() {
+ constructor () {
super(
'path',
{
@@ -28,7 +29,7 @@ class PathOption extends Option {
});
}
- return optionValue.endsWith('.cpp') ? [`${__dirname}/${optionValue}`] : [];
+ return optionValue.endsWith('.cpp') ? [{ fullPath: optionValue, fileName: path.basename(optionValue, '.cpp') }] : [];
}
}
diff --git a/cli-commands/commands/deploy/index.js b/cli-commands/commands/deploy/index.js
index 4c0afdb..217bda2 100644
--- a/cli-commands/commands/deploy/index.js
+++ b/cli-commands/commands/deploy/index.js
@@ -1,24 +1,26 @@
const Command = require('../command');
-const commandMessages = require('./messages');
+const MESSAGE_COMMAND = require('./messages').COMMAND;
+const MESSAGE_SCRIPT = require('./messages').SCRIPT;
+
const deployCommandDefinition = require('./definition');
// eoslime deploy --path --network --deployer
class DeployCommand extends Command {
- constructor() {
+ constructor () {
super(deployCommandDefinition);
}
async execute (args) {
try {
- commandMessages.StartDeployment();
+ MESSAGE_COMMAND.Start();
+
const optionsResults = await super.processOptions(args);
await runDeploymentScripts(optionsResults.path, optionsResults.network, optionsResults.deployer);
} catch (error) {
- commandMessages.UnsuccessfulDeployment(error);
+ MESSAGE_COMMAND.Error(error);
}
- return true;
}
}
@@ -27,9 +29,9 @@ const runDeploymentScripts = async function (deploymentScripts, ...configuration
const deploymentScript = deploymentScripts[i];
try {
await deploymentScript.deploy(...configuration);
- commandMessages.SuccessfulDeploymentOfScript(deploymentScript.fileName);
+ MESSAGE_SCRIPT.Processed(deploymentScript.fileName);
} catch (error) {
- commandMessages.UnsuccessfulDeploymentOfScript(deploymentScript.fileName, error);
+ MESSAGE_SCRIPT.NotProcessed(deploymentScript.fileName, error);
}
}
}
diff --git a/cli-commands/commands/deploy/messages.js b/cli-commands/commands/deploy/messages.js
index b76746d..7df124d 100644
--- a/cli-commands/commands/deploy/messages.js
+++ b/cli-commands/commands/deploy/messages.js
@@ -1,14 +1,12 @@
-const chalk = require('chalk');
+const logger = require('../../common/logger');
module.exports = {
- 'StartDeployment': () => { console.log(chalk.magentaBright('===== Deployment has started... =====')); },
- 'SuccessfulDeploymentOfScript': (script) => { console.log(chalk.greenBright(`===== Successful deployment of ${script} =====`)); },
- 'UnsuccessfulDeploymentOfScript': (script, error) => {
- console.log(chalk.redBright(`===== Unsuccessful deployment of ${script} =====`));
- console.log(error);
+ 'SCRIPT': {
+ 'Processed': (script) => { logger.success(`===== Successful deployment of ${script} =====`); },
+ 'NotProcessed': (script, error) => { logger.error(`===== Unsuccessful deployment of ${script} =====`, error); },
},
- 'UnsuccessfulDeployment': (error) => {
- console.log(chalk.redBright(`===== Unsuccessful deployment =====`));
- console.log(error);
+ 'COMMAND': {
+ 'Start': () => { logger.info('===== Deployment has started... ====='); },
+ 'Error': (error) => { logger.error(`===== Unsuccessful deployment =====`, error); }
}
}
\ No newline at end of file
diff --git a/cli-commands/commands/deploy/options/network-option.js b/cli-commands/commands/deploy/options/network-option.js
index e8b11a8..4f9cc94 100644
--- a/cli-commands/commands/deploy/options/network-option.js
+++ b/cli-commands/commands/deploy/options/network-option.js
@@ -2,7 +2,7 @@ const Option = require('../../option');
const eoslime = require('../../../../index');
class NetworkOption extends Option {
- constructor() {
+ constructor () {
super(
'network',
{
@@ -15,9 +15,7 @@ class NetworkOption extends Option {
}
process (optionValue) {
- if (optionValue) {
- return eoslime.init(optionValue);
- }
+ return eoslime.init(optionValue);
}
}
diff --git a/cli-commands/commands/deploy/options/path-option.js b/cli-commands/commands/deploy/options/path-option.js
index 710849d..c98f262 100644
--- a/cli-commands/commands/deploy/options/path-option.js
+++ b/cli-commands/commands/deploy/options/path-option.js
@@ -4,7 +4,7 @@ const Option = require('../../option');
const fileSystemUtil = require('../../../helpers/file-system-util');
class PathOption extends Option {
- constructor() {
+ constructor () {
super(
'path',
{
@@ -16,8 +16,8 @@ class PathOption extends Option {
}
async process (optionValue) {
- let deploymentFilesFunctions = [];
if (fileSystemUtil.isDir(optionValue)) {
+ const deploymentFilesFunctions = [];
const dirFiles = await fileSystemUtil.recursivelyReadDir(optionValue);
for (let i = 0; i < dirFiles.length; i++) {
@@ -27,16 +27,16 @@ class PathOption extends Option {
deploy: require(path.resolve('./', dirFile.fullPath))
});
}
+
+ return deploymentFilesFunctions;
}
if (fileSystemUtil.isFile(optionValue)) {
- deploymentFilesFunctions.push({
+ return [{
fileName: optionValue,
deploy: require(path.resolve('./', optionValue))
- });
+ }];
}
-
- return deploymentFilesFunctions;
}
}
diff --git a/cli-commands/commands/group-command.js b/cli-commands/commands/group-command.js
index 639564d..ab6ffde 100644
--- a/cli-commands/commands/group-command.js
+++ b/cli-commands/commands/group-command.js
@@ -1,17 +1,17 @@
const Command = require('./command');
class GroupCommand extends Command {
- constructor(commandDefinition) {
+ constructor (commandDefinition) {
super(commandDefinition);
}
async execute (args) {
if (optionsProvided(args, this.options)) {
await super.processOptions(args);
- return true;
+ this.hasBeenExecuted = true;
+ } else {
+ this.hasBeenExecuted = false;
}
-
- return false;
}
}
diff --git a/cli-commands/commands/init/index.js b/cli-commands/commands/init/index.js
index 3385bbe..05d47e3 100644
--- a/cli-commands/commands/init/index.js
+++ b/cli-commands/commands/init/index.js
@@ -4,7 +4,7 @@ const Command = require('../command');
const initDirectories = require('./specific/directories.json');
const initCommandDefinition = require('./definition');
-const commandMessages = require('./messages');
+const MESSAGE_COMMAND = require('./messages').COMMAND;
const fileSystemUtil = require('../../helpers/file-system-util');
const defaultPackageJsonDestination = `${__dirname}/specific/default-package.json`;
@@ -13,47 +13,45 @@ const defaultPackageJsonDestination = `${__dirname}/specific/default-package.jso
class InitCommand extends Command {
- constructor() {
+ constructor () {
super(initCommandDefinition);
}
async execute (args) {
+
try {
- commandMessages.Installation();
+ MESSAGE_COMMAND.Start();
createContractsDir();
createDeploymentDir();
createTestsDir();
copyDefaultPackageJson();
- super.processOptions(args);
- } catch (error) {
- commandMessages.UnsuccessfulInstallation(error);
- }
-
- const asyncSoftExec = new AsyncSoftExec('npm install eoslime');
- asyncSoftExec.onError((error) => { commandMessages.UnsuccessfulInstallation(error); });
- asyncSoftExec.onSuccess(() => { commandMessages.SuccessfulInstallation(); });
+ await super.processOptions(args);
- await asyncSoftExec.exec();
+ const asyncSoftExec = new AsyncSoftExec('npm install eoslime');
+ await asyncSoftExec.exec();
- return true;
+ MESSAGE_COMMAND.Success();
+ } catch (error) {
+ MESSAGE_COMMAND.Error(error);
+ }
}
}
-let createContractsDir = function () {
+const createContractsDir = function () {
fileSystemUtil.createDir(initDirectories.CONTRACTS);
}
-let createDeploymentDir = function () {
+const createDeploymentDir = function () {
fileSystemUtil.createDir(initDirectories.DEPLOYMENT);
}
-let createTestsDir = function () {
+const createTestsDir = function () {
fileSystemUtil.createDir(initDirectories.TESTS);
}
-let copyDefaultPackageJson = function () {
+const copyDefaultPackageJson = function () {
fileSystemUtil.copyFileFromTo(defaultPackageJsonDestination, initDirectories.PACKAGE_JSON);
}
diff --git a/cli-commands/commands/init/messages.js b/cli-commands/commands/init/messages.js
index 7b3967a..7fbee95 100644
--- a/cli-commands/commands/init/messages.js
+++ b/cli-commands/commands/init/messages.js
@@ -1,10 +1,9 @@
-const chalk = require('chalk');
+const logger = require('../../common/logger');
module.exports = {
- 'Installation': () => { console.log(chalk.magentaBright('===== Installing eoslime... =====')); },
- 'SuccessfulInstallation': () => { console.log(chalk.greenBright('===== Successfully installed =====')); },
- 'UnsuccessfulInstallation': (error) => {
- console.log(chalk.redBright('===== Unsuccessful installation ====='));
- console.log(error);
+ 'COMMAND': {
+ 'Start': () => { logger.info('===== Installing eoslime... ====='); },
+ 'Success': () => { logger.success('===== Successfully installed ====='); },
+ 'Error': (error) => { logger.error('===== Unsuccessful installation =====', error); }
}
-}
\ No newline at end of file
+}
diff --git a/cli-commands/commands/init/options/with-example/tests-example/tests.js b/cli-commands/commands/init/options/with-example/tests-example/tests.js
index d850183..b34f78b 100644
--- a/cli-commands/commands/init/options/with-example/tests-example/tests.js
+++ b/cli-commands/commands/init/options/with-example/tests-example/tests.js
@@ -32,7 +32,7 @@ describe("EOSIO Token", function (eoslime) {
});
it("Should create a new token", async () => {
- await tokenContract.create(tokensIssuer.name, TOTAL_SUPPLY);
+ await tokenContract.actions.create([tokensIssuer.name, TOTAL_SUPPLY]);
/*
You have access to the EOS(eosjs) instance:
@@ -45,25 +45,25 @@ describe("EOSIO Token", function (eoslime) {
});
it("Should issue tokens", async () => {
- await tokenContract.create(tokensIssuer.name, TOTAL_SUPPLY);
+ await tokenContract.actions.create([tokensIssuer.name, TOTAL_SUPPLY]);
/*
On each contract method you can provide an optional object -> { from: account }
If you don't provide a 'from' object, the method will be executed from the contract account authority
*/
- await tokenContract.issue(tokensHolder.name, HOLDER_SUPPLY, "memo", { from: tokensIssuer });
+ await tokenContract.actions.issue([tokensHolder.name, HOLDER_SUPPLY, "memo"], { from: tokensIssuer });
let holderBalance = await tokensHolder.getBalance("SYS", tokenContract.name);
assert.equal(holderBalance[0], HOLDER_SUPPLY, "Incorrect holder balance");
});
it("Should throw if tokens quantity is negative", async () => {
- await tokenContract.create(tokensIssuer.name, TOTAL_SUPPLY);
+ await tokenContract.actions.create([tokensIssuer.name, TOTAL_SUPPLY]);
const INVALID_ISSUING_AMOUNT = "-100.0000 SYS";
/*
For easier testing, eoslime provides you ('utils.test') with helper functions
*/
- await eoslime.tests.expectAssert(tokenContract.issue(tokensHolder.name, INVALID_ISSUING_AMOUNT, "memo", { from: tokensIssuer }));
+ await eoslime.tests.expectAssert(tokenContract.actions.issue([tokensHolder.name, INVALID_ISSUING_AMOUNT, "memo"], { from: tokensIssuer }));
let holderBalance = await tokensHolder.getBalance("SYS", tokenContract.name);
assert.equal(holderBalance.length, 0, "Incorrect holder balance");
diff --git a/cli-commands/commands/init/options/with-example/with-example-option.js b/cli-commands/commands/init/options/with-example/with-example-option.js
index ee57beb..e41a75c 100644
--- a/cli-commands/commands/init/options/with-example/with-example-option.js
+++ b/cli-commands/commands/init/options/with-example/with-example-option.js
@@ -5,7 +5,7 @@ const Option = require('../../../option');
class WithExampleOption extends Option {
- constructor() {
+ constructor () {
super(
'with-example',
{
diff --git a/cli-commands/commands/nodeos/specific/nodeos-data/data-manager.js b/cli-commands/commands/nodeos/specific/nodeos-data/data-manager.js
index e259471..e641c34 100644
--- a/cli-commands/commands/nodeos/specific/nodeos-data/data-manager.js
+++ b/cli-commands/commands/nodeos/specific/nodeos-data/data-manager.js
@@ -14,8 +14,7 @@ const nodeosDataManager = {
try {
const pid = fileSystemUtil.readFile(path + '/eosd.pid').toString();
return process.kill(pid, 0);
- }
- catch (e) {
+ } catch (e) {
return e.code === 'EPERM'
}
},
diff --git a/cli-commands/commands/nodeos/subcommands/accounts/index.js b/cli-commands/commands/nodeos/subcommands/accounts/index.js
index 046b74f..04a301e 100644
--- a/cli-commands/commands/nodeos/subcommands/accounts/index.js
+++ b/cli-commands/commands/nodeos/subcommands/accounts/index.js
@@ -1,7 +1,7 @@
const AccountsTable = require('./specific/accounts-table');
const Command = require('../../../command');
-const commandMessages = require('./messages');
+const MESSAGE_COMMAND = require('./messages').COMMAND;
const accountsCommandDefinition = require('./definition');
const predefinedAccounts = require('../common/accounts');
@@ -9,13 +9,13 @@ const predefinedAccounts = require('../common/accounts');
// eoslime nodeos show accounts
class AccountsCommand extends Command {
- constructor() {
+ constructor () {
super(accountsCommandDefinition);
}
async execute (args) {
try {
- commandMessages.PreloadedAccounts();
+ MESSAGE_COMMAND.Start();
const accountsTable = new AccountsTable();
const accounts = predefinedAccounts.accounts();
@@ -26,10 +26,8 @@ class AccountsCommand extends Command {
accountsTable.draw();
} catch (error) {
- commandMessages.UnsuccessfulShowing(error);
+ MESSAGE_COMMAND.Error(error);
}
-
- return true;
}
}
diff --git a/cli-commands/commands/nodeos/subcommands/accounts/messages.js b/cli-commands/commands/nodeos/subcommands/accounts/messages.js
index eb325c6..a80bd08 100644
--- a/cli-commands/commands/nodeos/subcommands/accounts/messages.js
+++ b/cli-commands/commands/nodeos/subcommands/accounts/messages.js
@@ -1,9 +1,8 @@
-const chalk = require('chalk');
+const logger = require('../../../../common/logger');
module.exports = {
- 'PreloadedAccounts': () => { console.log(chalk.magentaBright('===== Preloaded accounts =====')); },
- 'UnsuccessfulShowing': (error) => {
- console.log(chalk.redBright(`===== Accounts has not been shown =====`));
- console.log(error);
+ 'COMMAND': {
+ 'Start': () => { logger.info('===== Preloaded accounts ====='); },
+ 'Error': (error) => { logger.error(`===== Accounts has not been shown =====`, error); }
}
}
\ No newline at end of file
diff --git a/cli-commands/commands/nodeos/subcommands/common/accounts.js b/cli-commands/commands/nodeos/subcommands/common/accounts.js
index c778d90..2f9692c 100644
--- a/cli-commands/commands/nodeos/subcommands/common/accounts.js
+++ b/cli-commands/commands/nodeos/subcommands/common/accounts.js
@@ -8,13 +8,13 @@ const preDefinedAccounts = [
},
{
"name": "eoslimekevin",
- "publicKey": "EOS7UyV15G2t47MqRm4WpUP6KTfy9sNU3HHGu9aAgR2A3ktxoBTLv",
- "privateKey": "5KS9t8LGsaQZxLP6Ln5WK6XwYU8M3AYHcfx1x6zoGmbs34vQsPT"
+ "publicKey": "EOS6Zz4iPbjm6FNys1zUMaRE4zPXrHcX3SRG65YWneVbdXQTSiqDp",
+ "privateKey": "5KieRy975NgHk5XQfn8r6o3pcqJDF2vpeV9bDiuB5uF4xKCTwRF"
},
{
"name": "eoslimemarty",
- "publicKey": "EOS7UyV15G2t47MqRm4WpUP6KTfy9sNU3HHGu9aAgR2A3ktxoBTLv",
- "privateKey": "5KS9t8LGsaQZxLP6Ln5WK6XwYU8M3AYHcfx1x6zoGmbs34vQsPT"
+ "publicKey": "EOS7FDeYdY3G8yMNxtrU8MSYnAJc3ZogYHgL7RG3rBf8ZDYA3xthi",
+ "privateKey": "5JtbCXgK5NERDdFdrmxb8rpYMkoxVfSyH1sR6TYxHBG5zNLHfj5"
}
]
diff --git a/cli-commands/commands/nodeos/subcommands/logs/index.js b/cli-commands/commands/nodeos/subcommands/logs/index.js
index d1f1ef9..106f2f8 100644
--- a/cli-commands/commands/nodeos/subcommands/logs/index.js
+++ b/cli-commands/commands/nodeos/subcommands/logs/index.js
@@ -3,20 +3,21 @@ const nodoesDataManager = require('../../specific/nodeos-data/data-manager');
const Command = require('../../../command');
const AsyncSoftExec = require('../../../../helpers/async-soft-exec');
-const commandMessages = require('./messages');
+const MESSAGE_COMMAND = require('./messages').COMMAND;
+const MESSAGE_LOGS = require('./messages').LOGS;
const logsCommandDefinition = require('./definition');
// eoslime nodeos show logs --lines
class LogsCommand extends Command {
- constructor() {
+ constructor () {
super(logsCommandDefinition);
}
async execute (args) {
if (!nodoesDataManager.nodeosIsRunning(nodoesDataManager.nodeosPath())) {
- commandMessages.EmptyLogs();
- return true;
+ MESSAGE_LOGS.Empty();
+ return void 0;
}
try {
@@ -24,13 +25,12 @@ class LogsCommand extends Command {
const nodeosLogFile = nodoesDataManager.nodeosPath() + '/nodeos.log';
const asyncSoftExec = new AsyncSoftExec(`tail -n ${optionsResults.lines} ${nodeosLogFile}`);
- asyncSoftExec.onSuccess((logs) => { commandMessages.NodeosLogs(logs); });
- await asyncSoftExec.exec();
+ const logs = await asyncSoftExec.exec();
+
+ MESSAGE_COMMAND.Success(logs);
} catch (error) {
- commandMessages.UnsuccessfulShowing(error);
+ MESSAGE_COMMAND.Error(error);
}
-
- return true;
}
}
diff --git a/cli-commands/commands/nodeos/subcommands/logs/messages.js b/cli-commands/commands/nodeos/subcommands/logs/messages.js
index 2ea92a0..adeaae1 100644
--- a/cli-commands/commands/nodeos/subcommands/logs/messages.js
+++ b/cli-commands/commands/nodeos/subcommands/logs/messages.js
@@ -1,15 +1,11 @@
-const chalk = require('chalk');
+const logger = require('../../../../common/logger');
module.exports = {
- 'NodeosLogs': (logs) => {
- console.log(chalk.magentaBright('===== Nodeos logs ====='));
- console.log(logs);
+ 'COMMAND': {
+ 'Success': (logs) => { logger.success(`===== Nodeos logs ===== \n ${logs}`); },
+ 'Error': (error) => { logger.error(`===== Logs has not been shown =====`, error); }
},
- 'EmptyLogs': () => {
- console.log(chalk.blueBright('===== Empty logs ====='));
- },
- 'UnsuccessfulShowing': (error) => {
- console.log(chalk.redBright(`===== Logs has not been shown =====`));
- console.log(error);
+ 'LOGS': {
+ 'Empty': () => { logger.info('===== Empty logs ====='); },
}
-}
\ No newline at end of file
+}
diff --git a/cli-commands/commands/nodeos/subcommands/start/index.js b/cli-commands/commands/nodeos/subcommands/start/index.js
index 242fcb1..6a6f7fc 100644
--- a/cli-commands/commands/nodeos/subcommands/start/index.js
+++ b/cli-commands/commands/nodeos/subcommands/start/index.js
@@ -1,7 +1,8 @@
const Command = require('../../../command');
const AsyncSoftExec = require('../../../../helpers/async-soft-exec');
-const commandMessages = require('./messages');
+const MESSAGE_COMMAND = require('./messages').COMMAND;
+const MESSAGE_NODEOS = require('./messages').NODEOS;
const startCommandDefinition = require('./definition');
const template = require('./specific/template');
@@ -12,20 +13,20 @@ const nodeosDataManager = require('../../specific/nodeos-data/data-manager');
// eoslime nodeos start --path
class StartCommand extends Command {
- constructor() {
+ constructor () {
super(startCommandDefinition);
}
async execute (args) {
if (nodeosDataManager.nodeosIsRunning(nodeosDataManager.nodeosPath())) {
- commandMessages.NodeosAlreadyRunning();
- return true;
+ MESSAGE_NODEOS.AlreadyRunning();
+ return void 0;
}
try {
- commandMessages.StartingNodeos();
- const optionsResults = await super.processOptions(args);
+ MESSAGE_COMMAND.Start();
+ const optionsResults = await super.processOptions(args);
nodeosDataManager.setNodeosPath(optionsResults.path);
const asyncSoftExec = new AsyncSoftExec(template.build(optionsResults.path));
@@ -34,12 +35,10 @@ class StartCommand extends Command {
nodeosDataManager.requireRunningNodeos(optionsResults.path);
await predefinedAccounts.load();
- commandMessages.SuccessfullyStarted();
+ MESSAGE_COMMAND.Success();
} catch (error) {
- commandMessages.UnsuccessfulStarting(error);
+ MESSAGE_COMMAND.Error(error);
}
-
- return true;
}
}
diff --git a/cli-commands/commands/nodeos/subcommands/start/messages.js b/cli-commands/commands/nodeos/subcommands/start/messages.js
index 94119a1..9009b50 100644
--- a/cli-commands/commands/nodeos/subcommands/start/messages.js
+++ b/cli-commands/commands/nodeos/subcommands/start/messages.js
@@ -1,11 +1,12 @@
-const chalk = require('chalk');
+const logger = require('../../../../common/logger');
module.exports = {
- 'StartingNodeos': () => { console.log(chalk.magentaBright('===== Starting nodeos ... =====')); },
- 'NodeosAlreadyRunning': () => { console.log(chalk.blueBright(`===== Nodeos is already running =====`)); },
- 'SuccessfullyStarted': () => { console.log(chalk.greenBright(`===== Successfully started =====`)); },
- 'UnsuccessfulStarting': (error) => {
- console.log(chalk.redBright(`===== Nodeos has not been started =====`));
- console.log(error);
+ 'COMMAND': {
+ 'Start': () => { logger.info('===== Starting nodeos ... ====='); },
+ 'Success': () => { logger.success(`===== Successfully started =====`); },
+ 'Error': (error) => { logger.error(`===== Nodeos has not been started =====`, error); }
+ },
+ 'NODEOS': {
+ 'AlreadyRunning': () => { logger.info(`===== Nodeos is already running =====`); },
}
}
\ No newline at end of file
diff --git a/cli-commands/commands/nodeos/subcommands/start/options/path-option.js b/cli-commands/commands/nodeos/subcommands/start/options/path-option.js
index d4a7a43..617e842 100644
--- a/cli-commands/commands/nodeos/subcommands/start/options/path-option.js
+++ b/cli-commands/commands/nodeos/subcommands/start/options/path-option.js
@@ -1,9 +1,10 @@
const Option = require('../../../../option');
+const fileSystemUtils = require('../../../../../helpers/file-system-util');
const nodeosDataManager = require('../../../specific/nodeos-data/data-manager');
class PathOption extends Option {
- constructor() {
+ constructor () {
super(
'path',
{
@@ -15,7 +16,9 @@ class PathOption extends Option {
}
async process (optionValue) {
- return optionValue;
+ if (fileSystemUtils.isDir(optionValue)) {
+ return optionValue;
+ }
}
}
diff --git a/cli-commands/commands/nodeos/subcommands/stop/index.js b/cli-commands/commands/nodeos/subcommands/stop/index.js
index 816ef51..9313fdb 100644
--- a/cli-commands/commands/nodeos/subcommands/stop/index.js
+++ b/cli-commands/commands/nodeos/subcommands/stop/index.js
@@ -4,19 +4,19 @@ const nodeosDataManager = require('../../specific/nodeos-data/data-manager');
const Command = require('../../../command');
const AsyncSoftExec = require('../../../../helpers/async-soft-exec');
-const commandMessages = require('./messages');
+const MESSAGE_COMMAND = require('./messages').COMMAND;
const stopCommandDefinition = require('./definition');
// eoslime nodeos stop
class StopCommand extends Command {
- constructor() {
+ constructor () {
super(stopCommandDefinition);
}
async execute (args) {
try {
- commandMessages.StoppingNodeos();
+ MESSAGE_COMMAND.Start();
if (nodeosDataManager.nodeosIsRunning(nodeosDataManager.nodeosPath())) {
const nodeosPid = fileSystemUtil.readFile(
@@ -27,12 +27,11 @@ class StopCommand extends Command {
}
await clearNodeosData(nodeosDataManager.nodeosPath());
- commandMessages.SuccessfullyStopped();
+
+ MESSAGE_COMMAND.Success();
} catch (error) {
- commandMessages.UnsuccessfulStopping(error);
+ MESSAGE_COMMAND.Error(error);
}
-
- return true;
}
}
diff --git a/cli-commands/commands/nodeos/subcommands/stop/messages.js b/cli-commands/commands/nodeos/subcommands/stop/messages.js
index 7af7b3f..4bd98c8 100644
--- a/cli-commands/commands/nodeos/subcommands/stop/messages.js
+++ b/cli-commands/commands/nodeos/subcommands/stop/messages.js
@@ -1,10 +1,9 @@
-const chalk = require('chalk');
+const logger = require('../../../../common/logger');
module.exports = {
- 'StoppingNodeos': () => { console.log(chalk.magentaBright('===== Stopping nodeos ... =====')); },
- 'SuccessfullyStopped': () => { console.log(chalk.greenBright(`===== Successfully stopped =====`)); },
- 'UnsuccessfulStopping': (error) => {
- console.log(chalk.redBright(`===== Nodeos has not been stopped =====`));
- console.log(error);
+ 'COMMAND': {
+ 'Start': () => { logger.info('===== Stopping nodeos ... ====='); },
+ 'Success': () => { logger.success(`===== Successfully stopped =====`); },
+ 'Error': (error) => { logger.error(`===== Nodeos has not been stopped =====`, error); }
}
-}
\ No newline at end of file
+}
diff --git a/cli-commands/commands/shape/index.js b/cli-commands/commands/shape/index.js
index d8c3df6..83169d1 100644
--- a/cli-commands/commands/shape/index.js
+++ b/cli-commands/commands/shape/index.js
@@ -2,33 +2,28 @@ const git = require('simple-git/promise')()
const Command = require('../command');
-const commandMessages = require('./messages');
+const MESSAGE_COMMAND = require('./messages').COMMAND;
+
const shapeCommandDefinition = require('./definition');
// eoslime shape --name
class ShapeCommand extends Command {
- constructor() {
+ constructor () {
super(shapeCommandDefinition);
}
async execute (args) {
try {
- commandMessages.StartShaping();
- const optionsResults = await super.processOptions(args);
-
- if (!optionsResults.framework) {
- commandMessages.InvalidShapeName(args.framework);
- }
+ MESSAGE_COMMAND.Start();
+ const optionsResults = await super.processOptions(args);
await git.clone(optionsResults.framework);
- commandMessages.SuccessfulShaping();
+ MESSAGE_COMMAND.Success();
} catch (error) {
- commandMessages.UnsuccessfulShaping(error);
+ MESSAGE_COMMAND.Error(error);
}
-
- return true;
}
}
diff --git a/cli-commands/commands/shape/messages.js b/cli-commands/commands/shape/messages.js
index 975c899..8fa1288 100644
--- a/cli-commands/commands/shape/messages.js
+++ b/cli-commands/commands/shape/messages.js
@@ -1,11 +1,9 @@
-const chalk = require('chalk');
+const logger = require('../../common/logger');
module.exports = {
- 'StartShaping': () => { console.log(chalk.magentaBright('===== Shaping of DApp has started... =====')); },
- 'SuccessfulShaping': () => { console.log(chalk.greenBright(`===== Successful shaping =====`)); },
- 'UnsuccessfulShaping': (error) => {
- console.log(chalk.redBright(`===== Unsuccessful shaping =====`));
- console.log(error);
- },
- 'InvalidShapeName': (name) => { console.log(chalk.redBright(`===== Invalid shape name ${name} =====`)); },
-}
\ No newline at end of file
+ 'COMMAND': {
+ 'Start': () => { logger.info('===== Shaping of DApp has started... ====='); },
+ 'Success': () => { logger.success(`===== Successful shaping =====`); },
+ 'Error': (error) => { logger.error(`===== Unsuccessful shaping =====`, error); },
+ }
+}
diff --git a/cli-commands/commands/shape/options/framework-option.js b/cli-commands/commands/shape/options/framework-option.js
index 763b762..3f19d2d 100644
--- a/cli-commands/commands/shape/options/framework-option.js
+++ b/cli-commands/commands/shape/options/framework-option.js
@@ -2,7 +2,7 @@ const Option = require('../../option');
const repositories = require('../specific/repositories.json');
class FrameworkOption extends Option {
- constructor() {
+ constructor () {
super(
'framework',
{
@@ -14,6 +14,10 @@ class FrameworkOption extends Option {
}
process (optionValue) {
+ if (!repositories[optionValue]) {
+ throw new Error('Invalid Shape framework');
+ }
+
return repositories[optionValue];
}
}
diff --git a/cli-commands/commands/test/definition.js b/cli-commands/commands/test/definition.js
index 165c588..d3d0ec1 100644
--- a/cli-commands/commands/test/definition.js
+++ b/cli-commands/commands/test/definition.js
@@ -1,6 +1,6 @@
const pathOption = require('./options/path-option');
const networkOption = require('./options/network-option');
-const resourceReportOption = require('./options/resource-usage-option/resource-usage-option');
+const resourceReportOption = require('./options/resource-usage-option');
module.exports = {
"template": "test",
diff --git a/cli-commands/commands/test/index.js b/cli-commands/commands/test/index.js
index 64777db..f975306 100644
--- a/cli-commands/commands/test/index.js
+++ b/cli-commands/commands/test/index.js
@@ -1,21 +1,24 @@
const Command = require('../command');
+
+const MESSAGE_COMMAND = require('./messages').COMMAND;
const testCommandDefinition = require('./definition');
const eoslime = require('../../../index');
-
const testUtils = require('./specific/utils');
// eoslime test --path --network --resource-usage=
class TestCommand extends Command {
- constructor(TestFramework) {
+ constructor (TestFramework) {
super(testCommandDefinition);
this.TestFramework = TestFramework;
}
async execute (args) {
try {
+ MESSAGE_COMMAND.Start();
+
args.eoslime = eoslime.init();
args.testFramework = new this.TestFramework();
@@ -24,12 +27,12 @@ class TestCommand extends Command {
setTestsHelpers(args.eoslime);
args.testFramework.setDescribeArgs(args.eoslime);
- args.testFramework.runTests();
+ await args.testFramework.runTests();
+
+ MESSAGE_COMMAND.Success();
} catch (error) {
- console.log(error);
+ MESSAGE_COMMAND.Error(error);
}
-
- return true;
}
}
diff --git a/cli-commands/commands/test/messages.js b/cli-commands/commands/test/messages.js
index 3f29265..5c0618a 100644
--- a/cli-commands/commands/test/messages.js
+++ b/cli-commands/commands/test/messages.js
@@ -1,14 +1,9 @@
-const chalk = require('chalk');
+const logger = require('../../common/logger');
module.exports = {
- 'StartTesting': () => { console.log(chalk.magentaBright('===== Deployment has started... =====')); },
- 'SuccessfulDeploymentOfScript': (script) => { console.log(chalk.greenBright(`===== Successful deployment of ${script} =====`)); },
- 'UnsuccessfulDeploymentOfScript': (script, error) => {
- console.log(chalk.redBright(`===== Unsuccessful deployment of ${script} =====`));
- console.log(error);
- },
- 'UnsuccessfulDeployment': (error) => {
- console.log(chalk.redBright(`===== Unsuccessful deployment =====`));
- console.log(error);
+ 'COMMAND': {
+ 'Start': () => { logger.info('===== Testing has started... ====='); },
+ 'Success': () => { logger.success(`===== Testing completed successfully =====`); },
+ 'Error': (error) => { logger.error(`===== Testing failed =====`, error); }
}
-}
\ No newline at end of file
+}
diff --git a/cli-commands/commands/test/options/network-option.js b/cli-commands/commands/test/options/network-option.js
index a37eeb8..f375839 100644
--- a/cli-commands/commands/test/options/network-option.js
+++ b/cli-commands/commands/test/options/network-option.js
@@ -1,7 +1,7 @@
const Option = require('../../option');
class NetworkOption extends Option {
- constructor() {
+ constructor () {
super(
'network',
{
diff --git a/cli-commands/commands/test/options/path-option.js b/cli-commands/commands/test/options/path-option.js
index d4465ee..d8fd653 100644
--- a/cli-commands/commands/test/options/path-option.js
+++ b/cli-commands/commands/test/options/path-option.js
@@ -4,7 +4,7 @@ const Option = require('../../option');
const fileSystemUtil = require('../../../helpers/file-system-util');
class PathOption extends Option {
- constructor() {
+ constructor () {
super(
'path',
{
diff --git a/cli-commands/commands/test/options/resource-usage-option/resource-usage-option.js b/cli-commands/commands/test/options/resource-usage-option/index.js
similarity index 69%
rename from cli-commands/commands/test/options/resource-usage-option/resource-usage-option.js
rename to cli-commands/commands/test/options/resource-usage-option/index.js
index 27a13b1..e545701 100644
--- a/cli-commands/commands/test/options/resource-usage-option/resource-usage-option.js
+++ b/cli-commands/commands/test/options/resource-usage-option/index.js
@@ -2,7 +2,7 @@ const Option = require('../../../option');
const ReportTable = require('./report-table');
class ResourceReportOption extends Option {
- constructor() {
+ constructor () {
super(
'resource-usage',
{
@@ -60,7 +60,7 @@ class ResourceReportOption extends Option {
}
const fillDeploymentsResources = function (eoslime, deploymentsResources) {
- eoslime.Contract.on('deploy', (txReceipts, contract) => {
+ eoslime.Contract.on('deploy', (contract, txReceipts) => {
const setCodeResources = extractResourcesCostsFromReceipt(txReceipts[0]);
const setABIResources = extractResourcesCostsFromReceipt(txReceipts[1]);
@@ -81,36 +81,31 @@ const fillDeploymentsResources = function (eoslime, deploymentsResources) {
const fillFunctionsResources = function (eoslime, contractsResources) {
eoslime.Contract.on('init', (contract) => {
- for (const functionName in contract) {
- if (contract.hasOwnProperty(functionName)) {
- const contractFunction = contract[functionName];
-
- if (contractFunction.isTransactional) {
- contractFunction.on('processed', (txReceipt, inputParams) => {
- const usedResources = extractResourcesCostsFromReceipt(txReceipt);
- if (!contractsResources[contract.name]) {
- contractsResources[contract.name] = {
- functions: {}
- }
- }
-
- if (!contractsResources[contract.name].functions[functionName]) {
- contractsResources[contract.name].functions[functionName] = {
- calls: 0,
- ram: [],
- cpu: [],
- net: []
- }
- }
-
- const functionResources = contractsResources[contract.name].functions[functionName];
- functionResources.ram = getMinMaxPair(functionResources.ram[0], functionResources.ram[1], usedResources.ramCost);
- functionResources.cpu = getMinMaxPair(functionResources.cpu[0], functionResources.cpu[1], usedResources.cpuCost);
- functionResources.net = getMinMaxPair(functionResources.net[0], functionResources.net[1], usedResources.netCost);
- functionResources.calls += 1;
- });
+ for (const functionName in contract.actions) {
+ const contractFunction = contract.actions[functionName];
+ contractFunction.on('processed', (txReceipt, inputParams) => {
+ const usedResources = extractResourcesCostsFromReceipt(txReceipt);
+ if (!contractsResources[contract.name]) {
+ contractsResources[contract.name] = {
+ functions: {}
+ }
}
- }
+
+ if (!contractsResources[contract.name].functions[functionName]) {
+ contractsResources[contract.name].functions[functionName] = {
+ calls: 0,
+ ram: [],
+ cpu: [],
+ net: []
+ }
+ }
+
+ const functionResources = contractsResources[contract.name].functions[functionName];
+ functionResources.ram = getMinMaxPair(functionResources.ram[0], functionResources.ram[1], usedResources.ramCost);
+ functionResources.cpu = getMinMaxPair(functionResources.cpu[0], functionResources.cpu[1], usedResources.cpuCost);
+ functionResources.net = getMinMaxPair(functionResources.net[0], functionResources.net[1], usedResources.netCost);
+ functionResources.calls += 1;
+ });
}
});
}
diff --git a/cli-commands/commands/test/specific/utils/index.js b/cli-commands/commands/test/specific/utils/index.js
index 79c592d..94635c6 100644
--- a/cli-commands/commands/test/specific/utils/index.js
+++ b/cli-commands/commands/test/specific/utils/index.js
@@ -1,10 +1,10 @@
const assert = require('assert');
module.exports = {
- expectAssert: function (promise) {
+ expectAssert: async function (promise) {
return expectEOSError(promise, 'eosio_assert_message_exception', 'assert');
},
- expectMissingAuthority: function (promise) {
+ expectMissingAuthority: async function (promise) {
return expectEOSError(promise, 'missing_auth_exception', 'missing authority');
},
// Todo: Uncomment it once test cli command is ready
@@ -20,12 +20,13 @@ module.exports = {
// }
}
-let expectEOSError = async function (promise, errorType, errorInfo) {
+const expectEOSError = async function (promise, errorType, errorInfo) {
try {
await promise;
} catch (error) {
- const expectedError = error.search(errorType) >= 0;
- assert(expectedError, `Expected ${errorInfo}, got '${error}' instead`);
+ const message = error.message || error;
+ const expectedError = message.search(errorType) >= 0;
+ assert(expectedError, `Expected ${errorInfo}, got '${message}' instead`);
return;
}
assert.fail(`Expected ${errorInfo} not received`);
diff --git a/cli-commands/common/logger.js b/cli-commands/common/logger.js
new file mode 100644
index 0000000..001726d
--- /dev/null
+++ b/cli-commands/common/logger.js
@@ -0,0 +1,19 @@
+const chalk = require('chalk');
+
+const logger = {
+ log: (message) => {
+ console.log(message);
+ },
+ success: (message) => {
+ console.log(chalk.greenBright(message));
+ },
+ info: (message) => {
+ console.log(chalk.blueBright(message));
+ },
+ error: (message, error) => {
+ console.log(chalk.redBright(message));
+ console.log(error);
+ }
+}
+
+module.exports = logger;
diff --git a/cli-commands/common/table.js b/cli-commands/common/table.js
index b232557..7fc3d7e 100644
--- a/cli-commands/common/table.js
+++ b/cli-commands/common/table.js
@@ -1,8 +1,10 @@
const chalk = require('chalk').default;
const CLITable = require('cli-table');
+const logger = require('./logger');
+
class Table {
- constructor(tableHead) {
+ constructor (tableHead) {
this.table = new CLITable(tableHead);
}
@@ -25,7 +27,7 @@ class Table {
}
draw () {
- console.log(this.table.toString());
+ logger.log(this.table.toString());
}
}
diff --git a/cli-commands/helpers/async-soft-exec.js b/cli-commands/helpers/async-soft-exec.js
index f1f44de..6176d9f 100644
--- a/cli-commands/helpers/async-soft-exec.js
+++ b/cli-commands/helpers/async-soft-exec.js
@@ -1,39 +1,21 @@
const exec = require('child_process').exec;
class AsyncSoftExec {
- constructor(command) {
+ constructor (command) {
this.command = command;
-
- this.successCallback = () => { };
- this.errorCallback = (error) => { throw new Error(error) };
- }
-
- onError (callback) {
- this.errorCallback = callback;
- }
-
- onSuccess (callback) {
- this.successCallback = callback;
}
async exec () {
return new Promise((resolve, reject) => {
exec(this.command, async (error, stdout) => {
- try {
- if (error) {
- await this.errorCallback(error);
- return void resolve(true);
- }
-
- await this.successCallback(stdout);
- return void resolve(true);
- } catch (error) {
- reject(error);
+ if (error) {
+ return void reject(error);
}
+
+ return void resolve(stdout);
});
});
}
}
-
module.exports = AsyncSoftExec;
diff --git a/cli-commands/helpers/file-system-util.js b/cli-commands/helpers/file-system-util.js
index 71d9c84..f468849 100644
--- a/cli-commands/helpers/file-system-util.js
+++ b/cli-commands/helpers/file-system-util.js
@@ -75,9 +75,6 @@ const fileSystemUtils = {
});
});
},
- exists: (path) => {
- return fs.existsSync(path);
- },
readFile: (filePath) => {
return fs.readFileSync(filePath);
},
diff --git a/index.d.ts b/index.d.ts
new file mode 100644
index 0000000..cb77958
--- /dev/null
+++ b/index.d.ts
@@ -0,0 +1,23 @@
+// Type definitions for EOSLime
+// Project: https://github.com/LimeChain/eoslime
+// Definitions by: Lyubomir Kiprov
+// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
+
+import { utils } from './types/utils';
+import { ContractFactory } from './types/contract';
+import { Provider, NetworkDetails } from './types/provider';
+import { AccountFactory, MultiSignatureFactory } from './types/account';
+
+interface EOSLime {
+ utils: utils;
+ Provider: Provider;
+ Account: AccountFactory;
+ Contract: ContractFactory;
+ MultiSigAccount: MultiSignatureFactory;
+}
+
+export const utils: utils;
+export const NETWORKS: Array;
+
+export function init (network?: string, config?: NetworkDetails): EOSLime;
+export function init (config?: NetworkDetails): EOSLime;
diff --git a/nyc.config.js b/nyc.config.js
new file mode 100644
index 0000000..7feeb4d
--- /dev/null
+++ b/nyc.config.js
@@ -0,0 +1,9 @@
+module.exports = {
+ "include": [
+ "**/*.js"
+ ],
+ "exclude": [
+ "tests/**/*.js",
+ "cli-commands/commands/test/specific/test-frameworks/mocha/index.js"
+ ]
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index b924d01..796ac67 100644
--- a/package.json
+++ b/package.json
@@ -1,11 +1,13 @@
{
"name": "eoslime",
- "version": "1.0.4",
+ "version": "2.0.0",
"description": "eoslime is an EOS development and deployment framework based on eosjs.js",
"main": "index.js",
+ "types": "index.d.ts",
"scripts": {
- "test": "bash ./tests/testing-contracts/compile.sh && nyc --check-coverage mocha './tests/*.js'",
- "test-dev": "bash ./tests/testing-contracts/compile.sh && mocha './tests/*.js'",
+ "build": "tsc",
+ "test": "nyc --check-coverage mocha './tests/**/*.js' && tsc&& bash ./tests/testing-contracts/compile.sh && mocha -r ts-node/register tests/**/*.ts",
+ "test-dev": "mocha './tests/**/*.js'&& tsc && bash ./tests/testing-contracts/compile.sh && mocha -r ts-node/register tests/**/*.ts",
"coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov"
},
"author": "Lyubomir Kiprov (Limechain)",
@@ -16,11 +18,21 @@
"crypto-js": "3.1.9-1",
"eosjs": "16.0.9",
"is-invalid-path": "1.0.2",
- "mocha": "5.2.0",
"prompts": "2.2.1",
"simple-git": "1.132.0",
"yargs": "12.0.5"
},
+ "devDependencies": {
+ "@types/assert": "^1.5.1",
+ "@types/mocha": "^7.0.2",
+ "assert": "^2.0.0",
+ "mocha": "^5.2.0",
+ "nyc": "14.1.1",
+ "proxyquire": "^2.1.3",
+ "sinon": "^9.0.2",
+ "ts-node": "^8.10.2",
+ "typescript": "^3.9.5"
+ },
"keywords": [
"lime",
"eos",
@@ -40,8 +52,5 @@
"homepage": "https://github.com/LimeChain/eoslime#readme",
"bin": {
"eoslime": "./cli.js"
- },
- "devDependencies": {
- "nyc": "14.1.1"
}
}
\ No newline at end of file
diff --git a/src/account/authority-account/account.js b/src/account/authority-account/account.js
deleted file mode 100644
index 2e7da6f..0000000
--- a/src/account/authority-account/account.js
+++ /dev/null
@@ -1,29 +0,0 @@
-const is = require('../../helpers/is')
-
-class AuthorityAccount {
-
- static construct(account, parentPermission) {
- account.setAuthorityAbilities = setAuthorityAbilities(account, parentPermission);
- return account;
- }
-}
-
-const setAuthorityAbilities = function (account, parentAuthority) {
- return async function (abilities) {
- is(abilities).instanceOf('Array');
-
- await account.provider.eos.transaction(tr => {
- for (let i = 0; i < abilities.length; i++) {
- const ability = abilities[i];
- tr.linkauth({
- account: account.name,
- code: ability.contract,
- type: ability.action,
- requirement: account.executiveAuthority.permission
- }, { authorization: [`${this.name}@${parentAuthority}`] });
- }
- }, { broadcast: true, sign: true, keyProvider: account.privateKey });
- }
-}
-
-module.exports = AuthorityAccount;
diff --git a/src/account/base-account.js b/src/account/base-account.js
index dd4fb37..ca7c1ac 100644
--- a/src/account/base-account.js
+++ b/src/account/base-account.js
@@ -2,10 +2,10 @@ const eosECC = require('eosjs').modules.ecc;
class BaseAccount {
- constructor(name, privateKey, provider, permission) {
+ constructor (name, privateKey, provider, permission) {
this.name = name;
this.provider = provider;
- this.executiveAuthority = {
+ this.authority = {
actor: name,
permission: permission
}
@@ -15,7 +15,7 @@ class BaseAccount {
}
async getAuthorityInfo () {
- const authority = arguments[0] ? arguments[0] : this.executiveAuthority.permission;
+ const authority = arguments[0] ? arguments[0] : this.authority.permission;
const accountInfo = await this.provider.eos.getAccount(this.name);
const authorityInfo = accountInfo.permissions.find((permission) => {
diff --git a/src/account/multi-signature-account/account.js b/src/account/multi-signature-account/account.js
index a7a95bf..1e14040 100644
--- a/src/account/multi-signature-account/account.js
+++ b/src/account/multi-signature-account/account.js
@@ -3,37 +3,37 @@ const BaseAccount = require('../base-account');
class MultiSignatureAccount extends BaseAccount {
- constructor(name, privateKey, provider, authority) {
+ constructor (name, privateKey, provider, authority) {
super(name, privateKey, provider, authority)
this.accounts = [];
this.proposals = {};
}
- loadKeys(privateKeys) {
+ loadKeys (privateKeys) {
for (let i = 0; i < privateKeys.length; i++) {
- this.accounts.push(new BaseAccount(this.name, privateKeys[i], this.provider, this.executiveAuthority.permission));
+ this.accounts.push(new BaseAccount(this.name, privateKeys[i], this.provider, this.authority.permission));
}
}
- loadAccounts(accounts) {
+ loadAccounts (accounts) {
for (let i = 0; i < accounts.length; i++) {
is(accounts[i]).instanceOf('BaseAccount');
this.accounts.push(accounts[i]);
}
}
- async propose(contractAction, actionData) {
+ async propose (contractAction, actionData) {
is(contractAction).instanceOf('ContractFunction');
- const actionTx = await contractAction.sign(this, ...actionData);
+ const actionTx = await contractAction.sign(actionData, { from: this });
const proposalId = Date.now();
this.proposals[proposalId] = actionTx;
return proposalId;
}
- async approve(publicKey, proposalId) {
+ async approve (publicKey, proposalId) {
const approver = this.accounts.find((account) => { return account.publicKey == publicKey });
requireExistingApprover(approver);
requireExistingProposal(this.proposals, proposalId);
@@ -47,7 +47,7 @@ class MultiSignatureAccount extends BaseAccount {
proposalTx.signatures.push(approverSignedTx.transaction.signatures[0]);
}
- async processProposal(proposalId) {
+ async processProposal (proposalId) {
requireExistingProposal(this.proposals, proposalId);
await requireEnoughApprovals(this, this.proposals[proposalId]);
diff --git a/src/account/normal-account/account-factory.js b/src/account/normal-account/account-factory.js
index 08416aa..86f42af 100644
--- a/src/account/normal-account/account-factory.js
+++ b/src/account/normal-account/account-factory.js
@@ -7,7 +7,7 @@ const utils = require('../../utils');
const DEFAULT_AUTHORITY = 'active';
class AccountFactory {
- constructor(provider) {
+ constructor (provider) {
this.provider = provider;
}
@@ -66,7 +66,7 @@ class AccountFactory {
const dataToBeEncrypted = {
name: newAccount.name,
network: newAccount.provider.network,
- authority: newAccount.executiveAuthority
+ authority: newAccount.authority
};
const dataHash = crypto.hash(JSON.stringify({ ...dataToBeEncrypted, privateKey: newAccount.privateKey }));
diff --git a/src/account/normal-account/account.js b/src/account/normal-account/account.js
index 3e68a25..45bc617 100644
--- a/src/account/normal-account/account.js
+++ b/src/account/normal-account/account.js
@@ -1,11 +1,10 @@
const is = require('../../helpers/is')
const eosECC = require('eosjs').modules.ecc;
const BaseAccount = require('../base-account');
-const AuthorityAccount = require('../authority-account/account');
class Account extends BaseAccount {
- constructor(name, privateKey, provider, permission) {
+ constructor (name, privateKey, provider, permission) {
super(name, privateKey, provider, permission);
}
@@ -42,21 +41,49 @@ class Account extends BaseAccount {
this.name,
receiver.name,
`${amount} ${symbol}`,
- this.executiveAuthority,
+ this.authority,
{ broadcast: true, sign: true, keyProvider: this.privateKey }
);
}
- async createSubAuthority (authorityName, threshold = 1) {
+ async addAuthority (authorityName, threshold = 1) {
const authorization = {
threshold,
keys: [{ key: this.publicKey, weight: threshold }]
}
- await updateAuthority.call(this, authorityName, this.executiveAuthority.permission, authorization);
- const authorityAccount = new Account(this.name, this.privateKey, this.provider, authorityName);
+ return updateAuthority.call(this, authorityName, this.authority.permission, authorization);
+ }
+
+ async setAuthorityAbilities (authorityName, abilities) {
+ is(abilities).instanceOf('Array');
- return AuthorityAccount.construct(authorityAccount, this.executiveAuthority.permission);
+ const accountInfo = await this.provider.eos.getAccount(this.name);
+ const hasAuthName = accountInfo.permissions.find((permissions) => {
+ return permissions.perm_name == authorityName;
+ });
+
+ if (!hasAuthName) {
+ throw new Error(`
+ Account does not have authority with name: [${authorityName}].
+ You could add it by using [addAuthority] function.
+ For details check [Set authority abilities] suite in account-tests.js
+ `);
+ }
+
+ const txReceipt = await this.provider.eos.transaction(tr => {
+ for (let i = 0; i < abilities.length; i++) {
+ const ability = abilities[i];
+ tr.linkauth({
+ account: this.name,
+ code: ability.contract,
+ type: ability.action,
+ requirement: authorityName
+ }, { authorization: [this.authority] });
+ }
+ }, { broadcast: true, sign: true, keyProvider: this.privateKey });
+
+ return txReceipt;
}
async increaseThreshold (threshold) {
@@ -82,7 +109,7 @@ class Account extends BaseAccount {
}
}
- async addAuthorityKey (publicKey, weight = 1) {
+ async addOnBehalfKey (publicKey, weight = 1) {
if (!eosECC.isValidPublic(publicKey)) {
throw new Error('Provided public key is not a valid one');
}
@@ -115,16 +142,18 @@ class Account extends BaseAccount {
}
const updateAuthority = async function (authorityName, parent, auth) {
- await this.provider.eos.transaction(tr => {
+ const txReceipt = await this.provider.eos.transaction(tr => {
tr.updateauth({
account: this.name,
permission: authorityName,
parent: parent,
auth: auth
- }, { authorization: [this.executiveAuthority] });
+ }, { authorization: [this.authority] });
}, { broadcast: true, sign: true, keyProvider: this.privateKey });
+ return txReceipt;
+
}
module.exports = Account;
diff --git a/src/contract/contract-factory.js b/src/contract/contract-factory.js
index 7d2b71a..d087c1b 100644
--- a/src/contract/contract-factory.js
+++ b/src/contract/contract-factory.js
@@ -22,7 +22,7 @@ const EVENTS = {
class ContractFactory extends ContractInitializator {
- constructor(provider) {
+ constructor (provider) {
super(provider);
Object.assign(this.events, EVENTS);
}
@@ -77,7 +77,7 @@ class ContractFactory extends ContractInitializator {
options = Object.assign(defaultDeployOptions, options);
await executeOptions(contract, options);
- this.emit(EVENTS.deploy, [setCodeTxReceipt, setAbiTxReceipt], contract);
+ this.emit(EVENTS.deploy, contract, [setCodeTxReceipt, setAbiTxReceipt]);
return contract;
}
diff --git a/src/contract/contract-function/contract-function.js b/src/contract/contract-function/contract-function.js
index d2571a7..c71e56f 100644
--- a/src/contract/contract-function/contract-function.js
+++ b/src/contract/contract-function/contract-function.js
@@ -8,102 +8,105 @@ const EVENTS = {
class ContractFunction extends EventClass {
- constructor(contract, functionName, functionFields) {
+ constructor (contract, functionName, functionFields) {
super(EVENTS);
+
this.contract = contract;
this.functionName = functionName;
this.functionFields = functionFields;
- this.isTransactional = true;
}
- async broadcast(...params) {
+ async broadcast (params, options) {
is(this.contract.executor).instanceOf('BaseAccount', 'executor is missing');
- const functionParamsCount = this.functionFields.length;
- const functionParams = params.slice(0, functionParamsCount);
- const functionRawTxData = buildFunctionRawTxData.call(this, this.contract.executor, functionParams);
-
- // Optionals starts from the last function parameter position
- const optionals = params[functionParamsCount] instanceof Object ? params[functionParamsCount] : null;
- for (let i = 0; i < optionalsFunctions.all.length; i++) {
- const optionalFunction = optionalsFunctions.all[i];
- optionalFunction(optionals, functionRawTxData);
+ const txOptions = {
+ broadcast: true,
+ sign: true
}
- const txReceipt = await executeFunction(
- this.contract.provider.eos,
- functionRawTxData,
- { broadcast: true, sign: true, keyProvider: functionRawTxData.defaultExecutor.privateKey }
- );
+ const txReceipt = await executeFunction.call(this, params, options, txOptions);
- this.emit(EVENTS.processed, txReceipt, functionParams);
+ this.emit(EVENTS.processed, txReceipt, params);
return txReceipt;
}
- async getRawTransaction(...params) {
- const functionRawTxData = buildFunctionRawTxData.call(this, this.contract.executor, params);
- const rawTransaction = await executeFunction(
- this.contract.provider.eos,
- functionRawTxData,
- { broadcast: false, sign: false }
- );
+ async getRawTransaction (params, options) {
+ const txOptions = {
+ broadcast: false,
+ sign: false
+ }
+ const rawTransaction = await executeFunction.call(this, params, options, txOptions);
return rawTransaction.transaction.transaction;
}
- async sign(signer, ...params) {
- is(signer).instanceOf('BaseAccount');
-
- const functionRawTxData = buildFunctionRawTxData.call(this, signer, params);
- const rawTransaction = await executeFunction(
- this.contract.provider.eos,
- functionRawTxData,
- { broadcast: false, sign: true, keyProvider: signer.privateKey }
- );
+ async sign (params, options) {
+ const txOptions = {
+ broadcast: false,
+ sign: true
+ }
+ const rawTransaction = await executeFunction.call(this, params, options, txOptions);
return rawTransaction.transaction;
}
}
-const buildFunctionRawTxData = function (authorizer, params) {
+async function executeFunction (params, fnOptions, txOptions) {
+ const functionRawTxData = buildFunctionRawTxData.call(
+ this,
+ this.contract.executor,
+ params,
+ fnOptions
+ );
+
+ return this.contract.provider.eos.transaction(
+ {
+ actions: functionRawTxData.actions
+ },
+ { ...txOptions, keyProvider: functionRawTxData.defaultExecutor.privateKey }
+ );
+};
+
+function buildFunctionRawTxData (authorizer, params, options) {
const structuredParams = structureParamsToExpectedLook(params, this.functionFields);
const functionTx = buildMainFunctionTx(this.contract.name, this.functionName, structuredParams, authorizer);
+ processOptions(options, functionTx);
+
return functionTx;
}
-const buildMainFunctionTx = function (contractName, actionName, data, authorizationAccount) {
+function structureParamsToExpectedLook (params, expectedParamsLook) {
+ let structuredParams = {};
+
+ for (let i = 0; i < expectedParamsLook.length; i++) {
+ let expectedParam = expectedParamsLook[i].name;
+ structuredParams[expectedParam] = params[i];
+ }
+
+ return structuredParams;
+};
+
+function buildMainFunctionTx (contractName, actionName, data, authorizationAccount) {
return {
defaultExecutor: authorizationAccount,
actions: [
{
account: contractName,
name: actionName,
- authorization: [authorizationAccount.executiveAuthority],
+ authorization: [authorizationAccount.authority],
data: data
}
]
};
};
-const structureParamsToExpectedLook = function (params, expectedParamsLook) {
- let structuredParams = {};
-
- for (let i = 0; i < expectedParamsLook.length; i++) {
- let expectedParam = expectedParamsLook[i].name;
- structuredParams[expectedParam] = params[i];
+function processOptions (options, functionRawTxData) {
+ const optionals = options instanceof Object ? options : null;
+ for (let i = 0; i < optionalsFunctions.all.length; i++) {
+ const optionalFunction = optionalsFunctions.all[i];
+ optionalFunction(optionals, functionRawTxData);
}
-
- return structuredParams;
-};
-
-const executeFunction = async function (eos, functionRawTx, options) {
- return eos.transaction(
- {
- actions: functionRawTx.actions
- },
- options
- );
-};
+}
module.exports = ContractFunction;
diff --git a/src/contract/contract-function/function-optionals/from.js b/src/contract/contract-function/function-optionals/from.js
index 44de550..4009bd7 100644
--- a/src/contract/contract-function/function-optionals/from.js
+++ b/src/contract/contract-function/function-optionals/from.js
@@ -1,10 +1,10 @@
-const Account = require("./../../../account/normal-account/account");
+const is = require('../../../helpers/is')
const fromOption = function (optionals, rawTransaction) {
- if (optionals && optionals.from instanceof Account) {
+ if (optionals && optionals.from && is(optionals.from).instanceOf('BaseAccount')) {
rawTransaction.defaultExecutor = optionals.from;
for (let i = 0; i < rawTransaction.actions.length; i++) {
- rawTransaction.actions[i].authorization = [rawTransaction.defaultExecutor.executiveAuthority];
+ rawTransaction.actions[i].authorization = [rawTransaction.defaultExecutor.authority];
}
}
};
diff --git a/src/contract/contract-function/function-optionals/tokens.js b/src/contract/contract-function/function-optionals/tokens.js
index ca3eeda..6d74287 100644
--- a/src/contract/contract-function/function-optionals/tokens.js
+++ b/src/contract/contract-function/function-optionals/tokens.js
@@ -1,10 +1,9 @@
const tokensOptional = function (optionals, rawTransaction) {
if (optionals && optionals.tokens) {
-
rawTransaction.actions.push({
account: "eosio.token",
name: "transfer",
- authorization: [rawTransaction.defaultExecutor.executiveAuthority],
+ authorization: [rawTransaction.defaultExecutor.authority],
data: {
from: rawTransaction.defaultExecutor.name,
to: rawTransaction.actions[0].account,
diff --git a/src/contract/contract-function/function-optionals/unique.js b/src/contract/contract-function/function-optionals/unique.js
index e8efff4..fee30ee 100644
--- a/src/contract/contract-function/function-optionals/unique.js
+++ b/src/contract/contract-function/function-optionals/unique.js
@@ -3,7 +3,7 @@ const uniqueOptional = function (optionals, rawTransaction) {
rawTransaction.actions.push({
account: "eosio.null",
name: "nonce",
- authorization: [rawTransaction.defaultExecutor.executiveAuthority],
+ authorization: [rawTransaction.defaultExecutor.authority],
data: {
value: `${Date.now()}`
}
diff --git a/src/contract/contract-function/functions-factory.js b/src/contract/contract-function/functions-factory.js
index 461413c..695a7a6 100644
--- a/src/contract/contract-function/functions-factory.js
+++ b/src/contract/contract-function/functions-factory.js
@@ -2,7 +2,7 @@ const ContractFunction = require('./contract-function');
class FunctionsFactory {
- static createFunction(contract, functionName, functionFields) {
+ static createFunction (contract, functionName, functionFields) {
const contractFunction = new ContractFunction(contract, functionName, functionFields);
const proxyHandler = {
diff --git a/src/contract/contract-initializator.js b/src/contract/contract-initializator.js
index ab2eedb..3892e09 100644
--- a/src/contract/contract-initializator.js
+++ b/src/contract/contract-initializator.js
@@ -10,14 +10,12 @@ const EVENTS = {
class ContractInitializator extends EventClass {
- constructor(provider) {
+ constructor (provider) {
super(EVENTS);
this.provider = provider;
}
fromFile (abi, contractName, contractExecutorAccount = this.provider.defaultAccount) {
- is(contractExecutorAccount).instanceOf('BaseAccount');
-
let abiInterface = abi;
if (contractFilesReader.doesAbiExists(abi)) {
abiInterface = contractFilesReader.readABIFromFile(abi);
@@ -30,8 +28,6 @@ class ContractInitializator extends EventClass {
}
async at (contractName, contractExecutorAccount = this.provider.defaultAccount) {
- is(contractExecutorAccount).instanceOf('BaseAccount');
-
const abiInterface = (await this.provider.eos.getAbi(contractName)).abi;
const contract = new Contract(this.provider, abiInterface, contractName, contractExecutorAccount);
diff --git a/src/contract/contract.js b/src/contract/contract.js
index b3e5681..acb5591 100644
--- a/src/contract/contract.js
+++ b/src/contract/contract.js
@@ -8,6 +8,9 @@ class Contract {
this.provider = provider;
this.executor = contractExecutorAccount;
+ this.actions = {};
+ this.tables = {};
+
declareFunctionsFromABI.call(this, abi);
declareTableGetters.call(this, abi);
}
@@ -37,7 +40,7 @@ let declareFunctionsFromABI = function (abi) {
for (let i = 0; i < contractActions.length; i++) {
const functionName = contractActions[i].name;
const functionType = contractActions[i].type;
- this[functionName] = FunctionsFactory.createFunction(this, functionName, contractStructs[functionType].fields)
+ this.actions[functionName] = FunctionsFactory.createFunction(this, functionName, contractStructs[functionType].fields)
}
};
@@ -46,7 +49,7 @@ let declareTableGetters = function (abi) {
for (let i = 0; i < contractTables.length; i++) {
const tableName = contractTables[i].name;
- this[tableName] = new Proxy({}, {
+ this.tables[tableName] = new Proxy({}, {
get: (target, name) => {
return this.provider.select(tableName).from(this.name)[name];
}
diff --git a/src/helpers/crypto.js b/src/helpers/crypto.js
index 1396330..e6f1075 100644
--- a/src/helpers/crypto.js
+++ b/src/helpers/crypto.js
@@ -6,7 +6,7 @@ module.exports = {
let dataHash = cryptoJS.SHA256(data).toString(cryptoJS.enc.Hex);
return dataHash;
} catch (error) {
- throw new Error('Couldn\'t hash the data')
+ throw new Error('Couldn\'t hash the data');
}
},
encrypt: function (data, password) {
diff --git a/src/helpers/is.js b/src/helpers/is.js
index 8a43457..313378f 100644
--- a/src/helpers/is.js
+++ b/src/helpers/is.js
@@ -6,7 +6,7 @@ module.exports = function (data) {
throw new Error(errorMessage);
}
- recursivelyCheckIfInstance(data, ofObject);
+ return recursivelyCheckIfInstance(data, ofObject);
}
}
}
diff --git a/src/network-providers/jungle3-provider.js b/src/network-providers/jungle3-provider.js
new file mode 100644
index 0000000..6bb0f31
--- /dev/null
+++ b/src/network-providers/jungle3-provider.js
@@ -0,0 +1,15 @@
+const BaseProvider = require('./base-provider');
+
+const Jungle3NetworkConfig = {
+ name: 'jungle3',
+ url: 'https://jungle3.cryptolions.io',
+ chainId: '2a02a0053e5a8cf73a56ba0fda11e4d92e0238a4a2aa74fccf46d5a910746840'
+}
+
+class Jungle3Provider extends BaseProvider {
+ constructor(networkConfig) {
+ super(Object.assign({}, Jungle3NetworkConfig, networkConfig))
+ }
+}
+
+module.exports = Jungle3Provider
diff --git a/src/network-providers/kylin-provider.js b/src/network-providers/kylin-provider.js
index 9c99cda..7ef9497 100644
--- a/src/network-providers/kylin-provider.js
+++ b/src/network-providers/kylin-provider.js
@@ -3,7 +3,7 @@ const BaseProvider = require('./base-provider');
const KylinNetworkConfig = {
name: 'kylin',
- url: 'https://kylin.eoscanada.com',
+ url: 'https://api.kylin.alohaeos.com',
chainId: '5fff1dae8dc8e2fc4d5b23b2c7665c97f9e9d8edf2b6485a86ba311c25639191'
}
diff --git a/src/network-providers/provider-factory.js b/src/network-providers/provider-factory.js
index 418095c..171d031 100644
--- a/src/network-providers/provider-factory.js
+++ b/src/network-providers/provider-factory.js
@@ -5,6 +5,7 @@ const MainProvider = require('./main-provider');
const KylinProvider = require('./kylin-provider');
const LocalProvider = require('./local-provider');
const JungleProvider = require('./jungle-provider');
+const Jungle3Provider = require('./jungle3-provider');
const WorbliProvider = require('./worbli-provider');
const CustomProvider = require('./custom-provider');
@@ -14,6 +15,7 @@ const PROVIDERS = {
kylin: (networkConfig) => { return new KylinProvider(networkConfig) },
local: (networkConfig) => { return new LocalProvider(networkConfig) },
jungle: (networkConfig) => { return new JungleProvider(networkConfig) },
+ jungle3: (networkConfig) => { return new Jungle3Provider(networkConfig) },
worbli: (networkConfig) => { return new WorbliProvider(networkConfig) },
custom: (networkConfig) => { return new CustomProvider(networkConfig) }
}
diff --git a/tests/account-tests.js b/tests/account-tests.js
index c798241..f9eb713 100644
--- a/tests/account-tests.js
+++ b/tests/account-tests.js
@@ -37,7 +37,7 @@ const Networks = {
},
kylin: {
name: 'kylin',
- url: 'https://kylin.eoscanada.com',
+ url: 'https://api.kylin.alohaeos.com',
chainId: '5fff1dae8dc8e2fc4d5b23b2c7665c97f9e9d8edf2b6485a86ba311c25639191'
},
custom: {
@@ -72,8 +72,8 @@ describe('Account', function () {
try {
const tokenAccount = await Account.createFromName('eosio.token');
const tokenContract = await eoslimeTool.Contract.deployOnAccount(TOKEN_WASM_PATH, TOKEN_ABI_PATH, tokenAccount);
- await tokenContract.create(tokenAccount.name, TOTAL_SUPPLY);
- await tokenContract.issue(ACCOUNT_NAME, TOTAL_SUPPLY, 'memo');
+ await tokenContract.actions.create([tokenAccount.name, TOTAL_SUPPLY]);
+ await tokenContract.actions.issue([ACCOUNT_NAME, TOTAL_SUPPLY, 'memo']);
} catch (error) {
}
}
@@ -86,8 +86,8 @@ describe('Account', function () {
assert(account.name == ACCOUNT_NAME, 'Incorrect name');
assert(account.privateKey == ACCOUNT_PRIVATE_KEY, 'Incorrect private key');
assert(account.publicKey == ACCOUNT_PUBLIC_KEY, 'Incorrect public key');
- assert(account.executiveAuthority.actor == EXECUTIVE_AUTHORITY.actor, 'Incorrect executive authority actor');
- assert(account.executiveAuthority.permission == EXECUTIVE_AUTHORITY.permission, 'Incorrect executive authority permission');
+ assert(account.authority.actor == EXECUTIVE_AUTHORITY.actor, 'Incorrect executive authority actor');
+ assert(account.authority.permission == EXECUTIVE_AUTHORITY.permission, 'Incorrect executive authority permission');
const network = account.provider.network;
assert(JSON.stringify(account.provider.network) == JSON.stringify(Networks[network.name]))
@@ -237,20 +237,22 @@ describe('Account', function () {
});
});
- describe('Create authority', function () {
+ describe('Add authority', function () {
const AUTHORITY = 'contracts';
const PARENT_AUTHORITY = 'active';
- it('Should create authority', async () => {
+ it('Should add authority', async () => {
let account = await Account.createRandom();
let authority = await getAuthorityForAccount(AUTHORITY, account.name);
assert(authority == undefined);
- const newAuthorityAccount = await account.createSubAuthority(AUTHORITY);
+ await account.addAuthority(AUTHORITY);
+
+ const newAuthorityAccount = Account.load(account.name, account.privateKey, AUTHORITY);
assert(newAuthorityAccount.name == account.name);
- assert(newAuthorityAccount.executiveAuthority.actor == newAuthorityAccount.name);
- assert(newAuthorityAccount.executiveAuthority.permission == AUTHORITY);
+ assert(newAuthorityAccount.authority.actor == newAuthorityAccount.name);
+ assert(newAuthorityAccount.authority.permission == AUTHORITY);
authority = await getAuthorityForAccount(AUTHORITY, newAuthorityAccount.name);
assert(authority.parent == PARENT_AUTHORITY);
@@ -288,7 +290,7 @@ describe('Account', function () {
it('Should throw if one try to create a permission for non-existing authority', async () => {
try {
let account = await Account.createRandom();
- account.executiveAuthority.permission = 'FAKE';
+ account.authority.permission = 'FAKE';
await account.addPermission(PERMISSION);
@@ -321,7 +323,7 @@ describe('Account', function () {
assert(authorityInfo.required_auth.keys.length == 1);
const keysPair = await eoslime.utils.generateKeys();
- await account.addAuthorityKey(keysPair.publicKey);
+ await account.addOnBehalfKey(keysPair.publicKey);
authorityInfo = await account.getAuthorityInfo();
assert(authorityInfo.required_auth.keys.find((keyData) => { return keyData.key == keysPair.publicKey }));
@@ -336,7 +338,7 @@ describe('Account', function () {
assert(authorityInfo.required_auth.keys[0].weight == 1);
const keysPair = await eoslime.utils.generateKeys();
- await account.addAuthorityKey(keysPair.publicKey, WEIGHT);
+ await account.addOnBehalfKey(keysPair.publicKey, WEIGHT);
authorityInfo = await account.getAuthorityInfo();
assert(authorityInfo.required_auth.keys.find((key) => { return key.weight == WEIGHT }));
@@ -349,8 +351,8 @@ describe('Account', function () {
assert(authorityInfo.required_auth.keys.length == 1);
const keysPair = await eoslime.utils.generateKeys();
- await account.addAuthorityKey(keysPair.publicKey);
- await account.addAuthorityKey(keysPair.publicKey);
+ await account.addOnBehalfKey(keysPair.publicKey);
+ await account.addOnBehalfKey(keysPair.publicKey);
authorityInfo = await account.getAuthorityInfo();
@@ -361,7 +363,7 @@ describe('Account', function () {
it('Should throw if one provide an invalid public key', async () => {
try {
const account = await Account.createRandom();
- await account.addAuthorityKey('Invalid public key');
+ await account.addOnBehalfKey('Invalid public key');
assert(false);
} catch (error) {
@@ -428,7 +430,7 @@ describe('Account', function () {
assert(authorityInfo.required_auth.threshold == 1);
const keysPair = await eoslime.utils.generateKeys();
- await account.addAuthorityKey(keysPair.publicKey);
+ await account.addOnBehalfKey(keysPair.publicKey);
await account.increaseThreshold(THRESHOLD);
authorityInfo = await account.getAuthorityInfo();
@@ -481,36 +483,62 @@ describe('Account', function () {
const faucetContract = await eoslimeTool.Contract.deploy(FAUCET_WASM_PATH, FAUCET_ABI_PATH);
const account = await eoslimeTool.Account.createRandom();
- const accountRandomAuth = await account.createSubAuthority('random');
+ await account.addAuthority('random');
+ const accountRandomAuth = eoslimeTool.Account.load(account.name, account.privateKey, 'random');
try {
- await faucetContract.produce(account.name, "100.0000 TKNS", account.name, "memo", { from: accountRandomAuth });
+ await faucetContract.actions.produce(
+ [account.name, "100.0000 TKNS", account.name, "memo"],
+ { from: accountRandomAuth }
+ );
} catch (error) {
assert(error.includes('action declares irrelevant authority'));
}
- await accountRandomAuth.setAuthorityAbilities([
+ await account.setAuthorityAbilities('random', [
{
action: 'produce',
contract: faucetContract.name
}
]);
- await faucetContract.produce(account.name, "100.0000 TKNS", account.name, "memo", { from: accountRandomAuth });
+ await faucetContract.actions.produce(
+ [account.name, "100.0000 TKNS", account.name, "memo"],
+ { from: accountRandomAuth }
+ );
});
it('Should throw if one does not provide array as abilities', async () => {
try {
const account = await eoslimeTool.Account.createRandom();
- const authorityAccount = await account.createSubAuthority('random');
-
- await authorityAccount.setAuthorityAbilities('Fake ability');
+ await account.addAuthority('random');
+ await account.setAuthorityAbilities('random', 'Fake ability');
assert(false);
} catch (error) {
assert(error.message.includes('Provided String is not an instance of Array'));
}
});
+
+ it('Should throw if one does not provide existing authority', async () => {
+ try {
+ const account = await eoslimeTool.Account.createRandom();
+
+ // Random does not exists
+ await account.setAuthorityAbilities('random', [
+ {
+ action: 'test',
+ contract: 'eosio'
+ }
+ ]);
+
+ assert(false);
+ } catch (error) {
+ assert(error.message.includes('Account does not have authority with name: [random].'));
+ assert(error.message.includes('You could add it by using [addAuthority] function.'));
+ assert(error.message.includes('For details check [Set authority abilities] suite in account-tests.js'));
+ }
+ });
});
const getAuthorityForAccount = async function (authorityName, accountName) {
@@ -715,8 +743,8 @@ describe('Account', function () {
assert(decryptedJSONAccount.name, 'Incorrect name');
assert(decryptedJSONAccount.privateKey, 'Incorrect private key');
assert(decryptedJSONAccount.publicKey, 'Incorrect public key');
- assert(decryptedJSONAccount.executiveAuthority.actor == decryptedJSONAccount.name, 'Incorrect authority actor');
- assert(decryptedJSONAccount.executiveAuthority.permission == 'active', 'Incorrect authority permission');
+ assert(decryptedJSONAccount.authority.actor == decryptedJSONAccount.name, 'Incorrect authority actor');
+ assert(decryptedJSONAccount.authority.permission == 'active', 'Incorrect authority permission');
assert(JSON.stringify(decryptedJSONAccount.provider.network) == JSON.stringify(Networks['local']), 'Incorrect network');
});
diff --git a/tests/cli-commands/compile-tests.js b/tests/cli-commands/compile-tests.js
new file mode 100644
index 0000000..6189abf
--- /dev/null
+++ b/tests/cli-commands/compile-tests.js
@@ -0,0 +1,203 @@
+const sinon = require('sinon');
+const assert = require('assert');
+const proxyquire = require('proxyquire').noCallThru();
+
+const definition = require('../../cli-commands/commands/compile/definition');
+
+const Command = require('../../cli-commands/commands/command');
+const CompileCommand = require('../../cli-commands/commands/compile/index');
+
+const Logger = require('./utils/logger');
+const logger = new Logger();
+
+describe('Compile Command', function () {
+
+ beforeEach(async () => {
+ logger.hide(sinon);
+ });
+
+ afterEach(async () => {
+ sinon.restore();
+ });
+
+ describe('Command', function () {
+
+ it('Should initialize command properly', async () => {
+ const compileCommand = new CompileCommand();
+ assert(compileCommand instanceof Command);
+ assert(compileCommand.template == definition.template);
+ assert(compileCommand.description = definition.description);
+ assert(compileCommand.options == definition.options);
+ assert(compileCommand.subcommands.length == 0);
+ });
+
+ function stubBaseCommand (cb) {
+ return {
+ '../command': class FakeBaseCommand {
+ processOptions () {
+ return cb();
+ }
+ }
+ }
+ }
+
+ function stubAsyncSoftExec (checkPoints) {
+ return {
+ '../../helpers/async-soft-exec': class FakeAsyncSoftExec {
+ exec () { checkPoints.exec--; }
+ }
+ }
+ }
+
+ it('Should compile ', async () => {
+ const checkPoints = {
+ exec: 1,
+ createDir: 1
+ }
+
+ const compileCommand = new (proxyquire(
+ '../../cli-commands/commands/compile/index',
+ {
+ ...stubBaseCommand(() => {
+ return { path: [{ fileName: 'test', fullPath: './test.cpp' }] }
+ }),
+ ...stubAsyncSoftExec(checkPoints),
+ '../../helpers/file-system-util': {
+ createDir: () => {
+ checkPoints.createDir--;
+ }
+ }
+ }
+ ));
+
+ await compileCommand.execute();
+
+ assert(checkPoints.exec == 0);
+ assert(checkPoints.createDir == 0);
+ });
+
+ it('Should log in case any contracts was found', async () => {
+ const compileCommand = new (proxyquire('../../cli-commands/commands/compile/index',
+ { ...stubBaseCommand(() => { return { path: [] } }) }
+ ));
+
+ const waitToPass = new Promise(async (resolve, reject) => {
+ logger.on('info', (message) => {
+ if (message.includes('There is not a contract to compile')) {
+ return resolve(true);
+ }
+ });
+
+ await compileCommand.execute({ 'path': './' });
+ });
+
+ await waitToPass;
+ });
+
+ it('Should log in case a contract could not be compiled', async () => {
+ const compileCommand = new (proxyquire(
+ '../../cli-commands/commands/compile/index',
+ {
+ ...stubBaseCommand(() => {
+ return { path: [{ fileName: 'test', fullPath: './test.cpp' }] }
+ }),
+ '../../helpers/async-soft-exec': class FakeAsyncSoftExec {
+ exec () { throw new Error('Fake error'); }
+ },
+ '../../helpers/file-system-util': {
+ createDir: () => { }
+ }
+ }
+ ));
+
+ const waitToPass = new Promise(async (resolve, reject) => {
+ logger.on('error', (message) => {
+ if (message.includes('Unsuccessful compilation of')) {
+ return resolve(true);
+ }
+ });
+
+ await compileCommand.execute({ 'path': './' });
+ });
+
+ await waitToPass;
+ });
+
+ it('Should log in case of an error', async () => {
+ const compileCommand = new (proxyquire('../../cli-commands/commands/compile/index',
+ { ...stubBaseCommand(() => { throw new Error('Fake Error') }) }
+ ));
+
+ const waitToPass = new Promise(async (resolve, reject) => {
+ logger.on('error', (message) => {
+ if (message.includes('Unsuccessful compilation')) {
+ return resolve(true);
+ }
+ });
+
+ await compileCommand.execute({ 'path': './' });
+ });
+
+ await waitToPass;
+ });
+ });
+
+
+ describe('Options', function () {
+ describe('Path', function () {
+
+ function stubFileSystemUtils (isFolder) {
+ const Option = proxyquire(
+ '../../cli-commands/commands/compile/options/path-option',
+ {
+ '../../../helpers/file-system-util': {
+ isDir: () => {
+ return isFolder;
+ },
+ recursivelyReadDir: () => {
+ return [
+ {
+ fileName: 'test1.cpp',
+ fullPath: `./custom/test1.cpp`
+ }, {
+ fileName: 'test2.cpp',
+ fullPath: `./custom/test2.cpp`
+ }
+ ]
+ }
+ }
+ }
+ );
+
+ return Option;
+ }
+
+ it('Should return contract path', async () => {
+ const pathOption = stubFileSystemUtils(false);
+ const result = await pathOption.process('./test.cpp');
+
+ assert(result.length == 1);
+ assert(result[0].fileName == 'test');
+ assert(result[0].fullPath == './test.cpp');
+ });
+
+ it('Should return contracts paths from a folder', async () => {
+ const pathOption = stubFileSystemUtils(true);
+ const result = await pathOption.process('./test.cpp');
+
+ assert(result.length == 2);
+ assert(result[0].fileName == 'test1');
+ assert(result[1].fileName == 'test2');
+ assert(result[0].fullPath == './custom/test1.cpp');
+ assert(result[1].fullPath == './custom/test2.cpp');
+ });
+
+ it('Should return empty array if any contracts was found', async () => {
+ const pathOption = stubFileSystemUtils(false);
+ const result = await pathOption.process('./test.fake');
+
+ assert(result.length == 0);
+ });
+ });
+ });
+});
diff --git a/tests/cli-commands/deploy-tests.js b/tests/cli-commands/deploy-tests.js
new file mode 100644
index 0000000..134873a
--- /dev/null
+++ b/tests/cli-commands/deploy-tests.js
@@ -0,0 +1,199 @@
+const path = require('path')
+const sinon = require('sinon');
+const assert = require('assert');
+const proxyquire = require('proxyquire').noCallThru();
+
+const definition = require('../../cli-commands/commands/deploy/definition');
+
+const Command = require('../../cli-commands/commands/command');
+const DeployCommand = require('../../cli-commands/commands/deploy/index');
+
+const NetworkOption = require('../../cli-commands/commands/deploy/options/network-option');
+
+const Logger = require('./utils/logger');
+const logger = new Logger();
+
+describe('Deploy Command', function () {
+
+ let deployCommand;
+
+ beforeEach(async () => {
+ logger.hide(sinon);
+ deployCommand = new DeployCommand();
+ });
+
+ afterEach(async () => {
+ sinon.restore();
+ });
+
+ describe('Command', function () {
+
+ it('Should initialize command properly', async () => {
+ assert(deployCommand instanceof Command);
+ assert(deployCommand.template == definition.template);
+ assert(deployCommand.description = definition.description);
+ assert(deployCommand.options == definition.options);
+ assert(deployCommand.subcommands.length == 0);
+ });
+
+ function stubBaseCommand (cb) {
+ return {
+ '../command': class FakeBaseCommand {
+ processOptions (args) {
+ return cb(args);
+ }
+ }
+ }
+ }
+
+ it('Should deploy contracts', async () => {
+ const deployCommand = new (proxyquire('../../cli-commands/commands/deploy/index', {
+ ...stubBaseCommand(() => {
+ return {
+ path: [{
+ deploy: (network, deployer) => {
+ assert(network == 'custom');
+ assert(deployer == 'deployer');
+ }
+ }],
+ network: 'custom',
+ deployer: 'deployer'
+ }
+ })
+ }));
+
+ const waitToPass = new Promise(async (resolve, reject) => {
+ logger.on('success', (message) => {
+ if (message.includes('Successful deployment of')) {
+ return resolve(true);
+ }
+ });
+
+ await deployCommand.execute();
+ });
+
+ await waitToPass;
+ });
+
+ it('Should log error message in case a deployment script throws', async () => {
+ const deployCommand = new (proxyquire('../../cli-commands/commands/deploy/index', {
+ ...stubBaseCommand(() => {
+ return {
+ path: [{
+ deploy: () => {
+ throw new Error('Fake Error');
+ }
+ }]
+ }
+ })
+ }));
+
+ const waitToPass = new Promise(async (resolve, reject) => {
+ logger.on('error', (message) => {
+ if (message.includes('Unsuccessful deployment of')) {
+ return resolve(true);
+ }
+ });
+
+ await deployCommand.execute();
+ });
+
+ await waitToPass;
+ });
+
+ it('Should log error message in case of error', async () => {
+ const deployCommand = new (proxyquire('../../cli-commands/commands/deploy/index', {
+ ...stubBaseCommand(() => { throw new Error('Fake error'); })
+ }));
+
+ const waitToPass = new Promise(async (resolve, reject) => {
+ logger.on('error', (message) => {
+ if (message.includes(' Unsuccessful deployment')) {
+ return resolve(true);
+ }
+ });
+
+ await deployCommand.execute();
+ });
+
+ await waitToPass;
+ });
+ });
+
+
+ describe('Options', function () {
+
+ describe('Path', function () {
+
+ function stubFileSystemUtils (isFolder) {
+ return {
+ '../../../helpers/file-system-util': {
+ isDir: () => { return isFolder; },
+ isFile: () => { return !isFolder; },
+ recursivelyReadDir: (dir) => {
+ return [{ fileName: 'fileName', fullPath: `${dir}/fullPath` }];
+ }
+ }
+ }
+ }
+
+ function stubDeploymentPath (deploymentPath) {
+ return {
+ [deploymentPath]: 'deploymentPath'
+ }
+ }
+
+ it('Should return a deployment script', async () => {
+ const pathOption = proxyquire('../../cli-commands/commands/deploy/options/path-option', {
+ ...stubFileSystemUtils(false),
+ ...stubDeploymentPath(path.resolve('./', './custom.js'))
+ });
+
+ const deploymentScript = (await pathOption.process('./custom.js'))[0];
+ assert(deploymentScript.fileName == './custom.js');
+ assert(deploymentScript.deploy == 'deploymentPath');
+ });
+
+ it('Should return all deployment scripts from folder', async () => {
+ const pathOption = proxyquire('../../cli-commands/commands/deploy/options/path-option', {
+ ...stubFileSystemUtils(true),
+ ...stubDeploymentPath(path.resolve('./', './custom/fullPath'))
+ });
+
+ const deploymentScripts = await pathOption.process('./custom');
+ assert(deploymentScripts[0].fileName == 'fileName');
+ assert(deploymentScripts[0].deploy == 'deploymentPath');
+ });
+ });
+
+ describe('Network', function () {
+
+ it('Should return an instance of eoslime', async () => {
+ const eoslimeInstance = NetworkOption.process('local');
+ assert(eoslimeInstance.Provider.network.name == 'local');
+ });
+ });
+
+ describe('Deployer', function () {
+
+ function stubPrompts (output) {
+ return {
+ 'prompts': () => { return { value: output } }
+ }
+ }
+
+ it('Should return an instance of eoslime.Account', async () => {
+ const deployerOption = proxyquire('../../cli-commands/commands/deploy/options/deployer-option', {
+ ...stubPrompts('5KieRy975NgHk5XQfn8r6o3pcqJDF2vpeV9bDiuB5uF4xKCTwRF@active')
+ });
+
+ const deployer = await deployerOption.process('name', { network: 'local' });
+
+ assert(deployer.constructor.name == 'Account');
+ assert(deployer.name == 'name');
+ assert(deployer.privateKey == '5KieRy975NgHk5XQfn8r6o3pcqJDF2vpeV9bDiuB5uF4xKCTwRF');
+ assert(deployer.authority.permission == 'active');
+ });
+ });
+ });
+});
diff --git a/tests/cli-commands/init-tests.js b/tests/cli-commands/init-tests.js
new file mode 100644
index 0000000..2e88182
--- /dev/null
+++ b/tests/cli-commands/init-tests.js
@@ -0,0 +1,160 @@
+const sinon = require('sinon');
+const assert = require('assert');
+const proxyquire = require('proxyquire').noCallThru();
+
+const definition = require('../../cli-commands/commands/init/definition');
+
+const Command = require('../../cli-commands/commands/command');
+const InitCommand = require('../../cli-commands/commands/init/index');
+
+const Logger = require('./utils/logger');
+const logger = new Logger();
+
+describe('Init Command', function () {
+
+ beforeEach(async () => {
+ logger.hide(sinon);
+ });
+
+ afterEach(async () => {
+ sinon.restore();
+ });
+
+ describe('Command', function () {
+
+ it('Should initialize command properly', async () => {
+ const initCommand = new InitCommand();
+ assert(initCommand instanceof Command);
+ assert(initCommand.template == definition.template);
+ assert(initCommand.description = definition.description);
+ assert(initCommand.options == definition.options);
+ assert(initCommand.subcommands.length == 0);
+ });
+
+ function stubBaseCommand (cb) {
+ return {
+ '../command': class FakeBaseCommand {
+ processOptions (args) {
+ return cb(args);
+ }
+ }
+ }
+ }
+
+ function stubFileSystemUtils (checkPoints) {
+ return {
+ '../../helpers/file-system-util': {
+ createDir: () => {
+ checkPoints.createDir--;
+ },
+ copyFileFromTo: () => {
+ checkPoints.copyFileFromTo--;
+ }
+ }
+ }
+ }
+
+ function stubAsyncSoftExec (checkPoints) {
+ return {
+ '../../helpers/async-soft-exec': class FakeAsyncSoftExec {
+ exec () { checkPoints.exec--; }
+ }
+ }
+ }
+
+ it('Should init project structure', async () => {
+ const checkPoints = {
+ exec: 1,
+ createDir: 3,
+ copyFileFromTo: 1,
+ }
+
+ const initCommand = new (proxyquire('../../cli-commands/commands/init/index', {
+ ...stubAsyncSoftExec(checkPoints),
+ ...stubFileSystemUtils(checkPoints),
+ ...stubBaseCommand((args) => {
+ return new Promise((resolve) => {
+ assert(args['with-example'] == false);
+ resolve(true);
+ });
+ })
+ }));
+
+ await initCommand.execute({ 'with-example': false });
+
+ assert(checkPoints.exec == 0);
+ assert(checkPoints.createDir == 0);
+ assert(checkPoints.copyFileFromTo == 0);
+ });
+
+ it('Should log error message in case an option throws', async () => {
+ const initCommand = new (proxyquire('../../cli-commands/commands/init/index', {
+ ...stubAsyncSoftExec(),
+ ...stubFileSystemUtils(),
+ ...stubBaseCommand(() => { throw new Error('Fake error'); })
+ }));
+
+ const waitToPass = new Promise(async (resolve, reject) => {
+ logger.on('error', (message) => {
+ if (message.includes('Unsuccessful installation')) {
+ return resolve(true);
+ }
+ });
+
+ await initCommand.execute({ 'with-example': true });
+ });
+
+ await waitToPass;
+ });
+ });
+
+ describe('Options', function () {
+ describe('With-example', function () {
+
+ const checkPoints = {
+ createDir: 1,
+ copyFileFromTo: 2,
+ copyAllFilesFromDirTo: 1
+ }
+
+ function stubFileSystemUtils () {
+ const Option = proxyquire(
+ '../../cli-commands/commands/init/options/with-example/with-example-option',
+ {
+ '../../../../helpers/file-system-util': {
+ createDir: () => {
+ checkPoints.createDir--;
+ },
+ copyFileFromTo: () => {
+ checkPoints.copyFileFromTo--;
+ },
+ copyAllFilesFromDirTo: () => {
+ checkPoints.copyAllFilesFromDirTo--;
+ }
+ }
+ }
+ );
+
+ return Option;
+ }
+
+ it('Should init project structure [with-example = false]', async () => {
+ const checkPointUntouched = JSON.stringify(checkPoints);
+
+ const exampleOption = stubFileSystemUtils();
+ exampleOption.process(false);
+
+ assert(checkPointUntouched == JSON.stringify(checkPoints));
+ });
+
+ it('Should init project structure and provide example files', async () => {
+ const exampleOption = stubFileSystemUtils();
+ exampleOption.process(true);
+
+ assert(checkPoints.createDir == 0);
+ assert(checkPoints.copyFileFromTo == 0);
+ assert(checkPoints.copyAllFilesFromDirTo == 0);
+ });
+ });
+ });
+});
diff --git a/tests/cli-commands/miscellaneous.js b/tests/cli-commands/miscellaneous.js
new file mode 100644
index 0000000..bf0e012
--- /dev/null
+++ b/tests/cli-commands/miscellaneous.js
@@ -0,0 +1,397 @@
+const sinon = require('sinon');
+const assert = require('assert');
+const proxyquire = require('proxyquire').noCallThru();
+
+const Command = require('../../cli-commands/commands/command');
+const GroupCommand = require('../../cli-commands/commands/group-command');
+
+// Commons
+const logger = require('../../cli-commands/common/logger');
+const Table = require('../../cli-commands/common/table');
+
+const Logger = require('./utils/logger');
+const testLogger = new Logger();
+
+describe('Miscellaneous', function () {
+
+ describe('CLI Command', function () {
+ it('Should process command options', async () => {
+ const commandOptions = [{ name: 'test', process: (args) => { return args; } }];
+ const command = new Command({ options: commandOptions });
+
+ const result = await command.processOptions({ 'test': true });
+ assert(result.test);
+ });
+
+ it('Should execute command', async () => {
+ const command = new Command({});
+ await command.execute();
+ });
+ });
+
+ describe('Group Command', function () {
+ it('Should execute provided option', async () => {
+ const commandOptions = [{ name: 'test', process: (args) => { return args; } }];
+ const groupCommand = new GroupCommand({ options: commandOptions });
+ await groupCommand.execute({ 'test': true });
+
+ assert(groupCommand.hasBeenExecuted);
+ });
+
+ it('Should set hasBeenExecuted to false if no option has been provided', async () => {
+ const groupCommand = new GroupCommand({});
+ await groupCommand.execute();
+
+ assert(!groupCommand.hasBeenExecuted);
+ });
+ });
+
+ describe('Common', function () {
+ describe('Logger', function () {
+ it('Should print all type of logs', async () => {
+ const originalConsoleLog = console.log;
+ console.log = () => { assert(true); }
+
+ logger.log('message');
+ logger.success('message');
+ logger.info('message');
+ logger.error('message', 'error');
+
+ console.log = originalConsoleLog;
+ });
+ });
+
+ describe('Table', function () {
+
+ it('Should add a row', async () => {
+ const table = new Table(['head']);
+ table.addRow(['row']);
+
+ assert(table.table[0][0] == 'row');
+ });
+
+ it('Should add a section', async () => {
+ const table = new Table(['head']);
+ table.addSection('sectionName', [['row']]);
+
+ assert(Array.isArray(table.table[0]['\u001b[96msectionName\u001b[39m']));
+ assert(table.table[1][0] == '');
+ assert(table.table[1][1] == 'row');
+ });
+
+ it('Should visualize the table', async () => {
+ testLogger.hide(sinon);
+ testLogger.on('log', (table) => {
+ assert(table.includes('sectionName'));
+ assert(table.includes('row'));
+ });
+
+ const table = new Table(['head']);
+ table.addSection('sectionName', [['row']]);
+ table.draw();
+
+ sinon.restore();
+ });
+ });
+ });
+
+ describe('Helpers', function () {
+ describe('AsyncSoftExec', function () {
+ function stubChildProcess (error, stdout) {
+ const AsyncSoftExec = proxyquire('../../cli-commands/helpers/async-soft-exec', {
+ 'child_process': {
+ exec: (command, cb) => { cb(error, stdout); }
+ }
+ });
+
+ return AsyncSoftExec;
+ }
+
+ it('Should execute command', async () => {
+ const AsyncSoftExec = stubChildProcess('', 'executed');
+ const asyncSoftExec = new AsyncSoftExec('Test');
+
+ const result = await asyncSoftExec.exec();
+ assert(result == 'executed');
+ });
+
+ it('Should throw error when executing', async () => {
+ const AsyncSoftExec = stubChildProcess('Fake error', '');
+ const asyncSoftExec = new AsyncSoftExec('Test');
+
+ try {
+ await asyncSoftExec.exec();
+ assert(false);
+ } catch (error) {
+ assert(error == 'Fake error');
+ }
+ });
+ });
+
+ describe('File system utils', function () {
+
+ function stubExistsSync (output) {
+ return { existsSync: () => { return output; } }
+ }
+
+ function stubMkdirSync (cb) {
+ return { mkdirSync: (dirName) => { cb(dirName); } }
+ }
+
+ function stubCopyFileSync (cb) {
+ return { copyFileSync: (source, destination) => { cb(source, destination); } }
+ }
+
+ function stubReaddir (...output) {
+ return { readdir: (dir, cb) => { cb(...output); } }
+ }
+
+ function stubLstatSyncFile (output) {
+ return { lstatSync: () => { return { isFile: () => { return output; } } } }
+ }
+
+ function stubLstatSyncDir (output) {
+ return { lstatSync: () => { return { isDirectory: () => { return output; } } } }
+ }
+
+ function stubReadFileSync () {
+ return { readFileSync: (filePath) => { return filePath; } }
+ }
+
+ function stubWriteFileSync (cb) {
+ return { writeFileSync: (filePath, fileContent) => { cb(filePath, fileContent); } }
+ }
+
+ function stubUnlinkSync () {
+ return { unlinkSync: () => { } }
+ }
+
+ function stubRmdirSync () {
+ return { rmdirSync: () => { } }
+ }
+
+ it('Should create dir', async () => {
+ const utils = proxyquire('../../cli-commands/helpers/file-system-util', {
+ 'fs': {
+ ...stubExistsSync(false),
+ ...stubMkdirSync((dir) => {
+ assert(dir == 'dir');
+ })
+ }
+ });
+
+ utils.createDir('dir');
+ });
+
+ it('Should copy file', async () => {
+ const utils = proxyquire('../../cli-commands/helpers/file-system-util', {
+ 'fs': {
+ ...stubExistsSync(false),
+ ...stubCopyFileSync((src, dst) => {
+ assert(src == 'here');
+ assert(dst == 'there');
+ })
+ }
+ });
+
+ utils.copyFileFromTo('here', 'there');
+ });
+
+ it('Should copy all files in dir', async () => {
+ const utils = proxyquire('../../cli-commands/helpers/file-system-util', {
+ 'fs': {
+ ...stubExistsSync(true),
+ ...stubCopyFileSync((src, dst) => {
+ assert(src == 'src/file');
+ assert(dst == 'dst/file');
+ }),
+ ...stubReaddir(undefined, ['file'])
+ }
+ });
+
+ utils.copyAllFilesFromDirTo('src/', 'dst/');
+ });
+
+ it('Should throw if coping of all files in dir fails', async () => {
+ const utils = proxyquire('../../cli-commands/helpers/file-system-util', {
+ 'fs': {
+ ...stubExistsSync(true),
+ ...stubCopyFileSync((src, dst) => {
+ assert(src == 'src/file');
+ assert(dst == 'dst/file');
+ }),
+ ...stubReaddir('error', [])
+ }
+ });
+
+ try {
+ utils.copyAllFilesFromDirTo('src/', 'dst/');
+ assert(false);
+ } catch (error) {
+ assert(error.message == 'Example files can not be copied');
+ }
+
+ });
+
+ it('Should return if path is dir', async () => {
+ const utils = proxyquire('../../cli-commands/helpers/file-system-util', {
+ 'fs': {
+ ...stubLstatSyncDir(true),
+ }
+ });
+
+ assert(utils.isDir('dir'));
+ });
+
+ it('Should return if path is a file', async () => {
+ const utils = proxyquire('../../cli-commands/helpers/file-system-util', {
+ 'fs': {
+ ...stubLstatSyncFile(true)
+ }
+ });
+
+ assert(utils.isFile('path'));
+ });
+
+ it('Should read file', async () => {
+ const utils = proxyquire('../../cli-commands/helpers/file-system-util', {
+ 'fs': {
+ ...stubReadFileSync(true),
+ }
+ });
+
+ assert(utils.readFile('file') == 'file');
+ });
+
+ it('Should read dir with files only', async () => {
+ const utils = proxyquire('../../cli-commands/helpers/file-system-util', {
+ 'fs': {
+ ...stubLstatSyncDir(false),
+ ...stubReaddir(undefined, ['file'])
+ }
+ });
+
+ const result = await utils.recursivelyReadDir('dir');
+ assert(result[0].fullPath == 'dir/file');
+ });
+
+ it('Should read dir with sub dirs', async () => {
+ let dirLevel = 2;
+ const utils = proxyquire('../../cli-commands/helpers/file-system-util', {
+ 'fs': {
+ lstatSync: () => { return { isDirectory: () => { dirLevel--; return dirLevel; } } },
+ ...stubReaddir(undefined, ['file'])
+ }
+ });
+
+ const result = await utils.recursivelyReadDir('dir')
+ assert(result[0].fullPath == 'dir/file/file');
+ });
+
+ it('Should throw if reading of a dir fails', async () => {
+ const utils = proxyquire('../../cli-commands/helpers/file-system-util', {
+ 'fs': {
+ ...stubReaddir({ message: 'Error' }, [])
+ }
+ });
+
+ try {
+ await utils.recursivelyReadDir('dir');
+ assert(false);
+ } catch (error) {
+ assert(error == 'Error');
+ }
+ });
+
+ it('Should clean up dir containing only files', async () => {
+ const utils = proxyquire('../../cli-commands/helpers/file-system-util', {
+ 'fs': {
+ ...stubLstatSyncDir(false),
+ ...stubReaddir(undefined, ['file']),
+ ...stubUnlinkSync(),
+ ...stubRmdirSync()
+ }
+ });
+
+ await utils.recursivelyDeleteDir('dir');
+ });
+
+ it('Should clean up dir containing sub dirs', async () => {
+ let dirLevel = 2;
+ const utils = proxyquire('../../cli-commands/helpers/file-system-util', {
+ 'fs': {
+ lstatSync: () => { return { isDirectory: () => { dirLevel--; return dirLevel; } } },
+ ...stubReaddir(undefined, ['file']),
+ ...stubRmdirSync(),
+ ...stubUnlinkSync()
+ }
+ });
+
+ await utils.recursivelyDeleteDir('dir');
+ });
+
+ it('Should throw if deletion of a dir fails', async () => {
+ const utils = proxyquire('../../cli-commands/helpers/file-system-util', {
+ 'fs': {
+ ...stubReaddir({ message: 'Error' }, [])
+ }
+ });
+
+ try {
+ await utils.recursivelyDeleteDir('dir');
+ assert(false);
+ } catch (error) {
+ assert(error == 'Error');
+ }
+ });
+
+ it('Should write to a file', async () => {
+ const utils = proxyquire('../../cli-commands/helpers/file-system-util', {
+ 'fs': {
+ ...stubWriteFileSync((path, content) => {
+ assert(path == 'path');
+ assert(content == 'content');
+ }),
+ }
+ });
+
+ utils.writeFile('path', 'content');
+ });
+
+ it('Should throw if writing to a file fails', async () => {
+ const utils = proxyquire('../../cli-commands/helpers/file-system-util', {
+ 'fs': {
+ ...stubWriteFileSync(() => { throw new Error('Fake error'); })
+ }
+ });
+
+ try {
+ utils.writeFile('path', 'content');
+ assert(false);
+ } catch (error) {
+ assert(error.message.includes('Fake error'));
+ }
+ });
+
+ it('Should remove a file', async () => {
+ const utils = proxyquire('../../cli-commands/helpers/file-system-util', {
+ 'fs': {
+ ...stubUnlinkSync(true),
+ }
+ });
+
+ utils.rmFile('file');
+ });
+
+ it('Should remove dir', async () => {
+ const utils = proxyquire('../../cli-commands/helpers/file-system-util', {
+ 'fs': {
+ ...stubRmdirSync(true),
+ }
+ });
+
+ utils.rmDir('dir');
+ });
+ });
+ });
+});
diff --git a/tests/cli-commands/nodeos-tests.js b/tests/cli-commands/nodeos-tests.js
new file mode 100644
index 0000000..b3692dd
--- /dev/null
+++ b/tests/cli-commands/nodeos-tests.js
@@ -0,0 +1,524 @@
+const sinon = require('sinon');
+const assert = require('assert');
+const proxyquire = require('proxyquire').noCallThru();
+
+const Command = require('../../cli-commands/commands/command');
+const GroupCommand = require('../../cli-commands/commands/group-command');
+const NodeosCommand = require('../../cli-commands/commands/nodeos/index');
+
+// Sub-commands
+const LogsCommand = require('../../cli-commands/commands/nodeos/subcommands/logs/index');
+const StopCommand = require('../../cli-commands/commands/nodeos/subcommands/stop/index');
+const StartCommand = require('../../cli-commands/commands/nodeos/subcommands/start/index');
+const AccountsCommand = require('../../cli-commands/commands/nodeos/subcommands/accounts/index');
+
+// Definitions
+const logsDefinition = require('../../cli-commands/commands/nodeos/subcommands/logs/definition');
+const stopDefinition = require('../../cli-commands/commands/nodeos/subcommands/stop/definition');
+const startDefinition = require('../../cli-commands/commands/nodeos/subcommands/start/definition');
+const nodeosDefinition = require('../../cli-commands/commands/nodeos/definition');
+const accountsDefinition = require('../../cli-commands/commands/nodeos/subcommands/accounts/definition');
+
+// Options
+const PathOption = require('../../cli-commands/commands/nodeos/subcommands/start/options/path-option');
+const LinesOption = require('../../cli-commands/commands/nodeos/subcommands/logs/options/lines-option');
+
+// Common & Specifics
+const dataManager = require('../../cli-commands/commands/nodeos/specific/nodeos-data/data-manager');
+const predefinedAccounts = require('../../cli-commands/commands/nodeos/subcommands/common/accounts');
+
+const Logger = require('./utils/logger');
+const logger = new Logger();
+
+describe('Nodeos Command', function () {
+
+ beforeEach(async () => {
+ logger.hide(sinon);
+ });
+
+ afterEach(async () => {
+ sinon.restore();
+ });
+
+ describe('Command', function () {
+
+ it('Should initialize command properly', async () => {
+ let nodeosCommand = new NodeosCommand();
+
+ assert(nodeosCommand instanceof GroupCommand);
+ assert(nodeosCommand.template == nodeosDefinition.template);
+ assert(nodeosCommand.description = nodeosDefinition.description);
+ assert(nodeosCommand.options == nodeosDefinition.options);
+ assert(nodeosCommand.subcommands.length > 0);
+ });
+ });
+
+ describe('Sub-commands', function () {
+
+ function stubNodeosDataManager (nodeosRunning, checkPoints) {
+ return {
+ '../../specific/nodeos-data/data-manager': {
+ nodeosIsRunning: () => { return nodeosRunning; },
+ nodeosPath: () => { return ''; },
+ setNodeosPath: (path) => { checkPoints.setNodeosPath--; },
+ requireRunningNodeos: () => { checkPoints.requireRunningNodeos--; }
+ }
+ }
+ }
+
+ function stubAsyncSoftExec (checkPoints) {
+ return {
+ '../../../../helpers/async-soft-exec': class FakeAsyncSoftExec {
+ constructor () { }
+ exec () { checkPoints.exec--; }
+ }
+ }
+ }
+
+ describe('Start Command', function () {
+ let startCommand;
+
+ beforeEach(async () => {
+ startCommand = new StartCommand();
+ });
+
+ it('Should initialize command properly', async () => {
+ assert(startCommand instanceof Command);
+ assert(startCommand.template == startDefinition.template);
+ assert(startCommand.description = startDefinition.description);
+ assert(startCommand.options == startDefinition.options);
+ assert(startCommand.subcommands.length == 0);
+ });
+
+ function stubPredefinedAccounts (checkPoints) {
+ return {
+ '../common/accounts': {
+ load: () => { checkPoints.load--; }
+ }
+ }
+ }
+
+ it('Should log in case another nodeos instance has been run already', async () => {
+ const startCommand = new (proxyquire('../../cli-commands/commands/nodeos/subcommands/start/index', {
+ ...stubNodeosDataManager(true)
+ }));
+
+ const waitToPass = new Promise(async (resolve, reject) => {
+ logger.on('info', (message) => {
+ if (message.includes('Nodeos is already running')) {
+ return resolve(true);
+ }
+ });
+
+ await startCommand.execute();
+ });
+
+ await waitToPass;
+ });
+
+ it('Should start nodeos', async () => {
+ const checkPoints = {
+ setNodeosPath: 1,
+ requireRunningNodeos: 1,
+ load: 1,
+ exec: 1
+ }
+
+ const startCommand = new (proxyquire('../../cli-commands/commands/nodeos/subcommands/start/index', {
+ ...stubNodeosDataManager(false, checkPoints),
+ ...stubAsyncSoftExec(checkPoints),
+ ...stubPredefinedAccounts(checkPoints)
+ }));
+
+ await startCommand.execute({ path: './' });
+
+ assert(checkPoints.setNodeosPath == 0);
+ assert(checkPoints.requireRunningNodeos == 0);
+ assert(checkPoints.load == 0);
+ assert(checkPoints.exec == 0);
+ });
+
+ it('Should log in case of an error', async () => {
+ const startCommand = new (proxyquire('../../cli-commands/commands/nodeos/subcommands/start/index', {
+ '../../command': class FakeCommand {
+ processOptions () { throw new Error('Fake error') }
+ },
+ ...stubNodeosDataManager(false)
+ }));
+
+ const waitToPass = new Promise(async (resolve, reject) => {
+ logger.on('error', (message) => {
+ if (message.includes('Nodeos has not been started')) {
+ return resolve(true);
+ }
+ });
+
+ await startCommand.execute();
+ });
+
+ await waitToPass;
+ });
+
+ describe('Options', function () {
+ describe('Path', function () {
+ it('Should return provided path', async () => {
+ const path = await PathOption.process('./');
+ assert(path == './');
+ });
+
+ it('Should throw in case the provided path is an incorrect one', async () => {
+ try {
+ await PathOption.process('./custom');
+ assert(false);
+ } catch (error) {
+ assert(error.message.includes('no such file or directory, lstat \'./custom\''));
+ }
+ });
+ });
+ });
+ });
+
+ describe('Stop Command', function () {
+ let stopCommand;
+
+ beforeEach(async () => {
+ stopCommand = new StopCommand();
+ });
+
+ function stubFileSystemUtils (checkPoints) {
+ return {
+ '../../../../helpers/file-system-util': {
+ rmFile: (dirPath) => { checkPoints.rmFile--; },
+ recursivelyDeleteDir: () => { checkPoints.recursivelyDeleteDir--; },
+ readFile: () => { checkPoints.readFile--; }
+ }
+ }
+ }
+
+ it('Should initialize command properly', async () => {
+ assert(stopCommand instanceof Command);
+ assert(stopCommand.template == stopDefinition.template);
+ assert(stopCommand.description = stopDefinition.description);
+ assert(stopCommand.options == stopDefinition.options);
+ assert(stopCommand.subcommands.length == 0);
+ });
+
+ it('Should stop nodeos instance', async () => {
+ const checkPoints = {
+ exec: 1,
+ rmFile: 2,
+ readFile: 1,
+ recursivelyDeleteDir: 2
+ }
+
+ const dataManager = stubNodeosDataManager(true);
+ const asyncSoftExec = stubAsyncSoftExec(checkPoints);
+ const fileSystemUtils = stubFileSystemUtils(checkPoints);
+
+ const stopCommand = new (proxyquire('../../cli-commands/commands/nodeos/subcommands/stop/index', {
+ ...dataManager,
+ ...fileSystemUtils,
+ ...asyncSoftExec
+ }));
+
+ await stopCommand.execute();
+ assert(checkPoints.exec == 0);
+ assert(checkPoints.rmFile == 0);
+ assert(checkPoints.readFile == 0);
+ assert(checkPoints.recursivelyDeleteDir == 0);
+ });
+
+ it('Should clear only nodeos data in case of no running nodeos instance', async () => {
+ const checkPoints = {
+ exec: 1,
+ rmFile: 2,
+ readFile: 1,
+ recursivelyDeleteDir: 2
+ }
+
+ const dataManager = stubNodeosDataManager(false);
+ const asyncSoftExec = stubAsyncSoftExec(checkPoints);
+ const fileSystemUtils = stubFileSystemUtils(checkPoints);
+
+ const stopCommand = new (proxyquire('../../cli-commands/commands/nodeos/subcommands/stop/index', {
+ ...dataManager,
+ ...fileSystemUtils,
+ ...asyncSoftExec
+ }));
+
+ await stopCommand.execute();
+ assert(checkPoints.exec == 1);
+ assert(checkPoints.rmFile == 0);
+ assert(checkPoints.readFile == 1);
+ assert(checkPoints.recursivelyDeleteDir == 0);
+ });
+
+ it('Should log in case of an error', async () => {
+ const stopCommand = new (proxyquire('../../cli-commands/commands/nodeos/subcommands/stop/index', {
+ '../../specific/nodeos-data/data-manager': {
+ nodeosIsRunning: () => { throw new Error(); },
+ nodeosPath: () => { return ''; }
+ }
+ }));
+
+ const waitToPass = new Promise(async (resolve, reject) => {
+ logger.on('error', (message) => {
+ if (message.includes('Nodeos has not been stopped')) {
+ return resolve(true);
+ }
+ });
+
+
+ await stopCommand.execute();
+ });
+
+ await waitToPass;
+ });
+ });
+
+ describe('Logs Command', function () {
+ let logsCommand;
+
+ beforeEach(async () => {
+ logsCommand = new LogsCommand();
+ });
+
+ it('Should initialize command properly', async () => {
+ assert(logsCommand instanceof Command);
+ assert(logsCommand.template == logsDefinition.template);
+ assert(logsCommand.description = logsDefinition.description);
+ assert(logsCommand.options == logsDefinition.options);
+ assert(logsCommand.subcommands.length == 0);
+ });
+
+ it('Should log in case of no running nodeos instance', async () => {
+ const dataManager = stubNodeosDataManager(false);
+
+ const logsCommand = new (proxyquire('../../cli-commands/commands/nodeos/subcommands/logs/index', {
+ ...dataManager
+ }));
+
+ const waitToPass = new Promise(async (resolve, reject) => {
+ logger.on('info', (message) => {
+ if (message.includes('Empty logs')) {
+ return resolve(true);
+ }
+ });
+
+ await logsCommand.execute();
+ });
+
+ await waitToPass;
+ });
+
+ it('Should display nodeos logs', async () => {
+ const checkPoints = {
+ exec: 1
+ }
+
+ const dataManager = stubNodeosDataManager(true);
+ const asyncSoftExec = stubAsyncSoftExec(checkPoints);
+
+ const logsCommand = new (proxyquire('../../cli-commands/commands/nodeos/subcommands/logs/index', {
+ ...dataManager,
+ ...asyncSoftExec
+ }));
+
+ const waitToPass = new Promise(async (resolve, reject) => {
+ logger.on('success', (message) => {
+ if (message.includes('Nodeos logs')) {
+ return resolve(true);
+ }
+ });
+
+ await logsCommand.execute({ lines: 1 });
+ });
+
+ await waitToPass;
+ assert(checkPoints.exec == 0);
+ });
+
+ it('Should log in case of an error', async () => {
+ const logsCommand = new (proxyquire('../../cli-commands/commands/nodeos/subcommands/logs/index', {
+ '../../../command': class FakeCommand {
+ processOptions () {
+ throw new Error();
+ }
+ },
+ ...stubNodeosDataManager(true)
+ }));
+
+ const waitToPass = new Promise(async (resolve, reject) => {
+ logger.on('error', (message) => {
+ if (message.includes('Logs has not been shown')) {
+ return resolve(true);
+ }
+ });
+
+ await logsCommand.execute({ lines: 1 });
+ });
+
+ await waitToPass;
+ });
+
+ describe('Options', function () {
+ describe('Number of lines', function () {
+ it('Should return provided number of lines', async () => {
+ assert(LinesOption.process(1) == 1);
+ assert(LinesOption.definition.default == 10);
+ });
+ });
+ });
+ });
+
+ describe('Accounts Command', function () {
+ let accountsCommand;
+
+ beforeEach(async () => {
+ accountsCommand = new AccountsCommand();
+ });
+
+ it('Should initialize command properly', async () => {
+ assert(accountsCommand instanceof Command);
+ assert(accountsCommand.template == accountsDefinition.template);
+ assert(accountsCommand.description = accountsDefinition.description);
+ assert(accountsCommand.options == accountsDefinition.options);
+ assert(accountsCommand.subcommands.length == 0);
+ });
+
+ it('Should display a table with preloaded accounts', async () => {
+ const waitToPass = new Promise(async (resolve, reject) => {
+ logger.on('log', (message) => {
+ for (let i = 0; i < predefinedAccounts.length; i++) {
+ assert(message.includes(predefinedAccounts[i].name));
+ assert(message.includes(predefinedAccounts[i].publicKey));
+ assert(message.includes(predefinedAccounts[i].privateKey));
+ }
+
+ return resolve(true);
+ });
+
+ await accountsCommand.execute();
+ });
+
+ await waitToPass;
+ });
+
+ it('Should log in case of an error', async () => {
+ const accountsCommand = new (proxyquire('../../cli-commands/commands/nodeos/subcommands/accounts/index', {
+ '../common/accounts': {
+ accounts () {
+ throw new Error();
+ }
+ }
+ }));
+
+ const waitToPass = new Promise(async (resolve, reject) => {
+ logger.on('error', (message) => {
+ if (message.includes('Accounts has not been shown')) {
+ return resolve(true);
+ }
+ });
+
+ await accountsCommand.execute();
+ });
+
+ await waitToPass;
+ });
+
+ });
+ });
+
+ describe('Command specifics', function () {
+
+ describe('Data Manager', function () {
+
+ function stubFileSystemUtilsCallback (cb) {
+ return proxyquire('../../cli-commands/commands/nodeos/specific/nodeos-data/data-manager', {
+ '../../../../helpers/file-system-util': {
+ writeFile: (path, content) => { return cb(path, content) },
+ readFile: (filePath) => { return cb(filePath) }
+ }
+ });
+ }
+
+ it('Should return dirname as default path', async () => {
+ assert(dataManager.defaultPath().includes('eoslime/cli-commands/commands/nodeos/specific/nodeos-data'));
+ });
+
+ it('Should return the last set nodeosPath', async () => {
+ assert(dataManager.nodeosPath());
+ });
+
+ it('Should set new nodeos path', async () => {
+ const dataManagerStub = stubFileSystemUtilsCallback((path, content) => {
+ assert(path.includes('eoslime/cli-commands/commands/nodeos/specific/nodeos-data/nodeos.json'));
+ assert(content == '{"nodeosPath":"./custom"}');
+ });
+
+ dataManagerStub.setNodeosPath('./custom');
+ });
+
+ it('Should return if nodeos is running', async () => {
+ const dataManagerStub = stubFileSystemUtilsCallback((path) => {
+ assert('./custom/eosd.pid' == path);
+ return { toString: () => { return 'content'; } }
+ });
+
+ dataManagerStub.nodeosIsRunning('./custom');
+ });
+
+ it('Should throw in case nodeos is not running', async () => {
+ try {
+ dataManager.nodeosIsRunning = () => { return false; }
+ dataManager.requireRunningNodeos('./custom');
+
+ assert(false);
+ } catch (error) {
+ assert(error.message === 'Check if another nodeos has been started already');
+ }
+ });
+ });
+
+ describe('Pre-defined accounts', function () {
+
+ it('Should return pre-defined accounts', async () => {
+ const accounts = predefinedAccounts.accounts();
+
+ assert(accounts.length == 3);
+
+ assert(accounts[0].name == 'eoslimedavid');
+ assert(accounts[0].publicKey == 'EOS7UyV15G2t47MqRm4WpUP6KTfy9sNU3HHGu9aAgR2A3ktxoBTLv');
+ assert(accounts[0].privateKey == '5KS9t8LGsaQZxLP6Ln5WK6XwYU8M3AYHcfx1x6zoGmbs34vQsPT');
+
+ assert(accounts[1].name == 'eoslimekevin');
+ assert(accounts[1].publicKey == 'EOS6Zz4iPbjm6FNys1zUMaRE4zPXrHcX3SRG65YWneVbdXQTSiqDp');
+ assert(accounts[1].privateKey == '5KieRy975NgHk5XQfn8r6o3pcqJDF2vpeV9bDiuB5uF4xKCTwRF');
+
+ assert(accounts[2].name == 'eoslimemarty');
+ assert(accounts[2].publicKey == 'EOS7FDeYdY3G8yMNxtrU8MSYnAJc3ZogYHgL7RG3rBf8ZDYA3xthi');
+ assert(accounts[2].privateKey == '5JtbCXgK5NERDdFdrmxb8rpYMkoxVfSyH1sR6TYxHBG5zNLHfj5');
+ });
+
+ it('Should create pre-defined accounts on the chain', async () => {
+ let numberOfCreations = 3;
+
+ // Stub eoslime
+ const accounts = proxyquire('../../cli-commands/commands/nodeos/subcommands/common/accounts', {
+ '../../../../../': {
+ init: () => {
+ return {
+ Account: {
+ create: () => { numberOfCreations--; }
+ }
+ }
+ }
+ }
+ });
+
+ await accounts.load();
+ assert(numberOfCreations == 0);
+ });
+ });
+ });
+});
diff --git a/tests/cli-commands/shape-tests.js b/tests/cli-commands/shape-tests.js
new file mode 100644
index 0000000..6743980
--- /dev/null
+++ b/tests/cli-commands/shape-tests.js
@@ -0,0 +1,104 @@
+const sinon = require('sinon');
+const assert = require('assert');
+const proxyquire = require('proxyquire').noCallThru();
+
+const definition = require('../../cli-commands/commands/shape/definition');
+
+const Command = require('../../cli-commands/commands/command');
+const ShapeCommand = require('../../cli-commands/commands/shape/index');
+
+const FrameworkOption = require('../../cli-commands/commands/shape/options/framework-option');
+
+const Logger = require('./utils/logger');
+const logger = new Logger();
+
+describe('Shape Command', function () {
+
+ beforeEach(async () => {
+ logger.hide(sinon);
+ });
+
+ afterEach(async () => {
+ sinon.restore();
+ });
+
+ describe('Command', function () {
+
+ it('Should initialize command properly', async () => {
+ const shapeCommand = new ShapeCommand();
+
+ assert(shapeCommand instanceof Command);
+ assert(shapeCommand.template == definition.template);
+ assert(shapeCommand.description = definition.description);
+ assert(shapeCommand.options == definition.options);
+ assert(shapeCommand.subcommands.length == 0);
+ });
+
+ it('Should prepare shape ', async () => {
+ const shapeCommand = new (proxyquire('../../cli-commands/commands/shape/index',
+ {
+ 'simple-git/promise': () => {
+ return { clone: () => { assert(true); } }
+ }
+ }
+ ));
+
+ const waitToPass = new Promise(async (resolve, reject) => {
+ logger.on('success', (message) => {
+ if (message.includes('Successful shaping')) {
+ return resolve(true);
+ }
+ });
+
+ await shapeCommand.execute({ framework: 'react' });
+ });
+
+ await waitToPass;
+ });
+
+ function stubBaseCommand (cb) {
+ return {
+ '../command': class FakeBaseCommand {
+ processOptions () {
+ return cb();
+ }
+ }
+ }
+ }
+
+ it('Should log in case of an error', async () => {
+ const shapeCommand = new (proxyquire('../../cli-commands/commands/shape/index', {
+ ...stubBaseCommand(() => { throw new Error('Fake error'); })
+ }));
+
+ const waitToPass = new Promise(async (resolve, reject) => {
+ logger.on('error', (message) => {
+ if (message.includes('Unsuccessful shaping')) {
+ return resolve(true);
+ }
+ });
+
+ await shapeCommand.execute();
+ });
+
+ await waitToPass;
+ });
+ });
+
+ describe('Options', function () {
+ describe('Framework', function () {
+
+ it('Should return the repository of the shape framework', async () => {
+ assert(FrameworkOption.process('react') == 'https://github.com/LimeChain/eoslime-shape-react.git');
+ });
+
+ it('Should throw in case the provided framework is not supported', async () => {
+ try {
+ await FrameworkOption.process('Not supported');
+ } catch (error) {
+ assert(error.message == 'Invalid Shape framework');
+ }
+ });
+ });
+ });
+});
diff --git a/tests/cli-commands/test-tests.js b/tests/cli-commands/test-tests.js
new file mode 100644
index 0000000..0c82748
--- /dev/null
+++ b/tests/cli-commands/test-tests.js
@@ -0,0 +1,303 @@
+const path = require('path');
+const sinon = require('sinon');
+const assert = require('assert');
+const proxyquire = require('proxyquire').noCallThru();
+
+const Command = require('../../cli-commands/commands/command');
+const TestCommand = require('../../cli-commands/commands/test/index');
+
+const NetworkOption = require('../../cli-commands/commands/test/options/network-option');
+const ResourceReportOption = require('../../cli-commands/commands/test/options/resource-usage-option');
+
+const definition = require('../../cli-commands/commands/test/definition');
+
+const Logger = require('./utils/logger');
+const logger = new Logger();
+
+const eoslime = require('../../').init();
+const MochaFramework = require('../../cli-commands/commands/test/specific/test-frameworks/mocha');
+
+describe('Test Command', function () {
+
+ this.timeout(10000);
+
+ beforeEach(async () => {
+ logger.hide(sinon);
+ });
+
+ afterEach(async () => {
+ sinon.restore();
+ });
+
+ describe('Command', function () {
+
+ it('Should initialize command properly', async () => {
+ const testCommand = new TestCommand();
+ assert(testCommand instanceof Command);
+ assert(testCommand.template == definition.template);
+ assert(testCommand.description = definition.description);
+ assert(testCommand.options == definition.options);
+ assert(testCommand.subcommands.length == 0);
+ });
+
+ it('Should run test scripts', async () => {
+ const checkPoint = {
+ runTests: 1,
+ setDescribeArgs: 1
+ }
+
+ const testCommand = new TestCommand(class TestFramework {
+ setDescribeArgs () { checkPoint.setDescribeArgs--; }
+ runTests () { checkPoint.runTests--; }
+ });
+
+ const args = {};
+ const waitToPass = new Promise(async (resolve, reject) => {
+ logger.on('success', (message) => {
+ if (message.includes('Testing completed successfully')) {
+ return resolve(true);
+ }
+ });
+
+ await testCommand.execute(args);
+ });
+
+ await waitToPass;
+
+ assert(args.eoslime.tests);
+ assert(checkPoint.runTests == 0);
+ assert(checkPoint.setDescribeArgs == 0);
+ });
+
+ it('Should log error message in case of error', async () => {
+ // Because no test framework has been provided, it will throw
+ const testCommand = new TestCommand();
+
+ const waitToPass = new Promise(async (resolve, reject) => {
+ logger.on('error', (message, error) => {
+ if (message.includes('Testing failed')) {
+ return resolve(true);
+ }
+ });
+
+ await testCommand.execute();
+ });
+
+ await waitToPass;
+ });
+ });
+
+ describe('Options', function () {
+
+ describe('Path', function () {
+
+ function stubFileSystemUtils (isFolder) {
+ return {
+ '../../../helpers/file-system-util': {
+ isDir: () => { return isFolder; },
+ isFile: () => { return !isFolder; },
+ recursivelyReadDir: (dir) => {
+ return [{ fullPath: `${dir}/fullPath` }];
+ }
+ }
+ }
+ }
+
+ it('Should load a test script into the test framework', async () => {
+ const pathOption = proxyquire('../../cli-commands/commands/test/options/path-option', {
+ ...stubFileSystemUtils(false)
+ });
+
+ await pathOption.process('./custom.js',
+ {
+ testFramework: {
+ addTestFiles: (files) => { assert(files[0] == path.resolve('./', './custom.js')); }
+ }
+ }
+ );
+ });
+
+ it('Should load all test scripts from a folder into the test framework', async () => {
+ const pathOption = proxyquire('../../cli-commands/commands/test/options/path-option', {
+ ...stubFileSystemUtils(true)
+ });
+
+ await pathOption.process('./custom',
+ {
+ testFramework: {
+ addTestFiles: (files) => { assert(files[0] == './custom/fullPath'); }
+ }
+ }
+ );
+ });
+ });
+
+ describe('Network', function () {
+ const eoslime = require('../../').init();
+
+ it('Should set eoslime on provided network', async () => {
+ NetworkOption.process('jungle', { eoslime });
+ assert(eoslime.Provider.network.name == 'jungle');
+ });
+
+ it('Should set eoslime on local network none has been provided', async () => {
+ NetworkOption.process(undefined, { eoslime });
+ assert(eoslime.Provider.network.name == 'local');
+ });
+ });
+
+ describe('Resources usage report', function () {
+
+ const FAUCET_ABI_PATH = "./tests/testing-contracts/compiled/faucet.abi";
+ const FAUCET_WASM_PATH = "./tests/testing-contracts/compiled/faucet.wasm";
+
+ it('Should show correct data in report', async () => {
+ const testFramework = new MochaFramework();
+
+ const waitToPass = new Promise(async (resolve, reject) => {
+ const contractAccount = await eoslime.Account.createRandom();
+
+ // The result is a table visualization
+ // Because of that we are waiting for the table output to check if all good
+ logger.on('log', () => {
+ const table = ResourceReportOption.reportTable.table;
+ assert(JSON.stringify(table.options.head) == JSON.stringify([
+ '',
+ 'Contract',
+ 'Action',
+ 'CPU ( MIN | MAX )',
+ 'NET ( MIN | MAX )',
+ 'RAM ( MIN | MAX )',
+ 'Calls'
+ ]));
+
+ assert(table[1][1] == contractAccount.name);
+ assert(table[3][1] == contractAccount.name);
+ assert(table[4][2] == 'test');
+
+ return resolve(true);
+ });
+
+ ResourceReportOption.process(true, { eoslime, testFramework });
+
+ const contract = await eoslime.Contract.deployOnAccount(FAUCET_WASM_PATH, FAUCET_ABI_PATH, contractAccount);
+ await contract.actions.test();
+
+ testFramework.eventsHooks[0].callback();
+ });
+
+ await waitToPass;
+ });
+ });
+ });
+
+ describe('Command specifics', function () {
+
+ describe('Test utils', function () {
+
+ async function expect (promise, expectCb) {
+ const testCommand = new TestCommand(class TestFramework {
+ setDescribeArgs () { }
+ runTests () { }
+ });
+
+ const args = {};
+ const waitToPass = new Promise(async (resolve, reject) => {
+ logger.on('success', async () => {
+ try {
+ await args.eoslime.tests[expectCb](
+ promise
+ )
+ resolve(true);
+ } catch (error) {
+ reject(error);
+ }
+ });
+
+ await testCommand.execute(args);
+ });
+
+ await waitToPass;
+ }
+
+ describe('expectAssert', function () {
+
+ it('Should expectAssert', async () => {
+ await expect(
+ new Promise((reject, resolve) => {
+ throw new Error('eosio_assert_message_exception');
+ }),
+ 'expectAssert'
+ );
+ });
+
+ it('Should throw in case unexpected error happens', async () => {
+ try {
+ await expect(
+ new Promise((resolve, reject) => {
+ throw new Error('Another error');
+ }),
+ 'expectAssert'
+ );
+ assert(false);
+ } catch (error) {
+ assert(error.message.includes('Expected assert, got \'Another error\' instead'));
+ }
+ });
+
+ it('Should throw in case assert error has not been received', async () => {
+ try {
+ await expect(
+ new Promise((resolve, reject) => {
+ resolve(true);
+ }),
+ 'expectAssert'
+ );
+ assert(false);
+ } catch (error) {
+ assert(error.message.includes('Expected assert not received'));
+ }
+ });
+ });
+
+ describe('expectMissingAuthority', function () {
+ it('Should expectMissingAuthority', async () => {
+ await expect(
+ new Promise((reject, resolve) => {
+ throw new Error('missing_auth_exception');
+ }),
+ 'expectMissingAuthority'
+ );
+ });
+
+ it('Should throw in case unexpected error happens', async () => {
+ try {
+ await expect(
+ new Promise((resolve, reject) => {
+ throw new Error('Another error');
+ }),
+ 'expectMissingAuthority'
+ );
+ assert(false);
+ } catch (error) {
+ assert(error.message.includes('Expected missing authority, got \'Another error\' instead'));
+ }
+ });
+
+ it('Should throw in case missing authority error has not been received', async () => {
+ try {
+ await expect(
+ new Promise((resolve, reject) => {
+ resolve(true);
+ }),
+ 'expectMissingAuthority'
+ );
+ assert(false);
+ } catch (error) {
+ assert(error.message.includes('Expected missing authority not received'));
+ }
+ });
+ });
+ });
+ });
+});
diff --git a/tests/cli-commands/utils/logger.js b/tests/cli-commands/utils/logger.js
new file mode 100644
index 0000000..38ad196
--- /dev/null
+++ b/tests/cli-commands/utils/logger.js
@@ -0,0 +1,55 @@
+const logger = require('../../../cli-commands/common/logger');
+
+class Logger {
+
+ constructor () {
+ this.events = {}
+ }
+
+ hide (sinon) {
+ const self = this
+ sinon.stub(logger, 'log').callsFake((message) => {
+ if (self.events['log']) {
+ for (let i = 0; i < self.events['log'].length; i++) {
+ self.events['log'][i](message)
+ }
+ }
+ });
+
+ sinon.stub(logger, 'info').callsFake((message) => {
+ if (self.events['info']) {
+ for (let i = 0; i < self.events['info'].length; i++) {
+ self.events['info'][i](message)
+ }
+ }
+ });
+
+ sinon.stub(logger, 'success').callsFake((message) => {
+ if (self.events['success']) {
+ for (let i = 0; i < self.events['success'].length; i++) {
+ self.events['success'][i](message)
+ }
+ }
+ });
+
+ sinon.stub(logger, 'error').callsFake((message, error) => {
+ if (self.events['error']) {
+ for (let i = 0; i < self.events['error'].length; i++) {
+ self.events['error'][i](message)
+ }
+ }
+
+ // throw new Error(error.message);
+ });
+ }
+
+ on (event, cb) {
+ if (!this.events[event]) {
+ this.events[event] = [];
+ }
+
+ this.events[event].push(cb)
+ }
+}
+
+module.exports = Logger;
diff --git a/tests/contract-tests.js b/tests/contract-tests.js
index 15d9c37..5f827a0 100644
--- a/tests/contract-tests.js
+++ b/tests/contract-tests.js
@@ -29,7 +29,7 @@ describe("Contract", function () {
try {
const tokenAccount = await eoslime.Account.createRandom();
tokenContract = await eoslime.Contract.deployOnAccount(TOKEN_WASM_PATH, TOKEN_ABI_PATH, tokenAccount);
- await tokenContract.create(faucetAccount.name, TOTAL_SUPPLY);
+ await tokenContract.actions.create([faucetAccount.name, TOTAL_SUPPLY]);
} catch (error) {
console.log(error);
}
@@ -60,8 +60,8 @@ describe("Contract", function () {
it("Should instantiate correct instance of Contract from ABI file", async () => {
const faucetContract = eoslime.Contract.fromFile(FAUCET_ABI_PATH, faucetAccount.name, faucetAccount);
- assert(typeof faucetContract.produce == "function");
- assert(typeof faucetContract.withdraw == "function");
+ assert(typeof faucetContract.actions.produce == "function");
+ assert(typeof faucetContract.actions.withdraw == "function");
assert(faucetContract.name == faucetAccount.name);
assert(JSON.stringify(faucetContract.executor) == JSON.stringify(faucetAccount));
@@ -71,8 +71,8 @@ describe("Contract", function () {
it("Should instantiate correct instance of Contract from blockchain account name", async () => {
const faucetContract = await eoslime.Contract.at(faucetAccount.name, faucetAccount);
- assert(typeof faucetContract.produce == "function");
- assert(typeof faucetContract.withdraw == "function");
+ assert(typeof faucetContract.actions.produce == "function");
+ assert(typeof faucetContract.actions.withdraw == "function");
assert(faucetContract.name == faucetAccount.name);
assert(JSON.stringify(faucetContract.executor) == JSON.stringify(faucetAccount));
@@ -92,7 +92,7 @@ describe("Contract", function () {
const faucetContract = eoslime.Contract.fromFile(FAUCET_ABI_PATH, faucetAccount.name, "INVALID");
eoslime.Provider.defaultAccount = '';
- await faucetContract.produce(tokensHolder.name, "100.0000 TKNS", tokenContract.name, "memo");
+ await faucetContract.actions.produce([tokensHolder.name, "100.0000 TKNS", tokenContract.name, "memo"]);
assert(false, "Should throw");
} catch (error) {
@@ -157,9 +157,9 @@ describe("Contract", function () {
const tokensHolder = await eoslime.Account.createRandom();
// faucetAccount is the executor
- await faucetContract.produce(tokensHolder.name, "100.0000 TKNS", tokenContract.name, "memo");
+ await faucetContract.actions.produce([tokensHolder.name, "100.0000 TKNS", tokenContract.name, "memo"]);
- const result = await faucetContract.withdrawers.limit(1).equal(tokensHolder.name).find();
+ const result = await faucetContract.tables.withdrawers.limit(1).equal(tokensHolder.name).find();
assert(result[0].quantity == PRODUCED_TOKENS_AMOUNT);
assert(result[0].token_name == tokenContract.name);
@@ -170,7 +170,7 @@ describe("Contract", function () {
const tokensHolder = await eoslime.Account.createRandom();
const executor = await eoslime.Account.createRandom();
- await faucetContract.produce(tokensHolder.name, "100.0000 TKNS", tokenContract.name, "memo", { from: executor });
+ await faucetContract.actions.produce([tokensHolder.name, "100.0000 TKNS", tokenContract.name, "memo"], { from: executor });
// After the execution, the contract executor should be the same as the initially provided one
assert(faucetContract.executor.name == faucetAccount.name);
@@ -181,8 +181,8 @@ describe("Contract", function () {
const tokensHolder = await eoslime.Account.createRandom();
const executor = await eoslime.Account.createRandom();
- await faucetContract.produce(tokensHolder.name, '100.0000 TKNS', tokenContract.name, 'memo', { from: executor, unique: true });
- await faucetContract.produce(tokensHolder.name, '100.0000 TKNS', tokenContract.name, 'memo', { from: executor, unique: true });
+ await faucetContract.actions.produce([tokensHolder.name, '100.0000 TKNS', tokenContract.name, 'memo'], { from: executor, unique: true });
+ await faucetContract.actions.produce([tokensHolder.name, '100.0000 TKNS', tokenContract.name, 'memo'], { from: executor, unique: true });
assert(true);
});
@@ -192,52 +192,102 @@ describe("Contract", function () {
const executor = await eoslime.Account.createRandom();
try {
- await faucetContract.produce(tokensHolder.name, '100.0000 TKNS', tokenContract.name, 'memo', { from: executor });
- await faucetContract.produce(tokensHolder.name, '100.0000 TKNS', tokenContract.name, 'memo', { from: executor });
+ await faucetContract.actions.produce([tokensHolder.name, '100.0000 TKNS', tokenContract.name, 'memo'], { from: executor });
+ await faucetContract.actions.produce([tokensHolder.name, '100.0000 TKNS', tokenContract.name, 'memo'], { from: executor });
} catch (error) {
assert(error.includes('duplicate transaction'));
}
});
- it('Should get the raw transaction from the action', async () => {
+ function assertRawTransaction (tx, contractName) {
+ assert(tx.expiration != undefined);
+ assert(tx.ref_block_num != undefined);
+ assert(tx.ref_block_prefix != undefined);
+ assert(tx.max_net_usage_words != undefined);
+ assert(tx.max_cpu_usage_ms != undefined);
+ assert(tx.delay_sec != undefined);
+ assert(tx.context_free_actions != undefined);
+ assert(tx.actions != undefined);
+ assert(tx.actions[0].name == 'produce');
+ assert(tx.actions[0].account == contractName);
+ assert(tx.actions[0].data != undefined);
+ assert(tx.actions[0].authorization != undefined);
+ }
+
+ it('Should get a raw transaction from action', async () => {
+ const faucetContract = eoslime.Contract.fromFile(FAUCET_ABI_PATH, faucetAccount.name, faucetAccount);
+ const tokensHolder = await eoslime.Account.createRandom();
+
+ const rawActionTx = await faucetContract.actions.produce.getRawTransaction([tokensHolder.name, '100.0000 TKNS', tokenContract.name, 'memo']);
+ assertRawTransaction(rawActionTx, faucetContract.name);
+ });
+
+ it('Should get a raw transaction from payable action', async () => {
+ const faucetContract = eoslime.Contract.fromFile(FAUCET_ABI_PATH, faucetAccount.name, faucetAccount);
+ const tokensHolder = await eoslime.Account.createRandom();
+
+ const rawActionTx = await faucetContract.actions.produce.getRawTransaction([tokensHolder.name, '100.0000 TKNS', tokenContract.name, 'memo'], { tokens: '5.0000 SYS' });
+
+ assertRawTransaction(rawActionTx, faucetContract.name);
+ assert(rawActionTx.actions[1].name == 'transfer');
+ assert(rawActionTx.actions[1].account == 'eosio.token');
+ assert(rawActionTx.actions[1].data != undefined);
+ assert(rawActionTx.actions[1].authorization != undefined);
+ });
+
+ it('Should get a raw transaction from unique action', async () => {
+ const faucetContract = eoslime.Contract.fromFile(FAUCET_ABI_PATH, faucetAccount.name, faucetAccount);
+ const tokensHolder = await eoslime.Account.createRandom();
+
+ const rawActionTx = await faucetContract.actions.produce.getRawTransaction([tokensHolder.name, '100.0000 TKNS', tokenContract.name, 'memo'], { unique: true });
+
+ assertRawTransaction(rawActionTx, faucetContract.name);
+ assert(rawActionTx.actions[1].name == 'nonce');
+ assert(rawActionTx.actions[1].account == 'eosio.null');
+ assert(rawActionTx.actions[1].data != undefined);
+ assert(rawActionTx.actions[1].authorization != undefined);
+ });
+
+ function assertSignedTransaction (tx, contractName) {
+ assert(tx.signatures.length == 1);
+ assertRawTransaction(tx.transaction, contractName);
+ }
+
+ it('Should sign an action without broadcasting it', async () => {
+ const faucetContract = eoslime.Contract.fromFile(FAUCET_ABI_PATH, faucetAccount.name, faucetAccount);
+ const tokensHolder = await eoslime.Account.createRandom();
+ const signer = await eoslime.Account.createRandom();
+
+ const signedActionTx = await faucetContract.actions.produce.sign([tokensHolder.name, '100.0000 TKNS', tokenContract.name, 'memo'], { from: signer });
+ assertSignedTransaction(signedActionTx, faucetContract.name);
+ });
+
+ it('Should sign a payable action ', async () => {
const faucetContract = eoslime.Contract.fromFile(FAUCET_ABI_PATH, faucetAccount.name, faucetAccount);
const tokensHolder = await eoslime.Account.createRandom();
+ const signer = await eoslime.Account.createRandom();
+
+ const signedActionTx = await faucetContract.actions.produce.sign([tokensHolder.name, '100.0000 TKNS', tokenContract.name, 'memo'], { tokens: '5.0000 SYS', from: signer });
- const rawActionTx = await faucetContract.produce.getRawTransaction(tokensHolder.name, '100.0000 TKNS', tokenContract.name, 'memo');
- assert(rawActionTx.expiration != undefined);
- assert(rawActionTx.ref_block_num != undefined);
- assert(rawActionTx.ref_block_prefix != undefined);
- assert(rawActionTx.max_net_usage_words != undefined);
- assert(rawActionTx.max_cpu_usage_ms != undefined);
- assert(rawActionTx.delay_sec != undefined);
- assert(rawActionTx.context_free_actions != undefined);
- assert(rawActionTx.actions != undefined);
- assert(rawActionTx.actions[0].name == 'produce');
- assert(rawActionTx.actions[0].account == faucetContract.name);
- assert(rawActionTx.actions[0].data != undefined);
- assert(rawActionTx.actions[0].authorization != undefined);
+ assertSignedTransaction(signedActionTx, faucetContract.name);
+ assert(signedActionTx.transaction.actions[1].name == 'transfer');
+ assert(signedActionTx.transaction.actions[1].account == 'eosio.token');
+ assert(signedActionTx.transaction.actions[1].data != undefined);
+ assert(signedActionTx.transaction.actions[1].authorization != undefined);
});
- it('Should sign the action without broadcasting it', async () => {
+ it('Should sign unique action ', async () => {
const faucetContract = eoslime.Contract.fromFile(FAUCET_ABI_PATH, faucetAccount.name, faucetAccount);
const tokensHolder = await eoslime.Account.createRandom();
const signer = await eoslime.Account.createRandom();
- const signedActionTx = await faucetContract.produce.sign(signer, tokensHolder.name, '100.0000 TKNS', tokenContract.name, 'memo');
-
- assert(signedActionTx.signatures.length == 1);
- assert(signedActionTx.transaction.expiration != undefined);
- assert(signedActionTx.transaction.ref_block_num != undefined);
- assert(signedActionTx.transaction.ref_block_prefix != undefined);
- assert(signedActionTx.transaction.max_net_usage_words != undefined);
- assert(signedActionTx.transaction.max_cpu_usage_ms != undefined);
- assert(signedActionTx.transaction.delay_sec != undefined);
- assert(signedActionTx.transaction.context_free_actions != undefined);
- assert(signedActionTx.transaction.actions != undefined);
- assert(signedActionTx.transaction.actions[0].name == 'produce');
- assert(signedActionTx.transaction.actions[0].account == faucetContract.name);
- assert(signedActionTx.transaction.actions[0].data != undefined);
- assert(signedActionTx.transaction.actions[0].authorization != undefined);
+ const signedActionTx = await faucetContract.actions.produce.sign([tokensHolder.name, '100.0000 TKNS', tokenContract.name, 'memo'], { unique: true, from: signer });
+
+ assertSignedTransaction(signedActionTx, faucetContract.name);
+ assert(signedActionTx.transaction.actions[1].name == 'nonce');
+ assert(signedActionTx.transaction.actions[1].account == 'eosio.null');
+ assert(signedActionTx.transaction.actions[1].data != undefined);
+ assert(signedActionTx.transaction.actions[1].authorization != undefined);
});
it('Should throw if trying to sign the action with an invalid signer', async () => {
@@ -245,7 +295,7 @@ describe("Contract", function () {
const faucetContract = eoslime.Contract.fromFile(FAUCET_ABI_PATH, faucetAccount.name, faucetAccount);
const tokensHolder = await eoslime.Account.createRandom();
- await faucetContract.produce.sign('Fake signer', tokensHolder.name, '100.0000 TKNS', tokenContract.name, 'memo');
+ await faucetContract.actions.produce.sign([tokensHolder.name, '100.0000 TKNS', tokenContract.name, 'memo'], { from: 'Fake signer' });
} catch (error) {
assert(error.message.includes('String is not an instance of BaseAccount'));
}
@@ -255,51 +305,51 @@ describe("Contract", function () {
describe("Blockchain tables", function () {
it("Should have a default table getter", async () => {
- const faucetContract = eoslime.Contract.fromFile(FAUCET_ABI_PATH, faucetAccount.name, faucetAccount);
+ const faucetContract = eoslime.Contract.fromFile(FAUCET_ABI_PATH, faucetAccount.name);
// withdrawers is a table in the contract
- assert(faucetContract.withdrawers);
+ assert(faucetContract.tables.withdrawers);
});
it("Should apply the default query params if none provided", async () => {
- const faucetContract = eoslime.Contract.fromFile(FAUCET_ABI_PATH, faucetAccount.name, faucetAccount);
+ const faucetContract = eoslime.Contract.fromFile(FAUCET_ABI_PATH, faucetAccount.name);
const tokensHolder = await eoslime.Account.createRandom();
// faucetAccount is the executor
- await faucetContract.produce(tokensHolder.name, "100.0000 TKNS", tokenContract.name, "memo");
+ await faucetContract.actions.produce([tokensHolder.name, "100.0000 TKNS", tokenContract.name, "memo"]);
- const allWithdrawers = await faucetContract.withdrawers.find();
+ const allWithdrawers = await faucetContract.tables.withdrawers.find();
assert(allWithdrawers[0].quantity == PRODUCED_TOKENS_AMOUNT);
assert(allWithdrawers[0].token_name == tokenContract.name);
});
it("Should query a table", async () => {
- const faucetContract = eoslime.Contract.fromFile(FAUCET_ABI_PATH, faucetAccount.name, faucetAccount);
+ const faucetContract = eoslime.Contract.fromFile(FAUCET_ABI_PATH, faucetAccount.name);
const tokensHolder = await eoslime.Account.createRandom();
// faucetAccount is the executor
- await faucetContract.produce(tokensHolder.name, "100.0000 TKNS", tokenContract.name, "memo");
+ await faucetContract.actions.produce([tokensHolder.name, "100.0000 TKNS", tokenContract.name, "memo"]);
// With equal criteria
- const equalResult = await faucetContract.withdrawers.equal(tokensHolder.name).find();
+ const equalResult = await faucetContract.tables.withdrawers.equal(tokensHolder.name).find();
assert(equalResult[0].quantity == PRODUCED_TOKENS_AMOUNT);
assert(equalResult[0].token_name == tokenContract.name);
// With range criteria
- const rangeResult = await faucetContract.withdrawers.range(0, 100 * TOKEN_PRECISION).index(2).find();
+ const rangeResult = await faucetContract.tables.withdrawers.range(0, 100 * TOKEN_PRECISION).index(2).find();
assert(rangeResult[0].quantity == PRODUCED_TOKENS_AMOUNT);
assert(rangeResult[0].token_name == tokenContract.name);
// With limit
// There is only one withdrawer
- const allWithdrawers = await faucetContract.withdrawers.limit(10).find();
+ const allWithdrawers = await faucetContract.tables.withdrawers.limit(10).find();
assert(allWithdrawers.length == 1);
assert(allWithdrawers[0].quantity == PRODUCED_TOKENS_AMOUNT);
assert(allWithdrawers[0].token_name == tokenContract.name);
// With different index (By Balance)
- const balanceWithdrawers = await faucetContract.withdrawers.equal(100 * TOKEN_PRECISION).index(2).find();
+ const balanceWithdrawers = await faucetContract.tables.withdrawers.equal(100 * TOKEN_PRECISION).index(2).find();
assert(balanceWithdrawers[0].quantity == PRODUCED_TOKENS_AMOUNT);
assert(balanceWithdrawers[0].token_name == tokenContract.name);
});
@@ -311,13 +361,13 @@ describe("Contract", function () {
await faucetContract.makeInline();
const tokensHolder = await eoslime.Account.createRandom();
- await faucetContract.produce(tokensHolder.name, PRODUCED_TOKENS_AMOUNT, tokenContract.name, "memo");
+ await faucetContract.actions.produce([tokensHolder.name, PRODUCED_TOKENS_AMOUNT, tokenContract.name, "memo"]);
const tokensHolderBeforeBalance = await tokensHolder.getBalance("TKNS", tokenContract.name);
assert(tokensHolderBeforeBalance.length == 0);
// withdraw method behind the scene calls token's contract issue method
- await faucetContract.withdraw(tokensHolder.name);
+ await faucetContract.actions.withdraw([tokensHolder.name]);
const tokensHolderAfterBalance = await tokensHolder.getBalance("TKNS", tokenContract.name);
assert(tokensHolderAfterBalance[0] == PRODUCED_TOKENS_AMOUNT);
diff --git a/tests/helpers-tests.js b/tests/helpers-tests.js
index 45dedde..b81c3a6 100644
--- a/tests/helpers-tests.js
+++ b/tests/helpers-tests.js
@@ -1,4 +1,5 @@
const assert = require('assert');
+
const is = require('./../src/helpers/is');
const crypto = require('./../src/helpers/crypto');
const EventClass = require('./../src/helpers/event-class');
@@ -13,32 +14,31 @@ describe('Helpers scripts', function () {
const expectedHash = 'a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e';
const resultedHash = crypto.hash('Hello World');
- assert(expectedHash == resultedHash)
+ assert(expectedHash == resultedHash);
});
- it('Should encrypt and decrypt a data', async () => {
+ it('Should encrypt and decrypt data', async () => {
const encryptedData = crypto.encrypt('Hello World', '123');
const decryptedData = crypto.decrypt(encryptedData, '123');
- assert(decryptedData == 'Hello World')
+ assert(decryptedData == 'Hello World');
});
- it('Should throw if it is not able to encrypt a data', async () => {
+
+ it('Should throw if it is not able to encrypt data', async () => {
try {
crypto.encrypt('Hello World', { fake: 'FAKE' });
- assert(false);
} catch (error) {
- assert(error.message.includes('Couldn\'t encrypt the data'))
+ assert(error.message.includes('Couldn\'t encrypt the data'));
}
});
- it('Should throw if it is not able to decrypt a data', async () => {
+ it('Should throw if it is not able to decrypt data', async () => {
try {
const encryptedData = crypto.encrypt('Hello World', '123');
crypto.decrypt(encryptedData, { fake: 'FAKE' });
- assert(false);
} catch (error) {
- assert(error.message.includes('Couldn\'t decrypt the data'))
+ assert(error.message.includes('Couldn\'t decrypt the data'));
}
});
});
@@ -58,8 +58,24 @@ describe('Helpers scripts', function () {
eventClass.on('created', () => x++);
eventClass.emit('created');
- assert(x == 2)
+ assert(x == 2);
});
+
+ it('Should be able for more than one subscriber to listen for an event', async () => {
+ const eventClass = new EventClass({ 'created': 'created' });
+ eventClass.on('created', () => { });
+ eventClass.on('created', () => { });
+
+ assert(eventClass.eventsHooks['created'].length == 2);
+ });
+
+ it('Should not be able to subscribe for unknown event', async () => {
+ const eventClass = new EventClass({});
+ eventClass.on('created', () => { });
+
+ assert(eventClass.eventsHooks['created'] == undefined);
+ });
+
});
describe('is.js', function () {
diff --git a/tests/multisig-account-test.js b/tests/multisig-account-test.js
index 59c7d2a..35a1cb5 100644
--- a/tests/multisig-account-test.js
+++ b/tests/multisig-account-test.js
@@ -27,11 +27,11 @@ describe('Multi signature account', function () {
const multiSigAccount = eoslime.MultiSigAccount.load(account.name, account.privateKey);
multiSigAccount.loadAccounts(accounts);
- const proposalId = await multiSigAccount.propose(faucetContract.produce, [account.name, "100.0000 TKNS", account.name, "memo"]);
- await multiSigAccount.approve(multiSigAccount.accounts[0].publicKey, proposalId);
+ const proposalId = await multiSigAccount.propose(faucetContract.actions.produce, [account.name, "100.0000 TKNS", account.name, "memo"]);
+ await multiSigAccount.approve(multiSigAccount.accounts[1].publicKey, proposalId);
await multiSigAccount.processProposal(proposalId);
- const withdrawers = (await faucetContract.withdrawers.find())[0];
+ const withdrawers = (await faucetContract.tables.withdrawers.find())[0];
assert(eoslime.utils.toName(withdrawers.account) == account.name);
assert(withdrawers.quantity == "100.0000 TKNS");
});
@@ -44,18 +44,18 @@ describe('Multi signature account', function () {
await eoslime.utils.generateKeys()
]
- await account.addAuthorityKey(keys[0].publicKey)
- await account.addAuthorityKey(keys[1].publicKey)
+ await account.addOnBehalfKey(keys[0].publicKey)
+ await account.addOnBehalfKey(keys[1].publicKey)
await account.increaseThreshold(2);
const multiSigAccount = eoslime.MultiSigAccount.load(account.name, account.privateKey);
multiSigAccount.loadKeys(keys.map((key) => { return key.privateKey }));
- const proposalId = await multiSigAccount.propose(faucetContract.produce, [multiSigAccount.name, "100.0000 TKNS", multiSigAccount.name, "memo"])
+ const proposalId = await multiSigAccount.propose(faucetContract.actions.produce, [multiSigAccount.name, "100.0000 TKNS", multiSigAccount.name, "memo"])
await multiSigAccount.approve(multiSigAccount.accounts[1].publicKey, proposalId)
await multiSigAccount.processProposal(proposalId);
- const withdrawers = (await faucetContract.withdrawers.find())[0];
+ const withdrawers = (await faucetContract.tables.withdrawers.find())[0];
assert(eoslime.utils.toName(withdrawers.account) == account.name);
assert(withdrawers.quantity == "100.0000 TKNS");
});
@@ -71,7 +71,7 @@ describe('Multi signature account', function () {
const multiSigAccount = eoslime.MultiSigAccount.load(account.name, account.privateKey);
multiSigAccount.loadAccounts(accounts);
- const proposalId = await multiSigAccount.propose(faucetContract.produce, [account.name, "100.0000 TKNS", account.name, "memo"]);
+ const proposalId = await multiSigAccount.propose(faucetContract.actions.produce, [account.name, "100.0000 TKNS", account.name, "memo"]);
for (let i = 0; i < accounts.length; i++) {
await multiSigAccount.approve(accounts[i].publicKey, proposalId);
}
@@ -80,7 +80,7 @@ describe('Multi signature account', function () {
await multiSigAccount.processProposal(proposalId);
- const withdrawers = (await faucetContract.withdrawers.find())[0];
+ const withdrawers = (await faucetContract.tables.withdrawers.find())[0];
assert(eoslime.utils.toName(withdrawers.account) == account.name);
assert(withdrawers.quantity == "100.0000 TKNS");
});
@@ -119,7 +119,7 @@ describe('Multi signature account', function () {
const multiSigAccount = eoslime.MultiSigAccount.load(account.name, account.privateKey);
multiSigAccount.loadAccounts(accounts);
- const proposalId = await multiSigAccount.propose(faucetContract.produce, [account.name, "100.0000 TKNS", account.name, "memo"]);
+ const proposalId = await multiSigAccount.propose(faucetContract.actions.produce, [account.name, "100.0000 TKNS", account.name, "memo"]);
await multiSigAccount.approve('Fake account', proposalId);
assert(false);
@@ -140,8 +140,8 @@ describe('Multi signature account', function () {
const multiSigAccount = eoslime.MultiSigAccount.load(account.name, account.privateKey);
multiSigAccount.loadAccounts(accounts);
- await multiSigAccount.propose(faucetContract.produce, [account.name, "100.0000 TKNS", account.name, "memo"]);
- await multiSigAccount.approve(multiSigAccount.accounts[0].publicKey, 'Fake proposal');
+ await multiSigAccount.propose(faucetContract.actions.produce, [account.name, "100.0000 TKNS", account.name, "memo"]);
+ await multiSigAccount.approve(multiSigAccount.accounts[1].publicKey, 'Fake proposal');
assert(false);
} catch (error) {
@@ -164,8 +164,8 @@ describe('Multi signature account', function () {
const multiSigAccount = eoslime.MultiSigAccount.load(account.name, account.privateKey);
multiSigAccount.loadAccounts(accounts);
- const proposalId = await multiSigAccount.propose(faucetContract.produce, [account.name, "100.0000 TKNS", account.name, "memo"]);
- await multiSigAccount.approve(multiSigAccount.accounts[0].publicKey, proposalId);
+ const proposalId = await multiSigAccount.propose(faucetContract.actions.produce, [account.name, "100.0000 TKNS", account.name, "memo"]);
+ await multiSigAccount.approve(multiSigAccount.accounts[1].publicKey, proposalId);
await multiSigAccount.processProposal('Fake proposal');
@@ -187,7 +187,7 @@ describe('Multi signature account', function () {
const multiSigAccount = eoslime.MultiSigAccount.load(account.name, account.privateKey);
multiSigAccount.loadAccounts(accounts);
- const proposalId = await multiSigAccount.propose(faucetContract.produce, [account.name, "100.0000 TKNS", account.name, "memo"]);
+ const proposalId = await multiSigAccount.propose(faucetContract.actions.produce, [account.name, "100.0000 TKNS", account.name, "memo"]);
for (let i = 0; i < accounts.length; i++) {
await multiSigAccount.approve(accounts[i].publicKey, proposalId);
}
@@ -212,7 +212,7 @@ describe('Multi signature account', function () {
const multiSigAccount = eoslime.MultiSigAccount.load(account.name, account.privateKey);
multiSigAccount.loadAccounts(accounts);
- const proposalId = await multiSigAccount.propose(faucetContract.produce, [account.name, "100.0000 TKNS", account.name, "memo"]);
+ const proposalId = await multiSigAccount.propose(faucetContract.actions.produce, [account.name, "100.0000 TKNS", account.name, "memo"]);
await multiSigAccount.processProposal(proposalId);
assert(false);
diff --git a/tests/providers-tests.js b/tests/providers-tests.js
index dc6641e..a8d4b91 100644
--- a/tests/providers-tests.js
+++ b/tests/providers-tests.js
@@ -27,6 +27,11 @@ const Networks = {
url: 'https://jungle2.cryptolions.io',
chainId: 'e70aaab8997e1dfce58fbfac80cbbb8fecec7b99cf982a9444273cbc64c41473'
},
+ jungle3: {
+ name: 'jungle3',
+ url: 'https://jungle3.cryptolions.io',
+ chainId: '2a02a0053e5a8cf73a56ba0fda11e4d92e0238a4a2aa74fccf46d5a910746840'
+ },
main: {
name: 'main',
url: 'https://eos.greymass.com',
@@ -34,7 +39,7 @@ const Networks = {
},
kylin: {
name: 'kylin',
- url: 'https://kylin.eoscanada.com',
+ url: 'https://api.kylin.alohaeos.com',
chainId: '5fff1dae8dc8e2fc4d5b23b2c7665c97f9e9d8edf2b6485a86ba311c25639191'
},
custom: {
@@ -66,6 +71,10 @@ describe('Providers', function () {
const jungleProvider = eoslime.init('jungle').Provider;
assert(JSON.stringify(jungleProvider.network) == JSON.stringify(Networks.jungle));
+ // Jungle3
+ const jungle3Provider = eoslime.init('jungle3').Provider;
+ assert(JSON.stringify(jungle3Provider.network) == JSON.stringify(Networks.jungle3));
+
// Worbli
const worbliProvider = eoslime.init('worbli').Provider;
assert(JSON.stringify(worbliProvider.network) == JSON.stringify(Networks.worbli));
@@ -101,6 +110,12 @@ describe('Providers', function () {
assert(JSON.stringify(jungleProvider.network.url) == JSON.stringify(Networks.jungle.url));
assert(jungleProvider.network.chainId == Networks.custom.chainId);
+ // Jungle3
+ const jungle3Provider = eoslime.init('jungle3', { chainId: Networks.custom.chainId }).Provider;
+ assert(JSON.stringify(jungle3Provider.network.name) == JSON.stringify(Networks.jungle3.name));
+ assert(JSON.stringify(jungle3Provider.network.url) == JSON.stringify(Networks.jungle3.url));
+ assert(jungle3Provider.network.chainId == Networks.custom.chainId);
+
// Worbli
const worbliProvider = eoslime.init('worbli', { url: Networks.custom.url }).Provider;
assert(JSON.stringify(worbliProvider.network.name) == JSON.stringify(Networks.worbli.name));
@@ -147,6 +162,10 @@ describe('Providers', function () {
const jungleProvider = new eoslimeInstance.Provider('jungle');
assert(JSON.stringify(jungleProvider.network) == JSON.stringify(Networks.jungle));
+ // Jungle3
+ const jungle3Provider = new eoslimeInstance.Provider('jungle3');
+ assert(JSON.stringify(jungle3Provider.network) == JSON.stringify(Networks.jungle3));
+
// Worbli
const worbliProvider = new eoslimeInstance.Provider('worbli');
assert(JSON.stringify(worbliProvider.network) == JSON.stringify(Networks.worbli));
@@ -183,6 +202,12 @@ describe('Providers', function () {
assert(JSON.stringify(jungleProvider.network.url) == JSON.stringify(Networks.jungle.url));
assert(jungleProvider.network.chainId == Networks.custom.chainId);
+ // Jungle3
+ const jungle3Provider = new eoslimeInstance.Provider('jungle3', { chainId: Networks.custom.chainId });
+ assert(JSON.stringify(jungle3Provider.network.name) == JSON.stringify(Networks.jungle3.name));
+ assert(JSON.stringify(jungle3Provider.network.url) == JSON.stringify(Networks.jungle3.url));
+ assert(jungle3Provider.network.chainId == Networks.custom.chainId);
+
// Worbli
const worbliProvider = new eoslimeInstance.Provider('worbli', { url: Networks.custom.url });
assert(JSON.stringify(worbliProvider.network.name) == JSON.stringify(Networks.worbli.name));
@@ -240,9 +265,9 @@ describe('Providers', function () {
const tokenContract = await eoslimeInstance.Contract.deploy(TOKEN_WASM_PATH, TOKEN_ABI_PATH);
const faucetContract = await eoslimeInstance.Contract.deploy(FAUCET_WASM_PATH, FAUCET_ABI_PATH);
- await tokenContract.create(faucetContract.name, TOTAL_SUPPLY);
+ await tokenContract.actions.create([faucetContract.name, TOTAL_SUPPLY]);
const tokensHolder = await eoslimeInstance.Account.createRandom();
- await faucetContract.produce(tokensHolder.name, PRODUCED_TOKENS_AMOUNT, tokenContract.name, "memo");
+ await faucetContract.actions.produce([tokensHolder.name, PRODUCED_TOKENS_AMOUNT, tokenContract.name, "memo"]);
// With equal criteria
const equalResult = await Provider.select('withdrawers').from(faucetContract.name).equal(tokensHolder.name).find();
@@ -281,9 +306,9 @@ describe('Providers', function () {
const tokenContract = await eoslimeInstance.Contract.deploy(TOKEN_WASM_PATH, TOKEN_ABI_PATH);
const faucetContract = await eoslimeInstance.Contract.deploy(FAUCET_WASM_PATH, FAUCET_ABI_PATH);
- await tokenContract.create(faucetContract.name, TOTAL_SUPPLY);
+ await tokenContract.actions.create([faucetContract.name, TOTAL_SUPPLY]);
const tokensHolder = await eoslimeInstance.Account.createRandom();
- await faucetContract.produce(tokensHolder.name, PRODUCED_TOKENS_AMOUNT, tokenContract.name, "memo");
+ await faucetContract.actions.produce([tokensHolder.name, PRODUCED_TOKENS_AMOUNT, tokenContract.name, "memo"]);
await Provider.select().find();
} catch (error) {
@@ -299,9 +324,9 @@ describe('Providers', function () {
const tokenContract = await eoslimeInstance.Contract.deploy(TOKEN_WASM_PATH, TOKEN_ABI_PATH);
const faucetContract = await eoslimeInstance.Contract.deploy(FAUCET_WASM_PATH, FAUCET_ABI_PATH);
- await tokenContract.create(faucetContract.name, TOTAL_SUPPLY);
+ await tokenContract.actions.create([faucetContract.name, TOTAL_SUPPLY]);
const tokensHolder = await eoslimeInstance.Account.createRandom();
- await faucetContract.produce(tokensHolder.name, PRODUCED_TOKENS_AMOUNT, tokenContract.name, "memo");
+ await faucetContract.actions.produce([tokensHolder.name, PRODUCED_TOKENS_AMOUNT, tokenContract.name, "memo"]);
await Provider.select('withdrawers').from().find();
} catch (error) {
@@ -317,9 +342,9 @@ describe('Providers', function () {
const tokenContract = await eoslimeInstance.Contract.deploy(TOKEN_WASM_PATH, TOKEN_ABI_PATH);
const faucetContract = await eoslimeInstance.Contract.deploy(FAUCET_WASM_PATH, FAUCET_ABI_PATH);
- await tokenContract.create(faucetContract.name, TOTAL_SUPPLY);
+ await tokenContract.actions.create([faucetContract.name, TOTAL_SUPPLY]);
const tokensHolder = await eoslimeInstance.Account.createRandom();
- await faucetContract.produce(tokensHolder.name, PRODUCED_TOKENS_AMOUNT, tokenContract.name, "memo");
+ await faucetContract.actions.produce([tokensHolder.name, PRODUCED_TOKENS_AMOUNT, tokenContract.name, "memo"]);
await Provider.select('withdrawers').from(faucetContract.name).scope().find();
} catch (error) {
diff --git a/tests/testing-contracts/compiled/faucet.abi b/tests/testing-contracts/compiled/faucet.abi
index a4c8c59..02cd667 100644
--- a/tests/testing-contracts/compiled/faucet.abi
+++ b/tests/testing-contracts/compiled/faucet.abi
@@ -25,6 +25,11 @@
}
]
},
+ {
+ "name": "test",
+ "base": "",
+ "fields": []
+ },
{
"name": "withdraw",
"base": "",
@@ -64,6 +69,11 @@
"type": "produce",
"ricardian_contract": ""
},
+ {
+ "name": "test",
+ "type": "test",
+ "ricardian_contract": ""
+ },
{
"name": "withdraw",
"type": "withdraw",
diff --git a/tests/testing-contracts/compiled/faucet.wasm b/tests/testing-contracts/compiled/faucet.wasm
index a6c4179..5d5fd64 100755
Binary files a/tests/testing-contracts/compiled/faucet.wasm and b/tests/testing-contracts/compiled/faucet.wasm differ
diff --git a/tests/testing-contracts/faucet.cpp b/tests/testing-contracts/faucet.cpp
index 255d15e..dc1577e 100644
--- a/tests/testing-contracts/faucet.cpp
+++ b/tests/testing-contracts/faucet.cpp
@@ -60,4 +60,6 @@ CONTRACT faucet : public contract
}
}
}
+
+ ACTION test() {}
};
\ No newline at end of file
diff --git a/tests/types/account.ts b/tests/types/account.ts
new file mode 100644
index 0000000..cb11551
--- /dev/null
+++ b/tests/types/account.ts
@@ -0,0 +1,387 @@
+import assert from 'assert';
+import { it } from 'mocha';
+
+import { init, utils } from '../../';
+const eoslime = init();
+
+import {
+ Contract,
+ Account,
+ MultiSignatureAccount
+} from '../../types';
+
+import { assertTransactionResult } from './utils';
+
+describe.only('All types of accounts', function () {
+
+ this.timeout(20000);
+
+ const ACCOUNT_NAME = 'eosio';
+ const ACCOUNT_PRIVATE_KEY = '5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3';
+
+ const ABI_PATH = "./tests/testing-contracts/compiled/faucet.abi";
+ const WASM_PATH = "./tests/testing-contracts/compiled/faucet.wasm";
+
+ describe('Normal Account', function () {
+
+ function assertAccount (account: Account) {
+ assert(account.name !== undefined);
+ assert(account.provider !== undefined);
+ assert(account.publicKey !== undefined);
+ assert(account.privateKey !== undefined);
+ assert(account.authority.actor !== undefined);
+ assert(account.authority.permission !== undefined);
+
+ assert(typeof (account.send) == 'function');
+ assert(typeof (account.buyRam) == 'function');
+ assert(typeof (account.setWeight) == 'function');
+ assert(typeof (account.getBalance) == 'function');
+ assert(typeof (account.buyBandwidth) == 'function');
+ assert(typeof (account.addAuthority) == 'function');
+ assert(typeof (account.addPermission) == 'function');
+ assert(typeof (account.addOnBehalfKey) == 'function');
+ assert(typeof (account.getAuthorityInfo) == 'function');
+ assert(typeof (account.increaseThreshold) == 'function');
+ assert(typeof (account.addOnBehalfAccount) == 'function');
+ assert(typeof (account.setAuthorityAbilities) == 'function');
+ }
+
+ describe('Static functions', function () {
+ it('Should load account', async () => {
+ const account = eoslime.Account.load(ACCOUNT_NAME, ACCOUNT_PRIVATE_KEY);
+ assertAccount(account);
+ });
+
+ it('Should create account [account creator]', async () => {
+ const creatorAccount = eoslime.Account.load(ACCOUNT_NAME, ACCOUNT_PRIVATE_KEY);
+
+ const accountName = await utils.randomName();
+ const privateKey = await utils.randomPrivateKey();
+
+ const account = await eoslime.Account.create(accountName, privateKey, creatorAccount);
+ assertAccount(account);
+ });
+
+ it('Should create account [default account]', async () => {
+ const accountName = await utils.randomName();
+ const privateKey = await utils.randomPrivateKey();
+
+ const account = await eoslime.Account.create(accountName, privateKey);
+ assertAccount(account);
+ });
+
+ it('Should create account from name [account creator]', async () => {
+ const creatorAccount = eoslime.Account.load(ACCOUNT_NAME, ACCOUNT_PRIVATE_KEY);
+
+ const accountName = await utils.randomName();
+ const account = await eoslime.Account.createFromName(accountName, creatorAccount);
+ assertAccount(account);
+ });
+
+ it('Should create account from name [default account]', async () => {
+ const accountName = await utils.randomName();
+ const account = await eoslime.Account.createFromName(accountName);
+
+ assertAccount(account);
+ });
+
+ it('Should create random account [account creator]', async () => {
+ const creatorAccount = eoslime.Account.load(ACCOUNT_NAME, ACCOUNT_PRIVATE_KEY);
+ const account = await eoslime.Account.createRandom(creatorAccount);
+
+ assertAccount(account);
+ });
+
+ it('Should create random account [default account]', async () => {
+ const account = await eoslime.Account.createRandom();
+ assertAccount(account);
+ });
+
+ it('Should create random accounts [account creator]', async () => {
+ const creatorAccount = eoslime.Account.load(ACCOUNT_NAME, ACCOUNT_PRIVATE_KEY);
+
+ const accounts = await eoslime.Account.createRandoms(2, creatorAccount);
+ for (const account of accounts) {
+ assertAccount(account);
+ }
+ });
+
+ it('Should create random accounts [default account]', async () => {
+ const accounts = await eoslime.Account.createRandoms(2);
+ for (const account of accounts) {
+ assertAccount(account);
+ }
+ });
+
+ it('Should create encrypted account [account creator]', async () => {
+ const creatorAccount = eoslime.Account.load(ACCOUNT_NAME, ACCOUNT_PRIVATE_KEY);
+ const encryptedAccount = await eoslime.Account.createEncrypted('PASSWORD', creatorAccount);
+
+ assert(encryptedAccount.network);
+ assert(encryptedAccount.cipherText);
+ assert(encryptedAccount.authority.actor);
+ assert(encryptedAccount.authority.permission);
+ });
+
+ it('Should create encrypted account [default account]', async () => {
+ const encryptedAccount = await eoslime.Account.createEncrypted('PASSWORD');
+
+ assert(encryptedAccount.network);
+ assert(encryptedAccount.cipherText);
+ assert(encryptedAccount.authority.actor);
+ assert(encryptedAccount.authority.permission);
+ });
+
+ it('Should convert encrypted account into account', async () => {
+ const encryptedAccount = await eoslime.Account.createEncrypted('PASSWORD');
+ const decryptedAccount = eoslime.Account.fromEncrypted(encryptedAccount, 'PASSWORD');
+
+ assertAccount(decryptedAccount);
+ });
+ });
+
+ describe('Main functions', function () {
+
+ it('Should send EOS tokens', async () => {
+ const SEND_AMOUNT = '10.0000';
+ const senderAccount = eoslime.Account.load(ACCOUNT_NAME, ACCOUNT_PRIVATE_KEY);
+ const receiverAccount = await eoslime.Account.createRandom();
+
+ const tx = await senderAccount.send(receiverAccount, SEND_AMOUNT, 'SYS');
+ assertTransactionResult(tx);
+ });
+
+ it('Should buy ram [payer]', async () => {
+ const payer = eoslime.Account.load(ACCOUNT_NAME, ACCOUNT_PRIVATE_KEY);
+ const account = await eoslime.Account.createRandom();
+
+ const tx = await account.buyRam(1000, payer);
+ assertTransactionResult(tx);
+ });
+
+ it('Should buy ram by self', async () => {
+ const eosAccount = eoslime.Account.load(ACCOUNT_NAME, ACCOUNT_PRIVATE_KEY);
+ const account = await eoslime.Account.createRandom();
+
+ await eosAccount.send(account, '10.0000', 'SYS');
+
+ const tx = await account.buyRam(1000);
+ assertTransactionResult(tx);
+ });
+
+ it('Should buy bandwidth [payer]', async () => {
+ const payer = eoslime.Account.load(ACCOUNT_NAME, ACCOUNT_PRIVATE_KEY);
+ const account = await eoslime.Account.createRandom();
+
+ const tx = await account.buyBandwidth('10.0000 SYS', '10.0000 SYS', payer);
+ assertTransactionResult(tx);
+ });
+
+ it('Should buy bandwidth by self', async () => {
+ const eosAccount = eoslime.Account.load(ACCOUNT_NAME, ACCOUNT_PRIVATE_KEY);
+ const account = await eoslime.Account.createRandom();
+
+ await eosAccount.send(account, '10.0000', 'SYS');
+
+ const tx = await account.buyBandwidth('10 SYS', '10 SYS');
+ assertTransactionResult(tx);
+ });
+
+ it('Should add authority', async () => {
+ const account = await eoslime.Account.createRandom();
+ const tx = await account.addAuthority('custom');
+ assertTransactionResult(tx);
+ });
+
+ it('Should create permission for active authority', async () => {
+ const account = await eoslime.Account.createRandom();
+ const tx = await account.addPermission('eosio.code');
+
+ assertTransactionResult(tx);
+ });
+
+ it('Should add permission with weight', async () => {
+ const accounts = await eoslime.Account.createRandom();
+ const tx = await accounts.addPermission('eosio.code', 2);
+
+ assertTransactionResult(tx);
+ });
+
+ it('Should allow another a keys pair to act on behalf', async () => {
+ const account = await eoslime.Account.createRandom();
+ const keysPair = await utils.generateKeys();
+
+ const tx = await account.addOnBehalfKey(keysPair.publicKey);
+ assertTransactionResult(tx);
+ });
+
+ it('Should add keys pair with weight', async () => {
+ const WEIGHT = 2;
+
+ const account = await eoslime.Account.createRandom();
+ const keysPair = await utils.generateKeys();
+
+ const tx = await account.addOnBehalfKey(keysPair.publicKey, WEIGHT);
+ assertTransactionResult(tx);
+ });
+
+ it('Should allow another account to act on behalf', async () => {
+ const accounts = await eoslime.Account.createRandoms(2);
+ const child = accounts[0];
+ const parent = accounts[1];
+
+ const tx = await child.addOnBehalfAccount(parent.name, 'active');
+ assertTransactionResult(tx);
+ });
+
+ it('Should add authority account with weight', async () => {
+ const WEIGHT = 2;
+
+ const accounts = await eoslime.Account.createRandoms(2);
+ const child = accounts[0];
+ const parent = accounts[1];
+
+ const tx = await child.addOnBehalfAccount(parent.name, 'active', WEIGHT);
+ assertTransactionResult(tx);
+ });
+
+ it('Should increase authority threshold', async () => {
+ const THRESHOLD = 2;
+ const account = await eoslime.Account.createRandom();
+
+ const keysPair = await utils.generateKeys();
+ await account.addOnBehalfKey(keysPair.publicKey);
+ const tx = await account.increaseThreshold(THRESHOLD);
+
+ assertTransactionResult(tx);
+ });
+
+ it('Should set weight correctly authority threshold', async () => {
+ const account = await eoslime.Account.createRandom();
+
+ const WEIGHT = 2;
+ const tx = await account.setWeight(WEIGHT);
+
+ assertTransactionResult(tx);
+ });
+
+ it('Should get authority details', async () => {
+ const account = await eoslime.Account.createRandom();
+ const authorityInfo = await account.getAuthorityInfo();
+
+ assert(authorityInfo.perm_name)
+ assert(authorityInfo.parent)
+ assert(authorityInfo.required_auth.threshold)
+ assert(Array.isArray(authorityInfo.required_auth.keys))
+ assert(Array.isArray(authorityInfo.required_auth.accounts))
+ assert(Array.isArray(authorityInfo.required_auth.waits))
+ });
+
+ it('Should get balance', async () => {
+ const account = await eoslime.Account.createRandom();
+ const accBalance = await account.getBalance();
+
+ assert(accBalance.length == 0);
+ });
+ });
+ });
+
+ describe('Authority Account', function () {
+ it('Should set authority abilities', async () => {
+ const { name } = await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+
+ const account = await eoslime.Account.createRandom();
+ await account.addAuthority('custom');
+ const tx = await account.setAuthorityAbilities('custom', [
+ {
+ action: 'test',
+ contract: name
+ }
+ ]);
+
+ assertTransactionResult(tx);
+ });
+ });
+
+ describe('MultiSignature Account', function () {
+ function assertMultiSigAccount (account: MultiSignatureAccount) {
+ assert(account.name);
+ assert(account.accounts);
+ assert(account.provider);
+ assert(account.proposals);
+ assert(account.publicKey);
+ assert(account.privateKey);
+ assert(account.authority.actor);
+ assert(account.authority.permission);
+
+ assert(typeof (account.loadKeys) == 'function');
+ assert(typeof (account.loadAccounts) == 'function');
+
+ assert(typeof (account.propose) == 'function');
+ assert(typeof (account.approve) == 'function');
+ assert(typeof (account.processProposal) == 'function');
+ }
+
+ describe('Static functions', function () {
+ it('Should load multi signature account', async () => {
+ const account = eoslime.MultiSigAccount.load(ACCOUNT_NAME, ACCOUNT_PRIVATE_KEY);
+ assertMultiSigAccount(account);
+ });
+ });
+
+ describe('Main functions', function () {
+
+ let contract: Contract;
+
+ // TODO: Implement stub version
+ beforeEach(async () => {
+ contract = await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+ });
+
+ it('Should load more keys', async () => {
+ const keys = [
+ (await utils.generateKeys()).privateKey,
+ (await utils.generateKeys()).privateKey
+ ];
+
+ const multiSigAccount = eoslime.MultiSigAccount.load(ACCOUNT_NAME, ACCOUNT_PRIVATE_KEY);
+ multiSigAccount.loadKeys(keys);
+ });
+
+ it('Should load more accounts', async () => {
+ const accounts = await eoslime.Account.createRandoms(2);
+
+ const multiSigAccount = eoslime.MultiSigAccount.load(ACCOUNT_NAME, ACCOUNT_PRIVATE_KEY);
+ multiSigAccount.loadAccounts(accounts);
+ });
+
+ it('Should propose a transaction to be broadcasted', async () => {
+ const multiSigAccount = eoslime.MultiSigAccount.load(ACCOUNT_NAME, ACCOUNT_PRIVATE_KEY);
+ const proposalId = await multiSigAccount.propose(contract.actions.test, []);
+
+ assert(proposalId);
+ });
+
+ it('Should approve a transaction for broadcasting', async () => {
+ const accounts = await eoslime.Account.createRandoms(2);
+ const multiSigAccount = eoslime.MultiSigAccount.load(ACCOUNT_NAME, ACCOUNT_PRIVATE_KEY);
+ multiSigAccount.loadAccounts(accounts);
+
+ const proposalId = await multiSigAccount.propose(contract.actions.test, []);
+
+ await multiSigAccount.approve(multiSigAccount.accounts[0].publicKey, proposalId);
+ });
+
+ it('Should broadcast a proposed transaction', async () => {
+ const { name, privateKey } = await eoslime.Account.createRandom();
+
+ const multiSigAccount = eoslime.MultiSigAccount.load(name, privateKey);
+ const proposalId = await multiSigAccount.propose(contract.actions.test, []);
+
+ const tx = await multiSigAccount.processProposal(proposalId);
+ assert(tx.processed !== undefined);
+ assert(tx.transaction_id !== undefined);
+ });
+ });
+ });
+});
diff --git a/tests/types/contract.ts b/tests/types/contract.ts
new file mode 100644
index 0000000..492643e
--- /dev/null
+++ b/tests/types/contract.ts
@@ -0,0 +1,215 @@
+import assert from 'assert';
+import { it } from 'mocha';
+
+import { init } from '../../';
+const eoslime = init();
+
+import {
+ Contract,
+ TransactionResult
+} from '../../types';
+
+import { assertRawTransaction, assertSignedAction, assertTransactionResult } from './utils';
+
+const ABI_PATH = "./tests/testing-contracts/compiled/faucet.abi";
+const WASM_PATH = "./tests/testing-contracts/compiled/faucet.wasm";
+
+describe("Contract", function () {
+
+ this.timeout(20000);
+
+ const eosio = eoslime.Account.load('eosio', '5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3');
+
+ const assertContract = function (contract: Contract): void {
+ assert(typeof contract.actions.produce == "function");
+ assert(typeof contract.tables.withdrawers !== undefined);
+
+
+ assert(contract.abi !== undefined);
+ assert(contract.name !== undefined);
+ assert(contract.executor !== undefined);
+ }
+
+ describe("Instantiation", function () {
+ it("Should have fromFile function", async () => {
+ const contract = eoslime.Contract.fromFile(ABI_PATH, 'contracttest', eosio);
+ assertContract(contract);
+ });
+
+ it("Should have at function", async () => {
+ const { name } = await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+ const contract = await eoslime.Contract.at(name, eosio);
+ assertContract(contract);
+ });
+
+ it("Should set default eosio as executor if none is provided", async () => {
+ const contract = eoslime.Contract.fromFile(ABI_PATH, 'contracttest');
+ assertContract(contract);
+ });
+ });
+
+ describe("Deployment", function () {
+ it("Should have deploy function", async () => {
+ const contract = await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+ assertContract(contract);
+ });
+
+ it("Should have deployOnAccount function", async () => {
+ const contractAccount = await eoslime.Account.createRandom()
+ const contract = await eoslime.Contract.deployOnAccount(WASM_PATH, ABI_PATH, contractAccount);
+ assertContract(contract);
+ });
+
+ it("Should have deployRaw function", async () => {
+ const contract_A = await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+ const rawWASM = await contract_A.getRawWASM();
+
+ const contract = await eoslime.Contract.deployRaw(rawWASM, contract_A.abi);
+ assertContract(contract);
+ });
+
+ it("Should have deployRawOnAccount function", async () => {
+ const contract_A = await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+ const rawWASM = await contract_A.getRawWASM();
+ const contractAccount = await eoslime.Account.createRandom()
+
+ const contract = await eoslime.Contract.deployRawOnAccount(
+ rawWASM,
+ contract_A.abi,
+ contractAccount
+ );
+ assertContract(contract);
+ });
+ });
+
+ describe("Blockchain actions", function () {
+
+ it("Should have blockchain actions", async () => {
+ const contract = await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+ const tx = await contract.actions.test([])
+
+ assertTransactionResult(tx);
+ });
+
+ it("Should execute a blockchain action from another executor", async () => {
+ const contract = await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+ await contract.actions.test([], { from: eosio });
+ });
+
+ it('Should process nonce-action', async () => {
+ const contract = await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+ await contract.actions.test([], { unique: true });
+ });
+
+ it('Should process token action', async () => {
+ const contract = await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+ await contract.actions.test([], { from: eosio, tokens: '5.0000 SYS' });
+ });
+
+ describe("Methods", function () {
+
+ it('Should get a raw transaction from an action', async () => {
+ const contract = await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+ const rawActionTx = await contract.actions.test.getRawTransaction([]);
+
+ assertRawTransaction(rawActionTx);
+ });
+
+ it('Should get a raw transaction from an action with options', async () => {
+ const contract = await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+ const rawActionTx = await contract.actions.test.getRawTransaction([], { from: eosio });
+
+ assertRawTransaction(rawActionTx);
+ });
+
+ it('Should sign an action without broadcasting it', async () => {
+ const contract = await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+ const signedActionTx = await contract.actions.test.sign([]);
+ assertSignedAction(signedActionTx);
+ });
+
+ it('Should sign an action with options without broadcasting it', async () => {
+ const contract = await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+
+ const signer = await eoslime.Account.createRandom();
+ const signedActionTx = await contract.actions.test.sign([], { from: signer, unique: true });
+ assertSignedAction(signedActionTx);
+ });
+ });
+ });
+
+ describe("Blockchain tables", function () {
+
+ it("Should have a default table getter", async () => {
+ const contract = await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+ assert(typeof contract.tables.withdrawers !== undefined);
+ });
+
+ it("Should have table query functions", async () => {
+ const contract = await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+
+ // With equal criteria
+ await contract.tables.withdrawers.equal('custom').find();
+
+ // With range criteria
+ await contract.tables.withdrawers.range(0, 1).find();
+
+ // With limit
+ await contract.tables.withdrawers.limit(10).find();
+
+ // With different index (By Balance)
+ await contract.tables.withdrawers.index(2).find();
+
+ // With scope
+ await contract.tables.withdrawers.scope(contract.name).find();
+ });
+ });
+
+ describe("Inline a contract", function () {
+ it("Should have makeInline function", async () => {
+ const contract = await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+
+ assert(typeof contract.makeInline == 'function')
+ await contract.makeInline();
+ });
+ });
+
+ describe("Retrieve raw WASM", function () {
+ it("Should have getRawWASM function", async () => {
+ const contract = await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+
+ assert(typeof contract.getRawWASM == 'function');
+ await contract.getRawWASM();
+ });
+ });
+
+ describe("Events", function () {
+ it("Should have init event", async () => {
+ const { name } = await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+
+ eoslime.Contract.on('init', (contract: Contract) => { assertContract(contract) });
+ eoslime.Contract.fromFile(ABI_PATH, name, eosio);
+ });
+
+ it("Should have deploy event", async () => {
+ eoslime.Contract.on('deploy', (contract: Contract, deployTx) => {
+ assertContract(contract);
+ assert(deployTx.length == 2);
+ });
+
+ await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+ });
+
+ describe("Blockchain action events", function () {
+ it("Should have getRawWASM function", async () => {
+ const contract = await eoslime.Contract.deploy(WASM_PATH, ABI_PATH);
+ contract.actions.test.on('processed', (txReceipt: TransactionResult, ...params: any[]) => {
+ assertTransactionResult(txReceipt);
+ assert(params[0] == contract.executor.name);
+ });
+
+ await contract.actions.withdraw([contract.executor.name]);
+ });
+ });
+ });
+});
diff --git a/tests/types/provider.ts b/tests/types/provider.ts
new file mode 100644
index 0000000..1e7c3fc
--- /dev/null
+++ b/tests/types/provider.ts
@@ -0,0 +1,279 @@
+import assert from 'assert';
+import { it } from 'mocha';
+
+import { init } from '../../';
+const { Provider } = init();
+
+describe('Provider', function () {
+
+ const Networks = {
+ bos: {
+ name: 'bos',
+ url: 'https://hapi.bos.eosrio.io',
+ chainId: 'd5a3d18fbb3c084e3b1f3fa98c21014b5f3db536cc15d08f9f6479517c6a3d86'
+ },
+ local: {
+ name: 'local',
+ url: 'http://127.0.0.1:8888',
+ chainId: 'cf057bbfb72640471fd910bcb67639c22df9f92470936cddc1ade0e2f2e7dc4f'
+ },
+ worbli: {
+ name: 'main',
+ url: 'https://eos.greymass.com',
+ chainId: 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906'
+ },
+ jungle: {
+ name: 'jungle',
+ url: 'https://jungle2.cryptolions.io',
+ chainId: 'e70aaab8997e1dfce58fbfac80cbbb8fecec7b99cf982a9444273cbc64c41473'
+ },
+ main: {
+ name: 'main',
+ url: 'https://eos.greymass.com',
+ chainId: 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906'
+ },
+ kylin: {
+ name: 'kylin',
+ url: 'https://api.kylin.alohaeos.com',
+ chainId: '5fff1dae8dc8e2fc4d5b23b2c7665c97f9e9d8edf2b6485a86ba311c25639191'
+ },
+ custom: {
+ name: 'custom',
+ url: 'https://custom.com',
+ chainId: '123'
+ },
+ }
+
+ describe('Instantiation eoslime', function () {
+ it('Should instantiate with a correct Provider from connection', async () => {
+ // Local
+ const localProvider = init().Provider;
+ assert(JSON.stringify(localProvider.network) == JSON.stringify(Networks.local));
+
+ // Jungle
+ const jungleProvider = init('jungle').Provider;
+ assert(JSON.stringify(jungleProvider.network) == JSON.stringify(Networks.jungle));
+
+ // Worbli
+ const worbliProvider = init('worbli').Provider;
+ assert(JSON.stringify(worbliProvider.network) == JSON.stringify(Networks.worbli));
+
+ // Main
+ const mainProvider = init('main').Provider;
+ assert(JSON.stringify(mainProvider.network) == JSON.stringify(Networks.main));
+
+ // Bos
+ const bosProvider = init('bos').Provider;
+ assert(JSON.stringify(bosProvider.network) == JSON.stringify(Networks.bos));
+
+ // Kylin
+ const kylinProvider = init('kylin').Provider;
+ assert(JSON.stringify(kylinProvider.network) == JSON.stringify(Networks.kylin));
+
+ // Custom
+ const customProvider = init({ url: Networks.custom.url, chainId: Networks.custom.chainId }).Provider;
+ assert(JSON.stringify(customProvider.network) == JSON.stringify(Networks.custom));
+ });
+
+ it('Should instantiate with a correct Provider from provided connection', async () => {
+
+ // Local
+ const localProvider = init('local', { url: Networks.custom.url }).Provider;
+ assert(JSON.stringify(localProvider.network.name) == JSON.stringify(Networks.local.name));
+ assert(JSON.stringify(localProvider.network.chainId) == JSON.stringify(Networks.local.chainId));
+ assert(JSON.stringify(localProvider.network.url) == JSON.stringify(Networks.custom.url));
+
+ // Jungle
+ const jungleProvider = init('jungle', { chainId: Networks.custom.chainId }).Provider;
+ assert(JSON.stringify(jungleProvider.network.name) == JSON.stringify(Networks.jungle.name));
+ assert(JSON.stringify(jungleProvider.network.url) == JSON.stringify(Networks.jungle.url));
+ assert(jungleProvider.network.chainId == Networks.custom.chainId);
+
+ // Worbli
+ const worbliProvider = init('worbli', { url: Networks.custom.url }).Provider;
+ assert(JSON.stringify(worbliProvider.network.name) == JSON.stringify(Networks.worbli.name));
+ assert(JSON.stringify(worbliProvider.network.url) == JSON.stringify(Networks.custom.url));
+ assert(JSON.stringify(worbliProvider.network.chainId) == JSON.stringify(Networks.worbli.chainId));
+
+ // Main
+ const mainProvider = init('main', { url: Networks.custom.url }).Provider;
+ assert(JSON.stringify(mainProvider.network.name) == JSON.stringify(Networks.main.name));
+ assert(JSON.stringify(mainProvider.network.url) == JSON.stringify(Networks.custom.url));
+ assert(JSON.stringify(mainProvider.network.chainId) == JSON.stringify(Networks.main.chainId));
+
+ // Bos
+ const bosProvider = init('bos', { url: Networks.custom.url }).Provider;
+ assert(JSON.stringify(bosProvider.network.name) == JSON.stringify(Networks.bos.name));
+ assert(JSON.stringify(bosProvider.network.url) == JSON.stringify(Networks.custom.url));
+ assert(JSON.stringify(bosProvider.network.chainId) == JSON.stringify(Networks.bos.chainId));
+
+ // Kylin
+ const kylinProvider = init('kylin', { url: Networks.custom.url }).Provider;
+ assert(JSON.stringify(kylinProvider.network.name) == JSON.stringify(Networks.kylin.name));
+ assert(JSON.stringify(kylinProvider.network.url) == JSON.stringify(Networks.custom.url));
+ assert(JSON.stringify(kylinProvider.network.chainId) == JSON.stringify(Networks.kylin.chainId));
+ });
+ });
+
+ describe('Create Provider', function () {
+ it('Should be able to create a new Provider with default connection', async () => {
+ // Local
+ const localProvider = new Provider('local');
+ assert(JSON.stringify(localProvider.network) == JSON.stringify(Networks.local));
+
+ // Jungle
+ const jungleProvider = new Provider('jungle');
+ assert(JSON.stringify(jungleProvider.network) == JSON.stringify(Networks.jungle));
+
+ // Worbli
+ const worbliProvider = new Provider('worbli');
+ assert(JSON.stringify(worbliProvider.network) == JSON.stringify(Networks.worbli));
+
+ // Main
+ const mainProvider = new Provider('main');
+ assert(JSON.stringify(mainProvider.network) == JSON.stringify(Networks.main));
+
+ // Bos
+ const bosProvider = new Provider('bos');
+ assert(JSON.stringify(bosProvider.network) == JSON.stringify(Networks.bos));
+
+ // Kylin
+ const kylinProvider = new Provider('kylin');
+ assert(JSON.stringify(kylinProvider.network) == JSON.stringify(Networks.kylin));
+
+ // Custom
+ const customProvider = new Provider({ url: Networks.custom.url, chainId: Networks.custom.chainId });
+ assert(JSON.stringify(customProvider.network) == JSON.stringify(Networks.custom));
+ });
+
+ it('Should be able to create a new Provider from connection', async () => {
+ // Local
+ const localProvider = new Provider('local', { url: Networks.custom.url });
+ assert(JSON.stringify(localProvider.network.name) == JSON.stringify(Networks.local.name));
+ assert(JSON.stringify(localProvider.network.chainId) == JSON.stringify(Networks.local.chainId));
+ assert(JSON.stringify(localProvider.network.url) == JSON.stringify(Networks.custom.url));
+
+ // Jungle
+ const jungleProvider = new Provider('jungle', { chainId: Networks.custom.chainId });
+ assert(JSON.stringify(jungleProvider.network.name) == JSON.stringify(Networks.jungle.name));
+ assert(JSON.stringify(jungleProvider.network.url) == JSON.stringify(Networks.jungle.url));
+ assert(jungleProvider.network.chainId == Networks.custom.chainId);
+
+ // Worbli
+ const worbliProvider = new Provider('worbli', { url: Networks.custom.url });
+ assert(JSON.stringify(worbliProvider.network.name) == JSON.stringify(Networks.worbli.name));
+ assert(JSON.stringify(worbliProvider.network.url) == JSON.stringify(Networks.custom.url));
+ assert(JSON.stringify(worbliProvider.network.chainId) == JSON.stringify(Networks.worbli.chainId));
+
+ // Main
+ const mainProvider = new Provider('main', { url: Networks.custom.url });
+ assert(JSON.stringify(mainProvider.network.name) == JSON.stringify(Networks.main.name));
+ assert(JSON.stringify(mainProvider.network.url) == JSON.stringify(Networks.custom.url));
+ assert(JSON.stringify(mainProvider.network.chainId) == JSON.stringify(Networks.main.chainId));
+
+ // Bos
+ const bosProvider = new Provider('bos', { url: Networks.custom.url });
+ assert(JSON.stringify(bosProvider.network.name) == JSON.stringify(Networks.bos.name));
+ assert(JSON.stringify(bosProvider.network.url) == JSON.stringify(Networks.custom.url));
+ assert(JSON.stringify(bosProvider.network.chainId) == JSON.stringify(Networks.bos.chainId));
+
+ // Kylin
+ const kylinProvider = new Provider('kylin', { url: Networks.custom.url });
+ assert(JSON.stringify(kylinProvider.network.name) == JSON.stringify(Networks.kylin.name));
+ assert(JSON.stringify(kylinProvider.network.url) == JSON.stringify(Networks.custom.url));
+ assert(JSON.stringify(kylinProvider.network.chainId) == JSON.stringify(Networks.kylin.chainId));
+ });
+ });
+
+ describe('Reset provider', function () {
+ it('Should be able to reset the provider', async () => {
+ const jungleProvider = new Provider('jungle');
+ Provider.reset(jungleProvider);
+
+ assert(JSON.stringify(Provider.network) == JSON.stringify(Networks.jungle));
+ });
+ });
+
+ describe('Retrieve table [Table Reader]', function () {
+
+ describe("Select Query", function () {
+ it("Should have correct chain of functions", async () => {
+ const query = Provider.select('table');
+ assert(typeof query.from == 'function');
+ });
+ });
+
+ describe("From Query", function () {
+ it("Should have correct chain of functions", async () => {
+ const query = Provider.select('table').from('from');
+ assert(typeof query.scope == 'function');
+ assert(typeof query.equal == 'function');
+ assert(typeof query.range == 'function');
+ assert(typeof query.limit == 'function');
+ assert(typeof query.index == 'function');
+ assert(typeof query.find == 'function');
+ });
+ });
+
+ describe("Scope Query", function () {
+ it("Should have correct chain of functions", async () => {
+ const query = Provider.select('table').from('from').scope('scope');
+ assert(typeof query.equal == 'function');
+ assert(typeof query.range == 'function');
+ assert(typeof query.limit == 'function');
+ assert(typeof query.index == 'function');
+ assert(typeof query.find == 'function');
+ });
+ });
+
+ describe("Equal Query", function () {
+ it("Should have correct chain of functions", async () => {
+ const query = Provider.select('table').from('from').scope('scope').equal('equal');
+ assert(typeof query.limit == 'function');
+ assert(typeof query.index == 'function');
+ assert(typeof query.find == 'function');
+ });
+ });
+
+ describe("Range Query", function () {
+ it("Should have correct chain of functions", async () => {
+ const query = Provider.select('table').from('from').scope('scope').range(0, 1);
+ assert(typeof query.limit == 'function');
+ assert(typeof query.index == 'function');
+ assert(typeof query.find == 'function');
+ });
+ });
+
+ describe("Limit Query", function () {
+ it("Should have correct chain of functions", async () => {
+ const query = Provider.select('table').from('from').scope('scope').limit(10);
+ assert(typeof query.equal == 'function');
+ assert(typeof query.range == 'function');
+ assert(typeof query.index == 'function');
+ assert(typeof query.find == 'function');
+ });
+ });
+
+ describe("Index Query", function () {
+ it("Should have correct chain of functions", async () => {
+ const query = Provider.select('table').from('from').scope('scope').index(2);
+ assert(typeof query.equal == 'function');
+ assert(typeof query.range == 'function');
+ assert(typeof query.limit == 'function');
+ assert(typeof query.find == 'function');
+ });
+ });
+ });
+
+ describe('Retrieve contract ABI', function () {
+ it('Should retrieve contract ABI', async () => {
+ await Provider.getABI('eosio');
+ });
+ });
+
+ describe('Retrieve contract raw WASM', function () {
+ it('Should retrieve contract raw WASM', async () => {
+ await Provider.getRawWASM('eosio');
+ });
+ });
+});
diff --git a/tests/types/utils/index.ts b/tests/types/utils/index.ts
new file mode 100644
index 0000000..3a6e6a2
--- /dev/null
+++ b/tests/types/utils/index.ts
@@ -0,0 +1,38 @@
+import assert from 'assert';
+
+import { TransactionResult, RawTransaction, SignedTransaction } from '../../../types';
+
+export function assertRawTransaction (rawTransaction: RawTransaction): void {
+ assert(rawTransaction.actions !== undefined);
+ assert(rawTransaction.delay_sec !== undefined);
+ assert(rawTransaction.expiration !== undefined);
+ assert(rawTransaction.ref_block_num !== undefined);
+ assert(rawTransaction.max_cpu_usage_ms !== undefined);
+ assert(rawTransaction.ref_block_prefix !== undefined);
+ assert(rawTransaction.max_net_usage_words !== undefined);
+ assert(rawTransaction.context_free_actions !== undefined);
+}
+
+export function assertSignedAction (signedTx: SignedTransaction): void {
+ assert(signedTx.compression !== undefined);
+ assert(signedTx.signatures.length > 0);
+ assertRawTransaction(signedTx.transaction);
+}
+
+export function assertTransactionResult (txResult: TransactionResult): void {
+ assert(txResult.broadcast !== undefined);
+ assert(txResult.transaction_id !== undefined);
+ assert(txResult.processed.id !== undefined);
+ assert(txResult.processed.block_num !== undefined);
+ assert(txResult.processed.block_time !== undefined);
+ assert(txResult.processed.producer_block_id !== undefined);
+ assert(txResult.processed.receipt !== undefined);
+ assert(txResult.processed.elapsed !== undefined);
+ assert(txResult.processed.net_usage !== undefined);
+ assert(txResult.processed.scheduled !== undefined);
+ assert(txResult.processed.action_traces !== undefined);
+ assert(txResult.processed.account_ram_delta !== undefined);
+ assert(txResult.processed.except !== undefined);
+ assert(txResult.processed.error_code !== undefined);
+ assertSignedAction(txResult.transaction);
+}
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..3092dbc
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,27 @@
+{
+ "compilerOptions": {
+ "module": "commonjs",
+ "esModuleInterop": true,
+ "resolveJsonModule": true,
+ "allowSyntheticDefaultImports": true,
+ "suppressImplicitAnyIndexErrors": true,
+ "target": "es6",
+ "noImplicitAny": true,
+ "moduleResolution": "node",
+ "sourceMap": true,
+ "outDir": "dist",
+ "baseUrl": ".",
+ "paths": {
+ "*": [
+ "node_modules/*",
+ "types/*"
+ ]
+ },
+ "experimentalDecorators": true,
+ "emitDecoratorMetadata": true
+ },
+ "include": [
+ "./index.d.ts",
+ "./types/**/*"
+ ]
+}
\ No newline at end of file
diff --git a/types/account/index.d.ts b/types/account/index.d.ts
new file mode 100644
index 0000000..d937ac9
--- /dev/null
+++ b/types/account/index.d.ts
@@ -0,0 +1,274 @@
+import { BaseProvider } from '../provider';
+import { ContractFunction } from '../contract';
+import { TransactionResult, AuthorityDetails, BroadCastedTransaction } from '../miscellaneous';
+
+interface ExecutiveAuthority {
+ actor: string,
+ permission: string;
+}
+
+interface EncryptedAccount {
+ name: string;
+ network: string;
+ authority: ExecutiveAuthority;
+ cipherText: string;
+}
+
+export class AccountFactory {
+
+ constructor (provider: BaseProvider);
+
+ /**
+ *
+ * @description Load existing network account
+ * @param {string} name Account name
+ * @param {string} privateKey Private key of the signer
+ * @param {string} [authorityName] Authority account will act from
+ * @returns {Account} Loaded account
+ */
+ public load (name: string, privateKey: string, authorityName?: string): Account;
+
+ /**
+ * @description Creates a fresh new account for a given name and private key
+ *
+ * @param {string} accountName Desired name of the created account
+ * @param {string} privateKey Desired private key of the created account
+ * @param {Account} [accountCreator] Another account responsible for paying creation fees
+ * @returns {Promise} Created account
+ */
+ public create (accountName: string, privateKey: string, accountCreator?: Account): Promise;
+
+ /**
+ * @description Creates a fresh new account for a given name
+ *
+ * @param {string} accountName Desired name of the created account
+ * @param {Account} [accountCreator] Another account responsible for paying creation fees
+ * @returns {Promise} Created account
+ */
+ public createFromName (accountName: string, accountCreator?: Account): Promise;
+
+ /**
+ * @description Create new random account
+ *
+ * @param {Account} [accountCreator] Another account responsible for paying creation fees
+ * @returns {Promise} Created account
+ */
+ public createRandom (accountCreator?: Account): Promise;
+
+ /**
+ * @description Create new random accounts
+ *
+ * @param {number} accountsCount Number of accounts to be created
+ * @param {Account} [accountCreator] Another account responsible for paying creation fees
+ * @returns {Promise>} Array of created account
+ */
+ public createRandoms (accountsCount: number, accountCreator?: Account): Promise>
+
+ /**
+ * @description Create a new random account and encrypt it.
+ *
+ * @param {string} password Password the account data will be encrypted with
+ * @param {Account} [accountCreator] Another account responsible for paying creation fees
+ * @returns {Promise} Encrypted account data in JSON
+ */
+ public createEncrypted (password: string, accountCreator?: Account): Promise;
+
+ /**
+ * @description Decrypt an encrypted account
+ *
+ * @param {EncryptedAccount} encryptedAccount JSON format of the encrypted account
+ * @param {string} password Password for decrypting
+ * @returns {Account} Decrypted account
+ */
+ public fromEncrypted (encryptedAccount: EncryptedAccount, password: string): Account;
+}
+
+declare class BaseAccount {
+ public name: string;
+ public publicKey: string;
+ public privateKey: string;
+ public provider: BaseProvider;
+ public authority: ExecutiveAuthority;
+
+ constructor (name: string, privateKey: string, provider: BaseProvider, permission: string);
+
+ /**
+ * @description Returns information for loaded authority
+ *
+ * @returns {Promise}
+ */
+ public getAuthorityInfo (): Promise;
+}
+
+interface AuthorityAbilities {
+ action: string;
+ contract: string;
+}
+
+export class Account extends BaseAccount {
+
+ constructor (name: string, privateKey: string, provider: BaseProvider, permission: string);
+
+ /**
+ * @description Buy ram for this account
+ *
+ * @param {number} bytes Number of RAM bytes
+ * @param {Account} [payer] Another account responsible for paying
+ * @returns {Promise} Transaction receipt
+ */
+ public buyRam (bytes: number, payer?: Account): Promise;
+
+ /**
+ * @description Buy cpu and network for this account
+ *
+ * @param {string} cpu Amount of tokens one want to buy cpu for
+ * @param {string} net Amount of tokens one want to buy net for
+ * @param {Account} [payer] Another account responsible for paying
+ * @returns {Promise} Transaction receipt
+ */
+ public buyBandwidth (cpu: string, net: string, payer?: Account): Promise;
+
+ /**
+ * @description Send tokens to another account
+ *
+ * @param {Account} receiver Account tokens will be sent to
+ * @param {string} amount Tokens amount
+ * @param {string} symbol Token symbol
+ * @returns {Promise} Transaction receipt
+ */
+ public send (receiver: Account, amount: string, symbol: string): Promise;
+
+ /**
+ * @description Add sub authority to the current account's one
+ *
+ * @param {string} authorityName Desired name of the new authority
+ * @param {number} [threshold] Desired threshold of the new authority
+ * @returns {Promise} Transaction receipt
+ */
+ public addAuthority (authorityName: string, threshold?: number): Promise;
+
+ /**
+ * @description Define what actions of which contracts the authority has permissions to execute
+ *
+ * @param {string} authorityName Sub authority one is setting permissions for
+ * @param {Array} abilities Array of permissions
+ * @returns {Promise} Transaction receipt
+ */
+ public setAuthorityAbilities (authorityName: string, abilities: Array): Promise;
+
+ /**
+ * @description Increase authority's threshold
+ *
+ * @param {number} threshold Number of desired threshold
+ * @returns {Promise} Transaction receipt
+ */
+ public increaseThreshold (threshold: number): Promise;
+
+ /**
+ * @description Add permission to authority such as eosio.code
+ *
+ * @param {string} authorityName Permissions [eosio.code]
+ * @param {number} [weight] Weight of the permission
+ * @returns {Promise} Transaction receipt
+ */
+ public addPermission (authorityName: string, weight?: number): Promise;
+
+ /**
+ * @description Allow another account to act from your account's authority
+ *
+ * @param {string} accountName Name of another account
+ * @param {string} [authority] Authority of another account
+ * @param {number} [weight] Weight another account has
+ * @returns {Promise} Transaction receipt
+ */
+ public addOnBehalfAccount (accountName: string, authority?: string, weight?: number): Promise;
+
+ /**
+ * @description Allow more keys to sign transactions from your account
+ *
+ * @param {string} publicKey Allowed public key
+ * @param {number} [weight] Weight the key has
+ * @returns {Promise} Transaction receipt
+ */
+ public addOnBehalfKey (publicKey: string, weight?: number): Promise;
+
+ /**
+ * @description Set weight on account public key.
+ *
+ * @param {number} weight Number of weight
+ * @returns {Promise} Transaction receipt
+ */
+ public setWeight (weight: number): Promise;
+
+ /**
+ * @description Returns the balance of provided token account has
+ *
+ * @param {string} [symbol] Token symbol
+ * @param {string} [code] Token contract name
+ * @returns {Promise>} Balance
+ */
+ public getBalance (symbol?: string, code?: string): Promise>;
+}
+
+export class MultiSignatureFactory {
+
+ constructor (provider: BaseProvider);
+
+ /**
+ * @description Load existing network multisig account
+ *
+ * @param {string} name Account name
+ * @param {string} privateKey Private key of one of the multisig owners
+ * @param {string} [authorityName] Authority the multisig will act from
+ * @returns {MultiSignatureAccount} Loaded multisig account
+ */
+ public load (name: string, privateKey: string, authorityName?: string): MultiSignatureAccount;
+}
+
+export class MultiSignatureAccount extends BaseAccount {
+
+ public accounts: Array;
+ public proposals: Array;
+
+ constructor (name: string, privateKey: string, provider: BaseProvider, authority: string);
+
+ /**
+ * @description Load the private keys of the authority public keys in order to approve transactions with them
+ *
+ * @param {Array} privateKeys Private keys one will use to approve transactions with
+ */
+ public loadKeys (privateKeys: Array): void;
+
+ /**
+ * @description Load the accounts configured to act on behalf of the multisig authority
+ *
+ * @param {Array} accounts Accounts one will use to approve transactions with
+ */
+ public loadAccounts (accounts: Array): void;
+
+ /**
+ * @description Propose a transaction to be executed
+ *
+ * @param {ContractFunction} contractAction Action one propose to be broadcasted
+ * @param {Array} actionData Action data
+ * @returns {Promise} Proposal id
+ */
+ public propose (contractAction: ContractFunction, actionData: Array): Promise;
+
+ /**
+ * @description Sign a proposed transaction
+ *
+ * @param {string} publicKey Key of the approver
+ * @param {number} proposalId ID of proposal
+ * @returns {Promise}
+ */
+ public approve (publicKey: string, proposalId: number): Promise;
+
+ /**
+ * @description Broadcast proposal in case of enough approvals
+ *
+ * @param {number} proposalId ID of proposal
+ * @returns {Promise} Transaction receipt
+ */
+ public processProposal (proposalId: number): Promise;
+}
diff --git a/types/contract/index.d.ts b/types/contract/index.d.ts
new file mode 100644
index 0000000..3cee94d
--- /dev/null
+++ b/types/contract/index.d.ts
@@ -0,0 +1,164 @@
+import { FromQuery } from '../table-reader';
+import { BaseProvider } from '../provider';
+import { Account, BaseAccount } from '../account';
+import { TransactionResult, RawTransaction, SignedTransaction } from '../miscellaneous';
+
+declare abstract class EventClass {
+ public events: Array;
+ public eventsHooks: Map void>;
+
+ constructor (events: Array);
+
+ public on (eventName: string, callback: (...params: any[]) => void): void;
+ public emit (eventName: string, ...params: any[]): void;
+}
+
+declare class ContractInitializator extends EventClass {
+
+ constructor (provider: BaseProvider);
+
+ /**
+ * @description Instantiate a contract by retrieving the ABI from the chain
+ *
+ * @param {string} contractName Contract name of the contract one wants to instantiate
+ * @param {Account} [contractExecutorAccount] Account responsible for signing and broadcasting transactions
+ * @returns {Promise} Instantiated contract
+ */
+ public at (contractName: string, contractExecutorAccount?: Account): Promise;
+
+ /**
+ * @description Instantiate a contract by providing the ABI
+ *
+ * @param {*} abi Contract ABI
+ * @param {string} contractName Contract name of the contract one wants to instantiate
+ * @param {Account} [contractExecutorAccount] Account responsible for signing and broadcasting transactions
+ * @returns {Contract} Instantiated contract
+ */
+ public fromFile (abi: any, contractName: string, contractExecutorAccount?: Account): Contract
+}
+
+
+interface DeployOptions {
+ inline: boolean;
+}
+
+export class ContractFactory extends ContractInitializator {
+
+ constructor (provider: BaseProvider);
+
+ /* Overwrite EventClass */
+ public on (eventName: 'init', callback: (contract: Contract) => void): void;
+ public on (eventName: 'deploy', callback: (contract: Contract, deployTx: [TransactionResult, TransactionResult]) => void): void;
+
+ /* Own functions */
+
+ /**
+ * @description Deploy a new contract on a random generated account from ABI and WASM files
+ *
+ * @param {string} wasmPath Path to the contract WASM file
+ * @param {string} abiPath Path to the contract ABI file
+ * @param {DeployOptions} [options]
+ * @returns {Promise} Deployed contract
+ */
+ public deploy (wasmPath: string, abiPath: string, options?: DeployOptions): Promise;
+
+ /**
+ * @description Deploy a new contract on a random generated account from loaded ABI and WASM
+ *
+ * @param {string} wasm Contract WASM
+ * @param {*} abi Contract ABI
+ * @param {DeployOptions} [options]
+ * @returns {Promise} Deployed contract
+ */
+ public deployRaw (wasm: string, abi: any, options?: DeployOptions): Promise;
+
+ /**
+ * @description Deploy a new contract on the provided account from ABI and WASM files
+ *
+ * @param {string} wasmPath Path to the contract WASM file
+ * @param {string} abiPath Path to the contract ABI file
+ * @param {Account} contractAccount Account the contract will be deployed on
+ * @param {DeployOptions} [options]
+ * @returns {Promise} Deployed contract
+ */
+ public deployOnAccount (wasmPath: string, abiPath: string, contractAccount: Account, options?: DeployOptions): Promise;
+
+ /**
+ * @description Deploy a new contract on the provided account from loaded ABI and WASM
+ *
+ * @param {string} wasm Contract WASM
+ * @param {*} abi Contract ABI
+ * @param {Account} contractAccount Account the contract will be deployed on
+ * @param {DeployOptions} [options]
+ * @returns {Promise} Deployed contract
+ */
+ public deployRawOnAccount (wasm: string, abi: any, contractAccount: Account, options?: DeployOptions): Promise;
+}
+
+interface ContractFunctionOptions {
+ from?: BaseAccount;
+ unique?: boolean;
+ tokens?: string
+}
+
+export interface ContractFunction extends EventClass {
+
+ (params: any[], options?: ContractFunctionOptions): Promise;
+
+ /* Overwrite EventClass */
+ on (eventName: 'processed', callback: (txResult: TransactionResult, ...fnParams: any[]) => void): void;
+
+ /* Own functions */
+
+ /**
+ * @description Construct raw transaction for an action
+ *
+ * @param {any[]} params Action arguments
+ * @param {ContractFunctionOptions} [options]
+ * @returns {Promise} Raw transaction
+ */
+ getRawTransaction (params: any[], options?: ContractFunctionOptions): Promise;
+
+ /**
+ * @description Sign action and return a ready-to-broadcast transaction
+ *
+ * @param {any[]} params Action arguments
+ * @param {ContractFunctionOptions} [options]
+ * @returns {Promise} Ready to broadcast transaction
+ */
+ sign (params: any[], options?: ContractFunctionOptions): Promise;
+}
+
+interface ContractFunctions {
+ [prop: string]: ContractFunction;
+}
+
+interface ContractTables {
+ [prop: string]: FromQuery;
+}
+
+export class Contract {
+ public abi: any;
+ public name: string;
+ public executor: BaseAccount;
+ public provider: BaseProvider;
+
+ public tables: ContractTables;
+ public actions: ContractFunctions;
+
+ constructor (provider: BaseProvider, abi: any, contractName: string, contractExecutorAccount: Account);
+
+ /**
+ * @description Enable the contract to make inline actions
+ *
+ * @returns {Promise} void
+ */
+ public makeInline (): Promise;
+
+ /**
+ * @description Retrieve contract raw WASM
+ *
+ * @returns {Promise} Contract raw WASM
+ */
+ public getRawWASM (): Promise;
+}
diff --git a/types/index.d.ts b/types/index.d.ts
new file mode 100644
index 0000000..6d339da
--- /dev/null
+++ b/types/index.d.ts
@@ -0,0 +1,5 @@
+export * from './account';
+export * from './contract';
+export * from './provider';
+export * from './miscellaneous';
+export * from './utils';
diff --git a/types/miscellaneous/index.d.ts b/types/miscellaneous/index.d.ts
new file mode 100644
index 0000000..3ac9b0c
--- /dev/null
+++ b/types/miscellaneous/index.d.ts
@@ -0,0 +1,103 @@
+interface TxActionTrace {
+ action_ordinal: number;
+ creator_action_ordinal: number;
+ closest_unnotified_ancestor_action_ordinal: number;
+ receipt: TxReceipt;
+ receiver: string;
+ act: TxAction;
+ context_free: boolean;
+ elapsed: number;
+ console: string;
+ trx_id: string;
+ block_num: number;
+ block_time: string;
+ producer_block_id: string;
+ account_ram_deltas: Array;
+ except: string;
+ error_code: string;
+ inline_traces: TxActionTrace
+}
+
+interface TxReceipt {
+ status: string;
+ cpu_usage_us: number;
+ net_usage_words: number;
+}
+
+interface TxAction {
+ account: string;
+ name: string;
+ authorization: [
+ {
+ actor: string;
+ permission: string;
+ }
+ ];
+ data: string;
+}
+
+export interface RawTransaction {
+ expiration: string;
+ ref_block_num: number;
+ ref_block_prefix: number;
+ max_net_usage_words: number;
+ max_cpu_usage_ms: number;
+ delay_sec: number;
+ context_free_actions: Array;
+ actions: Array;
+ transaction_extensions: Array;
+}
+
+export interface SignedTransaction {
+ compression: string;
+ transaction: RawTransaction;
+ signatures: Array;
+}
+
+export interface BroadCastedTransaction {
+ transaction_id: string;
+ processed:
+ {
+ id: string;
+ block_num: number;
+ block_time: string;
+ producer_block_id: string;
+ receipt: TxReceipt;
+ elapsed: number;
+ net_usage: number;
+ scheduled: boolean;
+ action_traces: Array;
+ account_ram_delta: string;
+ except: string;
+ error_code: string;
+ }
+}
+
+export interface TransactionResult extends BroadCastedTransaction {
+ broadcast: boolean;
+ transaction: SignedTransaction;
+}
+
+interface TxAuthorityKey {
+ key: string;
+ weight: number;
+}
+
+interface AuthAccount {
+ permission: {
+ actor: string;
+ permission: string
+ };
+ weight: number;
+}
+
+export interface AuthorityDetails {
+ perm_name: string;
+ parent: string;
+ required_auth: {
+ threshold: number;
+ keys: Array;
+ accounts: Array;
+ waits: Array;
+ }
+}
\ No newline at end of file
diff --git a/types/provider/index.d.ts b/types/provider/index.d.ts
new file mode 100644
index 0000000..4bc7372
--- /dev/null
+++ b/types/provider/index.d.ts
@@ -0,0 +1,73 @@
+import { Account } from '../account';
+import { SelectQuery } from '../table-reader';
+
+export interface NetworkDetails {
+ url?: string;
+ chainId?: string;
+}
+
+interface NetworkData {
+ name: string;
+ url: string;
+ chainId: string;
+}
+
+export class BaseProvider {
+ public eos: any;
+ public network: NetworkData;
+ public defaultAccount: Account;
+
+ constructor (networkConfig: NetworkData);
+
+ /**
+ * @description Table query chain
+ *
+ * @param {string} table Contract table one wants to read data from
+ * @returns {SelectQuery} Select query chain
+ */
+ public select (table: string): SelectQuery;
+
+ /**
+ * @description Retrieve contract ABI from the chain
+ *
+ * @param {string} contractName Name of the contract
+ * @returns {Promise} Contract ABI
+ */
+ public getABI (contractName: string): Promise;
+
+ /**
+ * @description Retrieve contract WASM from the chain. Useful for deploying another contract directly
+ *
+ * @param {string} contractName Name of the contract
+ * @returns {Promise} Contract WASM
+ */
+ public getRawWASM (contractName: string): Promise;
+}
+
+declare class ProviderFactory {
+
+ private instance: Provider;
+ private __provider: BaseProvider;
+
+ constructor (network: string, config: NetworkDetails);
+
+ /**
+ * @description Reset provider to another one
+ *
+ * @param {BaseProvider} newProvider New provider the current one will be set to
+ */
+ public reset (newProvider: BaseProvider): void;
+
+ /**
+ * @description List of eoslime supported networks
+ *
+ * @returns {Array} Supported networks names
+ */
+ public availableNetworks (): Array;
+}
+
+export interface Provider extends BaseProvider, ProviderFactory {
+ new(network?: string, config?: NetworkDetails): BaseProvider;
+ new(config?: NetworkDetails): BaseProvider;
+}
+
diff --git a/types/table-reader/index.d.ts b/types/table-reader/index.d.ts
new file mode 100644
index 0000000..7cb5f71
--- /dev/null
+++ b/types/table-reader/index.d.ts
@@ -0,0 +1,52 @@
+export class SelectQuery {
+ from (contractName: string): FromQuery;
+}
+
+export class FromQuery {
+ equal (value: any): EqualQuery;
+ limit (limit: number): LimitQuery;
+ scope (accountName: string): ScopeQuery;
+ range (minValue: any, maxValue: any): RangeQuery;
+ index (index: number, keyType?: string): IndexQuery;
+
+ find (): Promise>;
+}
+
+export class ScopeQuery {
+ equal (value: any): EqualQuery;
+ limit (limit: number): LimitQuery;
+ range (minValue: any, maxValue: any): RangeQuery;
+ index (index: number, keyType?: string): IndexQuery;
+
+ find (): Promise>;
+}
+
+export class EqualQuery {
+ limit (limit: number): LimitQuery;
+ index (index: number, keyType: string): IndexQuery;
+
+ find (): Promise>;
+}
+
+export class RangeQuery {
+ limit (limit: number): LimitQuery;
+ index (index: number, keyType: string): IndexQuery;
+
+ find (): Promise>;
+}
+
+export class LimitQuery {
+ equal (value: any): EqualQuery;
+ range (minValue: any, maxValue: any): RangeQuery;
+ index (index: number, keyType: string): IndexQuery;
+
+ find (): Promise>;
+}
+
+export class IndexQuery {
+ equal (value: any): EqualQuery;
+ limit (limit: number): LimitQuery;
+ range (minValue: any, maxValue: any): RangeQuery;
+
+ find (): Promise>;
+}
\ No newline at end of file
diff --git a/types/utils/index.d.ts b/types/utils/index.d.ts
new file mode 100644
index 0000000..2bc90fc
--- /dev/null
+++ b/types/utils/index.d.ts
@@ -0,0 +1,43 @@
+interface KeysPair {
+ publicKey: string;
+ privateKey: string;
+}
+
+export interface utils {
+ /**
+ * @description Convert account name from uint64 to string
+ *
+ * @param {string} encodedName Uint64 format of account name
+ * @returns {string} String format of account name
+ */
+ toName (encodedName: string): string;
+
+ /**
+ * @description Generate a random account name
+ *
+ * @returns {Promise} Account name
+ */
+ randomName (): Promise;
+
+ /**
+ * @description Generate a random public/private keys pair
+ *
+ * @returns {Promise} Keys pair
+ */
+ generateKeys (): Promise;
+
+ /**
+ * @description Generate a random private key
+ *
+ * @returns {Promise} Random key
+ */
+ randomPrivateKey (): Promise;
+
+ /**
+ * @description Construct an account name from a private key. The name is constructed in a custom way, it is not related to the private key in any manner
+ *
+ * @param {string} privateKey Private key
+ * @returns {Promise} Account name
+ */
+ nameFromPrivateKey (privateKey: string): Promise;
+}