Use subgraph for Gnosis Safe information

Signed-off-by: Sebastian Martinez <sebastinez@me.com>
This commit is contained in:
Sebastian Martinez
2021-11-17 14:36:03 +01:00
parent 299e7a2c32
commit 9a4f3547b6
2 changed files with 48 additions and 51 deletions
+38 -14
View File
@@ -31,17 +31,42 @@ const GetOrgs = `
}
`;
const GetOrgsByOwner = `
query GetOrgsByOwner($owners: [String!]!) {
const GetSafesByOwners = `
query GetSafesByOwner($owners: [String!]!) {
safes(where: { owners_contains: $owners }) {
id
owners
threshold
}
}
`;
const GetOrgsByOwners = `
query GetOrgsByOwners($owners: [String!]!) {
orgs(where: { owner_in: $owners }) {
id
owner
safe {
id
owners
threshold
}
creator
timestamp
}
}
`;
export const GetSafe = `
query GetSafe($addr: ID!) {
safe(id: $addr) {
id
owners
threshold
}
}
`;
export class Org {
address: string;
owner: string;
@@ -259,20 +284,19 @@ export class Org {
return profile;
}
// Return only Orgs that have a specific user as owner
static async getOrgsByOwner(owner: string, config: Config): Promise<Org[]> {
const orgsResult = await utils.querySubgraph(config.orgs.subgraph, GetOrgsByOwner, { owners: [owner] });
return orgsResult.orgs.map((o: { id: string; owner: string }) => {
return new Org(o.id, o.owner);
});
}
static async getOrgsByMember(owner: string, config: Config): Promise<Org[]> {
type Safe = { id: string; owners: string[]; threshold: number };
static async getOrgsByMember(memberAddr: string, config: Config): Promise<Org[]> {
const wallets = await utils.getOwnerSafes(memberAddr, config);
const owners = wallets?.concat([memberAddr]);
const orgsResult = await utils.querySubgraph(config.orgs.subgraph, GetOrgsByOwner, { owners });
// TODO: We use two subgraph queries since we can't do a filter query yet in the subgraph
// https://github.com/graphprotocol/graph-node/issues/2539#issuecomment-855979841
const safesByOwner = await utils.querySubgraph(config.orgs.subgraph, GetSafesByOwners, { owners: [owner] });
const safes = safesByOwner.safes.reduce(
(prev: any, curr: Safe) => prev.concat(curr.id), []);
const orgsByOwner = await utils.querySubgraph(config.orgs.subgraph, GetOrgsByOwners, { owners: [...safes, owner] });
return orgsResult.orgs.map((o: { id: string; owner: string }) => {
const orgs: any[] = [...orgsByOwner.orgs];
return orgs.map((o: { id: string; owner: string }) => {
return new Org(o.id, o.owner);
});
}
+10 -37
View File
@@ -11,6 +11,7 @@ import { getAvatar, getSeedHost, getSeedId, getAnchorsAccount, getRegistration }
import type { BasicProfile } from '@datamodels/identity-profile-basic';
import { ProfileType } from '@app/profile';
import { parseUnits } from "@ethersproject/units";
import { GetSafe } from "@app/base/orgs/Org";
export enum AddressType {
Contract,
@@ -354,56 +355,28 @@ export async function resolveEnsProfile(addressOrName: string, profileType: Prof
// Check whether a Gnosis Safe exists at an address.
export async function isSafe(address: string, config: Config): Promise<boolean> {
if (! config.safe.api) return false;
// For the subgraph we need to pass a lowercase address
const query = await querySubgraph(config.orgs.subgraph, GetSafe, { addr: address.toLowerCase() });
const addr = ethers.utils.getAddress(address);
const response = await fetch(`${config.safe.api}/api/v1/safes/${addr}/`, { method: 'HEAD' });
return response.ok;
return query.safe !== null ? true : false;
}
// Get a Gnosis Safe at an address.
export async function getSafe(address: string, config: Config): Promise<Safe | null> {
if (! config.safe.api) return null;
// For the subgraph we need to pass a lowercase address
const query = await querySubgraph(config.orgs.subgraph, GetSafe, { addr: address.toLowerCase() });
const addr = ethers.utils.getAddress(address);
const response = await fetch(`${config.safe.api}/api/v1/safes/${addr}/`, {
method: 'GET',
headers: {
'Accept': 'application/json',
}
});
if (! response.ok) {
if (! query.safe) {
return null;
}
const json = await response.json();
return {
address: json.address,
owners: json.owners,
threshold: json.threshold
address: query.safe.id,
owners: query.safe.owners,
threshold: query.safe.threshold
};
}
// Get the Gnosis Safe addresses owned by the given address.
export async function getOwnerSafes(owner: string, config: Config): Promise<string[] | null> {
if (! config.safe.api) return null;
const addr = ethers.utils.getAddress(owner);
const response = await fetch(`${config.safe.api}/api/v1/owners/${addr}/safes/`, {
method: 'GET',
headers: { 'Accept': 'application/json' }
});
if (! response.ok) {
return null;
}
const json = await response.json();
return json.safes;
}
// Get token balances for an address.
export async function getTokens(address: string, config: Config): Promise<Array<Token>> {
const userBalances = await config.provider.send("alchemy_getTokenBalances", [address, "DEFAULT_TOKENS"]);