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.ClientParam; 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.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; 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 = 10, backoff = @Backoff(delay = 5000), value = BusinessException.class) public 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(Constants.CONTRACT_NAME) .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失败"); } }