# 05 — Smart Contract: DocumentRegistry

**File:** `blockchain/contracts/DocumentRegistry.sol`  
**Solidity version:** `^0.8.24`  
**Network:** Ethereum Sepolia Testnet (production) / Hardhat Local (development)  
**Purpose:** Tamper-proof, timestamped proof-of-deposit for BFSI contract documents.

---

## Design Philosophy

> No document content is stored on-chain — only its SHA-256 hash.

This design provides:
- **Privacy**: No sensitive data ever reaches the blockchain
- **Verifiability**: Anyone with the original document can verify it existed at a specific time
- **Immutability**: Once registered, the hash and timestamp cannot be altered
- **Legal Standing**: Block timestamp provides a cryptographically provable submission date

---

## How It Works

```
1. User uploads contract PDF to LexiChain
2. Server computes SHA-256 hash of the raw file bytes
3. Server wallet signs and sends registerDocument(bytes32) transaction
4. Transaction is mined → block.timestamp becomes the proof date
5. txHash, blockNumber, blockTimestamp saved to PostgreSQL
6. User can verify anytime via verifyDocument(bytes32)
```

---

## Contract Architecture

### State Variables

| Variable | Type | Visibility | Description |
|----------|------|-----------|-------------|
| `owner` | `address` | `public` | Platform backend wallet address |
| `totalDocuments` | `uint256` | `public` | Total number of registered document hashes |
| `documents` | `mapping(bytes32 => DocumentRecord)` | `private` | Hash → registration record |
| `depositorDocuments` | `mapping(address => bytes32[])` | `private` | Address → list of hashes they registered |

### Structs

```solidity
struct DocumentRecord {
    uint256 timestamp;   // block.timestamp at registration
    address depositor;   // msg.sender (platform wallet)
    bool exists;         // false = not registered
}
```

### Events

```solidity
event DocumentRegistered(
    bytes32 indexed docHash,
    uint256 timestamp,
    address indexed depositor
);

event DocumentVerified(
    bytes32 indexed docHash,
    bool exists,
    address indexed verifier
);
```

### Modifiers

```solidity
modifier onlyOwner() {
    require(msg.sender == owner, "Only owner can call this function");
    _;
}
```

---

## Function Reference

### `registerDocument(bytes32 _docHash)` — write
```
Access:    onlyOwner
Gas:       ~50,000 gas
```

Registers a document hash on-chain. Reverts if the same hash is already registered (idempotent via `requires`).

**Parameters:**
- `_docHash` — SHA-256 hash of the document as `bytes32`

**Emits:** `DocumentRegistered(docHash, block.timestamp, msg.sender)`

---

### `verifyDocument(bytes32 _docHash)` — view (free)
```
Access:    Anyone
Gas:       0 (read-only call)
```

Checks if a document hash is registered and returns its record.

**Returns:**
```solidity
bool exists          // true if registered
uint256 timestamp    // Unix timestamp of registration (0 if not found)
address depositor    // Address that registered it (address(0) if not found)
```

---

### `getTimestamp(bytes32 _docHash)` — view (free)
Returns only the registration timestamp for a given hash (0 if not registered).

---

### `getDocumentsByDepositor(address _depositor)` — view (free)
Returns all document hashes registered by a specific address.

---

### `getDocumentCount(address _depositor)` — view (free)
Returns the count of documents registered by a specific address.

---

### `transferOwnership(address _newOwner)` — write
```
Access:    onlyOwner
```
Transfers contract ownership to a new address. Required if the platform wallet changes.

---

## ABI (Application Binary Interface)

```json
[
  "function registerDocument(bytes32 _docHash) external",
  "function verifyDocument(bytes32 _docHash) external view returns (bool exists, uint256 timestamp, address depositor)",
  "function getTimestamp(bytes32 _docHash) external view returns (uint256)",
  "function getDocumentsByDepositor(address _depositor) external view returns (bytes32[] memory)",
  "function getDocumentCount(address _depositor) external view returns (uint256)",
  "function totalDocuments() external view returns (uint256)",
  "function owner() external view returns (address)",
  "function transferOwnership(address _newOwner) external",
  "event DocumentRegistered(bytes32 indexed docHash, uint256 timestamp, address indexed depositor)"
]
```

---

## Security Model

| Property | Implementation |
|----------|---------------|
| **Owner-only writes** | `onlyOwner` modifier prevents anyone else from registering |
| **No duplicates** | `require(!documents[hash].exists)` prevents double-registration |
| **Privacy** | Only hashes stored — no filename, no metadata, no user data |
| **Immutability** | No update/delete functions — hashes are permanent once registered |
| **Dedicated wallet** | Platform uses a separate wallet (not a personal wallet) |

---

## Deployment

### Prerequisites

1. Install Hardhat dependencies:
   ```bash
   cd blockchain
   npm install
   ```

2. Compile the contract:
   ```bash
   npx hardhat compile
   ```

---

### Local Development (Hardhat Node)

The `npm run dev` command in the root automatically:
1. Starts a Hardhat node on `http://localhost:8545`
2. Deploys `DocumentRegistry.sol` to the local chain
3. Saves the contract address to `blockchain/.dev-deploy.json`
4. Starts the Next.js dev server with the correct env vars

To deploy manually:
```bash
# Terminal 1: Start local node
cd blockchain
npx hardhat node

# Terminal 2: Deploy
npx hardhat run scripts/deploy.ts --network localhost
```

---

### Production (Ethereum Sepolia Testnet)

**Why Sepolia?**
- 100% free (no real ETH needed)
- Stable Ethereum testnet maintained by the Ethereum Foundation
- Supported by Etherscan, Alchemy, Infura, MetaMask
- No node to run or maintain
- Transactions viewable on https://sepolia.etherscan.io

**Step 1: Get Sepolia ETH (free)**

Use one of these faucets:
- https://sepoliafaucet.com (Alchemy — requires account)
- https://faucet.quicknode.com/ethereum/sepolia
- https://www.infura.io/faucet/sepolia

A few test ETH is enough for thousands of contract registrations (~0.0005 ETH per registration).

**Step 2: Set environment variables**

```bash
# In blockchain/.env or your shell:
SEPOLIA_RPC_URL=https://rpc.sepolia.org
DEPLOYER_PRIVATE_KEY=0x<your-dedicated-wallet-private-key>
```

> ⚠️ **CRITICAL**: Never use a wallet that holds real ETH. Create a dedicated deployment wallet.

**Step 3: Deploy to Sepolia**

```bash
cd blockchain
npx hardhat run scripts/deploy.ts --network sepolia
```

The script outputs:
```
DocumentRegistry deployed to: 0x<CONTRACT_ADDRESS>
BLOCKCHAIN_CONTRACT_ADDRESS=0x<CONTRACT_ADDRESS>
```

**Step 4: Set app environment variables**

```bash
BLOCKCHAIN_NETWORK=sepolia
BLOCKCHAIN_RPC_URL=https://rpc.sepolia.org
BLOCKCHAIN_CONTRACT_ADDRESS=0x<your-deployed-address>
BLOCKCHAIN_PRIVATE_KEY=0x<your-wallet-private-key>
```

**Step 5: Verify deployment (optional)**

Visit `https://sepolia.etherscan.io/address/<CONTRACT_ADDRESS>` to confirm deployment.

---

## Running Tests

```bash
cd blockchain
npx hardhat test
```

Test file: `blockchain/test/DocumentRegistry.test.ts`

---

## Deployed Contract Information

After deploying, record your contract address here for team reference:

| Network | Contract Address | Deployer | Deployed At |
|---------|-----------------|---------|-------------|
| Sepolia | `0x...` | `0x...` | — |
| Hardhat (dev) | Auto-deployed | Account #0 | Per session |
