Giter VIP home page Giter VIP logo

mallet's Introduction

Mallet

Mallet, the minimum wallet, is a command line utility for deploying smart contracts and interacting with the Cardano IELE and KEVM testnets developed by IOHK. Mallet is written in Javascript and is based on the Node.js REPL, so it gives access to some handy functions as well as libraries such as Web3. Mallet can also be included as a library in your own JavaScript programs.

Installing

We have tested Mallet with Node.js version 10.16.3. The repository contains a proper .nvmrc file, so you can call nvm to use this particular version, provided it is already installed in your system.

$ git clone https://github.com/input-output-hk/mallet

$ cd mallet

$ cat .nvmrc
10.16.3

$ nvm use
Found '/tmp/mallet/.nvmrc' with version <10.16.3>
Now using node v10.16.3 (npm v6.14.5)

$ npm install

$ ./mallet -d . http://127.0.0.1:8546

The last step uses mallet to connect to a local Mantis client that accepts JSON-RPC calls on port 8546.

Older installation instructions

There are more detailed instructions for installing Node.js and Mallet in two places.

First, there are pages on installing Node.js and Mallet along with a tutorial.

Second, there is a video, Getting Started with Mallet.

Once you have Node.js installed, run:

$ npm install -g --engine-strict @iohk/mallet

This will download and install all the dependencies. The --engine-strict flag makes sure you have the required version of Node installed.

Running the command line interface

Type the following to see Mallet's usage help:

$ mallet --help

Running Mallet with proper arguments will open a Node.js REPL session with the Mallet commands available.

mallet iele

Everything has to be valid JavaScript:

mallet> 1 + 1
2
mallet> const x = _
undefined
mallet> x
2
mallet> x = 3
TypeError: Assignment to constant variable.
mallet> help
[Function: help]
mallet> help()
undefined

Caveats

  • Mallet is a command line tool to be run on Node.js. Although it may be possible to import Mallet into a browser, this has not been tested and is not officially supported.
  • Mallet takes advantage of BigInt arbitrary-precision integers, which were added to the V8 Javascript engine in May 2018.
  • To meet the requirements of an interactive shell environment, all Mallet's functions are synchronous.
  • Because of an issue with the embeddable Node.js REPL, an augmented version of rlp.js has been put in the lib folder

Mallet commands

Technically speaking, the ‘commands’ discussed here are actually functions and properties of a Mallet object. We refer to them as commands because that reflects how Mallet is used.

Getting help

When running Mallet, these commands may be useful.

help

Opens the README file you are reading in your default browser:

mallet> help()
undefined

listCommands

Lists the available commands:

mallet> listCommands()
[ 'currentAccount',
  'getBalance',
  'getNonce',
  'getReceipt',
  'help',
  'iele.contractCall',
  'iele.createContract',
  'iele.simpleTransfer',
  'importPrivateKey',
  'lastTransaction',
  'listAccounts',
  'listCommands',
  'newAccount',
  'requestFunds',
  'selectAccount',
  'sendTransaction',
  'web3' ]

Account management

These management commands operate on the local keystore and do not connect to a testnet.

newAccount

Creates a random key pair for a new managed account. The private key is stored in the datadir that is encrypted with the provided password. The command returns the corresponding account’s address.

mallet> newAccount()
Enter password:
Repeat password:
'0x8cc7c261b5dda47755ac9629ec32bba0ab4d1d32'

importPrivateKey

Imports a known private key as a managed account. The private key is stored in the datadir that is encrypted with the provided password. This import command returns the corresponding account’s address.

mallet> importPrivateKey()
Enter private key:
Enter password:
Repeat password:
'0xb0ff13c14e071b11ab678524ae28e6eb248de96a'

listAccounts

Lists the addresses of all managed accounts:

mallet> listAccounts()
[ '0xfc7e805d72ca57aff872cd010a4c9c5e8e8f22f2',
  '0xd7f3583b8805cfbe0979050f5a1b3587a8fee900',
  '0x724e5991252860ca530542719b25b39b1b437a1c',
  '0x60950641e7382a120c8825464391da3b84db2a86',
  '0xb0ff13c14e071b11ab678524ae28e6eb248de96a' ]

selectAccount

Selects an account for commands such as sendTransaction, getBalance, requestFunds:

mallet> selectAccount('0xfc7e805d72ca57aff872cd010a4c9c5e8e8f22f2')
'0xfc7e805d72ca57aff872cd010a4c9c5e8e8f22f2'

currentAccount

mallet> currentAccount()
'0xfc7e805d72ca57aff872cd010a4c9c5e8e8f22f2'

Interacting with the testnet

The following commands interact with nodes on Mantis, the Ethereum client, via the JSON remote procedure call (RPC) protocol (using the Web3 library).

getBalance

Show the balance of an account:

mallet> currentAccount()
'0xfc7e805d72ca57aff872cd010a4c9c5e8e8f22f2'
mallet> getBalance()
'98474579999999000'
mallet> getBalance('0x60950641e7382a120c8825464391da3b84db2a86')
'1000'

sendTransaction

Sends a transaction signed with the selected account’s key and returns the transaction hash. This command requires a password to decrypt the private key.

mallet> tx = {
    to: '0x60950641e7382a120c8825464391da3b84db2a86', // recipient's address, optional, new contract created if not provided
    gas: 100000,                                      // gas limit, mandatory
    gasPrice: 5000000000,                             // gasPrice, optional, default: 5 Gwei
    value: 1000000,                                   // optional, default: 0
    data: '0xcafebabe'                                // optional, default: empty
}
mallet> sendTransaction(tx)

getReceipt

Obtains a receipt of a transaction with a given hash. If a hash is not provided, the hash of the most recent transaction will be used.

mallet> sendTransaction(tx)
Enter password:
'0xc71a634009c85640996d64124cf35c3748009c45c952ed456ff5c239ccd5b1d3'
mallet> getReceipt()
null
mallet> getReceipt()
{ transactionHash:
   '0xc71a634009c85640996d64124cf35c3748009c45c952ed456ff5c239ccd5b1d3',
  transactionIndex: 0,
  blockNumber: 295346,
  blockHash:
   '0x007643f3198296fe6e1b3f125ec603aa758d813cb9ae2c7a2a06daf5357d30bc',
  cumulativeGasUsed: 21272,
  gasUsed: 21272,
  contractAddress: null,
  logs: [],
  statusCode: '0x00',
  status: true,
  returnData: [],
  rawReturnData: '0xc0' }
mallet> getReceipt('0x00039c02c1ca8cb2b25226f74887fc0afcf485797de65afbc105dab13497ba57')
{ transactionHash:
   '0x00039c02c1ca8cb2b25226f74887fc0afcf485797de65afbc105dab13497ba57',
  transactionIndex: 0,
  blockNumber: 295367,
  ...  

Note that the receipt may not be readily available, indicated with null value, because it takes time for a transaction to be forged.

If the receipt is for a IELE transaction (technically if it has statusCode field and the return data is RLP-decodable) then returnData field contains an array of integers, and raw undecoded data (hex string) is available in rawReturnData.

requestFunds

This command is different, in that it doesn't interact with the JSON RPC. Instead, it calls the testnet Faucet to obtain funds for a given account. It returns the transaction hash.

mallet> currentAccount()
'0xfc7e805d72ca57aff872cd010a4c9c5e8e8f22f2'
mallet> getBalance()
'972415314998966999'
mallet> requestFunds()
'0x1fc10c0ae70b09fb89fbc39d827c301d05ed0f196f3c54f3c52c4e683b89ff27'
mallet> getBalance()
'1002415314998966999'
mallet> requestFunds('0xd7f3583b8805cfbe0979050f5a1b3587a8fee900')
'0x03c485c980faf11c89d74c92a8d26efda7860edbb7de4a689220e33180a82e6c'
mallet> requestFunds('0xd7f3583b8805cfbe0979050f5a1b3587a8fee900')
Thrown: Faucet error: The user has sent too many requests in a given amount of time.

IELE commands

The following commands are variations of sendTransaction. They ensure that data is properly encoded for the IELE virtual machine. The argument transaction object is the same as in the case of sendTransaction, except for the data field.

iele.simpleTransfer

This transfers value between accounts Technically, this calls the deposit function of the IELE virtual machine on the recipient's account.

mallet> getBalance('0xd7f3583b8805cfbe0979050f5a1b3587a8fee900')
'0'
mallet> iele.simpleTransfer({to: '0xd7f3583b8805cfbe0979050f5a1b3587a8fee900', gas: 100000, value: 1000})
Enter password:
'0x1a0ef8a980851ade10f76bcb4b21cd2ad79e13d0b181419a7785ac620fbd2b82'
mallet> getBalance('0xd7f3583b8805cfbe0979050f5a1b3587a8fee900')
'1000'

iele.deployContract

Creates a contract with the bytecode provided in the code field, with optional constructor arguments as args – an array of integers.

mallet> let code = '00000091630369000F696E6372656D656E745828696E742969000667657458282967000000006600003400650002006180016101025511660001F60000660002620101F7016800010001660000340165000201610102541301001C6101025514660001F60000660002620102F7026800020000660000340065000200610101540A6013640001660001F6000103660002620101F701'
undefined
mallet> iele.deployContract({gas: 1000000, value: 0, code: code, args: []})
Enter password:
'0xb13e7783c86dda3f880b2d875201a1d4c4f7f0ae5b085e320dc32a7688ce394d'
mallet> getReceipt()
{ transactionHash:
   '0xb13e7783c86dda3f880b2d875201a1d4c4f7f0ae5b085e320dc32a7688ce394d',
  transactionIndex: 0,
  blockNumber: 36577,
  blockHash:
   '0x4d65719d5be6ce74ea02f8a59461bde8b831ae02ad72c127e9004b29a394f4c6',
  cumulativeGasUsed: 60730,
  gasUsed: 60730,
  contractAddress: '0x79c7f680aa944545744f611a1a9770426903cee9',
  logs: [],
  status: '0x00',
  returnData: '0xd59479c7f680aa944545744f611a1a9770426903cee9' }

iele.callContract

Calls function func of a contract at the to address. As with the previous command, there are optional arguments, args, as an array of integers.

mallet> iele.callContract({to: '0x79c7f680aa944545744f611a1a9770426903cee9', gas: 1000000, func: 'getX()', args: []})
Enter password:
'0x767f44039fbb67503a18688c38576fe0396dc55e18d057b7bef86d9a62fffb57'
mallet> getReceipt()
{ transactionHash:
   '0x767f44039fbb67503a18688c38576fe0396dc55e18d057b7bef86d9a62fffb57',
  transactionIndex: 0,
  blockNumber: 36663,
  blockHash:
   '0x20d1063fad4453e15f74962ba8d9bc009b4827ca3df6b7dd130a8723f8bb6ebf',
  cumulativeGasUsed: 21838,
  gasUsed: 21838,
  contractAddress: null,
  logs: [],
  statusCode: '0x00',
  status: true,
  returnData: [ 0n ],
  returnData: '0xc100' }
mallet> iele.callContract({to: '0x79c7f680aa944545744f611a1a9770426903cee9', gas: 1000000, func: 'incrementX(int)', args: [13]})
Enter password:
'0x9592150326c811ad71e55a007b589763c6dbd6365eae2cb66f6532ca780b0799'
mallet> getReceipt()
null
mallet> getReceipt()
{ transactionHash:
   '0x9592150326c811ad71e55a007b589763c6dbd6365eae2cb66f6532ca780b0799',
  transactionIndex: 0,
  blockNumber: 36670,
  blockHash:
   '0x7daf8a59044c66a1d320043287837b3d1f7d78e2b462e8dc218487cae6d80349',
  cumulativeGasUsed: 28263,
  gasUsed: 28263,
  contractAddress: null,
  logs: [],
  statusCode: '0x00',
  status: true,
  returnData: [],
  rawReturnData: '0xc0' }

iele.constantCall

This command is equivalent to web3.eth.call except with IELE-specific data encoding. It can be used for calling contract functions that do not change the state (Solidity's view functions). No account has to be selected to run this command. The TX argument is the same as for iele.callContract. The command returns decoded array of integers comprising the function return data.

mallet> iele.constantCall({to: '0x79c7f680aa944545744f611a1a9770426903cee9', gas: 1000000, func: 'getX()', args: []})
[ 0n ]

Note on IELE function names

Solidity functions compiled to IELE have a naming convention that includes function the original function name along with its argument types (this is to support function overloading). Examples

Solidity function header IELE function name
function getX() returns (int) getX()
`function incrementX(int i) `incrementX(int)
function somethingComplex(address a, bytes b, int[] i) returns (string, int) somethingComplex(address,bytes,int[])

Note on type encoding

IELE functions by design accept and return array of unbounded integers. To encode/decode different Solidity to/from integers use iele.enc/iele.dec. Both functions take a value to be converted and a Solidity type as a string. Consider a Solidity function like this:

function dummyFunc(address a, bytes b, int[] i) public pure returns (string, int) {
    return ("I'm a dummy", i[0]);
}

Here's how you can use iele.enc and iele.dec:

mallet> contractAddress = '0x9785367f32a97ec34090307368a4368f2ab4bc01'
'0x9785367f32a97ec34090307368a4368f2ab4bc01'
mallet> args = [iele.enc(contractAddress, 'address'), iele.enc('0xcafebabe', 'bytes'), iele.enc([42, -1], 'int[]')]
[ 865028352852446724060954038272434378925942291457n,
  4222355708056220710451082685618494097063946n,
  1455792646560079078679811948732730198604464062977n ]
mallet> result = iele.constantCall({to: contractAddress, gas: 1000000, func: 'dummyFunc(address,bytes,int[])', args: args})
[ 1631388912461674177904633800030782296862752779n, 42n ]
mallet> iele.dec(result[0], 'string')
'I\'m a dummy'
mallet> iele.dec(result[1], 'int')
42

Compiling contracts

Compiling contracts is currently only supported for IELE, and only for a single source file. Both IELE assembly language and Solidity (using a Solidity-to-IELE compiler) contracts can be compiled. Both compilers are services of the testnet that Mallet connects to (there are no additional dependencies).

iele.compile

Sends the source code from the provided file path to the compiler. The mode of compilation is determined by the extension of the source file:

  • .sol: two-step compilation: Solidity to IELE and then to IELE assembly
  • .iele: direct to IELE assembly
mallet> iele.compile('test/contracts/sendEther.sol')
{ source:   '// Simple contract ...'
  solidityCompilerOutput: 'Warning: This is a pre-release compiler version...',
  error: false,
  ieleCode: 'contract "main.sol:test" ...',
  bytecode: '000000AA630469000F612...' }

The compiled contract is available in the bytecode property, which can then be used as an argument to iele.createContract. In the case of a compilation failure, the error property will be set to true and the relevant compiler output can be found in solidityCompilerOutput.

With direct IELE assembly compilation, the compiler interface is simpler:

mallet> iele.compile('test/contracts/sendEther.iele')
{ source: 'contract "sendEther" {\n\ndefine @init() ...',
  result: '000000AA630469000...' }

The result property will contain either the correctly compiled bytecode, or textual error information.

Importing as library

To use Mallet as library add:

const Mallet = require('@iohk/mallet');

in your script. See test/basic-kevm.js for an example of using Mallet in a script.

Need more help?

As mentioned before, the IELE testnet pages have detailed instructions and a rather good video:

mallet's People

Contributors

catch-21 avatar elviejo79 avatar loverdos avatar pkellyiohk avatar rtkaczyk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mallet's Issues

Working?

Without making any changes at all, breaks:

git clone https://github.com/input-output-hk/mallet.git
cd mallet
npm install
./mallet --help
/home/ubuntu/MALLET/mallet/lib/mallet.js:51
  const dim = function(n, l = 1n, r = 0n) {
                              ^

SyntaxError: Invalid or unexpected token
    at createScript (vm.js:80:10)
    at Object.runInThisContext (vm.js:139:10)
    at Module._compile (module.js:607:28)
    at Object.Module._extensions..js (module.js:654:10)
    at Module.load (module.js:556:32)
    at tryModuleLoad (module.js:499:12)
    at Function.Module._load (module.js:491:3)
    at Module.require (module.js:587:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/home/ubuntu/MALLET/mallet/cli.js:3:16)

Set password with parameter for sendTransaction not working

Description

Simple test deploy of a Hello World contract with password hardcoded.

I create an account:

myAccount = mallet.newAccount('123');
mallet.selectAccount(myAccount);
res = mallet.requestFunds();
// some sort of awaitReceipt()

I deploy a contract:

deploymentHash = mallet.sendTransaction(tx,'123');

Problem

Transaction appears in Explorer but is never added to chain. If I skip the password parameter in sendTransaction() and type it manually, it is working as expected.

Iele Testnet Servers SSL Certificates have expired.

Going thru the mallet tutorial as interested in Iele and LLVM development and ecosystem

Below are the SSL Certificate Details -- this is not nice been expired almost 1 year.
Please update SSL Cert or at minimum update ReadMe to clearly indicate what works and doesn't.

Screenshot from 2021-05-19 15-48-39****

iele.contractCall and iele.createContract won't accept non Integers.

Playing around with a basic "hello world" contract. It worked well in IELE using https://iele-testnet.iohkdev.io/ But...

Perhaps I'm doing something wrong, but I can't get mallet to accept values different to integers when creating or calling a contract:

`mallet> let bytecode = '0000037463046900096D65737361676528296900127365744D65737361676528737472696E672969001B7365744D65737361676528737472696E67292E696E7465726E616C69001669656C6572742E6D656D6F72792E616C6C6F6361746569001269656C6572742E6D656D6F72792E66696C6C69001369656C6572742E73746F726167652E66696C6C69001C69656C6572742E6D656D6F72792E636F70792E746F2E6D656D6F727969001D69656C6572742E6D656D6F72792E636F70792E746F2E73746F7261676569001D69656C6572742E73746F726167652E636F70792E746F2E6D656D6F727969001E69656C6572742E73746F726167652E636F70792E746F2E73746F72616765680001000066000034006500010061010151126101010101236101015313610101010133618004610101541561080652643501064461010161010701071854890D095A52543A010544513BF600010B660001620101F7016700000001660000340165000201610102512361010201023461010253246101020102445340618005610202F800040001000126606761080850854901085550954A0C0A9A0D0A9A010955536961010201026B53BA607061010261020CF80008000300000C20660001F60000660002620102F7026800020001660000340165000101610102512361010201023461010253246101020102445340618005610202F800040001000126606761080850854901085550954A0C0A9A0D0A9A010955536961010201026B53BA6070F800030001000000F60000660001620102F7026700030001660000610101610202F80008000300000210660001F60000670004000166000061010151126102010101230100226101015312F600010367000500036600001513650001035302610104010400610104030411640000660001F6000067000600036600001513650001035502610104010400610104030411640000660001F60000670007000366000015236500010351045314610105010500610105010511610105030522640000660001F60000670008000366000015236500010351045514610105010500610105010511610105030522640000660001F60000670009000366000015236500010354045314610105010500610105010511610105030522640000660001F6000067000A000366000015236500010354045514610105010500610105010511610105030522640000660001F60000'
undefined
mallet> iele.createContract({gas: 1000000, value: 0, code: bytecode, func: 'setMessage(string)', args: ['hello world']})
SyntaxError: Cannot convert hello world to a BigInt

mallet>
`

Do you intend to improve this behavior? perhaps I need to call another function? Or should we stick to integers only?

./mallet --version

Typing -

./mallet --version

Gives -

internal/modules/cjs/loader.js:638
    throw err;
Error: Cannot find module 'uuid/v4'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:636:15)
    at Function.Module._load (internal/modules/cjs/loader.js:562:25)
    at Module.require (internal/modules/cjs/loader.js:692:17)
    at require (internal/modules/cjs/helpers.js:25:18)
    at Object.<anonymous> (/mallet/lib/web3/web3/jsonrpc.js:25:17)
    at Module._compile (internal/modules/cjs/loader.js:778:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)

I am just trying to check my version, so this is disconcerting. I can see that I have all the necessaries listed here: https://developers.cardano.org/en/virtual-machines/kevm/getting-started/mallet-end-to-end/

But this simple command is throwing an error.

getBalance()

i followed the guide but at getBalance() I get this error.

mallet> getBalance()
Thrown:
Error: Invalid JSON RPC response: undefined
at Object.InvalidResponse (/mnt/c/pr0/mallet/lib/web3/web3/errors.js:38:16)
at HttpProvider.send (/mnt/c/pr0/mallet/lib/web3/web3/httpprovider.js:102:18)
at RequestManager.send (/mnt/c/pr0/mallet/lib/web3/web3/requestmanager.js:65:32)
at Eth.send [as getBalance] (/mnt/c/pr0/mallet/lib/web3/web3/method.js:145:58)
at Mallet.getBalance (/mnt/c/pr0/mallet/lib/mallet.js:238:26)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.