GET STARTED
- Home
- Quickstart
- Use AI Tooling
- Supported Networks
- Authentication
- CDP Portal
- Demo Apps
WALLETS
- Comparing Our Wallets
- Wallet APIv2
- Wallet APIv1
- Smart Wallet
PAYMENTS
- Send & Receive
- Onramp & Offramp
- x402
SWAPS
- SwapsBeta
BASE TOOLS
- Paymaster
- Appchains
- Onchainkit
DATA
- Introduction
- Node
- Address History
- WebhooksAlpha
- Smart Contract Events
- ReputationBeta
- Verifications
AI
- AgentKit
STAKING
- Staking API
- Staking Delegation Guides
FAUCET
- Using Faucets
CONSUMER APIS
- Coinbase App
- Coinbase Wallet
- Coinbase Commerce
- Coinbase Mesh
INSTITUTIONAL APIS
- Overview
- Coinbase Exchange
- Coinbase International Exchange
- Coinbase Prime
- Coinbase Derivatives
Verifications Quickstart
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.
Prerequisites
- Node >= 14.0.0
- npm >= 6.0.0
- CDP account
- Base mainnet endpoint
How to get a Base Mainnet Endpoint:
- Log into CDP > Node.
- Set the dropdown for RPC Endpoint to Base Mainnet.
- Copy and save your endpoint to use later.
We use Base mainnet because it is a read-only contract that does not require any gas.
Get Attestation Data
Initialize your project
In your terminal:
- Create a directory called
attestation-tutorial
- Initialize a project using npm.
- Download dependencies:
eas-sdk
andethers
.
mkdir attestation-tutorial & cd attestation-tutorial
npm install @ethereum-attestation-service/eas-sdk
npm install ethers
Set up imported variables
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');
Load and import ABI
- Import the ABI file for the Coinbase Indexer contract.
- Move the file to the
attestation-tutorial
directory. - Import the ABI as a variable.
const ABI = require('./attestation_ABI.js');
Create contract instance
Connect to the Base RPC endpoint and create a contract instance:
- Copy your endpoint and paste it as the input for the
ethers.JsonRpcProvider
function. - Input the Coinbase Indexer contract address:
0x2c7eE1E5f416dfF40054c27A62f7B357C4E8619C
. - Create the contract instance with
contract address
,ABI
, andprovider
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);
Get attestation UID
- Setup a function that inputs a
walletAddress
andschemaID
to return theattestationUID
.
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);
}
}
Get attestation data
Setup a function that inputs a uid
to return attestation
:
- Input the contract address into
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)
}
}
Call Functions
- Create your main function.
- Call the
getAttestationUID
andgetAttestationData
functions and input a valid Wallet Address and Schema ID. - Try with the following:
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();
Output
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'
]
ABI File
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
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?