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

# Content Identifiers

> How we use CIDs to bind payments to specific content

<Tip>
  **TL;DR**: we pin your files to IPFS first, and the returned CID becomes the authoritative identifier. That CID goes into the on-chain deposit — binding your payment to the exact content that was pinned.
</Tip>

## What is a CID?

A **Content Identifier (CID)** is a cryptographic hash that uniquely identifies content in IPFS. The same content always produces the same CID, enabling verifiable, immutable storage.

Example: `bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi`

## Why CID Matters

In traditional cloud storage, you pay for space regardless of what you store. With the sdk, **you pay for specific content** identified by its CID. This creates a binding between your payment and your data.

### The Problem We're Solving

Without binding payments to a specific CID, we'd run into issues like:

* **Upload without paying**: Pin files to IPFS first, then never actually pay
* **Pay once, upload many**: Reuse a single payment for multiple different files
* **Content substitution**: Pay for one file, store something completely different

### The Pin-First Approach

We pin files to IPFS **before** creating the on-chain deposit, making the CID a **cryptographic commitment**:

```
User selects files
     ↓
Server pins files to IPFS
     ↓
Server returns authoritative CID
     ↓
CID is included in the on-chain deposit
     ↓
User pays (locked to this specific CID)
     ↓
Server marks upload active
```

The CID in the deposit is exactly what was pinned — no separate verification step needed.

## How It Works

### 1. CID from IPFS

When you upload files, we pin them to IPFS and receive the authoritative CID back:

```
bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi
```

IPFS uses:

* **SHA-256** hashing
* **dagPB** codec (IPFS directory structure)
* **UnixFS** for file and directory representation

### 2. CID in Blockchain Deposit

The CID becomes part of your on-chain deposit:

```typescript theme={null}
// Create deposit instruction with CID
const instruction = createDepositInstruction({
  publicKey: userWallet,
  contentCID: cid,  // ← Locked to this CID
  fileSize: totalBytes,
  durationDays: 30,
  depositAmount: costInSOL,
});

// Creates a unique deposit account derived from:
// - User's wallet address
// - SHA-256 hash of the CID
// - Deposit seed constant
```

This means:

* Same user + same CID = same deposit account
* Different CID = different deposit account
* Can't reuse deposits for different content

### 3. Payment Confirmed

Once the on-chain transaction is confirmed, we mark the upload active in our database. The CID is now permanently linked to your payment — accessible for the full duration you paid for.

## Benefits

<CardGroup cols={2}>
  <Card title="Payment Integrity" icon="shield-check">
    Deposits are locked to specific content, preventing fraud
  </Card>

  <Card title="Content Verification" icon="fingerprint">
    Server verifies uploaded content matches committed CID
  </Card>

  <Card title="Deterministic Accounts" icon="key">
    Same content produces same on-chain deposit account
  </Card>

  <Card title="Renewal Capability" icon="rotate">
    CID serves as stable identifier for storage renewals
  </Card>
</CardGroup>

## Multi-File Uploads

For directories with multiple files, the sdk generates a **root CID** that represents all files:

```
Root CID (bafybei...)
├── file1.jpg (bafybei...)
├── file2.pdf (bafybei...)
└── file3.txt (bafybei...)
```

Each file has its own CID, but the directory has a **root CID** that cryptographically links to all files. This is what gets stored in the blockchain deposit.

You can access:

* Whole directory: `ipfs://{rootCID}/`
* Individual file: `ipfs://{rootCID}/file1.jpg`
* File by its own CID: `ipfs://{fileCID}`

## Security Properties

### Prevents Double-Spending

```typescript theme={null}
// First deposit for CID "bafyabc..."
const deposit1 = createDeposit({ cid: "bafyabc..." }); // ✅ Success

// Try to create another deposit for same CID
const deposit2 = createDeposit({ cid: "bafyabc..." }); // ❌ Fails
// Same user + same CID = same PDA = already exists
```

### Prevents Content Substitution

Because we pin files to IPFS before building the deposit, the CID in the on-chain deposit is always exactly what was pinned. There's no window to swap content after paying — the pin and the payment reference the same CID.

### Enables Renewals

```typescript theme={null}
// Original upload: CID "bafyabc...", expires in 30 days

// Later, renew storage for same CID
await renewStorageDuration({
  cid: "bafyabc...",  // Find deposit by CID
  additionalDays: 30,
});

// Database lookup: WHERE contentCid = "bafyabc..."
// Extends expiration date ✅
```

## Advanced Details

<AccordionGroup>
  <Accordion title="CID Format & Structure">
    We use **CIDv1** with base32 encoding:

    ```
    bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi
    │   │                                                      │
    │   └─ base32 encoded hash                                │
    └─ multibase prefix (b = base32)
    ```

    Breaking it down:

    * **b**: base32 encoding
    * **afy**: CID version 1
    * **bei...**: SHA-256 hash of content
  </Accordion>

  <Accordion title="On-Chain Account Derivation">
    Deposit accounts are deterministically derived using:

    ```typescript theme={null}
    const cidHash = sha256(cid);  // Hash the CID string
    const seeds = [
      "deposit",           // Constant seed
      userPublicKey,       // User's wallet
      cidHash              // Hash of CID
    ];

    const [depositPDA] = PublicKey.findProgramAddressSync(seeds, programId);
    ```

    This creates an address that:

    * Is unique per user per content
    * Can be found without storing addresses
    * Prevents duplicate deposits
  </Accordion>

  <Accordion title="Why Pin First?">
    Pinning before creating the deposit means the CID in the on-chain record is always the real IPFS CID — not a locally computed estimate that might differ from what the storage backend produces.

    Different IPFS implementations can produce different CIDs for the same content depending on chunk size, codec settings, and directory encoding. By pinning first and using the returned CID, we eliminate that mismatch entirely.
  </Accordion>
</AccordionGroup>

## Learn More

<CardGroup cols={2}>
  <Card title="IPFS CID Spec" icon="book" href="https://docs.ipfs.tech/concepts/content-addressing/">
    Deep dive into content addressing
  </Card>

  <Card title="CAR Format" icon="file-archive" href="https://ipld.io/specs/transport/car/">
    Content Addressable aRchive format
  </Card>

  <Card title="dagPB Codec" icon="diagram-project" href="https://ipld.io/specs/codecs/dag-pb/">
    IPFS directory structure
  </Card>

  <Card title="Solana PDAs" icon="key" href="https://solana.com/docs/core/pda">
    Program Derived Addresses
  </Card>
</CardGroup>
