> ## Documentation Index
> Fetch the complete documentation index at: https://fhenix-ci-version-drift-check.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Decrypt to Transact

> Decrypt with a verifiable Threshold Network signature for onchain use

Use `decryptForTx` to reveal a confidential (encrypted) value onchain. It returns the plaintext together with a Threshold Network signature, so a contract can verify the reveal when you publish it in a transaction.

Common use cases:

* **Unshield a confidential token**: reveal the encrypted amount you're unshielding so the contract can finalize the public transfer.
* **Finalize a private auction / game move**: bids or moves are submitted encrypted, and the winner is revealed later in a verifiable way.

<Note>
  If you only need to show plaintext in your UI (and you do **not** need an onchain-verifiable signature), use [`decryptForView`](/client-sdk/guides/decrypt-to-view) instead.
</Note>

## Prerequisites

1. [Create and connect a client](/client-sdk/guides/client-setup).
2. Know the onchain encrypted handle (`ctHash`) you want to decrypt.
3. Determine whether the contract's ACL policy for this `ctHash` requires a [ACP](/client-sdk/guides/acps).

<Note>
  `decryptForTx` does not take a `utype`. It always returns the plaintext as a `bigint` because the result is intended to be passed into a transaction. If you need UI-friendly decoding, use [`decryptForView`](/client-sdk/guides/decrypt-to-view).
</Note>

## ACP: when is it needed?

Often, `decryptForTx` is used to reveal a value that the protocol already considers OK to make public. In those cases, the contract's ACL policy can allow anyone to decrypt, and you can use `.withoutACP()`.

Examples where an ACP is **not** needed:

* **Unshielding**: the amount being unshielded is no longer meant to stay secret.
* **Auction/game reveal**: it doesn't matter who submits the reveal, only that the result is verified.

If the ACL policy restricts decryption, you must use `.withACP(...)`.

## What `decryptForTx` returns

`.execute()` resolves to an object with:

* `ctHash: bigint | string`: the ciphertext handle you decrypted
* `decryptedValue: bigint`: the plaintext value (always a `bigint`)
* `signature: 0x${string}`: the Threshold Network signature as a hex string

## Decrypt (choose ACP mode)

<CodeGroup>
  ```typescript No ACP theme={null}
  const decryptResult = await client
    .decryptForTx(ctHash)
    .withoutACP()
    .execute();

  decryptResult.decryptedValue;
  decryptResult.signature;
  ```

  ```typescript Active ACP theme={null}
  const decryptResult = await client
    .decryptForTx(ctHash)
    .withACP()
    .execute();
  ```

  ```typescript Explicit ACP theme={null}
  const acp = await client.acp.getOrCreateSelfACP();

  const decryptResult = await client
    .decryptForTx(ctHash)
    .withACP(acp)
    .execute();
  ```
</CodeGroup>

After decrypting, see [Writing Decrypt Result to Contract](/client-sdk/guides/writing-decrypt-result) for how to publish or verify the result onchain.

## Builder API

### `.execute()` (required, call last)

Runs the decryption and returns `{ ctHash, decryptedValue, signature }`.

### `.withACP(...)` (required unless using `.withoutACP()`)

* `.withACP()`: uses the active ACP
* `.withACP(acpHash)`: fetches a stored ACP by hash
* `.withACP(acp)`: uses the provided ACP object

### `.withoutACP()` (required unless using `.withACP(...)`)

Decrypt via global allowance (no ACP). Only works if the contract's ACL policy allows anyone to decrypt that `ctHash`.

### `.setAccount(address)` (optional)

Overrides the account used to resolve the active/stored ACP.

### `.setChainId(chainId)` (optional)

Overrides the chain used to resolve the Threshold Network URL and ACPs.

### `.onPoll(callback)` (optional)

Register a callback that fires once per poll attempt while `decryptForTx` waits for the Threshold Network to return the plaintext. Useful for surfacing progress in a UI.

```typescript theme={null}
const decryptResult = await client
  .decryptForTx(ctHash)
  .withoutACP()
  .onPoll(({ operation, requestId, attemptIndex, elapsedMs, intervalMs, timeoutMs }) => {
    console.log(`[${operation}] attempt ${attemptIndex} after ${elapsedMs}ms (next in ${intervalMs}ms, budget ${timeoutMs}ms)`);
  })
  .execute();
```

The callback receives:

| Field          | Type                        | Description                                                                                                                     |
| -------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `operation`    | `'decrypt' \| 'sealoutput'` | Which Threshold Network flow is polling. For `decryptForTx` this is always `'decrypt'`.                                         |
| `requestId`    | `string`                    | The Threshold Network request id. **May be the empty string** during submit-time retries, see `.set404RetryTimeout(...)` below. |
| `attemptIndex` | `number`                    | Zero-based poll attempt counter.                                                                                                |
| `elapsedMs`    | `number`                    | Time since the first submit attempt.                                                                                            |
| `intervalMs`   | `number`                    | Delay until the next poll.                                                                                                      |
| `timeoutMs`    | `number`                    | Overall budget shared by submit-retries and status-polling.                                                                     |

### `.set404RetryTimeout(timeoutMs)` (optional)

Configures how long `decryptForTx` keeps retrying when the Threshold Network's submit endpoint responds with `404 Not Found` before a `requestId` is available. This typically happens on slower backends where the ciphertext isn't visible yet at submit time. Defaults to `10_000` ms.

```typescript theme={null}
const decryptResult = await client
  .decryptForTx(ctHash)
  .withoutACP()
  .set404RetryTimeout(20_000) // give a slower backend more time
  .execute();
```

Pass `0` to disable submit-time retries (`404` becomes a hard failure). Submit retries share the same overall timeout budget as status polling, so a larger value here trades poll time for submit-recovery time.

## Common pitfalls

* **ACP mode must be selected**: you must call exactly one of `.withACP(...)` or `.withoutACP()` before `.execute()`.
* **Wrong chain/account**: ACPs are scoped to `chainId + account`. If you get an ACL/ACP error, double-check the connected chain and account.
