Эх сурвалжийг харах

Merge branch 'dev' of xiongzhu/raex_back into master

熊竹 4 жил өмнө
parent
commit
33ce2ed292

+ 19 - 11
src/main/contract/9th.sol

@@ -158,7 +158,7 @@ library EnumerableMap {
         uint256 key,
         identity value
     ) internal returns (bool) {
-        return _set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
+        return _set(map._inner, bytes32(key), bytes32(uint256(value)));
     }
 
     function remove(UintToAddressMap storage map, uint256 key)
@@ -190,7 +190,7 @@ library EnumerableMap {
         returns (uint256, identity)
     {
         (bytes32 key, bytes32 value) = _at(map._inner, index);
-        return (uint256(key), identity(uint160(uint256(value))));
+        return (uint256(key), identity(uint256(value)));
     }
 
     function tryGet(UintToAddressMap storage map, uint256 key)
@@ -199,7 +199,7 @@ library EnumerableMap {
         returns (bool, identity)
     {
         (bool success, bytes32 value) = _tryGet(map._inner, bytes32(key));
-        return (success, identity(uint160(uint256(value))));
+        return (success, identity(uint256(value)));
     }
 
     function get(UintToAddressMap storage map, uint256 key)
@@ -207,7 +207,7 @@ library EnumerableMap {
         view
         returns (identity)
     {
-        return identity(uint160(uint256(_get(map._inner, bytes32(key)))));
+        return identity(uint256(_get(map._inner, bytes32(key))));
     }
 
     function get(
@@ -217,7 +217,7 @@ library EnumerableMap {
     ) internal view returns (identity) {
         return
             identity(
-                uint160(uint256(_get(map._inner, bytes32(key), errorMessage)))
+                uint256(_get(map._inner, bytes32(key), errorMessage))
             );
     }
 }
@@ -307,15 +307,15 @@ library EnumerableSet {
     }
 
     function add(AddressSet storage set, identity value) internal returns (bool) {
-        return _add(set._inner, bytes32(uint256(uint160(value))));
+        return _add(set._inner, bytes32(uint256(value)));
     }
 
     function remove(AddressSet storage set, identity value) internal returns (bool) {
-        return _remove(set._inner, bytes32(uint256(uint160(value))));
+        return _remove(set._inner, bytes32(uint256(value)));
     }
 
     function contains(AddressSet storage set, identity value) internal view returns (bool) {
-        return _contains(set._inner, bytes32(uint256(uint160(value))));
+        return _contains(set._inner, bytes32(uint256(value)));
     }
 
     function length(AddressSet storage set) internal view returns (uint256) {
@@ -323,7 +323,7 @@ library EnumerableSet {
     }
 
     function at(AddressSet storage set, uint256 index) internal view returns (identity) {
-        return identity(uint160(uint256(_at(set._inner, index))));
+        return identity(uint256(_at(set._inner, index)));
     }
 
     struct UintSet {
@@ -1030,8 +1030,8 @@ contract ERC721PresetMinterPauserAutoId is Context, AccessControl, ERC721Burnabl
 
         // We cannot just use balanceOf to create the new tokenId because tokens
         // can be burned (destroyed), so we need a separate counter.
-        _mint(to, _tokenIdTracker.current());
-        _tokenIdTracker.increment();
+        _mint(to, tokenId);
+        //_tokenIdTracker.increment();
     }
 
     /**
@@ -1069,4 +1069,12 @@ contract ERC721PresetMinterPauserAutoId is Context, AccessControl, ERC721Burnabl
     function ownerTransfer(identity from, identity to, uint256 tokenId) public onlyowner {
         _transfer(from, to, tokenId);
     }
+
+    function setTokenURI(uint256 tokenId, string memory _tokenURI) public onlyowner {
+        _setTokenURI(tokenId, _tokenURI);
+    }
+
+    function setBaseURI(string memory baseURI_) public onlyowner {
+        _setBaseURI(baseURI_);
+    }
 }

+ 2 - 0
src/main/java/com/izouma/nineth/domain/IdentityAuth.java

@@ -26,10 +26,12 @@ public class IdentityAuth extends BaseEntity {
     @Searchable
     private String realName;
 
+    @Searchable
     private String phone;
 
     private String email;
 
+    @Searchable
     private String idNo;
 
     private String idFront;

+ 5 - 15
src/main/java/com/izouma/nineth/service/AssetMintService.java

@@ -8,9 +8,7 @@ import com.izouma.nineth.dto.NFTAccount;
 import com.izouma.nineth.event.CreateAssetEvent;
 import com.izouma.nineth.exception.BusinessException;
 import com.izouma.nineth.repo.AssetRepo;
-import com.izouma.nineth.repo.TokenHistoryRepo;
 import com.izouma.nineth.repo.UserRepo;
-import com.izouma.nineth.utils.SnowflakeIdWorker;
 import io.ipfs.api.IPFS;
 import io.ipfs.api.MerkleNode;
 import io.ipfs.api.NamedStreamable;
@@ -19,12 +17,10 @@ import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.context.ApplicationContext;
-import org.springframework.core.env.Environment;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
 import java.io.File;
-import java.math.BigInteger;
-import java.util.Arrays;
 
 @Service
 @Slf4j
@@ -34,10 +30,9 @@ public class AssetMintService {
     private UserRepo           userRepo;
     private NFTService         nftService;
     private ApplicationContext applicationContext;
-    private TokenHistoryRepo   tokenHistoryRepo;
-    private Environment        env;
 
-    public void mint(Asset asset, Long historyId) {
+    @Async
+    public void mint(Asset asset) {
         User user = userRepo.findById(asset.getUserId()).orElseThrow(new BusinessException("用户不存在"));
         if (StringUtils.isEmpty(user.getPublicKey())) {
             NFTAccount account = nftService.createAccount(user.getUsername() + "_");
@@ -47,7 +42,7 @@ public class AssetMintService {
             userRepo.save(user);
         }
         try {
-            NFT nft = nftService.createToken(user.getNftAccount());
+            NFT nft = nftService.createToken(user.getNftAccount(), asset.getTokenId());
             if (nft != null) {
                 asset.setTokenId(nft.getTokenId());
                 asset.setBlockNumber(nft.getBlockNumber());
@@ -57,14 +52,9 @@ public class AssetMintService {
                     asset.setIpfsUrl(ipfsUpload(asset.getPic().get(0).getUrl()));
                 }
                 assetRepo.save(asset);
-
-                tokenHistoryRepo.findById(historyId).ifPresent(tokenHistory -> {
-                    tokenHistory.setTokenId(nft.getTokenId());
-                    tokenHistoryRepo.save(tokenHistory);
-                });
             }
         } catch (Exception e) {
-            e.printStackTrace();
+            log.error("铸造失败", e);
         }
         applicationContext.publishEvent(new CreateAssetEvent(this, true, asset));
     }

+ 12 - 14
src/main/java/com/izouma/nineth/service/AssetService.java

@@ -14,6 +14,7 @@ import com.izouma.nineth.lock.RedisLockable;
 import com.izouma.nineth.repo.*;
 import com.izouma.nineth.utils.JpaUtils;
 import com.izouma.nineth.utils.SecurityUtils;
+import com.izouma.nineth.utils.TokenUtils;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
@@ -22,7 +23,6 @@ import org.springframework.context.ApplicationContext;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 import org.springframework.scheduling.annotation.Async;
-import org.springframework.scheduling.annotation.AsyncResult;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
@@ -32,7 +32,6 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
-import java.util.concurrent.Future;
 import java.util.stream.Collectors;
 
 @Service
@@ -53,16 +52,15 @@ public class AssetService {
         return assetRepo.findAll(JpaUtils.toSpecification(pageQuery, Asset.class), JpaUtils.toPageRequest(pageQuery));
     }
 
-    @Async
-    public Future<Asset> createAsset(Collection collection, User user, Long orderId, BigDecimal price, String type, Integer number) {
+    public Asset createAsset(Collection collection, User user, Long orderId, BigDecimal price, String type, Integer number) {
         Asset asset = Asset.create(collection, user);
+        asset.setTokenId(TokenUtils.genTokenId());
         asset.setNumber(number);
         asset.setOrderId(orderId);
         asset.setPrice(price);
-        asset.setIpfsUrl(assetMintService.ipfsUpload(collection.getPic().get(0).getUrl()));
         assetRepo.save(asset);
 
-        TokenHistory tokenHistory = tokenHistoryRepo.save(TokenHistory.builder()
+        tokenHistoryRepo.save(TokenHistory.builder()
                 .tokenId(asset.getTokenId())
                 .fromUser(collection.getMinter())
                 .fromUserId(collection.getMinterId())
@@ -73,19 +71,19 @@ public class AssetService {
                 .operation(type)
                 .price(price)
                 .build());
-        assetMintService.mint(asset, tokenHistory.getId());
-        return new AsyncResult<>(asset);
+        assetMintService.mint(asset);
+        return asset;
     }
 
-    @Async
-    public Future<Asset> createAsset(BlindBoxItem winItem, User user, Long orderId, BigDecimal price, String type, Integer number) {
+    public Asset createAsset(BlindBoxItem winItem, User user, Long orderId, BigDecimal price, String type, Integer number) {
         Asset asset = Asset.create(winItem, user);
+        asset.setTokenId(TokenUtils.genTokenId());
         asset.setNumber(number);
         asset.setOrderId(orderId);
         asset.setPrice(price);
-        asset.setIpfsUrl(assetMintService.ipfsUpload(winItem.getPic().get(0).getUrl()));
         assetRepo.save(asset);
-        TokenHistory tokenHistory = tokenHistoryRepo.save(TokenHistory.builder()
+
+        tokenHistoryRepo.save(TokenHistory.builder()
                 .tokenId(asset.getTokenId())
                 .fromUser(winItem.getMinter())
                 .fromUserId(winItem.getMinterId())
@@ -96,8 +94,8 @@ public class AssetService {
                 .operation(type)
                 .price(price)
                 .build());
-        assetMintService.mint(asset, tokenHistory.getId());
-        return new AsyncResult<>(asset);
+        assetMintService.mint(asset);
+        return asset;
     }
 
 

+ 4 - 0
src/main/java/com/izouma/nineth/service/CollectionService.java

@@ -148,6 +148,10 @@ public class CollectionService {
     @Transactional
     public Collection createBlindBox(CreateBlindBox createBlindBox) {
         Collection blindBox = createBlindBox.getBlindBox();
+        if (blindBox.getId() != null) {
+            collectionRepo.save(blindBox);
+            return blindBox;
+        }
 
         List<Collection> list =
                 collectionRepo.findAllById(createBlindBox.getItems().stream().map(BlindBoxItem::getCollectionId)

+ 49 - 30
src/main/java/com/izouma/nineth/service/NFTService.java

@@ -3,22 +3,21 @@ package com.izouma.nineth.service;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alipay.mychain.sdk.api.utils.Utils;
-import com.alipay.mychain.sdk.domain.transaction.LogEntry;
 import com.antfinancial.mychain.baas.tool.restclient.RestClient;
 import com.antfinancial.mychain.baas.tool.restclient.RestClientProperties;
 import com.antfinancial.mychain.baas.tool.restclient.model.CallRestBizParam;
 import com.antfinancial.mychain.baas.tool.restclient.model.Method;
 import com.antfinancial.mychain.baas.tool.restclient.model.ReceiptDecoration;
 import com.antfinancial.mychain.baas.tool.restclient.response.BaseResp;
-import com.izouma.nineth.config.GeneralProperties;
 import com.izouma.nineth.config.Constants;
+import com.izouma.nineth.config.GeneralProperties;
 import com.izouma.nineth.dto.NFT;
 import com.izouma.nineth.dto.NFTAccount;
 import com.izouma.nineth.exception.BusinessException;
-import com.izouma.nineth.utils.HashUtils;
 import com.izouma.nineth.utils.SnowflakeIdWorker;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.binary.Hex;
 import org.springframework.retry.annotation.Backoff;
 import org.springframework.retry.annotation.Retryable;
 import org.springframework.stereotype.Service;
@@ -60,15 +59,16 @@ public class NFTService {
     }
 
     @Retryable(maxAttempts = 100, backoff = @Backoff(delay = 5000), value = BusinessException.class)
-    public synchronized NFT createToken(String toAccount) throws Exception {
+    public synchronized NFT createToken(String toAccount, String tokenId) throws Exception {
         JSONArray jsonArray = new JSONArray();
         jsonArray.add(Utils.getIdentityByName(toAccount));
+        jsonArray.add(new BigInteger(tokenId, 16));
         CallRestBizParam callRestBizParam = CallRestBizParam.builder()
                 .orderId(String.valueOf(new SnowflakeIdWorker(0, 0).nextId()))
                 .bizid(restClientProperties.getBizid())
                 .account(restClientProperties.getAccount())
                 .contractName(generalProperties.getContractName())
-                .methodSignature("mint(identity)")
+                .methodSignature("mint(identity,uint256)")
                 .inputParamListStr(jsonArray.toJSONString())
                 .outTypes("[]")//合约返回值类型
                 .mykmsKeyId(restClientProperties.getKmsId())
@@ -87,15 +87,9 @@ public class NFTService {
             BigInteger gasUsed = txReceipt.getGasUsed();
             long result = txReceipt.getResult();
             log.info("EVM合约交易内容: 哈希 " + txReceipt.getHash() + ", 消耗燃料 " + gasUsed + ", 结果 " + result);
-            for (LogEntry logEntry : txReceipt.getLogs()) {
-                if (logEntry.getTopics().get(0).equals(HashUtils.Keccak256("Transfer(identity,identity,uint256)"))) {
-                    String tokenId = logEntry.getTopics().get(3);
-                    txReceipt.getBlockNumber();
-                    NFT nft = new NFT(txReceipt.getHash(), tokenId, txReceipt.getBlockNumber(), txReceipt.getGasUsed());
-                    log.info("NFT生成成功 {}", nft);
-                    return nft;
-                }
-            }
+            NFT nft = new NFT(txReceipt.getHash(), tokenId, txReceipt.getBlockNumber(), txReceipt.getGasUsed());
+            log.info("NFT生成成功 {}", nft);
+            return nft;
         } else {
             // 异步交易未成功需要根据状态码判断交易状态
             log.error("EVM合约执行未成功: " + resp.getCode());
@@ -103,19 +97,52 @@ public class NFTService {
         throw new BusinessException("创建nft失败");
     }
 
+    public String ownerOf(String tokenId) throws Exception {
+        CallRestBizParam callRestBizParam = CallRestBizParam.builder()
+                .orderId(String.valueOf(new SnowflakeIdWorker(0, 0).nextId()))
+                .bizid(restClientProperties.getBizid())
+                .account(restClientProperties.getAccount())
+                .contractName(generalProperties.getContractName())
+                .methodSignature("ownerOf(uint256)")
+                .inputParamListStr("[" + new BigInteger(tokenId, 16) + "]")
+                .outTypes("[identity]")//合约返回值类型
+                .mykmsKeyId(restClientProperties.getKmsId())
+                .method(Method.CALLCONTRACTBIZASYNC)
+                .tenantid(restClientProperties.getTenantid())
+                .gas(500000L)
+                .build();
+        BaseResp resp = restClient.bizChainCallWithReceipt(callRestBizParam);
+        if (!resp.isSuccess()) {
+            log.info("EVM合约执行失败: " + resp.getCode() + ", " + resp.getData());
+        }
+        if ("200".equals(resp.getCode())) {
+            log.info("EVM合约执行成功");
+            // 合约调用交易回执内容
+            ReceiptDecoration txReceipt = JSON.parseObject(resp.getData(), ReceiptDecoration.class);
+            BigInteger gasUsed = txReceipt.getGasUsed();
+            long result = txReceipt.getResult();
+            log.info("EVM合约交易内容: 哈希 " + txReceipt.getHash() + ", 消耗燃料 " + gasUsed + ", 结果 " + result);
+            String identity = Hex.encodeHexString(txReceipt.getOutput());
+            log.info("owner is: {}", identity);
+            return identity;
+        } else {
+            // 异步交易未成功需要根据状态码判断交易状态
+            log.error("EVM合约执行未成功: " + resp.getCode());
+            throw new BusinessException("EVM合约执行未成功: " + resp.getCode());
+        }
+    }
 
     public NFT transferToken(String tokenId, String fromAccount, String toAccount) throws Exception {
         JSONArray jsonArray = new JSONArray();
-        jsonArray.add(Utils.getIdentityByName(fromAccount));
-        jsonArray.add(Utils.getIdentityByName(toAccount));
-        jsonArray.add(Long.parseLong(tokenId, 16));
-
+        jsonArray.add(Utils.getIdentityByName("raex_official"));
+        jsonArray.add(Utils.getIdentityByName("9th_HCWWflAZ_"));
+        jsonArray.add("95057808871064671354760012409081314299");
         CallRestBizParam callRestBizParam = CallRestBizParam.builder()
                 .orderId(String.valueOf(new SnowflakeIdWorker(0, 0).nextId()))
                 .bizid(restClientProperties.getBizid())
                 .account(restClientProperties.getAccount())
-                .contractName(generalProperties.getContractName())
-                .methodSignature("transferFrom(identity,identity,uint256)")
+                .contractName("raex12")
+                .methodSignature("ownerTransfer(identity,identity,uint256)")
                 .inputParamListStr(jsonArray.toJSONString())
                 .outTypes("[]")//合约返回值类型
                 .mykmsKeyId(restClientProperties.getKmsId())
@@ -134,20 +161,12 @@ public class NFTService {
             BigInteger gasUsed = txReceipt.getGasUsed();
             long result = txReceipt.getResult();
             log.info("EVM合约交易内容: 哈希 " + txReceipt.getHash() + ", 消耗燃料 " + gasUsed + ", 结果 " + result);
-            for (LogEntry logEntry : txReceipt.getLogs()) {
-                if (logEntry.getTopics().get(0).equals(HashUtils.Keccak256("Transfer(identity,identity,uint256)"))) {
-                    String transferTokenId = logEntry.getTopics().get(3);
-                    txReceipt.getBlockNumber();
-                    NFT nft = new NFT(txReceipt.getHash(), tokenId, txReceipt.getBlockNumber(), txReceipt.getGasUsed());
-                    log.info("NFT转移成功 {}", nft);
-                    return nft;
-                }
-            }
+            return new NFT(txReceipt.getHash(), tokenId, txReceipt.getBlockNumber(), txReceipt.getGasUsed());
         } else {
             // 异步交易未成功需要根据状态码判断交易状态
             log.error("EVM合约执行未成功: " + resp.getCode());
         }
-        throw new BusinessException("创建nft失败");
+        throw new BusinessException("转移token失败");
     }
 
     public NFT setApprovalForAll(String account) throws Exception {

+ 13 - 2
src/main/java/com/izouma/nineth/service/UserService.java

@@ -64,6 +64,7 @@ public class UserService {
     private AdapayService     adapayService;
     private UserBankCardRepo  userBankCardRepo;
     private InviteRepo        inviteRepo;
+    private NFTService        nftService;
 
     @CacheEvict(value = "user", key = "#user.username")
     public User update(User user) {
@@ -116,7 +117,16 @@ public class UserService {
         if (StringUtils.isNotBlank(userRegister.getPassword())) {
             user.setPassword(new BCryptPasswordEncoder().encode(userRegister.getPassword()));
         }
-        return userRepo.save(user);
+        user = userRepo.save(user);
+        User finalUser = user;
+        new Thread(() -> {
+            NFTAccount account = nftService.createAccount(finalUser.getUsername() + "_");
+            finalUser.setNftAccount(account.getAccountId());
+            finalUser.setKmsId(account.getAccountKmsId());
+            finalUser.setPublicKey(account.getPublicKey());
+            userRepo.save(finalUser);
+        }).start();
+        return user;
     }
 
     public User phoneRegister(String phone, String code, String password, String inviteCode) {
@@ -125,6 +135,7 @@ public class UserService {
         if (StringUtils.isNotBlank(inviteCode)) {
             invite = inviteRepo.findFirstByCode(inviteCode).orElse(null);
         }
+        smsService.verify(phone, code);
         User user = create(UserRegister.builder()
                 .authorities(Collections.singleton(Authority.get(AuthorityName.ROLE_USER)))
                 .username(name)
@@ -477,7 +488,7 @@ public class UserService {
             if (userRepo.findByPhoneAndDelFalse(phone).isPresent()) {
                 exist.add(phone);
             } else {
-                if (!Pattern.matches("^1[3-9]\\d{9}]$", phone)) {
+                if (!Pattern.matches("^1[3-9]\\d{9}$", phone)) {
                     err.add(phone);
                 } else {
                     try {

+ 23 - 0
src/main/java/com/izouma/nineth/utils/TokenUtils.java

@@ -0,0 +1,23 @@
+package com.izouma.nineth.utils;
+
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
+
+public class TokenUtils {
+    public static String genTokenId() {
+        try {
+            Random random = ThreadLocalRandom.current();
+            byte[] r = new byte[32];
+            random.nextBytes(r);
+            MessageDigest m = MessageDigest.getInstance("MD5");
+            m.update(r, 0, r.length);
+            return new BigInteger(1, m.digest()).toString(16);
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+}

+ 1 - 1
src/main/resources/application.yaml

@@ -87,7 +87,7 @@ aliyun:
   sms-code: SMS_228870098
 general:
   host: https://test.raex.vip
-  contract-name: raex
+  contract-name: raex_new
   name: 绿洲数字藏品中心
   org: 华储艺术品中心(深圳)有限公司
   short-name: 华储

+ 12 - 8
src/main/vue/src/views/BlindBoxEdit.vue

@@ -129,19 +129,23 @@
                     <!-- <el-form-item prop="likes" label="点赞">
                         <el-input-number v-model="formData.likes"></el-input-number>
                     </el-form-item> -->
-                    <el-form-item prop="onShelf" label="上架">
+                    <el-form-item prop="startTime" label="定时发布">
+                        <el-switch v-model="formData.scheduleSale" active-text="是" inactive-text="否"></el-switch>
+                        <div style="margin-top: 10px" v-if="formData.scheduleSale">
+                            <el-date-picker
+                                v-model="formData.startTime"
+                                type="datetime"
+                                value-format="yyyy-MM-dd HH:mm:ss"
+                                placeholder="发布时间"
+                            ></el-date-picker>
+                        </div>
+                    </el-form-item>
+                    <el-form-item prop="onShelf" label="上架" v-if="!formData.scheduleSale">
                         <el-switch v-model="formData.onShelf" active-text="上架" inactive-text="下架"></el-switch>
                     </el-form-item>
                     <el-form-item prop="salable" label="可售">
                         <el-switch v-model="formData.salable" active-text="可销售" inactive-text="仅展示"></el-switch>
                     </el-form-item>
-                    <el-form-item prop="startTime" label="开售时间">
-                        <el-date-picker
-                            v-model="formData.startTime"
-                            type="datetime"
-                            value-format="yyyy-MM-dd HH:mm:ss"
-                        ></el-date-picker>
-                    </el-form-item>
                     <el-form-item class="form-submit">
                         <el-button @click="onSave" :loading="saving" type="primary" v-if="!formData.id">
                             保存

+ 1 - 1
src/main/vue/src/views/CollectionEdit.vue

@@ -274,7 +274,7 @@ export default {
                 type: 'DEFAULT',
                 source: 'OFFICIAL',
                 pic: [],
-                scheduleSale: false,
+                scheduleSale: true,
                 sort: 0,
                 privileges: []
             },

+ 19 - 3
src/test/java/com/izouma/nineth/CommonTest.java

@@ -1,11 +1,11 @@
 package com.izouma.nineth;
 
+import com.alibaba.fastjson.JSONArray;
 import com.github.kevinsawicki.http.HttpRequest;
 import com.izouma.nineth.config.Constants;
 import com.izouma.nineth.domain.BaseEntity;
 import com.izouma.nineth.domain.BlindBoxItem;
 import com.izouma.nineth.domain.User;
-import com.izouma.nineth.utils.SnowflakeIdWorker;
 import com.izouma.nineth.web.BaseController;
 import io.ipfs.api.IPFS;
 import io.ipfs.api.MerkleNode;
@@ -52,12 +52,16 @@ import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Method;
 import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.math.RoundingMode;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Paths;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.util.List;
 import java.util.*;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.regex.Pattern;
 
 import static java.nio.file.StandardOpenOption.CREATE;
@@ -374,7 +378,19 @@ public class CommonTest {
     }
 
     @Test
-    public void sdfsdf() {
-        System.out.println(new SnowflakeIdWorker(0, 0).nextId());
+    public void random256() throws NoSuchAlgorithmException {
+        Random random = ThreadLocalRandom.current();
+        byte[] r = new byte[2]; //Means 2048 bit
+        random.nextBytes(r);
+        MessageDigest m = MessageDigest.getInstance("MD5");
+        m.update(r, 0, r.length);
+        BigInteger bi = new BigInteger(1, m.digest());
+        System.out.println(bi);
+        System.out.println(bi.toString(16));
+        System.out.println(new BigInteger(bi.toString(16), 16));
+
+        JSONArray jsonArray = new JSONArray();
+        jsonArray.add(bi);
+        System.out.println(jsonArray.toString());
     }
 }

+ 2 - 71
src/test/java/com/izouma/nineth/service/AssetServiceTest.java

@@ -3,14 +3,11 @@ package com.izouma.nineth.service;
 import com.izouma.nineth.ApplicationTests;
 import com.izouma.nineth.TokenHistory;
 import com.izouma.nineth.domain.*;
-import com.izouma.nineth.dto.NFT;
-import com.izouma.nineth.dto.NFTAccount;
 import com.izouma.nineth.repo.*;
 import org.apache.commons.lang3.StringUtils;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 
-import java.util.Arrays;
 import java.util.List;
 
 class AssetServiceTest extends ApplicationTests {
@@ -67,7 +64,7 @@ class AssetServiceTest extends ApplicationTests {
     @Test
     public void mint() {
         Asset asset = assetRepo.findById(4622L).get();
-        assetMintService.mint(asset, 1L);
+        assetMintService.mint(asset);
     }
 
     @Test
@@ -86,78 +83,12 @@ class AssetServiceTest extends ApplicationTests {
         }
     }
 
-    @Test
-    public void fixHash() throws Exception {
-        for (Asset asset : assetRepo.findByTxHash("1")) {
-            User user = userRepo.findById(asset.getUserId()).get();
-            if (StringUtils.isEmpty(user.getPublicKey())) {
-                NFTAccount account = nftService.createAccount(user.getUsername() + "_");
-                user.setNftAccount(account.getAccountId());
-                user.setKmsId(account.getAccountKmsId());
-                user.setPublicKey(account.getPublicKey());
-                userRepo.save(user);
-            }
-            NFT nft = nftService.createToken(user.getNftAccount());
-            if (nft != null) {
-                asset.setTokenId(nft.getTokenId());
-                asset.setBlockNumber(nft.getBlockNumber());
-                asset.setTxHash(nft.getTxHash());
-                asset.setGasUsed(nft.getGasUsed());
-                assetRepo.save(asset);
-
-                List<TokenHistory> list = tokenHistoryRepo.findByTokenIdOrderByCreatedAtDesc(asset.getTokenId());
-                for (TokenHistory tokenHistory : list) {
-                    tokenHistory.setTokenId(asset.getTokenId());
-                }
-                tokenHistoryRepo.saveAll(list);
-            }
-        }
-    }
-
-    @Test
-    public void fixHash1() throws Exception {
-        List<Long> ids = Arrays.asList(27206L, 27216L, 27242L, 27271L, 27276L, 27280L, 27292L, 27294L, 43485L);
-        for (Asset asset : assetRepo.findByIdIn(ids)) {
-            User user = userRepo.findById(asset.getUserId()).get();
-            if (StringUtils.isEmpty(user.getPublicKey())) {
-                NFTAccount account = nftService.createAccount(user.getUsername() + "_");
-                user.setNftAccount(account.getAccountId());
-                user.setKmsId(account.getAccountKmsId());
-                user.setPublicKey(account.getPublicKey());
-                userRepo.save(user);
-            }
-            NFT nft = nftService.createToken(user.getNftAccount());
-            if (nft != null) {
-                asset.setTokenId(nft.getTokenId());
-                asset.setBlockNumber(nft.getBlockNumber());
-                asset.setTxHash(nft.getTxHash());
-                asset.setGasUsed(nft.getGasUsed());
-                assetRepo.save(asset);
-
-                TokenHistory tokenHistory = tokenHistoryRepo.save(TokenHistory.builder()
-                        .tokenId(asset.getTokenId())
-                        .fromUser(asset.getMinter())
-                        .fromUserId(asset.getMinterId())
-                        .fromAvatar(asset.getMinterAvatar())
-                        .toUser(user.getNickname())
-                        .toUserId(user.getId())
-                        .toAvatar(user.getAvatar())
-                        .operation("出售")
-                        .price(asset.getPrice())
-                        .tokenId(asset.getTokenId())
-                        .build());
-                tokenHistory.setCreatedAt(asset.getCreatedAt());
-                tokenHistoryRepo.save(tokenHistory);
-            }
-        }
-    }
-
     @Test
     public void fixNoHistory() {
         List<Asset> assets = assetRepo.findByNoHistory();
 
         for (Asset asset : assets) {
-            if (StringUtils.isNotBlank(asset.getTokenId())){
+            if (StringUtils.isNotBlank(asset.getTokenId())) {
                 User user = userRepo.findById(asset.getUserId()).get();
                 TokenHistory tokenHistory = tokenHistoryRepo.save(TokenHistory.builder()
                         .tokenId(asset.getTokenId())

+ 159 - 3
src/test/java/com/izouma/nineth/service/NFTServiceTest.java

@@ -1,16 +1,43 @@
 package com.izouma.nineth.service;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alipay.mychain.sdk.api.utils.Utils;
+import com.alipay.mychain.sdk.domain.transaction.LogEntry;
+import com.antfinancial.mychain.baas.tool.restclient.RestClient;
+import com.antfinancial.mychain.baas.tool.restclient.RestClientProperties;
+import com.antfinancial.mychain.baas.tool.restclient.model.CallRestBizParam;
+import com.antfinancial.mychain.baas.tool.restclient.model.Method;
+import com.antfinancial.mychain.baas.tool.restclient.model.ReceiptDecoration;
+import com.antfinancial.mychain.baas.tool.restclient.response.BaseResp;
 import com.izouma.nineth.ApplicationTests;
+import com.izouma.nineth.config.GeneralProperties;
+import com.izouma.nineth.dto.NFT;
+import com.izouma.nineth.utils.HashUtils;
+import com.izouma.nineth.utils.SnowflakeIdWorker;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.binary.Hex;
 import org.apache.commons.lang3.RandomStringUtils;
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 
 import java.io.File;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.util.Random;
 import java.util.Scanner;
+import java.util.concurrent.ThreadLocalRandom;
 
+@Slf4j
 public class NFTServiceTest extends ApplicationTests {
     @Autowired
-    private NFTService nftService;
+    private NFTService           nftService;
+    @Autowired
+    private RestClient           restClient;
+    @Autowired
+    private RestClientProperties restClientProperties;
+    @Autowired
+    private GeneralProperties    generalProperties;
 
     @Test
     public void createAccount() {
@@ -19,8 +46,51 @@ public class NFTServiceTest extends ApplicationTests {
 
     @Test
     public void createToken() throws Exception {
-        for (int i = 0; i < 10; i++) {
-            nftService.createToken("raex_official");
+        JSONArray jsonArray = new JSONArray();
+        jsonArray.add(Utils.getIdentityByName("raex_official"));
+        Random random = ThreadLocalRandom.current();
+        byte[] r = new byte[32]; //Means 2048 bit
+        random.nextBytes(r);
+        MessageDigest m = MessageDigest.getInstance("MD5");
+        m.update(r, 0, r.length);
+        BigInteger bi = new BigInteger(1, m.digest());
+        jsonArray.add(bi.toString());
+        log.info("data {}", jsonArray.toJSONString());
+        CallRestBizParam callRestBizParam = CallRestBizParam.builder()
+                .orderId(String.valueOf(new SnowflakeIdWorker(0, 0).nextId()))
+                .bizid(restClientProperties.getBizid())
+                .account(restClientProperties.getAccount())
+                .contractName("raex12")
+                .methodSignature("mint(identity,uint256)")
+                .inputParamListStr(jsonArray.toJSONString())
+                .outTypes("[]")//合约返回值类型
+                .mykmsKeyId(restClientProperties.getKmsId())
+                .method(Method.CALLCONTRACTBIZASYNC)
+                .tenantid(restClientProperties.getTenantid())
+                .gas(500000L)
+                .build();
+        BaseResp resp = restClient.bizChainCallWithReceipt(callRestBizParam);
+        if (!resp.isSuccess()) {
+            log.info("EVM合约执行失败: " + resp.getCode() + ", " + resp.getData());
+        }
+        if ("200".equals(resp.getCode())) {
+            log.info("EVM合约执行成功");
+            // 合约调用交易回执内容
+            ReceiptDecoration txReceipt = JSON.parseObject(resp.getData(), ReceiptDecoration.class);
+            BigInteger gasUsed = txReceipt.getGasUsed();
+            long result = txReceipt.getResult();
+            log.info("EVM合约交易内容: 哈希 " + txReceipt.getHash() + ", 消耗燃料 " + gasUsed + ", 结果 " + result);
+            for (LogEntry logEntry : txReceipt.getLogs()) {
+                if (logEntry.getTopics().get(0).equals(HashUtils.Keccak256("Transfer(identity,identity,uint256)"))) {
+                    String tokenId = logEntry.getTopics().get(3);
+                    txReceipt.getBlockNumber();
+                    NFT nft = new NFT(txReceipt.getHash(), tokenId, txReceipt.getBlockNumber(), txReceipt.getGasUsed());
+                    log.info("NFT生成成功 {}", nft);
+                }
+            }
+        } else {
+            // 异步交易未成功需要根据状态码判断交易状态
+            log.error("EVM合约执行未成功: " + resp.getCode());
         }
     }
 
@@ -70,4 +140,90 @@ public class NFTServiceTest extends ApplicationTests {
 
         nftService.deployContract("nine_space_test" + System.currentTimeMillis(), lines[idx + 2]);
     }
+
+    @Test
+    public void ownerof() throws Exception {
+        CallRestBizParam callRestBizParam = CallRestBizParam.builder()
+                .orderId(String.valueOf(new SnowflakeIdWorker(0, 0).nextId()))
+                .bizid(restClientProperties.getBizid())
+                .account(restClientProperties.getAccount())
+                .contractName("raex12")
+                .methodSignature("ownerOf(uint256)")
+                .inputParamListStr("[\"95057808871064671354760012409081314299\"]")
+                .outTypes("[identity]")//合约返回值类型
+                .mykmsKeyId(restClientProperties.getKmsId())
+                .method(Method.CALLCONTRACTBIZASYNC)
+                .tenantid(restClientProperties.getTenantid())
+                .gas(500000L)
+                .build();
+        BaseResp resp = restClient.bizChainCallWithReceipt(callRestBizParam);
+        if (!resp.isSuccess()) {
+            log.info("EVM合约执行失败: " + resp.getCode() + ", " + resp.getData());
+        }
+        if ("200".equals(resp.getCode())) {
+            log.info("EVM合约执行成功");
+            // 合约调用交易回执内容
+            ReceiptDecoration txReceipt = JSON.parseObject(resp.getData(), ReceiptDecoration.class);
+            BigInteger gasUsed = txReceipt.getGasUsed();
+            long result = txReceipt.getResult();
+            log.info("EVM合约交易内容: 哈希 " + txReceipt.getHash() + ", 消耗燃料 " + gasUsed + ", 结果 " + result);
+            log.info("owner:{}", Hex.encodeHexString(txReceipt.getOutput()));
+            for (LogEntry logEntry : txReceipt.getLogs()) {
+                if (logEntry.getTopics().get(0).equals(HashUtils.Keccak256("Transfer(identity,identity,uint256)"))) {
+                    String tokenId = logEntry.getTopics().get(3);
+                    txReceipt.getBlockNumber();
+                    NFT nft = new NFT(txReceipt.getHash(), tokenId, txReceipt.getBlockNumber(), txReceipt.getGasUsed());
+                    log.info("NFT生成成功 {}", nft);
+                }
+            }
+        } else {
+            // 异步交易未成功需要根据状态码判断交易状态
+            log.error("EVM合约执行未成功: " + resp.getCode());
+        }
+    }
+
+    @Test
+    public void transfer() throws Exception {
+        JSONArray jsonArray = new JSONArray();
+        jsonArray.add(Utils.getIdentityByName("raex_official"));
+        jsonArray.add(Utils.getIdentityByName("9th_HCWWflAZ_"));
+        jsonArray.add("95057808871064671354760012409081314299");
+        CallRestBizParam callRestBizParam = CallRestBizParam.builder()
+                .orderId(String.valueOf(new SnowflakeIdWorker(0, 0).nextId()))
+                .bizid(restClientProperties.getBizid())
+                .account(restClientProperties.getAccount())
+                .contractName("raex12")
+                .methodSignature("ownerTransfer(identity,identity,uint256)")
+                .inputParamListStr(jsonArray.toJSONString())
+                .outTypes("[]")//合约返回值类型
+                .mykmsKeyId(restClientProperties.getKmsId())
+                .method(Method.CALLCONTRACTBIZASYNC)
+                .tenantid(restClientProperties.getTenantid())
+                .gas(500000L)
+                .build();
+        BaseResp resp = restClient.bizChainCallWithReceipt(callRestBizParam);
+        if (!resp.isSuccess()) {
+            log.info("EVM合约执行失败: " + resp.getCode() + ", " + resp.getData());
+        }
+        if ("200".equals(resp.getCode())) {
+            log.info("EVM合约执行成功");
+            // 合约调用交易回执内容
+            ReceiptDecoration txReceipt = JSON.parseObject(resp.getData(), ReceiptDecoration.class);
+            BigInteger gasUsed = txReceipt.getGasUsed();
+            long result = txReceipt.getResult();
+            log.info("EVM合约交易内容: 哈希 " + txReceipt.getHash() + ", 消耗燃料 " + gasUsed + ", 结果 " + result);
+            log.info("owner:{}", Hex.encodeHexString(txReceipt.getOutput()));
+            for (LogEntry logEntry : txReceipt.getLogs()) {
+                if (logEntry.getTopics().get(0).equals(HashUtils.Keccak256("Transfer(identity,identity,uint256)"))) {
+                    String tokenId = logEntry.getTopics().get(3);
+                    txReceipt.getBlockNumber();
+                    NFT nft = new NFT(txReceipt.getHash(), tokenId, txReceipt.getBlockNumber(), txReceipt.getGasUsed());
+                    log.info("NFT生成成功 {}", nft);
+                }
+            }
+        } else {
+            // 异步交易未成功需要根据状态码判断交易状态
+            log.error("EVM合约执行未成功: " + resp.getCode());
+        }
+    }
 }

+ 1 - 26
src/test/java/com/izouma/nineth/service/OrderServiceTest.java

@@ -5,8 +5,8 @@ import com.huifu.adapay.core.exception.BaseAdaPayException;
 import com.huifu.adapay.model.Payment;
 import com.izouma.nineth.ApplicationTests;
 import com.izouma.nineth.TokenHistory;
-import com.izouma.nineth.domain.*;
 import com.izouma.nineth.domain.Collection;
+import com.izouma.nineth.domain.*;
 import com.izouma.nineth.dto.UserBankCard;
 import com.izouma.nineth.enums.AssetStatus;
 import com.izouma.nineth.enums.AuthStatus;
@@ -23,7 +23,6 @@ import org.springframework.beans.factory.annotation.Autowired;
 import java.io.IOException;
 import java.time.LocalDateTime;
 import java.util.*;
-import java.util.concurrent.Future;
 import java.util.stream.Collectors;
 
 @Slf4j
@@ -177,30 +176,6 @@ public class OrderServiceTest extends ApplicationTests {
         }
     }
 
-    @Test
-    public void mint() {
-        for (Order order : orderRepo.findByStatus(OrderStatus.PROCESSING)) {
-            if (order.getPayTime().isBefore(LocalDateTime.of(2021, 12, 18, 15, 8))) {
-                try {
-                    Collection collection = collectionRepo.findById(order.getCollectionId())
-                            .orElseThrow(new BusinessException("无记录"));
-                    User user = userRepo.findById(order.getUserId()).orElseThrow(new BusinessException("无记录"));
-                    Future<Asset> f = assetService.createAsset(collection, user, order.getId(), order.getPrice(), "出售",
-                            collectionService.getNextNumber(order.getCollectionId()));
-                    while (true) {
-                        if (f.isDone()) {
-                            break;
-                        }
-                        Thread.sleep(300);
-                    }
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
-            }
-
-        }
-    }
-
     @Test
     public void removeDuplicate() {
         List<Long> ids = new ArrayList<>();

+ 28 - 0
src/test/java/com/izouma/nineth/service/UserServiceTest.java

@@ -74,4 +74,32 @@ public class UserServiceTest extends ApplicationTests {
                     .build());
         }
     }
+
+    @Test
+    public void batchRegister() {
+        userService.batchRegister("13226246698\n" +
+                "13793310531\n" +
+                "13358006613\n" +
+                "18898406893\n" +
+                "17615876370\n" +
+                "13267002685\n" +
+                "15888548080\n" +
+                "13678662069\n" +
+                "15659009359\n" +
+                "13011776866\n" +
+                "18810668532\n" +
+                "13543322894\n" +
+                "13589360750\n" +
+                "18582589484\n" +
+                "15194185209\n" +
+                "15063692500\n" +
+                "13605489618\n" +
+                "18069783568\n" +
+                "15801815684\n" +
+                "13285413859\n" +
+                "13688419164\n" +
+                "15979115671\n" +
+                "13799940755\n" +
+                "18301015323", "123456");
+    }
 }