A general library wrapped in javascript for interacting with Ultrain
npm install u3.js
A general library wrapped in javascript for interacting with Ultrain.
Browser(ES6)or NodeJS
If you want to integrate u3.js into a react native environment, there is a workable way to do this with rn-nodeify, see the example U3RNDemo
* #### Installation
npm install u3.js 或 yarn add u3.js
* #### Initialization
``
const { createU3 } = require('u3.js');
let config = {
httpEndpoint: "http://127.0.0.1:8888",
httpEndpointHistory: "http://127.0.0.1:3000",
chainId: "baf8bb9d3636379e3cd6779d2a72e693494670f1040d45154bb61dc8852c8971",
broadcast: true,
sign: true,
logger: {
directory: "../../logs", // daily rotate file directory
level: "info", // error->warn->info->verbose->debug->silly
console: true, // print to console
file: false // append to file
},
symbol: "UGAS",
//keyProvider:[],
//expireInSeconds:60
}
let u3 = createU3(config);
u3.getChainInfo((err, info) => {
if (err) {throw err;}
console.log(info);
});
`
* #### Local environment running
Running u3 locally requires relying on docker.
1.Download docker from here and install it;
2.Then add the Chinese mirror address:https://registry.docker-cn.com;
3.Click on "Apply & Restart";
4.Go to u3.js/docker && ./start.sh
#### Global configuration
httpEndpoint string - http or https location of a ultrain providing a chain API. When using u3.js from a browser remember to configure the same origin policy in nodultrain or proxy server. For testing, nodultrain configuration access-control-allow-origin = could be used.
* httpEndpointHistory string - http or https location of a ultrain providing a chain history API. When using u3.js from a browser remember to configure the same origin policy in nodultrain or proxy server. .
* chainId Unique ID for the blockchain you're connecting to. This is required for valid transaction signing. The chainId is provided via the get_chain_info API call.
* keyProvider [array
If a keyProvider is not provided here, you should provided on a per-action or per-transaction basis in Options.
* expireInSeconds number - number of seconds before the transaction will expire. The time is based on the nodultrain's clock. An unexpired transaction that may have had an error is a liability until the expiration is reached, this time should be brief.
* broadcast [boolean=true] - post the transaction to the blockchain. Use false to obtain a fully signed transaction and it will not push to the blockchain.
* sign [boolean=true] - sign the transaction with a private key. Leaving a transaction unsigned avoids the need to provide a private key.
* logger - default logging configuration.
``
logger: {
directory: "../../logs", // daily rotate file directory
level: "info", // error->warn->info->verbose->debug->silly
console: true, // print to console
file: false // append to file
}
#### Options configuration
Options may be provided after parameters. Authorization is for individual actions.eg:
`
options = {
authorization: 'alice@active',
broadcast: true,
sign: true
}
```
u3.transfer('alice', 'bob', '1.0000 UGAS', '', options)
* authorization [array
* broadcast [boolean=true] - post the transaction to the blockchain. Use false to obtain a fully signed transaction.
* sign [boolean=true] - sign the transaction with a private key. Leaving a transaction unsigned avoids the need to provide a private key.
* keyProvider [array
``
await u3.anyAction('args', {keyProvider})
await u3.transaction(tr => { tr.anyAction() }, {keyProvider})
create accounts will need some staked tokens for RAM and bandwidth.
``
const u3 = createU3(config);
const name = 'abcdefg12345'; //common account should satisfy rule: Must be 12 bit in 12345abcdefghijklmnopqrstuvwxyz
let params = {
creator: 'ben',
name: name,
owner: pubkey,
active: pubkey,
updateable: 1,//[optional]whether the account can be updated( update contract)
};
await u3.createUser(params);
Transfer(UGAS)
transfer functions are used more frequently.
* transfer(from,to,content,memo) the content param should be using strict format with right decimal and symbol, eg '1.0000 UGAS'
`
const u3 = createU3(config);
const c = await u3.contract('utrio.token')
// with positional parameters
const result = await c.transfer('ben', 'bob', '1.2000 UGAS', '')
// or with named parameters
const result = await c.transfer({from: 'bob', to: 'ben', quantity: '1.3000 UGAS', memo: ''})
``
* If you want to confirm that the transfer logic has been really done, please follow these steps:
// first check whether the transaction was failed
if (!result || result.processed.receipt.status !== "executed") {
console.log("the transaction was failed");
return;
}
// then check whether the transaction was irreversible when it was not expired
let timeout = new Date(result.transaction.transaction.expiration + "Z") - new Date();
await U3Utils.test.waitUntil(async () => {
let tx = await u3.getTxByTxId(result.transaction_id);
return tx && tx.irreversible;
}, timeout, 1000);
`
Sign
#### send unsigned_transaction
Using { sign: false, broadcast: false } to create a U3 instance and do some action.`
And Then send the unsigned_transaction object to the ultrain-chain wallet.
Under these circumstances, you still need the network.
`
const u3_offline = createU3({ sign: false, broadcast: false });
const c = u3_offline.contract('utrio.token');
let unsigned_transaction = await c.transfer('ben', 'bob', '1 UGAS', 'test');
U3 will not initiate a network request if you set httpEndpoint to null.transactionHeaders
And you should pass in the parameters as below.abi
The parameter is optional. when you ignore it, u3 will looking it from its local directory.expiration
There are only two abis of 'ultrainio' and 'utrio.token' cached in local file.
Note that the max time is an hour (3600).ref_block_num
And you can fetch the and ref_block_prefix through u3.getBlockInfo or the rest api http://xxx/v1/chain/get_block_info
``
const u3_offline = createU3({
sign: false,
broadcast: false,
httpEndpoint: null,
transactionHeaders: {
expiration: expiration.toISOString().split('.')[0],
ref_block_num: 5,
ref_block_prefix: 2950683920,
},
abi: JSON.parse('{"version":"ultraio:1.0","types":[{"new_type_name":"account_name","type":"name"}],"structs":[{"name":"transfer","base":"","fields":[{"name":"from","type":"account_name"},{"name":"to","type":"account_name"},{"name":"quantity","type":"asset"},{"name":"memo","type":"string"}]},{"name":"safe_transfer","base":"","fields":[{"name":"from","type":"account_name"},{"name":"to","type":"account_name"},{"name":"quantity","type":"asset"},{"name":"memo","type":"string"}]},{"name":"create","base":"","fields":[{"name":"issuer","type":"account_name"},{"name":"maximum_supply","type":"asset"}]},{"name":"issue","base":"","fields":[{"name":"to","type":"account_name"},{"name":"quantity","type":"asset"},{"name":"memo","type":"string"}]},{"name":"account","base":"","fields":[{"name":"balance","type":"asset"},{"name":"last_block_height","type":"uint32"}]},{"name":"currency_stats","base":"","fields":[{"name":"supply","type":"asset"},{"name":"max_supply","type":"asset"},{"name":"issuer","type":"account_name"}]}],"actions":[{"name":"transfer","type":"transfer","ricardian_contract":""},{"name":"safe_transfer","type":"safe_transfer","ricardian_contract":""},{"name":"issue","type":"issue","ricardian_contract":""},{"name":"create","type":"create","ricardian_contract":""}],"tables":[{"name":"accounts","type":"account","index_type":"i64","key_names":["currency"],"key_types":["uint64"]},{"name":"stat","type":"currency_stats","index_type":"i64","key_names":["currency"],"key_types":["uint64"]}],"ricardian_clauses":[],"abi_extensions":[]}'),
});
const c = u3_offline.contract('utrio.token');
let unsigned_transaction = await c.transfer('ben', 'bob', '1 UGAS', 'test');
Another example is createUser.
`ben@active
let expiration = new Date(new Date().getTime() + 60 * 1000);
const u3_offline = createU3({
httpEndpoint: null,
transactionHeaders: {
expiration: expiration.toISOString().split('.')[0],
ref_block_num: 5,
ref_block_prefix: 2950683920,
},
});
const name = randomName();
let params = {
creator: 'ben',
name: 'bob123',
owner: 'UTR6r...',
active: 'UTR6r...',
};
const unsigned_transaction = await u3_offline.createUser(params, {
sign: false,
broadcast: false,
authorization: [],`
});
#### sign and push signed_transaction
In the wallet you can provide your privateKey or mnemonic to make a signature.
And then push the signedTransaction to the ultrain-chain.
`
const u3_online = createU3();
let signature = await u3_online.sign(unsigned_transaction, privateKeyOrMnemonic, chainId);
if (signature) {
let signedTransaction = Object.assign({}, unsigned_transaction.transaction, { signatures: [signature] });
let processedTransaction = await u3_online.pushTx(signedTransaction);
}
`
Calling a contract will only spend the contract owner's resource. So if your want to deploy
a contract, buy some resource before.
Please go to the developer website and choose the right resource package and make a purchase if you are in the MainNet environment,
and go to the testnet explorer to do the self-service account recharge and resource purchase if you are in the TestNet environment.
* resourcelease(payer,receiver,slot,days,location)
`
const u3 = createU3(config);
const c = await u3.contract('ultrainio')
await c.resourcelease('ben', 'bob', 1, 10, "ultrainio");// 1 slot for 10 days on the side chain named ultrainio
`
And querying resource detail through the method below.
`
const account = await u3.getAccountInfo({ account_name: 'abcdefg12345' });
console.log(account.chain_resource[0].lease_num)
`
#### deploy
Deploy and call smart contracts. Before you deploy the smart contract, you need to compile the typescript source files
to webassembly targets, which are .abi,.wast,*.wasm.
deploy(contracts_files_path, deploy_account) the contracts_files_path param is the absolute path of .abi,.wast,.wasm.
and the deploy_account is the one who will deploy the smart contract.
`
const u3 = createU3(config);
await u3.deploy(path.resolve(__dirname, '../contracts/token/token'), 'bob');
`
#### call actions
`
const u3 = createU3(config);
const tr = await u3.contract('ben');
await tr.transfer('bob', 'ben', '1.0000 UGAS','');
//or maybe like this
await u3.contract('ben').then(sm => sm.transfer('bob', 'ben', '1.0000 UGAS',''))
// Transaction with multiple contracts
await u3.transaction(['ben', 'bob'], ({sm1, sm2}) => {
sm1.myaction(..)
sm2.myaction(..)
})
`
#### custom Token
`
const u3 = createU3(config);
const account = 'bob';
await u3.transaction(account, token => {
token.create(account, '10000000.0000 DDD');
token.issue(account, '10000000.0000 DDD', 'issue');
});
const balance = await u3.getCurrencyBalance(account, account, 'DDD')
console.log('currency balance', balance)
`
Ultrain provides an event registration and listening mechanism for asynchronous scenarios that trigger another action in the contract.The client needs to first register a listener address to the ultrain, then trigger the event via the emit method in the contract, and Ultrain will push the message to the registered listener address.
#### register/unregister
* registerEvent(deployer, listen_url)
* unregisterEvent(deployer, listen_url)
deployer : the account who deploy the contract
listen_url : the listening url which will receive the message
note: If you are testing in a docker envirnment, make sure the listening address is a local IP and can be access from docker.
`
const u3 = createU3(config);
const subscribe = await u3.registerEvent('ben', 'http://192.168.1.5:3002');
//or
const unsubscribe = await u3.unregisterEvent('ben', 'http://192.168.1.5:3002');
`
#### listen
`
const { createU3 listener } = require('u3.js');
listener(function(data) {
// do callback logic
console.log(data);
});
U3Utils.test.wait(2000);
//must call listener function before emit event
const contract = await u3.contract(account);
contract.hi('ben', 30, 'It is a test', { authorization: [ben@active] });
``