Real-World Examples
Common Workflows
Practical examples for building on Influence Protocol: dashboards, analytics, and integrations.
Note: All examples assume Base Mainnet. The SDK defaults to Base Sepolia, so Base Mainnet examples include custom contract config. For Base Sepolia, you can omit the config parameter.
Workflow 1: Participant Dashboard
Build a dashboard showing a participant's influence graph and attestations:
import { createRelationalClient } from '@influence-protocol/sdk';
import { JsonRpcProvider } from 'ethers';
async function buildParticipantDashboard(participantAddress: string) {
const provider = new JsonRpcProvider('https://mainnet.base.org');
// For Base Mainnet, pass custom contract addresses
const client = createRelationalClient(provider, {
visualizationAssembler: '0x...', // Base Mainnet address
relationalResolver: '0xdaabbfc98a09f542f5f3f13694284ca96dd32934',
illuminationAnalyzer: '0x4b2f2a03ed6744df981198fc3c231953179db699',
});
// Get participant graph
const graph = await client.getParticipantGraph(participantAddress);
// Get attestation summaries
const summaries = await client.getParticipantSummaries(participantAddress, {
offset: 0,
limit: 50,
});
// Get influence metrics
const metrics = await client.getInfluencerMetrics(participantAddress);
// Get all creator tokens
const creatorTokens = await client.getParticipantCreatorTokens(participantAddress);
return {
graph: {
nodes: graph.nodes,
edges: graph.edges,
},
attestations: summaries.items,
totalAttestations: summaries.total,
metrics: {
creatorPillar: metrics.breakdown.creatorPillar,
portfolioPillar: metrics.breakdown.portfolioPillar,
networkPillar: metrics.breakdown.networkPillar,
consistencyPillar: metrics.breakdown.consistencyPillar,
totalScore: metrics.totalScore,
},
creatorTokens,
};
}Workflow 2: Creator Analytics
Analyze a creator's network and participant engagement:
async function analyzeCreator(creatorTokenAddress: string) {
const provider = new JsonRpcProvider('https://mainnet.base.org');
const client = createRelationalClient(provider, {
visualizationAssembler: '0x...', // Base Mainnet address
relationalResolver: '0xdaabbfc98a09f542f5f3f13694284ca96dd32934',
illuminationAnalyzer: '0x4b2f2a03ed6744df981198fc3c231953179db699',
});
// Get creator topology
const topology = await client.getCreatorTopology(creatorTokenAddress);
// Get attestation summaries
const summaries = await client.getCreatorTokenSummaries(creatorTokenAddress, {
offset: 0,
limit: 100,
});
// Get all participants
const participants = await client.getCreatorTokenParticipants(creatorTokenAddress);
// Calculate engagement metrics
const uniqueParticipants = new Set(participants).size;
const totalAttestations = summaries.total;
const avgAttestationsPerParticipant = totalAttestations / uniqueParticipants;
return {
creatorNode: topology.node,
participants: {
total: uniqueParticipants,
addresses: participants,
},
attestations: {
total: totalAttestations,
recent: summaries.items.slice(0, 10),
avgPerParticipant: avgAttestationsPerParticipant,
},
};
}Workflow 3: Subgraph Dashboard
Build a fast dashboard using subgraph queries:
async function buildSubgraphDashboard() {
const endpoint = 'https://api.thegraph.com/subgraphs/name/aaronvick/radiant';
const query = `
{
# Get active creators
activeCreators: creatorTokens(
where: { active: true }
first: 100
) {
id
symbol
name
attestationCount
holderCount
}
# Get recent attestations
recentAttestations: attestations(
first: 20
orderBy: timestamp
orderDirection: desc
) {
id
creatorToken {
symbol
name
}
participant
timestamp
illuminationCount
}
# Get top creators by attestations
topCreators: creatorTokens(
where: { attestationCount_gt: 0 }
first: 10
orderBy: attestationCount
orderDirection: desc
) {
id
symbol
name
attestationCount
}
}
`;
const res = await fetch(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query }),
});
const { data } = await res.json();
return {
activeCreators: data.activeCreators.length,
creators: data.activeCreators,
recentAttestations: data.recentAttestations,
topCreators: data.topCreators,
};
}Workflow 4: Hybrid Query Pattern
Combine subgraph for lists, contracts for validation:
async function hybridQuery(participantAddress: string) {
// Step 1: Use subgraph for fast list of attestation UIDs
const subgraphQuery = `
{
attestations(where: { participant: "${participantAddress}" }) {
id
}
}
`;
const subgraphRes = await fetch('https://api.thegraph.com/subgraphs/name/aaronvick/radiant', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query: subgraphQuery }),
});
const { data } = await subgraphRes.json();
const uids = data.attestations.map((a: any) => a.id);
// Step 2: Use contracts for authoritative record data
const provider = new JsonRpcProvider('https://mainnet.base.org');
const client = createRelationalClient(provider, {
visualizationAssembler: '0x...', // Base Mainnet address
relationalResolver: '0xdaabbfc98a09f542f5f3f13694284ca96dd32934',
illuminationAnalyzer: '0x4b2f2a03ed6744df981198fc3c231953179db699',
});
// Batch get attestation records
const records = await client.batchGetAttestations(uids);
// Step 3: Validate and combine
return records.map((record, i) => ({
uid: uids[i],
...record,
// Add any additional processing
}));
}Workflow 5: Illumination Flow
Complete flow for illuminating an attestation:
import { Wallet } from 'ethers';
import { createRelationalClient, buildIlluminateTx } from '@influence-protocol/sdk';
async function illuminateAttestation(
attestationUid: string,
radiantAmount: bigint,
privateKey: string
) {
const provider = new JsonRpcProvider('https://mainnet.base.org');
const signer = new Wallet(privateKey, provider);
const client = createRelationalClient(provider, {
visualizationAssembler: '0x...', // Base Mainnet address
relationalResolver: '0xdaabbfc98a09f542f5f3f13694284ca96dd32934',
illuminationAnalyzer: '0x4b2f2a03ed6744df981198fc3c231953179db699',
});
// Step 1: Validate attestation exists
const record = await client.getAttestationRecord(attestationUid);
if (!record) {
throw new Error('Attestation not found');
}
// Step 2: Check if already illuminated (optional)
// You might want to check illumination stats here
// Step 3: Build transaction
const tx = buildIlluminateTx({
registry: '0x2aaca41ef9bb156ce3c302e696cff5e7e2b974bf',
attestationUid,
radiantAmount,
});
// Step 4: Send transaction
const receipt = await signer.sendTransaction(tx);
await receipt.wait();
return {
txHash: receipt.hash,
attestationUid,
amount: radiantAmount,
};
}Workflow 6: Creator Network Visualization
Build a network graph showing connections between creators:
async function buildCreatorNetwork(creatorTokenAddresses: string[]) {
const provider = new JsonRpcProvider('https://mainnet.base.org');
const client = createRelationalClient(provider, {
visualizationAssembler: '0x...', // Base Mainnet address
relationalResolver: '0xdaabbfc98a09f542f5f3f13694284ca96dd32934',
illuminationAnalyzer: '0x4b2f2a03ed6744df981198fc3c231953179db699',
});
// Get network edges
const edges = await client.getCreatorNetwork(creatorTokenAddresses);
// Get topology for each creator
const topologies = await Promise.all(
creatorTokenAddresses.map(addr =>
client.getCreatorTopology(addr)
)
);
// Build graph structure
const nodes = topologies.map(t => t.node);
const networkEdges = edges;
// Calculate shared participants
const sharedParticipants = new Map();
for (const edge of edges) {
const key = `${edge.fromToken}-${edge.toToken}`;
sharedParticipants.set(key, edge.sharedParticipants);
}
return {
nodes,
edges: networkEdges,
sharedParticipants: Object.fromEntries(sharedParticipants),
};
}Workflow 7: Influence Leaderboard
Build a leaderboard of top influencers:
async function buildInfluenceLeaderboard(limit: number = 100) {
const provider = new JsonRpcProvider('https://mainnet.base.org');
const client = createRelationalClient(provider, {
visualizationAssembler: '0x...', // Base Mainnet address
relationalResolver: '0xdaabbfc98a09f542f5f3f13694284ca96dd32934',
illuminationAnalyzer: '0x4b2f2a03ed6744df981198fc3c231953179db699',
});
// Step 1: Get all participants from subgraph (faster)
const subgraphQuery = `
{
attestations(first: 1000) {
participant
}
}
`;
const res = await fetch('https://api.thegraph.com/subgraphs/name/aaronvick/radiant', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query: subgraphQuery }),
});
const { data } = await res.json();
const uniqueParticipants = [...new Set(data.attestations.map((a: any) => a.participant))];
// Step 2: Get metrics for each participant
const metricsPromises = uniqueParticipants.slice(0, limit).map(addr =>
client.getInfluencerMetrics(addr).catch(() => null)
);
const metricsResults = await Promise.all(metricsPromises);
// Step 3: Sort by total score
const leaderboard = metricsResults
.filter(m => m !== null)
.map((metrics, i) => ({
address: uniqueParticipants[i],
totalScore: metrics!.totalScore,
breakdown: metrics!.breakdown,
rank: metrics!.rank,
}))
.sort((a, b) => Number(b.totalScore - a.totalScore))
.slice(0, limit);
return leaderboard;
}Workflow 8: Real-time Attestation Monitor
Monitor new attestations in real-time:
import { Contract, JsonRpcProvider } from 'ethers';
async function monitorAttestations(creatorTokenAddress: string, callback: (uid: string) => void) {
const provider = new JsonRpcProvider('https://mainnet.base.org');
const client = createRelationalClient(provider, {
visualizationAssembler: '0x...', // Base Mainnet address
relationalResolver: '0xdaabbfc98a09f542f5f3f13694284ca96dd32934',
illuminationAnalyzer: '0x4b2f2a03ed6744df981198fc3c231953179db699',
});
// Get current attestations
let knownUids = new Set(await client.getCreatorTokenAttestations(creatorTokenAddress));
// Poll for new attestations
setInterval(async () => {
const currentUids = await client.getCreatorTokenAttestations(creatorTokenAddress);
const newUids = currentUids.filter(uid => !knownUids.has(uid));
for (const uid of newUids) {
knownUids.add(uid);
callback(uid);
}
}, 5000); // Poll every 5 seconds
}
// Usage
monitorAttestations('0x...', async (uid) => {
const record = await client.getAttestationRecord(uid);
console.log('New attestation:', record);
});Best Practices
- Use subgraph for lists and aggregations: Faster and more efficient for large datasets.
- Use contracts for validation: Always validate critical data on-chain before transactions.
- Batch operations: Use
batchGetAttestationsinstead of multiple individual calls. - Cache results: Subgraph data can be cached for a few seconds; contract data should be fresh.
- Handle errors gracefully: Subgraph may lag; fall back to contracts when needed.
- Normalize addresses: Always checksum addresses before comparing or storing.
- Paginate large queries: Use offset/limit for large result sets to avoid timeouts.
Agent Notes
- These workflows are production-ready patterns used in the Influence Protocol ecosystem.
- Always validate user inputs (addresses, amounts) before making contract calls.
- Consider rate limiting when polling contracts or subgraph in production.
- Use TypeScript for type safety when working with SDK responses.
- Monitor gas costs when batching operations; some may be more efficient as separate calls.