Skip to main content
An operator is an address that may move any amount of a holder’s tokens until a deadline. FHERC20 has no per-amount allowance, so operators are how a holder lets someone else spend: a payment app, a vault, or a second wallet.

How do you grant and revoke an operator?

The holder calls setOperator(address operator, uint48 until), where until is a Unix timestamp in seconds:
Each call replaces the previous deadline for that pair, so the same call extends or shortens it. To revoke, set until to 0:
Every call emits OperatorSet(holder, operator, until). isOperator(holder, spender) returns true while block.timestamp <= until, so the deadline second itself is still valid. A holder is always its own operator.
An operator can move the holder’s whole balance, in any number of transfers, until the deadline. There is no amount cap. Grant the shortest window that covers the task, and revoke it when the task is done.

What can an operator call?

Operator rights apply to every function that takes a from address:
  • confidentialTransferFrom, in both the wallet and the contract form. See transfers.
  • confidentialTransferFromAndCall. See transfer callbacks.
  • unshield(from, to, amount) on the wrappers, which sends the underlying tokens to any to.
A caller that is not an operator for from gets FHERC20UnauthorizedSpender(holder, spender).

How does an operator transfer from a wallet?

The operator encrypts the amount with its own SDK client and sends the transaction itself. An input encrypted by the holder fails with InvalidSigner when the operator submits it, because the proof is bound to the sender.
A balance that is too low moves zero, as with any transfer. The operator does not learn the holder’s balance from the result unless it is the recipient.

How does a contract act as an operator?

A contract that pulls tokens from users, such as a vault, must be an operator for each user. The user calls setOperator(vaultAddress, until) before calling the vault. The vault then calls the sharedEuint64 form of confidentialTransferFrom, and msg.sender in the token is the vault. Call a token from your contract has a complete vault that deposits and withdraws this way.