Skip to content
This repository has been archived by the owner on Oct 4, 2024. It is now read-only.

Adding support for EVM view and function calls #517

Merged
merged 13 commits into from
Nov 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ For a list of up-to-date commands, run `near` in your terminal with no arguments
near delete-key [accessKey] # delete access key
```

#### For smart contract:
#### For native smart contracts:
```bash
near deploy [accountId] [wasmFile] [initFunction] [initArgs] [initGas] [initDeposit] # deploy your smart contract
near dev-deploy [wasmFile] # deploy your smart contract using temporary account (TestNet only)
Expand All @@ -47,6 +47,12 @@ For a list of up-to-date commands, run `near` in your terminal with no arguments
near clean # clean the smart contract build locally (remove ./out )
```

#### For NEAR EVM smart contracts:
```bash
near evm-view <evmAccount> <contractName> <methodName> [args] # make an EVM smart contract call which can view state
near evm-call <evmAccount> <contractName> <methodName> [args] # schedule an EVM smart contract call which can modify state
```

#### For transactions:
```bash
near tx-status <hash> # lookup transaction status by hash
Expand Down
3 changes: 3 additions & 0 deletions bin/near-cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ yargs // eslint-disable-line
.middleware(require('../middleware/print-options'))
.middleware(require('../middleware/key-store'))
.middleware(require('../middleware/ledger'))
.middleware(require('../middleware/abi'))
.middleware(require('../middleware/seed-phrase'))
.command(require('../commands/create-account').createAccountCommand)
.command(require('../commands/create-account').createAccountCommandDeprecated)
Expand All @@ -244,6 +245,8 @@ yargs // eslint-disable-line
.command(require('../commands/delete-key'))
.command(require('../commands/validators'))
.command(require('../commands/proposals'))
.command(require('../commands/evm-call'))
.command(require('../commands/evm-view'))
.config(config)
.alias({
'accountId': ['account_id'],
Expand Down
56 changes: 56 additions & 0 deletions commands/evm-call.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
const exitOnError = require('../utils/exit-on-error');
const web3 = require('web3');
const { NearProvider, utils } = require('near-web3-provider');
const assert = require('assert');

module.exports = {
command: 'evm-call <evmAccount> <contractName> <methodName> [args]',
mikedotexe marked this conversation as resolved.
Show resolved Hide resolved
desc: 'Schedule call inside EVM machine',
builder: (yargs) => yargs
.option('gas', {
desc: 'Max amount of NEAR gas this call can use',
type: 'string',
default: '100000000000000'
})
.option('amount', {
desc: 'Number of tokens to attach',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In NEAR or yoctoNEAR

type: 'string',
default: '0'
})
.option('args', {
desc: 'Arguments to the contract call, in JSON format (e.g. \'[1, "str"]\') based on contract ABI',
type: 'string',
default: null
})
.option('accountId', {
required: true,
desc: 'Unique identifier for the account that will be used to sign this call',
type: 'string',
})
.option('abi', {
required: true,
desc: 'Path to ABI for given contract',
type: 'string',
}),
handler: exitOnError(scheduleEVMFunctionCall)
};

async function scheduleEVMFunctionCall(options) {
const args = JSON.parse(options.args || '[]');
console.log(`Scheduling a call inside ${options.evmAccount} EVM:`);
console.log(`${options.contractName}.${options.methodName}()` +
(options.amount && options.amount !== '0' ? ` with attached ${options.amount} NEAR` : ''));
console.log(' with args', args);
const web = new web3();
web.setProvider(new NearProvider({
nodeUrl: options.nodeUrl,
// TODO: make sure near-api-js has the same version between near-web3-provider.
// keyStore: options.keyStore,
masterAccountId: options.accountId,
networkId: options.networkId,
evmAccountId: options.evmAccount,
}));
const contract = new web.eth.Contract(options.abi, options.contractName);
assert(options.methodName in contract.methods, `${options.methodName} is not present in ABI`);
await contract.methods[options.methodName](...args).send({ from: utils.nearAccountToEvmAddress(options.accountId) });
}
42 changes: 42 additions & 0 deletions commands/evm-view.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const exitOnError = require('../utils/exit-on-error');
const web3 = require('web3');
const { NearProvider, utils } = require('near-web3-provider');
const assert = require('assert');

module.exports = {
command: 'evm-view <evmAccount> <contractName> <methodName> [args]',
desc: 'View call inside EVM machine',
builder: (yargs) => yargs
.option('args', {
desc: 'Arguments to the contract call, in JSON format (e.g. \'[1, "str"]\') based on contract ABI',
type: 'string',
default: null
})
.option('accountId', {
required: true,
desc: 'Unique identifier for the account that will be used to sign this call',
type: 'string',
})
.option('abi', {
desc: 'Path to ABI for given contract',
type: 'string',
}),
handler: exitOnError(scheduleEVMFunctionView)
};

async function scheduleEVMFunctionView(options) {
const web = new web3();
web.setProvider(new NearProvider({
nodeUrl: options.nodeUrl,
// TODO: make sure near-api-js has the same version between near-web3-provider.
// keyStore: options.keyStore,
masterAccountId: options.accountId,
networkId: options.networkId,
evmAccountId: options.evmAccount,
}));
const contract = new web.eth.Contract(options.abi, options.contractName);
const args = JSON.parse(options.args || '[]');
assert(options.methodName in contract.methods, `${options.methodName} is not present in ABI`);
const result = await contract.methods[options.methodName](...args).call({ from: utils.nearAccountToEvmAddress(options.accountId) });
console.log(result);
}
11 changes: 11 additions & 0 deletions middleware/abi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const fs = require('fs');

async function loadAbi(abiPath) {
return JSON.parse(fs.readFileSync(abiPath)).abi;
}

module.exports = async function parseAbi(options) {
if (options.abi) {
options.abi = await loadAbi(options.abi);
}
};
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
"jest-environment-node": "^26.0.0",
"mixpanel": "^0.13.0",
"ncp": "^2.0.0",
"near-api-js": "^0.31.0",
"near-web3-provider": "^1.0.0",
"near-api-js": "^0.34.0",
"near-seed-phrase": "^0.1.0",
"open": "^7.0.1",
"rimraf": "^3.0.0",
Expand All @@ -51,6 +52,7 @@
"update-notifier": "^5.0.0",
"uuid": "^8.0.0",
"v8flags": "^3.1.3",
"web3": "^1.2.11",
"yargs": "^16.0.3"
},
"optionalDependencies": {
Expand Down
Loading