Skip to main content
A plain transfer to a contract gives the contract tokens but no chance to react. The AndCall functions transfer, then call the recipient, which can record the deposit or send the tokens back. Use them when a contract must act on what it received, such as crediting a deposit.

Which functions make the callback?

In the wallet forms, inputProof comes right after the encrypted amount and before data. Both are bytes, so swapping them compiles and fails at runtime. data is passed to the recipient unchanged.

How does the callback work?

The token moves the amount first. If to has code, it then calls onConfidentialTransferReceived on it:
  1. The token shares the moved amount with to as a sharedEuint64 and calls the receiver with the operator (the caller of the token function), from, that amount, and data.
  2. The receiver returns a sharedEbool: true to keep the tokens, false to refuse them.
  3. The token moves back whatever the receiver refused: the full amount on false, zero on true.
If to has no code, there is no callback and the tokens stay with to. The function returns sent - refund as a sharedEuint64. That is zero when the receiver refused, and also zero when the sender’s balance was too low.

How do you implement a receiver?

Implement IERC7984Receiver. This receiver accepts deposits up to a cap and refuses larger ones:
CappedDepositBox.sol
Each step in the callback has a reason:
  • Check msg.sender. FHE.receiveEuint64Param accepts any share whose sharer is the caller. A contract you do not know can share an amount it invented and call you directly, so only trust the token you expect.
  • Unwrap with FHE.receiveEuint64Param. It reverts with NotShared or UnexpectedSharer unless the caller shared the amount with this contract in this transaction.
  • Call FHE.allowThis on what you store. The received amount carries access for this transaction only. Values you derive from it and keep need a persistent grant.
  • Return FHE.shareEbool(result, msg.sender). The token accepts the result only as a share from the address it called.
Decide in encrypted form. A receiver that branches on the amount in plaintext would have to decrypt it, which it cannot do inside the callback.
Do not move the tokens back yourself and also return false. The token refunds on false, so a receiver that does both pays twice. If the receiver no longer holds the amount when it returns false, the refund moves zero and the sender gets nothing back.

When does the transfer revert?

What does a callback transfer emit?

The refund step runs on every AndCall, even when it refunds zero or to has no code. Each call therefore emits Transfer and ConfidentialTransfer twice: once from from to to, then once from to back to from. The two steps also cancel out in the indicators. A callback transfer leaves both indicators where they were, except that a first-time recipient moves from 0 to 7984.0000.