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

# Shield Contract

> Smart contract for access control

# Shield Contract

The Shield contract manages access policies on the Base blockchain.

## Contract Address

| Network      | Address                                      |
| ------------ | -------------------------------------------- |
| Base Mainnet | `0x4b8F46e5E3d95D78f30F80F1280fE7e5F92c8ce8` |

## Overview

The Shield contract stores access policies that define:

* Who can access content (recipient)
* When access expires (timestamp)
* How many attempts are allowed (maxAttempts)
* How many attempts have been made (attempts)

## Data Structures

### AccessPolicy

```solidity theme={null}
struct AccessPolicy {
    address sender;      // Creator of the policy
    address recipient;   // Authorized accessor
    uint64 expiry;       // Expiration timestamp
    uint32 maxAttempts;  // Maximum access attempts
    uint32 attempts;     // Current attempt count
    bool valid;          // Policy validity flag
}
```

### Storage

```solidity theme={null}
mapping(bytes32 => AccessPolicy) public policies;
```

Policies are indexed by `policyId` (keccak256 hash).

## Functions

### createPolicy

Create a new access policy.

```solidity theme={null}
function createPolicy(
    bytes32 policyId,
    address recipient,
    uint256 expiry,
    uint256 maxAttempts
) external
```

**Parameters:**

| Parameter     | Type    | Description                     |
| ------------- | ------- | ------------------------------- |
| `policyId`    | bytes32 | Unique identifier (hash)        |
| `recipient`   | address | Wallet authorized to access     |
| `expiry`      | uint256 | Unix timestamp of expiration    |
| `maxAttempts` | uint256 | Maximum access attempts allowed |

**Requirements:**

* Policy doesn't already exist
* Recipient is not zero address
* Expiry is in the future
* maxAttempts > 0

**Emits:** `PolicyCreated`

**Example:**

```typescript theme={null}
const policyId = keccak256(toUtf8Bytes(uniqueString));
const recipient = '0x742d...';
const expiry = Math.floor(Date.now() / 1000) + 86400; // 24 hours
const maxAttempts = 3;

await contract.createPolicy(policyId, recipient, expiry, maxAttempts);
```

### logAttempt

Log an access attempt. Must be called by recipient.

```solidity theme={null}
function logAttempt(bytes32 policyId, bool success) external
```

**Parameters:**

| Parameter  | Type    | Description                |
| ---------- | ------- | -------------------------- |
| `policyId` | bytes32 | Policy to log attempt for  |
| `success`  | bool    | Whether access was granted |

**Requirements:**

* Policy exists
* Policy is valid
* Caller is the recipient
* Not expired
* Attempts remaining

**Emits:** `VerificationAttempt`

**Example:**

```typescript theme={null}
await contract.logAttempt(policyId, true);
```

### isPolicyValid

Check if a policy is currently valid.

```solidity theme={null}
function isPolicyValid(bytes32 policyId) external view returns (bool)
```

Returns `true` if:

* Policy exists
* `valid` flag is true
* Not expired
* Attempts remaining

**Example:**

```typescript theme={null}
const isValid = await contract.isPolicyValid(policyId);
```

## Events

### PolicyCreated

```solidity theme={null}
event PolicyCreated(
    bytes32 indexed policyId,
    address indexed sender,
    address indexed recipient,
    uint256 expiry,
    uint256 maxAttempts
);
```

Emitted when a new policy is created.

### VerificationAttempt

```solidity theme={null}
event VerificationAttempt(
    bytes32 indexed policyId,
    bool success
);
```

Emitted when an access attempt is logged.

## Access Control

| Function        | Who Can Call   |
| --------------- | -------------- |
| `createPolicy`  | Anyone         |
| `logAttempt`    | Recipient only |
| `isPolicyValid` | Anyone (view)  |

## Error Messages

| Error                                   | Meaning                   |
| --------------------------------------- | ------------------------- |
| "Policy already exists"                 | policyId is taken         |
| "Policy does not exist"                 | policyId not found        |
| "Policy is not valid"                   | valid flag is false       |
| "Only the recipient can log an attempt" | Wrong caller              |
| "Policy has expired"                    | expiry \< block.timestamp |
| "Max attempts reached"                  | attempts >= maxAttempts   |

## Flow Example

### Creating a Link

```typescript theme={null}
// 1. Generate unique policyId
const uniqueString = `${address}-${Date.now()}-${randomBytes(8)}`;
const policyId = keccak256(toUtf8Bytes(uniqueString));

// 2. Create policy
const tx = await contract.createPolicy(
  policyId,
  recipientAddress,
  Math.floor(Date.now() / 1000) + 86400,
  3
);
await tx.wait();

// 3. Store metadata (off-chain)
await fetch('/api/storeMetadata', {
  method: 'POST',
  body: JSON.stringify({
    policyId,
    cid: ipfsCid,
    sender: address,
    recipient: recipientAddress,
    // ...
  })
});
```

### Accessing Content

```typescript theme={null}
// 1. Verify SIWE
const token = await authenticate();

// 2. Check policy
const isValid = await contract.isPolicyValid(policyId);
if (!isValid) throw new Error('Policy invalid');

// 3. Log attempt
const tx = await contract.logAttempt(policyId, true);
await tx.wait();

// 4. Fetch and decrypt content
const content = await fetchFromIPFS(cid);
const decrypted = await decrypt(content, secretKey);
```

## Security Considerations

* **Immutable policies**: Once created, cannot be modified
* **Self-enforcing**: Rules are enforced by contract, not trust
* **Transparent**: All policies and attempts are public
* **Auditable**: Complete history on-chain

## Gas Costs

| Function      | Approximate Gas |
| ------------- | --------------- |
| createPolicy  | \~50,000        |
| logAttempt    | \~30,000        |
| isPolicyValid | \~5,000 (view)  |

## Source Code

```solidity theme={null}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract Shield {
    struct AccessPolicy {
        address sender;
        address recipient;
        uint64 expiry;
        uint32 maxAttempts;
        uint32 attempts;
        bool valid;
    }

    mapping(bytes32 => AccessPolicy) public policies;

    event PolicyCreated(bytes32 indexed policyId, address indexed sender, address indexed recipient, uint256 expiry, uint256 maxAttempts);
    event VerificationAttempt(bytes32 indexed policyId, bool success);

    function createPolicy(bytes32 policyId, address recipient, uint256 expiry, uint256 maxAttempts) external {
        require(policies[policyId].sender == address(0), "Policy already exists");
        policies[policyId] = AccessPolicy({
            sender: msg.sender,
            recipient: recipient,
            expiry: uint64(expiry),
            maxAttempts: uint32(maxAttempts),
            attempts: 0,
            valid: true
        });
        emit PolicyCreated(policyId, msg.sender, recipient, expiry, maxAttempts);
    }

    function logAttempt(bytes32 policyId, bool success) external {
        AccessPolicy storage policy = policies[policyId];
        require(policy.sender != address(0), "Policy does not exist");
        require(policy.valid, "Policy is not valid");
        require(msg.sender == policy.recipient, "Only the recipient can log an attempt");
        require(block.timestamp < policy.expiry, "Policy has expired");
        require(policy.attempts < policy.maxAttempts, "Max attempts reached");

        policy.attempts++;

        if (policy.attempts >= policy.maxAttempts) {
            policy.valid = false;
        }

        emit VerificationAttempt(policyId, success);
    }

    function isPolicyValid(bytes32 policyId) external view returns (bool) {
        AccessPolicy storage policy = policies[policyId];
        return policy.valid && block.timestamp < policy.expiry && policy.attempts < policy.maxAttempts;
    }
}
```
