# Fundamentals

<figure><img src="https://3152654701-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fw182g9YzR34mTxEBTKXX%2Fuploads%2Fgit-blob-6fb6f1302f120413acf3c351c3fff79517f38baa%2Fschema-attestation-erd.svg?alt=media" 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](https://docs.sign.global/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.
