Qweb3 — web3.js for Qtum, a Qtum Developer Tool

Do you find writing command-line commands for qtum-cli tedious and tiring?

We at Bodhi have a solution for you! We have just released Qweb3 0.4.0 for Qtum dApp developers! We built this tool for improving development capabilities on the Qtum blockchain.

What does it do?

Qweb3.js is a Javascript wrapper around the qtum-cli that makes it easier for developers to make cli commands without the need for having to do all the conversions and padding that the Qtum command-line expects.

As an example, given the smart contract function:

function createTopic(
 address _oracle, 
 bytes32[10] _name, 
 bytes32[10] _resultNames, 
 uint256 _bettingStartBlock,
 uint256 _bettingEndBlock,
 uint256 _resultSettingStartBlock,
 uint256 _resultSettingEndBlock)
 public
 returns (TopicEvent topicEvent) { }

To do a sendtocontract with qtum-cli to this function would look like this:

$ ./qtum-cli sendtocontract 73f9bcccc2f4e9fc93c06b434a11d83f4a043e9e b7b6d82200000000000000000000000017e7888aa7412a735f336d2f6d784caefabb6fa357686f2077696c6c20626520746865204e424120416c6c2053746172204d565020696e20323031383f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004375727279000000000000000000000000000000000000000000000000000000447572616e7400000000000000000000000000000000000000000000000000004461766973000000000000000000000000000000000000000000000000000000416e7465746f6b6f756e6d706f000000000000000000000000000000000000005061756c000000000000000000000000000000000000000000000000000000005765737462726f6f6b000000000000000000000000000000000000000000000048617264656e00000000000000000000000000000000000000000000000000004a616d6573000000000000000000000000000000000000000000000000000000477265656e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111010000000000000000000000000000000000000000000000000000000000011170000000000000000000000000000000000000000000000000000000000001117a0000000000000000000000000000000000000000000000000000000000011558 0 4000000 0.0000004 qKjn4fStBaAtwGiwueJf9qFxgpbAvf1xAy

That just seems unruly and super hard to work with. So we created an easy way to interact with the local Qtum node. Here is the equivalent of the above call in Qweb3:

const oracleAddress = ‘qKjn4fStBaAtwGiwueJf9qFxgpbAvf1xAy’;
const eventName = ‘My event name’;
const resultNames = [‘Yes’, ’No’];
const bettingStartBlock = 68000;
const bettingEndBlock = 68100;
const resultSettingStartBlock = 68200;
const resultSettingEndBlock = 68300;
return await contract.send(‘createTopic’, {
 methodArgs: [oracleAddress, eventName, resultNames, bettingStartBlock, bettingEndBlock, resultSettingStartBlock, resultSettingEndBlock],
 gasLimit: 4000000,
 senderAddress: ‘ qKjn4fStBaAtwGiwueJf9qFxgpbAvf1xAy’,
 });

Qweb3 makes it easier to construct and execute these qtum-cli commands, but using Javascript.

How do I install it?

Using NPM, run the following command to pull and save the qweb3.js module into your project:

$ npm install qweb3 --save

How do I use it?

You will have to start your qtumd local node and specify rpcuser and rpcpassword while starting your qtumd instance:

// you can use whatever rpcuser and rpcpassword you choose
$ ./qtumd -testnet -logevents -rpcuser=bodhi -rpcpassword=bodhi

Once you have the NPM module in your project, you can instantiate a new Qweb3 instance like so:

const Qweb3 = require('qweb3').default;
// Pass in the path of your local Qtum node rpc port with username/password
// In our case, username=bodhi, password=bodhi, port=13889 (default port)
const qClient = new Qweb3('http://bodhi:bodhi@localhost:13889');

Once you have your Qweb3 instance and your qtumd is running, you can call commands on Qweb3 such as:

async function getBlockCount() {
return await qClient.getBlockCount();
}
getBlockCount();
async function getTransactionReceipt(args) {
const {
transactionId, // string
} = args;

return await qClient.getTransactionReceipt(transactionId);
}
getTransactionReceipt('
1d498254fd672d6e8deaff9b92b95bcd9ab6a9591ff415b9f0b3be442fcc9392');

The full list of commands can be found in our Github repo readme: https://github.com/bodhiproject/qweb3.js

Or if you want to do direct contract calls like callcontract or sendtocontract you will need to instantiate a Contract instance:

const Contract = require('qweb3').Contract;

// The path to your local Qtum node via RPC
const rpcAddress = 'http://bodhi:bodhi@localhost:13889';

// contractAddress = The address of your contract deployed on the blockchain
const contractAddress = 'f7b958eac2bdaca0f225b86d162f263441d23c19';

// contractAbi = The ABI of the contract
const contractAbi =
[{ constant: true, inputs: [{ name: '', type: 'bytes32' }], name: 'topics', outputs: [{ name: '', type: 'address' }], payable: false, stateMutability: 'view', type: 'function' }, { constant: false, inputs: [{ name: '_oracle', type: 'address' }, { name: '_name', type: 'bytes32[10]' }, { name: '_resultNames', type: 'bytes32[10]' }, { name: '_bettingEndBlock', type: 'uint256' }, { name: '_resultSettingEndBlock', type: 'uint256' }], name: 'createTopic', outputs: [{ name: 'topicEvent', type: 'address' }], payable: false, stateMutability: 'nonpayable', type: 'function' }, { constant: true, inputs: [{ name: '_name', type: 'bytes32[10]' }, { name: '_resultNames', type: 'bytes32[10]' }, { name: '_bettingEndBlock', type: 'uint256' }, { name: '_resultSettingEndBlock', type: 'uint256' }], name: 'doesTopicExist', outputs: [{ name: '', type: 'bool' }], payable: false, stateMutability: 'view', type: 'function' }, { inputs: [{ name: '_addressManager', type: 'address' }], payable: false, stateMutability: 'nonpayable', type: 'constructor' }, { anonymous: false, inputs: [{ indexed: true, name: '_topicAddress', type: 'address' }, { indexed: true, name: '_creator', type: 'address' }, { indexed: true, name: '_oracle', type: 'address' }, { indexed: false, name: '_name', type: 'bytes32[10]' }, { indexed: false, name: '_resultNames', type: 'bytes32[10]' }, { indexed: false, name: '_bettingEndBlock', type: 'uint256' }, { indexed: false, name: '_resultSettingEndBlock', type: 'uint256' }], name: 'TopicCreated', type: 'event' }];

const contract = new Contract(rpcAddress, contractAddress, contractAbi);

Here’s an example callcontract:

// callcontract on a method named 'myCallFunc'
async function exampleCall(args) {
const {
senderAddress, // address
} = args;

return await contract.call('myCallFunc', {
methodArgs: [],
senderAddress: senderAddress,
});
}
exampleCall('
qKjn4fStBaAtwGiwueJf9qFxgpbAvf1xAy');

Here’s an example sendtocontract:

// sendtocontract on a method named 'mySendFunc'
async function exampleSend(args) {
const {
resultIndex, // number
senderAddress, // address
} = args;

return await contract.send('mySendFunc', {
methodArgs: [resultIndex], // match contract function params
gasLimit: 1000000, // setting the gas limit to 1 million
senderAddress: senderAddress,
});
}
exampleSend(1, '
qKjn4fStBaAtwGiwueJf9qFxgpbAvf1xAy');

References

If you have any comments, suggestions, or feature requests you can create an issue in the Github repo: