├── pom.xml
└── src
└── main
├── java
└── ai
│ └── turbochain
│ └── ipex
│ └── wallet
│ ├── WalletRpcApplication.java
│ ├── component
│ └── UsdtWatcher.java
│ ├── config
│ ├── Constant.java
│ ├── JsonrpcClient.java
│ ├── RpcClientConfig.java
│ └── Swagger2.java
│ ├── controller
│ └── WalletController.java
│ ├── entity
│ ├── BTCBalanceCalledCount.java
│ ├── BalanceData.java
│ ├── BitCoin.java
│ ├── BitCoinBlock.java
│ ├── BitCoinTX.java
│ ├── BtcBean.java
│ ├── BtcInput.java
│ ├── BtcOutput.java
│ ├── BtcUtxo.java
│ ├── Input.java
│ ├── Out.java
│ └── SpendingOutpoints.java
│ ├── service
│ └── TransactionService.java
│ └── util
│ ├── BTCAccountGenerator.java
│ ├── HttpRequest.java
│ └── MessageResult.java
└── resources
├── application-dev.properties
├── application-prod.properties
├── application.properties
└── logback-spring.xml
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 | java-usdt-api
7 | 1.0.1
8 |
9 |
10 | ai.turbochain.ipex
11 | ipex-wallet-rpc
12 | 1.0.1
13 |
14 |
15 |
16 |
17 | org.springframework.boot
18 | spring-boot-starter
19 |
20 |
21 | io.springfox
22 | springfox-swagger2
23 | 2.6.1
24 |
25 |
26 | io.springfox
27 | springfox-swagger-ui
28 | 2.6.1
29 |
30 |
31 | org.springframework.boot
32 | spring-boot-starter-web
33 |
34 |
35 | org.springframework.cloud
36 | spring-cloud-starter-eureka
37 |
38 |
39 | org.springframework.kafka
40 | spring-kafka
41 |
42 |
43 | org.springframework.boot
44 | spring-boot-starter-test
45 | test
46 |
47 |
48 | com.spark.bc
49 | bitcoin-rpc
50 |
51 |
52 | org.apache.commons
53 | commons-lang3
54 |
55 |
56 | com.alibaba
57 | fastjson
58 |
59 |
60 | org.projectlombok
61 | lombok
62 |
63 |
64 | com.mashape.unirest
65 | unirest-java
66 | 1.4.9
67 |
68 |
69 | ai.turbochain.ipex
70 | ipex-rpc-common
71 | 1.0.1
72 |
73 |
75 |
76 | org.bitcoinj
77 | bitcoinj-core
78 | 0.15.5
79 |
80 |
81 | com.google.guava
82 | guava
83 | 27.1-jre
84 |
85 |
86 | org.apache.httpcomponents
87 | httpcore
88 | 4.4.8
89 |
90 |
91 | com.osp.blockchain
92 | blockchain-base
93 | 0.0.1-SNAPSHOT
94 |
95 |
96 | com.osp.blockchain
97 | blockchain-common
98 | 0.0.1-SNAPSHOT
99 |
100 |
101 |
102 | java-usdt-api
103 |
104 |
105 | org.springframework.boot
106 | spring-boot-maven-plugin
107 |
108 |
109 | maven-surefire-plugin
110 |
111 | true
112 |
113 |
114 |
115 | org.apache.maven.plugins
116 | maven-compiler-plugin
117 |
118 | 1.8
119 | 1.8
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/src/main/java/ai/turbochain/ipex/wallet/WalletRpcApplication.java:
--------------------------------------------------------------------------------
1 | package ai.turbochain.ipex.wallet;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
6 | import org.springframework.scheduling.annotation.EnableScheduling;
7 |
8 | @EnableEurekaClient
9 | @SpringBootApplication
10 | @EnableScheduling
11 | public class WalletRpcApplication {
12 | public static void main(String[] args){
13 | SpringApplication.run(WalletRpcApplication.class,args);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/ai/turbochain/ipex/wallet/component/UsdtWatcher.java:
--------------------------------------------------------------------------------
1 | package ai.turbochain.ipex.wallet.component;
2 |
3 | import ai.turbochain.ipex.wallet.config.Constant;
4 | import ai.turbochain.ipex.wallet.config.JsonrpcClient;
5 | import ai.turbochain.ipex.wallet.entity.Coin;
6 | import ai.turbochain.ipex.wallet.entity.Deposit;
7 | import ai.turbochain.ipex.wallet.entity.WatcherLog;
8 | import ai.turbochain.ipex.wallet.event.DepositEvent;
9 | import ai.turbochain.ipex.wallet.service.AccountService;
10 | import ai.turbochain.ipex.wallet.service.WatcherLogService;
11 | import ai.turbochain.ipex.wallet.util.HttpRequest;
12 | import com.alibaba.fastjson.JSONArray;
13 | import com.alibaba.fastjson.JSONObject;
14 | import com.spark.blockchain.rpcclient.Bitcoin;
15 | import com.spark.blockchain.rpcclient.BitcoinRPCClient;
16 | import org.apache.commons.lang.StringUtils;
17 | import org.slf4j.Logger;
18 | import org.slf4j.LoggerFactory;
19 | import org.springframework.beans.factory.annotation.Autowired;
20 | import org.springframework.stereotype.Component;
21 |
22 | import java.math.BigDecimal;
23 | import java.util.ArrayList;
24 | import java.util.Date;
25 | import java.util.List;
26 |
27 | @Component
28 | public class UsdtWatcher extends Watcher {
29 | private Logger logger = LoggerFactory.getLogger(UsdtWatcher.class);
30 | @Autowired
31 | private AccountService accountService;
32 | @Autowired
33 | private WatcherLogService watcherLogService;
34 | @Autowired
35 | private DepositEvent depositEvent;
36 | @Autowired
37 | private Coin coin;
38 | // 默认同步间隔3分钟
39 | private Long checkInterval = 180000L;
40 | private boolean stop = false;
41 | // 区块确认数
42 | private int confirmation = 1;
43 |
44 | @Override
45 | public List replayBlock(Long startBlockNumber, Long endBlockNumber) {
46 | List deposits = new ArrayList();
47 | try {
48 | for (Long blockHeight = startBlockNumber; blockHeight <= endBlockNumber; blockHeight++) {
49 | String blockHeightData = HttpRequest
50 | .sendGetData(Constant.ACT_BLOCKNO_HEIGHT + blockHeight, "");
51 | JSONObject jsonObject = JSONObject.parseObject(blockHeightData);
52 | JSONArray blocksArray = jsonObject.getJSONArray("data");
53 | String blockHash = blocksArray.getJSONObject(0).getString("blockhash");
54 | Long height = blocksArray.getJSONObject(0).getLong("block_no");
55 | JSONArray txList = blocksArray.getJSONObject(0).getJSONArray("txs");
56 | for (int i = 0; i < txList.size(); i++) {
57 | JSONObject txObj = txList.getJSONObject(i);
58 | String txHash = txObj.getString("txid");
59 | JSONArray outArray = txObj.getJSONArray("outputs");
60 | for (int j = 0; j < outArray.size(); j++) {
61 | JSONObject out = outArray.getJSONObject(j);
62 | String address = out.getString("address");
63 | if (StringUtils.isNotBlank(address) && accountService.isAddressExist(address)) {
64 | BigDecimal amount = out.getBigDecimal("value");
65 | Deposit deposit = new Deposit();
66 | deposit.setTxid(txHash);
67 | deposit.setBlockHeight(height);
68 | deposit.setBlockHash(blockHash);
69 | deposit.setAddress(address);
70 | deposit.setAmount(amount);
71 | deposit.setTime(txObj.getDate("time"));
72 | deposits.add(deposit);
73 | }
74 | }
75 | }
76 | }
77 | } catch (Exception e) {
78 | e.printStackTrace();
79 | }
80 | return deposits;
81 | }
82 |
83 | @Override
84 | public Long getNetworkBlockHeight() {
85 | try {
86 | // 获取最新块的块高
87 | String result = HttpRequest.sendGetData(Constant.ACT_BLOCKNO_LATEST, "");
88 | JSONObject resultObj = JSONObject.parseObject(result);
89 | return resultObj.getLong("data");
90 | } catch (Exception e) {
91 | e.printStackTrace();
92 | return 0L;
93 | }
94 | }
95 |
96 | public void check() {
97 | try {
98 | Long networkBlockNumber = getNetworkBlockHeight() - confirmation + 1;
99 | Thread.sleep(90000);
100 | if (getCurrentBlockHeight() < networkBlockNumber) {
101 | long startBlockNumber = getCurrentBlockHeight() + 1;
102 | logger.info("replay block {}", startBlockNumber);
103 | List deposits = replayBlock(startBlockNumber, startBlockNumber);
104 | deposits.forEach(deposit -> {
105 | depositEvent.onConfirmed(deposit);
106 | });
107 | // 记录日志
108 | watcherLogService.update(coin.getName(), startBlockNumber);
109 | setCurrentBlockHeight(startBlockNumber);
110 | } else {
111 | logger.info("already latest height {},nothing to do!", getCurrentBlockHeight());
112 | }
113 | } catch (Exception e) {
114 | e.printStackTrace();
115 | }
116 | }
117 |
118 | @Override
119 | public void run() {
120 | stop = false;
121 | long nextCheck = 0;
122 | while (!(Thread.interrupted() || stop)) {
123 | if (nextCheck <= System.currentTimeMillis()) {
124 | try {
125 | nextCheck = System.currentTimeMillis() + checkInterval;
126 | logger.info("check...");
127 | check();
128 | } catch (Exception ex) {
129 | logger.info(ex.getMessage());
130 | }
131 | } else {
132 | try {
133 | Thread.sleep(Math.max(nextCheck - System.currentTimeMillis(), 100));
134 | } catch (InterruptedException ex) {
135 | logger.info(ex.getMessage());
136 | }
137 | }
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/src/main/java/ai/turbochain/ipex/wallet/config/Constant.java:
--------------------------------------------------------------------------------
1 | package ai.turbochain.ipex.wallet.config;
2 |
3 | /**
4 | *
5 | * TODO
6 | * @author: shangxl
7 | * @Date : 2018年3月7日 下午5:37:00
8 | */
9 | public class Constant {
10 | /**
11 | * zcash币编码
12 | */
13 | public static final String ZCASH = "zec";
14 | /**
15 | * tv编码
16 | */
17 | public static final String TV = "tv";
18 | /**
19 | * usdt编码
20 | */
21 | public static final String USDT = "USDT";
22 | /**
23 | * usdt的token Id 正式网络usdt=31,测试网络可以用2
24 | */
25 | public static final String PROPERTYID_USDT = "31";
26 |
27 | /**
28 | * 精度
29 | */
30 | public static final String DECIMALS = "_DECIMALS";
31 | /**
32 | * neo
33 | */
34 | public static final String NEO = "NEO";
35 | /**
36 | * bds
37 | */
38 | public static final String BDS = "BDS";
39 | /**
40 | * bts
41 | */
42 | public static final String BTS = "BTS";
43 | /**
44 | * gxs
45 | */
46 | public static final String GXS = "GXS";
47 | /**
48 | * eth编码
49 | */
50 | public static final String ETHER = "ETH";
51 | /**
52 | * etc编码
53 | */
54 | public static final String ETC = "ETC";
55 | /**
56 | * etz编码
57 | */
58 | public static final String ETZ = "ETZ";
59 |
60 | public static final String ACT_PREFIX = "http://www.tokenview.com:8088/";
61 | public static final String ACT_BLOCKNO_HEIGHT = ACT_PREFIX + "block/usdt/";
62 | public static final String ACT_BLOCKNO_LATEST = ACT_PREFIX + "coin/latest/usdt";
63 | public static final String ACT_BLANCE_ADDRESS = ACT_PREFIX + "addr/b/usdt/";
64 | public static final String ACT_TRANSACTION_HASH = ACT_PREFIX + "tx/usdt/";
65 | public static final String ACT_TRANSACTION_PUSHTX = ACT_PREFIX + "onchainwallet/usdt";
66 | public static final String ACT_CREATE_WALLET="https://tc.ipcom.io/btcwallet/api/v2/create";
67 | public static final String FORMAT_PARAM = "?format=json";
68 | public static final String PWD_PARAM = "?password=";
69 | public static final String APICODE_PARAM = "&api_code=818ac2ad-fd55-426a-93e3-bc861dc2061f";
70 | public static final String PRIV_PARAM = "&priv=";
71 | public static final String LABLE_PARAM = "&lable=";
72 | public static final String EMAIL_PARAM = "&email=";
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/ai/turbochain/ipex/wallet/config/JsonrpcClient.java:
--------------------------------------------------------------------------------
1 | package ai.turbochain.ipex.wallet.config;
2 |
3 |
4 | import java.math.BigDecimal;
5 | import java.net.MalformedURLException;
6 | import java.util.List;
7 | import java.util.Map;
8 |
9 | import org.apache.commons.lang3.StringUtils;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | import com.spark.blockchain.rpcclient.BitcoinException;
14 | import com.spark.blockchain.rpcclient.BitcoinRPCClient;
15 |
16 |
17 | /**
18 | * 基于比特币rpc接口开发新的功能
19 | *
20 | * TODO
21 | *
22 | *
23 | * @author: shangxl
24 | * @Date : 2017年11月16日 下午6:10:02
25 | */
26 | public class JsonrpcClient extends BitcoinRPCClient {
27 |
28 | private Logger logger = LoggerFactory.getLogger(JsonrpcClient.class);
29 | /**
30 | *
31 | * TODO
32 | *
33 | *
34 | * @author: shangxl
35 | * @param: @param
36 | * rpcUrl
37 | * @param: @throws
38 | * MalformedURLException
39 | */
40 | public JsonrpcClient(String rpcUrl) throws MalformedURLException {
41 | super(rpcUrl);
42 | }
43 |
44 | @Override
45 | public String getNewAddress(String accountName) {
46 | try {
47 | if (StringUtils.isNotEmpty(accountName)) {
48 | return super.getNewAddress(accountName);
49 | } else {
50 | return super.getNewAddress();
51 | }
52 | } catch (BitcoinException e) {
53 | logger.info("创建新币账户出错: accountName=" + accountName);
54 | e.printStackTrace();
55 | return null;
56 | }
57 | }
58 |
59 | /**
60 | * 获取 btc余额
61 | * @param address
62 | * @return
63 | */
64 | public BigDecimal getAddressBalance(String address) {
65 | BigDecimal balance = BigDecimal.ZERO;
66 | try {
67 | List unspents = this.listUnspent(3, 99999999, address);
68 | for(Unspent unspent:unspents){
69 | balance = balance.add(unspent.amount());
70 | }
71 | return balance;
72 | }
73 | catch (Exception e){
74 | e.printStackTrace();
75 | }
76 | return new BigDecimal("-1");
77 | }
78 |
79 |
80 |
81 | /**
82 | * 根据地址获取usdt的账户余额
83 | *
84 | * TODO
85 | *
86 | *
87 | * @author: shangxl
88 | * @param: @param
89 | * address
90 | * @param: @return
91 | * @return: String
92 | * @Date : 2017年12月18日 下午5:39:04
93 | * @throws:
94 | */
95 | public BigDecimal omniGetBalance(String address) {
96 | String balance="0";
97 | try {
98 | Integer propertyid = Integer.valueOf(Constant.PROPERTYID_USDT);
99 | Map map = (Map) query("omni_getbalance", new Object[] { address, propertyid });
100 | if (map != null) {
101 | balance= map.get("balance").toString();
102 | }
103 | } catch (BitcoinException e) {
104 | e.printStackTrace();
105 | }
106 | return new BigDecimal(balance);
107 | }
108 |
109 | public Map omniGetTransactions(String txid){
110 | try {
111 | return (Map) query("omni_gettransaction", new Object[]{txid});
112 | } catch (BitcoinException e) {
113 | e.printStackTrace();
114 | return null;
115 | }
116 | }
117 |
118 | public List omniListBlockTransactions(Long blockHeight){
119 | try {
120 | return (List) query("omni_listblocktransactions", new Object[]{blockHeight});
121 | } catch (BitcoinException e) {
122 | e.printStackTrace();
123 | return null;
124 | }
125 | }
126 |
127 | /**
128 | * usdt 转币
129 | * TODO
130 | * @author: shangxl
131 | * @param: @return
132 | * @return: String
133 | * @Date : 2017年12月19日 下午3:38:31
134 | * @throws:
135 | */
136 | public String omniSend(String fromaddress,String toaddress,BigDecimal amount){
137 | try {
138 | return query("omni_send", new Object[]{fromaddress,toaddress,Integer.valueOf(Constant.PROPERTYID_USDT),amount.toPlainString()}).toString();
139 | } catch (BitcoinException e) {
140 | logger.info("fromaddress="+fromaddress+" toaddress="+toaddress+" propertyid="+Constant.PROPERTYID_USDT+" amount="+amount);
141 | e.printStackTrace();
142 | return null;
143 | }
144 | }
145 |
146 | public String omniSend(String fromaddress, String toaddress, BigDecimal amount, BigDecimal bitcoinFee){
147 | try {
148 | return query("omni_send", new Object[]{fromaddress,toaddress,Integer.valueOf(Constant.PROPERTYID_USDT),amount.toPlainString(),fromaddress,bitcoinFee.toPlainString()}).toString();
149 | } catch (BitcoinException e) {
150 | logger.info("fromaddress="+fromaddress+" toaddress="+toaddress+" propertyid="+Constant.PROPERTYID_USDT+" amount="+amount);
151 | e.printStackTrace();
152 | return null;
153 | }
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/src/main/java/ai/turbochain/ipex/wallet/config/RpcClientConfig.java:
--------------------------------------------------------------------------------
1 | package ai.turbochain.ipex.wallet.config;
2 |
3 | import java.net.MalformedURLException;
4 |
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.beans.factory.annotation.Value;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.context.annotation.Configuration;
10 |
11 | /**
12 | * 初始化RPC客户端
13 | */
14 | @Configuration
15 | public class RpcClientConfig {
16 | private Logger logger = LoggerFactory.getLogger(RpcClientConfig.class);
17 |
18 | @Bean
19 | public JsonrpcClient setClient(@Value("${coin.rpc}") String uri){
20 | try {
21 | logger.info("uri={}",uri);
22 | JsonrpcClient client = new JsonrpcClient(uri);
23 | logger.info("=============================");
24 | logger.info("client={}",client);
25 | logger.info("=============================");
26 | return client;
27 | } catch (MalformedURLException e) {
28 | logger.info("init wallet failed");
29 | e.printStackTrace();
30 | return null;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/ai/turbochain/ipex/wallet/config/Swagger2.java:
--------------------------------------------------------------------------------
1 | package ai.turbochain.ipex.wallet.config;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 |
6 | import springfox.documentation.builders.ApiInfoBuilder;
7 | import springfox.documentation.builders.PathSelectors;
8 | import springfox.documentation.builders.RequestHandlerSelectors;
9 | import springfox.documentation.service.ApiInfo;
10 | import springfox.documentation.service.Contact;
11 | import springfox.documentation.spi.DocumentationType;
12 | import springfox.documentation.spring.web.plugins.Docket;
13 | import springfox.documentation.swagger2.annotations.EnableSwagger2;
14 |
15 | @Configuration
16 | @EnableSwagger2
17 | public class Swagger2 {
18 |
19 | @Bean
20 | public Docket createRestApi() {
21 | return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
22 | .apis(RequestHandlerSelectors.basePackage("ai.turbochain.ipex.wallet.controller")).paths(PathSelectors.any())
23 | .build();
24 | }
25 |
26 | /**
27 | * 构建Api文档的详细信息函数
28 | *
29 | * @return
30 | */
31 | private ApiInfo apiInfo() {
32 | return new ApiInfoBuilder().title("Java usdt api文档")
33 | .description("简单优雅的restful风格,https://www.pansoft.com")
34 | .contact(new Contact("usdt", "", ""))
35 | .termsOfServiceUrl("https://www.pansoft.com").version("1.0").build();
36 | }
37 | }
38 |
39 |
--------------------------------------------------------------------------------
/src/main/java/ai/turbochain/ipex/wallet/controller/WalletController.java:
--------------------------------------------------------------------------------
1 | package ai.turbochain.ipex.wallet.controller;
2 |
3 | import java.math.BigDecimal;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 | import java.util.Map;
7 |
8 | import ai.turbochain.ipex.wallet.config.Constant;
9 | import ai.turbochain.ipex.wallet.entity.Account;
10 | import ai.turbochain.ipex.wallet.entity.Deposit;
11 | import ai.turbochain.ipex.wallet.service.TransactionService;
12 | import ai.turbochain.ipex.wallet.util.HttpRequest;
13 | import com.alibaba.fastjson.JSON;
14 | import com.alibaba.fastjson.JSONArray;
15 | import com.alibaba.fastjson.JSONObject;
16 | import com.google.common.collect.Lists;
17 | import com.osp.blockchain.btc.client.OspBlockExplorer;
18 | import com.osp.blockchain.btc.model.BlockchainAddressResponse;
19 | import com.osp.blockchain.http.HttpUtil;
20 | import com.spark.blockchain.rpcclient.Bitcoin;
21 | import com.spark.blockchain.rpcclient.BitcoinException;
22 | import info.blockchain.api.blockexplorer.entity.Input;
23 | import info.blockchain.api.blockexplorer.entity.Output;
24 | import info.blockchain.api.blockexplorer.entity.Transaction;
25 | import org.apache.commons.lang.StringUtils;
26 | import org.bitcoinj.core.UTXO;
27 | import org.slf4j.Logger;
28 | import org.slf4j.LoggerFactory;
29 | import org.springframework.beans.factory.annotation.Autowired;
30 | import org.springframework.scheduling.annotation.Scheduled;
31 | import org.springframework.web.bind.annotation.*;
32 |
33 | import ai.turbochain.ipex.wallet.config.JsonrpcClient;
34 | import ai.turbochain.ipex.wallet.entity.BtcBean;
35 | import ai.turbochain.ipex.wallet.service.AccountService;
36 | import ai.turbochain.ipex.wallet.util.BTCAccountGenerator;
37 | import ai.turbochain.ipex.wallet.util.MessageResult;
38 | import io.swagger.annotations.Api;
39 | import io.swagger.annotations.ApiOperation;
40 |
41 | @Api(description = "usdt java api接口")
42 | @RestController
43 | @RequestMapping("/rpc")
44 | public class WalletController {
45 | private Logger logger = LoggerFactory.getLogger(WalletController.class);
46 |
47 | @Autowired
48 | private JsonrpcClient jsonrpcClient;
49 | @Autowired
50 | private BTCAccountGenerator btcAccountGenerator;
51 | @Autowired
52 | private AccountService accountService;
53 | @Autowired
54 | private TransactionService transactionService;
55 |
56 | @PostMapping("/test")
57 | public MessageResult test(String address) {
58 | try {
59 | // List< UTXO > utxos = transactionService.getUnspent(fromAddress);
60 | // Long fee = transactionService.getOmniFee(utxos);
61 | // String signedHex = transactionService.omniSign(fromAddress, address, "", amount, fee, propertyid, utxos);
62 | return MessageResult.success();
63 | } catch (Exception e) {
64 | e.printStackTrace();
65 | return MessageResult.error(500, "error:" + e.getMessage());
66 | }
67 | }
68 |
69 |
70 | /**
71 | * 获取USDT链高度
72 | *
73 | * @return
74 | */
75 | @ApiOperation(value = "获取USDT链高度", notes = "获取USDT链高度")
76 | @RequestMapping(value = "height", method = { RequestMethod.GET, RequestMethod.POST })
77 | public MessageResult getNetworkBlockHeight() {
78 | try {
79 | MessageResult result = new MessageResult(0, "success");
80 | String resultStr = HttpRequest.sendGetData(Constant.ACT_BLOCKNO_LATEST, "");
81 | if (StringUtils.isNotBlank(resultStr)) {
82 | JSONObject resultObj = JSONObject.parseObject(resultStr);
83 | if (null != resultObj) {
84 | result.setData(resultObj.getLong("data"));
85 | }
86 | }
87 | // result.setData(Long.valueOf(jsonrpcClient.getBlockCount()));
88 | return result;
89 | } catch (Exception e) {
90 | e.printStackTrace();
91 | return MessageResult.error(500, "error:" + e.getMessage());
92 | }
93 | }
94 |
95 | /**
96 | * 获取USDT区块高度为startBlockNumber的交易数据
97 | *
98 | * @return
99 | */
100 | @ApiOperation(value = "获取USDT链区块交易数据", notes = "获取USDT链区块交易数据")
101 | @RequestMapping(value = "block-txns/{blockNumber}", method = { RequestMethod.GET, RequestMethod.POST })
102 | public MessageResult blockTxns(@PathVariable Long blockNumber) {
103 | try {
104 | MessageResult result = new MessageResult(0, "success");
105 | String resultStr = HttpRequest.sendGetData(Constant.ACT_BLOCKNO_HEIGHT + blockNumber, "");
106 | if (StringUtils.isNotBlank(resultStr)) {
107 | JSONObject resultObj = JSONObject.parseObject(resultStr);
108 | if (null != resultObj) {
109 | JSONArray resultData = resultObj.getJSONArray("data");
110 | if (null != resultData && null != resultData.getJSONObject(0)) {
111 | JSONObject blockData = resultData.getJSONObject(0);
112 | JSONArray txArray = blockData.getJSONArray("txs");
113 | result.setData(txArray);
114 | }
115 | }
116 | }
117 | // result.setData(jsonrpcClient.omniListBlockTransactions(blockNumber));
118 | return result;
119 | } catch (Exception e) {
120 | e.printStackTrace();
121 | return MessageResult.error(500, "error:" + e.getMessage());
122 | }
123 | }
124 |
125 | /**
126 | * 根据交易编号获取交易详细数据
127 | *
128 | * @return
129 | */
130 | @ApiOperation(value = "根据交易编号获取交易详细数据", notes = "根据交易编号获取交易详细数据")
131 | @RequestMapping(value = "txninfo/{txid}", method = { RequestMethod.GET, RequestMethod.POST })
132 | public MessageResult txninfo(@PathVariable String txid) {
133 | try {
134 | MessageResult result = new MessageResult(0, "success");
135 | String resultStr = HttpRequest.sendGetData(Constant.ACT_TRANSACTION_HASH + txid, "");
136 | if (StringUtils.isNotBlank(resultStr)) {
137 | JSONObject resultObj = JSONObject.parseObject(resultStr);
138 | if (null != resultObj) {
139 | JSONObject resultData = resultObj.getJSONObject("data");
140 | result.setData(resultData);
141 | }
142 | }
143 | // Map map = jsonrpcClient.omniGetTransactions(txid);
144 | // result.setData(map);
145 | return result;
146 | } catch (Exception e) {
147 | e.printStackTrace();
148 | return MessageResult.error(500, "error:" + e.getMessage());
149 | }
150 | }
151 |
152 | /**
153 | * 创建钱包
154 | *
155 | * @param account
156 | * @return
157 | */
158 | @ApiOperation(value = "获取账户地址", notes = "获取账户地址")
159 | @GetMapping("address/{account}")
160 | public MessageResult createWallet(@PathVariable String account,
161 | @RequestParam(required = false, defaultValue = "") String password) {
162 | logger.info("create new wallet:account={},password={}", account, password);
163 | try {
164 | BtcBean btcBean = btcAccountGenerator.createBtcAccount();
165 | accountService.saveBTCOne(account, btcBean.getFile(), btcBean.getBtcAddress(), "");
166 | MessageResult result = new MessageResult(0, "success");
167 | result.setData(btcBean.getBtcAddress());
168 | return result;
169 | } catch (Exception e) {
170 | e.printStackTrace();
171 | return MessageResult.error(500, "查询失败, error: " + e.getMessage());
172 | }
173 | }
174 |
175 | /**
176 | * 转账
177 | *
178 | * @param fromAddress
179 | * @param address
180 | * @param amount
181 | * @return
182 | */
183 | @ApiOperation(value = "转账", notes = "转账")
184 | @RequestMapping(value = "transfer-from-address", method = { RequestMethod.GET, RequestMethod.POST })
185 | public MessageResult transferFromAddress(String username, String fromAddress, String address, BigDecimal amount) {
186 | logger.info("transfer:fromeAddress={},address={},amount={}", fromAddress, address, amount);
187 | try {
188 | if (fromAddress.equalsIgnoreCase(address)) {
189 | return MessageResult.error(500, "转入转出地址不能一样");
190 | }
191 | Account account = accountService.findByName(username);
192 | if (account == null) {
193 | return MessageResult.error(500, "请传入正确的用户名" + username);
194 | }
195 | // BigDecimal availAmt = jsonrpcClient.omniGetBalance(fromAddress);
196 | // 查询余额
197 | BigDecimal availAmt = new BigDecimal(0);
198 | String resultStr = HttpRequest.sendGetData(Constant.ACT_BLANCE_ADDRESS + fromAddress, "");
199 | if (StringUtils.isNotBlank(resultStr)) {
200 | JSONObject resultObj = JSONObject.parseObject(resultStr);
201 | if (null != resultObj && null != resultObj.getBigDecimal("data")) {
202 | availAmt = resultObj.getBigDecimal("data");
203 | } else {
204 | return MessageResult.error(500, "地址余额为空");
205 | }
206 | }
207 | if (availAmt.compareTo(amount) < 0) {
208 | return MessageResult.error(500, "余额不足不能转账");
209 | }
210 | // String txid = jsonrpcClient.omniSend(fromAddress, address, amount);
211 | //发送交易
212 | MessageResult result = transactionService.transferFromWallet(account ,fromAddress, address, amount);
213 | return result;
214 | } catch (Exception e) {
215 | e.printStackTrace();
216 | return MessageResult.error(500, "error:" + e.getMessage());
217 | }
218 | }
219 |
220 | /**
221 | * 获取账户地址余额
222 | *
223 | * @param address
224 | * @return
225 | */
226 | @ApiOperation(value = "根据USDT地址获取余额", notes = "根据USDT地址获取余额")
227 | @RequestMapping(value = "balance/{address}", method = { RequestMethod.GET, RequestMethod.POST })
228 | public MessageResult balance(@PathVariable String address) {
229 | try {
230 | MessageResult result = new MessageResult(0, "success");
231 | String resultStr = HttpRequest.sendGetData(Constant.ACT_BLANCE_ADDRESS + address, "");
232 | if (StringUtils.isNotBlank(resultStr)) {
233 | JSONObject resultObj = JSONObject.parseObject(resultStr);
234 | if (null != resultObj) {
235 | BigDecimal balance = resultObj.getBigDecimal("data");
236 | result.setData(balance);
237 | }
238 |
239 | }
240 | // BigDecimal balance = jsonrpcClient.omniGetBalance(address);
241 | return result;
242 | } catch (Exception e) {
243 | e.printStackTrace();
244 | return MessageResult.error(500, "error:" + e.getMessage());
245 | }
246 | }
247 |
248 | }
249 |
--------------------------------------------------------------------------------
/src/main/java/ai/turbochain/ipex/wallet/entity/BTCBalanceCalledCount.java:
--------------------------------------------------------------------------------
1 | package ai.turbochain.ipex.wallet.entity;
2 |
3 | import java.util.Date;
4 |
5 | public class BTCBalanceCalledCount {
6 | private Integer id;
7 |
8 | private Integer calledCount;
9 |
10 | private Date createTime;
11 |
12 | public Integer getId() {
13 | return id;
14 | }
15 |
16 | public void setId(Integer id) {
17 | this.id = id;
18 | }
19 |
20 | public Integer getCalledCount() {
21 | return calledCount;
22 | }
23 |
24 | public void setCalledCount(Integer calledCount) {
25 | this.calledCount = calledCount;
26 | }
27 |
28 | public Date getCreateTime() {
29 | return createTime;
30 | }
31 |
32 | public void setCreateTime(Date createTime) {
33 | this.createTime = createTime;
34 | }
35 | }
--------------------------------------------------------------------------------
/src/main/java/ai/turbochain/ipex/wallet/entity/BalanceData.java:
--------------------------------------------------------------------------------
1 | package ai.turbochain.ipex.wallet.entity;
2 |
3 | public class BalanceData {
4 |
5 | private String finalBalance;
6 |
7 | private String totalReceived;
8 |
9 | private String txCount;
10 |
11 | private String address;
12 |
13 | public String getAddress() {
14 | return address;
15 | }
16 |
17 | public void setAddress(String address) {
18 | this.address = address;
19 | }
20 |
21 | public String getFinalBalance() {
22 | return finalBalance;
23 | }
24 |
25 | public void setFinalBalance(String finalBalance) {
26 | this.finalBalance = finalBalance;
27 | }
28 |
29 | public String getTotalReceived() {
30 | return totalReceived;
31 | }
32 |
33 | public void setTotalReceived(String totalReceived) {
34 | this.totalReceived = totalReceived;
35 | }
36 |
37 | public String getTxCount() {
38 | return txCount;
39 | }
40 |
41 | public void setTxCount(String txCount) {
42 | this.txCount = txCount;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/ai/turbochain/ipex/wallet/entity/BitCoin.java:
--------------------------------------------------------------------------------
1 | package ai.turbochain.ipex.wallet.entity;
2 |
3 | import java.util.List;
4 |
5 | public class BitCoin {
6 | private String hash;
7 | private Long ver;
8 | private String prev_block;
9 | private List next_block;
10 | private String mrkl_root;
11 | private Long time;
12 | private Long bits;
13 | private Long fee;
14 | private Long nonce;
15 | private Long n_tx;
16 | private Long size;
17 | private Long block_index;
18 | private Boolean main_chain;
19 | private Long height;
20 | private Long received_time;
21 | private String relayed_by;
22 | private List tx;
23 |
24 | public String getHash() {
25 | return hash;
26 | }
27 |
28 | public void setHash(String hash) {
29 | this.hash = hash;
30 | }
31 |
32 | public Long getVer() {
33 | return ver;
34 | }
35 |
36 | public void setVer(Long ver) {
37 | this.ver = ver;
38 | }
39 |
40 | public String getPrev_block() {
41 | return prev_block;
42 | }
43 |
44 | public void setPrev_block(String prev_block) {
45 | this.prev_block = prev_block;
46 | }
47 |
48 | public List getNext_block() {
49 | return next_block;
50 | }
51 |
52 | public void setNext_block(List next_block) {
53 | this.next_block = next_block;
54 | }
55 |
56 | public String getMrkl_root() {
57 | return mrkl_root;
58 | }
59 |
60 | public void setMrkl_root(String mrkl_root) {
61 | this.mrkl_root = mrkl_root;
62 | }
63 |
64 | public Long getTime() {
65 | return time;
66 | }
67 |
68 | public void setTime(Long time) {
69 | this.time = time;
70 | }
71 |
72 | public Long getBits() {
73 | return bits;
74 | }
75 |
76 | public void setBits(Long bits) {
77 | this.bits = bits;
78 | }
79 |
80 | public Long getFee() {
81 | return fee;
82 | }
83 |
84 | public void setFee(Long fee) {
85 | this.fee = fee;
86 | }
87 |
88 | public Long getNonce() {
89 | return nonce;
90 | }
91 |
92 | public void setNonce(Long nonce) {
93 | this.nonce = nonce;
94 | }
95 |
96 | public Long getN_tx() {
97 | return n_tx;
98 | }
99 |
100 | public void setN_tx(Long n_tx) {
101 | this.n_tx = n_tx;
102 | }
103 |
104 | public Long getSize() {
105 | return size;
106 | }
107 |
108 | public void setSize(Long size) {
109 | this.size = size;
110 | }
111 |
112 | public Long getBlock_index() {
113 | return block_index;
114 | }
115 |
116 | public void setBlock_index(Long block_index) {
117 | this.block_index = block_index;
118 | }
119 |
120 | public Boolean getMain_chain() {
121 | return main_chain;
122 | }
123 |
124 | public void setMain_chain(Boolean main_chain) {
125 | this.main_chain = main_chain;
126 | }
127 |
128 | public Long getHeight() {
129 | return height;
130 | }
131 |
132 | public void setHeight(Long height) {
133 | this.height = height;
134 | }
135 |
136 | public Long getReceived_time() {
137 | return received_time;
138 | }
139 |
140 | public void setReceived_time(Long received_time) {
141 | this.received_time = received_time;
142 | }
143 |
144 | public String getRelayed_by() {
145 | return relayed_by;
146 | }
147 |
148 | public void setRelayed_by(String relayed_by) {
149 | this.relayed_by = relayed_by;
150 | }
151 |
152 | public List getTx() {
153 | return tx;
154 | }
155 |
156 | public void setTx(List tx) {
157 | this.tx = tx;
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/src/main/java/ai/turbochain/ipex/wallet/entity/BitCoinBlock.java:
--------------------------------------------------------------------------------
1 | package ai.turbochain.ipex.wallet.entity;
2 |
3 | import java.util.List;
4 |
5 | public class BitCoinBlock {
6 | private List blocks;
7 |
8 | public List getBlocks() {
9 | return blocks;
10 | }
11 |
12 | public void setBlocks(List blocks) {
13 | this.blocks = blocks;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/ai/turbochain/ipex/wallet/entity/BitCoinTX.java:
--------------------------------------------------------------------------------
1 | package ai.turbochain.ipex.wallet.entity;
2 |
3 | import java.util.List;
4 |
5 | public class BitCoinTX {
6 | private Long lock_time;
7 | private Integer ver;
8 | private Integer size;
9 | private List inputs;
10 | private Integer weight;
11 | private Long time;
12 | private Long tx_index;
13 | private Integer vin_sz;
14 | private String hash;
15 | private Integer vout_sz;
16 | private String relayed_by;
17 | private List out;
18 |
19 | public Long getLock_time() {
20 | return lock_time;
21 | }
22 |
23 | public void setLock_time(Long lock_time) {
24 | this.lock_time = lock_time;
25 | }
26 |
27 | public Integer getVer() {
28 | return ver;
29 | }
30 |
31 | public void setVer(Integer ver) {
32 | this.ver = ver;
33 | }
34 |
35 | public Integer getSize() {
36 | return size;
37 | }
38 |
39 | public void setSize(Integer size) {
40 | this.size = size;
41 | }
42 |
43 | public List getInputs() {
44 | return inputs;
45 | }
46 |
47 | public void setInputs(List inputs) {
48 | this.inputs = inputs;
49 | }
50 |
51 | public Integer getWeight() {
52 | return weight;
53 | }
54 |
55 | public void setWeight(Integer weight) {
56 | this.weight = weight;
57 | }
58 |
59 | public Long getTime() {
60 | return time;
61 | }
62 |
63 | public void setTime(Long time) {
64 | this.time = time;
65 | }
66 |
67 | public Long getTx_index() {
68 | return tx_index;
69 | }
70 |
71 | public void setTx_index(Long tx_index) {
72 | this.tx_index = tx_index;
73 | }
74 |
75 | public Integer getVin_sz() {
76 | return vin_sz;
77 | }
78 |
79 | public void setVin_sz(Integer vin_sz) {
80 | this.vin_sz = vin_sz;
81 | }
82 |
83 | public String getHash() {
84 | return hash;
85 | }
86 |
87 | public void setHash(String hash) {
88 | this.hash = hash;
89 | }
90 |
91 | public String getRelayed_by() {
92 | return relayed_by;
93 | }
94 |
95 | public void setRelayed_by(String relayed_by) {
96 | this.relayed_by = relayed_by;
97 | }
98 |
99 | public Integer getVout_sz() {
100 | return vout_sz;
101 | }
102 |
103 | public void setVout_sz(Integer vout_sz) {
104 | this.vout_sz = vout_sz;
105 | }
106 |
107 | public List getOut() {
108 | return out;
109 | }
110 |
111 | public void setOut(List out) {
112 | this.out = out;
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/src/main/java/ai/turbochain/ipex/wallet/entity/BtcBean.java:
--------------------------------------------------------------------------------
1 | package ai.turbochain.ipex.wallet.entity;
2 |
3 | import java.util.List;
4 |
5 | import lombok.Builder;
6 |
7 | @Builder
8 | public class BtcBean {
9 | private String btcAddress;
10 | private String btcPrivKey;
11 | private String btcPubKey;
12 | private String mnemonic;
13 | private List mnemonicList;
14 | private String file;
15 |
16 | public String getBtcAddress() {
17 | return btcAddress;
18 | }
19 |
20 | public void setBtcAddress(String btcAddress) {
21 | this.btcAddress = btcAddress;
22 | }
23 |
24 | public String getBtcPrivKey() {
25 | return btcPrivKey;
26 | }
27 |
28 | public void setBtcPrivKey(String btcPrivKey) {
29 | this.btcPrivKey = btcPrivKey;
30 | }
31 |
32 | public String getBtcPubKey() {
33 | return btcPubKey;
34 | }
35 |
36 | public void setBtcPubKey(String btcPubKey) {
37 | this.btcPubKey = btcPubKey;
38 | }
39 |
40 | public String getMnemonic() {
41 | return mnemonic;
42 | }
43 |
44 | public void setMnemonic(String mnemonic) {
45 | this.mnemonic = mnemonic;
46 | }
47 |
48 | public List getMnemonicList() {
49 | return mnemonicList;
50 | }
51 |
52 | public void setMnemonicList(List mnemonicList) {
53 | this.mnemonicList = mnemonicList;
54 | }
55 |
56 | public String getFile() {
57 | return file;
58 | }
59 |
60 | public void setFile(String file) {
61 | this.file = file;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/ai/turbochain/ipex/wallet/entity/BtcInput.java:
--------------------------------------------------------------------------------
1 | package ai.turbochain.ipex.wallet.entity;
2 |
3 | import info.blockchain.api.blockexplorer.entity.Input;
4 | import info.blockchain.api.blockexplorer.entity.Output;
5 |
6 | public class BtcInput extends Input {
7 |
8 | public BtcInput(String address) {
9 |
10 | super(new BtcOutput(address), 0, "");
11 | }
12 | public BtcInput(Output previousOutput, long sequence, String scriptSignature) {
13 | super(previousOutput, sequence, scriptSignature);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/ai/turbochain/ipex/wallet/entity/BtcOutput.java:
--------------------------------------------------------------------------------
1 | package ai.turbochain.ipex.wallet.entity;
2 |
3 | import info.blockchain.api.blockexplorer.entity.Output;
4 |
5 | public class BtcOutput extends Output {
6 |
7 |
8 | public BtcOutput(int n, long value, String address, long txIndex, String script, boolean spent) {
9 | super(n, value, address, txIndex, script, spent);
10 | }
11 |
12 | public BtcOutput(Long value, String address) {
13 | super(0, value, address, 0, "", false);
14 | }
15 | public BtcOutput(String address) {
16 | super(0, 0, address, 0, "", false);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/ai/turbochain/ipex/wallet/entity/BtcUtxo.java:
--------------------------------------------------------------------------------
1 | package ai.turbochain.ipex.wallet.entity;
2 |
3 | public class BtcUtxo {
4 |
5 | private String confirmations;
6 |
7 | private String n;
8 |
9 | private String transactionHash;
10 |
11 | private String value;
12 |
13 | private String script;
14 |
15 | private String transactionIndex;
16 |
17 | private String path;
18 |
19 | public String getScript() {
20 | return script;
21 | }
22 |
23 | public void setScript(String script) {
24 | this.script = script;
25 | }
26 |
27 | public String getConfirmations() {
28 | return confirmations;
29 | }
30 |
31 | public void setConfirmations(String confirmations) {
32 | this.confirmations = confirmations;
33 | }
34 |
35 | public String getN() {
36 | return n;
37 | }
38 |
39 | public void setN(String n) {
40 | this.n = n;
41 | }
42 |
43 | public String getTransactionHash() {
44 | return transactionHash;
45 | }
46 |
47 | public void setTransactionHash(String transactionHash) {
48 | this.transactionHash = transactionHash;
49 | }
50 |
51 | public String getValue() {
52 | return value;
53 | }
54 |
55 | public void setValue(String value) {
56 | this.value = value;
57 | }
58 |
59 | public String getTransactionIndex() {
60 | return transactionIndex;
61 | }
62 |
63 | public void setTransactionIndex(String transactionIndex) {
64 | this.transactionIndex = transactionIndex;
65 | }
66 |
67 | public String getPath() {
68 | return path;
69 | }
70 |
71 | public void setPath(String path) {
72 | this.path = path;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/ai/turbochain/ipex/wallet/entity/Input.java:
--------------------------------------------------------------------------------
1 | package ai.turbochain.ipex.wallet.entity;
2 |
3 | import jnr.ffi.annotations.In;
4 |
5 | public class Input {
6 | private Long sequence;
7 | private String witness;
8 | private Out prev_out;
9 | private String script;
10 |
11 | public Long getSequence() {
12 | return sequence;
13 | }
14 |
15 | public void setSequence(Long sequence) {
16 | this.sequence = sequence;
17 | }
18 |
19 | public String getWitness() {
20 | return witness;
21 | }
22 |
23 | public void setWitness(String witness) {
24 | this.witness = witness;
25 | }
26 |
27 | public Out getPrev_out() {
28 | return prev_out;
29 | }
30 |
31 | public void setPrev_out(Out prev_out) {
32 | this.prev_out = prev_out;
33 | }
34 |
35 | public String getScript() {
36 | return script;
37 | }
38 |
39 | public void setScript(String script) {
40 | this.script = script;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/ai/turbochain/ipex/wallet/entity/Out.java:
--------------------------------------------------------------------------------
1 | package ai.turbochain.ipex.wallet.entity;
2 |
3 | import java.util.List;
4 |
5 | public class Out {
6 | private Boolean spent;
7 | private List spending_outpoints;
8 | private Long tx_index;
9 | private Integer type;
10 | private String addr;
11 | private Long value;
12 | private Integer n;
13 | private String script;
14 |
15 | public Boolean getSpent() {
16 | return spent;
17 | }
18 |
19 | public void setSpent(Boolean spent) {
20 | this.spent = spent;
21 | }
22 |
23 | public List getSpending_outpoints() {
24 | return spending_outpoints;
25 | }
26 |
27 | public void setSpending_outpoints(List spending_outpoints) {
28 | this.spending_outpoints = spending_outpoints;
29 | }
30 |
31 | public Long getTx_index() {
32 | return tx_index;
33 | }
34 |
35 | public void setTx_index(Long tx_index) {
36 | this.tx_index = tx_index;
37 | }
38 |
39 | public Integer getType() {
40 | return type;
41 | }
42 |
43 | public void setType(Integer type) {
44 | this.type = type;
45 | }
46 |
47 | public String getAddr() {
48 | return addr;
49 | }
50 |
51 | public void setAddr(String addr) {
52 | this.addr = addr;
53 | }
54 |
55 | public Long getValue() {
56 | return value;
57 | }
58 |
59 | public void setValue(Long value) {
60 | this.value = value;
61 | }
62 |
63 | public Integer getN() {
64 | return n;
65 | }
66 |
67 | public void setN(Integer n) {
68 | this.n = n;
69 | }
70 |
71 | public String getScript() {
72 | return script;
73 | }
74 |
75 | public void setScript(String script) {
76 | this.script = script;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/main/java/ai/turbochain/ipex/wallet/entity/SpendingOutpoints.java:
--------------------------------------------------------------------------------
1 | package ai.turbochain.ipex.wallet.entity;
2 |
3 | public class SpendingOutpoints {
4 | private Long tx_index;
5 | private Integer n;
6 |
7 | public Long getTx_index() {
8 | return tx_index;
9 | }
10 |
11 | public void setTx_index(Long tx_index) {
12 | this.tx_index = tx_index;
13 | }
14 |
15 | public Integer getN() {
16 | return n;
17 | }
18 |
19 | public void setN(Integer n) {
20 | this.n = n;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/ai/turbochain/ipex/wallet/service/TransactionService.java:
--------------------------------------------------------------------------------
1 | package ai.turbochain.ipex.wallet.service;
2 |
3 | import ai.turbochain.ipex.wallet.config.Constant;
4 | import ai.turbochain.ipex.wallet.entity.Account;
5 | import ai.turbochain.ipex.wallet.entity.BalanceData;
6 | import ai.turbochain.ipex.wallet.util.HttpRequest;
7 | import ai.turbochain.ipex.wallet.util.MessageResult;
8 | import com.alibaba.fastjson.JSON;
9 | import com.alibaba.fastjson.JSONArray;
10 | import com.alibaba.fastjson.JSONObject;
11 | import com.google.common.collect.Lists;
12 | import com.osp.blockchain.btc.client.BtcClient;
13 | import com.osp.blockchain.btc.client.BtcInterface;
14 | import com.osp.blockchain.http.HttpUtil;
15 | import org.apache.commons.lang3.StringUtils;
16 | import org.bitcoinj.core.*;
17 | import org.bitcoinj.crypto.TransactionSignature;
18 | import org.bitcoinj.params.MainNetParams;
19 | import org.bitcoinj.params.TestNet3Params;
20 | import org.bitcoinj.script.Script;
21 | import org.bitcoinj.script.ScriptBuilder;
22 | import org.bitcoinj.core.Coin;
23 | import org.bitcoinj.core.DumpedPrivateKey;
24 | import org.bitcoinj.core.ECKey;
25 | import org.bitcoinj.core.NetworkParameters;
26 | import org.bitcoinj.core.Sha256Hash;
27 | import org.bitcoinj.core.Transaction;
28 | import org.bitcoinj.core.TransactionInput;
29 | import org.bitcoinj.core.UTXO;
30 | import org.bitcoinj.core.Utils;
31 | import org.slf4j.Logger;
32 | import org.slf4j.LoggerFactory;
33 | import org.spongycastle.util.encoders.Hex;
34 | import org.springframework.beans.factory.annotation.Autowired;
35 | import org.springframework.stereotype.Service;
36 |
37 | import java.math.BigDecimal;
38 | import java.util.ArrayList;
39 | import java.util.List;
40 | import java.util.Map;
41 |
42 | @Service
43 | public class TransactionService {
44 |
45 | private static Logger logger = LoggerFactory.getLogger(TransactionService.class);
46 |
47 | private NetworkParameters params;
48 |
49 | @Autowired
50 | private AccountService accountService;
51 |
52 | public TransactionService() {
53 | params = MainNetParams.get();
54 | }
55 |
56 | /**
57 | * usdt 离线签名
58 | *
59 | * @param privateKey:私钥
60 | * @param toAddress:接收地址
61 | * @param amount:转账金额
62 | * @return
63 | */
64 | public String omniSign(String fromAddress, String toAddress, String privateKey, BigDecimal amount, Long fee,
65 | Integer propertyid, List utxos) throws Exception {
66 | NetworkParameters networkParameters = MainNetParams.get();
67 | Transaction tran = new Transaction(networkParameters);
68 | if(utxos==null||utxos.size()==0){
69 | throw new Exception("utxo为空");
70 | }
71 | //这是比特币的限制最小转账金额,所以很多usdt转账会收到一笔0.00000546的btc
72 | Long miniBtc = 546L;
73 | tran.addOutput(Coin.valueOf(miniBtc),LegacyAddress.fromBase58(networkParameters, toAddress));
74 |
75 | //构建usdt的输出脚本 注意这里的金额是要乘10的8次方
76 | Long amoutTemp = amount.longValue();
77 | String usdtHex = "6a146f6d6e69" + String.format("%016x", propertyid) + String.format("%016x", amoutTemp);
78 | tran.addOutput(Coin.valueOf(0L), new Script(Utils.HEX.decode(usdtHex)));
79 |
80 | //如果有找零就添加找零
81 | String changeAddress = fromAddress;
82 | Long changeAmount = 0L;
83 | Long utxoAmount = 0L;
84 | List needUtxo = new ArrayList<>();
85 | for (UTXO utxo : utxos) {
86 | if (utxoAmount > (fee + miniBtc)) {
87 | break;
88 | } else {
89 | needUtxo.add(utxo);
90 | utxoAmount += utxo.getValue().value;
91 | }
92 | }
93 | changeAmount = utxoAmount - (fee + miniBtc);
94 | //余额判断
95 | if (changeAmount < 0) {
96 | throw new Exception("utxo余额不足");
97 | }
98 | if (changeAmount > 0) {
99 | tran.addOutput(Coin.valueOf(changeAmount), LegacyAddress.fromBase58(networkParameters, changeAddress));
100 | }
101 |
102 | //先添加未签名的输入,也就是utxo
103 | for (UTXO utxo : needUtxo) {
104 | tran.addInput(utxo.getHash(), utxo.getIndex(), utxo.getScript()).setSequenceNumber(TransactionInput.NO_SEQUENCE - 2);
105 | }
106 |
107 | //下面就是签名
108 | for (int i = 0; i < needUtxo.size(); i++) {
109 | ECKey ecKey = DumpedPrivateKey.fromBase58(networkParameters, privateKey).getKey();
110 | TransactionInput transactionInput = tran.getInput(i);
111 | Script scriptPubKey = ScriptBuilder.createOutputScript(LegacyAddress.fromBase58(networkParameters, fromAddress));
112 | Sha256Hash hash = tran.hashForSignature(i, scriptPubKey, Transaction.SigHash.ALL, false);
113 | ECKey.ECDSASignature ecSig = ecKey.sign(hash);
114 | TransactionSignature txSig = new TransactionSignature(ecSig, Transaction.SigHash.ALL, false);
115 | transactionInput.setScriptSig(ScriptBuilder.createInputScript(txSig, ecKey));
116 | }
117 |
118 | //这是签名之后的原始交易,直接去广播就行了
119 | String signedHex = Hex.toHexString(tran.bitcoinSerialize());
120 | //这是交易的hash
121 | String txHash = Hex.toHexString(Utils.reverseBytes(Sha256Hash.hash(Sha256Hash.hash(tran.bitcoinSerialize()))));
122 | logger.info("fee:{},utxoAmount:{},changeAmount:{}", fee, utxoAmount, changeAmount);
123 | return signedHex;
124 | }
125 |
126 | /**
127 | * 获取矿工费用
128 | * @param utxos
129 | * @return
130 | */
131 | public Long getOmniFee(List utxos) {
132 | Long miniBtc = 546L;
133 | Long feeRate = getFeeRate();
134 | Long utxoAmount = 0L;
135 | Long fee = 0L;
136 | Long utxoSize = 0L;
137 | for (UTXO output : utxos) {
138 | utxoSize++;
139 | if (utxoAmount > (fee + miniBtc)) {
140 | break;
141 | } else {
142 | utxoAmount += output.getValue().value;
143 | fee = (utxoSize * 148 * 34 * 3 + 10) * feeRate;
144 | }
145 | }
146 | return fee;
147 | }
148 |
149 | /***
150 | * 获取未消费列表
151 | * @param address :地址
152 | * @return
153 | */
154 | public List getUnspent(String address) {
155 | List utxos = Lists.newArrayList();
156 | String host = "blockchain.info";
157 | String url = "https://" + host + "/zh-cn/unspent?active=" + address;
158 | try {
159 | String httpGet = HttpUtil.sendGet(url);//TODO;联网
160 | if (StringUtils.equals("No free outputs to spend", httpGet)) {
161 | return utxos;
162 | }
163 | JSONObject jsonObject = JSON.parseObject(httpGet);
164 | JSONArray unspentOutputs = jsonObject.getJSONArray("unspent_outputs");
165 | List