Skip to main content

Overview

FHERC20 supports safe transfers with callbacks. When you use the ...AndCall functions, the recipient contract is notified of the incoming transfer and can accept or reject it. This enables atomic operations where token transfers and contract logic execute together.

Atomic Operations

Transfer tokens and execute contract logic in a single transaction, ensuring both succeed or both fail.

Recipient Validation

Recipients must explicitly accept transfers by implementing IERC7984Receiver, preventing tokens from being locked in incompatible contracts.

Custom Logic

Recipients can execute arbitrary logic upon receiving tokens, enabling complex DeFi interactions.

Data Passing

Pass arbitrary data along with transfers to provide context or instructions to the recipient.

Transfer And Call Functions

FHERC20 provides four functions that support callbacks:

Confidential Transfer And Call

Transfer tokens from caller to recipient with callback:

Confidential Transfer From And Call

Transfer tokens from a third party to recipient with callback (requires operator permission):
Parameters:
  • to: Recipient address (must implement IERC7984Receiver if it’s a contract)
  • from: Source address (only for ...From... variants)
  • inValue/value: Encrypted amount to transfer
  • data: Arbitrary data to pass to recipient
Returns:
  • transferred: The actual encrypted amount transferred (may be zero if insufficient balance)

The IERC7984Receiver Interface

Any contract that wants to receive tokens via ...AndCall functions must implement the IERC7984Receiver interface:

Function Parameters

  • operator: The address that initiated the transfer (msg.sender of the …AndCall function)
  • from: The address tokens are being transferred from
  • amount: The encrypted amount being transferred (euint64)
  • data: Arbitrary data passed along with the transfer

Return Value

The function must return an ebool (encrypted boolean):
  • FHE.asEbool(true): Accept the transfer
  • FHE.asEbool(false): Reject the transfer (tokens will be returned to sender)
If onConfidentialTransferReceived returns encrypted false, the entire transfer is reversed. The tokens return to the sender as if the transfer never happened.

How It Works

1

Initiate Transfer

User calls confidentialTransferAndCall or confidentialTransferFromAndCall with recipient address, encrypted amount, and optional data.
2

Execute Transfer

FHERC20 performs the normal confidential transfer, updating balances and access controls.
3

Check Recipient

If the recipient is a contract (code size > 0), FHERC20 checks if it implements IERC7984Receiver.
4

Call Callback

If implemented, FHERC20 calls onConfidentialTransferReceived on the recipient contract.
5

Evaluate Response

The recipient returns encrypted true (accept) or false (reject). FHERC20 evaluates this response.
6

Finalize or Revert

If accepted, the transfer is complete. If rejected, tokens are returned to sender.

Implementing IERC7984Receiver

Basic Implementation

Here’s a minimal receiver that accepts all transfers:

Conditional Acceptance

Accept transfers only under certain conditions:

With Custom Logic

Execute logic upon receiving tokens:

Using Transfer Callbacks

Basic Usage

Passing Data

You can encode arbitrary data to pass to the recipient:
The recipient can decode this data:

Reversion Behavior

When Does It Revert?

The transfer will revert if:

When Does It Succeed?

The transfer succeeds if:

Security Considerations

Reentrancy Protection

The callback happens after the balance transfer but before the transaction completes. Implement reentrancy guards if your receiver makes external calls.

Gas Limits

Callback execution is subject to gas limits. Keep logic simple:

Untrusted Senders

Your receiver will be called by anyone who transfers tokens to you. Validate the sender:

Data Validation

Always validate the data parameter before using it:

Best Practices

Keep Callbacks Simple

Minimize gas usage in your onConfidentialTransferReceived implementation. Complex logic should be moved to separate functions.

Validate Everything

Always validate the token sender (msg.sender), the transfer initiator (operator), and the source (from) before accepting transfers.

Handle Failures Gracefully

Return FHE.asEbool(false) to reject transfers rather than reverting, when possible. This provides better UX.

Test Thoroughly

Test both acceptance and rejection scenarios, including edge cases like zero transfers and malformed data.