├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── mvc │ │ ├── PolymorphicApplication.java │ │ └── polymorphic │ │ ├── common │ │ ├── BlockChainService.java │ │ ├── BlockConfig.java │ │ ├── BlockException.java │ │ ├── BlockResult.java │ │ ├── SpringContextUtil.java │ │ ├── bean │ │ │ ├── BchTransaction.java │ │ │ └── BtcTransaction.java │ │ └── interceptor │ │ │ └── ServiceAuthRestInterceptor.java │ │ ├── configuration │ │ ├── CorsConfig.java │ │ ├── RpcConfiguration.java │ │ ├── SwaggerConfig.java │ │ └── TokenConfig.java │ │ ├── controller │ │ ├── BlockController.java │ │ ├── Controller.java │ │ ├── DemoController.java │ │ └── EthereumController.java │ │ ├── exceptions │ │ └── ExceededGasException.java │ │ ├── model │ │ ├── Account.java │ │ ├── ApprovalEventResponse.java │ │ ├── Block.java │ │ ├── EthTransaction.java │ │ ├── Filter.java │ │ ├── HumanStandardToken.java │ │ ├── JsonCredentials.java │ │ ├── Method.java │ │ ├── NodeConfiguration.java │ │ ├── Receipt.java │ │ ├── TransactionResponse.java │ │ ├── TransferEventResponse.java │ │ └── dto │ │ │ ├── BalanceDTO.java │ │ │ ├── ExportAccountDTO.java │ │ │ ├── ImportRawKeyDTO.java │ │ │ ├── NewAccountDTO.java │ │ │ ├── PersonalByPrivateKeyDTO.java │ │ │ ├── RawTransactionDTO.java │ │ │ ├── SendTransactionDTO.java │ │ │ ├── TransactionByHashDTO.java │ │ │ └── TransactionCountDTO.java │ │ ├── service │ │ ├── BchService.java │ │ ├── BtcService.java │ │ ├── ContractService.java │ │ ├── EthService.java │ │ ├── EtherscanUrl.java │ │ ├── RpcService.java │ │ └── RpcServiceImpl.java │ │ └── utils │ │ ├── BlockServiceUtil.java │ │ ├── Denomination.java │ │ ├── EthereumUtil.java │ │ ├── FileUtil.java │ │ └── RSACoder.java └── resources │ ├── application-template.yml │ └── logback.xml └── test └── resources ├── SimpleStorage.sol └── sample.sol /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .settings 3 | .classpath 4 | .project 5 | 6 | .idea/ 7 | *.iml 8 | *.ipr 9 | *.iws 10 | .gradle/ 11 | build/ 12 | mods/ 13 | .idea/libraries 14 | *.DS_Store 15 | application.yml 16 | 17 | *.class 18 | 19 | *_blockstore 20 | 21 | # Package Files 22 | # *.jar 23 | *.war 24 | *.ear 25 | 26 | # IDEA 27 | *.iml 28 | .idea/ 29 | .DS_Store 30 | local.* 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 mvchain 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wallet demo 2 | about Ethereum 3 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.mvc 8 | polymorphic-api 9 | 1.0-SNAPSHOT 10 | jar 11 | 12 | 13 | org.springframework.boot 14 | spring-boot-starter-parent 15 | 2.0.0.RELEASE 16 | 17 | 18 | 19 | com.mvc.PolymorphicApplication 20 | UTF-8 21 | 1.8 22 | 1.8 23 | 1.16.6 24 | 1.2.0 25 | 4.12 26 | 1.10 27 | 18.0 28 | 4.2.5.RELEASE 29 | 2.0.2-beta 30 | 31 | 32 | 33 | 34 | 35 | io.yope 36 | yope-ethereum-rest 37 | ${project.version} 38 | 39 | 40 | io.yope 41 | yope-ethereum-rpc 42 | ${project.version} 43 | 44 | 45 | io.yope 46 | yope-ethereum-services 47 | ${project.version} 48 | 49 | 50 | io.yope 51 | yope-ethereum-model 52 | ${project.version} 53 | 54 | 55 | org.projectlombok 56 | lombok 57 | ${lombok.version} 58 | 59 | 60 | com.github.briandilley.jsonrpc4j 61 | jsonrpc4j 62 | ${jsonrpc4j.version} 63 | 64 | 65 | junit 66 | junit 67 | ${junit.version} 68 | 69 | 70 | commons-codec 71 | commons-codec 72 | ${commons-codec.version} 73 | 74 | 75 | com.google.guava 76 | guava 77 | ${guava.version} 78 | 79 | 80 | org.apache.commons 81 | commons-lang3 82 | 3.4 83 | 84 | 85 | org.springframework 86 | spring-test 87 | ${spring-test.version} 88 | test 89 | 90 | 91 | org.mockito 92 | mockito-all 93 | ${mockito.version} 94 | test 95 | 96 | 97 | com.cegeka 98 | tetherj 99 | 1.0.11 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | org.springframework.boot 108 | spring-boot-configuration-processor 109 | true 110 | 111 | 112 | 113 | org.web3j 114 | core 115 | 3.2.0 116 | 117 | 118 | 119 | org.web3j 120 | geth 121 | 3.2.0 122 | 123 | 124 | 125 | 126 | org.web3j 127 | quorum 128 | 0.8.0 129 | 130 | 131 | 132 | com.alibaba 133 | fastjson 134 | 1.2.39 135 | 136 | 137 | 138 | org.springframework.boot 139 | spring-boot-starter-web 140 | 2.0.0.RELEASE 141 | 142 | 143 | org.projectlombok 144 | lombok 145 | 146 | 147 | com.github.briandilley.jsonrpc4j 148 | jsonrpc4j 149 | 150 | 151 | junit 152 | junit 153 | 154 | 155 | commons-codec 156 | commons-codec 157 | 158 | 159 | org.slf4j 160 | slf4j-api 161 | 162 | 163 | com.google.guava 164 | guava 165 | 166 | 167 | org.springframework 168 | spring-test 169 | 170 | 171 | org.mockito 172 | mockito-all 173 | 174 | 175 | org.apache.commons 176 | commons-lang3 177 | 3.4 178 | 179 | 180 | com.mvc 181 | tools 182 | 1.0-SNAPSHOT 183 | 184 | 185 | 186 | com.spring4all 187 | spring-boot-starter-swagger 188 | 1.5.1.RELEASE 189 | 190 | 191 | 192 | 193 | org.bitcoincashj 194 | bitcoincashj 195 | 1.0-SNAPSHOT 196 | 197 | 198 | org.bitcoinj 199 | bitcoinj-core 200 | 0.14.6 201 | compile 202 | 203 | 204 | 205 | 206 | 207 | alternateBuildDir 208 | 209 | 210 | alt.build.dir 211 | 212 | 213 | 214 | ${alt.build.dir} 215 | 216 | 217 | 218 | 219 | 220 | 221 | ethereum-api 222 | 223 | 224 | 225 | org.springframework.boot 226 | spring-boot-maven-plugin 227 | 228 | 229 | org.apache.maven.plugins 230 | maven-compiler-plugin 231 | 232 | ${maven.compiler.source} 233 | ${maven.compiler.target} 234 | ${project.build.sourceEncoding} 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | spring-milestones 243 | http://repo.spring.io/libs-snapshot 244 | 245 | true 246 | 247 | 248 | 249 | 250 | 251 | 252 | oss.jfrog.org 253 | Repository from Bintray 254 | http://dl.bintray.com/ethereum/maven 255 | 256 | 257 | cgk-nexus-blockchain 258 | blockchain releases 259 | http://nexus.cegeka.be/nexus/content/repositories/blockchain-releases 260 | 261 | 262 | 263 | 264 | 265 | releases 266 | Nexus Release Repository 267 | http://192.168.203.7:8081/nexus/content/repositories/releases/ 268 | 269 | 270 | snapshots 271 | Nexus Snapshot Repository 272 | http://192.168.203.7:8081/nexus/content/repositories/snapshots/ 273 | 274 | 275 | 276 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/PolymorphicApplication.java: -------------------------------------------------------------------------------- 1 | package com.mvc; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.scheduling.annotation.EnableAsync; 8 | import org.springframework.scheduling.annotation.EnableScheduling; 9 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 10 | 11 | 12 | @Configuration 13 | @EnableAutoConfiguration 14 | @EnableScheduling 15 | @EnableSwagger2 16 | @EnableAsync 17 | @SpringBootApplication 18 | public class PolymorphicApplication { 19 | public static void main(String[] args) throws Exception { 20 | SpringApplication.run(PolymorphicApplication.class, args); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/common/BlockChainService.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.common; 2 | 3 | import com.mvc.polymorphic.configuration.TokenConfig; 4 | import com.mvc.tools.context.BaseContextHandler; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.CommandLineRunner; 7 | import org.springframework.stereotype.Service; 8 | 9 | import java.math.BigDecimal; 10 | 11 | /** 12 | * @author ethands 13 | */ 14 | @Service 15 | public abstract class BlockChainService implements CommandLineRunner { 16 | 17 | @Autowired 18 | protected TokenConfig tokenConfig; 19 | @Autowired 20 | protected BlockConfig blockConfig; 21 | 22 | private BlockChainService getService(String serviceName) { 23 | BlockChainService service = SpringContextUtil.getBean(serviceName); 24 | if (null == service) { 25 | throw new BlockException(String.format("%s is not found", serviceName)); 26 | } 27 | return service; 28 | } 29 | 30 | public BlockResult getBalance(String serviceName, String address) throws Exception { 31 | return getService(serviceName).getBalance(address); 32 | } 33 | 34 | protected abstract BlockResult getBalance(String address) throws Exception; 35 | 36 | public BlockResult getTransactionByHash(String serviceName, String transactionHash) throws Exception { 37 | return getService(serviceName).getTransactionByHash(transactionHash); 38 | } 39 | 40 | protected abstract BlockResult getTransactionByHash(String transactionHash) throws Exception; 41 | 42 | public BlockResult sendTransaction(String serviceName, String pass, String from, String to, BigDecimal value) throws Exception { 43 | return getService(serviceName).sendTransaction(pass, from, to, value); 44 | } 45 | 46 | protected abstract BlockResult sendTransaction(String pass, String from, String to, BigDecimal value) throws Exception; 47 | 48 | public BlockResult newAccount(String serviceName, String pass) { 49 | return getService(serviceName).newAccount(pass); 50 | } 51 | 52 | protected abstract BlockResult newAccount(String pass); 53 | 54 | public BlockResult getConfirmation(String serviceName, String transactionHash) throws Exception { 55 | return getService(serviceName).getConfirmation(transactionHash); 56 | } 57 | 58 | protected abstract BlockResult getConfirmation(String transactionHash) throws Exception; 59 | 60 | protected abstract void onTransaction(Object... objects); 61 | 62 | protected BlockResult tokenSuccess(String tokenName, Object result) { 63 | return new BlockResult(tokenName, true, null, result); 64 | } 65 | 66 | protected BlockResult tokenFail(String tokenName, String msg) { 67 | return new BlockResult(tokenName, false, msg, null); 68 | } 69 | 70 | protected String getType() { 71 | return (String) BaseContextHandler.get("type"); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/common/BlockConfig.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.common; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.math.BigInteger; 8 | 9 | /** 10 | * @author qiyichen 11 | * @create 2018/4/9 15:33 12 | */ 13 | @ConfigurationProperties( 14 | prefix = "mvc.block" 15 | )@Component 16 | @Data 17 | public class BlockConfig { 18 | 19 | public String ethService = "http://localhost:8545"; 20 | public Integer timeoutSec = 120; 21 | public BigInteger ethPrice = BigInteger.valueOf(45000); 22 | public BigInteger ethLimit = BigInteger.valueOf(45000); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/common/BlockException.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.common; 2 | 3 | /** 4 | * BlockException 5 | * 6 | * @author qiyichen 7 | * @create 2018/4/9 17:09 8 | */ 9 | public class BlockException extends RuntimeException { 10 | 11 | private static final long serialVersionUID = -6526974425772871300L; 12 | 13 | 14 | public BlockException(String msg) { 15 | super(msg); 16 | } 17 | 18 | public BlockException(String msg, Exception e) { 19 | super(msg, e); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/common/BlockResult.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.common; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * block result 9 | * 10 | * @author qiyichen 11 | * @create 2018/4/9 16:22 12 | */ 13 | @Data 14 | @AllArgsConstructor 15 | @NoArgsConstructor 16 | public class BlockResult { 17 | private String type; 18 | private Boolean success; 19 | private Object error; 20 | private Object result; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/common/SpringContextUtil.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.common; 2 | 3 | import com.mvc.polymorphic.common.interceptor.ServiceAuthRestInterceptor; 4 | import org.springframework.beans.BeansException; 5 | import org.springframework.beans.factory.BeanFactory; 6 | import org.springframework.beans.factory.BeanFactoryAware; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.stereotype.Component; 9 | import org.springframework.web.servlet.config.annotation.InterceptorRegistration; 10 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 11 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 12 | 13 | @Component 14 | @Configuration 15 | public class SpringContextUtil implements BeanFactoryAware, WebMvcConfigurer { 16 | private static BeanFactory beanFactory; 17 | 18 | @Override 19 | public void setBeanFactory(BeanFactory beanFactory) throws BeansException { 20 | SpringContextUtil.beanFactory = beanFactory; 21 | } 22 | 23 | @Override 24 | public void addInterceptors(InterceptorRegistry registry) { 25 | InterceptorRegistration addInterceptor = registry.addInterceptor(new ServiceAuthRestInterceptor()); 26 | // 排除配置 27 | addInterceptor.excludePathPatterns("/error"); 28 | addInterceptor.excludePathPatterns("/login**"); 29 | // 拦截配置 30 | addInterceptor.addPathPatterns("/**"); 31 | } 32 | 33 | public static T getBean(String beanName) { 34 | if (null != beanFactory) { 35 | return (T) beanFactory.getBean(beanName); 36 | } 37 | return null; 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/common/bean/BchTransaction.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.common.bean; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.mvc.bitcoincashj.core.Transaction; 5 | import com.mvc.bitcoincashj.wallet.Wallet; 6 | import lombok.Data; 7 | 8 | import java.io.Serializable; 9 | import java.util.Date; 10 | import java.util.stream.Collectors; 11 | 12 | /** 13 | * BtcTransaction 14 | * 15 | * @author qiyichen 16 | * @create 2018/3/1 11:43 17 | */ 18 | @Data 19 | public class BchTransaction implements Serializable { 20 | private static final long serialVersionUID = -8380806472534356994L; 21 | private String hash; 22 | private Date updatedAt; 23 | private Long value; 24 | private String valueStr; 25 | private String feeStr; 26 | private Long fee; 27 | private Long version; 28 | private Integer depth; 29 | private String fromAddress; 30 | private String toAddress; 31 | 32 | public static BchTransaction build(Transaction trans, Wallet wallet) { 33 | BchTransaction transaction = new BchTransaction(); 34 | transaction.setHash(trans.getHashAsString()); 35 | transaction.setFeeStr(null == trans.getFee() ? "0" : trans.getFee().toFriendlyString()); 36 | transaction.setFee(null == trans.getFee() ? 0 : trans.getFee().getValue()); 37 | transaction.setValueStr(trans.getValue(wallet).toFriendlyString()); 38 | transaction.setVersion(trans.getVersion()); 39 | String from = JSON.toJSONString(trans.getInputs().stream().map(obj -> obj.getFromAddress().toString()).collect(Collectors.toList())); 40 | transaction.setFromAddress(from); 41 | String to = JSON.toJSONString(trans.getOutputs().stream().map(obj -> obj.getAddressFromP2PKHScript(wallet.getParams()).toString()).collect(Collectors.toList())); 42 | transaction.setToAddress(to); 43 | transaction.setDepth(trans.getConfidence().getDepthInBlocks()); 44 | transaction.setValue(trans.getValue(wallet).getValue()); 45 | transaction.setUpdatedAt(trans.getUpdateTime()); 46 | return transaction; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/common/bean/BtcTransaction.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.common.bean; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import lombok.Data; 5 | import org.bitcoinj.core.Transaction; 6 | import org.bitcoinj.wallet.Wallet; 7 | 8 | import java.io.Serializable; 9 | import java.util.Date; 10 | import java.util.stream.Collectors; 11 | 12 | /** 13 | * BtcTransaction 14 | * 15 | * @author qiyichen 16 | * @create 2018/3/1 11:43 17 | */ 18 | @Data 19 | public class BtcTransaction implements Serializable { 20 | private static final long serialVersionUID = -8380806472534356994L; 21 | private String hash; 22 | private Date updatedAt; 23 | private Long value; 24 | private String valueStr; 25 | private String feeStr; 26 | private Long fee; 27 | private Long version; 28 | private Integer depth; 29 | private String fromAddress; 30 | private String toAddress; 31 | 32 | public static BtcTransaction build(Transaction trans, Wallet wallet) { 33 | BtcTransaction transaction = new BtcTransaction(); 34 | transaction.setHash(trans.getHashAsString()); 35 | transaction.setFeeStr(null == trans.getFee() ? "0" : trans.getFee().toFriendlyString()); 36 | transaction.setFee(null == trans.getFee() ? 0 : trans.getFee().getValue()); 37 | transaction.setValueStr(trans.getValue(wallet).toFriendlyString()); 38 | transaction.setVersion(trans.getVersion()); 39 | // lamda expression, transform input streams to a list, then to a JSON string. 40 | String from = JSON.toJSONString(trans.getInputs().stream().map(obj -> obj.getFromAddress().toString()).collect(Collectors.toList())); 41 | transaction.setFromAddress(from); 42 | String to = JSON.toJSONString(trans.getOutputs().stream().map(obj -> obj.getAddressFromP2PKHScript(wallet.getParams()).toString()).collect(Collectors.toList())); 43 | transaction.setToAddress(to); 44 | // conformation count 45 | transaction.setDepth(trans.getConfidence().getDepthInBlocks()); 46 | transaction.setValue(trans.getValue(wallet).getValue()); 47 | transaction.setUpdatedAt(trans.getUpdateTime()); 48 | return transaction; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/common/interceptor/ServiceAuthRestInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.common.interceptor; 2 | 3 | import com.mvc.tools.context.BaseContextHandler; 4 | import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; 5 | 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | 9 | /** 10 | * @author qyc 11 | */ 12 | public class ServiceAuthRestInterceptor extends HandlerInterceptorAdapter { 13 | 14 | @Override 15 | public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 16 | BaseContextHandler.remove(); 17 | super.afterCompletion(request, response, handler, ex); 18 | } 19 | 20 | @Override 21 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 22 | return super.preHandle(request, response, handler); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/configuration/CorsConfig.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.configuration; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.web.cors.CorsConfiguration; 7 | import org.springframework.web.cors.UrlBasedCorsConfigurationSource; 8 | 9 | import java.util.Arrays; 10 | 11 | /** 12 | * 本机联调跨域问题 13 | */ 14 | @Configuration 15 | public class CorsConfig { 16 | 17 | @Value("${cors.allowedOrigin}") 18 | private String allowedOrigin; 19 | 20 | private CorsConfiguration buildConfig() { 21 | CorsConfiguration corsConfiguration = new CorsConfiguration(); 22 | corsConfiguration.setAllowedOrigins(Arrays.asList(allowedOrigin)); 23 | // corsConfiguration.setAllowedOrigin(allowedOrigin); // 1 24 | corsConfiguration.addAllowedHeader("*"); // 2 25 | corsConfiguration.addAllowedMethod("*"); // 3 26 | return corsConfiguration; 27 | } 28 | 29 | @Bean 30 | public org.springframework.web.filter.CorsFilter corsFilter() { 31 | UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); 32 | source.registerCorsConfiguration("/**", buildConfig()); // 4 33 | return new org.springframework.web.filter.CorsFilter(source); 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/configuration/RpcConfiguration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.mvc.polymorphic.configuration; 5 | 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.web.client.RestTemplate; 12 | import org.web3j.protocol.Web3j; 13 | import org.web3j.protocol.admin.Admin; 14 | import org.web3j.protocol.geth.Geth; 15 | import org.web3j.protocol.http.HttpService; 16 | import org.web3j.quorum.Quorum; 17 | 18 | @Configuration 19 | @EnableConfigurationProperties 20 | @Slf4j 21 | public class RpcConfiguration { 22 | 23 | @Value("${org.ethereum.address}") 24 | private String ethereumAddress; 25 | 26 | @Bean 27 | public RestTemplate restTemplate() { 28 | return new RestTemplate(); 29 | } 30 | 31 | @Bean 32 | public Web3j web3j() { 33 | return Web3j.build(new HttpService(ethereumAddress)); 34 | } 35 | 36 | @Bean 37 | public Admin admin() { 38 | 39 | return Admin.build(new HttpService(ethereumAddress)); 40 | } 41 | 42 | @Bean 43 | public Geth geth() { 44 | return Geth.build(new HttpService(ethereumAddress)); 45 | } 46 | 47 | @Bean 48 | public Quorum quorum() { 49 | return Quorum.build(new HttpService(ethereumAddress)); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/configuration/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.configuration; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import springfox.documentation.builders.ApiInfoBuilder; 6 | import springfox.documentation.builders.PathSelectors; 7 | import springfox.documentation.builders.RequestHandlerSelectors; 8 | import springfox.documentation.service.ApiInfo; 9 | import springfox.documentation.spi.DocumentationType; 10 | import springfox.documentation.spring.web.plugins.Docket; 11 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 12 | 13 | @Configuration 14 | @EnableSwagger2 15 | public class SwaggerConfig { 16 | 17 | @Bean 18 | public Docket createRestApi() { 19 | return new Docket(DocumentationType.SWAGGER_2) 20 | .apiInfo(apiInfo()) 21 | .select() 22 | .apis(RequestHandlerSelectors.basePackage("com.mvc.polymorphic")) 23 | .paths(PathSelectors.any()) 24 | .build(); 25 | } 26 | 27 | private ApiInfo apiInfo() { 28 | return new ApiInfoBuilder() 29 | .title("MVC Polymorphic Wallet APIs") 30 | .description("For more:") 31 | .termsOfServiceUrl("http://www.mvchain.net") 32 | .contact("") 33 | .version("1.0") 34 | .build(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/configuration/TokenConfig.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.configuration; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.stereotype.Component; 6 | 7 | import java.math.BigInteger; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | @Data 12 | @ConfigurationProperties(prefix = "mvc") 13 | @Component 14 | public class TokenConfig { 15 | 16 | public static final String ENV_LOCAL = "local"; 17 | public static final String ENV_TEST = "test"; 18 | public static final String ENV_PROD = "prod"; 19 | 20 | private Map env = new HashMap<>(); 21 | 22 | private Map> url = new HashMap<>(); 23 | private Map> path = new HashMap<>(); 24 | private Map> pass = new HashMap<>(); 25 | private Map>> gas = new HashMap<>(); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/controller/BlockController.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.controller; 2 | 3 | import com.mvc.polymorphic.common.BlockChainService; 4 | import com.mvc.polymorphic.common.BlockResult; 5 | import com.mvc.polymorphic.model.dto.NewAccountDTO; 6 | import com.mvc.polymorphic.model.dto.SendTransactionDTO; 7 | import com.mvc.polymorphic.utils.BlockServiceUtil; 8 | import com.mvc.tools.controller.BaseController; 9 | import com.mvc.tools.pojo.Result; 10 | import io.swagger.annotations.ApiOperation; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.web.bind.annotation.*; 13 | 14 | import javax.validation.Valid; 15 | 16 | /** 17 | * block controller 18 | * 19 | * @author qiyichen 20 | * @create 2018/4/9 17:13 21 | */ 22 | @RestController 23 | @RequestMapping("/token") 24 | public class BlockController extends BaseController { 25 | 26 | @Autowired 27 | private BlockChainService blockChainService; 28 | 29 | @ApiOperation(value = "New Account", notes = "Currently, the address is useless for BTC and BCH.") 30 | @GetMapping("/{type}/{address}") 31 | public Result getBalance(@PathVariable String type, @PathVariable String address) throws Exception { 32 | String serviceName = BlockServiceUtil.getServiceName(type); 33 | BlockResult result = blockChainService.getBalance(serviceName, address); 34 | return success(result); 35 | } 36 | 37 | @GetMapping("/{type}/hash/{hash}") 38 | public Result getTransactionByHash(@PathVariable String type, @PathVariable String hash) throws Exception { 39 | String serviceName = BlockServiceUtil.getServiceName(type); 40 | BlockResult result = blockChainService.getTransactionByHash(serviceName, hash); 41 | return success(result); 42 | } 43 | 44 | @GetMapping("/{type}/confirmation/{hash}") 45 | public Result getConfirmation(@PathVariable String type, @PathVariable String hash) throws Exception { 46 | String serviceName = BlockServiceUtil.getServiceName(type); 47 | BlockResult result = blockChainService.getConfirmation(serviceName, hash); 48 | return success(result); 49 | } 50 | 51 | @ApiOperation(value = "New Account", notes = "Currently, the password is useless for BTC and BCH.") 52 | @PostMapping("/{type}/account") 53 | public Result newAccount(@PathVariable String type, @Valid @RequestBody NewAccountDTO newAccountDTO) { 54 | String serviceName = BlockServiceUtil.getServiceName(type); 55 | BlockResult result = blockChainService.newAccount(serviceName, newAccountDTO.getPassphrase()); 56 | return success(result); 57 | } 58 | 59 | @PostMapping("/{type}/transaction") 60 | public Result sendTransaction(@PathVariable String type, @Valid @RequestBody SendTransactionDTO sendTransactionDTO) throws Exception { 61 | String serviceName = BlockServiceUtil.getServiceName(type); 62 | BlockResult result = blockChainService.sendTransaction(serviceName, sendTransactionDTO.getPass(), sendTransactionDTO.getFrom(), sendTransactionDTO.getTo(), sendTransactionDTO.getValue()); 63 | return success(result); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/controller/Controller.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.controller; 2 | 3 | import com.mvc.polymorphic.model.dto.BalanceDTO; 4 | import com.mvc.polymorphic.model.dto.TransactionCountDTO; 5 | import com.mvc.polymorphic.service.ContractService; 6 | import com.mvc.polymorphic.service.RpcService; 7 | import io.swagger.annotations.Api; 8 | import io.swagger.annotations.ApiOperation; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | /** 13 | * Controller for our ERC-20 contract API. 14 | */ 15 | @Api("ERC-20 token standard API") 16 | @RestController 17 | public class Controller { 18 | @Autowired 19 | private ContractService ContractService; 20 | 21 | @Autowired 22 | private RpcService rpcService; 23 | 24 | @ApiOperation("Get token balance for address") 25 | @RequestMapping( 26 | value = "/{contractAddress}/eth_getBalance", method = RequestMethod.POST) 27 | public Object balanceOf( 28 | @PathVariable String contractAddress, 29 | @RequestBody final BalanceDTO balanceDTO) { 30 | return ContractService.balanceOf(contractAddress, balanceDTO.getAddress()); 31 | } 32 | 33 | // @RequestMapping(value = "/{contractAddress}/eth_sendTransaction", method = RequestMethod.POST) 34 | // public Object approveAndCall(@PathVariable String contractAddress, @RequestBody SendTransactionDTO sendTransactionDTO) throws Exception { 35 | // Transaction transaction = new Transaction(sendTransactionDTO.getFrom(), sendTransactionDTO.getNonce(), sendTransactionDTO.getGasPrice(), sendTransactionDTO.getGas(), sendTransactionDTO.getTo(), 36 | // sendTransactionDTO.getValue().toBigInteger(), 37 | // sendTransactionDTO.getData()); 38 | // return rpcService.eth_sendTransaction(transaction, sendTransactionDTO.getPass(), contractAddress); 39 | // } 40 | 41 | @RequestMapping(value = "/{contractAddress}/txList", method = RequestMethod.POST) 42 | private Object txList(@PathVariable String contractAddress, @RequestBody TransactionCountDTO transactionCountDTO) { 43 | return rpcService.txList(transactionCountDTO.getAddress()); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/controller/DemoController.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.controller; 2 | 3 | import com.mvc.polymorphic.configuration.TokenConfig; 4 | import io.swagger.annotations.Api; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | 10 | @Api("Some Demos") 11 | @RestController 12 | @RequestMapping("/demo") 13 | public class DemoController { 14 | 15 | @Autowired 16 | private TokenConfig tokenConfig; 17 | 18 | @GetMapping("/config") 19 | public Object config() { 20 | return tokenConfig.getUrl(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/controller/EthereumController.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.controller; 2 | 3 | import com.mvc.polymorphic.model.dto.*; 4 | import com.mvc.polymorphic.service.RpcService; 5 | import com.mvc.polymorphic.utils.FileUtil; 6 | import com.mvc.polymorphic.utils.RSACoder; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.web.bind.annotation.*; 9 | import org.springframework.web.multipart.MultipartFile; 10 | 11 | import javax.servlet.http.HttpServletRequest; 12 | 13 | /** 14 | * all demo in this controller 15 | */ 16 | @RestController 17 | @RequestMapping("ethereum") 18 | public class EthereumController { 19 | 20 | @Autowired 21 | private RpcService rpcService; 22 | 23 | /** 24 | * getBalance 25 | * 26 | * @param balanceDTO 27 | * @return 28 | */ 29 | @RequestMapping(value = "eth_getBalance", method = RequestMethod.POST) 30 | public Object eth_getBalance(HttpServletRequest request, @RequestBody final BalanceDTO balanceDTO) throws Exception { 31 | return rpcService.eth_getBalance(balanceDTO.getAddress(), balanceDTO.getBlockId()); 32 | } 33 | 34 | /** 35 | * getTransactionByHash 36 | * 37 | * @return 38 | */ 39 | @RequestMapping(value = "eth_getTransactionByHash", method = RequestMethod.POST) 40 | public Object eth_getTransactionByHash(@RequestBody TransactionByHashDTO transactionByHashDTO) throws Exception { 41 | return rpcService.eth_getTransactionByHash(transactionByHashDTO.getTransactionHash()); 42 | } 43 | 44 | /** 45 | * sendRawTransaction 46 | * 47 | * @param rawTransactionDTO 48 | * @return 49 | * @throws Exception 50 | */ 51 | @RequestMapping(value = "eth_sendRawTransaction", method = RequestMethod.POST) 52 | public Object ethSendRawTransaction(@RequestBody RawTransactionDTO rawTransactionDTO) throws Exception { 53 | return rpcService.ethSendRawTransaction(rawTransactionDTO.getSignedMessage()); 54 | } 55 | 56 | /** 57 | * sendTransaction 58 | * 59 | * @param sendTransactionDTO 60 | * @return 61 | * @throws Exception 62 | */ 63 | // @RequestMapping(value = "eth_sendTransaction", method = RequestMethod.POST) 64 | // public Object eth_sendTransaction(@RequestBody SendTransactionDTO sendTransactionDTO) throws Exception { 65 | // Transaction transaction = new Transaction(sendTransactionDTO.getFrom(), sendTransactionDTO.getNonce(), sendTransactionDTO.getGasPrice(), sendTransactionDTO.getGas(), sendTransactionDTO.getTo(), 66 | // Convert.toWei(sendTransactionDTO.getValue(), Convert.Unit.ETHER).toBigInteger(), 67 | // sendTransactionDTO.getData()); 68 | // return rpcService.eth_sendTransaction(transaction, sendTransactionDTO.getPass()); 69 | // } 70 | 71 | /** 72 | * search user list 73 | * 74 | * @return 75 | * @throws Exception 76 | */ 77 | @RequestMapping(value = "personal_listAccounts", method = RequestMethod.POST) 78 | public Object personal_listAccounts() throws Exception { 79 | return rpcService.personal_listAccounts(); 80 | } 81 | 82 | /** 83 | * create new Account 84 | * 85 | * @return 86 | * @throws Exception 87 | */ 88 | @RequestMapping(value = "personal_newAccount", method = RequestMethod.POST) 89 | public Object personal_newAccount(@RequestBody NewAccountDTO newAccountDTO) throws Exception { 90 | return rpcService.personal_newAccount(newAccountDTO.getPassphrase()); 91 | } 92 | 93 | /** 94 | * import key 95 | * 96 | * @return 97 | * @throws Exception 98 | */ 99 | @RequestMapping(value = "personal_importRawKey", method = RequestMethod.POST) 100 | public Object personal_importRawKey(@RequestBody ImportRawKeyDTO importRawKeyDTO) throws Exception { 101 | return rpcService.personal_importRawKey(importRawKeyDTO.getKeydata(), importRawKeyDTO.getPassphrase()); 102 | } 103 | 104 | /** 105 | * get publickey for RSA 106 | * 107 | * @return 108 | * @throws Exception 109 | */ 110 | @RequestMapping(value = "publicKey", method = RequestMethod.POST) 111 | public Object publicKey() throws Exception { 112 | return RSACoder.getPublicKey(); 113 | } 114 | 115 | /** 116 | * get TransactionCount for nonce 117 | * 118 | * @return 119 | * @throws Exception 120 | */ 121 | @RequestMapping(value = "transactionCount", method = RequestMethod.POST) 122 | public Object getTransactionCount(@RequestBody TransactionCountDTO transactionCountDTO) throws Exception { 123 | return rpcService.getTransactionCount(transactionCountDTO.getAddress()); 124 | } 125 | 126 | /** 127 | * personal by keyDate 128 | * @param file 129 | * @param passhphrase 130 | * @return 131 | * @throws Exception 132 | */ 133 | @RequestMapping(value = "personalByKeyDate", method = RequestMethod.POST) 134 | public Object eth_personalByKeyDate(@RequestParam("file") MultipartFile file, @RequestParam String passhphrase) throws Exception { 135 | String source = FileUtil.readFile(file.getInputStream()); 136 | return rpcService.eth_personalByKeyDate(source, passhphrase); 137 | } 138 | 139 | /** 140 | * personal by privateKey 141 | * @param personalByPrivateKeyDTO 142 | * @return 143 | * @throws Exception 144 | */ 145 | @RequestMapping(value = "personalByPrivateKey", method = RequestMethod.POST) 146 | public Object eth_personalByPrivateKey(@RequestBody PersonalByPrivateKeyDTO personalByPrivateKeyDTO) throws Exception { 147 | return rpcService.eth_personalByPrivateKey(personalByPrivateKeyDTO.getPrivateKey()); 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/exceptions/ExceededGasException.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.exceptions; 2 | 3 | public class ExceededGasException extends Throwable { 4 | public ExceededGasException(String message) { 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/Account.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import lombok.*; 5 | 6 | @Builder(builderClassName="Builder", toBuilder=true) 7 | @Setter 8 | @Getter 9 | @NoArgsConstructor 10 | @AllArgsConstructor 11 | @JsonIgnoreProperties(ignoreUnknown = true) 12 | @ToString 13 | public class Account { 14 | private String passphrase; 15 | private String address; 16 | private long balance; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/ApprovalEventResponse.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class ApprovalEventResponse { 7 | private String owner; 8 | private String spender; 9 | private long value; 10 | 11 | public ApprovalEventResponse() { } 12 | 13 | public ApprovalEventResponse( 14 | HumanStandardToken.ApprovalEventResponse approvalEventResponse) { 15 | this.owner = approvalEventResponse._owner.toString(); 16 | this.spender = approvalEventResponse._spender.toString(); 17 | this.value = approvalEventResponse._value.getValue().longValueExact(); 18 | } 19 | } -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/Block.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import lombok.*; 5 | 6 | @Builder(builderClassName="Builder", toBuilder=true) 7 | @Setter 8 | @Getter 9 | @NoArgsConstructor 10 | @AllArgsConstructor 11 | @JsonIgnoreProperties(ignoreUnknown = true)public class Block { 12 | private String nonce; 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/EthTransaction.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import lombok.*; 5 | 6 | 7 | @Builder(builderClassName="Builder", toBuilder=true) 8 | @Getter 9 | @Setter 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | @JsonIgnoreProperties(ignoreUnknown = true) 13 | public class EthTransaction { 14 | private String data; 15 | private String from; 16 | private String to; 17 | private long gas; 18 | private long gasPrice; 19 | private long value; 20 | // private long nonce; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/Filter.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import lombok.*; 5 | 6 | @Builder(builderClassName="Builder", toBuilder=true) 7 | @Getter 8 | @Setter 9 | @NoArgsConstructor 10 | @AllArgsConstructor 11 | @JsonIgnoreProperties(ignoreUnknown = true) 12 | public class Filter { 13 | private String fromBlock = "0x0"; 14 | private String toBlock = "lastest"; 15 | private String address; 16 | private String topics; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/HumanStandardToken.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model; 2 | 3 | import org.web3j.abi.EventEncoder; 4 | import org.web3j.abi.EventValues; 5 | import org.web3j.abi.FunctionEncoder; 6 | import org.web3j.abi.TypeReference; 7 | import org.web3j.abi.datatypes.*; 8 | import org.web3j.abi.datatypes.generated.Uint256; 9 | import org.web3j.abi.datatypes.generated.Uint8; 10 | import org.web3j.crypto.Credentials; 11 | import org.web3j.protocol.Web3j; 12 | import org.web3j.protocol.core.DefaultBlockParameter; 13 | import org.web3j.protocol.core.methods.request.EthFilter; 14 | import org.web3j.protocol.core.methods.response.Log; 15 | import org.web3j.protocol.core.methods.response.TransactionReceipt; 16 | import org.web3j.protocol.exceptions.TransactionException; 17 | import org.web3j.tx.Contract; 18 | import org.web3j.tx.TransactionManager; 19 | import rx.Observable; 20 | import rx.functions.Func1; 21 | 22 | import java.io.IOException; 23 | import java.math.BigInteger; 24 | import java.util.ArrayList; 25 | import java.util.Arrays; 26 | import java.util.Collections; 27 | import java.util.List; 28 | import java.util.concurrent.Future; 29 | 30 | /** 31 | * Auto generated code.
32 | * Do not modify!
33 | * 34 | *

Generated with web3j version 2.2.1. 35 | */ 36 | public final class HumanStandardToken extends Contract { 37 | private static final String BINARY = "60a0604052600460608190527f48302e3100000000000000000000000000000000000000000000000000000000608090815261003e91600691906100d7565b50341561004757fe5b604051610b8f380380610b8f833981016040908152815160208301519183015160608401519193928301929091015b600160a060020a033316600090815260016020908152604082208690559085905583516100a991600391908601906100d7565b506004805460ff191660ff841617905580516100cc9060059060208401906100d7565b505b50505050610177565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061011857805160ff1916838001178555610145565b82800160010185558215610145579182015b8281111561014557825182559160200191906001019061012a565b5b50610152929150610156565b5090565b61017491905b80821115610152576000815560010161015c565b5090565b90565b610a09806101866000396000f300606060405236156100935763ffffffff60e060020a60003504166306fdde0381146100a9578063095ea7b31461013957806318160ddd1461016c57806323b872dd1461018e578063313ce567146101c757806354fd4d50146101ed57806370a082311461027d57806395d89b41146102ab578063a9059cbb1461033b578063cae9ca511461036e578063dd62ed3e146103e5575b341561009b57fe5b6100a75b60006000fd5b565b005b34156100b157fe5b6100b9610419565b6040805160208082528351818301528351919283929083019185019080838382156100ff575b8051825260208311156100ff57601f1990920191602091820191016100df565b505050905090810190601f16801561012b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561014157fe5b610158600160a060020a03600435166024356104a7565b604080519115158252519081900360200190f35b341561017457fe5b61017c610512565b60408051918252519081900360200190f35b341561019657fe5b610158600160a060020a0360043581169060243516604435610518565b604080519115158252519081900360200190f35b34156101cf57fe5b6101d761060e565b6040805160ff9092168252519081900360200190f35b34156101f557fe5b6100b9610617565b6040805160208082528351818301528351919283929083019185019080838382156100ff575b8051825260208311156100ff57601f1990920191602091820191016100df565b505050905090810190601f16801561012b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561028557fe5b61017c600160a060020a03600435166106a5565b60408051918252519081900360200190f35b34156102b357fe5b6100b96106c4565b6040805160208082528351818301528351919283929083019185019080838382156100ff575b8051825260208311156100ff57601f1990920191602091820191016100df565b505050905090810190601f16801561012b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561034357fe5b610158600160a060020a0360043516602435610752565b604080519115158252519081900360200190f35b341561037657fe5b604080516020600460443581810135601f8101849004840285018401909552848452610158948235600160a060020a03169460248035956064949293919092019181908401838280828437509496506107fe95505050505050565b604080519115158252519081900360200190f35b34156103ed57fe5b61017c600160a060020a03600435811690602435166109b0565b60408051918252519081900360200190f35b6003805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152929183018282801561049f5780601f106104745761010080835404028352916020019161049f565b820191906000526020600020905b81548152906001019060200180831161048257829003601f168201915b505050505081565b600160a060020a03338116600081815260026020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b60005481565b600160a060020a0383166000908152600160205260408120548290108015906105685750600160a060020a0380851660009081526002602090815260408083203390941683529290522054829010155b80156105745750600082115b1561060257600160a060020a03808416600081815260016020908152604080832080548801905588851680845281842080548990039055600283528184203390961684529482529182902080548790039055815186815291519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a3506001610606565b5060005b5b9392505050565b60045460ff1681565b6006805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152929183018282801561049f5780601f106104745761010080835404028352916020019161049f565b820191906000526020600020905b81548152906001019060200180831161048257829003601f168201915b505050505081565b600160a060020a0381166000908152600160205260409020545b919050565b6005805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152929183018282801561049f5780601f106104745761010080835404028352916020019161049f565b820191906000526020600020905b81548152906001019060200180831161048257829003601f168201915b505050505081565b600160a060020a03331660009081526001602052604081205482901080159061077b5750600082115b156107ef57600160a060020a03338116600081815260016020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a350600161050c565b50600061050c565b5b92915050565b600160a060020a03338116600081815260026020908152604080832094881680845294825280832087905580518781529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a383600160a060020a031660405180807f72656365697665417070726f76616c28616464726573732c75696e743235362c81526020017f616464726573732c627974657329000000000000000000000000000000000000815250602e019050604051809103902060e060020a9004338530866040518563ffffffff1660e060020a0281526004018085600160a060020a0316600160a060020a0316815260200184815260200183600160a060020a0316600160a060020a03168152602001828051906020019080838360008314610950575b80518252602083111561095057601f199092019160209182019101610930565b505050905090810190601f16801561097c5780820380516001836020036101000a031916815260200191505b509450505050506000604051808303816000876161da5a03f19250505015156109a55760006000fd5b5060015b9392505050565b600160a060020a038083166000908152600260209081526040808320938516835292905220545b929150505600a165627a7a7230582095fa82c5fd259e30fb0a7f8bfebb52ec799ca55b26bdbbea3153c6cebdb2fd080029"; 38 | 39 | private HumanStandardToken(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { 40 | super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit); 41 | } 42 | 43 | private HumanStandardToken(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { 44 | super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit); 45 | } 46 | 47 | public List getTransferEvents(TransactionReceipt transactionReceipt) { 48 | final Event event = new Event("Transfer", 49 | Arrays.>asList(new TypeReference

() {}, new TypeReference
() {}), 50 | Arrays.>asList(new TypeReference() {})); 51 | List valueList = extractEventParameters(event, transactionReceipt); 52 | ArrayList responses = new ArrayList(valueList.size()); 53 | for (EventValues eventValues : valueList) { 54 | TransferEventResponse typedResponse = new TransferEventResponse(); 55 | typedResponse._from = (Address) eventValues.getIndexedValues().get(0); 56 | typedResponse._to = (Address) eventValues.getIndexedValues().get(1); 57 | typedResponse._value = (Uint256) eventValues.getNonIndexedValues().get(0); 58 | responses.add(typedResponse); 59 | } 60 | return responses; 61 | } 62 | 63 | public Observable transferEventObservable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { 64 | final Event event = new Event("Transfer", 65 | Arrays.>asList(new TypeReference
() {}, new TypeReference
() {}), 66 | Arrays.>asList(new TypeReference() {})); 67 | EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); 68 | filter.addSingleTopic(EventEncoder.encode(event)); 69 | return web3j.ethLogObservable(filter).map(new Func1() { 70 | @Override 71 | public TransferEventResponse call(Log log) { 72 | EventValues eventValues = extractEventParameters(event, log); 73 | TransferEventResponse typedResponse = new TransferEventResponse(); 74 | typedResponse._from = (Address) eventValues.getIndexedValues().get(0); 75 | typedResponse._to = (Address) eventValues.getIndexedValues().get(1); 76 | typedResponse._value = (Uint256) eventValues.getNonIndexedValues().get(0); 77 | return typedResponse; 78 | } 79 | }); 80 | } 81 | 82 | public List getApprovalEvents(TransactionReceipt transactionReceipt) { 83 | final Event event = new Event("Approval", 84 | Arrays.>asList(new TypeReference
() {}, new TypeReference
() {}), 85 | Arrays.>asList(new TypeReference() {})); 86 | List valueList = extractEventParameters(event, transactionReceipt); 87 | ArrayList responses = new ArrayList(valueList.size()); 88 | for (EventValues eventValues : valueList) { 89 | ApprovalEventResponse typedResponse = new ApprovalEventResponse(); 90 | typedResponse._owner = (Address) eventValues.getIndexedValues().get(0); 91 | typedResponse._spender = (Address) eventValues.getIndexedValues().get(1); 92 | typedResponse._value = (Uint256) eventValues.getNonIndexedValues().get(0); 93 | responses.add(typedResponse); 94 | } 95 | return responses; 96 | } 97 | 98 | public Observable approvalEventObservable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) { 99 | final Event event = new Event("Approval", 100 | Arrays.>asList(new TypeReference
() {}, new TypeReference
() {}), 101 | Arrays.>asList(new TypeReference() {})); 102 | EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress()); 103 | filter.addSingleTopic(EventEncoder.encode(event)); 104 | return web3j.ethLogObservable(filter).map(new Func1() { 105 | @Override 106 | public ApprovalEventResponse call(Log log) { 107 | EventValues eventValues = extractEventParameters(event, log); 108 | ApprovalEventResponse typedResponse = new ApprovalEventResponse(); 109 | typedResponse._owner = (Address) eventValues.getIndexedValues().get(0); 110 | typedResponse._spender = (Address) eventValues.getIndexedValues().get(1); 111 | typedResponse._value = (Uint256) eventValues.getNonIndexedValues().get(0); 112 | return typedResponse; 113 | } 114 | }); 115 | } 116 | 117 | public Future name() throws IOException { 118 | Function function = new Function("name", 119 | Arrays.asList(), 120 | Arrays.>asList(new TypeReference() {})); 121 | return executeCallSingleValueReturn(function); 122 | } 123 | 124 | public TransactionReceipt approve(Address _spender, Uint256 _value) throws IOException, TransactionException { 125 | Function function = new Function("approve", Arrays.asList(_spender, _value), Collections.>emptyList()); 126 | return executeTransaction(function); 127 | } 128 | 129 | public Future totalSupply() throws IOException { 130 | Function function = new Function("totalSupply", 131 | Arrays.asList(), 132 | Arrays.>asList(new TypeReference() {})); 133 | return executeCallSingleValueReturn(function); 134 | } 135 | 136 | public TransactionReceipt transferFrom(Address _from, Address _to, Uint256 _value) throws IOException, TransactionException { 137 | Function function = new Function("transferFrom", Arrays.asList(_from, _to, _value), Collections.>emptyList()); 138 | return executeTransaction(function); 139 | } 140 | 141 | public Future decimals() throws IOException { 142 | Function function = new Function("decimals", 143 | Arrays.asList(), 144 | Arrays.>asList(new TypeReference() {})); 145 | return executeCallSingleValueReturn(function); 146 | } 147 | 148 | public Future version() throws IOException { 149 | Function function = new Function("version", 150 | Arrays.asList(), 151 | Arrays.>asList(new TypeReference() {})); 152 | return executeCallSingleValueReturn(function); 153 | } 154 | 155 | public Uint256 balanceOf(Address _owner) throws IOException { 156 | Function function = new Function("balanceOf", 157 | Arrays.asList(_owner), 158 | Arrays.>asList(new TypeReference() {})); 159 | return executeCallSingleValueReturn(function); 160 | } 161 | 162 | public Future symbol() throws IOException { 163 | Function function = new Function("symbol", 164 | Arrays.asList(), 165 | Arrays.>asList(new TypeReference() {})); 166 | return executeCallSingleValueReturn(function); 167 | } 168 | 169 | public TransactionReceipt transfer(Address _to, Uint256 _value) throws IOException, TransactionException { 170 | Function function = new Function("transfer", Arrays.asList(_to, _value), Collections.>emptyList()); 171 | return executeTransaction(function); 172 | } 173 | 174 | public TransactionReceipt approveAndCall(Address _spender, Uint256 _value, DynamicBytes _extraData) throws IOException, TransactionException { 175 | Function function = new Function("approveAndCall", Arrays.asList(_spender, _value, _extraData), Collections.>emptyList()); 176 | return executeTransaction(function); 177 | } 178 | 179 | public Future allowance(Address _owner, Address _spender) throws IOException { 180 | Function function = new Function("allowance", 181 | Arrays.asList(_owner, _spender), 182 | Arrays.>asList(new TypeReference() {})); 183 | return executeCallSingleValueReturn(function); 184 | } 185 | 186 | public static HumanStandardToken deploy(Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit, BigInteger initialWeiValue, Uint256 _initialAmount, Utf8String _tokenName, Uint8 _decimalUnits, Utf8String _tokenSymbol) throws IOException, TransactionException { 187 | String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol)); 188 | return deploy(HumanStandardToken.class, web3j, credentials, gasPrice, gasLimit, BINARY, encodedConstructor, initialWeiValue); 189 | } 190 | 191 | public static HumanStandardToken deploy(Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit, BigInteger initialWeiValue, Uint256 _initialAmount, Utf8String _tokenName, Uint8 _decimalUnits, Utf8String _tokenSymbol) throws IOException, TransactionException { 192 | String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(_initialAmount, _tokenName, _decimalUnits, _tokenSymbol)); 193 | return deploy(HumanStandardToken.class, web3j, transactionManager, gasPrice, gasLimit, BINARY, encodedConstructor, initialWeiValue); 194 | } 195 | 196 | public static HumanStandardToken load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { 197 | return new HumanStandardToken(contractAddress, web3j, credentials, gasPrice, gasLimit); 198 | } 199 | 200 | public static HumanStandardToken load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) { 201 | return new HumanStandardToken(contractAddress, web3j, transactionManager, gasPrice, gasLimit); 202 | } 203 | 204 | public static class TransferEventResponse { 205 | public Address _from; 206 | 207 | public Address _to; 208 | 209 | public Uint256 _value; 210 | } 211 | 212 | public static class ApprovalEventResponse { 213 | public Address _owner; 214 | 215 | public Address _spender; 216 | 217 | public Uint256 _value; 218 | } 219 | 220 | } 221 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/JsonCredentials.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model; 2 | 3 | import lombok.Data; 4 | import org.web3j.crypto.Credentials; 5 | 6 | @Data 7 | public class JsonCredentials { 8 | 9 | private String publicKey; 10 | private String privateKey; 11 | private String address; 12 | 13 | 14 | public JsonCredentials(Credentials credentials) { 15 | this.address = credentials.getAddress(); 16 | this.privateKey = credentials.getEcKeyPair().getPrivateKey().toString(16); 17 | this.publicKey = credentials.getEcKeyPair().getPublicKey().toString(16); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/Method.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import lombok.*; 5 | 6 | import javax.validation.constraints.NotNull; 7 | 8 | @Builder(builderClassName="Builder", toBuilder=true) 9 | @Getter 10 | @Setter 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | @JsonIgnoreProperties(ignoreUnknown = true) 14 | public class Method { 15 | @NotNull 16 | private Object[] args; 17 | private String name; 18 | public Object[] getArgs() { 19 | if (args != null) { 20 | return args; 21 | } 22 | return new Object[0]; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/NodeConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | import org.springframework.stereotype.Component; 6 | 7 | /** 8 | * Node configuration bean. 9 | */ 10 | @Data 11 | @ConfigurationProperties 12 | @Component 13 | public class NodeConfiguration { 14 | 15 | private String nodeEndpoint; 16 | private String fromAddress; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/Receipt.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import com.mvc.polymorphic.utils.EthereumUtil; 5 | import lombok.*; 6 | import org.apache.commons.lang3.StringUtils; 7 | 8 | import java.io.Serializable; 9 | 10 | @Builder(builderClassName="Builder", toBuilder=true) 11 | @Setter 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | @JsonIgnoreProperties(ignoreUnknown = true) 15 | @ToString(of= {"contractAddress", "accountAddr"}, includeFieldNames = false) 16 | public class Receipt implements Serializable { 17 | @Getter 18 | private String transactionHash; 19 | @Getter 20 | private String contractAddress; 21 | @Getter 22 | private String blockHash; 23 | private String transactionIndex; 24 | private String blockNumber; 25 | private String cumulativeGasUsed; 26 | private String gasUsed; 27 | private Type type; 28 | @Getter 29 | @Setter 30 | private String accountAddr; 31 | 32 | public enum Type {CREATE, MODIFY}; 33 | 34 | public long getTransactionIndex() { 35 | return decrypt(transactionIndex); 36 | } 37 | 38 | public long getBlockNumber() { 39 | return decrypt(blockNumber); 40 | } 41 | 42 | public long getCumulativeGasUsed() { 43 | return decrypt(cumulativeGasUsed); 44 | } 45 | 46 | public long getGasUsed() { 47 | return decrypt(gasUsed); 48 | } 49 | 50 | private static long decrypt(final String data) { 51 | if (StringUtils.isNotBlank(data)) { 52 | return EthereumUtil.decryptQuantity(data); 53 | } 54 | return 0; 55 | 56 | } 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/TransactionResponse.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | /** 7 | * TransactionResponse wrapper. 8 | */ 9 | @Getter 10 | @Setter 11 | public class TransactionResponse { 12 | 13 | private String transactionHash; 14 | private T event; 15 | 16 | TransactionResponse() { } 17 | 18 | public TransactionResponse(String transactionHash) { 19 | this(transactionHash, null); 20 | } 21 | 22 | public TransactionResponse(String transactionHash, T event) { 23 | this.transactionHash = transactionHash; 24 | this.event = event; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/TransferEventResponse.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class TransferEventResponse { 7 | private String from; 8 | private String to; 9 | private long value; 10 | 11 | public TransferEventResponse() { 12 | } 13 | 14 | public TransferEventResponse( 15 | HumanStandardToken.TransferEventResponse transferEventResponse) { 16 | this.from = transferEventResponse._from.toString(); 17 | this.to = transferEventResponse._to.toString(); 18 | this.value = transferEventResponse._value.getValue().longValueExact(); 19 | } 20 | } -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/dto/BalanceDTO.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model.dto; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | @Data 8 | public class BalanceDTO implements Serializable { 9 | private String address; 10 | private String blockId; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/dto/ExportAccountDTO.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model.dto; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class ExportAccountDTO { 7 | private String address; 8 | private String passphrase; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/dto/ImportRawKeyDTO.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model.dto; 2 | 3 | 4 | import lombok.Data; 5 | 6 | @Data 7 | public class ImportRawKeyDTO { 8 | 9 | private String keydata; 10 | private String passphrase; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/dto/NewAccountDTO.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model.dto; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class NewAccountDTO { 7 | 8 | private String passphrase; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/dto/PersonalByPrivateKeyDTO.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model.dto; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class PersonalByPrivateKeyDTO { 7 | 8 | private String privateKey; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/dto/RawTransactionDTO.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model.dto; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class RawTransactionDTO { 7 | 8 | private String signedMessage; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/dto/SendTransactionDTO.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model.dto; 2 | 3 | import lombok.Data; 4 | 5 | import javax.validation.constraints.NotNull; 6 | import java.io.Serializable; 7 | import java.math.BigDecimal; 8 | 9 | /** 10 | * @author ethands 11 | */ 12 | @Data 13 | public class SendTransactionDTO implements Serializable { 14 | private static final long serialVersionUID = 6477321453043666156L; 15 | @NotNull 16 | private String pass; 17 | @NotNull 18 | private String from; 19 | @NotNull 20 | private String to; 21 | @NotNull 22 | private BigDecimal value; 23 | 24 | } -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/dto/TransactionByHashDTO.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model.dto; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class TransactionByHashDTO { 7 | private String transactionHash; 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/model/dto/TransactionCountDTO.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.model.dto; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class TransactionCountDTO { 7 | 8 | private String address; 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/mvc/polymorphic/service/BchService.java: -------------------------------------------------------------------------------- 1 | package com.mvc.polymorphic.service; 2 | 3 | import com.mvc.bitcoincashj.core.*; 4 | import com.mvc.bitcoincashj.core.listeners.TransactionConfidenceEventListener; 5 | import com.mvc.bitcoincashj.kits.WalletAppKit; 6 | import com.mvc.bitcoincashj.params.MainNetParams; 7 | import com.mvc.bitcoincashj.params.TestNet3Params; 8 | import com.mvc.bitcoincashj.script.Script; 9 | import com.mvc.bitcoincashj.wallet.Wallet; 10 | import com.mvc.bitcoincashj.wallet.listeners.KeyChainEventListener; 11 | import com.mvc.bitcoincashj.wallet.listeners.ScriptsChangeEventListener; 12 | import com.mvc.bitcoincashj.wallet.listeners.WalletCoinsReceivedEventListener; 13 | import com.mvc.bitcoincashj.wallet.listeners.WalletCoinsSentEventListener; 14 | import com.mvc.polymorphic.common.BlockChainService; 15 | import com.mvc.polymorphic.common.BlockResult; 16 | import com.mvc.polymorphic.common.bean.BchTransaction; 17 | import lombok.extern.java.Log; 18 | import org.springframework.stereotype.Service; 19 | import org.springframework.util.StringUtils; 20 | 21 | import java.io.File; 22 | import java.math.BigDecimal; 23 | import java.util.Arrays; 24 | import java.util.HashMap; 25 | import java.util.List; 26 | import java.util.Map; 27 | 28 | /** 29 | * bcc service 30 | * 31 | * @author qiyichen 32 | * @create 2018/4/12 13:43 33 | */ 34 | @Service("BchService") 35 | @Log 36 | public class BchService extends BlockChainService { 37 | 38 | private WalletAppKit kit; 39 | private final static String DEFAULT_FILE_PREFIX = "DEFAULT_FILE_PREFIX"; 40 | private final static String TEST_KEY = "local"; 41 | private final static String TOKEN_NAME = "bch"; 42 | private static Boolean initFinished = false; 43 | 44 | @Override 45 | protected BlockResult getBalance(String address) { 46 | Object result = kit.wallet().getBalance().toFriendlyString(); 47 | return tokenSuccess(TOKEN_NAME, result); 48 | } 49 | 50 | @Override 51 | protected BlockResult getTransactionByHash(String transactionHash) { 52 | Transaction trans = kit.wallet().getTransaction(Sha256Hash.wrap(transactionHash)); 53 | BchTransaction transaction = BchTransaction.build(trans, kit.wallet()); 54 | return tokenSuccess(TOKEN_NAME, transaction); 55 | } 56 | 57 | @Override 58 | protected BlockResult sendTransaction(String pass, String from, String toAddress, BigDecimal data) { 59 | String blockEnv = tokenConfig.getEnv().get(TOKEN_NAME); 60 | if (!initFinished) { 61 | return tokenFail(TOKEN_NAME, String.format("wallet is async, please wait, now height is %s", kit.wallet().getLastBlockSeenHeight())); 62 | } 63 | log.info("send money to: " + toAddress); 64 | Coin value = Coin.parseCoin(String.valueOf(data)); 65 | // if the wallet have more than 1 ecKey, we need to choose one for pay 66 | Address to = Address.fromBase58(kit.params(), toAddress); 67 | Wallet.SendResult result = null; 68 | try { 69 | if (TEST_KEY.equalsIgnoreCase(blockEnv)) { 70 | kit.peerGroup().setMaxConnections(4); 71 | } 72 | result = kit.wallet().sendCoins(kit.peerGroup(), to, value, true); 73 | } catch (Exception e) { 74 | return tokenFail(TOKEN_NAME, e.getMessage()); 75 | } finally { 76 | if (!kit.wallet().isEncrypted()) { 77 | kit.wallet().encrypt(pass); 78 | } 79 | } 80 | log.info("coins sent. transaction hash: " + result.tx.getHashAsString()); 81 | return tokenSuccess(TOKEN_NAME, result.tx.getHashAsString()); 82 | } 83 | 84 | @Override 85 | protected BlockResult newAccount(String pass) { 86 | if (!initFinished) { 87 | return tokenFail(TOKEN_NAME, String.format("wallet is async, please wait, now height is %s", kit.wallet().getLastBlockSeenHeight())); 88 | } 89 | Address address = kit.wallet().freshReceiveAddress(); 90 | kit.wallet().addWatchedAddress(address); 91 | return tokenSuccess(TOKEN_NAME, address.toString()); 92 | } 93 | 94 | @Override 95 | protected BlockResult getConfirmation(String transactionHash) { 96 | BchTransaction transaction = (BchTransaction) getTransactionByHash(transactionHash).getResult(); 97 | return tokenSuccess(TOKEN_NAME, transaction.getDepth()); 98 | } 99 | 100 | @Override 101 | protected void onTransaction(Object... objects) { 102 | System.out.println("db save"); 103 | } 104 | 105 | @Override 106 | public void run(String... args) throws Exception { 107 | 108 | if (!StringUtils.isEmpty(tokenConfig.getEnv().get(TOKEN_NAME))) { 109 | String blockEnv = tokenConfig.getEnv().get(TOKEN_NAME); 110 | String blockPath = tokenConfig.getPath().get(TOKEN_NAME).get(blockEnv); 111 | WalletAppKit kit = new WalletAppKit(getNetWork(blockEnv), new File(blockPath + blockEnv), DEFAULT_FILE_PREFIX); 112 | this.kit = kit; 113 | System.out.println("BCH Service initialized and nothing happened."); 114 | startListen(); 115 | // init wallet 116 | if (kit.wallet().getImportedKeys().size() == 0) { 117 | String pass = tokenConfig.getPass().get(TOKEN_NAME).get(blockEnv); 118 | ECKey ecKey = new ECKey(); 119 | kit.wallet().encrypt(pass); 120 | kit.wallet().importKeysAndEncrypt(Arrays.asList(ecKey), pass); 121 | kit.wallet().addWatchedAddress(ecKey.toAddress(kit.params())); 122 | } 123 | initFinished = true; 124 | } else { 125 | log.info("BCH not supported!"); 126 | } 127 | } 128 | 129 | private void startListen() { 130 | log.info("Start peer group"); 131 | kit.startAsync(); 132 | kit.awaitRunning(); 133 | log.info("Downloading block chain"); 134 | log.info("start listen"); 135 | kit.wallet().addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() { 136 | @Override 137 | public void onCoinsReceived(Wallet wallet, Transaction transaction, Coin coin, Coin coin1) { 138 | System.out.println("coins received"); 139 | Map map = new HashMap<>(); 140 | onTransaction(map); 141 | } 142 | }); 143 | 144 | kit.wallet().addCoinsSentEventListener(new WalletCoinsSentEventListener() { 145 | @Override 146 | public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) { 147 | System.out.println("coins sent"); 148 | Map map = new HashMap<>(); 149 | onTransaction(map); 150 | } 151 | }); 152 | 153 | kit.wallet().addKeyChainEventListener(new KeyChainEventListener() { 154 | @Override 155 | public void onKeysAdded(List keys) { 156 | System.out.println("new key added"); 157 | Map map = new HashMap<>(); 158 | onTransaction(map); 159 | } 160 | }); 161 | 162 | kit.wallet().addScriptsChangeEventListener(new ScriptsChangeEventListener() { 163 | @Override 164 | public void onScriptsChanged(Wallet wallet, List