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.
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.
// SPDX-License-Identifier: MITpragmasolidity ^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.contractWhitelistManangerisOwnable {mapping(address attester =>bool allowed) public whitelist;errorUnauthorizedAttester();constructor() Ownable(_msgSender()) { }functionsetWhitelist(address attester,bool allowed) externalonlyOwner { whitelist[attester] = allowed; }function_checkAttesterWhitelistStatus(address attester) internalview {// solhint-disable-next-line custom-errorsrequire(whitelist[attester],UnauthorizedAttester()); }}// @dev This contract implements the actual schema hook.contractWhitelistHookisISPHook, WhitelistMananger {functiondidReceiveAttestation(address attester,uint64,// schemaIduint64,// attestationIdbytescalldata// extraData )externalpayable {_checkAttesterWhitelistStatus(attester); }functiondidReceiveAttestation(address attester,uint64,// schemaIduint64,// attestationIdIERC20,// resolverFeeERC20Tokenuint256,// resolverFeeERC20Amountbytescalldata// extraData )externalview {_checkAttesterWhitelistStatus(attester); }functiondidReceiveRevocation(address attester,uint64,// schemaIduint64,// attestationIdbytescalldata// extraData )externalpayable {_checkAttesterWhitelistStatus(attester); }functiondidReceiveRevocation(address attester,uint64,// schemaIduint64,// attestationIdIERC20,// resolverFeeERC20Tokenuint256,// resolverFeeERC20Amountbytescalldata// extraData )externalview {_checkAttesterWhitelistStatus(attester); }}