Muta is a high-performance blockchain framework, aiming to build a high-quality blockchain system. @nervosnetwork/muta-sdk-js
is an SDK(Software Development Kit) implemented by TypeScript, and used to interact with Muta instance. The runnable demo in this tutorial works well in NodeJS >= 10 as it is written by JavaScript, and some structures that need to be explained will be described by TypeScript interface. It is highly recommended that editing the demo code in VS Code or WebStorm, since a modern IDE would be better to help you to auto-complete the code.
npm install [email protected] @mutadev/muta-sdk@dev
yarn add [email protected] @mutadev/muta-sdk@dev
The SDK is organized with
monorepo
mode that means the SDK is modular, and the@mutadev/muta-sdk
is an all-in-one module containing other modules. Therefore, we generally only need to use@mutadev/muta-sdk
Module
in the SDK are exported as ES6 named module, so import always like this wayconst { SomeThing } = require('@mutadev/some-module');
Class
are exported with first letter uppercase CamelCase , e.g.Client
AssetService
function
orstatic module
are exported with first letter lowercase camelCase, e.g.utils
createTransactionSignature
const { Client, Account, retry, /*...*/ } = require('@mutadev/muta-sdk');
async function main() {
const client = new Client();
const block = await client.getBlock();
console.log(block);
}
There is a concept called service in Muta. Simply said, service is a class composed of multiple methods, so we can call them in the same way.
{
"serviceName": "the_service_name",
"method": "the_method_name",
"payload": "{ \"a_payload_key\": \"a_value\" }"
}
- serviceName: a string that means namespace of service, we can think of it as a class
- method: a string that means a method of a service
- payload: a string that means method arguments, in most case, it is a JSON serialized string
Here is a short demo to show how to query balance
await client.queryService({
serviceName: 'asset',
method: 'get_balance',
payload: JSON.stringify({
asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000',
user: 'muta1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqggfy0d'
})
});
When we try to modify the service status, such as transfer, we need to send a signed transaction. A transaction is composed by following structure. In order to ensure security, the transaction processed by Muta will only be a transaction within a certain gap in the future, so the structure of the signature contains the timeout
field. We can use the composeTransaction
to help up to generate a raw(unsigned) transaction
The following code shows how to create a raw transaction, that used to call the asset service for transfer.
await client.composeTransaction({
service: 'asset',
method: 'transfer',
payload: "{ \"user\": \"muta1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqggfy0d", \"value\": 1 }"
});
Muta will only execute transactions that have been correctly signed. So we need to sign the transaction before we send it.
The private key is essential for the signature process, and it is important to note that the private key should not be known to anyone other than you, otherwise you will be impersonated.
const account = new Account('0x0000000000000000000000000000000000000000000000000000000000000001');
We can sign a transaction in this way
const signedTransaction = account.signTransaction(rawTransaction);
The rawTransaction
was generated by composeTransaction
that we mentioned above. Next, just send the transaction to Muta, and we'll get a txHash
from the Muta, meaning that the transaction is already known to Muta.
const txHash = await client.sendTransaction(signedTransaction);
The transfer wasn't successful until we got the receipt.
Note that a receipt does not return immediately, it waits until the consensus node succeeds, so we can retry
until it succeeds.
const receipt = await retry(() => client.getReceipt(txHash));
We can see all the demo classes above constructed without argument, this is because the @mutadev/defaults provided the default variables. We can change the default variables by changing environment variables
export MUTA_ENDPOINT=http://127.0.0.1:8001
Also we can config when constructing
const client = new Client({
endpoint: 'http://127.0.0.1:8001'
});
The configuration priorities is Constructor
> Environment Variable
> default variables
.
Here is a short demo showing how we build an asset on Muta via @mutadev/service
const { AssetService } = require('@mutadev/service');
async function main() {
const service = new AssetService();
const created = await service.write.create_asset({
name: 'MyToken',
supply: 10000000,
symbol: 'MT'
});
const asset = await service.read.get_asset({
id: created.response.response.succeedData.id
});
console.log(`I have created an asset [${asset.succeedData.name}] on Muta succeffuly`);
}