From 562656c9ff27b5ec15091f7a01ed18daa0448fb1 Mon Sep 17 00:00:00 2001 From: Naiem Date: Tue, 16 Jun 2026 01:00:07 +0300 Subject: [PATCH 1/3] Update PoD with latest MpcCore --- .../cookbook-private-investor-allocations.md | 20 ++++++++---- .../for-developers-mapping-to-the-sdk.md | 13 +++++++- privacy-on-demand/tutorial-custom-logic.md | 2 +- .../tutorial-private-adder-sepolia.md | 31 +++++++++++-------- privacy-on-demand/typescript-pod-sdk.md | 27 ++++++++++++++-- 5 files changed, 69 insertions(+), 24 deletions(-) diff --git a/privacy-on-demand/cookbook-private-investor-allocations.md b/privacy-on-demand/cookbook-private-investor-allocations.md index 91b774e..cd732a7 100644 --- a/privacy-on-demand/cookbook-private-investor-allocations.md +++ b/privacy-on-demand/cookbook-private-investor-allocations.md @@ -40,7 +40,8 @@ The public version is useful because it gives you a known baseline: owner assign - A Solidity toolchain such as Hardhat or Foundry. - A Sepolia wallet with test ETH for deploys, transactions, and PoD request fees. - Node.js 18+ for scripts. -- The PoD SDK package: `npm install "@coti/pod-sdk"`. +- The PoD SDK package: `npm install "@coti/pod-sdk"` (ships the vendored `MpcCore.sol` under `@coti/pod-sdk/contracts/utils/mpc/`, so the COTI‑side contract no longer needs the `@coti-io/coti-contracts` package). +- The COTI client crypto package: `npm install "@coti-io/coti-sdk-typescript@^1.0.7"` (provides `decryptUint256({ ciphertextHigh, ciphertextLow }, key)` for the 256‑bit ciphertext shape). - A way for users to complete PoD onboarding and obtain their account AES key for local decryption. Before implementing the private version, read: @@ -411,14 +412,17 @@ const encryptedAllocation = await CotiPodCrypto.encrypt( If you use `PodContract.encryptAndCallMethod`, you can pass the plaintext string plus `DataType.itUint256`; the SDK encrypts and encodes the argument before sending the transaction. If the browser or backend already encrypted the value, use `callMethod` with the ciphertext JSON. -Investors decrypt only the ciphertext that was off-boarded to them. +Investors decrypt only the ciphertext that was off-boarded to them. Because `ctUint256` is a struct, the contract read returns a tuple `{ ciphertextHigh, ciphertextLow }`: ```typescript -const ct = await sepoliaAllocations.readResultByRequest(requestId); -const ctHex = typeof ct === "bigint" ? "0x" + ct.toString(16) : String(ct); +const raw = await sepoliaAllocations.readResultByRequest(requestId); +const ct = { + ciphertextHigh: BigInt(raw.ciphertextHigh ?? raw[0]), + ciphertextLow: BigInt(raw.ciphertextLow ?? raw[1]), +}; const plain = CotiPodCrypto.decrypt( - ctHex, + ct, accountAesKeyFromOnboarding, DataType.Uint256 ); @@ -426,6 +430,8 @@ const plain = CotiPodCrypto.decrypt( console.log("private allocation:", plain); ``` +Under the hood, the 256‑bit decrypt path calls `decryptUint256({ ciphertextHigh, ciphertextLow }, key)` from `@coti-io/coti-sdk-typescript` (`^1.0.7`). Narrower lanes (`Uint64`, `Uint128`) still take a single ciphertext word. + > **Warning:** Never log, persist, or transmit the account AES key as ordinary application data. Treat it as user-controlled key material. ## Part 7: Allocate and read private allocations @@ -482,6 +488,8 @@ function onSetAllocationCompleted(bytes memory resultData) external onlyInbox { For investor reads, the investor asks COTI to off-board their allocation to their address. The callback stores `ctUint256`, and the investor decrypts locally with their account AES key. +`ctUint256` is a Solidity **struct** with two `ctUint128` limbs (`ciphertextHigh`, `ciphertextLow`), so the decoded local needs a `memory` location and the storage mapping holds the two‑limb tuple. + ```solidity mapping(bytes32 => ctUint256) public allocationReadResults; @@ -490,7 +498,7 @@ function onAllocationRead(bytes memory resultData) external onlyInbox { require(callerChain == COTI_TESTNET_CHAIN_ID && callerContract == cotiAllocationPeer, "not allowed"); bytes32 requestId = IInbox(inbox).inboxSourceRequestId(); - ctUint256 allocation = abi.decode(resultData, (ctUint256)); + ctUint256 memory allocation = abi.decode(resultData, (ctUint256)); allocationReadResults[requestId] = allocation; } diff --git a/privacy-on-demand/for-developers-mapping-to-the-sdk.md b/privacy-on-demand/for-developers-mapping-to-the-sdk.md index 96750f6..5140f46 100644 --- a/privacy-on-demand/for-developers-mapping-to-the-sdk.md +++ b/privacy-on-demand/for-developers-mapping-to-the-sdk.md @@ -28,10 +28,21 @@ Then deep dives: | **Callback guard** | [InboxUser.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/InboxUser.sol) (`onlyInbox`) — see [Features](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/03-features.md). | | **PodLib** | [PodLib.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/mpc/PodLib.sol) and width-specific libraries (`PodLib64`, `PodLib128`, `PodLib256`). | | **PodUser / presets** | [PodUser.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/mpc/PodUser.sol), network mixins such as [PodUserSepolia.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/mpc/PodUserSepolia.sol) in [Getting started](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/04-getting-started.md). | -| **Types (`it*`, `ct*`, `gt*`)** | [MpcCore.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/utils/mpc/MpcCore.sol) and [Data types](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/01-it-ct-gt-data-types.md). | +| **Types (`it*`, `ct*`, `gt*`)** | Vendored [MpcCore.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/utils/mpc/MpcCore.sol) (and `MpcInterface.sol`) inside the PoD SDK — no separate `@coti-io/coti-contracts` package is needed for PoD apps. See [Data types](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/01-it-ct-gt-data-types.md). | | **Custom COTI calls** | [MpcAbiCodec.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/mpccodec/MpcAbiCodec.sol) and the **custom mode** section of [Writing privacy contracts](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05-writing-privacy-contracts-on-ethereum.md). | | **Client crypto** | [coti-pod-crypto.ts](https://github.com/cotitech-io/coti-pod-sdk/blob/main/src/coti-pod-crypto.ts) via `CotiPodCrypto` ([TypeScript integration](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/06-typescript-integration-ux-development.md)). | +## Type model at a glance + +The PoD SDK ships **`MpcCore.sol`** under `@coti/pod-sdk/contracts/utils/mpc/`. In the current revision: + +- **`gtUint8` … `gtUint256` and `gtBool`** are **user‑defined value types** (`type gtUint256 is uint256`). Pass and assign them like `uint256` — **no `memory` / `calldata` on `gt*` parameters or locals**. +- **`ctUint8` … `ctUint128`** are also user‑defined value types (single `uint256` word). +- **`ctUint256`** is a **struct** `{ ctUint128 ciphertextHigh; ctUint128 ciphertextLow; }` — decoded locals and callback variables must use a `memory` location, and off‑chain reads return the two limbs as a tuple. +- **`itUint*`** (user encrypted inputs, `ciphertext + signature`), **`utUint*`** (dual‑ciphertext), **`gtString`** and **`ctString`** remain structs — keep their `calldata` / `memory` locations. + +If you previously imported from **`@coti-io/coti-contracts`** in PoD code, switch the import to **`@coti/pod-sdk/contracts/utils/mpc/MpcCore.sol`**. Off‑chain decryption uses **`@coti-io/coti-sdk-typescript@^1.0.7`**, which exposes `decryptUint256({ ciphertextHigh, ciphertextLow }, accountAesKey)` for the 256‑bit lane. + ## Implementation checklist (condensed) Derived from the SDK’s [Writing privacy contracts](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05-writing-privacy-contracts-on-ethereum.md) and [Async execution](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05a-async-execution.md): diff --git a/privacy-on-demand/tutorial-custom-logic.md b/privacy-on-demand/tutorial-custom-logic.md index 15fd783..21ea805 100644 --- a/privacy-on-demand/tutorial-custom-logic.md +++ b/privacy-on-demand/tutorial-custom-logic.md @@ -41,7 +41,7 @@ The COTI contract **inherits `InboxUser`**, so only the Inbox can enter `receive pragma solidity ^0.8.19; import "../InboxUserCotiTestnet.sol"; -import "@coti-io/coti-contracts/contracts/utils/mpc/MpcCore.sol"; +import "@coti/pod-sdk/contracts/utils/mpc/MpcCore.sol"; contract DirectMessageCotiSide is InboxUserCotiTestnet { function receiveMessage(gtString calldata message, address sender, address recipient) external onlyInbox { diff --git a/privacy-on-demand/tutorial-private-adder-sepolia.md b/privacy-on-demand/tutorial-private-adder-sepolia.md index 04bb85b..6de6e67 100644 --- a/privacy-on-demand/tutorial-private-adder-sepolia.md +++ b/privacy-on-demand/tutorial-private-adder-sepolia.md @@ -93,7 +93,7 @@ contract PrivateAdder is PodLib, PodUserSepolia { requestId = inbox.inboxRequestId(); } - ctUint256 sum = abi.decode(data, (ctUint256)); + ctUint256 memory sum = abi.decode(data, (ctUint256)); sumByRequest[requestId] = sum; statusByRequest[requestId] = RequestStatus.Completed; emit AddCompleted(requestId); @@ -105,6 +105,7 @@ contract PrivateAdder is PodLib, PodUserSepolia { - **`onDefaultMpcError`** is implemented on `PodLibBase` and forwards failures to **`ErrorRemoteCall`** on `PodUser`. Your UI can listen for that event to mark a request failed. - **`addCallback`** must stay **`onlyInbox`** so random accounts cannot forge results. +- **`ctUint256`** is a Solidity **struct** `{ ctUint128 ciphertextHigh; ctUint128 ciphertextLow; }`, so the decoded local must use a `memory` location and the storage mapping holds the two‑limb tuple. The narrower garbled / ciphertext types (`gtUint8…gtUint256`, `gtBool`, and `ctUint8…ctUint128`) are **user‑defined value types** — pass and assign them like `uint256` (no `memory` / `calldata`). Encrypted-input wrappers such as **`itUint256`** stay structs and keep their `calldata` / `memory` location as before. ## Step 3: Compile and deploy on Sepolia @@ -145,8 +146,10 @@ import { import { ethers } from "ethers"; // Minimal ABI fragment — prefer the full artifact from your build (Hardhat / Foundry). +// itUint256 = { ctUint256 ciphertext; bytes signature }, and ctUint256 = { uint256 ciphertextHigh; uint256 ciphertextLow } +// so each `itUint256` parameter encodes as ((uint256,uint256),bytes). const privateAdderAbi = [ - "function add((uint256 ciphertext,bytes signature),(uint256 ciphertext,bytes signature),uint256) payable returns (bytes32)", + "function add(((uint256,uint256),bytes),((uint256,uint256),bytes),uint256) payable returns (bytes32)", ] as const; const pod = new PodContract( @@ -206,35 +209,37 @@ Private addition is **asynchronous**: the sum appears only after the Inbox invok ## Step 7: Read the encrypted sum and decrypt locally -After status is **Completed**, read **`sumByRequest(requestId)`**. The value is **`ctUint256`** (ciphertext), not plaintext. +After status is **Completed**, read **`sumByRequest(requestId)`**. The value is **`ctUint256`** (ciphertext), not plaintext. Because **`ctUint256`** is a Solidity **struct** with two `ctUint128` limbs, the contract read returns a tuple `{ ciphertextHigh, ciphertextLow }` (each is a single `uint256`). ```typescript import { CotiPodCrypto, DataType } from "@coti/pod-sdk"; // accountAesKey: hex string from your app’s COTI onboarding flow (never log it) -const ct = await privateAdder.sumByRequest(requestId); // bytes32 from extractRequestIds or return value -const ctHex = - typeof ct === "bigint" - ? "0x" + ct.toString(16) - : String(ct); +const raw = await privateAdder.sumByRequest(requestId); +// ethers / viem return the struct as a tuple — normalize to { ciphertextHigh, ciphertextLow } +const ct = { + ciphertextHigh: BigInt(raw.ciphertextHigh ?? raw[0]), + ciphertextLow: BigInt(raw.ciphertextLow ?? raw[1]), +}; const decryptedString = CotiPodCrypto.decrypt( - ctHex, + ct, accountAesKey, - DataType.Uint64 + DataType.Uint256 ); console.log("sum (plaintext string):", decryptedString); // Expect "30" for plainA=10 and plainB=20 ``` -`CotiPodCrypto.decrypt` delegates to `@coti-io/coti-sdk-typescript` and expects a **scalar ciphertext** as a **hex string** for `Uint64`, plus the user’s **AES key** (see SDK source [coti-pod-crypto.ts](https://github.com/cotitech-io/coti-pod-sdk/blob/main/src/coti-pod-crypto.ts)). +`CotiPodCrypto.decrypt` delegates to **`@coti-io/coti-sdk-typescript`** (`^1.0.7`), which now exposes `decryptUint256({ ciphertextHigh, ciphertextLow }, accountAesKey)` for the 256‑bit lane. Narrower lanes (`Uint64`, `Uint128`, …) still take a single `uint256` ciphertext as a `bigint` or `0x`‑prefixed hex string (see SDK source [coti-pod-crypto.ts](https://github.com/cotitech-io/coti-pod-sdk/blob/main/src/coti-pod-crypto.ts)). ## Step 8: Sanity checks and next steps -- **Callback decode** must stay **`(ctUint256)`** — changing the executor op or COTI-side behavior without updating the decode tuple will corrupt storage reads. -- **Type lane** — This contract uses **`add256`** with **`itUint256`** / **`ctUint256`** on chain. **`CotiPodCrypto.decrypt`** still takes a **`DataType`** for the scalar decode; keep **`DataType.Uint64`** (or **`Uint256`**, etc.) aligned with how your app and onboarding produce the ciphertext for this flow, per your installed SDK. +- **Callback decode** must stay **`(ctUint256)`** — and the local must use `memory` because `ctUint256` is a struct. Changing the executor op or COTI-side behavior without updating the decode tuple will corrupt storage reads. +- **Type lane** — This contract uses **`add256`** with **`itUint256`** / **`ctUint256`** on chain, so pass **`DataType.Uint256`** to `CotiPodCrypto.decrypt` and feed it the **`{ ciphertextHigh, ciphertextLow }`** tuple read from the contract. Narrower lanes (`Uint64`, `Uint128`) still take a single ciphertext word. +- **Type model** — In the current `MpcCore.sol`, `gtUint*`, `gtBool`, and `ctUint8…ctUint128` are **user‑defined value types** (`type X is uint256`) — drop `memory` / `calldata` on them. `ctUint256` is a struct (two `ctUint128` limbs); `itUint*` / `utUint*` are also still structs, so keep `calldata` / `memory` on those. - **Production**: add tests for non-Inbox callers on `addCallback`, under-funded `msg.value`, and decrypt failures; follow the [first production checklist](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/04-getting-started.md) in Getting started. ## Reference links diff --git a/privacy-on-demand/typescript-pod-sdk.md b/privacy-on-demand/typescript-pod-sdk.md index 5a2f4af..9851588 100644 --- a/privacy-on-demand/typescript-pod-sdk.md +++ b/privacy-on-demand/typescript-pod-sdk.md @@ -12,7 +12,7 @@ Use these helpers from a wallet script, backend service, or dApp frontend once y - You can also pass a full encryption service URL. - `DataType` distinguishes plaintext types (`Uint64`, `String`, etc.) from **`it*`** types that become ciphertext tuples on chain. -`CotiPodCrypto.decrypt` uses the user's **account AES key** and `@coti-io/coti-sdk-typescript` under the hood. +`CotiPodCrypto.decrypt` uses the user's **account AES key** and **`@coti-io/coti-sdk-typescript`** (`^1.0.7`) under the hood. ```typescript import { CotiPodCrypto, DataType } from "@coti/pod-sdk"; @@ -20,10 +20,31 @@ import { CotiPodCrypto, DataType } from "@coti/pod-sdk"; // Encrypt plaintext for Solidity itUint256 parameters const enc = await CotiPodCrypto.encrypt("42", "testnet", DataType.itUint256); -// Decrypt scalar ciphertext read from contract storage -const plain = CotiPodCrypto.decrypt("0x...", accountAesKeyFromOnboarding, DataType.Uint64); +// Decrypt a narrow scalar ciphertext (one uint256 word) read from contract storage +const plain64 = CotiPodCrypto.decrypt("0x...", accountAesKeyFromOnboarding, DataType.Uint64); + +// Decrypt a ctUint256 value (a struct with two ctUint128 limbs) +const plain256 = CotiPodCrypto.decrypt( + { ciphertextHigh, ciphertextLow }, + accountAesKeyFromOnboarding, + DataType.Uint256 +); ``` +### Ciphertext shape in the current `MpcCore.sol` + +After the gt‑type upgrade, the on‑chain types you read back have these shapes: + +| Type | Solidity | Off‑chain shape | +| -------------------------- | --------------------------------------------------------- | ---------------------------------------------- | +| `gtUint8` … `gtUint256`, `gtBool` | User‑defined value type (`type … is uint256`), no `memory`/`calldata` | n/a — never crosses the chain boundary | +| `ctUint8` … `ctUint128` | User‑defined value type | single `uint256` word | +| `ctUint256` | Struct `{ ctUint128 ciphertextHigh; ctUint128 ciphertextLow; }` | tuple `{ ciphertextHigh, ciphertextLow }` (each `bigint`) | +| `itUint*` / `utUint*` | Struct (ciphertext + signature, unchanged) | tuple / object | +| `gtString` / `ctString` | Struct (array of `gtUint64` / `ctUint64`, unchanged) | array of words | + +When you read a `ctUint256` value via ethers or viem, the storage getter returns the two limbs as a tuple — normalize it to `{ ciphertextHigh, ciphertextLow }` before passing it to `CotiPodCrypto.decrypt` (or to `decryptUint256` from `@coti-io/coti-sdk-typescript`). The narrower `ct*` lanes can still be passed as a `bigint` or `0x`‑prefixed hex string. + ## Gas estimation and method calls (`PodContract`) `PodContract` wraps `ethers.Contract` with PoD-aware helpers: From 8d69b007b6eda8a6545e17879722ec53ccd4cb16 Mon Sep 17 00:00:00 2001 From: Naiem Date: Tue, 30 Jun 2026 19:25:32 +0300 Subject: [PATCH 2/3] Remove references to pod-sdk contracts --- privacy-on-demand/README.md | 7 ++++--- .../cookbook-private-investor-allocations.md | 5 +++-- .../for-developers-mapping-to-the-sdk.md | 21 ++++++++++--------- privacy-on-demand/tutorial-custom-logic.md | 14 ++++++------- .../tutorial-private-adder-sepolia.md | 19 +++++++++-------- .../tutorials-privacy-on-demand.md | 2 +- privacy-on-demand/typescript-pod-sdk.md | 2 +- .../what-is-privacy-on-demand.md | 2 +- 8 files changed, 37 insertions(+), 35 deletions(-) diff --git a/privacy-on-demand/README.md b/privacy-on-demand/README.md index 34ecb96..ab2d8b0 100644 --- a/privacy-on-demand/README.md +++ b/privacy-on-demand/README.md @@ -16,7 +16,7 @@ Privacy on Demand lets applications use **strong privacy for data and computatio

Further resources

-- **[Examples](https://github.com/cotitech-io/coti-pod-sdk/tree/main/contracts/examples)** — Contract examples in the PoD SDK repo. +- **[Examples](https://github.com/coti-io/coti-contracts/tree/main/contracts/pod/examples)** — Contract examples in the COTI contracts repo. - **[PoD SDK documentation](https://github.com/cotitech-io/coti-pod-sdk/tree/main/docs)** — Full SDK docs on GitHub. The same **Quick Access** and **Further resources** blocks appear on the [docs homepage](../README.md). @@ -25,7 +25,7 @@ The same **Quick Access** and **Further resources** blocks appear on the [docs h --- -This section explains **what PoD is**, **how it feels to users and operators**, and **how the main pieces fit together**. For step-by-step integration with the **COTI PoD SDK**, use the [npm package](https://www.npmjs.com/package/@coti/pod-sdk), the [documentation on GitHub](https://github.com/cotitech-io/coti-pod-sdk/tree/main/docs), and the links below. +This section explains **what PoD is**, **how it feels to users and operators**, and **how the main pieces fit together**. For step-by-step integration, use **`@coti-io/coti-contracts`** for Solidity contracts, the [TypeScript PoD SDK](https://www.npmjs.com/package/@coti/pod-sdk) for client helpers, and the links below. ## Who this documentation is for @@ -60,6 +60,7 @@ This section explains **what PoD is**, **how it feels to users and operators**, ## Official technical reference -The machine-readable contracts, types, and APIs live in the open-source SDK. Treat this book chapter as the **human-oriented companion**; treat the repository as the **source of truth** for signatures, fees, and network constants: +The machine-readable **Solidity contracts** live in [**coti-contracts**](https://github.com/coti-io/coti-contracts). **TypeScript helpers** and integration guides live in the [**PoD SDK**](https://github.com/cotitech-io/coti-pod-sdk/tree/main/docs). Treat this book chapter as the **human-oriented companion**; treat those repositories as the **source of truth** for signatures, fees, and network constants: +- [COTI contracts — PoD contracts](https://github.com/coti-io/coti-contracts/tree/main/contracts/pod) - [COTI PoD SDK — documentation index](https://github.com/cotitech-io/coti-pod-sdk/tree/main/docs) diff --git a/privacy-on-demand/cookbook-private-investor-allocations.md b/privacy-on-demand/cookbook-private-investor-allocations.md index cd732a7..6bac5f0 100644 --- a/privacy-on-demand/cookbook-private-investor-allocations.md +++ b/privacy-on-demand/cookbook-private-investor-allocations.md @@ -40,7 +40,8 @@ The public version is useful because it gives you a known baseline: owner assign - A Solidity toolchain such as Hardhat or Foundry. - A Sepolia wallet with test ETH for deploys, transactions, and PoD request fees. - Node.js 18+ for scripts. -- The PoD SDK package: `npm install "@coti/pod-sdk"` (ships the vendored `MpcCore.sol` under `@coti/pod-sdk/contracts/utils/mpc/`, so the COTI‑side contract no longer needs the `@coti-io/coti-contracts` package). +- The COTI contracts library: `npm install "@coti-io/coti-contracts"`. +- The TypeScript PoD SDK: `npm install "@coti/pod-sdk"`. - The COTI client crypto package: `npm install "@coti-io/coti-sdk-typescript@^1.0.7"` (provides `decryptUint256({ ciphertextHigh, ciphertextLow }, key)` for the 256‑bit ciphertext shape). - A way for users to complete PoD onboarding and obtain their account AES key for local decryption. @@ -447,7 +448,7 @@ function setPrivateAllocation( uint256 callbackFeeLocalWei ) external payable onlyOwner returns (bytes32 requestId) { // Build an Inbox method call to the COTI-side allocation contract. - // Follow MpcAbiCodec argument construction from your installed SDK version. + // Follow MpcAbiCodec argument construction from your installed @coti-io/coti-contracts version. requestId = IInbox(inbox).sendTwoWayMessage{value: msg.value}( COTI_TESTNET_CHAIN_ID, diff --git a/privacy-on-demand/for-developers-mapping-to-the-sdk.md b/privacy-on-demand/for-developers-mapping-to-the-sdk.md index 5140f46..92a15dd 100644 --- a/privacy-on-demand/for-developers-mapping-to-the-sdk.md +++ b/privacy-on-demand/for-developers-mapping-to-the-sdk.md @@ -22,26 +22,26 @@ Then deep dives: ## Component → source file map -| Concept (this book) | Where it lives in the SDK docs / repo | +| Concept (this book) | Source / reference | | --- | --- | -| **Inbox** | [IInbox.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/IInbox.sol) and cross-domain flow in the [domain model](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/01-privacy-decentralized-apps-on-any-evm-chain-with-coti-pod.md) diagram. | -| **Callback guard** | [InboxUser.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/InboxUser.sol) (`onlyInbox`) — see [Features](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/03-features.md). | -| **PodLib** | [PodLib.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/mpc/PodLib.sol) and width-specific libraries (`PodLib64`, `PodLib128`, `PodLib256`). | -| **PodUser / presets** | [PodUser.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/mpc/PodUser.sol), network mixins such as [PodUserSepolia.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/mpc/PodUserSepolia.sol) in [Getting started](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/04-getting-started.md). | -| **Types (`it*`, `ct*`, `gt*`)** | Vendored [MpcCore.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/utils/mpc/MpcCore.sol) (and `MpcInterface.sol`) inside the PoD SDK — no separate `@coti-io/coti-contracts` package is needed for PoD apps. See [Data types](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/01-it-ct-gt-data-types.md). | -| **Custom COTI calls** | [MpcAbiCodec.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/mpccodec/MpcAbiCodec.sol) and the **custom mode** section of [Writing privacy contracts](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05-writing-privacy-contracts-on-ethereum.md). | +| **Inbox** | [IInbox.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/IInbox.sol) and cross-domain flow in the [domain model](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/01-privacy-decentralized-apps-on-any-evm-chain-with-coti-pod.md) diagram. | +| **Callback guard** | [InboxUser.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/InboxUser.sol) (`onlyInbox`) — see [Features](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/03-features.md). | +| **PodLib** | [PodLib.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpc/PodLib.sol) and width-specific libraries (`PodLib64`, `PodLib128`, `PodLib256`). | +| **PodUser / presets** | [PodUser.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpc/PodUser.sol), network mixins such as [PodUserSepolia.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpc/PodUserSepolia.sol) in [Getting started](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/04-getting-started.md). | +| **Types (`it*`, `ct*`, `gt*`)** | [`MpcCore.sol`](https://github.com/coti-io/coti-contracts/blob/main/contracts/utils/mpc/MpcCore.sol) and [`MpcInterface.sol`](https://github.com/coti-io/coti-contracts/blob/main/contracts/utils/mpc/MpcInterface.sol) in **`@coti-io/coti-contracts`**. See [Data types](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/01-it-ct-gt-data-types.md). | +| **Custom COTI calls** | [MpcAbiCodec.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpccodec/MpcAbiCodec.sol) and the **custom mode** section of [Writing privacy contracts](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05-writing-privacy-contracts-on-ethereum.md). | | **Client crypto** | [coti-pod-crypto.ts](https://github.com/cotitech-io/coti-pod-sdk/blob/main/src/coti-pod-crypto.ts) via `CotiPodCrypto` ([TypeScript integration](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/06-typescript-integration-ux-development.md)). | ## Type model at a glance -The PoD SDK ships **`MpcCore.sol`** under `@coti/pod-sdk/contracts/utils/mpc/`. In the current revision: +In the current revision: - **`gtUint8` … `gtUint256` and `gtBool`** are **user‑defined value types** (`type gtUint256 is uint256`). Pass and assign them like `uint256` — **no `memory` / `calldata` on `gt*` parameters or locals**. - **`ctUint8` … `ctUint128`** are also user‑defined value types (single `uint256` word). - **`ctUint256`** is a **struct** `{ ctUint128 ciphertextHigh; ctUint128 ciphertextLow; }` — decoded locals and callback variables must use a `memory` location, and off‑chain reads return the two limbs as a tuple. - **`itUint*`** (user encrypted inputs, `ciphertext + signature`), **`utUint*`** (dual‑ciphertext), **`gtString`** and **`ctString`** remain structs — keep their `calldata` / `memory` locations. -If you previously imported from **`@coti-io/coti-contracts`** in PoD code, switch the import to **`@coti/pod-sdk/contracts/utils/mpc/MpcCore.sol`**. Off‑chain decryption uses **`@coti-io/coti-sdk-typescript@^1.0.7`**, which exposes `decryptUint256({ ciphertextHigh, ciphertextLow }, accountAesKey)` for the 256‑bit lane. +Off‑chain decryption uses **`@coti-io/coti-sdk-typescript@^1.0.7`**, which exposes `decryptUint256({ ciphertextHigh, ciphertextLow }, accountAesKey)` for the 256‑bit lane. ## Implementation checklist (condensed) @@ -62,7 +62,8 @@ If you build **directly on COTI V2** with precompiles and private types, start f ## Package install ```bash +npm install "@coti-io/coti-contracts" npm install "@coti/pod-sdk" ``` -See [Getting started](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/04-getting-started.md) for Solidity imports and the `contract MyApp is PodLib, PodUserSepolia` pattern. +See [Getting started](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/04-getting-started.md) for the `contract MyApp is PodLib, PodUserSepolia` pattern. diff --git a/privacy-on-demand/tutorial-custom-logic.md b/privacy-on-demand/tutorial-custom-logic.md index 21ea805..35521a7 100644 --- a/privacy-on-demand/tutorial-custom-logic.md +++ b/privacy-on-demand/tutorial-custom-logic.md @@ -40,8 +40,8 @@ The COTI contract **inherits `InboxUser`**, so only the Inbox can enter `receive // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import "../InboxUserCotiTestnet.sol"; -import "@coti/pod-sdk/contracts/utils/mpc/MpcCore.sol"; +import "@coti-io/coti-contracts/contracts/pod/InboxUserCotiTestnet.sol"; +import "@coti-io/coti-contracts/contracts/utils/mpc/MpcCore.sol"; contract DirectMessageCotiSide is InboxUserCotiTestnet { function receiveMessage(gtString calldata message, address sender, address recipient) external onlyInbox { @@ -52,8 +52,6 @@ contract DirectMessageCotiSide is InboxUserCotiTestnet { } ``` -Paths like `../InboxUser.sol` assume you follow the SDK’s example layout; adjust imports to your repo. - ## Sepolia-side contract: orchestration only The Sepolia contract **inherits `PodUserSepolia`** (or your network’s `PodUser` preset), tracks the **COTI peer address**, and: @@ -61,15 +59,15 @@ The Sepolia contract **inherits `PodUserSepolia`** (or your network’s `PodUser 1. **`sendMessage`** — Wraps encrypted input (`itString`) and public addresses in an **`IInbox.MpcMethodCall`** built with **`MpcAbiCodec`** (see the SDK’s [Request builder and remote calls](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/03-request-builder-and-remote-calls.md)). It sends a **two-way** message so the result comes back asynchronously. 2. **`onMessageReceived`** — Decodes the tuple produced on COTI, **re-checks `inboxMsgSender()`**, and stores **`ctString`** keyed by conversation participants (or whatever your product needs). -The Solidity below is **structurally** correct; wire **`MpcAbiCodec`**’s `create` / `addArgument` / `build` steps exactly as in your installed `@coti/pod-sdk` version (argument order and `gt`/`it` interface types **must** match the COTI method signature). +The Solidity below is **structurally** correct; wire **`MpcAbiCodec`**’s `create` / `addArgument` / `build` steps exactly as in your installed `@coti-io/coti-contracts` version (argument order and `gt`/`it` interface types **must** match the COTI method signature). ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import {PodUserSepolia} from "../mpc/PodUserSepolia.sol"; -import {MpcAbiCodec} from "../mpccodec/MpcAbiCodec.sol"; -import {IInbox} from "../IInbox.sol"; +import "@coti-io/coti-contracts/contracts/pod/mpc/PodUserSepolia.sol"; +import "@coti-io/coti-contracts/contracts/pod/mpccodec/MpcAbiCodec.sol"; +import "@coti-io/coti-contracts/contracts/pod/IInbox.sol"; // Interface MUST match the COTI `DirectMessageCotiSide.receiveMessage` ABI // (including `gt` vs `it` types on each parameter). diff --git a/privacy-on-demand/tutorial-private-adder-sepolia.md b/privacy-on-demand/tutorial-private-adder-sepolia.md index 6de6e67..695a60f 100644 --- a/privacy-on-demand/tutorial-private-adder-sepolia.md +++ b/privacy-on-demand/tutorial-private-adder-sepolia.md @@ -2,7 +2,7 @@ This walkthrough is the **primitive-only** path: your host-chain contract calls **`PodLib`** helpers (the SDK surface for **MpcLib**-style primitives) and never deploys custom Solidity on COTI. If you are unsure whether that is enough for your product, read **[Tutorials: building Privacy on Demand (PoD) dApps](tutorials-privacy-on-demand.md)** first. -This guide shows how to build a minimal **Privacy on Demand** dApp that **adds two encrypted integers** on COTI and stores the **encrypted sum** on your EVM contract. It follows the same ideas as the SDK’s [MpcAdder.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/examples/MpcAdder.sol) example, extended with **Sepolia routing presets** and **request correlation** suitable for a real UI. +This guide shows how to build a minimal **Privacy on Demand** dApp that **adds two encrypted integers** on COTI and stores the **encrypted sum** on your EVM contract. It follows the same ideas as the [MpcAdder.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/examples/MpcAdder.sol) example, extended with **Sepolia routing presets** and **request correlation** suitable for a real UI. For background on async flows and fees, see [Async private operations](async-private-operations.md), [How do PoA fees work?](how-poa-fees-work.md), and the SDK’s [Fees, gas, and oracle](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/04-fees-gas-and-oracle.md) page. @@ -24,11 +24,12 @@ After that works, you harden for production: per-user request ownership, explici - **Sepolia ETH** for deployment and for **`msg.value`** on each `add` call (plus gas). - **User onboarding** so your client can obtain an **account AES key** for decryption (see the SDK’s [TypeScript integration](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/06-typescript-integration-ux-development.md) and [Onboarding / account AES key](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/06c-onboarding-account-account-aes-key.md) docs). -Always confirm **Inbox**, **COTI chain id**, and **MPC executor** against the version of `PodUserSepolia.sol` in your installed `@coti/pod-sdk` package; constants can change between releases. +Always confirm **Inbox**, **COTI chain id**, and **MPC executor** against the version of `PodUserSepolia.sol` in your installed `@coti-io/coti-contracts` package; constants can change between releases. -## Step 1: Install the SDK +## Step 1: Install dependencies ```bash +npm install "@coti-io/coti-contracts" npm install "@coti/pod-sdk" ``` @@ -44,9 +45,9 @@ Save as `PrivateAdder.sol`. The contract: // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.26; -import "@coti/pod-sdk/contracts/mpc/PodLib.sol"; -import "@coti/pod-sdk/contracts/mpc/PodUserSepolia.sol"; -import "@coti/pod-sdk/contracts/utils/mpc/MpcCore.sol"; +import "@coti-io/coti-contracts/contracts/pod/mpc/PodLib.sol"; +import "@coti-io/coti-contracts/contracts/pod/mpc/PodUserSepolia.sol"; +import "@coti-io/coti-contracts/contracts/utils/mpc/MpcCore.sol"; /// @title PrivateAdder /// @notice Adds two encrypted uint64 values via PoD on Sepolia (SDK preset addresses). @@ -109,7 +110,7 @@ contract PrivateAdder is PodLib, PodUserSepolia { ## Step 3: Compile and deploy on Sepolia -Configure remappings so `@coti/pod-sdk` resolves (Hardhat `paths`, Foundry `remappings.txt`, etc.), then compile and deploy `PrivateAdder` to **Ethereum Sepolia**. Record the deployed address for scripts. +Configure remappings so `@coti-io/coti-contracts` resolves (Hardhat `paths`, Foundry `remappings.txt`, etc.), then compile and deploy `PrivateAdder` to **Ethereum Sepolia**. Record the deployed address for scripts. ## Step 4: Budget `msg.value` and `callbackFeeLocalWei` @@ -239,13 +240,13 @@ console.log("sum (plaintext string):", decryptedString); - **Callback decode** must stay **`(ctUint256)`** — and the local must use `memory` because `ctUint256` is a struct. Changing the executor op or COTI-side behavior without updating the decode tuple will corrupt storage reads. - **Type lane** — This contract uses **`add256`** with **`itUint256`** / **`ctUint256`** on chain, so pass **`DataType.Uint256`** to `CotiPodCrypto.decrypt` and feed it the **`{ ciphertextHigh, ciphertextLow }`** tuple read from the contract. Narrower lanes (`Uint64`, `Uint128`) still take a single ciphertext word. -- **Type model** — In the current `MpcCore.sol`, `gtUint*`, `gtBool`, and `ctUint8…ctUint128` are **user‑defined value types** (`type X is uint256`) — drop `memory` / `calldata` on them. `ctUint256` is a struct (two `ctUint128` limbs); `itUint*` / `utUint*` are also still structs, so keep `calldata` / `memory` on those. +- **Type model** — In `MpcCore.sol`, `gtUint*`, `gtBool`, and `ctUint8…ctUint128` are **user‑defined value types** (`type X is uint256`) — drop `memory` / `calldata` on them. `ctUint256` is a struct (two `ctUint128` limbs); `itUint*` / `utUint*` are also still structs, so keep `calldata` / `memory` on those. - **Production**: add tests for non-Inbox callers on `addCallback`, under-funded `msg.value`, and decrypt failures; follow the [first production checklist](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/04-getting-started.md) in Getting started. ## Reference links - [`pod-method-call.ts` (`PodContract`, fees, `extractRequestIds`)](https://github.com/cotitech-io/coti-pod-sdk/blob/main/src/pod-method-call.ts) -- [MpcAdder.sol (minimal repo example)](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/examples/MpcAdder.sol) +- [MpcAdder.sol (minimal repo example)](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/examples/MpcAdder.sol) - [Examples with description](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05c-examples-with-description.md) - [Getting started (PodUserSepolia pattern)](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/04-getting-started.md) - [Async execution](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05a-async-execution.md) diff --git a/privacy-on-demand/tutorials-privacy-on-demand.md b/privacy-on-demand/tutorials-privacy-on-demand.md index e19f720..53fc498 100644 --- a/privacy-on-demand/tutorials-privacy-on-demand.md +++ b/privacy-on-demand/tutorials-privacy-on-demand.md @@ -26,7 +26,7 @@ For **64-, 128-, and 256-bit** lanes, the library surface includes (names may be **Randomness:** `randBoundedBits` -For the authoritative list, signatures, and gas notes, use the SDK’s **[MPC library (PodLib)](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05b-multi-party-computing-library-mpclib.md)** and **[PodLib.sol](https://github.com/cotitech-io/coti-pod-sdk/blob/main/contracts/mpc/PodLib.sol)** in your installed `@coti/pod-sdk` version. +For the authoritative list, signatures, and gas notes, use the SDK’s **[MPC library (PodLib)](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05b-multi-party-computing-library-mpclib.md)** and **[PodLib.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpc/PodLib.sol)** in your installed `@coti-io/coti-contracts` version. ### Example tutorial (simple PoD dApp) diff --git a/privacy-on-demand/typescript-pod-sdk.md b/privacy-on-demand/typescript-pod-sdk.md index 9851588..6680d8c 100644 --- a/privacy-on-demand/typescript-pod-sdk.md +++ b/privacy-on-demand/typescript-pod-sdk.md @@ -31,7 +31,7 @@ const plain256 = CotiPodCrypto.decrypt( ); ``` -### Ciphertext shape in the current `MpcCore.sol` +### Ciphertext shape in `MpcCore.sol` After the gt‑type upgrade, the on‑chain types you read back have these shapes: diff --git a/privacy-on-demand/what-is-privacy-on-demand.md b/privacy-on-demand/what-is-privacy-on-demand.md index dc230ac..80d3692 100644 --- a/privacy-on-demand/what-is-privacy-on-demand.md +++ b/privacy-on-demand/what-is-privacy-on-demand.md @@ -29,7 +29,7 @@ What PoD does **not** automatically guarantee by itself: ## What ships in the SDK versus what your team builds -The **COTI PoD SDK** ([GitHub](https://github.com/cotitech-io/coti-pod-sdk), [npm](https://www.npmjs.com/package/@coti/pod-sdk)) provides **contracts and TypeScript helpers** for the PoD pattern. Your project still typically supplies: +The **COTI PoD SDK** ([GitHub](https://github.com/cotitech-io/coti-pod-sdk), [npm](https://www.npmjs.com/package/@coti/pod-sdk)) provides **TypeScript helpers** for the PoD pattern. **Solidity contracts** (`PodLib`, `PodUser`, Inbox interfaces, and related types) ship in **`@coti-io/coti-contracts`**. Your project still typically supplies: - **Application-specific** EVM contracts and state machines. - **User experience** for onboarding, showing **pending / completed / failed** private operations, and **safe key handling**. From 469359c6f182aa43f7adc8a691d35cf16ec2207f Mon Sep 17 00:00:00 2001 From: Naiem Date: Thu, 2 Jul 2026 15:31:45 +0300 Subject: [PATCH 3/3] Merge in documentation from coti-sdk-pod --- README.md | 2 +- SUMMARY.md | 8 +- privacy-on-demand/README.md | 54 +++-- .../account-onboarding-aes-key.md | 66 +++++ .../architecture-and-components.md | 73 +++--- privacy-on-demand/async-private-operations.md | 34 ++- .../contract-patterns-checklist.md | 72 ++++++ .../cookbook-private-investor-allocations.md | 2 +- .../coti-typescript-sdk-for-pod.md | 76 ++++++ .../for-developers-mapping-to-the-sdk.md | 71 ++---- privacy-on-demand/glossary.md | 29 ++- ...ow-a-private-request-travels-end-to-end.md | 6 +- privacy-on-demand/how-poa-fees-work.md | 8 +- privacy-on-demand/reference-data-types.md | 93 +++++++ .../reference-examples-and-contracts.md | 72 ++++++ .../reference-podlib-and-primitives.md | 87 +++++++ privacy-on-demand/tutorial-custom-logic.md | 7 +- .../tutorial-private-adder-sepolia.md | 38 ++- .../tutorials-privacy-on-demand.md | 24 +- privacy-on-demand/typescript-pod-sdk.md | 228 +++++++++++++----- .../what-is-privacy-on-demand.md | 4 +- 21 files changed, 811 insertions(+), 243 deletions(-) create mode 100644 privacy-on-demand/account-onboarding-aes-key.md create mode 100644 privacy-on-demand/contract-patterns-checklist.md create mode 100644 privacy-on-demand/coti-typescript-sdk-for-pod.md create mode 100644 privacy-on-demand/reference-data-types.md create mode 100644 privacy-on-demand/reference-examples-and-contracts.md create mode 100644 privacy-on-demand/reference-podlib-and-primitives.md diff --git a/README.md b/README.md index baf9505..c31ced0 100644 --- a/README.md +++ b/README.md @@ -12,4 +12,4 @@ Our developer documentation serves as a comprehensive guide to understanding and * [**Technology Overview**](how-coti-works/): Dive into the technical foundations of the COTI network, including the cryptographic principles and innovative solutions behind its operation. * [**Quickstart Guide**](build-on-coti/quickstart.md): Get up and running with the COTI network quickly, using step-by-step instructions and practical examples. -* [**Developer Tools**](build-on-coti/tools/): Check out the innovative tools and resources to empower developers and organizations. +* [Privacy on Demand](privacy-on-demand/README.md) — Private computation on COTI with EVM orchestration (PoD) diff --git a/SUMMARY.md b/SUMMARY.md index 9448ef4..1e34738 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -116,8 +116,14 @@ * [Async private operations](privacy-on-demand/async-private-operations.md) * [How do PoA fees work?](privacy-on-demand/how-poa-fees-work.md) * [For developers: mapping concepts to the SDK](privacy-on-demand/for-developers-mapping-to-the-sdk.md) + * [Account onboarding (AES key)](privacy-on-demand/account-onboarding-aes-key.md) + * [COTI TypeScript SDK for PoD](privacy-on-demand/coti-typescript-sdk-for-pod.md) + * [TypeScript PoD SDK](privacy-on-demand/typescript-pod-sdk.md) + * [Reference: data types (it/ct/gt)](privacy-on-demand/reference-data-types.md) + * [Reference: PodLib primitives](privacy-on-demand/reference-podlib-and-primitives.md) + * [Contract patterns checklist](privacy-on-demand/contract-patterns-checklist.md) + * [Reference: examples and contracts](privacy-on-demand/reference-examples-and-contracts.md) * [Tutorials: building PoD dApps](privacy-on-demand/tutorials-privacy-on-demand.md) - * [TypeScript PoD SDK (CotiPodCrypto, PodContract)](privacy-on-demand/typescript-pod-sdk.md) * [Cookbook: private investor allocations with PoD](privacy-on-demand/cookbook-private-investor-allocations.md) * [Tutorial: private Adder on Sepolia](privacy-on-demand/tutorial-private-adder-sepolia.md) * [Tutorial: custom privacy logic with PoD](privacy-on-demand/tutorial-custom-logic.md) diff --git a/privacy-on-demand/README.md b/privacy-on-demand/README.md index ab2d8b0..b35755f 100644 --- a/privacy-on-demand/README.md +++ b/privacy-on-demand/README.md @@ -16,16 +16,17 @@ Privacy on Demand lets applications use **strong privacy for data and computatio

Further resources

-- **[Examples](https://github.com/coti-io/coti-contracts/tree/main/contracts/pod/examples)** — Contract examples in the COTI contracts repo. -- **[PoD SDK documentation](https://github.com/cotitech-io/coti-pod-sdk/tree/main/docs)** — Full SDK docs on GitHub. - -The same **Quick Access** and **Further resources** blocks appear on the [docs homepage](../README.md). +- **[Examples](reference-examples-and-contracts.md)** — Contract examples in `@coti-io/coti-contracts`. +- **[TypeScript PoD SDK](typescript-pod-sdk.md)** — Full `@coti/pod-sdk` reference. +- **[coti-sdk-pod on GitHub](https://github.com/coti-io/coti-sdk-pod)** — TypeScript SDK source. +- **[coti-contracts on GitHub](https://github.com/coti-io/coti-contracts/tree/main/contracts/pod)** — Solidity libraries and examples. +- **[coti-pod-inbox-contracts on GitHub](https://github.com/coti-io/coti-pod-inbox-contracts)** — Inbox implementation and fee contracts. --- -This section explains **what PoD is**, **how it feels to users and operators**, and **how the main pieces fit together**. For step-by-step integration, use **`@coti-io/coti-contracts`** for Solidity contracts, the [TypeScript PoD SDK](https://www.npmjs.com/package/@coti/pod-sdk) for client helpers, and the links below. +This section is the **canonical user-facing documentation** for PoD. See [Architecture and main components](architecture-and-components.md) for the three-package stack (`@coti/pod-sdk`, `@coti-io/coti-contracts`, `@coti-io/coti-pod-inbox-contracts`). ## Who this documentation is for @@ -33,34 +34,45 @@ This section explains **what PoD is**, **how it feels to users and operators**, | --- | --- | | **Product, compliance, and business readers** | Plain-language model of privacy, where data lives, and what “async” private operations mean in practice. | | **Architects and technical leads** | End-to-end diagrams, component roles, and boundaries between chains and domains. | -| **Developers** | A clear map from concepts to Solidity/TypeScript work, plus pointers to the authoritative SDK docs. | +| **Developers** | Tutorials, API reference, checklists, and links to authoritative contract source. | ## Table of contents ### Understand first (readable without writing code) -1. [What is Privacy on Demand?](what-is-privacy-on-demand.md) — Problem, promise, and constraints in everyday language. -2. [How a private request travels end to end](how-a-private-request-travels-end-to-end.md) — Timeline from user action to decrypted result. -3. [Architecture and main components](architecture-and-components.md) — Where **Inbox**, **MPC executor**, **PodUser**, and **PodLib** sit, with diagrams. -4. [Glossary](glossary.md) — Short definitions of terms you will see in PoD and SDK docs. +1. [What is Privacy on Demand?](what-is-privacy-on-demand.md) +2. [Privacy on Demand (PoD) for Dummies](pod-for-dummies.md) — non-technical overview +3. [How a private request travels end to end](how-a-private-request-travels-end-to-end.md) +4. [Architecture and main components](architecture-and-components.md) +5. [Glossary](glossary.md) ### Deeper context -5. [Async private operations (why it is not instant)](async-private-operations.md) — What “pending” means and why UX must reflect it. -6. [How do PoA fees work?](how-poa-fees-work.md) — Two-way Inbox budgets, oracle conversion, and step-by-step gas-unit consumption (worked example). -7. [For developers: mapping concepts to the SDK](for-developers-mapping-to-the-sdk.md) — Checklists and links to the [PoD SDK documentation on GitHub](https://github.com/cotitech-io/coti-pod-sdk/tree/main/docs). +6. [Async private operations (why it is not instant)](async-private-operations.md) +7. [How do PoA fees work?](how-poa-fees-work.md) +8. [For developers: mapping concepts to the SDK](for-developers-mapping-to-the-sdk.md) + +### Integration reference + +9. [Account onboarding (AES key)](account-onboarding-aes-key.md) +10. [COTI TypeScript SDK for PoD](coti-typescript-sdk-for-pod.md) +11. [TypeScript PoD SDK](typescript-pod-sdk.md) — full `@coti/pod-sdk` reference +12. [Reference: data types (`it*`, `ct*`, `gt*`)](reference-data-types.md) +13. [Reference: PodLib primitives](reference-podlib-and-primitives.md) +14. [Contract patterns checklist](contract-patterns-checklist.md) +15. [Reference: examples and contracts](reference-examples-and-contracts.md) ### Tutorials (hands-on) -8. [Tutorials: building PoD dApps](tutorials-privacy-on-demand.md) — When to use **MpcLib / PodLib** primitives vs **custom COTI + host** contracts, with links to focused walkthroughs. -9. [TypeScript PoD SDK (`CotiPodCrypto`, `PodContract`)](typescript-pod-sdk.md) — Encryption/decryption, fee estimation, method calls, and request ID extraction. -10. [Cookbook: private investor allocations with PoD](cookbook-private-investor-allocations.md) — Start from a familiar public Sepolia allocation dApp, then make allocation reads and withdrawals private with PoD. -11. [Tutorial: private Adder on Sepolia](tutorial-private-adder-sepolia.md) — Minimal primitive-only adder: `PodUserSepolia`, fees, TypeScript crypto. -12. [Tutorial: custom privacy logic with PoD](tutorial-custom-logic.md) — Encrypted messaging shape: `DirectMessageCotiSide` + Sepolia orchestrator. +16. [Tutorials: building PoD dApps](tutorials-privacy-on-demand.md) +17. [Cookbook: private investor allocations with PoD](cookbook-private-investor-allocations.md) +18. [Tutorial: private Adder on Sepolia](tutorial-private-adder-sepolia.md) +19. [Tutorial: custom privacy logic with PoD](tutorial-custom-logic.md) -## Official technical reference +## Official code repositories -The machine-readable **Solidity contracts** live in [**coti-contracts**](https://github.com/coti-io/coti-contracts). **TypeScript helpers** and integration guides live in the [**PoD SDK**](https://github.com/cotitech-io/coti-pod-sdk/tree/main/docs). Treat this book chapter as the **human-oriented companion**; treat those repositories as the **source of truth** for signatures, fees, and network constants: +Machine-readable **signatures and constants** live in the repos above. This book is the **documentation source of truth** for integration guidance: - [COTI contracts — PoD contracts](https://github.com/coti-io/coti-contracts/tree/main/contracts/pod) -- [COTI PoD SDK — documentation index](https://github.com/cotitech-io/coti-pod-sdk/tree/main/docs) +- [COTI PoD SDK — TypeScript source](https://github.com/coti-io/coti-sdk-pod) +- [COTI PoD inbox contracts](https://github.com/coti-io/coti-pod-inbox-contracts) diff --git a/privacy-on-demand/account-onboarding-aes-key.md b/privacy-on-demand/account-onboarding-aes-key.md new file mode 100644 index 0000000..9fd7420 --- /dev/null +++ b/privacy-on-demand/account-onboarding-aes-key.md @@ -0,0 +1,66 @@ +# Account onboarding (AES key) + +Every PoD user needs an **account AES key** to decrypt `ct*` values returned from private operations. The key is a 16-byte AES secret represented as **32 hexadecimal characters without a `0x` prefix**. + +This page describes a practical onboarding flow. Low-level crypto helpers live in [`@coti-io/coti-sdk-typescript`](coti-typescript-sdk-for-pod.md); decryption in app code typically goes through [`CotiPodCrypto`](typescript-pod-sdk.md). + +## Trust model + +- AES key recovery happens on a **trusted client** (browser, mobile app, or user-controlled wallet extension). +- A backend may broker encrypted key shares but must **never** see the plaintext AES key. +- Do not pass the recovered key in URLs, query parameters, or server logs. + +## Typical flow + +1. Client generates an RSA key pair. +2. Client sends the RSA **public** key to your onboarding service. +3. Service returns two encrypted key shares. +4. Client decrypts and combines shares into the account AES key. +5. Client stores the key in secure local storage. + +## Example implementation + +```typescript +import { generateRSAKeyPair, recoverUserKey } from "@coti-io/coti-sdk-typescript"; + +type KeySharesResponse = { + encryptedKeyShare0: string; + encryptedKeyShare1: string; +}; + +async function onboardAccount( + requestShares: (publicKey: Uint8Array) => Promise +): Promise { + const { publicKey, privateKey } = generateRSAKeyPair(); + const { encryptedKeyShare0, encryptedKeyShare1 } = await requestShares(publicKey); + + const accountAesKey = recoverUserKey(privateKey, encryptedKeyShare0, encryptedKeyShare1); + + if (!/^[0-9a-fA-F]{32}$/.test(accountAesKey)) { + throw new Error("invalid AES key format"); + } + + return accountAesKey; +} +``` + +## Storage recommendations + +| Environment | Recommendation | +| --- | --- | +| Web dApp | Encrypted-at-rest in browser storage with strict origin and session controls | +| Mobile | OS keychain or secure enclave | +| Server-rendered apps | Avoid persisting the AES key on the server | + +## Operational guardrails + +- Never log key shares or the recovered key. +- Enforce TLS and authenticated onboarding endpoints. +- Define account recovery and key-rotation policy before production launch. +- Pair onboarding with [async UX guidance](async-private-operations.md): users cannot decrypt results until onboarding completes. + +## See also + +- [COTI TypeScript SDK for PoD](coti-typescript-sdk-for-pod.md) — `generateRSAKeyPair`, `recoverUserKey`, decrypt helpers +- [TypeScript PoD SDK](typescript-pod-sdk.md) — `CotiPodCrypto.decrypt` +- [Tutorial: private Adder on Sepolia](tutorial-private-adder-sepolia.md) — end-to-end walkthrough that assumes a key is available diff --git a/privacy-on-demand/architecture-and-components.md b/privacy-on-demand/architecture-and-components.md index 788dbf7..4d9e202 100644 --- a/privacy-on-demand/architecture-and-components.md +++ b/privacy-on-demand/architecture-and-components.md @@ -3,21 +3,29 @@ ## Vocabulary: PoD versus “Pod” in code - **PoD** — **Privacy on Demand**, the **product pattern**: private work on COTI, orchestration on your EVM chain. -- **PodUser / PodLib** — **Solidity building blocks**. They help your **dApp contract** configure routing and call common private operations. They are **not** a separate blockchain; they are **libraries and base contracts** you inherit or use. +- **PodUser / PodLib** — **Solidity building blocks** in `@coti-io/coti-contracts`. They help your **dApp contract** configure routing and call common private operations. They are **not** a separate blockchain. + +## Three repositories + +| Package | What it ships | +| --- | --- | +| `@coti-io/coti-contracts` | `PodLib`, `PodUser*`, `IInbox` interface, `MpcAbiCodec`, examples, tokens | +| `@coti-io/coti-pod-inbox-contracts` | Inbox **implementation**, `InboxMiner`, `InboxFeeManager`, `PriceOracle` | +| `@coti/pod-sdk` | TypeScript client: encrypt/decrypt, fee-aware calls, request tracking | + +The Inbox uses a **CREATE3 deterministic address** shared across Sepolia, COTI testnet, and Avalanche Fuji (`0xAb625bE229F603f6BBF964474AFf6d5487e364De` in [`PodNetworkConstants`](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/PodNetworkConstants.sol)). ## High-level deployment view Think of **three domains**: 1. **User device** — keys, encryption, decryption, UX. -2. **Your EVM chain** — your app’s contracts, assets, and the **Inbox** contract that speaks cross-domain. -3. **COTI execution** — private computation and the **MPC executor** contract your integration targets. +2. **Your EVM chain** — your app’s contracts, assets, and the **Inbox** contract. +3. **COTI execution** — private computation and the **MPC executor** (or custom COTI contract). -**Inbox** sits on **your chain** and is the **trusted bridge** between your contract logic and COTI. **MPC executor** sits on **COTI** and is the **entry point** for the SDK-configured private operation flow. +**Inbox** sits on **your chain** and is the **trusted bridge** between your contract logic and COTI. A matching Inbox on COTI receives cross-domain messages for the return leg. -## Component diagram: your dApp contract’s perspective - -The next diagram shows **logical modules** as engineers wire them. Exact inheritance names come from the SDK (for example `PodUserSepolia` on test networks). +## Component diagram ```mermaid flowchart TB @@ -26,10 +34,9 @@ flowchart TB PodInboxEvm["Inbox contract (EVM)"] end - - subgraph CotiSyetem["Privacy Application (EVM)"] + subgraph CotiSystem["COTI testnet"] PodInboxCoti["Inbox contract (COTI)"] - Exec["MPC executor or Custom Executor (COTI)"] + Exec["MPC executor or custom contract"] end AppLogic --> PodInboxEvm @@ -39,45 +46,43 @@ flowchart TB ### Inbox -- **What it is**: An on-chain **message router** and **callback** mechanism between domains. -- **Why it matters**: Without it, your EVM contract cannot **reach** COTI private execution or **receive** structured answers. -- **Analogy**: A **certified courier** between two offices: it does not replace either office, but **only** it can hand off the parcel and bring the signed reply back. +- **What it is**: On-chain **message router** and **callback** mechanism between domains. +- **Implementation**: [`coti-pod-inbox-contracts`](https://github.com/coti-io/coti-pod-inbox-contracts); interface in [`IInbox.sol`](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/IInbox.sol). +- **Why it matters**: Without it, your EVM contract cannot reach COTI private execution or receive structured answers. ### MPC executor (COTI) -- **What it is**: The **COTI-side contract address** your dApp is configured to call for a given deployment. The SDK’s network presets expose this as a constant you set during construction (for example `MPC_EXECUTOR_ADDRESS` alongside `COTI_CHAIN_ID` in [Getting started](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/04-getting-started.md)). -- **Why it matters**: It anchors **where** private execution is invoked in the COTI environment for **library-style** flows. +- **What it is**: The COTI-side contract your dApp targets for **library-style** flows. Network presets such as [`PodUserSepolia`](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpc/PodUserSepolia.sol) call `configureCoti` in their constructor with the current executor address from `PodNetworkConstants`. +- **Why it matters**: Anchors where private execution is invoked on COTI. ### PodUser -- **What it is**: A **configuration surface** for integrators: **which Inbox**, **which COTI chain**, **which executor**. Administrative changes are expected to be **access-controlled** (`onlyOwner` patterns in the SDK). -- **Why it matters**: Lets the same codebase target **different environments** (testnet vs mainnet, future routing updates) without rewriting core logic—**if** governance is handled responsibly. +- **What it is**: Configuration surface for **Inbox address**, **COTI chain id**, and **executor address**. Presets (`PodUserSepolia`, `PodUserFuji`) auto-wire testnet values; production changes should be **access-controlled** (`onlyOwner`). +- **Why it matters**: Same codebase can target different environments without rewriting core logic. ### PodLib -- **What it is**: **High-level helpers** for **common private operations** (for example comparisons and arithmetic at fixed bit widths—see the SDK [features](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/03-features.md) table). -- **Why it matters**: Faster path than writing a **custom** COTI contract for every operation. If you outgrow it, you move to **custom** encoding and COTI-side contracts using `MpcAbiCodec`, described in the SDK’s [Writing privacy contracts](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05-writing-privacy-contracts-on-ethereum.md). - -## Data shapes: a non-developer mental model +- **What it is**: High-level helpers for **common private operations** (arithmetic, comparison, bitwise ops at 64/128/256 bits). See [Reference: PodLib primitives](reference-podlib-and-primitives.md). +- **Why it matters**: Faster than a custom COTI contract for every operation. When you outgrow it, use `MpcAbiCodec` and custom COTI contracts ([Tutorial: custom privacy logic](tutorial-custom-logic.md)). -Engineers talk about **`it*`**, **`gt*`**, and **`ct*`**. At a high level: +## Data shapes -| Symbol (in docs) | Think of it as | Where it “lives” | +| Symbol | Think of it as | Where it lives | | --- | --- | --- | -| **`it*`** | **Signed, encrypted user input** bundled for submission | Built on the **client**, consumed by **your EVM contract** | -| **`gt*`** | **Private compute representation** during the operation | **Inside COTI** private execution | -| **`ct*`** | **Encrypted output** you can **store on your chain** and **decrypt client-side** | **Returned** to your contract, **read** by the user’s app | +| **`it*`** | Signed encrypted user input | Built on **client**, consumed by **EVM contract** | +| **`gt*`** | Private compute representation | **Inside COTI** execution | +| **`ct*`** | Encrypted output stored on-chain | **Returned** to your contract, **decrypted** client-side | -A fuller table lives in the SDK’s [data types](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/01-it-ct-gt-data-types.md) page. +Full reference: [Reference: data types](reference-data-types.md). -## Trust and security highlights (for architects) +## Trust and security highlights -- **Callback authentication**: Your contract should only accept **Inbox-originated** callbacks for private results—otherwise anyone could try to spoof answers. The SDK’s `onlyInbox` pattern exists for this boundary ([features](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/03-features.md)). -- **Request correlation**: Private work completes **later**; your system must track **request IDs** and statuses honestly in UX and backends ([Async private operations](async-private-operations.md)). -- **Key stewardship**: Client-side AES material is powerful; treat it like **credentials**, not analytics metadata ([TypeScript integration](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/06-typescript-integration-ux-development.md)). +- **Callback authentication**: Only accept **Inbox-originated** callbacks (`onlyInbox` from [`InboxUser.sol`](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/InboxUser.sol)). +- **Request correlation**: Track **request IDs** in UX and backends ([Async private operations](async-private-operations.md), [`PodRequest`](typescript-pod-sdk.md)). +- **Key stewardship**: Account AES keys are credentials ([Account onboarding](account-onboarding-aes-key.md)). ## Next steps -- **[Interactive PoD architecture (pod.coti.io)](https://pod.coti.io/)** — Explore the same cross-chain picture interactively: step through **MpcAdder**, open linked contracts on GitHub, and see how fees deplete across blocks. -- [Glossary](glossary.md) — quick term lookup. -- [For developers: mapping concepts to the SDK](for-developers-mapping-to-the-sdk.md) — concrete doc links and checklists. +- **[Interactive PoD architecture (pod.coti.io)](https://pod.coti.io/)** +- [Glossary](glossary.md) +- [For developers: mapping concepts to the SDK](for-developers-mapping-to-the-sdk.md) diff --git a/privacy-on-demand/async-private-operations.md b/privacy-on-demand/async-private-operations.md index 1a7e05b..862abc9 100644 --- a/privacy-on-demand/async-private-operations.md +++ b/privacy-on-demand/async-private-operations.md @@ -8,7 +8,7 @@ On a normal smart contract call, many teams think in terms of: **submit transact With PoD, the meaningful private result usually arrives in a **second step**: -1. **Request transaction** — your dApp contract submits work **through the Inbox** and receives or emits a **request identifier**. +1. **Request transaction** — your dApp contract submits work **through the Inbox** and emits a **request identifier** (in the compact `MessageSent` event). 2. **Wait** — COTI performs private computation. 3. **Callback transaction** — the Inbox invokes your contract’s **callback** with **encrypted outputs** (`ct*`). @@ -16,24 +16,38 @@ So the user’s mental model should be closer to **“I submitted a job”** tha ## Why the platform works this way -Private execution happens **outside** your chain’s normal synchronous EVM frame. The **Inbox** pattern exists precisely to **carry a message out** and **bring a response back** through a **controlled channel**. +Private execution happens **outside** your chain’s normal synchronous EVM frame. The **Inbox** pattern carries a message out and brings a response back through a controlled channel. -The SDK’s [Async execution](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05a-async-execution.md) page lists the canonical lifecycle and common mistakes (wrong decode shape, missing `onlyInbox`, expecting same-block completion). +See [Contract patterns checklist](contract-patterns-checklist.md) for callback lifecycle requirements. + +## Tracking requests in TypeScript + +Use [`PodRequest.trackRequest`](typescript-pod-sdk.md) to poll inbox state until a terminal condition: + +| UI state | Typical condition | +| --- | --- | +| **Pending** | Request emitted on source chain, not yet mined on target | +| **Executing** | `minedOnTarget === true` on outbound leg; waiting for callback | +| **Completed** | Two-way: `response.minedOnTarget === true`. One-way: outbound `minedOnTarget` only | +| **Failed** | `execution` or `response.execution` populated with error code/message | + +Extract `requestId` from the submit transaction with [`PodContract.extractRequestIds`](typescript-pod-sdk.md). ## What product and support teams should plan for | Topic | Recommendation | | --- | --- | -| **UI states** | Show **Pending / Completed / Failed** (or equivalent) per request ID. | -| **Indexing** | Expect teams to use **events**, **subgraphs**, or internal indexers to connect callbacks to user actions. | -| **Errors** | Surface **structured failure** where the SDK exposes error callbacks and codes—users need actionable next steps. | -| **Support** | Train staff that **“stuck pending”** may be **fee**, **routing**, or **downstream execution** issues—not always “user error.” | +| **UI states** | Show **Pending / Completed / Failed** per request ID | +| **Indexing** | Index compact Inbox `MessageSent` events (`requestId` in indexed topics) | +| **Errors** | Surface `execution.errorMessage` from `PodRequest`; use `decodeInboxErrorMessage` for raw revert data | +| **Support** | “Stuck pending” may be fee, routing, or miner issues — not always user error | ## Relationship to decryption -Even after **completion**, plaintext is **not** magically public on-chain. **Authorized clients** decrypt **`ct*` outputs** locally. Planning must cover **key recovery**, **device loss**, and **clear disclosure** of who can decrypt what. +Even after **completion**, plaintext is **not** public on-chain. Authorized clients decrypt **`ct*` outputs** locally. Plan for [account onboarding](account-onboarding-aes-key.md), device loss, and clear disclosure of who can decrypt what. ## Next steps -- [How a private request travels end to end](how-a-private-request-travels-end-to-end.md) — full path diagram. -- [For developers: mapping concepts to the SDK](for-developers-mapping-to-the-sdk.md) — testing and callback checklists. +- [How a private request travels end to end](how-a-private-request-travels-end-to-end.md) +- [TypeScript PoD SDK](typescript-pod-sdk.md) — `PodRequest` reference +- [For developers: mapping concepts to the SDK](for-developers-mapping-to-the-sdk.md) diff --git a/privacy-on-demand/contract-patterns-checklist.md b/privacy-on-demand/contract-patterns-checklist.md new file mode 100644 index 0000000..0f5e939 --- /dev/null +++ b/privacy-on-demand/contract-patterns-checklist.md @@ -0,0 +1,72 @@ +# Contract patterns and production checklist + +Use this checklist before deploying a production PoD contract. For conceptual background, see [Architecture and main components](architecture-and-components.md) and [Async private operations](async-private-operations.md). + +## Recommended contract shape + +1. Inherit from `PodLib` (primitive path) or `InboxUser` (custom path). +2. Add a network preset mixin such as [`PodUserSepolia`](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpc/PodUserSepolia.sol) or [`PodUserFuji`](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpc/PodUserFuji.sol) — presets auto-wire inbox and COTI routing in their constructor. +3. Accept private values as `it*` on EVM entrypoints. +4. Submit via `PodLib` helpers (e.g. `add64`, `gt256`) or `IInbox.sendTwoWayMessage{value: ...}(..., callbackFeeLocalWei)`. +5. Store `requestId` correlation state. +6. Implement success and error callbacks with `onlyInbox`. +7. Decode callback data into `ct*` and persist. +8. Expose status/result readers for async UX. + +Preset wiring (`PodLib` + `PodUserSepolia` / `PodUserFuji`): [Reference: PodLib primitives](reference-podlib-and-primitives.md). + +## Fee and gas checklist + +- Expose **payable** entrypoints when using two-way sends; forward **`msg.value`** as the total fee and pass explicit **`callbackFeeLocalWei`**. +- Call **`calculateTwoWayFeeRequiredInLocalToken`** on the deployed Inbox before production sends (see [How do PoA fees work?](how-poa-fees-work.md)). +- Test **too-low total** and **too-low callback** reverts in addition to the happy path. + +## Critical security controls + +- Access-control any method that changes routing or configuration. +- Gate any call path that invokes `configureCoti(...)`. +- Keep callback handlers `onlyInbox`. +- In custom COTI flows, verify `inboxMsgSender()` matches the expected peer contract. +- Avoid external calls before state updates inside callback handlers. + +## ABI correctness checklist + +- Selector in `MpcAbiCodec.create(...)` matches the COTI-side target function. +- `.addArgument(...)` order matches COTI parameter order. +- Callback `abi.decode(...)` tuple matches COTI `abi.encode(...)` exactly. +- Add regression tests when callback tuple schema changes. + +## Async robustness checklist + +- Request starts as `PENDING` and transitions to a terminal state. +- Unknown or duplicate callback handling is defined. +- Errors are observable (`requestId`, error code, message). +- Frontend can query status by request ID (see [`PodRequest`](typescript-pod-sdk.md)). + +## Privacy and type checklist + +- No plaintext sensitive values in EVM storage. +- No `gt*` in EVM public interfaces. +- `ct*` used for user-decryptable outputs. +- Type width consistency preserved through the full flow (see [Reference: data types](reference-data-types.md)). + +## Observability checklist + +- Emit request-created event with indexed `requestId`. +- Emit completion and failure events. +- Index `MessageSent` on the Inbox for off-chain correlation (compact event carries `requestId` in indexed topics). + +## Testing checklist + +- Success callback updates expected state. +- Non-Inbox callback call reverts. +- Error callback updates failure state. +- Request ID mapping is deterministic. +- Frontend integration decrypts returned ciphertext correctly. +- Fee sufficiency: success with estimated fees plus buffer; reverts when under-funded. + +## See also + +- [Reference: examples and contracts](reference-examples-and-contracts.md) +- [Contract patterns in custom logic tutorial](tutorial-custom-logic.md) +- [Cookbook: private investor allocations](cookbook-private-investor-allocations.md) diff --git a/privacy-on-demand/cookbook-private-investor-allocations.md b/privacy-on-demand/cookbook-private-investor-allocations.md index 6bac5f0..b54581a 100644 --- a/privacy-on-demand/cookbook-private-investor-allocations.md +++ b/privacy-on-demand/cookbook-private-investor-allocations.md @@ -592,4 +592,4 @@ Before adapting this cookbook for a real launch, add: - [Tutorial: private Adder on Sepolia](tutorial-private-adder-sepolia.md) - [Tutorial: custom privacy logic with PoD](tutorial-custom-logic.md) - [TypeScript PoD SDK (`CotiPodCrypto`, `PodContract`)](typescript-pod-sdk.md) -- [PoD SDK documentation](https://github.com/cotitech-io/coti-pod-sdk/tree/main/docs) +- [Privacy on Demand documentation](README.md) diff --git a/privacy-on-demand/coti-typescript-sdk-for-pod.md b/privacy-on-demand/coti-typescript-sdk-for-pod.md new file mode 100644 index 0000000..7e5f383 --- /dev/null +++ b/privacy-on-demand/coti-typescript-sdk-for-pod.md @@ -0,0 +1,76 @@ +# COTI TypeScript SDK for PoD + +Package: **`@coti-io/coti-sdk-typescript`** + +This is the **low-level cryptography layer** beneath [`@coti/pod-sdk`](typescript-pod-sdk.md). Use it when you need signed `it*` payload construction, account key recovery, or direct decrypt helpers. Most PoD apps call `CotiPodCrypto` instead, which delegates decrypt to this package. + +```bash +npm install @coti-io/coti-sdk-typescript +``` + +## APIs commonly used with PoD + +| API | Purpose | +| --- | --- | +| `buildInputText` | Build signed encrypted numeric input payload | +| `buildStringInputText` | Build signed encrypted string input payload | +| `decryptUint` / `decryptUint256` | Decrypt numeric ciphertext with account AES key | +| `decryptString` | Decrypt string ciphertext with account AES key | +| `generateRSAKeyPair` | Generate onboarding RSA keys | +| `recoverUserKey` | Reconstruct account AES key from encrypted shares | + +See [Account onboarding (AES key)](account-onboarding-aes-key.md) for the recovery flow. + +## Safer selector handling + +Avoid hardcoding function selectors. Build from the contract ABI: + +```typescript +import { Interface, Wallet } from "ethers"; +import { buildInputText } from "@coti-io/coti-sdk-typescript"; + +const iface = new Interface(["function compare((uint256,bytes),(uint256,bytes))"]); +const selector = iface.getFunction("compare")!.selector; + +const sender = { + wallet: new Wallet(process.env.PRIVATE_KEY!), + userKey: accountAesKey, +}; + +const itValue = buildInputText(42n, sender, contractAddress, selector); +``` + +The `contractAddress` and `selector` used when signing must match the on-chain call target exactly. + +## String input example + +```typescript +import { buildStringInputText } from "@coti-io/coti-sdk-typescript"; + +const itMemo = buildStringInputText("private memo", sender, contractAddress, selector); +``` + +## Decryption example + +```typescript +import { decryptUint, decryptString } from "@coti-io/coti-sdk-typescript"; + +const amount = decryptUint(BigInt(ctAmountHex), accountAesKey); +const note = decryptString({ value: ctStringCells }, accountAesKey); +``` + +For `ctUint256` limbs, prefer `decryptUint256({ ciphertextHigh, ciphertextLow }, accountAesKey)` (see [Reference: data types](reference-data-types.md)). + +## Relationship to `@coti/pod-sdk` + +| Task | Package | +| --- | --- | +| Encrypt plaintext via PoD encryption HTTP service | `@coti/pod-sdk` (`CotiPodCrypto.encrypt`) | +| Decrypt `ct*` in app code | `@coti/pod-sdk` (`CotiPodCrypto.decrypt`) or this package directly | +| Onboard user / recover AES key | This package | +| Fee estimate, submit tx, track request | `@coti/pod-sdk` (`PodContract`, `PodRequest`) | + +## See also + +- [Account onboarding (AES key)](account-onboarding-aes-key.md) +- [TypeScript PoD SDK](typescript-pod-sdk.md) diff --git a/privacy-on-demand/for-developers-mapping-to-the-sdk.md b/privacy-on-demand/for-developers-mapping-to-the-sdk.md index 92a15dd..457fe27 100644 --- a/privacy-on-demand/for-developers-mapping-to-the-sdk.md +++ b/privacy-on-demand/for-developers-mapping-to-the-sdk.md @@ -1,63 +1,32 @@ # For developers: mapping concepts to the SDK -This page is the **bridge** from [Architecture and main components](architecture-and-components.md) to the canonical [PoD SDK documentation on GitHub](https://github.com/cotitech-io/coti-pod-sdk/tree/main/docs). It repeats a few facts on purpose so engineers can verify mental models quickly. +This page is the **developer index**: concept → source file, plus a fast path into hands-on guides. For architecture and the three-package stack, start with [Architecture and main components](architecture-and-components.md). For the full reading list, use the [section index](README.md). -For a guided first implementation, read **[Tutorials: building Privacy on Demand (PoD) dApps](tutorials-privacy-on-demand.md)** to pick the integration model, then follow [Tutorial: private Adder on Sepolia](tutorial-private-adder-sepolia.md) for a **primitive-only** Solidity + TypeScript walkthrough (Sepolia presets). - -## Official reading order (SDK) - -The upstream docs recommend: - -1. [Privacy dApps on any EVM chain with COTI PoD](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/01-privacy-decentralized-apps-on-any-evm-chain-with-coti-pod.md) -2. [Getting started](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/04-getting-started.md) -3. [Writing privacy contracts on Ethereum](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05-writing-privacy-contracts-on-ethereum.md) -4. [TypeScript integration (UX development)](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/06-typescript-integration-ux-development.md) - -Then deep dives: - -- [Async execution](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05a-async-execution.md) -- [MPC library (PodLib)](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05b-multi-party-computing-library-mpclib.md) -- [Examples with description](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05c-examples-with-description.md) -- Contract references: [Data types](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/01-it-ct-gt-data-types.md), [Patterns and checklist](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/02-contract-patterns-and-checklist.md), [Request builder and remote calls](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/03-request-builder-and-remote-calls.md), [Fees, gas, and oracle](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/04-fees-gas-and-oracle.md) +**Fast path:** [Tutorials overview](tutorials-privacy-on-demand.md) → [private Adder tutorial](tutorial-private-adder-sepolia.md) → [TypeScript PoD SDK](typescript-pod-sdk.md). ## Component → source file map -| Concept (this book) | Source / reference | +| Concept | Source / reference | | --- | --- | -| **Inbox** | [IInbox.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/IInbox.sol) and cross-domain flow in the [domain model](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/01-privacy-decentralized-apps-on-any-evm-chain-with-coti-pod.md) diagram. | -| **Callback guard** | [InboxUser.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/InboxUser.sol) (`onlyInbox`) — see [Features](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/03-features.md). | -| **PodLib** | [PodLib.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpc/PodLib.sol) and width-specific libraries (`PodLib64`, `PodLib128`, `PodLib256`). | -| **PodUser / presets** | [PodUser.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpc/PodUser.sol), network mixins such as [PodUserSepolia.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpc/PodUserSepolia.sol) in [Getting started](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/04-getting-started.md). | -| **Types (`it*`, `ct*`, `gt*`)** | [`MpcCore.sol`](https://github.com/coti-io/coti-contracts/blob/main/contracts/utils/mpc/MpcCore.sol) and [`MpcInterface.sol`](https://github.com/coti-io/coti-contracts/blob/main/contracts/utils/mpc/MpcInterface.sol) in **`@coti-io/coti-contracts`**. See [Data types](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/01-it-ct-gt-data-types.md). | -| **Custom COTI calls** | [MpcAbiCodec.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpccodec/MpcAbiCodec.sol) and the **custom mode** section of [Writing privacy contracts](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05-writing-privacy-contracts-on-ethereum.md). | -| **Client crypto** | [coti-pod-crypto.ts](https://github.com/cotitech-io/coti-pod-sdk/blob/main/src/coti-pod-crypto.ts) via `CotiPodCrypto` ([TypeScript integration](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/06-typescript-integration-ux-development.md)). | - -## Type model at a glance - -In the current revision: - -- **`gtUint8` … `gtUint256` and `gtBool`** are **user‑defined value types** (`type gtUint256 is uint256`). Pass and assign them like `uint256` — **no `memory` / `calldata` on `gt*` parameters or locals**. -- **`ctUint8` … `ctUint128`** are also user‑defined value types (single `uint256` word). -- **`ctUint256`** is a **struct** `{ ctUint128 ciphertextHigh; ctUint128 ciphertextLow; }` — decoded locals and callback variables must use a `memory` location, and off‑chain reads return the two limbs as a tuple. -- **`itUint*`** (user encrypted inputs, `ciphertext + signature`), **`utUint*`** (dual‑ciphertext), **`gtString`** and **`ctString`** remain structs — keep their `calldata` / `memory` locations. - -Off‑chain decryption uses **`@coti-io/coti-sdk-typescript@^1.0.7`**, which exposes `decryptUint256({ ciphertextHigh, ciphertextLow }, accountAesKey)` for the 256‑bit lane. - -## Implementation checklist (condensed) - -Derived from the SDK’s [Writing privacy contracts](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05-writing-privacy-contracts-on-ethereum.md) and [Async execution](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05a-async-execution.md): - -1. **Classify data** — public metadata vs `it*` inputs vs `ct*` outputs vs internal `gt*` (COTI-only). -2. **Pick integration mode** — `PodLib` helpers vs custom `MpcAbiCodec` + COTI contract. -3. **Model async state** — persist `requestId`, track pending/completed/failed. -4. **Harden callbacks** — `onlyInbox`, correct `abi.decode` tuple, validate peer context when applicable. -5. **Configure routing safely** — gated `configure` / `configureCoti` / inbox updates. -6. **Budget fees** — understand `msg.value` and `callbackFeeLocalWei`; use Inbox fee views where available ([Fees doc](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/04-fees-gas-and-oracle.md)). -7. **Test failure paths** — spoofed callback must revert, error callbacks must mark failures, decrypt integration must match widths. +| **Inbox (interface)** | [IInbox.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/IInbox.sol) in `@coti-io/coti-contracts` | +| **Inbox (implementation)** | [Inbox.sol](https://github.com/coti-io/coti-pod-inbox-contracts/blob/main/contracts/Inbox.sol) in `@coti-io/coti-pod-inbox-contracts` | +| **Callback guard** | [InboxUser.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/InboxUser.sol) (`onlyInbox`) | +| **PodLib** | [PodLib.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpc/PodLib.sol), `PodLib64` / `128` / `256` — see [Reference: PodLib primitives](reference-podlib-and-primitives.md) | +| **PodUser / presets** | [PodUserSepolia.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpc/PodUserSepolia.sol), [PodUserFuji.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpc/PodUserFuji.sol) | +| **Network constants** | [PodNetworkConstants.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/PodNetworkConstants.sol) | +| **Types (`it*`, `ct*`, `gt*`)** | [MpcCore.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/utils/mpc/MpcCore.sol) — see [Reference: data types](reference-data-types.md) | +| **Custom COTI calls** | [MpcAbiCodec.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpccodec/MpcAbiCodec.sol) — see [Tutorial: custom privacy logic](tutorial-custom-logic.md) | +| **Client crypto** | [coti-pod-crypto.ts](https://github.com/coti-io/coti-sdk-pod/blob/main/src/coti-pod-crypto.ts) — see [TypeScript PoD SDK](typescript-pod-sdk.md) | +| **Request tracking** | [pod-request.ts](https://github.com/coti-io/coti-sdk-pod/blob/main/src/pod-request.ts) — `PodRequest.trackRequest` | +| **Fee oracle** | [InboxFeeManager.sol](https://github.com/coti-io/coti-pod-inbox-contracts/blob/main/contracts/fee/InboxFeeManager.sol) | + +## Before you ship + +Use the [Contract patterns checklist](contract-patterns-checklist.md) for production contract shape, fees, security, async UX, and tests. Pair it with [Async private operations](async-private-operations.md) for product-facing pending states. ## Relationship to native COTI “build” documentation -If you build **directly on COTI V2** with precompiles and private types, start from **[Build on COTI](../build-on-coti/README.md)**. PoD adds the **Inbox-mediated cross-chain** angle; many **cryptographic ideas rhyme**, but **deployment and UX** differ. +If you build **directly on COTI V2**, start from **[Build on COTI](../build-on-coti/README.md)**. PoD adds the **Inbox-mediated cross-chain** angle. ## Package install @@ -66,4 +35,4 @@ npm install "@coti-io/coti-contracts" npm install "@coti/pod-sdk" ``` -See [Getting started](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/04-getting-started.md) for the `contract MyApp is PodLib, PodUserSepolia` pattern. +Solidity preset pattern: [Reference: PodLib primitives](reference-podlib-and-primitives.md). diff --git a/privacy-on-demand/glossary.md b/privacy-on-demand/glossary.md index cbf6577..1610c78 100644 --- a/privacy-on-demand/glossary.md +++ b/privacy-on-demand/glossary.md @@ -1,18 +1,23 @@ # Glossary -Short definitions for **Privacy on Demand** readers. Precise Solidity definitions and type tables are in the [PoD SDK contract types](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/01-it-ct-gt-data-types.md) document. +Short definitions for **Privacy on Demand** readers. Precise type tables: [Reference: data types](reference-data-types.md). | Term | Meaning | | --- | --- | | **Privacy on Demand (PoD)** | Pattern and tooling for **private computation on COTI** while **orchestrating** from **another EVM chain** via an **Inbox**. | -| **Inbox** | **On-chain router** on your EVM chain that **forwards** private jobs toward COTI and **delivers callbacks** with results to your contract. | -| **MPC executor** | **COTI-side contract** configured as the execution target for **library-style** PoD flows; referenced from your dApp’s routing configuration. | -| **PodUser** | Solidity **configuration mixin** for **Inbox address**, **COTI chain id**, and **executor address**; changes should be **governed** (for example `onlyOwner`). | -| **PodLib** | Solidity **helper library** for **common private operations** (fixed-width arithmetic and comparisons in supported paths). | -| **`it*` (input types)** | **Encrypted user input** with required **signature material**, prepared client-side and sent to your contract. | -| **`gt*` (garbled / compute types)** | **Internal private representation** during computation on **COTI**—not something your EVM contract should expose as a public API. | -| **`ct*` (ciphertext types)** | **Encrypted outputs** suitable to **store on your chain**; users **decrypt locally** with **account AES** keys where applicable. | -| **PoA fees** | In this book, **Privacy on Demand (PoD) fees** for **two-way Inbox** traffic: native token on your chain that funds **COTI-side** and **callback** execution budgets. See [How do PoA fees work?](how-poa-fees-work.md). | -| **Two-way message** | Inbox flow: **outbound** request to COTI plus **inbound callback** to your contract; typically needs **fee** planning for both legs. | -| **Request ID** | Correlator tying a **submission** to a **callback**; essential for **async** UX and troubleshooting. | -| **Account AES key** | User-side secret material used to **decrypt** many `ct*` outputs after onboarding; must be **handled like credentials**. | +| **Inbox** | On-chain **message router** on each chain that forwards private jobs toward COTI and delivers callbacks. Implementation in [`coti-pod-inbox-contracts`](https://github.com/coti-io/coti-pod-inbox-contracts). | +| **MPC executor** | COTI-side contract configured as the execution target for **library-style** PoD flows. | +| **PodUser** | Solidity **configuration mixin** for Inbox address, COTI chain id, and executor address. | +| **PodUserSepolia / PodUserFuji** | Network presets that auto-wire inbox and COTI routing in the constructor. | +| **PodLib** | Solidity **helper library** for built-in private operations at 64/128/256-bit widths. | +| **`it*` (input types)** | Encrypted user input with signature material, prepared client-side. | +| **`gt*` (compute types)** | Internal private representation during computation on **COTI** — not for EVM public APIs. | +| **`ct*` (ciphertext types)** | Encrypted outputs stored on your chain; users decrypt locally with the account AES key. | +| **PoA / PoD fees** | Native token on your chain funding COTI-side and callback execution budgets. See [How do PoA fees work?](how-poa-fees-work.md). | +| **Two-way message** | Outbound request to COTI plus inbound callback to your contract. | +| **Request ID** | 32-byte correlator tying submission to callback; indexed in compact `MessageSent` events. | +| **Account AES key** | 32-hex-character user secret for decrypting `ct*` outputs. See [Account onboarding](account-onboarding-aes-key.md). | +| **PodRequest** | TypeScript helper (`@coti/pod-sdk`) that polls inbox state across chains for async UX. | +| **PodSdkConfig** | JSON config (chains, inbox addresses, RPCs, encryption network) shared by `PodContract` and `PodRequest`. | +| **`@coti-io/coti-contracts`** | npm package with PoD Solidity libraries, interfaces, and examples. | +| **`@coti-io/coti-pod-inbox-contracts`** | npm package with Inbox implementation, fee manager, and miner contracts. | diff --git a/privacy-on-demand/how-a-private-request-travels-end-to-end.md b/privacy-on-demand/how-a-private-request-travels-end-to-end.md index 5008a90..4cf5e9d 100644 --- a/privacy-on-demand/how-a-private-request-travels-end-to-end.md +++ b/privacy-on-demand/how-a-private-request-travels-end-to-end.md @@ -1,6 +1,6 @@ # How a private request travels end to end -This page describes **one full cycle** of Privacy on Demand **without assuming Solidity knowledge**. Names match what you will see in the [PoD SDK documentation](https://github.com/cotitech-io/coti-pod-sdk/tree/main/docs). +This page describes **one full cycle** of Privacy on Demand **without assuming Solidity knowledge**. Names match what you will see in the [developer documentation](for-developers-mapping-to-the-sdk.md). ## Cast of roles @@ -12,7 +12,7 @@ This page describes **one full cycle** of Privacy on Demand **without assuming S | **Inbox (EVM)** | On-chain **messaging hub** on **your chain** that **forwards** jobs to the **Inbox (COTI)** and **calls back** into your contract when the answer is ready. | | **Inbox (COTI)** | The **COTI-side Inbox contract**—the **counterpart** to the host Inbox. It receives cross-domain messages and routes work to the MPC Executor. | | **COTI private execution** | The environment that performs **private computation** on **compute-domain values** (`gt*` in developer docs). | -| **MPC Executor** | The **COTI-side contract** your integration targets for a given network (see SDK presets such as `PodUserSepolia` in [Getting started](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/04-getting-started.md)). The **Inbox (COTI)** invokes it; it is **not** the same contract as either Inbox. | +| **MPC Executor** | The **COTI-side contract** your integration targets for a given network (see presets such as `PodUserSepolia` in [Reference: PodLib primitives](reference-podlib-and-primitives.md)). The **Inbox (COTI)** invokes it; it is **not** the same contract as either Inbox. | ## The journey in seven steps @@ -79,7 +79,7 @@ sequenceDiagram ## Fees and gas -Private jobs that cross from your chain to COTI and back incur **network and execution costs**. Integrations typically attach **native token value** on the request and split it between **remote execution** and the **callback** leg. Operators configure **fee parameters** and **oracle** behavior on supporting contracts (see the SDK’s [Fees, gas, and oracle](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/04-fees-gas-and-oracle.md) page). +Private jobs that cross from your chain to COTI and back incur **network and execution costs**. Integrations typically attach **native token value** on the request and split it between **remote execution** and the **callback** leg. Operators configure **fee parameters** and **oracle** behavior in [`coti-pod-inbox-contracts`](https://github.com/coti-io/coti-pod-inbox-contracts) (see [How do PoA fees work?](how-poa-fees-work.md)). ## Next steps diff --git a/privacy-on-demand/how-poa-fees-work.md b/privacy-on-demand/how-poa-fees-work.md index 9a0f9b9..5c05127 100644 --- a/privacy-on-demand/how-poa-fees-work.md +++ b/privacy-on-demand/how-poa-fees-work.md @@ -4,7 +4,9 @@ This page explains how that payment is **split**, converted (via **oracles**) into **execution budgets** on each side—often described as **gas units**—and **consumed** step by step. -The numbers below are a **single worked example** so you can follow the arithmetic. Live networks use **oracle and Inbox policy** to set conversion rates and minimums; use your deployment’s **views** (for example `calculateTwoWayFeeRequiredInLocalToken`) and the SDK’s [Fees, gas, and oracle](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/04-fees-gas-and-oracle.md) reference for production. +The numbers below are a **single worked example** so you can follow the arithmetic. Live networks use **oracle and Inbox policy** to set conversion rates and minimums; use your deployment’s **views** (for example `calculateTwoWayFeeRequiredInLocalToken`) and [TypeScript PoD SDK](typescript-pod-sdk.md) fee estimation for production. + +Operator contracts: [`InboxFeeManager.sol`](https://github.com/coti-io/coti-pod-inbox-contracts/blob/main/contracts/fee/InboxFeeManager.sol), [`PriceOracle.sol`](https://github.com/coti-io/coti-pod-inbox-contracts/blob/main/contracts/fee/PriceOracle.sol) in **`@coti-io/coti-pod-inbox-contracts`**. ## Example call @@ -38,7 +40,7 @@ Solidity shape (conceptually): ## Walkthrough -Read the **first table top to bottom:** user ETH is split by leg, oracles supply **COTI** and **ETH** prices, the COTI leg is expressed as **quote → COTI tokens**, then policy turns each leg into **gas-unit budgets**. The **second table** spends **COTI** first, then **Sepolia** after the result exists. Underspend remains are illustrative; production behavior depends on **InboxMiner** / **InboxFeeManager** and operator policy (see the SDK [Fees, gas, and oracle](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/04-fees-gas-and-oracle.md) doc). +Read the **first table top to bottom:** user ETH is split by leg, oracles supply **COTI** and **ETH** prices, the COTI leg is expressed as **quote → COTI tokens**, then policy turns each leg into **gas-unit budgets**. The **second table** spends **COTI** first, then **Sepolia** after the result exists. Underspend remainders are illustrative; production behavior depends on **InboxMiner** / **InboxFeeManager** in [`coti-pod-inbox-contracts`](https://github.com/coti-io/coti-pod-inbox-contracts). ## Why this matters for `add(a, b) → ctUint64 c` @@ -49,7 +51,7 @@ Read the **first table top to bottom:** user ETH is split by leg, oracles supply ## Where to implement this in code - Solidity: payable **`add`** with **`msg.value`** and **`callbackFeeLocalWei`**, as in [Tutorial: private Adder on Sepolia](tutorial-private-adder-sepolia.md) (see [Tutorials overview](tutorials-privacy-on-demand.md) for how this fits the **primitive-only** model). -- Estimation: Inbox **`calculateTwoWayFeeRequiredInLocalToken`** and the [Fees, gas, and oracle](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/04-fees-gas-and-oracle.md) document in the PoD SDK repo. +- Estimation: Inbox **`calculateTwoWayFeeRequiredInLocalToken`** via [`PodContract.estimateFee`](typescript-pod-sdk.md). ## Disclaimer diff --git a/privacy-on-demand/reference-data-types.md b/privacy-on-demand/reference-data-types.md new file mode 100644 index 0000000..2fb3e15 --- /dev/null +++ b/privacy-on-demand/reference-data-types.md @@ -0,0 +1,93 @@ +# Reference: data types (`it*`, `ct*`, `gt*`) + +Canonical Solidity source: [`MpcCore.sol`](https://github.com/coti-io/coti-contracts/blob/main/contracts/utils/mpc/MpcCore.sol) in **`@coti-io/coti-contracts`**. + +PoD uses three type families. Mixing them at the wrong boundary breaks signature validation, callback decode, or privacy guarantees. For plain-language definitions, see the [Glossary](glossary.md). + +## Why the split exists + +| Family | Role | +| --- | --- | +| **`it*`** | User-submitted encrypted input plus signature material | +| **`ct*`** | Encrypted value stored on EVM and decrypted client-side with the account AES key | +| **`gt*`** | Private compute-domain value used on COTI | + +## `it*` (input payload) + +Valid on EVM entrypoints and in `MpcAbiCodec` payloads. + +| Type | Solidity shape | Typical use | +| --- | --- | --- | +| `itBool` | `{ ctBool ciphertext; bytes signature; }` | Signed encrypted bool input | +| `itUint8` … `itUint64` | `{ ctUint* ciphertext; bytes signature; }` | Signed encrypted scalar input | +| `itUint128` | `{ ctUint128 ciphertext; bytes[2] signature; }` | Signed 128-bit input | +| `itUint256` | `{ ctUint256 ciphertext; bytes[2][2] signature; }` | Signed 256-bit input | +| `itString` | `{ ctString ciphertext; bytes[] signature; }` | Signed encrypted string | + +## `ct*` (ciphertext output) + +Valid in EVM storage, callback payloads, and read APIs. + +| Type | Solidity shape | Off-chain decrypt shape | +| --- | --- | --- | +| `ctBool` … `ctUint128` | `type ctUint* is uint256` | single `uint256` word (`bigint` or `0x` hex) | +| `ctUint256` | `struct { ctUint128 ciphertextHigh; ctUint128 ciphertextLow; }` | `{ ciphertextHigh, ciphertextLow }` tuple | +| `ctString` | `struct { ctUint64[] value; }` | array of 64-bit cells | + +> **Note:** `ctUint128` is a user-defined value type wrapping one `uint256` word — not a struct of two limbs. Only `ctUint256` uses a two-limb struct. + +## `gt*` (private compute domain) + +Valid only on COTI-side contracts and executor operations. Never expose `gt*` in EVM public interfaces. + +| Type | Solidity shape | +| --- | --- | +| `gtBool` … `gtUint128` | `type gtUint* is uint256` | +| `gtUint256` | `struct { gtUint128 high; gtUint128 low; }` | +| `gtString` | `struct { gtUint64[] value; }` | + +## Conversion operations (`MpcCore`) + +- `onBoard(ct*) → gt*` — move ciphertext into compute domain +- `offBoard(gt*) → ct*` — contract-held ciphertext +- `offBoardToUser(gt*, address) → ct*` — user-targeted decryptable ciphertext + +## End-to-end boundary flow + +1. Client builds `it*`. +2. EVM accepts `it*` and sends a request through the Inbox. +3. `MpcAbiCodec.reEncodeWithGt(...)` validates and converts `it*` to `gt*` argument shape. +4. COTI logic computes on `gt*`. +5. COTI returns `ct*`. +6. EVM callback stores `ct*`. +7. Client decrypts `ct*` with the account AES key. + +## Critical gotcha: EVM `it*` maps to COTI `gt*` + +For custom COTI-side logic: + +- EVM function accepts `itUint64 amount` +- COTI function must be declared `gtUint64 amount` + +Declaring COTI parameters as `it*` for methods invoked through the Inbox pipeline will not match ABI expectations. + +## Required usage rules + +1. EVM private inputs: `it*` +2. EVM private results: `ct*` +3. COTI private compute: `gt*` +4. Keep width consistent (`itUint64 → gtUint64 → ctUint64`) +5. Do not store plaintext sensitive values on EVM + +## Frequent mistakes + +- Wrong decrypt type or AES key for the stored `ct*` width +- Mismatch between frontend `DataType` and Solidity type width +- Decoding callback tuple as the wrong `ct*` type +- Skipping `requestId` correlation in callback handlers + +## See also + +- [TypeScript PoD SDK](typescript-pod-sdk.md) — `DataType` enum and `CotiPodCrypto` +- [Reference: PodLib primitives](reference-podlib-and-primitives.md) +- [Tutorial: custom privacy logic with PoD](tutorial-custom-logic.md) diff --git a/privacy-on-demand/reference-examples-and-contracts.md b/privacy-on-demand/reference-examples-and-contracts.md new file mode 100644 index 0000000..9ef3315 --- /dev/null +++ b/privacy-on-demand/reference-examples-and-contracts.md @@ -0,0 +1,72 @@ +# Reference: examples and contracts + +Shipped reference contracts live in [**`@coti-io/coti-contracts`**](https://github.com/coti-io/coti-contracts/tree/main/contracts/pod/examples). They teach integration patterns — not production templates. For hardening guidance, see [Contract patterns checklist](contract-patterns-checklist.md). + +## Example matrix + +| Example | Path | What it demonstrates | +| --- | --- | --- | +| MPC Adder | [`MpcAdder.sol`](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/examples/MpcAdder.sol) | Minimal `PodLib` async request and `ctUint64` callback storage | +| Pod Adder 128 | [`PodAdder128.sol`](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/examples/it128/PodAdder128.sol) | 128-bit lane primitive flow | +| Pod Adder 256 | [`PodAdder256.sol`](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/examples/it256/PodAdder256.sol) | 256-bit lane primitive flow | +| Pausable Adder | [`MpcAdderPausable.sol`](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/examples/MpcAdderPausable.sol) | Same as `MpcAdder`, but callback reverts while paused — useful for testing fault paths | + +## Related token and portal contracts + +For private token flows beyond primitives: + +| Area | Starting point | +| --- | --- | +| Private ERC20 (PoD) | [`PodERC20.sol`](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/token/perc20/PodERC20.sol) and [`token/perc20/`](https://github.com/coti-io/coti-contracts/tree/main/contracts/pod/token/perc20) | +| ERC-7984 portal tokens | [`token/erc7984/`](https://github.com/coti-io/coti-contracts/tree/main/contracts/pod/token/erc7984) | +| Privacy portal | [`privacy/PrivacyPortal.sol`](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/privacy/PrivacyPortal.sol) | + +Live demos: [pod.coti.io](https://pod.coti.io/) (MpcAdder journey), [millionaire.demo.coti.io](https://millionaire.demo.coti.io) (comparison game — source may differ from current repo layout). + +## `MpcAdder.sol` + +Key ideas: + +- Extend `PodLib` with a network preset (`PodUserSepolia` or similar). +- Accept `itUint64` inputs on a payable entrypoint. +- Pass `msg.value` and `callbackFeeLocalWei` into `add64`. +- Decode callback payload as `ctUint64`. + +**Start here** for the smallest working async private flow. Step-by-step guide: [Tutorial: private Adder on Sepolia](tutorial-private-adder-sepolia.md). Production hardening: [Contract patterns checklist](contract-patterns-checklist.md). + +## `PodAdder128.sol` / `PodAdder256.sol` + +Same pattern as `MpcAdder` at wider bit widths. Use when your product needs `itUint128` / `itUint256` lanes and matching `PodLib128` / `PodLib256` helpers. + +## `MpcAdderPausable.sol` + +Extends `MpcAdder` with OpenZeppelin `Pausable`. The success callback (`receiveC`) is gated with `whenNotPaused`, so **private execution on COTI can still complete** while the **callback on your host chain reverts** if the contract is paused. + +Use this example to test fault scenarios end to end: + +1. Submit an `add` request while the contract is **paused**. +2. Observe the outbound leg succeed on COTI, but the callback fail when the Inbox invokes `receiveC`. +3. Verify your client handles the failure — for example [`PodRequest`](typescript-pod-sdk.md) reporting `response.execution`, `onDefaultMpcError` / `ErrorRemoteCall` events, or UI **failed** state ([Async private operations](async-private-operations.md)). +4. Call `unpause()` and retry, or confirm stuck requests behave as your product expects. + +This is primarily a **testing and integration** reference, not a production pause design. For operational controls in production, pair pause logic with explicit request status, error callbacks, and support runbooks ([Contract patterns checklist](contract-patterns-checklist.md)). + +## Custom-logic patterns (not in `examples/`) + +Stateful comparison games and custom COTI orchestration follow the split-contract model in: + +- [Tutorial: custom privacy logic with PoD](tutorial-custom-logic.md) +- [Cookbook: private investor allocations](cookbook-private-investor-allocations.md) + +## Suggested study order + +1. `MpcAdder.sol` + [private Adder tutorial](tutorial-private-adder-sepolia.md) +2. `MpcAdderPausable.sol` when you need to test callback failure (e.g. paused contract) +3. `PodAdder256.sol` if you need 256-bit lanes +4. Custom logic tutorial when primitives are insufficient +5. Token/portal contracts when building private assets + +## See also + +- [Reference: PodLib primitives](reference-podlib-and-primitives.md) +- [Tutorials: building PoD dApps](tutorials-privacy-on-demand.md) diff --git a/privacy-on-demand/reference-podlib-and-primitives.md b/privacy-on-demand/reference-podlib-and-primitives.md new file mode 100644 index 0000000..3848cf8 --- /dev/null +++ b/privacy-on-demand/reference-podlib-and-primitives.md @@ -0,0 +1,87 @@ +# Reference: PodLib primitives + +Source: [`PodLib.sol`](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpc/PodLib.sol) and bit-width modules [`PodLib64.sol`](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpc/PodLib64.sol), [`PodLib128.sol`](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpc/PodLib128.sol), [`PodLib256.sol`](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpc/PodLib256.sol) in **`@coti-io/coti-contracts`**. + +`PodLib` is the fast path for **built-in private operations** on COTI without writing a custom COTI contract. It inherits `PodLibBase`, which forwards total and callback native fees to `IInbox.sendTwoWayMessage`. + +## Network presets + +Compose `PodLib` with a chain preset mixin: + +| Mixin | Host chain | Source | +| --- | --- | --- | +| `PodUserSepolia` | Ethereum Sepolia (11155111) | [`PodUserSepolia.sol`](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpc/PodUserSepolia.sol) | +| `PodUserFuji` | Avalanche Fuji (43113) | [`PodUserFuji.sol`](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpc/PodUserFuji.sol) | + +Presets call `setInbox` and `configureCoti` in their constructor. Your contract only needs: + +```solidity +contract MyApp is PodLib, PodUserSepolia { + constructor() PodLibBase(msg.sender) {} +} +``` + +Network constants (inbox address, COTI chain id, MPC executor) live in [`PodNetworkConstants.sol`](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/PodNetworkConstants.sol). Confirm values against your installed package version. + +## What PodLib does + +- Builds method payloads with `MpcAbiCodec` +- Routes messages to the configured COTI MPC executor +- Sends two-way Inbox requests with callback and error selectors +- Provides default error handler `onDefaultMpcError(bytes32 requestId)` + +**Type mapping:** EVM helpers accept `it*` arguments; COTI executor methods use `gt*` parameters. The inbox pipeline validates and re-encodes before COTI invocation. + +## Primitive families (by bit width) + +Each helper follows a fee-aware shape: + +```solidity +function add64( + itUint64 memory a, + itUint64 memory b, + address cOwner, + bytes4 callbackSelector, + bytes4 errorSelector, + uint256 totalValueWei, + uint256 callbackFeeLocalWei +) internal returns (bytes32); +``` + +256-bit examples from `PodLib256` include: + +| Category | Functions | +| --- | --- | +| Arithmetic | `add256`, `sub256`, `mul256`, `mulWrapping256` | +| Bitwise | `and256`, `or256`, `xor256` | +| Compare | `eq256`, `ne256`, `ge256`, `gt256`, `le256`, `lt256`, `min256`, `max256` | +| Select | `mux256` | +| Shift | `shl256`, `shr256` | +| Random | `rand256`, `randBoundedBits256` | + +64- and 128-bit variants mirror the same families on `PodLib64` / `PodLib128`. See the source files for the complete matrix and exact signatures. + +## Fees + +Library sends go through `_sendTwoWayWithFee`: + +- **`totalValueWei`** — forwarded as `msg.value` to the Inbox (entire message budget) +- **`callbackFeeLocalWei`** — slice reserved for the callback leg + +See [How do PoA fees work?](how-poa-fees-work.md) for oracle conversion and worked examples. + +## When to move beyond PodLib + +Use custom EVM + COTI contracts when: + +- The operation is not a built-in primitive +- The callback payload is a custom tuple +- COTI logic needs multiple private steps and persistent state + +See [Tutorial: custom privacy logic with PoD](tutorial-custom-logic.md) and [Tutorials: building PoD dApps](tutorials-privacy-on-demand.md). + +## See also + +- [Reference: data types](reference-data-types.md) +- [Contract patterns checklist](contract-patterns-checklist.md) +- [Tutorial: private Adder on Sepolia](tutorial-private-adder-sepolia.md) — full walkthrough with TypeScript diff --git a/privacy-on-demand/tutorial-custom-logic.md b/privacy-on-demand/tutorial-custom-logic.md index 35521a7..669060d 100644 --- a/privacy-on-demand/tutorial-custom-logic.md +++ b/privacy-on-demand/tutorial-custom-logic.md @@ -56,7 +56,7 @@ contract DirectMessageCotiSide is InboxUserCotiTestnet { The Sepolia contract **inherits `PodUserSepolia`** (or your network’s `PodUser` preset), tracks the **COTI peer address**, and: -1. **`sendMessage`** — Wraps encrypted input (`itString`) and public addresses in an **`IInbox.MpcMethodCall`** built with **`MpcAbiCodec`** (see the SDK’s [Request builder and remote calls](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/03-request-builder-and-remote-calls.md)). It sends a **two-way** message so the result comes back asynchronously. +1. **`sendMessage`** — Wraps encrypted input (`itString`) and public addresses in an **`IInbox.MpcMethodCall`** built with **`MpcAbiCodec`** (see [Reference: data types](reference-data-types.md) and [Contract patterns checklist](contract-patterns-checklist.md)). It sends a **two-way** message so the result comes back asynchronously. 2. **`onMessageReceived`** — Decodes the tuple produced on COTI, **re-checks `inboxMsgSender()`**, and stores **`ctString`** keyed by conversation participants (or whatever your product needs). The Solidity below is **structurally** correct; wire **`MpcAbiCodec`**’s `create` / `addArgument` / `build` steps exactly as in your installed `@coti-io/coti-contracts` version (argument order and `gt`/`it` interface types **must** match the COTI method signature). @@ -132,9 +132,8 @@ contract DirectMessageEvm is PodUserSepolia { This chapter stops at **Solidity** to highlight the **chain split**. For **encryption**, **Inbox fee estimation**, and **client-side decryption** of `ctString`, continue with: - [Tutorial: private Adder on Sepolia](tutorial-private-adder-sepolia.md) — includes **`PodContract`**, **`encryptAndCallMethod`**, **`estimateFee`**, and **`extractRequestIds`** so you can copy the same client pattern to **`sendMessage`** (build **`PodMethodArgument[]`** with types that match your ABI: **`itString`** for the ciphertext argument, plain types for addresses and the callback-fee slot, **`isCallBackFee: true`** on the fee parameter). -- [TypeScript PoD SDK (`CotiPodCrypto`, `PodContract`)](typescript-pod-sdk.md) — short reference for **`CotiPodCrypto`** and **`PodContract`** with links to [`coti-pod-crypto.ts`](https://github.com/cotitech-io/coti-pod-sdk/blob/main/src/coti-pod-crypto.ts) and [`pod-method-call.ts`](https://github.com/cotitech-io/coti-pod-sdk/blob/main/src/pod-method-call.ts). -- [TypeScript integration — SDK](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/06-typescript-integration-ux-development.md) -- [Writing privacy contracts on Ethereum — SDK](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05-writing-privacy-contracts-on-ethereum.md) (custom mode) +- [TypeScript PoD SDK](typescript-pod-sdk.md) — `CotiPodCrypto`, `PodContract`, `PodRequest` with links to [`coti-pod-crypto.ts`](https://github.com/coti-io/coti-sdk-pod/blob/main/src/coti-pod-crypto.ts) and [`pod-method-call.ts`](https://github.com/coti-io/coti-sdk-pod/blob/main/src/pod-method-call.ts). +- [Contract patterns checklist](contract-patterns-checklist.md) — custom mode hardening After **`encryptAndCallMethod("sendMessage", args, feeCfg)`** (or a raw **`ethers.Contract`** send), use **`await pod.extractRequestIds(receipt.hash)`** on the same **`PodContract`** instance so your UI stores the **`requestId`** emitted in the Inbox **`MessageSent`** logs—same helper as in the adder walkthrough. diff --git a/privacy-on-demand/tutorial-private-adder-sepolia.md b/privacy-on-demand/tutorial-private-adder-sepolia.md index 695a60f..e4c7b18 100644 --- a/privacy-on-demand/tutorial-private-adder-sepolia.md +++ b/privacy-on-demand/tutorial-private-adder-sepolia.md @@ -4,7 +4,7 @@ This walkthrough is the **primitive-only** path: your host-chain contract calls This guide shows how to build a minimal **Privacy on Demand** dApp that **adds two encrypted integers** on COTI and stores the **encrypted sum** on your EVM contract. It follows the same ideas as the [MpcAdder.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/examples/MpcAdder.sol) example, extended with **Sepolia routing presets** and **request correlation** suitable for a real UI. -For background on async flows and fees, see [Async private operations](async-private-operations.md), [How do PoA fees work?](how-poa-fees-work.md), and the SDK’s [Fees, gas, and oracle](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/04-fees-gas-and-oracle.md) page. +For background on async flows and fees, see [Async private operations](async-private-operations.md), [How do PoA fees work?](how-poa-fees-work.md), and [TypeScript PoD SDK](typescript-pod-sdk.md) fee estimation. ## Writing a PoD example @@ -15,14 +15,14 @@ In this example we will do the following: 3. **Implement a success callback** that decodes `abi.encode(ctUint256)` and stores the ciphertext. 4. **Wire `onDefaultMpcError.selector`** so failed remote runs surface through the SDK’s default error path (and emit `ErrorRemoteCall` from `PodUser`). -After that works, you harden for production: per-user request ownership, explicit `pending / completed / failed` state, fee estimation via the Inbox, and tests for under-funded sends. The SDK’s [Examples with description](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05c-examples-with-description.md) lists what the shipped `MpcAdder` omits on purpose. +After that works, you harden for production: per-user request ownership, explicit `pending / completed / failed` state, fee estimation via the Inbox, and tests for under-funded sends. See [Reference: examples and contracts](reference-examples-and-contracts.md) for what the shipped `MpcAdder` omits on purpose. ## Prerequisites - **Solidity toolchain** (Foundry or Hardhat) targeting **Ethereum Sepolia** (where the SDK’s `PodUserSepolia` Inbox is deployed). - **Node.js 18+** for scripts and `fetch` used by encryption helpers. - **Sepolia ETH** for deployment and for **`msg.value`** on each `add` call (plus gas). -- **User onboarding** so your client can obtain an **account AES key** for decryption (see the SDK’s [TypeScript integration](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/06-typescript-integration-ux-development.md) and [Onboarding / account AES key](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/06c-onboarding-account-account-aes-key.md) docs). +- **User onboarding** so your client can obtain an **account AES key** for decryption (see [Account onboarding (AES key)](account-onboarding-aes-key.md)). Always confirm **Inbox**, **COTI chain id**, and **MPC executor** against the version of `PodUserSepolia.sol` in your installed `@coti-io/coti-contracts` package; constants can change between releases. @@ -39,7 +39,7 @@ Save as `PrivateAdder.sol`. The contract: - Inherits **`PodLib`** and **`PodUserSepolia`** (Sepolia defaults for Inbox and COTI routing). - Calls **`add256`** with the caller’s encrypted inputs and your callback selector. -- Resolves **`requestId`** in the callback the same way as the SDK’s [Getting started](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/04-getting-started.md) example. +- Resolves **`requestId`** in the callback using `inboxSourceRequestId()` with fallback to `inboxRequestId()` (see [Contract patterns checklist](contract-patterns-checklist.md)). ```solidity // SPDX-License-Identifier: UNLICENSED @@ -64,10 +64,8 @@ contract PrivateAdder is PodLib, PodUserSepolia { event AddRequested(bytes32 indexed requestId, address indexed caller); event AddCompleted(bytes32 indexed requestId); - constructor() PodLibBase(msg.sender) { - setInbox(INBOX_ADDRESS); - configureCoti(MPC_EXECUTOR_ADDRESS, COTI_CHAIN_ID); - } + constructor() PodLibBase(msg.sender) {} + // PodUserSepolia constructor auto-wires inbox and COTI routing from PodNetworkConstants /// @param callbackFeeLocalWei Wei reserved for the callback leg; must be <= msg.value (see SDK fee docs). function add( @@ -106,7 +104,7 @@ contract PrivateAdder is PodLib, PodUserSepolia { - **`onDefaultMpcError`** is implemented on `PodLibBase` and forwards failures to **`ErrorRemoteCall`** on `PodUser`. Your UI can listen for that event to mark a request failed. - **`addCallback`** must stay **`onlyInbox`** so random accounts cannot forge results. -- **`ctUint256`** is a Solidity **struct** `{ ctUint128 ciphertextHigh; ctUint128 ciphertextLow; }`, so the decoded local must use a `memory` location and the storage mapping holds the two‑limb tuple. The narrower garbled / ciphertext types (`gtUint8…gtUint256`, `gtBool`, and `ctUint8…ctUint128`) are **user‑defined value types** — pass and assign them like `uint256` (no `memory` / `calldata`). Encrypted-input wrappers such as **`itUint256`** stay structs and keep their `calldata` / `memory` location as before. +- **`ctUint256`** callback decode uses a `memory` struct — see [Reference: data types](reference-data-types.md) for type shapes. ## Step 3: Compile and deploy on Sepolia @@ -118,7 +116,7 @@ Two-way Inbox traffic needs enough native token to cover **outbound execution** ## Step 5: Encrypt the two summands (TypeScript) -`CotiPodCrypto.encrypt` calls the PoD encryption service. For Sepolia-style test usage, pass **`"testnet"`** as the network key (see [`coti-pod-crypto.ts`](https://github.com/cotitech-io/coti-pod-sdk/blob/main/src/coti-pod-crypto.ts) in the SDK: `testnet` maps to the COTI testnet encryption endpoint). +`CotiPodCrypto.encrypt` calls the PoD encryption service. For Sepolia-style test usage, pass **`"testnet"`** as the network key (see [`coti-pod-crypto.ts`](https://github.com/coti-io/coti-sdk-pod/blob/main/src/coti-pod-crypto.ts): `testnet` maps to the COTI testnet encryption endpoint). Use **`DataType.itUint256`** when you build **`itUint256`** calldata yourself (for example with **`ethers.Contract`**). If you use **`PodContract.encryptAndCallMethod`** in the next step, you can skip manual encryption: pass **plaintext numeric strings** and **`DataType.itUint256`** in each `PodMethodArgument`, and the SDK encrypts before encoding the transaction. @@ -135,7 +133,7 @@ const encB = await CotiPodCrypto.encrypt(plainB, "testnet", DataType.itUint256); ## Step 6: Submit the `add` transaction (`PodContract`, fees, `extractRequestIds`) -[`PodContract`](https://github.com/cotitech-io/coti-pod-sdk/blob/main/src/pod-method-call.ts) wraps your **`ethers.Contract`**: it **`estimateFee`**s against the Inbox, maps **`PodMethodArgument`** values (including **`encryptAndCallMethod`** encryption for **`it*`** types), injects the **`callBackFee`** into the slot marked **`isCallBackFee: true`**, sends **`value: totalFee`** on payable functions, and exposes **`extractRequestIds(txHash)`** to read **`requestId`** values from **`MessageSent`** logs on the Inbox (reliable across layouts where parsing logs from the app contract alone is brittle). +[`PodContract`](https://github.com/coti-io/coti-sdk-pod/blob/main/src/pod-method-call.ts) wraps your **`ethers.Contract`**: it **`estimateFee`**s against the Inbox, maps **`PodMethodArgument`** values (including **`encryptAndCallMethod`** encryption for **`it*`** types), injects the **`callBackFee`** into the slot marked **`isCallBackFee: true`**, sends **`value: totalFee`** on payable functions, and exposes **`extractRequestIds(txHash)`** to read **`requestId`** values from compact **`MessageSent`** logs on the Inbox. ```typescript import { @@ -234,22 +232,22 @@ console.log("sum (plaintext string):", decryptedString); // Expect "30" for plainA=10 and plainB=20 ``` -`CotiPodCrypto.decrypt` delegates to **`@coti-io/coti-sdk-typescript`** (`^1.0.7`), which now exposes `decryptUint256({ ciphertextHigh, ciphertextLow }, accountAesKey)` for the 256‑bit lane. Narrower lanes (`Uint64`, `Uint128`, …) still take a single `uint256` ciphertext as a `bigint` or `0x`‑prefixed hex string (see SDK source [coti-pod-crypto.ts](https://github.com/cotitech-io/coti-pod-sdk/blob/main/src/coti-pod-crypto.ts)). +`CotiPodCrypto.decrypt` delegates to **`@coti-io/coti-sdk-typescript`**, which exposes `decryptUint256({ ciphertextHigh, ciphertextLow }, accountAesKey)` for the 256‑bit lane. See [COTI TypeScript SDK for PoD](coti-typescript-sdk-for-pod.md). ## Step 8: Sanity checks and next steps -- **Callback decode** must stay **`(ctUint256)`** — and the local must use `memory` because `ctUint256` is a struct. Changing the executor op or COTI-side behavior without updating the decode tuple will corrupt storage reads. -- **Type lane** — This contract uses **`add256`** with **`itUint256`** / **`ctUint256`** on chain, so pass **`DataType.Uint256`** to `CotiPodCrypto.decrypt` and feed it the **`{ ciphertextHigh, ciphertextLow }`** tuple read from the contract. Narrower lanes (`Uint64`, `Uint128`) still take a single ciphertext word. -- **Type model** — In `MpcCore.sol`, `gtUint*`, `gtBool`, and `ctUint8…ctUint128` are **user‑defined value types** (`type X is uint256`) — drop `memory` / `calldata` on them. `ctUint256` is a struct (two `ctUint128` limbs); `itUint*` / `utUint*` are also still structs, so keep `calldata` / `memory` on those. -- **Production**: add tests for non-Inbox callers on `addCallback`, under-funded `msg.value`, and decrypt failures; follow the [first production checklist](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/04-getting-started.md) in Getting started. +- **Callback decode** must stay **`(ctUint256)`** with a `memory` local — see [Reference: data types](reference-data-types.md). +- **Type lane** — This walkthrough uses **`add256`** / **`itUint256`** / **`ctUint256`**; pass **`DataType.Uint256`** to `CotiPodCrypto.decrypt` with the `{ ciphertextHigh, ciphertextLow }` tuple from storage. +- **Production**: follow the [Contract patterns checklist](contract-patterns-checklist.md). ## Reference links -- [`pod-method-call.ts` (`PodContract`, fees, `extractRequestIds`)](https://github.com/cotitech-io/coti-pod-sdk/blob/main/src/pod-method-call.ts) +- [TypeScript PoD SDK](typescript-pod-sdk.md) — `PodContract`, `PodRequest`, fees +- [`pod-method-call.ts`](https://github.com/coti-io/coti-sdk-pod/blob/main/src/pod-method-call.ts) - [MpcAdder.sol (minimal repo example)](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/examples/MpcAdder.sol) -- [Examples with description](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05c-examples-with-description.md) -- [Getting started (PodUserSepolia pattern)](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/04-getting-started.md) -- [Async execution](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05a-async-execution.md) +- [Reference: examples and contracts](reference-examples-and-contracts.md) +- [Reference: PodLib primitives](reference-podlib-and-primitives.md) +- [Async private operations](async-private-operations.md)
diff --git a/privacy-on-demand/tutorials-privacy-on-demand.md b/privacy-on-demand/tutorials-privacy-on-demand.md index 53fc498..96aa408 100644 --- a/privacy-on-demand/tutorials-privacy-on-demand.md +++ b/privacy-on-demand/tutorials-privacy-on-demand.md @@ -10,23 +10,9 @@ In the **PoD Solidity SDK**, these primitives are exposed as helpers on **`PodLi If your business logic **only** needs these operations, and only **once or twice** per user action (or in a similarly small composition), you can usually implement the whole flow from your **host-chain contract** by calling **`PodLib`** helpers, which package the Inbox round-trip to the executor. -### Available primitive families (per width) +### Primitive catalog -For **64-, 128-, and 256-bit** lanes, the library surface includes (names may be width-suffixed in Solidity, for example `add64` / `add128` / `add256`): - -**Arithmetic and bitwise:** `add`, `mul`, `div`, `rem`, `and`, `or`, `xor` - -**Min / max:** `min`, `max` - -**Comparisons:** `eq`, `ne`, `ge`, `le`, `lt` - -**Control:** `mux` - -**Shifts:** `shl`, `shr` - -**Randomness:** `randBoundedBits` - -For the authoritative list, signatures, and gas notes, use the SDK’s **[MPC library (PodLib)](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05b-multi-party-computing-library-mpclib.md)** and **[PodLib.sol](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/mpc/PodLib.sol)** in your installed `@coti-io/coti-contracts` version. +Arithmetic, comparison, bitwise, shift, mux, and randomness helpers exist at **64-, 128-, and 256-bit** widths (`add64`, `add256`, …). Full signatures and categories: [Reference: PodLib primitives](reference-podlib-and-primitives.md). ### Example tutorial (simple PoD dApp) @@ -42,7 +28,7 @@ Same topic as the **blue callout at the top of this page**: one primitive (`add` TypeScript usage is documented on a dedicated page so this overview stays short: -- [TypeScript PoD SDK (`CotiPodCrypto`, `PodContract`)](typescript-pod-sdk.md) — encryption/decryption, `estimateFee`, `encryptAndCallMethod`, `callMethod`, and `extractRequestIds`. +- [TypeScript PoD SDK](typescript-pod-sdk.md) — encryption/decryption, `PodContract`, `PodRequest`, fee estimation, and request tracking. ### Business dApp cookbook @@ -138,9 +124,9 @@ flowchart LR | Your situation | Start here | | --- | --- | -| Logic fits the primitive list and a small number of MPC steps | [Tutorial: private Adder on Sepolia](tutorial-private-adder-sepolia.md), [TypeScript PoD SDK (`CotiPodCrypto`, `PodContract`)](typescript-pod-sdk.md), then [MPC library (PodLib) — SDK](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05b-multi-party-computing-library-mpclib.md) | +| Logic fits the primitive list and a small number of MPC steps | [Tutorial: private Adder on Sepolia](tutorial-private-adder-sepolia.md), [TypeScript PoD SDK](typescript-pod-sdk.md), [Reference: PodLib primitives](reference-podlib-and-primitives.md) | | You want a business-oriented public-to-private migration | [Cookbook: private investor allocations with PoD](cookbook-private-investor-allocations.md), then [Tutorial: custom privacy logic with PoD](tutorial-custom-logic.md) | -| Logic needs custom COTI processing, `gt*` handling, or richer state | [Tutorial: custom privacy logic with PoD](tutorial-custom-logic.md), then [Writing privacy contracts on Ethereum — SDK](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/05-writing-privacy-contracts-on-ethereum.md) and [Request builder and remote calls — SDK](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/contracts/03-request-builder-and-remote-calls.md) | +| Logic needs custom COTI processing, `gt*` handling, or richer state | [Tutorial: custom privacy logic with PoD](tutorial-custom-logic.md), [Contract patterns checklist](contract-patterns-checklist.md) | | Fees, async UX, and components | [How do PoA fees work?](how-poa-fees-work.md), [Async private operations](async-private-operations.md), [Architecture and main components](architecture-and-components.md) | Return to the [Privacy on Demand section index](README.md). diff --git a/privacy-on-demand/typescript-pod-sdk.md b/privacy-on-demand/typescript-pod-sdk.md index 6680d8c..6bb21f4 100644 --- a/privacy-on-demand/typescript-pod-sdk.md +++ b/privacy-on-demand/typescript-pod-sdk.md @@ -1,76 +1,95 @@ -# TypeScript PoD SDK (`CotiPodCrypto`, `PodContract`) +# TypeScript PoD SDK (`CotiPodCrypto`, `PodContract`, `PodRequest`) -The npm package **`@coti/pod-sdk`** ships TypeScript helpers for **encrypting and decrypting** PoD payloads and for **encoding, fee estimation, and sending** calls against your host-chain contract through [`coti-pod-crypto.ts`](https://github.com/cotitech-io/coti-pod-sdk/blob/main/src/coti-pod-crypto.ts) and [`pod-method-call.ts`](https://github.com/cotitech-io/coti-pod-sdk/blob/main/src/pod-method-call.ts). +The npm package **`@coti/pod-sdk`** is the canonical TypeScript client for PoD dApps. It covers encryption/decryption, fee-aware contract calls, and cross-chain request tracking through [`coti-pod-crypto.ts`](https://github.com/coti-io/coti-sdk-pod/blob/main/src/coti-pod-crypto.ts), [`pod-method-call.ts`](https://github.com/coti-io/coti-sdk-pod/blob/main/src/pod-method-call.ts), and [`pod-request.ts`](https://github.com/coti-io/coti-sdk-pod/blob/main/src/pod-request.ts). -Use these helpers from a wallet script, backend service, or dApp frontend once you have a **`Signer`** (or **`Provider`** for read-only helpers) and your contract **ABI**. +```bash +npm install @coti/pod-sdk ethers +``` -## Encrypt and decrypt data (`CotiPodCrypto`) +| Concern | Class / helpers | +| --- | --- | +| Encrypt `it*` inputs and decrypt `ct*` results | `CotiPodCrypto` | +| Submit PoD method calls (fees, encryption, event parsing) | `PodContract` | +| Track async request lifecycle across chains | `PodRequest` | -`CotiPodCrypto.encrypt` POSTs to the PoD encryption service: +Account key recovery is **not** in this package — use [`@coti-io/coti-sdk-typescript`](coti-typescript-sdk-for-pod.md) (see [Account onboarding](account-onboarding-aes-key.md)). -- `"testnet"` and `"mainnet"` resolve to SDK defaults. -- You can also pass a full encryption service URL. -- `DataType` distinguishes plaintext types (`Uint64`, `String`, etc.) from **`it*`** types that become ciphertext tuples on chain. +## Shared config (`PodSdkConfig`) -`CotiPodCrypto.decrypt` uses the user's **account AES key** and **`@coti-io/coti-sdk-typescript`** (`^1.0.7`) under the hood. +`PodSdkConfig` is plain JSON shared by `PodContract` and `PodRequest`: ```typescript -import { CotiPodCrypto, DataType } from "@coti/pod-sdk"; +import { + CotiPodCrypto, + DataType, + PodContract, + PodRequest, + SEPOLIA_DEFAULT_INBOX_ADDRESS, + COTI_TESTNET_DEFAULT_INBOX_ADDRESS, + type PodSdkConfig, +} from "@coti/pod-sdk"; -// Encrypt plaintext for Solidity itUint256 parameters -const enc = await CotiPodCrypto.encrypt("42", "testnet", DataType.itUint256); +const config: PodSdkConfig = { + encryptionNetwork: "testnet", // or "mainnet" or a full service URL + chains: [ + { + chainId: 11155111, + inboxAddress: SEPOLIA_DEFAULT_INBOX_ADDRESS, + rpcUrl: process.env.SEPOLIA_RPC_URL!, + }, + { + chainId: 7082400, + inboxAddress: COTI_TESTNET_DEFAULT_INBOX_ADDRESS, + rpcUrl: process.env.COTI_TESTNET_RPC_URL!, + }, + ], +}; +``` + +- **`chainId`** — EIP-155 chain id +- **`inboxAddress`** — PoD Inbox on that chain (CREATE3 address from [`PodNetworkConstants`](https://github.com/coti-io/coti-contracts/blob/main/contracts/pod/PodNetworkConstants.sol)) +- **`rpcUrl`** — JSON-RPC for fee estimation and `PodRequest` polling +- **`encryptionNetwork`** — `"testnet"` / `"mainnet"` keyword or full URL for `CotiPodCrypto.encrypt` + +`PodContract` resolves inbox address from `config.chains` or falls back to `DEFAULT_INBOX_ADDRESS_BY_CHAIN_ID`. + +## Encrypt and decrypt (`CotiPodCrypto`) -// Decrypt a narrow scalar ciphertext (one uint256 word) read from contract storage -const plain64 = CotiPodCrypto.decrypt("0x...", accountAesKeyFromOnboarding, DataType.Uint64); +`CotiPodCrypto.encrypt` POSTs to the PoD encryption service (`"testnet"`, `"mainnet"`, or a full URL). `CotiPodCrypto.decrypt` uses the account AES key and `@coti-io/coti-sdk-typescript` under the hood. -// Decrypt a ctUint256 value (a struct with two ctUint128 limbs) +```typescript +import { CotiPodCrypto, DataType } from "@coti/pod-sdk"; + +const enc = await CotiPodCrypto.encrypt("42", "testnet", DataType.itUint256); +const plain64 = CotiPodCrypto.decrypt("0x...", accountAesKey, DataType.Uint64); const plain256 = CotiPodCrypto.decrypt( { ciphertextHigh, ciphertextLow }, - accountAesKeyFromOnboarding, + accountAesKey, DataType.Uint256 ); ``` -### Ciphertext shape in `MpcCore.sol` - -After the gt‑type upgrade, the on‑chain types you read back have these shapes: - -| Type | Solidity | Off‑chain shape | -| -------------------------- | --------------------------------------------------------- | ---------------------------------------------- | -| `gtUint8` … `gtUint256`, `gtBool` | User‑defined value type (`type … is uint256`), no `memory`/`calldata` | n/a — never crosses the chain boundary | -| `ctUint8` … `ctUint128` | User‑defined value type | single `uint256` word | -| `ctUint256` | Struct `{ ctUint128 ciphertextHigh; ctUint128 ciphertextLow; }` | tuple `{ ciphertextHigh, ciphertextLow }` (each `bigint`) | -| `itUint*` / `utUint*` | Struct (ciphertext + signature, unchanged) | tuple / object | -| `gtString` / `ctString` | Struct (array of `gtUint64` / `ctUint64`, unchanged) | array of words | +Off-chain decrypt shapes for `ct*` / `it*` types: [Reference: data types](reference-data-types.md). -When you read a `ctUint256` value via ethers or viem, the storage getter returns the two limbs as a tuple — normalize it to `{ ciphertextHigh, ciphertextLow }` before passing it to `CotiPodCrypto.decrypt` (or to `decryptUint256` from `@coti-io/coti-sdk-typescript`). The narrower `ct*` lanes can still be passed as a `bigint` or `0x`‑prefixed hex string. +## Method calls (`PodContract`) -## Gas estimation and method calls (`PodContract`) +`PodContract` wraps `ethers.Contract` with: -`PodContract` wraps `ethers.Contract` with PoD-aware helpers: - -- `estimateFee` for Inbox two-way fee calculation. -- `encryptAndCallMethod` to encrypt `it*` plaintext args and send the tx. -- `callMethod` to send pre-encrypted JSON ciphertext values. -- `extractRequestIds(txHash)` to parse Inbox `MessageSent` logs and recover request IDs for async tracking. +- `estimateFee` — Inbox `calculateTwoWayFeeRequiredInLocalToken` +- `encryptAndCallMethod` — encrypt `it*` plaintext args and send +- `callMethod` — submit pre-built `it*` JSON ciphertext +- `extractRequestIds` — read `requestId` from compact Inbox `MessageSent` events ```typescript -import { - PodContract, - DataType, - type PodFeeEstimationConfig, - type PodMethodArgument, -} from "@coti/pod-sdk"; +import { PodContract, DataType, type PodFeeEstimationConfig, type PodMethodArgument } from "@coti/pod-sdk"; import { ethers } from "ethers"; -const pod = new PodContract(contractAddress, abi, signer, { - encryptionNetwork: "testnet", -}); +const pod = new PodContract(contractAddress, abi, signer, { config }); const args: PodMethodArgument[] = [ { type: DataType.itUint256, value: "10", isCallBackFee: false }, { type: DataType.itUint256, value: "20", isCallBackFee: false }, - { type: DataType.Uint256, value: "0", isCallBackFee: true }, // auto-replaced with callback fee + { type: DataType.Uint256, value: "0", isCallBackFee: true }, ]; const feeCfg: PodFeeEstimationConfig = { @@ -80,29 +99,116 @@ const feeCfg: PodFeeEstimationConfig = { callBackDataSize: 512n, }; -const fee = await pod.estimateFee("add", args, feeCfg); -// fee.totalFee, fee.remoteFee, fee.callBackFee +const tx = await pod.encryptAndCallMethod("add", args, feeCfg); +const receipt = await (tx as ethers.ContractTransactionResponse).wait(); +const requestIds = receipt?.hash ? await pod.extractRequestIds(receipt.hash) : []; +``` -const txResponse = await pod.encryptAndCallMethod("add", args, feeCfg); -const receipt = await (txResponse as ethers.ContractTransactionResponse).wait(); +**Fee config rules:** -const requestIds = receipt?.hash ? await pod.extractRequestIds(receipt.hash) : []; +- `forwardGasLimit` and `gasPrice` are required +- `callBackGasLimit` and `callBackDataSize` must be set together or both omitted +- Exactly one argument may have `isCallBackFee: true` — `PodContract` overwrites its value with the computed callback fee + +## Request tracking (`PodRequest`) + +Poll `trackRequest(chainId, requestId)` for a fresh snapshot until the UI reaches a terminal state: + +```typescript +const tracker = new PodRequest(config); +const status = await tracker.trackRequest(11155111n, requestId); +``` + +| Field | Meaning | +| --- | --- | +| `minedOnTarget` | Target inbox ingested the request | +| `isTwoWay` | Callback expected | +| `execution` | Encode/subcall failure on target (`errorCode`, `errorMessage`) | +| `response` | Recursive tracking of the callback leg (two-way only) | + +**Completed two-way round-trip:** + +``` +status.isTwoWay === true +status.minedOnTarget === true +status.response !== null +status.response.minedOnTarget === true ``` -### Important fee config rules +**Error codes:** `ERROR_CODE_EXECUTION_FAILED` (1n), `ERROR_CODE_ENCODE_FAILED` (2n). Use `decodeInboxErrorMessage(rawHex)` to decode revert data. UI state mapping: [Async private operations](async-private-operations.md). -- `forwardGasLimit` and `gasPrice` are required. -- `callBackGasLimit` and `callBackDataSize` must be provided together (or both omitted). -- `forwardDataSize` is optional; SDK can estimate from argument string sizes. +## End-to-end example + +```typescript +import { + CotiPodCrypto, + DataType, + PodContract, + PodRequest, + SEPOLIA_DEFAULT_INBOX_ADDRESS, + COTI_TESTNET_DEFAULT_INBOX_ADDRESS, + type PodSdkConfig, +} from "@coti/pod-sdk"; +import { ethers } from "ethers"; + +const config: PodSdkConfig = { + encryptionNetwork: "testnet", + chains: [ + { chainId: 11155111, inboxAddress: SEPOLIA_DEFAULT_INBOX_ADDRESS, rpcUrl: SEPOLIA_RPC }, + { chainId: 7082400, inboxAddress: COTI_TESTNET_DEFAULT_INBOX_ADDRESS, rpcUrl: COTI_RPC }, + ], +}; + +const tracker = new PodRequest(config); + +async function compareAndWait( + signer: ethers.Signer, + aesKey: string, + aPlain: string, + bPlain: string +): Promise { + const pod = new PodContract(COMPARE_APP_ADDRESS, COMPARE_APP_ABI, signer, { config }); + const feeData = await signer.provider!.getFeeData(); + + const tx = await pod.encryptAndCallMethod( + "compare", + [ + { type: DataType.itUint64, value: aPlain, isCallBackFee: false }, + { type: DataType.itUint64, value: bPlain, isCallBackFee: false }, + { type: DataType.Uint256, value: "0", isCallBackFee: true }, + ], + { + forwardGasLimit: 1_500_000n, + callBackGasLimit: 400_000n, + gasPrice: feeData.gasPrice!, + } + ); + const receipt = await tx.wait(); + const [requestId] = await pod.extractRequestIds(receipt!.hash); + const { chainId } = await signer.provider!.getNetwork(); + + while (true) { + const s = await tracker.trackRequest(chainId, requestId); + if (s.execution) throw new Error(s.execution.errorMessage); + if (s.isTwoWay && s.response?.minedOnTarget) break; + if (!s.isTwoWay && s.minedOnTarget) break; + await new Promise((r) => setTimeout(r, 3_000)); + } + + const ct: string = await pod.contract.resultByRequest(requestId); + return CotiPodCrypto.decrypt(ct, aesKey, DataType.Bool) === "true"; +} +``` -## Choosing `encryptAndCallMethod` vs `callMethod` +## Common patterns -- Use **`encryptAndCallMethod`** when your app currently has plaintext user input. -- Use **`callMethod`** when the app already has ciphertext JSON from a prior `CotiPodCrypto.encrypt` step and you want to submit it directly. +- **Long-lived `PodRequest`, short-lived `PodContract`** — one tracker per app; new `PodContract` per contract/signer binding +- **Persist `requestId`** alongside user-facing entities; transport status and on-chain `ct*` storage are separate concerns +- **Polling cadence** — 2–5 seconds; cap total wait time and offer manual re-check ## See also -- [Tutorial: private Adder on Sepolia](tutorial-private-adder-sepolia.md) — full walkthrough including `PodContract` and `extractRequestIds`. -- [Tutorial: custom privacy logic with PoD](tutorial-custom-logic.md) — custom COTI-side pattern. -- [TypeScript integration (SDK docs)](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/06-typescript-integration-ux-development.md) -- [PoD SDK docs index](https://github.com/cotitech-io/coti-pod-sdk/tree/main/docs) +- [Account onboarding (AES key)](account-onboarding-aes-key.md) +- [COTI TypeScript SDK for PoD](coti-typescript-sdk-for-pod.md) +- [Tutorial: private Adder on Sepolia](tutorial-private-adder-sepolia.md) +- [How do PoA fees work?](how-poa-fees-work.md) diff --git a/privacy-on-demand/what-is-privacy-on-demand.md b/privacy-on-demand/what-is-privacy-on-demand.md index 80d3692..123265e 100644 --- a/privacy-on-demand/what-is-privacy-on-demand.md +++ b/privacy-on-demand/what-is-privacy-on-demand.md @@ -29,13 +29,13 @@ What PoD does **not** automatically guarantee by itself: ## What ships in the SDK versus what your team builds -The **COTI PoD SDK** ([GitHub](https://github.com/cotitech-io/coti-pod-sdk), [npm](https://www.npmjs.com/package/@coti/pod-sdk)) provides **TypeScript helpers** for the PoD pattern. **Solidity contracts** (`PodLib`, `PodUser`, Inbox interfaces, and related types) ship in **`@coti-io/coti-contracts`**. Your project still typically supplies: +The **COTI PoD SDK** ([GitHub](https://github.com/coti-io/coti-sdk-pod), [npm](https://www.npmjs.com/package/@coti/pod-sdk)) provides **TypeScript helpers**. **Solidity contracts** ship in **`@coti-io/coti-contracts`**; the **Inbox implementation** in **`@coti-io/coti-pod-inbox-contracts`**. See [Architecture and main components](architecture-and-components.md) for how the packages fit together. Your project still typically supplies: - **Application-specific** EVM contracts and state machines. - **User experience** for onboarding, showing **pending / completed / failed** private operations, and **safe key handling**. - **Operations**: monitoring, indexing, or internal tools for stuck requests and fee configuration, as appropriate for your deployment. -The SDK’s own [documentation README](https://github.com/cotitech-io/coti-pod-sdk/blob/main/docs/README.md) states scope clearly: it does not replace deployment scripts, indexers, or backend services for you. +Full documentation lives in this book ([Privacy on Demand](README.md)). The SDK repo ships code only — it does not replace deployment scripts, indexers, or backend services for you. ## Next steps