Contract의 지출 자동 로깅

in eos •  2 years ago  (edited)

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 컨트랙트 코드의 일부이고 조만간 전체 코드를 공개하도록 하겠습니다.

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

포스팅 잘보았습니다~~ 풀보팅드려용

감사합니다~ 누군가에게 도움이 되었으면 좋겠네요~

코드 오픈했습니다! 컨트랙 코드는 아래 링크에서 확인 가능합니다.
https://github.com/bada-studio/knights_contract