Skip to content

Commit

Permalink
Merge pull request #85 from hypercerts-org/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
Jipperism authored Jun 19, 2024
2 parents 4507f93 + 3cd135a commit 1f6d455
Show file tree
Hide file tree
Showing 17 changed files with 567 additions and 110 deletions.
2 changes: 1 addition & 1 deletion lib/hypercerts-indexer
77 changes: 72 additions & 5 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ input BasicAttestationWhereInput {
uid: StringSearchOptions
}

input BasicCollectionWhereInput {
admin_id: StringSearchOptions
chain_id: NumberSearchOptions
id: IdSearchOptions
}

input BasicContractWhereInput {
chain_id: NumberSearchOptions
contract_address: StringSearchOptions
Expand All @@ -122,7 +128,6 @@ input BasicHypercertWhereInput {
creator_address: StringSearchOptions
hypercert_id: StringSearchOptions
id: IdSearchOptions
owner_address: StringSearchOptions
token_id: NumberSearchOptions
uri: StringSearchOptions
}
Expand Down Expand Up @@ -158,10 +163,30 @@ input BooleanSearchOptions {
eq: Boolean
}

type Collection {
admin_address: String!
background_image: String!
chain_id: BigInt
grayscale_image: Boolean!
id: ID!
name: String!
tile_border_color: String!
}

input CollectionFetchInput {
by: ContractSortOptions
}

"""Pointer to a contract deployed on a chain"""
type Contract {
"""The ID of the chain on which the contract is deployed"""
chain_id: BigInt

"""The address of the contract"""
contract_address: String
id: ID!

"""The block number at which the contract was deployed"""
start_block: BigInt
}

Expand Down Expand Up @@ -190,14 +215,25 @@ enum CountKeys {
scalar EthBigInt

type Fraction {
claims_id: String
creation_block_timestamp: BigInt
hypercert_id: ID

"""
The ID of the fraction concatenated from the chain ID, contract address, and token ID
"""
fraction_id: ID
id: ID!
last_block_update_timestamp: BigInt

"""The metadata for the fraction"""
metadata: Metadata

"""Marketplace orders related to this fraction"""
orders: GetOrdersResponse

"""Address of the owner of the fractions"""
owner_address: String

"""Units held by the fraction"""
units: EthBigInt
}

Expand Down Expand Up @@ -234,6 +270,11 @@ type GetAttestationsSchemaResponse {
data: [AttestationSchema!]!
}

type GetCollectionsResponse {
count: Int
data: [Collection!]
}

type GetContractsResponse {
count: Int
data: [Contract!]
Expand All @@ -257,23 +298,49 @@ type GetMetadataResponse {
type GetOrdersResponse {
count: Int
data: [Order!]
lowestAvailablePrice: BigInt
totalUnitsForSale: BigInt
}

type Hypercert {
"""Attestations for the hypercert or parts of its data"""
attestations: GetAttestationsResponse

"""The block number at which the hypercert was stored on chain"""
block_number: BigInt

"""The contract that the hypercert is associated with"""
contract: Contract

"""The UUID of the contract as stored in the database"""
contracts_id: ID

"""The address of the creator of the hypercert"""
creator_address: String

"""Transferable fractions representing partial ownership of the hypercert"""
fractions: GetFractionsResponse

"""
Concatenation of [chainID]-[contractAddress]-[tokenID] to discern hypercerts across chains
"""
hypercert_id: ID
id: ID!
last_block_update_timestamp: BigInt

"""The metadata for the hypercert as referenced by the uri"""
metadata: Metadata

"""Marketplace orders related to this hypercert"""
orders: GetOrdersResponse
owner_address: String

"""The token ID of the hypercert"""
token_id: EthBigInt

"""The total units held by the hypercert"""
units: EthBigInt

"""References the metadata for this claim"""
uri: String
}

Expand Down Expand Up @@ -301,7 +368,6 @@ input HypercertsWhereInput {
hypercert_id: StringSearchOptions
id: IdSearchOptions
metadata: BasicMetadataWhereInput
owner_address: StringSearchOptions
token_id: NumberSearchOptions
uri: StringSearchOptions
}
Expand Down Expand Up @@ -402,6 +468,7 @@ input OrderFetchInput {
type Query {
attestationSchemas(count: CountKeys, first: Int, offset: Int, sort: AttestationSchemaFetchInput, where: AttestationSchemaWhereInput): GetAttestationsSchemaResponse!
attestations(count: CountKeys, first: Int, offset: Int, sort: AttestationFetchInput, where: AttestationWhereInput): GetAttestationsResponse!
collections(count: CountKeys, first: Int, offset: Int, sort: CollectionFetchInput, where: BasicCollectionWhereInput): GetCollectionsResponse!
contracts(count: CountKeys, first: Int, offset: Int, sort: ContractFetchInput, where: BasicContractWhereInput): GetContractsResponse!
fractions(count: CountKeys, first: Int, offset: Int, sort: FractionFetchInput, where: FractionWhereInput): GetFractionsResponse!
hypercerts(count: CountKeys, first: Int, offset: Int, sort: HypercertFetchInput, where: HypercertsWhereInput): GetHypercertsResponse!
Expand Down
17 changes: 17 additions & 0 deletions src/graphql/schemas/args/collectionArgs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ArgsType, Field } from "type-graphql";
import { PaginationArgs } from "./paginationArgs.js";
import {BasicCollectionWhereInput, CollectionFetchInput} from "../inputs/collectionInput.js";

@ArgsType()
export class GetCollectionArgs extends PaginationArgs {
@Field({ nullable: true })
where?: BasicCollectionWhereInput;
@Field({ nullable: true })
sort?: CollectionFetchInput;
}

@ArgsType()
export class GetCollectionByIdArgs {
@Field({ nullable: true })
id?: string;
}
22 changes: 22 additions & 0 deletions src/graphql/schemas/inputs/collectionInput.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Field, InputType } from "type-graphql";
import type { WhereOptions } from "./whereOptions.js";
import {IdSearchOptions, NumberSearchOptions, StringSearchOptions} from "./searchOptions.js";
import { ContractSortOptions } from "./sortOptions.js";
import {Collection} from "../typeDefs/collectionTypeDefs.js";
import {CollectionOptions} from "./collectionOptions.js";

@InputType()
export class BasicCollectionWhereInput implements WhereOptions<Collection> {
@Field((_) => IdSearchOptions, { nullable: true })
id?: IdSearchOptions | null;
@Field((_) => NumberSearchOptions, { nullable: true })
chain_id?: NumberSearchOptions | null;
@Field((_) => StringSearchOptions, { nullable: true })
admin_id?: StringSearchOptions | null;
}

@InputType()
export class CollectionFetchInput implements CollectionOptions<Collection> {
@Field((_) => ContractSortOptions, { nullable: true })
by?: ContractSortOptions;
}
13 changes: 13 additions & 0 deletions src/graphql/schemas/inputs/collectionOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {
AttestationSchemaSortOptions,
AttestationSortOptions,
ContractSortOptions, FractionSortOptions,
HypercertSortOptions,
MetadataSortOptions
} from "./sortOptions.js";


export type CollectionOptions<T extends object> = {
by?: HypercertSortOptions | ContractSortOptions | MetadataSortOptions | AttestationSortOptions | AttestationSchemaSortOptions | FractionSortOptions | null;
}

2 changes: 0 additions & 2 deletions src/graphql/schemas/inputs/hypercertsInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ export class BasicHypercertWhereInput implements WhereOptions<Hypercert> {
@Field(_ => NumberSearchOptions, {nullable: true})
token_id?: NumberSearchOptions;
@Field(_ => StringSearchOptions, {nullable: true})
owner_address?: StringSearchOptions;
@Field(_ => StringSearchOptions, {nullable: true})
creator_address?: StringSearchOptions;
@Field(_ => StringSearchOptions, {nullable: true})
uri?: StringSearchOptions;
Expand Down
50 changes: 50 additions & 0 deletions src/graphql/schemas/resolvers/collectionResolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { Args, Field, Int, ObjectType, Query, Resolver } from "type-graphql";
import { inject, injectable } from "tsyringe";
import { Order } from "../typeDefs/orderTypeDefs.js";
import { SupabaseDataService } from "../../../services/SupabaseDataService.js";
import {Collection} from "../typeDefs/collectionTypeDefs.js";
import {GetCollectionArgs} from "../args/collectionArgs.js";

@ObjectType()
export default class GetCollectionsResponse {
@Field(() => [Collection], { nullable: true })
data?: Collection[];

@Field(() => Int, { nullable: true })
count?: number;
}

@injectable()
@Resolver((_) => Order)
class CollectionResolver {
constructor(
@inject(SupabaseDataService)
private readonly supabaseService: SupabaseDataService,
) {}

@Query((_) => GetCollectionsResponse)
async collections(@Args() args: GetCollectionArgs) {
try {
const res = await this.supabaseService.getCollections(args)

const { data, error, count } = res;

if (error) {
console.warn(
`[CollectionResolver::collections] Error fetching collections: `,
error,
);
return { data };
}

return { data, count: count ? count : data?.length };
} catch (e) {
throw new Error(
`[CollectionResolver::collections] Error fetching collections: ${(e as Error).message}`,
);
}
}

}

export { CollectionResolver };
2 changes: 2 additions & 0 deletions src/graphql/schemas/resolvers/composed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { FractionResolver } from "./fractionResolver.js";
import { AttestationResolver } from "./attestationResolver.js";
import { AttestationSchemaResolver } from "./attestationSchemaResolver.js";
import { OrderResolver } from "./orderResolver.js";
import { CollectionResolver } from "./collectionResolver.js";

export const resolvers = [
ContractResolver,
Expand All @@ -14,4 +15,5 @@ export const resolvers = [
AttestationResolver,
AttestationSchemaResolver,
OrderResolver,
CollectionResolver
] as const;
31 changes: 31 additions & 0 deletions src/graphql/schemas/resolvers/hypercertResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { SupabaseCachingService } from "../../../services/SupabaseCachingService
import { GetHypercertArgs } from "../args/hypercertsArgs.js";
import { SupabaseDataService } from "../../../services/SupabaseDataService.js";
import { parseClaimOrFractionId } from "@hypercerts-org/sdk";
import {decodeAbiParameters, parseAbiParameters} from "viem";

@ObjectType()
export default class GetHypercertsResponse {
Expand Down Expand Up @@ -294,7 +295,37 @@ class HypercertResolver {
return { data: [], count: 0 };
}

// For each fraction, find all orders and find the max units for sale for that fraction
const totalUnitsForSale = fractionsData.map((fraction) => {
const ordersForFraction = ordersData.filter(
(order) =>
parseClaimOrFractionId(fraction.hypercert_id).id.toString() ===
order.itemIds[0],
);

const unitsPerOrder = ordersForFraction.map((order) => {
const decodedParams = decodeAbiParameters(
parseAbiParameters("uint256 minUnitAmount, uint256 maxUnitAmount, uint256 minUnitsToKeep, bool sellLeftOverFraction"),
order.additionalParameters as `0x{string}`,
);
const unitsToKeep = decodedParams[2];
const units = BigInt(fraction.units);
return units - unitsToKeep;
});

// Find max units per order
return unitsPerOrder.reduce((acc, val) => {
return val > acc ? val : acc;
}, BigInt(0));
}).reduce((acc, val) => acc + val, BigInt(0));

const lowestAvailablePrice = ordersData.reduce((acc, val) => {
return BigInt(val.price) < acc ? BigInt(val.price) : acc;
}, BigInt(ordersData[0]?.price || 0));

return {
totalUnitsForSale,
lowestAvailablePrice,
data: ordersData || [],
count: ordersCount || 0,
};
Expand Down
8 changes: 8 additions & 0 deletions src/graphql/schemas/resolvers/orderResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Order } from "../typeDefs/orderTypeDefs.js";
import { SupabaseDataService } from "../../../services/SupabaseDataService.js";
import { GetOrdersArgs } from "../args/orderArgs.js";
import { SupabaseCachingService } from "../../../services/SupabaseCachingService.js";
import {GraphQLBigInt} from "graphql-scalars";

@ObjectType()
export default class GetOrdersResponse {
Expand All @@ -12,6 +13,13 @@ export default class GetOrdersResponse {

@Field(() => Int, { nullable: true })
count?: number;

@Field(() => GraphQLBigInt, { nullable: true })
totalUnitsForSale?: bigint;

@Field(() => GraphQLBigInt, { nullable: true })
lowestAvailablePrice?: bigint;

}

@injectable()
Expand Down
21 changes: 21 additions & 0 deletions src/graphql/schemas/typeDefs/collectionTypeDefs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Field, ObjectType } from "type-graphql";
import { BasicTypeDef } from "./basicTypeDef.js";
import {GraphQLBigInt} from "graphql-scalars";

@ObjectType()
class Collection extends BasicTypeDef {
@Field()
name?: string;
@Field({name: "admin_address"})
admin_id?: string;
@Field(() => GraphQLBigInt, {nullable: true})
chain_id?: number;
@Field()
background_image?: string;
@Field()
grayscale_image?: boolean;
@Field()
tile_border_color?: string;
}

export { Collection };
8 changes: 4 additions & 4 deletions src/graphql/schemas/typeDefs/contractTypeDefs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import {Field, ObjectType} from "type-graphql";
import {GraphQLBigInt} from 'graphql-scalars';
import {BasicTypeDef} from "./basicTypeDef.js";

@ObjectType()
@ObjectType({description: "Pointer to a contract deployed on a chain"})
class Contract extends BasicTypeDef {
@Field(_ => GraphQLBigInt, {nullable: true})
@Field(_ => GraphQLBigInt, {nullable: true, description: "The ID of the chain on which the contract is deployed"})
chain_id?: bigint | number | string;
@Field({nullable: true})
@Field({nullable: true, description: "The address of the contract"})
contract_address?: string;
@Field(_ => GraphQLBigInt, {nullable: true})
@Field(_ => GraphQLBigInt, {nullable: true, description: "The block number at which the contract was deployed"})
start_block?: bigint | number | null;
}

Expand Down
Loading

0 comments on commit 1f6d455

Please sign in to comment.