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 contract@eosio.code 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 contract@eosio.code and thus fail as account@active does not contain contract@eosio.code?

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 []

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
    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 contract@eosio.code
        // and thus fail as from@active does not contain contract@eosio.code?

        print("Printing deferred ", eosio::name{from}, " : ",  message);

    /// @abi action
    void send(account_name from, const string &message)

        eosio::transaction t{};

        // sending this passes the require_auth(from) check in _self::deferred
            permission_level(from, N(active)),
            std::make_tuple(from, message));

        // sending this fails the require_auth(from) check in eosio.token::transfer
        // because from@active does not contain contract@eosio.code 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))

I would refer to this: https://github.com/EOSIO/eos/issues/3013

It looks like Dawn 4.0 changed the permissions a contract needs to call another contract. You need to grant account@eosio.code permissions to the contract you are calling from "account".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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