Eos: Signing action that is made inside the contract?

Created on 5 Jun 2018  ยท  8Comments  ยท  Source: EOSIO/eos

I wonder whether it is possible to sign the action, that inside makes a transaction as well (and requires signing by sender not by the contract itself):

action{
   permission_level{ sender, N(active) },
   N(TOKEN),
   N(transfer),
   currency::transfer{
   .from = sender,.to = receiver,.quantity = receiverasset,.memo = "transaction" }
  }.send();

When I try to run it I get an error:

Error 3090003: provided keys, permissions, and delays do not satisfy declared authorizations
Ensure that you have the related private keys inside your wallet and your wallet is unlocked.
Error Details:
transaction declares authority '{"actor":"senderaccount","permission":"active"}', but does not have signatures
for it under a provided delay of 0 ms

Most helpful comment

When a contract (say its deployed on the account contract1111) sends an inline action or a deferred transaction, it only provides the automatically satisfied permission [email protected]. If the authorizations of the actions can be satisfied (perhaps indirectly) by [email protected], then it can send those actions. Otherwise, it is not possible (with the exception of the contract account being privileged, as can be seen with the eosio.system contract deployed on the privileged eosio account).

Just because a user signs a transaction including an action delivered to some contract, it does not necessarily mean that the user wants to give that contract authorization to sign any transaction on that user's behalf. If EOSIO were to be designed in that alternative way, a user sending a low stakes action to some minimally-trusted contract might have had their tokens stolen by the contract.

If you want the contract to be able to generally send tokens on a user's behalf, the user must allow the [email protected] permission to unilaterally satisfy one of their permissions which is (or is the parent of) the minimum permission the eosio.token::transfer action is linked to. Unless overridden with the eosio::linkauth action, all actions by default link to the active permission of the authorizing account.

However, that strategy is not recommended for what it appears you are trying to do. After all, why should a user trust your contract with the ability to spend all of their money whenever and however they want? Instead, it appears that you wish to execute an action in your contract that relies on the user sending a certain amount of tokens to the contract.

Instead of doing an inline send of the eosio.token::transfer action, your contract could listen to the eosio.token::transfer action and use the contents of the memo field to decide what action to do in response. See how depositing funds works in the exchange example contract.

Alternatively, your contract's action could hold an index to another action in the transaction which your contract could read and require it to be a eosio.token::transfer action from the user to the contract for the exact amount required by the contract. This approach can work assuming the exact amount required by the contract can be known prior to the contract executing. This would put the burden on the user (or more likely the client-side tools used by the user) to properly craft the transaction with the two actions included within. Unfortunately, we don't yet have a good example in the contracts folder demonstrating this approach.

All 8 comments

When a contract (say its deployed on the account contract1111) sends an inline action or a deferred transaction, it only provides the automatically satisfied permission [email protected]. If the authorizations of the actions can be satisfied (perhaps indirectly) by [email protected], then it can send those actions. Otherwise, it is not possible (with the exception of the contract account being privileged, as can be seen with the eosio.system contract deployed on the privileged eosio account).

Just because a user signs a transaction including an action delivered to some contract, it does not necessarily mean that the user wants to give that contract authorization to sign any transaction on that user's behalf. If EOSIO were to be designed in that alternative way, a user sending a low stakes action to some minimally-trusted contract might have had their tokens stolen by the contract.

If you want the contract to be able to generally send tokens on a user's behalf, the user must allow the [email protected] permission to unilaterally satisfy one of their permissions which is (or is the parent of) the minimum permission the eosio.token::transfer action is linked to. Unless overridden with the eosio::linkauth action, all actions by default link to the active permission of the authorizing account.

However, that strategy is not recommended for what it appears you are trying to do. After all, why should a user trust your contract with the ability to spend all of their money whenever and however they want? Instead, it appears that you wish to execute an action in your contract that relies on the user sending a certain amount of tokens to the contract.

Instead of doing an inline send of the eosio.token::transfer action, your contract could listen to the eosio.token::transfer action and use the contents of the memo field to decide what action to do in response. See how depositing funds works in the exchange example contract.

Alternatively, your contract's action could hold an index to another action in the transaction which your contract could read and require it to be a eosio.token::transfer action from the user to the contract for the exact amount required by the contract. This approach can work assuming the exact amount required by the contract can be known prior to the contract executing. This would put the burden on the user (or more likely the client-side tools used by the user) to properly craft the transaction with the two actions included within. Unfortunately, we don't yet have a good example in the contracts folder demonstrating this approach.

Ok. Many thanks @arhag - you have clearly read my intentions and basically I understand being able to sign the transactions inside the contract would be clearly risky.

Instead of doing an inline send of the eosio.token::transfer action, your contract could listen to the
eosio.token::transfer action and use the contents of the memo field to decide what action to do in
response. See how depositing funds works in the exchange example contract.

What I want to do is: when a user sends a payment to my contract it is send to other accounts.
I have an account "payment" and a token contract "mytoken" with token "MYTOKEN".
I want to run payment::process each time account "payment" receives "MYTOKEN" (so mytoken::transfer).
How to listen to it?

What I want to do is: when a user sends a payment to my contract it is send to other accounts.

Take a look at the proxy contract. It does something very similar to what you want to do. Although, if you do not need to delay (like the proxy contract does), then it would be better to send an inline action for your case rather than sending a deferred transaction as the proxy contract does.

Also, the proxy example contract's setowner action does not prevent someone from overriding a currently existing owner, so don't follow that bad security practice from the example. But the example contract does show the general principle of listening to a transfer action and acting in response to it.

Thank you for the tips. Still I do not understand how it works.

I am just calling transfer method on eosio.token and how proxy contract knows that this method was launched? I mean where is this magic, that the event took place and we now run the method?
Because of this apply_transfer method? I see it takes some transaction, then makes the asserts and creates another transaction to send to owner account https://github.com/EOSIO/eos/blob/v1.0.1/contracts/proxy/proxy.cpp#L36
How this works that this apply_transfer knows which contract and method listen to?
How executing eosio.token::transfer makes executing method within proxy contract as well?

Anyway I understand that proxy contract is not up-to-date right now?
https://github.com/EOSIO/eos/issues/3086

Ok. It seems I found it:
https://forums.eosgo.io/discussion/786/how-do-you-subscribe-for-events

extern "C" {

/// The apply method implements the dispatch of events to this contract
void apply( uint64_t receiver, uint64_t code, uint64_t action ) {

@filipniziol the apply can't get all transfer actions, transfer only broadcast to from and to. So how do you solve the problem then?

@breadbread1984 check this other contract as example.
It handles a few different events in the same action, including a transcation and a custom action.

@Falci thx. Later I see EOS's contract register the recipient of the broadcast by require_recipient(). Not all nodes can receive the notification of a transaction

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bezalel picture bezalel  ยท  3Comments

congnghebitcoin picture congnghebitcoin  ยท  3Comments

zxf969175364 picture zxf969175364  ยท  3Comments

toonsevrin picture toonsevrin  ยท  3Comments

ResponsiveWebApps picture ResponsiveWebApps  ยท  3Comments