Documentation
  • INTRODUCTION
  • USERS
    • White Paper
    • Main features of CyberWay
    • Bandwidth differences between EOS and CyberWay
    • Bandwidth implementation
    • How to Launch EOS dApps on CyberWay
    • Glossary
  • DEVELOPMENT ENVIRONMENT
    • Core Concepts
    • 1 Before You Begin
    • 2 Install the CDT
    • 3 Create Development Wallet
    • 4 Start keosd and nodeos
    • 5 Create Test Accounts
  • SOFTWARE MANUALS
    • Core
      • nodeos
      • cleos
      • keosd
      • cyberway.cdt
    • How To Guides
      • How To Ban An Unwanted Account
      • How To Calculate Reward For An Author
      • How To Calculate Reward For A Beneficiary
      • How To Calculate Reward For A Curator
      • How To Create A Wallet
      • How To Create An Account
      • How To Create A Proxy Account
      • How To Create Key Pair
      • How To Delegate Resources
      • How To Deploy A Node Using A Snapshot
      • How To Deploy A Smart Contract
      • How To Get Account Information
      • How To Get Block Information
      • How To Get Transaction Information
      • How To Import A Key
      • How To Link Permission
      • How To List All Key Pair
      • How To Stake Tokens
      • How To Stop A Node Using Docker
      • How To Submit A Proposal For HardFork
      • How To Transfer Tokens To A Worker
      • How To Undelegate Resources
      • How To Unlink Permission
      • How To Unstake Tokens
      • How To Vote
    • API Reference
      • Nodeos Chain API
      • Nodeos Producer API
      • Nodeos Net API
    • Cleos Command Reference
      • Convert
      • Create
      • Get
      • Multisig
      • Net
      • Push
      • Set
      • Sign
      • System
      • Transfer
      • Version
      • Wallet
    • Explorer Command Reference
      • How To Check Your Balance
      • How To Find Out Account ID
      • How To Convert Golos To Golos Power And Vice Versa
      • How To Stake Tokens CYBER
      • How To Transfer Funds From One Account To Another
      • How To Transfer Funds From Pending to Liquid
      • How To Bay Stake
      • How To Withdraw Stake
      • How To Vote For A Validator
      • How To Revoke Your Vote For A Validator
      • How To Bay Vesting Using Explorer
      • How To Vote For A Witness
      • How To Revoke Your Vote For A Witness
  • DEVPORTAL
    • System Contracts
      • BIOS
      • Domain names
      • Govern
      • Multi-Signature
      • Stake
      • Tokens
    • Application Contracts
      • Golos Contracts
        • Charge
        • Control
        • Emission
        • Publication
        • Referral program
        • Social
        • Vesting
        • Memo-keys
        • Determining Rewards for a Post
    • Guide to Creating and Deploying an Application on CyberWay
      • 1 Preliminary Work
      • 2 Creating a Simple Contract
      • 3 Creating Tokens
      • 4 Understanding ABI Files
      • 5 Data Persistence
      • 6 Secondary Indexes
      • 7 Adding Inline Actions
      • 8 Inline Action to External Contract
      • 9 Conclusion
    • The cyberway_wallet designed for the Bittrex market
    • The Event Model
  • VALIDATORS
    • Testnet Installation Guide
      • 1 General
      • 2 Configuring the Docker Image
      • 3 Create Container
      • 4 Connecting to a Node
      • 5 List of Commands Applicable to Any Kind of Container
    • Mainnet Connection Guide
      • Docker-Compose Start-up Instructions
      • APPENDIX A
      • APPENDIX B
    • Golos Blockchain Transit
    • How to join CyberWay for those who are interested in being validators ?
    • Stake Usage Guide
    • Regulations for CyberWay validators. Voting for Validators
Powered by GitBook
On this page
  • 8.1 Addressbook counter address contract
  • 8.2 Create an account for abcounter contract
  • 8.3 Compile and install the abcounter contract
  • 8.4 Modify the contract addressbook to send inline actions to a new abcounter contract
  • 8.5 Recompile and set the addressbook contract
  • 8.6 Perform testing of sending an action from an addressbook contract to an abcounter contract
  1. DEVPORTAL
  2. Guide to Creating and Deploying an Application on CyberWay

8 Inline Action to External Contract

This section of the guide provides instructions for sending actions to an external contract. The examples of the execution of instructions are shown in the contract, where the performed actions are kept.

8.1 Addressbook counter address contract

Log into CONTRACTS_DIR and create a directory there with the name abcounter, as well as the file abcounter.cpp.

cd CONTRACTS_DIR
mkdir abcounter
cd abcounter
touch abcounter.cpp

Open the abcounter.cpp file and write the following program text into it:

#include <eosiolib/eosio.hpp>

using namespace eosio;

class [[eosio::contract]] abcounter : public eosio::contract {
  private:
    struct [[eosio::table]] counter {
      name key;
      uint64_t emplaced;
      uint64_t modified;
      uint64_t erased;
      uint64_t primary_key() const {
      return key.value;
    }
  };

    using count_index = eosio::multi_index<"counter"_n, counter>;
  public:
    using contract::contract;

    abcounter(name receiver, name code,  datastream<const char*> ds):
contract(receiver, code, ds) {}

    [[eosio::action]]
    void count(name user, std::string type) {
      require_auth( name("addressbook"));
      count_index counts(name(_code), _code.value);
      auto iterator = counts.find(user.value);

      if (iterator == counts.end()) {
        counts.emplace("addressbook"_n, [&]( auto& row ) {
          row.key = user;
          row.emplaced = (type == "emplace") ? 1 : 0;
          row.modified = (type == "modify") ? 1 : 0;
          row.erased = (type == "erase") ? 1 : 0;
        });
      }
      else {
        counts.modify(iterator, "addressbook"_n, [&]( auto& row ) {
          if(type == "emplace") { row.emplaced += 1; }
          if(type == "modify") { row.modified += 1; }
          if(type == "erase") { row.erased += 1; }
        });
      }
    }
};

EOSIO_DISPATCH( abcounter, (count));

The peculiarity of this text is that it has a restriction on calls to an action for the contract account. For restriction, use require_auth for the addressbook contract. Only the addressbook contract account is authorized to perform require_auth. The count action is not sent by the user, but by the addressbook contract.

require_auth( name("addressbook"));

8.2 Create an account for abcounter contract

cleos create account cyber abcounter YOUR_PUBLIC_KEY

8.3 Compile and install the abcounter contract

eosio-cpp -o abcounter.wasm abcounter.cpp --abigen
cleos set contract abcounter CONTRACTS_DIR/abcounter

8.4 Modify the contract addressbook to send inline actions to a new abcounter contract

cd CONTRACTS_DIR/addressbook

Open the file addressbook.cpp and create in it another helper named increment_counter in the private part of the contract.

void increment_counter(name user, std::string type) {

  action counter = action(
    permission_level{get_self(),"active"_n},
    "abcounter"_n,
    "count"_n,
    std::make_tuple(user, type)
  );

  counter.send();
}

The action body contains:

  • выдача разрешения уровня active .Для разрешения функция get_self() возвращает текущий контракт addressbook;

  • the abcounter account name of the contract;

  • the count action to call;

  • data, username and line type.

Add calls to «set», «modify» and «erase» helpers.

//Emplace
increment_counter(user, "emplace");
//Modify
increment_counter(user, "modify");
//Erase
increment_counter(user, "erase");

As a result, the addressbook.cpp file should look like this:

#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>

using namespace eosio;

class [[eosio::contract]] addressbook : public eosio::contract {

  private:
    struct [[eosio::table]] person {
      name key;
      std::string first_name;
      std::string last_name;
      uint64_t age;
      std::string street;
      std::string city;
      std::string state;

      uint64_t primary_key() const { return key.value; }

      uint64_t get_secondary_1() const { return age;}

    };

    void send_summary(name user, std::string message) {
      action(
        permission_level{get_self(),"active"_n},
        get_self(),
        "notify"_n,
        std::make_tuple(user, name{user}.to_string() + message)
      ).send();
    };

    void increment_counter(name user, std::string type) {

      action counter = action(
        permission_level{get_self(),"active"_n},
        "abcounter"_n,
        "count"_n,
        std::make_tuple(user, type)
      );

    counter.send();
  }

  typedef eosio::multi_index<"person"_n, person,
    indexed_by<"byage"_n, member<person, uint64_t, &person::get_secondary_1>>
  > address_index;
  public:
    using contract::contract;

    addressbook(name receiver, name code,  datastream<const char*> ds):  contract(receiver, code, ds) {}

    [[eosio::action]]
    void upsert(name user, std::string first_name, std::string last_name, uint64_t age, std::string street, std::string city, std::string state) {
      require_auth(user);
      address_index addresses(_code, _code.value);
      auto iterator = addresses.find(user.value);
      if( iterator == addresses.end() )
      {
        addresses.emplace(user, [&]( auto& row ) {
         row.key = user;
         row.first_name = first_name;
         row.last_name = last_name;
         row.age = age;
         row.street = street;
         row.city = city;
         row.state = state;

         send_summary(user, " successfully emplaced record to addressbook");
         increment_counter(user, "emplace");
        });
      }
      else {
        std::string changes;
        addresses.modify(iterator, user, [&]( auto& row ) {
          row.key = user;
          row.first_name = first_name;
          row.last_name = last_name;
          row.age = age;
          row.street = street;
          row.city = city;
          row.state = state;

          send_summary(user, " successfully modified record to addressbook");
          increment_counter(user, "modify");
      });

    }
  }

  [[eosio::action]]
    void erase(name user) {
      require_auth(user);

      address_index addresses(_code, _code.value);
      auto iterator = addresses.find(user.value);
      eosio_assert(iterator != addresses.end(), "Record does not exist");
      addresses.erase(iterator);
      send_summary(user, " successfully erased record from addressbook");
      increment_counter(user, "erase");
    }

  [[eosio::action]]
    void notify(name user, std::string msg) {
      require_auth(get_self());
      require_recipient(user);
    }

  };

EOSIO_DISPATCH( addressbook, (upsert)(notify)(erase));

8.5 Recompile and set the addressbook contract

Since the changes should not affect the ABI, you do not need to re-edit the ABI file (make sure that this file has not been updated).

eosio-cpp -o addressbook.wasm addressbook.cpp
cleos set contract addressbook CONTRACTS_DIR/addressbook

8.6 Perform testing of sending an action from an addressbook contract to an abcounter contract

Before testing, make sure that the abcounter and addressbook contracts are set.

8.6.1 Verify that a notification is sent to the abcounter contract, as well as a change in the entry in the addressbook contract table by executing:

cleos push action addressbook upsert '["alice", "alice", "liddell", 19, "123 drink me way", "wonderland", "amsterdam"]' -p alice@active

The action is considered successful if the output contains the following information:

executed transaction: ...
#   addressbook <= addressbook::upsert          {"user":"alice","first_name":"alice","last_name":"liddell","street":"123 drink me way","city":"wonde...
#   addressbook <= addressbook::notify          {"user":"alice","msg":"alice successfully modified record in addressbook"}
#         alice <= addressbook::notify          {"user":"alice","msg":"alice successfully modified record in addressbook"}
#     abcounter <= abcounter::count             {"user":"alice","type":"modify"}

8.6.2 Check the appearance of a row in the table for the alice user.

cleos get table abcounter abcounter counts --lower alice --limit 1

The action is considered successful if the result is the following:

{
  "rows": [{
      "key": "alice",
      "emplaced": 1,
      "modified": 0,
      "erased": 0
    }
  ],
  "more": false
}

8.6.3 Check that the upsert method modifies the record.

cleos push action addressbook upsert '["alice", "alice", "liddell", 21,"1 there we go", "wonderland", "amsterdam"]' -p alice@active

The actions are considered successfully completed if the resulting output contains the following information:

executed transaction: …
#   addressbook <= addressbook::upsert          {"user":"alice","first_name":"alice","last_name":"liddell","street":"1 coming down","city":"normalla...
#   addressbook <= addressbook::notify          {"user":"alice","msg":"alice successfully emplaced record to addressbook"}
>> Notified
#         alice <= addressbook::notify          {"user":"alice","msg":"alice successfully emplaced record to addressbook"}
#     abcounter <= abcounter::count             {"user":"alice","type":"emplace"}
warning: transaction executed locally, but may not be confirmed by the network yet    ]

8.6.4 Verify the liquidation of the alice user entry from the table by running:

cleos push action addressbook erase '["alice"]' -p alice@active

The action is considered to be successfully completed if the resulting output contains the following information:

executed transaction: ...
#   addressbook <= addressbook::erase           {"user":"alice"}
>> Erased
#   addressbook <= addressbook::notify          {"user":"alice","msg":"alice successfully erased record from addressbook"}
>> Notified
#         alice <= addressbook::notify          {"user":"alice","msg":"alice successfully erased record from addressbook"}
#     abcounter <= abcounter::count             {"user":"alice","type":"erase"}
warning: transaction executed locally, but may not be confirmed by the network yet    ]
Toaster:addressbook sandwich$

8.6.5 Test the ability to manipulate abcounter contract data by executing:

cleos push action abcounter count '["alice", "erase"]' -p alice@active
cleos get table abcounter abcounter counts --lower alice

The abcounter contract table should contain the following information:

{
  "rows": [{
      "key": "alice",
      "emplaced": 1,
      "modified": 1,
      "erased": 1
    }
  ],
  "more": false
}
Previous7 Adding Inline ActionsNext9 Conclusion

Last updated 5 years ago