1. What does "require_recipient" function actually do? What's the difference between require_recipient and inline action?
  2. If contract A calls contract B using require_recipient, can contract B use require_recipient again and call contract C? If not, why?

Actually, I am coding my "notify" function which will listen to eosio.token then take actions when somebody transfer eos to my contract, and wondering if the answer to question 2 is yes, is an attacker have chance that call my "notify" function more than once in a single transaction.
As you can see the code of transfer function in eosio.token(code here), the transfer function will call both sender's and receiver's "notify" function, so, what will happen if sender calls receiver's "notify" in its "notify" function using require_recipient? Will receiver's "notify" function called twice?
I tested it and it turns out that the transaction was succeed but receiver's "notify" function only ran once, but I don't know if EOS has any mechanism to prevent that, or just some error in my test code.

In other words, I am asking if this situation could happen:
1. attacker calls eosio.token and transfer to victim.
2. eosio.token calls attacker's "notify" function.
3. attacker's "notify" function uses require_recipient and calls victim's "notify" function, victim's "notify" function executed for the first time.
4. eosio.token calls victim's "notify" function, so victim's "notify" function executed for the second time.
Since the transfer is real happened and require_recipient do not change the data, victim's "notify" function will called twice with code == "eosio.token", action == "transfer" and to == _self. It seems that it it impossible to distinguish these two calls by action data. But in my test victim's "notify" function only called once, so does eos have any mechanism to prevent that?

1 Answer 1



Read this medium article regarding attack vectors and inline actions:


Original Answer:

  1. require_recipient sends a notification to the account of the transaction that they are being included in, you cannot change what data is being sent because it is set by the action. An inline action allows you to specify who it's going to and what data it contains. Furthermore require_recipient could be responded to (like an inline action as you suggest) if the recipient has a contract loaded on their account configured to respond with an assertion or an inline action of their own. If they have no contract then it will not do anything.

  2. Contract A could call contract B with the require_recipient and contract B could handle that and send a require_recipient to contract C but with the notification of the action it was included in from contract B, not the original from contract A.

In summary:

The require_recipient is meant to be like a receipt of the transaction taking place. This is to ensure that the end user is notified and has a copy of what transpired. Inline actions can be custom configured, here's an example:

// send msgnotify to 'to' account
eosio::action( eosio::permission_level{_self, "active"_n}, 
    to, "msgnotify"_n, std::make_tuple( from, msg_id, msg_sha) ).send();

Docs link for require_recipient. The docs aren't displaying correctly, but it's under the command I linked to.

  • Your answer to question 2 is yes, is there any way for contract C to know which contract initiated the call? Furthermore, I am curious about if there is a vulnerability and I have my question updated. Thanks.
    – sabersauce
    Dec 17, 2018 at 2:49
  • There's a great medium article that answer this in detail. I'll attach it to my answer.
    – Nat
    Dec 17, 2018 at 11:20
  • The article is great but did not answer my question. I have my question updated again with more details.
    – sabersauce
    Dec 18, 2018 at 2:39
  • Hm, I'm not sure on that one. Sorry. I hope someone else can answer your question in more detail.
    – Nat
    Dec 18, 2018 at 2:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.