I'm playing around with deferred transactions and encountered an oddity.
Say, we have a contract deployed on contract
, and an account account
.
contract
has [email protected]
as part of its active permission, account
does not.
The EOS Portal developer documentation states:
Deferred transactions carry the authority of the contract that sends them.
In my deferred action handler I require_auth(account)
and it passes.
Shouldn't it fail as the transaction has authorization [email protected] and thus fail as account@active does not contain [email protected]?
If I add a deferred transaction to transfer eosio.token it however does not correctly pass the authorization check.
Exception Details: 3090003 unsatisfied_authorization: Provided keys, permissions, and delays do not satisfy declared authorizations
transaction declares authority '{"actor":"account","permission":"active"}', but does not have signatures for it under a provided delay of 3000 ms, provided permissions [{"actor":"contract","permission":"eosio.code"}], and provided keys []
{"auth":{"actor":"account","permission":"active"},"provided_delay":3000,"provided_permissions":[{"actor":"contract","permission":"eosio.code"}],"provided_keys":[],"delay_max_limit_ms":3888000000}
Why does one require_auth
check pass, but the other doesn't?
Here's the code I deploy on contract
#include <string>
#include <eosiolib/eosio.hpp>
#include <eosiolib/transaction.hpp>
#include <eosiolib/currency.hpp>
using namespace eosio;
using namespace std;
class deferred_example : public eosio::contract
{
public:
deferred_example(account_name self) : contract(self)
{
}
/// @abi action
void deferred(account_name from, const string &message)
{
// why does this pass? shouldn't the permission be [email protected]
// and thus fail as from@active does not contain [email protected]?
require_auth(from);
print("Printing deferred ", eosio::name{from}, " : ", message);
}
/// @abi action
void send(account_name from, const string &message)
{
require_auth(from);
eosio::transaction t{};
// sending this passes the require_auth(from) check in _self::deferred
t.actions.emplace_back(
permission_level(from, N(active)),
_self,
N(deferred),
std::make_tuple(from, message));
// sending this fails the require_auth(from) check in eosio.token::transfer
// because from@active does not contain [email protected] to
// t.actions.emplace_back(permission_level(from, N(active)),
// N(eosio.token),
// N(transfer),
// currency::transfer{
// .from = from,
// .to = _self,
// .quantity = asset(10000, S(4, EOS)),
// .memo = "transfer EOS"});
t.delay_sec = 3;
// use now() as sender id for ease of use
t.send(now(), from);
print("Deferred transaction scheduled");
}
};
EOSIO_ABI(deferred_example, (send)(deferred))