diff --git a/back-end-projects/Explorer/account.json b/back-end-projects/Explorer/account.json
new file mode 100644
index 00000000..79b1fa13
--- /dev/null
+++ b/back-end-projects/Explorer/account.json
@@ -0,0 +1 @@
+{"accounts":[],"createTime":"2020-03-26T10:46:52Z","defaultAccountAddress":"","defaultOntid":"did:ont:ARR7Rk4hpvnkAAWkyHGtrF2H3htHWrKFby","identities":[{"controls":[{"address":"ARR7Rk4hpvnkAAWkyHGtrF2H3htHWrKFby","algorithm":"ECDSA","enc-alg":"aes-256-gcm","hash":"sha256","id":"keys-1","key":"KDCGqt8JbwcN6wKQasQcUrDjjIUy152SfE1dIVvQjYGmuhzd74dnLnLhjgfJAkJY","parameters":{"curve":"P-256"},"publicKey":"034044d1ab03d42543e806c4242fe0ab42f0df530c7548f2078e00a79b087892bb","salt":"hf/9mY5kH9567GZQYnn4hw=="}],"isDefault":true,"label":"c7b82a36","lock":false,"ontid":"did:ont:ARR7Rk4hpvnkAAWkyHGtrF2H3htHWrKFby"},{"controls":[{"address":"Ae6XnePYWiBUALD2c2EdnuDAAWEsqf2JGr","algorithm":"ECDSA","enc-alg":"aes-256-gcm","hash":"sha256","id":"keys-1","key":"zgNPyJb3UtIA2jdHoS2I6RgnYPRc50cC89gIN9frbnZMtp+pMSm9iR3Oxd9/kIBQ","parameters":{"curve":"P-256"},"publicKey":"0376104dd7bba89580540f9e923a32ad9470af8759774c578936d96004fc492218","salt":"oNyhAmy2RLtv64wmnAlK6g=="}],"isDefault":false,"label":"06c59f9d","lock":false,"ontid":"did:ont:Ae6XnePYWiBUALD2c2EdnuDAAWEsqf2JGr"}],"name":"com.github.ontio","scrypt":{"dkLen":64,"n":16384,"p":8,"r":8},"version":"1.0"}
diff --git a/back-end-projects/Explorer/config/application.properties b/back-end-projects/Explorer/config/application.properties
index 848a1234..f25e459a 100644
--- a/back-end-projects/Explorer/config/application.properties
+++ b/back-end-projects/Explorer/config/application.properties
@@ -63,4 +63,20 @@ tomcat.maxThread=2000
reqlimit.expire.millisecond=1000
-swagger.enable=true
\ No newline at end of file
+swagger.enable=true
+
+coinmarketcap.api.key=
+
+
+##user login
+login.callbackUrl=
+login.qrcode.url=
+
+identity.ontid =
+identity.password =
+identity.salt =
+
+jwt.accessTokenExpireTime=120
+jwt.encryptJWTKey=
+
+oneUser.address.count.limit=5
\ No newline at end of file
diff --git a/back-end-projects/Explorer/pom.xml b/back-end-projects/Explorer/pom.xml
index a921634d..108212c7 100644
--- a/back-end-projects/Explorer/pom.xml
+++ b/back-end-projects/Explorer/pom.xml
@@ -24,6 +24,7 @@
1.8
2.9.2
2.3.0
+ 3.4.1
@@ -185,6 +186,12 @@
${retrofit2.version}
+
+ com.auth0
+ java-jwt
+ ${jwt.version}
+
+
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/SimpleCORSFilter.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/SimpleCORSFilter.java
index 7078e561..3a06d42f 100644
--- a/back-end-projects/Explorer/src/main/java/com/github/ontio/SimpleCORSFilter.java
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/SimpleCORSFilter.java
@@ -19,6 +19,7 @@
package com.github.ontio;
+import com.github.ontio.util.ConstantParam;
import org.springframework.stereotype.Component;
import javax.servlet.*;
@@ -29,26 +30,26 @@
@Component
public class SimpleCORSFilter implements Filter {
- public void doFilter(ServletRequest req, ServletResponse res,
+ public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
- HttpServletResponse response = (HttpServletResponse) res;
- HttpServletRequest request = (HttpServletRequest) req;
- String origin = request.getHeader("Origin");
- response.setHeader("Access-Control-Allow-Origin", "*");
- response.setHeader("Access-Control-Allow-Credentials", "true");
- response.setHeader("Access-Control-Allow-Methods",
- "POST, PUT, GET, OPTIONS, DELETE");
- response.setHeader("Access-Control-Max-Age", "3600");
- response.setHeader(
- "Access-Control-Allow-Headers",
- "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With");
- chain.doFilter(req, res);
- }
-
- public void init(FilterConfig filterConfig) {
- }
-
- public void destroy() {
- }
+ HttpServletResponse response = (HttpServletResponse) res;
+ HttpServletRequest request = (HttpServletRequest) req;
+ String origin = request.getHeader("Origin");
+ response.setHeader("Access-Control-Allow-Origin", "*");
+ response.setHeader("Access-Control-Allow-Credentials", "true");
+ response.setHeader("Access-Control-Allow-Methods",
+ "POST, PUT, GET, OPTIONS, DELETE");
+ response.setHeader("Access-Control-Max-Age", "3600");
+ response.setHeader(
+ "Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers"));
+ response.setHeader("Access-Control-Expose-Headers", ConstantParam.HTTPHEADER_TOKEN);
+ chain.doFilter(req, res);
+ }
+
+ public void init(FilterConfig filterConfig) {
+ }
+
+ public void destroy() {
+ }
}
\ No newline at end of file
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/config/ParamsConfig.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/config/ParamsConfig.java
index 849c7ca7..827d0931 100644
--- a/back-end-projects/Explorer/src/main/java/com/github/ontio/config/ParamsConfig.java
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/config/ParamsConfig.java
@@ -141,4 +141,23 @@ public String getContractHash(String token) {
}
}
+ @Value("${login.callbackUrl:https://explorer.ont.io/v2/users/login}")
+ public String loginCallbackUrl;
+
+ @Value("${identity.ontid}")
+ public String IDENTITY_ONTID;
+
+ @Value("${identity.password}")
+ public String IDENTITY_PASSWORD;
+
+ @Value("${identity.salt}")
+ public String IDENTITY_SALT;
+
+ @Value("${login.qrcode.url:https://explorer.ont.io/v2/users/login_qrcode/}")
+ public String loginQrCodeUrl;
+
+
+ @Value("${oneUser.address.count.limit}")
+ public Integer oneUserAddressCountLimit;
+
}
\ No newline at end of file
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/controller/TokenController.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/controller/TokenController.java
index 4dd6aa75..22d069cf 100644
--- a/back-end-projects/Explorer/src/main/java/com/github/ontio/controller/TokenController.java
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/controller/TokenController.java
@@ -10,11 +10,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
@@ -72,9 +68,9 @@ public ResponseBean queryTokenDetail(@PathVariable("token_type") @Pattern(regexp
@GetMapping(value = "/oep8/{contract_hash}/{token_name}/transactions")
public ResponseBean queryOep8TxsByPage(@PathVariable("contract_hash") @Length(min = 40, max = 40, message = "Incorrect " +
"contract hash") String contractHash,
- @PathVariable("token_name") String tokenName,
- @RequestParam("page_size") @Min(1) @Max(20) Integer pageSize,
- @RequestParam("page_number") @Min(1) Integer pageNumber) {
+ @PathVariable("token_name") String tokenName,
+ @RequestParam("page_size") @Min(1) @Max(20) Integer pageSize,
+ @RequestParam("page_number") @Min(1) Integer pageNumber) {
log.info("###{}.{} begin...contract_hash:{},token_name:{}", CLASS_NAME, Helper.currentMethod(), contractHash, tokenName);
@@ -120,4 +116,14 @@ public ResponseBean queryPrice(
return tokenService.queryPrice(token, fiat);
}
+
+ @ApiOperation(value = "Get oep logos")
+ @GetMapping(value = "/logos")
+ public ResponseBean queryOepLogos(@RequestParam("contract_hash") @Length(min = 40, max = 40, message = "Incorrect contract hash") String contractHash,
+ @RequestParam("page_size") @Min(1) @Max(50) int pageSize,
+ @RequestParam("page_number") @Min(1) int pageNumber) {
+ log.info("###{}.{} begin...", CLASS_NAME, Helper.currentMethod());
+ return tokenService.queryOepLogos(contractHash, pageSize, pageNumber);
+ }
+
}
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/controller/UserController.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/controller/UserController.java
new file mode 100644
index 00000000..a8dd64eb
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/controller/UserController.java
@@ -0,0 +1,159 @@
+package com.github.ontio.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import com.github.ontio.exception.ExplorerException;
+import com.github.ontio.model.common.ResponseBean;
+import com.github.ontio.model.dao.User;
+import com.github.ontio.model.dao.UserAddress;
+import com.github.ontio.model.dto.login.CallBackDto;
+import com.github.ontio.model.dto.login.CallBackResponse;
+import com.github.ontio.model.dto.login.QrCodeDto;
+import com.github.ontio.service.IUserService;
+import com.github.ontio.util.ConstantParam;
+import com.github.ontio.util.ErrorInfo;
+import com.github.ontio.util.Helper;
+import com.github.ontio.util.JwtUtil;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import javax.validation.constraints.Pattern;
+import java.util.List;
+
+/**
+ * @author zhouq
+ * @version 1.0
+ * @date 2020/3/24
+ */
+@Slf4j
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/v2/users/")
+@Validated
+public class UserController {
+
+ private final String CLASS_NAME = this.getClass().getSimpleName();
+
+ private final IUserService userService;
+
+
+ @ApiOperation(value = "Web Query login qrcode")
+ @GetMapping(value = "/web_login_qrcode")
+ public ResponseBean queryWebQrCode() {
+ ResponseBean rs = userService.queryWebQrCode();
+ return rs;
+ }
+
+ @ApiOperation(value = "ONTO APP Query login qrcode")
+ @GetMapping(value = "/login_qrcode/{qrcode_id}")
+ public QrCodeDto queryQrCode(@PathVariable("qrcode_id") String qrcodeId) {
+ QrCodeDto rs = userService.queryQrCode(qrcodeId);
+ return rs;
+ }
+
+
+ @ApiOperation(value = "Query login user info")
+ @GetMapping(value = "/login_user_info")
+ public ResponseBean queryLoginUserInfo(@RequestParam("code") String code) {
+ ResponseBean rs = userService.queryLoginUserInfo(code);
+ return rs;
+ }
+
+
+ @ApiOperation(value = "ONTO User login")
+ @PostMapping(value = "/login")
+ public CallBackResponse userLogin(@RequestBody JSONObject jsonObject) {
+ log.info("###{}.{} begin...param:{}", CLASS_NAME, Helper.currentMethod(), jsonObject);
+ CallBackDto callBackDto = new CallBackDto();
+ callBackDto.setSigner(jsonObject.getString("signer"));
+ callBackDto.setSignedTx(jsonObject.getString("signedTx"));
+ CallBackDto.CallbackExtraData callbackExtraData = CallBackDto.CallbackExtraData.builder()
+ .id(jsonObject.getJSONObject("extraData").getString("id"))
+ .build();
+ callBackDto.setExtraData(callbackExtraData);
+ CallBackResponse rs = userService.login(callBackDto);
+ return rs;
+ }
+
+
+ @ApiImplicitParams({@ApiImplicitParam(paramType = "header", dataType = "String", name = "ONT_EXP_TOKEN", value = "login token", required = true)})
+ @ApiOperation(value = "Query user addresses")
+ @GetMapping(value = "/addresses")
+ public ResponseBean queryUserAddresses(@RequestParam("ont_id") @Pattern(regexp = "did:ont:[A-Za-z0-9]{34}", message = "Incorrect ONT ID format") String ontId) {
+ log.info("###{}.{} begin...ontId:{}", CLASS_NAME, Helper.currentMethod(), ontId);
+ checkToken(ontId);
+ ResponseBean rs = userService.queryUserAddresses(ontId);
+ refreshToken(ontId);
+ return rs;
+ }
+
+
+ @ApiImplicitParams({@ApiImplicitParam(paramType = "header", dataType = "String", name = "ONT_EXP_TOKEN", value = "login token", required = true)})
+ @ApiOperation(value = "Add or Update user addresses")
+ @PostMapping(value = "/addresses")
+ public ResponseBean addOrUpdateUserAddresses(@RequestParam("ont_id") @Pattern(regexp = "did:ont:[A-Za-z0-9]{34}", message = "Incorrect ONT ID format") String ontId,
+ @RequestBody @Valid List userAddresses) {
+ log.info("###{}.{} begin...ontId:{}", CLASS_NAME, Helper.currentMethod(), ontId);
+ checkToken(ontId);
+ ResponseBean rs = userService.addOrUpdateUserAddresses(userAddresses, ontId);
+ refreshToken(ontId);
+ return rs;
+ }
+
+
+ @ApiImplicitParams({@ApiImplicitParam(paramType = "header", dataType = "String", name = "ONT_EXP_TOKEN", value = "login token", required = true)})
+ @ApiOperation(value = "Delete user address")
+ @DeleteMapping(value = "/addresses")
+ public ResponseBean delUserAddress(@RequestParam("ont_id") @Pattern(regexp = "did:ont:[A-Za-z0-9]{34}", message = "Incorrect ONT ID format") String ontId,
+ @RequestBody JSONObject jsonObject) {
+ log.info("###{}.{} begin...ontId:{}", CLASS_NAME, Helper.currentMethod(), ontId);
+ checkToken(ontId);
+ ResponseBean rs = userService.delUserAddress(jsonObject.getString("address"), ontId);
+ refreshToken(ontId);
+ return rs;
+ }
+
+
+ @ApiImplicitParams({@ApiImplicitParam(paramType = "header", dataType = "String", name = "ONT_EXP_TOKEN", value = "login token", required = true)})
+ @ApiOperation(value = "Update user information")
+ @PostMapping
+ public ResponseBean updateUser(@RequestParam("ont_id") @Pattern(regexp = "did:ont:[A-Za-z0-9]{34}", message = "Incorrect ONT ID format") String ontId,
+ @RequestBody @Validated User user) {
+ log.info("###{}.{} begin...ontId:{}", CLASS_NAME, Helper.currentMethod(), ontId);
+ checkToken(ontId);
+ user.setOntId(ontId);
+ ResponseBean rs = userService.updateUser(user);
+ refreshToken(ontId);
+ return rs;
+ }
+
+
+ private void checkToken(String ontId) {
+ HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+ String token = request.getHeader(ConstantParam.HTTPHEADER_TOKEN);
+ if (Helper.isEmptyOrNull(token)) {
+ throw new ExplorerException(ErrorInfo.TOKEN_EMPTY);
+ }
+ if (!JwtUtil.verifyToken(token)) {
+ throw new ExplorerException(ErrorInfo.TOKEN_EXPIRED);
+ } else if (!JwtUtil.getClaim(token, ConstantParam.JWT_LOGINID).asString().equals(ontId)) {
+ throw new ExplorerException(ErrorInfo.TOKEN_UNMATCH);
+ }
+ }
+
+ private void refreshToken(String ontId) {
+ String newToken = JwtUtil.signToken(ontId);
+ HttpServletResponse resp = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
+ resp.setHeader(ConstantParam.HTTPHEADER_TOKEN, newToken);
+ }
+
+}
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/exception/ExplorerException.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/exception/ExplorerException.java
index 0e91dbf8..546fcda6 100644
--- a/back-end-projects/Explorer/src/main/java/com/github/ontio/exception/ExplorerException.java
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/exception/ExplorerException.java
@@ -1,5 +1,6 @@
package com.github.ontio.exception;
+import com.github.ontio.util.ErrorInfo;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -19,6 +20,18 @@ public ExplorerException(Integer code, String msg, Object result){
this.result = result;
}
+ public ExplorerException(ErrorInfo errorInfo, Object result){
+ this.code = errorInfo.code();
+ this.msg = errorInfo.desc();
+ this.result = result;
+ }
+
+ public ExplorerException(ErrorInfo errorInfo){
+ this.code = errorInfo.code();
+ this.msg = errorInfo.desc();
+ this.result = false;
+ }
+
public ExplorerException(){super();}
public ExplorerException(String msg){super(msg);}
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/AddressBlacklistMapper.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/AddressBlacklistMapper.java
new file mode 100644
index 00000000..e3f07b94
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/AddressBlacklistMapper.java
@@ -0,0 +1,7 @@
+package com.github.ontio.mapper;
+
+import com.github.ontio.model.dao.AddressBlacklist;
+import tk.mybatis.mapper.common.Mapper;
+
+public interface AddressBlacklistMapper extends Mapper {
+}
\ No newline at end of file
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/OepLogoMapper.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/OepLogoMapper.java
new file mode 100644
index 00000000..9a99e4c0
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/OepLogoMapper.java
@@ -0,0 +1,7 @@
+package com.github.ontio.mapper;
+
+import com.github.ontio.model.dao.OepLogo;
+import tk.mybatis.mapper.common.Mapper;
+
+public interface OepLogoMapper extends Mapper {
+}
\ No newline at end of file
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/UserAddressMapper.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/UserAddressMapper.java
new file mode 100644
index 00000000..41e1629a
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/UserAddressMapper.java
@@ -0,0 +1,12 @@
+package com.github.ontio.mapper;
+
+import com.github.ontio.model.dao.UserAddress;
+import tk.mybatis.mapper.common.Mapper;
+
+import java.util.List;
+
+public interface UserAddressMapper extends Mapper {
+
+ int saveUserAddress(List userAddresses);
+
+}
\ No newline at end of file
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/UserMapper.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/UserMapper.java
new file mode 100644
index 00000000..f7d444dc
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/mapper/UserMapper.java
@@ -0,0 +1,10 @@
+package com.github.ontio.mapper;
+
+import com.github.ontio.model.dao.User;
+import tk.mybatis.mapper.common.Mapper;
+
+public interface UserMapper extends Mapper {
+
+ int saveUser(User user);
+
+}
\ No newline at end of file
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/model/common/RedisKey.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/common/RedisKey.java
new file mode 100644
index 00000000..87a0d5e0
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/common/RedisKey.java
@@ -0,0 +1,12 @@
+package com.github.ontio.model.common;
+
+/**
+ * @author zhouq
+ * @version 1.0
+ * @date 2020/3/25
+ */
+public class RedisKey {
+
+ public static final String USERLOGIN_QRCODEID = "userLogin:qrCodeId:%s";
+
+}
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/AddressBlacklist.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/AddressBlacklist.java
new file mode 100644
index 00000000..73004555
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/AddressBlacklist.java
@@ -0,0 +1,68 @@
+package com.github.ontio.model.dao;
+
+import javax.persistence.Column;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.util.Date;
+
+@Table(name = "tbl_address_blacklist")
+public class AddressBlacklist {
+ @Id
+ @GeneratedValue(generator = "JDBC")
+ private String address;
+
+ /**
+ * 备注
+ */
+ private String note;
+
+ @Column(name = "create_time")
+ private Date createTime;
+
+ /**
+ * @return address
+ */
+ public String getAddress() {
+ return address;
+ }
+
+ /**
+ * @param address
+ */
+ public void setAddress(String address) {
+ this.address = address == null ? null : address.trim();
+ }
+
+ /**
+ * 获取备注
+ *
+ * @return note - 备注
+ */
+ public String getNote() {
+ return note;
+ }
+
+ /**
+ * 设置备注
+ *
+ * @param note 备注
+ */
+ public void setNote(String note) {
+ this.note = note == null ? null : note.trim();
+ }
+
+ /**
+ * @return create_time
+ */
+ public Date getCreateTime() {
+ return createTime;
+ }
+
+ /**
+ * @param createTime
+ */
+ public void setCreateTime(Date createTime) {
+ this.createTime = createTime;
+ }
+}
\ No newline at end of file
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/OepLogo.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/OepLogo.java
new file mode 100644
index 00000000..6a497fd0
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/OepLogo.java
@@ -0,0 +1,166 @@
+package com.github.ontio.model.dao;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.github.ontio.util.TxDateSerializer;
+
+import javax.persistence.Column;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.util.Date;
+
+@Table(name = "tbl_oep_logo")
+public class OepLogo {
+ @Id
+ @GeneratedValue(generator = "JDBC")
+ private Integer id;
+
+ /**
+ * 合约hash
+ */
+ @Column(name = "contract_hash")
+ private String contractHash;
+
+ /**
+ * oep5,oep8
+ */
+ private String type;
+
+ /**
+ * 合约token id
+ */
+ @Column(name = "token_id")
+ private String tokenId;
+
+ /**
+ * logo链接
+ */
+ private String logo;
+
+ /**
+ * token名称
+ */
+ private String name;
+
+ @JsonSerialize(using = TxDateSerializer.class)
+ @Column(name = "create_time")
+ private Date createTime;
+
+ /**
+ * @return id
+ */
+ public Integer getId() {
+ return id;
+ }
+
+ /**
+ * @param id
+ */
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ /**
+ * 获取合约hash
+ *
+ * @return contract_hash - 合约hash
+ */
+ public String getContractHash() {
+ return contractHash;
+ }
+
+ /**
+ * 设置合约hash
+ *
+ * @param contractHash 合约hash
+ */
+ public void setContractHash(String contractHash) {
+ this.contractHash = contractHash == null ? null : contractHash.trim();
+ }
+
+ /**
+ * 获取oep5,oep8
+ *
+ * @return type - oep5,oep8
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * 设置oep5,oep8
+ *
+ * @param type oep5,oep8
+ */
+ public void setType(String type) {
+ this.type = type == null ? null : type.trim();
+ }
+
+ /**
+ * 获取合约token id
+ *
+ * @return token_id - 合约token id
+ */
+ public String getTokenId() {
+ return tokenId;
+ }
+
+ /**
+ * 设置合约token id
+ *
+ * @param tokenId 合约token id
+ */
+ public void setTokenId(String tokenId) {
+ this.tokenId = tokenId == null ? null : tokenId.trim();
+ }
+
+ /**
+ * 获取logo链接
+ *
+ * @return logo - logo链接
+ */
+ public String getLogo() {
+ return logo;
+ }
+
+ /**
+ * 设置logo链接
+ *
+ * @param logo logo链接
+ */
+ public void setLogo(String logo) {
+ this.logo = logo == null ? null : logo.trim();
+ }
+
+ /**
+ * 获取token名称
+ *
+ * @return name - token名称
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * 设置token名称
+ *
+ * @param name token名称
+ */
+ public void setName(String name) {
+ this.name = name == null ? null : name.trim();
+ }
+
+ /**
+ * @return create_time
+ */
+ public Date getCreateTime() {
+ return createTime;
+ }
+
+ /**
+ * @param createTime
+ */
+ public void setCreateTime(Date createTime) {
+ this.createTime = createTime;
+ }
+}
\ No newline at end of file
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/User.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/User.java
new file mode 100644
index 00000000..922ac0cb
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/User.java
@@ -0,0 +1,146 @@
+package com.github.ontio.model.dao;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.github.ontio.util.TxDateSerializer;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Column;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.Pattern;
+import java.util.Date;
+
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Table(name = "tbl_user")
+public class User {
+ /**
+ * ONT ID
+ */
+ @Id
+ @Column(name = "ont_id")
+ @GeneratedValue(generator = "JDBC")
+ private String ontId;
+
+ /**
+ * 用户名
+ */
+ @Column(name = "user_name")
+ private String userName;
+
+ /**
+ * 邮箱
+ */
+ @NotEmpty
+ @Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", message = "email format error")
+ private String email;
+
+ /**
+ * 创建时间
+ */
+ @JsonSerialize(using = TxDateSerializer.class)
+ @Column(name = "create_time")
+ private Date createTime;
+
+ /**
+ * 上次登录时间
+ */
+ @JsonSerialize(using = TxDateSerializer.class)
+ @Column(name = "last_login_time")
+ private Date lastLoginTime;
+
+ /**
+ * 获取ONT ID
+ *
+ * @return ont_id - ONT ID
+ */
+ public String getOntId() {
+ return ontId;
+ }
+
+ /**
+ * 设置ONT ID
+ *
+ * @param ontId ONT ID
+ */
+ public void setOntId(String ontId) {
+ this.ontId = ontId == null ? null : ontId.trim();
+ }
+
+ /**
+ * 获取用户名
+ *
+ * @return user_name - 用户名
+ */
+ public String getUserName() {
+ return userName;
+ }
+
+ /**
+ * 设置用户名
+ *
+ * @param userName 用户名
+ */
+ public void setUserName(String userName) {
+ this.userName = userName == null ? null : userName.trim();
+ }
+
+ /**
+ * 获取邮箱
+ *
+ * @return email - 邮箱
+ */
+ public String getEmail() {
+ return email;
+ }
+
+ /**
+ * 设置邮箱
+ *
+ * @param email 邮箱
+ */
+ public void setEmail(String email) {
+ this.email = email == null ? null : email.trim();
+ }
+
+ /**
+ * 获取创建时间
+ *
+ * @return create_time - 创建时间
+ */
+ public Date getCreateTime() {
+ return createTime;
+ }
+
+ /**
+ * 设置创建时间
+ *
+ * @param createTime 创建时间
+ */
+ public void setCreateTime(Date createTime) {
+ this.createTime = createTime;
+ }
+
+ /**
+ * 获取上次登录时间
+ *
+ * @return last_login_time - 上次登录时间
+ */
+ public Date getLastLoginTime() {
+ return lastLoginTime;
+ }
+
+ /**
+ * 设置上次登录时间
+ *
+ * @param lastLoginTime 上次登录时间
+ */
+ public void setLastLoginTime(Date lastLoginTime) {
+ this.lastLoginTime = lastLoginTime;
+ }
+}
\ No newline at end of file
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/UserAddress.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/UserAddress.java
new file mode 100644
index 00000000..06eb0a2f
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dao/UserAddress.java
@@ -0,0 +1,159 @@
+package com.github.ontio.model.dao;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.Column;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.Pattern;
+
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@Table(name = "tbl_user_address")
+public class UserAddress {
+ @Id
+ @GeneratedValue(generator = "JDBC")
+ private Integer id;
+
+ /**
+ * ONT ID
+ */
+ @Column(name = "ont_id")
+ private String ontId;
+
+ /**
+ * 地址
+ */
+ @NotEmpty
+ @Pattern(regexp = "A[A-Za-z0-9]{33}")
+ private String address;
+
+ /**
+ * 地址备注
+ */
+ private String note;
+
+ /**
+ * 监听策略。0:不监听 1:监听所有入金出金,2:只监听入金 3:只监听出金
+ */
+ @Min(0)
+ @Max(3)
+ private Integer strategy;
+
+ /**
+ * 1:监听oep资产 0:不监听oep资产
+ */
+ @Column(name = "include_oep_token")
+ private Boolean includeOepToken;
+
+ /**
+ * @return id
+ */
+ public Integer getId() {
+ return id;
+ }
+
+ /**
+ * @param id
+ */
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ /**
+ * 获取ONT ID
+ *
+ * @return ont_id - ONT ID
+ */
+ public String getOntId() {
+ return ontId;
+ }
+
+ /**
+ * 设置ONT ID
+ *
+ * @param ontId ONT ID
+ */
+ public void setOntId(String ontId) {
+ this.ontId = ontId == null ? null : ontId.trim();
+ }
+
+ /**
+ * 获取地址
+ *
+ * @return address - 地址
+ */
+ public String getAddress() {
+ return address;
+ }
+
+ /**
+ * 设置地址
+ *
+ * @param address 地址
+ */
+ public void setAddress(String address) {
+ this.address = address == null ? null : address.trim();
+ }
+
+ /**
+ * 获取地址备注
+ *
+ * @return note - 地址备注
+ */
+ public String getNote() {
+ return note;
+ }
+
+ /**
+ * 设置地址备注
+ *
+ * @param note 地址备注
+ */
+ public void setNote(String note) {
+ this.note = note == null ? null : note.trim();
+ }
+
+ /**
+ * 获取监听策略。0:不监听 1:监听所有入金出金,2:只监听入金 3:只监听出金
+ *
+ * @return strategy - 监听策略。0:不监听 1:监听所有入金出金,2:只监听入金 3:只监听出金
+ */
+ public Integer getStrategy() {
+ return strategy;
+ }
+
+ /**
+ * 设置监听策略。0:不监听 1:监听所有入金出金,2:只监听入金 3:只监听出金
+ *
+ * @param strategy 监听策略。0:不监听 1:监听所有入金出金,2:只监听入金 3:只监听出金
+ */
+ public void setStrategy(Integer strategy) {
+ this.strategy = strategy;
+ }
+
+ /**
+ * 获取1:监听oep资产 0:不监听oep资产
+ *
+ * @return include_oep_token - 1:监听oep资产 0:不监听oep资产
+ */
+ public Boolean getIncludeOepToken() {
+ return includeOepToken;
+ }
+
+ /**
+ * 设置1:监听oep资产 0:不监听oep资产
+ *
+ * @param includeOepToken 1:监听oep资产 0:不监听oep资产
+ */
+ public void setIncludeOepToken(Boolean includeOepToken) {
+ this.includeOepToken = includeOepToken;
+ }
+}
\ No newline at end of file
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dto/login/CallBackDto.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dto/login/CallBackDto.java
new file mode 100644
index 00000000..f080e5aa
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dto/login/CallBackDto.java
@@ -0,0 +1,31 @@
+package com.github.ontio.model.dto.login;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author zhouq
+ * @version 1.0
+ * @date 2020/3/25
+ */
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@Data
+public class CallBackDto {
+
+ private String signer;
+ private String signedTx;
+ private CallbackExtraData extraData;
+
+ @NoArgsConstructor
+ @AllArgsConstructor
+ @Builder
+ @Data
+ public static class CallbackExtraData{
+ private String id;
+ }
+
+}
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dto/login/CallBackResponse.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dto/login/CallBackResponse.java
new file mode 100644
index 00000000..68828f65
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dto/login/CallBackResponse.java
@@ -0,0 +1,50 @@
+package com.github.ontio.model.dto.login;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.UUID;
+
+/**
+ * @author zhouq
+ * @version 1.0
+ * @date 2020/3/25
+ */
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Data
+public class CallBackResponse {
+ private String action;
+ private String version;
+ private long error;
+ private String id;
+ private JSONObject result;
+
+
+ public static CallBackResponse successResponse(JSONObject object) {
+ CallBackResponse callBackResponse = CallBackResponse.builder()
+ .action("")
+ .version("1.0.0")
+ .id(UUID.randomUUID().toString())
+ .error(0L)
+ .result(object)
+ .build();
+ return callBackResponse;
+ }
+
+ public static CallBackResponse errorResponse(long error) {
+ CallBackResponse callBackResponse = CallBackResponse.builder()
+ .action("")
+ .version("1.0.0")
+ .id(UUID.randomUUID().toString())
+ .error(error)
+ .result(new JSONObject())
+ .build();
+ return callBackResponse;
+ }
+
+}
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dto/login/QrCodeDto.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dto/login/QrCodeDto.java
new file mode 100644
index 00000000..2c57579e
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/model/dto/login/QrCodeDto.java
@@ -0,0 +1,112 @@
+package com.github.ontio.model.dto.login;
+
+import com.github.ontio.util.JacksonUtil;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * @author zhouq
+ * @version 1.0
+ * @date 2020/3/25
+ */
+@Builder
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class QrCodeDto {
+
+ private String callback;
+ private String chain;
+ private String data;
+ private long exp;
+ private String id;
+ private String requester;
+ private String signature;
+ private String signer;
+ private String ver;
+
+
+ public static QrCodeDto mainNetLoginQrCode(String id, String requester, String signature, QrCodeData qrCodeData, String callback, long exp) {
+ QrCodeDto qrCodeDto = QrCodeDto.builder()
+ .ver("1.0.0")
+ .id(id)
+ .requester(requester)
+ .signature(signature)
+ .signer("")
+ .data(JacksonUtil.beanToJSonStr(qrCodeData))
+ .callback(callback)
+ .exp(exp)
+ .chain("Mainnet")
+ .build();
+ return qrCodeDto;
+ }
+
+ public static QrCodeDto testNetLoginQrCode(String id, String requester, String signature, QrCodeData qrCodeData, String callback, long exp) {
+ QrCodeDto qrCodeDto = QrCodeDto.builder()
+ .ver("1.0.0")
+ .id(id)
+ .requester(requester)
+ .signature(signature)
+ .signer("")
+ .data(JacksonUtil.beanToJSonStr(qrCodeData))
+ .callback(callback)
+ .exp(exp)
+ .chain("Testnet")
+ .build();
+ return qrCodeDto;
+ }
+
+
+ @NoArgsConstructor
+ @AllArgsConstructor
+ @Builder
+ @Data
+ public static class QrCodeData {
+ private String action;
+ private QrCodeDataParam params;
+ }
+
+ @NoArgsConstructor
+ @AllArgsConstructor
+ @Builder
+ @Data
+ public static class QrCodeDataParam {
+ private QrCodeDataParamDetail invokeConfig;
+ }
+
+ @NoArgsConstructor
+ @AllArgsConstructor
+ @Builder
+ @Data
+ public static class QrCodeDataParamDetail {
+ private String contractHash;
+ private List functions;
+ private BigDecimal gasLimit;
+ private BigDecimal gasPrice;
+ private String payer;
+ }
+
+ @NoArgsConstructor
+ @AllArgsConstructor
+ @Builder
+ @Data
+ public static class QrCodeDataParamFun {
+ private List args;
+ private String operation;
+ }
+
+ @NoArgsConstructor
+ @AllArgsConstructor
+ @Builder
+ @Data
+ public static class QrCodeDataParamFunArg {
+ private String name;
+ private String value;
+ }
+
+}
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/service/ITokenService.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/service/ITokenService.java
index 40bbc5a3..79ba7ed8 100644
--- a/back-end-projects/Explorer/src/main/java/com/github/ontio/service/ITokenService.java
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/service/ITokenService.java
@@ -24,4 +24,6 @@ public interface ITokenService {
ResponseBean queryPrice(String token, String fiat);
+ ResponseBean queryOepLogos(String contractHash, int pageSize, int pageNumber);
+
}
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/service/IUserService.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/service/IUserService.java
new file mode 100644
index 00000000..c26dc991
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/service/IUserService.java
@@ -0,0 +1,35 @@
+package com.github.ontio.service;
+
+import com.github.ontio.model.common.ResponseBean;
+import com.github.ontio.model.dao.User;
+import com.github.ontio.model.dao.UserAddress;
+import com.github.ontio.model.dto.login.CallBackDto;
+import com.github.ontio.model.dto.login.CallBackResponse;
+import com.github.ontio.model.dto.login.QrCodeDto;
+
+import java.util.List;
+
+/**
+ * @author zhouq
+ * @version 1.0
+ * @date 2020/3/24
+ */
+public interface IUserService {
+
+ ResponseBean queryWebQrCode();
+
+ QrCodeDto queryQrCode(String qrcodeId);
+
+ ResponseBean queryLoginUserInfo(String code);
+
+ CallBackResponse login(CallBackDto callBackDto);
+
+ ResponseBean queryUserAddresses(String ontId);
+
+ ResponseBean addOrUpdateUserAddresses(List userAddresses, String ontId);
+
+ ResponseBean delUserAddress(String address, String ontId);
+
+ ResponseBean updateUser(User user);
+
+}
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/ContractServiceImpl.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/ContractServiceImpl.java
index cfe9df50..17ea66e0 100644
--- a/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/ContractServiceImpl.java
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/ContractServiceImpl.java
@@ -57,6 +57,7 @@
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -144,6 +145,7 @@ public ResponseBean queryTxsByContractHash(String contractType, String contractH
//TODO 云斗龙特殊查询,多asset_name,json_url字段。后续oep5需要统一规范
if (paramsConfig.OEP5_DRAGON_CONTRACTHASH.equals(contractHash)) {
List oep5TxDetailDtos = oep5TxDetailMapper.selectTxs4Dragon(contractHash, start, pageSize);
+ oep5TxDetailDtos = filterDragonTxDetails(oep5TxDetailDtos);
count = oep5TxDetailMapper.selectCountByCalledContracthash(contractHash);
pageResponseBean = new PageResponseBean(oep5TxDetailDtos, count);
} else {
@@ -191,6 +193,7 @@ public ResponseBean queryTxsByContractHash(String contractHash, Integer pageNumb
//TODO 云斗龙特殊查询,多asset_name,json_url字段。后续oep5需要统一规范
if (paramsConfig.OEP5_DRAGON_CONTRACTHASH.equals(contractHash)) {
List oep5TxDetailDtos = oep5TxDetailMapper.selectTxs4Dragon(contractHash, start, pageSize);
+ oep5TxDetailDtos = filterDragonTxDetails(oep5TxDetailDtos);
count = oep5TxDetailMapper.selectCountByCalledContracthash(contractHash);
pageResponseBean = new PageResponseBean(oep5TxDetailDtos, count);
} else {
@@ -636,4 +639,21 @@ private long getDaysAgo0HourTimestamp(int days) {
return zeroHourTimestamp;
}
+ private List filterDragonTxDetails(List details) {
+ if (details == null || details.isEmpty()) {
+ return details;
+ }
+ Map detailMap = new LinkedHashMap<>();
+ details.forEach(detail -> detailMap.compute(detail.getTxHash(), (k, v) -> {
+ if (v == null) {
+ return detail;
+ } else if (detail.getAssetName() != null && detail.getAssetName().startsWith("HyperDragons")) {
+ return detail;
+ } else {
+ return v;
+ }
+ }));
+ return new ArrayList<>(detailMap.values());
+ }
+
}
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/TokenServiceImpl.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/TokenServiceImpl.java
index 8c44eda2..30654914 100644
--- a/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/TokenServiceImpl.java
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/TokenServiceImpl.java
@@ -3,19 +3,11 @@
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.github.ontio.config.ParamsConfig;
-import com.github.ontio.mapper.Oep4Mapper;
-import com.github.ontio.mapper.Oep5Mapper;
-import com.github.ontio.mapper.Oep8Mapper;
-import com.github.ontio.mapper.Oep8TxDetailMapper;
-import com.github.ontio.mapper.RankingMapper;
-import com.github.ontio.mapper.TokenDailyAggregationMapper;
+import com.github.ontio.mapper.*;
import com.github.ontio.model.common.PageResponseBean;
import com.github.ontio.model.common.ResponseBean;
-import com.github.ontio.model.dto.Oep4DetailDto;
-import com.github.ontio.model.dto.Oep5DetailDto;
-import com.github.ontio.model.dto.Oep8DetailDto;
-import com.github.ontio.model.dto.TokenPriceDto;
-import com.github.ontio.model.dto.TxDetailDto;
+import com.github.ontio.model.dao.OepLogo;
+import com.github.ontio.model.dto.*;
import com.github.ontio.model.dto.ranking.TokenRankingDto;
import com.github.ontio.service.ITokenService;
import com.github.ontio.util.ConstantParam;
@@ -28,13 +20,10 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import tk.mybatis.mapper.entity.Example;
import java.time.Duration;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import java.util.stream.Collectors;
/**
@@ -53,11 +42,12 @@ public class TokenServiceImpl implements ITokenService {
private final TokenDailyAggregationMapper tokenDailyAggregationMapper;
private final RankingMapper rankingMapper;
private final CoinMarketCapApi coinMarketCapApi;
+ private final OepLogoMapper oepLogoMapper;
@Autowired
public TokenServiceImpl(Oep4Mapper oep4Mapper, Oep5Mapper oep5Mapper, Oep8Mapper oep8Mapper,
- Oep8TxDetailMapper oep8TxDetailMapper, TokenDailyAggregationMapper tokenDailyAggregationMapper,
- RankingMapper rankingMapper, CoinMarketCapApi coinMarketCapApi) {
+ Oep8TxDetailMapper oep8TxDetailMapper, TokenDailyAggregationMapper tokenDailyAggregationMapper,
+ RankingMapper rankingMapper, CoinMarketCapApi coinMarketCapApi, OepLogoMapper oepLogoMapper) {
this.oep4Mapper = oep4Mapper;
this.oep5Mapper = oep5Mapper;
this.oep8Mapper = oep8Mapper;
@@ -65,6 +55,7 @@ public TokenServiceImpl(Oep4Mapper oep4Mapper, Oep5Mapper oep5Mapper, Oep8Mapper
this.tokenDailyAggregationMapper = tokenDailyAggregationMapper;
this.rankingMapper = rankingMapper;
this.coinMarketCapApi = coinMarketCapApi;
+ this.oepLogoMapper = oepLogoMapper;
}
@Override
@@ -220,4 +211,17 @@ public void setParamsConfig(ParamsConfig paramsConfig) {
});
}
+
+ @Override
+ public ResponseBean queryOepLogos(String contractHash, int pageSize, int pageNumber) {
+ PageHelper.startPage(pageNumber, pageSize);
+ Example example = new Example(OepLogo.class);
+ example.and()
+ .andEqualTo("contractHash", contractHash);
+ example.orderBy("id").desc();
+ List oepLogos = oepLogoMapper.selectByExample(example);
+ Long total = ((Page) oepLogos).getTotal();
+ PageResponseBean responseBean = new PageResponseBean(oepLogos, total.intValue());
+ return new ResponseBean(ErrorInfo.SUCCESS.code(), ErrorInfo.SUCCESS.desc(), responseBean);
+ }
}
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/UserServiceImpl.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/UserServiceImpl.java
new file mode 100644
index 00000000..68cdbd3e
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/service/impl/UserServiceImpl.java
@@ -0,0 +1,240 @@
+package com.github.ontio.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.github.benmanes.caffeine.cache.Caffeine;
+import com.github.benmanes.caffeine.cache.LoadingCache;
+import com.github.ontio.config.ParamsConfig;
+import com.github.ontio.core.asset.Sig;
+import com.github.ontio.core.transaction.Transaction;
+import com.github.ontio.crypto.Digest;
+import com.github.ontio.mapper.AddressBlacklistMapper;
+import com.github.ontio.mapper.UserAddressMapper;
+import com.github.ontio.mapper.UserMapper;
+import com.github.ontio.model.common.PageResponseBean;
+import com.github.ontio.model.common.RedisKey;
+import com.github.ontio.model.common.ResponseBean;
+import com.github.ontio.model.dao.AddressBlacklist;
+import com.github.ontio.model.dao.User;
+import com.github.ontio.model.dao.UserAddress;
+import com.github.ontio.model.dto.login.CallBackDto;
+import com.github.ontio.model.dto.login.CallBackResponse;
+import com.github.ontio.model.dto.login.QrCodeDto;
+import com.github.ontio.service.IUserService;
+import com.github.ontio.util.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * @author zhouq
+ * @version 1.0
+ * @date 2020/3/24
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class UserServiceImpl implements IUserService {
+
+ private static final String CACHEKEY_BLACKADDR = "blackAddress";
+ private static final String SIGNATURE_PREFIX = "01";
+
+ private final UserAddressMapper userAddressMapper;
+ private final UserMapper userMapper;
+ private final ParamsConfig paramsConfig;
+ private final StringRedisTemplate redisTemplate;
+ private final AddressBlacklistMapper addressBlacklistMapper;
+ private final OntologySDKService sdkService;
+
+ private LoadingCache> blackAddressCache = null;
+
+ @Autowired
+ private void setCache() {
+ blackAddressCache = Caffeine.newBuilder()
+ .expireAfterWrite(5, TimeUnit.MINUTES)
+ .build(key -> {
+ List addressBlacklist = addressBlacklistMapper.selectAll();
+ return addressBlacklist.stream().map(item -> item.getAddress()).collect(Collectors.toList());
+ });
+ }
+
+ @Override
+ public ResponseBean queryWebQrCode() {
+ String qrCodeId = Helper.generateQrCodeId();
+ redisTemplate.opsForValue().set(String.format(RedisKey.USERLOGIN_QRCODEID, qrCodeId), "", 2, TimeUnit.MINUTES);
+ Map rsMap = new HashMap<>();
+ rsMap.put("ONTAuthScanProtocol", paramsConfig.loginQrCodeUrl + qrCodeId);
+ rsMap.put("Id", qrCodeId);
+ return Helper.successResult(rsMap);
+ }
+
+ @Override
+ public QrCodeDto queryQrCode(String qrCodeId) {
+ QrCodeDto qrCodeDto = generateQrCode(qrCodeId);
+ return qrCodeDto;
+ }
+
+ private QrCodeDto generateQrCode(String qrCodeId) {
+ QrCodeDto.QrCodeDataParamFunArg qrCodeDataParamFunArg = QrCodeDto.QrCodeDataParamFunArg.builder()
+ .name("message")
+ .value("")
+ .build();
+ QrCodeDto.QrCodeDataParamFun qrCodeDataParamFun = QrCodeDto.QrCodeDataParamFun.builder()
+ .operation("signMessage")
+ .args(Arrays.asList(qrCodeDataParamFunArg))
+ .build();
+ QrCodeDto.QrCodeDataParamDetail qrCodeDataParamDetail = QrCodeDto.QrCodeDataParamDetail.builder()
+ .contractHash("0000000000000000000000000000000000000000")
+ .payer("")
+ .gasLimit(new BigDecimal("0"))
+ .gasPrice(new BigDecimal("0"))
+ .functions(Arrays.asList(qrCodeDataParamFun))
+ .build();
+ QrCodeDto.QrCodeDataParam qrCodeDataParam = QrCodeDto.QrCodeDataParam.builder()
+ .invokeConfig(qrCodeDataParamDetail)
+ .build();
+ QrCodeDto.QrCodeData qrCodeData = QrCodeDto.QrCodeData.builder()
+ .action("signMessage")
+ .params(qrCodeDataParam)
+ .build();
+ String signature = sdkService.signData2HexStr(JacksonUtil.beanToJSonStr(qrCodeData));
+
+ return QrCodeDto.mainNetLoginQrCode(qrCodeId, paramsConfig.IDENTITY_ONTID, signature, qrCodeData, paramsConfig.loginCallbackUrl, System.currentTimeMillis() + 2 * 60 * 1000L);
+ }
+
+
+ @Override
+ public ResponseBean queryLoginUserInfo(String qrCodeId) {
+ String token = redisTemplate.opsForValue().get(String.format(RedisKey.USERLOGIN_QRCODEID, qrCodeId));
+ if (token == null) {
+ return Helper.successResult(ErrorInfo.QRCODE_EXPIRED.code());
+ } else if ("".equals(token)) {
+ return Helper.successResult(ErrorInfo.NO_LOGIN_USERINFO.code());
+ }
+ String ontId = JwtUtil.getClaim(token, ConstantParam.JWT_LOGINID).asString();
+ User user = userMapper.selectByPrimaryKey(ontId);
+ //get last login time
+ Date lastLoginTime = user.getLastLoginTime();
+ user.setLastLoginTime(new Date());
+ userMapper.updateByPrimaryKeySelective(user);
+ user.setLastLoginTime(lastLoginTime);
+ //set token
+ HttpServletResponse resp = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
+ resp.setHeader(ConstantParam.HTTPHEADER_TOKEN, token);
+ return Helper.successResult(user);
+ }
+
+
+ @Override
+ public CallBackResponse login(CallBackDto callBackDto) {
+ String ontId = callBackDto.getSigner();
+ String signedTx = callBackDto.getSignedTx();
+ String qrCodeId = callBackDto.getExtraData().getId();
+ Boolean verifyFlag = verifySignature(ontId, signedTx);
+ if (!verifyFlag) {
+ return CallBackResponse.errorResponse(ErrorInfo.VERIFY_SIGN_FAILED.code());
+ }
+ String redisValue = redisTemplate.opsForValue().get(String.format(RedisKey.USERLOGIN_QRCODEID, qrCodeId));
+ if (redisValue == null) {
+ return CallBackResponse.errorResponse(ErrorInfo.QRCODE_EXPIRED.code());
+ }
+ String token = JwtUtil.signToken(ontId);
+ redisTemplate.opsForValue().set(String.format(RedisKey.USERLOGIN_QRCODEID, qrCodeId), token, 60, TimeUnit.SECONDS);
+
+ User user = userMapper.selectByPrimaryKey(ontId);
+ if (user == null) {
+ Date now = new Date();
+ user = User.builder()
+ .ontId(ontId)
+ .userName("")
+ .email("")
+ .lastLoginTime(now)
+ .createTime(now)
+ .build();
+ userMapper.insert(user);
+ }
+ return CallBackResponse.successResponse(new JSONObject());
+ }
+
+ private boolean verifySignature(String ontId, String signedTx) {
+ Transaction transaction = null;
+ try {
+ transaction = Transaction.deserializeFrom(com.github.ontio.common.Helper.hexToBytes(signedTx));
+ } catch (IOException e) {
+ log.error("{} error...", Helper.currentMethod(), e);
+ return false;
+ }
+ byte[] sigBytes = transaction.sigs[0].sigData[0];
+ String signature = com.github.ontio.common.Helper.toHexString(sigBytes);
+ if (!signature.startsWith(SIGNATURE_PREFIX)) {
+ signature = SIGNATURE_PREFIX + signature;
+ }
+ transaction.sigs = new Sig[0];
+ String hex = transaction.toHexString();
+ String tx = hex.substring(0, hex.length() - 2);
+ String data = com.github.ontio.common.Helper.toHexString(Digest.hash256(com.github.ontio.common.Helper.hexToBytes(tx)));
+ return sdkService.verifySignature(ontId, data, signature);
+ }
+
+
+ @Override
+ public ResponseBean queryUserAddresses(String ontId) {
+ UserAddress userAddress = UserAddress.builder()
+ .ontId(ontId)
+ .build();
+ List userAddresses = userAddressMapper.select(userAddress);
+ PageResponseBean pageResponseBean = new PageResponseBean(userAddresses, userAddresses.size());
+ return Helper.successResult(pageResponseBean);
+ }
+
+
+ @Override
+ public ResponseBean addOrUpdateUserAddresses(List userAddressList, String ontId) {
+ if (userAddressList.size() > paramsConfig.oneUserAddressCountLimit) {
+ //normal response can refresh token
+ return Helper.errorResult(ErrorInfo.ADDRESS_TOOMANY, false);
+ }
+ if (CollectionUtils.containsAny(blackAddressCache.get(CACHEKEY_BLACKADDR), userAddressList.stream().map(key -> key.getAddress()).collect(Collectors.toList()))) {
+ return Helper.errorResult(ErrorInfo.IN_BLACKADDRESS, false);
+ }
+ userAddressList.forEach(userAddress -> {
+ userAddress.setOntId(ontId);
+ });
+ userAddressMapper.saveUserAddress(userAddressList);
+ return Helper.successResult(true);
+ }
+
+ @Override
+ public ResponseBean delUserAddress(String address, String ontId) {
+ if (address.length() != 34 || !address.startsWith("A")) {
+ return Helper.errorResult(ErrorInfo.ADDRESS_FORMAT_INCORRECT, false);
+ }
+ UserAddress userAddress = UserAddress.builder()
+ .ontId(ontId)
+ .address(address)
+ .build();
+ int count = userAddressMapper.delete(userAddress);
+ if (count == 0) {
+ return Helper.errorResult(ErrorInfo.ADDRESS_ONTID_UNMATCH, false);
+ }
+ return Helper.successResult(true);
+ }
+
+
+ @Override
+ public ResponseBean updateUser(User user) {
+ userMapper.updateByPrimaryKeySelective(user);
+ return Helper.successResult(true);
+ }
+}
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/util/ConstantParam.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/ConstantParam.java
index 792f8fc3..debc22f0 100644
--- a/back-end-projects/Explorer/src/main/java/com/github/ontio/util/ConstantParam.java
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/ConstantParam.java
@@ -172,5 +172,9 @@ public class ConstantParam {
public static final String CONTRACTHASH_ONT = "0100000000000000000000000000000000000000";
+ public static final String HTTPHEADER_TOKEN = "ont_exp_token";
+
+ public static final String JWT_LOGINID = "loginId";
+
}
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/util/ErrorInfo.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/ErrorInfo.java
index bfc6115e..f7d239e1 100644
--- a/back-end-projects/Explorer/src/main/java/com/github/ontio/util/ErrorInfo.java
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/ErrorInfo.java
@@ -88,6 +88,25 @@ public enum ErrorInfo {
*/
ALREADY_AUDITPASS(61011,"FAIL, already on shelves."),
+ QRCODE_EXPIRED(61012,"Qrcode expired."),
+
+ NO_LOGIN_USERINFO(61013,"No login user info."),
+
+ TOKEN_EXPIRED(61014,"Token expired."),
+
+ TOKEN_UNMATCH(61015,"Token unmatch."),
+
+ TOKEN_EMPTY(61016,"Token empty."),
+
+ IN_BLACKADDRESS(61017,"Address in blacklist."),
+
+ ADDRESS_TOOMANY(61018,"Too many addresses."),
+
+ ADDRESS_ONTID_UNMATCH(61019,"Address unmatch ontid."),
+
+ ADDRESS_FORMAT_INCORRECT(61020,"Address format incorrect."),
+
+
@@ -116,6 +135,10 @@ public enum ErrorInfo {
*/
DB_ERROR(62005, "FAIL, db operate fail."),
+ VERIFY_SIGN_FAILED(62006,"Verify signature failed."),
+
+ TX_ERROR(62007,"transaction error."),
+
/**
* inner error
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/util/Helper.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/Helper.java
index b1646492..721dac81 100644
--- a/back-end-projects/Explorer/src/main/java/com/github/ontio/util/Helper.java
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/Helper.java
@@ -21,12 +21,14 @@
import com.github.ontio.mapper.BlockMapper;
import com.github.ontio.model.common.OntIdEventEnum;
+import com.github.ontio.model.common.ResponseBean;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.Base64;
+import java.util.Random;
/**
* @author zhouq
@@ -60,6 +62,28 @@ public static Boolean isNotEmptyAndNull(Object... params) {
return !isEmptyOrNull(params);
}
+ public static ResponseBean successResult(Object obj) {
+ return new ResponseBean(ErrorInfo.SUCCESS.code(), ErrorInfo.SUCCESS.desc(), obj);
+ }
+
+ public static ResponseBean errorResult(ErrorInfo errorInfo, Object obj) {
+ return new ResponseBean(errorInfo.code(), errorInfo.desc(), obj);
+ }
+
+ public static String generateQrCodeId() {
+ return String.valueOf(System.currentTimeMillis()) + getRandomString(5);
+ }
+
+ public static String getRandomString(int length) {
+ String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ Random random = new Random();
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < length; i++) {
+ int number = random.nextInt(62);
+ sb.append(str.charAt(number));
+ }
+ return sb.toString();
+ }
/**
* 判断时间范围是否超过一个月
@@ -133,6 +157,7 @@ public static String templateOntIdOperation(String inputStr) {
/**
* 判断redis的key是否属于REDIS_LONGEXPIRETIME_KEYLIST
+ *
* @param redisKey
* @return
*/
@@ -154,6 +179,7 @@ public static Boolean isBelongRedisLongExpireMapper(String redisKey) {
/**
* 判断redis的key是否属于REDIS_MEDIUMEXPIRETIME_KEYLIST
+ *
* @param redisKey
* @return
*/
@@ -221,7 +247,6 @@ public static String currentMethod() {
}
-
/**
* 根据base64后的图片数据生成本地文件
*
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/util/JwtUtil.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/JwtUtil.java
new file mode 100644
index 00000000..543e4949
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/JwtUtil.java
@@ -0,0 +1,82 @@
+package com.github.ontio.util;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.JWTVerifier;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.exceptions.JWTDecodeException;
+import com.auth0.jwt.interfaces.Claim;
+import com.auth0.jwt.interfaces.DecodedJWT;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.util.Base64;
+import java.util.Date;
+
+/**
+ * JAVA-JWT util
+ */
+@Component
+@Slf4j
+public class JwtUtil {
+
+ private static String accessTokenExpireTime;
+
+ private static String encryptJWTKey;
+
+ @Value("${jwt.accessTokenExpireTime}")
+ public void setAccessTokenExpireTime(String tokenExpireTime) {
+ JwtUtil.accessTokenExpireTime = tokenExpireTime.trim();
+ }
+
+ @Value("${jwt.encryptJWTKey}")
+ public void setEncryptJWTKey(String jWTKey) {
+ JwtUtil.encryptJWTKey = jWTKey.trim();
+ }
+
+
+ public static boolean verifyToken(String token) {
+ try {
+ String ontId = getClaim(token, ConstantParam.JWT_LOGINID).asString();
+ String secret = preSecret(ontId);
+ Algorithm algorithm = Algorithm.HMAC256(secret);
+ JWTVerifier verifier = JWT.require(algorithm).build();
+ DecodedJWT jwt = verifier.verify(token);
+ log.info("verifytoken jwt:{}", jwt.toString());
+ } catch (Exception e) {
+ log.error("verifyToken error...{}", e.getMessage());
+ return false;
+ }
+ return true;
+ }
+
+
+ public static Claim getClaim(String token, String claim) {
+ try {
+ DecodedJWT jwt = JWT.decode(token);
+ return jwt.getClaim(claim);
+ } catch (JWTDecodeException e) {
+ log.error("getClaim error...{}", e.getMessage());
+ return null;
+ }
+ }
+
+
+ public static String signToken(String ontId) {
+ // ontId+JWT key
+ String secret = preSecret(ontId);
+ Date date = new Date(System.currentTimeMillis() + Long.parseLong(accessTokenExpireTime) * 1000);
+ Algorithm algorithm = Algorithm.HMAC256(secret);
+ return JWT.create()
+ .withClaim(ConstantParam.JWT_LOGINID, ontId)
+ .withExpiresAt(date)
+ .sign(algorithm);
+ }
+
+ private static String preSecret(String ontId) {
+ String secret = ontId + new String(Base64.getDecoder().decode(encryptJWTKey));
+ return secret;
+ }
+
+
+}
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/util/OntologySDKService.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/OntologySDKService.java
index 9dfcc7fa..f4a6baac 100644
--- a/back-end-projects/Explorer/src/main/java/com/github/ontio/util/OntologySDKService.java
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/OntologySDKService.java
@@ -24,9 +24,11 @@
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.ontio.OntSdk;
+import com.github.ontio.account.Account;
import com.github.ontio.common.Address;
import com.github.ontio.common.Helper;
import com.github.ontio.config.ParamsConfig;
+import com.github.ontio.core.DataSignature;
import com.github.ontio.core.payload.InvokeWasmCode;
import com.github.ontio.core.transaction.Transaction;
import com.github.ontio.smartcontract.neovm.abi.BuildParams;
@@ -295,4 +297,56 @@ private OntSdk getOep5OntSdk(String codeHash) {
return wm;
}
+
+ /**
+ * verify signature
+ *
+ * @param ontId
+ * @param origDataStr
+ * @param signatureStr
+ * @return
+ */
+ public boolean verifySignature(String ontId, String origDataStr, String signatureStr) {
+ try {
+ Boolean verify = Boolean.FALSE;
+ OntSdk ontSdk = OntSdk.getInstance();
+ ontSdk.setRestful(paramsConfig.MASTERNODE_RESTFUL_URL);
+ String issuerDdo = ontSdk.nativevm().ontId().sendGetDDO(ontId);
+
+ JSONArray owners = JSONObject.parseObject(issuerDdo).getJSONArray("Owners");
+ for (int i = 0; i < owners.size(); ++i) {
+ String pubkeyStr = owners.getJSONObject(i).getString("Value");
+ Account account = new Account(false, Helper.hexToBytes(pubkeyStr));
+ verify = account.verifySignature(Helper.hexToBytes(origDataStr), Helper.hexToBytes(signatureStr));
+ if (verify) {
+ break;
+ }
+ }
+ return verify;
+ } catch (Exception e) {
+ log.error("{} error...", com.github.ontio.util.Helper.currentMethod(), e);
+ }
+ return false;
+ }
+
+ /**
+ * sign
+ *
+ * @param origData
+ * @return
+ */
+ public String signData2HexStr(String origData) {
+ try {
+ OntSdk ontSdk = OntSdk.getInstance();
+ ontSdk.openWalletFile("account.json");
+ Account account = ontSdk.getWalletMgr().getAccount(paramsConfig.IDENTITY_ONTID, paramsConfig.IDENTITY_PASSWORD, Base64.getDecoder().decode(paramsConfig.IDENTITY_SALT));
+ DataSignature sign = new DataSignature(ontSdk.defaultSignScheme, account, origData.getBytes());
+ String sigdata = Helper.toHexString(sign.signature());
+ return sigdata;
+ } catch (Exception e) {
+ log.error("{} error...", com.github.ontio.util.Helper.currentMethod(), e);
+ }
+ return "";
+ }
+
}
diff --git a/back-end-projects/Explorer/src/main/java/com/github/ontio/util/TxDateSerializer.java b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/TxDateSerializer.java
new file mode 100644
index 00000000..06dd2b88
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/java/com/github/ontio/util/TxDateSerializer.java
@@ -0,0 +1,23 @@
+package com.github.ontio.util;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+import java.io.IOException;
+import java.util.Date;
+
+/**
+ * @author zhouq
+ * @version 1.0
+ * @date 2019/7/25
+ */
+public class TxDateSerializer extends JsonSerializer {
+
+ @Override
+ public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
+ jsonGenerator.writeNumber(date.getTime() / 1000L);
+ }
+
+}
diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.38__tbl_tx_detail_index.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.38__tbl_tx_detail_index.sql
new file mode 100644
index 00000000..ffb9d4a1
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.38__tbl_tx_detail_index.sql
@@ -0,0 +1,16 @@
+-- ----------------------------
+-- Table structure for tbl_tx_detail_index
+-- ----------------------------
+DROP TABLE IF EXISTS `tbl_tx_detail_index`;
+CREATE TABLE `tbl_tx_detail_index` (
+ `address` CHAR(80) NOT NULL DEFAULT '' COMMENT '交易地址',
+ `desc_block_height` INT(11) NOT NULL COMMENT '倒序区块高度',
+ `tx_hash` CHAR(64) NOT NULL DEFAULT '' COMMENT '交易hash',
+ `tx_index` INT(11) NOT NULL COMMENT '该event在交易eventlog里的索引',
+ `called_contract_hash` CHAR(40) NOT NULL DEFAULT '' COMMENT '该交易真正调用的合约hash',
+ `tx_time` INT(11) NOT NULL COMMENT '交易时间戳',
+ `asset_name` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '交易资产名',
+ `tx_direction` TINYINT NOT NULL COMMENT '交易方向 0:FROM 1:TO 2:BOTH',
+ PRIMARY KEY (`address`, `desc_block_height`, `tx_hash`, `tx_index`),
+ KEY `idx_address_contract_hash`(`address`, `called_contract_hash`)
+) ENGINE = InnoDB DEFAULT CHARSET = utf8;
diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.39__tbl_oep5_tx_detail.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.39__tbl_oep5_tx_detail.sql
new file mode 100644
index 00000000..a34a174c
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.39__tbl_oep5_tx_detail.sql
@@ -0,0 +1,5 @@
+-- ----------------------------
+-- Change index structure for tbl_oep5_tx_detail
+-- ----------------------------
+DROP INDEX idx_called_contract_hash ON tbl_oep5_tx_detail;
+CREATE INDEX idx_called_contract_hash_block_height ON tbl_oep5_tx_detail(`called_contract_hash`, `block_height`);
diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.40__tbl_tx_eventlog.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.40__tbl_tx_eventlog.sql
new file mode 100644
index 00000000..c810eeae
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.40__tbl_tx_eventlog.sql
@@ -0,0 +1,5 @@
+-- ----------------------------
+-- Change index structure for tbl_tx_eventlog
+-- ----------------------------
+DROP INDEX idx_called_contract_hash ON tbl_tx_eventlog;
+CREATE INDEX idx_called_contract_hash_block_height ON tbl_tx_eventlog (`called_contract_hash`, `block_height`);
diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.41__tbl_oep4_tx_detail.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.41__tbl_oep4_tx_detail.sql
new file mode 100644
index 00000000..951ab650
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.41__tbl_oep4_tx_detail.sql
@@ -0,0 +1,5 @@
+-- ----------------------------
+-- Change index structure for tbl_oep4_tx_detail
+-- ----------------------------
+DROP INDEX idx_called_contract_hash ON tbl_oep4_tx_detail;
+CREATE INDEX idx_called_contract_hash_block_height ON tbl_oep4_tx_detail (`called_contract_hash`, `block_height`);
\ No newline at end of file
diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.42__tbl_address_blacklist.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.42__tbl_address_blacklist.sql
new file mode 100644
index 00000000..10dd4ba0
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.42__tbl_address_blacklist.sql
@@ -0,0 +1,10 @@
+-- ----------------------------
+-- Table structure for tbl_address_blacklist
+-- ----------------------------
+DROP TABLE IF EXISTS `tbl_address_blacklist`;
+CREATE TABLE `tbl_address_blacklist` (
+ `address` varchar(255) NOT NULL DEFAULT '',
+ `note` varchar(255) NOT NULL DEFAULT '' COMMENT '备注',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`address`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.43__tbl_user.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.43__tbl_user.sql
new file mode 100644
index 00000000..54ef3536
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.43__tbl_user.sql
@@ -0,0 +1,12 @@
+-- ----------------------------
+-- Table structure for tbl_user
+-- ----------------------------
+DROP TABLE IF EXISTS `tbl_user`;
+CREATE TABLE `tbl_user` (
+ `ont_id` varchar(255) NOT NULL DEFAULT '' COMMENT 'ONT ID',
+ `user_name` varchar(255) NOT NULL DEFAULT '' COMMENT '用户名',
+ `email` varchar(255) NOT NULL DEFAULT '' COMMENT '邮箱',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
+ `last_login_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '上次登录时间',
+ PRIMARY KEY (`ont_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.44__tbl_user_address.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.44__tbl_user_address.sql
new file mode 100644
index 00000000..5e3ee632
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.44__tbl_user_address.sql
@@ -0,0 +1,16 @@
+-- ----------------------------
+-- Table structure for tbl_user_address
+-- ----------------------------
+DROP TABLE IF EXISTS `tbl_user_address`;
+CREATE TABLE `tbl_user_address` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `ont_id` varchar(255) NOT NULL DEFAULT '' COMMENT 'ONT ID',
+ `address` varchar(255) NOT NULL DEFAULT '' COMMENT '地址',
+ `note` varchar(255) NOT NULL DEFAULT '' COMMENT '地址备注',
+ `strategy` int(11) NOT NULL DEFAULT '0' COMMENT '监听策略。0:不监听 1:监听所有入金出金,2:只监听入金 3:只监听出金',
+ `include_oep_token` tinyint(1) NOT NULL DEFAULT '0' COMMENT '1:监听oep资产 0:不监听oep资产',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `unq_ontid_address` (`address`,`ont_id`),
+ KEY `fkey_ontId` (`ont_id`),
+ CONSTRAINT `fkey_ontId` FOREIGN KEY (`ont_id`) REFERENCES `tbl_user` (`ont_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.45__tbl_oep_logo.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.45__tbl_oep_logo.sql
new file mode 100644
index 00000000..9be93cd6
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.45__tbl_oep_logo.sql
@@ -0,0 +1,15 @@
+-- ----------------------------
+-- Table structure for tbl_oep_logo
+-- ----------------------------
+DROP TABLE IF EXISTS `tbl_oep_logo`;
+CREATE TABLE `tbl_oep_logo` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `contract_hash` varchar(255) NOT NULL DEFAULT '' COMMENT '合约hash',
+ `type` varchar(255) NOT NULL DEFAULT '' COMMENT 'oep5,oep8',
+ `token_id` varchar(255) NOT NULL DEFAULT '' COMMENT '合约token id',
+ `logo` varchar(255) NOT NULL DEFAULT '' COMMENT 'logo链接',
+ `name` varchar(255) NOT NULL DEFAULT '' COMMENT 'token名称',
+ `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `unq_contracthash_tokenid` (`contract_hash`,`token_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.46__tbl_user.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.46__tbl_user.sql
new file mode 100644
index 00000000..16df1f2d
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.46__tbl_user.sql
@@ -0,0 +1 @@
+ALTER TABLE tbl_user MODIFY last_login_time datetime NOT NULL COMMENT '上次登录时间';
diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.47__tbl_tx_detail_index.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.47__tbl_tx_detail_index.sql
new file mode 100644
index 00000000..06ada90e
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.47__tbl_tx_detail_index.sql
@@ -0,0 +1,2 @@
+DROP INDEX idx_address_contract_hash ON tbl_tx_detail_index;
+CREATE INDEX idx_contract_hash_block_height ON tbl_tx_detail_index(`called_contract_hash`, `desc_block_height`);
\ No newline at end of file
diff --git a/back-end-projects/Explorer/src/main/resources/db/migration/V1.48__tbl_oep5_tx_detail_index.sql b/back-end-projects/Explorer/src/main/resources/db/migration/V1.48__tbl_oep5_tx_detail_index.sql
new file mode 100644
index 00000000..7ffc4e31
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/resources/db/migration/V1.48__tbl_oep5_tx_detail_index.sql
@@ -0,0 +1 @@
+CREATE INDEX idx_called_contract_hash_tx_hash ON tbl_oep5_tx_detail(`called_contract_hash`, `tx_hash`);
diff --git a/back-end-projects/Explorer/src/main/resources/generator/generatorConfig.xml b/back-end-projects/Explorer/src/main/resources/generator/generatorConfig.xml
index 2bb304d6..fb5b44e9 100644
--- a/back-end-projects/Explorer/src/main/resources/generator/generatorConfig.xml
+++ b/back-end-projects/Explorer/src/main/resources/generator/generatorConfig.xml
@@ -18,7 +18,7 @@
+ password="zaq12wsx">
@@ -41,7 +41,7 @@
-
+
+
+
diff --git a/back-end-projects/Explorer/src/main/resources/mapper/AddressBlacklistMapper.xml b/back-end-projects/Explorer/src/main/resources/mapper/AddressBlacklistMapper.xml
new file mode 100644
index 00000000..97596a30
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/resources/mapper/AddressBlacklistMapper.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/back-end-projects/Explorer/src/main/resources/mapper/Oep5TxDetailMapper.xml b/back-end-projects/Explorer/src/main/resources/mapper/Oep5TxDetailMapper.xml
index fc48779d..8cca448e 100644
--- a/back-end-projects/Explorer/src/main/resources/mapper/Oep5TxDetailMapper.xml
+++ b/back-end-projects/Explorer/src/main/resources/mapper/Oep5TxDetailMapper.xml
@@ -51,30 +51,26 @@
diff --git a/back-end-projects/Explorer/src/main/resources/mapper/OepLogoMapper.xml b/back-end-projects/Explorer/src/main/resources/mapper/OepLogoMapper.xml
new file mode 100644
index 00000000..07972d54
--- /dev/null
+++ b/back-end-projects/Explorer/src/main/resources/mapper/OepLogoMapper.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/back-end-projects/Explorer/src/main/resources/mapper/TxDetailMapper.xml b/back-end-projects/Explorer/src/main/resources/mapper/TxDetailMapper.xml
index d15a60dc..ba3da1f4 100644
--- a/back-end-projects/Explorer/src/main/resources/mapper/TxDetailMapper.xml
+++ b/back-end-projects/Explorer/src/main/resources/mapper/TxDetailMapper.xml
@@ -107,7 +107,6 @@
AND asset_name = #{assetName}
- AND event_type IN (2, 3)
ORDER BY desc_block_height, tx_hash, tx_index
LIMIT #{startIndex}, #{pageSize}
) idx ON idx.hash = d.tx_hash
@@ -134,7 +133,6 @@
AND asset_name = #{assetName}
- AND event_type IN (2, 3)
ORDER BY desc_block_height, tx_hash, tx_index
) idx ON idx.hash = d.tx_hash AND idx.`index` = d.tx_index
diff --git a/back-end-projects/Explorer/src/main/resources/mapper/TxEventLogMapper.xml b/back-end-projects/Explorer/src/main/resources/mapper/TxEventLogMapper.xml
index ae3532ee..9a98535b 100644
--- a/back-end-projects/Explorer/src/main/resources/mapper/TxEventLogMapper.xml
+++ b/back-end-projects/Explorer/src/main/resources/mapper/TxEventLogMapper.xml
@@ -42,15 +42,16 @@
-->
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/back-end-projects/OntSynHandler/src/main/resources/mapper/TxDetailIndexMapper.xml b/back-end-projects/OntSynHandler/src/main/resources/mapper/TxDetailIndexMapper.xml
index 87b68c00..69a98c51 100644
--- a/back-end-projects/OntSynHandler/src/main/resources/mapper/TxDetailIndexMapper.xml
+++ b/back-end-projects/OntSynHandler/src/main/resources/mapper/TxDetailIndexMapper.xml
@@ -4,19 +4,19 @@
INSERT INTO tbl_tx_detail_index
- (address, desc_block_height, tx_hash, tx_index, called_contract_hash, tx_time, event_type, asset_name, tx_direction)
- SELECT from_address, (~0 >> 33) - block_height, tx_hash, tx_index, called_contract_hash, tx_time, event_type, asset_name, 0
+ (address, desc_block_height, tx_hash, tx_index, called_contract_hash, tx_time, asset_name, tx_direction)
+ SELECT from_address, (~0 >> 33) - block_height, tx_hash, tx_index, called_contract_hash, tx_time, asset_name, 0
FROM tbl_tx_detail
- WHERE block_height BETWEEN #{beginHeight} AND #{endHeight}
+ WHERE block_height BETWEEN #{beginHeight} AND #{endHeight} AND from_address <> '' AND event_type IN (2, 3)
ORDER BY block_height, tx_time;
INSERT INTO tbl_tx_detail_index
- (address, desc_block_height, tx_hash, tx_index, called_contract_hash, tx_time, event_type, asset_name, tx_direction)
- SELECT to_address, (~0 >> 33) - block_height, tx_hash, tx_index, called_contract_hash, tx_time, event_type, asset_name, 1
+ (address, desc_block_height, tx_hash, tx_index, called_contract_hash, tx_time, asset_name, tx_direction)
+ SELECT to_address, (~0 >> 33) - block_height, tx_hash, tx_index, called_contract_hash, tx_time, asset_name, 1
FROM tbl_tx_detail
- WHERE block_height BETWEEN #{beginHeight} AND #{endHeight}
+ WHERE block_height BETWEEN #{beginHeight} AND #{endHeight} AND to_address <> '' AND event_type IN (2, 3)
ORDER BY block_height, tx_time
ON DUPLICATE KEY UPDATE tx_direction = 2;
diff --git a/back-end-projects/OntSynHandler/src/main/resources/mapper/TxEventLogMapper.xml b/back-end-projects/OntSynHandler/src/main/resources/mapper/TxEventLogMapper.xml
index 33821d4b..db7b0633 100644
--- a/back-end-projects/OntSynHandler/src/main/resources/mapper/TxEventLogMapper.xml
+++ b/back-end-projects/OntSynHandler/src/main/resources/mapper/TxEventLogMapper.xml
@@ -48,5 +48,15 @@
)
+
+
+ ALTER TABLE tbl_tx_eventlog
+ AUTO_INCREMENT = #{id};
+
+
+
\ No newline at end of file
diff --git a/back-end-projects/OntSynHandler/src/main/resources/mapper/UserAddressMapper.xml b/back-end-projects/OntSynHandler/src/main/resources/mapper/UserAddressMapper.xml
new file mode 100644
index 00000000..067b2aac
--- /dev/null
+++ b/back-end-projects/OntSynHandler/src/main/resources/mapper/UserAddressMapper.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/back-end-projects/OntSynHandler/src/main/resources/mapper/UserMapper.xml b/back-end-projects/OntSynHandler/src/main/resources/mapper/UserMapper.xml
new file mode 100644
index 00000000..99b58702
--- /dev/null
+++ b/back-end-projects/OntSynHandler/src/main/resources/mapper/UserMapper.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file