Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ens wip #121

Merged
merged 1 commit into from
Aug 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
13 changes: 12 additions & 1 deletion Implementations/API/backend/functions/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,15 @@ export const snapshotApiConfig: { [key: string]: any } = {

export const nonusApiConfig: { [key: string]: any } = {
'1': 'https://api.thegraph.com/subgraphs/name/nounsdao/nouns-subgraph'
}
}

export const delegationsSubgraphs: { [key: string]: string } = {
"1": "https://subgrapher.snapshot.org/gateway.thegraph.com/api/0f15b42bdeff7a063a4e1757d7e2f99e/deployments/id/QmXZiV6S13ha6QXq4dmaM3TB4CHcDxBMvGexSNu9Kc28EH",
"5": "https://subgrapher.snapshot.org/api.thegraph.com/subgraphs/name/snapshot-labs/snapshot-goerli",
"10": "https://subgrapher.snapshot.org/api.thegraph.com/subgraphs/name/snapshot-labs/snapshot-optimism",
"56": "https://subgrapher.snapshot.org/api.thegraph.com/subgraphs/name/snapshot-labs/snapshot-binance-smart-chain",
"100": "https://subgrapher.snapshot.org/api.thegraph.com/subgraphs/name/snapshot-labs/snapshot-gnosis-chain",
"137": "https://subgrapher.snapshot.org/api.thegraph.com/subgraphs/name/snapshot-labs/snapshot-polygon",
"250": "https://subgrapher.snapshot.org/api.thegraph.com/subgraphs/name/snapshot-labs/snapshot-fantom",
"42161": "https://subgrapher.snapshot.org/api.thegraph.com/subgraphs/name/snapshot-labs/snapshot-arbitrum"
}
91 changes: 91 additions & 0 deletions Implementations/API/backend/functions/snapshot/getDelegations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { APIGatewayProxyHandlerV2 } from 'aws-lambda'
import { delegationsSubgraphs } from 'functions/config'
import snapshot from '@snapshot-labs/snapshot.js';
import { getAddress } from '@ethersproject/address';


const {
subgraphRequest,
} = snapshot.utils;

async function getDelegationsOutAndIn(
network: string,
space: string
): Promise<string[]> {
if (!delegationsSubgraphs[network]) return [];

const max = 1000;
let result: any = [];
let page = 0;

const members: string[] = []

const query = {
delegations: {
__args: {
first: max,
skip: 0,
where: {
space_in: [space],
}
},
delegator: true,
delegate: true,
space: true
}
};
while (true) {
query.delegations.__args.skip = page * max;
const pageResult = await subgraphRequest(delegationsSubgraphs[network], query);
const pageDelegations = pageResult.delegations || [];
result = result.concat(pageDelegations);
page++;
if (pageDelegations.length < max) break;
}

result.forEach((delegation: any) => {
const delegator = getAddress(delegation.delegator);
const delegate = getAddress(delegation.delegate);
if (delegation.space === space) {
members.push(delegator)
members.push(delegate)

}
});

return members
}

export const handler: APIGatewayProxyHandlerV2 = async (event) => {

const space = event?.pathParameters?.id
if (!space) return { statusCode: 400, message: 'Missing id' }

const template = {
'@context': {
'@vocab': 'http://daostar.org/',
},
type: 'DAO',
name: space,
}

const members = await getDelegationsOutAndIn('1', space)

console.log({ members })

const membersFormatted = members.map((m: string) => {
return { id: m, type: 'EthereumAddress' }
})

const transformed = { members: membersFormatted, ...template }

return transformed
? {
statusCode: 200,
body: JSON.stringify(transformed),
}
: {
statusCode: 404,
body: JSON.stringify({ error: true }),
}
}
10 changes: 10 additions & 0 deletions Implementations/API/backend/utils/snapshot/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import 'dotenv/config';
import strategies from './strategies';
import validations from './validations';
import utils from './utils';

export default {
strategies,
validations,
utils
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Contract call strategy

Allows to get Voting power or Proposition power from an Aave GovernanceStrategy contract.

## Strategy Parameters

| Param | Type | Description | | |
| ------------------ | ------ | -------------------------------------------------------------------------------------------------------------------------- | --- | --- |
| governanceStrategy | string | The Ethereum address of the GovernanceStrategy contract to measure voting or proposition power from an address at a block. | | |
| powerType | string | Use `vote` for Voting Power or `proposition` for Proposition Power | | |
| | | | | |
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[
{
"name": "Example of Aave Governance Power strategy",
"strategy": {
"name": "aave-governance-power",
"params": {
"governanceStrategy": "0xb7e383ef9b1e9189fc0f71fb30af8aa14377429e",
"powerType": "vote",
"symbol": "Voting Power",
"decimals": 18
}
},
"network": "1",
"addresses": ["0x5BC928BF0DAb1e4A2ddd9e347b0F22e88026D76c"],
"snapshot": 12657715
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { BigNumber } from '@ethersproject/bignumber';
import { formatUnits } from '@ethersproject/units';
import { multicall } from '../../utils';

export const author = 'kartojal';
export const version = '0.1.0';

/**
* Aave Governance strategy to measure voting or
*/

const abi = [
{
inputs: [
{ internalType: 'address', name: 'user', type: 'address' },
{ internalType: 'uint256', name: 'blockNumber', type: 'uint256' }
],
name: 'getPropositionPowerAt',
outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
stateMutability: 'view',
type: 'function'
},
{
inputs: [
{ internalType: 'address', name: 'user', type: 'address' },
{ internalType: 'uint256', name: 'blockNumber', type: 'uint256' }
],
name: 'getVotingPowerAt',
outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
stateMutability: 'view',
type: 'function'
}
];

const powerTypesToMethod = {
vote: 'getVotingPowerAt',
proposition: 'getPropositionPowerAt'
};

export async function strategy(
space,
network,
provider,
addresses,
options,
snapshot
) {
const blockTag =
typeof snapshot === 'number'
? snapshot
: await provider.getBlockNumber(snapshot);

// Early return 0 voting power if governanceStrategy or powerType is not correctly set
if (!options.governanceStrategy || !powerTypesToMethod[options.powerType]) {
return Object.fromEntries(addresses.map((address) => [address, '0']));
}

const response: BigNumber[] = await multicall(
network,
provider,
abi,
addresses.map((address: any) => [
options.governanceStrategy,
powerTypesToMethod[options.powerType],
[address.toLowerCase(), blockTag]
]),
{ blockTag }
);
return Object.fromEntries(
response.map((value, i) => [
addresses[i],
parseFloat(formatUnits(value.toString(), options.decimals))
])
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"name": "AGIP 17: Voting power for GHST value of parcels",
"strategy": {
"name": "aavegotchi-agip-17",
"params": {
"symbol": "REALM"
}
},
"network": "137",
"addresses": ["0x027Ffd3c119567e85998f4E6B9c3d83D5702660c"],
"snapshot": 22089223
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { subgraphRequest } from '../../utils';

export const author = 'candoizo';
export const version = '0.1.2';

const AAVEGOTCHI_SUBGRAPH_URL = {
137: 'https://subgraph.satsuma-prod.com/tWYl5n5y04oz/aavegotchi/aavegotchi-core-matic/api'
};

const maxResponsePerQuery = 1000;

// agip 17: Voting power of 0.5 GHST/pixel
const realmSizeVotePower = {
0: 32, // humble
1: 128, // reasonable
2: 1028, // spacious
3: 1028, // spacious
4: 2048 // partner
};

export async function strategy(
_space,
network,
provider,
addresses,
options,
snapshot
) {
const blockTag = typeof snapshot === 'number' ? snapshot : 'latest';

const args: {
where: { id_in: string[] };
first: number;
block?: { number: number };
} = {
where: {
id_in: addresses.map((addr: string) => addr.toLowerCase())
},
first: addresses.length
};
if (blockTag !== 'latest') args.block = { number: blockTag };

const batchQuery = (i) => {
return {
['parcelsOwned_' + i]: {
__aliasFor: 'parcelsOwned',
__args: {
first: maxResponsePerQuery,
skip: maxResponsePerQuery * i
},
size: true
}
};
};
let parcelsOwnedQueryParams = {
users: {
__args: args,
id: true
}
};
for (let i = 0; i < 6; i++) {
parcelsOwnedQueryParams = {
...parcelsOwnedQueryParams,
users: {
...parcelsOwnedQueryParams.users,
...batchQuery(i)
}
};
}

const result = await subgraphRequest(
AAVEGOTCHI_SUBGRAPH_URL[network],
parcelsOwnedQueryParams
);

const userToInfo = Object.fromEntries(
result.users.map((user) => {
return [user.id, user];
})
);

return Object.fromEntries(
addresses.map((addr: string) => {
let realmVotingPowerValue = 0;
const res = userToInfo[addr.toLowerCase()];
if (res) {
const parcelsOwned = Object.entries(res)
.map(([key, val]) => {
if (key.startsWith('parcelsOwned')) return val;
else return [];
})
.flat(1) as unknown as { size: number }[];
if (parcelsOwned.length > 0) {
parcelsOwned.map((r: { size: number }) => {
let votePower = realmSizeVotePower[r.size];
if (isNaN(votePower)) votePower = 0;
realmVotingPowerValue += votePower;
});
}
}
return [addr, realmVotingPowerValue];
})
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Aavegotchi AGIP 37 GLTR Staked LP Strategy

## Description

This snapshot strategy enables voting power for the following assets staked in GLTR staking pools

- GHST-FUD LP
- GHST-FOMO LP
- GHST-ALPHA LP
- GHST-KEK LP
- GHST-GLTR LP
- GHST-USDC LP
- GHST-WMATIC LP

Please note this excludes voting power from:
- Staked wapGHST and unstaked wapGHST held in a wallet (see aavegotchi-agip-37-wap-ghst)
- amGHST (see erc20-balance-of)
- Unstaked GHST-FUD, GHST-FOMO, GHST-ALPHA, GHST-KEK, GHST-GLTR LP tokens (see erc20-tokens-per-uni)

## References

Aavegotchi AGIP 37: https://snapshot.org/#/aavegotchi.eth/proposal/0x9923aab6825158ec2503d88e3ee2f9c5fbb12000581d06343ac9829aa59b66a6
Loading