TDC 开发文档
一、 依赖注入
<‑‑ 核心依赖 ‑‑>
<dependency>
<groupId>io.nuls.v2</groupId>
<artifactId>sdk4j-jdk8</artifactId>
<version>1.1.10.RELEASE</version>
</dependency>
<‑‑ RPC依赖 ‑>
<dependency>
<groupId>com.github.briandilley.jsonrpc4j</groupId>
<artifactId>jsonrpc4j</artifactId>
<version>1.1</version>
</dependency>
二、 地址创建
ECKey key = new ECKey();
Address address = new Address(CHAIN_ID, CoinType,
BaseConstant.DEFAULT_ADDRESS_TYPE,
SerializeUtils.sha256hash160(key.getPubKey()));
// 账户地址
String walletAddress =
AddressTool.getStringAddressByBytes(address.getAddressBytes(),
address.getPrefix());
// Private key
String privateKey = key.getPrivateKeyAsHex();
三
三、 交易
3.1 主币转账
/** Transfer */
public void transfer() {
String randomSeedNodeUrl = "http://47.241.101.72:8004/"; // 节点地址
String privateKey = ""; // 发送地址私钥
String fromAddress = ""; // 发送地址
String toAddress = ""; // 接收地址;
BigInteger amount = BigInteger.valueOf(10); // 转账金额
BigInteger scale = BigInteger.valueOf(8); // 精度
String nonce = getNonce(randomSeedNodeUrl, fromAddress) ;
BigInteger value = NumberUtil.mul(amount, scale ).toBigInteger();
List inputs = new ArrayList<>() ;
List outputs = new ArrayList<>() ;
TransferDto transferDto = new TransferDto();
CoinFromDto coinFromDto = new CoinFromDto();
CoinToDto coinToDto = 新 CoinToDto();
coinFromDto.setAssetChainId(chainId);
coinFromDto.setAssetId(assetId);
coinFromDto.setAddress(fromAddress);
coinFromDto.setAmount(value);
coinFromDto.setNonce(nonce);
inputs.add(coinFromDto);
coinToDto.setAssetChainId(chainId);
coinToDto.setAssetId(assetId);
coinToDto.setAddress(toAddress);
coinToDto.setAmount(value);
outputs.add(coinToDto);
transferDto.setInputs(inputs);
transferDto.setOutputs(outputs);
transferDto.setTime(DateUtil.currentSeconds());
Result transferTxOffline1 =
NulsSDKTool.createTransferTxOffline(transferDto);
Map
String> transferTxOffline = (Map)
transferTxOffline .getData() , String> transferTxOffline = (Map) transferTxOffline1.getData();
JSONObject j1 = new JSONObject();
j1. put("txput("ad
Hex", 传 输T Tx离线 .get("txHex"));
j1. dress", 从地 址取) ;
e 尔 K ey ,私t私 钥 匙串 y);Object>>;
j1. put(tFulR
Res ul/Key/si 三节在 g,
Result 资源 u 1 g结果 = post(randomSeedNodeUrl
点
+ "api/acco 预 ",
JSONObject jsonObject1 =
JSONObject.parseObject(JSONObject.toJSONString(resultSingResult.getData()));
SDKContext. 钱包_url = randomSeedNodeUrl;
结果<Map> result =
NulsSDKTool.broadcast(jsonObject1.get("txHex").toString());
}
3.2 代币转账
public void tokenTransfer() {
String randomSeedNodeUrl = "http://47.241.101.72:8004/"; // 节点地址
String privateKey = ""; // 发送地址的私钥
String fromAddress = ""; // 发送地址
String toAddress = ""; // 接收地址
BigInteger amount = BigInteger.valueOf(10); // 转账金额
BigInteger scale = BigInteger.valueOf(8); // 精度
String contractAddress = ""; // 合约地址
BigInteger tokenBalance = BigInteger.valueOf(10); // 发送地址的
代币余额
BigInteger value = NumberUtil.mul(amount, scale ).toBigInteger();
// 获取交易 gasLimit
int gasLimit = getGasLimit(fromAddress , contractAddress , "transfer" , new
Object[]{toAddress, value});
String nonce = getNonce(randomSeedNodeUrl, fromAddress);
//组装交易
JSONObject 参数 = new JSONObject();
参数.put( "fromAddress", fromAddress);
参数.put( "senderBalance", tokenBalance);
param.put("nonce", nonce);
param.put("toAddress", toAddress);
param.put("contractAddress", contractAddress);
param.put("gasLimit", gasLimit);
param.put("amount", value);
String resultSing = HttpRequest.post(randomSeedNodeUrl +
"api/contract/tokentransfer/offline").body(param.toJSONString()).execute().body
();
// String resultSing = HttpUtil.URLPostByJsonParameter(main +
"api/contract/tokentransfer/offline", param.toJSONString());
JSONObject jsonObject = JSONObject.parseObject(resultSing);
JSONObject jsonObject1 = (JSONObject) jsonObject.get("data");
//签名交易
param = new JSONObject();
param.put("txHex", jsonObject1.get("txHex"));
param.put("address", fromAddress);
param.put("priKey", 私钥) ;
, Object>> resultSingResult = post(randomSeedNodeUrl
+ "api/account/priKey/sign", param);
JSONObject jsonObject3 =
JSONObject.parseObject(JSONObject.toJSONString(resultSingResult.getData()));
//广播交易
SDKContext.wallet_url = randomSeedNodeUrl;
Result<Map<String , Object>> result =
NulsSDKTool.broadcast(jsonObject3.get("txHex").toString());
}
3.3 交易中使用的辅助方法:
公 共 静态 String 获取 Nonce(S 三 次方
baseU rl, String 地址 ) {
Result<M ap, String>> 余额> 上 ddre sByPr钥匙 =, 链Id, 资产Id);
getAccountB (randomSeedNode eUrl, 地址
}
公 共 静态 c 结果 获取 账户 转存款
录结 ( 字符串基础网址, 字符串地址, 链ID ,
在资产ID ) {
验证链 ID() ;
Map<Strin 对象 参数 = 新 H链ID", 哈希图() ;
params.put("asse chainIdID", );
params.put("asse assetsId);
结果 结果 ;
RestFulResult restFulResult = 发布 base rl + "api/accountledger/balance/"+
添加dress, params;
if(restFulResult.isSuccess()) {
result = Resu}lt.get uccess(restFulResult.getData());
else {
ErrorCode errorCode =
ErrorCode.init(restFulResult.getError().getCode());
result =
Result.getFailed(errorCode).setMsg(restFulResult.getError().getMessage());
}
return result;
public static RestFulResult<Map<String, Object>> post(String url, Map<String,
Object> params) {
try {
String resultStr =
HttpRequest.post(url).body(JSON.toJSONString(params)).execute().body();
RestFulResult<Map<String, Object>> result = toResult(resultStr);
return result;
} catch (Exception e) {
return RestFulResult.failed(CommonCodeConstanst. DATA_ERROR.getCode(),
e.getMessage(), null);
}
}
private static RestFulResult toResult (String str) throws IOException {
Map , Object> resultMap = JSONUtils.json map(str) ;
RestFulResult result = null;
Boolean b = (Boolean) resultMap.get("success");
if (b) {
result = RestFulResult.success(resultMap.get("data"));
} else {
Object dataObj = resultMap.get("data");
if (dataObj instanceof Map) {
, Object> data = (Map<String, Object>)
resultMap.get("data");
if (data != null) {
result = RestFulResult.failed(data.get("code").toString(),
data.get("msg").toString());
}
} 否则 {
结果 =
RestFulResult.failed(CommonCodeConstanst.SYS_UNKOWN_EXCEPTION.getCode(),
resultMap.toString());
}
}
return result;
}
public static int getGasLimit(String address, String contractAddress, String method,
Object[] args) {
估算Gas合约调用表单 gasContractCallForm = new
估算Gas合约调用表单() ;
gasContractCallForm.setSender(address);
gasContractCallForm.setContractAddress(contractAddress);
gasContractCallForm.setMethodName(method);
gasContractCallForm.setArgs(args);
Result gasResult =
NulsSDKTool.imputedContractCallGas(gasContractCallForm);
// 解析和获取gasLimit
return 0;
}
3.4 主要币种离线转账
public void createTxSimpleTransferOfTDC() throws Exception {
String fromAddress = ""; // 发送地址
String toAddress = ""; // 接收地址
NulsSDKBootStrap.initMain("http://47.241.101.72:8004/");
SDKContext.addressPrefix = "TDC";
SDKContext.main_chain_id = 66;
String value = "1.5";
int tokenDecimals = 8;
BigInteger amount = new
BigDecimal(value).multiply(BigDecimal.TEN.pow(tokenDecimals)).toBigInteger();
Result<Map> result = NulsSDKTool.createTxSimpleTransferOfNuls(fromAddress ,
toAddress, amount) ;
String txHex = (String) result.getData().get("txHex");
//签名
String prikey = ""; //发送地址私钥
result = NulsSDKTool.sign(txHex, fromAddress , prikey) ;
txHex = (String) result.getData().get("txHex");
String txHash = (String) result.getData().get("hash");
//广播
result = NulsSDKTool.broadcast(txHex);
System.out.println(String.format("hash: %s", txHash));
}
3.5 代币离线转账
public void tokenTransferTxOffline() throws Exception {
String fromAddress = ""; // 发送地址
String privateKey = ""; // 发送地址私钥
NulsSDKBootStrap.initMain("http://47.241.101.72:8004/");
SDKContext.addressPrefix = "TDC";
SDKContext.main_chain_id = 66;
// 在线接口(不能跳过,必须调用)‑ 账户余额
信息
Result accountBalanceR = NulsSDKTool.getAccountBalance(fromAddress,
SDKContext.main_chain_id, SDKContext.main_asset_id);
字符串 s = JSONUtils.obj PrettyJson(accountBalanceR) ;
地图 余额 = (地图) accountBalanceR.getData() ;
大整数 发送者费用余额 = new
大整数(余额.get( "available").toString());
字符串 nonce = 余额.get( "nonce").toString();
字符串 接收地址 = ""; // 接收地址
字符串 合约地址 = ""; // 合约地址
int tokenDecimals = 8;
// 转账代币数量
String tokenAmount = "10";
BigInteger amount = new
BigDecimal(tokenAmount).multiply(BigDecimal.TEN.pow(tokenDecimals)).toBigIntege
r();
String methodName = "transfer";
String methodDesc = "";
Object[] args = new Object[]{toAddress, amount};
假定GasContractCall表单iForm = new ImputedGasContractCallForm();
iForm.setSender(fromAddress);
iForm.setContractAddress(contractAddress);
iForm.setMethodName(methodName);
iForm.setMethodDesc(methodDesc);
iForm.setArgs(args);
Result iResult = NulsSDKTool.imputedContractCallGas(iForm);
Assert.assertTrue(JSONUtils.obj2PrettyJson(iResult), iResult.isSuccess());
Map result = (Map) iResult.getData();
Long gasLimit = Long.valueOf(result.get("gasLimit").toString());
Result<Map> map = NulsSDKTool.tokenTransferTxOffline(fromAddress,
senderFeeBalance, nonce, toAddress, contractAddress, gasLimit, amount,
"tokenTransferTxOffline");
String txHex = map.getData().get("txHex").toString();
System.out.println("txHex : {}" + txHex);
// 签名
Result res = NulsSDKTool.sign(txHex, fromAddress, privateKey);
Map signMap = (Map) res.getData();
// 在线接口 ‑ 交易广播
System.out.println("signMap.get(\"txHex\").toString() : {}" +
signMap.get("txHex").toString());
Result broadcaseTxR =
NulsSDKTool.broadcast(signMap.get("txHex").toString());
Assert.assertTrue(JSONUtils.obj2PrettyJson(broadcaseTxR),
broadcaseTxR.isSuccess());
Map data = broadcaseTxR.getData();
String hash1 = (String) data.get("hash");
System.out.println(String.format("hash: %s", hash1));
}
四、查询方法
4.1 余额查询
依赖注入:
public void getBalanceRpc() {
String randomSeedNodeUrl = "http://47.241.101.72:18003/jsonrpc"; // RPC
连接地址
String address = ""; // 地址
try {
JsonRpcHttpClient client = new JsonRpcHttpClient(new
URL(randomSeedNodeUrl));
Map result = client.invoke("getAccountBalance", new Object[]{CHAIN_ID,
TDCUtil.CHAIN_ID, 1, address}, Map.class, new HashMap<>( 1));
} catch (Throwable throwable)
}
}
4.2 代币余额查询
public void getTokenBalanceRpc() {
String address = ""; // 地址
Str ng合约 地址 = ""; // 合约地址
S r in Url
随机种子节点
= "http://47.241.101.72:18003/jsonrpc"; / RP C
connection address
BigDecimal balance = BigDecimal.ZERO;
try {
JsonRpcHttpClient client = new JsonRpcHttpClient(new
URL(ra domSeedNodeUrl));JSONObject result =
client.invoke("getAccountTokens", new Object[]{CHAIN_ID,
1, 100, address}, JSONObject.class, new HashMap<>());iffor (Object obj : list)
class);(result != null && result.containsKey("list") &&
result.getJSONArray("list").size() > 0) { List<JSONObject> list
=
JSON.parseArray(result.getJSONArray("list").toJSONString(),
JSONObject
Object: obj; ;
for (JSONObject json accData {
if
=
tAd
(contr acc dress.equals(jsonObject.getString( "合 约 地 址 )" )))) {
balance =
jsonObject.get 大 BigDecimal("balance").movePoint 余 额(jsonObject.get Integer("decima
ls"));
中 ;
}
}
} }
catch (Exception e) {
}
}
4.3 根据哈希查询交易详情
公共 哔结正在处哈 RPC查查询TX()
悠果理中 希 询=""; // 交易 哈希
String randomSeedNodeUrl = "http://47.241.101.72:18003/jsonrpc"; // RPC
连接地址 try {
Result result = null;
Map<String , String> headers = new HashMap<String , String>() 1);
JsonRpcHttpClient client = new JsonRpcHttpClient(new
URL(randomSeedNodeUrl), headers);
Map resultMap = client.invoke("getTx", new Object[]{CHAIN_ID, txHash},
Map.class, headers);
if (resultMap != null) {
result = Result.getSuccess(null);
result.setData(resultMap);
return result;
}
} catch (Throwable ex) {
}
}
五、查询接口列表
功能 方法名称 参数 参数说明
说明
查询 getChainInfo 无
区块链
信息
查询有关
区块链 getInfo [chainId]
操作的
一般信息
查询最新 getBestBlockHead [chainId]
区块头
根据高度 getHeaderByHeight [chainId,
查询区块 t blockHeight]
头
查询区块 通过哈希获取头部 [chainId,
通过哈希获取头部 blockHash]
通过高度查询 通过高度获取区块 [chainId,
完整的区块 blockHeight]
查询区块 通过哈希获取完整的区块 [chainId,
完整的区块 blockHash]
通过哈希
查询区块 getBlockHeaderLi [链ID, 页码 chainId: int //链ID
头列表 st pageNumber:int //页码
页面大小, pageSize:int //每页项数
是否隐藏 [1‑1000] 检索 值
打包地址
isHidden:boolean //是否
隐藏只有共识奖励交易的区块
packedAddress:string //按区块
打包地址过滤,非必需
查询账户详情 getAccount [chainId,address]
根据别名查询 getAccountByAlia [chainId,alias]
账户详情 s
查询账户 getAccountLedger [chainId,address]
链上资产列表 列表
查询账户单一 getAccountBalanc [chainId,assetChainId,assetId,address]
chainId:int //链ID
资产余额 e assetChainId:int //资产
链ID
assetId: int //资 资产ID //
产ID地址: 账户
string
查询别名可用性 isAliasUsable [chainId,
alias]
查询交易详 getTx [chainId,
情 txHash]
查询 getAccountTxs chainId: int //链ID
交易 [chainId, 页码:整数 页 //页码
列表 页码,页大 页大小:整 数 // /每页项目数量
小, ,获取地址,
地址, 取值[1‑1000]
交易类型, 交易类型:整数 //交易
是否隐藏] 类型(交易类型),类型=0时查询所
有交易
是否隐藏:布尔 //是否隐藏共识奖
励交易
txType=1)
查询 getBlockTxList chainId: int //链ID
交易 [chainId, pageNumber:int //页码
pageNumber, pageSize:int //每页条数
block pageSize, 每页检索
blockHeight, 值[1‑1000]
txType] blockHeight:long //区块
高度
txType:int //交易 类型
(txType),查询所有
type= 的交易
查询 获取账户交易 链ID: int //Chain ID
账户 [链ID, 页码:int //页码
交易 页码, 每页大小:int / //条目 数
列表 每页大小, 每页检索
地址, 值[1‑1000]
交易类型, 地址: 字符串 //账户地址
是否隐藏]
交易类型:int //交易
类型(交易类型),查询所有
当类型=0时的交易记录
是否隐藏:boolean //是否
隐藏共识奖励
交易(交易类型为
1时)
验证 验证交易 [链ID, 链ID: 整数 //链 in ID
离线交易 交易数据] 交易数据:字符串 //组装的
合法性 十六进制字符串
组装好的 交易 与组装
序列
化
交易
广播 广播交易 [链ID, 链ID:int //链 编号
离线 txHex] txHex:string // 十六进制
组装 组装后的
交易
交易序列化字符串
查询可用 获取共识节点 [链ID, chainId: int //链ID
委派的 s 页码, 页码:int //页码
共识节点 每页大小, 每页大小:int / 每页条数
列表 类型] 每页检索
值[1‑1000]
类型:int //节点类型
//0:所有节点,1:正常
节点,2:开发者
节点,3:大使节点
查询所有 getAllConsensusN [链 ID, 链 ID: int //链 ID
委托的 节点 页码, 页码:int //页码
共识节点 页大小] 页大小:int //每页条数
列表 每页获取
值[1‑1000]
查询 获取账户共 [链ID, 链ID: int //链 ID
共识节点 合集 页码, 页码: int //页码
列表 委托 页大小, pageSize:int //每页条数
地址]
由账号 每页检索
取值[1‑1000]
address:string //帐 户
地址
chainId: int //链ID
查询共识节点 getConsensusNode [chainId,
详情 txHash] txHash:string //交易
交易哈希 当节点
创建的
查询账户创建的 getAccountConsensusNode
[chainId,
共识节点详情 查 address]
询列表
getConsensusDeposit [chainId, chainId: int //链ID
节点委托信息 页码, pageNumber:int //页码
交易哈
希
页面大小, pageSize:int //每页条数
txHash] 每页检索
值[1‑1000]
txHash:string //交易
哈希当 节点
创建时
节点创建时
查询 获取所有共识委 [chainId, chainId: int //链ID
历史 存款 pageNumber, pageNumber:int //页码
pageSize,
节点的委托列 pageSize:int //每页条目数
txHash,
表 每页获取
type]
取值[1‑1000]
txHash:string //交易
哈希创建时 的哈希
type:int //0:加入委托,1:
退出委托,2:所有
chainId: int //链ID
查询账户 getAccountDeposi [chainId,
委托列表 t 页码, 页码: int //页码
页面大小, pageSize:int //每页项目数
地址, 每页检索
代理哈希] 数值[1‑1000]
地址:string //账户地址
交易哈希:string //节点
创建时的交易哈希
查询所有账户 如果为空
getAccountDeposi
tValue chainId:int //链ID
查询账户的总委托金额
[chainId, 地址:string //账户
地址,
代理哈希 ] 地址
交易哈希:string //节点创建时的
交易哈希,查询所有账户
如果为空
查询共识
处罚 链 id:int // 链ID
getPunishList
[chainId,
PageNumbe , 页码:int //页码
列表 页大小, 页大小:int //每页条数
0, 每页检索
代理地址 值[1‑1000]
] 类型:int // 处罚类型
0:所有,1:黄牌,2:红牌
代理地址:string
//共识节点的
委托账户地址
查询 轮次 getRoundList [chainId, chainId: int //链 ID
列表 pageNumber,pageSize]
pageNumber:int //页码
pageSize:int //每页条数
每页检索数量
取值[1‑1000]
查询合约详情 chainId: int //链ID
getContract [chainId,contractAddress] contractAddress:string
//合约地址
查询合约列表 chainId: int //链ID
getContractList pageNumber:int //页码 pageSize:int
//每页条数
[chainId,pageNumber,pageSize,
仅NRC 20, 每页检索
是否隐藏] 数值[1‑1000]
仅NRC 20:布尔型
//仅查询 NRC 20
合约
isHidden: 布尔型 //是否
隐藏NRC 20 合约,此
参数仅在
NRC 20=false
查询 getContractTxList chainId: int //链 ID
合约相关交易 t [chainId, pageNumber:in //页码 number
pageNumber, pageSize:int //每页条目数 数量
列表 页大小, 每页取
交易类型, 取值[1‑1000]
合约地址 交易类型:int //交易类型
ess] 查询所有交易时
默认值为0
合约地址:string
//合约地址
查询NRC 获取合约代币 [链ID, 链ID: int //链ID
合约 页码, 页码:int //页号 页
s
转账记录 页大小, pageSize:整 数 //每页 条目数
合约地址
列表
ess] 每页,取值
范围[1‑1000]
contractAddress:string
//合约地址
查询 getTokenTransfer [chainId, chainId: 整型 //链 ID
账户 NRC s pageNumber, pageNumber: int //页码 页码
转账记录列表 每页数量, 每页数量:int / /项目数量
地址,合约地 每页, 检索值[1‑1000]
址] address:string //账户地址
contractAddress:string //合约
地址
chainId: int //链ID
type: int //0:过去14天, 1:
过去一周, 2:过去一月,
3:过去一年
交易量统计 getTxStatistical [chainId,type]
共识节点数量 getConsensusNode [chainId]
统计 计数
s
共识奖励 getConsensusStat [chainId, chainId: int //链ID
统计 类型 type] type: int //0:14天,1:周,
2:月,3:年,4:所有
获取年度奖励统计年化奖励率 奖励 [chainId, type: int //0:14天,1:周,
type] 2:月,3:年,4:全部
统计