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.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.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Retryable; import org.springframework.stereotype.Service; import java.math.BigInteger; @Service @Slf4j @AllArgsConstructor public class NFTService { private final RestClient restClient; private final RestClientProperties restClientProperties; private final GeneralProperties generalProperties; public NFTAccount createAccount(String username) { CallRestBizParam callRestBizParam = CallRestBizParam.builder() .orderId(String.valueOf(new SnowflakeIdWorker(0, 0).nextId())) .bizid(Constants.bizId) .account(restClientProperties.getAccount()) .mykmsKeyId(restClientProperties.getKmsId()) .newAccountId(username) .newAccountKmsId(Constants.kmsKey) .method(Method.TENANTCREATEACCUNT) .gas(100000L).build(); try { BaseResp baseResp = restClient.chainCallForBiz(callRestBizParam); NFTAccount account = new NFTAccount(username, Constants.kmsKey, baseResp.getData()); if (baseResp.isSuccess()) { log.info("创建账户成功 {}", account); return account; } else { throw new RuntimeException(baseResp.getCode()); } } catch (Exception e) { e.printStackTrace(); log.error("创建账户失败", e); throw new BusinessException("创建账户失败"); } } @Retryable(maxAttempts = 100, backoff = @Backoff(delay = 5000), value = BusinessException.class) public synchronized NFT createToken(String toAccount) throws Exception { JSONArray jsonArray = new JSONArray(); jsonArray.add(Utils.getIdentityByName(toAccount)); CallRestBizParam callRestBizParam = CallRestBizParam.builder() .orderId(String.valueOf(new SnowflakeIdWorker(0, 0).nextId())) .bizid(restClientProperties.getBizid()) .account(restClientProperties.getAccount()) .contractName(generalProperties.getContractName()) .methodSignature("mint(identity)") .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); return nft; } } } else { // 异步交易未成功需要根据状态码判断交易状态 log.error("EVM合约执行未成功: " + resp.getCode()); } throw new BusinessException("创建nft失败"); } 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)); 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)") .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 transferTokenId = logEntry.getTopics().get(3); txReceipt.getBlockNumber(); NFT nft = new NFT(txReceipt.getHash(), tokenId, txReceipt.getBlockNumber(), txReceipt.getGasUsed()); log.info("NFT转移成功 {}", nft); return nft; } } } else { // 异步交易未成功需要根据状态码判断交易状态 log.error("EVM合约执行未成功: " + resp.getCode()); } throw new BusinessException("创建nft失败"); } public NFT setApprovalForAll(String account) throws Exception { JSONArray jsonArray = new JSONArray(); jsonArray.add(Utils.getIdentityByName(account)); jsonArray.add(true); CallRestBizParam callRestBizParam = CallRestBizParam.builder() .orderId(String.valueOf(new SnowflakeIdWorker(0, 0).nextId())) .bizid(restClientProperties.getBizid()) .account(restClientProperties.getAccount()) .contractName(generalProperties.getContractName()) .methodSignature("setApprovalForAll(identity,bool)") .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); } else { // 异步交易未成功需要根据状态码判断交易状态 log.error("EVM合约执行未成功: " + resp.getCode()); } throw new BusinessException("创建nft失败"); } public void deployContract(String name, String code) throws Exception { String orderId = "order_" + System.currentTimeMillis(); CallRestBizParam callRestBizParam = CallRestBizParam.builder() .orderId(orderId) .bizid(restClientProperties.getBizid()) .account(restClientProperties.getAccount()) .contractName(name) .contractCode(code) .mykmsKeyId(restClientProperties.getKmsId()) .method(Method.DEPLOYCONTRACTFORBIZ) .tenantid(restClientProperties.getTenantid()) .gas(1000000L).build(); BaseResp resp = restClient.chainCallForBiz(callRestBizParam); if (!resp.isSuccess()) { log.info("EVM合约执行失败: " + resp.getCode() + ", " + resp.getData()); } 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); } }