[Caver] Contract를 사용하여 수수료를 대납해보자

Tech at Klaytn
42 min readJun 11, 2021

--

전체 포스팅은 여기에서 확인하세요.

Caver v1.6.1부터 caver.contract에서 수수료 대납 모델을 지원합니다. 아래의 포스팅으로 Caver에서 Contract를 사용할 때 수수료 대납 모델을 적용하는 방법에 대해 설명해보겠습니다.

각 파트에서는 코드의 일부분을 설명하며, 전체 코드는 아래 링크에서 확인할 수 있습니다.

📢 주의
이 포스팅에서 제공하는 예제를 실행하려면 KLAY를 충분히 소유한 계정이 필요합니다.

1. in-memory wallet에 테스트 계정 추가하기

caver.contract로 스마트 컨트랙트를 배포하고 실행하려면 KLAY를 소유한 계정을 in-memory wallet인 caver.wallet에 추가해야 합니다. 그러려면 트랜잭션을 전송하는 deployer와 트랜잭션 수수료를 대납할 feePayer 계정이 필요합니다.

먼저 caver-js를 사용하여 caver.wallet에 추가하는 방법입니다.

// Create keyrings and add to the in-memory wallet - caver-js
const deployerAddress = '0x{address}'
const deployerPrivateKey = '0x{private key}'
const feePayerAddress = '0x{address}'
const feePayerPrivateKey = '0x{private key}'

const deployerKeyring = caver.wallet.keyring.create(deployerAddress, deployerPrivateKey)
caver.wallet.add(deployerKeyring)
const feePayerKeyring = caver.wallet.keyring.create(feePayerAddress, feePayerPrivateKey)
caver.wallet.add(feePayerKeyring)

caver.wallet.keyring.create함수를 활용하여 테스트 계정에서 사용하는 address와 private key를 파라미터로 Keyring 인스턴스를 생성합니다. 생성한 Keyring 인스턴스는 caver.wallet.add를 사용하여 in-memory wallet에 추가합니다.

Private key가 아니라 keystore를 소유하고 있는 경우, caver.wallet.keyring.decrypt를 사용하여 Keyring 인스턴스를 생성할 수 있습니다. 계정 키가 업데이트된 경우에도 caver.wallet.keyring.create를 사용하여 Keyring 인스턴스를 생성할 수 있습니다.

caver-java도 마찬가지로 caver.wallet.add 함수를 사용합니다.

// Create a keyring and add to the in-memory wallet - caver-java
String deployerAddress = "0x{address}";
String deployerPrivateKey = "0x{private key}";String feePayerAddress = "0x{address}";String feePayerPrivateKey = "0x{private key}";

SingleKeyring deployerKeyring = caver.wallet.keyring.(deployerAddress, deployerPrivateKey);
caver.wallet.add(deployerKeyring);

SingleKeyring feePayerKeyring = caver.wallet.keyring.create(feePayerAddress, feePayerPrivateKey);
caver.wallet.add(feePayerKeyring);

2. 스마트 컨트랙트 배포하기

이 단계에서는 간단하게 key, value를 관리하는 스마트 컨트랙트를 사용합니다. 사용하는 스마트 컨트랙트는 아래와 같습니다.

pragma solidity ^0.5.6;

contract KVstore {
mapping(string=>string) store;

constructor (string memory key, string memory value) public {
store[key] = value;
}

function get(string memory key) public view returns (string memory) {
return store[key];
}

function set(string memory key, string memory value) public {
store[key] = value;
}
}

다음은 caver-js에서 수수료 대납 기능으로 스마트 컨트랙트를 배포하는 방법입니다. 아래 소스코드에서 abibyteCode는 위 스마트 컨트랙트를 컴파일한 결과입니다.

// Deploy a smart contract to the Klaytn - caver-js
const byteCode = '0x608060405234801561001057600080fd5b5060405161072d38038061072d8339810180604052604081101561003357600080fd5b81019080805164010000000081111561004b57600080fd5b8281019050602081018481111561006157600080fd5b815185600182028301116401000000008211171561007e57600080fd5b5050929190602001805164010000000081111561009a57600080fd5b828101905060208101848111156100b057600080fd5b81518560018202830111640100000000821117156100cd57600080fd5b5050929190505050806000836040518082805190602001908083835b6020831061010c57805182526020820191506020810190506020830392506100e9565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020908051906020019061015292919061015a565b5050506101ff565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061019b57805160ff19168380011785556101c9565b828001600101855582156101c9579182015b828111156101c85782518255916020019190600101906101ad565b5b5090506101d691906101da565b5090565b6101fc91905b808211156101f85760008160009055506001016101e0565b5090565b90565b61051f8061020e6000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063693ec85e1461003b578063e942b5161461016f575b600080fd5b6100f46004803603602081101561005157600080fd5b810190808035906020019064010000000081111561006e57600080fd5b82018360208201111561008057600080fd5b803590602001918460018302840111640100000000831117156100a257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506102c1565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610134578082015181840152602081019050610119565b50505050905090810190601f1680156101615780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102bf6004803603604081101561018557600080fd5b81019080803590602001906401000000008111156101a257600080fd5b8201836020820111156101b457600080fd5b803590602001918460018302840111640100000000831117156101d657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019064010000000081111561023957600080fd5b82018360208201111561024b57600080fd5b8035906020019184600183028401116401000000008311171561026d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506103cc565b005b60606000826040518082805190602001908083835b602083106102f957805182526020820191506020810190506020830392506102d6565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390208054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156103c05780601f10610395576101008083540402835291602001916103c0565b820191906000526020600020905b8154815290600101906020018083116103a357829003601f168201915b50505050509050919050565b806000836040518082805190602001908083835b6020831061040357805182526020820191506020810190506020830392506103e0565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020908051906020019061044992919061044e565b505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061048f57805160ff19168380011785556104bd565b828001600101855582156104bd579182015b828111156104bc5782518255916020019190600101906104a1565b5b5090506104ca91906104ce565b5090565b6104f091905b808211156104ec5760008160009055506001016104d4565b5090565b9056fea165627a7a72305820adabefbb9574a90843d986f100c723c37f37e79f289b16aa527705b5341499aa0029'
const abi = [
{
constant: true,
inputs: [{ name: 'key', type: 'string' }],
name: 'get',
outputs: [{ name: '', type: 'string' }],
payable: false,
stateMutability: 'view',
type: 'function',
},
{
constant: false,
inputs: [{ name: 'key', type: 'string' }, { name: 'value', type: 'string' }],
name: 'set',
outputs: [],
payable: false,
stateMutability: 'nonpayable',
type: 'function',
},
{
inputs: [{ name: 'key', type: 'string' }, { name: 'value', type: 'string' }],
payable: false,
stateMutability: 'nonpayable',
type: 'constructor',
},
]
let contract = caver.contract.create(abi)const keyString = 'keyString'// Send a FeeDelegatedSmartContractDeploy transaction to Klaytn directly.
contract = await contract.deploy({
from: deployerKeyring.address,
feeDelegation: true,
feePayer: feePayerKeyring.address,
gas: 1000000,
}, byteCode, keyString, 'valueString')console.log(`The address of deployed smart contract: ${contract.options.address}`)

스마트 컨트랙트의 ABI(Application binary interface)를 caver.contract.create 함수의 파라미터로 전달하여 Contract 인스턴스를 생성합니다. 그 후, contract.deploy 메서드를 사용하여 스마트 컨트랙트를 Klaytn에 배포합니다. 해당 메서드의 첫 번째 파라미터는 트랜잭션 전송에 필요한 값들이 정의된 options 객체입니다. 위 예제에서 options객체 내부에 feeDelegation: truefeePayer가 정의된 것을 확인할 수 있습니다.

feeDelegation 필드가 true면 스마트 컨트랙트를 배포할 때 수수료 대납 트랜잭션을 사용합니다. 추가적으로, options 오브젝트에 feeRatio 필드가 정의되어 있으면 FeeDelegatedSmartContractDeployWithRatio 트랜잭션을, 그렇지 않으면 FeeDelegatedSmartContractDeploy 트랜잭션을 사용합니다.

위 예제에서 사용된 contract.deploy는 스마트 컨트랙트를 배포하기 위한 FeeDelegatedSmartContractDeploy 트랜잭션을 생성합니다. caver.wallet에서 관리하는 deployer와 fee payer의 keyring으로 트랜잭션에 서명한 후 Klaytn에 전송하기 때문에 수수료 대납을 사용하는 경우 fee payer 계정의 주소도 feePayer 필드에 정의해야 합니다. 그리고 두 번째 파라미터로는 배포하고자 하는 스마트 컨트랙트의 byte code, 그 다음은 스마트 컨트랙트의 constructor 파라미터를 차례대로 전달하면 됩니다. contract.deploy는 배포된 스마트 컨트랙트의 주소를 저장하고 있는 Contract 인스턴스를 리턴합니다.

만약 deployer와 fee payer의 주체가 서로 달라 트랜잭션을 바로 전송하지 못하는 경우, 아래와 같이 deployer와 fee payer가 서명을 각자 수행하여 Klaytn에 전송할 수 있습니다.

// The deployer signs the transaction to deploy a smart contract. - caver-js
const deployTx = await contract.sign({
from: deployerKeyring.address,
feeDelegation: true,
gas: 1000000,
}, 'constructor', byteCode, keyString, 'valueString')
console.log(`Deployer signed transaction: `)
console.log(deployTx)
const rlpEncoded = deployTx.getRLPEncoding()

contract.sign 함수를 사용하면 deployer의 서명이 담긴 트랜잭션을 구할 수 있습니다. 위 예제에서 contract.sign 함수의 첫 번째 파라미터로 트랜잭션 생성에 필요한 정보가 담긴 options 객체를, 메서드 이름이 전달되어야 하는 두 번째 파라미터에는 constructor를 볼 수 있습니다.

contract.sign의 두 번째 파라미터로는 실행하고자 하는 메서드 이름을 전달해야 하는데, 스마트 컨트랙트를 배포하는 경우라면 실행하고자 하는 메서드의 이름 대신 constructor를 넘겨줍니다. contract.sign은 전송자의 서명을 트랜잭션에 추가하는 동작이므로 수수료 대납 기능을 사용하고자 할 때 optionsfeePayer를 정의하지 않아도 됩니다. contract.sign의 결과로 반환된 signedFeeDelegatedSmartContractDeploy 트랜잭션은 getRLPEncoding 함수를 사용하여 RLP 인코딩된 문자열을 구할 수 있습니다.

// The fee payer signs the transaction to deploy a smart contract. - caver-js
const deployTx = caver.transaction.decode(rlpEncoded)

await caver.wallet.signAsFeePayer(feePayerKeyring.address, deployTx) // Signs the transaction as a fee payer
const receipt = await caver.rpc.klay.sendRawTransaction(deployTx)
console.log(`The address of deployed smart contract: ${receipt.contractAddress}`)
contract = caver.contract.create(abi, receipt.contractAddress)

RLP 인코딩된 문자열을 전달 받은 fee payer는 caver.transaction.decode를 사용하여 트랜잭션 인스턴스를 생성합니다. Fee payer는 caver.wallet.signAsFeePayer를 사용하여 caver.transaction.decode의 결과로 반환된 FeeDelegatedSmartContractDeploy트랜잭션에 서명할 수 있습니다. Deployer와 fee payer의 서명이 모두 완료된 트랜잭션은 caver.rpc.klay.sendRawTransaction을 사용하여 Klaytn에 전송할 수 있습니다.

만약 수수료 대납자가 먼저 서명해야 하는 경우 contract.signAsFeePayer을 사용할 수 있습니다. contract.signAsFeePayer는 수수료 대납자의 서명으로 feePayerSignatures에 추가한 트랜잭션을 반환합니다. 그 이후 caver.wallet.sign을 사용하여 deployer의 서명을 추가하고, caver.rpc.klay.sendRawTransaction을 통해 Klaytn에 전송할 수 있습니다.

caver-java의 경우 아래와 같이 수수료 대납을 사용하여 스마트 컨트랙트를 배포할 수 있습니다.

// Deploy a smart contract to the Klaytn - caver-javaString byteCode = "0x608060405234801561001057600080fd5b5060405161072d38038061072d8339810180604052604081101561003357600080fd5b81019080805164010000000081111561004b57600080fd5b8281019050602081018481111561006157600080fd5b815185600182028301116401000000008211171561007e57600080fd5b5050929190602001805164010000000081111561009a57600080fd5b828101905060208101848111156100b057600080fd5b81518560018202830111640100000000821117156100cd57600080fd5b5050929190505050806000836040518082805190602001908083835b6020831061010c57805182526020820191506020810190506020830392506100e9565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020908051906020019061015292919061015a565b5050506101ff565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061019b57805160ff19168380011785556101c9565b828001600101855582156101c9579182015b828111156101c85782518255916020019190600101906101ad565b5b5090506101d691906101da565b5090565b6101fc91905b808211156101f85760008160009055506001016101e0565b5090565b90565b61051f8061020e6000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063693ec85e1461003b578063e942b5161461016f575b600080fd5b6100f46004803603602081101561005157600080fd5b810190808035906020019064010000000081111561006e57600080fd5b82018360208201111561008057600080fd5b803590602001918460018302840111640100000000831117156100a257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506102c1565b6040518080602001828103825283818151815260200191508051906020019080838360005b83811015610134578082015181840152602081019050610119565b50505050905090810190601f1680156101615780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102bf6004803603604081101561018557600080fd5b81019080803590602001906401000000008111156101a257600080fd5b8201836020820111156101b457600080fd5b803590602001918460018302840111640100000000831117156101d657600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019064010000000081111561023957600080fd5b82018360208201111561024b57600080fd5b8035906020019184600183028401116401000000008311171561026d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506103cc565b005b60606000826040518082805190602001908083835b602083106102f957805182526020820191506020810190506020830392506102d6565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390208054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156103c05780601f10610395576101008083540402835291602001916103c0565b820191906000526020600020905b8154815290600101906020018083116103a357829003601f168201915b50505050509050919050565b806000836040518082805190602001908083835b6020831061040357805182526020820191506020810190506020830392506103e0565b6001836020036101000a0380198251168184511680821785525050505050509050019150509081526020016040518091039020908051906020019061044992919061044e565b505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061048f57805160ff19168380011785556104bd565b828001600101855582156104bd579182015b828111156104bc5782518255916020019190600101906104a1565b5b5090506104ca91906104ce565b5090565b6104f091905b808211156104ec5760008160009055506001016104d4565b5090565b9056fea165627a7a72305820adabefbb9574a90843d986f100c723c37f37e79f289b16aa527705b5341499aa0029";
String abi = "[\n" +
" {\n" +
" \"constant\":true,\n" +
" \"inputs\":[\n" +
" {\n" +
" \"name\":\"key\",\n" +
" \"type\":\"string\"\n" +
" }\n" +
" ],\n" +
" \"name\":\"get\",\n" +
" \"outputs\":[\n" +
" {\n" +
" \"name\":\"\",\n" +
" \"type\":\"string\"\n" +
" }\n" +
" ],\n" +
" \"payable\":false,\n" +
" \"stateMutability\":\"view\",\n" +
" \"type\":\"function\"\n" +
" },\n" +
" {\n" +
" \"constant\":false,\n" +
" \"inputs\":[\n" +
" {\n" +
" \"name\":\"key\",\n" +
" \"type\":\"string\"\n" +
" },\n" +
" {\n" +
" \"name\":\"value\",\n" +
" \"type\":\"string\"\n" +
" }\n" +
" ],\n" +
" \"name\":\"set\",\n" +
" \"outputs\":[],\n" +
" \"payable\":false,\n" +
" \"stateMutability\":\"nonpayable\",\n" +
" \"type\":\"function\"\n" +
" },\n" +
" {\n" +
" \"inputs\":[\n" +
" {\n" +
" \"name\":\"key\",\n" +
" \"type\":\"string\"\n" +
" },\n" +
" {\n" +
" \"name\":\"value\",\n" +
" \"type\":\"string\"\n" +
" }\n" +
" ],\n" +
" \"payable\":false,\n" +
" \"stateMutability\":\"nonpayable\",\n" +
" \"type\":\"constructor\"\n" +
" }\n" +
"]";

Contract contract = caver.contract.create(abi);
String keyString = "keyString";
String valueString = "valueString";

SendOptions sendOptionsForDeployment = new SendOptions();
sendOptionsForDeployment.setFrom(deployerKeyring.getAddress());
sendOptionsForDeployment.setGas(BigInteger.valueOf(1000000));
sendOptionsForDeployment.setFeeDelegation(true);
sendOptionsForDeployment.setFeePayer(feePayerKeyring.getAddress());

// Send a FeeDelegatedSmartContractDeploy transaction to the Klaytn directly.
contract.deploy(sendOptionsForDeployment, byteCode, keyString, valueString);
System.out.println("The address of deployed smart contract:" + contract.getContractAddress());

만약 deployer와 fee payer의 주체가 서로 달라 트랜잭션을 즉시 전송하지 못하는 경우, caver-java도 아래와 같이 deployer와 fee payer가 각자 서명할 수 있습니다.

// The deployer and fee payer each sign the transaction to deploy a smart contract. - caver-java
SendOptions sendOptionsForSigning = new SendOptions();
sendOptionsForSigning.setFrom(deployerKeyring.getAddress());
sendOptionsForSigning.setGas(BigInteger.valueOf(1000000));
sendOptionsForSigning.setFeeDelegation(true);
AbstractTransaction signedTx = contract.sign(sendOptionsForSigning, "constructor", byteCode, keyString, "valueString");
String rlpEncoded = signedTx.getRLPEncoding();
// The fee payer signs the transaction to deploy a smart contract. - caver-java
AbstractTransaction signedTx = caver.transaction.decode(rlpEncoded);

caver.wallet.signAsFeePayer(feePayer.getAddress(), (AbstractFeeDelegatedTransaction)signedTx);
Bytes32 sendResult = caver.rpc.klay.sendRawTransaction(signedTx).send();
String txHash = sendResult.getResult();
TransactionReceiptProcessor receiptProcessor = new PollingTransactionReceiptProcessor(caver, 1000, 15);

TransactionReceipt.TransactionReceiptData receiptData = receiptProcessor.waitForTransactionReceipt(txHash);
System.out.println("The address of deployed smart contract:" + receiptData.getContractAddress());

3. 스마트 컨트랙트 함수 호출하기

3.1. call

생성자에 전달된 key, value가 잘 저장되었는지 확인하기 위하여 스마트 컨트랙트의 get 함수를 호출합니다. get 함수는 컨트랙트 상태를 바꾸지 않고 단순히 데이터를 읽어 오는 함수입니다. contract.call을 사용하여 호출할 수 있습니다.

아래는 caver-js를 사용하여 get 함수를 호출하는 방법입니다.

// Read value from smart contract - caver-js
let valueString = await contract.call('get', keyString)
console.log(`key: ${keyString} / value: ${valueString}`)

contract.call을 사용하여 스마트 컨트랙트의 함수를 호출할 수 있습니다. 첫 번째 파라미터로 호출할 함수의 이름, 두 번째 파라미터로 함수에 전달할 파라미터를 담아 차례로 넘겨줍니다. 만약 함수를 호출할 때 options를 정의하려면 제일 첫 번째 파라미터로 오브젝트를 넘겨주면 됩니다. 자세한 사용방법은 Klaytn Docs를 참고해 주시기 바랍니다.

caver-java로 get 함수를 호출하는 방법은 아래와 같습니다.

// Read value from smart contract - caver-java
Utf8String valueString = (Utf8String)contract.call("get", keyString).get(0);
System.out.println("key: " + keyString + " / value: " + valueString.toString());

3.2. send

스마트 컨트랙트에 저장되어 있는 데이터를 변경하기 위하여 배포된 스마트 컨트랙트의 set 함수를 호출합니다. set 함수는 스마트 컨트랙트의 상태를 변경하는 함수로, 이를 호출하려면 트랜잭션을 전송해야 합니다. 호출 시contract.send 함수를 사용할 수 있습니다. contract.send는 첫 번째 파라미터로 트랜잭션 생성에 필요한 값들을 정의한 오브젝트를 전달받습니다. 수수료 대납 기능을 사용하는 경우 해당 오브젝트에 feeDelegation, feePayer 그리고 feeRatio를 추가적으로 정의하면 됩니다.

아래는 caver-js를 사용하여 set 함수를 호출하는 방법입니다.

// Send a FeeDelegatedSmartContractExecutionWithRatio transaction to Klaytn directly. - caver-js
const setResult = await contract.send({
from: deployerKeyring.address,
feeDelegation: true,
feePayer: feePayerKeyring.address,
feeRatio: 50, // Without feeRatio, `send` will use FeeDelegatedSmartContractExecution
gas: 1000000,
}, 'set', keyString, 'anotherValue')

contract.send에 첫 번째 파라미터로 전달된 오브젝트를 보면 feeDelegationtrue로 정의된 것을 확인할 수 있습니다. 그러므로 set 함수를 실행하기 위하여 수수료 대납 트랜잭션을 사용하게 됩니다. feeRatio 또한 정의되어 있기 때문에 FeeDelegatedSmartContractExecutionWithRatio 트랜잭션을 사용합니다. 두 번째 파라미터로는 호출하고자 하는 함수의 이름을, 다음에는 스마트 컨트랙트 함수의 파라미터를 차례대로 전달합니다. contract.send도 마찬가지로 트랜잭션을 생성하고, deployer와 fee payer가 모두 서명한 뒤에 바로 Klaytn으로 트랜잭션을 전송합니다. 그렇기 때문에 수수료 대납 기능을 사용하려면 첫 번째 파라미터에 feePayer가 정의되어 있어야 합니다.

만약 deployer와 fee payer의 주체가 서로 달라 트랜잭션을 바로 전송하지 못하는 경우, 아래와 같이 deployer와 fee payer가 각자 서명할 수 있습니다.

// The deployer and fee payer each sign the transaction to execute a smart contract. - caver-js
const executionTx = await contract.sign({
from: deployerKeyring.address,
feeDelegation: true,
feeRatio: 50, // Without feeRatio, `send` will use FeeDelegatedSmartContractExecution
gas: 1000000,
}, 'set', keyString, 'anotherValue')
console.log(`Deployer signed transaction: `)
console.log(executionTx)

await caver.wallet.signAsFeePayer(feePayerKeyring.address, executionTx) // Signs the transaction as a fee payer
const setResult = await caver.rpc.klay.sendRawTransaction(executionTx)

contract.sign 함수를 사용하여 deployer가 서명하고, caver.wallet.signAsFeePayer 함수를 사용하여 수수료 대납자의 서명을 추가합니다. 이렇게 서명한 트랜잭션은 caver.rpc.klay.sendRawTransaction을 사용하여 Klaytn에 전송됩니다.

위 트랜잭션이 모두 실행 완료되면 contract.call을 사용하여 아래와 같이 결과를 확인할 수 있습니다.

// Read value string from the smart contract. - caver-jsvalueString = await contract.call('get', keyString)
console.log(`After executing set function => key: ${keyString} / value: ${valueString}`)

Caver-java는 아래와 같이 set 함수를 호출할 수 있습니다.

// Send a FeeDelegatedSmartContractExecutionWithRatio transaction to Klaytn directly. - caver-java
SendOptions sendOptionsForExecution = new SendOptions();
sendOptionsForExecution.setFrom(deployer.getAddress());
sendOptionsForExecution.setGas(BigInteger.valueOf(1000000));
sendOptionsForExecution.setFeeDelegation(true);
sendOptionsForExecution.setFeePayer(feePayer.getAddress());
sendOptionsForExecution.setFeeRatio(BigInteger.valueOf(50)); // Without feeRatio, `send` will use FeeDelegatedSmartContractExecution
TransactionReceipt.TransactionReceiptData receiptData = contract.send(sendOptionsForExecution, "set", "key_inserted", "value_inserted");
System.out.println("Transaction type : " + receiptData.getType());
System.out.println("From : " + receiptData.getFrom());
System.out.println("Fee payer : " + receiptData.getFeePayer());
System.out.println("Fee ratio : " + receiptData.getFeeRatio());

만약 deployer와 fee payer의 주체가 서로 달라 트랜잭션을 바로 전송하지 못하는 경우, caver-java도 아래와 같이 deployer와 fee payer가 각자 서명할 수 있습니다.

// The deployer and fee payer each sign the transaction to execute a smart contract. - caver-javaSendOptions sendOptionsForExecution = new SendOptions();
sendOptionsForExecution.setFrom(deployer.getAddress());
sendOptionsForExecution.setGas(BigInteger.valueOf(1000000));
sendOptionsForExecution.setFeeDelegation(true);
sendOptionsForExecution.setFeeRatio(BigInteger.valueOf(50)); // Without feeRatio, `send` will use FeeDelegatedSmartContractExecution

AbstractTransaction executionTx = contract.sign(sendOptionsForExecution, "set", "key_inserted", "value_inserted");
caver.wallet.signAsFeePayer(feePayer.getAddress(), (AbstractFeeDelegatedTransaction)executionTx);

Bytes32 sendResult = caver.rpc.klay.sendRawTransaction(executionTx).send();
String txHash_executed = sendResult.getResult();
TransactionReceiptProcessor receiptProcessor = new PollingTransactionReceiptProcessor(caver, 1000, 15);

TransactionReceipt.TransactionReceiptData receiptData = receiptProcessor.waitForTransactionReceipt(txHash_executed);

위의 트랜잭션이 모두 실행이 완료되면 contract.call을 사용하여 아래와 같이 결과를 확인할 수 있습니다.

// Use short-cut function to read value from smart contract. - caver-java
Utf8String value = (Utf8String)contract.call("get", keyString).get(0);
System.out.println("After executing set function => key: " + keyString + "value: " + value.toString());

**포스팅에 사용된 전체 소스코드 링크

이 포스트가 여러분께 도움이 되었길 바랍니다. 질문이 있으시면 댓글을 남겨주시거나 개발자 포럼에 남겨주세요.

감사합니다!

--

--

Tech at Klaytn
Tech at Klaytn

No responses yet