From 7c8a076b9d69a6eb7bedb3fa70198f77be1f55b0 Mon Sep 17 00:00:00 2001 From: alresarena2021 Date: Fri, 11 Feb 2022 21:59:53 +0800 Subject: [PATCH 1/7] feat: revamp api service --- token-gating/api/library/object-id.ts | 1 + token-gating/api/package-lock.json | 1307 ++++++++++++++++- token-gating/api/package.json | 4 + .../account/controllers/holder-account.ts | 56 + token-gating/api/services/account/index.ts | 3 + .../account/repositories/holder-account.ts | 52 + token-gating/api/services/account/types.ts | 2 + token-gating/api/services/api/index.ts | 5 + .../api/services/api/loaders/index.ts | 7 + .../api/resolvers/authentication/mutation.ts | 98 ++ .../api/resolvers/project/mutation.ts | 31 +- .../services/api/type-defs/authentication.ts | 42 +- .../api/services/api/type-defs/project.ts | 6 +- token-gating/api/services/api/types.ts | 7 +- .../services/project/controllers/project.ts | 2 +- .../services/project/repositories/project.ts | 8 +- .../api/services/worker/inversify.config.ts | 6 +- .../worker/src/controllers/collection.ts | 58 + .../worker/src/controllers/ownership.ts | 61 + token-gating/api/services/worker/src/index.ts | 25 +- .../services/worker/src/inversify.config.ts | 6 +- .../worker/src/repositories/collection.ts | 4 +- .../worker/src/repositories/ownership.ts | 2 +- token-gating/api/services/worker/src/types.ts | 2 + .../tests/helpers/generate-ownership.ts | 2 +- .../worker/tests/worker-service-test.spec.ts | 2 +- token-gating/api/types/holder-account.ts | 7 + token-gating/api/types/index.ts | 1 + token-gating/api/types/project.ts | 1 + 29 files changed, 1741 insertions(+), 67 deletions(-) create mode 100644 token-gating/api/services/account/controllers/holder-account.ts create mode 100644 token-gating/api/services/account/repositories/holder-account.ts create mode 100644 token-gating/api/services/worker/src/controllers/collection.ts create mode 100644 token-gating/api/services/worker/src/controllers/ownership.ts create mode 100644 token-gating/api/types/holder-account.ts diff --git a/token-gating/api/library/object-id.ts b/token-gating/api/library/object-id.ts index 49571da9..7ef96fd7 100644 --- a/token-gating/api/library/object-id.ts +++ b/token-gating/api/library/object-id.ts @@ -7,6 +7,7 @@ export enum ObjectType { OWNERSHIP = 1, ADMIN = 2, PROJECT = 3, + HOLDER = 4, } export default class ObjectId { diff --git a/token-gating/api/package-lock.json b/token-gating/api/package-lock.json index b2498f20..194c177c 100644 --- a/token-gating/api/package-lock.json +++ b/token-gating/api/package-lock.json @@ -13,6 +13,7 @@ "@graphql-tools/load-files": "^6.5.3", "@graphql-tools/merge": "^8.2.1", "@graphql-tools/schema": "^8.3.1", + "@highoutput/async-group": "^0.4.1", "@highoutput/delay": "^0.2.8", "@highoutput/hash": "^0.1.11", "@highoutput/logger": "^0.5.4", @@ -47,6 +48,7 @@ "eslint-plugin-prettier": "^3.4.0", "eslint-plugin-react": "^7.24.0", "eslint-plugin-react-hooks": "^4.2.0", + "ethers": "^5.5.4", "faker": "^5.5.3", "google-auth-library": "^7.11.0", "graphql-scalars": "^1.14.1", @@ -56,6 +58,7 @@ "koa": "^2.13.4", "koa-bodyparser": "^4.3.0", "lru-cache": "^7.3.0", + "luxon": "^2.3.0", "mongodb": "^4.2.2", "mongodb-memory-server": "^8.0.4", "mongoose": "^6.2.1", @@ -86,6 +89,7 @@ "@types/koa": "^2.13.4", "@types/koa-bodyparser": "^4.3.5", "@types/lru-cache": "^5.1.1", + "@types/luxon": "^2.0.9", "@types/mongodb": "^4.0.7", "@types/ms": "^0.7.31", "@types/node-cron": "^3.0.1", @@ -971,6 +975,705 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/@ethersproject/abi": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.5.0.tgz", + "integrity": "sha512-loW7I4AohP5KycATvc0MgujU6JyCHPqHdeoo9z3Nr9xEiNioxa65ccdm1+fsoJhkuhdRtfcL8cfyGamz2AxZ5w==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/address": "^5.5.0", + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/constants": "^5.5.0", + "@ethersproject/hash": "^5.5.0", + "@ethersproject/keccak256": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/strings": "^5.5.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.5.1.tgz", + "integrity": "sha512-m+MA/ful6eKbxpr99xUYeRvLkfnlqzrF8SZ46d/xFB1A7ZVknYc/sXJG0RcufF52Qn2jeFj1hhcoQ7IXjNKUqg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/networks": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/transactions": "^5.5.0", + "@ethersproject/web": "^5.5.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.5.0.tgz", + "integrity": "sha512-lj//7r250MXVLKI7sVarXAbZXbv9P50lgmJQGr2/is82EwEb8r7HrxsmMqAjTsztMYy7ohrIhGMIml+Gx4D3mA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.5.0", + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/properties": "^5.5.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.5.0.tgz", + "integrity": "sha512-l4Nj0eWlTUh6ro5IbPTgbpT4wRbdH5l8CQf7icF7sb/SI3Nhd9Y9HzhonTSTi6CefI0necIw7LJqQPopPLZyWw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/keccak256": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/rlp": "^5.5.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.5.0.tgz", + "integrity": "sha512-tdayUKhU1ljrlHzEWbStXazDpsx4eg1dBXUSI6+mHlYklOXoXF6lZvw8tnD6oVaWfnMxAgRSKROg3cVKtCcppA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.5.0" + } + }, + "node_modules/@ethersproject/basex": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.5.0.tgz", + "integrity": "sha512-ZIodwhHpVJ0Y3hUCfUucmxKsWQA5TMnavp5j/UOuDdzZWzJlRmuOjcTMIGgHCYuZmHt36BfiSyQPSRskPxbfaQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/properties": "^5.5.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.5.0.tgz", + "integrity": "sha512-6Xytlwvy6Rn3U3gKEc1vP7nR92frHkv6wtVr95LFR3jREXiCPzdWxKQ1cx4JGQBXxcguAwjA8murlYN2TSiEbg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "bn.js": "^4.11.9" + } + }, + "node_modules/@ethersproject/bignumber/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/@ethersproject/bytes": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.5.0.tgz", + "integrity": "sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.5.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.5.0.tgz", + "integrity": "sha512-2MsRRVChkvMWR+GyMGY4N1sAX9Mt3J9KykCsgUFd/1mwS0UH1qw+Bv9k1UJb3X3YJYFco9H20pjSlOIfCG5HYQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.5.0" + } + }, + "node_modules/@ethersproject/contracts": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.5.0.tgz", + "integrity": "sha512-2viY7NzyvJkh+Ug17v7g3/IJC8HqZBDcOjYARZLdzRxrfGlRgmYgl6xPRKVbEzy1dWKw/iv7chDcS83pg6cLxg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abi": "^5.5.0", + "@ethersproject/abstract-provider": "^5.5.0", + "@ethersproject/abstract-signer": "^5.5.0", + "@ethersproject/address": "^5.5.0", + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/constants": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/transactions": "^5.5.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.5.0.tgz", + "integrity": "sha512-dnGVpK1WtBjmnp3mUT0PlU2MpapnwWI0PibldQEq1408tQBAbZpPidkWoVVuNMOl/lISO3+4hXZWCL3YV7qzfg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.5.0", + "@ethersproject/address": "^5.5.0", + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/keccak256": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/strings": "^5.5.0" + } + }, + "node_modules/@ethersproject/hdnode": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.5.0.tgz", + "integrity": "sha512-mcSOo9zeUg1L0CoJH7zmxwUG5ggQHU1UrRf8jyTYy6HxdZV+r0PBoL1bxr+JHIPXRzS6u/UW4mEn43y0tmyF8Q==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.5.0", + "@ethersproject/basex": "^5.5.0", + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/pbkdf2": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/sha2": "^5.5.0", + "@ethersproject/signing-key": "^5.5.0", + "@ethersproject/strings": "^5.5.0", + "@ethersproject/transactions": "^5.5.0", + "@ethersproject/wordlists": "^5.5.0" + } + }, + "node_modules/@ethersproject/json-wallets": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.5.0.tgz", + "integrity": "sha512-9lA21XQnCdcS72xlBn1jfQdj2A1VUxZzOzi9UkNdnokNKke/9Ya2xA9aIK1SC3PQyBDLt4C+dfps7ULpkvKikQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.5.0", + "@ethersproject/address": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/hdnode": "^5.5.0", + "@ethersproject/keccak256": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/pbkdf2": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/random": "^5.5.0", + "@ethersproject/strings": "^5.5.0", + "@ethersproject/transactions": "^5.5.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.5.0.tgz", + "integrity": "sha512-5VoFCTjo2rYbBe1l2f4mccaRFN/4VQEYFwwn04aJV2h7qf4ZvI2wFxUE1XOX+snbwCLRzIeikOqtAoPwMza9kg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.5.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.5.0.tgz", + "integrity": "sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ] + }, + "node_modules/@ethersproject/networks": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.5.2.tgz", + "integrity": "sha512-NEqPxbGBfy6O3x4ZTISb90SjEDkWYDUbEeIFhJly0F7sZjoQMnj5KYzMSkMkLKZ+1fGpx00EDpHQCy6PrDupkQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.5.0" + } + }, + "node_modules/@ethersproject/pbkdf2": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.5.0.tgz", + "integrity": "sha512-SaDvQFvXPnz1QGpzr6/HToLifftSXGoXrbpZ6BvoZhmx4bNLHrxDe8MZisuecyOziP1aVEwzC2Hasj+86TgWVg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/sha2": "^5.5.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.5.0.tgz", + "integrity": "sha512-l3zRQg3JkD8EL3CPjNK5g7kMx4qSwiR60/uk5IVjd3oq1MZR5qUg40CNOoEJoX5wc3DyY5bt9EbMk86C7x0DNA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.5.0" + } + }, + "node_modules/@ethersproject/providers": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.5.3.tgz", + "integrity": "sha512-ZHXxXXXWHuwCQKrgdpIkbzMNJMvs+9YWemanwp1fA7XZEv7QlilseysPvQe0D7Q7DlkJX/w/bGA1MdgK2TbGvA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.5.0", + "@ethersproject/abstract-signer": "^5.5.0", + "@ethersproject/address": "^5.5.0", + "@ethersproject/basex": "^5.5.0", + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/constants": "^5.5.0", + "@ethersproject/hash": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/networks": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/random": "^5.5.0", + "@ethersproject/rlp": "^5.5.0", + "@ethersproject/sha2": "^5.5.0", + "@ethersproject/strings": "^5.5.0", + "@ethersproject/transactions": "^5.5.0", + "@ethersproject/web": "^5.5.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, + "node_modules/@ethersproject/providers/node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@ethersproject/random": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.5.1.tgz", + "integrity": "sha512-YaU2dQ7DuhL5Au7KbcQLHxcRHfgyNgvFV4sQOo0HrtW3Zkrc9ctWNz8wXQ4uCSfSDsqX2vcjhroxU5RQRV0nqA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/logger": "^5.5.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.5.0.tgz", + "integrity": "sha512-hLv8XaQ8PTI9g2RHoQGf/WSxBfTB/NudRacbzdxmst5VHAqd1sMibWG7SENzT5Dj3yZ3kJYx+WiRYEcQTAkcYA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/logger": "^5.5.0" + } + }, + "node_modules/@ethersproject/sha2": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.5.0.tgz", + "integrity": "sha512-B5UBoglbCiHamRVPLA110J+2uqsifpZaTmid2/7W5rbtYVz6gus6/hSDieIU/6gaKIDcOj12WnOdiymEUHIAOA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.5.0.tgz", + "integrity": "sha512-5VmseH7qjtNmDdZBswavhotYbWB0bOwKIlOTSlX14rKn5c11QmJwGt4GHeo7NrL/Ycl7uo9AHvEqs5xZgFBTng==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "bn.js": "^4.11.9", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/@ethersproject/solidity": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.5.0.tgz", + "integrity": "sha512-9NgZs9LhGMj6aCtHXhtmFQ4AN4sth5HuFXVvAQtzmm0jpSCNOTGtrHZJAeYTh7MBjRR8brylWZxBZR9zDStXbw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/keccak256": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/sha2": "^5.5.0", + "@ethersproject/strings": "^5.5.0" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.5.0.tgz", + "integrity": "sha512-9fy3TtF5LrX/wTrBaT8FGE6TDJyVjOvXynXJz5MT5azq+E6D92zuKNx7i29sWW2FjVOaWjAsiZ1ZWznuduTIIQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/constants": "^5.5.0", + "@ethersproject/logger": "^5.5.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.5.0.tgz", + "integrity": "sha512-9RZYSKX26KfzEd/1eqvv8pLauCKzDTub0Ko4LfIgaERvRuwyaNV78mJs7cpIgZaDl6RJui4o49lHwwCM0526zA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/address": "^5.5.0", + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/constants": "^5.5.0", + "@ethersproject/keccak256": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/rlp": "^5.5.0", + "@ethersproject/signing-key": "^5.5.0" + } + }, + "node_modules/@ethersproject/units": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.5.0.tgz", + "integrity": "sha512-7+DpjiZk4v6wrikj+TCyWWa9dXLNU73tSTa7n0TSJDxkYbV3Yf1eRh9ToMLlZtuctNYu9RDNNy2USq3AdqSbag==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/constants": "^5.5.0", + "@ethersproject/logger": "^5.5.0" + } + }, + "node_modules/@ethersproject/wallet": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.5.0.tgz", + "integrity": "sha512-Mlu13hIctSYaZmUOo7r2PhNSd8eaMPVXe1wxrz4w4FCE4tDYBywDH+bAR1Xz2ADyXGwqYMwstzTrtUVIsKDO0Q==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.5.0", + "@ethersproject/abstract-signer": "^5.5.0", + "@ethersproject/address": "^5.5.0", + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/hash": "^5.5.0", + "@ethersproject/hdnode": "^5.5.0", + "@ethersproject/json-wallets": "^5.5.0", + "@ethersproject/keccak256": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/random": "^5.5.0", + "@ethersproject/signing-key": "^5.5.0", + "@ethersproject/transactions": "^5.5.0", + "@ethersproject/wordlists": "^5.5.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.5.1.tgz", + "integrity": "sha512-olvLvc1CB12sREc1ROPSHTdFCdvMh0J5GSJYiQg2D0hdD4QmJDy8QYDb1CvoqD/bF1c++aeKv2sR5uduuG9dQg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/base64": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/strings": "^5.5.0" + } + }, + "node_modules/@ethersproject/wordlists": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.5.0.tgz", + "integrity": "sha512-bL0UTReWDiaQJJYOC9sh/XcRu/9i2jMrzf8VLRmPKx58ckSlOJiohODkECCO50dtLZHcGU6MLXQ4OOrgBwP77Q==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/hash": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/strings": "^5.5.0" + } + }, "node_modules/@graphql-tools/load-files": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/@graphql-tools/load-files/-/load-files-6.5.3.tgz", @@ -1035,6 +1738,24 @@ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@highoutput/async-group": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@highoutput/async-group/-/async-group-0.4.1.tgz", + "integrity": "sha512-oLWBVBrgDtt93lUUWcafrOleWfeVsfSYylrv0dna8+VLxog9Kt+TgovfUVKduPXqcXavlihx3KVmO6vaRiOy6Q==", + "dependencies": { + "@types/node": "^14.11.1", + "uuid": "^3.4.0" + } + }, + "node_modules/@highoutput/async-group/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, "node_modules/@highoutput/delay": { "version": "0.2.8", "resolved": "https://registry.npmjs.org/@highoutput/delay/-/delay-0.2.8.tgz", @@ -2181,6 +2902,12 @@ "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", "dev": true }, + "node_modules/@types/luxon": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-2.0.9.tgz", + "integrity": "sha512-ZuzIc7aN+i2ZDMWIiSmMdubR9EMMSTdEzF6R+FckP4p6xdnOYKqknTo/k+xXQvciSXlNGIwA4OPU5X7JIFzYdA==", + "dev": true + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -2706,6 +3433,11 @@ "node": ">=0.4.0" } }, + "node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0=" + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -3321,6 +4053,11 @@ } ] }, + "node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" + }, "node_modules/bignumber.js": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", @@ -3409,8 +4146,7 @@ "node_modules/brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "peer": true + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" }, "node_modules/browser-pack": { "version": "6.1.0", @@ -4619,7 +5355,6 @@ "version": "6.5.4", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "peer": true, "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -4633,8 +5368,7 @@ "node_modules/elliptic/node_modules/bn.js": { "version": "4.12.0", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "peer": true + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" }, "node_modules/emittery": { "version": "0.8.1", @@ -5379,6 +6113,53 @@ "node": ">=0.10.0" } }, + "node_modules/ethers": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.5.4.tgz", + "integrity": "sha512-N9IAXsF8iKhgHIC6pquzRgPBJEzc9auw3JoRkaKe+y4Wl/LFBtDDunNe7YmdomontECAcC5APaAgWZBiu1kirw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abi": "5.5.0", + "@ethersproject/abstract-provider": "5.5.1", + "@ethersproject/abstract-signer": "5.5.0", + "@ethersproject/address": "5.5.0", + "@ethersproject/base64": "5.5.0", + "@ethersproject/basex": "5.5.0", + "@ethersproject/bignumber": "5.5.0", + "@ethersproject/bytes": "5.5.0", + "@ethersproject/constants": "5.5.0", + "@ethersproject/contracts": "5.5.0", + "@ethersproject/hash": "5.5.0", + "@ethersproject/hdnode": "5.5.0", + "@ethersproject/json-wallets": "5.5.0", + "@ethersproject/keccak256": "5.5.0", + "@ethersproject/logger": "5.5.0", + "@ethersproject/networks": "5.5.2", + "@ethersproject/pbkdf2": "5.5.0", + "@ethersproject/properties": "5.5.0", + "@ethersproject/providers": "5.5.3", + "@ethersproject/random": "5.5.1", + "@ethersproject/rlp": "5.5.0", + "@ethersproject/sha2": "5.5.0", + "@ethersproject/signing-key": "5.5.0", + "@ethersproject/solidity": "5.5.0", + "@ethersproject/strings": "5.5.0", + "@ethersproject/transactions": "5.5.0", + "@ethersproject/units": "5.5.0", + "@ethersproject/wallet": "5.5.0", + "@ethersproject/web": "5.5.1", + "@ethersproject/wordlists": "5.5.0" + } + }, "node_modules/event-target-shim": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", @@ -6078,7 +6859,6 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "peer": true, "dependencies": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" @@ -6096,7 +6876,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "peer": true, "dependencies": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -7461,6 +8240,11 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -8020,6 +8804,14 @@ "node": ">=12" } }, + "node_modules/luxon": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-2.3.0.tgz", + "integrity": "sha512-gv6jZCV+gGIrVKhO90yrsn8qXPKD8HYZJtrUDSfEbow8Tkw84T9OnCyJhWvnJIaIF/tBuiAjZuQHUt1LddX2mg==", + "engines": { + "node": ">=12" + } + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -8187,14 +8979,12 @@ "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "peer": true + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, "node_modules/minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "peer": true + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" }, "node_modules/minimatch": { "version": "3.0.5", @@ -9776,6 +10566,11 @@ "object-assign": "^4.1.1" } }, + "node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" + }, "node_modules/semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", @@ -12168,6 +12963,397 @@ } } }, + "@ethersproject/abi": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.5.0.tgz", + "integrity": "sha512-loW7I4AohP5KycATvc0MgujU6JyCHPqHdeoo9z3Nr9xEiNioxa65ccdm1+fsoJhkuhdRtfcL8cfyGamz2AxZ5w==", + "requires": { + "@ethersproject/address": "^5.5.0", + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/constants": "^5.5.0", + "@ethersproject/hash": "^5.5.0", + "@ethersproject/keccak256": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/strings": "^5.5.0" + } + }, + "@ethersproject/abstract-provider": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.5.1.tgz", + "integrity": "sha512-m+MA/ful6eKbxpr99xUYeRvLkfnlqzrF8SZ46d/xFB1A7ZVknYc/sXJG0RcufF52Qn2jeFj1hhcoQ7IXjNKUqg==", + "requires": { + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/networks": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/transactions": "^5.5.0", + "@ethersproject/web": "^5.5.0" + } + }, + "@ethersproject/abstract-signer": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.5.0.tgz", + "integrity": "sha512-lj//7r250MXVLKI7sVarXAbZXbv9P50lgmJQGr2/is82EwEb8r7HrxsmMqAjTsztMYy7ohrIhGMIml+Gx4D3mA==", + "requires": { + "@ethersproject/abstract-provider": "^5.5.0", + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/properties": "^5.5.0" + } + }, + "@ethersproject/address": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.5.0.tgz", + "integrity": "sha512-l4Nj0eWlTUh6ro5IbPTgbpT4wRbdH5l8CQf7icF7sb/SI3Nhd9Y9HzhonTSTi6CefI0necIw7LJqQPopPLZyWw==", + "requires": { + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/keccak256": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/rlp": "^5.5.0" + } + }, + "@ethersproject/base64": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.5.0.tgz", + "integrity": "sha512-tdayUKhU1ljrlHzEWbStXazDpsx4eg1dBXUSI6+mHlYklOXoXF6lZvw8tnD6oVaWfnMxAgRSKROg3cVKtCcppA==", + "requires": { + "@ethersproject/bytes": "^5.5.0" + } + }, + "@ethersproject/basex": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.5.0.tgz", + "integrity": "sha512-ZIodwhHpVJ0Y3hUCfUucmxKsWQA5TMnavp5j/UOuDdzZWzJlRmuOjcTMIGgHCYuZmHt36BfiSyQPSRskPxbfaQ==", + "requires": { + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/properties": "^5.5.0" + } + }, + "@ethersproject/bignumber": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.5.0.tgz", + "integrity": "sha512-6Xytlwvy6Rn3U3gKEc1vP7nR92frHkv6wtVr95LFR3jREXiCPzdWxKQ1cx4JGQBXxcguAwjA8murlYN2TSiEbg==", + "requires": { + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "bn.js": "^4.11.9" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "@ethersproject/bytes": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.5.0.tgz", + "integrity": "sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog==", + "requires": { + "@ethersproject/logger": "^5.5.0" + } + }, + "@ethersproject/constants": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.5.0.tgz", + "integrity": "sha512-2MsRRVChkvMWR+GyMGY4N1sAX9Mt3J9KykCsgUFd/1mwS0UH1qw+Bv9k1UJb3X3YJYFco9H20pjSlOIfCG5HYQ==", + "requires": { + "@ethersproject/bignumber": "^5.5.0" + } + }, + "@ethersproject/contracts": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.5.0.tgz", + "integrity": "sha512-2viY7NzyvJkh+Ug17v7g3/IJC8HqZBDcOjYARZLdzRxrfGlRgmYgl6xPRKVbEzy1dWKw/iv7chDcS83pg6cLxg==", + "requires": { + "@ethersproject/abi": "^5.5.0", + "@ethersproject/abstract-provider": "^5.5.0", + "@ethersproject/abstract-signer": "^5.5.0", + "@ethersproject/address": "^5.5.0", + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/constants": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/transactions": "^5.5.0" + } + }, + "@ethersproject/hash": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.5.0.tgz", + "integrity": "sha512-dnGVpK1WtBjmnp3mUT0PlU2MpapnwWI0PibldQEq1408tQBAbZpPidkWoVVuNMOl/lISO3+4hXZWCL3YV7qzfg==", + "requires": { + "@ethersproject/abstract-signer": "^5.5.0", + "@ethersproject/address": "^5.5.0", + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/keccak256": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/strings": "^5.5.0" + } + }, + "@ethersproject/hdnode": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.5.0.tgz", + "integrity": "sha512-mcSOo9zeUg1L0CoJH7zmxwUG5ggQHU1UrRf8jyTYy6HxdZV+r0PBoL1bxr+JHIPXRzS6u/UW4mEn43y0tmyF8Q==", + "requires": { + "@ethersproject/abstract-signer": "^5.5.0", + "@ethersproject/basex": "^5.5.0", + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/pbkdf2": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/sha2": "^5.5.0", + "@ethersproject/signing-key": "^5.5.0", + "@ethersproject/strings": "^5.5.0", + "@ethersproject/transactions": "^5.5.0", + "@ethersproject/wordlists": "^5.5.0" + } + }, + "@ethersproject/json-wallets": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.5.0.tgz", + "integrity": "sha512-9lA21XQnCdcS72xlBn1jfQdj2A1VUxZzOzi9UkNdnokNKke/9Ya2xA9aIK1SC3PQyBDLt4C+dfps7ULpkvKikQ==", + "requires": { + "@ethersproject/abstract-signer": "^5.5.0", + "@ethersproject/address": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/hdnode": "^5.5.0", + "@ethersproject/keccak256": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/pbkdf2": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/random": "^5.5.0", + "@ethersproject/strings": "^5.5.0", + "@ethersproject/transactions": "^5.5.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "@ethersproject/keccak256": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.5.0.tgz", + "integrity": "sha512-5VoFCTjo2rYbBe1l2f4mccaRFN/4VQEYFwwn04aJV2h7qf4ZvI2wFxUE1XOX+snbwCLRzIeikOqtAoPwMza9kg==", + "requires": { + "@ethersproject/bytes": "^5.5.0", + "js-sha3": "0.8.0" + } + }, + "@ethersproject/logger": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.5.0.tgz", + "integrity": "sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg==" + }, + "@ethersproject/networks": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.5.2.tgz", + "integrity": "sha512-NEqPxbGBfy6O3x4ZTISb90SjEDkWYDUbEeIFhJly0F7sZjoQMnj5KYzMSkMkLKZ+1fGpx00EDpHQCy6PrDupkQ==", + "requires": { + "@ethersproject/logger": "^5.5.0" + } + }, + "@ethersproject/pbkdf2": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.5.0.tgz", + "integrity": "sha512-SaDvQFvXPnz1QGpzr6/HToLifftSXGoXrbpZ6BvoZhmx4bNLHrxDe8MZisuecyOziP1aVEwzC2Hasj+86TgWVg==", + "requires": { + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/sha2": "^5.5.0" + } + }, + "@ethersproject/properties": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.5.0.tgz", + "integrity": "sha512-l3zRQg3JkD8EL3CPjNK5g7kMx4qSwiR60/uk5IVjd3oq1MZR5qUg40CNOoEJoX5wc3DyY5bt9EbMk86C7x0DNA==", + "requires": { + "@ethersproject/logger": "^5.5.0" + } + }, + "@ethersproject/providers": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.5.3.tgz", + "integrity": "sha512-ZHXxXXXWHuwCQKrgdpIkbzMNJMvs+9YWemanwp1fA7XZEv7QlilseysPvQe0D7Q7DlkJX/w/bGA1MdgK2TbGvA==", + "requires": { + "@ethersproject/abstract-provider": "^5.5.0", + "@ethersproject/abstract-signer": "^5.5.0", + "@ethersproject/address": "^5.5.0", + "@ethersproject/basex": "^5.5.0", + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/constants": "^5.5.0", + "@ethersproject/hash": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/networks": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/random": "^5.5.0", + "@ethersproject/rlp": "^5.5.0", + "@ethersproject/sha2": "^5.5.0", + "@ethersproject/strings": "^5.5.0", + "@ethersproject/transactions": "^5.5.0", + "@ethersproject/web": "^5.5.0", + "bech32": "1.1.4", + "ws": "7.4.6" + }, + "dependencies": { + "ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "requires": {} + } + } + }, + "@ethersproject/random": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.5.1.tgz", + "integrity": "sha512-YaU2dQ7DuhL5Au7KbcQLHxcRHfgyNgvFV4sQOo0HrtW3Zkrc9ctWNz8wXQ4uCSfSDsqX2vcjhroxU5RQRV0nqA==", + "requires": { + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/logger": "^5.5.0" + } + }, + "@ethersproject/rlp": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.5.0.tgz", + "integrity": "sha512-hLv8XaQ8PTI9g2RHoQGf/WSxBfTB/NudRacbzdxmst5VHAqd1sMibWG7SENzT5Dj3yZ3kJYx+WiRYEcQTAkcYA==", + "requires": { + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/logger": "^5.5.0" + } + }, + "@ethersproject/sha2": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.5.0.tgz", + "integrity": "sha512-B5UBoglbCiHamRVPLA110J+2uqsifpZaTmid2/7W5rbtYVz6gus6/hSDieIU/6gaKIDcOj12WnOdiymEUHIAOA==", + "requires": { + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "hash.js": "1.1.7" + } + }, + "@ethersproject/signing-key": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.5.0.tgz", + "integrity": "sha512-5VmseH7qjtNmDdZBswavhotYbWB0bOwKIlOTSlX14rKn5c11QmJwGt4GHeo7NrL/Ycl7uo9AHvEqs5xZgFBTng==", + "requires": { + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "bn.js": "^4.11.9", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "@ethersproject/solidity": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.5.0.tgz", + "integrity": "sha512-9NgZs9LhGMj6aCtHXhtmFQ4AN4sth5HuFXVvAQtzmm0jpSCNOTGtrHZJAeYTh7MBjRR8brylWZxBZR9zDStXbw==", + "requires": { + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/keccak256": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/sha2": "^5.5.0", + "@ethersproject/strings": "^5.5.0" + } + }, + "@ethersproject/strings": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.5.0.tgz", + "integrity": "sha512-9fy3TtF5LrX/wTrBaT8FGE6TDJyVjOvXynXJz5MT5azq+E6D92zuKNx7i29sWW2FjVOaWjAsiZ1ZWznuduTIIQ==", + "requires": { + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/constants": "^5.5.0", + "@ethersproject/logger": "^5.5.0" + } + }, + "@ethersproject/transactions": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.5.0.tgz", + "integrity": "sha512-9RZYSKX26KfzEd/1eqvv8pLauCKzDTub0Ko4LfIgaERvRuwyaNV78mJs7cpIgZaDl6RJui4o49lHwwCM0526zA==", + "requires": { + "@ethersproject/address": "^5.5.0", + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/constants": "^5.5.0", + "@ethersproject/keccak256": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/rlp": "^5.5.0", + "@ethersproject/signing-key": "^5.5.0" + } + }, + "@ethersproject/units": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.5.0.tgz", + "integrity": "sha512-7+DpjiZk4v6wrikj+TCyWWa9dXLNU73tSTa7n0TSJDxkYbV3Yf1eRh9ToMLlZtuctNYu9RDNNy2USq3AdqSbag==", + "requires": { + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/constants": "^5.5.0", + "@ethersproject/logger": "^5.5.0" + } + }, + "@ethersproject/wallet": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.5.0.tgz", + "integrity": "sha512-Mlu13hIctSYaZmUOo7r2PhNSd8eaMPVXe1wxrz4w4FCE4tDYBywDH+bAR1Xz2ADyXGwqYMwstzTrtUVIsKDO0Q==", + "requires": { + "@ethersproject/abstract-provider": "^5.5.0", + "@ethersproject/abstract-signer": "^5.5.0", + "@ethersproject/address": "^5.5.0", + "@ethersproject/bignumber": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/hash": "^5.5.0", + "@ethersproject/hdnode": "^5.5.0", + "@ethersproject/json-wallets": "^5.5.0", + "@ethersproject/keccak256": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/random": "^5.5.0", + "@ethersproject/signing-key": "^5.5.0", + "@ethersproject/transactions": "^5.5.0", + "@ethersproject/wordlists": "^5.5.0" + } + }, + "@ethersproject/web": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.5.1.tgz", + "integrity": "sha512-olvLvc1CB12sREc1ROPSHTdFCdvMh0J5GSJYiQg2D0hdD4QmJDy8QYDb1CvoqD/bF1c++aeKv2sR5uduuG9dQg==", + "requires": { + "@ethersproject/base64": "^5.5.0", + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/strings": "^5.5.0" + } + }, + "@ethersproject/wordlists": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.5.0.tgz", + "integrity": "sha512-bL0UTReWDiaQJJYOC9sh/XcRu/9i2jMrzf8VLRmPKx58ckSlOJiohODkECCO50dtLZHcGU6MLXQ4OOrgBwP77Q==", + "requires": { + "@ethersproject/bytes": "^5.5.0", + "@ethersproject/hash": "^5.5.0", + "@ethersproject/logger": "^5.5.0", + "@ethersproject/properties": "^5.5.0", + "@ethersproject/strings": "^5.5.0" + } + }, "@graphql-tools/load-files": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/@graphql-tools/load-files/-/load-files-6.5.3.tgz", @@ -12217,6 +13403,22 @@ "tslib": "~2.3.0" } }, + "@highoutput/async-group": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@highoutput/async-group/-/async-group-0.4.1.tgz", + "integrity": "sha512-oLWBVBrgDtt93lUUWcafrOleWfeVsfSYylrv0dna8+VLxog9Kt+TgovfUVKduPXqcXavlihx3KVmO6vaRiOy6Q==", + "requires": { + "@types/node": "^14.11.1", + "uuid": "^3.4.0" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } + } + }, "@highoutput/delay": { "version": "0.2.8", "resolved": "https://registry.npmjs.org/@highoutput/delay/-/delay-0.2.8.tgz", @@ -13141,6 +14343,12 @@ "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", "dev": true }, + "@types/luxon": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-2.0.9.tgz", + "integrity": "sha512-ZuzIc7aN+i2ZDMWIiSmMdubR9EMMSTdEzF6R+FckP4p6xdnOYKqknTo/k+xXQvciSXlNGIwA4OPU5X7JIFzYdA==", + "dev": true + }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -13547,6 +14755,11 @@ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==" }, + "aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0=" + }, "agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -14013,6 +15226,11 @@ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, + "bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" + }, "bignumber.js": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", @@ -14080,8 +15298,7 @@ "brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "peer": true + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" }, "browser-pack": { "version": "6.1.0", @@ -15073,7 +16290,6 @@ "version": "6.5.4", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "peer": true, "requires": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -15087,8 +16303,7 @@ "bn.js": { "version": "4.12.0", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "peer": true + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" } } }, @@ -15630,6 +16845,43 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" }, + "ethers": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.5.4.tgz", + "integrity": "sha512-N9IAXsF8iKhgHIC6pquzRgPBJEzc9auw3JoRkaKe+y4Wl/LFBtDDunNe7YmdomontECAcC5APaAgWZBiu1kirw==", + "requires": { + "@ethersproject/abi": "5.5.0", + "@ethersproject/abstract-provider": "5.5.1", + "@ethersproject/abstract-signer": "5.5.0", + "@ethersproject/address": "5.5.0", + "@ethersproject/base64": "5.5.0", + "@ethersproject/basex": "5.5.0", + "@ethersproject/bignumber": "5.5.0", + "@ethersproject/bytes": "5.5.0", + "@ethersproject/constants": "5.5.0", + "@ethersproject/contracts": "5.5.0", + "@ethersproject/hash": "5.5.0", + "@ethersproject/hdnode": "5.5.0", + "@ethersproject/json-wallets": "5.5.0", + "@ethersproject/keccak256": "5.5.0", + "@ethersproject/logger": "5.5.0", + "@ethersproject/networks": "5.5.2", + "@ethersproject/pbkdf2": "5.5.0", + "@ethersproject/properties": "5.5.0", + "@ethersproject/providers": "5.5.3", + "@ethersproject/random": "5.5.1", + "@ethersproject/rlp": "5.5.0", + "@ethersproject/sha2": "5.5.0", + "@ethersproject/signing-key": "5.5.0", + "@ethersproject/solidity": "5.5.0", + "@ethersproject/strings": "5.5.0", + "@ethersproject/transactions": "5.5.0", + "@ethersproject/units": "5.5.0", + "@ethersproject/wallet": "5.5.0", + "@ethersproject/web": "5.5.1", + "@ethersproject/wordlists": "5.5.0" + } + }, "event-target-shim": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", @@ -16142,7 +17394,6 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "peer": true, "requires": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" @@ -16157,7 +17408,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "peer": true, "requires": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -17167,6 +18417,11 @@ } } }, + "js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -17617,6 +18872,11 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.3.1.tgz", "integrity": "sha512-nX1x4qUrKqwbIAhv4s9et4FIUVzNOpeY07bsjGUy8gwJrXH/wScImSQqXErmo/b2jZY2r0mohbLA9zVj7u1cNw==" }, + "luxon": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-2.3.0.tgz", + "integrity": "sha512-gv6jZCV+gGIrVKhO90yrsn8qXPKD8HYZJtrUDSfEbow8Tkw84T9OnCyJhWvnJIaIF/tBuiAjZuQHUt1LddX2mg==" + }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -17743,14 +19003,12 @@ "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "peer": true + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" }, "minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "peer": true + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" }, "minimatch": { "version": "3.0.5", @@ -18908,6 +20166,11 @@ "object-assign": "^4.1.1" } }, + "scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" + }, "semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", diff --git a/token-gating/api/package.json b/token-gating/api/package.json index 20ed8607..b346066c 100644 --- a/token-gating/api/package.json +++ b/token-gating/api/package.json @@ -19,6 +19,7 @@ "@graphql-tools/load-files": "^6.5.3", "@graphql-tools/merge": "^8.2.1", "@graphql-tools/schema": "^8.3.1", + "@highoutput/async-group": "^0.4.1", "@highoutput/delay": "^0.2.8", "@highoutput/hash": "^0.1.11", "@highoutput/logger": "^0.5.4", @@ -53,6 +54,7 @@ "eslint-plugin-prettier": "^3.4.0", "eslint-plugin-react": "^7.24.0", "eslint-plugin-react-hooks": "^4.2.0", + "ethers": "^5.5.4", "faker": "^5.5.3", "google-auth-library": "^7.11.0", "graphql-scalars": "^1.14.1", @@ -62,6 +64,7 @@ "koa": "^2.13.4", "koa-bodyparser": "^4.3.0", "lru-cache": "^7.3.0", + "luxon": "^2.3.0", "mongodb": "^4.2.2", "mongodb-memory-server": "^8.0.4", "mongoose": "^6.2.1", @@ -92,6 +95,7 @@ "@types/koa": "^2.13.4", "@types/koa-bodyparser": "^4.3.5", "@types/lru-cache": "^5.1.1", + "@types/luxon": "^2.0.9", "@types/mongodb": "^4.0.7", "@types/ms": "^0.7.31", "@types/node-cron": "^3.0.1", diff --git a/token-gating/api/services/account/controllers/holder-account.ts b/token-gating/api/services/account/controllers/holder-account.ts new file mode 100644 index 00000000..0390a182 --- /dev/null +++ b/token-gating/api/services/account/controllers/holder-account.ts @@ -0,0 +1,56 @@ +import { injectable, inject } from 'inversify'; +import R from 'ramda'; +import { + ID, + AccountRole, + HolderAccount, + InputData, +} from '../../../types'; +import { FilterQuery } from '../../../library/repository'; +import { TYPES } from '../types'; +import HolderAccountRepository from '../repositories/holder-account'; + +@injectable() +export default class HolderAccountController { + @inject(TYPES.HolderAccountRepository) private readonly holderAccountRepository!: HolderAccountRepository; + + async holderAccountExists(params: { filter: FilterQuery }): Promise { + return this.holderAccountRepository.exists(params); + } + + async createHolderAccount(params: { id: ID } & InputData>): Promise { + const document = await this.holderAccountRepository.create(params); + + return { + ...document, + role: AccountRole.HOLDER, + }; + } + + async findOneHolderAccount(params: { id: ID }): Promise; + + async findOneHolderAccount(params: { filter: FilterQuery }): Promise; + + async findOneHolderAccount(params: { id?: ID; filter?: FilterQuery }): Promise { + const document = await this.holderAccountRepository.findOne(params as never); + + if (!document) { + return null; + } + + return { + ...document, + role: AccountRole.HOLDER, + }; + } + + async findHolderAccount( + params: { filter: FilterQuery }, + ): Promise { + return R.map((item) => ({ + ...item, + role: AccountRole.HOLDER, + }), await this.holderAccountRepository.find(params)); + } +} diff --git a/token-gating/api/services/account/index.ts b/token-gating/api/services/account/index.ts index b129f54e..f39428b5 100644 --- a/token-gating/api/services/account/index.ts +++ b/token-gating/api/services/account/index.ts @@ -1,8 +1,11 @@ import { injectable, inject } from 'inversify'; import AdminAccountController from './controllers/admin-account'; +import HolderAccountController from './controllers/holder-account'; import { TYPES } from './types'; @injectable() export class AccountService { @inject(TYPES.AdminAccountController) readonly adminAccountController!: AdminAccountController; + + @inject(TYPES.HolderAccountController) readonly holderAccountController!: HolderAccountController; } diff --git a/token-gating/api/services/account/repositories/holder-account.ts b/token-gating/api/services/account/repositories/holder-account.ts new file mode 100644 index 00000000..8b959a9f --- /dev/null +++ b/token-gating/api/services/account/repositories/holder-account.ts @@ -0,0 +1,52 @@ +/* eslint-disable no-underscore-dangle */ +import { Connection, Document, Schema } from 'mongoose'; +import { injectable } from 'inversify'; +import { + ID, + HolderAccount, +} from '../../../types'; +import Repository from '../../../library/repository'; + +type HolderAccountDocument = Document & HolderAccount; + +@injectable() +export default class HolderAccountRepository + extends Repository< + HolderAccount, + Pick & Partial>, + Partial> + > { + async getModel(db: Connection) { + const schema = new Schema({ + _id: { + type: Buffer, + required: true, + }, + ethereumAddress: { + type: String, + required: true, + }, + discordAccessToken: { + type: String, + required: true, + }, + createdAt: { + type: Date, + default: Date.now, + }, + updatedAt: { + type: Date, + default: Date.now, + }, + + }, { id: false, _id: false }); + + schema.virtual('id').get(function (this: HolderAccountDocument) { + return Buffer.from(this._id as never); + }); + + schema.index({ createdAt: 1 }); + + return db.model('HolderAccount', schema); + } +} diff --git a/token-gating/api/services/account/types.ts b/token-gating/api/services/account/types.ts index c530034d..6a7392fe 100644 --- a/token-gating/api/services/account/types.ts +++ b/token-gating/api/services/account/types.ts @@ -1,4 +1,6 @@ export const TYPES = { AdminAccountRepository: Symbol.for('AdminAccountRepository'), AdminAccountController: Symbol.for('AdminAccountController'), + HolderAccountRepository: Symbol.for('HolderAccountRepository'), + HolderAccountController: Symbol.for('HolderAccountController'), }; diff --git a/token-gating/api/services/api/index.ts b/token-gating/api/services/api/index.ts index ff71e32e..82d92900 100644 --- a/token-gating/api/services/api/index.ts +++ b/token-gating/api/services/api/index.ts @@ -16,6 +16,7 @@ import { createServer, Server } from 'http'; import { ApolloError, ApolloServerPluginLandingPageGraphQLPlayground } from 'apollo-server-core'; import cryptoRandomString from 'crypto-random-string'; import assert from 'assert'; +import AsyncGroup from '@highoutput/async-group'; import loaders from './loaders'; import { AccountRole, TYPES as GLOBAL_TYPES } from '../../types'; import { AccountService } from '../account'; @@ -102,6 +103,8 @@ export class ApiService { if (ctx.state.claims.role === AccountRole.ADMIN) { user = await ctx.loaders.adminAccount.load(ObjectId.from(ctx.state.claims.sub).buffer); + } else if (ctx.state.claims.role === AccountRole.HOLDER) { + user = await ctx.loaders.holderAccount.load(ObjectId.from(ctx.state.claims.sub).buffer); } assert(user, '`user` is null'); @@ -186,6 +189,8 @@ export class ApiService { await promisify(this.server.close).call(this.server); } + await AsyncGroup.wait(); + this.logger.info('stopped'); } } diff --git a/token-gating/api/services/api/loaders/index.ts b/token-gating/api/services/api/loaders/index.ts index 81922ca7..c2810c58 100644 --- a/token-gating/api/services/api/loaders/index.ts +++ b/token-gating/api/services/api/loaders/index.ts @@ -1,5 +1,6 @@ import { AdminAccount, + HolderAccount, Project, } from '../../../types'; import BasicDataLoader from '../../../library/basic-data-loader'; @@ -20,6 +21,12 @@ export default function (ctx: Context) { id: { $in: ids }, }, })), + holderAccount: new BasicDataLoader(async (ids) => ctx.services.account + .holderAccountController.findHolderAccount({ + filter: { + id: { $in: ids }, + }, + })), }; } diff --git a/token-gating/api/services/api/resolvers/authentication/mutation.ts b/token-gating/api/services/api/resolvers/authentication/mutation.ts index 40acf422..19db7b04 100644 --- a/token-gating/api/services/api/resolvers/authentication/mutation.ts +++ b/token-gating/api/services/api/resolvers/authentication/mutation.ts @@ -1,8 +1,12 @@ /* eslint-disable no-console */ import jsonwebtoken from 'jsonwebtoken'; import { OAuth2Client } from 'google-auth-library'; +import { DateTime } from 'luxon'; +import ethers from 'ethers'; +import axios from 'axios'; import ObjectId, { ObjectType } from '../../../../library/object-id'; import { Context } from '../../types'; +import { DiscordResponse } from '../../../../types/discord-response'; export default { Mutation: { @@ -54,5 +58,99 @@ export default { error: null, }; }, + async generateProjectAccessToken(_: never, args: { + request: { + discordAccessToken: string; + ethAddress: string; + timestamp: Date; + signature: string; + ttl: string; + } + }, ctx: Context) { + const { + discordAccessToken, ethAddress, timestamp, signature, + } = args.request; + + if (DateTime.now() + .diff(DateTime.fromISO(timestamp.toISOString()), 'minutes').minutes < 10) { + return { + error: { + __typename: 'InvalidAuthenticationSignatureError', + message: 'Invalid Timestamp', + }, + data: null, + }; + } + + const message = `Timestamp: ${timestamp.toISOString()}`; + + const timestampBytes = ethers.utils.toUtf8Bytes( + `\u0019Ethereum Signed Message:\n${ + message.length.toString() + }${message}`, + ethers.utils.UnicodeNormalizationForm.current, + ); + const timestampHash = ethers.utils.keccak256(timestampBytes); + + const recoveredAddress = ethers.utils.verifyMessage(timestampHash, signature); + + if (ethAddress !== recoveredAddress) { + return { + error: { + __typename: 'InvalidAuthenticationSignatureError', + message: 'Invalid Authentication Signature', + }, + data: null, + }; + } + + const response = await axios.get('https://discord.com/api/users/@me', { + headers: { + Authorization: `Bearer ${discordAccessToken}`, + }, + }); + + const userInfo:DiscordResponse = response.data; + + if (!userInfo.email) { + return { + data: null, + error: { + __typename: 'InvalidDiscordAccessTokenError', + message: 'Invalid Discord Access Token', + }, + }; + } + + let holderAccount = await ctx.services.account.holderAccountController.findOneHolderAccount({ + filter: { + ethereumAddress: ethAddress, + }, + }); + + if (!holderAccount) { + holderAccount = await ctx.services.account.holderAccountController.createHolderAccount({ + id: ObjectId.generate(ObjectType.HOLDER).buffer, + data: { + ethereumAddress: ethAddress, + discordAccessToken, + }, + }); + } + + return { + data: { + accessToken: jsonwebtoken.sign( + { role: holderAccount.role }, + ctx.config.JWT_SECRET, + { + subject: new ObjectId(holderAccount.id).toString(), + expiresIn: '30d', + }, + ), + }, + error: null, + }; + }, }, }; diff --git a/token-gating/api/services/api/resolvers/project/mutation.ts b/token-gating/api/services/api/resolvers/project/mutation.ts index 2b338ba0..b3ed7744 100644 --- a/token-gating/api/services/api/resolvers/project/mutation.ts +++ b/token-gating/api/services/api/resolvers/project/mutation.ts @@ -2,9 +2,11 @@ import R from 'ramda'; import axios from 'axios'; +import AsyncGroup from '@highoutput/async-group'; import ObjectId, { ObjectType } from '../../../../library/object-id'; import { Context } from '../../types'; import { DiscordResponse } from '../../../../types/discord-response'; +import logger from '../../../../library/logger'; export default { Mutation: { @@ -31,7 +33,7 @@ export default { const userInfo:DiscordResponse = response.data; if (!userInfo.email) { - console.log('discord token error'); + logger.warn('Invalid Discord Bot Access Token'); return { data: null, error: { @@ -41,6 +43,32 @@ export default { }; } + const collectionExists = await ctx.services.worker.collectionController.collectionExists({ + filter: { + contractAddress, + }, + }); + + if (collectionExists) { + logger.warn('Contract Address exists on other projects'); + return { + data: null, + error: { + __typename: 'ContractAddressExistsError', + message: 'Contract Address exists on other projects', + }, + }; + } + + const collection = await ctx.services.worker.collectionController.createCollection({ + id: ObjectId.generate(ObjectType.COLLECTION).buffer, + data: { + contractAddress, + }, + }); + + AsyncGroup.add(ctx.services.worker.syncCollection(collection.id, true)); + const project = await ctx.services.project.projectController.createProject({ id: ObjectId.generate(ObjectType.PROJECT).buffer, data: { @@ -49,6 +77,7 @@ export default { contractAddress, discordId, discordChannel, + discordBotAccessToken, }, }); diff --git a/token-gating/api/services/api/type-defs/authentication.ts b/token-gating/api/services/api/type-defs/authentication.ts index 80afc384..e240dc56 100644 --- a/token-gating/api/services/api/type-defs/authentication.ts +++ b/token-gating/api/services/api/type-defs/authentication.ts @@ -31,26 +31,38 @@ input GenerateAccessTokenByGoogleRequest { accessToken: String! } +# -# type GenerateProjectAccessTokenResponseData { -# accessToken: String! -# } +type InvalidDiscordAccessTokenError implements Error { + message: String! +} -# type GenerateProjectAccessTokenResponse { -# error: GenerateAccessTokenByGoogleError -# data: GenerateProjectAccessTokenResponseData -# } +type InvalidAuthenticationSignatureError implements Error { + message: String! +} -# input GenerateProjectAccessTokenRequest { -# discordAccessToken: String! -# ethAddress: String! -# timestamp: DateTime! -# signature: String! -# ttl: Duration -# } +union GenerateProjectAccessTokenError = InvalidDiscordAccessTokenError | InvalidAuthenticationSignatureError + +union GenerateAccessTokenByGoogleError = InvalidGoogleAccessTokenError +type GenerateProjectAccessTokenResponseData { + accessToken: String! +} + +type GenerateProjectAccessTokenResponse { + error: GenerateAccessTokenByGoogleError + data: GenerateProjectAccessTokenResponseData +} + +input GenerateProjectAccessTokenRequest { + discordAccessToken: String! + ethAddress: String! + timestamp: DateTime! + signature: String! + ttl: Duration +} type Mutation { generateAccessTokenByGoogle(request: GenerateAccessTokenByGoogleRequest): GenerateAccessTokenByGoogleResponse! - # generateProjectAccessToken(request: GenerateProjectAccessTokenRequest): GenerateProjectAccessTokenResponse! + generateProjectAccessToken(request: GenerateProjectAccessTokenRequest): GenerateProjectAccessTokenResponse! } `; diff --git a/token-gating/api/services/api/type-defs/project.ts b/token-gating/api/services/api/type-defs/project.ts index e3c60de6..2f2453ae 100644 --- a/token-gating/api/services/api/type-defs/project.ts +++ b/token-gating/api/services/api/type-defs/project.ts @@ -15,7 +15,11 @@ type InvalidDiscordBotAccessTokenError implements Error { message: String! } -union CreateProjectError = InvalidDiscordBotAccessTokenError +type ContractAddressExistsError implements Error { + message: String! +} + +union CreateProjectError = InvalidDiscordBotAccessTokenError | ContractAddressExistsError type CreateProjectResponseData { project: Project! diff --git a/token-gating/api/services/api/types.ts b/token-gating/api/services/api/types.ts index d8329315..ab1ea4c1 100644 --- a/token-gating/api/services/api/types.ts +++ b/token-gating/api/services/api/types.ts @@ -1,5 +1,7 @@ import { ParameterizedContext } from 'koa'; -import { AccountRole, AdminAccount, Project } from '../../types'; +import { + AccountRole, AdminAccount, HolderAccount, Project, +} from '../../types'; import BasicDataLoader from '../../library/basic-data-loader'; import { AccountService } from '../account'; import { ProjectService } from '../project'; @@ -17,7 +19,7 @@ export type Context = ParameterizedContext<{ sub: string; role: AccountRole; }; - user: Pick; + user: Pick | Pick; }> & { services: { account: AccountService; @@ -34,5 +36,6 @@ export type Context = ParameterizedContext<{ loaders: { adminAccount: BasicDataLoader; project: BasicDataLoader; + holderAccount: BasicDataLoader; } }; diff --git a/token-gating/api/services/project/controllers/project.ts b/token-gating/api/services/project/controllers/project.ts index e4ba561b..7a55612e 100644 --- a/token-gating/api/services/project/controllers/project.ts +++ b/token-gating/api/services/project/controllers/project.ts @@ -18,7 +18,7 @@ export default class ProjectController { } async createProject(params: { id: ID } & InputData>): Promise { + 'discordId' | 'discordChannel' | 'discordBotAccessToken'>>): Promise { const document = await this.projectRepository.create(params); return { diff --git a/token-gating/api/services/project/repositories/project.ts b/token-gating/api/services/project/repositories/project.ts index b7b62a3d..b39ac964 100644 --- a/token-gating/api/services/project/repositories/project.ts +++ b/token-gating/api/services/project/repositories/project.ts @@ -17,10 +17,10 @@ type ProjectDocument = Document & Project; export default class ProjectRepository extends Repository< Project, - Pick & + Pick & Partial>, Partial> + 'discordBotAccessToken' | 'createdAt' | 'updatedAt'>> > { @inject(TYPES.retrievePage) private readonly baseRetrievePage!: typeof baseRetrievePage; @@ -50,6 +50,10 @@ export default class ProjectRepository type: String, required: true, }, + discordBotAccessToken: { + type: String, + required: true, + }, createdAt: { type: Date, default: Date.now, diff --git a/token-gating/api/services/worker/inversify.config.ts b/token-gating/api/services/worker/inversify.config.ts index 697f6a25..526d4023 100644 --- a/token-gating/api/services/worker/inversify.config.ts +++ b/token-gating/api/services/worker/inversify.config.ts @@ -16,12 +16,8 @@ globalContainer.bind(TYPES.ENV).toConstantValue(process.env.ENV || process.env.N globalContainer.bind(TYPES.mongoose) .toDynamicValue(async (ctx) => mongoose.createConnection(ctx.container.get(TYPES.MONGODB_URI), { readPreference: 'secondaryPreferred', - useFindAndModify: false, - useCreateIndex: true, - useNewUrlParser: true, - useUnifiedTopology: true, socketTimeoutMS: ms('5m'), - connectTimeoutMS: ms('5m'), + maxPoolSize: ctx.container.get(TYPES.MONGODB_POOL_SIZE), })).inSingletonScope(); const container = Container.merge( diff --git a/token-gating/api/services/worker/src/controllers/collection.ts b/token-gating/api/services/worker/src/controllers/collection.ts new file mode 100644 index 00000000..2afdc1f3 --- /dev/null +++ b/token-gating/api/services/worker/src/controllers/collection.ts @@ -0,0 +1,58 @@ +import { injectable, inject } from 'inversify'; +import R from 'ramda'; +import { + ID, + Collection, + InputData, +} from '../../types'; +import { FilterQuery } from '../../../../library/repository'; +import { TYPES } from '../types'; +import CollectionRepository from '../repositories/collection'; + +@injectable() +export default class CollectionController { + @inject(TYPES.CollectionRepository) private readonly collectionRepository!: CollectionRepository; + + async collectionExists(params: { filter: FilterQuery }): Promise { + return this.collectionRepository.exists(params); + } + + async createCollection(params: { id: ID } & InputData>): Promise { + const document = await this.collectionRepository.create(params); + + return { + ...document, + }; + } + + async findOneCollection(params: { id: ID }): Promise; + + async findOneCollection(params: { filter: FilterQuery }): Promise; + + async findOneCollection(params: { id?: ID; filter?: FilterQuery }): Promise { + const document = await this.collectionRepository.findOne(params as never); + + if (!document) { + return null; + } + + return { + ...document, + }; + } + + async updateOneCollection(params: { filter: FilterQuery } + & InputData>>): Promise { + const document = await this.collectionRepository.updateOne(params); + if (!document) return null; + return document; + } + + async findCollections( + params: { filter: FilterQuery }, + ): Promise { + return R.map((item) => ({ + ...item, + }), await this.collectionRepository.find(params)); + } +} diff --git a/token-gating/api/services/worker/src/controllers/ownership.ts b/token-gating/api/services/worker/src/controllers/ownership.ts new file mode 100644 index 00000000..7c424858 --- /dev/null +++ b/token-gating/api/services/worker/src/controllers/ownership.ts @@ -0,0 +1,61 @@ +import { injectable, inject } from 'inversify'; +import R from 'ramda'; +import { + ID, + Ownership, + InputData, +} from '../../types'; +import { FilterQuery } from '../../../../library/repository'; +import { TYPES } from '../types'; +import OwnershipRepository from '../repositories/ownership'; + +@injectable() +export default class OwnershipController { + @inject(TYPES.OwnershipRepository) private readonly ownershipRepository!: OwnershipRepository; + + async ownershipExists(params: { filter: FilterQuery }): Promise { + return this.ownershipRepository.exists(params); + } + + async createOwnership(params: { id: ID } & InputData>): Promise { + const document = await this.ownershipRepository.create(params); + + return { + ...document, + }; + } + + async findOneOwnership(params: { id: ID }): Promise; + + async findOneOwnership(params: { filter: FilterQuery }): Promise; + + async findOneOwnership(params: { id?: ID; filter?: FilterQuery }): Promise { + const document = await this.ownershipRepository.findOne(params as never); + + if (!document) { + return null; + } + + return { + ...document, + }; + } + + + async bulkWrite(instructions: Record[]): Promise + { + const model = await this.ownershipRepository.model; + + return model.bulkWrite(instructions); + + } + + + async findOwnerships( + params: { filter: FilterQuery }, + ): Promise { + return R.map((item) => ({ + ...item, + }), await this.ownershipRepository.find(params)); + } +} diff --git a/token-gating/api/services/worker/src/index.ts b/token-gating/api/services/worker/src/index.ts index 4368b2dd..6201d891 100644 --- a/token-gating/api/services/worker/src/index.ts +++ b/token-gating/api/services/worker/src/index.ts @@ -17,9 +17,9 @@ import { CollectionStatus, } from '../types'; import { TYPES } from './types'; -import CollectionRepository from './repositories/collection'; -import OwnershipRepository from './repositories/ownership'; -import ObjectId, { ObjectType } from '../library/object-id'; +import CollectionController from './controllers/collection'; +import OwnershipController from './controllers/ownership'; +import ObjectId, { ObjectType } from '../../../library/object-id'; @injectable() export class WorkerService { @@ -27,9 +27,9 @@ export class WorkerService { @inject(GLOBAL_TYPES.logger) private readonly logger!: Logger; - @inject(TYPES.CollectionRepository) private readonly collectionRepository!: CollectionRepository; + @inject(TYPES.CollectionRepository) readonly collectionController!: CollectionController; - @inject(TYPES.OwnershipRepository) private readonly ownershipRepository!: OwnershipRepository; + @inject(TYPES.OwnershipController) readonly ownershipController!: OwnershipController; private static localQueue: Queue; @@ -109,7 +109,7 @@ export class WorkerService { private async digestEvents(events: Event[], _batchSize?: number | null) { const tokenIDList = R.uniq(events.map((event) => event.tokenID)); - const ownerships = await this.ownershipRepository.find({ + const ownerships = await this.ownershipController.findOwnerships({ filter: { tokenID: { $in: tokenIDList, @@ -120,7 +120,6 @@ export class WorkerService { const batchSize = _batchSize || 10000; let batch : Record[] = []; - const model = await this.ownershipRepository.model; let startTimestamp = 0; for (const event of events) { @@ -166,7 +165,7 @@ export class WorkerService { } if (batch.length >= batchSize) { - await model.bulkWrite(batch); + await this.ownershipController.bulkWrite(batch); this.logger.info(`BulkWrite(BATCH): timestamp => ${startTimestamp}-${timestamp} size => ${batch.length}`); startTimestamp = timestamp; batch = []; @@ -174,14 +173,14 @@ export class WorkerService { } if (batch.length > 0) { - await model.bulkWrite(batch); + await this.ownershipController.bulkWrite(batch); this.logger.info(`BulkWrite(FINAL): timestamp => ${startTimestamp}-${R.last(events)?.timestamp} size => ${batch.length}`); batch = []; } } async syncCollection(collection: ID, priority: boolean, blockSize?: number | null, batchSize?: number | null) { - const collectionData = await this.collectionRepository.findOne({ + const collectionData = await this.collectionController.findOneCollection({ id: collection, }); @@ -225,8 +224,10 @@ export class WorkerService { } } - await this.collectionRepository.updateOne({ - id: collection, + await this.collectionController.updateOneCollection({ + filter: { + id: collection, + }, data: { blockNumber: latestBlock || '0', status: latestBlock ? CollectionStatus.UPDATED : CollectionStatus.INITIALIZING, diff --git a/token-gating/api/services/worker/src/inversify.config.ts b/token-gating/api/services/worker/src/inversify.config.ts index b3338ace..bea541c9 100644 --- a/token-gating/api/services/worker/src/inversify.config.ts +++ b/token-gating/api/services/worker/src/inversify.config.ts @@ -5,13 +5,17 @@ import { WorkerService } from '.'; import { TYPES } from './types'; import CollectionRepository from './repositories/collection'; import OwnershipRepository from './repositories/ownership'; +import CollectionController from './controllers/collection'; +import OwnershipController from './controllers/ownership'; const container = new Container(); container.bind(TYPES.ETHERSCAN_KEY).toConstantValue('S1W3GXNSMC72X93RF6XD2VPMQVXUUC5KY2'); container.bind(TYPES.CollectionRepository).to(CollectionRepository).inSingletonScope(); container.bind(TYPES.OwnershipRepository).to(OwnershipRepository).inSingletonScope(); +container.bind(TYPES.CollectionController).to(CollectionController).inSingletonScope(); +container.bind(TYPES.OwnershipController).to(OwnershipController).inSingletonScope(); container.bind(GLOBAL_TYPES.WorkerService).to(WorkerService).inSingletonScope(); -container.bind(TYPES.PORT).toConstantValue(parseInt(process.env.PORT || '8080', 10)); + export { container }; diff --git a/token-gating/api/services/worker/src/repositories/collection.ts b/token-gating/api/services/worker/src/repositories/collection.ts index 1eb81346..40aa2c43 100644 --- a/token-gating/api/services/worker/src/repositories/collection.ts +++ b/token-gating/api/services/worker/src/repositories/collection.ts @@ -6,7 +6,7 @@ import { Collection, CollectionStatus, } from '../../types'; -import Repository from '../../library/repository'; +import Repository from '../../../../library/repository'; type CollectionDocument = Document & Collection; @@ -14,7 +14,7 @@ type CollectionDocument = Document & Collection; export default class CollectionRepository extends Repository< Collection, - Pick & Partial>, + Pick & Partial>, Partial> > { async getModel(db: Connection) { diff --git a/token-gating/api/services/worker/src/repositories/ownership.ts b/token-gating/api/services/worker/src/repositories/ownership.ts index c83f80c9..f903d818 100644 --- a/token-gating/api/services/worker/src/repositories/ownership.ts +++ b/token-gating/api/services/worker/src/repositories/ownership.ts @@ -5,7 +5,7 @@ import { ID, Ownership, } from '../../types'; -import Repository from '../../library/repository'; +import Repository from '../../../../library/repository'; type OwnershipDocument = Document & Ownership; diff --git a/token-gating/api/services/worker/src/types.ts b/token-gating/api/services/worker/src/types.ts index b0b4a5b7..01dd686a 100644 --- a/token-gating/api/services/worker/src/types.ts +++ b/token-gating/api/services/worker/src/types.ts @@ -6,4 +6,6 @@ export const TYPES = { BASE_URL: Symbol.for('BASE_URL'), CollectionRepository: Symbol.for('CollectionRepository'), OwnershipRepository: Symbol.for('OwnershipRepository'), + CollectionController: Symbol.for('CollectionController'), + OwnershipController: Symbol.for('OwnershipController'), }; diff --git a/token-gating/api/services/worker/tests/helpers/generate-ownership.ts b/token-gating/api/services/worker/tests/helpers/generate-ownership.ts index 75daeb00..b604bb90 100644 --- a/token-gating/api/services/worker/tests/helpers/generate-ownership.ts +++ b/token-gating/api/services/worker/tests/helpers/generate-ownership.ts @@ -1,5 +1,5 @@ import faker from 'faker'; -import ObjectId, { ObjectType } from '../../library/object-id'; +import ObjectId, { ObjectType } from '../../../../library/object-id'; import { ID } from '../../types'; export default function (collectionID: ID, tokenId?: string | null) { diff --git a/token-gating/api/services/worker/tests/worker-service-test.spec.ts b/token-gating/api/services/worker/tests/worker-service-test.spec.ts index d3545def..7f4481fe 100644 --- a/token-gating/api/services/worker/tests/worker-service-test.spec.ts +++ b/token-gating/api/services/worker/tests/worker-service-test.spec.ts @@ -7,7 +7,7 @@ import { Context as FixtureContext, setup, teardown } from './helpers/fixture'; import { TYPES } from '../src/types'; import { TYPES as GLOBAL_TYPES, CollectionStatus, Collection } from '../types'; import { container } from '../inversify.config'; -import ObjectId, { ObjectType } from '../library/object-id'; +import ObjectId, { ObjectType } from '../../../library/object-id'; import { WorkerService } from '../src/index'; import OwnershipRepository from '../src/repositories/ownership'; import generateOwnership from './helpers/generate-ownership'; diff --git a/token-gating/api/types/holder-account.ts b/token-gating/api/types/holder-account.ts new file mode 100644 index 00000000..8bbe9a75 --- /dev/null +++ b/token-gating/api/types/holder-account.ts @@ -0,0 +1,7 @@ +import { AccountNext, AccountRole } from './account'; + +export type HolderAccount = AccountNext & { + ethereumAddress: string; + discordAccessToken: string; + role: AccountRole.HOLDER; +}; diff --git a/token-gating/api/types/index.ts b/token-gating/api/types/index.ts index b44a6923..efb2bf39 100644 --- a/token-gating/api/types/index.ts +++ b/token-gating/api/types/index.ts @@ -4,6 +4,7 @@ export * from './collection'; export * from './ownership'; export * from './admin-account'; export * from './project'; +export * from './holder-account'; export const TYPES = { MONGODB_URI: Symbol.for('MONGODB_URI'), diff --git a/token-gating/api/types/project.ts b/token-gating/api/types/project.ts index 08b1079c..86afbf07 100644 --- a/token-gating/api/types/project.ts +++ b/token-gating/api/types/project.ts @@ -6,6 +6,7 @@ export type Project = Node & { contractAddress: string; discordId: string; discordChannel: string; + discordBotAccessToken: string; createdAt: Date; updatedAt: Date; }; From d4c9b0027b4a74b45d81c5bd190d19bca6a1c479 Mon Sep 17 00:00:00 2001 From: alresarena2021 Date: Mon, 14 Feb 2022 10:11:03 +0800 Subject: [PATCH 2/7] build(package): add koa router module --- token-gating/api/package-lock.json | 112 +++++++++++++++++++++++++++++ token-gating/api/package.json | 9 ++- 2 files changed, 118 insertions(+), 3 deletions(-) diff --git a/token-gating/api/package-lock.json b/token-gating/api/package-lock.json index 194c177c..5e3b5a95 100644 --- a/token-gating/api/package-lock.json +++ b/token-gating/api/package-lock.json @@ -18,6 +18,7 @@ "@highoutput/hash": "^0.1.11", "@highoutput/logger": "^0.5.4", "@koa/cors": "^3.1.0", + "@koa/router": "^10.1.1", "@types/bluebird": "^3.5.36", "@types/node": "^14.17.5", "@types/p-queue": "^3.2.1", @@ -78,6 +79,7 @@ "ts-node": "^10.2.1", "tsify": "^5.0.4", "typescript": "^4.4.2", + "with-query": "^1.3.0", "ws": "^8.2.3" }, "devDependencies": { @@ -87,6 +89,7 @@ "@types/jsonfile": "^6.0.1", "@types/jsonwebtoken": "^8.5.8", "@types/koa": "^2.13.4", + "@types/koa__router": "^8.0.11", "@types/koa-bodyparser": "^4.3.5", "@types/lru-cache": "^5.1.1", "@types/luxon": "^2.0.9", @@ -2259,6 +2262,47 @@ "node": ">= 8.0.0" } }, + "node_modules/@koa/router": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@koa/router/-/router-10.1.1.tgz", + "integrity": "sha512-ORNjq5z4EmQPriKbR0ER3k4Gh7YGNhWDL7JBW+8wXDrHLbWYKYSJaOJ9aN06npF5tbTxe2JBOsurpJDAvjiXKw==", + "dependencies": { + "debug": "^4.1.1", + "http-errors": "^1.7.3", + "koa-compose": "^4.1.0", + "methods": "^1.1.2", + "path-to-regexp": "^6.1.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@koa/router/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@koa/router/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/@koa/router/node_modules/path-to-regexp": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.0.tgz", + "integrity": "sha512-f66KywYG6+43afgE/8j/GoiNyygk/bnoCbps++3ErRKsIYkGGupyv07R2Ok5m9i67Iqc+T2g1eAUGUPzWhYTyg==" + }, "node_modules/@next/env": { "version": "12.0.10", "resolved": "https://registry.npmjs.org/@next/env/-/env-12.0.10.tgz", @@ -2875,6 +2919,15 @@ "@types/koa": "*" } }, + "node_modules/@types/koa__router": { + "version": "8.0.11", + "resolved": "https://registry.npmjs.org/@types/koa__router/-/koa__router-8.0.11.tgz", + "integrity": "sha512-WXgKWpBsbS14kzmzD9LeFapOIa678h7zvUHxDwXwSx4ETKXhXLVUAToX6jZ/U7EihM7qwyD9W/BZvB0MRu7MTQ==", + "dev": true, + "dependencies": { + "@types/koa": "*" + } + }, "node_modules/@types/koa-bodyparser": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/@types/koa-bodyparser/-/koa-bodyparser-4.3.5.tgz", @@ -12118,6 +12171,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/with-query": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/with-query/-/with-query-1.3.0.tgz", + "integrity": "sha512-grR6VEgM5imGOcQChTHN7D+mqavGBUo9EXzzge18EVagyFqBLVfA+amXmN30RLtnt9gJoiHmpSzhq6sfI3GrKQ==", + "dependencies": { + "@types/qs": "^6.9.1", + "qs": "^6.9.3" + } + }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -13826,6 +13888,38 @@ "vary": "^1.1.2" } }, + "@koa/router": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@koa/router/-/router-10.1.1.tgz", + "integrity": "sha512-ORNjq5z4EmQPriKbR0ER3k4Gh7YGNhWDL7JBW+8wXDrHLbWYKYSJaOJ9aN06npF5tbTxe2JBOsurpJDAvjiXKw==", + "requires": { + "debug": "^4.1.1", + "http-errors": "^1.7.3", + "koa-compose": "^4.1.0", + "methods": "^1.1.2", + "path-to-regexp": "^6.1.0" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "path-to-regexp": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.0.tgz", + "integrity": "sha512-f66KywYG6+43afgE/8j/GoiNyygk/bnoCbps++3ErRKsIYkGGupyv07R2Ok5m9i67Iqc+T2g1eAUGUPzWhYTyg==" + } + } + }, "@next/env": { "version": "12.0.10", "resolved": "https://registry.npmjs.org/@next/env/-/env-12.0.10.tgz", @@ -14316,6 +14410,15 @@ "@types/koa": "*" } }, + "@types/koa__router": { + "version": "8.0.11", + "resolved": "https://registry.npmjs.org/@types/koa__router/-/koa__router-8.0.11.tgz", + "integrity": "sha512-WXgKWpBsbS14kzmzD9LeFapOIa678h7zvUHxDwXwSx4ETKXhXLVUAToX6jZ/U7EihM7qwyD9W/BZvB0MRu7MTQ==", + "dev": true, + "requires": { + "@types/koa": "*" + } + }, "@types/koa-bodyparser": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/@types/koa-bodyparser/-/koa-bodyparser-4.3.5.tgz", @@ -21368,6 +21471,15 @@ "is-typed-array": "^1.1.7" } }, + "with-query": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/with-query/-/with-query-1.3.0.tgz", + "integrity": "sha512-grR6VEgM5imGOcQChTHN7D+mqavGBUo9EXzzge18EVagyFqBLVfA+amXmN30RLtnt9gJoiHmpSzhq6sfI3GrKQ==", + "requires": { + "@types/qs": "^6.9.1", + "qs": "^6.9.3" + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", diff --git a/token-gating/api/package.json b/token-gating/api/package.json index b346066c..28365c83 100644 --- a/token-gating/api/package.json +++ b/token-gating/api/package.json @@ -7,9 +7,9 @@ "clean": "rimraf dist/", "lint": "eslint . --ext .ts", "lint:fix": "eslint . --ext .ts --fix --cache", - "start:local": "cross-env MONGODB_URI=mongodb://localhost/token-gating DEBUG=error*,critical*,info* TS_NODE_PROJECT=./tsconfig.json TS_NODE_FILES=true ts-node ./index.ts", - "start": "cross-env MONGODB_URI=mongodb+srv://obiwan45:lasaw321@cluster0.2crm5.mongodb.net/token-gating?connectTimeoutMS=20000&authSource=admin&authMechanism=SCRAM-SHA-1 DEBUG=error*,critical*,info* TS_NODE_PROJECT=./tsconfig.json TS_NODE_FILES=true ts-node ./index.ts", - "test": "cross-env DEBUG=error*,critical*,info* jest -w 1 --detectOpenHandles --forceExit", + "start:local": "cross-env MONGODB_URI=mongodb://localhost/token-gating DEBUG=error*,critical*,info*,warn* TS_NODE_PROJECT=./tsconfig.json TS_NODE_FILES=true ts-node ./index.ts", + "start": "cross-env MONGODB_URI=mongodb+srv://obiwan45:lasaw321@cluster0.2crm5.mongodb.net/token-gating?connectTimeoutMS=20000&authSource=admin&authMechanism=SCRAM-SHA-1 DEBUG=error*,critical*,info*,warn* TS_NODE_PROJECT=./tsconfig.json TS_NODE_FILES=true ts-node ./index.ts", + "test": "cross-env DEBUG=error*,critical*,info*,warn* jest -w 1 --detectOpenHandles --forceExit", "typecheck": "tsc --project tsconfig.json --noEmit" }, "author": "", @@ -24,6 +24,7 @@ "@highoutput/hash": "^0.1.11", "@highoutput/logger": "^0.5.4", "@koa/cors": "^3.1.0", + "@koa/router": "^10.1.1", "@types/bluebird": "^3.5.36", "@types/node": "^14.17.5", "@types/p-queue": "^3.2.1", @@ -84,6 +85,7 @@ "ts-node": "^10.2.1", "tsify": "^5.0.4", "typescript": "^4.4.2", + "with-query": "^1.3.0", "ws": "^8.2.3" }, "devDependencies": { @@ -93,6 +95,7 @@ "@types/jsonfile": "^6.0.1", "@types/jsonwebtoken": "^8.5.8", "@types/koa": "^2.13.4", + "@types/koa__router": "^8.0.11", "@types/koa-bodyparser": "^4.3.5", "@types/lru-cache": "^5.1.1", "@types/luxon": "^2.0.9", From 29fd178964717c4452e8d56691ba4d75cb62600f Mon Sep 17 00:00:00 2001 From: alresarena2021 Date: Mon, 14 Feb 2022 10:16:50 +0800 Subject: [PATCH 3/7] feat: add holder account bindings to inversify --- token-gating/api/services/account/inversify.config.ts | 5 ++++- .../api/services/account/repositories/holder-account.ts | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/token-gating/api/services/account/inversify.config.ts b/token-gating/api/services/account/inversify.config.ts index 41d1dee8..d63ce376 100644 --- a/token-gating/api/services/account/inversify.config.ts +++ b/token-gating/api/services/account/inversify.config.ts @@ -7,13 +7,16 @@ import { AccountService } from './index'; import AdminAccountRepository from './repositories/admin-account'; import AdminAccountController from './controllers/admin-account'; +import HolderAccountRepository from './repositories/holder-account'; +import HolderAccountController from './controllers/holder-account'; const container = new Container(); container.bind(GLOBAL_TYPES.cryptoRandomString).toFunction(cryptoRandomString); container.bind(TYPES.AdminAccountRepository).to(AdminAccountRepository).inSingletonScope(); container.bind(TYPES.AdminAccountController).to(AdminAccountController).inSingletonScope(); - +container.bind(TYPES.HolderAccountRepository).to(HolderAccountRepository).inSingletonScope(); +container.bind(TYPES.HolderAccountController).to(HolderAccountController).inSingletonScope(); container.bind(GLOBAL_TYPES.AccountService).to(AccountService).inSingletonScope(); export { container }; diff --git a/token-gating/api/services/account/repositories/holder-account.ts b/token-gating/api/services/account/repositories/holder-account.ts index 8b959a9f..be94f861 100644 --- a/token-gating/api/services/account/repositories/holder-account.ts +++ b/token-gating/api/services/account/repositories/holder-account.ts @@ -47,6 +47,6 @@ export default class HolderAccountRepository schema.index({ createdAt: 1 }); - return db.model('HolderAccount', schema); + return db.model('holder', schema); } } From 57ff3db15267bb1318a841a834620c4fe9481380 Mon Sep 17 00:00:00 2001 From: alresarena2021 Date: Mon, 14 Feb 2022 10:18:47 +0800 Subject: [PATCH 4/7] refactor: refactor admin account mongodb collection name to admin --- token-gating/api/services/account/repositories/admin-account.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/token-gating/api/services/account/repositories/admin-account.ts b/token-gating/api/services/account/repositories/admin-account.ts index d1a44584..5fddb3f5 100644 --- a/token-gating/api/services/account/repositories/admin-account.ts +++ b/token-gating/api/services/account/repositories/admin-account.ts @@ -43,6 +43,6 @@ export default class AdminAccountRepository schema.index({ createdAt: 1 }); - return db.model('AdminAccount', schema); + return db.model('admin', schema); } } From d76faca401910c0eda08b55ca46f3dc7eff2e4eb Mon Sep 17 00:00:00 2001 From: alresarena2021 Date: Mon, 14 Feb 2022 10:20:14 +0800 Subject: [PATCH 5/7] feat: add ownership validation on generateProjectAccessToken endpoint --- .../api/resolvers/authentication/mutation.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/token-gating/api/services/api/resolvers/authentication/mutation.ts b/token-gating/api/services/api/resolvers/authentication/mutation.ts index 19db7b04..38f1a735 100644 --- a/token-gating/api/services/api/resolvers/authentication/mutation.ts +++ b/token-gating/api/services/api/resolvers/authentication/mutation.ts @@ -122,6 +122,22 @@ export default { }; } + const ownershipExists = await ctx.services.worker.ownershipController.ownershipExists({ + filter: { + owner: ethAddress, + }, + }); + + if (!ownershipExists) { + return { + data: null, + error: { + __typename: 'NftOwnershipDoesNotExistError', + message: 'NFT Ownership does not exist', + }, + }; + } + let holderAccount = await ctx.services.account.holderAccountController.findOneHolderAccount({ filter: { ethereumAddress: ethAddress, From c6862f3a67f17caf1d3e0d361c8fc9b0731492c0 Mon Sep 17 00:00:00 2001 From: alresarena2021 Date: Mon, 14 Feb 2022 10:20:44 +0800 Subject: [PATCH 6/7] feat: revamp create project endpoint --- .../api/resolvers/project/mutation.ts | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/token-gating/api/services/api/resolvers/project/mutation.ts b/token-gating/api/services/api/resolvers/project/mutation.ts index b3ed7744..1773efc6 100644 --- a/token-gating/api/services/api/resolvers/project/mutation.ts +++ b/token-gating/api/services/api/resolvers/project/mutation.ts @@ -43,13 +43,35 @@ export default { }; } - const collectionExists = await ctx.services.worker.collectionController.collectionExists({ + logger.info(`DiscordToken: ${userInfo.email}`); + + let collection = await ctx.services.worker.collectionController.findOneCollection({ + filter: { + contractAddress, + }, + }); + + if (!collection) { + collection = await ctx.services.worker.collectionController.createCollection({ + id: ObjectId.generate(ObjectType.COLLECTION).buffer, + data: { + contractAddress, + }, + }); + + AsyncGroup.add(ctx.services.worker.syncCollection({ + collection: collection.id, + priority: true, + })); + } + + const projectExists = await ctx.services.project.projectController.findOneProject({ filter: { contractAddress, }, }); - if (collectionExists) { + if (projectExists) { logger.warn('Contract Address exists on other projects'); return { data: null, @@ -60,15 +82,6 @@ export default { }; } - const collection = await ctx.services.worker.collectionController.createCollection({ - id: ObjectId.generate(ObjectType.COLLECTION).buffer, - data: { - contractAddress, - }, - }); - - AsyncGroup.add(ctx.services.worker.syncCollection(collection.id, true)); - const project = await ctx.services.project.projectController.createProject({ id: ObjectId.generate(ObjectType.PROJECT).buffer, data: { From ce3d784771946792fa6654f4f3f80c7f08a79308 Mon Sep 17 00:00:00 2001 From: alresarena2021 Date: Mon, 14 Feb 2022 10:36:42 +0800 Subject: [PATCH 7/7] feat: revamp generate project access token --- .../api/services/api/type-defs/authentication.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/token-gating/api/services/api/type-defs/authentication.ts b/token-gating/api/services/api/type-defs/authentication.ts index e240dc56..fa4e2ba1 100644 --- a/token-gating/api/services/api/type-defs/authentication.ts +++ b/token-gating/api/services/api/type-defs/authentication.ts @@ -1,11 +1,11 @@ +/* eslint-disable max-len */ import { gql } from 'apollo-server-koa'; export default gql` enum AccountRole { ADMIN - CREATOR - FOLLOWER + HOLDER } type InvalidGoogleAccessTokenError implements Error { @@ -13,7 +13,6 @@ type InvalidGoogleAccessTokenError implements Error { } - union GenerateAccessTokenByGoogleError = InvalidGoogleAccessTokenError @@ -31,7 +30,6 @@ input GenerateAccessTokenByGoogleRequest { accessToken: String! } -# type InvalidDiscordAccessTokenError implements Error { message: String! @@ -41,15 +39,19 @@ type InvalidAuthenticationSignatureError implements Error { message: String! } -union GenerateProjectAccessTokenError = InvalidDiscordAccessTokenError | InvalidAuthenticationSignatureError +type NftOwnershipDoesNotExistError implements Error { + message: String! +} + + +union GenerateProjectAccessTokenError = InvalidDiscordAccessTokenError | InvalidAuthenticationSignatureError | NftOwnershipDoesNotExistError -union GenerateAccessTokenByGoogleError = InvalidGoogleAccessTokenError type GenerateProjectAccessTokenResponseData { accessToken: String! } type GenerateProjectAccessTokenResponse { - error: GenerateAccessTokenByGoogleError + error: GenerateProjectAccessTokenError data: GenerateProjectAccessTokenResponseData }