[klaytn][caver-java] 4. 수수료대납 Klay Transfer

Woody Kim
Day34 Inc.
Published in
11 min readJul 25, 2019

안녕하세요. 저는 (주)34일의 주니어 개발자 우디(Woody)라고 합니다. 이번 주제는 클레이튼에서 caver-java를 이용해 Klay Transfer를 수수료를 대납해주는 것에 대해 이야기하도록 하겠습니다.

EOA에서 EOA로의 수수료 대납 klay transfer

FeePayerManager를 이용하여 수수료 대납 Klay Transfer를 하기 위해서는 다음의 과정이 필요합니다.

  1. ValueTransferTransaction 객체 생성
  2. TransactionManager를 이용하여 ValueTransferTransaction을 Sender의 개인키로 사인하여 FeeDelegatedValueTransferTransaction생성(두번째 인자 true)
  3. FeePayerManager을 이용하여 FeeDelegatedValueTransferTransaction을 실행

이를 코드로 표현하면 다음과 같습니다.

TransactionManager transactionManager 
= new TransactionManager.Builder(caver, sender)
.setChaindId(ChainId.BAOBAB_TESTNET)
.build();
ValueTransferTransaction valueTransferTransaction
= ValueTransferTransaction.create(
<fromAddress>,
<toAddress>,
<amount>,
<gasLimit>);
String senderRawTransaction
= transactionManager
.sign(valueTransferTransaction, true)
.getValueAsString();
KlayCredentials feePayer
= KlayCredentials.create(<feePayer private key>);
FeePayerManager feePayerManager
= new FeePayerManager.Builder(caver, feePayer)
.setChaindId(ChainId.BAOBAB_TESTNET)
.build();
feePayerManager.executeTransaction(senderRawTransaction);

ValueTransferTransaction 객체 생성에 필요한 인자는 (1)fromAddress, (2)toAddress, (3)amount, (4)gasLimit 입니다. (1)fromAddress는 klay를 전송하는 sender의 주소이이며, (2)toAddress는 klay를 받는 recipient의 주소입니다. (3)amount는 BigInteger 타입이며, peb단위(이더리움의 wei단위)를 인자로 받습니다.

생성된 ValueTransferTransaction 객체는, TransacitonManager를 이용하여 sender의 개인키로 서명해야 합니다. 그리고, 두번째 인자를 true로 설정해야 수수료 대납을 할 수 있는 FeeDelegatedValueTransferTransaction 객체를 만들 수 있으며 getValueAsString()을 이용하여 String타입으로 만들어 줍니다.

마지막으로 FeePayerManager를 이용하여, String타입으로 만들어진FeeDelegatedValueTransferTransaction FeePayer의 개인키로 서명 후 클레이튼 네트워크로 트랜잭션을 실행하면 모든 과정이 끝이 납니다.

Example :

다음은 제가 작성한 테스트 코드입니다. sender가 recipient에게 1Klay(1000000000000000000Peb)를 전송하고, 해당 트랜잭션의 수수료를 feePayer가 대납하도록 하였으며, 트랜잭션해쉬를 출력하여 클레이튼 scope에서 트랜잭션을 확인하였습니다.

Test code : FeeDelegatedValueTransfer From EOA To EOA

저는 수수료 대납에 대한 Klay전송을 조금 더 시각적으로 보여드리기 위해, transactionHash뿐만 아니라, 트랜잭션 실행 전과 후의 sender, recipient, feePayer의 Klay에 대한 balance를 같이 출력하였습니다.

output: transactionHash

위의 사진에서 확인할 수 있듯이, sender의 balance는 1Klay만큼 줄었고, recipient의 balance는 1Klay만큼 늘었음을 알 수 있습니다. 또한, feePayer의 balance를 확인하면 트랜잭션에 필요한 0.000775만큼의 수수료를 지불하였음을 알 수 있습니다.

Klaytn Scope result

위의 사진은 해당 트랜잭션의 트랜잭션해쉬값을 클레이튼 스코프에 검색한 결과이며, Fee Delegated Value Transfer 타입으로 성공적으로 트랙잰션이 실행되었음을 알 수 있습니다.

EOA에서 CA로의 수수료 대납 klay transfer

EOA뿐만 아니라, 폴백 함수(fallback function)를 가지고 있는 CA(Contract Account)에게도 Klay를 전송할 수 있습니다.

폴백 함수는 이름 없는 함수이며, 인자와 반환값이 없는 함수입니다. 스마트 컨트랙트는 하나의 폴백함수를 가질 수 있습니다. 폴백함수는 트랜잭션이 Klay(이더리움의 ether 개념)를 전송하지만, 메소드를 호출하지 않은 경우에 호출되는 함수로, 스마트 컨트랙트가 fallback함수를 포함하지 않으면, 예외가 발생해 Klay를 보낸 계정으로 다시 돌려보냅니다.

불행히도, 기존에 설명한 Klay Transfer 방식으로는 CA로의 Klay를 전송할 수 없습니다. CA로의 Klay 전송을 하기 위해선, ValueTransferTransaction 객체가 아니라 SmartContractExecutionTransaction 객체를 이용하여야 합니다.

수수료를 대납하며 EOA에서 CA로의 Klay transfer하는 방법은 다음과 같습니다.

SmartContractExecutionTransaction contractExecutionTransaction  
= SmartContractExecutionTransaction.create(
<fromAddress>, // EOA 계정
<toAddress>, // CA 계정
<amount>, // pebValue
Numeric.hexStringToByteArray(""), // payload
new DefaultGasProvider().getGasLimit() // gasLimit
);

TransactionManager transactionManager
= new TransactionManager.Builder( caver, sender )
.setChaindId(ChainId.BAOBAB_TESTNET)
.build();
String senderRawTransaction
= transactionManager
.sign(contractExecutionTransaction, true)
.getValueAsString();


KlayCredentials feePayer
= KlayCredentials.create(FEEPAYER_PRIVATE_KEY);
FeePayerManager feePayerManager
= new FeePayerManager.Builder( caver, feePayer)
.setChainId(ChainId.BAOBAB_TESTNET).build();
feePayerManager.executeTransaction(senderRawTransaction);

SmartcontractExcutionTransaction 객체를 생성할 때의 인자로는 (1)fromAddress, (2)toAddress, (3)amount, (4)payload, (5)gasLimit을 필요로 합니다.

(1)fromAddress는 Klay를 보내는 EOA의 주소이며, (2)toAddress는 Klay를 받는 CA 주소입니다. 이때, CA는 폴백함수를 포함하고 있어야 Klay를 받을 수 있습니다. (3)amount는 BigInteger타입으로 Peb단위(이더리움의 wei단위)를 인자로 받습니다. (4)payload는 toAddress에게 보내는 바이너리 데이터입니다. toAddress가 코드를 포함하고 있으면 코드는 실행되고 payload는 입력 데이터로 제공됩니다. payload에 대해서 수수료 대납 컨트랙트 실행에 대해서 자세히 살펴보도록 하겠습니다. 이번 과정에서는 위의 코드와 같이 입력하시면 됩니다. (5)gasLimit은 해당 트랜잭션이 수행에 소비될 총 가스량에 대한 추정치로, gasLimit을 넘어선 수수료가 발생하면 해당 트랜잭션은 revert됩니다.

Example :

예제를 보여드리기 위해, 다음과 같이 fallback함수와 Klay를 전송할 수 있는 함수를 포함한 정말 간단한 스마트 컨트랙트를 만들었습니다. 컨트랙트를 배포하여, EOA에서 해당 컨트랙트로 Klay를 전송하도록 하겠습니다.

solidity code : ExampleCA

다음 사진은 EOA에서 CA로 1Klay(1000000000000000000Peb)을 전송하는 테스트 코드입니다. 보시는 거와 같이 EOA에서 EOA로의 Klay Transfer와 차이점은 ValueTransferTransaction객체 대신 SmartcontractExcutionTransaction 객체를 사용했다는 점 입니다.

Test code : FeeDelegatedValueTransfer From EOA To CA

저는 결과를 조금 더 시각적으로 보여드리기 위해, sender, recipient, feePayer의 balance를 같이 출력하였습니다.

output : transactionHash

위의 출력된 결과를 살펴보면 sender(EOA)의 balance가 1Klay만큼 줄었고, recipient(CA)의 balance가 1Klay만큼 증가하였음을 알 수있으며, feePayer의 balance는 0.000776 Klay 수수료만큼 줄었음을 알 수 있습니다.

Klaytn Scope result

위의 사진은 해당 트랜잭션의 트랜잭션해쉬를 클레이튼 스코프에 검색한 결과이며, Fee Delegated Smart Contract Execution 타입으로 성공적으로 트랙잰셕이 실행되었음을 알 수 있습니다.

다음 시간에는 수수료 대납으로 스마트 컨트랙트를 배포하는 방법과 실행하는 방법에 대해 알아보겠습니다.

혹시 잘못된 부분이 있으면, 언제든지 말씀해주세요. 선배 개발자로서 조언도 감사하겠습니다 :)

[참고] https://docs.klaytn.com/sdk/caverjava/getting_started

--

--