Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client-sdk/guides/acps.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ client.acp.removeACP(acpHash);
client.acp.removeActiveACP();
```

## Validating {#validating-permits}
## Validating

`ACPUtils.validate` enforces the full check: schema, signed, and not expired. The decrypt flows call it for you and surface failures as typed errors, so validate manually only when you want to inspect or filter ACPs first.

Expand Down
4 changes: 2 additions & 2 deletions client-sdk/guides/client-setup.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const config = createCofheConfig({
supportedChains: [chains.sepolia],

// Optional knobs
// defaultPermitExpiration: 60 * 60 * 24 * 30,
// defaultACPExpiration: 60 * 60 * 24 * 30,
// useWorkers: true,
});
```
Expand Down Expand Up @@ -170,7 +170,7 @@ cofheClient.connection.account; // Alice's address

To manually disconnect, call `cofheClient.disconnect()`. This clears the in-memory connection state (clients/account/chainId) and marks the client as disconnected.

It does **not** delete persisted permits or stored FHE keys.
It does **not** delete persisted ACPs or stored FHE keys.

```typescript
cofheClient.disconnect();
Expand Down
52 changes: 26 additions & 26 deletions client-sdk/guides/decrypt-to-tx.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: Decrypt to Transact
description: "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.
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:

Expand All @@ -18,21 +18,21 @@ If you only need to show plaintext in your UI (and you do **not** need an onchai

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 [permit](/client-sdk/guides/permits).
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>

## Permit: when is it needed?
## 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 `.withoutPermit()`.
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 a permit is **not** needed:
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 `.withPermit(...)`.
If the ACL policy restricts decryption, you must use `.withACP(...)`.

## What `decryptForTx` returns

Expand All @@ -42,33 +42,33 @@ If the ACL policy restricts decryption, you must use `.withPermit(...)`.
- `decryptedValue: bigint`: the plaintext value (always a `bigint`)
- `signature: 0x${string}`: the Threshold Network signature as a hex string

## Decrypt (choose permit mode)
## Decrypt (choose ACP mode)

<CodeGroup>

```typescript No permit
```typescript No ACP
const decryptResult = await client
.decryptForTx(ctHash)
.withoutPermit()
.withoutACP()
.execute();

decryptResult.decryptedValue;
decryptResult.signature;
```

```typescript Active permit
```typescript Active ACP
const decryptResult = await client
.decryptForTx(ctHash)
.withPermit()
.withACP()
.execute();
```

```typescript Explicit permit
const permit = await client.permits.getOrCreateSelfPermit();
```typescript Explicit ACP
const acp = await client.acp.getOrCreateSelfACP();

const decryptResult = await client
.decryptForTx(ctHash)
.withPermit(permit)
.withACP(acp)
.execute();
```

Expand All @@ -82,23 +82,23 @@ After decrypting, see [Writing Decrypt Result to Contract](/client-sdk/guides/wr

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

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

- `.withPermit()`: uses the active permit
- `.withPermit(permitHash)`: fetches a stored permit by hash
- `.withPermit(permit)`: uses the provided permit object
- `.withACP()`: uses the active ACP
- `.withACP(acpHash)`: fetches a stored ACP by hash
- `.withACP(acp)`: uses the provided ACP object

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

Decrypt via global allowance (no permit). Only works if the contract's ACL policy allows anyone to decrypt that `ctHash`.
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 permit.
Overrides the account used to resolve the active/stored ACP.

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

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

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

Expand All @@ -107,7 +107,7 @@ Register a callback that fires once per poll attempt while `decryptForTx` waits
```typescript
const decryptResult = await client
.decryptForTx(ctHash)
.withoutPermit()
.withoutACP()
.onPoll(({ operation, requestId, attemptIndex, elapsedMs, intervalMs, timeoutMs }) => {
console.log(`[${operation}] attempt ${attemptIndex} after ${elapsedMs}ms (next in ${intervalMs}ms, budget ${timeoutMs}ms)`);
})
Expand All @@ -132,7 +132,7 @@ Configures how long `decryptForTx` keeps retrying when the Threshold Network's s
```typescript
const decryptResult = await client
.decryptForTx(ctHash)
.withoutPermit()
.withoutACP()
.set404RetryTimeout(20_000) // give a slower backend more time
.execute();
```
Expand All @@ -141,5 +141,5 @@ Pass `0` to disable submit-time retries (`404` becomes a hard failure). Submit r

## Common pitfalls

- **Permit mode must be selected**: you must call exactly one of `.withPermit(...)` or `.withoutPermit()` before `.execute()`.
- **Wrong chain/account**: permits are scoped to `chainId + account`. If you get an ACL/permit error, double-check the connected chain and account.
- **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.
52 changes: 26 additions & 26 deletions client-sdk/guides/decrypt-to-view.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Decrypt to View
description: "Reveal encrypted values locally for UI display using permits"
description: "Reveal encrypted values locally for UI display using ACPs"
---

Use `decryptForView` to reveal a confidential (encrypted) value locally in your app so you can display it in the UI.
Expand All @@ -10,18 +10,18 @@ Unlike [`decryptForTx`](/client-sdk/guides/decrypt-to-tx), this flow does **not*
## Flow

1. Read the encrypted handle (`ctHash`) from your contract.
2. Ensure you have a permit that authorizes decryption of that value.
2. Ensure you have an ACP that authorizes decryption of that value.
3. Call `decryptForView(ctHash, utype).execute()` to get the plaintext.

<Note>
`decryptForView` always decrypts using a permit (there is no `.withoutPermit()` mode). If your protocol intends for the plaintext to become publicly visible onchain, use [`decryptForTx`](/client-sdk/guides/decrypt-to-tx) instead.
`decryptForView` always decrypts using an ACP (there is no `.withoutACP()` mode). If your protocol intends for the plaintext to become publicly visible onchain, use [`decryptForTx`](/client-sdk/guides/decrypt-to-tx) instead.
</Note>

## Prerequisites

1. [Create and connect a client](/client-sdk/guides/client-setup).
2. Know the encrypted handle (`ctHash`) and the encrypted type (`utype`).
3. Have a [permit](/client-sdk/guides/permits) available for the connected `chainId + account`.
3. Have a [ACP](/client-sdk/guides/acps) available for the connected `chainId + account`.

<Tip>
**Getting `ctHash`**: In most apps, `ctHash` comes from reading a stored encrypted value, an event arg, or a return value from a `view` call.
Expand All @@ -36,45 +36,45 @@ Supported `utype`s:
- `FheTypes.Uint8 | Uint16 | Uint32 | Uint64 | Uint128` to returns a `bigint`
</Tip>

## Permit setup
## ACP setup

If you don't have a permit yet, create one once after connecting:
If you don't have an ACP yet, create one once after connecting:

```typescript
await client.connect(publicClient, walletClient);

// Creates a permit if needed, stores it, and selects it as the active permit.
await client.permits.getOrCreateSelfPermit();
// Creates an ACP if needed, stores it, and selects it as the active ACP.
await client.acp.getOrCreateSelfACP();
```

## Decrypt for UI

Choose the pattern that matches how your app manages permits:
Choose the pattern that matches how your app manages ACPs:

<CodeGroup>

```typescript Active permit
```typescript Active ACP
await client.connect(publicClient, walletClient);
await client.permits.getOrCreateSelfPermit();
await client.acp.getOrCreateSelfACP();

const plaintext = await client
.decryptForView(ctHash, FheTypes.Uint32)
.execute();
```

```typescript Permit object
const permit = await client.permits.getOrCreateSelfPermit();
```typescript ACP object
const acp = await client.acp.getOrCreateSelfACP();

const plaintext = await client
.decryptForView(ctHash, FheTypes.Uint64)
.withPermit(permit)
.withACP(acp)
.execute();
```

```typescript Permit hash
```typescript ACP hash
const plaintext = await client
.decryptForView(ctHash, FheTypes.Uint8)
.withPermit(permitHash)
.withACP(acpHash)
.execute();
```

Expand All @@ -94,23 +94,23 @@ Running `.execute()` resolves to a scalar JS value:

Runs the decryption and returns a UI-friendly scalar value.

### `.withPermit(...)` (optional)
### `.withACP(...)` (optional)

Select which permit to use:
Select which ACP to use:

- `.withPermit()`: uses the active permit
- `.withPermit(permitHash)`: fetches a stored permit by hash
- `.withPermit(permit)`: uses the provided permit object
- `.withACP()`: uses the active ACP
- `.withACP(acpHash)`: fetches a stored ACP by hash
- `.withACP(acp)`: uses the provided ACP object

If you don't call `.withPermit(...)`, the active permit is used by default.
If you don't call `.withACP(...)`, the active ACP is used by default.

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

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

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

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

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

Expand Down Expand Up @@ -174,6 +174,6 @@ const shortOwner = `${decryptedOwner.slice(0, 6)}…${decryptedOwner.slice(-4)}`

## Common pitfalls

- **Missing permit**: `decryptForView` will fail if there is no active permit for the current `chainId + account`.
- **Missing ACP**: `decryptForView` will fail if there is no active ACP for the current `chainId + account`.
- **Wrong `utype`**: you must pass the correct FHE type for the ciphertext.
- **Wrong chain/account**: permits are scoped to `chainId + account`. If the user switches wallets or networks, create/select the correct permit.
- **Wrong chain/account**: ACPs are scoped to `chainId + account`. If the user switches wallets or networks, create/select the correct ACP.
Loading
Loading