> ## Documentation Index
> Fetch the complete documentation index at: https://cofhe-docs.fhenix.zone/llms.txt
> Use this file to discover all available pages before exploring further.

# Operators

> Let another account or contract move FHERC20 tokens for a holder until a deadline

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:

```typescript theme={null}
const block = await provider.getBlock('latest');
await token.setOperator(operatorAddress, block.timestamp + 3600);
```

Each call replaces the previous deadline for that pair, so the same call extends or shortens it. To revoke, set `until` to `0`:

```typescript theme={null}
await token.setOperator(operatorAddress, 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.

<Warning>
  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.
</Warning>

## 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](/cofhe/fhe-library/confidential-contracts/fherc20/core-features#which-transfer-function-do-you-call).
* `confidentialTransferFromAndCall`. See [transfer callbacks](/cofhe/fhe-library/confidential-contracts/fherc20/transfer-callbacks).
* `unshield(from, to, amount)` on the [wrappers](/cofhe/fhe-library/confidential-contracts/fherc20/fherc20-wrapper), 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.

```typescript theme={null}
import { Encryptable } from '@cofhe/sdk';

const [amount, inputProof] = await operatorClient
  .encryptInputs([Encryptable.uint64(30_000_000n)])
  .setConsumingContract(await token.getAddress())
  .execute();

await token
  .connect(operatorSigner)
  ['confidentialTransferFrom(address,address,bytes32,bytes)'](holder, recipient, amount, inputProof);
```

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](/cofhe/fhe-library/confidential-contracts/calling-from-contracts) has a complete vault that deposits and withdraws this way.

## Related pages

* [Transfers and disclosure](/cofhe/fhe-library/confidential-contracts/fherc20/core-features)
* [Best practices](/cofhe/fhe-library/confidential-contracts/fherc20/best-practices)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.