# Getting Started

👋 Welcome to Permission Docs

Welcome to the official documentation hub for **Permission**.

Permission is a platform built for a future where **AI works for people,** enabling individuals and families to retain agency, clarity, and control as AI systems become more embedded in everyday life.

This documentation provides an overview of Permission’s platform, principles, and direction.

Inside these docs, you’ll find:

* What Permission is and the problem it’s designed to solve
* Our vision for the agentic web and A2A economy
* Families as a first-class use case for Permission
* ASK token utility and roadmap
* How the ASK token powers rewards and agent-to-agent value exchange
* Resources, FAQs, and smart contract details

### Who This Is For

These docs are intended for:

* **Individuals** thinking seriously about the future of AI and personal agency
* **Families** navigating technology together with intention
* **Builders and researchers** exploring agent-based systems and the emerging agentic web
* **Developers and partners** interested in building on the **Permission Protocol** — an open-source foundation for permission-based interactions powered by ASK

> 👉 Start with What is Permission or explore ASK Token Utility


# What is Permission?

**Permission is a platform built for a future where AI works for people and earns their trust.**

As artificial intelligence becomes embedded into everyday life, the most important question is no longer what AI can do, but who it works for and whether it can be trusted to act in human interests.

Permission exists to ensure that individuals and families retain agency, clarity, and confidence in an increasingly automated, agent-driven world.

### The internet is entering a new phase.

AI systems are no longer passive tools. They are becoming **active participants** — shaping decisions, influencing behavior, and mediating how people interact with information, commerce, and one another.

At the same time, individuals are increasingly:

* Marketed to by algorithms
* Profiled by opaque systems
* Acted upon without meaningful consent or context

Without new infrastructure, this evolution risks repeating the mistakes of the last internet era: centralized control, misaligned incentives, and eroding trust.

Permission is building for what comes next.

### Permission’s Role

Permission is designed to sit at the intersection of:

* **People**
* **AI agents**
* **Future marketing and value exchange**

Our platform enables individuals — and eventually families — to be represented by their own AI agents, operating with clearly defined values, rules, and boundaries.

Rather than reacting to technology after the fact, Permission allows people to **define how AI engages with them in the first place**.

### The Permission Agent

At the core of the platform is the **Permission Agent,** an AI agent that represents an individual (or family) in digital environments.

The Permission Agent is designed to:

* Act in the interest of the human it represents
* Understand context, preferences, intent, and boundaries
* Deliver insights and mediate interactions with other agents
* Support transparent, permissioned engagement over time

This architecture shifts the balance of power:

* From platforms → to people
* From extraction → to representation
* From reactive controls → to proactive agency

Over time, this enables a world where intelligent systems negotiate with one another, while humans remain in control of outcomes.&#x20;

### Families as a First-Class Use Case

As AI systems become more embedded in everyday life, **families are one of the earliest and most consequential environments where AI will have real impact**.

Children are engaging with digital platforms earlier, for longer periods, and across more surfaces — while parents are often left with:

* Less visibility
* Less context
* Fewer tools to guide outcomes responsibly

Permission views families as a **canary for the broader AI future**.

If AI cannot work responsibly for families, it will not work responsibly for society.

### AI That Supports (Not Replaces) Parenting

Permission’s next major product direction applies its agentic architecture to the family context.

The goal is not surveillance, enforcement, or control.

It is **context, alignment, and agency**.

The platform aims to:

* Support diverse parenting styles without prescribing outcomes
* Enhance parent-led decision-making rather than automate it
* Translate complex digital behavior into intelligible and actionable signals for parents
* Preserve trust, privacy, and participation within households

This reflects a core design principle of Permission:

**AI should strengthen human relationships — not bypass them.**

### Insight Over Data, Context Over Control

Rather than exposing raw data or enabling intrusive monitoring, Permission focuses on **patterns, shifts, and signals** that help humans make better decisions.

This principle extends across the platform: AI systems should surface **meaningful context**, not overwhelm people with noise or opaque automation.

### The Agentic Web & A2A Economy

Permission is built for the emerging **agentic web** — a world where AI agents interact directly with one another on behalf of humans.

In this future:

* People won’t negotiate with every system directly
* Their agents will
* Value, intent, and decisions will flow through **agent-to-agent (A2A) interactions**

Permission provides the **human anchor** in that system — ensuring that as machines communicate at machine speed, outcomes remain grounded in human-defined rules and values.

### Why Permission Matters

Without new infrastructure, the next phase of AI risks amplifying:

* Loss of agency
* Invisible decision-making
* Misaligned incentives
* Erosion of trust

Permission is building toward a different future:

* Where consent is foundational
* Where representation replaces extraction
* Where AI works in service of people and families
* Where technology improves everyday life without compromising values

### Who Permission Is For

Permission is for:

* Individuals thinking seriously about the future of AI
* Families navigating technology together
* Builders exploring agent-based systems
* Developers and partners building on the **Permission Protocol** and ASK permission technology

If you believe AI should **work for people**, Permission is building what comes next.

👉 [Explore ASK Token Utility](/ask-token) \
\
👉 [Learn More About Permission's Ai for the Family](/permission-founding-families)


# Refer & Earn

Guides, setup instructions, and tips for individual Permission Agent users

The Permission Referral Program is an easy way to boost your ASK balance while introducing others to the benefits of Permission.

Invite friends to join the Permission ecosystem and you’ll both earn bonus rewards.&#x20;

### How It Works

1. **Get Your Referral Link**
   * Sign in to your Permission account.
   * Go to **Referral Program** in your dashboard to find your unique link.
2. **Invite Friends**
   * Share your link by email, social media, or direct message.
3. **Earn Rewards**
   * When someone signs up using your link and activates a Permission account, you both earn a **bonus ASK reward**.

### Reward Structure

* **You earn**:
  * A one-time ASK bonus when your referral activates the Permission Agent.
* **They earn**:
  * A one-time ASK bonus for joining via your link.

Rewards drop straight into your Permission Wallet like magic.

### Track Your Progress

You can track your referrals any time from the **Referral Program** section of your Permission dashboard.


# ASK Token

### 🪙 ASK Token

### Introduction

ASK is the native token of the Permission ecosystem. It is the economic layer that enables **trust, consent, and value exchange** in an AI-driven world.

As AI systems become more present in everyday life, Permission is building infrastructure that ensures people and families remain active participants, not passive inputs. ASK makes that possible by tying participation to consent, incentives, and accountability.

**ASK enables a system where:**

* **Participation is intentional**
* **Incentives are aligned**
* **Trust is verifiable**

When individuals engage through Permission-powered experiences, ASK provides a transparent mechanism for rewards, coordination, and alignment across people, platforms, and AI systems. It is how Permission moves AI interactions from opaque to accountable.

### **Token Utility**

ASK functions as the connective layer between humans, agents, and AI systems across the Permission ecosystem.&#x20;

It enables:

* **Incentives & Rewards**\
  ASK supports incentive mechanisms that reinforce positive, value-aligned behaviors. In family contexts, ASK is used to motivate learning, responsibility, and healthy digital habits. Across the broader ecosystem, it enables participation without exploitation.
* **Agent-to-Agent (A2A) Coordination**\
  ASK powers permissioned, auditable value exchange between AI agents operating within the Permission Protocol. It allows agents to coordinate actions, request participation, and settle interactions transparently.
* **Ecosystem Alignment**\
  Developers, integrators, and ecosystem contributors may earn or use ASK as they help expand Permission-powered products, experiences, and infrastructure.
* **Governance & Staking (Future)**\
  Over time, ASK will support protocol governance and participation-based mechanisms designed to align long-term stakeholders with the health of the ecosystem.

### **Token Supply & Allocation**

ASK has a fixed supply of **100,000,000,000 tokens**, with distribution designed to support long-term ecosystem health, contributor alignment, and widespread participation.

Token unlocks are designed to align with real-world adoption and platform usage. Core team and advisor allocations are subject to long-term vesting, while ecosystem rewards unlock dynamically as new Permission-powered products and participation models come online.

*See* [*ASK Tokenomics*](https://app.gitbook.com/o/JRVVUtmQvSfdZW9zeI2r/s/YUH9oKJSw5GreYurGAF6/ask-token/ask-tokenomics) *for details.*&#x20;

This structure ensures that the majority of tokens support active participants — those who help build, use, and grow the Permission ecosystem.

### **Multichain Native**

ASK is deployed as an **OFT (Omnichain Fungible Token)** via [LayerZero](https://layerzeroscan.com/oft/ASK/Permission), enabling seamless cross-chain movement while preserving a unified supply. It is live on **Stargate**, supporting gas-efficient bridging and integrated liquidity.

**Active Networks**:

* **Base**: `0xBB146326778227A8498b105a18f84E0987A684b4`
* **Polygon**: `0xaA3717090CDDc9B227e49d0D84A28aC0a996e6Ff`

ASK will expand to additional EVM-compatible chains in step with ecosystem demand.

### **A Token for a More Trustworthy Internet**

ASK is not just a reward. It is a mechanism for a more accountable AI. &#x20;

As AI systems increasingly influence learning, behavior, and decision-making, ASK ensures that participation is grounded in consent and that incentives are transparent. It connects value to responsibility, and innovation to trust.

ASK enables a shift:

* From extraction to participation
* From opacity to accountability
* From surveillance to agency

Every ASK-powered interaction reinforces the idea that AI should work within human-defined values, not outside of them.

That is the role ASK plays in the Permission ecosystem.


# ASK Tokenomics

ASK is the native token powering the Permission ecosystem. \
\
It underpins how value flows across the platform — aligning incentives between individuals, families, AI agents, and the broader Permission Protocol.\
\
ASK enables permissioned participation, agent-to-agent (A2A) value exchange, and long-term ecosystem alignment. Over time, it will also support governance and staking.

ASK is omnichain via LayerZero’s OFT standard, meaning it flows across the chains that power Permission (currently, Base and Polygon), with additional chains planned as the ecosystem expands.

### **A Closed-loop flywheel**

As Permission’s family-focused products scale, **subscription revenue** generated from parents using the platform is used, in part, to **buy back ASK from the open market**.

These buybacks:

* Create sustained, non-speculative demand for ASK
* Align long-term holders with product adoption
* Reinforce ASK’s role as permission and incentive infrastructure

ASK acquired through buybacks is used to **fund rewards and incentives** across the Permission ecosystem — particularly in family contexts where ASK is used to motivate, reinforce, and reward positive behaviors.

This creates a flywheel where:

1. Parents subscribe to Permission products
2. Subscription revenue funds ASK buybacks
3. ASK is used to power rewards and incentives
4. Increased ASK utility reinforces demand
5. The cycle repeats as adoption grows

### Supply Allocation

**Total Supply**: 100 billion ASK (fixed, uninflatable). \
\
Below is a breakdown of ASK’s total token supply, including allocations for growth, contributors, and ecosystem participants.\
\
These allocations are designed to incentivize long-term participation and value creation across the Permission network.

<figure><img src="/files/Uu1px256fut5wRtfITAX" alt=""><figcaption></figcaption></figure>

### Unlock Schedule

ASK follows a long-term unlock schedule designed to:&#x20;

* Align incentives across stakeholders
* Support sustainable ecosystem growth

You can view real-time supply data via our API:

* Total supply: `https://api.permission.io/v1/token/supply?q=total`
* Circulating supply: `https://api.permission.io/v1/token/supply?q=circulating`

The unlock schedule may adjust over time in response to governance decisions or strategic platform evolution.

<figure><img src="/files/SCAFe0GzYSmEL9XvtJnz" alt=""><figcaption></figcaption></figure>

### ASK Utility & Use Cases

ASK has multiple, reinforcing utilities across the Permission ecosystem:

#### **Family Rewards & Incentives**

ASK is used by parents as a flexible reward mechanism to:

* Incentivize positive behaviors
* Reinforce habits, learning, and responsibility
* Support goal-setting and value-aligned motivation within families

This use case represents a core demand driver for ASK as family adoption scales.

#### **Agent-to-Agent (A2A) Value Exchange**

ASK powers value exchange between AI agents operating within the Permission Protocol.

As agents negotiate, coordinate, and transact on behalf of humans, ASK serves as the native medium for permissioned, auditable A2A interactions.

#### **Protocol Participation & Governance**

ASK holders will be able to participate in governance decisions related to the Permission Protocol, including:

* Platform parameters
* Incentive mechanisms
* Ecosystem evolution

#### **Staking & Yield (Future)**

ASK is expected to support staking and other participation-based mechanisms over time, designed to:

* Encourage long-term alignment
* Support protocol security
* Reward active ecosystem contributors

Trusted One-to-One Relationships™


# Contract Addresses

Official ASK Token Contracts

ASK is an omnichain token deployed using the LayerZero OFT (Omnichain Fungible Token) standard.&#x20;

The smart contract addresses listed below represent the only official ASK token contracts authorized by Permission.

#### ✅ ASK Contract Addresses

<table><thead><tr><th width="158.59161376953125">Network</th><th width="160.5440673828125">Token Standard</th><th width="432.571044921875">Contract Address</th></tr></thead><tbody><tr><td><strong>Base</strong></td><td>OFT-20</td><td><code>0xBB146326778227A8498b105a18f84E0987A684b4</code></td></tr><tr><td><strong>Polygon</strong></td><td>OFT-20</td><td><code>0xaA3717090CDDc9B227e49d0D84A28aC0a996e6Ff</code></td></tr></tbody></table>

### 🔗 Stargate Support

ASK is officially integrated into [Stargate](https://layerzeroscan.com/oft/ASK/Permission), allowing for:

* Secure bridging between supported chains
* Unified liquidity across the Permission ecosystem
* Native compatibility with Stargate routers and liquidity pools

This Stargate integration ensures fast, gas-efficient transfers with enhanced user experience.

### ⚠️ Verification

Always verify ASK contract addresses through:

* This Gitbook
* [Permission.io](https://www.permission.io)
* Our verified channels (Twitter, Discord, Telegram)

Do **not** interact with contracts not listed here.

### 🛠 Technical Details

* **Omnichain Protocol:** LayerZero
* **Token Standard:** OFT-20 (ERC-20 compatible)
* **Bridging:** Stargate live
* **Omnichain Routing:** LayerZero messaging with canonical supply
* **Planned Expansions:** Ethereum Mainnet, Arbitrum, and other EVM-compatible chains

***


# Trading & Liquidity

⚠️ **Disclaimer:** This page is for informational purposes only and does not constitute financial, investment, or legal advice. Token values can fluctuate and all participation involves risk. Always do your own research before trading or providing liquidity.\
\
**Overview**

ASK is available for trading on decentralized exchanges. The primary liquidity venue is **Aerodrome Finance**, the leading DEX on Base, Coinbase's Layer 2 network.

Trading ASK requires a compatible EVM wallet and access to the Base network. See [Contract Addresses](https://docs.permission.ai/ask-token/contract-addresses) for official token contract details before trading.

**Trading on Aerodrome Finance**

**Aerodrome Finance** is the primary decentralized exchange for ASK on Base.

* **Network:** Base (Layer 2)
* **Trading Pair:** ASK / USDC
* **Official Pool:** [View on Aerodrome](https://aerodrome.finance/pools?token0=0xbb146326778227a8498b105a18f84e0987a684b4\&chain0=8453\&token1=0x833589fcd6edb6e08f4c7c32d4f71b54bda02913\&chain1=8453)
* **ASK Contract Address on Base:** `0xBB146326778227A8498b105a18f84E0987A684b4`

Always confirm you are using the official contract address before trading. Permission will never ask you to use an unofficial contract.

**How to Trade ASK**

1. Set up a compatible EVM wallet (e.g., MetaMask, Coinbase Wallet)
2. Add the Base network to your wallet
3. Fund your wallet with ETH on Base for gas fees and USDC to swap
4. Navigate to the [official ASK/USDC pool on Aerodrome](https://aerodrome.finance/pools?token0=0xbb146326778227a8498b105a18f84e0987a684b4\&chain0=8453\&token1=0x833589fcd6edb6e08f4c7c32d4f71b54bda02913\&chain1=8453)
5. Connect your wallet and execute your swap

For help setting up your wallet, see [Contract Addresses](https://docs.permission.ai/ask-token/contract-addresses).

**Providing Liquidity**

ASK holders can provide liquidity to the USDC/ASK pool on Aerodrome. Liquidity providers earn a share of trading fees generated by the pool.

**To provide liquidity:**

1. Navigate to the [USDC/ASK pool on Aerodrome](https://aerodrome.finance/pools?token0=0xbb146326778227a8498b105a18f84e0987a684b4\&chain0=8453\&token1=0x833589fcd6edb6e08f4c7c32d4f71b54bda02913\&chain1=8453)
2. Connect your wallet
3. Select "Add Liquidity" and follow the on-screen instructions

Aerodrome uses a **ve(3,3)** governance model. Additional liquidity incentive opportunities may become available as the ecosystem evolves.

**Supported Networks**

ASK is deployed as an **OFT (Omnichain Fungible Token)** via LayerZero, enabling movement across supported networks while preserving a unified supply.

| Network | Status   | Contract Address                             |
| ------- | -------- | -------------------------------------------- |
| Base    | ✅ Active | `0xBB146326778227A8498b105a18f84E0987A684b4` |
| Polygon | ✅ Active | `0xaA3717090CDDc9B227e49d0D84A28aC0a996e6Ff` |

For instructions on moving ASK between networks, see How to Bridge ASK.

**Security Reminders**

* **Always verify the official contract address** before trading or providing liquidity
* **Never share your private key or seed phrase** with anyone
* Permission will never DM you asking for wallet access or credentials
* If in doubt, contact <support@permission.ai>


# Cross-Chain Access

**Overview**

ASK is deployed as an **OFT (Omnichain Fungible Token)** via [LayerZero](https://layerzeroscan.com/oft/ASK/Permission), the leading cross-chain interoperability protocol. This architecture allows ASK to move natively across supported blockchain networks without wrapping or re-minting, preserving a single unified token supply across all chains.

ASK is currently live on **Base** and **Polygon**, with additional EVM-compatible networks planned in step with ecosystem demand.

**Why LayerZero**

LayerZero enables ASK to be truly omnichain by providing:

* **Native cross-chain movement** — ASK moves between supported networks without asset swaps, wrapping, or re-minting
* **Unified supply** — Token supply remains consistent across all chains at all times
* **Decentralized security** — Lightweight messaging architecture with no central point of failure
* **Scalability** — ASK can expand to additional networks with minimal friction as the ecosystem grows
* **On-chain transparency** — Every permission and reward interaction is immutably recorded and auditable

**Supported Networks**

| Network | Status   | Contract Address                             |
| ------- | -------- | -------------------------------------------- |
| Base    | ✅ Active | `0xBB146326778227A8498b105a18f84E0987A684b4` |
| Polygon | ✅ Active | `0xaA3717090CDDc9B227e49d0D84A28aC0a996e6Ff` |

Always confirm you are using the official contract address before interacting with ASK on any network. See [Contract Addresses](https://docs.permission.ai/ask-token/contract-addresses) for full details.

**Compatible Wallets and Applications**

ASK is EVM-compatible and works with most standard Ethereum wallets. Confirmed compatible platforms include:

* **Coinbase Wallet**
* **MetaMask**
* **Stargate** (bridging)
* **Aerodrome Finance** (DEX on Base)

**Moving ASK Between Networks**

ASK can be bridged between Base and Polygon via **Stargate**, powered by LayerZero infrastructure.

For step-by-step bridging instructions, see How to Bridge ASK.

**A Note for Holders of Legacy Wormhole-Bridged ASK**

Prior to the LayerZero integration, some users bridged ASK to Base via Wormhole. That wrapped token contract (`0x79322CEE6C90735b967d2396b9ADc392915aeBB6`) has been deprecated and is no longer supported.

If you still hold Wormhole-bridged ASK, see How to Bridge ASK for migration instructions, or contact <support@permission.ai> for assistance.

**Security Reminders**

* **Always verify contract addresses** before interacting with ASK on any network
* Permission will never DM you asking for wallet credentials or private keys
* Use only official Permission channels for support: <support@permission.ai>


# How to Bridge ASK

## **Overview**

ASK is an **OFT (Omnichain Fungible Token)** powered by LayerZero, currently live on both **Base** and **Polygon**. You can move ASK between these networks using **Stargate**, LayerZero's official bridging interface.

⚠️ **Important:** Always verify contract addresses before initiating any bridge transaction. See [Contract Addresses](https://docs.permission.ai/ask-token/contract-addresses) for official details.

**Official Contract Addresses**

<table><thead><tr><th width="330.8828125">Network</th><th>Contract Address</th></tr></thead><tbody><tr><td>Base</td><td><code>0xBB146326778227A8498b105a18f84E0987A684b4</code></td></tr><tr><td>Polygon</td><td><code>0xaA3717090CDDc9B227e49d0D84A28aC0a996e6Ff</code></td></tr></tbody></table>

⚠️ **Important:** The bridging instructions on this page are provided for informational purposes only. Bridging transactions are executed directly on third-party protocols (Stargate, LayerZero, Portal Bridge) and are not controlled by Permission. Permission is not responsible for failed transactions, lost funds, delays, or errors arising from user error, wallet misconfiguration, network congestion, or third-party platform issues. Blockchain transactions are irreversible. Always verify contract addresses and transaction details carefully before confirming. When in doubt, contact <support@permission.ai> before proceeding.

#### **Bridging ASK from Polygon to Base**

**Prerequisites:**

* A compatible EVM wallet (MetaMask, Coinbase Wallet, etc.)
* ASK tokens on Polygon
* MATIC (POL) on Polygon for gas fees

**Steps:**

1. Visit [Stargate Finance](https://stargate.finance/bridge) and connect your wallet
2. Select **Polygon** as the source chain and **Base** as the destination chain
3. Select ASK as the token and enter the amount to bridge
4. Confirm the contract address on Base is `0xBB146326778227A8498b105a18f84E0987A684b4`
5. Review the transaction details and confirm in your wallet
6. Wait for the transaction to complete — bridging typically takes a few minutes

#### **Bridging ASK from Base to Polygon**

**Prerequisites:**

* A compatible EVM wallet
* ASK tokens on Base
* ETH on Base for gas fees

**Steps:**

1. Visit [Stargate Finance](https://stargate.finance/bridge) and connect your wallet
2. Select **Base** as the source chain and **Polygon** as the destination chain
3. Select ASK as the token and enter the amount to bridge
4. Confirm the contract address on Base is `0xBB146326778227A8498b105a18f84E0987A684b4`
5. Review the transaction details and confirm in your wallet
6. Wait for the transaction to complete

#### **Legacy Wormhole Migration**

Prior to the LayerZero integration, some users bridged ASK to Base via Wormhole. That wrapped token contract has been deprecated and is no longer supported or tradable.

**Deprecated contract (do not use):** `0x79322CEE6C90735b967d2396b9ADc392915aeBB6`

If you still hold Wormhole-bridged ASK, follow these steps to migrate:

**Step 1 — Bridge from Base back to Polygon via Wormhole**

1. Visit [Portal Bridge](https://portalbridge.com) and connect your wallet
2. Ensure you have ETH on Base for gas fees
3. Select **Base** as the source chain and **Polygon** as the destination
4. Enter the deprecated contract address: `0x79322CEE6C90735b967d2396b9ADc392915aeBB6`
5. Bridge your ASK back to Polygon and confirm in your wallet

**Step 2 — Bridge from Polygon to Base via Stargate**

1. Follow the Polygon to Base bridging steps above
2. Confirm you are using the current Base contract address: `0xBB146326778227A8498b105a18f84E0987A684b4`&#x20;

**Security Reminders**

* **Never use the deprecated Wormhole contract address** for new transactions
* **Always verify contract addresses** against the official list in [Contract Addresses](https://docs.permission.ai/ask-token/contract-addresses) before bridging
* Permission will never DM you with bridging instructions or ask for your private key
* If you need help, contact <support@permission.ai>


# Earning & Referrals

Users of the **Permission Agent Chrome Extension** can earn ASK through referral activity and milestone bonuses.

> ⚠️ **Disclaimer:** This page is for informational purposes only and does not constitute financial, investment, or legal advice. ASK is a utility token used within the Permission platform. It is not an investment product. See [Terms of Use](https://www.permission.ai/terms-of-use) for full details.

**Referral Earnings**

When you refer someone to Permission and they become an active user, you earn ASK tied to their ongoing activity within the ecosystem.

* **You earn 10% of the ASK your direct referrals earn** — automatically, on an ongoing basis
* As your referrals refer others and those users earn ASK, your earnings compound through the network
* Referral earnings are calculated monthly and deposited into your Permission Wallet on the **15th of each month**
* All earning opportunities are opt-in and presented clearly within the Permission Agent Chrome Extension
* Rewards are transparent and participation is always voluntary

**Milestone Bonuses**

As your referral network grows, you unlock additional ASK through milestone bonuses. Milestone thresholds and bonus amounts are disclosed within the Permission Agent Chrome Extension.

**Milestone Bonuses**

As your referral network grows, you unlock one-time ASK bonuses at the following thresholds:

| Milestone                                  | Bonus                                        |
| ------------------------------------------ | -------------------------------------------- |
| 5 direct referrals                         | 5,000 ASK                                    |
| 10 direct referrals                        | 10,000 ASK                                   |
| One of your referrals reaches 10 referrals | 10,000 ASK (you) + 5,000 ASK (your referral) |

Milestone bonuses are deposited into your Permission Wallet on the 15th of the month following the milestone being reached.

**Holding and Using ASK**

ASK earned through referrals and milestones can be held in your Permission Wallet or moved to a compatible external wallet for trading or redemption.

See [Trading & Liquidity](https://docs.permission.ai/ask-token/trading-and-liquidity) and [Contract Addresses](https://docs.permission.ai/ask-token/contract-addresses) for more.

**Security Reminders**

* Permission will never ask for your private key or wallet credentials
* Referral earnings and milestone bonuses are only accessible through your official Permission account
* For support, contact <support@permission.ai>

Permission reserves the right to modify, suspend, or discontinue the referral program at any time, with or without notice. Continued participation in the referral program constitutes acceptance of any such changes. See [Terms of Use](https://www.permission.ai/terms-of-use) for full details.


# Governance

**Governance**

ASK is issued by the **Permission Association**, a Swiss nonprofit association seated in Zug, Switzerland. The Association was established to develop, empower, and expand the Permission Platform in a decentralized, independent way, providing the independent governance structure that ensures the Permission ecosystem operates with transparency, accountability, and long-term integrity.

The Association is led by an experienced board: **Charles Silver** (President and founder of Permission.io), **Patrick Storchenegger** (owner of PST Legal in Zug, specializing in Swiss and international corporate, tax, and blockchain law, and a member of the Ethereum Foundation council), and **Raffaela Piraino** (former CEO and CFO of the Energy Web Foundation).

The Association received a formal ruling from **FINMA,** Switzerland's Federal Financial Market Supervisory Authority, confirming ASK's classification as a **utility token** under Swiss law. This classification, obtained through FINMA's No-Action letter process, governs how ASK is issued, transferred, and used within the Permission ecosystem. The Permission Association is the legal issuer of ASK.

ASK's utility is grounded in Permission's core mission: giving individuals ownership and control over their data, and ensuring that when data has value, the people who generate it benefit from it. ASK is the mechanism through which that value exchange becomes real — transparent, on-chain, and tied to intentional participation rather than passive extraction.

In the family context, ASK is the rewards layer that makes Permission's mission tangible. Parents fund ASK. Kids earn it through positive online behavior, educational content, and family tasks. Earned ASK can be redeemed for real-world value or traded on secondary markets by parents — giving families both immediate utility and broader liquidity. This creates an incentive structure that aligns good digital behavior with genuine reward — replacing surveillance and restriction with participation and trust.

Across the broader ecosystem, ASK powers incentive alignment between users, developers, and AI systems operating within the Permission Protocol — ensuring that every interaction is grounded in consent, every incentive is transparent, and every participant is recognized for the value they contribute.

For more on the Permission Association, its governance structure, and how to participate, visit [permissionassociation.org/governance](https://www.permissionassociation.org/governance) and read our [founding announcement](https://www.permission.io/blog/permission-association-a-swiss-association-for-data-ownership).

<br>


# Gas Fees

**What Are Gas Fees?**

Gas fees are small transaction costs paid to the blockchain network every time you perform an on-chain action — such as sending ASK from your wallet or redeeming ASK for rewards.

Think of gas fees like a postage stamp. You're not paying Permission — you're paying the network to process and record your transaction. Without enough gas in your wallet, transactions simply won't go through.

Gas fees are always paid in the **native token of the network you're transacting on** — not in ASK.

**Which Token Do I Need?**

ASK is a multi-chain token. The gas token you need depends on which network you're using:

| Network | Gas Token | Where to Get It                      |
| ------- | --------- | ------------------------------------ |
| Polygon | **POL**   | Coinbase, Binance, Kraken, Uniswap   |
| Base    | **ETH**   | Coinbase, Binance, Kraken, Aerodrome |

> Permission operates across multiple chains and may expand to additional networks in the future. Always confirm which network your wallet is connected to before transacting.

***

**How Much Do I Need?**

Gas fees on both Polygon and Base are very low — typically a fraction of a cent per transaction. A small amount goes a long way. For most users, $1–$2 worth of the relevant gas token is sufficient to cover numerous transactions.

***

**How to Add Gas to Your Permission Wallet**

**Step 1 — Get your Permission wallet address:** Log in to your Permission account and navigate to **Wallet**. Copy your wallet address.

**Step 2 — Acquire the gas token:** Purchase POL or ETH on any major exchange (Coinbase, Binance, Kraken, Gemini) or decentralized exchange (Uniswap, Aerodrome, etc.).

**Step 3 — Send the gas token to your Permission wallet address:** From your external wallet (e.g. MetaMask, Coinbase Wallet):

1. Make sure you are connected to the correct network (Polygon for POL, Base for ETH)
2. Select **Send**
3. Paste your Permission wallet address
4. Enter a small amount (e.g. $1–$2 worth)
5. Review and confirm the transaction

Once confirmed, your gas balance will appear in your Permission wallet and you'll be able to send ASK and process redemptions.

***

**Important Reminders**

* **Always confirm you are on the correct network** before sending — sending POL on the Base network or ETH on Polygon will result in failed or lost transactions
* **Double-check your wallet address** before confirming any transaction — blockchain transactions are irreversible
* Start with a small test amount if you are new to on-chain transactions

> ⚠️ Permission is not responsible for assets lost due to incorrect network selection, wrong wallet addresses, or user error. See our [Terms of Use](https://www.permission.ai/terms-of-use) for more.

***

**Need Help?**

Contact <support@permission.ai> and our team will be happy to assist.


# Permission Agent Chrome Extension

**Overview**

The "Permission Agent Chrome Extension: Share to Earn" is a legacy product available to  Permission community members. It allows users to share Permission-provided content, grow the Permission ecosystem, and earn ASK rewards through referrals and intentional participation.

The Permission Agent is separate from Permission AI for the Family, which is available at [permission.ai](https://www.permission.ai). Existing Agent users log in at [permission.ai/legacy-login](https://www.permission.ai/legacy-login).

**What the Permission Agent Does**

The Permission Agent Chrome Extension runs in your browser and serves as your ambassador tool within the Permission ecosystem. It enables you to:

* Share Permission-provided content with your network
* Earn ASK through your referral network on an ongoing basis
* Participate in guided actions that support the growth of the Permission platform
* Access your Permission Wallet and ASK balance

The Agent operates on a principle of intentional participation — you choose when and how to engage, and you are rewarded for the value you create within the ecosystem.

**How to Access the Agent**

**Existing users** log in at: 👉 [permission.ai/legacy-login](https://www.permission.ai/legacy-login)

Your wallet, ASK balance, referral network, and Agent utilities remain intact.

**New to the Permission Agent?** Install the extension from the Chrome Web Store: 👉 [Install Permission Agent Chrome Extension](https://chromewebstore.google.com/detail/Permission%20Agent%20%E2%80%93%20Earn%20by%20Powering%20AI/nkfpegmmhcipdkgoiimdegfaicbdnndh?hl=en-US\&utm_source=ext_sidebar)

**How Earning Works**

Earning through the Permission Agent is powered by your referral network and intentional participation.

**Referral Earnings**

* You earn **10% of the ASK your direct referrals earn** — automatically and on an ongoing basis
* As your referrals refer others, your earnings compound through the network
* Referral earnings are calculated monthly and deposited into your Permission Wallet on the **15th of each month**

**Milestone Bonuses**

| Milestone                                  | Bonus                                        |
| ------------------------------------------ | -------------------------------------------- |
| 5 direct referrals                         | 5,000 ASK                                    |
| 10 direct referrals                        | 10,000 ASK                                   |
| One of your referrals reaches 10 referrals | 10,000 ASK (you) + 5,000 ASK (your referral) |

Milestone bonuses are deposited into your Permission Wallet on the 15th of the month following the milestone being reached.

Permission reserves the right to modify, suspend, or discontinue the referral program at any time, with or without notice. Continued participation constitutes acceptance of any such changes. See [Terms of Use](https://www.permission.ai/terms-of-use) for full details.

**Your ASK Balance**

All existing ASK balances are unaffected by platform changes. Your ASK can be:

* Held in your Permission Wallet
* Moved to a compatible external wallet
* Traded or redeemed via supported platforms

See [Trading & Liquidity](https://docs.permission.ai/ask-token/trading-and-liquidity), [How to Bridge ASK](https://docs.permission.ai/ask-token/how-to-bridge-ask), and [Contract Addresses](https://docs.permission.ai/ask-token/contract-addresses) for more.

**The Role of ASK**

ASK is the token that powers the Permission ecosystem. It connects the legacy Permission Agent community with Permission's evolving family product, where ASK is used as a structured reward and incentive mechanism to help families encourage positive digital behavior and connect actions to outcomes.

This expanding utility means that ASK earned through the Permission Agent Chrome Extension is part of a growing ecosystem — one where data ownership, trust, and value exchange remain at the core.

> ⚠️ **Disclaimer:** ASK is a utility token used within the Permission platform. It is not an investment product. See [Terms of Use](https://www.permission.ai/terms-of-use) for full details.

**Security Reminders**

* Permission will never ask for your private key or wallet credentials
* Always access your Agent through the official legacy login at [permission.ai/legacy-login](https://www.permission.ai/legacy-login)
* For support, contact <support@permission.ai>


# Resources


# Whitepaper

Vision & First Principles

### **Why We Exist**

\
AI is becoming a decision-making layer for everyday life, shaping how people learn, communicate, shop, and are marketed to.

The question is no longer whether AI will influence human outcomes, but **who defines the rules under which it operates**.

Permission exists to ensure that AI systems work in service of people — with human values, boundaries, and consent embedded at the infrastructure level.

We are building a platform for the agentic web: a future where AI agents act on behalf of individuals and families, negotiate with other agents, and participate in value exchange — transparently and accountably.

ASK is the coordination mechanism that makes this possible. It enables permissioned participation, aligns incentives across agents, and supports a future where people are represented, not extracted.

#### First Principles

* AI should work for people
* Consent must be explicit, durable, and enforceable
* Agents should represent human interests, not platform incentives
* Tokens are the best way to align incentives and reinforce responsible behavior at scale
* AI needs Permission.

📄 [Read the full whitepaper](https://www.permission.ai/white-paper)


# FAQs

Here are answers to the most common questions about the Permission Agent, ASK token rewards, and our platform.

<details>

<summary>What does Permission actually do for my family?</summary>

Permission helps parents understand and notice meaningful patterns and shifts in their child’s digital life - across apps and online environments - without reading private messages or hovering over every interaction. As platforms evolve and AI systems shape what kids see, Permission translates digital behavior into clear, actionable insights so parents can stay informed, while teaching and supporting their children with confidence. It’s designed to reduce fear, guesswork, and conflict — and strengthen connection instead.

</details>

<details>

<summary>Is Permission a monitoring or surveillance tool?</summary>

No.

Permission is not designed for invasive monitoring or constant enforcement. It focuses on patterns, signals, and emerging risks, not raw content or private conversations.\
Instead of exposing everything, Permission highlights what actually matters, so parents can step in thoughtfully when needed.

Permission's AI is designed to strengthen relationships — not control them.

</details>

<details>

<summary>How is Permission different from other parental control apps?</summary>

Most parental control apps focus on blocking content, alerts, logs, and screen limits.

Permission is built around insight and guidance.

Instead of overwhelming you with notifications, Permission identififes and summarizes patterns, highlights meaningful changes, and helps you understand what’s actually happening online — so you can respond thoughtfully.

It also includes positive reinforcement tools like ASK rewards, giving families a way to motivate healthy digital habits, not just restrict them.

</details>

<details>

<summary>How does the rewards system ($ASK) work for families?</summary>

Permission includes a structured digital reward system called $ASK that helps families reinforce positive behavior. Children can earn ASK for responsible digital habits and family-aligned goals. Parents remain fully in control of how rewards are defined, earned, and used.

ASK gives parents a practical way to motivate and guide their children — connecting actions to outcomes in a clear, consistent way.

At the same time, it introduces kids to digital responsibility and financial literacy, helping them understand value, ownership, and long-term thinking in a modern digital world.

</details>

<details>

<summary>How does Permission help with online safety?</summary>

Permission helps families stay aware of evolving digital risks, including algorithmic influence, persuasive design, and off-platform exposure, without requiring parents to become tech experts.

By surfacing meaningful changes in behavior and engagement, Permission helps parents notice early warning signs and take practical, informed steps when needed.

The goal isn’t fear. It’s clarity and protection.

</details>

<details>

<summary>What is the Permission Agent? </summary>

The Permission Agent is your persistent “digital mini-me” — a smart browser assistant that helps you passively earn ASK rewards and enjoy more personalized AI experiences. It runs quietly in the background, detects when your data has value, secures your consent, and ensures you benefit when it’s used.

</details>

<details>

<summary>What can the Permission Agent do today? </summary>

Right now, the Agent learns from your responses, preferences, and interactions — such as surveys, intent signals, and browsing behavior. It can:

* Spot moments when your data has value
* Present relevant opportunities based on your interests
* Secure your explicit consent before sharing

</details>

<details>

<summary>What will the Permission Agent be able to do in the future? </summary>

Over time, the Agent will:

* Connect to additional data sources (email, social accounts, connected apps) for richer earning opportunities
* Perform automated tasks on your behalf with your permission
* Operate across agents, apps, and interfaces in the agentic web
* Provide more advanced personalization based on your approved data history

</details>

<details>

<summary>What kind of data is shared? </summary>

Only the information you actively choose to share: survey-style responses, search intent, preferences, or context from your browsing sessions that you approve.

Your Permission Agent is designed to behave like a trusted assistant; it doesn’t collect everything by default. Instead, it captures what you value and consent to share. That data is **encrypted end-to-end**, stored securely, and enriched with metadata like:

* Timestamped consent
* Scoped usage permissions
* Provenance tracing

This approach powers the precise personalization you appreciate without compromising privacy.&#x20;

As the Permission Agent learns more about your preferences, it unlocks more relevant AI experiences and earning opportunities, always with your permission intact.

</details>

<details>

<summary>Is my data secure? </summary>

Yes. Your data profile is stored in a highly secure, encrypted environment designed for maximum privacy and protection.

* **End-to-end encryption** protects your data in transit and at rest.
* **Granular access controls** ensure that only authorized systems can interact with your profile.
* **Segregated data storage** keeps your information isolated from unrelated systems.
* **Continuous monitoring and threat detection** safeguard against unauthorized access.

We never share your data without your explicit consent, and every approved interaction is logged with full transparency. The Permission Agent is built from the ground up to protect your information while enabling you to earn from it confidently.

***

</details>

<details>

<summary>Do I need a wallet to use the Permission Agent?</summary>

No external wallet is required. When you create your Permission account, you automatically get a **Permission Wallet** — a secure, built-in wallet that stores your ASK rewards and is ready to use immediately.

You can start earning right away without setting up anything extra.

If you prefer to connect your own external wallet, you can do that easily at any time. ASK is an **EVM-compatible token**, so it works with most standard Ethereum wallets. Connecting an external wallet allows you to move your ASK onto the broader blockchain ecosystem, trade, or use it with other applications.

**Popular compatible wallets include:**

* MetaMask
* Coinbase
* SafePal
* Uniswap

**How to Connect an External Wallet:**

1. Get a compatible wallet (e.g., download MetaMask from its official site).
2. Open your wallet and use the **“Add Token”** or **“Import Token”** feature.
3. Enter the ASK token contract address for your preferred network (Base or Polygon). See Contract Address for details.
4. Once added, your wallet can receive and send ASK.

With the Permission Wallet built in, you can start earning immediately — and with EVM compatibility, you have the flexibility to take your ASK anywhere in the Ethereum ecosystem.

</details>

<details>

<summary>What can I do with ASK? </summary>

ASK is the native utility token of the Permission ecosystem, designed for use across the agentic web. With ASK, you can:

* **Trade it on supported exchanges** — Move ASK off-platform and trade on third-party centralized or decentralized exchanges.
* **Hold it in your Permission Wallet** — Keep ASK in your built-in wallet to track rewards and access future incentives.
* **Redeem it for digital goods & platform-specific features** — Use ASK for exclusive services, premium personalization options, and partner experiences within the Permission ecosystem.
* **Participate in on-chain governance** — Use ASK to propose and vote on ecosystem priorities, incentive structures, integrations, and other key protocol decisions that shape the future of the Permission Platform.
* **Stake** *(future feature)* — Lock ASK to earn additional rewards.

Because ASK is an **EVM-compatible token**, it works with most standard Ethereum wallets, giving you the freedom to move, hold, stake, and use it anywhere in the Ethereum ecosystem.

In time, ASK will become more than just a reward — it will be the currency of a permissioned data economy, powering the exchange of value between individuals, AI agents, and the applications they serve, while giving token holders a direct voice in governing its evolution.

</details>

<details>

<summary>Why is a distributed ledger system necessary? </summary>

The Permission Platform is built on a distributed ledger system for three equally important reasons:

* **Transactional Efficiency** — Settling transactions and distributing rewards across a global user base is faster, easier, and more reliable on-chain than off-chain systems. This allows ASK rewards to be earned and transferred seamlessly in over 190 countries.
* **Transparency & Provenance** — Recording consent events and reward transactions on-chain creates an immutable proof that data was shared with permission, and that rewards were distributed fairly. This transparency strengthens trust between users, AI builders, and the broader ecosystem.
* **User Ownership** — A distributed ledger ensures users truly own their contributions — their data, their consent, and their rewards. Without on-chain infrastructure, that ownership would remain in the hands of platforms, perpetuating the same extractive models we’re working to change.

The distributed ledger isn’t just a technical choice — it’s the foundation of a permissioned data economy where trust, fairness, and user benefit are built into the protocol itself.

</details>

<details>

<summary>What happens if I revoke consent?</summary>

If you revoke consent, no new data will be shared from that point forward. Any previously shared data that has already been integrated into an AI model cannot be “unlearned,” but it will no longer be included in future datasets.

</details>

<details>

<summary>How often are ASK rewards distributed? </summary>

ASK rewards are updated in your Permission Wallet as soon as a permissioned data interaction is completed. &#x20;

</details>

<details>

<summary>Why does AI need permissioned data?</summary>

AI runs on data — but not just any data. To work well, models need **real, high-signal human input**. The problem? Most of the pipelines feeding AI today come from **scraped, black-box sources** that are biased, unverifiable, and legally risky.

Permission changes that.\
\
We source directly from individuals with explicit permission, embedding **verifiable consent and provenance** in every data point. The result is **structured, compliant datasets** that are safe for commercial use, built for personalization, and proven to be ethically sourced.

Better data. Better outcomes.

</details>


# Community

[Twitter (X)](https://x.com/PermissionIO)

[Meta (Facebook)](https://www.facebook.com/PermissionIO/)

[Instagram](https://www.instagram.com/permissionio/)

[LinkedIn](https://www.linkedin.com/company/permission-io/)

[Reddit](https://www.reddit.com/r/PermissionIO/)

[TikTok](https://www.tiktok.com/@permission.io)

[Youtube](https://www.youtube.com/@PermissionIO)

[Telegram](https://t.me/permission_io)

[Discord](https://discord.gg/bPpvHbusu5)


# Early Access


# Ai4 Early Access Sweepstakes

Permission Agent Early Access Launch Giveaway – Official Rules

### 1. Sponsor

Permission, Inc., 888 Prospect Street, Suite 200 San Diego, CA, is the sponsor of this giveaway (“Sweepstakes”).

### 2. Eligibility

Open only to legal residents of the 50 United States and the District of Columbia who are 18 years of age or older at the time of entry. Void where prohibited. Employees, officers, directors, and agents of Sponsor, its affiliates, subsidiaries, advertising and promotion agencies, and immediate family members or those living in the same household are not eligible.

### 3. Sweepstakes Period

Begins at 12:00 a.m. PT on August 11, 2025, and ends at 11:59 p.m. PT on the date that is fourteen (14) days after the official launch date of the Permission Agent Early Access program (“End Date”). The official launch date will be announced by email to all Early Access registrants.

### 4. How to Enter

* During the Sweepstakes Period, sign up for Early Access to the Permission Agent at the AI4 conference or via the designated QR code.
* Once Early Access invitations are sent, activate your account within fourteen (14) days of receipt to confirm your entry.
* Limit: One (1) entry per person.

### 5. Prizes

* **Total Prize Pool:** 5,000,000 ASK tokens (Approximate Retail Value “ARV”: $750 USD at time of giveaway launch)
* Multiple winners will share the total prize pool.
* Winners may choose to receive ASK tokens or the USD equivalent based on the value at time of award.
* ASK token value may fluctuate. No substitution or transfer of prize permitted, except at Sponsor’s discretion.

### 6. Winner Selection and Notification

* Winners will be selected at random from all eligible entries received.
* Odds of winning depend on the total number of eligible entries.
* Winners will be notified via the email address associated with their Early Access registration within seven (7) days of the End Date.
* Winners must respond within five (5) business days of notification or prize may be forfeited and awarded to an alternate winner.

### 7. General Conditions

Sponsor reserves the right to disqualify any entrant found to be tampering with the entry process or violating these Official Rules. By entering, entrants agree to be bound by these rules and release Sponsor, its affiliates, subsidiaries, advertising and promotion agencies, and their respective officers, directors, employees, and agents from any liability related to participation or prize acceptance.

### 8. Privacy

Personal information collected in connection with this Sweepstakes will be used in accordance with Sponsor’s [Privacy Policy](https://www.permission.io/privacy-policy).

### 9. Governing Law

This Sweepstakes is governed by the laws of the State of California, without regard to its conflict of law principles.


# WSAI Permission Agent Launch Sweepstakes

Permission Agent Launch Giveaway – Official Rules

### 1. Sponsor

Permission Association, Baarerstrasse 10, 6300, Zug, Switzerland, is the Organizer of this giveaway (“Sweepstakes”).

### 2. Eligibility

* Open worldwide to individuals who are at least 18 years of age at the time of participation, unless prohibited by local laws or regulations.
* Employees, officers, and contractors of Organizer, and their immediate families, are not eligible.
* By participating, entrants confirm that participation is legal under the laws of their jurisdiction.
* All participants must be registered Permission members and agree to comply with [Permission’s Terms of Use](https://www.permission.io/terms-of-use?utm_source=chatgpt.com).

### 3. Sweepstakes Period

Begins at 12:00 a.m. PT on October 8th, 2025, and ends at 11:59 p.m. PT on October 23, 2025 (“End Date”).&#x20;

### 4. How to Enter

* During the Sweepstakes Period, sign up for Permission Agent at the WSAI conference or via the designated QR code.
* Complete a three-question feedback survey within fourteen (14) days of activating your Agent to confirm your entry.
* Limit: One (1) entry per person.

### 5. Prizes

* **Total Prize Pool:** 5,000,000 ASK tokens (Approximate Retail Value “ARV”: $750 USD at time of giveaway launch)
* Multiple winners will share the total prize pool.
* ASK token value may fluctuate. No substitution or transfer of prize permitted, except at Organizer’s discretion.

### 6. Winner Selection and Notification

* Winners will be selected at random from all eligible entries received.
* Odds of winning depend on the total number of eligible entries.
* Winners will be notified via the email address associated with their  registration within ten (10) days from the End Date.
* Winners must respond within seven (7) business days of notification or prize may be forfeited and awarded to an alternate winner.

### 7. General Conditions

Organizer reserves the right to disqualify any entrant found to be tampering with the entry process or violating these Official Rules. By entering, entrants agree to be bound by these rules and release Organizer, its affiliates, subsidiaries, advertising and promotion agencies, and their respective officers, directors, employees, and agents from any liability related to participation or prize acceptance.

### 8. Privacy

Personal information collected in connection with this Sweepstakes will be used in accordance with Organizer’s [Privacy Policy](https://www.permission.io/privacy-policy).

### 9. Governing Law

This Sweepstakes is governed by the laws of Switzerland, without giving effect to any choice or conflict of law provision or rule (whether of Switzerland or any other jurisdiction).

<br>


# Permission Protocol


# Concepts


# Overview

**The Permission Protocol** is an on-chain ledger that records and maintains a public, auditable history of data-sharing agreements and permissions. It is designed to make data transactions more transparent by establishing a verifiable record of **who** is permitted to use data, **for what purposes**, **under which referenced terms**, and whether that permission is **active, expired, or revoked**. The Protocol does not store personal data; it records the binding facts that support compliance, governance, and dispute resolution.

### Entities

#### Data Providers

**Data Providers** are individuals or sources of data who authorize the use of their data. The Protocol enables providers to grant permission tied to a specific agreement and to revoke that permission when allowed by the agreement, creating an immutable record of authorization over time.

#### Data Consumers

**Data Consumers** are companies or agents that request access to data for defined purposes. The Protocol enables consumers to rely on a consistent, independently verifiable record that permission exists and to demonstrate the current status of permission to partners, auditors, and compliance teams.

#### Data Processors

**Data Processors** act on behalf of a consumer to store, analyze, or otherwise process data. The Protocol supports processor involvement by making permissions verifiable and referenceable, so processors can confirm that processing is tied to an active permission record and the governing terms.

### Service Providers

A **Service Provider** is a website or platform that implements the Permission Protocol to operate a real-world data-sharing system. The service provider typically:

* publishes or hosts the underlying terms referenced by agreements,
* collects and stores data off-chain,
* enforces access to that data based on on-chain permission status, and
* may reward providers for granting permission, using its own commercial and operational payout systems.

In short: **the Protocol records and proves permission; the service provider delivers the terms, the data access, and the user experience.**

### Key components

#### Decentralized Identifiers

The Protocol uses **Decentralized Identifiers** to represent parties in a consistent, portable way. These identifiers allow providers and consumers to be referenced across systems without relying on a single platform’s internal user database.

#### Agreements

An **Agreement** is the public on-chain record that references the governing terms and permitted purposes for data use. It anchors a fingerprint of the terms so the terms relied upon can be verified later.

#### Proof of Permission

A **Proof of Permission** is the on-chain record that a provider authorized a specific agreement, including the permission’s lifecycle status over time, such as active, expired, or revoked.


# Examples

This section shows how the Permission Protocol is commonly used by websites and marketplaces.

In each case, the Protocol provides a public record of the agreement and the user’s permission, while the data itself remains off-chain and is delivered by the service provider.

#### Example 1: Website

A website asks users to opt in to specific data uses, records each opt-in on the blockchain, and rewards users for participating.

**How it works**

* The website publishes an **agreement** that states the permitted purposes and references the governing terms.
* A user opts in, creating an on-chain **proof of permission** tied to that agreement. The permission can be ongoing or time-limited, and it can be revoked when allowed by the agreement.
* The website stores and manages the user’s data off-chain. When the data is used or shared, the website checks the on-chain permission status to confirm it is active.
* The website rewards the user under its reward program, using the on-chain permission record as the auditable basis for the reward.

**What this provides**

* A clear record of what the user authorized and when.
* A defensible permission trail for audits and partner reviews.
* A shared source of truth for permission status without relying only on internal logs.

***

#### Example 2: Data Marketplace

A marketplace connects users with third-party brands. Brands publish offers and terms, users choose what to share, and each permission is recorded on-chain.

**How it works**

* Brands publish offers with defined purposes and referenced terms. Each offer is anchored as an on-chain **agreement**.
* Users opt in by data product, which may include surveys, AI chats they choose to share, paid brand lead forms, linked public content, clickstream, browsing signals, and other user-generated data.
* Each opt-in creates an on-chain **proof of permission** tied to the specific brand agreement, with a visible status over time.
* The marketplace or designated service providers package and deliver the approved data off-chain, and can require that permission remains active before providing access.
* Users are rewarded under the marketplace’s commercial model, with the on-chain permission record supporting transparency and auditability.

**What this provides**

* Brands receive permissioned data tied to stated purposes and referenced terms.
* Users can view and manage permissions across many brands in one place.
* The marketplace can demonstrate it brokered permissioned access using a public, tamper-evident record.


# DID Generation

DID is an ethereum wallet address

Did is a basic secp256k1 key generated ethereum address which is written in format

`did:pkh:{address_key}` e.g `did:pkh:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2`

#### Generating Ethereum Compatible DiD

**Install Protocol SDK and Viem**

{% tabs %}
{% tab title="NPM" %}

```javascript
npm install viem @permission-io/protocol-sdk
```

{% endtab %}

{% tab title="Yarn" %}

```python
yarn add viem @permission-io/protocol-sdk
```

{% endtab %}

{% tab title="Bun" %}

```ruby
bun add viem @permission-io/protocol-sdk
```

{% endtab %}
{% endtabs %}

```
import { generatePrivateKey, privateKeyToDid, defaultPermissionDIDDocument } from "@permission-io/protocol-sdk/did";

// 1. Generate a random private key
const privateKey = generatePrivateKey();

// 2. Derive the DID (did:pkh:...)
const did = await privateKeyToDid(privateKey);
console.log(`Generated DID: ${did}`);

// 3. Create a default DID Document
const didDoc = defaultPermissionDIDDocument(privateKey);
console.log(didDoc);
```

### DID Document Structure

A DID Document (Decentralized Identifier Document) is a fundamental component of the Decentralized Identifiers architecture, serving as the digital identity profile for a DID subject

DID Document structure for permission protocol requirements is as follows

```json
{
  "@context": ["https://w3id.org/security/suites/secp256k1recovery-2020/v2", "https://www.w3.org/ns/cid/v1"],
  "id": "did:pkh:0x998b41de68d45d452e248478a98cc803c097094f",
  "verificationMethod": [
    {
      "id": "did:pkh:0x998b41de68d45d452e248478a98cc803c097094f#verify-signature",
      "type": "EcdsaSecp256k1RecoveryMethod2020",
      "controller": "did:pkh:0x998b41de68d45d452e248478a98cc803c097094f",
      "blockchainAccountId": "eip155:1:0x998b41de68d45d452e248478a98cc803c097094f"
    },
    {
      "id": "did:pkh:0x998b41de68d45d452e248478a98cc803c097094f#encryption-key",
      "type": "Multikey",
      "controller": "did:pkh:0x998b41de68d45d452e248478a98cc803c097094f",
      "publicKeyMultibase": "z6MkmM42vxfqZQsv4ehtTjFFxQ4sQKS2w6WR7emozFAn5cxu"
    }
  ],
  "authentication": ["did:pkh:0x998b41de68d45d452e248478a98cc803c097094f#verify-signature"],
  "assertionMethod": ["did:pkh:0x998b41de68d45d452e248478a98cc803c097094f#verify-signature"],
  "keyAgreement": ["did:pkh:0x998b41de68d45d452e248478a98cc803c097094f#encryption-key"]
}

```

{% hint style="info" %}
**Multikey** verification method is required for encrypted data access through IPFS

[More on this in Data Access Patterns](/permission-protocol/v1-protocol/data-access-patterns#ipfs-encrypted-mode)
{% endhint %}

## Permission Protocol SDK

### Quick Start

#### 1. Generate an Identity

Create a new private key and derived DID.

```typescript
import { generatePrivateKey, privateKeyToDid, defaultPermissionDIDDocument } from "@permission-io/protocol-sdk/did";

// 1. Generate a random private key
const privateKey = generatePrivateKey();

// 2. Derive the DID (did:pkh:...)
const did = await privateKeyToDid(privateKey);
console.log(`Generated DID: ${did}`);

// 3. Create a default DID Document
const didDoc = defaultPermissionDIDDocument(privateKey);
console.log(didDoc);
```

### Usage Guide

#### Prerequisites

Initialize a `viem` Client (Wallet and Public) to interact with the blockchain.

```typescript
import { createWalletClient, createPublicClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains"; // or your target chain

const account = privateKeyToAccount(YOUR_PRIVATE_KEY);

const walletClient = createWalletClient({
  account,
  chain: base,
  transport: http()
});

const publicClient = createPublicClient({
  chain: base,
  transport: http()
});
```

#### Registering a DID

**Method A: Self-Registration**

Register your own DID directly on-chain.

```typescript
import { publishDIDDocument, defaultPermissionDIDDocument } from "@permission-io/protocol-sdk/did";

// Prepare the DID Document
const didDoc = defaultPermissionDIDDocument(YOUR_PRIVATE_KEY);

// Publish to the registry
const txHash = await publishDIDDocument(didDoc, walletClient);
console.log(`DID Registered. Tx Hash: ${txHash}`);
```

**Method B: Delegated Registration (Meta-Transaction)**

Allow a third party (relayer) to pay for the gas fees while you sign the intent.

**Signer (Identity Owner):**

```typescript
import { signDIDDocumentOf, defaultPermissionDIDDocument } from "@permission-io/protocol-sdk/did";
import { base } from "viem/chains";

const didDoc = defaultPermissionDIDDocument(signerPrivateKey);
const chainId = base.id; // Target Chain ID

// Sign the document
const { didDocumentStruct, signature } = await signDIDDocumentOf(didDoc, chainId, signerWalletClient);
```

**Relayer (Gas Payer):**

```typescript
import { publishDIDDocumentOf } from "@permission-io/protocol-sdk/did";

// Relayer submits the signed payload
const txHash = await publishDIDDocumentOf(
  didDoc,            // The original JSON DID Document
  signerAddress,     // Address of the identity owner
  signature,         // The signature generated by the owner
  relayerWalletClient // Relayer's wallet client pays for gas
);
```

#### Updating a DID

**Method A: Self-Update**

Update your existing DID Document.

```typescript
import { updateDIDDocument } from "@permission-io/protocol-sdk/did";

// Modify your DID Document (e.g., add a new service or key)
const updatedDoc = { ...oldDoc, nonce: oldDoc.nonce + 1 }; 

const txHash = await updateDIDDocument(updatedDoc, account.address, walletClient);
```

**Method B: Delegated Update**

Update a DID Document via a relayer.

```typescript
import { updateDIDDocumentOf } from "@permission-io/protocol-sdk/did";

// 1. Owner signs the update
// ... (similar signing process as registration)

// 2. Relayer submits
const txHash = await updateDIDDocumentOf(
  updatedDoc,
  ownerAddress,
  signature,
  relayerWalletClient
);
```

#### Resolving a DID

Fetch and decode a DID Document from the blockchain.

```typescript
import { fetchDidDocument } from "@permission-io/protocol-sdk/did";

const did = "did:pkh:0x123...";
const document = await fetchDidDocument(did, publicClient);

if (document) {
  console.log("DID Document:", document);
} else {
  console.log("DID not found");
}
```

> **🚧 Content in Progress 🚧**\
> This documentation page is currently being created and is incomplete. Please check back later for updates.

W3C DiD Spec: <https://www.w3.org/TR/did-1.0/>


# Proof of Consent

## What is Proof of Consent?

Proof of consent under GDPR involves demonstrating that an individual has given free, specific, informed, and unambiguous consent for their data to be processed.


# V1 Protocol


# Consent Record Schema

### Supported Usecases

The schemas are designed to support a variety of use cases and be extensible enough to allow external dependencies for extensible support.

Example Usecases:

1. Data Collection:
   1. Purpose Key: DATA\_COLLECTION
   2. Agreement Kind: CONSENT\_V1
   3. <mark style="color:$warning;">DataRef: Optional</mark>&#x20;
2. Product License
   1. Agreement Kind: TOS\_V1
   2. Purpose Key: LEGAL\_COMPLIANCE
3. Data Distribution
   1. Agreement Kind: LICENSE\_V1
   2. Purpose Key: ATTRIBUTION\_ANALYTICS, MODE\_TRANING
4. TOS or Policy:
   1. Agreement Kind: CONSENT\_V1
   2. Purpose Key: TOS\_V1
   3. Terms Ref: ipfs link

### Agreement

An agreement is something two parties decide upon, it could be in any format, from a text file to a pdf or even an image, the agreement must clearly define the terms which both parties agreed on.

### Data Schema Consent

| Field Name                                                                                      | Description                                                                                                               | Required                                                                |
| ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| Schema Version                                                                                  |                                                                                                                           | Not Required Explicity, Implicit Contract Versioning                    |
| Agreement Id                                                                                    | ID/Ref of Agreement onchain                                                                                               | Required                                                                |
| Consent Signature                                                                               | Signed by supplier of consent, more on this later                                                                         | Required                                                                |
| Supplier DID                                                                                    | The DID of the person providing consent                                                                                   | Required                                                                |
| [Data Ref](/permission-protocol/v1-protocol/data-access-patterns#dataref-driven-access-pattern) | This could be anything from a url, to a hash, to an internal ID of the collected Data if any data is collected            | Optional, Can be used if any data is being shared                       |
| disclosed                                                                                       | This flag tells if the data ref is disclosed openly or if It is encrypted or authorization is required                    | Optional, only needed with dataref, default false, encrypted by default |
| validityEnd                                                                                     | This signifies the validity period of the consent, this can either be 0 showing no expiry or a timestamp of expiry date   | Required by default 0                                                   |
| revocationRef                                                                                   | This is refrence to an external record of revocation. This could be a sperate contract or schema housing revocation data. | Optional (Revocation eligibility is governed by agreement schema)       |

### Data Schema Agreement

Each Agreement has a id or hash of it.

| Field Name                 | Description                                                                                                                                 | Required                                                                                                                                                                                        |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Agreement Kind             | <p>Legal/Operational Frame <br>e.g CONSENT\_V1, LICENSE\_V1 etc</p>                                                                         | Required                                                                                                                                                                                        |
| Purpose Key                | <p>How the data will be used</p><p>E.g: EMAIL\_MARKETING, ATTRIBUTION\_ANALYTICS, MODEL\_TRAINING, ADS\_PERSONALIZATION</p>                 | <p>Optional, if there is an external defined agreement and single field can't define the purpose then this field can be omited for greater terms in terms ref<br>But this has high priority</p> |
| Terms Ref                  | <p>This could be a terms url, or an ipfs id where terms can be viewed or hash if terms provided offchain<br>starts with: http, ipfs, 0x</p> | Optional, Not required if the purpose and other fields are enough for the legal uses                                                                                                            |
| Terms Hash                 | This would be hash of the terms so terms ref can be verified incase it is external web2 url                                                 | In case of IPFS terms this is not required, otherwise if terms are present this must exists                                                                                                     |
| conditionsRef              | A hash of conditions that should bet met for rewarding consent                                                                              | Optional, in case of permission this is a hash of platform-verification                                                                                                                         |
| Counter Party DID          | The DID of the party to whom consent is being provided to                                                                                   | Required                                                                                                                                                                                        |
| Revocation Eligibility     | This field tells if consent once given can be revoked or not, while governing few mechanisms for revocation                                 | Required                                                                                                                                                                                        |
| `revokeGracePeriodSeconds` | This field governs when the consent can be revoked if it is revokable                                                                       | Optional (Required if revocation is set for eligibility)                                                                                                                                        |

&#x20;

### Consent Signature

This will be end product signature which will be derived by the supplier using the following fields

* Agreement Data
  * kind, purpose, termsref, conditionsref, counterpartydid
* Payout Amount
* Validity end

### Agreement Kind (max: 32 chars)

It is the single, versioned key that states the legal/operational frame (e.g., "this record is a consent" vs "this record is a license").

e.g

* CONSENT\_V1 (consent for data collection/access/tracking)
* LICENSE\_V1 (useage rights on collected/drived data)
* DATA\_SHARING\_CONTRACT\_V1 (contract governing disclosure/transfer)
* MODEL\_TRAINING\_LICENSE\_V1 (rights to use data for model training)
* USAGE\_RIGHTS\_V1 (generic usage rights without transfer)
* TOS\_V1 (terms of service acceptance)
* DPA\_V1 (data processing agreement, B2B controller–processor)

### Purpose Key (Multi) (max: 32 chars)

It’s the controlled vocabulary key (or keys) stating the intended use(s) of the data.

* MODEL\_TRAINING (data will be used for model training)
* REWARD\_FULFILLMENT ()
* LEGAL\_COMPLIANCE
* AD\_PERSONALIZATION
* PRODUCT\_ANALYTICS
* ATTRIBUTION\_ANALYTICS
* EMAIL\_MARKETING
* THIRD\_PARTY\_DISCLOSURE
* RECOMMENDATIONS
* PERSONALIZATION
* DATA\_COLLECTION

### Data Ref

The purpose of data ref for Permission is to have a record of data that is used in processing.\
This could be hash of the data which is collected, or a url which points to the data which will be shared, \
or points to the web page where this data can be managed.

### ConditionsRef

This will be a hash value, which use is upto the implementer. Its primary focus is to tell the conditions which should be met for the supplier before they are eligible for gaining the payout.

{% hint style="info" %}
For Permission:\
Condition Ref ⇒ 'platform\_verified' ⇒ hash

Once it is signed by the platform DID, a user can perform withdraws through the governing withdraw contract
{% endhint %}

{% hint style="info" %}
ConditionsRef is an extra field which doesn't directly affect consent hence, it can be used by others as required
{% endhint %}

### Revocation Eligibility

Revocation eligibility is an enumeration with the following values:

1. **Unrevokable**: Consent cannot be revoked once given.
2. **Instantly Revokable**: Consent can be revoked immediately by the user.
3. **RevokableAfterGracePeriod**: Consent can be revoked only after a specified grace period has elapsed. For this type, there will be an additional field called `revokeGracePeriodSeconds` that dictates the duration of the grace period before revocation can occur.

## Questions:

<details>

<summary>Who can add to revocation ref?</summary>

Only supplier can add  the revocation ref.

</details>

<details>

<summary>When can the consent be revokable?</summary>

Supplier can only revoke consent if the agreement supports it, it could either be instantly revokable or revokable after certain grace period depending on the agreement.

</details>

<details>

<summary>If i am supplying user's data to some other party who doesn't have DID, how do i take consent then?</summary>

You will take consent with purpose key THIRD\_PARTY\_DISCLOSURE

</details>

<details>

<summary>How url is stored in smart contract</summary>

Url is stored as string in the ref states, global uri can be implemented later for saving gas

</details>


# Data Access Patterns

Defined process of accessing data in permission protocol by a consumer utilizing dataRef in a consent record for secure access of supplier provided data according to consent.

## <mark style="color:green;">DataRef</mark> driven Access Pattern

There are two ways to access data from supplier, IPFS encrypted and Signature Gated mode

#### Chossing Correct Mode

* dataRef starts with ipfs\:// ⇒ **IPFS Encrypted Mode**
* dataRef starts with http\:// or https\:// ⇒ **API Signature-Gated Mode**

***

## 1. Public Access Mode (disclosed: true)

**Condition**: When the consent record contains { disclosed: true, dataRef: "..." }

**Behavior**:

* Data is **publicly accessible** without any cryptographic protection
* No EIP-712 signatures required
* No ECDH encryption/decryption needed
* Consumer can directly fetch data using the dataRef URI
* Suitable for non-sensitive, publicly shareable datasets

**Example Consent Record**:

```
{
  agreementId: "0x...",
  supplier: "did:pkh:0xSUPPLIER",
  consumer: "did:pkh:0xCONSUMER",
  disclosed: true, // ← Public access flag
  dataRef: "ipfs://bafybeipublicdata..."
  ....
}
```

***

## 2. Restricted Access Mode (disclosed: false)

When disclosed: false (or undefined), the protocol uses secure access based on dataRef scheme:

### A. Signature Gated Api Mode

**Consumer Flow**:

1. Sign EIP-712 ConsentRecord structure containing:
   * supplier: Supplier's blockchain address
   * agreementContract: Agreement contract address
   * agreementId: The specific agreement identifier
2. Attach signature to API request headers:
   * X-Signature: EIP-712 signature
   * X-Consent-ID: The onchain id of associated consent record

**Supplier Flow**:

1. Extract signature and identifiers from request headers
2. Recover signer from EIP-712 signature
3. Verify:
   * Signer matches consent consumer
4. Serve data if verification passes, otherwise reject

{% hint style="info" %}
Supplier and Consumer doesn't need to have a DID Document when using signature based verification
{% endhint %}

**Consumer Code**:

```typescript
import { IPublicClient, IWalletClient } from "@permission-io/protocol-sdk";
import { createDataConsumerSignature } from "@permission-io/protocol-sdk/data";

const walletClient = // Consumer Wallet for signature creation

const sig = await createDataConsumerSignature(
  { consentRecordId: BigInt(consentId) },
  {
    wallet: walletClient,
    public: publicClient,
  },
);
```

**Supplier Code**:

```typescript
import { verifyDataConsumerSignature } from "@permission-io/protocol-sdk/data";

const isValid = await verifyDataConsumerSignature(
  {
    consentRecordId: BigInt(consentId),
    signature: signatureHex as Hex,
  },
  {
    public: publicClient as IPublicClient,
  },
);

if(isValid)
  // Allow data access
else
  // return 401 status

```

**Api Request Example:**

```javascript
const signature = "0x..."

const response = await fetch("https://api.yourservice.com/data", {
  headers: {
    "x-signature": signature,
    "x-consent-id": "1"
  },
});
```

**Api Middleware Example**

```typescript
import { parseRequestHeaders} from "@permission-io/protocol-sdk/data";

middleware((request)=>{
    const parsed = parseRequestHeaders(request.headers)
    if(parsed){
        const {signature, consentId} = parsed;
        // Logic to return data    
    }else {
        throw UnauthorizedException()
    }
})
```

### B. IPFS Encrypted Mode&#x20;

{% hint style="warning" %}
Consumer and Supplier must have DID Documents so public keys can be extracted for encryption
{% endhint %}

**Condition**: open: false AND dataRef.startsWith("ipfs\://")

**Supplier Flow**:

1. Extract consumer's public key from DID Document (keyAgreement section)
2. Generate ECDH shared secret: secp256k1.getSharedSecret(supplierPrivKey, consumerPubKey)
3. Encrypt data with AES-256-GCM using SHA256(sharedSecret) as key
4. Upload envelope JSON to IPFS: { ciphertext, iv, authTag }
5. Set dataRef to the IPFS CID

**Consumer Flow**:

1. Fetch encrypted envelope from IPFS using the CID
2. Extract supplier's public key from DID Document
3. Generate same ECDH shared secret: secp256k1.getSharedSecret(consumerPrivKey, supplierPubKey)
4. Decrypt using AES-256-GCM with authenticated verification

{% hint style="info" %}
Public key of the DID subject can be found in DID document under **keyAgreement**
{% endhint %}

**Code for Supplier Encryption:**

```typescript
import { fetchPublicKey, encryptData } from "@permission-io/protocol-sdk/data";

// Private key of data supplier/controller
const supplierPrivateKey = "0x..."

const dataToEncrypt = "Hellow World!"

const consumerPublicKey = await fetchPublicKey({
  did: consumerDid,
  clients: { public: publicClient },
});

// Encrypt the data
const encrypted= encryptData({
  data: dataToEncrypt,
  consumerPublicKey,
  supplierPrivateKey,
});

const cid = await publishToIPFS(JSON.stringify(encrypted));
// The generated cid will be put in dataRef inside consent record
// e.g ipfs://bafybeicn7i3soqdgr7dwnrwytgq4zxy7a5jpkizrvhm5mv6bgjd32wm3q4

```

**Code for Consumer Decryption:**

```typescript
import { fetchPublicKey, decryptData } from "@permission-io/protocol-sdk/data";

// Private key of data consumer
const consumerPrivateKey = "0x..."

const dataToDecrypt = {
  cipherText: "0x0..",
  iv: "0x.."
}

const supplierPublicKey = await fetchPublicKey({
  did: supplierDid,
  clients: { public: publicClient },
});

// Decrypt the data
const decrypted = decryptData({
  ciphertext: dataToDecrypt.ciphertext,
  iv: dataToDecrypt.iv,
  supplierPublicKey,
  consumerPrivateKey,
});

```

{% hint style="info" %}
Need to fetch file data from IPFS E.g\
<https://docs.ipfs.tech/quickstart/retrieve/#ipfs-retrieval-methods>
{% endhint %}


# Contracts

Smart Contracts Addresses and Repositories

Permission Protocol Smart Contracts Repository: <https://github.com/permission-io/protocol-contracts>

## Base Testnet

<table><thead><tr><th width="199">Contract</th><th>Address</th></tr></thead><tbody><tr><td>Agreement</td><td><a href="https://sepolia.basescan.org/address/0xD82bD992eBf0797382D17bE11E2302f398c03Fd3"><code>0xD82bD992eBf0797382D17bE11E2302f398c03Fd3</code></a></td></tr><tr><td>Consent</td><td><a href="https://sepolia.basescan.org/address/0xb3E6e422f6Fa90Ea800710AC1B363C9Af2EC00E6"><code>0xb3E6e422f6Fa90Ea800710AC1B363C9Af2EC00E6</code></a></td></tr><tr><td>DIDRegistry</td><td><a href="https://sepolia.basescan.org/address/0x6e0EEE3dCA15Ee3E0bce0657BF6a13c5d42b3D6f"><code>0x6e0EEE3dCA15Ee3E0bce0657BF6a13c5d42b3D6f</code></a></td></tr></tbody></table>

## Base Mainnet

TBD


# Agreement

### Overview

The **Agreement** contract is a core component of the Permission Protocol that manages consent agreements between parties. It uses EIP-712 typed data signatures for secure, gasless agreement creation and prevents replay attacks through digest tracking.

### Contract Details

| Property         | Value                          |
| ---------------- | ------------------------------ |
| Solidity Version | ^0.8.28                        |
| License          | MIT                            |
| Inheritance      | EIP712, Context (OpenZeppelin) |
| Implements       | IAgreement                     |

***

### Purpose

The Agreement contract serves as the foundation for creating legally-binding consent agreements on-chain. It enables:

* **Typed Data Signing**: Counterparties sign agreements off-chain using EIP-712
* **Replay Protection**: Each unique agreement can only be created once
* **Flexible Terms**: Supports multiple purpose keys and conditions
* **Revocation Control**: Configurable revocation eligibility with optional grace periods
* **Human-Readable Data**: Provides parsed agreement data with string conversions
* **Batch Operations**: Create multiple agreements in a single transaction

***

### Data Structures

#### RevokeEligibility Enum

Defines the revocation rules for an agreement.

```solidity
enum RevokeEligibility {
    UnRevokable,              // Cannot be revoked
    InstantlyRevokable,       // Can be revoked immediately
    RevokableAfterGracePeriod // Can only be revoked after grace period passes
}
```

| Value                       | Description                                              |
| --------------------------- | -------------------------------------------------------- |
| `UnRevokable`               | Consent records cannot be revoked                        |
| `InstantlyRevokable`        | Consent records can be revoked at any time               |
| `RevokableAfterGracePeriod` | Consent records can only be revoked after a grace period |

#### AgreementData (IAgreement Interface)

The primary structure for storing agreement details, defined in the `IAgreement` interface.

```solidity
struct AgreementData {
    bytes32 kind;                      // Type of agreement (encoded as bytes32)
    bytes32[] purpose;                 // List of purpose keys
    bytes32 termsHash;                 // Hash of the terms content
    bytes32 conditions;                // Hash of specific conditions or limitations
    address counterParty;              // Address of the other party
    uint64 revokeGracePeriodSeconds;   // Waiting period before revocation is allowed
    RevokeEligibility revokeEligibility; // Revocation rules
    string termsRef;                   // Reference URL to full terms
}
```

| Field                      | Type              | Description                                                       |
| -------------------------- | ----------------- | ----------------------------------------------------------------- |
| `kind`                     | bytes32           | The type/category of the agreement                                |
| `purpose`                  | bytes32\[]        | Array of purpose keys defining data usage                         |
| `termsHash`                | bytes32           | Keccak256 hash of the full terms document                         |
| `conditions`               | bytes32           | Hash of additional conditions/limitations                         |
| `counterParty`             | address           | The party consenting to the agreement                             |
| `revokeGracePeriodSeconds` | uint64            | Seconds to wait before revocation (for RevokableAfterGracePeriod) |
| `revokeEligibility`        | RevokeEligibility | Rules for when/if the agreement can be revoked                    |
| `termsRef`                 | string            | URL or IPFS hash pointing to full terms                           |

#### ParsedAgreementData

Human-readable version with strings instead of bytes32.

```solidity
struct ParsedAgreementData {
    string kind;                       // Type as readable string
    string[] purpose;                  // Purpose keys as strings
    bytes32 termsHash;                 // Hash of terms (unchanged)
    bytes32 conditions;                // Conditions hash (unchanged)
    address counterParty;              // Counterparty address
    uint64 revokeGracePeriodSeconds;   // Grace period in seconds
    RevokeEligibility revokeEligibility; // Revocation rules
    string termsRef;                   // Reference URL
}
```

#### AgreementInput

Input structure for batch agreement creation.

```solidity
struct AgreementInput {
    bytes32 kind;                      // The agreement kind
    bytes32[] purpose;                 // Array of purpose keys
    bytes32 termsHash;                 // Hash of the terms
    bytes32 conditions;                // The conditions hash
    address counterParty;              // The counterparty address
    uint64 revokeGracePeriodSeconds;   // Grace period for revocation
    RevokeEligibility revokeEligibility; // Revocation eligibility
    string termsRef;                   // Reference to the terms
    bytes signature;                   // The EIP-712 signature from the counterparty
}
```

***

### State Variables

| Variable           | Type                              | Visibility | Description                                               |
| ------------------ | --------------------------------- | ---------- | --------------------------------------------------------- |
| `agreementCounter` | uint256                           | public     | Counter for generating unique agreement IDs (starts at 1) |
| `agreements`       | mapping(uint256 => AgreementData) | public     | Storage mapping of agreement ID to data                   |
| `usedDigests`      | mapping(bytes32 => uint256)       | public     | Tracks used EIP-712 digests to agreement IDs              |

***

### Functions

#### Constructor

```solidity
constructor(string memory name, string memory version)
```

Initializes the contract with EIP-712 domain separator parameters.

**Parameters:**

| Name      | Type   | Description                     |
| --------- | ------ | ------------------------------- |
| `name`    | string | Domain name (e.g., "Agreement") |
| `version` | string | Domain version (e.g., "1")      |

***

#### createAgreement

```solidity
function createAgreement(
    bytes32 kind,
    bytes32[] calldata purpose,
    bytes32 termsHash,
    bytes32 conditions,
    address counterParty,
    uint64 revokeGracePeriodSeconds,
    RevokeEligibility revokeEligibility,
    string calldata termsRef,
    bytes calldata signature
) external returns (uint256 agreementId)
```

Creates a new agreement with EIP-712 signature verification.

**Parameters:**

| Name                       | Type              | Description                            |
| -------------------------- | ----------------- | -------------------------------------- |
| `kind`                     | bytes32           | The agreement type                     |
| `purpose`                  | bytes32\[]        | Array of purpose keys                  |
| `termsHash`                | bytes32           | Hash of terms content                  |
| `conditions`               | bytes32           | Conditions hash                        |
| `counterParty`             | address           | Address that must sign (or msg.sender) |
| `revokeGracePeriodSeconds` | uint64            | Grace period before revocation allowed |
| `revokeEligibility`        | RevokeEligibility | Revocation rules                       |
| `termsRef`                 | string            | Reference to full terms                |
| `signature`                | bytes             | EIP-712 signature from counterParty    |

**Returns:**

| Name          | Type    | Description                            |
| ------------- | ------- | -------------------------------------- |
| `agreementId` | uint256 | The unique ID of the created agreement |

**Requirements:**

* `kind` cannot be empty (bytes32(0))
* If `counterParty` != `msg.sender`, signature must be valid
* Agreement with same parameters cannot already exist

**Emits:** `AgreementCreated`

***

#### batchCreateAgreements

```solidity
function batchCreateAgreements(
    AgreementInput[] calldata inputs
) external returns (uint256[] memory agreementIds)
```

Creates multiple agreements in a single transaction.

**Parameters:**

| Name     | Type              | Description               |
| -------- | ----------------- | ------------------------- |
| `inputs` | AgreementInput\[] | Array of agreement inputs |

**Returns:**

| Name           | Type       | Description                    |
| -------------- | ---------- | ------------------------------ |
| `agreementIds` | uint256\[] | Array of created agreement IDs |

**Requirements:**

* Input array must not be empty

**Emits:** `AgreementCreated` for each agreement

***

#### isRevokable

```solidity
function isRevokable(
    uint256 agreementId,
    uint64 createdAt
) public view returns (bool)
```

Checks if a consent record for this agreement can be revoked based on the agreement's revocation rules.

**Parameters:**

| Name          | Type    | Description                                   |
| ------------- | ------- | --------------------------------------------- |
| `agreementId` | uint256 | The agreement identifier                      |
| `createdAt`   | uint64  | Timestamp when the consent record was created |

**Returns:**

| Name   | Type | Description                                        |
| ------ | ---- | -------------------------------------------------- |
| (bool) | bool | `true` if revocation is allowed, `false` otherwise |

**Logic:**

* `UnRevokable`: Always returns `false`
* `InstantlyRevokable`: Always returns `true`
* `RevokableAfterGracePeriod`: Returns `true` only if `(block.timestamp - createdAt) >= revokeGracePeriodSeconds`

**Reverts:** `AgreementNotFound` if agreement doesn't exist

***

#### getAgreementData

```solidity
function getAgreementData(uint256 agreementId) public view returns (AgreementData memory)
```

Retrieves raw agreement data by ID.

**Parameters:**

| Name          | Type    | Description              |
| ------------- | ------- | ------------------------ |
| `agreementId` | uint256 | The agreement identifier |

**Returns:** `AgreementData` struct

**Reverts:** `AgreementNotFound` if agreement doesn't exist

***

#### getParsedAgreementData

```solidity
function getParsedAgreementData(uint256 agreementId) public view returns (ParsedAgreementData memory)
```

Returns agreement data with human-readable strings.

**Parameters:**

| Name          | Type    | Description              |
| ------------- | ------- | ------------------------ |
| `agreementId` | uint256 | The agreement identifier |

**Returns:** `ParsedAgreementData` struct with kind and purpose as strings

**Reverts:** `AgreementNotFound` if agreement doesn't exist

***

#### hashAgreementData

```solidity
function hashAgreementData(
    bytes32 kind,
    bytes32[] calldata purpose,
    bytes32 termsHash,
    bytes32 conditions,
    address counterParty,
    uint64 revokeGracePeriodSeconds,
    RevokeEligibility revokeEligibility,
    string calldata termsRef
) public pure returns (bytes32)
```

Computes the EIP-712 struct hash for agreement data.

**Returns:** The keccak256 hash of the encoded struct

***

#### getTypedDataHash

```solidity
function getTypedDataHash(
    bytes32 kind,
    bytes32[] calldata purpose,
    bytes32 termsHash,
    bytes32 conditions,
    address counterParty,
    uint64 revokeGracePeriodSeconds,
    RevokeEligibility revokeEligibility,
    string calldata termsRef
) public view returns (bytes32)
```

Returns the complete EIP-712 typed data hash for signing.

**Returns:** The hash that should be signed by the counterparty

***

### Events

#### AgreementCreated

```solidity
event AgreementCreated(
    uint256 indexed agreementId,
    bytes32 kind,
    bytes32[] purpose,
    bytes32 termsHash,
    bytes32 conditions,
    address counterParty,
    uint64 revokeGracePeriodSeconds,
    RevokeEligibility revokeEligibility,
    string termsRef
);
```

Emitted when a new agreement is successfully created.

***

### Errors

| Error                             | Description                                            |
| --------------------------------- | ------------------------------------------------------ |
| `AgreementNotFound()`             | The requested agreement ID does not exist (IAgreement) |
| `Unauthorized()`                  | Caller is not authorized for the action                |
| `InvalidSignature()`              | The provided signature is invalid or from wrong signer |
| `AgreementAlreadyExists(uint256)` | An agreement with the same parameters already exists   |
| `EmptyBatchInput()`               | The batch input array is empty                         |

***

### EIP-712 Type Definition

The contract uses the following EIP-712 type for signing:

```javascript
const types = {
  AgreementData: [
    { name: "kind", type: "bytes32" },
    { name: "purpose", type: "bytes32[]" },
    { name: "termsHash", type: "bytes32" },
    { name: "conditions", type: "bytes32" },
    { name: "counterParty", type: "address" },
    { name: "revokeGracePeriodSeconds", type: "uint64" },
    { name: "revokeEligibility", type: "uint8" },
    { name: "termsRef", type: "string" },
  ],
};
```

***

### Usage Examples

#### Creating an Agreement (TypeScript/Viem)

```typescript
import { stringToHex, keccak256 } from "viem";

// RevokeEligibility enum values
const RevokeEligibility = {
  UnRevokable: 0,
  InstantlyRevokable: 1,
  RevokableAfterGracePeriod: 2,
};

// Prepare agreement data
const kind = stringToHex("data-sharing", { size: 32 });
const purpose = [stringToHex("analytics", { size: 32 }), stringToHex("marketing", { size: 32 })];
const termsHash = keccak256(stringToHex("Full terms content here"));
const conditions = stringToHex("30-day-retention", { size: 32 });
const counterParty = "0x..."; // Counterparty address
const revokeGracePeriodSeconds = 86400n; // 24 hours (only used if RevokableAfterGracePeriod)
const revokeEligibility = RevokeEligibility.InstantlyRevokable;
const termsRef = "https://example.com/terms/v1";

// Create EIP-712 typed data
const typedData = {
  domain: {
    name: "Agreement",
    version: "1",
    chainId: 1n,
    verifyingContract: agreementContractAddress,
  },
  types: {
    AgreementData: [
      { name: "kind", type: "bytes32" },
      { name: "purpose", type: "bytes32[]" },
      { name: "termsHash", type: "bytes32" },
      { name: "conditions", type: "bytes32" },
      { name: "counterParty", type: "address" },
      { name: "revokeGracePeriodSeconds", type: "uint64" },
      { name: "revokeEligibility", type: "uint8" },
      { name: "termsRef", type: "string" },
    ],
  },
  primaryType: "AgreementData",
  message: {
    kind,
    purpose,
    termsHash,
    conditions,
    counterParty,
    revokeGracePeriodSeconds,
    revokeEligibility,
    termsRef,
  },
};

// Counterparty signs
const signature = await counterPartyWallet.signTypedData(typedData);

// Create the agreement on-chain
const agreementId = await agreementContract.write.createAgreement([
  kind,
  purpose,
  termsHash,
  conditions,
  counterParty,
  revokeGracePeriodSeconds,
  revokeEligibility,
  termsRef,
  signature,
]);
```

#### Creating an UnRevokable Agreement

```typescript
// For agreements that should never be revoked
const agreementId = await agreementContract.write.createAgreement([
  kind,
  purpose,
  termsHash,
  conditions,
  counterParty,
  0n, // revokeGracePeriodSeconds not used for UnRevokable
  RevokeEligibility.UnRevokable,
  termsRef,
  signature,
]);
```

#### Creating an Agreement with Grace Period

```typescript
// For agreements that can only be revoked after a waiting period
const sevenDaysInSeconds = 7n * 24n * 60n * 60n; // 604800 seconds

const agreementId = await agreementContract.write.createAgreement([
  kind,
  purpose,
  termsHash,
  conditions,
  counterParty,
  sevenDaysInSeconds, // Must wait 7 days before consent can be revoked
  RevokeEligibility.RevokableAfterGracePeriod,
  termsRef,
  signature,
]);
```

#### Checking Revocation Eligibility

```typescript
// Get the consent record's createdAt timestamp
const consentRecord = await consentContract.read.getConsentRecord([consentRecordId]);
const createdAt = consentRecord.createdAt;

// Check if revocation is allowed
const canRevoke = await agreementContract.read.isRevokable([agreementId, createdAt]);

if (canRevoke) {
  // Proceed with revocation
} else {
  // Revocation not allowed yet (or never allowed)
}
```

#### Batch Creating Agreements

```typescript
// Prepare multiple agreement inputs
const agreementInputs = [
  {
    kind: stringToHex("data-sharing", { size: 32 }),
    purpose: [stringToHex("analytics", { size: 32 })],
    termsHash: keccak256(stringToHex("Terms 1")),
    conditions: stringToHex("condition-1", { size: 32 }),
    counterParty: counterParty1Address,
    revokeGracePeriodSeconds: 0n,
    revokeEligibility: RevokeEligibility.InstantlyRevokable,
    termsRef: "https://example.com/terms/1",
    signature: signature1,
  },
  {
    kind: stringToHex("licensing", { size: 32 }),
    purpose: [stringToHex("commercial-use", { size: 32 })],
    termsHash: keccak256(stringToHex("Terms 2")),
    conditions: stringToHex("condition-2", { size: 32 }),
    counterParty: counterParty2Address,
    revokeGracePeriodSeconds: 604800n, // 7 days
    revokeEligibility: RevokeEligibility.RevokableAfterGracePeriod,
    termsRef: "https://example.com/terms/2",
    signature: signature2,
  },
];

// Create all agreements in one transaction
const agreementIds = await agreementContract.write.batchCreateAgreements([agreementInputs]);
```

#### Reading Agreement Data

```typescript
// Get raw data
const agreementData = await agreementContract.read.getAgreementData([1n]);
console.log(agreementData.revokeEligibility); // 0, 1, or 2
console.log(agreementData.revokeGracePeriodSeconds); // Grace period in seconds

// Get human-readable data
const parsed = await agreementContract.read.getParsedAgreementData([1n]);
console.log(parsed.kind); // "data-sharing"
console.log(parsed.purpose); // ["analytics", "marketing"]
```

***

### Security Considerations

1. **Replay Protection**: Each unique agreement can only be created once via digest tracking
2. **Signature Verification**: Counterparty signatures are verified using EIP-712 ECDSA recovery
3. **Self-Signing**: If `counterParty` equals `msg.sender`, no signature verification is needed
4. **Immutability**: Once created, agreements cannot be modified or deleted
5. **Revocation Control**: The `revokeEligibility` setting is immutable and enforced by the Consent contract

***

### Related Contracts

* **IAgreement**: Interface defining AgreementData struct and core functions
* **Consent**: Creates consent records referencing agreements
* **DIDRegistry**: Manages decentralized identities for parties

***

### Deployment

The contract is deployed using Hardhat Ignition:

```typescript
// ignition/modules/Agreement.ts
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";

export default buildModule("AgreementModule", (m) => {
  const agreement = m.contract("Agreement", ["Agreement", "1"]);
  return { agreement };
});
```


# DIDRegistry

### Overview

The **DIDRegistry** contract implements a decentralized identity (DID) registry following the W3C DID specification. It enables users to register, update, and manage DID Documents on-chain with support for verification methods, services, and delegated control.

### Contract Details

| Property         | Value                          |
| ---------------- | ------------------------------ |
| Solidity Version | ^0.8.28                        |
| License          | MIT                            |
| Inheritance      | Context, EIP712 (OpenZeppelin) |
| DID Method       | `did:pkh` (Public Key Hash)    |

***

### Purpose

The DIDRegistry contract provides a complete on-chain DID management system:

* **Self-Sovereign Identity**: Users control their own DID documents
* **Delegated Control**: Authorized controllers can manage DIDs on behalf of subjects
* **Verification Methods**: Support for multiple cryptographic keys with relationship types
* **Services**: Link external services to DID documents
* **Meta-Transactions**: EIP-712 signatures enable gasless updates

***

### Data Structures

#### VerificationMethod

Represents a cryptographic key or verification method.

```solidity
struct VerificationMethod {
    string id;              // Unique identifier (e.g., "did:pkh:0x...#key-1")
    string methodType;      // Type (e.g., "EcdsaSecp256k1VerificationKey2019")
    string metadata;        // JSON string with additional properties
    address controller;     // Address that controls this method
    uint8 relationships;    // Packed bitflags for relationship types
}
```

| Field           | Type    | Description                                    |
| --------------- | ------- | ---------------------------------------------- |
| `id`            | string  | Full DID URL identifier for the method         |
| `methodType`    | string  | Cryptographic suite type                       |
| `metadata`      | string  | JSON-encoded additional properties             |
| `controller`    | address | Ethereum address of the controller             |
| `relationships` | uint8   | Bitflags indicating verification relationships |

#### Service

Represents an external service endpoint.

```solidity
struct Service {
    string id;              // Service identifier
    string serviceType;     // Type of service (e.g., "LinkedDomains")
    string serviceEndpoint; // URL or endpoint reference
}
```

| Field             | Type   | Description                     |
| ----------------- | ------ | ------------------------------- |
| `id`              | string | Unique service identifier       |
| `serviceType`     | string | Type classification             |
| `serviceEndpoint` | string | URL, URI, or JSON endpoint data |

#### DIDDocument

The complete DID Document structure.

```solidity
struct DIDDocument {
    string[] context;                       // JSON-LD @context values
    address[] controllers;                  // Addresses authorized to update
    string[] alsoKnownAs;                   // Alternative identifiers
    VerificationMethod[] verificationMethods; // Cryptographic methods
    Service[] services;                     // Service endpoints
    uint256 nonce;                          // Replay protection counter
}
```

| Field                 | Type                  | Description                           |
| --------------------- | --------------------- | ------------------------------------- |
| `context`             | string\[]             | JSON-LD context URIs                  |
| `controllers`         | address\[]            | Delegated controller addresses        |
| `alsoKnownAs`         | string\[]             | Alias identifiers                     |
| `verificationMethods` | VerificationMethod\[] | Array of verification methods         |
| `services`            | Service\[]            | Array of service endpoints            |
| `nonce`               | uint256               | Auto-incrementing counter for updates |

***

### Verification Relationships

Verification relationships are stored as packed bitflags in a `uint8`:

| Constant                | Value | Hex  | Description                                    |
| ----------------------- | ----- | ---- | ---------------------------------------------- |
| `AUTHENTICATION`        | 1     | 0x01 | Key can authenticate as the DID subject        |
| `ASSERTION`             | 2     | 0x02 | Key can make assertions/claims                 |
| `KEY_AGREEMENT`         | 4     | 0x04 | Key can be used for key agreement (encryption) |
| `CAPABILITY_INVOCATION` | 8     | 0x08 | Key can invoke capabilities                    |
| `CAPABILITY_DELEGATION` | 16    | 0x10 | Key can delegate capabilities                  |

#### Examples

| Relationships              | Value | Binary |
| -------------------------- | ----- | ------ |
| Authentication only        | 1     | 00001  |
| Authentication + Assertion | 3     | 00011  |
| Key Agreement only         | 4     | 00100  |
| All relationships          | 31    | 11111  |

***

### State Variables

| Variable                | Type                            | Visibility      | Description                        |
| ----------------------- | ------------------------------- | --------------- | ---------------------------------- |
| `DID_TYPE`              | string                          | public constant | DID method type (`"did:pkh"`)      |
| `AUTHENTICATION`        | uint8                           | public constant | Authentication bitflag (1)         |
| `ASSERTION`             | uint8                           | public constant | Assertion bitflag (2)              |
| `KEY_AGREEMENT`         | uint8                           | public constant | Key Agreement bitflag (4)          |
| `CAPABILITY_INVOCATION` | uint8                           | public constant | Capability Invocation bitflag (8)  |
| `CAPABILITY_DELEGATION` | uint8                           | public constant | Capability Delegation bitflag (16) |
| `didDocuments`          | mapping(address => DIDDocument) | internal        | DID document storage               |

***

### Functions

#### Constructor

```solidity
constructor(string memory name, string memory version)
```

Initializes the contract with EIP-712 domain parameters.

**Parameters:**

| Name      | Type   | Description                       |
| --------- | ------ | --------------------------------- |
| `name`    | string | Domain name (e.g., "DIDRegistry") |
| `version` | string | Domain version (e.g., "1")        |

***

#### Registration Functions

**registerDID**

```solidity
function registerDID(DIDDocument calldata _didDocument) external
```

Registers a new DID document for `msg.sender`.

**Parameters:**

| Name           | Type        | Description                  |
| -------------- | ----------- | ---------------------------- |
| `_didDocument` | DIDDocument | The DID document to register |

**Requirements:**

* Subject must not already have a registered DID (nonce == 0)
* Context array must not be empty

**Emits:** `DIDRegistered`

***

**registerDIDOf**

```solidity
function registerDIDOf(
    DIDDocument calldata _didDocument,
    address _didSubject,
    bytes calldata _subjectSignature
) external
```

Registers a DID on behalf of another address using their signature.

**Parameters:**

| Name                | Type        | Description                         |
| ------------------- | ----------- | ----------------------------------- |
| `_didDocument`      | DIDDocument | The DID document to register        |
| `_didSubject`       | address     | The address to register the DID for |
| `_subjectSignature` | bytes       | EIP-712 signature from the subject  |

**Requirements:**

* Signature must be from the `_didSubject`
* Subject must not already have a registered DID

**Emits:** `DIDRegistered`

***

#### Update Functions

**updateDID**

```solidity
function updateDID(
    DIDDocument calldata _didDocument,
    address _didSubject
) external
```

Updates an existing DID document.

**Parameters:**

| Name           | Type        | Description                     |
| -------------- | ----------- | ------------------------------- |
| `_didDocument` | DIDDocument | The updated DID document        |
| `_didSubject`  | address     | The address whose DID to update |

**Requirements:**

* Caller must be the subject OR a listed controller
* Provided nonce must match current stored nonce
* Context array must not be empty

**Emits:** `DIDUpdated`

***

**updateDIDOf**

```solidity
function updateDIDOf(
    DIDDocument calldata _didDocument,
    address _didSubject,
    bytes calldata _signature
) external
```

Updates a DID document using a signature from an authorized party.

**Parameters:**

| Name           | Type        | Description                                  |
| -------------- | ----------- | -------------------------------------------- |
| `_didDocument` | DIDDocument | The updated DID document                     |
| `_didSubject`  | address     | The address whose DID to update              |
| `_signature`   | bytes       | EIP-712 signature from subject or controller |

**Requirements:**

* Signer must be the subject OR a listed controller
* Provided nonce must match current stored nonce

**Emits:** `DIDUpdated`

***

#### Query Functions

**getDIDDocument**

```solidity
function getDIDDocument(address subject) public view returns (DIDDocument memory)
```

Retrieves the DID document for a given address.

**Parameters:**

| Name      | Type    | Description             |
| --------- | ------- | ----------------------- |
| `subject` | address | The DID subject address |

**Returns:** `DIDDocument` struct (empty if not registered)

***

**isController**

```solidity
function isController(address subject, address account) public view returns (bool)
```

Checks if an address is a controller for a DID.

**Parameters:**

| Name      | Type    | Description             |
| --------- | ------- | ----------------------- |
| `subject` | address | The DID subject address |
| `account` | address | The address to check    |

**Returns:** `true` if account is listed as a controller

***

#### Relationship Helper Functions

**hasRelationship**

```solidity
function hasRelationship(uint8 relationships, uint8 flag) public pure returns (bool)
```

Checks if a relationship flag is set.

**Parameters:**

| Name            | Type  | Description                                |
| --------------- | ----- | ------------------------------------------ |
| `relationships` | uint8 | The packed relationship bitflags           |
| `flag`          | uint8 | The flag to check (e.g., `AUTHENTICATION`) |

**Returns:** `true` if the flag is set

**Example:**

```solidity
// Check if key has authentication relationship
bool canAuth = registry.hasRelationship(vm.relationships, registry.AUTHENTICATION());
```

***

**addRelationship**

```solidity
function addRelationship(uint8 relationships, uint8 flag) public pure returns (uint8)
```

Adds a relationship flag.

**Parameters:**

| Name            | Type  | Description                   |
| --------------- | ----- | ----------------------------- |
| `relationships` | uint8 | Current relationship bitflags |
| `flag`          | uint8 | The flag to add               |

**Returns:** Updated relationship bitflags

***

**removeRelationship**

```solidity
function removeRelationship(uint8 relationships, uint8 flag) public pure returns (uint8)
```

Removes a relationship flag.

**Parameters:**

| Name            | Type  | Description                   |
| --------------- | ----- | ----------------------------- |
| `relationships` | uint8 | Current relationship bitflags |
| `flag`          | uint8 | The flag to remove            |

**Returns:** Updated relationship bitflags

***

#### Hashing Functions

**hashDIDDocument**

```solidity
function hashDIDDocument(DIDDocument calldata doc) public pure returns (bytes32)
```

Computes the EIP-712 struct hash for a DID document.

**getTypedDataHash**

```solidity
function getTypedDataHash(DIDDocument calldata doc) public view returns (bytes32)
```

Returns the complete EIP-712 typed data hash for signing.

***

### Events

#### DIDRegistered

```solidity
event DIDRegistered(address indexed subject);
```

Emitted when a new DID document is registered.

#### DIDUpdated

```solidity
event DIDUpdated(
    address indexed subject,
    address indexed updatedBy,
    uint256 nonce
);
```

Emitted when a DID document is updated.

| Parameter   | Description                           |
| ----------- | ------------------------------------- |
| `subject`   | The DID subject address               |
| `updatedBy` | The address that performed the update |
| `nonce`     | The new nonce value after update      |

***

### Errors

| Error                  | Description                               |
| ---------------------- | ----------------------------------------- |
| `InvalidContext()`     | Context array is empty                    |
| `InvalidControllers()` | Controllers array validation failed       |
| `InvalidSignature()`   | Signature verification failed             |
| `InvalidNonce()`       | Provided nonce doesn't match stored nonce |
| `Unauthorized()`       | Caller is not authorized to update        |
| `AlreadyRegistered()`  | DID already registered for this address   |

***

### EIP-712 Type Definitions

#### VerificationMethod

```javascript
const VerificationMethod = [
  { name: "id", type: "string" },
  { name: "methodType", type: "string" },
  { name: "controller", type: "address" },
  { name: "metadata", type: "string" },
  { name: "relationships", type: "uint8" },
];
```

#### Service

```javascript
const Service = [
  { name: "id", type: "string" },
  { name: "serviceType", type: "string" },
  { name: "serviceEndpoint", type: "string" },
];
```

#### DIDDocument

```javascript
const DIDDocument = [
  { name: "context", type: "string[]" },
  { name: "controllers", type: "address[]" },
  { name: "alsoKnownAs", type: "string[]" },
  { name: "verificationMethods", type: "VerificationMethod[]" },
  { name: "services", type: "Service[]" },
  { name: "nonce", type: "uint256" },
];
```

***

### Usage Examples

#### Registering a DID Document (TypeScript/Viem)

```typescript
// Helper function to calculate relationships
function calculateRelationships(flags: {
  authentication?: boolean;
  assertion?: boolean;
  keyAgreement?: boolean;
  capabilityInvocation?: boolean;
  capabilityDelegation?: boolean;
}): number {
  let relationships = 0;
  if (flags.authentication) relationships |= 1;
  if (flags.assertion) relationships |= 2;
  if (flags.keyAgreement) relationships |= 4;
  if (flags.capabilityInvocation) relationships |= 8;
  if (flags.capabilityDelegation) relationships |= 16;
  return relationships;
}

// Prepare DID document
const userAddress = userWallet.account.address;
const did = `did:pkh:${userAddress}`;

const didDocument = {
  context: ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/secp256k1-2019/v1"],
  controllers: [], // No delegated controllers
  alsoKnownAs: [],
  verificationMethods: [
    {
      id: `${did}#key-1`,
      methodType: "EcdsaSecp256k1VerificationKey2019",
      controller: userAddress,
      metadata: JSON.stringify({ blockchainAccountId: `eip155:1:${userAddress}` }),
      relationships: calculateRelationships({
        authentication: true,
        assertion: true,
      }),
    },
  ],
  services: [
    {
      id: `${did}#profile`,
      serviceType: "LinkedDomains",
      serviceEndpoint: "https://example.com",
    },
  ],
  nonce: 0n,
};

// Register DID
await registry.write.registerDID([didDocument], { account: userWallet.account });
```

#### Registering on Behalf of Another User

```typescript
const typedData = {
  domain: {
    name: "DIDRegistry",
    version: "1",
    chainId: 1n,
    verifyingContract: registryAddress,
  },
  types: {
    VerificationMethod: [
      { name: "id", type: "string" },
      { name: "methodType", type: "string" },
      { name: "controller", type: "address" },
      { name: "metadata", type: "string" },
      { name: "relationships", type: "uint8" },
    ],
    Service: [
      { name: "id", type: "string" },
      { name: "serviceType", type: "string" },
      { name: "serviceEndpoint", type: "string" },
    ],
    DIDDocument: [
      { name: "context", type: "string[]" },
      { name: "controllers", type: "address[]" },
      { name: "alsoKnownAs", type: "string[]" },
      { name: "verificationMethods", type: "VerificationMethod[]" },
      { name: "services", type: "Service[]" },
      { name: "nonce", type: "uint256" },
    ],
  },
  primaryType: "DIDDocument",
  message: didDocument,
};

// Subject signs the document
const signature = await subjectWallet.signTypedData(typedData);

// Relayer submits the transaction
await registry.write.registerDIDOf([didDocument, subjectAddress, signature], {
  account: relayerWallet.account,
});
```

#### Updating with Delegated Controller

```typescript
// Original registration includes controller
const docWithController = {
  ...didDocument,
  controllers: [controllerAddress],
};
await registry.write.registerDID([docWithController], { account: userWallet.account });

// Controller can now update (nonce is 1 after registration)
const updatedDoc = {
  ...didDocument,
  context: ["https://www.w3.org/ns/did/v1", "https://example.com/custom-context"],
  controllers: [controllerAddress],
  nonce: 1n, // Must match current nonce
};

await registry.write.updateDID([updatedDoc, userAddress], {
  account: controllerWallet.account,
});
```

#### Reading and Decoding a DID Document

```typescript
const storedDoc = await registry.read.getDIDDocument([userAddress]);

// Check if registered
const isRegistered = storedDoc.nonce > 0n;

// Parse verification method metadata
const vm = storedDoc.verificationMethods[0];
const metadata = JSON.parse(vm.metadata);

// Check relationships
const AUTHENTICATION = 1;
const ASSERTION = 2;
const hasAuth = (vm.relationships & AUTHENTICATION) !== 0;
const hasAssertion = (vm.relationships & ASSERTION) !== 0;
```

***

### W3C DID Document Mapping

The contract's structures map to W3C DID Document format:

| W3C Property           | Contract Field          | Notes                            |
| ---------------------- | ----------------------- | -------------------------------- |
| `@context`             | `context`               | Array of context URIs            |
| `id`                   | N/A (mapping key)       | Derived from `did:pkh:{address}` |
| `controller`           | `controllers`           | Array of controller addresses    |
| `alsoKnownAs`          | `alsoKnownAs`           | Alternative identifiers          |
| `verificationMethod`   | `verificationMethods`   | Array of methods                 |
| `authentication`       | `relationships` bitflag | Derived from bitflag             |
| `assertionMethod`      | `relationships` bitflag | Derived from bitflag             |
| `keyAgreement`         | `relationships` bitflag | Derived from bitflag             |
| `capabilityInvocation` | `relationships` bitflag | Derived from bitflag             |
| `capabilityDelegation` | `relationships` bitflag | Derived from bitflag             |
| `service`              | `services`              | Array of services                |

#### Example: JSON-LD to Solidity Encoding

**W3C JSON-LD Format:**

```json
{
  "@context": ["https://www.w3.org/ns/did/v1"],
  "id": "did:pkh:0x1234...",
  "verificationMethod": [
    {
      "id": "did:pkh:0x1234...#key-1",
      "type": "EcdsaSecp256k1VerificationKey2019",
      "controller": "did:pkh:0x1234...",
      "blockchainAccountId": "eip155:1:0x1234..."
    }
  ],
  "authentication": ["did:pkh:0x1234...#key-1"],
  "assertionMethod": ["did:pkh:0x1234...#key-1"]
}
```

**Solidity Struct Encoding:**

```typescript
{
  context: ["https://www.w3.org/ns/did/v1"],
  controllers: [],
  alsoKnownAs: [],
  verificationMethods: [{
    id: "did:pkh:0x1234...#key-1",
    methodType: "EcdsaSecp256k1VerificationKey2019",
    controller: "0x1234...",
    metadata: '{"blockchainAccountId":"eip155:1:0x1234..."}',
    relationships: 3  // AUTHENTICATION (1) | ASSERTION (2)
  }],
  services: [],
  nonce: 0n
}
```

***

### Security Considerations

1. **Nonce Protection**: Each update increments the nonce, preventing replay attacks
2. **Controller Authorization**: Only subject or listed controllers can update
3. **Signature Verification**: Meta-transactions verified via EIP-712 ECDSA recovery
4. **Context Validation**: Empty context arrays are rejected
5. **Immutable Registration**: DID cannot be re-registered once created

***

### Related Contracts

* **Agreement**: Uses DIDs for party identification
* **Consent**: Links consent records to DID-identified suppliers

***

### Deployment

The contract is deployed using Hardhat Ignition:

```typescript
// ignition/modules/DIDRegistry.ts
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";

const DOMAIN_NAME = "DIDRegistry";
const DOMAIN_VERSION = "1";

export default buildModule("DIDRegistryModule", (m) => {
  const didRegistry = m.contract("DIDRegistry", [DOMAIN_NAME, DOMAIN_VERSION]);

  return { didRegistry };
});
```


# Consent

### Overview

The **Consent** contract manages individual user consents linked to agreements in the Permission Protocol. It enables users (data suppliers) to create, revoke, and extend consent records through cryptographically signed actions.

### Contract Details

| Property         | Value                 |
| ---------------- | --------------------- |
| Solidity Version | ^0.8.28               |
| License          | MIT                   |
| Inheritance      | EIP712 (OpenZeppelin) |
| Dependencies     | IAgreement interface  |

***

### Purpose

The Consent contract provides a complete lifecycle management system for user consents:

* **Create Consent**: Users grant consent to an existing agreement
* **Revoke Consent**: Users can revoke their consent (based on agreement's revocation rules)
* **Extend Validity**: Users can extend the expiration of their consent
* **Batch Operations**: Create multiple consent records in a single transaction

All operations require EIP-712 signatures from the data supplier, enabling gasless (meta-transaction) patterns.

***

### Data Structures

#### ConsentRecord

The primary structure for storing consent details.

```solidity
struct ConsentRecord {
    uint256 agreementId;     // Reference to the parent Agreement ID
    IAgreement agreement;    // Reference to the Agreement contract
    uint64 createdAt;        // Timestamp when consent was created
    address supplier;        // Data supplier (user giving consent)
    uint64 validityEnd;      // Unix timestamp when consent expires (0 = never)
    uint16 nonce;            // Replay protection for modifications
    bool disclosed;          // Whether data is publicly disclosed
    string dataRef;          // Reference to the data (IPFS/URL)
    string revocationRef;    // Reason/reference if revoked (empty = active)
}
```

| Field           | Type       | Description                                            |
| --------------- | ---------- | ------------------------------------------------------ |
| `agreementId`   | uint256    | ID of the associated Agreement                         |
| `agreement`     | IAgreement | Reference to the Agreement contract                    |
| `createdAt`     | uint64     | Timestamp when consent was created (for revoke checks) |
| `supplier`      | address    | Address of the data supplier                           |
| `validityEnd`   | uint64     | Expiration timestamp (0 = never expires)               |
| `nonce`         | uint16     | Counter for replay protection on updates               |
| `disclosed`     | bool       | If `true`, data is publicly accessible                 |
| `dataRef`       | string     | IPFS hash or URL pointing to the data                  |
| `revocationRef` | string     | Revocation reason (empty if not revoked)               |

#### ConsentRecordInput

Input structure for batch consent record creation.

```solidity
struct ConsentRecordInput {
    uint256 agreementId;     // The associated agreement ID
    IAgreement agreement;    // The agreement contract
    address supplier;        // The supplier address (signer)
    uint64 validityEnd;      // The validity expiration timestamp
    bool disclosed;          // Whether the data is disclosed
    string dataRef;          // Reference to the data
    bytes32 r;               // The 'r' component of the signature
    bytes32 vs;              // The 'vs' component of the signature
}
```

***

### State Variables

| Variable               | Type                              | Visibility | Description                                  |
| ---------------------- | --------------------------------- | ---------- | -------------------------------------------- |
| `consentRecordCounter` | uint256                           | public     | Counter for unique consent IDs (starts at 1) |
| `usedDigests`          | mapping(bytes32 => uint256)       | public     | Tracks used EIP-712 digests                  |
| `consentRecords`       | mapping(uint256 => ConsentRecord) | public     | Storage of consent records                   |

***

### Functions

#### Constructor

```solidity
constructor(
    string memory name,
    string memory version
)
```

Initializes the contract with EIP-712 domain parameters.

**Parameters:**

| Name      | Type   | Description                   |
| --------- | ------ | ----------------------------- |
| `name`    | string | Domain name (e.g., "Consent") |
| `version` | string | Domain version (e.g., "1")    |

***

#### createConsentRecord

```solidity
function createConsentRecord(
    uint256 agreementId,
    IAgreement agreement,
    address supplier,
    uint64 validityEnd,
    bool disclosed,
    string calldata dataRef,
    bytes32 r,
    bytes32 vs
) external returns (uint256 consentRecordId)
```

Creates a new consent record with supplier signature verification.

**Parameters:**

| Name          | Type       | Description                               |
| ------------- | ---------- | ----------------------------------------- |
| `agreementId` | uint256    | ID of the parent agreement                |
| `agreement`   | IAgreement | The Agreement contract reference          |
| `supplier`    | address    | Address of the data supplier (signer)     |
| `validityEnd` | uint64     | Expiration timestamp (0 = never expires)  |
| `disclosed`   | bool       | Public disclosure flag                    |
| `dataRef`     | string     | Reference to the data                     |
| `r`           | bytes32    | ECDSA signature component r               |
| `vs`          | bytes32    | ECDSA compact signature component (v + s) |

**Returns:**

| Name              | Type    | Description                          |
| ----------------- | ------- | ------------------------------------ |
| `consentRecordId` | uint256 | The unique ID of the created consent |

**Requirements:**

* Referenced agreement must exist
* Signature must be from the supplier
* Consent with same parameters cannot already exist

**Effects:**

* Sets `createdAt` to the current block timestamp

**Emits:** `ConsentRecordCreated`

***

#### batchCreateConsentRecords

```solidity
function batchCreateConsentRecords(
    ConsentRecordInput[] calldata inputs
) external returns (uint256[] memory consentRecordIds)
```

Creates multiple consent records in a single transaction.

**Parameters:**

| Name     | Type                  | Description                    |
| -------- | --------------------- | ------------------------------ |
| `inputs` | ConsentRecordInput\[] | Array of consent record inputs |

**Returns:**

| Name               | Type       | Description                         |
| ------------------ | ---------- | ----------------------------------- |
| `consentRecordIds` | uint256\[] | Array of created consent record IDs |

**Requirements:**

* Input array must not be empty

**Emits:** `ConsentRecordCreated` for each consent record

***

#### revokeConsentRecord

```solidity
function revokeConsentRecord(
    uint256 consentRecordId,
    string calldata revocationRef,
    uint16 nonce,
    bytes32 r,
    bytes32 vs
) external
```

Revokes an existing consent record.

**Parameters:**

| Name              | Type    | Description                         |
| ----------------- | ------- | ----------------------------------- |
| `consentRecordId` | uint256 | ID of the consent to revoke         |
| `revocationRef`   | string  | Reason or reference for revocation  |
| `nonce`           | uint16  | Current nonce of the consent record |
| `r`               | bytes32 | ECDSA signature component r         |
| `vs`              | bytes32 | ECDSA compact signature component   |

**Requirements:**

* Agreement must allow revocation (`agreement.isRevokable()` returns true)
* Nonce must match current consent record nonce
* Signature must be from the original supplier
* Revocation reference cannot be empty
* Consent must not already be revoked

**Emits:** `ConsentRecordRevoked`

**Effects:**

* Sets `revocationRef` to the provided value
* Increments `nonce` by 1

***

#### extendValidity

```solidity
function extendValidity(
    uint256 consentRecordId,
    uint64 newValidityEnd,
    uint16 nonce,
    bytes32 r,
    bytes32 vs
) external
```

Extends the validity period of a consent record.

**Parameters:**

| Name              | Type    | Description                         |
| ----------------- | ------- | ----------------------------------- |
| `consentRecordId` | uint256 | ID of the consent to extend         |
| `newValidityEnd`  | uint64  | New expiration timestamp            |
| `nonce`           | uint16  | Current nonce of the consent record |
| `r`               | bytes32 | ECDSA signature component r         |
| `vs`              | bytes32 | ECDSA compact signature component   |

**Requirements:**

* Nonce must match current consent record nonce
* New validity must be greater than current validity
* Current validity cannot be 0 (consents with no expiry cannot be extended)
* Consent must not be revoked
* Signature must be from the original supplier

**Emits:** `ConsentRecordValidityExtended`

**Effects:**

* Updates `validityEnd` to new value
* Increments `nonce` by 1

***

#### getConsentRecord

```solidity
function getConsentRecord(uint256 consentRecordId) public view returns (ConsentRecord memory)
```

Retrieves a consent record by ID.

**Parameters:**

| Name              | Type    | Description                   |
| ----------------- | ------- | ----------------------------- |
| `consentRecordId` | uint256 | The consent record identifier |

**Returns:** `ConsentRecord` struct

**Reverts:** `ConsentRecordNotFound` if record doesn't exist

***

#### Hash Functions

**hashConsentRecord**

```solidity
function hashConsentRecord(
    uint256 agreementId,
    address agreement,
    address supplier,
    uint64 validityEnd,
    bool disclosed,
    string calldata dataRef
) public pure returns (bytes32)
```

Computes the EIP-712 struct hash for consent record creation.

**getTypedDataHash**

```solidity
function getTypedDataHash(
    uint256 agreementId,
    address agreement,
    address supplier,
    uint64 validityEnd,
    bool disclosed,
    string calldata dataRef
) public view returns (bytes32)
```

Returns the complete EIP-712 typed data hash for signing.

***

### Events

#### ConsentRecordCreated

```solidity
event ConsentRecordCreated(
    uint256 consentRecordId,
    uint256 indexed agreementId,
    IAgreement indexed agreement,
    address indexed supplier,
    uint64 validityEnd,
    bool disclosed,
    string dataRef,
    bytes32 r,
    bytes32 vs
);
```

Emitted when a new consent record is created. Includes the agreement contract reference and signature components for verification.

#### ConsentRecordRevoked

```solidity
event ConsentRecordRevoked(
    uint256 indexed consentRecordId,
    string revocationRef,
    uint16 nonce
);
```

Emitted when a consent record is revoked.

#### ConsentRecordValidityExtended

```solidity
event ConsentRecordValidityExtended(
    uint256 indexed consentRecordId,
    uint64 newValidityEnd,
    uint16 nonce
);
```

Emitted when consent validity is extended.

***

### Errors

| Error                                 | Description                                       |
| ------------------------------------- | ------------------------------------------------- |
| `ConsentRecordAlreadyExists(uint256)` | A consent with the same parameters already exists |
| `InvalidSignature()`                  | The provided signature is invalid                 |
| `InvalidRevocationRef()`              | The revocation reference is empty                 |
| `InvalidNonce()`                      | The provided nonce doesn't match                  |
| `InvalidNewValidityEnd()`             | New validity is not greater than current          |
| `ConsentRecordNotFound()`             | The requested consent ID does not exist           |
| `EmptyBatchInput()`                   | The batch input array is empty                    |
| `ConsentRecordAlreadyRevoked()`       | The consent record has already been revoked       |
| `RevokeFailed()`                      | Revocation not allowed by agreement's rules       |

***

### EIP-712 Type Definitions

The contract uses multiple EIP-712 types for different operations:

#### ConsentRecord (for creation)

```javascript
const types = {
  ConsentRecord: [
    { name: "agreementId", type: "uint256" },
    { name: "agreement", type: "address" },
    { name: "supplier", type: "address" },
    { name: "validityEnd", type: "uint64" },
    { name: "disclosed", type: "bool" },
    { name: "dataRef", type: "string" },
  ],
};
```

#### RevokeRecord (for revocation)

```javascript
const types = {
  RevokeRecord: [
    { name: "consentRecordId", type: "uint256" },
    { name: "revocationRef", type: "string" },
    { name: "nonce", type: "uint16" },
  ],
};
```

#### ExtendValidityRecord (for extension)

```javascript
const types = {
  ExtendValidityRecord: [
    { name: "consentRecordId", type: "uint256" },
    { name: "newValidityEnd", type: "uint64" },
    { name: "nonce", type: "uint16" },
  ],
};
```

***

### Usage Examples

#### Creating a Consent Record (TypeScript/Viem)

```typescript
import { parseSignature, signatureToCompactSignature } from "viem";

// Prepare consent data
const agreementContract = "0x..."; // Agreement contract address
const agreementId = 1n;
const supplier = supplierWallet.account.address;
const dataRef = "ipfs://QmXxx...";
const validityEnd = BigInt(Math.floor(Date.now() / 1000) + 30 * 24 * 3600); // 30 days
const disclosed = true;

// Create EIP-712 typed data
const typedData = {
  domain: {
    name: "Consent",
    version: "1",
    chainId: 1n,
    verifyingContract: consentContractAddress,
  },
  types: {
    ConsentRecord: [
      { name: "agreementId", type: "uint256" },
      { name: "agreement", type: "address" },
      { name: "supplier", type: "address" },
      { name: "validityEnd", type: "uint64" },
      { name: "disclosed", type: "bool" },
      { name: "dataRef", type: "string" },
    ],
  },
  primaryType: "ConsentRecord",
  message: {
    agreementId,
    agreement: agreementContract,
    supplier,
    validityEnd,
    disclosed,
    dataRef,
  },
};

// Sign with supplier wallet
const signature = await supplierWallet.signTypedData(typedData);
const parsedSig = parseSignature(signature);
const compactSig = signatureToCompactSignature(parsedSig);

// Create consent record on-chain
const consentId = await consentContract.write.createConsentRecord([
  agreementId,
  agreementContract,
  supplier,
  validityEnd,
  disclosed,
  dataRef,
  compactSig.r,
  compactSig.yParityAndS,
]);
```

#### Batch Creating Consent Records

```typescript
// Prepare multiple consent record inputs
const consentInputs = [
  {
    agreementId: 1n,
    agreement: agreementContractAddress,
    supplier: supplier1Address,
    validityEnd: validityEnd1,
    disclosed: true,
    dataRef: "ipfs://QmAbc...",
    r: compactSig1.r,
    vs: compactSig1.yParityAndS,
  },
  {
    agreementId: 2n,
    agreement: agreementContractAddress,
    supplier: supplier2Address,
    validityEnd: validityEnd2,
    disclosed: false,
    dataRef: "ipfs://QmDef...",
    r: compactSig2.r,
    vs: compactSig2.yParityAndS,
  },
];

// Create all consent records in one transaction
const consentIds = await consentContract.write.batchCreateConsentRecords([consentInputs]);
```

#### Revoking a Consent Record

```typescript
const consentRecordId = 1n;
const revocationRef = "User requested data deletion";
const nonce = 0; // Current nonce from getConsentRecord

const revokeTypedData = {
  domain: {
    name: "Consent",
    version: "1",
    chainId: 1n,
    verifyingContract: consentContractAddress,
  },
  types: {
    RevokeRecord: [
      { name: "consentRecordId", type: "uint256" },
      { name: "revocationRef", type: "string" },
      { name: "nonce", type: "uint16" },
    ],
  },
  primaryType: "RevokeRecord",
  message: {
    consentRecordId,
    revocationRef,
    nonce,
  },
};

const signature = await supplierWallet.signTypedData(revokeTypedData);
const parsedSig = parseSignature(signature);
const compactSig = signatureToCompactSignature(parsedSig);

// Note: This will fail if the agreement doesn't allow revocation
await consentContract.write.revokeConsentRecord([
  consentRecordId,
  revocationRef,
  nonce,
  compactSig.r,
  compactSig.yParityAndS,
]);
```

#### Extending Validity

```typescript
const consentRecordId = 1n;
const newValidityEnd = BigInt(Math.floor(Date.now() / 1000) + 60 * 24 * 3600); // 60 days
const nonce = 0; // Current nonce

const extendTypedData = {
  domain: {
    name: "Consent",
    version: "1",
    chainId: 1n,
    verifyingContract: consentContractAddress,
  },
  types: {
    ExtendValidityRecord: [
      { name: "consentRecordId", type: "uint256" },
      { name: "newValidityEnd", type: "uint64" },
      { name: "nonce", type: "uint16" },
    ],
  },
  primaryType: "ExtendValidityRecord",
  message: {
    consentRecordId,
    newValidityEnd,
    nonce,
  },
};

const signature = await supplierWallet.signTypedData(extendTypedData);
const parsedSig = parseSignature(signature);
const compactSig = signatureToCompactSignature(parsedSig);

await consentContract.write.extendValidity([
  consentRecordId,
  newValidityEnd,
  nonce,
  compactSig.r,
  compactSig.yParityAndS,
]);
```

#### Checking Consent Status

```typescript
const record = await consentContract.read.getConsentRecord([1n]);

// Check if revoked
const isRevoked = record.revocationRef !== "";

// Check if expired (validityEnd of 0 means never expires)
const now = BigInt(Math.floor(Date.now() / 1000));
const isExpired = record.validityEnd > 0n && now > record.validityEnd;

// Check if active
const isActive = !isRevoked && !isExpired;

// Access consent information
const agreementAddress = record.agreement;
const agreementId = record.agreementId;
const createdAt = record.createdAt;
```

#### Checking if Revocation is Allowed

```typescript
// Before attempting to revoke, check if the agreement allows it
const record = await consentContract.read.getConsentRecord([consentRecordId]);
const canRevoke = await agreementContract.read.isRevokable([
  record.agreementId,
  record.createdAt,
]);

if (!canRevoke) {
  // Check the agreement's revokeEligibility to understand why
  const agreementData = await agreementContract.read.getAgreementData([record.agreementId]);
  
  if (agreementData.revokeEligibility === 0) { // UnRevokable
    console.log("This consent cannot be revoked");
  } else if (agreementData.revokeEligibility === 2) { // RevokableAfterGracePeriod
    const gracePeriodEnd = record.createdAt + agreementData.revokeGracePeriodSeconds;
    console.log(`Revocation allowed after: ${new Date(Number(gracePeriodEnd) * 1000)}`);
  }
}
```

***

### Consent Lifecycle

```
┌─────────────┐
│   Created   │ ──── nonce: 0, createdAt: block.timestamp
└──────┬──────┘
       │
       ▼
┌─────────────┐     ┌─────────────┐
│   Active    │◄────│  Extended   │ ──── nonce: n+1
└──────┬──────┘     └─────────────┘
       │
       ▼ (if agreement allows)
┌─────────────┐
│   Revoked   │ ──── nonce: n+1 (permanent)
└─────────────┘
```

**Note:** Unlike previous versions, revocation is now permanent. Once a consent is revoked, it cannot be restored (undoRevocation has been removed).

***

### Revocation Rules

The ability to revoke a consent record depends on the parent agreement's `revokeEligibility` setting:

| RevokeEligibility               | Can Revoke?                                       |
| ------------------------------- | ------------------------------------------------- |
| `UnRevokable` (0)               | Never - `revokeConsentRecord` will always fail    |
| `InstantlyRevokable` (1)        | Always - can revoke immediately after creation    |
| `RevokableAfterGracePeriod` (2) | Only after `createdAt + revokeGracePeriodSeconds` |

The Consent contract calls `agreement.isRevokable(agreementId, createdAt)` to verify revocation eligibility before allowing the revoke operation.

***

### Security Considerations

1. **Compact Signatures**: Uses EIP-2098 compact signatures (r, vs) for gas efficiency
2. **Nonce Protection**: Each modification increments the nonce, preventing replay attacks
3. **Supplier Authorization**: Only the original supplier can modify their consent
4. **Agreement Validation**: Consent can only be created for existing agreements (verified by calling `getAgreementData`)
5. **Revocation Control**: Revocation eligibility is enforced by the parent Agreement contract
6. **Digest Tracking**: Prevents duplicate consent records with identical parameters
7. **Flexible Agreement Reference**: Each consent stores a reference to its Agreement contract, allowing consents to reference agreements from different Agreement contract deployments
8. **Timestamp Recording**: `createdAt` is recorded for grace period calculations

***

### Related Contracts

* **Agreement**: Parent contract that defines consent terms and revocation rules
* **IAgreement**: Interface for Agreement contract
* **DIDRegistry**: Identity management for suppliers

***

### Deployment

The contract is deployed using Hardhat Ignition:

```typescript
// ignition/modules/Consent.ts
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
import Agreement from "./Agreement.js";

const DOMAIN_NAME = "Consent";
const DOMAIN_VERSION = "1";

export default buildModule("ConsentModule", (m) => {
  const { agreement } = m.useModule(Agreement);
  const consent = m.contract("Consent", [DOMAIN_NAME, DOMAIN_VERSION], { after: [agreement] });

  return { consent };
});
```


# Subgraph

Coming Soon

| **Feature**            | **Description**                                                                                                                        |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| **Deployed Contracts** | Access the subgraph for the deployed contracts on the testnet.                                                                         |
| **Access Link**        | [Subgraph Access](https://api.goldsky.com/api/public/project_cmj6unnfxt1dv01uh7emp4jif/subgraphs/permission-protocol-testnet/1.0.8/gn) |


# MCP Protocol

Permission Protocol MCP Server Example

## MCP Integration

The Permission Protocol SDK includes a built-in [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server, enabling AI agents to interact with blockchain-based permissions, consents, and identities.

### What is MCP?

MCP is an open protocol that standardizes how AI applications connect to external data sources and tools. Think of it as a universal adapter that lets AI agents:

* Query blockchain data (agreements, consents, DIDs)
* Resolve Web3 identities
* Access Permission Protocol without custom integrations

### Starting the Server

There are two ways to start the MCP server:

#### Option 1: Command Line

Run directly with Bun from the project root:

```bash
bun run src/mcp/start.ts
```

This starts the server with default settings on `http://localhost:3000/mcp`.

#### Option 2: Programmatic

Import and call `startMcpServer` in your own code for custom configuration:

```typescript
import { startMcpServer } from "@permission-io/protocol-sdk/mcp";

startMcpServer({
  rpcUrl: "https://sepolia.base.org", // Custom RPC (optional)
  chainId: 84532, // Base Sepolia
  port: 3000, // Server port
});
```

#### Configuration Options

| Option    | Default    | Description               |
| --------- | ---------- | ------------------------- |
| `rpcUrl`  | Public RPC | Blockchain RPC endpoint   |
| `chainId` | `84532`    | Network ID (Base Sepolia) |
| `port`    | `3000`     | HTTP server port          |

### Available Tools

#### Identity

| Tool               | Description                      | Input                 |
| ------------------ | -------------------------------- | --------------------- |
| `get_address_did`  | Convert wallet address to DID    | `address` (0x...)     |
| `get_did_document` | Fetch on-chain DID document      | `did` (did:pkh:0x...) |
| `get_web3_domain`  | Resolve .ASK domain from address | `address` (0x...)     |

#### Agreements

| Tool                    | Description               | Input                    |
| ----------------------- | ------------------------- | ------------------------ |
| `get_agreements_by_did` | Get user's agreements     | `did` or `walletAddress` |
| `get_agreement_data`    | Get agreement by ID       | `agreementId`            |
| `get_agreements_count`  | Total agreements on-chain | —                        |

#### Consents

| Tool                           | Description               | Input                    |
| ------------------------------ | ------------------------- | ------------------------ |
| `get_consent_proofs_by_did`    | Get user's consent proofs | `did` or `walletAddress` |
| `get_consent_record_data`      | Get consent record by ID  | `consentRecordId`        |
| `get_consent_records_count`    | Total consent records     | —                        |
| `is_consent_records_revokable` | Check revokability        | `consentRecordIds[]`     |

### Integration Examples

#### Google ADK (Python)

```python
from google.adk.agents import LlmAgent
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset, McpToolsetConfig

config = McpToolsetConfig(
    streamable_http_connection_params=StreamableHTTPConnectionParams(
        url="http://localhost:3000/mcp"
    )
)

toolset = MCPToolset.from_config(config=config, config_abs_path="")

agent = LlmAgent(
    model="gemini-2.0-flash",
    name="permission_agent",
    instruction="Query Permission Protocol for consents and agreements.",
    tools=[toolset]
)
```

#### Claude Desktop

Add to your Claude Desktop config (`claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "permission-protocol": {
      "command": "bun",
      "args": ["run", "/path/to/permission-protocol-sdk/src/mcp/start.ts"]
    }
  }
}
```

#### Custom HTTP Client

```typescript
const response = await fetch("http://localhost:3000/mcp", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    jsonrpc: "2.0",
    method: "tools/call",
    params: {
      name: "get_agreement_data",
      arguments: { agreementId: 1 },
    },
    id: 1,
  }),
});
```

### Example Queries

Once connected, AI agents can answer questions like:

| User Query                                | Tool Used                      |
| ----------------------------------------- | ------------------------------ |
| "What agreements has 0x123... created?"   | `get_agreements_by_did`        |
| "Show me consent record #5"               | `get_consent_record_data`      |
| "What's the DID for this wallet?"         | `get_address_did`              |
| "Can consent records 1, 2, 3 be revoked?" | `is_consent_records_revokable` |
| "What's the web3 domain for 0xabc...?"    | `get_web3_domain`              |

### Limitations**Read-Only**: The MCP server only exposes read operations. Creating agreements or consents requires wallet signing via the SDK directly.

* **Supported Chain**: Base Sepolia (`84532`) only. Base mainnet contracts coming soon.
* **Address Format**: Must be valid Ethereum addresses (`0x` + 40 hex chars)
* **DID Format**: Must follow `did:pkh:0x...` format
* **Indexer Delay**: Graph-based queries may have slight delays after on-chain transactions


# Get Started With Our Testing Opportunities


# Become a Founding Family

Permission Founding Families is a research and test program for parents of kids ages 4–17 who want **peace of mind** through clearer visibility, better conversations, and healthier digital habits around screens, social media, and AI — **without surveillance, constant conflict, or guesswork**.

Built for modern families, Permission helps parents stay involved and informed while empowering kids to build responsibility and trust.

We’re inviting a small group of families to shape and test our early platform and help us build something that fundamentally changes how families navigate digital life — **shifting from monitoring and enforcement to guidance, incentives, and shared understanding**.

👉 Apply to join the program: [Take the screening survey](https://docs.google.com/forms/d/e/1FAIpQLSe6v-ZwV1sdAbtNhrS5-CjFu1VqUkh9stFiZn3xJId1Ko50MA/viewform?usp=header).

### The Problem We’re Solving

Digital life is raising kids faster than parents can adapt.

Parents today face:

* Endless apps, platforms, and algorithms
* Conflicting advice about screen time and safety
* Tools that either spy, block, or punish — creating secrecy and tension
* Very little help understanding patterns, emotions, or when to step in

**Most tools focus on control**. **Most kids respond with avoidance**.

Permission was created to break that cycle. **It exists to help parents lead — not chase — their child’s digital life.**

### What Permission Does (In Plain English)

Permission helps parents stay meaningfully connected to their child’s digital world — without having to directly read messages or invade privacy.

Instead of monitoring content, **Permission provides an AI partner for parents** that:

* Surfaces privacy-respecting signals about time, tone, routines, and patterns
* Highlights changes that matter, not noise
* Helps parents know when and how to start conversations
* Encourages collaboration instead of conflict

Equally important, Permission gives kids a positive reason to participate — not hide — by aligning healthy digital behavior with clear expectations and meaningful rewards.

Think of Permission as a calm, informed partner that helps you parent the digital side of childhood.\
\
*Want to understand how Permission motivates kids and teaches healthy digital habits?* → [**Learn more about how Permission works**](/permission-founding-families/a-platform-built-on-trust)**.**&#x20;

### What Is the Permission Founding Families Program?

Permission Founding Families is an early access research program designed to validate and shape the parent experience before launch, and it will continue after the product goes live.

You’ll be reviewing the product to help us answer critical questions like:

* What are your top concerns about your child's online activity?
* Is there value in having an AI partner that is dedicated to bringing you visibility over your child's digital world?
* Is the experience intuitive?
* Do the insights feel useful and actionable?
* Does this strengthen trust rather than tension?
* Does this feel supportive — not intrusive?

As a Founding Family, your input will directly influence product decisions, tone, and priorities — not just bug fixes.

### What You’ll Be Asked to Do

Research and Testing period: from February, 17 2026.

During this time, you’ll review:

* The parent onboarding experience
* The parent parent dashboard
* Weekly insights and highlights
* Samples of educational content
* How our rewards system works between parents and children
* Provide feedback via surveys and interviews (if selected)

You can complete everything at your own pace.

<figure><img src="/files/jhuy2Q1X8lwFZkZJIZ6W" alt=""><figcaption></figcaption></figure>

### Rewards for Participating

We value your time and insight.

Complete the tests + all program surveys\
→ $25 gift card

Provide high-quality written feedback\
→ Additional $25 gift card

Optional 15-minute interview (by invitation)\
→ Additional $25 gift card

### Founding Families ASK Grant

As a thank-you for helping us shape Permission from the beginning, **Founding Families who complete the program will receive 5,000 ASK.**

**Founding Families will be among the first parents to use ASK in a real family setting.**

### Who Should Apply

You’re a great fit if you:

* Are a parent of a child ages 4–17
* Live in the US
* Feel overwhelmed by digital parenting decisions
* Want tools that support conversation — not control
* Care about privacy, trust, and long-term digital habits
* Want to help define a healthier, more effective, more human approach to parenting in the AI era.&#x20;

👉 Apply here to become a Permission Founding Family: [Take the screening survey](https://docs.google.com/forms/d/e/1FAIpQLSe6v-ZwV1sdAbtNhrS5-CjFu1VqUkh9stFiZn3xJId1Ko50MA/viewform?usp=header).

<br>


# A Platform Built on Trust

**Your Values. Your Boundaries.**&#x20;

Permission is a privacy-first AI platform that helps parents stay informed and engaged in their child’s digital life — without surveillance or intrusion.

Our mission is to help parents educate and guide their children as they grow up online with clarity and confidence, fostering connection, responsibility and trust.

We don’t replace your parenting. **We strengthen it**.

Permission supports families navigating:

* Screen time and online routines
* Emotional wellbeing in digital spaces
* Social media and gaming dynamics
* Healthy boundaries, habits, and conversations

All without reading messages, tracking content, or spying.

### How Permission Is Different

Most digital parenting tools are built around on:

* Blocking
* Monitoring
* Punishment
* Control

Permission takes a fundamentally different approach. We focus on:

* Understanding, not surveillance,&#x20;
* Patterns, not isolated incidents
* Timing, not constant intervention
* Connection, not control

Instead of just blocking or monitoring content, we use derived, privacy-respecting signals — not private messages — to help parents notice:

* Shifts in routines or engagement
* Changes in tone or behavior over time
* Patterns that may signal stress, isolation, or overuse

This allows parents to respond early, calmly, and thoughtfully - **before problems escalate and without breaking trust**.&#x20;

### Built for Collaboration, Not Secrecy

Permission is designed to be transparent and collaborative — not hidden or punitive.

Children know:

* What the platform does
* What it does *not* do
* How rewards, goals, and expectations work

This transparency:

* Reduces secrecy
* Builds trust
* Turns digital challenges into shared problem-solving moments

### Motivating Healthy Behavior — Not Just Observing It

Permission doesn’t just help parents *see* patterns. It helps families **shape better ones**.

Children are motivated through a rewards-based system that reinforces:

* Healthy screen routines
* Following family agreements
* Positive online behavior
* Open communication

This gives kids a **positive reason to participate**, rather than hide — and gives parents a constructive alternative to punishment, restriction, or constant enforcement.

### Teaching Responsibility Through Rewards

Digital life already runs on incentives — likes, points, streaks, levels.

Permission uses that reality **intentionally and responsibly**.

By aligning rewards with healthy behavior and clear expectations, Permission helps children:

* Understand cause and effect in digital spaces
* Practice self-regulation
* Build long-term habits, not short-term compliance

Rewards aren’t about control.\
They’re about **learning, agency, and trust**.

### What Is ASK?

<figure><img src="/files/4vu0zP8s81xLDNxQUBbL" alt=""><figcaption></figcaption></figure>

#### ASK: A Modern, Safe Digital Reward System

Permission is powered by ASK, a digital reward token designed to teach responsibility, consent, and value in a way kids already understand.

Think of ASK like Robux, V-Bucks, Points, Stars or gems…but grounded in real-world rules set by parents.

### How ASK Works

Children earn ASK by:

* Practicing healthy digital habits
* Completing missions or goals
* Following family agreements
* Demonstrating positive behavior

ASK is:

* Safe
* Parent-controlled
* Transparent

Parents decide:

* How ASK is earned
* What ASK can be redeemed for
* Whether ASK is saved, spent, or simply tracked as points

Through ASK, children learn:

* That digital behavior has consequences
* How rewards and incentives work
* The basics of privacy, consent, and value

All in an age-appropriate, guided way.

### A Healthier Model for the AI Era

The internet shouldn’t parent your kids.\
\
**You should.**

Permission helps parents stay at the center of digital decision-making — while helping children grow into confident, responsible participants in the modern digital world.


# Welcome to Permission Founding Families

Thank you for joining Permission Founding Families. Your feedback will directly shape how we support parents and improve children’s digital lives.

### What This Test Is About

This testing round focuses on validating the parent experience.

Your feedback will help us:

* Validate onboarding clarity
* Assess the usefulness of insights
* Evaluate educational content
* Identify friction or confusion

Ensure the experience feels supportive and trustworthy.

### Scope of the Test

You’ll review representative examples of:

* Parent onboarding flow
* Parent dashboard experience
* Sample insights report
* Educational content samples
* Rewards mechanisms powered by ASK

No real child data is used.

### How to Participate

#### Step 1: Access the Prototype

* Prototype link: \[LINK]
* Optional video walkthrough: \[LINK]

Using the prototype:

* Go through onboarding
* Explore the parent dashboard
* Review the sample insights report
* Review how ASK-based rewards work

#### Step 2: Review Educational Content

* Content samples: \[LINK]\
  Review relevance, tone, and usefulness.

#### Step 3: Share Feedback

* Feedback survey: \[LINK]\
  (5–8 questions, \~10 minutes)

You may also be invited to:

* A 15-minute interview or group call
* ### Optional testimonial (with consent)  Timeline

  **January 6**: Testing begins\
  You receive:

  * Prototype access
  * Content links
  * Feedback survey

  **January 14**: Testing ends

  **January 15**: Feedback analysis begins\
  **From January 19**: Optional interviews

### Thank You

Your participation helps us validate assumptions, uncover usability issues, and build a platform that genuinely serves families.

We’re grateful you’re helping us shape a healthier digital future for kids - with parents firmly at the center.

\
\
\ <br>


