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
4 changes: 2 additions & 2 deletions client-sdk/examples/end-to-end.mdx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
---
title: End-to-End Example
description: "A complete encrypt store decrypt flow using @cofhe/sdk"
description: "A complete encrypt to store to decrypt flow using @cofhe/sdk"
---

This example demonstrates the full lifecycle of working with encrypted data: initialize the SDK, encrypt a value, send it to a contract, and decrypt the resultboth for UI display and for on-chain verification.
This example demonstrates the full lifecycle of working with encrypted data: initialize the SDK, encrypt a value, send it to a contract, and decrypt the result, both for UI display and for onchain verification.

## The contract

Expand Down
24 changes: 12 additions & 12 deletions client-sdk/foundry-plugin/getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ title: Getting Started
description: "Set up @cofhe/foundry-plugin for local FHE contract development and testing under Forge"
---

`@cofhe/foundry-plugin` is the Foundry counterpart to [`@cofhe/hardhat-plugin`](/client-sdk/hardhat-plugin/getting-started). It provides two abstract Solidity contracts`CofheTest` (test base, deploys all CoFHE mocks) and `CofheClient` (per-account encrypt/decrypt/permit shim) that let you exercise FHE contracts under `forge test` with **no JS SDK required**.
`@cofhe/foundry-plugin` is the Foundry counterpart to [`@cofhe/hardhat-plugin`](/client-sdk/hardhat-plugin/getting-started). It provides two abstract Solidity contracts, `CofheTest` (test base, deploys all CoFHE mocks) and `CofheClient` (per-account encrypt/decrypt/permit shim), that let you exercise FHE contracts under `forge test` with **no JS SDK required**.

<Tip>
Want to skip the setup? Clone the [cofhe-foundry-starter](https://github.com/FhenixProtocol/cofhe-foundry-starter) template to get a pre-configured project ready to go.
</Tip>

## What the plugin provides

- **`CofheTest`** abstract test base that inherits `forge-std/Test` and deploys the full CoFHE mock stack (`MockTaskManager`, `MockACL`, `MockZkVerifier`, `MockThresholdNetwork`).
- **`CofheClient`** in-Solidity SDK shim. One client per "user" in your scenario; each client carries a private key and produces encrypted inputs and signed permits as if it were that user's frontend SDK.
- **Plaintext assertions**`expectPlaintext(handle, value)` reads the on-chain plaintext from the mock task manager. Faster than `decryptForView` and needs no permit.
- **`CofheTest`**: abstract test base that inherits `forge-std/Test` and deploys the full CoFHE mock stack (`MockTaskManager`, `MockACL`, `MockZkVerifier`, `MockThresholdNetwork`).
- **`CofheClient`**: in-Solidity SDK shim. One client per "user" in your scenario; each client carries a private key and produces encrypted inputs and signed permits as if it were that user's frontend SDK.
- **Plaintext assertions**: `expectPlaintext(handle, value)` reads the onchain plaintext from the mock task manager. Faster than `decryptForView` and needs no permit.

## Prerequisites

Expand Down Expand Up @@ -71,12 +71,12 @@ code_size_limit = 100000 # mocks exceed 24 KB
```

<Warning>
- `code_size_limit = 100000` is required the mock contracts exceed the EIP-170 24 KB ceiling.
- `code_size_limit = 100000` is required, the mock contracts exceed the EIP-170 24 KB ceiling.
- `solc_version = "0.8.25"` matches the compiler used by `@fhenixprotocol/cofhe-contracts`.
</Warning>

<Note>
`evm_version = "cancun"` is no longer required as of `@cofhe/mock-contracts@0.5.0` `MockACL` was migrated off transient storage (`tstore`/`tload`) to block-number-based storage, and the pragma was lowered to `>=0.8.19`. Set it only if your own contracts need cancun-specific opcodes.
`evm_version = "cancun"` is no longer required as of `@cofhe/mock-contracts@0.5.0`. `MockACL` was migrated off transient storage (`tstore`/`tload`) to block-number-based storage, and the pragma was lowered to `>=0.8.19`. Set it only if your own contracts need cancun-specific opcodes.
</Note>

</Step>
Expand Down Expand Up @@ -123,7 +123,7 @@ contract MyTest is CofheTest {

## Version pinning

The plugin and `@cofhe/mock-contracts` pin `@fhenixprotocol/cofhe-contracts` *exactly* (no caret). Keep the three CoFHE packages aligned otherwise `npm install` may resolve `cofhe-contracts` to a newer version that the mocks don't implement, producing `MockTaskManager should be marked as abstract` at compile time.
The plugin and `@cofhe/mock-contracts` pin `@fhenixprotocol/cofhe-contracts` *exactly* (no caret). Keep the three CoFHE packages aligned, otherwise `npm install` may resolve `cofhe-contracts` to a newer version that the mocks don't implement, producing `MockTaskManager should be marked as abstract` at compile time.

Known-aligned tuple as of writing:

Expand All @@ -139,15 +139,15 @@ See the [Compatibility](/get-started/introduction/compatibility) page for the ca

The mocks are the same `@cofhe/mock-contracts` package the [Hardhat plugin](/client-sdk/hardhat-plugin/mock-contracts) uses. Behaviorally:

- Plaintext lives on-chain in `MockTaskManager.mockStorage` (so `expectPlaintext` and `getPlaintext` work).
- Plaintext lives onchain in `MockTaskManager.mockStorage` (so `expectPlaintext` and `getPlaintext` work).
- No real ZK proving; encrypted inputs are signed by `MockZkVerifierSigner`.
- Decryption is synchronous `decryptForTx_withoutPermit` returns the result immediately.
- Decryption is synchronous. `decryptForTx_withoutPermit` returns the result immediately.
- Mock signatures are accepted by the same `FHE.verifyDecryptResult` your contract uses on testnet.

The same test code runs unchanged against real CoFHE on a deployed network.

## Next steps

- [CofheTest](/client-sdk/foundry-plugin/cofhe-test) the test base contract: `deployMocks`, `expectPlaintext`, `getPlaintext`, log toggles.
- [CofheClient](/client-sdk/foundry-plugin/cofhe-client) per-user shim: `createInEuintN`, `decryptForTx_withoutPermit`, `decryptForView`, permits.
- [Testing](/client-sdk/foundry-plugin/testing) canonical test patterns and the migration mapping from the old `@cofhe/mock-contracts/foundry/CoFheTest.sol` API.
- [CofheTest](/client-sdk/foundry-plugin/cofhe-test): the test base contract: `deployMocks`, `expectPlaintext`, `getPlaintext`, log toggles.
- [CofheClient](/client-sdk/foundry-plugin/cofhe-client): per-user shim: `createInEuintN`, `decryptForTx_withoutPermit`, `decryptForView`, permits.
- [Testing](/client-sdk/foundry-plugin/testing): canonical test patterns and the migration mapping from the old `@cofhe/mock-contracts/foundry/CoFheTest.sol` API.
40 changes: 20 additions & 20 deletions client-sdk/guides/decrypt-to-tx.mdx
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
---
title: Decrypt to Transact
description: "Decrypt with a verifiable Threshold Network signature for on-chain use"
description: "Decrypt with a verifiable Threshold Network signature for onchain use"
---

Use `decryptForTx` to reveal a confidential (encrypted) value on-chain: 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:

- **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 on-chain-verifiable signature), use [`decryptForView`](/client-sdk/guides/decrypt-to-view) instead.
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 on-chain encrypted handle (`ctHash`) you want to decrypt.
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).

<Note>
Expand All @@ -30,17 +30,17 @@ Often, `decryptForTx` is used to reveal a value that the protocol already consid

Examples where a permit 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.
- **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(...)`.

## 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
- `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 permit mode)

Expand Down Expand Up @@ -74,33 +74,33 @@ const decryptResult = await client

</CodeGroup>

After decrypting, see [Writing Decrypt Result to Contract](/client-sdk/guides/writing-decrypt-result) for how to publish or verify the result on-chain.
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
### `.execute()` (required, call last)

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

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

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

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

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

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

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

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

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

### `.onPoll(callback)` optional
### `.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.

Expand All @@ -119,13 +119,13 @@ 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. |
| `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
### `.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.

Expand Down
30 changes: 15 additions & 15 deletions client-sdk/guides/decrypt-to-view.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: "Reveal encrypted values locally for UI display using permits"

Use `decryptForView` to reveal a confidential (encrypted) value locally in your app so you can display it in the UI.

Unlike [`decryptForTx`](/client-sdk/guides/decrypt-to-tx), this flow does **not** return an on-chain-verifiable signature, and it is **not** meant to be published on-chain.
Unlike [`decryptForTx`](/client-sdk/guides/decrypt-to-tx), this flow does **not** return an onchain-verifiable signature, and it is **not** meant to be published onchain.

## Flow

Expand All @@ -14,7 +14,7 @@ Unlike [`decryptForTx`](/client-sdk/guides/decrypt-to-tx), this flow does **not*
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 on-chain, use [`decryptForTx`](/client-sdk/guides/decrypt-to-tx) instead.
`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.
</Note>

## Prerequisites
Expand All @@ -31,9 +31,9 @@ Unlike [`decryptForTx`](/client-sdk/guides/decrypt-to-tx), this flow does **not*
**Providing `utype`**: `utype` must match the ciphertext's underlying FHE type. The SDK uses it to convert the decrypted `bigint` into a convenient JS type.

Supported `utype`s:
- `FheTypes.Bool` returns a `boolean`
- `FheTypes.Uint160` (address) returns a checksummed `0x...` string
- `FheTypes.Uint8 | Uint16 | Uint32 | Uint64 | Uint128` returns a `bigint`
- `FheTypes.Bool` to returns a `boolean`
- `FheTypes.Uint160` (address) to returns a checksummed `0x...` string
- `FheTypes.Uint8 | Uint16 | Uint32 | Uint64 | Uint128` to returns a `bigint`
</Tip>

## Permit setup
Expand Down Expand Up @@ -90,29 +90,29 @@ Running `.execute()` resolves to a scalar JS value:

## Builder API

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

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

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

Select which permit to use:

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

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

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

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

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

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

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

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

Expand All @@ -130,13 +130,13 @@ The callback receives:
| Field | Type | Description |
| --- | --- | --- |
| `operation` | `'decrypt' \| 'sealoutput'` | Which Threshold Network flow is polling. For `decryptForView` this is `'sealoutput'`. |
| `requestId` | `string` | The Threshold Network request id. **May be the empty string** during submit-time retries see `.set404RetryTimeout(...)` below. |
| `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
### `.set404RetryTimeout(timeoutMs)` (optional)

Configures how long `decryptForView` 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.

Expand Down
Loading
Loading