Skip to content

Commit

Permalink
[cli tools] bulk of implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
janedegtiareva committed Feb 27, 2019
1 parent 6c4cb9c commit ad569fa
Show file tree
Hide file tree
Showing 4 changed files with 209 additions and 23 deletions.
72 changes: 72 additions & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
const gulp = require("gulp");
const { SimpleKeyStoreSigner, InMemoryKeyStore, KeyPair, LocalNodeConnection, NearClient, Near } = require('nearlib');
const neardev = require('nearlib/dev');
const UnencryptedFileSystemKeyStore = require('./unencrypted_file_system_keystore');
const fs = require('fs');

gulp.task("build:model", function (done) {
const asc = require("assemblyscript/bin/asc");
Expand Down Expand Up @@ -34,3 +38,71 @@ gulp.task('copyfiles', function(done) {
gulp.task('build', gulp.series('copyfiles', 'build:all', function(done) {
done();
}));

// Only works for dev environments
gulp.task('createDevAccount', async function(argv) {
const keyPair = await KeyPair.fromRandomSeed();
const accountId = argv.account_id;
const nodeUrl = argv.node_url;

const options = {
nodeUrl,
accountId,
useDevAccount: true,
deps: {
keyStore: new InMemoryKeyStore(),
storage: {},
}
};

const near = await neardev.connect(options);
await neardev.createAccountWithLocalNodeConnection(accountId, keyPair.getPublicKey());
const keyStore = new UnencryptedFileSystemKeyStore();
keyStore.setKey(accountId, keyPair);
});


async function deployContractAndWaitForTransaction(accountId, contractName, data, near) {
const deployContractResult = await near.deployContract(accountId, contractName, data);
const waitResult = await near.waitForTransactionResult(deployContractResult);
return waitResult;
}

gulp.task('deploy', async function(argv) {
const keyStore = new UnencryptedFileSystemKeyStore();
let accountId = argv.account_id;
if (!accountId) {
// see if we only have one account in keystore and just use that.
const accountIds = await keyStore.getAccountIds();
if (accountIds.length == 1) {
accountId = accountIds[0];
}
}
if (!accountId) {
throw 'Please provide account id and make sure you created an account using near create_account';
}
const nodeUrl = argv.node_url;
const options = {
nodeUrl,
accountId,
deps: {
keyStore,
storage: {},
}
};

const near = await neardev.connect(options);
const contractData = [...fs.readFileSync('./out/main.wasm')];

// Contract name
const contractName = argv.contract_name;
console.log(
"Starting deployment. Account id " + accountId + ", contract " + contractName + ", url " + nodeUrl);
const res = await deployContractAndWaitForTransaction(
accountId, contractName, contractData, near);
if (res.status == "Completed") {
console.log("Deployment succeeded.");
} else {
console.log("Deployment transaction did not succeed: ", res);
}
});
85 changes: 68 additions & 17 deletions near
Original file line number Diff line number Diff line change
@@ -1,27 +1,78 @@
#!/usr/bin/env node

const commandLineArgs = require('command-line-args');
const nearLib = require('nearlib');
const gulp = require('gulp');
const gulpfile = require('./gulpfile') // import the gulp file
const yargs = require('yargs');

require('yargs') // eslint-disable-line
.command('build', 'build your smart contract', (yargs) => {
const deploy = {
command: 'deploy',
desc: 'deploy your smart contract',
builder: (yargs) => yargs
.option('contract_name', {
desc: 'Contract name',
type: 'string',
required: true
})
.option('node_url', {
desc: 'Near node url',
type: 'string',
default: 'http://localhost:3030'
})
.option('account_id', {
desc: 'Your developer account id. If you have only one account, that one will be selected by default',
type: 'string',
})
,
handler: (argv) => {
if (gulp.task('deploy')) {
const result = gulp.task('deploy')(argv);
} else {
throw "Unexpected error: deploy task not found in gulpfile."
}
}
};

}, (argv) => {
if (argv.verbose) console.info(`build contract on :${argv.port}`)
const build = {
command: 'build',
desc: 'build your smart contract',
builder: (yargs) => yargs,
handler: (argv) => {
if (gulp.task('build')) {
const result = gulp.task('build')();
} else {
throw "Unexpected error: build task not found in gulpfile."
}
}
};

const createAccount = {
command: 'create_account',
desc: 'create a developer account',
builder: (yargs) => yargs
.option('node_url', {
desc: 'Near node url',
type: 'string',
default: 'http://localhost:3030'
})
.option('account_id', {
desc: 'Unique identifier for the new account',
type: 'string',
required: true
})
,
handler: (argv) => {
if (gulp.task('createDevAccount')) {
const result = gulp.task('createDevAccount')(argv);
} else {
throw "Unexpected error: createDevAccount task not found in gulpfile."
}
})
.command('deploy', 'deploy your smart contract', (yargs) => {
yargs
.positional('contract_name', {
describe: 'Name of the contract to deploy',
default: 'default'
})
}, (argv) => {
if (argv.verbose) console.info(`deploy contract`)
console.log('NOT IMPLEMENTED YET')
})
}
};

yargs // eslint-disable-line
.command(createAccount)
.command(build)
.command(deploy)
.demandCommand(1, 'Please enter a command')
.argv;

11 changes: 5 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "near-shell",
"version": "1.0.0",
"version": "0.0.1",
"description": "Command line utilities to interact with near blockchain",
"main": "index.js",
"scripts": {
Expand All @@ -10,20 +10,19 @@
},
"repository": {
"type": "git",
"url": "git+https://github.com/nearprotocol/near-cli.git"
"url": "git+https://github.com/nearprotocol/near-shell.git"
},
"author": "",
"license": "MIT",
"bugs": {
"url": "https://github.com/nearprotocol/near-cli/issues"
"url": "https://github.com/nearprotocol/near-shell/issues"
},
"homepage": "https://github.com/nearprotocol/near-cli#readme",
"homepage": "https://github.com/nearprotocol/near-shell#readme",
"devDependencies": {
"assemblyscript": "github:nearprotocol/assemblyscript",
"command-line-args": "^5.0.2",
"fs": "0.0.1-security",
"gulp": "^4.0.0",
"nearlib": "^0.3.1",
"nearlib": "file:../nearcore/nearlib",
"run-sequence": "^2.2.1",
"yargs": "^13.2.1"
},
Expand Down
64 changes: 64 additions & 0 deletions unencrypted_file_system_keystore.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
const fs = require('fs');
const keyDir = './neardev';
const keyFile = 'devkey.json';
const KeyPair = require('nearlib/signing/key_pair')

/**
* Unencrypted file system key store.
*/
class UnencryptedFileSystemKeyStore {
constructor() {}

async setKey(accountId, keypair) {
if (!fs.existsSync(keyDir)){
fs.mkdirSync(keyDir);
}
const keyFileContent = {
public_key: keypair.getPublicKey(),
secret_key: keypair.getSecretKey(),
account_id: accountId
};
const writeResult = await fs.writeFileSync(this.getKeyFilePath(), JSON.stringify(keyFileContent));
}

async getKey(accountId) {
// Find keys/account id
if (!fs.existsSync(this.getKeyFilePath())) {
throw 'Key lookup failed. Please make sure you set up an account.';
}
const rawKey = JSON.parse(fs.readFileSync(this.getKeyFilePath()));
if (!rawKey.public_key || !rawKey.secret_key || !rawKey.account_id) {
throw 'Deployment failed. neardev/devkey.json format problem. Please make sure file contains public_key, secret_key, and account_id".';
}
if (rawKey.account_id != accountId) {
throw 'Deployment failed. Keystore contains data for wrong account.';
}
const result = new KeyPair(rawKey.public_key, rawKey.secret_key);
return result;
}

/**
* Returns all account ids.
*/
async getAccountIds() {
if (!fs.existsSync(this.getKeyFilePath())) {
return [];
}
const rawKey = JSON.parse(fs.readFileSync(this.getKeyFilePath()));
if (!rawKey.public_key || !rawKey.secret_key || !rawKey.account_id) {
return [];
}
return [rawKey.account_id];
}

async clear() {
this.keys = {};
}

// TODO: make this configurable
getKeyFilePath() {
return keyDir + "/" + keyFile;
}
}

module.exports = UnencryptedFileSystemKeyStore;

0 comments on commit ad569fa

Please sign in to comment.