├── 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 outputs = JSONObject.parseArray(unspentOutputs.toJSONString(), Map.class); 166 | if (outputs == null || outputs.size() == 0) { 167 | System.out.println("交易异常,余额不足"); 168 | } 169 | for (int i = 0; i < outputs.size(); i++) { 170 | Map outputsMap = outputs.get(i); 171 | String tx_hash = outputsMap.get("tx_hash").toString(); 172 | String tx_hash_big_endian = outputsMap.get("tx_hash_big_endian").toString(); 173 | String tx_index = outputsMap.get("tx_index").toString(); 174 | String tx_output_n = outputsMap.get("tx_output_n").toString(); 175 | String script = outputsMap.get("script").toString(); 176 | String value = outputsMap.get("value").toString(); 177 | String value_hex = outputsMap.get("value_hex").toString(); 178 | String confirmations = outputsMap.get("confirmations").toString(); 179 | UTXO utxo = new UTXO(Sha256Hash.wrap(tx_hash_big_endian), Long.valueOf(tx_output_n), Coin.valueOf(Long.valueOf(value)), 180 | 0, false, new Script(Hex.decode(script))); 181 | utxos.add(utxo); 182 | } 183 | return utxos; 184 | } catch (Exception e) { 185 | logger.error("【BTC获取未消费列表】失败,", e); 186 | return null; 187 | } 188 | 189 | } 190 | 191 | /** 192 | * 获取btc费率 193 | * 194 | * @return 195 | */ 196 | public Long getFeeRate() { 197 | try { 198 | String httpGet1 = HttpUtil.sendGet("https://bitcoinfees.earn.com/api/v1/fees/recommended"); 199 | Map map = JSON.parseObject(httpGet1, Map.class); 200 | Long fastestFee = Long.valueOf(map.get("fastestFee").toString()); 201 | return fastestFee; 202 | } catch (Exception e) { 203 | e.printStackTrace(); 204 | return 0L; 205 | } 206 | } 207 | 208 | /** 209 | * 转账 210 | * @param fromAddress 211 | * @param address 212 | * @param amount 213 | * @return 214 | */ 215 | public MessageResult transferFromWallet(Account account, String fromAddress, String address, BigDecimal amount) { 216 | // omni的propertyid是1,所以在omni_getbalance时最后传了一个1,正式环境usdt的propertyid是31。 217 | Integer propertyid = 31; 218 | // 获取UTXO列表 219 | List< UTXO > utxos = this.getUnspent(fromAddress); 220 | // 获取手续费 221 | Long fee = this.getOmniFee(utxos); 222 | try { 223 | // 获取签名后的交易 224 | String signedHex = this.omniSign(fromAddress, address, account.getPriv(), amount, fee, propertyid, utxos); 225 | // 广播交易 226 | String txHash = this.pushTx(signedHex); 227 | if (StringUtils.isNotBlank(txHash)) { 228 | // TODO 更新账户余额 229 | MessageResult result = new MessageResult(0, "success"); 230 | result.setData(txHash); 231 | return result; 232 | } else { 233 | // 转账失败 234 | return MessageResult.error(500, "error:" + "转账失败"); 235 | } 236 | } catch (Exception e) { 237 | e.printStackTrace(); 238 | return MessageResult.error(500, "error:" + e.getMessage()); 239 | } 240 | } 241 | 242 | private String pushTx(String signedHex) { 243 | JSONObject jsonObject = new JSONObject(); 244 | jsonObject.put("jsonrpc","2.0"); 245 | jsonObject.put("id", "viewtoken"); 246 | jsonObject.put("method", "sendrawtransaction"); 247 | jsonObject.put("params", signedHex); 248 | String resultStr = HttpRequest.sendPost(Constant.ACT_TRANSACTION_PUSHTX, jsonObject); 249 | if (StringUtils.isNotBlank(resultStr)) { 250 | JSONObject resultObj = JSONObject.parseObject(resultStr); 251 | if (null != resultObj && StringUtils.isNotBlank(resultObj.getString("result"))) { 252 | return resultObj.getString("result"); 253 | } 254 | } 255 | return ""; 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /src/main/java/ai/turbochain/ipex/wallet/util/BTCAccountGenerator.java: -------------------------------------------------------------------------------- 1 | package ai.turbochain.ipex.wallet.util; 2 | 3 | import java.io.File; 4 | import java.math.BigInteger; 5 | import java.security.SecureRandom; 6 | import java.text.SimpleDateFormat; 7 | import java.util.Arrays; 8 | import java.util.Date; 9 | import java.util.List; 10 | 11 | import org.bitcoinj.core.Address; 12 | import org.bitcoinj.core.ECKey; 13 | import org.bitcoinj.core.LegacyAddress; 14 | import org.bitcoinj.crypto.ChildNumber; 15 | import org.bitcoinj.crypto.DeterministicKey; 16 | import org.bitcoinj.crypto.HDKeyDerivation; 17 | import org.bitcoinj.params.MainNetParams; 18 | import org.bitcoinj.wallet.DeterministicSeed; 19 | import org.bitcoinj.wallet.Wallet; 20 | import org.slf4j.Logger; 21 | import org.slf4j.LoggerFactory; 22 | import org.springframework.beans.factory.annotation.Value; 23 | import org.springframework.stereotype.Component; 24 | import org.web3j.utils.Numeric; 25 | 26 | import com.google.common.base.Joiner; 27 | 28 | import ai.turbochain.ipex.wallet.entity.BtcBean; 29 | 30 | /** 31 | * 生成虚拟货币地址 32 | * 33 | * @author 34 | * @date 2018年11月16日 下午2:44:17 35 | */ 36 | @Component 37 | public class BTCAccountGenerator { 38 | 39 | @Value("${btc.keyStoreDirPath}") 40 | private String keyStoreDirPath; 41 | 42 | private static Logger logger = LoggerFactory.getLogger(BTCAccountGenerator.class); 43 | 44 | /** 45 | * 生成随机的DeterministicSeed 可以同时得到助记词(16进制seed值) 46 | */ 47 | public static DeterministicSeed createRandomDeterministicSeed(String password) { 48 | DeterministicSeed deterministicSeed = new DeterministicSeed(new SecureRandom(), 128, password); 49 | return deterministicSeed; 50 | } 51 | 52 | /** 53 | * 助记词数据变成String 54 | * 55 | * @param mnemonicList 56 | * @return 57 | */ 58 | public static String mnemonic2String(List mnemonicList) { 59 | return Joiner.on(" ").join(mnemonicList); 60 | } 61 | 62 | /** 63 | * 使用助记词种子生成钱包 64 | * 65 | * @param ds 66 | * @return 67 | */ 68 | public static ECKey generateECKey(DeterministicSeed ds) { 69 | DeterministicKey deterministicKey = HDKeyDerivation.createMasterPrivateKey(ds.getSeedBytes()); 70 | String[] pathArray = "m/0'/0/0".split("/"); 71 | for (int i = 1; i < pathArray.length; i++) { 72 | ChildNumber childNumber; 73 | if (pathArray[i].endsWith("'")) { 74 | int number = Integer.parseInt(pathArray[i].substring(0, pathArray[i].length() - 1)); 75 | childNumber = new ChildNumber(number, true); 76 | } else { 77 | int number = Integer.parseInt(pathArray[i]); 78 | childNumber = new ChildNumber(number, false); 79 | } 80 | deterministicKey = HDKeyDerivation.deriveChildKey(deterministicKey, childNumber); 81 | } 82 | BigInteger privKeyBTC = deterministicKey.getPrivKey(); 83 | ECKey ecKey = ECKey.fromPrivate(privKeyBTC); 84 | return ecKey; 85 | } 86 | 87 | /** 88 | * 从助记词中获取 DeterministicSeed 89 | * 90 | * @param mnemonicList 助记词 91 | * @param passphrase 密码 密码建议使用方法空字符,都这样使用 92 | * @return 93 | */ 94 | public static DeterministicSeed getDeterministicSeed(List mnemonicList, String passphrase) { 95 | if (passphrase == null) { 96 | passphrase = ""; 97 | } 98 | long creationTimeSeconds = System.currentTimeMillis() / 1000; 99 | DeterministicSeed deterministicSeed = new DeterministicSeed(mnemonicList, null, passphrase, 100 | creationTimeSeconds); 101 | System.out.println("16进制seed值为:" + deterministicSeed.toHexString()); 102 | return deterministicSeed; 103 | } 104 | 105 | /** 106 | * 助记词String转换为 list 107 | * 108 | * @param mnemonics 109 | * @return 110 | */ 111 | public static List mnemonicString2List(String mnemonics) { 112 | return Arrays.asList(mnemonics.split(" ")); 113 | } 114 | 115 | public BtcBean createBtcAccount() throws Exception { 116 | // 生成助记词 117 | DeterministicSeed deterministicSeed = BTCAccountGenerator.createRandomDeterministicSeed(""); 118 | List mnemonicList = deterministicSeed.getMnemonicCode(); 119 | String mnemonic = BTCAccountGenerator.mnemonic2String(mnemonicList); 120 | // 生成eckey 121 | ECKey ecKey = BTCAccountGenerator.generateECKey(deterministicSeed); 122 | // 解析公钥 123 | String publickey = Numeric.toHexStringNoPrefixZeroPadded(new BigInteger(ecKey.getPubKey()), 66); 124 | // 解析私钥 125 | String privateKey = ecKey.getPrivateKeyEncoded(MainNetParams.get()).toString(); 126 | // 解析地址 127 | // 正式网:MainNetParams.get(),测试网:TestNet3Params.get() 128 | Address myAddress = LegacyAddress.fromKey(MainNetParams.get(), ecKey); 129 | String btcAddress = myAddress.toString(); 130 | // 保存文件 131 | Wallet wallet = Wallet.fromSeed(MainNetParams.get(), deterministicSeed); 132 | // 文件名 133 | SimpleDateFormat dateFormat = new SimpleDateFormat("'BTC--'yyyy-MM-dd'T'HH-mm-ss.SSS'--'"); 134 | String fileName = dateFormat.format(new Date()) + btcAddress + ".wallet"; 135 | File keyStoreFile = new File(keyStoreDirPath, fileName); 136 | wallet.saveToFile(keyStoreFile); 137 | 138 | logger.info("eckey 生成的btcAddress:" + btcAddress + " ,wallet 生成的btcAddress:" + wallet.currentReceiveAddress()); 139 | 140 | BtcBean btcBean = BtcBean.builder().btcAddress(btcAddress).btcPrivKey(privateKey).btcPubKey(publickey) 141 | .mnemonic(mnemonic).mnemonicList(mnemonicList).file(fileName).build(); 142 | return btcBean; 143 | } 144 | 145 | 146 | } -------------------------------------------------------------------------------- /src/main/java/ai/turbochain/ipex/wallet/util/HttpRequest.java: -------------------------------------------------------------------------------- 1 | package ai.turbochain.ipex.wallet.util; 2 | 3 | import org.apache.commons.lang.StringUtils; 4 | import org.apache.http.HttpStatus; 5 | import org.apache.http.client.ClientProtocolException; 6 | import org.apache.http.client.methods.CloseableHttpResponse; 7 | import org.apache.http.client.methods.HttpGet; 8 | import org.apache.http.impl.client.CloseableHttpClient; 9 | import org.apache.http.impl.client.HttpClients; 10 | import org.apache.http.util.EntityUtils; 11 | import org.springframework.context.annotation.Configuration; 12 | 13 | import java.io.BufferedReader; 14 | import java.io.IOException; 15 | import java.io.InputStreamReader; 16 | import java.io.PrintWriter; 17 | import java.net.URL; 18 | import java.net.URLConnection; 19 | 20 | @Configuration 21 | public class HttpRequest { 22 | 23 | 24 | /** 25 | * 向指定 URL 发送POST方法的请求 26 | * 27 | * @param url 28 | * 发送请求的 URL 29 | * @param param 30 | * 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 31 | * @return 所代表远程资源的响应结果 32 | */ 33 | public static String sendPost(String url, Object param) { 34 | PrintWriter out = null; 35 | BufferedReader in = null; 36 | String result = ""; 37 | try { 38 | URL realUrl = new URL(url); 39 | // 打开和URL之间的连接 40 | URLConnection conn = realUrl.openConnection(); 41 | // 设置通用的请求属性 42 | conn.setRequestProperty("accept", "*/*"); 43 | conn.setRequestProperty("connection", "Keep-Alive"); 44 | conn.setRequestProperty("user-agent", 45 | "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); 46 | // conn.setRequestProperty("Cookie", 47 | // "XXL_JOB_LOGIN_IDENTITY=6333303830376536353837616465323835626137616465396638383162336437"); 48 | // conn.setRequestProperty("Cookie", 49 | // "LOGIN_IDENTITY=61646d696e5f313233343536"); 50 | conn.setConnectTimeout(60000); 51 | // 发送POST请求必须设置如下两行 52 | conn.setDoOutput(true); 53 | conn.setDoInput(true); 54 | // 获取URLConnection对象对应的输出流 55 | out = new PrintWriter(conn.getOutputStream()); 56 | // 发送请求参数 57 | out.print(param); 58 | // flush输出流的缓冲 59 | out.flush(); 60 | // 定义BufferedReader输入流来读取URL的响应 61 | in = new BufferedReader( 62 | new InputStreamReader(conn.getInputStream())); 63 | String line; 64 | while ((line = in.readLine()) != null) { 65 | result += line; 66 | } 67 | } catch (Exception e) { 68 | e.printStackTrace(); 69 | } 70 | //使用finally块来关闭输出流、输入流 71 | finally{ 72 | try{ 73 | if(out!=null){ 74 | out.close(); 75 | } 76 | if(in!=null){ 77 | in.close(); 78 | } 79 | } 80 | catch(IOException ex){ 81 | ex.printStackTrace(); 82 | } 83 | } 84 | return result; 85 | } 86 | 87 | public static void main(String[] args) { 88 | Long startTime = 1582807076404L; 89 | Long endTime = System.currentTimeMillis(); 90 | Long time = endTime - startTime; 91 | System.out.println("time: " + time/1000); 92 | // String str = sendGetData("https://blockchain.info/block-height/593323?format=json",""); 93 | // String str = sendPost("https://wallet.tokenview.com/onchainwallet/btc") 94 | // System.out.println("str: " + str); 95 | } 96 | 97 | /** 98 | * get请求传输数据 99 | * 100 | * @param url 101 | * @param encoding 102 | * @return 103 | * @throws ClientProtocolException 104 | * @throws IOException 105 | */ 106 | public static String sendGetData(String url, String encoding) { 107 | String result = ""; 108 | CloseableHttpResponse response = null; 109 | try { 110 | // 创建httpclient对象 111 | CloseableHttpClient httpClient = HttpClients.createDefault(); 112 | // 创建get方式请求对象 113 | HttpGet httpGet = new HttpGet(url); 114 | httpGet.addHeader("Content-type", "application/json"); 115 | // 通过请求对象获取响应对象 116 | response = httpClient.execute(httpGet); 117 | // 获取结果实体 118 | // 判断网络连接状态码是否正常(0--200都数正常) 119 | if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { 120 | encoding = StringUtils.isBlank(encoding) ? "utf-8" : encoding; 121 | result = EntityUtils.toString(response.getEntity(), encoding); 122 | } 123 | // 释放链接 124 | response.close(); 125 | } catch(Exception e) { 126 | e.printStackTrace(); 127 | } finally { 128 | try { 129 | if (null != response) { 130 | response.close(); 131 | } 132 | } catch (IOException e) { 133 | e.printStackTrace(); 134 | } 135 | } 136 | return result; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/main/java/ai/turbochain/ipex/wallet/util/MessageResult.java: -------------------------------------------------------------------------------- 1 | package ai.turbochain.ipex.wallet.util; 2 | 3 | 4 | import com.alibaba.fastjson.JSONObject; 5 | 6 | public class MessageResult { 7 | private Object data; 8 | public MessageResult(int code , String msg){ 9 | this.code = code; 10 | this.message = msg; 11 | } 12 | public MessageResult(int code , String msg, Object object){ 13 | this.code = code; 14 | this.message = msg; 15 | this.data = object; 16 | } 17 | public MessageResult() { 18 | // TODO Auto-generated constructor stub 19 | } 20 | 21 | public static MessageResult success(){ 22 | return new MessageResult(0,"SUCCESS"); 23 | } 24 | 25 | public static MessageResult success(String msg){ 26 | return new MessageResult(0,msg); 27 | } 28 | 29 | public static MessageResult error(int code,String msg){ 30 | return new MessageResult(code,msg); 31 | } 32 | 33 | private int code; 34 | private String message; 35 | private Object Data; 36 | 37 | public int getCode() { 38 | return code; 39 | } 40 | public void setCode(int code) { 41 | this.code = code; 42 | } 43 | public String getMessage() { 44 | return message; 45 | } 46 | public void setMessage(String message) { 47 | this.message = message; 48 | } 49 | 50 | public String toString(){ 51 | return JSONObject.toJSONString(this); 52 | //return "{\"code\":"+code+",\"message\":\""+message+"\"}"; 53 | } 54 | public Object getData() { 55 | return Data; 56 | } 57 | public void setData(Object data) { 58 | Data = data; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/resources/application-dev.properties: -------------------------------------------------------------------------------- 1 | server.port=7002 2 | spring.application.name=service-rpc-usdt 3 | eureka.client.serviceUrl.defaultZone=http://10.20.31.178:7000/eureka/ 4 | # \u6CE8\u518C\u65F6\u4F7F\u7528ip\u800C\u4E0D\u662F\u4E3B\u673A\u540D 5 | eureka.instance.prefer-ip-address=true 6 | #docker\u8BFB\u53D6\u7CFB\u7EDF\u73AF\u5883\u53D8\u91CF 7 | eureka.instance.instance-id=${spring.cloud.client.ipAddress}:${server.port} 8 | 9 | #kafka 10 | # \u6307\u5B9Akafka \u4EE3\u7406\u5730\u5740\uFF0C\u53EF\u4EE5\u591A\u4E2A 11 | spring.kafka.bootstrap-servers=10.20.32.123:9092 12 | # \u6307\u5B9A\u9ED8\u8BA4\u6D88\u8D39\u8005group id 13 | spring.kafka.consumer.group-id=default-group 14 | # \u6307\u5B9A\u9ED8\u8BA4topic id 15 | spring.kafka.template.default-topic= test 16 | # \u6307\u5B9Alistener \u5BB9\u5668\u4E2D\u7684\u7EBF\u7A0B\u6570\uFF0C\u7528\u4E8E\u63D0\u9AD8\u5E76\u53D1\u91CF 17 | spring.kafka.listener.concurrency= 3 18 | # \u6BCF\u6B21\u6279\u91CF\u53D1\u9001\u6D88\u606F\u7684\u6570\u91CF 19 | spring.kafka.producer.batch-size= 1000 20 | # mongodb 21 | spring.data.mongodb.uri=mongodb://fly:fly123456@10.20.31.178:27017/bitrade 22 | 23 | coin.rpc=http://usdt:usdt123@10.20.30.26:18332/ 24 | coin.name=USDT 25 | coin.unit=USDT 26 | #\u8F6C\u8D26\u65F6\u9ED8\u8BA4\u652F\u4ED8\u7684btc\u624B\u7EED\u8D39 27 | coin.default-miner-fee=0.0001 28 | #\u6BCF\u6B21\u7ED9USDT\u5730\u5740\u5145\u503C\u7684btc\u6570\u91CF 29 | coin.recharge-miner-fee=0.0001 30 | coin.min-collect-amount=1 31 | btc.keyStoreDirPath=D:// -------------------------------------------------------------------------------- /src/main/resources/application-prod.properties: -------------------------------------------------------------------------------- 1 | server.port=7002 2 | spring.application.name=service-rpc-usdt 3 | eureka.client.serviceUrl.defaultZone=http://10.20.32.144:7000/eureka/ 4 | # \u6CE8\u518C\u65F6\u4F7F\u7528ip\u800C\u4E0D\u662F\u4E3B\u673A\u540D 5 | eureka.instance.prefer-ip-address=true 6 | #docker\u8BFB\u53D6\u7CFB\u7EDF\u73AF\u5883\u53D8\u91CF 7 | eureka.instance.instance-id=${spring.cloud.client.ipAddress}:${server.port} 8 | #docker\u8BFB\u53D6\u7CFB\u7EDF\u73AF\u5883\u53D8\u91CF 9 | #eureka.instance.instance-id=${HOST}:${PORT0} 10 | 11 | #kafka 12 | # \u6307\u5B9Akafka \u4EE3\u7406\u5730\u5740\uFF0C\u53EF\u4EE5\u591A\u4E2A 13 | spring.kafka.bootstrap-servers=10.20.32.122:9092 14 | # \u6307\u5B9A\u9ED8\u8BA4\u6D88\u8D39\u8005group id 15 | spring.kafka.consumer.group-id=default-group 16 | # \u6307\u5B9A\u9ED8\u8BA4topic id 17 | spring.kafka.template.default-topic= test 18 | # \u6307\u5B9Alistener \u5BB9\u5668\u4E2D\u7684\u7EBF\u7A0B\u6570\uFF0C\u7528\u4E8E\u63D0\u9AD8\u5E76\u53D1\u91CF 19 | spring.kafka.listener.concurrency= 3 20 | # \u6BCF\u6B21\u6279\u91CF\u53D1\u9001\u6D88\u606F\u7684\u6570\u91CF 21 | spring.kafka.producer.batch-size= 1000 22 | # mongodb 23 | spring.data.mongodb.uri=mongodb://fly:fly123456@10.20.31.178:27017/exchange 24 | 25 | coin.rpc=http://usdt:usdt123@10.20.30.26:18332/ 26 | coin.name=USDT 27 | coin.unit=USDT 28 | #\u8F6C\u8D26\u65F6\u9ED8\u8BA4\u652F\u4ED8\u7684btc\u624B\u7EED\u8D39 29 | coin.default-miner-fee=0.0001 30 | #\u6BCF\u6B21\u7ED9USDT\u5730\u5740\u5145\u503C\u7684btc\u6570\u91CF 31 | coin.recharge-miner-fee=0.0001 32 | coin.min-collect-amount=1 33 | btc.keyStoreDirPath=/opt/usdt/keystore -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.profiles.active=prod -------------------------------------------------------------------------------- /src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | logback 4 | 5 | 6 | 9 | 10 | %d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n 11 | 12 | 13 | 14 | 15 | 16 | true 17 | 18 | 19 | /mnt/logs/usdt/%d{yyyy-MM-dd}/%d{yyyy-MM-dd}.log 20 | 21 | 22 | 23 | 24 | %d{yyyy-MM-dd HH:mm:ss} -%msg%n 25 | 26 | 27 | 28 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n 29 | UTF-8 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 41 | --------------------------------------------------------------------------------