Solidity¶
Your smart contract can create an attestation on behalf of a wallet interacting with it, but only if the wallet approves (signs) that attestation. The frontend must request the signature and forward it to your smart contract, which then creates the delegate attestation. Depending on your use case, you can generate the attestation object on the frontend or in the smart contract through a getter. This tutorial generates it on the frontend; see the examples here for creating an attestation object in Solidity.
Start with an empty Solidity contract that imports ISP and Attestation from @ethsign/sign-protocol-evm.
// 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()) { }
}
Store the Sign Protocol contract address in a state variable with a helper function to set it. Set it to the address for the network you deploy on, listed here. Your contract should now look like this:
// 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 that handles delegate attestation creation. It takes the attestation object, indexing value, delegation signature, and extra data to mirror the Sign Protocol attest function; you can change these parameters to hardcode the indexing value or extra data. The attestation object and delegation signature are required for delegated creation.
// ...
function createAttestation(Attestation calldata att, string calldata indexingKey, bytes calldata delegationSignature, bytes calldata extraData) external returns (uint64) {
uint64 attestationId = spInstance.attest(att, indexingKey, delegationSignature, extraData);
return attestationId;
}
// ...
(Frontend) Generating a delegation signature¶
Implement this section on your frontend. A delegation signature lets a third party upload an attestation on behalf of an attester. The attester must approve (sign) the attestation first, which prevents fraudulent attestations made with their wallet address. Once the user (attester) signs, send the attestation and signature to the smart contract above. Your frontend code should include the following:
import {
EvmChains,
delegateSignAttestation
} from "@ethsign/sp-sdk";
const schemaId = "0x...";
const attestationData = {
// The fields your schema defines
};
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 smart contract:
- Generate the attestation content. You can do this on the frontend (as shown above) or in your smart contract, from which the frontend requests it for step 2.
- Request a delegation signature from the user in a browser.
- Pass the attestation and delegation signature to your smart contract.
- Create the attestation in your smart contract, providing the attestation and delegation signature.