본문 바로가기
블록체인 backEnd/web3j

transaction 모듈화

by gun_poo 2023. 3. 15.

rawTransaction을 하나 하나 만들어서 쓰려니까 너무 비효율적이라 느껴 모듈화를 해보았다.

 

rawTransaction, EIP-1559를 사용한 방법이고 txHash를 반환한다.

현재 쓰고있는 로직은 하나의 트랜잭션이 성공하면 다음 트랜잭션으로 넘어가는 형식이기 때문에 이렇게 작성하였다.

package com.example.demo.controller.test.moduel;

import org.web3j.crypto.Credentials;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.request.Transaction;
import org.web3j.protocol.core.methods.response.EthEstimateGas;
import org.web3j.protocol.core.methods.response.EthGetTransactionCount;
import org.web3j.protocol.core.methods.response.EthGetTransactionReceipt;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.utils.Numeric;

import java.math.BigInteger;

import static com.example.demo.controller.TransactionController.credentials;
import static com.example.demo.controller.TransactionController.getBaseFeePerGas;

public class TransactionModule {

    public class TransactionResult {
        private String transactionHash;
        private EthGetTransactionReceipt transactionReceipt;

        public TransactionResult(String transactionHash) {
            this.transactionHash = transactionHash;
        }

        public String getTransactionHash() {
            return transactionHash;
        }

    }

    public static BigInteger checkNonce(Web3j web3j, String address) throws Exception {
        EthGetTransactionCount ethGetTransactionCount = web3j.ethGetTransactionCount(
                address, DefaultBlockParameterName.LATEST).sendAsync().get();
        BigInteger nonce = ethGetTransactionCount.getTransactionCount();
        System.out.println("nonce" + nonce);
        return nonce;
    };

    public static Credentials credentials(String privateKey) throws Exception {
        Credentials credentials = Credentials.create(privateKey);
        return credentials;
    };
    public TransactionResult TransactionModules(
            Web3j web3j,
            String from,
            BigInteger nonce,
            String to,
            String encodedFunction,
            long chainId,
            BigInteger value,
            String fromPrivate
    ) throws Exception {
        BigInteger baseFee = getBaseFeePerGas(web3j);
        BigInteger maxPriorityFee = BigInteger.valueOf(2).multiply(BigInteger.valueOf(1000000000));
        BigInteger maxPee = (baseFee.add(maxPriorityFee)).multiply(BigInteger.valueOf(2));

        Transaction transaction = Transaction.createFunctionCallTransaction(
                from,
                nonce,
                null,
                null,
                to,
                value,
                encodedFunction
        );
        EthEstimateGas ethEstimateGas = web3j.ethEstimateGas(transaction).send();
        BigInteger gasLimited = ethEstimateGas.getAmountUsed();

        RawTransaction Tx = RawTransaction.createTransaction(
                chainId,
                nonce,
                gasLimited,
                to,
                value,
                encodedFunction,
                maxPriorityFee,
                maxPee
        );
        byte[] mintSignedMessage = TransactionEncoder.signMessage(Tx, chainId, credentials(fromPrivate));
        String mintHexValue = Numeric.toHexString(mintSignedMessage);
        System.out.println("hexValue" + mintHexValue);
        EthSendTransaction ethSendTransaction = web3j.ethSendRawTransaction(mintHexValue).send();
        String transactionHash = ethSendTransaction.getTransactionHash();
        System.out.println("Tx hash : " + transactionHash);
        return new TransactionResult(transactionHash);
    }
}

 

이렇게 만든 함수를 사용해 실제 트랜잭션을 처리해보자.

아래 예시는 nft 민트와 setForSale이라는 컨트랙트 함수이다.

 

@Controller
public class moduelTest {

    @GetMapping("mintTransactionTest")
    public String mintTransactionTest () throws Exception {
        Web3j sepolia = Web3j.build(new HttpService("myUrlEndPoint"));
        long seploiaChainId = 11155111;
        String contractAddress = "contractAddress";
        String from = "from";
        String fromPrivate = "fromPrivate";
        String url = "1";
        BigInteger baseFee = getBaseFeePerGas(sepolia);
        BigInteger maxPriorityFeeHardCode = BigInteger.valueOf(2).multiply(BigInteger.valueOf(1000000000));
        BigInteger maxPee = (baseFee.add(maxPriorityFeeHardCode)).multiply(BigInteger.valueOf(2));

        Function mintFunction = new Function("mint",
                Arrays.asList(new Utf8String(url))
                , Collections.emptyList()
        );
        String mintEncodedFuntion = FunctionEncoder.encode(mintFunction);

        TransactionModule transactionModule = new TransactionModule();
        TransactionModule.TransactionResult receipt = transactionModule.TransactionModules(
                sepolia,
                from,
                checkNonce(sepolia, from),
                contractAddress,
                mintEncodedFuntion,
                seploiaChainId,
                BigInteger.ZERO,
                fromPrivate
                );
        System.out.println("transactionHash : " + receipt.getTransactionHash());
        while (true) {
            EthGetTransactionReceipt mintTransactionReceipt = sepolia
                    .ethGetTransactionReceipt(receipt.getTransactionHash())
                    .send();
            if (mintTransactionReceipt.getResult() != null) {
                JSONObject receipted = JSONObject.fromObject(mintTransactionReceipt);
                System.out.println("receipted : " +receipted);
                JSONObject receiptResult = JSONObject.fromObject(receipted.getJSONObject("result"));
                System.out.println("receiptResult : " +receiptResult);
                JSONObject receiptLogs = (JSONObject) JSONObject.fromObject(receiptResult).getJSONArray("logs").get(0);
                String tokenId = String.valueOf(Long.decode(receiptLogs.getJSONArray("topics").get(3).toString()));
                ///// set sale ////
                String nftPrice = "0.1";
                BigInteger toWeiPrice = Convert.toWei(nftPrice, Convert.Unit.ETHER).toBigInteger();

                Function setSaleFuction = new Function("setForSale",
                        Arrays.asList(new Uint256(Long.parseLong(tokenId)),
                                new Uint256(toWeiPrice)), Collections.emptyList());

                String setSaleFuntcionEncode = FunctionEncoder.encode(setSaleFuction);

                TransactionModule saleTransactionModule = new TransactionModule();
                TransactionModule.TransactionResult saleReceipt = saleTransactionModule.TransactionModules(
//            EthGetTransactionReceipt saleReceipt = TransactionModules(
                        sepolia,
                        from,
                        checkNonce(sepolia, from),
                        contractAddress,
                        setSaleFuntcionEncode,
                        seploiaChainId,
                        BigInteger.ZERO,
                        fromPrivate
                );
                while (true) {
                    EthGetTransactionReceipt saleTransactionReceipt = sepolia
                            .ethGetTransactionReceipt(saleReceipt.getTransactionHash())
                            .send();
                    if (saleTransactionReceipt.getResult() != null) {
                        JSONObject saleReceipted = JSONObject.fromObject(saleTransactionReceipt);
                        JSONObject saleReceiptResult = JSONObject.fromObject(saleReceipted.getJSONObject("result"));
                        System.out.println("saleReceiptResult" + saleReceiptResult);
                        break;
                      }
                    Thread.sleep(150000);
                }
                break;
            }
            Thread.sleep(150000);
        }
        return "redirect:/";
    }

}

정상적으로 작동하는 것을 확인했다!
많은 부분을 모듈화 할수는 없었다. 하나의 동작당 하나의 트랜잭션만 사용을 한다면 모든 부분을 처리해 하나의 함수로 처리할수 있었을것 같은데 하나의 동작에 여러 트랜잭션을 잡아 넣다 보니 이렇게 되었다.

 

방법이 없을까? 방법은 있다. 컨트랙트에서 하나의 동작에 필요한 여러 함수들을 하나의 함수로 만들어버리면 된다. 

'블록체인 backEnd > web3j' 카테고리의 다른 글

maxFeePerGas, maxPriorityFeePerGas 추정기  (0) 2023.03.18
가스에 대하여  (1) 2023.03.15
java web3j 컴파일 및 wrappers  (0) 2023.01.25
mac os web3j 설치하기  (0) 2023.01.25

댓글