From 7d0ac67d6e6e70cb0fa557a4d2f0c103bc6cf3f9 Mon Sep 17 00:00:00 2001 From: kiwvic Date: Sun, 28 Nov 2021 18:59:34 +0200 Subject: [PATCH 01/14] redesigned schema for mongoose, graphql (due to new collection "tokens") + getTokensByOwner --- lib/api/schema.ts | 14 +++++++------- lib/types/mongo.ts | 6 +++++- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/api/schema.ts b/lib/api/schema.ts index 1857f67..919a6ab 100644 --- a/lib/api/schema.ts +++ b/lib/api/schema.ts @@ -9,7 +9,7 @@ import { GraphQLString } from "graphql"; -import {Order, TokensCollection} from "../types/mongo"; +import {Order, TokensCollection, Tokens} from "../types/mongo"; import {OrderFront} from "../types/common"; import {Marketplace} from "../marketplace"; @@ -41,8 +41,11 @@ export function schema(marketplace: Marketplace): GraphQLSchema { const TokenType = new GraphQLObjectType({ name: "Token", fields: () => ({ + collectionObjectId: {type: GraphQLString}, tokenId: {type: GraphQLString}, + metadata_uri: {type: GraphQLString}, metadata: {type: MetadataType}, + last_update: {type: GraphQLInt}, owners: {type: TokenOwnersType}, }) }); @@ -54,7 +57,7 @@ export function schema(marketplace: Marketplace): GraphQLSchema { contractAddress: {type: GraphQLString}, tokenType: {type: GraphQLInt}, owner: {type: GraphQLString}, - tokens: {type: new GraphQLList(TokenType),} + // tokens: {type: new GraphQLList(TokenType),} }) }); @@ -93,13 +96,10 @@ export function schema(marketplace: Marketplace): GraphQLSchema { } }, getTokensByOwner: { - type: new GraphQLList(TokensCollectionType), + type: new GraphQLList(TokenType), args: {owner: {type: GraphQLString}}, resolve: (_, args) => { - return TokensCollection.find({ - tokenType: {$ne: null}, - tokens: {$elemMatch: {[`owners.${args.owner}`]: {$gt: 0}}} - }) + return Tokens.find({[`owners.${args.owner}`]: {$gt: 0}}); } }, diff --git a/lib/types/mongo.ts b/lib/types/mongo.ts index 4eabc2f..3c7c916 100644 --- a/lib/types/mongo.ts +++ b/lib/types/mongo.ts @@ -27,6 +27,8 @@ const TokenTransferEventSchema = new Schema({ }, { _id: false }); const TokenSchema = new Schema({ + collectionObjectId: String, + tokenId: String, metadata_uri: String, @@ -37,13 +39,15 @@ const TokenSchema = new Schema({ events: [TokenTransferEventSchema], }, { _id: false }) +export const Tokens = model("Tokens", TokenSchema); + export const TokensCollection = model('TokensCollection', new Schema({ contractAddress: String, tokenType: Number, name: String, owner: String, - tokens: [TokenSchema], + // tokens: [TokenSchema], })); From 07e57cf0b01c8af3581dee7ee60251977e0e2b36 Mon Sep 17 00:00:00 2001 From: kiwvic Date: Sun, 28 Nov 2021 22:31:08 +0200 Subject: [PATCH 02/14] apollo instead of express --- lib/api/api.ts | 30 +++++------------------------- lib/api/schema.ts | 10 +++++----- package.json | 1 + 3 files changed, 11 insertions(+), 30 deletions(-) diff --git a/lib/api/api.ts b/lib/api/api.ts index 72bb21e..17fd3f7 100644 --- a/lib/api/api.ts +++ b/lib/api/api.ts @@ -1,32 +1,12 @@ import { Marketplace } from "../marketplace"; -import express from 'express' -import bodyParser from 'body-parser' -import { OrderFront } from "../types/common"; -import { graphqlHTTP } from "express-graphql"; import { schema } from "./schema"; +import { ApolloServer} from "apollo-server"; export async function start(marketplace: Marketplace) { - - const app = express() - const jsonParser = bodyParser.json() - - app.use( - "/graphql", - graphqlHTTP({ - schema: schema(marketplace), - graphiql: true, - })); - - app.post('/orders', jsonParser, async (req: any, res: any) => res.json(await marketplace.createOrder(OrderFront.fromJson(req.body)))); - app.get('/orders', async (req: any, res: any) => res.json(await marketplace.getOrders())); - app.get('/orders/:orderId', async (req: any, res: any) => res.json(await marketplace.getOrder(req.params.orderId))); - app.get('/tokens', async (req: any, res: any) => res.json(await marketplace.getTokens())); - app.post('/asset/create', async (req: any, res: any) => res.set('Status Code', 202)); - - - console.log("starting") - app.listen(8080); - + const server = new ApolloServer({ schema: schema(marketplace) }) + server.listen({port: 8080}).then( + () => { console.log("ready at 8080") } + ).catch((err) => {console.log(err)}); } diff --git a/lib/api/schema.ts b/lib/api/schema.ts index 919a6ab..1ec0dfc 100644 --- a/lib/api/schema.ts +++ b/lib/api/schema.ts @@ -16,7 +16,6 @@ import {Marketplace} from "../marketplace"; export function schema(marketplace: Marketplace): GraphQLSchema { - const TokenOwnersType = new GraphQLScalarType({ name: "TokenOwners", serialize(val: any) { @@ -89,23 +88,24 @@ export function schema(marketplace: Marketplace): GraphQLSchema { fields: () => ({ tokensCollection: { type: new GraphQLList(TokensCollectionType), - resolve: () => { + resolve: async () => { return TokensCollection .find({tokenType: {$ne: null}}) .sort({'tokens.last_update': 1}); } }, + getTokensByOwner: { type: new GraphQLList(TokenType), args: {owner: {type: GraphQLString}}, - resolve: (_, args) => { + resolve: async (_, args) => { return Tokens.find({[`owners.${args.owner}`]: {$gt: 0}}); } }, orders: { type: new GraphQLList(OrderType), - resolve: () => { + resolve: async () => { return Order.find({}).sort({createTime: 1}) } }, @@ -116,7 +116,7 @@ export function schema(marketplace: Marketplace): GraphQLSchema { contractAddress: {type: GraphQLString}, tokenId: {type: GraphQLString}, }, - resolve: (_, args) => { + resolve: async (_, args) => { const {contractAddress, tokenId} = args const filter = {contractAddress, tokens: {tokenId}} return Order diff --git a/package.json b/package.json index c62ed49..1a2732c 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "@pinata/sdk": "^1.1.23", "@types/dotenv": "^8.2.0", "@types/mongoose": "^5.11.97", + "apollo-server": "^3.5.0", "dotenv": "^9.0.2", "ethereum-waffle": "^3.2.0", "ethers": "^5.5.1", From 26f413408b748c205b79cd903f22f14f61bf0bc1 Mon Sep 17 00:00:00 2001 From: kiwvic Date: Thu, 2 Dec 2021 20:46:29 +0200 Subject: [PATCH 03/14] redesign fake tokens gen --- lib/types/mongo.ts | 2 +- {test/utils => scripts}/gen_fake_tokens.ts | 44 ++++++++++++++-------- 2 files changed, 30 insertions(+), 16 deletions(-) rename {test/utils => scripts}/gen_fake_tokens.ts (54%) diff --git a/lib/types/mongo.ts b/lib/types/mongo.ts index 3c7c916..2899f68 100644 --- a/lib/types/mongo.ts +++ b/lib/types/mongo.ts @@ -37,7 +37,7 @@ const TokenSchema = new Schema({ last_update: Number, owners: { type: Map, of: Number }, events: [TokenTransferEventSchema], -}, { _id: false }) +}); export const Tokens = model("Tokens", TokenSchema); diff --git a/test/utils/gen_fake_tokens.ts b/scripts/gen_fake_tokens.ts similarity index 54% rename from test/utils/gen_fake_tokens.ts rename to scripts/gen_fake_tokens.ts index 1f8dc98..4bea70f 100644 --- a/test/utils/gen_fake_tokens.ts +++ b/scripts/gen_fake_tokens.ts @@ -1,32 +1,42 @@ -import {TokensCollection} from "../../lib/types/mongo"; +import {TokensCollection, Tokens} from "../lib/types/mongo"; import {ethers} from "ethers"; -import {zero} from "./utils"; -import {TokenType} from "../../lib/types/common"; +import {zero} from "../test/utils/utils"; +import {TokenType} from "../lib/types/common"; +import amongus from "mongoose"; +amongus.connect('mongodb://root:example@localhost:27017/admin'); -randomCollection() +generateFakeData(); -function randomCollection() { - const tokens = []; - for (let i=0; i<10; i++) - tokens.push(randomToken()) +function generateFakeData() { + let collectionObjId; new TokensCollection({ contractAddress: randomAddress(), tokenType: randomChoice([TokenType.ERC1155, TokenType.ERC721]), owner: randomAddress(), - tokens: [] - }).save().then((r:any) => console.log(r)); + }).save().then((r:any) => { + collectionObjId = r._id + const tokens = []; + for (let i=0; i<5; i++) + tokens.push(randomToken(collectionObjId)); + console.log(collectionObjId); + + tokens.forEach(value => { + new Tokens(value).save().then((r:any) => {}); + }); + }); } -function randomToken() { +function randomToken(collectionObjId: any) { const tokenId = randomFrom0To(1000).toString(); - const quantity = randomFrom0To(100) - const addr = randomAddress() + const quantity = randomFrom0To(100); + const addr = randomAddress(); return { + collectionObjectId: collectionObjId, tokenId: tokenId, metadata_uri: `http://localhost/${tokenId}`, metadata: @@ -55,11 +65,15 @@ function randomToken() { } } +function toHex(d: any) { + return ("0"+(Number(d).toString(16))).slice(-2).toUpperCase() +} function randomAddress() { - return "0x" + ethers.utils.keccak256(randomFrom0To(100000).toString()).toString().slice(0, 40) + let st = `0x${toHex(randomFrom0To(100000))}`; + return ethers.utils.keccak256(st).toString().slice(0, 40) } function randomHash() { - return "0x" + ethers.utils.keccak256(randomFrom0To(100000).toString()).toString().slice(0, 64) + return ethers.utils.keccak256(`0x${toHex(randomFrom0To(100000))}`).toString().slice(0, 64) } function randomChoice(items: any[]) { return items[randomFrom0To(items.length)]; From 6fc7e576f35de3d13c4fdae4f2b38262f83a4e19 Mon Sep 17 00:00:00 2001 From: kiwvic Date: Mon, 6 Dec 2021 23:32:39 +0200 Subject: [PATCH 04/14] add pagination --- lib/api/api.ts | 2 +- lib/api/pagination.ts | 41 ++++++++++++++++++++++ lib/api/schema.ts | 81 +++++++++++++++++++++++++++++++++++++------ 3 files changed, 113 insertions(+), 11 deletions(-) create mode 100644 lib/api/pagination.ts diff --git a/lib/api/api.ts b/lib/api/api.ts index 17fd3f7..64185e4 100644 --- a/lib/api/api.ts +++ b/lib/api/api.ts @@ -6,7 +6,7 @@ import { ApolloServer} from "apollo-server"; export async function start(marketplace: Marketplace) { const server = new ApolloServer({ schema: schema(marketplace) }) server.listen({port: 8080}).then( - () => { console.log("ready at 8080") } + () => { console.log("ready at 2289") } ).catch((err) => {console.log(err)}); } diff --git a/lib/api/pagination.ts b/lib/api/pagination.ts new file mode 100644 index 0000000..c66216e --- /dev/null +++ b/lib/api/pagination.ts @@ -0,0 +1,41 @@ +import { + GraphQLString, + GraphQLInt, + GraphQLBoolean, + GraphQLObjectType, + GraphQLList +} from "graphql" + + +const Edge = (itemType: any) => { + return new GraphQLObjectType({ + name: 'EdgeType', + fields: () => ({ + node: { type: itemType }, + cursor: { type: GraphQLString } + }) + }) +} + + +const PageInfo = new GraphQLObjectType({ + name: 'PageInfoType', + fields: () => ({ + startCursor: { type: GraphQLString }, + endCursor: { type: GraphQLString }, + hasNextPage: { type: GraphQLBoolean } + }) +}) + + +export const Page = (itemType: any) => { + return new GraphQLObjectType({ + name: 'PageType', + fields: () => ({ + totalCount: { type: GraphQLInt }, + edges: { type: new GraphQLList(Edge(itemType)) }, + pageInfo: { type: PageInfo } + }) + }) +} + diff --git a/lib/api/schema.ts b/lib/api/schema.ts index 1ec0dfc..26ee5c5 100644 --- a/lib/api/schema.ts +++ b/lib/api/schema.ts @@ -9,9 +9,13 @@ import { GraphQLString } from "graphql"; +import {Page} from "./pagination" + import {Order, TokensCollection, Tokens} from "../types/mongo"; import {OrderFront} from "../types/common"; import {Marketplace} from "../marketplace"; +// import {util} from "prettier"; +// import skip = util.skip; export function schema(marketplace: Marketplace): GraphQLSchema { @@ -90,16 +94,73 @@ export function schema(marketplace: Marketplace): GraphQLSchema { type: new GraphQLList(TokensCollectionType), resolve: async () => { return TokensCollection - .find({tokenType: {$ne: null}}) - .sort({'tokens.last_update': 1}); + .find({tokenType: {$ne: null}}) + .sort({'tokens.last_update': 1}); } }, + // getTokensByOwner: { + // type: new GraphQLList(TokenType), + // args: { + // owner: {type: GraphQLString}, + // limit: {type: GraphQLInt}, + // after: {type: GraphQLInt} // is a unix time + // }, + // resolve: async (_, args) => { + // // return Tokens.find({[`owners.${args.owner}`]: {$gt: 0}}); + // + // // return Tokens + // // .find({last_update: {$lte: args.after}, [`owners.${args.owner}`]: {$gt: 0}}) + // // .sort({last_update: -1}) + // // .limit(args.limit) + // + // + // } + // }, + getTokensByOwner: { - type: new GraphQLList(TokenType), - args: {owner: {type: GraphQLString}}, + type: Page(TokenType), + args: { + owner: {type: GraphQLString}, + first: {type: GraphQLInt}, + afterCursor: {type: GraphQLInt } // is a unix time + }, resolve: async (_, args) => { - return Tokens.find({[`owners.${args.owner}`]: {$gt: 0}}); + let afterIndex = 0; + return Tokens + .find({last_update: {$lte: args.afterCursor}, [`owners.${args.owner}`]: {$gt: 0}}) + .limit(args.first) + .then((res) => { + if (typeof args.afterCursor === "number") { + let nodeId = args.afterCursor; + let nodeIndex = res.findIndex(data => data.last_update === nodeId) + if (nodeIndex >= 0) { + afterIndex = nodeIndex + 1; + } + } + + const edges = res.map(node => ({ + node, + cursor: node.last_update + })); + + let startCursor, endCursor = null; + if (edges.length > 0) { + startCursor = edges[0].node.last_update; + endCursor = edges[edges.length - 1].node.last_update; + } + let hasNextPage = res.length > afterIndex + args.first; + + return { + totalCount: res.length, + edges, + pageInfo: { + startCursor, + endCursor, + hasNextPage + } + } + }) } }, @@ -120,11 +181,11 @@ export function schema(marketplace: Marketplace): GraphQLSchema { const {contractAddress, tokenId} = args const filter = {contractAddress, tokens: {tokenId}} return Order - .find({$or: [ - {left: {filter}}, - {right: {filter}}, - ]}) - .sort({createTime: 1}) + .find({$or: [ + {left: {filter}}, + {right: {filter}}, + ]}) + .sort({createTime: 1}) } }, From 978fad7841ecd54271fa41d79df8353642646f8d Mon Sep 17 00:00:00 2001 From: kiwvic Date: Mon, 6 Dec 2021 23:46:42 +0200 Subject: [PATCH 05/14] lil pagination fix --- lib/api/schema.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/api/schema.ts b/lib/api/schema.ts index 26ee5c5..4177f2d 100644 --- a/lib/api/schema.ts +++ b/lib/api/schema.ts @@ -129,6 +129,7 @@ export function schema(marketplace: Marketplace): GraphQLSchema { let afterIndex = 0; return Tokens .find({last_update: {$lte: args.afterCursor}, [`owners.${args.owner}`]: {$gt: 0}}) + .sort( {last_update: -1 }) .limit(args.first) .then((res) => { if (typeof args.afterCursor === "number") { From e3430c9c89ac60a83ec4b4548a167906f6de3320 Mon Sep 17 00:00:00 2001 From: kiwvic Date: Wed, 8 Dec 2021 18:54:27 +0200 Subject: [PATCH 06/14] swap to another cursor pagination lib --- lib/api/pagination.ts | 41 --------------------- lib/api/schema.ts | 85 ++++++++++++++----------------------------- lib/types/mongo.ts | 5 +-- package.json | 1 + 4 files changed, 30 insertions(+), 102 deletions(-) delete mode 100644 lib/api/pagination.ts diff --git a/lib/api/pagination.ts b/lib/api/pagination.ts deleted file mode 100644 index c66216e..0000000 --- a/lib/api/pagination.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { - GraphQLString, - GraphQLInt, - GraphQLBoolean, - GraphQLObjectType, - GraphQLList -} from "graphql" - - -const Edge = (itemType: any) => { - return new GraphQLObjectType({ - name: 'EdgeType', - fields: () => ({ - node: { type: itemType }, - cursor: { type: GraphQLString } - }) - }) -} - - -const PageInfo = new GraphQLObjectType({ - name: 'PageInfoType', - fields: () => ({ - startCursor: { type: GraphQLString }, - endCursor: { type: GraphQLString }, - hasNextPage: { type: GraphQLBoolean } - }) -}) - - -export const Page = (itemType: any) => { - return new GraphQLObjectType({ - name: 'PageType', - fields: () => ({ - totalCount: { type: GraphQLInt }, - edges: { type: new GraphQLList(Edge(itemType)) }, - pageInfo: { type: PageInfo } - }) - }) -} - diff --git a/lib/api/schema.ts b/lib/api/schema.ts index 4177f2d..b661f34 100644 --- a/lib/api/schema.ts +++ b/lib/api/schema.ts @@ -9,8 +9,6 @@ import { GraphQLString } from "graphql"; -import {Page} from "./pagination" - import {Order, TokensCollection, Tokens} from "../types/mongo"; import {OrderFront} from "../types/common"; import {Marketplace} from "../marketplace"; @@ -54,13 +52,32 @@ export function schema(marketplace: Marketplace): GraphQLSchema { }); + const PageInfoType = new GraphQLObjectType({ + name: "PageInfo", + fields: () => ({ + hasNext: {type: GraphQLBoolean}, + nextCursor: {type: GraphQLString} + }) + }); + + + const Page = (itemType: any) => { + return new GraphQLObjectType({ + name: "Page", + fields: () => ({ + results: {type: new GraphQLList(itemType)}, + pageInfo: {type: PageInfoType} + }) + }); + } + + const TokensCollectionType = new GraphQLObjectType({ name: "TokensCollection", fields: () => ({ contractAddress: {type: GraphQLString}, tokenType: {type: GraphQLInt}, owner: {type: GraphQLString}, - // tokens: {type: new GraphQLList(TokenType),} }) }); @@ -99,69 +116,21 @@ export function schema(marketplace: Marketplace): GraphQLSchema { } }, - // getTokensByOwner: { - // type: new GraphQLList(TokenType), - // args: { - // owner: {type: GraphQLString}, - // limit: {type: GraphQLInt}, - // after: {type: GraphQLInt} // is a unix time - // }, - // resolve: async (_, args) => { - // // return Tokens.find({[`owners.${args.owner}`]: {$gt: 0}}); - // - // // return Tokens - // // .find({last_update: {$lte: args.after}, [`owners.${args.owner}`]: {$gt: 0}}) - // // .sort({last_update: -1}) - // // .limit(args.limit) - // - // - // } - // }, - getTokensByOwner: { type: Page(TokenType), args: { owner: {type: GraphQLString}, first: {type: GraphQLInt}, - afterCursor: {type: GraphQLInt } // is a unix time + cursor: {type: GraphQLString } }, resolve: async (_, args) => { - let afterIndex = 0; + args.cursor = args.cursor === null ? undefined : args.cursor; + return Tokens - .find({last_update: {$lte: args.afterCursor}, [`owners.${args.owner}`]: {$gt: 0}}) - .sort( {last_update: -1 }) - .limit(args.first) - .then((res) => { - if (typeof args.afterCursor === "number") { - let nodeId = args.afterCursor; - let nodeIndex = res.findIndex(data => data.last_update === nodeId) - if (nodeIndex >= 0) { - afterIndex = nodeIndex + 1; - } - } - - const edges = res.map(node => ({ - node, - cursor: node.last_update - })); - - let startCursor, endCursor = null; - if (edges.length > 0) { - startCursor = edges[0].node.last_update; - endCursor = edges[edges.length - 1].node.last_update; - } - let hasNextPage = res.length > afterIndex + args.first; - - return { - totalCount: res.length, - edges, - pageInfo: { - startCursor, - endCursor, - hasNextPage - } - } - }) + .find({[`owners.${args.owner}`]: {$gt: 0}}) + .sort({last_update: -1}) + .limit(args.first) + .paginate(args.cursor) // If IDE lights this as error - all ok } }, diff --git a/lib/types/mongo.ts b/lib/types/mongo.ts index 2899f68..23bcf35 100644 --- a/lib/types/mongo.ts +++ b/lib/types/mongo.ts @@ -1,4 +1,5 @@ import { model, Schema } from 'mongoose'; +const paginationPlugin = require('@mother/mongoose-cursor-pagination') // todo https://mongoosejs.com/docs/typescript.html @@ -37,7 +38,7 @@ const TokenSchema = new Schema({ last_update: Number, owners: { type: Map, of: Number }, events: [TokenTransferEventSchema], -}); +}).plugin(paginationPlugin); export const Tokens = model("Tokens", TokenSchema); @@ -46,8 +47,6 @@ export const TokensCollection = model('TokensCollection', new Schema({ tokenType: Number, name: String, owner: String, - - // tokens: [TokenSchema], })); diff --git a/package.json b/package.json index 1a2732c..140c6c8 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ }, "dependencies": { "@gnosis.pm/safe-deployments": "^1.1.0", + "@mother/mongoose-cursor-pagination": "^0.0.5", "@nomiclabs/hardhat-ethers": "npm:hardhat-deploy-ethers", "@nomiclabs/hardhat-waffle": "^2.0.1", "@openzeppelin/contracts": "^4.1.0", From 66b65e1a161a78f85e4d4470d32b39fa7b30763e Mon Sep 17 00:00:00 2001 From: kiwvic Date: Wed, 8 Dec 2021 18:56:11 +0200 Subject: [PATCH 07/14] little fix --- lib/api/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/api.ts b/lib/api/api.ts index 64185e4..17fd3f7 100644 --- a/lib/api/api.ts +++ b/lib/api/api.ts @@ -6,7 +6,7 @@ import { ApolloServer} from "apollo-server"; export async function start(marketplace: Marketplace) { const server = new ApolloServer({ schema: schema(marketplace) }) server.listen({port: 8080}).then( - () => { console.log("ready at 2289") } + () => { console.log("ready at 8080") } ).catch((err) => {console.log(err)}); } From 51a0d1e3c23b4867da9605ea85c1ba8513df6f7f Mon Sep 17 00:00:00 2001 From: kiwvic Date: Wed, 8 Dec 2021 19:28:46 +0200 Subject: [PATCH 08/14] add getTokens --- lib/api/schema.ts | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/lib/api/schema.ts b/lib/api/schema.ts index b661f34..d8fef11 100644 --- a/lib/api/schema.ts +++ b/lib/api/schema.ts @@ -61,9 +61,9 @@ export function schema(marketplace: Marketplace): GraphQLSchema { }); - const Page = (itemType: any) => { + const Page = (itemType: any, pageName: any) => { return new GraphQLObjectType({ - name: "Page", + name: pageName, fields: () => ({ results: {type: new GraphQLList(itemType)}, pageInfo: {type: PageInfoType} @@ -116,8 +116,25 @@ export function schema(marketplace: Marketplace): GraphQLSchema { } }, + getTokens: { + type: Page(TokenType, "AllTokensPage"), + args: { + first: {type: GraphQLInt}, + cursor: {type: GraphQLString } + }, + resolve: async (_, args) => { + args.cursor = args.cursor === null ? undefined : args.cursor; + + return Tokens + .find({}) + .sort({last_update: -1}) + .limit(args.first) + .paginate(args.cursor) // If IDE lights this as error - all ok + } + }, + getTokensByOwner: { - type: Page(TokenType), + type: Page(TokenType, "TokensByOwnerPage"), args: { owner: {type: GraphQLString}, first: {type: GraphQLInt}, From c9f0f3633c3e6074c59687c8316a540a65de2aad Mon Sep 17 00:00:00 2001 From: kiwvic Date: Wed, 8 Dec 2021 19:35:33 +0200 Subject: [PATCH 09/14] add EventType --- lib/api/schema.ts | 50 ++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/lib/api/schema.ts b/lib/api/schema.ts index d8fef11..643f00d 100644 --- a/lib/api/schema.ts +++ b/lib/api/schema.ts @@ -17,6 +17,25 @@ import {Marketplace} from "../marketplace"; export function schema(marketplace: Marketplace): GraphQLSchema { + const PageInfoType = new GraphQLObjectType({ + name: "PageInfo", + fields: () => ({ + hasNext: {type: GraphQLBoolean}, + nextCursor: {type: GraphQLString} + }) + }); + + + const Page = (itemType: any, pageName: any) => { + return new GraphQLObjectType({ + name: pageName, + fields: () => ({ + results: {type: new GraphQLList(itemType)}, + pageInfo: {type: PageInfoType} + }) + }); + } + const TokenOwnersType = new GraphQLScalarType({ name: "TokenOwners", @@ -38,6 +57,16 @@ export function schema(marketplace: Marketplace): GraphQLSchema { }) }); + const EventType = new GraphQLObjectType({ + name: "Event", + fields: () => ({ + from: {type: GraphQLString}, + to: {type: GraphQLString}, + quantity: {type: GraphQLInt}, + timestamp: {type: GraphQLInt}, + txHash: {type: GraphQLString}, + }) + }); const TokenType = new GraphQLObjectType({ name: "Token", @@ -48,30 +77,11 @@ export function schema(marketplace: Marketplace): GraphQLSchema { metadata: {type: MetadataType}, last_update: {type: GraphQLInt}, owners: {type: TokenOwnersType}, + events: {type: new GraphQLList(EventType)} }) }); - const PageInfoType = new GraphQLObjectType({ - name: "PageInfo", - fields: () => ({ - hasNext: {type: GraphQLBoolean}, - nextCursor: {type: GraphQLString} - }) - }); - - - const Page = (itemType: any, pageName: any) => { - return new GraphQLObjectType({ - name: pageName, - fields: () => ({ - results: {type: new GraphQLList(itemType)}, - pageInfo: {type: PageInfoType} - }) - }); - } - - const TokensCollectionType = new GraphQLObjectType({ name: "TokensCollection", fields: () => ({ From 9483b9094a0a4b44f2225b712c4df1bbd3acb65d Mon Sep 17 00:00:00 2001 From: kiwvic Date: Wed, 8 Dec 2021 20:39:28 +0200 Subject: [PATCH 10/14] gen_fake_tokens little changes --- lib/api/schema.ts | 4 ++-- package.json | 1 + scripts/gen_fake_tokens.ts | 19 +++++++++---------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/api/schema.ts b/lib/api/schema.ts index 643f00d..03f6c4f 100644 --- a/lib/api/schema.ts +++ b/lib/api/schema.ts @@ -139,7 +139,7 @@ export function schema(marketplace: Marketplace): GraphQLSchema { .find({}) .sort({last_update: -1}) .limit(args.first) - .paginate(args.cursor) // If IDE lights this as error - all ok + .paginate(args.cursor) // noinspection } }, @@ -157,7 +157,7 @@ export function schema(marketplace: Marketplace): GraphQLSchema { .find({[`owners.${args.owner}`]: {$gt: 0}}) .sort({last_update: -1}) .limit(args.first) - .paginate(args.cursor) // If IDE lights this as error - all ok + .paginate(args.cursor) // noinspection } }, diff --git a/package.json b/package.json index 140c6c8..c0fb8ab 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "private": false, "scripts": { "api": "ts-node ./lib/main.ts", + "gen fake data": "ts-node ./scripts/gen_fake_tokens.ts", "build": "hardhat compile", "deploy": "hardhat deploy --network rinkeby", "verify": "hardhat etherscan-verify --network rinkeby", diff --git a/scripts/gen_fake_tokens.ts b/scripts/gen_fake_tokens.ts index 4bea70f..513c56a 100644 --- a/scripts/gen_fake_tokens.ts +++ b/scripts/gen_fake_tokens.ts @@ -7,10 +7,10 @@ import amongus from "mongoose"; amongus.connect('mongodb://root:example@localhost:27017/admin'); -generateFakeData(); +generateFakeData(2); -function generateFakeData() { +function generateFakeData(tokensAmount: number) { let collectionObjId; new TokensCollection({ contractAddress: randomAddress(), @@ -19,12 +19,12 @@ function generateFakeData() { }).save().then((r:any) => { collectionObjId = r._id const tokens = []; - for (let i=0; i<5; i++) + for (let i=0; i { - new Tokens(value).save().then((r:any) => {}); + new Tokens(value).save(); }); }); } @@ -65,19 +65,18 @@ function randomToken(collectionObjId: any) { } } -function toHex(d: any) { - return ("0"+(Number(d).toString(16))).slice(-2).toUpperCase() -} function randomAddress() { - let st = `0x${toHex(randomFrom0To(100000))}`; - return ethers.utils.keccak256(st).toString().slice(0, 40) + return randomHash().slice(0, 42) } + function randomHash() { - return ethers.utils.keccak256(`0x${toHex(randomFrom0To(100000))}`).toString().slice(0, 64) + return ethers.utils.hashMessage(randomFrom0To(100000).toString()) } + function randomChoice(items: any[]) { return items[randomFrom0To(items.length)]; } + function randomFrom0To(value: number) { return Math.floor(Math.random() * value) } From 5266961e7631470d9e11256a423f3013314732c4 Mon Sep 17 00:00:00 2001 From: kiwvic Date: Wed, 8 Dec 2021 20:45:41 +0200 Subject: [PATCH 11/14] 0x000... to ethers.constants.AddressZero --- lib/event_logger.ts | 2 +- test/utils/utils.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/event_logger.ts b/lib/event_logger.ts index b695b78..835dbb5 100644 --- a/lib/event_logger.ts +++ b/lib/event_logger.ts @@ -13,7 +13,7 @@ const interfaceId: { [key in TokenType]?: string } = { [TokenType.ERC721]: "0x80ac58cd", } -const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000" +const ZERO_ADDRESS = ethers.constants.AddressZero; const IPFS_GATEWAYS = [ "https://gateway.pinata.cloud/ipfs/", "https://cloudflare-ipfs.com/ipfs/", diff --git a/test/utils/utils.ts b/test/utils/utils.ts index 8eac21a..5b64dfe 100644 --- a/test/utils/utils.ts +++ b/test/utils/utils.ts @@ -1,5 +1,6 @@ import chai from "chai"; import chaiAsPromised from "chai-as-promised"; +import {constants} from "ethers"; chai.should(); @@ -7,7 +8,7 @@ chai.use(chaiAsPromised); export const expect = chai.expect; -export const zero = "0x0000000000000000000000000000000000000000" +export const zero = constants.AddressZero; export const endtime = (d: number) => { From 3f0a86d7dac0d51a4b638ccb2534a1b4a9473bef Mon Sep 17 00:00:00 2001 From: kiwvic Date: Thu, 9 Dec 2021 11:49:22 +0200 Subject: [PATCH 12/14] add uploadFile (def only), apollo-server-express --- lib/api/api.ts | 4 +++- lib/api/schema.ts | 16 ++++++++++++++++ package.json | 1 + 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/api/api.ts b/lib/api/api.ts index 17fd3f7..b2789db 100644 --- a/lib/api/api.ts +++ b/lib/api/api.ts @@ -1,6 +1,8 @@ import { Marketplace } from "../marketplace"; import { schema } from "./schema"; -import { ApolloServer} from "apollo-server"; +// import { ApolloServer} from "apollo-server"; +const ApolloServer = require('apollo-server-express'); +const express = require("express") export async function start(marketplace: Marketplace) { diff --git a/lib/api/schema.ts b/lib/api/schema.ts index 03f6c4f..6197b72 100644 --- a/lib/api/schema.ts +++ b/lib/api/schema.ts @@ -12,6 +12,9 @@ import { import {Order, TokensCollection, Tokens} from "../types/mongo"; import {OrderFront} from "../types/common"; import {Marketplace} from "../marketplace"; + +const GraphQLUpload = require("graphql-upload") + // import {util} from "prettier"; // import skip = util.skip; @@ -201,6 +204,19 @@ export function schema(marketplace: Marketplace): GraphQLSchema { const orderJson = JSON.parse(args.order); const order = OrderFront.fromJson(orderJson) await marketplace.createOrder(order); + return true; + } + }, + + uploadFile: { + type: GraphQLBoolean, + args: {file: {type: GraphQLUpload}}, + resolve: async (_, args) => { + const { createReadStream, filename, mimetype, encoding } = await args.file; + const stream = createReadStream(); + + // Do magic + return true; } } diff --git a/package.json b/package.json index c0fb8ab..8b08b39 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "ethers": "^5.5.1", "express-graphql": "^0.12.0", "graphql": "^16.0.1", + "graphql-upload": "^13.0.0", "hardhat": "^2.3.3", "hardhat-deploy": "^0.8.11", "hardhat-deploy-ethers": "0.3.0-beta.10", From 28816c2b8a7385194d7bd7f5c135b1dec3bdb7c9 Mon Sep 17 00:00:00 2001 From: kiwvic Date: Thu, 9 Dec 2021 17:39:17 +0200 Subject: [PATCH 13/14] add uploadFile, apollo-server-express --- lib/api/api.ts | 17 +++++++++-------- lib/api/schema.ts | 18 +++++++++++++----- package.json | 1 + 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/lib/api/api.ts b/lib/api/api.ts index b2789db..08828b4 100644 --- a/lib/api/api.ts +++ b/lib/api/api.ts @@ -1,14 +1,15 @@ import { Marketplace } from "../marketplace"; import { schema } from "./schema"; // import { ApolloServer} from "apollo-server"; -const ApolloServer = require('apollo-server-express'); -const express = require("express") - +import express from "express"; +import { ApolloServer } from 'apollo-server-express'; +const {graphqlUploadExpress} = require("graphql-upload"); export async function start(marketplace: Marketplace) { - const server = new ApolloServer({ schema: schema(marketplace) }) - server.listen({port: 8080}).then( - () => { console.log("ready at 8080") } - ).catch((err) => {console.log(err)}); + const app = express(); + app.use(graphqlUploadExpress()); + const server = new ApolloServer({schema: schema(marketplace)}); + await server.start(); + server.applyMiddleware({ app }); + await new Promise(resolve => app.listen({ port: 8080 }, resolve)); } - diff --git a/lib/api/schema.ts b/lib/api/schema.ts index 6197b72..b9332bd 100644 --- a/lib/api/schema.ts +++ b/lib/api/schema.ts @@ -13,13 +13,23 @@ import {Order, TokensCollection, Tokens} from "../types/mongo"; import {OrderFront} from "../types/common"; import {Marketplace} from "../marketplace"; -const GraphQLUpload = require("graphql-upload") +const {GraphQLUpload} = require("graphql-upload"); // import {util} from "prettier"; // import skip = util.skip; export function schema(marketplace: Marketplace): GraphQLSchema { + // const FileType = new GraphQLObjectType({ + // name: "FileType", + // fields: () => ({ + // filename: {type: GraphQLString}, + // mimetype: {type: GraphQLString}, + // encoding: {type: GraphQLString} + // }) + // }); + + const PageInfoType = new GraphQLObjectType({ name: "PageInfo", fields: () => ({ @@ -213,10 +223,8 @@ export function schema(marketplace: Marketplace): GraphQLSchema { args: {file: {type: GraphQLUpload}}, resolve: async (_, args) => { const { createReadStream, filename, mimetype, encoding } = await args.file; - const stream = createReadStream(); - - // Do magic - + let stream = createReadStream(); + // stream.on("readable", () => {console.log(stream.read())}); return true; } } diff --git a/package.json b/package.json index 8b08b39..204a036 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "@types/dotenv": "^8.2.0", "@types/mongoose": "^5.11.97", "apollo-server": "^3.5.0", + "apollo-server-express": "^3.0.0-rc.1", "dotenv": "^9.0.2", "ethereum-waffle": "^3.2.0", "ethers": "^5.5.1", From 60043383fba071069ceb043b12b4a915c03aa697 Mon Sep 17 00:00:00 2001 From: kiwvic Date: Wed, 22 Dec 2021 19:18:28 +0200 Subject: [PATCH 14/14] add getSpecificToken --- lib/api/schema.ts | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lib/api/schema.ts b/lib/api/schema.ts index b9332bd..572a4dd 100644 --- a/lib/api/schema.ts +++ b/lib/api/schema.ts @@ -148,6 +148,7 @@ export function schema(marketplace: Marketplace): GraphQLSchema { resolve: async (_, args) => { args.cursor = args.cursor === null ? undefined : args.cursor; + // @ts-ignore return Tokens .find({}) .sort({last_update: -1}) @@ -166,6 +167,7 @@ export function schema(marketplace: Marketplace): GraphQLSchema { resolve: async (_, args) => { args.cursor = args.cursor === null ? undefined : args.cursor; + // @ts-ignore return Tokens .find({[`owners.${args.owner}`]: {$gt: 0}}) .sort({last_update: -1}) @@ -174,6 +176,31 @@ export function schema(marketplace: Marketplace): GraphQLSchema { } }, + getSpecificToken: { + type: Page(TokenType, "SpecificTokens"), + args: { + tokenId: {type: GraphQLString}, + metadataName: {type: GraphQLString}, + owner: {type: GraphQLString}, + first: {type: GraphQLInt}, + cursor: {type: GraphQLString } + }, + resolve: async (_, args) => { + args.cursor = args.cursor === null ? undefined : args.cursor; + + // @ts-ignore + return Tokens + .find({$or: [ + {[`owners.${args.owner}`]: {$gt: 0}}, + {"metadata.name": args.metadataName}, + {"tokenId": args.tokendId}, + ]}) + .sort({last_update: -1}) + .limit(args.first) + .paginate(args.cursor) // noinspection + } + }, + orders: { type: new GraphQLList(OrderType), resolve: async () => {