diff --git a/package-lock.json b/package-lock.json index b09d041..669cb24 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1242,6 +1242,12 @@ "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=" }, + "prettier": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.17.0.tgz", + "integrity": "sha512-sXe5lSt2WQlCbydGETgfm1YBShgOX4HxQkFPvbxkcwgDvGDeqVau8h+12+lmSVlP3rHPz0oavfddSZg/q+Szjw==", + "dev": true + }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", diff --git a/package.json b/package.json index c8f09d2..8c8a9f2 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "@types/text-encoding": "0.0.35", "eosjs": "20.0.0", "eosjs-ecc": "4.0.4", + "prettier": "1.17.0", "ts-node": "8.1.0", "typedoc": "0.14.2", "typescript": "3.4.5" diff --git a/src/accounts/account.ts b/src/accounts/account.ts index 5ddcb53..ce2bcb9 100644 --- a/src/accounts/account.ts +++ b/src/accounts/account.ts @@ -4,7 +4,6 @@ import { Contract } from '../contracts'; import { AccountManager } from './accountManager'; export class Account { - /** EOSIO account name */ public name: string; /** EOSIO account public key */ @@ -18,7 +17,17 @@ export class Account { // Store references this.name = name; this.privateKey = privateKey; - this.publicKey = publicKey || ecc.privateToPublic(privateKey); + + this.publicKey = ecc.privateToPublic(privateKey); + + if (publicKey && publicKey !== this.publicKey) { + throw new Error( + `Supplied public key does not match private key. Supplied key: ${publicKey} Expected key: ${ecc.privateToPublic( + privateKey + )} This is usually caused by using the legacy key format vs the new style key format.` + ); + } + // Set default permissions this.permissions = { active: { diff --git a/src/accounts/accountManager.ts b/src/accounts/accountManager.ts index 40d29f0..28f4e5f 100644 --- a/src/accounts/accountManager.ts +++ b/src/accounts/accountManager.ts @@ -12,7 +12,6 @@ interface AccountCreationOptions { } export class AccountManager { - /** * Generates a new random account * @note Shorthand method for [[AccountManager.createAccounts]] @@ -136,7 +135,7 @@ export class AccountManager { // Execute the transaction return await EOSManager.transact({ actions }, eos); }; - + /** * Grants `eosio.code` permission to the specified account's `active` key * @note Should be moved to the `contracts/contract.ts` I think? @@ -148,19 +147,18 @@ export class AccountManager { static addCodePermission = async (account: Account) => { // We need to get their existing permissions, then add in a new eosio.code permission for this contract. const { permissions } = await EOSManager.rpc.get_account(account.name); - const { required_auth } = permissions.find((permission: any) => permission.perm_name == 'active'); + const { required_auth } = permissions.find( + (permission: any) => permission.perm_name == 'active' + ); // Check if `eosio.code` has already been set const existingPermission = required_auth.accounts.find( (account: any) => - account.permission.actor === account.name && - account.permission.permission === 'eosio.code' + account.permission.actor === account.name && account.permission.permission === 'eosio.code' ); // Throw if permission exists if (existingPermission) { throw new Error( - `Code permission is already present on account ${account.name} for contract ${ - account.name - }` + `Code permission is already present on account ${account.name} for contract ${account.name}` ); } // Append the `eosio.code` permission to existing diff --git a/src/cli/lamington-build.ts b/src/cli/lamington-build.ts index ad4738d..e6a09ad 100644 --- a/src/cli/lamington-build.ts +++ b/src/cli/lamington-build.ts @@ -12,13 +12,13 @@ const run = async () => { // Initialize configuration await ConfigManager.initWithDefaults(); // Stop container if running - if (!ConfigManager.keepAlive && await eosIsReady()) { + if (!ConfigManager.keepAlive && (await eosIsReady())) { await stopContainer(); } // This ensures we have our .gitignore inside the .lamington directory await GitIgnoreManager.createIfMissing(); // Start the EOSIO container image - if (!await eosIsReady()) { + if (!(await eosIsReady())) { await startEos(); } // Build all smart contracts diff --git a/src/cli/lamington-test.ts b/src/cli/lamington-test.ts index 11eb1d7..662a8a8 100644 --- a/src/cli/lamington-test.ts +++ b/src/cli/lamington-test.ts @@ -18,7 +18,7 @@ const run = async () => { // Ensures we have our .gitignore inside the .lamington directory await GitIgnoreManager.createIfMissing(); // Start an EOSIO instance if not running - if (!await eosIsReady()) { + if (!(await eosIsReady())) { await startEos(); } // Start compiling smart contracts @@ -31,13 +31,13 @@ const run = async () => { } }; -run().catch(async (error) => { +run().catch(async error => { if (await eosIsReady()) { stopContainer().then(() => { //console.log(error) process.exit(1); }); } else { - console.log(error) + console.log(error); } }); diff --git a/src/cli/logIndicator.ts b/src/cli/logIndicator.ts index 4308938..430fc97 100644 --- a/src/cli/logIndicator.ts +++ b/src/cli/logIndicator.ts @@ -2,25 +2,25 @@ import ora, { Ora } from 'ora'; import * as colors from 'colors'; /** Holds spinner instances */ -const cache:{ spinner?:Ora } = {}; +const cache: { spinner?: Ora } = {}; /** * Creates a new spinner instance with the specified message * @author Mitch Pierias * @param text Output display message */ -export const create = (text:string) => { - // Cleanup existing spinner - if (cache.spinner) { - cache.spinner.succeed(); - delete cache.spinner; - } - // Create and cache spinner - cache.spinner = ora({ - text:colors.white(text), - color: 'magenta' - }).start(); -} +export const create = (text: string) => { + // Cleanup existing spinner + if (cache.spinner) { + cache.spinner.succeed(); + delete cache.spinner; + } + // Create and cache spinner + cache.spinner = ora({ + text: colors.white(text), + color: 'magenta', + }).start(); +}; /** * Terminates the current spinner with the specified output message @@ -28,24 +28,24 @@ export const create = (text:string) => { * @param message Output message * @param isError Renders output as error toggle */ -export const end = (message:string = '', isError:boolean = false) => { - // Check spinner reference - if (!cache.spinner) return; - // Handle output - if (isError) { - cache.spinner.fail(colors.grey(message)) - } else { - cache.spinner.succeed(colors.grey(message)) - } - // Clear spinner reference - delete cache.spinner; -} +export const end = (message: string = '', isError: boolean = false) => { + // Check spinner reference + if (!cache.spinner) return; + // Handle output + if (isError) { + cache.spinner.fail(colors.grey(message)); + } else { + cache.spinner.succeed(colors.grey(message)); + } + // Clear spinner reference + delete cache.spinner; +}; /** * Terminates the current spinner as an error with output message * @author Mitch Pierias * @param message Spinner message. */ -export const fail = (message:string) => { - end(message, true); -} \ No newline at end of file +export const fail = (message: string) => { + end(message, true); +}; diff --git a/src/cli/utils.ts b/src/cli/utils.ts index 02e848b..f3cddf2 100644 --- a/src/cli/utils.ts +++ b/src/cli/utils.ts @@ -220,7 +220,7 @@ export const startEos = async () => { \n\ ==================================================== \n' ); - spinner.end("Started EOS docker container") + spinner.end('Started EOS docker container'); } catch (error) { spinner.fail('Failed to start the EOS container'); console.log(` --> ${error}`); @@ -354,20 +354,22 @@ export const compileContract = async (contractPath: string) => { const basename = path.basename(contractPath, '.cpp'); const fullPath = path.join(ConfigManager.outDir, path.dirname(contractPath)); // Pull docker images - await docker.command( - // Arg 1 is filename, arg 2 is contract name. - `exec lamington /opt/eosio/bin/scripts/compile_contract.sh "/${path.join( - 'opt', - 'eosio', - 'bin', - 'project', - contractPath - )}" "${fullPath}" "${basename}"` - ).catch(err => { - spinner.fail("Failed to compile"); - console.log(` --> ${err}`); - throw err; - }); + await docker + .command( + // Arg 1 is filename, arg 2 is contract name. + `exec lamington /opt/eosio/bin/scripts/compile_contract.sh "/${path.join( + 'opt', + 'eosio', + 'bin', + 'project', + contractPath + )}" "${fullPath}" "${basename}"` + ) + .catch(err => { + spinner.fail('Failed to compile'); + console.log(` --> ${err}`); + throw err; + }); // Notify build task completed spinner.end(`Compiled contract`); }; diff --git a/src/configManager.ts b/src/configManager.ts index ecf8dbd..bd53c83 100644 --- a/src/configManager.ts +++ b/src/configManager.ts @@ -27,8 +27,8 @@ export interface LamingtonConfig { cdt: string; eos: string; keepAlive?: boolean; - outDir?: string, - exclude?: string | RegExp | Array + outDir?: string; + exclude?: string | RegExp | Array; } /** @@ -36,7 +36,6 @@ export interface LamingtonConfig { * @author Kevin Brown */ export class ConfigManager { - /** @hidden EOSIO and EOSIO.CDT configuration settings */ private static config: LamingtonConfig; @@ -51,7 +50,9 @@ export class ConfigManager { */ private static async getAssetURL(organization: string, repository: string, filter: string) { // Get the projects latest GitHub repository release - const result = await axios.get(`https://api.github.com/repos/${organization}/${repository}/releases/latest`); + const result = await axios.get( + `https://api.github.com/repos/${organization}/${repository}/releases/latest` + ); // Handle failed GitHub request if (!result.data || !result.data.assets || !Array.isArray(result.data.assets)) { console.error(result); @@ -62,9 +63,10 @@ export class ConfigManager { asset.browser_download_url.includes(filter) ); // Handle no assets found - if (!asset) throw new Error ( - `Could not locate asset with ${filter} in the download URL in the ${organization}/${repository} repository` - ); + if (!asset) + throw new Error( + `Could not locate asset with ${filter} in the download URL in the ${organization}/${repository} repository` + ); // Return captured download url return asset.browser_download_url as string; } @@ -78,11 +80,11 @@ export class ConfigManager { public static async initWithDefaults() { // Load existing configuration const userConfig = { - outDir:CACHE_DIRECTORY, - keepAlive:false, - exclude:[], - ...await ConfigManager.readConfigFromProject() - } + outDir: CACHE_DIRECTORY, + keepAlive: false, + exclude: [], + ...(await ConfigManager.readConfigFromProject()), + }; // Check if configuration exists if (!(await ConfigManager.configExists())) { // Create the config directory @@ -90,7 +92,7 @@ export class ConfigManager { // Fetch the latest repository configuration const defaultConfig: LamingtonConfig = { cdt: await ConfigManager.getAssetURL('EOSIO', 'eosio.cdt', 'amd64.deb'), - eos: await ConfigManager.getAssetURL('EOSIO', 'eos', 'ubuntu-18.04') + eos: await ConfigManager.getAssetURL('EOSIO', 'eos', 'ubuntu-18.04'), }; // Freeze repository image await writeFile(CONFIG_FILE_PATH, JSON.stringify(defaultConfig, null, 4), ENCODING); @@ -98,10 +100,18 @@ export class ConfigManager { // Load cached config const existingConfig = JSON.parse(await readFile(CONFIG_FILE_PATH, ENCODING)); // Save cached configuration - await writeFile(CONFIG_FILE_PATH, JSON.stringify({ - ...existingConfig, - ...userConfig - }, null, 4), ENCODING); + await writeFile( + CONFIG_FILE_PATH, + JSON.stringify( + { + ...existingConfig, + ...userConfig, + }, + null, + 4 + ), + ENCODING + ); // Load existing configuration await ConfigManager.loadConfigFromDisk(); } @@ -134,7 +144,7 @@ export class ConfigManager { private static async readConfigFromProject() { return (await exists(CONFIGURATION_FILE_NAME)) ? JSON.parse(await readFile(CONFIGURATION_FILE_NAME, ENCODING)) - : {} + : {}; } /** diff --git a/src/contracts/contractDeployer.ts b/src/contracts/contractDeployer.ts index 22db6fe..1ea80e9 100644 --- a/src/contracts/contractDeployer.ts +++ b/src/contracts/contractDeployer.ts @@ -15,10 +15,9 @@ import { ConfigManager } from '../configManager'; * Provides a set of methods to manage contract deployment */ export class ContractDeployer { - /** * Deploys contract files to a specified account - * + * * ```typescript * // Create a new account * const account = await AccountManager.createAccount(); @@ -30,7 +29,10 @@ export class ContractDeployer { * @param account Account to apply contract code * @returns Deployed contract instance */ - public static async deployToAccount(contractIdentifier: string, account: Account) { + public static async deployToAccount( + contractIdentifier: string, + account: Account + ) { // Initialize the serialization buffer const buffer = new Serialize.SerialBuffer({ textEncoder: EOSManager.api.textEncoder, @@ -87,12 +89,12 @@ export class ContractDeployer { /** * Deploys contract files to a randomly generated account - * + * * ```typescript * // Deploy the contract with identifier * ContractDeployer.deploy('mycontract'); * ``` - * + * * @author Kevin Brown * @param contractIdentifier Contract identifier, typically the contract filename minus the extension * @returns Deployed contract instance @@ -106,19 +108,22 @@ export class ContractDeployer { /** * Deploys contract files to a specified account name - * + * * ```typescript * // Deploy the `mycontract` contract to the account with name `mycontractname` * ContractDeployer.deployToAccount('mycontract', 'mycontractname'); * ``` - * + * * @note Generating a random private key is not safe * @author Mitch Pierias * @param contractIdentifier Contract identifier, typically the contract filename minus the extension * @param accountName Account name * @returns Deployed contract instance */ - public static async deployWithName(contractIdentifier: string, accountName: string) { + public static async deployWithName( + contractIdentifier: string, + accountName: string + ) { // Generate a random private key const privateKey = await ecc.unsafeRandomKey(); // Initialize account with name diff --git a/src/contracts/typeGenerator.test.ts b/src/contracts/typeGenerator.test.ts index 736e1f2..796a93e 100644 --- a/src/contracts/typeGenerator.test.ts +++ b/src/contracts/typeGenerator.test.ts @@ -1,63 +1,92 @@ import { assert } from 'chai'; -import { - mapParameterType -} from './typeGenerator'; +import { mapParameterType } from './typeGenerator'; /** * Javascript only supports number, so CPP integer types need to be mapped accordingly */ const numberTypes = [ - 'int8','int16','int32','int64','int128','int256', - 'uint8','uint16','uint32','uint64','uint128','uint256', - 'uint8_t','uint16_t','uint32_t','uint64_t','uint128_t','uint256_t' + 'int8', + 'int16', + 'int32', + 'int64', + 'int128', + 'int256', + 'uint8', + 'uint16', + 'uint32', + 'uint64', + 'uint128', + 'uint256', + 'uint8_t', + 'uint16_t', + 'uint32_t', + 'uint64_t', + 'uint128_t', + 'uint256_t', ]; /** * Name types are typically a string or uint64_t and typically represent an identity on the EOS blockchain */ -const stringNumberTypes = ['name','action_name','scope_name','account_name','permission_name','table_name']; - -describe("type generator", () => { - - context('map parameter types', () => { - - it(`should map 'string' to 'string'`, () => { - assert.equal(mapParameterType('string'), 'string', `'string' types should map to 'string'`) - }); - - it(`should map 'bool' to 'boolean'`, () => { - assert.equal(mapParameterType('bool'), 'boolean'); - }); - - context('eos types', () => { - - it(`should map name types to 'string|number'`, () => { - stringNumberTypes.map(type => - assert.equal(mapParameterType(type), 'string|number', `'${type}' type should map to 'string' or 'number'`)) - }); - - it(`should map 'checksum' to 'string'`, () => { - assert.equal(mapParameterType('checksum'), 'string', `'checksum' type should map to 'string'`) - }); - }); - - context('big numbers', () => { - numberTypes.forEach(type => { - it(`should map '${type}' to 'number'`, () => { - assert.equal(mapParameterType(type), 'number', `Integer type '${type}' should map to 'number'`); - }); - }); - }); - - context('complex types', () => { - - it(`should handle array types`, () => { - assert.equal(mapParameterType('bool[]'), 'Array'); - }); - - xit(`should handle vector types`, () => { - assert.equal(mapParameterType('vector'), 'Array'); - }); - }); - }); -}); \ No newline at end of file +const stringNumberTypes = [ + 'name', + 'action_name', + 'scope_name', + 'account_name', + 'permission_name', + 'table_name', +]; + +describe('type generator', () => { + context('map parameter types', () => { + it(`should map 'string' to 'string'`, () => { + assert.equal(mapParameterType('string'), 'string', `'string' types should map to 'string'`); + }); + + it(`should map 'bool' to 'boolean'`, () => { + assert.equal(mapParameterType('bool'), 'boolean'); + }); + + context('eos types', () => { + it(`should map name types to 'string|number'`, () => { + stringNumberTypes.map(type => + assert.equal( + mapParameterType(type), + 'string|number', + `'${type}' type should map to 'string' or 'number'` + ) + ); + }); + + it(`should map 'checksum' to 'string'`, () => { + assert.equal( + mapParameterType('checksum'), + 'string', + `'checksum' type should map to 'string'` + ); + }); + }); + + context('big numbers', () => { + numberTypes.forEach(type => { + it(`should map '${type}' to 'number'`, () => { + assert.equal( + mapParameterType(type), + 'number', + `Integer type '${type}' should map to 'number'` + ); + }); + }); + }); + + context('complex types', () => { + it(`should handle array types`, () => { + assert.equal(mapParameterType('bool[]'), 'Array'); + }); + + xit(`should handle vector types`, () => { + assert.equal(mapParameterType('vector'), 'Array'); + }); + }); + }); +}); diff --git a/src/contracts/typeMap.ts b/src/contracts/typeMap.ts index 1caa4cb..aff792d 100644 --- a/src/contracts/typeMap.ts +++ b/src/contracts/typeMap.ts @@ -5,35 +5,35 @@ * // JSON object type map? */ -const types: { [key:string]:string } = { - 'string':'string', - 'bool':'boolean', - 'name':'string|number', - 'action_name':'string|number', - 'scope_name':'string|number', - 'account_name':'string|number', - 'permission_name':'string|number', - 'table_name':'string|number', - 'checksum':'string', - 'checksum256':'string', - 'int8':'number', - 'int16':'number', - 'int32':'number', - 'int64':'number', - 'int128':'number', - 'int256':'number', - 'uint8':'number', - 'uint16':'number', - 'uint32':'number', - 'uint64':'number', - 'uint128':'number', - 'uint256':'number', - 'uint8_t':'number', - 'uint16_t':'number', - 'uint32_t':'number', - 'uint64_t':'number', - 'uint128_t':'number', - 'uint256_t':'number' -} +const types: { [key: string]: string } = { + string: 'string', + bool: 'boolean', + name: 'string|number', + action_name: 'string|number', + scope_name: 'string|number', + account_name: 'string|number', + permission_name: 'string|number', + table_name: 'string|number', + checksum: 'string', + checksum256: 'string', + int8: 'number', + int16: 'number', + int32: 'number', + int64: 'number', + int128: 'number', + int256: 'number', + uint8: 'number', + uint16: 'number', + uint32: 'number', + uint64: 'number', + uint128: 'number', + uint256: 'number', + uint8_t: 'number', + uint16_t: 'number', + uint32_t: 'number', + uint64_t: 'number', + uint128_t: 'number', + uint256_t: 'number', +}; -export default types; \ No newline at end of file +export default types; diff --git a/src/eosManager.ts b/src/eosManager.ts index 2c848f4..b13d96b 100644 --- a/src/eosManager.ts +++ b/src/eosManager.ts @@ -8,7 +8,6 @@ import { Account } from './accounts'; * Manages client connection and communication with a local EOSIO node */ export class EOSManager { - /** Defaults to `eosio` administration account */ static adminAccount: Account; /** Development signature provider */ diff --git a/src/gitignoreManager.ts b/src/gitignoreManager.ts index 6f6c65b..68e080b 100644 --- a/src/gitignoreManager.ts +++ b/src/gitignoreManager.ts @@ -14,7 +14,6 @@ const encoding = 'utf8'; * Manages the `.gitignore` file and configuration */ export class GitIgnoreManager { - /** * Creates a `.gitignore` file when it doesn't exist * and configures the base ignore files diff --git a/src/utils.ts b/src/utils.ts index 0e6d11d..bea42f1 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -132,7 +132,9 @@ export const assertEOSError = async ( return; } else { // Fail if error not thrown by EOS - assert.fail(`Expected EOS error ${eosErrorName}, but got ${JSON.stringify(error, null, 4)} instead.`); + assert.fail( + `Expected EOS error ${eosErrorName}, but got ${JSON.stringify(error, null, 4)} instead.` + ); } } // Fail if no exception thrown