QuarkChain client library provides the interfaces for DApps to interact with QuarkChain network.
The library is built on top of web3.js. Though QuarkChain runs Ethereum Virtual Machine (EVM) and supports Ethereum smart contracts, due to the shard id encoding in the address and change of transaction data structure in QuarkChain the existing web3 library cannot work with QuarkChain JSON RPC directly without modification to handle the differences properly.
Instead of modifying the the web3 source code the quarkchain-web3.js library provides an interface (QuarkChain.injectWeb3(web3, <JRPC URL>)
) to inject QuarkChain features into web3 instances. QuarkChain functions will be available in web3.qkc
after injection and they mirror the same interfaces as their counterparts in web3.eth
with two notable differences.
- The addresses in QuarkChain are 24 bytes (48 hex chars)
- The transaction object in QuarkChain optionally can have three extra properties than in Ethereum
-
fromFullShardKey
: 4 bytes fixed -
toFullShardKey
: 4 bytes fixed -
networkId
: 4 bytes or less
-
The web3 instance passed into the injection function should manage user accounts and will be used to get account address (web3.eth.accounts[0]
) and sign transactions (eth_signTypedData
). The Ethereum provider of the web3 instance must support eth_signTypedData which is implemented by MetaMask. Follow this doc to integrate MetaMask.
Check out the Developer Guide to understand more basic concepts in QuarkChain.
To use for browsers, after cloning, can use webpack
to build the client version of the library:
$ npm install # Recommend node version 8 and above. Preferably v10.
$ npm run build # Calls `webpack`.
$ less dist/quarkchain-web3.js # Should be able to plug into browser directly.
Check out examples/browser
for how to use the library in the browser environment (which also links to the pre-built library file in CDN). Make sure you have MetaMask installed.
Since there aren't many web3 providers that have implemented eth_signTypedData
(provided by MetaMask), we added web3.qkc.setPrivateKey
API so clients will be able to manage keys and bypass signing typed data. To develop / interact with the library in node environment:
# Transpile.
$ npm run build:dist
# Build and start interacting using ndb. Prefer node 10 for running ndb.
$ npm run run:dist
To use it in a npm package, take a look at examples/node
as a toy project:
import QuarkChain from 'quarkchain-web3';
import Web3 from 'web3';
const web3 = new Web3();
QuarkChain.injectWeb3(web3, QKC_JRPC_URL);
web3.qkc.setPrivateKey(PRIVATE_KEY);
- QuarkChain
- web3
QuarkChain.getFullShardKeyFromQkcAddress(qkcAddressHexString)
Extracts full shard key from QKC address.
-
String
- QKC address as HEX string.
String
- Full shard key as HEX string.
var result = QuarkChain.getFullShardKeyFromQkcAddress("0x653EF52aa0D9f9186f3f311193C92Ed84707519C65D931d8");
console.log(result); // "0x65D931d8"
QuarkChain.getEthAddressFromQkcAddress(qkcAddressHexString)
Extracts ETH address from QKC address.
-
String
- QKC address as HEX string.
String
- ETH address as HEX string.
var result = QuarkChain.getEthAddressFromQkcAddress("0x653EF52aa0D9f9186f3f311193C92Ed84707519C65D931d8");
console.log(result); // "0x653EF52aa0D9f9186f3f311193C92Ed84707519C"
QuarkChain.injectWeb3(web3, QkcJrpcUrl)
Add QuarkChain specific functions to the web3 instance. web3.qkc will be available after this call.
-
Web3
- Web3 instance -
String
- URL for QuarkChain JRPC endpoint
QuarkChain.injectWeb3(web3, QKC_JRPC_URL);
console.log(!!web3.qkc); // true
The following API references are copied from Ethereum JavaScript API with modifications to match QuarkChain interfaces including function parameters and examples. We appreciate the efforts from people contributing to both docs.
Provides QuarkChain methods.
var qkc = web3.qkc;
web3.qkc.getBalance(addressHexString [, callback])
Get the balance of an address at the latest block.
-
String
- The address to get the balance of. -
Function
- (optional) If you pass a callback the HTTP request is made asynchronous. See this note for details.
String
- A BigNumber instance of the current balance for the given address in wei.
See the note on BigNumber.
var balance = web3.qkc.getBalance("0x653EF52aa0D9f9186f3f311193C92Ed84707519C65D931d8");
console.log(balance); // instanceof BigNumber
console.log(balance.toString(10)); // '1000000000000'
console.log(balance.toNumber()); // 1000000000000
web3.qkc.getTransactionCount(addressHexString [, callback])
Get the numbers of transactions sent from this address.
-
String
- The address to get the numbers of transactions from. -
Function
- (optional) If you pass a callback the HTTP request is made asynchronous. See this note for details.
Number
- The number of transactions sent from the given address.
var number = web3.qkc.getTransactionCount("0x653EF52aa0D9f9186f3f311193C92Ed84707519C65D931d8");
console.log(number); // 12
web3.qkc.sendTransaction(transactionObject [, callback])
Sends a transaction to the network.
web3.eth.accounts[0]
will be used to sign the transaction.
nonce
in the transaction object will be fetched from the network automatically.
-
Object
- The transaction object to send:
-
to
:String
- (optional) The destination address of the message, left undefined for a contract-creation transaction. -
value
:Number|String|BigNumber
- (optional) The value transferred for the transaction in Wei, also the endowment if it's a contract-creation transaction. -
gas
:Number|String|BigNumber
- (optional, default: 0) The amount of gas to use for the transaction (unused gas is refunded). -
gasPrice
:Number|String|BigNumber
- (optional, default: 0) The price of gas for this transaction in wei. -
data
:String
- (optional) Either a byte string containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code. -
fromFullShardKey
:String
- The full shard key for sender. -
toFullShardKey
:String
- The full shard key for the to address.
-
Function
- (optional) If you pass a callback the HTTP request is made asynchronous. See this note for details.
String
- The 36 Bytes transaction id as HEX string.
If the transaction was a contract creation use web3.qkc.getTransactionReceipt() to get the contract address, after the transaction was mined.
// compiled solidity source code
var code = "0x603d80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463c6888fa18114602d57005b6007600435028060005260206000f3";
web3.qkc.sendTransaction({data: code, gas: 1000000}, function(err, transactionId) {
if (!err)
console.log(transactionId); // "0xff49f2d47b9b92ad5ec66c2cd1790ec57cdf04bb6fc783fd17b55894ef11eeba65d931d8"
});
web3.qkc.getTransactionReceipt(transactionIdHexString [, callback])
Returns the receipt of a transaction by transaction id.
Note That the receipt is not available for pending transactions.
-
String
- The transaction id. -
Function
- (optional) If you pass a callback the HTTP request is made asynchronous. See this note for details.
Object
- A transaction receipt object, or null
when no receipt was found:
-
blockHash
:String
, 32 Bytes - hash of the block where this transaction was in. -
blockHeight
:Number
- block number where this transaction was in. -
transactionId
:String
, 36 Bytes - id of the transaction. -
transactionHash
:String
, 32 Bytes - hash of the transaction. -
transactionIndex
:Number
- integer of the transactions index position in the block. -
cumulativeGasUsed
:Number
- The total amount of gas used when this transaction was executed in the block. -
gasUsed
:Number
- The amount of gas used by this specific transaction alone. -
contractAddress
:String
- 20 Bytes - The contract address created without full shard key, if the transaction was a contract creation, otherwisenull
. To build a QKC contract address, append the toFullShardKey used in the contract creation transaction. Normally you should use web3.qkc.contract(abi).new() which returns the QKC address in the callback. -
status
:String
- '0x0' indicates transaction failure , '0x1' indicates transaction succeeded.
var receipt = web3.qkc.getTransactionReceipt('0xff49f2d47b9b92ad5ec66c2cd1790ec57cdf04bb6fc783fd17b55894ef11eeba65d931d8');
console.log(receipt);
{
blockHash: "0xfbc12d5c9b2b382bfc7efcd0843bd06b7e2f3ae0188627bc12599fce4ce9276f",
blockHeight: "0x369",
blockId: "0xfbc12d5c9b2b382bfc7efcd0843bd06b7e2f3ae0188627bc12599fce4ce9276f00000018",
contractAddress: "0xd08305d78c6df48c312c46125b919a79b3127397",
cumulativeGasUsed: 67954,
gasUsed: 67954,
status: "0x1",
transactionHash: "0xff49f2d47b9b92ad5ec66c2cd1790ec57cdf04bb6fc783fd17b55894ef11eeba",
transactionId: "0xff49f2d47b9b92ad5ec66c2cd1790ec57cdf04bb6fc783fd17b55894ef11eeba65d931d8",
transactionIndex: 0
}
web3.qkc.call(callObject [, callback])
Executes a message call transaction, which is directly executed in the VM of the node, but never mined into the blockchain.
-
Object
- A transaction object see web3.qkc.sendTransaction, with the difference that for calls thefrom
property is optional as well. -
Function
- (optional) If you pass a callback the HTTP request is made asynchronous. See this note for details.
String
- The returned data of the call, e.g. return value of a smart contract function.
var result = web3.qkc.call({
to: "0xD08305d78C6DF48c312c46125B919A79B312739765D931d8",
data: "0xc6888fa10000000000000000000000000000000000000000000000000000000000000003"
});
console.log(result); // "0x0000000000000000000000000000000000000000000000000000000000000015"
web3.qkc.contract(abiArray)
Creates a contract object for a solidity contract, which can be used to initiate contracts on an address. You can read more about events here.
-
Array
- ABI array with descriptions of functions and events of the contract.
Object
- A contract object, which can be initiated as follows:
var MyContract = web3.qkc.contract(abiArray);
// instantiate by address
var contractInstance = MyContract.at(address);
// deploy new contract
var contractInstance = MyContract.new([constructorParam1] [, constructorParam2], {data: '0x12345...', from: myAccount, gas: 1000000, gasPrice: 1000000000, fromFullShardKey: fromFullShardKey, toFullShardKey: toFullShardKey});
// Get the data to deploy the contract manually
var contractData = MyContract.new.getData([constructorParam1] [, constructorParam2], {data: '0x12345...'});
// contractData = '0x12345643213456000000000023434234'
And then you can either initiate an existing contract on an address, or deploy the contract using the compiled byte code:
// Instantiate from an existing address:
var myContractInstance = MyContract.at(myContractAddress);
// Or deploy a new contract:
// Deploy the contract asynchronous from Solidity file:
...
const fs = require("fs");
const solc = require('solc')
let source = fs.readFileSync('nameContract.sol', 'utf8');
let compiledContract = solc.compile(source, 1);
let abi = compiledContract.contracts['nameContract'].interface;
let bytecode = compiledContract.contracts['nameContract'].bytecode;
let MyContract = web3.eth.contract(JSON.parse(abi));
var myContractReturned = MyContract.new(param1, param2, {
data: bytecode,
gas: 1000000}, function(err, myContract){
if(!err) {
// NOTE: The callback will fire twice!
// Once the contract has the transactionId property set and once its deployed on an address.
// e.g. check tx hash on the first call (transaction send)
if(!myContract.address) {
console.log(myContract.transactionId); // The id of the transaction, which deploys the contract
// check address on the second call (contract deployed)
} else {
console.log(myContract.address); // the contract address
}
// Note that the returned "myContractReturned" === "myContract",
// so the returned "myContractReturned" object will also get the address set.
}
});
// contract abi
var abi = [{
name: 'myConstantMethod',
type: 'function',
constant: true,
inputs: [{ name: 'a', type: 'string' }],
outputs: [{name: 'd', type: 'string' }]
}, {
name: 'myStateChangingMethod',
type: 'function',
constant: false,
inputs: [{ name: 'a', type: 'string' }, { name: 'b', type: 'int' }],
outputs: []
}, {
name: 'myEvent',
type: 'event',
inputs: [{name: 'a', type: 'int', indexed: true},{name: 'b', type: 'bool', indexed: false}]
}];
// creation of contract object
var MyContract = web3.qkc.contract(abi);
// initiate contract for an address
var myContractInstance = MyContract.at('0xD08305d78C6DF48c312c46125B919A79B312739765D931d8');
// call constant function
var result = myContractInstance.myConstantMethod('myParam');
console.log(result) // '0x25434534534'
// send a transaction to a function
myContractInstance.myStateChangingMethod('someParam1', 23, {value: 200, gas: 2000});
// short hand style
web3.qkc.contract(abi).at(address).myAwesomeMethod(...);
// Automatically determines the use of call or sendTransaction based on the method type
myContractInstance.myMethod(param1 [, param2, ...] [, transactionObject] [, callback]);
// Explicitly calling this method
myContractInstance.myMethod.call(param1 [, param2, ...] [, transactionObject] [, callback]);
// Explicitly sending a transaction to this method
myContractInstance.myMethod.sendTransaction(param1 [, param2, ...] [, transactionObject] [, callback]);
// Get the call data, so you can call the contract through some other means
// var myCallData = myContractInstance.myMethod.request(param1 [, param2, ...]);
var myCallData = myContractInstance.myMethod.getData(param1 [, param2, ...]);
// myCallData = '0x45ff3ff6000000000004545345345345..'
The contract object exposes the contract's methods, which can be called using parameters and a transaction object.
-
String|Number|BigNumber
- (optional) Zero or more parameters of the function. If passing in a string, it must be formatted as a hex number, e.g. "0xdeadbeef" If you have already created BigNumber object, then you can just pass it too. -
Object
- (optional) The (previous) last parameter can be a transaction object, see web3.qkc.sendTransaction parameter 1 for more. Note:data
andto
properties will not be taken into account. -
Function
- (optional) If you pass a callback as the last parameter the HTTP request is made asynchronous. See this note for details.
String
- If its a call the result data, if its a send transaction a created contract address, or the transaction id, see web3.qkc.sendTransaction for details.
// creation of contract object
var MyContract = web3.qkc.contract(abi);
// initiate contract for an address
var myContractInstance = MyContract.at('0xD08305d78C6DF48c312c46125B919A79B312739765D931d8');
var result = myContractInstance.myConstantMethod('myParam');
console.log(result); // '0x25434534534'
myContractInstance.myStateChangingMethod('someParam1', 23, {value: 200, gas: 2000}, function(err, result){ ... });
You can skip MetaMask by providing the private key (a bit hacky but works) after injecting web3. This will make the library work in Node environment.
// Note the private key is a 32-byte hex string.
web3.qkc.setPrivateKey('0x...');
// Then continue with sendTransaction or contract methods (write), remember to set gasLimit and gasPrice correctly
// Unset and go back to MetaMask.
web3.qkc.unsetPrivateKey();