Eos Smart Contract Part 2, listening apply function, add and remove row from table

Words
405
Reading
2 min
Listen
Play
8y


Hello Steemit friends so this is part 2 of the Eos smart contract tutorial, this time, we will be creating an "apply function" that will listen to any transaction or action that interact with the smart contract

for example

let say user A send 0.01 EOS into our smart contract "helloworld11", upon receiving EOS, our smart contract should automatically add one row of data into our table

the syntax should be like below

#undef EOSIO_ABI

#define EOSIO_ABI( TYPE, MEMBERS ) \
extern "C" { \
   void apply( uint64_t receiver, uint64_t code, uint64_t action ) { \
      auto self = receiver; \
      TYPE thiscontract( self ); \
      if( action == N(onerror)) { \
         /* onerror is only valid if it is for the "eosio" code account and authorized by "eosio"'s "active permission */ \
         eosio_assert(code == N(eosio), "onerror action's are only valid from the \"eosio\" system account"); \
      } \
      if( code == self ) { \
         if (action != N(transfer)) {\
            switch( action ) { \
                EOSIO_API( TYPE, MEMBERS ) \
            } \
            /* does not allow destructor of thiscontract to run: eosio_exit(0); */ \
         }\
      } \
      else if (code == N(eosio.token) && action == N(transfer) ) {\
          execute_action(&thiscontract, &testtable2::droptable);\
      }\
   } \
}

the code must start with extern "C" because we want to makes a function-name in C++ have 'C' linkage

As you can see, when listening, we get 3 parameter which is the receiver, code and action

  • Receiver = who get the money, which is us "helloworld11"
  • Code = which smart contract the money belong to? the real EOS token belong to "EOSIO.TOKEN"
  • action = what action ? for this case, we check if the action is "TRANSFER"
So you can do a simple logic where if code = "EOSIO.token" and action = "transfer" then you go to the function "add", else you go to the normal function "EOSIO_API"

so upon receiving 0.01 EOS, our add function should look like below

[[eosio::action]]
      void add()
      {
        auto transfer_data = eosio::unpack_action_data<st_transfer>();

        std::string mymemo = transfer_data.memo;

        std::string haha = "lalala";

        datastore mystore(_self, _self);
        //first param = who pay, second param = constructor
        mystore.emplace(get_self(),[&](auto& p)
                                      {
                                        p.key =mystore.available_primary_key();
                                        p.secondid = mystore.available_primary_key();
                                        p.name = mymemo;
                                        p.account = haha;


                                      });
    }

      

first we must have [[eosio::action]] on top of the function so ABI file can recognise this function,

then we have "auto transfer_data = eosio::unpack_action_data<st_transfer>();" this will unpack the transaction data into "transfer_data"

the "st_transfer" is the structure that we must declare and match, as we know when receiving 0.01 EOS, the sender must send 4 parameter which is "sender, receiver, amount, memo" so the "st_transfer" struct look like below

struct st_transfer {
        account_name from;
        account_name to;
        asset        quantity;
        std::string  memo;
    };

then we can get the memo using syntax std::string mymemo = transfer_data.memo;

finally we add one row into the table using syntax emplace

full code is below

#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>
#include <eosiolib/asset.hpp>
using namespace eosio;

class testtable2 : public eosio::contract {
  public:
      using contract::contract;


      [[eosio::action]]
      void hi( account_name user ) {
         print( "Hello,STUPID ", name{user} );
      }


        [[eosio::action]]
        void droptable()
        {               datastore example(_self, _self); // code, scope
                for(auto itr = example.begin(); itr != example.end();) {
                        itr = example.erase(itr);
                }
        }




      [[eosio::action]]
      void add()
      {
        auto transfer_data = eosio::unpack_action_data<st_transfer>();

        std::string mymemo = transfer_data.memo;

        std::string haha = "lalala";

        datastore mystore(_self, _self);
        //first param = who pay, second param = constructor
        mystore.emplace(get_self(),[&](auto& p)
                                      {
                                        p.key =mystore.available_primary_key();
                                        p.secondid = mystore.available_primary_key();
                                        p.name = mymemo;
                                        p.account = haha;


                                      });
    }


  private:

    struct st_transfer {
        account_name from;
        account_name to;
        asset        quantity;
        std::string  memo;
    };
      struct [[eosio::table]] mystruct
      {
         uint64_t     key;
         uint64_t     secondid;
         std::string  name;
         std::string  account;
         uint64_t primary_key() const { return key; } // getter for primary key
         uint64_t by_id() const {return secondid; } // getter for additional key

        EOSLIB_SERIALIZE(mystruct,(key)(secondid)(name)(account))

      };

        typedef eosio::multi_index<N(mystruct), mystruct> datastore;




};
#undef EOSIO_ABI

#define EOSIO_ABI( TYPE, MEMBERS ) \
extern "C" { \
   void apply( uint64_t receiver, uint64_t code, uint64_t action ) { \
      auto self = receiver; \
      TYPE thiscontract( self ); \
      if( action == N(onerror)) { \
         /* onerror is only valid if it is for the "eosio" code account and authorized by "eosio"'s "active permission */ \
         eosio_assert(code == N(eosio), "onerror action's are only valid from the \"eosio\" system account"); \
      } \
      if( code == self ) { \
         if (action != N(transfer)) {\
            switch( action ) { \
                EOSIO_API( TYPE, MEMBERS ) \
            } \
            /* does not allow destructor of thiscontract to run: eosio_exit(0); */ \
         }\
      } \
      else if (code == N(eosio.token) && action == N(transfer) ) {\
          execute_action(&thiscontract, &testtable2::droptable);\
      }\
   } \
}

EOSIO_ABI( testtable2, (hi)(add)(droptable) )

so as you can see, i put everything inside folder "testtable2" and all code inside "testtable2.cpp"

to compile it i use below syntax

eosio-cpp -o testtable2.wasm testtable2.cpp --abigen

to deploy the smart contract to account "helloworld11" i use below syntax

cleos set contract helloworld11 ../testtable2 -p helloworld11@active

checking table

cleos get table helloworld11 helloworld11 mystruct

(so at first the table is empty)

sending 0.01 EOS from fundurianaaa to helloworld11

cleos push action eosio.token transfer '["fundurianaaa","helloworld11","0.0001 EOS","memo"]' -p fundurianaaa

then check table again

cleos get table helloworld11 helloworld11 mystruct

(this time i can see one row of data appear inside the table meaning our smart contract is working)

clean table

cleos push action helloworld11 droptable '{"user":"fundurianaaa"}' -p fundurianaaa

So thats all for today, by knowing how to listening to all transaction sending into your smart contract, you can do a lot of stuff already

thanks for reading

  <br /><center><hr/><em>Posted from my blog with <a href='https://wordpress.org/plugins/steempress/'>SteemPress</a> : http://fundurian.vornix.blog/2018/10/17/eos-smart-contract-part-2-listening-apply-function-add-and-remove-row-from-table/ </em><hr/></center>

Eos Smart Contract Part 2, listening apply function, add and remove... | Ecency