BUMO 智能合约是一段JavaScript
代码,标准(ECMAScript as specified in ECMA-262)。合约的初始化函数是 init
, 执行的入口函数是 main
函数,查询接口是 query
。这些函数的参数字符串 input
,是调用该合约的时候指定的。 下面是一个简单的例子
"use strict";
function init(input)
{
/*init whatever you want*/
return;
}
function main(input)
{
let para = JSON.parse(input);
if (para.do_foo)
{
let x = {
'hello' : 'world'
};
}
}
function query(input)
{
return input;
}
BUMO 智能合约内提供了全局对象 Chain
和 Utils
, 这两个对象提供了多样的方法和变量,可以获取区块链的一些信息,也可驱动账号发起所有交易,除了设置门限和权重这两种类型的操作。
注意,自定义的变量不要与内置对象重复,否则会造成不可控的数据错误。
对象.方法(变量)
获取账号余额
Chain.getBalance('buQsZNDpqHJZ4g5hz47CqVMk5154w1bHKsHY');
打印日志
Utils.log('hello');
当前区块号
Chain.block.number;
只读权限是指不会写数据到区块链的接口函数,比如获取余额 Chain.getBalance。
可写权限是指会写数据到区块链的接口函数,比如转账 Chain.payCoin。
init
和 main
能调用所有的内置函数
query
只能调用只读权限的函数,否则在调试或者执行过程中会提示接口未定义
所有内部函数的调用,如果失败则返回 false 或者直接抛出异常执行终止,成功则为其他对象。如果遇到参数错误,会在错误描述中提示参数位置出错,这里的位置指参数的索引号,即从 0 开始计数。例如 parameter 1
表示第 2 个参数错误。如下例子:
Chain.issueAsset("CNY", 10000);
/*
错误描述:
Contract execute error,issueAsset parameter 1 should be a string
指第 2 个参数应该为字符串
*/
本章节介绍 Chain 对象的一些方法,包括 Chain.load、 Chain.store、 Chain.del、 Chain.getBlockHash、 Chain.tlog、 Chain.getAccountMetadata、 Chain.getBalance、Chain.getAccountAsset、Chain.getContractProperty、Chain.payCoin、Chain.issueAsset、Chain.payAsset、Chain.delegateCall、Chain.delegateQuery、Chain.contractCall、Chain.contractQuery、Chain.contractCreate。
函数描述
获取合约账号的metadata信息。
函数调用
Chain.load(metadata_key);
参数说明
示例
let value = Chain.load('abc');
/*
权限:只读
返回:成功返回字符串,如 'values', 失败返回false
*/
函数描述
存储合约账号的metadata信息。
函数调用
Chain.store(metadata_key, metadata_value);
参数说明
示例
Chain.store('abc', 'values');
/*
权限:可写
返回:成功返回true, 失败抛异常
*/
函数描述
删除合约账号的metadata信息。
函数调用
Chain.del(metadata_key);
参数说明
示例
Chain.del('abc');
/*
权限:可写
返回:成功返回true, 失败抛异常
*/
函数描述
获取区块信息。
函数调用
Chain.getBlockHash(offset_seq);
参数说明
示例
let ledger = Chain.getBlockHash(4);
/*
权限:只读
返回:成功返回字符串,如 'c2f6892eb934d56076a49f8b01aeb3f635df3d51aaed04ca521da3494451afb3',失败返回 false
*/
函数描述
输出交易日志。
函数调用
Chain.tlog(topic,args...);
参数说明
示例
Chain.tlog('transfer',sender +' transfer 1000',true);
/*
权限:可写
返回:成功返回 true,失败抛异常
*/
函数描述
获取指定账号的metadata
函数调用
Chain.getAccountMetadata(account_address, metadata_key);
参数说明
示例
let value = Chain.getAccountMetadata('buQsZNDpqHJZ4g5hz47CqVMk5154w1bHKsHY', 'abc');
/*
权限:只读
返回:成功返回字符串,如 'values', 失败返回false
*/
函数描述
获取账号coin amount
函数调用
Chain.getBalance(address);
参数说明
示例
let balance = Chain.getBalance('buQsZNDpqHJZ4g5hz47CqVMk5154w1bHKsHY');
/*
权限:只读
返回:字符串格式数字 '9999111100000'
*/
函数描述
获取某个账号的资产信息
函数调用
Chain.getAccountAsset(account_address, asset_key);
参数说明
示例
let asset_key =
{
'issuer' : 'buQsZNDpqHJZ4g5hz47CqVMk5154w1bHKsHY',
'code' : 'CNY'
};
let bar = Chain.getAccountAsset('buQsZNDpqHJZ4g5hz47CqVMk5154w1bHKsHY', asset_key);
/*
权限:只读
返回:成功返回资产数字如'10000',失败返回 false
*/
函数描述
获取合约账号属性
函数调用
Chain.getContractProperty(contract_address);
参数说明
示例
let value = Chain.getContractProperty('buQcFSxQP6RV9vnFagZ31SEGh55YMkakBSGW');
/*
权限:只读
返回:成功返回JSON对象,如 {"type":0, "length" : 416}, type 指合约类型, length 指合约代码长度,如果该账户不是合约则,length 为0.
失败返回false
*/
函数描述
转账
函数调用
Chain.payCoin(address, amount[, input]);
参数说明
示例
Chain.payCoin("buQsZNDpqHJZ4g5hz47CqVMk5154w1bHKsHY", "10000", "{}");
/*
权限:可写
返回:成功返回 true,失败抛异常
*/
函数描述
发行资产
函数调用
Chain.issueAsset(code, amount);
参数说明
示例
Chain.issueAsset("CNY", "10000");
/*
权限:可写
返回:成功返回 true,失败抛异常
*/
函数描述
转移资产
函数调用
Chain.payAsset(address, issuer, code, amount[, input]);
参数说明
示例
Chain.payAsset("buQsZNDpqHJZ4g5hz47CqVMk5154w1bHKsHY", "buQgmhhxLwhdUvcWijzxumUHaNqZtJpWvNsf", "CNY", "10000", "{}");
/*
权限:可写
返回:成功返回 true,失败抛异常
*/
函数描述
委托调用
函数调用
Chain.delegateCall(contractAddress, input);
参数说明
Chain.delegateCall
函数会触发被调用的合约main
函数入口,并且把当前合约的执行环境赋予被调用的合约。
示例
let ret = Chain.delegateCall('buQBwe7LZYCYHfxiEGb1RE9XC9kN2qrGXWCY','{}');
/*
权限:可写
返回:成功会返回结果,失败抛出异常
*/
函数描述
委托查询
函数调用
Chain.delegateQuery(contractAddress, input);
参数说明
Chain.delegateQuery
函数会触发被调用的合约query
函数入口,且把当前合约的执行环境赋予被调用的合约
示例
let ret = Chain.delegateQuery('buQBwe7LZYCYHfxiEGb1RE9XC9kN2qrGXWCY',"");
/*
权限:只读
返回:如果目标账户为普通账户,则返回true,如果目标账户为合约,调用成功则返回字符串 {"result":"4"},其中 result 字段的值即查询的具体结果,调用失败返回 {"error":true} 字符串。
*/
函数描述
调用合约
函数调用
Chain.contractCall(contractAddress, asset, amount, input);
参数说明
Chain.contractCall
函数会触发被调用的合约 main
函数入口。
示例
let ret = Chain.contractCall('buQBwe7LZYCYHfxiEGb1RE9XC9kN2qrGXWCY',true, toBaseUnit("10"), "");
/*
权限:可写
返回:如果目标账户为普通账户,则返回true,如果目标账户为合约,调用成功则返回main函数的返回值,调用失败则抛出异常
*/
函数描述
查询合约
函数调用
Chain.contractQuery(contractAddress, input);
参数说明
Chain.contractQuery
会调用合约的查询接口
示例
let ret = Chain.contractQuery('buQBwe7LZYCYHfxiEGb1RE9XC9kN2qrGXWCY',"");
/*
权限:只读
返回:调用成功则返回字符串 {"result":"xxx"},其中 result 字段的值即查询的具体结果,调用失败返回 {"error":true} 字符串。
*/
函数描述
创建合约
函数调用
Chain.contractCreate(balance, type, code, input);
参数说明
Chain.contractCreate
创建合约。
示例
let ret = Chain.contractCreate(toBaseUnit("10"), 0, "'use strict';function init(input){return input;} function main(input){return input;} function query(input){return input;} ", "");
/*
权限:可写
返回:创建成功返回合约地址,失败则抛出异常
*/
本章节介绍Chain对象的一些变量,分别区块信息(Chain.block)、交易信息(Chain.tx)、消息(Chain.msg)相关变量和Chain.thisAddress。区块信息的变量包括 Chain.block.timestamp、Chain.block.number。交易信息的变量包括Chain.tx.initiator、 Chain.tx.sender、Chain.tx.gasPrice、 Chain.tx.hash、 chain.tx.feeLimit。消息的变量包括 Chain.msg.initiator、Chain.msg.sender、Chain.msg.coinAmount、Chain.msg.asset、Chain.msg.nonce、Chain.msg.operationIndex。
Chain.block.timestamp
变量描述
当前交易执行时候所在的区块时间戳。
Chain.block.number
变量描述
当前交易执行时候所在的区块高度。
交易是用户签名的那笔交易信息。
Chain.tx.initiator
变量描述
交易最原始的发起者,即交易的费用付款者。
Chain.tx.sender
变量描述
交易最原始的触发者,即交易里触发合约执行的操作的账户。 例如某账号发起了一笔交易,该交易中有个操作是调用合约Y(该操作的source_address是x),那么合约Y执行过程中,sender的值就是x账号的地址。
示例
let bar = Chain.tx.sender;
/*
那么bar的值是x的账号地址。
*/
Chain.tx.gasPrice
变量描述
交易签名里的gas价格。
Chain.tx.hash
变量描述
交易的hash值。
Chain.tx.feeLimit
变量描述
交易的限制费用。
消息是在交易里触发智能合约执行产生的信息。在触发的合约执行的过程中,交易信息不会被改变,消息会发生变化。例如在合约中调用 Chain.contractCall,Chain.contractQuery的时候,消息会变化。
Chain.msg.initiator
变量描述
本消息的原始的发起者账号。
Chain.msg.sender
变量描述
本次消息的触发者账号。
示例
例如某账号发起了一笔交易,该交易中有个操作是调用合约Y(该操作的source_address是x),那么合约Y执行过程中,sender的值就是x账号的地址。
let bar = Chain.msg.sender;
/*
那么bar的值是x的账号地址。
*/
Chain.msg.coinAmount
变量描述
本次支付操作的 BU coin
Chain.msg.asset
变量描述
本次支付操作的资产
示例
{
"amount": 1000,
"key" : {
"issuer": "buQsZNDpqHJZ4g5hz47CqVMk5154w1bHKsHY",
"code":"CNY"
}
}
Chain.msg.nonce
变量描述
本次交易里的发起者的nonce值,即Chain.msg.initiator账号的 nonce值。
Chain.msg.operationIndex
变量描述
触发本次合约调用的操作的序号
示例
例如某账号A发起了一笔交易tx0,tx0中第0(从0开始计数)个操作是给某个合约账户转移资产(调用合约), 那么Chain.msg.operationIndex
的值就是0。
let bar = Chain.msg.operationIndex;
/* bar 是一个非负整数*/
变量描述
当前合约账号的地址
示例
例如账号x发起了一笔交易调用合约Y,本次执行过程中,该值就是Y合约账号的地址。
let bar = Chain.msg.thisAddress;
/*
bar的值是Y合约的账号地址。
*/
本章节介绍 Utils 对象的一些方法,包括 Utils.log、Utils.stoI64Check、Utils.int64Add、Utils.int64Sub、Utils.int64Mul、Utils.int64Mod、Utils.int64Div、Utils.int64Compare、Utils.assert、Utils.sha256、Utils.ecVerify、Utils.toBaseUnit、Utils.addressCheck、Utils.toAddress。
函数描述
输出日志。
函数调用
Utils.log(info);
参数说明
示例
let ret = Utils.log('hello');
/*
权限:只读
返回:成功无返回值,会在对应的合约执行进程里,输出一段Trace级别的日志,如 V8contract log[buQsZNDpqHJZ4g5hz47CqVMk5154w1bHKsHY:hello];失败返回 false。
*/
函数描述
字符串数字合法性检查。
函数调用
Utils.stoI64Check(strNumber);
参数说明
示例
let ret = Utils.stoI64Check('12345678912345');
/*
权限:只读
返回:成功返回 true,失败返回 false
*/
函数描述
64位加法。
函数调用
Utils.int64Add(left_value, right_value);
参数说明
示例
let ret = Utils.int64Add('12345678912345', 1);
/*
权限:只读
返回:成功返回字符串 '12345678912346', 失败抛异常
*/
函数描述
64位减法。
函数调用
Utils.int64Sub(left_value, right_value);
参数说明
示例
let ret = Utils.int64Sub('12345678912345', 1);
/*
权限:只读
返回:成功返回字符串 '12345678912344',失败抛异常
*/
函数描述
64位乘法。
函数调用
Utils.int64Mul(left_value, right_value);
参数说明
示例
let ret = Utils.int64Mul('12345678912345', 2);
/*
权限:只读
返回:成功返回字符串 '24691357824690',失败抛异常
*/
函数描述
64位取模。
函数调用
Utils.int64Mod(left_value, right_value);
参数说明
示例
let ret = Utils.int64Mod('12345678912345', 2);
/*
权限:只读
返回:成功返回字符串 '1',失败抛异常
*/
函数描述
64位除法。
函数调用
Utils.int64Div(left_value, right_value);
参数说明
示例
let ret = Utils.int64Div('12345678912345', 2);
/*
权限:只读
返回:成功返回 '6172839456172',失败抛异常
*/
函数描述
64位比较。
函数调用
Utils.int64Compare(left_value, right_value);
参数说明
示例
let ret = Utils.int64Compare('12345678912345', 2);
/*
权限:只读
返回:成功返回数字 1(左值大于右值),失败抛异常
*/
返回值
1:左值大于右值,0:等于,-1 :小于
函数描述
64断言。
函数调用
Utils.assert(condition[, message]);
参数说明
示例
Utils.assert(1===1, "Not valid");
/*
权限:只读
返回:成功返回 true,失败抛异常
*/
函数描述
sha256计算。
函数调用
Utils.sha256(data[, dataType]);
参数说明
返回值
成功会hash之后的base16编码后的字符串,失败会返回 false。
示例
let ret = Utils.sha256('61626364');
/*
权限:只读
功能:对
返回:成功返回64个字节的base16格式字符串 '88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589',失败返回false
*/
函数描述
校验签名是否合法。
函数调用
Utils.ecVerify(signedData, publicKey,blobData [, blobDataType]);
参数说明
返回值
成功会返回true,失败会返回 false
示例
let ret = Utils.ecVerify('3471aceac411975bb83a22d7a0f0499b4bfcb504e937d29bb11ea263b5f657badb40714850a1209a0940d1ccbcfc095c4b2d38a7160a824a6f9ba11f743ad80a', 'b0014e28b305b56ae3062b2cee32ea5b9f3eccd6d738262c656b56af14a3823b76c2a4adda3c', 'abcd', 1);
/*
权限:只读
返回:成功会返回true,失败会返回 false
*/
函数描述
变换单位。
函数调用
Utils.toBaseUnit(value);
参数说明
返回值
成功会返回乘以 10^8 的字符串,失败会返回 false
示例
let ret = Utils.toBaseUnit('12345678912');
/*
权限:只读
返回:成功返回字符串 '1234567891200000000',失败抛异常
*/
函数描述
地址合法性检查。
函数调用
Utils.addressCheck(address);
参数说明
返回值
成功返回 true,失败返回 false。
示例
let ret = Utils.addressCheck('buQgmhhxLwhdUvcWijzxumUHaNqZtJpWvNsf');
/*
权限:只读
返回:成功返回 true,失败返回 false
*/
函数描述
公钥转地址。
函数调用
Utils.toAddress(public_key);
参数说明
返回值
成功,返回账号地址;失败返回false
示例
let ret = Utils.toAddress('b0016ebe6191f2eb73a4f62880b2874cae1191183f50e1b18b23fcf40b75b7cd5745d671d1c8');
/*
权限:只读
返回:成功返回 "buQi6f36idrKiGrno3RcdjUjGAibUC37FJK6",失败返回false
*/
JavaScript异常
当合约运行中出现未捕获的JavaScript异常时,处理规定:
151
。执行交易失败
合约中可以执行多个交易,只要有一个交易失败,就会抛出异常,导致整个交易失败