# Introduction

S.I.G.N. is sovereign-grade digital infrastructure for national systems of money, identity, and capital. Sign Protocol provides the shared evidence layer used across deployments.

S.I.G.N. is a sovereign-grade architecture for building and operating national digital infrastructure across three foundational systems:

* **New Money System**: CBDC and regulated stablecoins operating across public and private rails with policy-grade controls and supervisory visibility
* **New ID System**: verifiable credentials and national identity primitives enabling privacy-preserving verification at scale
* **New Capital System**: programmatic allocation and distribution for grants, benefits, incentives, and compliant capital programs

S.I.G.N. is not a product container. It is a system-level blueprint for deployments that must remain governable, auditable, and operable under national concurrency.

Across these systems, one requirement repeats: **inspection-ready evidence**. In many deployments, that evidence layer is implemented using **Sign Protocol**, an omni-chain attestation protocol for creating, retrieving, and verifying structured records.

This documentation includes:

* system architecture and deployment guidance for S.I.G.N.
* use case blueprints for Money, ID, and Capital
* documentation for Sign products, including Sign Protocol, TokenTable, and EthSign
* full developer documentation for Sign Protocol (smart contracts, SDKs, APIs, advanced topics)

If you came here for Sign Protocol developer docs, you are in the right place. The framing has expanded: S.I.G.N. describes the sovereign system architecture, and Sign Protocol is the evidence layer used across sovereign and institutional workloads. TokenTable and EthSign are standalone products that use the same core primitives and can be integrated into S.I.G.N. deployments when appropriate.

***

## Trust, but verify at sovereign scale

Every day, systems depend on claims:

* a person claims eligibility for a program
* a business claims compliance
* an institution claims approval
* a system claims a payment was executed
* a registry claims an asset record is accurate

Historically, these claims were accepted based on relationships and institutional trust. In digital systems that operate across agencies, vendors, and networks, trust assumptions become fragile. Verification must be repeatable, attributable, and compatible with oversight.

S.I.G.N. exists to make verification reliable, repeatable, and operable at national scale.

***

## Attestations as a modern solution to authenticity

Attestations are portable, verifiable proofs that can travel across systems and time. They encode a statement, bind it to an issuer, and make it verifiable later.

In consumer life, a person might need a notarized document to prove a claim. In a sovereign context, the same pattern scales to system-critical actions:

* eligibility for benefits and public programs
* compliance gates for regulated services
* approvals for high-impact actions (distributions, conversions, registry updates)
* proof that a distribution occurred under an approved ruleset version
* proof that a registry update was authorized and traceable

S.I.G.N. treats attestations as operational infrastructure, not as an abstract primitive.

***

## What is S.I.G.N.?

S.I.G.N. is a layered stack that unifies:

* **execution**: money movement and program logic
* **identity**: credentials and verification
* **evidence**: cryptographic records of what happened, when, and under which authority

Sovereign deployments must satisfy constraints that typical consumer systems do not:

* privacy by default for sensitive payloads
* lawful auditability and inspection readiness
* strict operational control (keys, upgrades, emergency actions)
* interoperability across agencies, vendors, and networks
* performance and availability under national concurrency

S.I.G.N. is designed so that policy and oversight remain under sovereign governance while the technical substrate stays verifiable.

Start here:

* [S.I.G.N. Overview](/s.i.g.n./sign)
* [Reference Architecture](/s.i.g.n./reference-architecture)
* [Security & Privacy](/s.i.g.n./security-privacy)
* [Governance & Operations](/s.i.g.n./governance-ops)

***

## The three systems

### New Money System

A sovereign digital money rail supporting CBDC and regulated stablecoins across public and private rails.

Common requirements:

* real-time settlement and deterministic finality targets
* policy controls (limits, approvals, emergency controls)
* supervisory visibility and reporting
* optional confidentiality for retail flows
* interoperability across rails and networks

Read: [New Money System](/national-systems/new-money-system)

### New ID System

A national identity and credential layer supporting reusable verification without central "query my identity" APIs.

Common requirements:

* W3C Verifiable Credentials (VC) and Decentralized Identifiers (DID)
* selective disclosure and privacy-preserving proofs
* trust registry and issuer accreditation
* revocation and status checks
* offline presentation patterns where required (QR, NFC)

Read: [New ID System](/national-systems/new-id-system)

### New Capital System

A programmatic capital and distribution layer for benefits, grants, incentives, and compliant capital programs.

Common requirements:

* identity-linked targeting and duplicate prevention
* schedule-based distributions (one-time, recurring, vesting)
* deterministic reconciliation and budget traceability
* evidence manifests for audits and disputes

Read: [New Capital System](/national-systems/new-capital-system)

***

## The evidence layer

All three systems rely on a shared trust and evidence layer to answer questions like:

* who approved what
* under which authority
* when the action occurred
* what ruleset version applied
* what evidence supports eligibility and compliance
* what settlement references prove execution

In the Sign ecosystem, this evidence layer is implemented by **Sign Protocol** using two primitives:

* **Schemas**: templates defining how structured data is represented
* **Attestations**: signed, verifiable records conforming to schemas

Sign Protocol supports multiple data placement models:

* fully on-chain attestations
* fully off-chain payloads with verifiable anchors (for large or sensitive data)
* hybrid models combining on-chain references and off-chain payloads
* privacy-enhanced modes including private and ZK attestations where applicable

SignScan provides unified querying across supported chains and storage:

* REST and GraphQL APIs
* SDK-based access patterns
* explorer and dataset visibility for non-programmers

Product overview: [Sign Protocol](/products-sign-ecosystem/sign-protocol)\
Developer entrypoint: [Getting Started](/for-builders/getting-started)

***

## Sign products and how they relate to S.I.G.N.

S.I.G.N. is the sovereign system architecture. Sign products are deployable offerings that can be used independently and are often combined in sovereign and regulated deployments.

* **Sign Protocol**: schemas, attestations, privacy modes, indexing and querying
* **TokenTable**: allocation, vesting, and large-scale distribution for capital programs
* **EthSign**: agreement and signature workflows producing verifiable proof of execution

These products share core primitives, but they are not defined as "subsystems of S.I.G.N.". They are components that can support S.I.G.N. deployments when the program requires their specific capabilities.

Products overview: [Products Overview](/products-sign-ecosystem/products)

***

## Technical snapshot (standards and interfaces)

This is a reference snapshot of standards commonly used in S.I.G.N. deployments.

Identity:

* W3C Verifiable Credentials (VC) and W3C DIDs
* issuance via OpenID for Verifiable Credential Issuance (OIDC4VCI)
* presentation via OpenID for Verifiable Presentations (OIDC4VP)
* revocation via W3C Bitstring Status List
* offline presentation patterns (QR, NFC) where required
* compatibility targets for mobile drivers license patterns (ISO/IEC 18013-5/7) when relevant

Evidence:

* schema-driven structured data models
* cryptographic signatures (ECDSA, EdDSA, RSA depending on deployment)
* privacy-preserving proofs (selective disclosure, ZK systems where applicable)
* indexing and query layers for operational reporting and audits

Money rails (deployment-dependent):

* public mode via L1 smart contracts or sovereign L2 deployments
* private mode via permissioned CBDC rails for confidentiality-first requirements
* controlled interoperability via bridging or messaging gateways

***

## Deployment modes (public, private, hybrid)

S.I.G.N. is designed for deployment realities, not ideology.

Public mode:

* optimized for transparency-first programs, public verification, and broad accessibility
* governance is expressed via chain parameters (L2) or contract governance (L1)

Private mode:

* optimized for confidentiality-first programs and regulated domestic payment flows
* governance is enforced through permissioning, membership controls, and audit access policy

Hybrid mode:

* combines public verification and private execution where required
* interoperability must be treated as critical infrastructure with explicit trust assumptions

***

## How to read these docs

### If you are exploring S.I.G.N. (systems, architecture, governance)

Start with:

* [S.I.G.N. Overview](/s.i.g.n./sign)
* [Reference Architecture](/s.i.g.n./reference-architecture)
* [Security & Privacy](/s.i.g.n./security-privacy)
* [Governance & Operations](/s.i.g.n./governance-ops)

Then:

* [New Money System](/national-systems/new-money-system)
* [New ID System](/national-systems/new-id-system)
* [New Capital System](/national-systems/new-capital-system)

### If you are building (developers, integrators)

Start with:

* [Getting Started](/for-builders/getting-started)

Then go deeper:

* writing data: [Writing Data](/for-builders/index-1)
* querying data: [Querying Data](/for-builders/index)
* advanced topics: [Advanced Topics](/for-builders/advanced-topics)
* supported networks: [Supported Networks](/for-builders/address-book)

### If you are evaluating products

Start with:

* [Products Overview](/products-sign-ecosystem/products)

***

## Tenets that guide S.I.G.N. (and Sign)

### Keep it simple, Signer.

Sovereign systems are already complex (policy, compliance, privacy, interoperability). Infrastructure should reduce complexity, not add it. The goal is to make verifiable systems intuitive to integrate and difficult to misuse.

### Improvise. Adapt. Excel.

The path to real infrastructure is never linear. Deployments evolve with policy, adoption, interoperability constraints, and emerging threats while remaining governable and auditable.

### An open stack

Verification is most valuable when it is portable. S.I.G.N. embraces open standards and interoperable primitives so systems can evolve without locking policy into one vendor or one network.

### Evidence maketh governance

Identity primitives establish representation. Evidence establishes history. Attestations are the bedrock of accountability: who approved what, under which authority, when, and according to which rules.

***

## Where to go next

* Start with S.I.G.N.: [S.I.G.N. Overview](/s.i.g.n./sign)
* Explore national systems:
  * [New Money System](/national-systems/new-money-system)
  * [New ID System](/national-systems/new-id-system)
  * [New Capital System](/national-systems/new-capital-system)
* Build with Sign Protocol:
  * [Getting Started](/for-builders/getting-started)
* Evaluate products:
  * [Products Overview](/products-sign-ecosystem/products)


# FAQ

This FAQ answers common questions about S.I.G.N. and the Sign ecosystem, with an emphasis on how the system is structured and how to use it correctly. It is not a replacement for the architecture and security documentation.

If you are new to the ecosystem, start with:

* [S.I.G.N. Overview](/s.i.g.n./sign)
* [Reference Architecture](/s.i.g.n./reference-architecture)
* [Security & Privacy](/s.i.g.n./security-privacy)
* [Governance & Operations](/s.i.g.n./governance-ops)

***

## S.I.G.N.

<details>

<summary>What is S.I.G.N.?</summary>

S.I.G.N. is a sovereign digital infrastructure framework for deploying national-scale systems for money, identity, and capital. It focuses on enforceable policy controls, controllable privacy, and inspection-ready evidence so institutions can operate systems that hold up under oversight, disputes, and audits.

See [S.I.G.N. Overview](/s.i.g.n./sign) for the full narrative and design goals.

</details>

<details>

<summary>What are the three national systems in S.I.G.N.?</summary>

S.I.G.N. organizes national digital infrastructure into three system domains:

* New Money System: policy-controlled digital money rails for CBDC and regulated stablecoins
* New ID System: verifiable identity and credential issuance and verification across agencies and regulated operators
* New Capital System: regulated real-world asset and programmable capital infrastructure for issuance, distribution, and reporting

These are described in detail under:

* [New Money System](/national-systems/new-money-system)
* [New ID System](/national-systems/new-id-system)
* [New Capital System](/national-systems/new-capital-system)

</details>

<details>

<summary>Is S.I.G.N. a blockchain, a single ledger, or a vendor platform?</summary>

No. S.I.G.N. is a system architecture and operating model that can use one or more ledger and data availability options, depending on sovereignty, privacy, performance, and compliance requirements.

The goal is to avoid coupling national policy and oversight to a single vendor or ledger design. See [Reference Architecture](/s.i.g.n./reference-architecture) for the layering model and trust boundaries.

</details>

<details>

<summary>How do Sign Protocol, TokenTable, and EthSign fit under S.I.G.N.?</summary>

S.I.G.N. is the top-level narrative and architecture. The products are implementation components that align to parts of the stack:

* Sign Protocol provides the evidence and attestation layer used for verification, authorization proofs, and audit trails.
* TokenTable provides capital allocation and distribution primitives, typically for regulated issuance and program distribution workflows.
* EthSign provides agreement and signature workflows that can integrate with identity and evidence primitives.

See [Products](/products-sign-ecosystem/products) for the product map and intended use.

</details>

***

## Sign Protocol

<details>

<summary>What is Sign Protocol?</summary>

Sign Protocol is an evidence and attestation layer for producing and verifying structured claims. A claim can represent a statement, an authorization, an eligibility result, an approval, a verification outcome, or other system-relevant facts that must be inspectable later.

The core idea is to make verification reusable across applications by standardizing how claims are structured, signed, stored, queried, and referenced.

See [Sign Protocol](/products-sign-ecosystem/sign-protocol).

</details>

<details>

<summary>Is Sign Protocol a blockchain?</summary>

No. Sign Protocol is not itself a base ledger. It can use underlying chains and storage layers for anchoring, settlement, and tamper-evidence, but it is best understood as a protocol layer that defines how attestations and related proofs are produced and verified.

This separation supports interoperability and reduces coupling between application workflows and any single ledger environment.

</details>

<details>

<summary>What is an attestation?</summary>

An attestation is a signed, structured statement about a subject, typically bound to a schema that defines its fields and semantics. An attestation is meaningful only relative to its verification context, including who signed it, what authority they had, what schema it conforms to, and how revocation and updates are handled.

For precise definitions, see:

* [Glossary: Attestations](/reference/index/attestations)

</details>

<details>

<summary>What is the difference between an attestation and "evidence"?</summary>

An attestation is the signed statement. Evidence is the supporting material that makes the statement credible and inspectable, such as references to documents, cryptographic proofs, verification transcripts, or audit artifacts.

A well-designed system treats evidence as a first-class input to verification and dispute resolution. Evidence handling is closely tied to privacy and access control. See [Security & Privacy](/s.i.g.n./security-privacy).

</details>

<details>

<summary>What is a schema?</summary>

A schema defines the structure and semantics of an attestation. It specifies what fields exist, how they are encoded, and how verifiers should interpret them.

Schemas are critical for interoperability because they make attestations machine-verifiable and comparable across applications and organizations.

See:

* [Glossary: Schema](/reference/index/schema)

</details>

<details>

<summary>What is the Schema Registry?</summary>

The Schema Registry is the system for registering and discovering schemas used by Sign Protocol. It enables reuse, consistent interpretation, and ecosystem interoperability, while providing a stable reference for verifiers.

See:

* [Glossary: Schema Registry](/reference/index/schema-registry)

</details>

<details>

<summary>Where does attestation data live, on-chain or off-chain?</summary>

Both patterns are supported, and the correct choice depends on privacy, cost, latency, and audit requirements.

Common approaches include:

* On-chain anchoring for integrity and global verifiability
* Off-chain storage for sensitive or large payloads, with cryptographic binding to an on-chain commitment or identifier

See [Reference Architecture](/s.i.g.n./reference-architecture) and the developer documentation sections on writing and querying data.

</details>

<details>

<summary>How do I verify an attestation?</summary>

Verification typically includes:

* Schema verification: confirm the attestation conforms to the referenced schema
* Signature verification: confirm the signer and the signing domain
* Authority verification: confirm the signer was authorized to issue that type of statement in the relevant governance model
* Status verification: confirm revocation, expiration, supersession, or dispute status
* Evidence verification: confirm referenced proofs or artifacts meet the verifier's acceptance policy

For implementation, see:

* [Querying Data](/for-builders/index)
* [Writing Data](/for-builders/index-1)

</details>

<details>

<summary>Can attestations be edited or deleted?</summary>

In general, you should treat attestations as append-only records. Instead of mutating history, systems typically:

* Revoke attestations
* Issue a superseding attestation
* Attach dispute or correction attestations under defined rules

The correct approach depends on your governance and audit requirements. For operational guidance, see [Governance & Operations](/s.i.g.n./governance-ops).

</details>

<details>

<summary>What networks and runtimes are supported?</summary>

Network support evolves over time and depends on deployment and operational requirements.

For the authoritative list, see:

* [Supported Networks](/for-builders/address-book)

</details>

<details>

<summary>How is Sign Protocol different from EAS?</summary>

EAS is commonly used in EVM environments and is tightly shaped by the EVM execution and data model.

Sign Protocol is designed as an attestation and evidence layer that can be deployed across multiple environments and can support different storage, privacy, and verification models. The practical differences typically show up in interoperability, data-location strategies, and how the protocol integrates with non-EVM systems.

If you are choosing between the two, decide based on your target environments, verification requirements, and long-term governance constraints.

</details>

***

## TokenTable and EthSign

<details>

<summary>What is TokenTable?</summary>

TokenTable is a product for capital allocation and distribution workflows. It is typically used where eligibility, allocation rules, controlled distribution, and reporting requirements must be implemented as an auditable system.

See [TokenTable](/products-sign-ecosystem/tokentable).

</details>

<details>

<summary>What is EthSign?</summary>

EthSign is a product for agreements and signatures, designed to support institutional workflows where execution, authorization, and evidence must be captured reliably.

See [EthSign](/products-sign-ecosystem/ethsign).

</details>

<details>

<summary>Do TokenTable and EthSign require Sign Protocol?</summary>

Not strictly. They can be used as standalone products, depending on deployment architecture.

In sovereign or regulated deployments, the common pattern is that agreements, allocations, and program operations benefit from a shared evidence layer so that verification and audit do not have to be rebuilt per application.

</details>

***

## Contributions and community

<details>

<summary>Do you accept public contributions?</summary>

Yes. Contributions are welcome where they improve correctness, security posture, developer experience, and integration quality.

Typical contribution paths include:

* Documentation fixes and clarifications
* Bug reports and reproducible test cases
* Pull requests to relevant repositories, where applicable

Follow the repository contribution guidelines for coding standards and review expectations.

</details>

<details>

<summary>How do I report a security issue?</summary>

Do not disclose sensitive vulnerabilities in public issue trackers.

Use the security reporting process defined by the project. If a dedicated security contact is not listed in the repository, start with the organization contact method provided in the documentation site or the repository metadata, and request secure disclosure instructions.

Also review:

* [Security & Privacy](/s.i.g.n./security-privacy)

</details>

<details>

<summary>Where should I ask questions or send feedback?</summary>

Use the most appropriate channel for the type of request:

* Documentation issues: open an issue or pull request in the relevant repository
* Developer support: use the community or developer channels referenced by the project
* Product and deployment discussions: use the contact paths intended for institutional engagements

When possible, include environment details, expected behavior, actual behavior, and minimal reproduction steps.

</details>


# Overview

Sovereign-grade digital infrastructure for national systems of money, identity, and capital.

S.I.G.N. (Sovereign Infrastructure for Global Nations) is sovereign-grade digital infrastructure that governments and regulated institutions can reuse across **three national systems**:

* **New Money System** — CBDC + regulated stablecoins on one national rail (public + private modes), with policy-grade controls and supervisory visibility.
* **New ID System** — national identity + verifiable credentials (VC/DID) with selective disclosure, offline verification, and strong issuer governance.
* **New Capital System** — programmable distribution + regulated real-world asset (RWA) tokenization with compliance controls and inspection-ready reporting.

## Why this documentation exists

Most national digital programs fail at scale due to fragmented foundations:

* identity and eligibility checks are duplicated across agencies and vendors,
* payments rails are opaque and hard to audit,
* distribution programs lack end-to-end evidence,
* on-chain and off-chain systems cannot be reconciled cleanly over time.

S.I.G.N. is designed as a **thin but critical** infrastructure layer where:

* GovTech execution,
* FinTech rails, and
* cryptographic verification\
  meet in a way that keeps **policy + oversight under sovereign control**.

## Who this is for

### Governments, central banks, regulators

You want a system that is:

* private to the public but auditable to lawful authorities,
* operable at national concurrency (millions of users, multi-operator),
* standards-aware (ISO 20022, W3C VC/DID),
* and deployable without vendor lock-in.

Start here:

* [Reference Architecture](/s.i.g.n./reference-architecture)
* [Security & Privacy](/s.i.g.n./security-privacy)
* [Governance & Operations](/s.i.g.n./governance-ops)
* [Use Cases](/national-systems/new-money-system)

### Builders and integrators

You want to integrate identity proofs, program rules, distribution, and audit evidence into real systems.

Start here:

* [Builder Getting Started](/for-builders/getting-started)
* [Writing Data (Sign Protocol)](/for-builders/index-1)
* [Querying Data (SignScan / APIs)](/for-builders/index)

## How the docs are organized

* **S.I.G.N.** (this section): system-level architecture, governance, security/privacy.
* **Use Cases**: New Money / New ID / New Capital.
* **Products**: EthSign, TokenTable, Sign Protocol (evidence layer).
* **For Builders**: deep developer docs (primarily Sign Protocol contracts/SDK/APIs).

## Core concepts (minimal glossary)

This repo already contains a full glossary; this is the “minimum set” to read the S.I.G.N. pages:

* **Credential (VC)**: cryptographically signed claim issued to a holder (citizen/business).
* **DID**: a decentralized identifier used to represent issuers, holders, and verifiers.
* **Attestation**: structured, verifiable data record anchored and queryable (the evidence layer).
* **Schema**: a template defining the structure of attestations/claims.
* **Trust Registry**: registry of authorized issuers + keys + schemas + revocation/status.
* **Evidence artifact**: a durable, inspectable record of critical actions (who verified what, when, under what authority).

See full definitions: [Glossary](/reference/index)

## The “stack at a glance”

A simplified mental model:

1. **Settlement / Ledger substrate**
   * public chain mode (transparent)
   * private chain mode (confidential)
2. **Trust & Evidence layer**
   * identity credentials, attestations, revocation/status, audit hashes
3. **Program execution**
   * payments, distribution, registries, approvals, reporting

S.I.G.N. is the system that makes these layers interoperable and operable at national scale.


# Reference Architecture

Reference architecture for S.I.G.N. (Money, ID, Capital) and how Sign Protocol + TokenTable compose across public/private rails.

## Purpose

This page defines a **reference architecture** for S.I.G.N. deployments. It is written to be:

* **implementation-neutral** (works with different sovereign constraints),
* **operator-friendly** (clear roles and trust boundaries),
* **audit-ready** (explicit evidence artifacts),
* **integration-ready** (legacy rails + standards).

## Audience

* Sovereign operators (central bank infra, GovTech platform teams)
* System integrators (banks/PSPs/telcos, identity vendors)
* Builders (wallets, program operators, auditors)

## Architectural invariants

S.I.G.N. is designed around five invariants:

1. **Controllable privacy**
   * private to the public,
   * auditable to lawful authorities,
   * minimal disclosure by default.
2. **National performance**
   * built for millions of users, multi-operator workflows, strict SLAs.
3. **Sovereign control**
   * key custody, upgrades, emergency controls, and oversight remain under sovereign governance.
4. **Interoperability**
   * standards-aligned identity (VC/DID),
   * standards-aware payments (ISO 20022),
   * compatibility with public + private rails.
5. **Inspection-ready evidence**
   * every critical action emits durable evidence:
     * who authorized what
     * under which authority
     * when
     * based on which identity/eligibility proof
     * with what rule version

***

## High-level component diagram

A reference decomposition (logical, not vendor-specific):

* **Public Rail (Transparent Mode)**
  * L2 sovereign chain or L1 smart contracts
  * suitable for public finance transparency, open verification, global access
* **Private Rail (Confidential Mode)**
  * permissioned CBDC infrastructure (e.g., Fabric-based)
  * suitable for privacy-sensitive retail flows and regulated confidentiality
* **Identity Stack**
  * issuers (government agencies / authorized institutions)
  * holder wallets (non-custodial)
  * verifiers (banks, agencies, service providers)
  * trust registry + revocation/status
* **Trust & Evidence Layer (Sign Protocol)**
  * schema registry (structured templates)
  * attestations (verifiable records)
  * privacy modes (on-chain / off-chain / hybrid / ZK)
  * indexing + query (SignScan / REST / GraphQL)
* **Program Engine (TokenTable / Distribution + Asset Engine)**
  * eligibility rules
  * batch distribution
  * scheduling
  * conditional logic
  * asset tokenization + registry integration
  * audit trail + reconciliation

***

## Trust model and roles

A typical sovereign trust model uses explicit roles:

* **Sovereign Authority**
  * defines policy rules, signs governance approvals
  * owns root governance keys or approval process
* **Operators**
  * run infrastructure components (indexers, APIs, chain nodes, bridges)
  * do not unilaterally control policy
* **Issuers**
  * issue credentials (VCs) and/or attestations
  * must be registered in a trust registry
* **Holders**
  * citizens, residents, businesses
  * hold credentials in non-custodial wallets
* **Verifiers / Relying Parties**
  * service providers verifying credentials/attestations
* **Auditors / Supervisors**
  * authorized parties that can inspect evidence and reconcile programs

> Design rule: **Separate duties** between (i) policy definition, (ii) issuance, (iii) operations, and (iv) audit.

***

## Data placement model

S.I.G.N. deployments must explicitly define where data lives.

### 1) What should be off-chain (typical)

* PII (name, address, biometric templates, passport scans)
* sensitive program enrollment payloads
* internal case files

### 2) What should be on-chain (typical)

* commitments/hashes of records
* attestations and schema IDs (when safe)
* revocation/status registries
* audit hashes + rule version hashes
* transaction settlement references

### 3) Hybrid patterns (recommended)

* keep sensitive payloads off-chain (encrypted),
* store references + integrity anchors on-chain,
* index only what is needed for verification.

***

## Reference technical specifications (summary)

This section is meant to guide planning and procurement, not constrain implementations.

### Public rail (Layer 2 reference)

* Runtime: EVM-based
* Block time: < 1 second
* TPS: up to \~4000 (reference)
* Consensus: PoA / PBFT variants
* Finality: 1–5 blocks (reference)

### Private rail (CBDC reference)

* Consensus: Arma BFT
* Throughput: 100,000+ TPS (reference)
* Finality: immediate on commitment
* Privacy: namespaces + configurable ZK privacy
* Token model: UTXO via Fabric Token SDK
* Identity: X.509 certificates (MSP)
* Standards: ISO 20022 compatible
* Namespaces: wCBDC, rCBDC, Regulatory
  * wCBDC: RTGS-like transparency
  * rCBDC: high privacy (ZK)

### National Digital Identity stack (reference)

* VC model: W3C Verifiable Credentials 2.0
* DID: W3C DIDs
* Formats: VC-JWT, SD-JWT VC, JSON-LD with BBS+
* Signatures: ECDSA, EdDSA, RSA
* ZK: Groth16 / Plonk / BBS+ (unlinkability)
* Issuance: OIDC4VCI
* Presentation: OIDC4VP
* Revocation: W3C Bitstring Status List
* Offline: QR + NFC presentation
* mDL compatibility: ISO/IEC 18013-5/7

### TokenTable (reference)

* Distribution size: unlimited
* Throughput: max chain TPS
* Scheduling: second-level granularity + calendar months
* Audit trail: on-chain

***

## End-to-end flows (canonical)

### Flow A: Eligibility → Distribution → Audit (most common)

1. Issuer issues VC (eligibility credential) to holder wallet
2. Holder proves eligibility to a program engine (selective disclosure)
3. Program engine generates a distribution batch
4. Settlement occurs on:
   * private rail (CBDC) for confidentiality, or
   * public rail (stablecoin) for transparency
5. Evidence is produced:
   * eligibility proof reference
   * rule version hash
   * distribution manifest hash
   * settlement references

### Flow B: Cross-rail conversion (CBDC ↔ Stablecoin bridge)

1. User requests conversion
2. Compliance checks run (identity, limits, AML)
3. Atomic mint/burn or lock/release occurs
4. Evidence: signed approval + conversion record + settlement references

### Flow C: Registry update (RWA tokenization)

1. Registry authority validates a property/asset record
2. TokenTable tokenizes ownership/transfer rules
3. Transfers are permitted only for eligible parties (whitelists, jurisdiction rules)
4. Evidence: registry sync logs + transfer approvals + ownership chain

***

## Where to go next

* Governance and operational control: [Governance & Operations](/s.i.g.n./governance-ops)
* Privacy and threat model: [Security & Privacy](/s.i.g.n./security-privacy)
* Use cases:
  * [New Money System](/national-systems/new-money-system)
  * [New ID System](/national-systems/new-id-system)
  * [New Capital System](/national-systems/new-capital-system)
* Deep developer docs (protocol layer): [For Builders](/for-builders/getting-started)


# Security & Privacy

Security and privacy model for S.I.G.N. including data placement, selective disclosure, audit access controls, and operational security practices.

## Purpose

This page defines the security and privacy posture expected for S.I.G.N. deployments:

* what goes on-chain vs off-chain,
* how privacy is preserved while keeping lawful auditability,
* the baseline security controls operators should implement.

This is not legal advice; each jurisdiction should adapt controls to local law and procurement rules.

***

## Security goals

S.I.G.N. deployments should satisfy:

1. **Integrity**
   * evidence and records cannot be forged without detection
   * state transitions are verifiable over time
2. **Confidentiality**
   * sensitive citizen data is not exposed broadly
   * privacy-sensitive payments remain confidential to the public
3. **Availability**
   * systems continue operating under national concurrency and adversarial conditions
4. **Non-repudiation**
   * actions (issuance, approvals, distributions) are cryptographically attributable
5. **Auditability**
   * authorized parties can reconstruct “who did what, when, and why”
   * evidence is inspection-ready and consistent across systems

***

## The privacy principle: “private to the public, auditable to lawful authorities”

This means:

* **The public** should not be able to trivially enumerate:
  * citizen identities,
  * balances,
  * private benefit distributions,
  * sensitive eligibility data.
* **Authorized oversight** can verify:
  * that rules were followed,
  * that recipients were eligible at time of distribution,
  * that budgets reconcile to outcomes,
  * that approvals exist for exceptional actions.

The mechanism is a combination of:

* **data minimization** (do not publish sensitive payloads),
* **cryptographic proofs** (prove without revealing),
* **segmented rails** (public vs private settlement),
* **access-controlled audit systems** (lawful inspection).

***

## Data classification and placement

### Recommended classification

* **Public**
  * program rulesets (high-level)
  * aggregate statistics
  * public benefit distributions (when transparency is desired)
* **Restricted**
  * issuer keys, operator runbooks, monitoring endpoints
* **Confidential**
  * PII
  * private payment details
  * eligibility payloads
  * internal case files and investigations
* **Sensitive (lawful access only)**
  * audit reconstruction maps linking pseudonyms to identities
  * regulatory investigation artifacts

### Placement rules of thumb

* **PII should be off-chain** by default.
* **On-chain artifacts should be proofs/anchors**, such as:
  * schema IDs
  * attestation IDs (or commitment hashes)
  * revocation/status registry references
  * rule version hashes
  * audit manifest hashes
  * settlement references (tx hashes / commit IDs)
* **Hybrid** is preferred when:
  * verifiers need open verification,
  * but payload confidentiality must be maintained.

***

## Cryptography and standards (reference)

### Credential + identity stack

* VC model: W3C Verifiable Credentials 2.0
* DID standard: W3C DIDs
* Formats: VC-JWT, SD-JWT VC, JSON-LD with BBS+
* Issuance protocol: OIDC4VCI
* Presentation protocol: OIDC4VP
* Revocation: W3C Bitstring Status List
* Offline presentation: QR and NFC
* mDL compatibility: ISO/IEC 18013-5/7

### Signature schemes (reference)

* ECDSA (secp256k1, P‑256)
* EdDSA (Ed25519)
* RSA

### Privacy / ZK (reference)

* Groth16, Plonk
* BBS+ (unlinkable credentials / selective disclosure)

### ePassport integration (reference)

* ICAO 9303 compatible proofs/verification

***

## Privacy mechanisms in practice

### Selective disclosure

A holder can prove a predicate (e.g., “age ≥ 18”) without revealing the underlying value (exact DOB).

### Unlinkability

When supported, presentations should prevent third parties from linking:

* the same citizen across different service contexts,
* or the same credential presentation across time.

### Minimal disclosure

A verifier should request only what is necessary:

* a “yes/no” eligibility proof instead of full identity payload,
* an attribute proof instead of a complete credential.

***

## Payment privacy (New Money System alignment)

A common pattern is dual-rail support:

* **Public rail** for transparency-first use cases\
  Example: public spending programs where the state wants public accountability.
* **Private rail (CBDC)** for confidentiality-first use cases\
  Example: sensitive assistance programs requiring strong privacy protections.

Within a private CBDC rail, privacy tiers may exist:

* **wCBDC** (wholesale): RTGS-like transparency for institutions
* **rCBDC** (retail): stronger privacy protections (potentially ZK-based)

***

## Access control and lawful audit

### Role-based access control (RBAC)

Deployments should define:

* who can issue credentials,
* who can approve distributions,
* who can operate bridges,
* who can run indexers,
* who can perform audits.

### Audit access

Audit access should be:

* logged,
* time-bounded,
* least-privilege,
* and require multi-party approval when appropriate.

### Evidence export

Audits should be able to export:

* signed approvals,
* rule versions and hashes,
* batch manifests and reconciliation outputs,
* settlement references,
* revocation/status proof checks.

***

## Operational security baseline

### Key management

* Root governance keys should be protected by **HSM** and/or **multisig**.
* Issuer keys (credential/attestation signing) should be separated by agency/domain.
* Operator keys (infrastructure) should not be issuer keys.
* Rotation and recovery must be documented and tested.

### Monitoring and incident response

Minimum recommended:

* service health dashboards (indexers, APIs, bridge)
* tamper-evident logs
* alerting for abnormal issuance/distribution rates
* rollback / pause procedures for emergency controls

### Supply chain and SDLC security

* dependency scanning + SBOM generation
* reproducible builds where possible
* staging environments mirroring production
* third-party audits for critical components
* bug bounty program / coordinated disclosure

***

## Threat model (high-level)

Threats to plan for:

* **Credential forgery / issuer compromise**
  * mitigations: trust registry, issuer governance, key custody, revocation
* **Sybil or duplicate claims**
  * mitigations: identity-linked targeting, duplicate prevention rules, attestation checks
* **Bridge abuse**
  * mitigations: atomicity, limits, approvals, monitoring, emergency pause
* **Indexer/API tampering**
  * mitigations: integrity anchors, replayable verification from raw sources, signed responses (optional)
* **Privacy leakage via metadata**
  * mitigations: minimal disclosure, unlinkability, careful logging and analytics policies

***

## Recommended evidence artifacts (standard set)

Every sovereign program should be able to produce:

* **RuleSet**
  * `ruleset_id`, `ruleset_version`, `ruleset_hash`
* **Eligibility proof reference**
  * VC presentation proof or attestation reference, plus status check time
* **Distribution manifest**
  * list of recipients (pseudonymous references), amounts, timestamps, assets
* **Settlement references**
  * public tx hash or private commit ID(s)
* **Audit export package**
  * signed approvals, logs, reconciliation outputs

(Examples appear in the [New Money System](/national-systems/new-money-system) and [New Capital System](/national-systems/new-capital-system) pages.)


# Governance & Operations

Governance and operations model for sovereign deployments including roles, key custody, change management, SLAs, and audit readiness.

## Purpose

S.I.G.N. deployments are not “just software.” They are **sovereign systems** that must be governable, operable, and auditable.

This page provides a reference governance + ops model that can be adapted per country.

***

## Governance model (three layers)

Successful deployments separate governance into:

### 1) Policy governance

Defines:

* what programs exist,
* what rules apply (eligibility, caps, schedules),
* what privacy level each program requires (public vs private mode),
* which entities are authorized.

Outputs:

* program policies
* rule definitions
* legal/regulatory approvals

### 2) Operational governance

Defines:

* who runs systems day-to-day,
* what the SLAs are,
* how incidents are handled,
* how audit exports are produced.

Outputs:

* runbooks
* escalation paths
* monitoring dashboards
* maintenance windows

### 3) Technical governance

Defines:

* upgrade policies,
* emergency controls,
* key custody,
* change approval workflows.

Outputs:

* change management process
* release cadence
* rollback plan
* key rotation policy

***

## Roles and responsibilities (reference)

### Sovereign Authority (root)

* owns high-level policy and oversight
* approves:
  * system upgrades
  * emergency actions (pause/freeze)
  * bridge parameter changes

### Central bank / treasury operator (money rail)

* governs CBDC policies and settlement operations (if applicable)
* controls CBDC network membership and compliance requirements

### Identity authority (ID system)

* accredits issuers
* governs schemas and revocation policies
* defines trust registry procedures

### Program authority (capital/distribution)

* defines eligibility rules and distribution policies
* approves large batch distributions
* manages program budgets and reconciliation

### Technical operator (SRE/Infra)

* runs nodes, indexers, APIs, monitoring
* executes approved changes
* maintains uptime and incident response

### Auditor / supervisor

* reviews evidence
* reconciles distribution outputs
* investigates exceptions and disputes

> Principle: **separation of duties**. The entity running infra should not be the entity issuing credentials.

***

## Key management (minimum expectations)

### Key categories

* **Governance keys**
  * used to approve upgrades, emergency actions, parameter changes
* **Issuer keys**
  * used to sign credentials or attestations
* **Operator keys**
  * used to run infrastructure components and access restricted systems
* **Audit keys**
  * used to decrypt or access lawful audit datasets (when applicable)

### Baseline requirements

* Governance keys should be **multisig** and/or **HSM-backed**
* Issuer keys should be HSM-backed where possible
* Rotate keys on schedule and after incidents
* Document and test recovery procedures

### Example approval policy (reference)

* Routine upgrade: 2-of-3 multisig (technical governance committee)
* High-risk upgrade: 3-of-5 multisig (policy + technical)
* Emergency pause: 2-of-3 “emergency council” + post-incident review
* Bridge parameter change: 3-of-5 + monitoring escalation requirement

***

## Change management

A change should not be “merged and shipped.” It should be governed.

### Change categories

* **Doc-only**
* **Config-only** (limits, schedules, whitelists)
* **Software upgrade** (contracts, nodes, APIs)
* **Emergency action**

### Required artifacts for each change

* change request + rationale
* impact assessment (security, availability, privacy)
* rollback plan
* approval signatures
* deployment log entry (time, operator, version)

***

## Operational readiness

### Monitoring

Minimum recommended dashboards:

* issuance volume (by issuer)
* verification volume (by verifier)
* distribution volume (by program)
* bridge conversion volume and error rates
* API latency / error rates (SignScan / SDK endpoints)
* node health (public/private rails)

### Incident response

Define:

* severity levels (SEV1–SEV4)
* on-call schedule
* communication plan (internal + public)
* postmortem template
* evidence export process for incident investigations

### Business continuity

Define:

* backups of off-chain stores
* disaster recovery procedure
* degraded-mode operations (read-only, limited issuance, etc.)
* manual override policy (with evidence logging)

***

## Audit operations

### What auditors need

Auditors typically require:

* rule definitions and versions
* identity and eligibility proof references
* revocation/status check logs
* distribution manifests
* settlement references
* reconciliation reports

### Recommended audit export format (reference)

* Program metadata
* RuleSet hash/version
* Distribution batch manifests (pseudonymous IDs)
* Settlement references (tx hashes / commit IDs)
* Signed approvals
* Exceptions log

See examples in:

* [New Money System](/national-systems/new-money-system)
* [New Capital System](/national-systems/new-capital-system)

***

## Deployment methodology (phased)

A common sovereign pattern:

1. **Assessment & planning**
   * map stakeholders and systems
   * define privacy requirements per program
   * define governance and key custody
2. **Pilot**
   * limited scope, limited users
   * strong monitoring + manual controls
3. **Expansion**
   * multiple agencies/operators
   * production-grade SLAs and audits
4. **Full integration**
   * connect to broader government service ecosystem
   * mature governance, stable operations, standard audits


# New Money System (CBDC & Stablecoins)

CBDC and regulated stablecoin infrastructure with dual public/private rail architecture, bridging, and sovereign controls.

## Purpose

The New Money System provides a sovereign digital money rail that supports:

* **CBDC** (privacy-sensitive, permissioned mode), and/or
* **regulated stablecoins** (transparent public mode)

under one national infrastructure with policy-grade controls, real-time settlement, and supervisory visibility.

## Audience

* Central banks / treasury operators
* Regulated financial institutions (banks, PSPs, telcos)
* Builders integrating wallets, merchant acceptance, or program disbursement
* Auditors and supervisors

***

## Architecture overview (dual-path)

S.I.G.N. supports two complementary approaches:

### A) Public blockchain approach (transparent mode)

Reference options:

* **Layer 2 sovereign chain** (max operational independence)
* **Layer 1 smart contracts** (direct access to existing ecosystems)

Use when:

* transparency is desired (public finance reporting),
* global liquidity and composability matter,
* cross-border interoperability and open verification are required.

### B) Private blockchain approach (CBDC mode)

Reference: **Hyperledger Fabric X–based CBDC** for privacy-first operations.

Use when:

* retail privacy is required,
* strong permissioning is required,
* supervisory visibility must be controlled with lawful access.

***

## Public blockchain approach (reference)

### Deployment option 1: Layer 2 sovereign chain

Characteristics:

* operational independence: government controls block production and validator/sequencer set
* customizable consensus (PoA / PBFT variants)
* security inheritance via state commitments to an underlying L1
* exit mechanisms to L1 in case of failure
* governance: chain-level governance for parameters and upgrades

Reference specs (illustrative; may vary by deployment):

* Runtime: EVM-based
* Block time: < 1 second
* TPS: up to \~4000
* Finality: 1–5 blocks

### Deployment option 2: Layer 1 smart contracts

Characteristics:

* simpler deployment (no separate consensus infrastructure)
* inherits L1 security model
* direct ecosystem integration (where policy allows)
* governance via upgradeable patterns and multisig
* compliance controls via contract-level access control (roles/whitelists)

### Quick decision guide

Choose Layer 2 if you need:

* maximal operational independence
* customizable consensus and chain parameters

Choose Layer 1 contracts if you need:

* fastest path to integrations
* lowest operational overhead

***

## Private blockchain approach (CBDC reference)

Reference capabilities:

* Consensus: Arma BFT
* Throughput: 100,000+ TPS (reference)
* Finality: immediate upon commitment
* Privacy: namespaces + configurable ZK privacy
* Token operations: UTXO model (Fabric Token SDK)
* Transaction model: peer-to-peer negotiation (Fabric Smart Client)
* Identity: X.509 certificates with MSP
* Governance: central bank–controlled consensus nodes
* Standards: ISO 20022 compatible
* Namespaces: wCBDC / rCBDC / Regulatory
  * wCBDC: RTGS-like transparency
  * rCBDC: high privacy (potentially ZK)

Interpretation:

* This model supports privacy-sensitive flows without sacrificing auditability for authorized authorities.
* It enables multiple privacy tiers under one rail.

***

## CBDC ↔ Stablecoin bridge (controlled interoperability)

The bridge enables conversion between:

* private CBDC accounts (confidential mode), and
* public stablecoin accounts (transparent mode)

### Security requirements (reference)

A bridge should implement:

* **atomicity** (no partial completion)
* **policy checks** (limits, eligibility, AML/CFT checks per local policy)
* **rate/volume controls** (per identity, per institution, per day)
* **emergency controls** (pause, rollback procedures)
* **evidence logging** (signed approvals plus conversion record)

### Operational flow (reference)

1. User or institution requests conversion
2. Compliance checks run (identity, limits, sanctions/AML per policy)
3. Convert:
   * burn/lock on source rail
   * mint/release on destination rail
4. Emit evidence artifacts:
   * conversion request ID
   * approvals and ruleset version/hash
   * settlement references (tx hash or commit ID)

***

## Program flows (canonical)

### Flow 1: Government-to-person (G2P) disbursement

1. Verify identity + eligibility ([New ID System](/national-systems/new-money-system))
2. Select rail:
   * CBDC for privacy-sensitive programs
   * stablecoin/public rail for transparency-first programs
3. Generate distribution batch ([TokenTable](/products-sign-ecosystem/tokentable))
4. Settle payments
5. Produce an audit package (manifest + settlement refs + rule version)

### Flow 2: Merchant acceptance

Typical requirements:

* wallet compatibility and recovery model
* settlement finality expectations
* fee model (sponsored vs user-paid)
* refund/reversal policy (governed)
* evidence logging for disputes

### Flow 3: Cross-border flows (reference)

When required, align with ISO 20022 message structures for interoperability and reporting.

***

## Evidence artifacts (minimum set)

### Distribution batch manifest (example)

```
{
  "program_id": "WELFARE_Q2_2026",
  "ruleset_version": "v3",
  "ruleset_hash": "0xabc...",
  "generated_at": "2026-04-01T12:00:00Z",
  "asset": "CBDC",
  "rail": "private",
  "recipients": [
    {
      "subject_ref": "did:example:citizen:8f1c...",
      "eligibility_proof_ref": "attestation:0x123...",
      "amount": "100.00",
      "currency": "CBDC",
      "settlement_ref": "fabric_commit:0000a1b2..."
    }
  ]
}
```

### Compliance check log (example)

```
{
  "check_id": "AMLCHK_2026_04_01_00042",
  "subject_ref": "did:example:citizen:8f1c...",
  "checks": ["sanctions", "limits", "jurisdiction"],
  "result": "pass",
  "performed_by": "operator:cb-compliance",
  "performed_at": "2026-04-01T11:59:20Z"
}
```

***

## Where to go next

* Identity prerequisites: [New ID System](/national-systems/new-id-system)
* Distribution engine: [New Capital System](/national-systems/new-capital-system) and [TokenTable](/products-sign-ecosystem/tokentable)
* Evidence layer (developer docs): [Getting Started](/for-builders/getting-started)


# New ID System (Verifiable Credentials)

National digital identity and verifiable credentials under S.I.G.N., including SSI principles, trust registry, offline verification, and revocation/status.

## Purpose

The New ID System provides a reusable national identity + credentialing layer built on:

* Self-Sovereign Identity (SSI) principles
* W3C Verifiable Credentials (VC)
* W3C Decentralized Identifiers (DID)
* selective disclosure + privacy-preserving proofs
* trust registry + revocation/status infrastructure

This system enables:

* one citizen, one verifiable identity layer (across agencies and regulated operators),
* interoperability across service providers,
* privacy-preserving verification without central “query my identity” APIs,
* standardized, inspection-ready audit evidence.

***

## SSI principles (operationalized)

A national SSI design should support:

* **User control and consent**: holders decide when/where to present credentials
* **Portability**: credentials usable across agencies and regulated operators
* **Privacy by design**: disclose only what is required; avoid linkability
* **Cryptographic verification**: verifiers validate without issuer live queries
* **Standards-based interoperability**: reduces fragmentation and vendor lock-in

***

## Credential lifecycle (VC)

### 1) Issuance

* Authorized issuer signs a VC bound to a schema
* Credential is delivered to a holder wallet (non-custodial)

### 2) Storage

* Holder stores VCs locally (device secured)
* Keys and credential material must be protected by device security and policy-approved recovery

### 3) Presentation

* Holder constructs a presentation (VP)
* Only required attributes are disclosed (or proved via ZK / selective disclosure)

### 4) Verification

Verifier checks:

* issuer signature validity
* issuer legitimacy via trust registry (accreditation)
* schema compliance (expected fields/types)
* revocation/status validity at verification time

### 5) Revocation / status

Issuer updates status registry; verifiers check during verification.

***

## Components

### A) Issuer services

* credential issuance service (OIDC4VCI recommended)
* issuer DID/key custody
* issuer governance and audit logging

### B) Holder wallets

Key capabilities:

* non-custodial storage
* biometric/device-protected access
* offline presentation (QR/NFC)
* multi-credential management
* secure key backup/recovery (as approved by policy)

### C) Verifier services

* verification SDK/service for VCs and VPs
* status check logic (bitstring status lists)
* verification event logging (evidence)

### D) Trust registry (anchored)

Tracks:

* issuer DIDs + public keys
* issuer accreditation status
* approved schemas and schema versions
* revocation/status endpoints/references
* governance policy for issuer onboarding/offboarding

***

## Reference technical specifications (identity stack)

* Credential model: W3C Verifiable Credentials 2.0
* Identifier: W3C DIDs
* Formats: VC-JWT, SD-JWT VC, JSON-LD with BBS+
* Signature algorithms: ECDSA (secp256k1, P-256), EdDSA (Ed25519), RSA
* ZK proof systems: Groth16, Plonk, BBS+ (unlinkable credentials)
* Wallet security: device secure enclave + biometric authentication
* Issuance protocol: OpenID for VC Issuance (OIDC4VCI)
* Presentation protocol: OpenID for VC Presentations (OIDC4VP)
* Revocation: W3C Bitstring Status List
* Offline support: QR and NFC-based credential presentation
* mDL compatibility: ISO/IEC 18013-5/7

***

## Privacy-preserving verification

### Selective disclosure patterns

Examples:

* “age ≥ 18” without revealing full DOB
* “resident of region X” without revealing full address
* “licensed professional” without revealing full license number

### Unlinkability patterns

When using unlinkable credentials (e.g., BBS+ or ZK-backed), design verifiers to:

* avoid storing correlatable identifiers
* store minimal evidence required for audit
* rotate verifier session identifiers to reduce metadata linking

***

## Revocation and status (recommended model)

A verifier should:

1. verify issuer signature
2. verify issuer trust registry accreditation
3. check status list at verification time
4. log the status check time + reference (evidence)

Example verification evidence (illustrative):

```
{
  "verification_event_id": "VERIF_2026_04_01_01002",
  "verifier_id": "bank:psp-001",
  "subject_ref": "did:example:citizen:8f1c...",
  "credential_type": "ResidentCredential",
  "schema_id": "schema:resident:v1",
  "issuer_did": "did:example:issuer:gov-id",
  "status_check_ref": "statuslist:bitstring:v1:0xaaa...",
  "status_at_time": "valid",
  "verified_at": "2026-04-01T12:05:00Z"
}
```

***

## How Sign Protocol fits (evidence layer)

Sign Protocol can anchor:

* issuer accreditation events
* schema publication and versions
* verification evidence (when appropriate)
* eligibility proofs for programs
* audit manifests and reconciliation anchors

It also supports privacy modes (including ZK attestations) to avoid exposing sensitive details on public rails.

***

## Interoperability with money + capital

### Identity → Money

* Identity proofs enable account creation (CBDC or regulated stablecoin)
* compliance checks can reuse credential evidence (per policy)

### Identity → Capital / distribution

* eligibility attributes gate access to benefits and subsidies
* duplicate prevention uses identity-linked targeting and evidence checks

***

## Where to go next

* Payments rail: [New Money System](/national-systems/new-money-system)
* Distribution + RWA: [New Capital System](/national-systems/new-capital-system)
* Deep attestations + schemas: [For Builders](/for-builders/getting-started)
* Full vocabulary: [Glossary](/reference/index)


# New Capital System (RWA / Programmable Capital)

Sovereign capital distribution, tokenized programs, and allocation infrastructure powered by TokenTable and Sign Protocol.

## Purpose

The New Capital System enables governments, regulators, and institutions to:

* distribute capital programmatically,
* enforce eligibility and policy constraints,
* maintain full auditability and transparency,
* prevent duplication, leakage, and fraud,
* operate at national or population scale.

This system is built on **TokenTable** for allocation and execution, and **Sign Protocol** for verifiable evidence.

***

## What problems this solves

Traditional capital programs suffer from:

* opaque beneficiary selection,
* manual reconciliation and audits,
* duplicate or fraudulent claims,
* poor interoperability between agencies,
* weak post-distribution accountability.

The New Capital System replaces these with **rule-driven, evidence-anchored capital flows**.

***

## Core components

### 1) Eligibility layer (input)

Inputs may include:

* identity credentials ([New ID System](/national-systems/new-id-system)),
* income or residency proofs,
* compliance checks (AML, sanctions, sector restrictions),
* program-specific attributes.

Eligibility evidence is cryptographically verifiable and reusable.

***

### 2) Allocation engine (TokenTable)

TokenTable acts as the **distribution and allocation engine**, supporting:

* one-to-many distributions,
* vesting schedules,
* cliffs and linear unlocks,
* revocation and clawback logic,
* delegated claiming,
* batch execution.

Allocations can represent:

* cash-like funds (CBDC / stablecoins),
* subsidies or benefits,
* grants or credits,
* tokenized assets or rights.

***

### 3) Settlement rails

Funds may settle on:

* private CBDC rails,
* public regulated stablecoins,
* hybrid bridges between private and public rails.

The capital system is **rail-agnostic**, but evidence-consistent.

***

### 4) Evidence & audit layer (Sign Protocol)

Sign Protocol anchors:

* eligibility attestations,
* allocation manifests,
* execution and settlement references,
* compliance approvals,
* post-distribution audits.

Evidence is immutable, queryable, and verifiable.

***

## Canonical flows

### Flow 1: Welfare / subsidy distribution

1. Define program ruleset (eligibility + caps)
2. Verify citizens via New ID System
3. Generate allocation table (TokenTable)
4. Execute distributions
5. Anchor evidence (ruleset hash + execution refs)

***

### Flow 2: Grants & incentives

1. Accept applications
2. Evaluate eligibility and scoring
3. Publish allocation results
4. Release funds via schedules
5. Provide transparent public audit trail

***

### Flow 3: Enterprise or sector support

Used for:

* SME stimulus,
* agricultural subsidies,
* energy credits,
* education vouchers.

Rules enforce **who**, **how much**, **when**, and **under what conditions**.

***

## Example allocation manifest (illustrative)

```
{
  "program_id": "SME_SUPPORT_2026",
  "ruleset_version": "v2",
  "asset": "CBDC",
  "total_budget": "10000000",
  "currency": "CBDC",
  "allocations": [
    {
      "beneficiary_ref": "did:example:entity:company123",
      "amount": "50000",
      "vesting": "linear_12_months",
      "eligibility_ref": "attestation:0xabc..."
    }
  ],
  "generated_at": "2026-05-01T10:00:00Z"
}
```

***

## Controls & safeguards

* hard caps per identity or entity
* duplicate prevention via identity linkage
* revocation and clawback mechanisms
* emergency pause
* versioned rulesets for audit replay

***

## Where to go next

* Identity prerequisites: [New ID System](/national-systems/new-id-system)
* Payments rails: [New Money System](/national-systems/new-money-system)
* Distribution tooling: [TokenTable](/products-sign-ecosystem/tokentable)
* Evidence layer: [Sign Protocol](/products-sign-ecosystem/sign-protocol)


# Overview

Standalone products developed by Sign, including Sign Protocol, TokenTable, and EthSign. These products share core primitives and can be deployed independently or integrated into S.I.G.N. architecture

This section documents the products developed by Sign.

These products are standalone offerings. They share core primitives and are often used together in sovereign and regulated deployments, but they are not defined as "subsystems of S.I.G.N.". S.I.G.N. is the sovereign system architecture for national deployments across money, identity, and capital.

If you are looking for system narrative and operating model, start with the S.I.G.N. section:

* [S.I.G.N. Overview](/s.i.g.n./sign)
* [Reference Architecture](/s.i.g.n./reference-architecture)
* [Security & Privacy](/s.i.g.n./security-privacy)
* [Governance & Operations](/s.i.g.n./governance-ops)

***

## How to use this section

Use the product pages when you need to answer:

* What does this product do and what does it not do?
* What evidence does it produce and how is it verified?
* What are the integration boundaries and operating assumptions?
* How does it typically integrate into sovereign and institutional workflows?

Deep technical documentation remains under the developer sections.

* Developer entrypoint: [For Builders](/for-builders/getting-started)
* Quickstart: [For Hackers](/for-hackers/getting-started)

***

## Product map

The Sign ecosystem includes three primary products:

| Product                                                 | Scope                                              | Primary outputs                                                                    | Typical consumers                                          |
| ------------------------------------------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| [Sign Protocol](/products-sign-ecosystem/sign-protocol) | Evidence, attestation, and verification primitives | Schemas, attestations, verification references, audit anchors                      | Platform teams, regulated operators, auditors, integrators |
| [TokenTable](/products-sign-ecosystem/tokentable)       | Allocation and distribution workflows              | Allocation manifests, vesting schedules, execution outcomes, distribution evidence | Program operators, treasury teams, distributors, auditors  |
| [EthSign](/products-sign-ecosystem/ethsign)             | Agreements and signature workflows                 | Signed agreements, execution proofs, signature verification evidence               | Procurement, legal, compliance, institutional operators    |

A useful mental model is:

* **Sign Protocol** defines how actions are expressed as verifiable records and how those records are verified later.
* **TokenTable** determines who receives what, when, and under which rules, then produces deterministic distribution outputs.
* **EthSign** captures agreements and approvals as verifiable proof of execution.

***

## How products relate to S.I.G.N.

S.I.G.N. groups national deployments into three system domains. Products do not replace these systems. They are deployed to implement specific capabilities inside them where appropriate.

| National system                                            | What it needs                                                                                            | Products commonly used                                                                                 |
| ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| [New Money System](/national-systems/new-money-system)     | policy-controlled payment execution, supervisory visibility, settlement references                       | Sign Protocol for evidence, plus settlement rails and operators                                        |
| [New ID System](/national-systems/new-id-system)           | credential issuance and verification, trust registries, status and revocation, privacy-preserving proofs | Sign Protocol for anchoring accreditation and verification evidence, plus issuer and verifier services |
| [New Capital System](/national-systems/new-capital-system) | eligibility-gated allocation, schedules, reconciliation, inspection-ready reporting                      | TokenTable for allocation and execution, Sign Protocol for evidence and audits                         |

A deployment may use Sign Protocol without TokenTable or EthSign. TokenTable and EthSign can also be deployed independently, depending on workflow requirements and operating constraints.

***

## Composition patterns

### Pattern A: Evidence-first deployments

Use when the primary requirement is standardizing verification and auditability across applications and operators.

Typical uses:

* accreditation and authorization records
* verification evidence and inspection packages
* compliance approvals and ruleset version anchoring
* registry state transitions and dispute trails

Start with:

* [Sign Protocol](/products-sign-ecosystem/sign-protocol)
* [Writing Data](/for-builders/index-1)
* [Querying Data](/for-builders/index)

### Pattern B: Programmatic distribution deployments

Use when value must be distributed at scale under deterministic rules, with reconciliation and inspection-ready reporting.

Typical uses:

* benefits and subsidy distribution
* grants and incentives
* budget-constrained programs with reconciliation requirements
* vesting and unlock schedules with controlled claiming

Start with:

* [TokenTable](/products-sign-ecosystem/tokentable)
* [New Capital System](/national-systems/new-capital-system)
* [Sign Protocol](/products-sign-ecosystem/sign-protocol)

### Pattern C: Agreement and approval workflows

Use when agreements, acknowledgements, and approvals must be cryptographically verifiable and linked to downstream execution evidence.

Typical uses:

* procurement agreements and operator onboarding
* compliance acknowledgements and policy acceptance
* governed approvals for high-impact actions
* institutional signature workflows tied to audit evidence

Start with:

* [EthSign](/products-sign-ecosystem/ethsign)
* [Sign Protocol](/products-sign-ecosystem/sign-protocol)

***

## Integration boundaries

These products are designed to integrate with existing sovereign and regulated infrastructure.

### Identity systems

S.I.G.N. deployments often use W3C Verifiable Credentials and DID-based identity primitives. Products integrate with issuer, wallet, and verifier components rather than imposing a single identity stack.

* Identity blueprint: [New ID System](/national-systems/new-id-system)

### Money rails

The ecosystem does not assume a single settlement rail. Deployments may use private CBDC rails, regulated stablecoins on public rails, or hybrid architectures.

* Money blueprint: [New Money System](/national-systems/new-money-system)

### Governance and operations

Institutional deployments must make control explicit: keys, upgrades, emergency actions, access policies, and evidence retention. Governance is treated as part of the system, not a post-deployment add-on.

* Operational model: [Governance & Operations](/s.i.g.n./governance-ops)
* Controls posture: [Security & Privacy](/s.i.g.n./security-privacy)

***

## Product selection guide

Choose based on the requirement you are trying to satisfy.

If you need to:

* standardize verifiable records, approvals, and audit trails across systems\
  Start with [Sign Protocol](/products-sign-ecosystem/sign-protocol).
* allocate and distribute value at scale with deterministic schedules and reconciliation\
  Start with [TokenTable](/products-sign-ecosystem/tokentable), and pair it with [Sign Protocol](/products-sign-ecosystem/sign-protocol) for evidence.
* capture agreements and signatures in institutional workflows and prove execution later\
  Start with [EthSign](/products-sign-ecosystem/ethsign), and pair it with [Sign Protocol](/products-sign-ecosystem/sign-protocol) for verification and audit references.

If you are unsure, start from the system domain and work downward:

* [New Money System](/national-systems/new-money-system)
* [New ID System](/national-systems/new-id-system)
* [New Capital System](/national-systems/new-capital-system)

***

## Where to go next

* Read product docs:
  * [Sign Protocol](/products-sign-ecosystem/sign-protocol)
  * [TokenTable](/products-sign-ecosystem/tokentable)
  * [EthSign](/products-sign-ecosystem/ethsign)
* Build and integrate:
  * [For Builders](/for-builders/getting-started)
  * [Supported Networks](/for-builders/address-book)
  * [Writing Data](/for-builders/index-1)
  * [Querying Data](/for-builders/index)
* Clarifications:
  * [FAQ](/faq)


# Sign Protocol (Evidence Layer)

The core evidence, attestation, and verification layer powering the S.I.G.N. stack.

## What is Sign Protocol?

Sign Protocol is the **cryptographic evidence layer** of the S.I.G.N. stack.

It enables governments, institutions, and developers to:

* define structured schemas,
* issue verifiable attestations,
* anchor evidence across chains and systems,
* query, verify, and audit data reliably.

Sign Protocol is **infrastructure**, not an application.

***

## What Sign Protocol does

* Standardizes how facts are expressed (schemas)
* Cryptographically binds data to issuers and subjects
* Enables selective disclosure and privacy
* Supports public, private, and hybrid attestations
* Provides immutable audit references

***

## Core primitives

### Schemas

Schemas define:

* data structure,
* field types,
* validation rules,
* versioning.

They ensure attestations are **machine-readable and interoperable**.

***

### Attestations

Attestations are signed statements such as:

* “This citizen is eligible”
* “This payment was executed”
* “This entity passed compliance”
* “This program followed rule version X”

They can be:

* public,
* private,
* ZK-based,
* cross-chain.

***

### Indexing & querying

SignScan aggregates attestations across:

* chains,
* storage layers,
* execution environments.

Builders can query via:

* REST
* GraphQL
* SDKs

***

## Where Sign Protocol fits

Sign Protocol underpins:

* [New ID System](/national-systems/new-id-system) (identity & credentials)
* [New Money System](/national-systems/new-money-system) (payment evidence)
* [New Capital System](/national-systems/new-capital-system) (distribution & audits)
* Products like [EthSign](/products-sign-ecosystem/ethsign) and [TokenTable](/products-sign-ecosystem/tokentable)

***

## Who should use it

* protocol developers
* government platform teams
* auditors and compliance systems
* enterprise integrators

***

## Where to go next

* Developer docs: [For Builders](/for-builders/getting-started)
* Use cases:
  * [New ID System](/national-systems/new-id-system)
  * [New Money System](/national-systems/new-money-system)
  * [New Capital System](/national-systems/new-capital-system)
* Products:
  * [EthSign](/products-sign-ecosystem/ethsign)
  * [TokenTable](/products-sign-ecosystem/tokentable)


# TokenTable

TokenTable is the sovereign-grade allocation, vesting, and distribution engine for capital, benefits, and tokenized programs under the S.I.G.N. stack.

## What is TokenTable?

TokenTable is the **capital allocation and distribution engine** of the S.I.G.N. ecosystem.

It is designed to handle **large-scale, rules-driven distributions** of value, including:

* government benefits and subsidies,
* grants and incentive programs,
* tokenized capital and assets,
* ecosystem and protocol distributions,
* regulated airdrops and unlocks.

TokenTable focuses on **who gets what, when, and under which rules**, while delegating **evidence, identity, and verification** to Sign Protocol.

***

## Why TokenTable exists

Traditional distribution systems rely on:

* spreadsheets and manual reconciliation,
* opaque beneficiary lists,
* one-off scripts or centralized payment processors,
* post-hoc audits that are slow and incomplete.

These approaches do not scale and are prone to:

* duplicate payments,
* eligibility fraud,
* operational errors,
* weak accountability.

TokenTable replaces these with **deterministic, auditable, programmatic distributions**.

***

## Core responsibilities

TokenTable is responsible for:

* defining allocation logic,
* executing distributions,
* managing vesting and unlock schedules,
* enforcing eligibility constraints,
* producing deterministic allocation outputs.

It is **not** responsible for identity issuance or cryptographic evidence — those are handled by Sign Protocol.

***

## Key capabilities

### 1) Allocation tables

TokenTable operates on allocation tables that define:

* beneficiary identifiers (DIDs, addresses, or internal references),
* allocation amounts,
* vesting parameters,
* claim conditions,
* revocation and clawback rules.

Allocation tables are versioned and immutable once finalized.

***

### 2) Vesting and unlocks

Supported vesting models include:

* immediate release,
* cliff-based vesting,
* linear vesting,
* custom schedules.

Each vesting schedule is enforced deterministically by the system.

***

### 3) Claim execution

TokenTable supports:

* direct distribution (push),
* beneficiary-initiated claiming (pull),
* delegated claiming (third-party execution),
* batched settlement.

Execution can occur on:

* private CBDC rails,
* public regulated stablecoins,
* public blockchain tokens.

***

### 4) Revocation and clawback

Programs may define:

* revocation conditions,
* partial or full clawbacks,
* emergency freezes,
* expiry windows.

All revocations are versioned and auditable.

***

### 5) Delegation and operators

TokenTable supports operational delegation:

* custodians executing on behalf of beneficiaries,
* government agencies operating sub-programs,
* service providers handling claims.

Delegation is policy-controlled and logged.

***

## Relationship to Sign Protocol

TokenTable integrates tightly with Sign Protocol:

* eligibility proofs are referenced via attestations,
* allocation manifests are anchored as evidence,
* execution results are linked to settlement attestations,
* audits replay allocation logic deterministically.

TokenTable **consumes** Sign Protocol evidence and **produces** new evidence.

***

## Canonical flows

### Flow 1: Welfare or subsidy distribution

1. Eligibility verified via [New ID System](/national-systems/new-id-system)
2. Eligibility evidence anchored via [Sign Protocol](/products-sign-ecosystem/sign-protocol)
3. Allocation table generated in [TokenTable](/products-sign-ecosystem/tokentable)
4. Funds distributed according to rules
5. Allocation + execution evidence published

***

### Flow 2: Grant or incentive program

1. Applications collected and evaluated
2. Scoring and eligibility finalized
3. Allocation table published
4. Vesting schedules enforced
5. Public or restricted audit trail provided

***

### Flow 3: Tokenized capital distribution

1. Define token or asset class
2. Generate allocation table
3. Enforce vesting and unlocks
4. Support secondary compliance checks
5. Anchor final settlement evidence

***

## Example allocation manifest (illustrative)

```
{
  "program_id": "EDUCATION_GRANT_2026",
  "ruleset_version": "v1.2",
  "asset_type": "CBDC",
  "total_budget": "25000000",
  "currency": "CBDC",
  "allocations": [
    {
      "beneficiary_ref": "did:example:citizen:92fa...",
      "amount": "5000",
      "vesting": "immediate",
      "eligibility_ref": "attestation:0xabc123..."
    }
  ],
  "generated_at": "2026-06-01T09:00:00Z"
}
```

***

## Governance and controls

TokenTable supports:

* program-level governance,
* allocation approval workflows,
* ruleset versioning,
* emergency pause and rollback,
* audit and reconciliation tooling.

Governance actions are logged and referenceable.

***

## Security model

* deterministic execution
* role-based permissions
* cryptographic references to eligibility and settlement
* separation of concerns between allocation, evidence, and payment rails

***

## Typical users

* government finance ministries
* welfare and social services agencies
* regulators overseeing distribution programs
* Web3 protocols and ecosystems
* auditors and compliance teams

***

## Where TokenTable fits in S.I.G.N.

TokenTable sits between:

* [**New ID System**](/national-systems/new-id-system) (who is eligible),
* [**New Money System**](/national-systems/new-money-system) (how value moves),
* [**Sign Protocol**](/products-sign-ecosystem/sign-protocol) (what evidence exists).

It ensures capital moves **according to rules**, not discretion.

***

## Where to go next

* Capital architecture: [New Capital System](/national-systems/new-capital-system)
* Identity prerequisites: [New ID System](/national-systems/new-id-system)
* Evidence layer: [Sign Protocol](/products-sign-ecosystem/sign-protocol)
* Money rails: [New Money System](/national-systems/new-money-system)


# EthSign

Legal agreements, signatures, and compliance workflows built on Sign Protocol.

## What is EthSign?

EthSign is a **legal and agreement product** built on top of Sign Protocol.

It allows users and organizations to:

* create legally binding agreements,
* sign documents digitally,
* verify signatures cryptographically,
* anchor proof of agreement on-chain.

***

## Key capabilities

* digital document signing
* multi-party workflows
* jurisdiction-aware compliance
* immutable proof of execution
* integration with wallets and identities

***

## Why it matters

EthSign bridges:

* legal systems ↔ cryptographic proof
* off-chain agreements ↔ on-chain verification
* Web2 compliance ↔ Web3 attestations

***

## Relationship to Sign Protocol

EthSign:

* uses Sign Protocol schemas and attestations,
* emits verifiable evidence of agreements,
* acts as a **vertical application**, not infrastructure.

***

## Example use cases

* government procurement
* enterprise contracts
* compliance acknowledgements
* DAO or protocol governance agreements

***

## Where to go next

* Core infrastructure: [Sign Protocol](/products-sign-ecosystem/sign-protocol)
* Identity integration: [New ID System](/national-systems/new-id-system)
* Audit trail concepts: [Use Cases](/national-systems/new-money-system)


# Quickstart

A brief introduction to Sign Protocol for hackers.

### Introduction

Sign Protocol is an omni-chain attestation protocol, enabling users to freely attest and retrieve structured and verifiable data on-chain. It also accommodates large-size data by offloading storage to IPFS\* and Arweave. With Sign Protocol, participating contracts collectively define data schemas and deposit relevant data in the form of attestations in Sign Protocol's smart contract.

*\*Storage on IPFS is free but not permanent. We recommend Arweave over IPFS.*

### Getting Started

#### Defining a Schema

A schema is a representation or configuration that defines the type and structure of data that is presented in the making of an attestation. Schemas create standards that allow an attestation to be accurate, composable, and insightful for any observer (verifier).

A helpful analogy to understand a schema is to envision it as the blueprint for an attestation. A schema facilitates how an attester provides the much-needed context and confirmation in the attestation they wish to create.

To create a schema, you will need to understand the attestation you are trying to create. What kind(s) of information are you planning to store in an attestation and how large will the data be? Typically, all data is stored onchain. However, larger datasets will be cheaper to store offchain in a [Hybrid Attestation](/for-builders/advanced-topics/hybrid-attestations) or fully off-chain on Arweave/IPFS.

<figure><img src="/files/9q2pecUfvCJvJQfsuK7o" alt=""><figcaption><p>Storage Solutions for Sign Protocol</p></figcaption></figure>

You can read more about schemas [here](/reference/index/schema) and can find examples [here](/for-builders/getting-started/tutorials/building-a-simple-notary-platform/schema-creation) and [here](/for-builders/index-1/npm-sdk/examples).

#### Schema Hooks

To use a schema hook with the schema you are creating, you will need to create a smart contract that implements the functions defined [here](/for-builders/index-1/index/index/index/isphook). Schema Hooks can help you whitelist attesters, charge fees, and perform other application logic when attestations are created or revoked. If you would like to see a sample whitelist schema hook, please navigate to the [Schema Hooks](/for-builders/advanced-topics/schema-hooks) page.

#### Creating an Attestation

Sign Protocol implements attestations as digitally signed structured data that adhere to a registered schema under a schema registry. These attestations are then stored in a secure domain, either on-chain or off-chain. You will need to create or find a schema before creating an attestation.

Your attestation must adhere to its schema's defined format in order to be parseable. To learn more about the concept of attestations, you can find more information [here](/reference/index/attestations). To create an attestation, you can find examples [here](/for-builders/getting-started/tutorials/building-a-simple-notary-platform/attestation-creation) and [here](/for-builders/index-1/npm-sdk/examples). If you would like to create attestations on behalf of a user (to sponsor gas, for example), you will need to provide a delegate signature from the user when creating the attestation. You can find examples of delegate attestation creation with our NPM SDK [here](/for-builders/index-1/npm-sdk/examples).

#### Querying for Attestations

Sign Protocol offers an indexing service to quickly query and retrieve schema and attestation data. This service is available at a [REST](/for-builders/index/index-1) endpoint and a [GraphQL](/for-builders/index-1) endpoint and can also be accessed directly through our [NPM SDK](/for-builders/index/index/indexing-service).

### Final Details

You can find more development-related details and examples using Sign Protocol in the [For Builders](/for-builders/getting-started) section of the docs. If you are interested in seeing the thought process behind Sign Protocol and the higher-level overview of relevant topics, see the [For Thinkers](/for-thinkers/a-future-of-verifiable-trust) section of the docs.

We recommend using a testnet for building on Sign Protocol during the hackathon. You can find a list of supported networks [here](/for-builders/address-book). If we do not currently support a network you are looking to build on, reach out to us on Discord and we will see if we can support it.

Lastly, if you encounter any bugs, think there is something missing/incorrect in the docs, or have any questions, please reach out to the Sign Protocol team on ETHGlobal's Discord channel. We cannot wait to see what you build and look forward to interacting with you over the course of the hackathon and beyond!

As a developer on Sign Protocol, we would love to hear from you! Please join Sign's [Discord](https://discord.gg/NQ2v4cJNDs) channel and [Telegram](https://t.me/signecosystem) developer chat.


# Getting Started

***

### description: An overview of S.I.G.N. and the underlying systems that power sovereign digital infrastructure.

## S.I.G.N.

* [Overview](https://github.com/EthSign/sign-protocol-docs/blob/main/for-builders/getting-started/sign/README.md)
* [Reference Architecture](https://github.com/EthSign/sign-protocol-docs/blob/main/for-builders/getting-started/sign/reference-architecture.md)
* [Security & Privacy](https://github.com/EthSign/sign-protocol-docs/blob/main/for-builders/getting-started/sign/security-privacy.md)
* [Governance & Operations](https://github.com/EthSign/sign-protocol-docs/blob/main/for-builders/getting-started/sign/governance-ops.md)

## Use Cases

* [New Money System](https://github.com/EthSign/sign-protocol-docs/blob/main/for-builders/getting-started/use-cases/new-money-system.md)
* [New ID System](https://github.com/EthSign/sign-protocol-docs/blob/main/for-builders/getting-started/use-cases/new-id-system.md)
* [New Capital System](https://github.com/EthSign/sign-protocol-docs/blob/main/for-builders/getting-started/use-cases/new-capital-system.md)

## Getting Started with S.I.G.N.

### Introduction

S.I.G.N. is sovereign-grade digital infrastructure designed to support national-scale systems for **money**, **identity**, and **capital**.

Modern government and regulated financial systems increasingly rely on digital execution: CBDCs, regulated stablecoins, national ID systems, subsidy distribution, and tokenized real-world assets (RWA). While these systems appear different on the surface, they all depend on the same foundational requirements:

* Verifiable identity and eligibility
* Programmable execution rules
* Durable, inspectable records
* Interoperability across chains and systems
* Auditability without sacrificing privacy

S.I.G.N. provides a unified infrastructure layer that addresses these requirements through three interoperable systems.

***

### The Three Systems of S.I.G.N.

#### New Money System

The New Money System enables CBDCs and regulated stablecoins to operate on both public and private blockchains with policy controls, auditability, and interoperability.

It supports:

* Public-chain deployments (L1/L2) for transparency and composability
* Private-chain deployments (e.g. Fabric-based CBDC rails) for confidentiality
* Bridging between public and private money systems
* Identity-bound and policy-constrained execution

#### New ID System

The New ID System provides national digital identity and verifiable credentials using open standards.

It enables:

* W3C Verifiable Credentials (VC) and DIDs
* Selective disclosure and privacy-preserving proofs
* Cross-agency and cross-platform verification
* Trust registries and revocation mechanisms

#### New Capital System

The New Capital System supports tokenized real-world assets (RWA) and programmable capital distribution.

It enables:

* Large-scale allocation and distribution (grants, subsidies, incentives)
* Compliance-aware transfers and vesting
* Identity-gated participation
* Real-time reporting and audit trails

***

### The Trust and Evidence Layer (Where Sign Protocol Fits)

All three systems rely on a shared **trust and evidence layer** to record, verify, and query structured claims over time.

This layer is implemented by **Sign Protocol**.

Sign Protocol is an omni-chain attestation protocol that allows systems to define schemas and deposit verifiable data—called *attestations*—on-chain or via decentralized storage, while remaining easily discoverable and queryable.

Without a shared trust layer like Sign Protocol, digital systems face the same fragmentation problems:

1. Data is scattered across contracts, chains, and storage systems.
2. Developers must reverse-engineer contract interfaces and data layouts.
3. Historical state changes are difficult to track consistently.
4. Indexing requires bespoke infrastructure for each application.
5. Auditing and inspection become manual and error-prone.

Sign Protocol solves this by standardizing how structured data is defined, written, linked, and queried.

***

### How Sign Protocol Works

Sign Protocol is composed of several interoperable components.

<figure><img src="/files/WdJE3FtqLbfLclkBjBTE" alt=""><figcaption><p>An architectural overview of Sign Protocol</p></figcaption></figure>

#### Writing Data

Sign Protocol organizes data into two core primitives:

* **Schemas** — structured templates defining data formats
* **Attestations** — signed instances of schema-conformant data

Data can be written using three storage models:

* Fully on-chain (EVM, Starknet, Solana, TON)
* Fully Arweave
* Hybrid (on-chain references + off-chain payloads)

<figure><img src="/files/9q2pecUfvCJvJQfsuK7o" alt=""><figcaption><p>Storage solutions supported by Sign Protocol</p></figcaption></figure>

Fully on-chain and hybrid transactions can be initiated directly. Fully Arweave transactions are initiated through the Sign Protocol API. Once finalized, SignScan automatically indexes the data.

#### Reading Data

Data can be retrieved in two primary ways:

* **Direct reads** from smart contracts and Arweave\
  Suitable for low-level access, but limited in filtering and aggregation.
* **SignScan APIs**\
  SignScan is Sign’s indexing and aggregation service, providing REST and GraphQL APIs that unify data across all supported chains. It also powers the public explorer at <https://scan.sign.global>.

This architecture allows developers, auditors, and operators to focus on system logic rather than data plumbing.

***

### How This Enables Sovereign Systems

By combining:

* standardized attestations (Sign Protocol),
* identity-bound credentials (New ID),
* programmable execution (New Money, New Capital),

S.I.G.N. enables governments and regulated institutions to build systems that are:

* **Privacy-preserving to the public**
* **Inspectable by authorized parties**
* **Composable across programs**
* **Auditable by design**

***

### What’s Next?

Depending on your role:

* **Builders** can dive deeper into:
  * Sign Protocol smart contracts
  * SDKs and APIs
  * Indexing and querying
* **System designers** can explore:
  * Use cases for Money, ID, and Capital
  * Reference architectures
  * Governance and deployment models

Continue to:

* Sign Protocol Documentation
* Use Case Guides
* Integration Tutorials


# Fundamentals

This article will help you understand the basic building blocks of Sign Protocol.

<figure><img src="/files/LcVIczEpilAQo3dI0akf" alt=""><figcaption><p>ERD demonstrating the relationship between schemas and attestations</p></figcaption></figure>

### Schema

```solidity
struct Schema {
    address registrant;
    bool revocable;
    DataLocation dataLocation;
    uint64 maxValidFor;
    ISPHook hook;
    uint64 timestamp;
    string data;
}
```

* `registrant`: The address that registered this schema.
* `revocable`: Whether Attestations that adopt this Schema can be revoked.
* `dataLocation`: Where `Schema.data` is stored. See [DataLocation](#datalocation).
* `maxValidFor`: The maximum number of seconds that an Attestation can remain valid. 0 means Attestations can be valid forever. This is enforced through `Attestation.validUntil`.
* `hook`: The `ISPHook` that is called at the end of every function. 0 means no hook is set. See [ISPHook](#isphook).
* `timestamp`: When the schema was registered. This is automatically populated by `_register(...)`.
* `data`: The raw schema that `Attestation.data` should follow. Since there is no way to enforce this, it is a `string` for easy readability.

#### Notes

* Utilize the [ISPHook](#isphook) to take payments.
* Reverting from within the [ISPHook](#isphook) will revert the entire transaction, so the hook can provide additional checks and logic to validate attestation creation (for example, checking a whitelist). Use the `Attestation.extraData` field to pass in additional information that can be used from within the hook.

### Attestation

```solidity
struct Attestation {
    uint64 schemaId;
    uint64 linkedAttestationId;
    uint64 attestTimestamp;
    uint64 revokeTimestamp;
    address attester;
    uint64 validUntil;
    DataLocation dataLocation;
    bool revoked;
    bytes[] recipients;
    bytes data;
}
```

* `schemaId`: The `Schema` that this Attestation is based on. It must exist.
* `linkedAttestationId`: Useful if the current Attestation references a previous Attestation. It can either be 0 or an existing attestation ID.
* `attestTimestamp`: When the attestation was made. This is automatically populated by `_attest(...)`.
* `revokeTimestamp`: When the attestation was revoked. This is automatically populated by `_revoke(...)`.
* `attester`: The attester.
* `validUntil`: The expiration timestamp of the Attestation. Must respect `Schema.maxValidFor`. 0 indicates no expiration date.
* `dataLocation`: Where `Attestation.data` is stored. See [DataLocation](#datalocation).
* `revoked`: If the Attestation has been revoked. It is possible to make a revoked Attestation.
* `recipients`: The intended ABI-encoded recipients of this Attestation. This is of type `bytes` to support non-EVM recipients.
* `data`: The raw data of the Attestation based on `Schema.schema`. There is no enforcement here, however. Recommended to use `abi.encode`.

#### Notes

* `attester` will be the caller of `attest()` by default. If a delegate signature is supplied with the call, `attester` will be the address found in the `Attestation` object supplied to the function instead of the caller of `attest()`.
* `recipients` is an array of addresses. A single attestation can support many recipients. If no recipient is provided when an attestation is created, the `attester` is used.
* `data` does not have any enforcement for what is supplied when an attestation is created by default. This validation can be performed in an [ISPHook](#isphook) on the schema. You can use `abi.encode` and `abi.decode` to perform the data handling, or use other functions like viem's `encodeAbiParameters` and `decodeAbiParameters` to work with the data in the frontend.

### ISPHook

```solidity
interface ISPHook {
    function didReceiveAttestation(
        address attester,
        uint64 schemaId,
        uint64 attestationId,
        bytes calldata extraData
    )
        external
        payable;

    function didReceiveAttestation(
        address attester,
        uint64 schemaId,
        uint64 attestationId,
        IERC20 resolverFeeERC20Token,
        uint256 resolverFeeERC20Amount,
        bytes calldata extraData
    )
        external;

    function didReceiveRevocation(
        address attester,
        uint64 schemaId,
        uint64 attestationId,
        bytes calldata extraData
    )
        external
        payable;

    function didReceiveRevocation(
        address attester,
        uint64 schemaId,
        uint64 attestationId,
        IERC20 resolverFeeERC20Token,
        uint256 resolverFeeERC20Amount,
        bytes calldata extraData
    )
        external;
}
```

A hook is registered for a specific schema. We will refer to this schema in the following definitions.

* `didReceiveAttestation` - Called when an attestation is created for the schema. The second definition of this function is to take payments.
* `didReceiveRevocation` - Called when an attestation is revoked for the schema. The second definition of this function is to take payments.

### Other Types

#### OffchainAttestation

```solidity
struct OffchainAttestation {
    address attester;
    uint64 timestamp;
}
```

* `attester`: The attester. At this time, the attester must be the caller of `attestOffchain()`.
* `timestamp`: The `block.timestamp` of the function call.

#### Notes

* `OffchainAttestation` is meant for true off-chain attestations where data is stored in other servers and a simple trace or record of the attestation is stored on-chain. This is distinct from the "Offchain Attestations" you can make from Sign Protocol's schema and attestation builders as these use schemas and attestations with data stored on Arweave, similar to how data is handled on-chain.

#### DataLocation

```solidity
enum DataLocation {
    ONCHAIN,
    ARWEAVE,
    IPFS,
    CUSTOM
}
```

This enum indicates where `Schema.data` and `Attestation.data` are stored.

#### Notes

* A `DataLocation` that is not `ONCHAIN` means that an associated attestation will be a [Hybrid Attestation](/for-builders/advanced-topics/hybrid-attestations). The SDK handles this case for you, but if you are directly interacting with any of the Sign Protocol smart contracts, ensure that you are passing in the correct `data` values (encoded CIDs) when creating a hybrid attestation.


# Tutorials


# Building a Simple Notary Platform

Through this tutorial, we will utilize direct interaction with the Sign Protocol [Smart Contract](/for-builders/index-1/index/index/index/isp), the [NPM SDK](/for-builders/index-1/npm-sdk), and the Indexing Service's APIs to query for attestations.

### Problem Statement: A Basic IRL Notary Platform

For simplicity, let's assume that Bob needs to sign a contract physically and needs the signature notarized by a second person, Alice. With digital signatures, anybody can validate the signature using public keys, but for signatures in real life, this cannot be easily done. How can we be sure that Bob signed instead of another person forging his signature? Enter Alice, a trusted notary. Alice's whole job is centered around attesting that the person signing a contract is who they say they are. If people know they can trust Alice, they know that Bob did indeed sign the contract if Alice says so. We will implement a system where Alice can attest Bob's signature using attestations on Sign Protocol.

### Finished Code

The finished code from this tutorial can be found [here](https://github.com/EthSign/sign-protocol-sdk-tutorial).


# Schema Creation

Creating a schema for a basic notary system.

## Understanding What We Need

The first step to creating a successful schema is understanding exactly what data your application needs. Let's say, for our application, we want to store two things:

* contractDetails: a string of text, corresponding to what Bob is signing
* signer: an address, corresponding to Bob's account

Note that the attester's address is automatically recorded in any attestation, so we do not need to store this in our schema.

## Creating the Schema

Now that we know what we want to store, we will create a schema on Sign Protocol. We can accomplish this in two ways: first, we can use the [Schema Builder](https://app.sign.global/create-schema). This is perfect for non-coders or setting up a schema quickly, rather than performing the action through code. Second, we can create it by directly interfacing with Sign Protocol's Smart Contract or using the NPM SDK.

The first step is to name your schema, add a description, and choose where to store attestation data. In this tutorial, we will store data on-chain using the Base Sepolia Testnet. Once you choose your configuration, continue to the next step.

{% hint style="warning" %}
NOTE: If you select a data storage option that is not directly on-chain (such as Arweave/IPFS), your schema will require [Hybrid Attestations](https://github.com/EthSign/sign-protocol-docs/blob/main/for-builders/getting-started/advanced-topics/hybrid-attestations.md). Our SDK will handle this for you, but if you are interacting directly with Sign Protocol smart contracts, ensure that you are passing in an encoded Content ID (CID) as `data` when creating a hybrid attestation.
{% endhint %}

### Schema Builder

<figure><img src="/files/oOfBSkfk2ff9A3yyfjZv" alt=""><figcaption><p>Schema Builder Metadata</p></figcaption></figure>

The next step is to create the schema's data structure. As stated earlier, we will create two fields: `contractDetails` and `signer`. The Schema Builder allows you to enter fields in a user-friendly UI or manually edit the JSON data structure (click "Input Raw Data"). Once you have entered your schema data structure fields, continue to the next step.

<figure><img src="/files/0VsvdoKXqUJlFHbylknr" alt=""><figcaption><p>Schema Builder Data Structure</p></figcaption></figure>

When creating a schema, you can designate an additional smart contract address that will be called whenever an event occurs (attestation created, revoked, etc). This can be useful for taking payments or reverting transactions (when some verification fails, i.e. whitelist), but it is outside the scope of this tutorial, so we will leave the field blank for now. We will leave the attestation as non-revocable: Alice cannot make mistakes. Once you have completed this step, press "Create Schema".

<figure><img src="/files/u2QmcPfPAF6X7s02qHf0" alt=""><figcaption><p>Schema Builder Final Details</p></figcaption></figure>

Success! You have successfully created your schema. Click "View Schema" to go to your schema's page.

<figure><img src="/files/NvXc6mV5N1b9nCuhuIvk" alt=""><figcaption><p>Schema Created</p></figcaption></figure>

### NPM SDK

Install the [SDK](#npm-sdk) into your project. Create a SignProtocolClient to make calls that write to the blockchain. The private key field is optional if you are operating from the frontend as the SDK will attempt to use `window.ethereum` if no private key is provided for signing transactions. If you use the SDK from a Node backend, you must provide a private key to make write calls to the blockchain.

{% hint style="warning" %}
NOTE: The `account` variable is marked as optional. If it is not provided, the SDK will use the provider from `window.ethereum` by default to derive an account. If a provider from `window.ethereum` cannot be located when an account is not provided, calls to the SDK will fail.
{% endhint %}

{% hint style="warning" %}
NOTE: You must provide an API key when initializing your SignClient to create offchain attestations. This key is optional for onchain attestations. You can generate a key [here](https://developer.sign.global/). For more information, see [Installation](/for-builders/index-1/npm-sdk/installation).
{% endhint %}

```typescript
const { SignProtocolClient, SpMode, EvmChains } = require("@ethsign/sp-sdk");
const { privateKeyToAccount } = require("viem/accounts");

const privateKey = "0x...";
const client = new SignProtocolClient(SpMode.OnChain, {
  chain: EvmChains.baseSepolia,
  account: privateKeyToAccount(privateKey), // Optional, depending on environment
  apiKey: 'xxx', // Optional for onchain, required for offchain
});
```

Next, you will need to create the schema we described above.

```typescript
const res = await client.createSchema({
  name: "SDK Test",
  data: [
    { name: "contractDetails", type: "string" },
    { name: "signer", type: "address" },
  ],
});
```

This will return information from the transaction, including the schema ID and transaction hash. For example, `res` may look like the following:

```json
{
  "schemaId": "0x34",
  "txHash": "0x..."
}
```

Now that you have created your schema, continue to the next page to create an attestation using this schema.


# Attestation Creation

Great! We now have a schema ready for use. We will refer to this schema throughout the remainder of the project by its ID, so save the ID of the schema you created. If you bypassed the previous step, you can use [this schema](https://testnet-scan.sign.global/schema/onchain_evm_84532_0x34) to continue through this tutorial (Schema ID: `onchain_evm_84532_0x34`). Note that the on-chain ID of the schema is `0x34` and we will use this when creating an attestation.

## Creating an Attestation

You can create an attestation using either our NPM SDK or by directly interacting with the respective Smart Contract for the specific network you are using.&#x20;

### Smart Contract Interaction

{% hint style="warning" %}
NOTE: If you selected a data storage option that is not directly on-chain (such as Arweave/IPFS), your schema will require [Hybrid Attestations](/for-builders/advanced-topics/hybrid-attestations). Our SDK will handle this for you, but if you are interacting directly with Sign Protocol smart contracts, ensure that you are passing in an encoded Content ID (CID) as `data` when creating a hybrid attestation.
{% endhint %}

Let's write a function that takes in a contract's message string and the address of the person who signed it. You can get the Contract Address in the [Address Book](/for-builders/address-book) and the latest ABI on Etherscan.

```typescript
import { Web3Provider } from "@ethersproject/providers";
import { BigNumber, Contract, ethers } from "ethers";

function createNotaryAttestation(contractDetails: string, signer: string) {
  let address = "0x..."; // Alice's address. Will need Alice's account to send the tx.
  let schemaData = ethers.utils.defaultAbiCoder.encode(
    ["string", "address"],
    [contractDetails, signer]
  );
  
  // Standard setup for the contract
  const provider = new ethers.providers.JsonRpcProvider(
    // Get an RPC URL (such as an infura link) to connect to the network
    getProviderUrl(84532)
  );
  // Get the contract address from the Address Book in docs.sign.global
  const contract = new Contract(CONTRACT_ADDRESS(84532), ISPABI.abi, provider);
  // Get the provider from the currently connected wallet
  const library = new Web3Provider(await connector.getProvider());
  // Create writable contract instance
  const instance = contract.connect(library.getSigner() as any) as Contract;
  
  // Send the attestation transaction
  try {
    await instance[
      "attest((uint64,uint64,uint64,uint64,address,uint64,uint8,bool,bytes[],bytes),string,bytes,bytes)"
    ](
      {
        schemaId: BigNumber.from("0x34"), // The final number from our schema's ID.
        linkedAttestationId: 0, // We are not linking an attestation.
        attestTimestamp: 0, // Will be generated for us.
        revokeTimestamp: 0, // Attestation is not revoked.
        attester: address, // Alice's address.
        validUntil: 0, // We are not setting an expiry date.
        dataLocation: 0, // We are placing data on-chain.
        revoked: false, // The attestation is not revoked.
        recipients: [signer], // Bob is our recipient.
        data: schemaData // The encoded schema data.
      },
      signer.toLowerCase(), // Bob's lowercase address will be our indexing key.
      "0x", // No delegate signature.
      "0x00" // No extra data.
    )
      .then(
        async (tx: any) =>
          await tx.wait(1).then((res) => {
            console.log("success", res);
            // You can find the attestation's ID using the following path:
            // res.events[0].args.attestationId
          })
      )
      .catch((err: any) => {
        console.log(err?.message ? err.message : err);
      });
  } catch (err: any) {
    console.log(err?.message ? err.message : err);
  }
}
```

### NPM SDK

The SDK simplifies the process rather than directly interacting with the smart contract. To perform the same action as above, we will do the following:

```typescript
function createNotaryAttestation(contractDetails: string, signer: string) {
  const res = await client.createAttestation({
    schemaId: "0x34",
    data: {
      contractDetails,
      signer
    },
    indexingValue: signer.toLowerCase()
  });
}
```

Note that we can pass in all the attestation information like we did when sending the transaction directly to the smart contract, but we do not need to. The SDK will fill in the blank fields with their respective defaults. `createAttestation` will return data in the following format:

```json
{
  attestationId: '0x..',
  txHash: '0x..',
  indexingValue: '...'
}
```

Now that you have successfully created an attestation, you need to be able to use it! When you're ready, move on to the next page.


# Querying Attestations

So now, how can you verify if Alice attested to Bob's signature? We will be using Sign Protocol's Indexing Service to do exactly that!

## Querying for an Attestation

You can query for an attestation using our NPM SDK or by making requests to our REST API.

### NPM SDK

Our [NPM SDK](#npm-sdk) includes an `IndexService` that you can use to query schemas and attestations.

```typescript
import { IndexService } from "@ethsign/sp-sdk";

async function queryAttestations() {
  const indexService = new IndexService("testnet");
    
  const attId = `onchain_evm_${chainId}_${attestationId}`;
  const res = await indexService.queryAttestationList({
    schemaId: "onchain_evm_84532_0x34", // Your full schema's ID
    attester: "0x...", // Alice's address
    page: 1,
    mode: "onchain", // Data storage location
    indexingValue: "0x...".toLowerCase(), // Bob's address
  });
  
  return {
    success: true,
    attestations: response.rows,
  };
}
```

### REST API

Alternatively, we will create a helper function that we can reuse to make requests to the Sign Protocol Indexing Service.

```typescript
import axios from "axios";

// Generate a function for making requests to the Sign Protocol Indexing Service
async function makeAttestationRequest(endpoint: string, options: any) {
  const url = `https://testnet-rpc.sign.global/api/${endpoint}`;
  const res = await axios.request({
    url,
    headers: {
      "Content-Type": "application/json; charset=UTF-8",
    },
    ...options,
  });
  // Throw API errors
  if (res.status !== 200) {
    throw new Error(JSON.stringify(res));
  }
  // Return original response
  return res.data;
}
```

Next, we will use this function to query for Alice's attestation of Bob's signature.

```typescript
async function queryAttestations() {
  const response = await makeAttestationRequest("index/attestations", {
    method: "GET",
    params: {
      mode: "onchain", // Data storage location
      schemaId: "onchain_evm_84532_0x34", // Your full schema's ID
      attester: "0x...", // Alice's address
      indexingValue: "0x...".toLowerCase(), // Bob's address
    },
  });

  // Make sure the request was successfully processed.
  if (!response.success) {
    return {
      success: false,
      message: response?.message ?? "Attestation query failed.",
    };
  }

  // Return a message if no attestations are found.
  if (response.data?.total === 0) {
    return {
      success: false,
      message: "No attestation for this address found.",
    };
  }

  // Return all attestations that match our query.
  return {
    success: true,
    attestations: response.data.rows,
  };
}
```

Great! So now, we have a list of available attestations that Alice has made, of Bob's signature. If we only need to check for the existence of at least one attestation that matches our criteria, we could stop here. But what if we wanted to validate the message that Alice was attesting? Perhaps there are several different contracts that Alice has notarized for Bob and we are looking for a specific one. When you are ready, move on to the next page where we will parse the attestation data.


# Parsing Attestation Data

Attestation data is encoded into a single hex string and can be decoded if you know the schema used to encode the data. With attestations on Sign Protocol, the attestation object returned also includes the schema's structure, which is exactly what we need.

{% hint style="warning" %}
NOTE: If you selected a data storage option that is not directly on-chain (such as Arweave/IPFS), your schema will utilize [Hybrid Attestations](/for-builders/advanced-topics/hybrid-attestations). Our SDK will handle this for you but note that you will receive an encoded Content ID (CID) as `data` when retrieving a hybrid attestation.
{% endhint %}

We will write a function that takes in a message and the list of attestations returned from our query. This function will find the specific attestation we are looking for and return it with the parsed data object.

{% hint style="info" %}
You can use our NPM SDK's `decodeOnChainData` function to decode your attestation data rather than directly interfacing with viem's `decodeAbiParameters` as shown in this tutorial. For more information and an example, see [here](/for-builders/index/index/indexing-service).
{% endhint %}

```typescript
import { decodeAbiParameters } from "viem";

function findAttestation(message: string, attestations: any[]) {
  // Iterate through the list of attestations
  for (const att of attestations) {
    if (!att.data) continue;

    let parsedData: any = {};
    
    // Parse the data.
    if (att.mode === "onchain") {
      // Looking for nested items in the on-chain schema
      try {
        const data = decodeAbiParameters(
          [att.dataLocation === "onchain" ? { components: att.schema.data, type: "tuple" } : { type: "string" }],
          att.data
        );
        parsedData = data[0];
      } catch (error) {
        // Looking for a regular schema format if the nested parse fails
        try {
          const data = decodeAbiParameters(
            att.dataLocation === "onchain" ? att.schema.data : [{ type: "string" }],
            att.data
          );
          const obj: any = {};
          data.forEach((item: any, i: number) => {
            obj[att.schema.data[i].name] = item;
          });
          parsedData = obj;
        } catch (error) {
          continue;
        }
      }
    } else {
      // Try parsing as a string (off-chain attestation)
      try {
        parsedData = JSON.parse(att.data);
      } catch (error) {
        console.log(error);
        continue;
      }
    }
    
    // Return the correct attestation and its parsed data.
    if(parsedData?.contractDetails === message) {
      return { parsedData, attestation: att };
    }
  }
  
  // Did not find the attestation we are looking for.
  return undefined;
}
```

Now, we can parse the attestations returned from our query to Sign Protocol's Indexing Service, perform additional checks, and utilize the data they contain. In our example, we can perform some action using Alice's attestation of Bob's signature, or display an error if no such valid attestation is found.

If you know the attestation or schema you are looking for, you can also directly request its data from the Sign Protocol Indexing Service. In our case, we were looking for an attestation that met certain criteria. To expand upon our example, if our application was responsible for creating Alice's attestation, it might make sense to store the returned ID in a database for quicker load times (querying will always take longer than direct access with an ID, even if marginally so).

## Finished Tutorial

You can find the finished tutorial implementation [here](https://github.com/EthSign/sign-protocol-sdk-tutorial).


# Delegate Attestation Creation

Through this tutorial, we will utilize direct interaction with the Sign Protocol [Smart Contract](/for-builders/index-1/index/index/index/isp) and the [NPM SDK](/for-builders/index-1/npm-sdk).

### Problem Statement: Delegate Attestation Creation

There are two main reasons for delegate attestation creation: when initiated offchain, delegate attestations allow your backend to pay the gas fees for your users; when initiated onchain, delegate attestations allow your smart contract to create attestations on behalf of wallets interacting with it. This tutorial assumes you have a schema created and know how to create an attestation. Any schema will work; if you need help getting started, refer to [Building a Simple Notary Platform](/for-builders/getting-started/tutorials/building-a-simple-notary-platform).

This tutorial will be split into two parts - a JS backend and a Solidity contract. Both parts will require shared code to be placed into your frontend for requesting a delegate signature from users.

### Finished Code

The finished code from this tutorial can be found in our examples repository [here](https://github.com/EthSign/sign-protocol-examples).


# Express Backend

We will start from a simple Express backend. You can use any backend infrastructure or library of your choosing but note that current library support is limited to JavaScript/TypeScript. Install `express`, `@ethsign/sp-sdk`, and `viem`.

```typescript
import express from "express";
const app = express()
const port = 3000

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})
```

This boilerplate code is the simplest backend you can create. It creates a new server and listens for requests on port 3000.

## Initializing the Sign Protocol Client

Since we are running this code from a backend server, Sign Protocol's SDK requires you to pass in a private key account when creating your `SignProtocolClient`. Typically, when no account is provided, the client will use `window.ethereum`, which does not exist in a backend environment. Your code should look something like the following, assuming you are building on Sepolia:

```typescript
import {
  SignProtocolClient,
  SpMode,
  EvmChains
} from "@ethsign/sp-sdk";
import { privateKeyToAccount } from "viem/accounts";

const privateKey = "0x..."; // account responsible for paying gas fees

const client = new SignProtocolClient(SpMode.OnChain, {
  chain: EvmChains.sepolia,
  account: privateKeyToAccount(privateKey) // required in backend environments
});
```

## Setting Up Your Controller

Your controller will be responsible for creating the attestation. Since this is a delegate attestation, it must provide the attestation object and the delegation signature. The backend is not responsible for generating the delegation signature because the user's wallet must sign a message to retrieve the signature. Your controller should look something like the following:

```typescript
app.post(
  "/delegate",
  async (req: Request<{}, {}, { attestation: Attestation; delegationSignature: string }>, res: Response) => {
    try {
      const { attestation, delegationSignature } = req.body;

      const response = await client.createAttestation(attestation, {
        delegationSignature
      });
      res.status(200).json({ message: response });
    } catch (error: any) {
      res.status(500).json({
        error: {
          message: error.message
        }
      });
    }
  }
);
```

## (Frontend) Generating a Delegation Signature

This section must be implemented on your frontend. Delegation signatures are a mechanism to allow a third party to upload an attestation on behalf of an attester. The attester must approve (sign) the attestation that is being created to prevent fraudulent attestations. In other words, you would not want someone making attestations using your wallet address without you approving the attestation content first - unapproved attestations could pose a major security threat. After attaining a signature from the user/attester, the attestation and signature can be sent to the backend we wrote above. Your frontend code should include the following:

```typescript
import {
  EvmChains,
  delegateSignAttestation
} from "@ethsign/sp-sdk";

const schemaId = "0x...";
const attestationData = {
  ...
};
const indexingValue = "0x...";

const res = await delegateSignAttestation(
  {
    schemaId: schemaId,
    data: attestationData,
    indexingValue: indexingValue
  },
  { chain: EvmChains.sepolia }
);

const attResponse = await fetch(`${YOUR_BACKEND_URL}/delegate`, {
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ attestation: res.attestation, delegationSignature: res.delegationSignature })
});

...

// You can now use `attResponse` for anything you need in your frontend code
```

## Recap

The general flow to create a delegated attestation using a backend is the following:

1. Generate the attestation content. This can be done on the frontend (as shown above) or on a dedicated backend (and then sent to the frontend for step 2).
2. Request a delegation signature from the user in a browser.
3. Forward the attestation and delegation signature to your dedicated backend.
4. Create the attestation, providing the attestation and delegation signature.


# Solidity

There are many reasons you may want to generate an attestation on behalf of a wallet interacting with your smart contract. However, this cannot be done without the wallet approving (signing) the attestation your smart contract is creating on their behalf. Signatures must be initiated from the frontend and forwarded to your smart contract to create the delegate attestation. Depending on your use case, it may make sense to generate the attestation object on the frontend, or you may need to generate it from the smart contract through a getter. For this tutorial, we will assume that the attestation is generated on the frontend, but we have examples [here](https://github.com/EthSign/sign-protocol-examples) to show how to create an attestation object in Solidity.

We will start with an empty solidity contract. We will need to import `ISP` and `Attestation` from `@ethsign/sign-protocol-evm`.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { ISP } from "@ethsign/sign-protocol-evm/src/interfaces/ISP.sol";
import { Attestation } from "@ethsign/sign-protocol-evm/src/models/Attestation.sol";

contract DelegateAttest is Ownable {
    constructor() Ownable(_msgSender()) { }
}
```

We will keep track of the Sign Protocol contract address. Create state variables and helper functions to set these values. This variable will need to be set based on the network you deploy your contract on, which can be found [here](/for-builders/address-book). Your contract should now look something like the following:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { ISP } from "@ethsign/sign-protocol-evm/src/interfaces/ISP.sol";
import { Attestation } from "@ethsign/sign-protocol-evm/src/models/Attestation.sol";

contract DelegateAttest is Ownable {
    ISP public spInstance;

    constructor() Ownable(_msgSender()) { }

    function setSPInstance(address instance) external onlyOwner {
        spInstance = ISP(instance);
    }
}
```

Create a function to handle delegate attestation creation. We will pass in the attestation object, indexing value, delegation signature, and extra data to mimic the Sign Protocol `attest` function, however, you can modify these parameters if you wish to hardcode the indexing value or extra data. The attestation object and delegation signature are required to create an attestation using delegation methods.

<pre class="language-solidity"><code class="lang-solidity">...
function createAttestation(Attestation calldata att, string calldata indexingKey, bytes calldata delegationSignature, bytes calldata extraData) external returns (uint64) {
<strong>    uint64 attestationId = spInstance.attest(att, indexingKey, delegationSignature, extraData);
</strong>    return attestationId;
}
...
</code></pre>

## (Frontend) Generating a Delegation Signature

This section must be implemented on your frontend. Delegation signatures are a mechanism to allow a third party to upload an attestation on behalf of an attester. The attester must approve (sign) the attestation that is being created to prevent fraudulent attestations. In other words, you would not want someone making attestations using your wallet address without you approving the attestation content first - unapproved attestations could pose a major security threat. After attaining a signature from the user/attester, the attestation and signature can be sent to the backend we wrote above. Your frontend code should include the following:

```typescript
import {
  EvmChains,
  delegateSignAttestation
} from "@ethsign/sp-sdk";

const schemaId = "0x...";
const attestationData = {
  ...
};
const indexingValue = "0x...";
const extraData = "0x...";

const res = await delegateSignAttestation(
  {
    schemaId: schemaId,
    data: attestationData,
    indexingValue: indexingValue
  },
  { chain: EvmChains.sepolia }
);

const response = await yourSmartContract.createAttestation(res.attestation, indexingValue, res.delegationSignature, extraData);

...

// You can now use `response` for anything you need in your frontend code
```

## Recap

The general flow to create a delegated attestation using a backend is the following:

1. Generate the attestation content. This can be done on the frontend (as shown above) or from your smart contract (and requested by the frontend for step 2).
2. Request a delegation signature from the user in a browser.
3. Pass in the attestation and delegation signature to your smart contract.
4. Create the attestation in your smart contract, providing the attestation and delegation signature.


# Examples


# Attestation Discord Bot

### Overview

<figure><img src="/files/7ajLDzAHXmPCYHWTx2HJ" alt=""><figcaption><p>AttestationBot in action</p></figcaption></figure>

EthSign's AttestationBot is a gatekeeping bot centered around attestations. Users can attest anything; by simply choosing an attestation's schema ID, Discord server administrators can use attestations from a specific schema to verify users within their Discord community. For a user's Discord account to be verified, the user must create an attestation with the chosen schema ID and sign a message with their wallet address to link their Discord account. Discord administrators can also require that a specific `Result` field be set to `true` on the attestations to add another layer of verification. Once these checks pass verification, users will be granted a role in Discord, granting them desired access as defined by the verification role in the server.

### Discord Admin Command Reference

<figure><img src="/files/8c59v2AMafu6szDykgoO" alt="" width="400"><figcaption><p>Configuring AttestationBot</p></figcaption></figure>

#### /register \<testnet> \<mode> \<schemaId> \<verifyAttestation> \[attester]

Register attestation data for the server's verification. Requires testnet (true/false), mode (on-chain/off-chain), the schema ID for verification, and whether or not to check the `Result` field (true/false). Optionally, Discord Server admins can supply an attester address for querying attestations created by a single address (a trusted delegate address).

#### /generate\_role \[name]

Generates a pre-defined Discord Role in the server with default permissions. If the name is left blank, the role's name will default to "Verified".

#### /set\_role \<role>

Sets the verification role to whichever role the user passes in as an argument.

#### /display\_count

If set to on, displays the number of verified users in the server.

### User Command Reference

#### /verify

DMs user a link for verification. Upon success, a role will be given to the user. Upon failure, tells the user why it failed (no role setup in server, no attestation linked to server, user already verified, etc).

## ID Format (Schema + Attestation)

IDs are generated in the following format: `{mode}_{chainType}_{chainId}_{id}`

Example schema ID: `onchain_evm_80001_0x3`

Example attestation ID: `onchain_evm_80001_0x11`

## Bot Initialization

#### 1. /register \<testnet> \<mode> \<schemaId> \<verifyAttestation> \[attester]

Register the Attestation-specific data for a server.

#### 2. /generate\_role or /set\_role

Set the verified role for a server.

#### 3. /display\_count (optional)

Show the number of verified users in a server.

#### 4. /verify

Users can now verify their Discord accounts to be granted special permissions as defined by the verified role.

## End User Verification Flow

1. Run /verify and click the link provided by direct message.
2. Connect MetaMask to the website.
3. Click the “Verify” button and sign the relevant message in MetaMask.
4. Return to Discord.

NOTE: If for any reason the role is removed from a verified Discord account in a Discord server, the user can simply re-run /verify and be granted the role without additional verification.

## Backend Endpoint Reference

#### /verify/:id

Validates request body message and signature for the given ID. If successful, the user is granted a role in the relevant Discord server, and the attestation ID is returned for display purposes. Failure will result in an error message.

#### /lookup/:id

Determines if the provided interaction ID exists in our backend. If successful, it will return data about the relevant Discord user for displaying on our frontend. Failure will result in an error message.

#### /interactions

Discord-specific endpoint used for all Discord bot commands generated through a Discord server.

#### /status

Used for pinging uptime of the server.

## Relevant Sign Protocol Code Examples

Querying for attestations and parsing the response:

```typescript
const endpoint = `${ATTESTATION_ENDPOINT}/index/attestations`;
// Use fetch() or axios to call the Sign Protocol indexing service:
const res = await AttestationRequest(
  endpoint,
  {
    method: "GET",
    // If we have an attester provided in the Discord Server's registration config,
    // we need to use it as the attester when querying. Otherwise, the recipient
    // (the address belonging to the user trying to verify themselves in Discord)
    // will be our attester. Use the recipient as the indexingValue (provided when
    // making an attestation) to query for the recipient when an attester is provided.
    params: attester
      ? {
          mode, // onchain/offchain
          schemaId, // {mode}_{chainType}_{chainId}_{id}
          attester: attester, // an address
          indexingValue: recipient.toLowerCase() // an address
        }
      : {
          mode, // onchain/offchain
          schemaId, // {mode}_{chainType}_{chainId}_{id}
          attester: recipient // an address
        }
  }
);

// Begin parsing the response from the indexing server.
if (!response.success) {
  return { success: false, message: response?.message ?? "Attestation query failed." };
}

// Check if there is no data matching our query.
if (response.data?.total === 0) {
  return { success: false, message: "No attestation for this address found." };
}

// Do something with the attestations found. We will "return" them in this example.
return {
  success: true,
  attestations: response.data.rows
};
```

Parsing the attestation data into a JSON Object:

```typescript
import { decodeAbiParameters } from "viem";

// List of attestations returned from indexing service.
const attestations = [...]; 

let dataObjects: any = [];
for (const att of attestations) {
  // No data to parse.
  if(!att.data) continue;
  
  // Use viem's decodeAbiParameters() to parse the data.
  // Note that this step may require slight modifications depending on the schema's
  // data type, such as nested tuples or parsing pure strings.
  const data = decodeAbiParameters(
    att.dataLocation === "onchain" ? att.schema.data : [{ type: "string" }],
    att.data
  );
  
  // Create a data object from the schema.
  const obj: any = {};
  data.forEach((item: any, i: number) => {
    obj[att.schema.data[i].name] = item;
  });
  
  // Add the obj to dataObjects.
  dataObjects.push(obj);
}

// Do something with the data objects we have recovered and populated in dataObjects.
// We can use the attestation data to determine if a user should be allowed into a
// Discord server based on some verification criteria, such as requiring an
// attestation's data to contain a field named "Result" with a value of "true".
```


# KYC-Gated Smart Contract Access Control

ZetaChain Airdrops 17.4M ZETA to Contributors Using TokenTable by EthSign

## Challenge <a href="#id-4476" id="id-4476"></a>

Under the ethos of progressive decentralization, L1 blockchains conduct airdrops to distribute ownership of the network to their community. Ideally, community members who participate in the network — by deploying smart contracts, testing applications, helping with ecosystem growth, etc.— are rewarded proportionately to the value they create.

A well-executed airdrop is essential in bootstrapping decentralization and real usage of a blockchain protocol and is also a huge marketing opportunity. ZetaChain allocated a total of 31.5M ZETA (1.5% of 2.1B ZETA total supply) to this [genesis mainnet airdrop](https://www.zetachain.com/blog/the-zetalabs-airdrop-pre-claim), with rewards allocated to over 800,000 contributors to ZetaLabs’ testnet. ([See full token distribution here](https://www.zetachain.com/docs/about/token-utility/distribution/)).

To ensure regulatory compliance, ZetaChain required KYC and AML checks on contributors receiving an airdrop greater than 200 ZETA; additionally, they prevented airdrop claiming from OFAC sanctioned geographies.

## Enter TokenTable <a href="#b726" id="b726"></a>

ZetaChain used EthSign’s [TokenTable ](https://www.tokentable.xyz/)to conduct their KYC-gated airdrop on January 31st, 2024. The engagement entailed the development of a custom version of TokenTable that facilitated a compliant, streamlined airdrop for both ZETA recipients and the ZetaChain team.

The following TokenTable modules were used to facilitate the ZetaChain airdrop:

* **KYC-Gated Smart Contract Access:** Integration of the reputable KYC/AML provider [SumSub](https://sumsub.com/) to verify the government identification and liveness of \~15,000 airdrop recipients. For these recipients, passing the KYC check is a smart-contract-enforced requirement to claim the airdrop.
* **Custom Claiming Interface:** Development of a co-branded TokenTable interface that recipients are routed to from ZetaHub to claim their airdrop. Users connecting to this custom interface from OFAC-sanctioned geographies will be blocked.
* **Pre-paid Gas Fees:** Before the airdrop, ZetaChain contributors could not obtain mainnet ZETA, so the [TokenTable Unlocker](broken://spaces/JP1jAQLitA1tqbIHqb4o/pages/evdFwVNh1DhoZAueoO8L) smart contract was outfitted with pre-pay gas fee functionality for claimers.

## Smart Contract Access Control via Sign Protocol <a href="#id-3ff7" id="id-3ff7"></a>

<figure><img src="/files/rDp218LvZPpGgjfIL3Rv" alt=""><figcaption><p>A KYCHook that gates TokenTable claiming</p></figcaption></figure>

In order to restrict non-KYC’ed addresses from claiming ZETA via TokenTable, the off-chain KYC verification status of recipient addresses must be communicated to [TokenTable’s Unlocker](broken://spaces/JP1jAQLitA1tqbIHqb4o/pages/evdFwVNh1DhoZAueoO8L) smart contract.

[SIGN Attestation Protocol](https://medium.com/ethsign/attestations-sign-everything-onchain-01db9ebf39e7) was implemented in parallel with SumSub to a) bind the airdrop recipient's wallet address to an their KYC verification status, and b) to port recipient addresses’ KYC verification status on-chain so that TokenTable’s Unlocker smart contract can validate it.

The airdrop claiming flow is as follows:

1. Whitelisted wallets from non-sanctioned geographies are able to connect to [claims.zetachain.com](https://claims.zetachain.com/).
2. Claimers can view how much ZETA they have available to claim, and any lockup terms.
3. Conduct KYC verification via Sumsub by submitting their government ID.
4. To bind their address and KYC verification, claimers must use SIGN Protocol to sign an attestation message that is a hash of their address and KYC status.
5. The TokenTable Unlocker smart contract must validate the KYC attestation before enabling the associated wallet to claim its ZETA airdrop.

{% embed url="<https://youtu.be/BTm0Bp-dzQ0>" %}

You can check out the SIGN Protocol attestation smart contract that is [deployed on ZetaChain mainnet here](https://zetachain.blockscout.com/address/0x1BC26dd23b773806f080Acf65Cfb744166be9463)!


# Supported Networks

Sign Protocol's maintained smart contract deployments are listed below.

Maintained EVM deployments are upgraded to version `1.1.4` and are owned by `0xAE45849165E17Dc555B8264dD4Ae01a3F42344e2`. Crossed-out networks are legacy deployments that are no longer maintained.

## Mainnet

|    Network   | Chain ID |                    Proxy                   | Version |                    Owner                   | GraphQL Subgraph                                                                                             |
| :----------: | -------: | :----------------------------------------: | ------- | :----------------------------------------: | ------------------------------------------------------------------------------------------------------------ |
|   Ethereum   |        1 | 0x3D8E699Db14d7781557fE94ad99d93Be180A6594 | 1.1.4   | 0xAE45849165E17Dc555B8264dD4Ae01a3F42344e2 | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-ethereum/v1.1.0/gn>     |
|   Optimism   |       10 | 0x945C44803E92a3495C32be951052a62E45A5D964 | 1.1.4   | 0xAE45849165E17Dc555B8264dD4Ae01a3F42344e2 | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-op/v1.1.0/gn>           |
|      BNB     |       56 | 0xe2C15B97F628B7Ad279D6b002cEDd414390b6D63 | 1.1.4   | 0xAE45849165E17Dc555B8264dD4Ae01a3F42344e2 | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-bnb/v1.1.2/gn>          |
|    Gnosis    |      100 | 0x4e4af2a21ebf62850fD99Eb6253E1eFBb56098cD | 1.1.4   | 0xAE45849165E17Dc555B8264dD4Ae01a3F42344e2 | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-gnosis/v1.1.0/gn>       |
|    Polygon   |      137 | 0xe2C15B97F628B7Ad279D6b002cEDd414390b6D63 | 1.1.4   | 0xAE45849165E17Dc555B8264dD4Ae01a3F42344e2 | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-matic/v1.1.0/gn>        |
|     opBNB    |      204 | 0x03688D459F172B058d39241456Ae213FC4E26941 | 1.1.4   | 0xAE45849165E17Dc555B8264dD4Ae01a3F42344e2 | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-opbnb/v1.1.0/gn>        |
|     Base     |     8453 | 0x2b3224D080452276a76690341e5Cfa81A945a985 | 1.1.4   | 0xAE45849165E17Dc555B8264dD4Ae01a3F42344e2 | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-base/v1.1.0/gn>         |
| Arbitrum One |    42161 | 0x4e4af2a21ebf62850fD99Eb6253E1eFBb56098cD | 1.1.4   | 0xAE45849165E17Dc555B8264dD4Ae01a3F42344e2 | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-arbitrum-one/v1.1.0/gn> |
|     Celo     |    42220 | 0x4e4af2a21ebf62850fD99Eb6253E1eFBb56098cD | 1.1.4   | 0xAE45849165E17Dc555B8264dD4Ae01a3F42344e2 | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-celo/v1.1.3/gn>         |

### Legacy Mainnet Deployments

These networks are no longer maintained.

|     Network     |                   Address                  | Version | GraphQL Subgraph                                                                                          |
| :-------------: | :----------------------------------------: | ------- | --------------------------------------------------------------------------------------------------------- |
|    ~~Cyber~~    | 0x4e4af2a21ebf62850fD99Eb6253E1eFBb56098cD | 1.1.1   | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-cyber/v1.1.0/gn>     |
|    ~~Degen~~    | 0x4e4af2a21ebf62850fD99Eb6253E1eFBb56098cD | 1.1.1   | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-degen/v1.1.0/gn>     |
| ~~OKX X Layer~~ | 0x4e4af2a21ebf62850fD99Eb6253E1eFBb56098cD | 1.1.1   | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-x1/v1.1.0/gn>        |
|    ~~Scroll~~   | 0xFBF614E89Ac79d738BaeF81CE6929897594b7E69 | 1.1.1   | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-scroll/v1.1.0/gn>    |
|  ~~ZetaChain~~  | 0xBbc279ee396074aC968b459d542DEE60c6bD71C1 | 1.1.1   | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-zetachain/v1.1.0/gn> |
|  ~~ZetaChain~~  | 0x1BC26dd23b773806f080Acf65Cfb744166be9463 | 1.0.1   | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-zetachain/v1.0.0/gn> |

## Testnet

*Testnet deployments are NOT production ready and subject to change without notice.*

| Network | Chain ID |                    Proxy                   | Version |                    Owner                   | GraphQL Subgraph                                                                                        |
| :-----: | -------: | :----------------------------------------: | ------- | :----------------------------------------: | ------------------------------------------------------------------------------------------------------- |
| Sepolia | 11155111 | 0x878c92FD89d8E0B93Dc0a3c907A2adc7577e39c5 | 1.1.4   | 0xAE45849165E17Dc555B8264dD4Ae01a3F42344e2 | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-sepolia/v1.1.0/gn> |

### Legacy Testnet Deployments

These networks are no longer maintained.

|        Network       |                   Address                  | Version | GraphQL Subgraph                                                                                                  |
| :------------------: | :----------------------------------------: | ------- | ----------------------------------------------------------------------------------------------------------------- |
| ~~Arbitrum Sepolia~~ | 0x4e4af2a21ebf62850fD99Eb6253E1eFBb56098cD | 1.1.1   | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-arbitrum-sepolia/v1.1.0/gn>  |
|   ~~Base Sepolia~~   | 0x4e4af2a21ebf62850fD99Eb6253E1eFBb56098cD | 1.1.1   | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-base-sepolia/v1.1.0/gn>      |
|  ~~Berachain Artio~~ | 0x2774d96a841E522549CE7ADd3825fC31075384Cf | 1.1.1   | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-berachain-testnet/v1.1.0/gn> |
|  ~~Celo Alfajores~~  | 0x4e4af2a21ebf62850fD99Eb6253E1eFBb56098cD | 1.1.3   | <https://api.studio.thegraph.com/query/49892/sp-celo-alfajores/version/latest>                                    |
|   ~~Gnosis Chiado~~  | 0x4e4af2a21ebf62850fD99Eb6253E1eFBb56098cD | 1.1.1   | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-gnosis-chiado/v1.1.0/gn>     |
|       ~~opBNB~~      | 0x72efA4093539A909C1f9bcCA1aE6bcDa435a3433 | 1.1.1   | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-opbnb-testnet/v1.1.0/gn>     |
| ~~Optimism Sepolia~~ | 0x4e4af2a21ebf62850fD99Eb6253E1eFBb56098cD | 1.1.1   | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-op-sepolia/v1.1.0/gn>        |
|       ~~Plume~~      | 0x4e4af2a21ebf62850fD99Eb6253E1eFBb56098cD | 1.1.1   | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-plume-sepolia/v1.1.0/gn>     |
|   ~~Polygon Amoy~~   | 0x4e4af2a21ebf62850fD99Eb6253E1eFBb56098cD | 1.1.1   | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-amoy/v1.1.0/gn>              |
|  ~~Polygon Mumbai~~  | 0x4665fffdD8b48aDF5bab3621F835C831f0ee36D7 | 1.1.1   | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-mumbai-testnet/v1.1.0/gn>    |
|  ~~Scroll Sepolia~~  | 0x4e4af2a21ebf62850fD99Eb6253E1eFBb56098cD | 1.1.1   | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-scroll-sepolia/v1.1.0/gn>    |
| ~~ZetaChain Athens~~ | 0x00aFD4466E4Afa4F43cCd414b1BC65e574ACA2f5 | 1.0.1   | <https://api.goldsky.com/api/public/project\\_cls8h0isrycgi01wfgmhv3hrf/subgraphs/sp-zetachain-testnet/v1.0.0/gn> |


# Sign Developer Platform

[Sign Developer Platform](https://developer.sign.global), or SDP, gives developers API access to various Sign Protocol services, such as paying for decentralized data storage.

### General Usage

Visit [Sign Developer Platform](https://developer.sign.global) and create an API key with the appropriate scopes. To fund the account balance to pay for API key usage, you can purchase credits with USDC (1 USDC = 100 Credits).

Once the account is properly funded, you can call the following API endpoints:

* Testnet: <https://testnet-rpc.sign.global/api>
* Mainnet: <https://mainnet-rpc.sign.global/api>

Make sure the proper header is attached in your API request:

```
Headers = {
	'x-sign-api-key': 'API key'
}
```

Alternatively, you can use our [SDK](https://www.npmjs.com/package/@ethsign/sp-sdk) (>= 0.9.7) which has been updated to work with API keys.

### Uploading Data to Decentralized Storage

To upload data to decentralized storage, use the following URL: `POST {endpoint}/sp/offchain-storage`

and request:

```json
{
    "storageType": 'arweave' | 'ipfs' | 'greenfield',
    "data": "your data"
}
```

The appropriate amount of fees will be deducted from the account. The total amount of fees paid is the sum of the base fee and size fee.

| Platform       | Base Fee | Size Fee (per byte) |
| -------------- | -------- | ------------------- |
| Arweave        | 0.01     | 0.0000000006        |
| BNB Greenfield | 0.01     | 0.00000000004       |
| IPFS           | 0.01     | 0.000000000002      |

*Please note the above fees may be adjusted without notice. All fee units are in Credits.*


# Advanced Topics


# Cross Chain Attestations

Ever since the dawn of blockchain systems, developers and users alike have faced the dilemma of data storage and availability, where data stored on one blockchain is completely inaccessible from another blockchain. Sign Protocol faces a similar challenge, where attested data simply isn’t available across different blockchains, even if they share a common key derivation algorithm. **At the very least, data that’s digitally signed and attested on Base should be just as valid on BNB Chain, for example.**

There are plenty of existing mature cross-chain solutions, such as Chainlink CCIP and LayerZero, but none of them satisfy the flexibility that Sign Protocol requires (e.g. pulling and validating data from atypical blockchains such as Arweave). As such, we have partnered with [Lit Protocol](https://www.litprotocol.com/) to present a TEE-based cross-chain attestation verification solution.

### What is a TEE?

A Trusted Execution Environment (TEE) is a secure part of a device's main processor that provides a protected space for sensitive operations. It ensures that sensitive data and code are stored, processed, and executed in a way that is isolated from the rest of the system, including the main operating system and applications. This isolation helps prevent unauthorized access or tampering, even if the primary system is compromised.

The TEE operates alongside the main environment but remains insulated from potential vulnerabilities or threats present in the general computing environment. It allows only trusted applications to execute within this secure space, ensuring the confidentiality and integrity of operations like cryptographic computations or secure key management. TEEs are commonly used in scenarios requiring high security, such as mobile payments, digital rights management, and authentication services.

Examples of TEEs include ARM's TrustZone, Intel's SGX, and AMD's ASP, which powers Lit Protocol's decentralized hardware TEE offering. Sign Protocol uses decentralized TEE to ensure the integrity of cross-chain attestation data and each cross-chain verification result is attached with a digital signature signed by at least 2/3 of the entire Lit network using threshold cryptography to prove consensus. You can read more about it [here](https://developer.litprotocol.com/resources/how-it-works).

### Workflow

1. The requester makes an attestation on an official cross-chain schema created by Sign. The attestation contains the target chain ID, target attestation ID, and encoded data to verify, all of which is encoded in `extraData` for gas efficiency (since `extraData` is only passed to the hook and emitted as an event instead of being stored, which makes it \~95% cheaper).
   1. We also support navigating a JSON path to make it possible to verify a particular field within a piece of large sized JSON data on Arweave.
2. The schema hook charges a fee to cover the cross-chain verification cost and emits a special event that makes `extraData` available for the Lit nodes.
3. Lit Action is triggered by this event.
4. Lit Action independently:
   1. Fetches the event and decodes `extraData`.
   2. Fetches the target attestation on the target chain.
   3. Compares target attestation data against decoded data.
   4. Returns a signed (with Lit key) delegated attestation signature based on the official cross-chain response schema that includes the comparison result boolean.
5. Sign Protocol makes the delegated attestation on behalf of the Lit nodes.
6. The cross-chain verification process is now complete.

### Roadmap

Cross-chain attestations will be available in Q1 2025. Stay tuned!


# Hybrid Attestations

Hybrid attestations are standard on-chain attestations that store data separate from the current blockchain network. For example, a hybrid attestation may store its data on Arweave or IPFS instead of directly within a Sign Protocol smart contract, where the metadata and schema information are stored. With hybrid attestations, the attestation data is uploaded to Arweave/IPFS, and the resulting CID is encoded and stored in the `data` field of the attestation on-chain.

This can be useful when the attestation data is expected to be sufficiently large that gas fees would be exceptionally high or when easy data access is required from front-end clients. Projects can cache CIDs for quick data retrieval instead of querying, fetching, and decoding data every time an attestation is retrieved.

<figure><img src="/files/RL2qWQTTSRDReKFYgBOA" alt=""><figcaption><p>Hybrid Attestation Model</p></figcaption></figure>

Sign Protocol's [SDK](/for-builders/index-1/npm-sdk/installation) allows direct interaction with hybrid attestations, and the [Schema Builder](https://app.sign.global/create-schema) enables users to easily build hybrid schemas by choosing an on-chain schema with a data storage location of Arweave or IPFS.

### Smart Contract Interaction with Hybrid Attestations

#### Steps

1. Upload the attestation's data to the storage location (Arweave/IPFS) in JSON format.
2. Encode the returned Content ID (CID).
3. Create an attestation, passing in the encoded CID as `data`.


# Schema Hooks

To run custom Solidity code when an attestation is created or revoked, you will need to use a Schema Hook. Schema hooks enable schema creators to add whitelists, take payments, and write any custom application logic which will be called from Sign Protocol's smart contract. Any reverts in the schema hook will revert the entire call, allowing schema builders to control attestation creation and revocation logic.

## Interface

Schema hooks must conform to the ISPHook interface, which can be found [here](/for-builders/index-1/index/index/index/isphook).

## Example

The following example implements a basic whitelist schema hook. The owner of the `WhitelistManager` contract can add or remove user addresses on the whitelist. The `WhitelistHook` contract will be called when attestations are created and revoked.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol";
import { ISPHook } from "@ethsign/sign-protocol-evm/src/interfaces/ISPHook.sol";

// @dev This contract manages the whitelist. We are separating the whitelist logic from the hook to make things easier
// to read.
contract WhitelistMananger is Ownable {
    mapping(address attester => bool allowed) public whitelist;

    error UnauthorizedAttester();

    constructor() Ownable(_msgSender()) { }

    function setWhitelist(address attester, bool allowed) external onlyOwner {
        whitelist[attester] = allowed;
    }

    function _checkAttesterWhitelistStatus(address attester) internal view {
        // solhint-disable-next-line custom-errors
        require(whitelist[attester], UnauthorizedAttester());
    }
}

// @dev This contract implements the actual schema hook.
contract WhitelistHook is ISPHook, WhitelistMananger {
    function didReceiveAttestation(
        address attester,
        uint64, // schemaId
        uint64, // attestationId
        bytes calldata // extraData
    )
        external
        payable
    {
        _checkAttesterWhitelistStatus(attester);
    }

    function didReceiveAttestation(
        address attester,
        uint64, // schemaId
        uint64, // attestationId
        IERC20, // resolverFeeERC20Token
        uint256, // resolverFeeERC20Amount
        bytes calldata // extraData
    )
        external
        view
    {
        _checkAttesterWhitelistStatus(attester);
    }

    function didReceiveRevocation(
        address attester,
        uint64, // schemaId
        uint64, // attestationId
        bytes calldata // extraData
    )
        external
        payable
    {
        _checkAttesterWhitelistStatus(attester);
    }

    function didReceiveRevocation(
        address attester,
        uint64, // schemaId
        uint64, // attestationId
        IERC20, // resolverFeeERC20Token
        uint256, // resolverFeeERC20Amount
        bytes calldata // extraData
    )
        external
        view
    {
        _checkAttesterWhitelistStatus(attester);
    }
}
```


# Tutorial: Checking Attestation Data

In this tutorial, we will create a schema hook that checks an attestation's `data` variable. A threshold value must be met for the attestation to be created. When you are ready to begin, please navigate to the next page.


# Schema Creation

To limit which attestations are created, we want to check the supplied attestation data using a custom schema hook. If our hook's code reverts, the attestation will not be created. If the attestation data meets our requirements, the hook will allow the attestation to be created.

First, we need to define our schema data. For this tutorial, the schema data will only include a number. Our schema looks like the following:

```json
[
  {
    "name": "threshold",
    "type": "uint256"
  }
]
```

Your schema hook's address must be supplied when you create a schema.  Now that you know what the schema's data looks like, let's build our schema hook.


# Schema Hook

A schema hook contract is a regular solidity smart contract that inherits from the [ISPHook](/for-builders/index-1/index/index/index/isphook) interface and implements all required functions. You can implement the ISPHook interface on any contract, allowing you to merge Sign Protocol schema callbacks with your application's smart contract logic.

For clarity in this tutorial, we will separate our schema hook contract from the contract containing validation logic.

### Validation Logic

Our schema hook is responsible for ensuring attestation data contains a number above a certain threshold. If this condition is met (the threshold value in the attestation data is large enough), the attestation will be successfully created. Otherwise, we will revert the transaction and the attestation will fail to be created.

For our validator contract, we need to create two functions: `setThreshold` and `_checkThreshold`. The threshold specified in `setThreshold` will determine which attestations are allowed to be created. We will enforce this by calling `_checkThreshold` in our schema hook contract.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

// @dev This contract manages attestation data validation logic.
contract DataValidator is Ownable {
    uint256 public threshold;

    error NumberBelowThreshold();

    constructor() Ownable(_msgSender()) { }

    function setThreshold(uint256 threshold_) external onlyOwner {
        threshold = threshold_;
    }

    function _checkThreshold(uint256 number) internal view {
        // solhint-disable-next-line custom-errors
        require(number >= threshold, NumberBelowThreshold());
    }
}
```

### Schema Hook Implementation

When an attestation is received, the schema hook's logic is pretty simple: we need to read the attestation data to extract the threshold value we are trying to validate, and then we need to validate it.

#### Reading Attestation Data

To get the attestation data, we need to read the attestation object from Sign Protocol's contract. You can find all available Sign Protocol smart contract functions [here](/for-builders/index-1/index/index/index/isp). Remember that your schema hook is being called from the Sign Protocol smart contract, so you can use `_msgSender()` to get the appropriate smart contract address that you need to call.

```solidity
import { Attestation } from "@ethsign/sign-protocol-evm/src/models/Attestation.sol";
...
Attestation memory attestation = ISP(_msgSender()).getAttestation(attestationId);
```

#### Decoding Attestation Data

The attestation object you retrieved in the last step will have `data` encoded according to your schema's data format. In our case, the schema we created contains only a `uint256`. We can use `abi.decode` to decode the attestation data into the correct format.

```solidity
abi.decode(attestation.data, (uint256));
```

You can now use this decoded data to call `_checkThreshold`.

If your schema has additional variables in its data field, these will be decoded similarly. For example, take the following schema data format:

<pre class="language-json"><code class="lang-json">[
<strong>    {
</strong>        "name": "name",
        "type": "string"
<strong>    },
</strong>    {
        "name": "timestamp",
        "type": "uint256"
    },
    {
        "name": "hash",
        "type": "bytes32"
    }
]
</code></pre>

An attestation's data following the above data format can be decoded in Solidity using the following:

```solidity
(string memory name, uint256 timestamp, bytes32 hash) = abi.decode(attestation.data, (string, uint256, bytes32));
```

### Bringing It All Together

For this tutorial, we will only implement `didReceiveAttestation`, but the process is the same for the other functions in ISPHook. In our case, we did not check the `attester`, nor did we use the `schemaId` or `extraData`.

{% hint style="info" %}
`extraData` is not the same as your attestation's data - this parameter provides a way for you to send additional information to your schema hook when an attestation is being created or revoked. `extraData` is not stored onchain with the attestation itself. It is only used in the schema hook.
{% endhint %}

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol";
import { ISP } from "@ethsign/sign-protocol-evm/src/interfaces/ISP.sol";
import { ISPHook } from "@ethsign/sign-protocol-evm/src/interfaces/ISPHook.sol";
import { Attestation } from "@ethsign/sign-protocol-evm/src/models/Attestation.sol";

// @dev This contract manages attestation data validation logic.
contract DataValidator is Ownable {
    uint256 public threshold;

    error NumberBelowThreshold();

    constructor() Ownable(_msgSender()) { }

    function setThreshold(uint256 threshold_) external onlyOwner {
        threshold = threshold_;
    }

    function _checkThreshold(uint256 number) internal view {
        // solhint-disable-next-line custom-errors
        require(number >= threshold, NumberBelowThreshold());
    }
}

// @dev This contract implements the actual schema hook.
contract DataValidatorHook is ISPHook, DataValidator {
    error UnsupportedOperation();

    function didReceiveAttestation(
        address, // attester
        uint64, // schemaId
        uint64 attestationId,
        bytes calldata // extraData
    )
        external
        payable
    {
        Attestation memory attestation = ISP(_msgSender()).getAttestation(attestationId);
        _checkThreshold(abi.decode(attestation.data, (uint256)));
    }

    function didReceiveAttestation(
        address, // attester
        uint64, // schemaId
        uint64, // attestationId
        IERC20, // resolverFeeERC20Token
        uint256, // resolverFeeERC20Amount
        bytes calldata // extraData
    )
        external
        pure
    {
        revert UnsupportedOperation();
    }

    function didReceiveRevocation(
        address, // attester
        uint64, // schemaId
        uint64, // attestationId
        bytes calldata // extraData
    )
        external
        payable
    {
        revert UnsupportedOperation();
    }

    function didReceiveRevocation(
        address, // attester
        uint64, // schemaId
        uint64, // attestationId
        IERC20, // resolverFeeERC20Token
        uint256, // resolverFeeERC20Amount
        bytes calldata // extraData
    )
        external
        pure
    {
        revert UnsupportedOperation();
    }
}
```

Once this contract has been deployed, you can create your schema and set the appropriate contract address as your schema hook. Once you have created your schema with a schema hook, move to the next page where we will go over how to create an attestation in solidity.


# Creating an Attestation (Solidity)

Now that you have created your schema with a schema hook address set, you must provide attestation data in the correct format that you set in your schema, or else verification will fail. If you are using the NPM SDK, we perform validation for you before the transaction call is sent. However, none of these safeguards exist when interacting with Sign Protocol directly from solidity.

Our simple schema only needs a `uint256`. We will use `abi.encode` to encode this number. Make sure that variables are provided in the same order they are set in the schema, which is the same order they will be decoded in your schema hook and on the SignScan attestation explorer.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { ISP } from "@ethsign/sign-protocol-evm/src/interfaces/ISP.sol";
import { Attestation } from "@ethsign/sign-protocol-evm/src/models/Attestation.sol";
import { DataLocation } from "@ethsign/sign-protocol-evm/src/models/DataLocation.sol";

contract DataAttester is Ownable {
    ISP public spInstance;
    uint64 public schemaId;

    constructor() Ownable(_msgSender()) { }

    function setSPInstance(address instance) external onlyOwner {
        spInstance = ISP(instance);
    }

    function setSchemaID(uint64 schemaId_) external onlyOwner {
        schemaId = schemaId_;
    }

    function attest(address recipient, uint256 someNumber) external onlyOwner returns (uint64) {
        bytes[] memory recipients = new bytes[](1);
        recipients[0] = abi.encode(recipient);
        Attestation memory a = Attestation({
            schemaId: schemaId,
            linkedAttestationId: 0,
            attestTimestamp: 0,
            revokeTimestamp: 0,
            attester: address(this),
            validUntil: 0,
            dataLocation: DataLocation.ONCHAIN,
            revoked: false,
            recipients: recipients,
            data: abi.encode(someNumber)
        });
        return spInstance.attest(a, "", "", "");
    }
}
```


# ZK Attestations

Steps to integrate ZK verifiers into Sign Protocol's Schema Hooks.

This tutorial will guide you in integrating a ZK Solidity verifier into a Sign Protocol [Schema Hook](/for-builders/advanced-topics/schema-hooks). This tutorial assumes you already know ZK basics and terminology, such as circuit, proof, and verifier. When you are ready to begin, continue to the next page.


# Compile a Circuit

There are many ZK libraries and languages that can be used with Sign Protocol, each with its pros and cons. We do not aim to cover these similarities and differences and it is up to you to decide which to use. However, we recommend using a library that can generate a Solidity verifier using your compiled circuit. We will use [Circom](https://iden3.io/circom).

First, follow Circom's docs for [installation](https://docs.circom.io/getting-started/installation/). If you have never used Circom before, we recommend reading through their [sample circuit](https://docs.circom.io/getting-started/writing-circuits/). For this tutorial, we will use a non-trivial example circuit, which you can find [here](https://github.com/boyuanx/circom-sha256-preimage-example). The circom file should contain the following:

```clike
pragma circom 2.0.0;

include "circomlib/circuits/sha256/sha256.circom";
include "circomlib/circuits/bitify.circom";

/**
 * Wrapper around SHA256 to support bytes as input instead of bits
 * @param  N   The number of input bytes
 * @input  in  The input bytes
 * @output out The SHA256 output of the n input bytes, in bytes
 *
 * SOURCE: https://github.com/celer-network/zk-benchmark/blob/main/circom/circuits/sha256/sha256_bytes.circom
 */
template Sha256Bytes(N) {
  signal input in[N];
  signal output out[32];

  // convert input bytes to bits
  component byte_to_bits[N];
  for (var i = 0; i < N; i++) {
    byte_to_bits[i] = Num2Bits(8);
    byte_to_bits[i].in <== in[i];
  }

  // sha256 over bits
  component sha256 = Sha256(N*8);
  for (var i = 0; i < N; i++) {
    for (var j = 0; j < 8; j++) {
      sha256.in[i*8+j] <== byte_to_bits[i].out[7-j];
    }
  }

  // convert output bytes to bits
  component bits_to_bytes[32];
  for (var i = 0; i < 32; i++) {
    bits_to_bytes[i] = Bits2Num(8);
    for (var j = 0; j < 8; j++) {
      bits_to_bytes[i].in[7-j] <== sha256.out[i*8+j];
    }
    out[i] <== bits_to_bytes[i].out;
  }
}

template Main(N) {
    signal input in[N];
    signal input hash[32];
    signal output out[32];

    component sha256 = Sha256Bytes(N);
    sha256.in <== in;
    out <== sha256.out;

    for (var i = 0; i < 32; i++) {
        out[i] === hash[i];
    }

    log("start ================");
    for (var i = 0; i < 32; i++) {
        log(out[i]);
    }
    log("finish ================");
}

// render this file before compilation
component main = Main(64);
```

This sha256 circuit will take in two signals as input: the first is an array of size 64 and the second is an array of size 32. The first array will be hashed using the sha256 algorithm, requiring that the output (hash) signal equals the provided hash. Next, we will compile our circuit.

### Compile Your Circuit

Your local Circom installation comes with the `circom` command. To compile your circuit, run:

```bash
> circom sha256.circom --r1cs --wasm --sym
```

This command will compile your source code into the required files, including the r1cs constraint system file, and wasm files for generating a witness. You can read more about the command flags [here](https://docs.circom.io/getting-started/compiling-circuits/). From here, you will generate your witness. Note that you do not need a witness to generate a smart contract verifier. Witnesses are used for creating proofs, which will be verified using your schema hook.

### Generate a Witness

In your output directory (likely named `sha256_js`), create a file named `input.json`. Paste the following in this file:

```json
{
  "in": [
    20, 207, 123, 94, 84, 118, 123, 180, 191, 195, 21, 180, 82, 88, 185, 223,
    207, 101, 103, 247, 201, 113, 113, 87, 111, 84, 191, 243, 87, 47, 134, 143,
    20, 207, 123, 94, 84, 118, 123, 180, 191, 195, 21, 180, 82, 88, 185, 223,
    207, 101, 103, 247, 201, 113, 113, 87, 111, 84, 191, 243, 87, 47, 134, 143
  ],
  "hash": [
    29, 131, 153, 39, 255, 114, 11, 253, 116, 101, 97, 195, 155, 112, 35, 76,
    226, 32, 120, 129, 165, 186, 145, 10, 192, 28, 49, 244, 143, 179, 101, 236
  ]
}
```

Next, navigate to your build directory and run the following command to generate a witness:

```bash
> node generate_witness.js sha256.wasm input.json witness.wtns
```

### Generating a Verifier Contract

This section follows the documentation located [here](https://docs.circom.io/getting-started/proving-circuits/). For more information about each step, please refer to Circom's documentation. Run the following commands to complete the Powers of Tau and Phase 2 requirements:

```bash
> snarkjs powersoftau new bn128 17 pot12_0000.ptau -v
> snarkjs powersoftau contribute pot12_0000.ptau pot12_0001.ptau --name="First contribution" -v
> snarkjs powersoftau prepare phase2 pot12_0001.ptau pot12_final.ptau -v
> snarkjs groth16 setup sha256.r1cs pot12_final.ptau sha256_0000.zkey
> snarkjs zkey contribute sha256_0000.zkey sha256_0001.zkey --name="1st Contributor Name" -v
> snarkjs zkey export verificationkey sha256_0001.zkey verification_key.json
```

Now that you have generated all required files, you can generate a smart contract verifier using the following command:

```bash
> snarkjs zkey export solidityverifier sha256_0001.zkey verifier.sol
```

This will generate a file named `verifier.sol` in your root project directory. To facilitate a function call for `verifyProof()`, you can run the following command:

```bash
> snarkjs generatecall
```

When you are ready, proceed to the next page to integrate `verifier.sol` with a schema hook.


# Create a Schema Hook

In this step, we will extend the verifier contract generated by the ZK library and implement the [ISPHook ](/for-builders/index-1/index/index/index/isphook)interface. From the previous step, our generated contract looks something like this:

```solidity
pragma solidity >=0.7.0 <0.9.0;

contract Groth16Verifier {
    ...

    function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[32] calldata _pubSignals) public view returns (bool) {
        ...
     }
 }
```

{% hint style="info" %}
In the generated verifier, change all instances of `calldata` to `memory`.
{% endhint %}

The generated verifier should now look like this:

```solidity
pragma solidity >=0.7.0 <0.9.0;

contract Groth16Verifier {
    ...

    function verifyProof(uint[2] memory _pA, uint[2][2] memory _pB, uint[2] memory _pC, uint[32] memory _pubSignals) public view returns (bool) {
        ...
     }
 }
```

To set up your schema hook, create another file that contains the following contents:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import { Groth16Verifier } from "./Verifier.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol";
import { ISPHook } from "@ethsign/sign-protocol-evm/src/interfaces/ISPHook.sol";

contract SHA256PreimageVerifier is Groth16Verifier, Ownable {
    address public spInstance;

    constructor() Ownable(_msgSender()) { }

    function setSPInstance(address instance) external onlyOwner {
        spInstance = instance;
    }
}

// @dev This contract implements the actual schema hook.
contract ZKHook is ISPHook, SHA256PreimageVerifier {
    error Unsupported();
    error ZKVerificationFailed();

    function didReceiveAttestation(
        address, // attester
        uint64, // schemaId
        uint64, // attestationId
        bytes calldata extraData
    )
        external
        payable
    {
        if (_msgSender() != spInstance) revert Unsupported();
        (uint256[2] memory _pA, uint256[2][2] memory _pB, uint256[2] memory _pC, uint256[32] memory _pubSignals) =
            abi.decode(extraData, (uint256[2], uint256[2][2], uint256[2], uint256[32]));
        // If the SHA256 preimage proof verification fails, revert.
        if (!verifyProof(_pA, _pB, _pC, _pubSignals)) revert ZKVerificationFailed();
    }

    function didReceiveAttestation(
        address, // attester
        uint64, // schemaId
        uint64, // attestationId
        IERC20, // resolverFeeERC20Token
        uint256, // resolverFeeERC20Amount
        bytes calldata // extraData
    )
        external
        pure
    {
        revert Unsupported();
    }

    function didReceiveRevocation(
        address, // attester
        uint64, // schemaId
        uint64, // attestationId
        bytes calldata // extraData
    )
        external
        payable
    {
        revert Unsupported();
    }

    function didReceiveRevocation(
        address, // attester
        uint64, // schemaId
        uint64, // attestationId
        IERC20, // resolverFeeERC20Token
        uint256, // resolverFeeERC20Amount
        bytes calldata // extraData
    )
        external
        pure
    {
        revert Unsupported();
    }
}
```

We begin by importing our generated `Groth16Verifier` contract, OpenZepplin packages, and the [ISPHook](/for-builders/index-1/index/index/index/isphook) contract.

Next, we create the `SHA256PreimageVerifier` contract which is responsible for setting the contract address for the Sign Protocol instance and adding ownable functionality.

Last, we create `ZKHook` to add all of our schema hook logic. Because ZK proofs can be large, we recommend making use of the `extraData` field - this data gets passed to Sign Protocol's contract when attestations are created or revoked but does not get stored onchain. `extraData` is only forwarded to schema hooks for data processing and verification, so this is a perfect scenario for providing required ZK-proof-related data. This hook decodes the inputted data and passes it to the verifier's `verifyProof()` function. The call reverts if verification fails. If verification succeeds, the attestation will be successfully created.

### Finishing Up

Once you have completed your ZK schema hook, it is time to deploy the contract to your desired network. After the contract gets deployed, [create a new schema](https://app.sign.global/create-schema) on the same network and set the hook smart contract address to the address of your deployed schema hook contract. Your ZK schema hook is ready to go!


# Private Attestations

Private, encrypted attestations using Lit Protocol.


# Querying Data

[SignScan](https://scan.sign.global) is the explorer for the Sign Protocol. Using SignScan, you can explore, create, validate, and search for schemas and attestations. Through tools that allow for no-code schema and attestation creation, we are aiming to make attestations accessible to everyone - coders and non-coders alike.

<figure><img src="https://github.com/EthSign/sign-protocol-docs/blob/main/for-builders/.gitbook/assets/sign_scan_01.png" alt=""><figcaption><p>SignScan Homepage</p></figcaption></figure>

## Feature Highlights

SignScan provides several easily accessible methods for interacting with Sign Protocol's schemas and attestations.

* Explore existing schemas and the data they require and contain.
* Search for existing schemas and attestations.
* Generate new schemas and attestations with no code.
* View the most popular schemas.
* Verify attestations.
* Retrieve all schemas and attestations made by any public address.
* And more!


# NPM SDK

### Installation

Install the [`@ethsign/sp-sdk`](https://www.npmjs.com/package/@ethsign/sp-sdk) package to use the Sign Protocol SDK in your frontend or Node backend projects.

### Creating an Index Service Client

```typescript
new IndexService(env);
```

#### Parameters

| Name | Type                 | Description                                                           |
| ---- | -------------------- | --------------------------------------------------------------------- |
| env  | `testnet`, `mainnet` | Whether the indexing service should be querying testnets or mainnets. |

#### Example

```typescript
async function getSchemaListFromIndexService() {
  const indexService = new IndexService("testnet");
  const res = await indexService.querySchemaList({ page: 1 });
}

async function getSchemaFromIndexService() {
  const indexService = new IndexService("testnet");
  const res = await indexService.querySchema("onchain_evm_80001_0x1");
}

async function getAttestationListFromIndexService() {
  const indexService = new IndexService("testnet");
  const res = await indexService.queryAttestationList({ page: 1 });
}

async function getAttestationFromIndexService() {
  const indexService = new IndexService("testnet");
  const res = await indexService.queryAttestation("onchain_evm_80001_0x1");
}
```


# Usage & Examples

## Schemas

### Querying Schemas

```typescript
async function querySchemaList(query: {
  id?: string;
  registrant?: string;
  mode?: "offchain" | "onchain";
  page: number;
  size?: number;
}): Promise<
  PageInfo & {
    rows: SchemaInfo[];
  }
>;
```

#### Parameters

| Name        | Type / Value          | Description                                                      |
| ----------- | --------------------- | ---------------------------------------------------------------- |
| id?         | `string`              | The schema ID you are querying for.                              |
| registrant? | `string`              | Find schemas that were created by a specific registrant address. |
| mode?       | `offchain`, `onchain` | The schema's location.                                           |
| page        | `number`              | The page to fetch.                                               |
| size?       | `number`              | The number of results to return.                                 |

#### Example

```typescript
const res = await indexService.querySchemaList({
  id: "onchain_evm_11155111_0xd",
  registrant: "0x526dDf0Cc975E0b5B039c85b5cD7ba1e1300500e",
  mode: "onchain",
  page: 1,
  size: 2,
});
```

### Getting a Schema By ID

```typescript
async function querySchema(schemaId: string): Promise<SchemaInfo | null>;
```

#### Parameters

| Name     | Type     | Description                       |
| -------- | -------- | --------------------------------- |
| schemaId | `string` | The ID of the schema to retrieve. |

#### Example

```typescript
const res = await indexService.querySchema("onchain_evm_11155111_0xd");
```

## Attestations

### Querying Attestations

```typescript
async function queryAttestationList(query: {
  id?: string;
  schemaId?: string;
  attester?: string;
  page: number;
  mode?: "offchain" | "onchain";
  indexingValue?: string;
}): Promise<
  PageInfo & {
    rows: AttestationInfo[];
  }
>;
```

#### Parameters

| Name           | Type / Value          | Description                                            |
| -------------- | --------------------- | ------------------------------------------------------ |
| id?            | `string`              | The attestation ID you are querying for.               |
| schemaId?      | `string`              | Find attestations that belong to a specific schema ID. |
| attester?      | `string`              | Find attestations that a specific attester created.    |
| page           | `number`              | The page to fetch.                                     |
| mode?          | `offchain`, `onchain` | The attestation's location.                            |
| indexingValue? | `string`              | Find attestations with a specific indexing value.      |

#### Example

```typescript
const res = await indexService.queryAttestationList({
  id: "",
  schemaId: "",
  attester: "",
  page: 1,
  mode: "onchain",
  indexingValue: "",
});
```

### Getting an Attestation By ID

```typescript
async function queryAttestation(
  attestationId: string
): Promise<AttestationInfo | null>;
```

#### Parameters

| Name          | Type     | Description                       |
| ------------- | -------- | --------------------------------- |
| attestationId | `string` | The ID of the schema to retrieve. |

#### Example

```typescript
const res = await indexService.queryAttestation("onchain_evm_11155111_0x5");
```

## Utils

### Decoding Attestation Data

```typescript
function decodeOnChainData(
  data: any,
  dataLocation: DataLocationOnChain,
  schemaData: SchemaItem[]
): any;
```

#### Parameters

| Name                | Type / Value          | Description                                                     |
| ------------------- | --------------------- | --------------------------------------------------------------- |
| data                | `string`              | The hex string retrieved from an onchain attestation object.    |
| DataLocationOnChain | `DataLocationOnChain` | Location of the data. Either `ONCHAIN`, `ARWEAVE`, or `IPFS`.   |
| schemaData          | `string`              | The data string of the schema that this attestation belongs to. |

#### Example

<pre class="language-typescript"><code class="lang-typescript">const { decodeOnChainData } from "@ethsign/sp-sdk";

const attestationData = "0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000b1987e041b79727cd2a190b53d86c2d1cd2869ef0000000000000000000000000000000000000000000000000000000000000012486f6d65776f726b2f446166742050756e6b0000000000000000000000000000";
<strong>const schemaData = `[{"name":"contractDetails","type":"string"},{"name":"signer","type":"address"}]`;
</strong>const res = decodeOnChainData(
  attestationData,
  DataLocationOnChain.ONCHAIN,
  JSON.parse(schemaData)
);
</code></pre>


# REST APIs

### Base Endpoints

#### Testnet

```
https://testnet-rpc.sign.global/api
```

#### Mainnet

```
https://mainnet-rpc.sign.global/api
```

### Hello World

```typescript
GET / index;
```

Status endpoint to verify the attestation backend is functional.

Parameters:

None

Response:

```json
{
  "success": true,
  "statusCode": 200,
  "data": "Welcome to Sign Protocol Service!",
  "message": "ok"
}
```

### Super Search

```typescript
GET / scan / search;
```

Search for relevant schemas, attestations, and addresses by providing a keyword and filter.

Query Parameters:

| Key       | Value       | Type                                     |
| --------- | ----------- | ---------------------------------------- |
| filter\*  | attestation | `"schema"`, `"attestation"`, `"address"` |
| keyword\* | 0x1         | string                                   |

\* Optional parameter.

Response:

```json
{
    "success": true,
    "statusCode": 200,
    "data": {
        "queryResult": [
            {
                "type": "attestation",
                "rows": [
                    {
                        "id": "onchain_evm_80001_0x1",
                        "chainType": "evm",
                        "chainId": "80001",
                        "attestationId": "0x1",
                        "attester": "0x9854E76134e6D729A633CED51042fF653f04f4C5",
                        "recipients": []
                    },
                    ...
                ],
                "total": 2
            }
        ]
    },
    "message": "ok"
}
```

### Get Address Statistics

```typescript
GET / scan / addresses / { address } / statistics;
```

Get attestation and schema statistics for an address.

Query Parameters:

| Key     | Value                                      | Type   |
| ------- | ------------------------------------------ | ------ |
| address | 0x059e6B8008d34aC26581fD3ED8378AA93c7941EE | string |

\* Optional parameter.

Response:

```json
{
  "success": true,
  "statusCode": 200,
  "data": {
    "schemaCreated": 6,
    "totalAttestations": 14,
    "attestationCreated": 13,
    "attestationReceived": 3
  },
  "message": "ok"
}
```


# Schemas

### Single Schema

```typescript
GET / index / schemas / { id };
```

Retrieve the data of a schema by providing a schema ID.

Query Parameters:

| Key | Value                    | Type   |
| --- | ------------------------ | ------ |
| id  | onchain\_evm\_80001\_0x1 | string |

\* Optional parameter.

Response:

```json
{
  "success": true,
  "statusCode": 200,
  "data": {
    "id": "onchain_evm_80001_0x1",
    "mode": "onchain",
    "chainType": "evm",
    "chainId": "80001",
    "schemaId": "0x1",
    "transactionHash": "0x97e69df2e65e97001da22953a4376233d792c50810cf3bff0fff1a14e7374b60",
    "name": "xxx",
    "description": "",
    "revocable": true,
    "maxValidFor": "0",
    "resolver": "0x0000000000000000000000000000000000000000",
    "registerTimestamp": "1705387959",
    "registrant": "0x9854E76134e6D729A633CED51042fF653f04f4C5",
    "data": [
      {
        "name": "name",
        "type": "string"
      }
    ]
  },
  "message": "ok"
}
```

### Schema Info

```typescript
GET / scan / schemas / { id };
```

Get the data of a schema by providing the schema ID.

Query Parameters:

|    |                          |        |
| -- | ------------------------ | ------ |
| id | onchain\_evm\_80001\_0x2 | string |

\* Optional parameters.

Response:

```json
{
  "success": true,
  "statusCode": 200,
  "data": {
    "id": "onchain_evm_80001_0x2",
    "mode": "onchain",
    "name": "message",
    "description": "",
    "registrant": "0x9854E76134e6D729A633CED51042fF653f04f4C5",
    "registerTimestamp": 1705483984,
    "chainType": "evm",
    "chainId": "80001",
    "schemaId": "0x2",
    "revocable": true,
    "maxValidFor": 0,
    "transactionHash": "0xb1b7aa7da95aced199551f9fd58944551472027f2a6533bf462c4b435b03c789",
    "data": [
      {
        "name": "message",
        "type": "string"
      }
    ]
  },
  "message": "ok"
}
```

### Filtered Schemas

```typescript
GET / index / schemas;
```

Query for a list of schemas using one or more filtering parameters. Results can be paginated with customizable page sizes.

Query Parameters:

| Key          | Value                                      | Type                 |
| ------------ | ------------------------------------------ | -------------------- |
| id\*         | onchain\_evm\_7001\_0x7                    | string               |
| page\*       | 1                                          | number               |
| registrant\* | 0xDfc4FbbDd9C47c7976fEBb14B1D37C7f85FE299D | string               |
| size\*       | 100                                        | number               |
| mode\*       | onchain                                    | "onchain"/"offchain" |

\* Optional parameter.

Response:

```json
{
  "success": true,
  "statusCode": 200,
  "data": {
    "total": 20,
    "rows": [
      {
        "id": "onchain_evm_7001_0x7",
        "mode": "onchain",
        "chainType": "evm",
        "chainId": "7001",
        "schemaId": "0x7",
        "transactionHash": "0xabddd6fe182a75d61eb0feef028a71a24fbdf46e7508c519c099c9d8a5805801",
        "name": "test",
        "description": "whasa",
        "revocable": true,
        "maxValidFor": "0",
        "resolver": "0x0000000000000000000000000000000000000000",
        "registerTimestamp": "1705912991",
        "registrant": "0xDfc4FbbDd9C47c7976fEBb14B1D37C7f85FE299D",
        "data": [
          {
            "name": "name",
            "type": "string"
          },
          {
            "name": "count",
            "type": "number"
          }
        ]
      }
    ],
    "size": "1",
    "page": 1
  },
  "message": "ok"
}
```

### Top 10 Schemas

```typescript
GET / scan / top - schemas;
```

Get the current top 10 schemas from the attestation backend.

Query Parameters:

None

Response:

```json
{
    "success": true,
    "statusCode": 200,
    "data": {
        "rows": [
            {
                "id": "onchain_evm_7001_0x4",
                "mode": "onchain",
                "name": "zeta kyc schema",
                "description": "",
                "registrant": "0x8D10D37BF3c50C9Dd34A4BC70987CD60f8f4a466",
                "chainType": "evm",
                "chainId": "7001",
                "schemaId": "0x4",
                "transactionHash": "0x8736b25a8c7644721791ddc544f39e49418bf1516378aa9386a0b2c47baf6c53",
                "attestationCount": 18
            },
            ...
        ]
    },
    "message": "ok"
}
```

### Trending Schemas

```typescript
GET / scan / trending - schemas;
```

Get the top trending schemas from the attestation backend.

Query Parameters:

None

Response:

```json
{
  "success": true,
  "statusCode": 200,
  "data": {
    "rows": [
      {
        "id": "onchain_evm_80001_0x1",
        "mode": "onchain",
        "name": "xxx",
        "description": "",
        "registrant": "0x9854E76134e6D729A633CED51042fF653f04f4C5",
        "chainType": "evm",
        "chainId": "80001",
        "schemaId": "0x1",
        "transactionHash": "0x97e69df2e65e97001da22953a4376233d792c50810cf3bff0fff1a14e7374b60",
        "attestationCount": 1
      }
    ]
  },
  "message": "ok"
}
```

### Latest 10 Schemas

```typescript
GET / scan / latest - attestations;
```

Get the most recently created 10 schemas from the attestation backend.

Query Parameters:

None

Response:

```json
{
    "success": true,
    "statusCode": 200,
    "data": {
        "rows": [
            {
                "id": "onchain_evm_80001_0x21",
                "mode": "onchain",
                "chainType": "evm",
                "chainId": "80001",
                "attestationId": "0x21",
                "schemaId": "0x1",
                "attester": "0x9854E76134e6D729A633CED51042fF653f04f4C5",
                "attestTimestamp": "1706065910",
                "recipients": [],
                "schema": {
                    "id": "onchain_evm_80001_0x1",
                    "schemaId": "0x1",
                    "name": "xxx"
                }
            },
            ...
        ]
    },
    "message": "ok"
}
```

### Paged Schemas

```typescript
GET / scan / schemas;
```

Query schemas by providing a keyword. Results may be paged if the query returns many results.

Query Parameters:

| Key       | Value | Type   |
| --------- | ----- | ------ |
| page\*    | 1     | number |
| keyword\* | 0x1   | string |

\* Optional parameter.

Response:

```json
{
    "success": true,
    "statusCode": 200,
    "data": {
        "total": 23,
        "rows": [
            {
                "id": "onchain_evm_80001_0x1",
                "mode": "onchain",
                "name": "xxx",
                "description": "",
                "registrant": "0x9854E76134e6D729A633CED51042fF653f04f4C5",
                "chainType": "evm",
                "chainId": "80001",
                "schemaId": "0x1",
                "transactionHash": "0x97e69df2e65e97001da22953a4376233d792c50810cf3bff0fff1a14e7374b60",
                "attestationCount": 17,
                "attesterCount": 2,
                "data": [
                    {
                        "name": "name",
                        "type": "string"
                    }
                ]
            },
            ...
        ],
        "page": 1,
        "size": 10
    },
    "message": "ok"
}
```

### Address Schemas

```typescript
GET / scan / addresses / { address } / schemas;
```

Get a list of schemas that a given address has created.

Query Parameters:

| Key     | Value                                      | Type   |
| ------- | ------------------------------------------ | ------ |
| address | 0x059e6B8008d34aC26581fD3ED8378AA93c7941EE | string |

\* Optional parameter.

Response:

```json
{
    "success": true,
    "statusCode": 200,
    "data": {
        "total": 12,
        "rows": [
            {
                "id": "onchain_evm_80001_0x4",
                "mode": "onchain",
                "chainType": "evm",
                "chainId": "80001",
                "schemaId": "0x4",
                "transactionHash": "0xe2bb19cfd5d45e20e2cc36cb5c6ef2a947c25fc006a3386a260520646fe35837",
                "name": "message",
                "description": "",
                "revocable": true,
                "maxValidFor": "0",
                "resolver": "0x0000000000000000000000000000000000000000",
                "registerTimestamp": "1705484040",
                "registrant": "0x9854E76134e6D729A633CED51042fF653f04f4C5",
                "data": [
                    {
                        "name": "message",
                        "type": "string"
                    }
                ],
                "extra": null,
                "syncAt": "1705932587177"
            },
            ...
        ],
        "page": 1,
        "size": 10
    },
    "message": "ok"
}
```


# Attestations

### Single Attestation

```
GET /index/attestations/{id}
```

Retrieve the data of an attestation by providing an attestation ID.

Query Parameters:

| Key | Value                    | Type   |
| --- | ------------------------ | ------ |
| id  | onchain\_evm\_80001\_0x3 | string |

\* Optional parameter.

Response:

```json
{
  "success": true,
  "statusCode": 200,
  "data": {
    "id": "onchain_evm_80001_0x3",
    "mode": "onchain",
    "chainType": "evm",
    "chainId": "80001",
    "attestationId": "0x3",
    "transactionHash": "0x9e83cc789a457e0bcaa0cd5457c6a1aae4f4db8138193a3179ef33059d82f6d6",
    "indexingValue": "0x059e6B8008d34aC26581fD3ED8378AA93c7941EE",
    "schemaId": "0x1",
    "fullSchemaId": "onchain_evm_80001_0x1",
    "linkedAttestation": "",
    "attester": "0x059e6B8008d34aC26581fD3ED8378AA93c7941EE",
    "attestTimestamp": "1705485146",
    "validUntil": "0",
    "revoked": false,
    "revokeTimestamp": null,
    "revokeReason": null,
    "revokeTransactionHash": "",
    "data": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000033232320000000000000000000000000000000000000000000000000000000000",
    "dataLocation": "ONCHAIN",
    "extra": "{}",
    "syncAt": "1705653417309",
    "lastSyncAt": null,
    "recipients": [],
    "schema": {
      "id": "onchain_evm_80001_0x1",
      "mode": "onchain",
      "chainType": "evm",
      "chainId": "80001",
      "schemaId": "0x1",
      "transactionHash": "0x97e69df2e65e97001da22953a4376233d792c50810cf3bff0fff1a14e7374b60",
      "name": "xxx",
      "description": "",
      "revocable": true,
      "maxValidFor": "0",
      "resolver": "0x0000000000000000000000000000000000000000",
      "registerTimestamp": "1705387959",
      "registrant": "0x9854E76134e6D729A633CED51042fF653f04f4C5",
      "data": [
        {
          "name": "name",
          "type": "string"
        }
      ],
      "extra": null,
      "syncAt": "1705932587177"
    }
  },
  "message": "ok"
}
```

### Attestation Info

```typescript
GET / scan / attestations / { id };
```

Get the data of an attestation by providing the attestation ID.

Query Parameters:

| Key | Value                    | Type   |
| --- | ------------------------ | ------ |
| id  | onchain\_evm\_80001\_0xd | string |

\* Optional parameter.

Response:

```json
{
  "success": true,
  "statusCode": 200,
  "data": {
    "id": "onchain_evm_80001_0xd",
    "mode": "onchain",
    "chainType": "evm",
    "chainId": "80001",
    "attestationId": "0xd",
    "transactionHash": "0x5154a89cc54e30d2d9a0c53aedbebdf1a07e864287d52696af352899bba913fe",
    "indexingValue": "0x059e6B8008d34aC26581fD3ED8378AA93c7941EE",
    "schemaId": "0x1",
    "fullSchemaId": "onchain_evm_80001_0x1",
    "linkedAttestation": "",
    "attester": "0x059e6B8008d34aC26581fD3ED8378AA93c7941EE",
    "attestTimestamp": "1705542705",
    "validUntil": "0",
    "revoked": false,
    "revokeTimestamp": null,
    "revokeReason": null,
    "revokeTransactionHash": "",
    "data": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000033232320000000000000000000000000000000000000000000000000000000000",
    "dataLocation": "ONCHAIN",
    "recipients": [
      "0x059e6B8008d34aC26581fD3ED8378AA93c7941EE",
      "0x2e6CEFDe38e2363be4CE8497bee68E23004ADfB4"
    ],
    "schema": {
      "id": "onchain_evm_80001_0x1",
      "schemaId": "0x1",
      "name": "xxx",
      "data": [
        {
          "name": "name",
          "type": "string"
        }
      ]
    }
  },
  "message": "ok"
}
```

### Filtered Attestations

```typescript
GET / index / attestations;
```

Query for a list of attestations using one or more filtering parameters. Results can be paginated with customizable page sizes.

Query Parameters:

| Key             | Value                                      | Type                 |
| --------------- | ------------------------------------------ | -------------------- |
| id\*            | onchain\_evm\_80001\_0xb                   | string               |
| page\*          | 1                                          | number               |
| mode\*          | onchain                                    | "onchain"/"offchain" |
| indexingValue\* | 0x34A6d2B552c34be8136d18773Fa79036c8315180 | string               |
| schemaId\*      | onchain\_evm\_80001\_0x3                   | string               |
| attester\*      | 0x8d10d37bf3c50c9dd34a4bc70987cd60f8f4a463 | string               |
| size\*          | 100                                        | number               |

\* Optional parameter.

Response:

```json
{
  "success": true,
  "statusCode": 200,
  "data": {
    "total": 1,
    "rows": [
      {
        "id": "onchain_evm_80001_0xb",
        "mode": "onchain",
        "chainType": "evm",
        "chainId": "80001",
        "attestationId": "0xb",
        "transactionHash": "0xd6a6207a429a7fcc02dedf60db021befb3c2fd8296086f386f5595985c4ccea3",
        "indexingValue": "0x059e6B8008d34aC26581fD3ED8378AA93c7941EE",
        "schemaId": "0x1",
        "fullSchemaId": "onchain_evm_80001_0x1",
        "linkedAttestation": "",
        "attester": "0x059e6B8008d34aC26581fD3ED8378AA93c7941EE",
        "attestTimestamp": "1705485350",
        "validUntil": "0",
        "revoked": true,
        "revokeTimestamp": "1705912687",
        "revokeReason": null,
        "revokeTransactionHash": "0x031e6400760d517f2ec008e017dc3be0fecceb6b583aa61505e4f19e93c5a7b9",
        "data": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000033232320000000000000000000000000000000000000000000000000000000000",
        "dataLocation": "ONCHAIN",
        "extra": "{}",
        "syncAt": "1705653417309",
        "lastSyncAt": null,
        "recipients": [],
        "schema": {
          "id": "onchain_evm_80001_0x1",
          "mode": "onchain",
          "chainType": "evm",
          "chainId": "80001",
          "schemaId": "0x1",
          "transactionHash": "0x97e69df2e65e97001da22953a4376233d792c50810cf3bff0fff1a14e7374b60",
          "name": "xxx",
          "description": "",
          "revocable": true,
          "maxValidFor": "0",
          "resolver": "0x0000000000000000000000000000000000000000",
          "registerTimestamp": "1705387959",
          "registrant": "0x9854E76134e6D729A633CED51042fF653f04f4C5",
          "data": [
            {
              "name": "name",
              "type": "string"
            }
          ],
          "extra": null,
          "syncAt": "1705932587177"
        }
      }
    ],
    "size": 100,
    "page": 1
  },
  "message": "ok"
}
```

### Filter Attestations by Schema

```typescript
GET / scan / attestations;
```

Get attestations for a schema by providing the relevant schema ID.

Query Parameters:

| Key      | Value                    | Type   |
| -------- | ------------------------ | ------ |
| schemaId | onchain\_evm\_80001\_0x1 | string |

\* Optional parameter.

Response:

```json
{
    "success": true,
    "statusCode": 200,
    "data": {
        "total": 17,
        "rows": [
            {
                "id": "onchain_evm_80001_0x21",
                "mode": "onchain",
                "chainType": "evm",
                "chainId": "80001",
                "attestationId": "0x21",
                "schemaId": "0x1",
                "attester": "0x9854E76134e6D729A633CED51042fF653f04f4C5",
                "attestTimestamp": "1706065910",
                "recipients": []
            },
            ...
        ],
        "page": 1,
        "size": 10
    },
    "message": "ok"
}
```

### Paged Attestations

```typescript
GET / scan / attestations;
```

Query attestations by providing the fields and a relevant keyword. Results may be paged if the query returns many results.

Query Parameters:

| Key       | Value  | Type     |
| --------- | ------ | -------- |
| fields\*  | detail | "detail" |
| page\*    | 1      | number   |
| keyword\* | 0x1    | string   |

\* Optional parameter.

Response:

```json
{
    "success": true,
    "statusCode": 200,
    "data": {
        "total": 52,
        "rows": [
            {
                "id": "onchain_evm_80001_0x21",
                "mode": "onchain",
                "chainType": "evm",
                "chainId": "80001",
                "attestationId": "0x21",
                "schemaId": "0x1",
                "attester": "0x9854E76134e6D729A633CED51042fF653f04f4C5",
                "attestTimestamp": "1706065910",
                "recipients": [],
                "schema": {
                    "id": "onchain_evm_80001_0x1",
                    "chainType": "evm",
                    "chainId": "80001",
                    "schemaId": "0x1",
                    "name": "xxx"
                }
            },
            ...
        ],
        "page": 1,
        "size": 10
    },
    "message": "ok"
}
```

### Address Attestations

```typescript
GET / scan / addresses / { address } / attestations;
```

Get a list of addresses that a given address has created.

Query Parameters:

| Key     | Value                                      | Type   |
| ------- | ------------------------------------------ | ------ |
| address | 0x059e6B8008d34aC26581fD3ED8378AA93c7941EE | string |

\* Optional parameter.

Response:

```json
{
    "success": true,
    "statusCode": 200,
    "data": {
        "total": 14,
        "rows": [
            {
                "id": "onchain_evm_80001_0x4",
                "mode": "onchain",
                "chainType": "evm",
                "chainId": "80001",
                "attestationId": "0x4",
                "transactionHash": "0xe0fcf6d8e3fc2040e2fc94395144d15ca43fba75de247f650150772e2692b768",
                "indexingValue": "0x059e6B8008d34aC26581fD3ED8378AA93c7941EE",
                "schemaId": "0x1",
                "fullSchemaId": "onchain_evm_80001_0x1",
                "linkedAttestation": "",
                "attester": "0x059e6B8008d34aC26581fD3ED8378AA93c7941EE",
                "attestTimestamp": "1705485310",
                "validUntil": "0",
                "revoked": false,
                "revokeTimestamp": null,
                "revokeReason": null,
                "revokeTransactionHash": "",
                "data": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000033232320000000000000000000000000000000000000000000000000000000000",
                "dataLocation": "ONCHAIN",
                "extra": "{}",
                "syncAt": "1705653417309",
                "lastSyncAt": null,
                "recipients": [],
                "schema": {
                    "id": "onchain_evm_80001_0x1",
                    "schemaId": "0x1",
                    "name": "xxx",
                    "description": ""
                }
            },
            ...
        ],
        "page": 1,
        "size": 10
    },
    "message": "ok"
}
```


# GraphQL


# Schemas

### Single Schema

```typescript
POST / graphql;
```

Retrieve the data of a schema by querying with a schema ID.

Body Parameters:

```graphql
# Write your query or mutation here
query getSchema {
  schema(id: "onchain_evm_80001_0x3") {
    id
    mode
    chainType
    chainId
    schemaId
    transactionHash
    name
    description
    revocable
    maxValidFor
    resolver
    registerTimestamp
    registrant
    data
  }
}
```

Response:

```json
{
  "data": {
    "schema": {
      "id": "onchain_evm_80001_0x3",
      "mode": "onchain",
      "chainType": "evm",
      "chainId": "80001",
      "schemaId": "0x3",
      "transactionHash": "0x73a6b43255ada4b165b55477f34fa4baa44d9090e6ecb6a145274e15ae0865b6",
      "name": "message",
      "description": "",
      "revocable": true,
      "maxValidFor": 0,
      "resolver": "0x0000000000000000000000000000000000000000",
      "registerTimestamp": 1705484022,
      "registrant": "0x9854E76134e6D729A633CED51042fF653f04f4C5",
      "data": "[{\"name\":\"message\",\"type\":\"string\"}]"
    }
  }
}
```

### Filtered Schemas

```typescript
POST / graphql;
```

Query for a list of schemas. Results can be filtered, paginated, ordered, etc. according to GraphQL standards.

Body Parameters:

```graphql
query querySchemas {
  pagedSchemas(page: 1, size: 10) {
    total
    page
    size
    schemas {
      id
      mode
      chainType
      chainId
      schemaId
      transactionHash
      name
      description
      revocable
      maxValidFor
      resolver
      registerTimestamp
      registrant
      data
    }
  }
}
```

Response:

```json
{
    "data": {
        "pagedSchemas": {
            "total": 20,
            "page": 1,
            "size": 10,
            "schemas": [
                {
                    "id": "onchain_evm_7001_0x7",
                    "mode": "onchain",
                    "chainType": "evm",
                    "chainId": "7001",
                    "schemaId": "0x7",
                    "transactionHash": "0xabddd6fe182a75d61eb0feef028a71a24fbdf46e7508c519c099c9d8a5805801",
                    "name": "test",
                    "description": "whasa",
                    "revocable": true,
                    "maxValidFor": 0,
                    "resolver": "0x0000000000000000000000000000000000000000",
                    "registerTimestamp": 1705912991,
                    "registrant": "0xDfc4FbbDd9C47c7976fEBb14B1D37C7f85FE299D",
                    "data": "[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"count\",\"type\":\"number\"}]"
                },
                ...
            ]
        }
    }
}
```


# Attestations

### Single Attestation

```typescript
POST / graphql;
```

Retrieve the data of an attestation by querying with an attestation ID.

Body Parameters:

```graphql
query getAttestation {
  attestation(id: "onchain_evm_80001_0x1") {
    # Write your query or mutation here
    attestationId
    attester
    attestTimestamp
    linkedAttestation
    chainId
    chainType
    data
    dataLocation
    transactionHash
    revokeTransactionHash
    id
    indexingValue
    mode
    recipients
    revoked
    revokeReason
    revokeTimestamp
    schema {
      id
      name
      registrant
    }
    validUntil
  }
}
```

Response:

```json
{
  "data": {
    "attestation": {
      "attestationId": "0x1",
      "attester": "0x9854E76134e6D729A633CED51042fF653f04f4C5",
      "attestTimestamp": 1705455448,
      "linkedAttestation": "",
      "chainId": "80001",
      "chainType": "evm",
      "data": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000033232320000000000000000000000000000000000000000000000000000000000",
      "dataLocation": "ONCHAIN",
      "transactionHash": "0x00ecb7e8c6d3ae6d0fab2432c1e7ccc3f1128716839c04b5b4a51457e9ce6eff",
      "revokeTransactionHash": "",
      "id": "onchain_evm_80001_0x1",
      "indexingValue": "",
      "mode": "onchain",
      "recipients": [],
      "revoked": false,
      "revokeReason": null,
      "revokeTimestamp": null,
      "schema": {
        "id": "onchain_evm_80001_0x1",
        "name": "xxx",
        "registrant": "0x9854E76134e6D729A633CED51042fF653f04f4C5"
      },
      "validUntil": 0
    }
  }
}
```

### Filtered Attestations

```typescript
POST / graphql;
```

Query for a list of attestations. Results can be filtered, paginated, ordered, etc. according to GraphQL standards.

Body Parameters:

```graphql
query queryAttestations {
  pagedAttestations(page: 1) {
    total
    attestations {
      attestationId
      attester
      attestTimestamp
      linkedAttestation
      chainId
      chainType
      data
      dataLocation
      transactionHash
      revokeTransactionHash
      id
      indexingValue
      mode
      recipients
      revoked
      revokeReason
      revokeTimestamp
      schema {
        id
        schemaId
        name
        registrant
        data
      }
      validUntil
    }
  }
}
```

Response:

```graphql
{
    "data": {
        "pagedAttestations": {
            "total": 52,
            "attestations": [
                {
                    "attestationId": "0x21",
                    "attester": "0x9854E76134e6D729A633CED51042fF653f04f4C5",
                    "attestTimestamp": 1706065910,
                    "linkedAttestation": "",
                    "chainId": "80001",
                    "chainType": "evm",
                    "data": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000033232320000000000000000000000000000000000000000000000000000000000",
                    "dataLocation": "ONCHAIN",
                    "transactionHash": "0x0f0fb01c520add97a74d6125729053559c7cffb96a5f5871118b766e9a3ddbb7",
                    "revokeTransactionHash": "0x2e0cda7c6222190c5065df8c8164ee26aec6132c98320733b2775c923fcca634",
                    "id": "onchain_evm_80001_0x21",
                    "indexingValue": "0x059e6B8008d34aC26581fD3ED8378AA93c7941EE",
                    "mode": "onchain",
                    "recipients": [],
                    "revoked": true,
                    "revokeReason": "test revoke",
                    "revokeTimestamp": 1706065942,
                    "schema": {
                        "id": "onchain_evm_80001_0x1",
                        "schemaId": "0x1",
                        "name": "xxx",
                        "registrant": "0x9854E76134e6D729A633CED51042fF653f04f4C5",
                        "data": "[{\"name\":\"name\",\"type\":\"string\"}]"
                    },
                    "validUntil": 0
                },
                ...
            ]
        }
    }
}
```


# Writing Data


# NPM SDK


# Installation

### Installation

Install the [`@ethsign/sp-sdk`](https://www.npmjs.com/package/@ethsign/sp-sdk) package to use the Sign Protocol SDK in your frontend or Node backend projects.

### Creating a Client Instance

```ts
new SignProtocolClient(spMode, options);
```

#### Parameters

| Name    | Type                                            | Description                                                                |
| ------- | ----------------------------------------------- | -------------------------------------------------------------------------- |
| spMode  | `SpMode`                                        | Whether the client is initialized in on-chain or Arweave (off-chain) mode. |
| options | `OnChainClientOptions`, `OffChainClientOptions` | Client options based on `spMode`.                                          |

{% hint style="warning" %}
NOTE: The `account` variable in `options` is marked as optional. If it is not provided, the SDK will use the provider from `window.ethereum` by default to derive an account. If a provider from `window.ethereum` cannot be located AND an account is not provided, calls to the SDK will fail.
{% endhint %}

#### Example

```typescript
const { privateKeyToAccount } = require("viem/accounts");
const client = new SignProtocolClient(SpMode.OnChain, {
  chain: EvmChains.baseSepolia,
  account: privateKeyToAccount(privateKey),
  apiKey: 'xxx', // Get a key from https://developer.sign.global/
});
```


# Usage


# Schemas

## Types

### Schema (Onchain)

| Name          | Type                       | Description                                                                                                                                                              |
| ------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| name          | `string`                   | Schema name.                                                                                                                                                             |
| description?  | `string`                   | Schema description.                                                                                                                                                      |
| revocable?    | `boolean`                  | Whether Attestations that adopt this Schema can be revoked.                                                                                                              |
| maxValidFor?  | `number`                   | The maximum number of seconds that an Attestation can remain valid. 0 means Attestations can be valid forever. This is enforced through `Attestation.validUntil`.        |
| hook?         | `address`                  | The contract address of the hook for this schema.                                                                                                                        |
| registrant    | `address`                  | The wallet address of the user that registered this schema.                                                                                                              |
| dataLocation? | `DataLocationOnChain`      | Where `Schema.data` is stored. See `DataLocation.DataLocation`.                                                                                                          |
| data          | `SchemaItem[]` or `string` | The data format defining this schema's data structure. When `dataLocation=ONCHAIN`, data is `SchemaItem[]`, when `dataLocation=ARWEAVE or IPFS`, data is id of the data. |

### Schema (Offchain)

| Name          | Type                   | Description                                                                                                                                                       |
| ------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name          | `string`               | Schema name.                                                                                                                                                      |
| description?  | `string`               | Schema description.                                                                                                                                               |
| revocable?    | `boolean`              | Whether Attestations that adopt this Schema can be revoked.                                                                                                       |
| maxValidFor?  | `number`               | The maximum number of seconds that an Attestation can remain valid. 0 means Attestations can be valid forever. This is enforced through `Attestation.validUntil`. |
| dataLocation? | `DataLocationOffChain` | Where `Schema.data` is stored. See `DataLocation.DataLocation`.                                                                                                   |
| data          | `SchemaItem[]`         | The data format defining this schema's data structure.                                                                                                            |

## Usage

### Registering a Schema

```ts
async function createSchema(
  schema: Schema,
  options?: { getTxHash?: (txHash: `0x${string}`) => void }
): Promise<SchemaResult>;
```

#### Parameters

| Name     | Type                  | Description                    |
| -------- | --------------------- | ------------------------------ |
| schema   | `Schema`              | The schema being registered.   |
| options? | `CreateSchemaOptions` | Options for creating a schema. |

#### CreateSchemaOptions

| Name                 | Type                                | Description                                                                                                           |
| -------------------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| delegationSignature? | string                              | The user's delegate signature for creating a schema on their behalf. Call `delegateSignSchema` to get this signature. |
| getTxHash?           | ``(txHash: `0x${string}`) => void`` | An optional callback that immediately returns the transaction hash.                                                   |

#### Example

```typescript
const res = await client.createSchema({
  name: "Example",
  data: [{ name: "name", type: "string" }],
});
```

### Retrieving a Schema

```ts
async function getSchema(schemaId: string): Promise<Schema>;
```

#### Parameters

| Name     | Type     | Description                                     |
| -------- | -------- | ----------------------------------------------- |
| schemaId | `string` | The ID of the schema we are trying to retrieve. |

#### Example

```typescript
const res = await client.getSchema("0x3e");
```

### Delegating On-chain Schema Registration via ECDSA

```ts
async function delegateSignSchema(
  schema: OnChainSchema,
  options: DelegateSignSchemaOptions
): Promise<SchemaDelegationSignature>;
```

#### Parameters

| Name    | Type                        | Description                              |
| ------- | --------------------------- | ---------------------------------------- |
| schema  | `OnChainSchema`             | An on-chain schema.                      |
| options | `DelegateSignSchemaOptions` | Options for delegate signing the schema. |

#### DelegateSignSchemaOptions

| Name               | Type                |                                                                                                                                |
| ------------------ | ------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| chain              | `EvmChains`         | The EVM chain you are targetting.                                                                                              |
| delegationAccount? | `PrivateKeyAccount` | The signer account that signs the message. See `viem/accounts`. If this is null, a signer from `window.ethereum` will be used. |
| rpcUrl?            | `string`            | Optional RPC URL.                                                                                                              |
| walletClient?      | `WalletClient`      | Optional `WalletClient` from viem to use for transactions.                                                                     |


# Attestations

## Types

### Attestation (Onchain)

| Name                 | Type                               | Description                                                                                                                    |
| -------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| schemaId             | `string`                           | Schema ID for this attestation.                                                                                                |
| linkedAttestationId? | `string`, `null`                   | The ID of the attestation that this attestation references.                                                                    |
| validUntil?          | `number`                           | Timestamp that this attestation is valid until.                                                                                |
| revoked?             | `boolean`, `null`                  | Whether or not this attestation is revoked.                                                                                    |
| recipients?          | `string[]`                         | List of recipient addresses.                                                                                                   |
| indexingValue        | `string`                           | The indexing value of this attestation. Can be used for filtering while querying using the indexing service.                   |
| attester?            | `address`                          | The attester's address.                                                                                                        |
| attestTimestamp?     | `number`                           | Timestamp that the attestation was created.                                                                                    |
| revokeTimestamp?     | `number`                           | Timestamp that the attestation was revoked.                                                                                    |
| dataLocation?        | `DataLocationOnchain`              | Where `Attestation.data` is stored. See `DataLocation.DataLocation`.                                                           |
| data                 | `{ [key: string]: any }`, `string` | If `dataLocation` is `ONCHAIN`, `data` is the data object. Otherwise, data is a `string` of the CID from the storage provider. |

### Attestation (Offchain)

| Name                 | Type                     | Description                                                                                                  |
| -------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------ |
| schemaId             | `string`                 | Schema ID for this attestation.                                                                              |
| linkedAttestationId? | `string`, `null`         | The ID of the attestation that this attestation references.                                                  |
| validUntil?          | `number`                 | Timestamp that this attestation is valid until.                                                              |
| revoked?             | `boolean`, `null`        | Whether or not this attestation is revoked.                                                                  |
| recipients?          | `string[]`               | List of recipient addresses.                                                                                 |
| indexingValue        | `string`                 | The indexing value of this attestation. Can be used for filtering while querying using the indexing service. |
| attester?            | `address`                | The attester's address.                                                                                      |
| dataLocation?        | `DataLocationOffchain`   | Where `Attestation.data` is stored. See `DataLocation.DataLocation`.                                         |
| data                 | `{ [key: string]: any }` | The data object to be stored with this attestation.                                                          |

## Creating Attestations

{% hint style="warning" %}
NOTE: You must provide an API key when initializing your SignClient to create offchain attestations. You can generate a key [here](https://developer.sign.global/). For more information, see [Installation](/for-builders/index-1/npm-sdk/installation).
{% endhint %}

### Creating an Attestation

```ts
async function createAttestation(
  attestation: Attestation,
  options?: CreateAttestationOnChainOptions
): Promise<AttestationResult>;
```

#### Parameters

| Name        | Type                              | Description                          |
| ----------- | --------------------------------- | ------------------------------------ |
| attestation | `Attestation`                     | An attestation object.               |
| options?    | `CreateAttestationOnChainOptions` | Options for creating an attestation. |

#### CreateAttestationOnChainOptions

| Name                   | Type                                | Description                                                                                          |
| ---------------------- | ----------------------------------- | ---------------------------------------------------------------------------------------------------- |
| resolverFeesETH?       | `BigInt`                            | ETH fees to be sent to the schema hook, in wei.                                                      |
| delegationSignature?   | `string`                            | The attester's delegate signature when creating an attestation on their behalf.                      |
| getTxHash?             | ``(txHash: `0x${string}`) => void`` | An optional callback that immediately returns the transaction hash.                                  |
| recipientEncodingType? | `RecipientEncodingType`             | Defines the attestation's recipient encoding type as either an address or string.                    |
| extraData?             | `0x${string}`                       | Extra data that is passed to the schema hook. This data is not stored by the Sign Protocol contract. |

#### Example

```typescript
const res = await client.createAttestation({
  schemaId: "0x3e",
  data: { name: "a" },
  indexingValue: "xxx",
});
```

### Delegating On-chain Attestation via ECDSA

```ts
async function delegateSignAttestation(
  attestation: Attestation,
  options: DelegateSignAttestationOptions
): Promise<AttestationDelegationSignature>;
```

#### Parameters

| Name        | Type                             | Description                                 |
| ----------- | -------------------------------- | ------------------------------------------- |
| attestation | `Attestation`                    | An attestation object.                      |
| options     | `DelegateSignAttestationOptions` | Options for delegate attestation signature. |

#### DelegateSignAttestationOptions

| Name                   | Type                    | Description                                                                                                                    |
| ---------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| chain                  | `EvmChains`             | The EVM chain we are targeting.                                                                                                |
| delegationAccount?     | `PrivateKeyAccount`     | The signer account that signs the message. See `viem/accounts`. If this is null, a signer from `window.ethereum` will be used. |
| recipientEncodingType? | `RecipientEncodingType` | Defines the attestation's recipient encoding type as either an address or string.                                              |
| rpcUrl?                | `string`                | Optional RPC URL.                                                                                                              |
| walletClient?          | `WalletClient`          | Optional `WalletClient` from viem to use for transactions.                                                                     |

#### Example

```typescript
const { privateKeyToAccount } = require("viem/accounts");
const delegationPrivateKey = "0x...";
const delegationResult = await delegateSignAttestation(
  { schemaId: "0x3e", data: { name: "a" }, indexingValue: "xxx" },
  {
    chain: EvmChains.baseSepolia,
    delegationAccount: privateKeyToAccount(delegationPrivateKey),
  }
);
const res = await client.createAttestation(delegationResult.attestation, {
  delegationSignature: delegationResult.delegationSignature,
});
```

### Retrieving an Attestation

```ts
async function getAttestation(attestationId: string): Promise<Attestation>;
```

#### Parameters

| Name          | Type     | Description                                          |
| ------------- | -------- | ---------------------------------------------------- |
| attestationId | `string` | The ID of the attestation we are trying to retrieve. |

#### Example

```typescript
const res = await client.getAttestation("0x44");
```

## Revoking Attestations

### Revoke an Attestation

```ts
async function revokeAttestation(
  attestationId: string,
  options?: RevokeAttestationOptions
): Promise<RevokeAttestationResult>;
```

#### Parameters

<table><thead><tr><th width="219">Name</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>attestationId</td><td><code>string</code></td><td>The ID of the attestation we are revoking.</td></tr><tr><td>options?</td><td><code>RevokeAttestationOptions</code></td><td>Options for revoking an attestation.</td></tr></tbody></table>

#### RevokeAttestationOptions

<table><thead><tr><th width="219">Name</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td>reason?</td><td><code>string</code></td><td>Reason for the revocation.</td></tr><tr><td>delegateSignature?</td><td><code>string</code></td><td>The user's delegate signature when revoking an attestation on their behalf.</td></tr><tr><td>getTxHash?</td><td><code>(txHash: `0x${string}`) => void</code></td><td>An optional callback that immediately returns the transaction hash.</td></tr></tbody></table>

#### Example

```typescript
const res = await client.revokeAttestation("0x44");
```

### Delegating On-chain Revocation via ECDSA

```ts
async function delegateSignRevokeAttestation(
  attestationId: string,
  options: {
    chain: EvmChains;
    delegationAccount?: PrivateKeyAccount;
    reason?: string;
  }
): Promise<RevokeDelegationSignature>;
```

#### Parameters

| Name          | Type                                   | Description                                   |
| ------------- | -------------------------------------- | --------------------------------------------- |
| attestationId | `string`                               | The ID of the attestation we are revoking.    |
| options       | `DelegateSignRevokeAttestationOptions` | Options for delegate revoking an attestation. |

#### DelegateSignRevokeAttestationOptions

| Name               | Type                | Description                                                                                                                    |
| ------------------ | ------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| chain              | `EvmChains`         | The EVM chain we are targeting.                                                                                                |
| delegationAccount? | `PrivateKeyAccount` | The signer account that signs the message. See `viem/accounts`. If this is null, a signer from `window.ethereum` will be used. |
| reason?            | `string`            | Reason for the revocation.                                                                                                     |
| rpcUrl?            | `string`            | Optional RPC URL.                                                                                                              |
| walletClient?      | `WalletClient`      | Optional `WalletClient` from viem to use for transactions.                                                                     |

#### Example

```typescript
const { privateKeyToAccount } = require("viem/accounts");
const delegationPrivateKey = "0x...";
const delegationResult = await delegateSignRevokeAttestation("0x46", {
  chain: EvmChains.baseSepolia,
  reason: "revoke reason",
  delegationAccount: privateKeyToAccount(delegationPrivateKey),
});
const res = await client.revokeAttestation(delegationResult.attestationId, {
  reason: delegationResult.reason,
  delegationSignature: delegationResult.delegationSignature,
});
```


# Examples

### On-chain Mode

```tsx
import {
  SignProtocolClient,
  SpMode,
  EvmChains,
  delegateSignAttestation,
  delegateSignRevokeAttestation,
  delegateSignSchema,
} from "@ethsign/sp-sdk";
import { privateKeyToAccount } from "viem/accounts";
const privateKey = "0xabc"; // Optional

const client = new SignProtocolClient(SpMode.OnChain, {
  chain: EvmChains.polygonMumbai,
  account: privateKeyToAccount(privateKey), // Optional if you are using an injected provider
  apiKey: 'xxx', // Optional, from https://developer.sign.global/
});

// Create schema
const createSchemaRes = await client.createSchema({
  name: "xxx",
  data: [{ name: "name", type: "string" }],
});

// Delegated create schema
const delegationPrivateKey = "0xaaaaa";
const info = await delegateSignSchema(
  {
    name: "xxx",
    data: [{ name: "name", type: "string" }],
  },
  {
    chain: EvmChains.sepolia,
    delegationAccount: privateKeyToAccount(delegationPrivateKey),
  }
);
const delegateCreateSchemaRes = await client.createSchema(info.schema, {
  delegationSignature: info.delegationSignature,
});

// Create attestation
const createAttestationRes = await client.createAttestation({
  schemaId: "0x3",
  data: { name: "a" },
  indexingValue: "xxx",
});

// Delegated create attestation
const delegationPrivateKey = "0xaaaaa";
const info = await delegateSignAttestation(
  {
    schemaId: "0x1",
    data: { name: "a" },
    indexingValue: "xxx",
  },
  {
    chain: EvmChains.sepolia,
    delegationAccount: privateKeyToAccount(delegationPrivateKey),
  }
);

const delegationCreateAttestationRes = await client.createAttestation(
  info.attestation,
  {
    delegationSignature: info.delegationSignature,
  }
);

// Revoke attestation
const revokeAttestationRes = await client.revokeAttestation("0x3", {
  reason: "test",
});

// Delegated revoke attestation
const delegationPrivateKey = "0xaaaaa";
const info = await delegateSignRevokeAttestation(attestationId, {
  chain: EvmChains.sepolia,
  reason: "test",
  delegationAccount: privateKeyToAccount(delegationPrivateKey),
});
const delegationRevokeAttestationRes = await client.revokeAttestation(
  info.attestationId,
  {
    reason: info.reason,
    delegationSignature: info.delegationSignature,
  }
);
```

### Off-chain (Arweave) Mode

```tsx
import {
  SignProtocolClient,
  SpMode,
  EvmChains,
  OffChainSignType,
} from "@ethsign/sp-sdk";
import { privateKeyToAccount } from "viem/accounts";
const privateKey = "0xabc"; // Optional
const client = new SignProtocolClient(SpMode.OffChain, {
  signType: OffChainSignType.EvmEip712,
  account: privateKeyToAccount(privateKey), // Optional
  apiKey: 'xxx', // Required, from https://developer.sign.global/
});

// Create schema
const schemaInfo = await client.createSchema({
  name: "xxx",
  data: [{ name: "name", type: "string" }],
});

// Create attestation
const attestationInfo = await client.createAttestation({
  schemaId: "xxxx", // `schemaInfo.schemaId` or other `schemaId`
  data: { name: "a" },
  indexingValue: "xxx",
});

// Revoke attestation
const attestationId = "xxx";
const revokeAttestationRes = await client.revokeAttestation(attestationId, {
  reason: "test",
});
```


# Changelog

See the full changelog [here](https://www.npmjs.com/package/@ethsign/sp-sdk#changelog).


# Smart Contract


# EVM

## Installation

```bash
npm i @ethsign/sign-protocol-evm -S
```

## Example Usage: Actually Met IRL

*Actually Met IRL* is a smart contract that only creates an attestation on EVM Sign Protocol for two people meeting in real life if both parties consent to this fact. In this example, we will demonstrate how to:

* Link your smart contract to an existing on-chain Sign Protocol deployment and schema
* Create an attestation programmatically

You can find the complete Foundry repository [here](https://github.com/EthSign/sign-protocol-evm-demo-0), a deployment of the example contract on Base Sepolia [here](https://sepolia.basescan.org/address/0x996a99676d286fCeFCc1920369548c62ff7d6D11), and the corresponding SignScan page [here](https://testnet-scan.sign.global/schema/onchain_evm_84532_0x12).

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { ISP } from "@ethsign/sign-protocol-evm/src/interfaces/ISP.sol";
import { Attestation } from "@ethsign/sign-protocol-evm/src/models/Attestation.sol";
import { DataLocation } from "@ethsign/sign-protocol-evm/src/models/DataLocation.sol";

contract ActuallyMetIRL is Ownable {
    ISP public spInstance;
    uint64 public schemaId;
    mapping(address partyA => address partyB) public metIRLMapping;

    error ConfirmationAddressMismatch();

    event DidMeetIRL(address partyA, address partyB, uint64 attestationId);

    constructor() Ownable(_msgSender()) { }

    function setSPInstance(address instance) external onlyOwner {
        spInstance = ISP(instance);
    }

    function setSchemaID(uint64 schemaId_) external onlyOwner {
        schemaId = schemaId_;
    }

    function claimMetIRL(address partyB) external {
        metIRLMapping[_msgSender()] = partyB;
    }


    function confirmMetIRL(address partyA, bytes memory data) external returns (uint64) {
        address partyB = _msgSender();
        if (metIRLMapping[partyA] == partyB) {
            // B has confirm A's claim of having met them IRL
            // We now make an attestation of having actually met IRL
            bytes[] memory recipients = new bytes[](2);
            recipients[0] = abi.encode(partyA);
            recipients[1] = abi.encode(partyB);
            Attestation memory a = Attestation({
                schemaId: schemaId,
                linkedAttestationId: 0,
                attestTimestamp: 0,
                revokeTimestamp: 0,
                attester: address(this),
                validUntil: 0,
                dataLocation: DataLocation.ONCHAIN,
                revoked: false,
                recipients: recipients,
                data: data // SignScan assumes this is from `abi.encode(...)`
            });
            uint64 attestationId = spInstance.attest(a, "", "", "");
            emit DidMeetIRL(partyA, partyB, attestationId);
            return attestationId;
        } else {
            revert ConfirmationAddressMismatch();
        }
    }
}
```

{% hint style="warning" %}
NOTE: `data` is expecting a value from `abi.encode()`. If your relevant schema is storing data on-chain, you need to encode the actual data you are trying to store. If you are storing data off-chain, such as IPFS, you will need to upload the data, in JSON format, to the storage provider first. Next, you will encode the resulting CID string and pass in this value as `data`.
{% endhint %}


# Changelog

All notable changes to the Sign Protocol EVM contract package are documented here.

## 1.1.4

* Hardened delegated signatures with EIP-712 domain binding, per-attester nonces, and deadlines.
* Added `delegationNonces(address)` and `getDelegatedAuthorizationDigest(...)` for delegated-action signing.
* Rejected legacy delegated signatures that do not use the new encoded `(nonce, deadline, signature)` format.
* Converted deployment and upgrade tooling from Hardhat scripts to Foundry scripts using the CREATE3 deployment template.
* Added deterministic SP implementation deployment and existing proxy upgrade scripts.
* Added `bun run patch:sp` for chain-aware proxy patching with Alchemy RPC URL derivation.
* Added optional proxy ownership transfer to `PROD_OWNER` after successful upgrades.
* Added standard JSON input for SP `1.1.4` contract verification.
* Removed legacy Hardhat, Prettier, and unused package tooling in favor of Bun and Foundry formatting.

## 1.1.3

* Removed `registerBatch` and related interface functions to reduce contract size.
* Added Soldeer support and refreshed Foundry dependency wiring.
* Added Monad testnet configuration and deployment metadata updates.

## 1.1.2

* Fixed linked-attestation validation behavior.
* Added missing revoked-attestation checks while attesting.
* Bumped the Solidity compiler configuration to `0.8.26`.

## 1.1.1

* Fixed schema existence checks.

## 1.1.0

* Added storage of schema and attestation timestamps.
* Added backward-compatible behavior for existing schema and attestation counters.
* Optimized SP core contract and interface types.

## 1.0.1

* Fixed incorrect data passed to hooks.

## 1.0.0

* Initial npm package release for Sign Protocol EVM contracts.


# Interfaces


# ISP

Version 1.0.0-beta18

## Events

### SchemaRegistered

```solidity
event SchemaRegistered(uint64 schemaId)
```

### AttestationMade

```solidity
event AttestationMade(uint64 attestationId, string indexingKey)
```

### AttestationRevoked

```solidity
event AttestationRevoked(uint64 attestationId, string reason)
```

### OffchainAttestationMade

```solidity
event OffchainAttestationMade(string attestationId)
```

### OffchainAttestationRevoked

```solidity
event OffchainAttestationRevoked(string attestationId, string reason)
```

## Errors

### SchemaNonexistent

```solidity
error SchemaNonexistent(uint64 nonexistentSchemaId)
```

*0x38f8c6c4*

### SchemaWrongRegistrant

```solidity
error SchemaWrongRegistrant(address expected, address actual)
```

*0x71984561*

### AttestationIrrevocable

```solidity
error AttestationIrrevocable(uint64 schemaId, uint64 offendingAttestationId)
```

*0x8ac42f49*

### AttestationNonexistent

```solidity
error AttestationNonexistent(uint64 nonexistentAttestationId)
```

*0x54681a13*

### AttestationInvalidDuration

```solidity
error AttestationInvalidDuration(uint64 offendingAttestationId, uint64 maxDuration, uint64 inputDuration)
```

*0xa65e02ed*

### AttestationAlreadyRevoked

```solidity
error AttestationAlreadyRevoked(uint64 offendingAttestationId)
```

*0xd8c3da86*

### AttestationWrongAttester

```solidity
error AttestationWrongAttester(address expected, address actual)
```

*0xa9ad2007*

### OffchainAttestationExists

```solidity
error OffchainAttestationExists(string existingOffchainAttestationId)
```

*0xc83e3cdf*

### OffchainAttestationNonexistent

```solidity
error OffchainAttestationNonexistent(string nonexistentOffchainAttestationId)
```

*0xa006519a*

### OffchainAttestationAlreadyRevoked

```solidity
error OffchainAttestationAlreadyRevoked(string offendingOffchainAttestationId)
```

*0xa0671d20*

### InvalidDelegateSignature

```solidity
error InvalidDelegateSignature()
```

*0xfdf4e6f9*

### LegacySPRequired

```solidity
error LegacySPRequired(address legacySP)
```

*0x5c34b9cc*

## Functions

### register

```solidity
function register(struct Schema schema, bytes delegateSignature) external returns (uint64 schemaId)
```

Registers a Schema.

*Emits `SchemaRegistered`.*

#### Parameters

| Name              | Type          | Description   |
| ----------------- | ------------- | ------------- |
| schema            | struct Schema | See `Schema`. |
| delegateSignature | bytes         |               |

#### Return Values

| Name     | Type   | Description                               |
| -------- | ------ | ----------------------------------------- |
| schemaId | uint64 | The assigned ID of the registered schema. |

### attest

```solidity
function attest(struct Attestation attestation, string indexingKey, bytes delegateSignature, bytes extraData) external returns (uint64 attestationId)
```

Makes an attestation.

*Emits `AttestationMade`.*

#### Parameters

| Name              | Type               | Description                                                                                         |
| ----------------- | ------------------ | --------------------------------------------------------------------------------------------------- |
| attestation       | struct Attestation | See `Attestation`.                                                                                  |
| indexingKey       | string             | Used by the frontend to aid indexing.                                                               |
| delegateSignature | bytes              | An optional ECDSA delegateSignature if this is a delegated attestation. Use `""` or `0x` otherwise. |
| extraData         | bytes              | This is forwarded to the resolver directly.                                                         |

#### Return Values

| Name          | Type   | Description                         |
| ------------- | ------ | ----------------------------------- |
| attestationId | uint64 | The assigned ID of the attestation. |

### attest

```solidity
function attest(struct Attestation attestation, uint256 resolverFeesETH, string indexingKey, bytes delegateSignature, bytes extraData) external payable returns (uint64 attestationId)
```

Makes an attestation where the schema hook expects ETH payment.

*Emits `AttestationMade`.*

#### Parameters

| Name              | Type               | Description                                                                                         |
| ----------------- | ------------------ | --------------------------------------------------------------------------------------------------- |
| attestation       | struct Attestation | See `Attestation`.                                                                                  |
| resolverFeesETH   | uint256            | Amount of funds to send to the hook.                                                                |
| indexingKey       | string             | Used by the frontend to aid indexing.                                                               |
| delegateSignature | bytes              | An optional ECDSA delegateSignature if this is a delegated attestation. Use `""` or `0x` otherwise. |
| extraData         | bytes              | This is forwarded to the resolver directly.                                                         |

#### Return Values

| Name          | Type   | Description                         |
| ------------- | ------ | ----------------------------------- |
| attestationId | uint64 | The assigned ID of the attestation. |

### attest

```solidity
function attest(struct Attestation attestation, contract IERC20 resolverFeesERC20Token, uint256 resolverFeesERC20Amount, string indexingKey, bytes delegateSignature, bytes extraData) external returns (uint64 attestationId)
```

Makes an attestation where the schema hook expects ERC20 payment.

*Emits `AttestationMade`.*

#### Parameters

| Name                    | Type               | Description                                                                                         |
| ----------------------- | ------------------ | --------------------------------------------------------------------------------------------------- |
| attestation             | struct Attestation | See `Attestation`.                                                                                  |
| resolverFeesERC20Token  | contract IERC20    | ERC20 token address used for payment.                                                               |
| resolverFeesERC20Amount | uint256            | Amount of funds to send to the hook.                                                                |
| indexingKey             | string             | Used by the frontend to aid indexing.                                                               |
| delegateSignature       | bytes              | An optional ECDSA delegateSignature if this is a delegated attestation. Use `""` or `0x` otherwise. |
| extraData               | bytes              | This is forwarded to the resolver directly.                                                         |

#### Return Values

| Name          | Type   | Description                         |
| ------------- | ------ | ----------------------------------- |
| attestationId | uint64 | The assigned ID of the attestation. |

### attestOffchain

```solidity
function attestOffchain(string offchainAttestationId, address delegateAttester, bytes delegateSignature) external
```

Timestamps an off-chain data ID.

*Emits `OffchainAttestationMade`.*

#### Parameters

| Name                  | Type    | Description                                                                                                                                         |
| --------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| offchainAttestationId | string  | The off-chain data ID.                                                                                                                              |
| delegateAttester      | address | An optional delegated attester that authorized the caller to attest on their behalf if this is a delegated attestation. Use `address(0)` otherwise. |
| delegateSignature     | bytes   | An optional ECDSA delegateSignature if this is a delegated attestation. Use `""` or `0x` otherwise. Use `""` or `0x` otherwise.                     |

### revoke

```solidity
function revoke(uint64 attestationId, string reason, bytes delegateSignature, bytes extraData) external
```

Revokes an existing revocable attestation.

*Emits `AttestationRevoked`. Must be called by the attester.*

#### Parameters

| Name              | Type   | Description                                                            |
| ----------------- | ------ | ---------------------------------------------------------------------- |
| attestationId     | uint64 | An existing attestation ID.                                            |
| reason            | string | The revocation reason. This is only emitted as an event to save gas.   |
| delegateSignature | bytes  | An optional ECDSA delegateSignature if this is a delegated revocation. |
| extraData         | bytes  | This is forwarded to the resolver directly.                            |

### revoke

```solidity
function revoke(uint64 attestationId, string reason, uint256 resolverFeesETH, bytes delegateSignature, bytes extraData) external payable
```

Revokes an existing revocable attestation where the schema hook expects ERC20 payment.

*Emits `AttestationRevoked`. Must be called by the attester.*

#### Parameters

| Name              | Type    | Description                                                            |
| ----------------- | ------- | ---------------------------------------------------------------------- |
| attestationId     | uint64  | An existing attestation ID.                                            |
| reason            | string  | The revocation reason. This is only emitted as an event to save gas.   |
| resolverFeesETH   | uint256 | Amount of funds to send to the hook.                                   |
| delegateSignature | bytes   | An optional ECDSA delegateSignature if this is a delegated revocation. |
| extraData         | bytes   | This is forwarded to the resolver directly.                            |

### revoke

```solidity
function revoke(uint64 attestationId, string reason, contract IERC20 resolverFeesERC20Token, uint256 resolverFeesERC20Amount, bytes delegateSignature, bytes extraData) external
```

Revokes an existing revocable attestation where the schema hook expects ERC20 payment.

*Emits `AttestationRevoked`. Must be called by the attester.*

#### Parameters

| Name                    | Type            | Description                                                            |
| ----------------------- | --------------- | ---------------------------------------------------------------------- |
| attestationId           | uint64          | An existing attestation ID.                                            |
| reason                  | string          | The revocation reason. This is only emitted as an event to save gas.   |
| resolverFeesERC20Token  | contract IERC20 | ERC20 token address used for payment.                                  |
| resolverFeesERC20Amount | uint256         | Amount of funds to send to the hook.                                   |
| delegateSignature       | bytes           | An optional ECDSA delegateSignature if this is a delegated revocation. |
| extraData               | bytes           | This is forwarded to the resolver directly.                            |

### revokeOffchain

```solidity
function revokeOffchain(string offchainAttestationId, string reason, bytes delegateSignature) external
```

Revokes an existing offchain attestation.

*Emits `OffchainAttestationRevoked`. Must be called by the attester.*

#### Parameters

| Name                  | Type   | Description                                                            |
| --------------------- | ------ | ---------------------------------------------------------------------- |
| offchainAttestationId | string | An existing attestation ID.                                            |
| reason                | string | The revocation reason. This is only emitted as an event to save gas.   |
| delegateSignature     | bytes  | An optional ECDSA delegateSignature if this is a delegated revocation. |

### registerBatch

```solidity
function registerBatch(struct Schema[] schemas, bytes delegateSignature) external returns (uint64[] schemaIds)
```

Batch registers a Schema.

### attestBatch

```solidity
function attestBatch(struct Attestation[] attestations, string[] indexingKeys, bytes delegateSignature, bytes extraData) external returns (uint64[] attestationIds)
```

Batch attests.

### attestBatch

```solidity
function attestBatch(struct Attestation[] attestations, uint256[] resolverFeesETH, string[] indexingKeys, bytes delegateSignature, bytes extraData) external payable returns (uint64[] attestationIds)
```

Batch attests where the schema hook expects ETH payment.

### attestBatch

```solidity
function attestBatch(struct Attestation[] attestations, contract IERC20[] resolverFeesERC20Tokens, uint256[] resolverFeesERC20Amount, string[] indexingKeys, bytes delegateSignature, bytes extraData) external returns (uint64[] attestationIds)
```

Batch attests where the schema hook expects ERC20 payment.

### attestOffchainBatch

```solidity
function attestOffchainBatch(string[] offchainAttestationIds, address delegateAttester, bytes delegateSignature) external
```

Batch timestamps off-chain data IDs.

### revokeBatch

```solidity
function revokeBatch(uint64[] attestationIds, string[] reasons, bytes delegateSignature, bytes extraData) external
```

Batch revokes revocable on-chain attestations.

### revokeBatch

```solidity
function revokeBatch(uint64[] attestationIds, string[] reasons, uint256[] resolverFeesETH, bytes delegateSignature, bytes extraData) external payable
```

Batch revokes revocable on-chain attestations where the schema hook expects ETH payment.

### revokeBatch

```solidity
function revokeBatch(uint64[] attestationIds, string[] reasons, contract IERC20[] resolverFeesERC20Tokens, uint256[] resolverFeesERC20Amount, bytes delegateSignature, bytes extraData) external
```

Batch revokes revocable on-chain attestations where the schema hook expects ERC20 payment.

### revokeOffchainBatch

```solidity
function revokeOffchainBatch(string[] offchainAttestationIds, string[] reasons, bytes delegateSignature) external
```

Batch revokes off-chain attestations.

### getSchema

```solidity
function getSchema(uint64 schemaId) external view returns (struct Schema)
```

Returns the specified `Schema`.

### getAttestation

```solidity
function getAttestation(uint64 attestationId) external view returns (struct Attestation)
```

Returns the specified `Attestation`.

### getOffchainAttestation

```solidity
function getOffchainAttestation(string offchainAttestationId) external view returns (struct OffchainAttestation)
```

Returns the specified `OffchainAttestation`.

### getDelegatedRegisterHash

```solidity
function getDelegatedRegisterHash(struct Schema schema) external pure returns (bytes32)
```

Returns the hash that will be used to authorize a delegated registration.

### getDelegatedRegisterBatchHash

```solidity
function getDelegatedRegisterBatchHash(struct Schema[] schemas) external pure returns (bytes32)
```

Returns the hash that will be used to authorize a delegated batch registration.

### getDelegatedAttestHash

```solidity
function getDelegatedAttestHash(struct Attestation attestation) external pure returns (bytes32)
```

Returns the hash that will be used to authorize a delegated attestation.

### getDelegatedAttestBatchHash

```solidity
function getDelegatedAttestBatchHash(struct Attestation[] attestations) external pure returns (bytes32)
```

Returns the hash that will be used to authorize a delegated batch attestation.

### getDelegatedOffchainAttestHash

```solidity
function getDelegatedOffchainAttestHash(string offchainAttestationId) external pure returns (bytes32)
```

Returns the hash that will be used to authorize a delegated offchain attestation.

### getDelegatedOffchainAttestBatchHash

```solidity
function getDelegatedOffchainAttestBatchHash(string[] offchainAttestationIds) external pure returns (bytes32)
```

Returns the hash that will be used to authorize a delegated batch offchain attestation.

### getDelegatedRevokeHash

```solidity
function getDelegatedRevokeHash(uint64 attestationId, string reason) external pure returns (bytes32)
```

Returns the hash that will be used to authorize a delegated revocation.

### getDelegatedRevokeBatchHash

```solidity
function getDelegatedRevokeBatchHash(uint64[] attestationIds, string[] reasons) external pure returns (bytes32)
```

Returns the hash that will be used to authorize a delegated batch revocation.

### getDelegatedOffchainRevokeHash

```solidity
function getDelegatedOffchainRevokeHash(string offchainAttestationId, string reason) external pure returns (bytes32)
```

Returns the hash that will be used to authorize a delegated offchain revocation.

### getDelegatedOffchainRevokeBatchHash

```solidity
function getDelegatedOffchainRevokeBatchHash(string[] offchainAttestationIds, string[] reasons) external pure returns (bytes32)
```

Returns the hash that will be used to authorize a delegated batch offchain revocation.

### schemaCounter

```solidity
function schemaCounter() external view returns (uint64)
```

Returns the current schema counter. This is incremented for each `Schema` registered.

### attestationCounter

```solidity
function attestationCounter() external view returns (uint64)
```

Returns the current on-chain attestation counter. This is incremented for each `Attestation` made.


# ISPHook

The hook is called for every attestation or revocation if the schema used specifies a hook.

## didReceiveAttestation

```solidity
function didReceiveAttestation(address attester, uint64 schemaId, uint64 attestationId, bytes extraData) external payable
```

## didReceiveAttestation

```solidity
function didReceiveAttestation(address attester, uint64 schemaId, uint64 attestationId, contract IERC20 resolverFeeERC20Token, uint256 resolverFeeERC20Amount, bytes extraData) external
```

## didReceiveRevocation

```solidity
function didReceiveRevocation(address attester, uint64 schemaId, uint64 attestationId, bytes extraData) external payable
```

## didReceiveRevocation

```solidity
function didReceiveRevocation(address attester, uint64 schemaId, uint64 attestationId, contract IERC20 resolverFeeERC20Token, uint256 resolverFeeERC20Amount, bytes extraData) external
```


# IVersionable

This interface helps contracts to keep track of their versioning.

## version

```solidity
function version() external pure returns (string)
```


# Data Models


# Schema

## Schema

This struct represents an on-chain Schema that Attestations can conform to.

`registrant`: The address that registered this schema.

`revocable`: Whether Attestations that adopt this Schema can be revoked.

`dataLocation`: Where `Schema.data` is stored. See `DataLocation.DataLocation`.

`maxValidFor`: The maximum number of seconds that an Attestation can remain valid. 0 means Attestations can be valid forever. This is enforced through `Attestation.validUntil`.

`hook`: The `ISPHook` that is called at the end of every function. 0 means there is no hook set. See `ISPHook`.

`timestamp`: When the schema was registered. This is automatically populated by `_register(...)`.

`data`: The raw schema that `Attestation.data` should follow. Since there is no way to enforce this, it is a `string` for easy readability.

```solidity
struct Schema {
  address registrant;
  bool revocable;
  enum DataLocation dataLocation;
  uint64 maxValidFor;
  ISPHook hook;
  uint64 timestamp;
  string data;
}
```


# Attestation

## Attestation

This struct represents an on-chain attestation record. This record is not deleted after revocation.

`schemaId`: The `Schema` that this Attestation is based on. It must exist.

`linkedAttestationId`: Useful if the current Attestation references a previous Attestation. It can either be 0 or an existing attestation ID.

`attestTimestamp`: When the attestation was made. This is automatically populated by `_attest(...)`.

`revokeTimestamp`: When the attestation was revoked. This is automatically populated by `_revoke(...)`.

`attester`: The attester. At this time, the attester must be the caller of `attest()`.

`validUntil`: The expiration timestamp of the Attestation. Must respect `Schema.maxValidFor`. 0 indicates no expiration date.

`dataLocation`: Where `Attestation.data` is stored. See `DataLocation.DataLocation`.

`revoked`: If the Attestation has been revoked. It is possible to make a revoked Attestation.

`recipients`: The intended ABI-encoded recipients of this Attestation. This is of type `bytes` to support non-EVM repicients.

`data`: The raw data of the Attestation based on `Schema.schema`. There is no enforcement here, however. Recommended to use `abi.encode`.

```solidity
struct Attestation {
  uint64 schemaId;
  uint64 linkedAttestationId;
  uint64 attestTimestamp;
  uint64 revokeTimestamp;
  address attester;
  uint64 validUntil;
  DataLocation dataLocation;
  bool revoked;
  bytes[] recipients;
  bytes data;
}
```

## OffchainAttestation

This struct represents an off-chain attestation record. This record is not deleted after revocation.

`attester`: The attester. At this time, the attester must be the caller of `attestOffchain()`.

`timestamp`: The `block.timestamp` of the function call.

```solidity
struct OffchainAttestation {
  address attester;
  uint64 timestamp;
}
```


# DataLocation

## DataLocation

This enum indicates where `Schema.data` and `Attestation.data` are stored.

```solidity
enum DataLocation {
  ONCHAIN,
  ARWEAVE,
  IPFS,
  CUSTOM
}
```


# A Future Of Verifiable Trust

## Introduction

Traditional trust systems have relied on institutional integrity, which has proven fallible. Recent scandals have highlighted the need for a new approach. Sign Protocol aims to restore trust through verifiable methodologies.

## Verifiable Trust

Verifiable Trust replaces blind trust with a system that ensures:

* **Soundness and Verifiability**: Information is well-defined, confirmed, and verifiable.
* **Hardness and Immutability**: Information is tamper-proof and finalized. Cryptographic solutions and blockchain systems ensure this.
* **Reliability and High Availability**: Information is always accessible for validation. Redundant data storage and blockchain incentives support this.

EthSign uses Attestations to deliver Verifiable Trust, forming the basis of Sign Protocol.

## Strategy: Web First, Then Global

The web serves as a testing ground for trust systems. EthSign's Next platform enables digital contract signing with cryptographic signatures and blockchain storage. Sign Protocol extends verification to all web interactions.

## Attestation Ecosystem

An attestation ecosystem coordinates operators, infrastructure, and methodologies to verify authenticity and integrity. It consists of four layers:

* **Trust Layer**: Societal infrastructures and institutions.
* **Application Layer**: Apps and services using verified trust.
* **Infrastructure Layer**: Processes attestation data for applications.
* **Attestation Layer**: Manages attestations and their elements.

<figure><img src="/files/1R8zPH3qpfjDyfOpFQHb" alt="Attestation Ecosystem Diagram"><figcaption><p>Figure: Hierarchical structure of the attestation ecosystem layers.</p></figcaption></figure>

## Summary

Sign Protocol is a platform-independent attestation protocol with tools and infrastructure to create a robust attestation ecosystem. It leverages blockchains, decentralized storage, and social networks to enhance digital trust systems.


# Effective Attestations

Sign Protocol introduces Effective Attestations (e/att) to address the limitations of current attestation systems. This approach enhances attestation systems by focusing on verifiability, relevancy, insightfulness, and universality, advancing trust systems for both web and global applications.

## Technical Attributes

Effective Attestations provide a framework for a resilient attestation ecosystem. Key technical attributes include:

* **Verifiability**: Attestations must be provably correct, supported by schemas and verification tools that ensure data integrity and authenticity. Developers can automate verification processes using these tools.
* **Relevancy**: Components should deliver meaningful impact, offering tangible value to developers and stakeholders. This involves creating attestations applicable to real-world scenarios.
* **Insightfulness**: Attestations should provide comprehensive context, facilitated by detailed schemas and attestation builders that enhance data interpretation. This allows developers to extract actionable insights from attestation data.
* **Universality**: Attestations and their components must be adaptable and interoperable across diverse environments, ensuring seamless integration and global applicability. This requires designing attestations with cross-platform compatibility in mind.

Sign Protocol is committed to leading the development of Effective Attestations, fostering a developer community and ecosystem that embodies these principles, and constructing efficient trust systems for both web and global use cases.


# Incentive-Aligned Public Good

## Overview

To build a trustworthy web powered by attestations, strategies must be pragmatic and impactful. The attestation ecosystem should be open, impactful, and neutral, rewarding contributors while benefiting the public. Sign Protocol balances ongoing development with impactful outputs, termed Pragmatic Sustainability and Net Positive Impact. Inspired by protocols like Git and Ethereum, it emphasizes practicality for sustainability and growth.

## Net Positive Impact

Sign Protocol provides tools for a robust attestation ecosystem, aiming for widespread adoption by offering neutral and open benefits. Users globally should experience improvements in trust systems without needing special permissions. The progress of Sign Protocol is expected to enhance related ecosystems, such as Ethereum and DAO governance. Establishing an ideal attestation ecosystem is a long-term goal, engaging the public to achieve a net positive impact.

## Pragmatic Sustainability

Sign Protocol's development must be reliable and sustainable. Traditional grant funding is unreliable, so alternative strategies are necessary. EthSign explores revenue models that maintain neutrality and impact, such as subscriptions and product sales, similar to GitHub and Red Hat. This initiative, Pragmatic Sustainability, aims to diversify contributors and ensure long-term success.

## Conclusion

Achieving a trustworthy web with attestations requires pragmatic strategies for Sign Protocol as an Incentive-Aligned Public Good. Balancing Pragmatic Sustainability and Net Positive Impact, EthSign aims to democratize benefits globally, inspired by protocols like Git and Ethereum. Diverse funding avenues ensure Sign Protocol's long-term viability.


# Glossary


# Attestations

## Overview

<figure><img src="/files/vZ5Em4Z2QtV777LsuDk6" alt=""><figcaption><p>An EthSign attestation on Sign Protocol</p></figcaption></figure>

An attestation confirms and certifies the validity of a claim or assertion, such as a statement, event, or legal document. It supports verifiers in confidently accepting or rejecting claims. Sign Protocol implements attestations as digitally signed structured data adhering to a registered schema, stored securely on-chain or off-chain.

## Evolution of Attestations

Attestations have evolved significantly, especially with the advent of computers and the internet. Historically, they involved physical seals or signatures. Today, they are structured data with digital signatures, driving Sign Protocol's work.

## Components of an Attestation

<figure><img src="/files/lmOl215ejDWSnksgHJEf" alt="" width="400"><figcaption><p>How Sign Protocol attestations are structured in Solidity</p></figcaption></figure>

An attestation in Sign Protocol includes:

* **Schema**: Defines the format and organization of data.
* **Context**: Provides additional details for insight.
* **Digital Signature**: Certifies the authenticity of the attester’s identity using asymmetric cryptography.
* **Cryptographic Proofs**: Prove data integrity, often without revealing the data itself (e.g., zero-knowledge proofs).

## Storage of Attestations

<figure><img src="/files/aBizkxW9FK2Ma5ZwJFYZ" alt="" width="400"><figcaption><p>Data locations available on Sign Protocol</p></figcaption></figure>

Attestations are stored in repositories, with accessibility determined by the hosting platform. Sign Protocol supports:

1. **Blockchain Systems (Onchain)**: Offer censorship-resistance, tamper-resistance, and global access. Examples: Ethereum, Optimism, Solana.
2. **Data Storage and Information Exchange Systems (Offchain)**: Focus on data storage and sharing, with privacy measures. Examples: Google Drive, iCloud, Arweave, IPFS.

## Applications

<figure><img src="/files/jgVHlpyYnLevDDXvxBMs" alt=""><figcaption><p>ZetaChain used TokenTable and Sign Protocol to perform a KYC-gated airdrop</p></figcaption></figure>

Attestations are crucial for confirming and certifying claims, with applications in:

* **Credit Scoring Systems**: Assess creditworthiness based on payment attestations.
* **Reward Distribution Systems**: Distribute rewards based on performance attestations.
* **Reputation Systems**: Evaluate entities based on feedback attestations.
* **Judicial Systems**: Resolve disputes using attestations from witnesses.

Attestations reinforce trust systems, making them verifiable and trustworthy. Sign Protocol is designed to be a tool for navigating this landscape.

For more on the value of attestations, see our blog post: [Attestations: A New Era of Trust and Verification](https://medium.com/ethsign/attestations-a-new-era-of-trust-and-verification-b7907e2801ab).


# Schema

## Overview

<figure><img src="/files/k44OU2kGtrNq9Us6n45u" alt=""><figcaption><p>An EthSign schema on Sign Protocol</p></figcaption></figure>

A schema defines the type and structure of data used in attestations, creating standards for accuracy and composability. It ensures attestations are insightful and verifiable. A Schema Registry stores and references schemas, coordinating standards and processes for efficient schema use.

## Purpose

Schemas establish rules for data organization in attestations, ensuring they are insightful and valid. They define structure and selection criteria for data points, providing context and provability. Schemas shape attestation standards, enhancing trust system efficiency.

## Design

<figure><img src="/files/DZGyI2J8SfoGlicRWsT6" alt="" width="400"><figcaption><p>How Sign Protocol schemas are structured in Solidity</p></figcaption></figure>

Sign Protocol schemas consist of two core modules:

1. **Header**: Contains metadata for initial attestation analysis, including:
   * **Attestation ID**: Unique identifier for cross-referencing.
   * **Claim Reference**: Points to a related claim or assertion.
   * **Attester ID**: Identifies the attestation creator.
   * **Signature**: Cryptographic certification of the attestation.
   * **Schema Registry ID**: References the schema used.
2. **Body**: Contains detailed attestation data, including:
   * **Timestamp**: When the event was observed.
   * **Subject ID**: Identifies the attestation subject.
   * **Boolean**: Indicates claim truthfulness.
   * **Cryptographic Proof**: Ensures data integrity.
   * **Evidence Data**: Supports or refutes the claim.

## Building a Schema

Schemas are typically JSON structures, organized as key-value pairs. They can be created using text editors or implemented as blockchain-based scripts. Sign Protocol's Schema Builder streamlines schema creation, offering intuitive flows and reducing complexity.

Schemas are vital for defining attestation nature, ensuring clarity and standardization. A well-crafted schema forms the basis for a robust attestation ecosystem.

For more on schemas, see our blog post: [Schemas: The Blueprint of Attestations](https://medium.com/ethsign/schemas-the-blueprint-of-attestations-c6b0e6faf430).


# Schema Registry

## Overview

A schema registry is a centralized repository for storing, managing, validating, and referencing schemas. It serves as an authoritative system that enforces standards for schema creation, ensuring compliance and efficiency within an attestation ecosystem.

## Role of a Schema Registry

Schema creators need a platform to store and publicize their schemas, while attesters require a reference point for schemas to make robust attestations. A schema registry acts as this central hub, offering an environment for schema validation against predefined rules and standards.

When creating an attestation, an attester can design a new schema or search for an existing one. The schema registry provides a comprehensive selection of schemas, contributed by both registry proprietors and third-party creators.

Sign Protocol offers a dedicated schema registry for public schema recording and referencing, facilitating the attestation process.

## Locating a Schema Registry

To reference or submit a schema, you must know the registry's location, which determines interaction permissions. Popular platforms for hosting a schema registry include:

1. **Blockchain Systems (Onchain)**: Provide censorship-resistance, tamper-resistance, and global access. Examples: Ethereum, Optimism, Solana.
2. **Data Storage and Information Exchange Systems (Offchain)**: Focus on data storage and sharing, with robust security measures. Examples: Google Drive, iCloud, Arweave, IPFS.

## Benefits of a Schema Registry

A schema registry offers several advantages:

* **Version Control**: Tracks changes and improvements, mitigating incompatibilities and conflicts.
* **Schema Evolution**: Allows schemas to improve over time, maintaining version control and provenance.
* **Validation**: Ensures schemas meet ecosystem standards, preventing errors and inefficiencies.
* **Governance**: Coordinates standards and guidelines, fostering growth and innovation.
* **Conformity**: Enforces quality control through strict rules for schema crafting.

A schema registry is essential for maintaining a high-quality attestation ecosystem, driving standardization and innovation.


# Attestation Repository

## Overview

An attestation repository is a dedicated location for storing, referencing, and analyzing attestations issued by an attester. It is equipped with robust tools and infrastructure to enhance accessibility and user experience for both end-users and developers.

## Sorting Attestations

When an attester issues a new attestation, it can be submitted to either 'the wild' or an attestation repository. This system provides a consolidated location for issuing and referencing attestations, ensuring comprehensive monitoring and indexing for reliable access.

Sign Protocol offers dedicated attestation repositories for attesters, verifiers, and other participants, facilitating convenient submission and referencing of attestations.

## Infrastructure

Attestation Repositories are equipped with infrastructure and tools to streamline submission, referencing, and analysis of attestations:

* **Attestation Explorer**: Enhances discoverability and viewing of attestations with features like search engines and tracking. Example: SignScan for Sign Protocol.
* **Attestation Indexer**: Extracts and transforms attestation data into a readable form, building a database for easy querying and analysis.
* **Attestation Client**: Provides a user-friendly interface for interacting with the repository, including issuing attestations and generating proofs.
* **Attestation API Framework**: Offers endpoints and documentation for developers to interact with the repository, enabling innovation on top of the attestation repository.

<figure><img src="/files/nvW3oC730utSABMovY2q" alt=""><figcaption><p>Attestation Repository Cluster</p></figcaption></figure>

## Deploying and Hosting

To become operational, an attestation repository must be hosted on a suitable platform. Current options include:

1. **Blockchain Systems (Onchain Platforms)**: Offer censorship-resistance, tamper-resistance, global access, and more. Examples: Ethereum, Starknet, Zetachain, Polygon.
2. **Data Storage Platforms (Offchain Platforms)**: Designed for efficient data storage with features like data protection and public accessibility. Examples: AWS, iCloud, ArDrive.
3. **Information Exchange Platforms (Offchain Platforms)**: Facilitate data distribution and exchange with features like lightweight design and bandwidth optimization. Examples: Git, Torrents, Farcaster.

Sign Protocol supports both onchain and offchain platforms for deploying and hosting attestation repositories.

## Attest Anywhere

Sign Protocol offers a range of platform options for issuing attestations, utilizing Arweave for offchain needs and supporting various blockchains for onchain needs.


# EthSign

Enhancing EthSign with witnessed agreements

EthSign has successfully created a platform that makes access to legal contracts and agreement signing processes more user-friendly, while ensuring the same level of cryptographic security as your everyday onchain dapp. The contracts established via EthSign remain siloed, limited to the contexts and parties directly involved. This creates a missed opportunity for agreements made via EthSign contracts to be composable and reusable across various dapps and experiences.

### Proof of Agreement

To address the lack of composability and extensibility of agreements made using EthSign, we will introduce Proof of Agreement.

Proof of Agreement is an attestation made using Sign Protocol that confirms the existence of an agreement between parties. This enables a third-party to verify the agreement's existence for business purposes, allowing EthSign and other third-parties to serve as witnesses that can attest to the signing of certain legal contracts.

### Witnessed Agreements

Witnessed Agreements allow EthSign users to choose whether they want EthSign or a third-party entity to witness the signing of their agreements, resulting in an Attestation that serves as proof of agreement.

This proof of agreement will allow EthSign’s users to indicate their ongoing contractual arrangements with other parties onchain without revealing any sensitive details.

As part of this initial integration, EthSign will utilize Sign Protocol's expert tooling and support necessary for seamlessly integrating EthSign's contract signing platform with Sign Protocol. This will encompass (but not be limited to):

* API frameworks: The entire lexicon needed to establish connections and interact with Sign Protocol’s backends and infrastructure.
* A dedicated schema: A schema that has been purpose-built to facilitate the issuance of attestations for agreements made with EthSign’s contract signing platform
* Sign Protocol Toolstack and Infra: This will involve a suite of essential tools and libraries needed to make the operations and overall integration as seamless as possible. Some of these may include: Custom Indexers, Smart Contracts, and more.

### Schemas

EthSign uses two schemas that cover the [signing](https://scan.sign.global/schema/SPS_blSzPTC9SIL9HS52PZXST) and [completion](https://scan.sign.global/schema/SPS_vpnl9gIq-mqOXlBYQMsqf) of agreements:

```json
[
  { "name": "chainType", "type": "string" },
  { "name": "signerAddress", "type": "string" },
  { "name": "cid", "type": "string" },
  { "name": "contractId", "type": "string" },
  { "name": "timestamp", "type": "string" }
]
```

```json
[
  { "name": "contractId", "type": "string" },
  { "name": "cid", "type": "string" },
  { "name": "signersAddress", "type": "string[]" },
  { "name": "senderAddress", "type": "string" },
  { "name": "timestamp", "type": "string" }
]
```

### Conclusion

EthSign presents a robust digital document signing application seamlessly integrated with any private key. With features like the Contract Template Library and Contract Verification, EthSign simplifies access to legal contracts while maintaining cryptographic security. However, the siloed nature of contracts limits their composability and reuse across different platforms. To address this challenge, we propose the Proof of Agreement concept, leveraging the Sign Protocol to attest to the existence of agreements.

By integrating Sign Protocol into EthSign through Witnessed Agreements, we anticipate enhanced composability, increased user sign-ups, and a network of attesters facilitating agreement signing sessions. This integration not only benefits EthSign users but also extends the reach of signed legal agreements into decentralized finance (DeFi) and beyond, fostering a more interconnected and efficient business landscape onchain.


# KYC-Gated Contract Calls

KYC-gated smart contract interactions with Sumsub

[ZetaChain](https://www.zetachain.com/), a new L1 blockchain with built-in interoperability, required KYC (Know Your Customer) and AML (Anti-Money Laundering) checks on contributors receiving an airdrop greater than 200 ZETA; additionally, they prevented airdrop claiming from OFAC sanctioned geographies.

ZetaChain used EthSign’s [TokenTable](https://www.tokentable.xyz/) to conduct their KYC-gated airdrop on January 31st, 2024 to facilitate a compliant, streamlined airdrop for both ZETA recipients and the ZetaChain team.

In order to restrict non-KYC’ed addresses from claiming ZETA via TokenTable, the off-chain KYC verification status of recipient addresses must be communicated to [TokenTable Unlocker](https://docs.tokentable.xyz/developers/v2.5) smart contract.

[Sign Protocol](https://docs.sign.global/) was implemented in parallel with SumSub to a) bind the airdrop recipient's wallet address to an their KYC verification status, and b) to port recipient addresses’ KYC verification status on-chain so that TokenTable’s Unlocker smart contract can validate it.

### Airdrop Claiming Flow

1. Whitelisted wallets from non-sanctioned geographies are able to connect to [claims.zetachain.com](https://claims.zetachain.com/).
2. Claimers can view how much ZETA they have available to claim, and any lockup terms.
3. Conduct KYC verification via Sumsub by submitting their government ID.
4. To bind their address and KYC verification, claimers must use SIGN Protocol to sign an attestation message that is a hash of their address and KYC status using the following Schema.

```json
{
  "name": "zeta kyc schema",
  "data": [
    {
      "type": "string",
      "name": "applicant"
    },
    {
      "type": "string",
      "name": "applicantId"
    }
  ]
}
```

### Impact

A total of **17,789,923 ZETA** airdropped to KYC’ed claimers valued at **$29,709,171.41** ($1.67/ZETA on 2/1/2024).

“Working with the product and team has been a pleasure. The combination of SIGN Protocol and TokenTable enabled an airdrop experience that was safe, transparent, and seamless for users, with the flexibility and attention to detail that was needed for such a critical moment for ZetaChain. As well, the team has been incredible in helping make sure users are heard and helping resolve any issues that came up at any step of the process.”

— [Brandon Truong](https://www.linkedin.com/in/truong-brandon/), lead product contributor for ZetaChain.

As of Febuary 5th, 2024:

* 14786 — Total KYC whitelisted addresses
* 13736 — Total KYC applicants
* 12858 — Passed KYC
* 295 — Rejected due to block list/fraud
* KYC pass rate - 98.21%
* Median verification time - 14 sec


# Proof of Audit

Cryptographically verify the integrity of OtterSec security audit reports

Conducting a smart contract audit is the preliminary step in bringing any DApp to the masses. However, to garner market trust, malicious project founders may make fake claims of a security audit. The traditional model of verification is using OtterSec’s website as the single source of truth, where the original audit PDF can be referenced. Naturally, there may be concerns of forgery of said documentation that could lead to malicious project founders sharing misinformation.

OtterSec creates detailed reports mentioning the vulnerabilities discovered for smart contracts that have been audited. With Sign Protocol, OtterSec will now create attestations to disclose that OtterSec has officially completed the audit of any given contract, the findings based in the report, and which team member conducted the audit.

### The Schema

```jsx
{
	"name": string,
	"domain": string,
	"repo": string,
	"findings": {
		"critical": uint8,
		"high": uint8,
		"medium": uint8,
		"low": uint8,
	},
	"auditor": string,
	"timestamp": uint64
}
```

You can also find it [here](https://scan.sign.global/schema/SPS_-xlWUxUmK805Gps_sImtp).

Once a smart contract audit has been completed by OtterSec, the audit summary will be recorded as an attestation directly on [SignScan](https://scan.sign.global/), serving as the single source of truth.


# Developer Onchain Reputation

Building your onchain reputation as a builder with Aspecta on Sign Protocol

The collaboration between Aspecta and Sign Protocol aims to leverage Sign Protocol's infrastructure to enhance on-chain attestations to help Builders to establish their on-chain reputation and developers' activities within the blockchain ecosystem. It seeks to introduce a comprehensive schema covering Builder Skills, Achievements, and Community Votes.

With Aspecta's intelligent identity solution, builders are able to demonstrate skills, impacts, and experiences with verifiable proof after linking GitHub, Stack Overflow, on-chain addresses, projects, blogs, and other web2 & web3 data.

Through Sign Protocol, developers can obtain verifiable attestations through Aspecta’s code analysis algorithm, validating their skills and contributions on-chain using the following [schema](https://scan.sign.global/schema/SPS_J_60ocIUOm6CwhFzn_qRs):

```json
[
  { "name": "name", "type": "string" },
  { "name": "aspecta_url", "type": "string" }
]
```

These attestations serve as credible endorsements, enhancing developers' visibility and credibility within the blockchain ecosystem, thereby fostering trust and transparency.

Aspecta will develop the Aspecta Developer Reputation System, leveraging Sign Protocol's attestation framework. Developers can build profiles showcasing their expertise, projects, and endorsements from trusted entities. Sign Protocol will augment these profiles with verifiable attestations, enhancing developers' credibility and opening doors to new opportunities within the blockchain community.


# Onboarding Web2 Data

Onboard Your Web2 Data with MPC-TLS on Sign Protocol

### What is the MPC-TLS + zkProof system?

Before we explain what **M**ulti-**P**arty **C**omputation **T**ransport **L**ayer **S**ecurity is and how zero-knowledge proofs play a vital part in this setup, let’s talk about vanilla TLS. It is the mechanism behind all HTTP**S** websites and serves to encrypt network traffic so nobody aside from you or the server can decrypt everything being sent and received. MPC-TLS adds a third party verifier into the TLS handshake who can only verify the authenticity of data transmitted without having any knowledge of the data. Throughout the entire process, the server is entirely unaware of the MPC mechanism and does not need to accommodate this setup. After the conclusion of data retrieval and integrity verification, the user and verifier jointly produce a zero-knowledge proof used to convince the verifier of some fact about the encrypted data (remember, the verifier cannot actually see the data in plain text).

### What does this mean for users?

The single most significant implication is the ability for any ordinary user to self-attest to the validity of any information loaded in their browser. In other words, as long as the user can see something in their browser, they can prove its validity. For example, users can self-attest their bank statement as a cryptographically secure proof-of-funds anytime anywhere with one click.

### What Sign Protocol brings

Leveraging a standardized and structured attestation format as well as an affordable permanent storage solution, Sign Protocol makes it possible for our partners and users to:

* Easily onboard MPC-TLS zero-knowledge proof validation results to any chain and bridge results to any other chain after the initial attestation.
* Encrypt and permanently store the captured TLS session and zero-knowledge proof for archival purposes and future retrieval.
* Enable any smart contract to access, correctly decode, and make use of your validation results.

Here is a sample schema from one of our partners:

```json
{
  "name": "prototype",
  "data": [
    {
      "name": "ProofType",
      "type": "string"
    },
    {
      "name": "Source",
      "type": "string"
    },
    {
      "name": "Content",
      "type": "string"
    },
    {
      "name": "Condition",
      "type": "string"
    },
    {
      "name": "SourceUserIdHash",
      "type": "bytes32"
    },
    {
      "name": "Result",
      "type": "bool"
    },
    {
      "name": "Timestamp",
      "type": "uint64"
    },
    {
      "name": "UserIdHash",
      "type": "bytes32"
    }
  ]
}
```

### Where can I experience this?

We are launching this initiative with PADO and zkPass.

#### PADO

PADO, powered by PADO Labs, is a decentralized zkAttestation and Computation Network designed to unlock and secure internet data for Web3. It enables users to attest their off-chain data from various internet sources in a secure and privacy-preserving manner. Users can generate attestations, or data proofs, from their private data and share them with third parties, such as dApps on blockchains, without revealing sensitive information. For instance, users can prove their gaming achievements or professional qualifications without exposing their account details. PADO Labs is developing essential components like the PADO extension for user data management, PADO developer toolkits for dApp creation, and node SDKs to maintain the network's integrity, including cryptographic nodes for data authentication and evaluation.

#### zkPass

zkPass is a private data protocol that enables privacy-preserving verification. It is built on the foundation of Multi-Party Computation (MPC), Zero-Knowledge Proofs (ZKP), and three-party Transport Layer Security (3P-TLS). zkPass provides TransGate, which enables users to selectively and privately validate their data on any HTTPS website to the web3 world. It can cover various data types such as legal identity, financial records, healthcare information, social interactions, work experience, education and skill certifications, etc. All these types of verifications can be done securely and privately without the need to disclose or upload any sensitive personal data to third parties.o


