[EOS #10] EOS json rpc를 이용한 token transfer
01 Dec 2018 | Blockchain EOS1. cleos의 push transaction과 json rpc의 push transaction
- Terminal의 cleos에서 transaction push 기능으로는 create, transfer, push transaction, push action, buyram, sellram, set contract 등 여러가지 간편한 기능들을 지원한다.
- cleos에서 EOS가 아닌 Token transfer를 하기 위해선 수행 내용을 json으로 작성하여 push action 기능을 사용해야 한다. 그 외 smart contract의 기능들도 마찬가지다.
- Json rpc에서의 push transaction은 push_transaction API 단 하나이다.
- 위의 cleos에서 제공하는 그외 push transaction 기능들을 수행하기 위해선 직접 transaction을 작성하고 서명한 후 push 해야한다.
- 이 문서에서는 eos-java-rpc-wrapper를 사용하여 push_transaction(Token transfer) 방법을 설명한다.
- 또한 https://git.doublechain.co.kr/backend/exchange/eos-service-webflux 에 자주 사용하는 push transaction들은 서비스로 만들어 놓을 예정이다.
2. push_transaction의 Parameter
- push_transaction 과정의 필요한 파라미터는 최신 블록 넘버, 블록 레퍼런스 등등 많으나 여기서는 사용자가 입력해야만 하는 파라미터만 작성하겠다.
-
account, name, permission, actor, walletName, walletPassword, compression, JSON data
-
account : Contract의 생성 계정명이다. 예를 들어 EOS transfer의 경우 eosio.token이며, buyram의 경우 eosio가 account로 들어간다.
-
name : Contract의 action name이다. 예를 들어 EOS transfer의 경우 tansfer이며, buyram의 경우 buyram이 name로 들어간다.
-
permission : 해당 action을 수행하기위한 permission이 들어간다.
-
actor : Contract 수행의 주체가 되는 계정명이다. EOS transfer의 경우 EOS를 전송하려는 계정명이다.
-
walletName : actor의 wallet name이다.
-
walletPassword : actor의 wallet password이다.
-
compression : 작성하는 transaction의 압축여부를 뜻한다. “none” 또는 “zlib”이 들어간다.
- JSON data : abi를 참고하면 structs의 fields에 있는 json이다. EOS transfer의 경우 아래와 같은 형태를 가진다. {“from”:”doublechain4”,”to”:”doublechainw”,”quantity”:”1.0000 EOS”,”memo”:”transfer test”}
3. push_transaction의 순서
- push_transaction API를 수행하기 전에 unlock, get_info, get_block, abi_json_to_bin, list_keys, get_required_keys, sign_transaction API들을 수행해야한다.
- unlock : 해당 wallet을 unlock한다.
- get_info : chain id와 최신 블럭 번호 정보를 가져온다.
- get_block : 최신 블럭의 ref_block_prefix 정보를 가져온다.
- abi_json_to_bin : json data를 binargs로 변환한다.
- list_keys : wallet의 key list를 반환한다.
- get_required_keys : list_keys 중의 sign에 필요한 public key를 반환한다.
- sign_transaction : 위의 data들로 작성된 transaction을 서명한다.
4. Token transfer 예제
- 위의 내용대로 작성된 token transfer 코드이다.
String account = "oasistokenn1";
String name = "transfer";
String permission = "active";
String actor = "doublechain4";
String walletName = "default";
String walletPassword = "PW5JjqqVLWDTPv2hX6oyFHL7UXe6893qHgC5kqe4araqX4PqHTRQK";
// wallet을 unlock한다.
eosApiRestClient.unlockWallet(walletName, walletPassword);
// chain 정보와 최신 block정보 가져오기
ChainInfo chainInfo = eosApiRestClient.getChainInfo();
Block block = eosApiRestClient.getBlock(chainInfo.getHeadBlockNum().toString());
// account와 name, 그리고 Map으로 만든 json데이터로 binargs 변환하기.
Map<String, Object> map = new HashMap<>();
map.put("from", "doublechain4");
map.put("to", "doublechainw");
map.put("quantity", "1.0000 OAS");
map.put("memo", "Token transfer example");
String binargs = eosApiRestClient.abiJsonToBin(account, name, map).getBinargs();
// wallet의 public key 가져오기
Iterator<List<String>> itr = eosApiRestClient.listKeys(walletName, walletPassword).iterator();
List<String> keys = new ArrayList<String>();
while (itr.hasNext()) {
keys.add(itr.next().get(0));
}
// transaction 작성
PackedTransaction packedTransaction = new PackedTransaction();
packedTransaction.getActions().add(new TransactionAction());
packedTransaction.getActions().get(0).setAccount(account);
packedTransaction.getActions().get(0).setData(binargs);
packedTransaction.getActions().get(0).setName(name);
packedTransaction.getActions().get(0).getAuthorization().add(new PermissionLevel());
packedTransaction.getActions().get(0).getAuthorization().get(0).setActor(actor);
packedTransaction.getActions().get(0).getAuthorization().get(0).setPermission(permission);
packedTransaction.setRefBlockNum(block.getBlockNum());
packedTransaction.setRefBlockPrefix(block.getRefBlockPrefix());
packedTransaction.setExpiration((((new Timestamp(System.currentTimeMillis() + 30000)).toInstant()).toString().subSequence(0, 20)) + block.getTimeStamp().substring(20));
// 서명에 필요한 key 받아오기
List<String> requiredKeys = eosApiRestClient.getRequiredKeys(packedTransaction, keys).getRequiredKeys();
// transaction에 서명하기
PackedTransaction signedPackedTransaction = eosApiRestClient.signTransaction(packedTransaction, requiredKeys, chainInfo.getChainId());
// 서명된 transaction push하기
System.out.println(eosApiRestClient.pushTransaction(compression, signedPackedTransaction));
// result
{"processed":{"id":"af2c9ac1471e56cf781d914f625e8f7d247da9cca78324c8a52613009981cbda","block_num":4657321,"block_time":"2018-12-21T05:20:09.500","producer_block_id":null,"receipt":{"status":"executed","cpu_usage_us":317,"net_usage_words":18,"trx":null},"elapsed":317,"net_usage":144,"scheduled":false,"action_traces":[{"receipt":{"receiver":"oasistokenn1","act_digest":"f97d029d115699d3f68dff3ada5ad37c2f62aa39c791e9426539d24e9ac23a24","global_sequence":24154506,"recv_sequence":16,"code_sequence":1,"abi_sequence":1},"act":{"account":"oasistokenn1","name":"transfer","authorization":[{"actor":"doublechain4","permission":"active"}],"data":{"from":"doublechain4","to":"doublechainw","quantity":"1.0000 OAS","memo":"OAS token transfer"},"hex_data":"40a6330da978344dc0a7330da978344d1027000000000000044f415300000000124f415320746f6b656e207472616e73666572"},"context_free":false,"elapsed":118,"console":"","trx_id":"af2c9ac1471e56cf781d914f625e8f7d247da9cca78324c8a52613009981cbda","block_num":4657321,"block_time":"2018-12-21T05:20:09.500","producer_block_id":null,"account_ram_deltas":[{"account":"doublechain4","delta":128},{"account":"oasiswkimdev","delta":-128}],"except":null,"inline_traces":[{"receipt":{"receiver":"doublechain4","act_digest":"f97d029d115699d3f68dff3ada5ad37c2f62aa39c791e9426539d24e9ac23a24","global_sequence":24154507,"recv_sequence":115,"code_sequence":1,"abi_sequence":1},"act":{"account":"oasistokenn1","name":"transfer","authorization":[{"actor":"doublechain4","permission":"active"}],"data":{"from":"doublechain4","to":"doublechainw","quantity":"1.0000 OAS","memo":"OAS token transfer"},"hex_data":"40a6330da978344dc0a7330da978344d1027000000000000044f415300000000124f415320746f6b656e207472616e73666572"},"context_free":false,"elapsed":6,"console":"","trx_id":"af2c9ac1471e56cf781d914f625e8f7d247da9cca78324c8a52613009981cbda","block_num":4657321,"block_time":"2018-12-21T05:20:09.500","producer_block_id":null,"account_ram_deltas":[],"except":null,"inline_traces":[]},{"receipt":{"receiver":"doublechainw","act_digest":"f97d029d115699d3f68dff3ada5ad37c2f62aa39c791e9426539d24e9ac23a24","global_sequence":24154508,"recv_sequence":69,"code_sequence":1,"abi_sequence":1},"act":{"account":"oasistokenn1","name":"transfer","authorization":[{"actor":"doublechain4","permission":"active"}],"data":{"from":"doublechain4","to":"doublechainw","quantity":"1.0000 OAS","memo":"OAS token transfer"},"hex_data":"40a6330da978344dc0a7330da978344d1027000000000000044f415300000000124f415320746f6b656e207472616e73666572"},"context_free":false,"elapsed":6,"console":"","trx_id":"af2c9ac1471e56cf781d914f625e8f7d247da9cca78324c8a52613009981cbda","block_num":4657321,"block_time":"2018-12-21T05:20:09.500","producer_block_id":null,"account_ram_deltas":[],"except":null,"inline_traces":[]}]}],"except":null},"transaction_id":"af2c9ac1471e56cf781d914f625e8f7d247da9cca78324c8a52613009981cbda"}
- 위와 같이 account, name, permission, actor, walletName, walletPassword, compression, JSON data만 있으면 cloes의 transfer, push transaction, push action, buyram 등등의 기능을 수행할 수 있다.