When programming smart contracts or writing eosjs
code, there are certain pitfalls that you might fall into if you are not careful. What are some of the patterns and anti-patterns to be aware of that specifically affect EOSIO code?
1 Answer
Check who receives a transfer when notifying a contract
If you have code which is activated upon receipt of a notification. For example:
[[eosio::on_notify("eosio.token::transfer")]] void transfer(eosio::name const & from, eosio::name const & to, eosio::asset const & quantity, std::string const & memo);
Then you should check that the to
field is actually this contract, and do nothing otherwise:
void mycontract::transfer(eosio::name const & from, eosio::name const & to, eosio::asset const & quantity, std::string const & memo)
{
if(to != get_self()) return;
// Process the transfer
}
This prevents people forwarding notifications for transactions that do not involve your contract, and tricking your contract into thinking that they have indeed sent money to you.
Check that the asset received truly is the one you expect
In EOSIO, anyone can make any asset and give it any name they want. So if I choose to, I can call an asset called EOS
on my personal smart contract based on eosio.token
, issue myself a billion of them, and then try to trick smart contracts that don't check for this vulnerability. This will affect your code if you accept multiple tokens for different reasons, using:
[[eosio::on_notify("*::transfer")]] void transfer(eosio::name const & from, eosio::name const & to, eosio::asset const & quantity, std::string const & memo);
You can check which token you are receiving with the following code:
void mycontract::transfer(eosio::name const & from, eosio::name const & to, eosio::asset const & quantity, std::string const & memo)
{
if(get_first_receiver() != eosio::name("eosio.token")) return;
}