Contract의 지출 자동 로깅
EOS 플랫폼에서 게임을 만드려고 공부하시는 분들은 대부분 dice app을 많이 참고하는데, 이 샘플은 권한 이슈가 있습니다. Contract에서 직접 유저의 EOS를 출금하기 때문에 유저가 contract에 active 권한을 승인해 줘야 합니다.
이 방법 말고 더 쉽고 간단한 방법이 있는데, 유저가 컨트랙트로 입금을 할때 Contract의 특정코드가 자동으로 실행되게 하는 방식입니다. eosio.token 컨트랙트를 보면 transfer 시점에 require_recipient 함수를 통해 from과 to 쪽에 모두 notification이 보내지는 것을 볼 수 있습니다.
void token::transfer(...) {
...
require_recipient( from );
require_recipient( to );
}
받는 쪽의 contract에서 이 notification을 받아서 처리할 수 있는데, 자세한 내용은 eos stackexchange의 글을 참고하거나, 몬스터 eos가 구현한 코드를 참고하시면 될 것 같습니다. 여기까지는 이미 어느정도 공유가 된 내용입니다.
여기서 부터가 본격적인 내용입니다. require_recipient 기능을 이용하면 입금 기능말고 출금을 자동으로 로깅하게 할 수 있습니다. 컨트랙트에서 출금이 발생했을 때 지출 내역이라면 해당 내용을 기록 하는 것입니다. 이를 통해 자동으로 잔고 관리가 가능합니다.
//@abi table expenseslog i64
struct expenseslog {
uint64_t no = 0;
uint32_t at = 0;
asset amount;
name to;
std::string memo;
...
}
void transfer(uint64_t sender, uint64_t receiver) {
...
// 출금시
if (transfer_data.from == self) {
auto to = to_name(transfer_data.to);
auto player = players.find(to);
// 유저의 withdraw가 아니고, 주주에게 보내는 쉐어가 아니라면 출금 내역 기록
if (player == players.cend() && admin_controller.is_stock_holder(to) == false) {
// 내부에서 expenseslog 테이블에 데이터를 쌓는다
admin_controller.add_expenses(transfer_data.quantity, to, transfer_data.memo);
}
}
// 입금시
if (transfer_data.to == self) {
// 유저 입금 처리
}
}
자그럼 한번 테스트 해보겠습니다. 이와 같은 컨트랙트 코드를 작성후 컨트랙트를 배포한다음 0.1 EOS 만큼의 램을 구매해 보겠습니다.
$ cleos -u $url system buyram eosknightsio eosknightsio '0.1000 EOS' -p eosknightsio
1148081ms thread-0 main.cpp:429 create_action ] result: {"binargs":"401dce8db9093155401dce8db9093155e80300000000000004454f5300000000"} arg: {"code":"eosio","action":"buyram","args":{"payer":"eosknightsio","receiver":"eosknightsio","quant":"0.1000 EOS"}}
executed transaction: 2fd4568358775e1e440cf81a4a9a5c6d7f6fc3463728bdd94bcf0e4ca0178b83 128 bytes 3468 us
# eosio <= eosio::buyram {"payer":"eosknightsio","receiver":"eosknightsio","quant":"0.1000 EOS"}
# eosio.token <= eosio.token::transfer {"from":"eosknightsio","to":"eosio.ram","quantity":"0.0995 EOS","memo":"buy ram"}
# eosknightsio <= eosio.token::transfer {"from":"eosknightsio","to":"eosio.ram","quantity":"0.0995 EOS","memo":"buy ram"}
# eosio.ram <= eosio.token::transfer {"from":"eosknightsio","to":"eosio.ram","quantity":"0.0995 EOS","memo":"buy ram"}
# eosio.token <= eosio.token::transfer {"from":"eosknightsio","to":"eosio.ramfee","quantity":"0.0005 EOS","memo":"ram fee"}
# eosknightsio <= eosio.token::transfer {"from":"eosknightsio","to":"eosio.ramfee","quantity":"0.0005 EOS","memo":"ram fee"}
# eosio.ramfee <= eosio.token::transfer {"from":"eosknightsio","to":"eosio.ramfee","quantity":"0.0005 EOS","memo":"ram fee"}
warning: transaction executed locally, but may not be confirmed by the network yet
로깅이 잘 되었나 봐볼까요?
$ cleos -u $url get table eosknightsio eosknightsio expenseslog
{
"rows": [{
"no": 0,
"at": 31203548,
"amount": "0.0995 EOS",
"to": "eosio.ram",
"memo": "buy ram"
},{
"no": 1,
"at": 31203548,
"amount": "0.0005 EOS",
"to": "eosio.ramfee",
"memo": "ram fee"
}
],
"more": false
}
ram과 ram.fee가 잘 기록되었네요.
UI를 이런식으로 붙이면 보기더 좋겠죠?
이상 컨트랙트를 잘 활용해서 지출내역을 자동으로 기록하는 방법이였습니다. 이 코드는 eosknights 컨트랙트 코드의 일부이고 조만간 전체 코드를 공개하도록 하겠습니다.
포스팅 잘보았습니다~~ 풀보팅드려용
감사합니다~ 누군가에게 도움이 되었으면 좋겠네요~
코드 오픈했습니다! 컨트랙 코드는 아래 링크에서 확인 가능합니다.
https://github.com/bada-studio/knights_contract