This Coinbase Verifications quickstart shows you how to get the metadata associated with a user’s attestation. Our implementation creates a read-only smart contract, to the ensure the integrity of the onchain data.
With a user wallet address and schema ID (a verification type ID), the Coinbase Indexer returns a UID. Then, with the UID, developers can call the EAS SDK to return the metadata associated with the attestation. If there is no attestation created, the Coinbase Indexer returns null.
How to get a Base Mainnet Endpoint:
We use Base mainnet because it is a read-only contract that does not require any gas.
In your terminal:
attestation-tutorial
eas-sdk
and ethers
.mkdir attestation-tutorial & cd attestation-tutorial
npm install @ethereum-attestation-service/eas-sdk
npm install ethers
Create a file called indexer.js
and add the following variables to import:
const { EAS } = require("@ethereum-attestation-service/eas-sdk");
const { ethers } = require('ethers');
attestation-tutorial
directory.const ABI = require('./attestation_ABI.js');
Connect to the Base RPC endpoint and create a contract instance:
ethers.JsonRpcProvider
function.0x2c7eE1E5f416dfF40054c27A62f7B357C4E8619C
.contract address
, ABI
, and provider
variables.Coinbase Indexer contract address: 0x2c7eE1E5f416dfF40054c27A62f7B357C4E8619C
//Set this to the Node RPC URL from Step 1.
const provider = new ethers.JsonRpcProvider("YOUR RPC URL");
const contractAddress = "0x2c7eE1E5f416dfF40054c27A62f7B357C4E8619C";
const indexerContract = new ethers.Contract(contractAddress, ABI, provider);
walletAddress
and schemaID
to return the attestationUID
.If the attestation does not exist, it returns null
.
Fetching Attestation UID
async function getAttestationUID(walletAddress,schemaID) {
try {
const attestationUID = await indexerContract.getAttestationUid(walletAddress, schemaID);
return attestationUID;
} catch (error) {
console.error("Error fetching Attestation UID:", error);
}
}
Setup a function that inputs a uid
to return attestation
:
EAS
.Fetching Metadata
async function getAttestationData(uid){
try{
const EASContractAddress = "0x4200000000000000000000000000000000000021"
const eas = new EAS(EASContractAddress);
eas.connect(provider);
const attestation = await eas.getAttestation(uid);
return attestation
} catch(error){
console.error("Error fetching Metadata: ", error)
}
}
getAttestationUID
and getAttestationData
functions and input a valid Wallet Address and Schema ID.Wallet Address: `0x115aBfDa6b101bDC813B90c2780952E89E185F54`
Schema ID: `0xf8b05c79f090979bf4a80270aba232dff11a10d9ca55c4f88de95317970f0de9
Check out recently claimed wallet addresses, schema IDs, and attestation UIDs we have here:
async function main() {
// Add any Wallet Address or SchemaID you would like to try.
const walletAddress = "0x115aBfDa6b101bDC813B90c2780952E89E185F54";
const schemaID = "0xf8b05c79f090979bf4a80270aba232dff11a10d9ca55c4f88de95317970f0de9";
try {
const uid = await getAttestationUID(walletAddress, schemaID);
console.log('UID:', uid);
const metadata = await getAttestationData(uid);
console.log('Metadata:', metadata);
} catch (error) {
console.error('Error:', error);
}
}
main();
You should return the output below. The comments above each line item represent the corresponding variable.
UID: 0x9c2108e7683176078b834068c0a8e6539213a56c3c4ae029d999f69840149911
Metadata: Result(10) [
//uid '0x9c2108e7683176078b834068c0a8e6539213a56c3c4ae029d999f69840149911',
// schemaID
'0xf8b05c79f090979bf4a80270aba232dff11a10d9ca55c4f88de95317970f0de9',
//time
1721434067n,
//expirationTime
0n,
//revocationTime
0n,
//refUID
'0x0000000000000000000000000000000000000000000000000000000000000000',
//recipient
'0x115aBfDa6b101bDC813B90c2780952E89E185F54',
//attester
'0x357458739F90461b99789350868CD7CF330Dd7EE',
//revocable[?]
true,
//data
'0x0000000000000000000000000000000000000000000000000000000000000001'
]
You can copy the ABI file here, or download coinbase-verifications-abi-code-snippet.json.tar.gz
tar -xvf coinbase-verifications-abi-code-snippet.json.tar.gz
Expand for the ABI File
const ABI = [
{
"inputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "attestationUid",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "expirationTime",
"type": "uint256"
}
],
"name": "AttestationExpired",
"type": "error"
},
{
"inputs": [
{
"internalType": "string",
"name": "reason",
"type": "string"
}
],
"name": "AttestationInvariantViolation",
"type": "error"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "attestationUid",
"type": "bytes32"
}
],
"name": "AttestationMissingRecipient",
"type": "error"
},
{
"inputs": [],
"name": "AttestationNotFound",
"type": "error"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "attestationUid",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "revocationTime",
"type": "uint256"
}
],
"name": "AttestationRevoked",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "previousAdmin",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "newAdmin",
"type": "address"
}
],
"name": "AdminChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "indexer",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "schema",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "attestationUid",
"type": "bytes32"
}
],
"name": "AttestationIndexed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "beacon",
"type": "address"
}
],
"name": "BeaconUpgraded",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint8",
"name": "version",
"type": "uint8"
}
],
"name": "Initialized",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "Paused",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "previousAdminRole",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "newAdminRole",
"type": "bytes32"
}
],
"name": "RoleAdminChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "RoleGranted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "RoleRevoked",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "Unpaused",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "implementation",
"type": "address"
}
],
"name": "Upgraded",
"type": "event"
},
{
"inputs": [],
"name": "DEFAULT_ADMIN_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "INDEXER_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "PAUSER_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "UPGRADER_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "bytes32",
"name": "schemaUid",
"type": "bytes32"
}
],
"name": "getAttestationUid",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
}
],
"name": "getRoleAdmin",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "grantRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "hasRole",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "attestationUid",
"type": "bytes32"
}
],
"name": "index",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "defaultAdmin",
"type": "address"
}
],
"name": "initialize",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "pause",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "paused",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "proxiableUUID",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "renounceRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "revokeRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "interfaceId",
"type": "bytes4"
}
],
"name": "supportsInterface",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "unpause",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newImplementation",
"type": "address"
}
],
"name": "upgradeTo",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newImplementation",
"type": "address"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "upgradeToAndCall",
"outputs": [],
"stateMutability": "payable",
"type": "function"
}
];
module.exports = ABI;
const ABI = [
{
"inputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "attestationUid",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "expirationTime",
"type": "uint256"
}
],
"name": "AttestationExpired",
"type": "error"
},
{
"inputs": [
{
"internalType": "string",
"name": "reason",
"type": "string"
}
],
"name": "AttestationInvariantViolation",
"type": "error"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "attestationUid",
"type": "bytes32"
}
],
"name": "AttestationMissingRecipient",
"type": "error"
},
{
"inputs": [],
"name": "AttestationNotFound",
"type": "error"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "attestationUid",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "revocationTime",
"type": "uint256"
}
],
"name": "AttestationRevoked",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "previousAdmin",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "newAdmin",
"type": "address"
}
],
"name": "AdminChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "indexer",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "schema",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "attestationUid",
"type": "bytes32"
}
],
"name": "AttestationIndexed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "beacon",
"type": "address"
}
],
"name": "BeaconUpgraded",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint8",
"name": "version",
"type": "uint8"
}
],
"name": "Initialized",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "Paused",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "previousAdminRole",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "bytes32",
"name": "newAdminRole",
"type": "bytes32"
}
],
"name": "RoleAdminChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "RoleGranted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "sender",
"type": "address"
}
],
"name": "RoleRevoked",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "Unpaused",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "implementation",
"type": "address"
}
],
"name": "Upgraded",
"type": "event"
},
{
"inputs": [],
"name": "DEFAULT_ADMIN_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "INDEXER_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "PAUSER_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "UPGRADER_ROLE",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "bytes32",
"name": "schemaUid",
"type": "bytes32"
}
],
"name": "getAttestationUid",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
}
],
"name": "getRoleAdmin",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "grantRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "hasRole",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "attestationUid",
"type": "bytes32"
}
],
"name": "index",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "defaultAdmin",
"type": "address"
}
],
"name": "initialize",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "pause",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "paused",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "proxiableUUID",
"outputs": [
{
"internalType": "bytes32",
"name": "",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "renounceRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "role",
"type": "bytes32"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "revokeRole",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "interfaceId",
"type": "bytes4"
}
],
"name": "supportsInterface",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "unpause",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newImplementation",
"type": "address"
}
],
"name": "upgradeTo",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newImplementation",
"type": "address"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "upgradeToAndCall",
"outputs": [],
"stateMutability": "payable",
"type": "function"
}
];
module.exports = ABI;
Was this page helpful?