Skip to content

Commit

Permalink
add subgraph module
Browse files Browse the repository at this point in the history
  • Loading branch information
bvalosek committed Dec 7, 2021
1 parent 8dc2ef6 commit f5e548f
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/hypervibes/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const SUPPORTED_NETWORKS = {
};

// https://docs.hypervibes.xyz/developers/links-and-repos#contract-addresses
export const CONTRACT_ADDRESSES: Record<string, string> = {
export const CONTRACT_ADDRESSES: Record<string, string | undefined> = {
[SUPPORTED_NETWORKS.mainnet]: '0x26887a9F95e1794e52aE1B72Bfa404c1562Eed0E',
[SUPPORTED_NETWORKS.matic]: '0x26887a9F95e1794e52aE1B72Bfa404c1562Eed0E',
[SUPPORTED_NETWORKS.fantom]: '0x26887a9F95e1794e52aE1B72Bfa404c1562Eed0E',
Expand All @@ -23,7 +23,7 @@ export const CONTRACT_ADDRESSES: Record<string, string> = {
};

// https://docs.hypervibes.xyz/developers/links-and-repos#subgraphs
export const SUBGRAPH_ENDPOINTS: Record<string, string> = {
export const SUBGRAPH_ENDPOINTS: Record<string, string | undefined> = {
[SUPPORTED_NETWORKS.mainnet]:
'https://api.thegraph.com/subgraphs/name/r-group-devs/hypervibes-mainnet',
[SUPPORTED_NETWORKS.matic]:
Expand Down
File renamed without changes.
152 changes: 152 additions & 0 deletions src/hypervibes/subgraph.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import { BigNumber } from 'ethers';
import request, { gql } from 'graphql-request';
import { SUBGRAPH_ENDPOINTS } from './constants';

export interface GetIndexedInfusionsInput {
nft: string;
tokenId: BigNumber;
}

export interface GetIndexedInfusionsOutput {
nft: string;
tokenId: BigNumber;
tokenUri: string;
currentOwner: string;
infusions: Array<{
realm: {
id: BigNumber;
name: string;
dailyRate: BigNumber;
token: {
address: string;
symbol: string;
name: string;
decimals: number;
};
};
initialInfusionBy: string;
initialInfusionAmount: BigNumber;
currentBalance: BigNumber;
lastClaimTimestamp: BigNumber;
}>;
}

const infusionsQuery = gql`
query getInfusions($ids: [ID!]!) {
nfts(where: { id_in: $ids }) {
id
tokenId
tokenUri
owner {
id
address
}
collection {
id
address
name
symbol
}
infusions {
id
balance
lastClaimAtTimestamp
realm {
id
name
description
dailyRate
token {
id
address
name
symbol
decimals
}
}
events(first: 1, orderBy: createdAtTimestamp, orderDirection: asc) {
id
eventType
createdAtTimestamp
createdAtBlock
msgSender {
address
}
target {
address
}
amount
}
}
}
}
`;

// WARN: the assumption about the ID format isn't great here
const computeNftId = (datum: { nft: string; tokenId: BigNumber }) =>
`${datum.nft}-${datum.tokenId.toNumber()}`;

// get indexed information about a batch of NFTs
//
// can be used when there is a list of NFTs presented in a UI (eg, a token grid
// UX) and you want to know if it has been infused in ANY realm
export const batchGetIndexedInfusions = async (
batch: GetIndexedInfusionsInput[],
chainId: number
): Promise<GetIndexedInfusionsOutput[]> => {
const endpoint = SUBGRAPH_ENDPOINTS[chainId];
if (endpoint == null) {
throw new Error(`unsupported network: ${chainId}`);
}

const ids = batch.map(computeNftId);
const { nfts } = await request(endpoint, infusionsQuery, { ids });

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const projected: GetIndexedInfusionsOutput[] = nfts.map((item: any) => {
const mapped: GetIndexedInfusionsOutput = {
nft: item.collection.address,
tokenId: BigNumber.from(item.tokenId),
tokenUri: item.tokenUri,
currentOwner: item.owner.address,
infusions: [],
};

for (const infusion of item.infusions) {
const { token } = infusion.realm;

const [event] = infusion.events;
if (event == null) throw new Error('missing initial infusion event');

const entry: GetIndexedInfusionsOutput['infusions'][0] = {
realm: {
id: BigNumber.from(infusion.realm.id),
name: infusion.realm.name,
dailyRate: BigNumber.from(infusion.realm.dailyRate),
token: {
address: token.address ?? '',
symbol: token.symbol ?? '',
name: token.name ?? '',
decimals: token.decimals,
},
},
currentBalance: BigNumber.from(infusion.balance),
lastClaimTimestamp: BigNumber.from(infusion.lastClaimAtTimestamp),
initialInfusionAmount: BigNumber.from(event.amount),
initialInfusionBy: event.target.address,
};
mapped.infusions.push(entry);
}

return mapped;
});

const outputLookup = new Map(projected.map(nft => [computeNftId(nft), nft]));
const ordered = batch.map(datum => {
const projected = outputLookup.get(computeNftId(datum));
if (!projected) throw new Error('batch input output mismatch');
return projected;
});

return ordered;
};

0 comments on commit f5e548f

Please sign in to comment.