Javascript封装的负责与链交互的通用库
浏览器(ES6)或 NodeJS
如果你想集成u3.js到react native环境中,有一个可行的方法,借助rn-nodeify实现,参考示例U3RNDemo
一、如果是在浏览器中使用u3,请参考以下用法:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
<script src="../dist/u3.js"></script>
<script>
let func = async () => {
let u3 = U3.createU3({
httpEndpoint: "http://127.0.0.1:8888",
httpEndpointHistory: "http://127.0.0.1:3000"
});
await u3.getChainInfo();
const keyProvider = () => {
return ["5JbedY3jGfNK7HcLXcqGqSYrmX2n8wQWqZAuq6K7Gcf4Dj62UfL"];
};
const c = await u3.contract("utrio.token");
await c.transfer("ben", "bob", "1.0000 UGAS", "", { keyProvider });
};
func();
</script>
</head>
<body>
</body>
</html>
二、 如果是在NodeJS环境中使用u3,请参照以下用法:
npm install u3.js 或 yarn add u3.js
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);
let info = await u3.getChainInfo();
本地运行u3,需要依赖docker.
1.从这里 下载docker并安装;
2.然后添加中国区镜像地址:https://registry.docker-cn.com;
3.点击"Apply & Restart";
4.进入u3.js/docker && ./start.sh
- httpEndpoint string - 链实时API的http或https地址.如果是在浏览器环境中使用u3,请注意配置相同的域名.
- httpEndpointHistory string - 链历史API的http或https地址.如果是在浏览器环境中使用u3,请注意配置相同的域名.
- chainId 链唯一的ID. 链ID可以通过 [httpEndpoint]/v1/chain/get_chain_info获得.
- keyProvider [array|string|function] - 提供私钥用来签名交易. 提供用于签名事务的私钥。 如果提供了多个私钥,不能确定使用哪个私钥,可以使用调用get_required_keysAPI 获取要使用签名的密钥. 如果是函数,那么每一个交易都将会使用该函数. 如果这里不提供keyProvider,那么它可能会Options配置项提供在每一个action或每一个transaction中
- expireInSeconds number - 事务到期前的秒数,时间基于nodultrain的时间.
- broadcast [boolean=true] - 默认是true。使用true将交易发布到区块链,使用false将获取签名的事务.
- sign [boolean=true] - 默认是true。使用私钥签名交易。保留未签名的交易避免了提供私钥的需要.
- logger - 默认日志配置.
logger: {
directory: "../../logs", // 每天日志的目录
level: "info", // error->warn->info->verbose->debug->silly
console: true, // 打印到控制台
file: false // 输出到文件
}
Options可以在方法参数之后添加. Authorization应用于单独的actions.比如:
options = {
authorization: 'alice@active',
broadcast: true,
sign: true
}
u3.transfer('alice', 'bob', '1.0000 UGAS', '', options)
- authorization [array|auth] - 指明账号和权限,典型地应用于多重签名的配置中. Authorization必须是一个字符串格式,形如account@permission.
- broadcast [boolean=true] - 默认是true。使用true将交易发布到区块链,使用false将获取签名的事务.
- sign [boolean=true] - 默认是true。使用私钥签名交易。保留未签名的交易避免了提供私钥的需要.
- keyProvider [array|string|function] - 就像global配置项中的keyProvider一样,这里的配置可以以覆盖全局配置的形式为每一个action或每一个transaction提供单独的私钥.
await u3.anyAction('args', {keyProvider})
await u3.transaction(tr => { tr.anyAction() }, {keyProvider})
创建账号需要花费creator账号的一些代币,为新账号抵押部分RAM和带宽
const u3 = createU3(config);
const name = 'abcd1';//普通账号需要满足规则:必须为12345abcdefghijklmnopqrstuvwxyz中的5-12位,且必须同时包含数字与字母
let params = {
creator: 'ben',
name: name,
owner: pubkey,
active: pubkey,
updateable: 1,//可选,账号是否可以更新(默认可以更新合约)
};
await u3.createUser(params);
主网与测试网为主侧链机制的多链架构,创建账号默认会先在主链上生成,然后需要同步到对应的侧链上,这一过程需要账号自身提供授权主动同步
以下示例为账号tester1主动将自身从主链同步到pioneer侧链上的过程, 注意config的节点配置需提供主链配置信息
- empoweruser(user,chain_name,owner_pk,active_pk,updateable)
const u3 = createU3(config);
const c = await u3.contract("ultrainio");
await c.empoweruser({
user: 'tester1',
chain_name: 'pioneer', // pioneer is one of the sidechain name
owner_pk: 'UTR...', // publicKey of owner permission
active_pk: 'UTR...', // publicKey of active permission
updateable: 1
})
转账方法使用非常频繁,UGAS的转账需要调用系统合约utrio.token.
- transfer(from,to,content,memo) 其中content这个字段必须严格为金额与符号拼接的字符串, 如 '1.0000 UGAS'
const u3 = createU3(config);
const c = await u3.contract('utrio.token')
// 使用位置参数
const result = await c.transfer('ben', 'bob', '1.2000 UGAS', '')
// 使用名称参数
const result = await c.transfer({from: 'bob', to: 'ben', quantity: '1.3000 UGAS', memo: ''})
- 如果要确认这笔转账正确被执行了,可以遵循以下步骤:
// 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: false, broadcast: false } 创建一个u3实例并且做一些action, 然后将未签名的交易发送到钱包中.
在这种情况下,u3仍然需要网络来发送请求
const u3_offline = createU3({ sign: false, broadcast: false });
const c = u3_offline.contract('utrio.token');
let unsigned_transaction = await c.transfer('ultrainio', 'ben', '1 UGAS', 'uu');
如果你把 httpEndpoint 设为null, u3将不发送网络请求
那么你需要像下面这样传入 transactionHeaders 参数.
其中abi 是可选的, 如果你忽略它, 那么u3会从本地目录下查找缓存文件.
本地缓存文件只有 'ultrainio' and 'utrio.token' 两个系统合约的abi
注意最大expiration时间是一个小时,也就是值为3600.
你可以通过u3.getBlockInfo 或者 rest 接口 http://xxx/v1/chain/get_block_info 来获取 ref_block_num 和 ref_block_prefix 的值
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');
另外一个例子是 createUser.
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: [`ben@active`],
});
在钱包中你可以提供私钥或助记词来签名,并将签名后的交易发送到链上.
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);
}
调用合约只会消耗合约Owner的资源,如果你想部署一个合约,请先购买一些资源.
主网环境下,请至开发者网站上选择合适的资源套餐并进行购买, 测试网环境下,请至测试网浏览器自行进行账号充值与资源购买。
- resourcelease(payer,receiver,slot,days,location)
location is the chain name you to use your resource
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
通过以下方法查询资源详情.
const account = await u3.getAccountInfo({ account_name: 'abcdefg12345' });
console.log(account.chain_resource[0].lease_num)
部署合约需要提供包含目标文件为 .abi,.wast,*.wasm 的三个文件的文件夹.
- deploy(contracts_files_path, deploy_account) 第一个参数为合约目标文件的绝对路径,第二个合约部署者账号.
const u3 = createU3(config);
await u3.deploy(path.resolve(__dirname, '../contracts/token/token'), 'bob');
const u3 = createU3(config);
const c = await u3.contract('ben');
await c.transfer('bob', 'ben', '1.0000 UGAS','');
//或者像这样调用
await u3.contract('ben').then(sm => sm.transfer('bob', 'ben', '1.0000 UGAS',''))
// 一笔交易也可以包含多个合约中的多个action
await u3.transaction(['ben', 'bob'], ({sm1, sm2}) => {
sm1.myaction(..)
sm2.myaction(..)
})
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提供了一个事件注册监听机制用来解决异步场景下业务需求.客户端首先订阅一个事件,提供一个用来接收消息的地址, 当合约中的某个方法触发时,该地址会收到来自链的推送消息.
- registerEvent(deployer, listen_url)
- unregisterEvent(deployer, listen_url)
deployer : 合约的部署者账号
listen_url : 接收消息的地址
注意: 如果你是在本地docker环境中使用改机制,请确认接收地址是一个可以从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');
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`] });

