Skip to content

Commit

Permalink
feat: index Leaderboard and proposer/voter counts (#159)
Browse files Browse the repository at this point in the history
* feat: index LeaderboardItem and proposer/voter counts

* feat: drop Item suffix for consistent naming
  • Loading branch information
Sekhmet authored Mar 7, 2024
1 parent 31e655d commit 4d63ef2
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 31 deletions.
10 changes: 10 additions & 0 deletions apps/api/src/schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ type Space {
@derivedFrom(field: "space")
proposal_count: Int!
vote_count: Int!
proposer_count: Int!
voter_count: Int!
created: Int!
tx: String!
proposals: [Proposal]! @derivedFrom(field: "space")
Expand Down Expand Up @@ -149,3 +151,11 @@ type User {
proposals: [Proposal]! @derivedFrom(field: "author")
votes: [Vote]! @derivedFrom(field: "voter")
}

type Leaderboard {
id: String!
space: Space!
user: User!
proposal_count: Int!
vote_count: Int!
}
18 changes: 17 additions & 1 deletion apps/api/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import fetch from 'cross-fetch';
import { BigNumberish, CallData, Contract, Provider, hash, shortString } from 'starknet';
import {
BigNumberish,
CallData,
Contract,
Provider,
hash,
shortString,
validateAndParseAddress
} from 'starknet';
import { Contract as EthContract } from '@ethersproject/contracts';
import { JsonRpcProvider } from '@ethersproject/providers';
import { faker } from '@faker-js/faker';
Expand Down Expand Up @@ -93,6 +101,14 @@ export function findVariant(value: { variant: Record<string, any> }) {
};
}

export function formatAddressVariant({ key, value }: { key: string; value: string }) {
return key === 'Starknet'
? validateAndParseAddress(value)
: key === 'Ethereum'
? getAddress(value)
: value;
}

export function getVoteValue(label: string) {
if (label === 'Against') return 2;
if (label === 'For') return 1;
Expand Down
49 changes: 36 additions & 13 deletions apps/api/src/writer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { validateAndParseAddress } from 'starknet';
import { getAddress } from '@ethersproject/address';
import { CheckpointWriter } from '@snapshot-labs/checkpoint';
import { Space, Vote, User, Proposal } from '../.checkpoint/models';
import { Space, Vote, User, Proposal, Leaderboard } from '../.checkpoint/models';
import { handleProposalMetadata, handleSpaceMetadata } from './ipfs';
import { networkProperties } from './overrrides';
import {
Expand All @@ -13,7 +12,8 @@ import {
handleStrategiesMetadata,
longStringToText,
updateProposaValidationStrategy,
registerProposal
registerProposal,
formatAddressVariant
} from './utils';

type Strategy = {
Expand Down Expand Up @@ -62,6 +62,8 @@ export const handleSpaceCreated: CheckpointWriter = async ({ block, tx, event })
space.authenticators = event.authenticators;
space.proposal_count = 0;
space.vote_count = 0;
space.proposer_count = 0;
space.voter_count = 0;
space.created = block?.timestamp ?? getCurrentTimestamp();
space.tx = tx.transaction_hash;

Expand Down Expand Up @@ -305,7 +307,7 @@ export const handlePropose: CheckpointWriter = async ({ block, tx, rawEvent, eve
if (!space) return;

const proposalId = parseInt(BigInt(event.proposal_id).toString());
const author = findVariant(event.author).value;
const author = formatAddressVariant(findVariant(event.author));

const created = block?.timestamp ?? getCurrentTimestamp();

Expand Down Expand Up @@ -358,8 +360,6 @@ export const handlePropose: CheckpointWriter = async ({ block, tx, rawEvent, eve
console.log(JSON.stringify(e).slice(0, 256));
}

space.proposal_count += 1;

const existingUser = await User.loadEntity(author);
if (existingUser) {
existingUser.proposal_count += 1;
Expand All @@ -370,6 +370,21 @@ export const handlePropose: CheckpointWriter = async ({ block, tx, rawEvent, eve
await user.save();
}

let leaderboardItem = await Leaderboard.loadEntity(`${spaceId}/${author}`);
if (!leaderboardItem) {
leaderboardItem = new Leaderboard(`${spaceId}/${author}`);
leaderboardItem.space = spaceId;
leaderboardItem.user = author;
leaderboardItem.vote_count = 0;
leaderboardItem.proposal_count = 0;
}

leaderboardItem.proposal_count += 1;
await leaderboardItem.save();

if (leaderboardItem.proposal_count === 1) space.proposer_count += 1;
space.proposal_count += 1;

const herodotusStrategiesIndicies = space.strategies
.map((strategy, i) => [strategy, i] as const)
.filter(([strategy]) =>
Expand Down Expand Up @@ -477,17 +492,11 @@ export const handleVote: CheckpointWriter = async ({ block, tx, rawEvent, event

const spaceId = validateAndParseAddress(rawEvent.from_address);
const proposalId = parseInt(event.proposal_id);
const voterVariant = findVariant(event.voter);
const choice = getVoteValue(findVariant(event.choice).key);
const vp = BigInt(event.voting_power);

const created = block?.timestamp ?? getCurrentTimestamp();
const voter =
voterVariant.key === 'Starknet'
? validateAndParseAddress(voterVariant.value)
: voterVariant.key === 'Ethereum'
? getAddress(voterVariant.value)
: voterVariant.value;
const voter = formatAddressVariant(findVariant(event.voter));

const vote = new Vote(`${spaceId}/${proposalId}/${voter}`);
vote.space = spaceId;
Expand All @@ -509,9 +518,23 @@ export const handleVote: CheckpointWriter = async ({ block, tx, rawEvent, event
await user.save();
}

let leaderboardItem = await Leaderboard.loadEntity(`${spaceId}/${voter}`);
if (!leaderboardItem) {
leaderboardItem = new Leaderboard(`${spaceId}/${voter}`);
leaderboardItem.space = spaceId;
leaderboardItem.user = voter;
leaderboardItem.vote_count = 0;
leaderboardItem.proposal_count = 0;
}

leaderboardItem.vote_count += 1;
await leaderboardItem.save();

const space = await Space.loadEntity(spaceId);
if (space) {
space.vote_count += 1;
if (leaderboardItem.vote_count === 1) space.voter_count += 1;

await space.save();
}

Expand Down
10 changes: 10 additions & 0 deletions apps/subgraph-api/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ type Space @entity {
@derivedFrom(field: "space")
proposal_count: Int!
vote_count: Int!
proposer_count: Int!
voter_count: Int!
created: Int!
tx: Bytes!
}
Expand Down Expand Up @@ -146,3 +148,11 @@ type User @entity {
vote_count: Int!
created: Int!
}

type Leaderboard @entity {
id: String!
space: Space!
user: User!
proposal_count: Int!
vote_count: Int!
}
62 changes: 45 additions & 17 deletions apps/subgraph-api/src/mapping.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
import {
Address,
BigDecimal,
BigInt,
Bytes,
DataSourceContext,
dataSource,
} from '@graphprotocol/graph-ts'
import { Address, BigDecimal, BigInt, Bytes, dataSource } from '@graphprotocol/graph-ts'
import { ProxyDeployed } from '../generated/ProxyFactory/ProxyFactory'
import { AvatarExecutionStrategy } from '../generated/ProxyFactory/AvatarExecutionStrategy'
import { AxiomExecutionStrategy } from '../generated/ProxyFactory/AxiomExecutionStrategy'
Expand Down Expand Up @@ -38,7 +31,15 @@ import {
SpaceMetadata as SpaceMetadataTemplate,
ProposalMetadata as ProposalMetadataTemplate,
} from '../generated/templates'
import { Space, ExecutionStrategy, ExecutionHash, Proposal, Vote, User } from '../generated/schema'
import {
Space,
ExecutionStrategy,
ExecutionHash,
Proposal,
Vote,
User,
Leaderboard,
} from '../generated/schema'
import { updateStrategiesParsedMetadata, updateProposalValidationStrategy } from './helpers'

const MASTER_SPACE = Address.fromString('0xC3031A7d3326E47D49BfF9D374d74f364B29CE4D')
Expand Down Expand Up @@ -142,6 +143,8 @@ export function handleSpaceCreated(event: SpaceCreated): void {
space.authenticators = event.params.input.authenticators.map<Bytes>((address) => address)
space.proposal_count = 0
space.vote_count = 0
space.proposer_count = 0
space.voter_count = 0
space.created = event.block.timestamp.toI32()
space.tx = event.transaction.hash

Expand Down Expand Up @@ -223,19 +226,31 @@ export function handleProposalCreated(event: ProposalCreated): void {

proposal.save()

space.proposal_count += 1
space.save()

let user = User.load(event.params.author.toHexString())
if (user == null) {
user = new User(event.params.author.toHexString())
user.proposal_count = 0
user.vote_count = 0
user.created = event.block.timestamp.toI32()
user.save()
}
user.proposal_count += 1
user.save()

let leaderboardItem = Leaderboard.load(`${space.id}/${user.id}`)
if (!leaderboardItem) {
leaderboardItem = new Leaderboard(`${space.id}/${user.id}`)
leaderboardItem.space = space.id
leaderboardItem.user = user.id
leaderboardItem.proposal_count = 0
leaderboardItem.vote_count = 0
}

leaderboardItem.proposal_count += 1
leaderboardItem.save()

if (leaderboardItem.proposal_count === 1) space.proposer_count += 1
space.proposal_count += 1
space.save()
}

export function handleProposalUpdated(event: ProposalUpdated): void {
Expand Down Expand Up @@ -346,9 +361,6 @@ export function handleVoteCreated(event: VoteCast): void {
vote.tx = event.transaction.hash
vote.save()

space.vote_count += 1
space.save()

let proposal = Proposal.load(`${space.id}/${event.params.proposalId}`)
if (proposal !== null) {
proposal.setBigDecimal(
Expand All @@ -366,10 +378,26 @@ export function handleVoteCreated(event: VoteCast): void {
user.proposal_count = 0
user.vote_count = 0
user.created = event.block.timestamp.toI32()
user.save()
}

user.vote_count += 1
user.save()

let leaderboardItem = Leaderboard.load(`${space.id}/${vote.voter}`)
if (!leaderboardItem) {
leaderboardItem = new Leaderboard(`${space.id}/${vote.voter}`)
leaderboardItem.space = space.id
leaderboardItem.user = vote.voter
leaderboardItem.proposal_count = 0
leaderboardItem.vote_count = 0
}

leaderboardItem.vote_count += 1
leaderboardItem.save()

if (leaderboardItem.vote_count === 1) space.voter_count += 1
space.vote_count += 1
space.save()
}

export function handleMetadataUriUpdated(event: MetadataURIUpdated): void {
Expand Down

0 comments on commit 4d63ef2

Please sign in to comment.