forked from aragon/osx-plugin-template-hardhat
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from vocdoni/f/plugin_members_subgraph
Subgraph plugin members support
- Loading branch information
Showing
6 changed files
with
178 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
// add your grapql queries here and export them with this file | ||
export * from './settings'; | ||
export * from './proposal'; | ||
export * from './members'; |
26 changes: 26 additions & 0 deletions
26
packages/js-client/src/internal/graphql-queries/members.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { gql } from 'graphql-request'; | ||
|
||
export const QueryPluginMembers = gql` | ||
query PluginMembers($address: String!, $block: Block_height) { | ||
pluginMembers(block: $block, where: { pluginAddress: $address }) { | ||
id | ||
address | ||
balance | ||
votingPower | ||
plugin { | ||
id | ||
} | ||
proposals { | ||
id | ||
} | ||
delegatee { | ||
id | ||
address | ||
} | ||
delegators { | ||
id | ||
address | ||
} | ||
} | ||
} | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import {PluginMember} from '../../generated/schema'; | ||
import { | ||
DelegateChanged, | ||
DelegateVotesChanged, | ||
Transfer, | ||
} from '../../generated/templates/GovernanceERC20/GovernanceERC20'; | ||
import {GovernanceERC20 as GovernanceERC20Contract} from '../../generated/templates/GovernanceERC20/GovernanceERC20'; | ||
import {Address, BigInt, dataSource, store} from '@graphprotocol/graph-ts'; | ||
|
||
function getOrCreateMember(user: Address, pluginId: string): PluginMember { | ||
let id = [user.toHexString(), pluginId].join('_'); | ||
let member = PluginMember.load(id); | ||
if (!member) { | ||
member = new PluginMember(id); | ||
member.address = user.toHexString(); | ||
member.balance = BigInt.zero(); | ||
member.plugin = pluginId; | ||
member.pluginAddress = dataSource.address().toHexString(); | ||
member.delegatee = null; | ||
member.votingPower = BigInt.zero(); | ||
} | ||
|
||
return member; | ||
} | ||
|
||
export function handleTransfer(event: Transfer): void { | ||
let context = dataSource.context(); | ||
let pluginId = context.getString('pluginId'); | ||
|
||
if (event.params.from != Address.zero()) { | ||
let fromMember = getOrCreateMember(event.params.from, pluginId); | ||
fromMember.balance = fromMember.balance.minus(event.params.value); | ||
fromMember.save(); | ||
} | ||
|
||
if (event.params.to != Address.zero()) { | ||
let toMember = getOrCreateMember(event.params.to, pluginId); | ||
toMember.balance = toMember.balance.plus(event.params.value); | ||
toMember.save(); | ||
} | ||
} | ||
|
||
export function handleDelegateChanged(event: DelegateChanged): void { | ||
let context = dataSource.context(); | ||
let pluginId = context.getString('pluginId'); | ||
const toDelegate = event.params.toDelegate; | ||
|
||
// make sure `fromDelegate` & `toDelegate`are members | ||
if (event.params.fromDelegate != Address.zero()) { | ||
let fromMember = getOrCreateMember(event.params.fromDelegate, pluginId); | ||
fromMember.save(); | ||
} | ||
if (toDelegate != Address.zero()) { | ||
let toMember = getOrCreateMember(toDelegate, pluginId); | ||
toMember.save(); | ||
} | ||
|
||
// make sure `delegator` is member and set delegatee | ||
if (event.params.delegator != Address.zero()) { | ||
let delegator = getOrCreateMember(event.params.delegator, pluginId); | ||
|
||
// set delegatee | ||
let delegatee: string | null = null; | ||
if (toDelegate != Address.zero()) { | ||
delegatee = [toDelegate.toHexString(), pluginId].join('_'); | ||
|
||
delegator.delegatee = delegatee; | ||
} | ||
|
||
delegator.save(); | ||
} | ||
} | ||
|
||
export function handleDelegateVotesChanged(event: DelegateVotesChanged): void { | ||
const delegate = event.params.delegate; | ||
if (delegate == Address.zero()) return; | ||
const newVotingPower = event.params.newBalance; | ||
|
||
const context = dataSource.context(); | ||
const pluginId = context.getString('pluginId'); | ||
let member = getOrCreateMember(delegate, pluginId); | ||
|
||
if (isZeroBalanceAndVotingPower(member.balance, newVotingPower)) { | ||
if (shouldRemoveMember(event.address, delegate)) { | ||
store.remove('PluginMember', member.id); | ||
return; | ||
} | ||
} | ||
member.votingPower = newVotingPower; | ||
member.save(); | ||
} | ||
|
||
function isZeroBalanceAndVotingPower( | ||
memberBalance: BigInt, | ||
votingPower: BigInt | ||
): boolean { | ||
return ( | ||
memberBalance.equals(BigInt.zero()) && votingPower.equals(BigInt.zero()) | ||
); | ||
} | ||
|
||
function shouldRemoveMember( | ||
contractAddress: Address, | ||
delegate: Address | ||
): boolean { | ||
const governanceERC20Contract = GovernanceERC20Contract.bind(contractAddress); | ||
const delegates = governanceERC20Contract.try_delegates(delegate); | ||
if (!delegates.reverted) { | ||
return delegates.value == delegate || delegates.value == Address.zero(); | ||
} | ||
return false; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters