ERC6551 Contract 테스트를 하고 있는데 오류가 발생해서 문의드립니다

안녕하세요. ERC6551 테스트를 web3j로 진행하고 있었습니다.
ERC6551에 관련된 Contract 모두 Baobab테스트넷에 배포하였고
NFT transferFrom 기능을 executeCall을 통해서 소유권을 이전하려고 합니다.

@Test
public void testERC6551Test() throws Exception{
    HttpService httpService = new HttpService(caverKasNodeUrl);
    httpService.addHeader("Authorization", okhttp3.Credentials.basic(accessKey, secretAccessKey));
    httpService.addHeader("x-chain-id", kasChainId);

    // web3j 객체생성
    Web3j web3j = Web3j.build(httpService);

    // NFT 컨트랙트 주소 토큰 ID, 구현 주소 설정
    String nftAddress = "0xfc9160db4083b165c79ea72efd1b34cb742d5f0e";               // ERC721 Contract
    BigInteger tokenId = BigInteger.valueOf(0);
    String ERC6551RegistryAddress = "0x9ffba4e502e7334068fbdcc7507087cde0952ebc";    // ERC6551 Registry 주소
    String ERC6551AccountAddress = "0x5aaa85ce664526c259375472b5d3159aa43896c3";    // ERC6551Account 주소
    String receiverAddress = "0x980e41f0a74f1c3d749b8ec54d9e3de3279e1feb";          // 받는사람
    BigInteger tokenAmount = BigInteger.valueOf(1);                               // NFT 구매금액

    // ERC6551 Registry 컨트랙트의 account 함수를 호출하여 TokenBoundAccount 주소를 얻음
    Function accountFunction = new Function(
            "account",
            Arrays.asList(new Address(ERC6551AccountAddress), new Uint256(1001), new Address(nftAddress), new Uint256(tokenId), new Uint256(0)),
            Arrays.asList(new TypeReference<Address>() {})
    );
    log.info("======== accountFunction : {}", objectToString(accountFunction));

    String encodedAccountFunction = FunctionEncoder.encode(accountFunction);
    log.info("======== encodedAccountFunction : {}", objectToString(encodedAccountFunction));

    // to : ERC6551Registry 컨트랙트 주소
    EthCall ethCall = web3j.ethCall(
            Transaction.createEthCallTransaction(null, ERC6551RegistryAddress, encodedAccountFunction),
            DefaultBlockParameterName.LATEST
    ).send();
    log.info("======== ethCall : {}", objectToString(ethCall));

    String tokenBoundAccountAddress = (String) FunctionReturnDecoder.decode(
            ethCall.getValue(),
            accountFunction.getOutputParameters()
    ).get(0).getValue();
    log.info("======= tokenBoundAccountAddress (Token Owner) : {}", tokenBoundAccountAddress);
    // Account 조회 종료

    // TokenBoundAccount 주소를 사용하여 Contract 객체 생성
    Credentials credentials = Credentials.create("0x07f2066d045c19f72479cf3079a8161244bb3a9d0899a3487b6ec00c13596360"); // Token 0번 Owner (Baobab)
    TransactionManager transactionManager = new RawTransactionManager(web3j, credentials);
    ContractGasProvider gasProvider = new StaticGasProvider(BigInteger.valueOf(25_000_000_000L), BigInteger.valueOf(250_000_000_000L));

    ERC6551Account erc6551Account = ERC6551Account.load(
            ERC6551AccountAddress,
            web3j,
            transactionManager,
            gasProvider
    );

    // NFT Transfer 함수 인코딩
    Function function = new Function(
            "transferFrom",
            Arrays.asList(new Address(tokenBoundAccountAddress), new Address(receiverAddress), new Uint256(tokenId)),
            Collections.emptyList()
    );
//        byte[] encodedFunction = FunctionEncoder.encode(function);
    String encodedFunction = FunctionEncoder.encode(function);
    byte[] data = Numeric.hexStringToByteArray(encodedFunction);

    TransactionReceipt receipt = erc6551Account.executeCall(receiverAddress, tokenAmount, data, BigInteger.ZERO).send();
    log.info("============= receipt : {}", receipt);
}

jUnit으로 테스트를 해보았는데

org.web3j.protocol.exceptions.TransactionException: JsonRpcError thrown with code -32000. Message: insufficient funds of the sender for value 

	at org.web3j.tx.Contract.executeTransaction(Contract.java:424)
	at org.web3j.tx.Contract.executeTransaction(Contract.java:373)
	at org.web3j.tx.Contract.executeTransaction(Contract.java:367)
	at org.web3j.tx.Contract.lambda$executeRemoteCallTransaction$4(Contract.java:472)
	at org.web3j.protocol.core.RemoteCall.send(RemoteCall.java:42)

이렇게 오류가 발생했습니다

잔액부족이라고 발생했었는데 ERC6551RegistryAddress, tokenBoundAccountAddress, Token 0번 소유자 모두 Klay가 충분한 상태에서 발생했습니다

어떤 부분이 문제인지 모르겠네요…

안녕하세요.

코드상으로 보았을때는, gas provider 세팅이 잘못된 것으로 보입니다.

gasprice 는 올바르게 세팅하였으나, gaslimit이 과도하게 크게 세팅되어있습니다.

klaytn core에서는 tx를 실행하기에 앞서서, 해당 계정이 gasPrice * gasLimit 만큼의 klay를 가지고 있는지

우선 검증하는 단계를 거칩니다.

여기서는 credentials에 저장된 account가 되겠네요.

이에 따라 tx를 생성할 때 올바른 값을 넣어주는 것이 중요합니다.

일반적으로는 gasPrice는 getGasPrice로 가져온 값, 혹은 현재 네트워크의 gasPrice값의 2배 정도로 책정하고(tx가 반영되는 동안 gasPrice가 증가할 수 있기 때문에)

Gas의 경우, estimateGas를 이용해 해당 tx가 소모하는 대략적인 gas 예상값을 가져와 이보다 조금 더 큰 수를 넣어줍니다.

같은 코드로 테스트 해보았을때 적절한 gasPrice, gas 값을 넣어주면 정상적으로 동작함을 알 수 있습니다.

@Jay gasLimit가 과도하게 셋팅되면 오류가 발생하는군요…
web3j로 가스비를 가져오려면

HttpService httpService = new HttpService(caverKasNodeUrl);
httpService.addHeader("Authorization", okhttp3.Credentials.basic(accessKey, secretAccessKey));
httpService.addHeader("x-chain-id", kasChainId);

// web3j 객체생성
Web3j web3j = Web3j.build(httpService);
BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice();
BigInteger gasLimit = gasPrice.multiply(BigInteger.TWO);

이런식으로 구현하면 될까요?

동일하게 오류가 발생했고
gasPrice : 50000000000 / gasLimit : 100000000000
로 확인했습니다

@Jay

혹시 몰라서 제가 ERC6551 배포했을 때 in/out 값도 같이 올려드립니다
Klaytn Web Remix를 사용했습니다.

1. NFT 배포
    - Contract : 0xfc9160db4083b165c79ea72efd1b34cb742d5f0e
    - Tx : 0x5e30d7c2bd63b714c13d6d575ec0349d44dfb8be60371596abb3a2514aebba6b

2. Token Mint : TokenId(0)
    - Owner : 0xd0ebb148db719bf24a7033acdcffaf18bcb68b1d / Pk : 0x07f2066d045c19f72479cf3079a8161244bb3a9d0899a3487b6ec00c13596360

3. ERC6551Registry 배포
    - Contract : 0x9ffba4e502e7334068fbdcc7507087cde0952ebc
    - Tx : 0x3127bfc42854e2e889aafee811b586f08d5e0f25e8355484eae6660021f5bde6

4. ERC6551Account 배포
    - Contract : 0x5aaa85ce664526c259375472b5d3159aa43896c3
    - Tx : 0xbb80cf4896312343fe7f9106c79567da98b30bbb2ee8bf2dfbbf19d334a346d6

5. ERC6551Registry Account 함수 호출
    - implementation : 0x5aaA85Ce664526c259375472B5D3159aa43896C3 (ERC6551Account Contract)
    - chainID : 1001 (Baobab)
    - tokenContract : 0xFC9160db4083b165C79ea72efD1B34CB742D5f0E (ERC721 Contract)
    - tokenID : 0
    - salt : 0
    - 결과 Address : 0x9c195528E65a0107Aaa16143c33b1881Ff83f546

6. ERC6551Registry createAccount 함수 호출
    - implementation : 0x5aaA85Ce664526c259375472B5D3159aa43896C3 (ERC6551Account Contract)
    - chainID : 1001 (Baobab)
    - tokenContract : 0xFC9160db4083b165C79ea72efD1B34CB742D5f0E (ERC721 Contract)
    - tokenID : 0
    - salt : 0
    - initData : []
    - 결과 Tx : 0x2dedd70fd8c478a49b1bccead308bbefdb8769b2b3f16f0e423ea486fbbc2534 / Internal Transactions에 CREATE2에 5번 Address 확인OK

7. ERC6551Account executeCall
    - to : 0x980e41f0a74f1c3d749b8ec54d9e3de3279e1feb (테스트용 개인지갑)
    - value : 1000000000000000000
    - data : []
    - 결과 Tx : 0x324cb13c61602715fd52abce63ac8083b248ade403331cbc89462e0e095ef5aa