Contract의 지출 자동 로깅

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

Sort:  

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

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

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