波场(Tron)trc20转账(java版本)

tronweb版本请参考 波场trc20转账(tronWeb版本)


前期准备

1、trc20代币的地址(contract-address)

发行trc20代币步骤详见 波场(Tron)发行trc20代币(Shasta测试网络)

2、含有该trc20代币的地址&秘钥(wallet-address & wallet-private-key)

3、FullNode服务地址

为了避免私钥泄露,一般都要我们搭建自己的本地节点。
我这里就直接搭建自己的FullNole (Nile测试网) 详细的搭建可以看 波场(Tron)发行trc20代币(Shasta测试网络) 的“写在后面”部分 里面有提及怎么搭建Nile网的FullNode节点


使用到的api

波场官方Api说明

1、只能合约调用API /wallet/triggersmartcontract
波场(Tron)trc20转账(java版本)_第1张图片
2、交易签名api /wallet/gettransactionsign
波场(Tron)trc20转账(java版本)_第2张图片
3、交易广播API /wallet/broadcasttransaction
波场(Tron)trc20转账(java版本)_第3张图片


trc20转账实现

feign接口

package com.tricky.tron.trc20.feign;

import com.alibaba.fastjson.JSONObject;
import com.tricky.tron.trc20.feign.dt.GetTransactionSign;
import com.tricky.tron.trc20.feign.dt.TriggerSmartContract;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

/**
 * tron-full-node接口
 *
 * @Autor Shadow 2020/10/22
 * @Date 2020-10-22 15:36:02
 */
@FeignClient(url = "${tron.url}", name = "tron-node", configuration = {
     JacksonEncoder.class, JacksonDecoder.class})
public interface TronFullNodeFeign {
     

	/**
	 * 只能合约调用接口
	 *
	 * @param param
	 * @return
	 */
	@PostMapping("/wallet/triggersmartcontract")
	TriggerSmartContract.Result triggerSmartContract(@RequestBody TriggerSmartContract.Param param);


	/**
	 * 使用私钥签名交易.(存在安全风险,trongrid已经关闭此接口服务,请使用离线方式或者自己部署的节点)
	 *
	 * @param param
	 * @return
	 */
	@PostMapping("/wallet/gettransactionsign")
	JSONObject getTransactionSign(@RequestBody GetTransactionSign.Param param);


	/**
	 * 广播签名后的交易.
	 *
	 * @param rawBody
	 * @return
	 */
	@PostMapping("/wallet/broadcasttransaction")
	JSONObject broadcastTransaction(@RequestBody Object rawBody);
}

转账的Service


import com.alibaba.fastjson.JSONObject;
import com.tricky.tron.trc20.feign.TronFullNodeFeign;
import com.tricky.tron.trc20.feign.dt.GetTransactionSign;
import com.tricky.tron.trc20.feign.dt.TriggerSmartContract;
import com.tricky.tron.trc20.utils.ByteArray;
import com.tricky.tron.trc20.utils.TronUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;

/**
 * trc20-service
 *
 * @Autor Shadow 2020/10/22
 * @Date 2020-10-22 15:49:41
 */
@Service
public class Trc20Service {
     
	private static Logger logger = LoggerFactory.getLogger(Trc20Service.class);

	@Value("${tron.contract-address}")
	private String contractAddress;//hex格式

	@Value("${tron.address}")
	private String address;//发币地址 hex格式

	@Value("${tron.private-key}")
	private String privateKey;//私钥

	//token的精度  就是小数点后面有多少位小数 然后1后面加多少个0就可以
	private static final BigDecimal decimal = new BigDecimal("1000000");

	@Autowired
	private TronFullNodeFeign feign;

	/**
	 * 发送trc20交易  返回交易id
	 *
	 * @param toAddress 收币地址
	 * @param amount    转出数量
	 * @param remark    备注
	 * @return
	 */
	public String sendTrc20Transaction(String toAddress, String amount, String remark) {
     
		try {
     
			String hexAddress = toAddress;
			if (toAddress.startsWith("T")) {
     
				hexAddress = TronUtils.toHexAddress(toAddress);
			}
			if (StringUtils.isEmpty(hexAddress)) {
     
				logger.error("转账失败:收款地址为空");
				return null;
			}
			if (StringUtils.isEmpty(amount)) {
     
				logger.error("转账失败:额度为空");
				return null;
			}
			BigDecimal a = new BigDecimal(amount);
			if (a.compareTo(BigDecimal.ZERO) <= 0) {
     
				logger.error("转账失败:额度不符合规则 " + amount);
				return null;
			}
			if (remark == null) {
     
				remark = "";
			}
			String params = hexAddress + "@" + amount + "@" + remark;
			TriggerSmartContract.Param param = createTriggerSmartContractParam();
			param.setFunction_selector("transfer(address,uint256)");
			String addressParam = addZero(hexAddress, 64);
			String amountParam = addZero(new BigDecimal(amount).multiply(decimal).toBigInteger().toString(16), 64);
			param.setParameter(addressParam + amountParam);
			logger.info("创建交易参数:" + JSONObject.toJSONString(param));
			TriggerSmartContract.Result obj = feign.triggerSmartContract(param);
			logger.info("创建交易结果:" + JSONObject.toJSONString(obj));
			if (!obj.isSuccess()) {
     
				logger.error("创建交易失败|" + params);
				return null;
			}
			//交易签名
			GetTransactionSign.Param signParam = new GetTransactionSign.Param();
			TriggerSmartContract.Transaction transaction = obj.getTransaction();
			transaction.getRaw_data().put("data", ByteArray.toHexString(remark.getBytes()));
			signParam.setTransaction(transaction);
			signParam.setPrivateKey(privateKey);
			logger.info("签名交易参数:" + JSONObject.toJSONString(signParam));
			Object dt = feign.getTransactionSign(signParam);
			logger.info("签名交易结果:" + JSONObject.toJSONString(dt));
			//广播交易
			if (dt != null) {
     
				logger.info("广播交易参数:" + JSONObject.toJSONString(dt));
				JSONObject rea = feign.broadcastTransaction(dt);
				logger.info("广播交易结果:" + JSONObject.toJSONString(rea));
				if (rea != null) {
     
					Object result = rea.get("result");
					if (result instanceof Boolean) {
     
						if ((boolean) result) {
     
							return (String) rea.get("txid");
						}
					}
				}
			}
		} catch (Throwable t) {
     
			logger.error(t.getMessage(), t);
		}
		return null;
	}

	/**
	 * 创建智能合约参数
	 *
	 * @return
	 */
	private TriggerSmartContract.Param createTriggerSmartContractParam() {
     
		TriggerSmartContract.Param tscParam = new TriggerSmartContract.Param();
		tscParam.setOwner_address(address);
		tscParam.setContract_address(contractAddress);
		tscParam.setFee_limit(1000000L);
		return tscParam;
	}

	/**
	 * 补充0到64个字节
	 *
	 * @param dt
	 * @return
	 */
	private String addZero(String dt, int length) {
     
		StringBuilder builder = new StringBuilder();
		final int count = length;
		int zeroAmount = count - dt.length();
		for (int i = 0; i < zeroAmount; i++) {
     
			builder.append("0");
		}
		builder.append(dt);
		return builder.toString();
	}
}

页面演示

打开页面 http://localhost:3600/zmm/
代码在最后
波场(Tron)trc20转账(java版本)_第4张图片

波场(Tron)trc20转账(java版本)_第5张图片


后台输出打印

波场(Tron)trc20转账(java版本)_第6张图片


交易结果查询 (我这里是Nile网络)

Nile测试网浏览器
输入上面的交易id 5e1863d83b363f04934d650dd8d8b9acd1d505820102ee2a95a0347e128cb79d

波场(Tron)trc20转账(java版本)_第7张图片

完美 我的备注也看到了

波场(Tron)trc20转账(java版本)_第8张图片


代码

有积分的就在这里下载吧
trc20-转账 如果积分超过15的话,可以留言喊我改一下(这个每下载一次,都会自动增加消耗积分,要手动把它改回去)
如果下载了我的代码的朋友,需要把 setFee_limit 里面的费用提高至少4倍(因为后面波场的这个费用涨了4倍)

demo页面

波场(Tron)trc20转账(java版本)_第9张图片


写在最后

如果有啥问题 可以评论留言哦~
不喜勿喷


2020-12月记
如果下载了我的代码的朋友,需要把 setFee_limit 里面的费用提高至少4倍(因为后面波场的这个费用涨了4倍)

你可能感兴趣的:(波场,java-tron,区块链)