From 6abf37f62c34db6e10e67afc94f98ed205c73e8e Mon Sep 17 00:00:00 2001 From: Nick Poulden Date: Tue, 3 Oct 2023 14:22:07 -0600 Subject: [PATCH 1/3] Proof of yield custom resolver --- .prettierrc | 12 +- package-lock.json | 188 ++++++++++++++++++++++++ package.json | 1 + src/server-extension/resolver.ts | 128 ++++++++++++++++ src/server-extension/resolvers/index.ts | 1 + 5 files changed, 321 insertions(+), 9 deletions(-) create mode 100644 src/server-extension/resolver.ts create mode 100644 src/server-extension/resolvers/index.ts diff --git a/.prettierrc b/.prettierrc index 49841bef..1a68d900 100644 --- a/.prettierrc +++ b/.prettierrc @@ -3,15 +3,9 @@ "trailingComma": "all", "tabWidth": 2, "semi": false, - "importOrder": [ - "^@core/(.*)$", - "^@server/(.*)$", - "^@ui/(.*)$", - "^[./]" - ], + "importOrder": ["^@core/(.*)$", "^@server/(.*)$", "^@ui/(.*)$", "^[./]"], "importOrderSeparation": true, "importOrderSortSpecifiers": true, - "plugins": [ - "@trivago/prettier-plugin-sort-imports" - ] + "importOrderParserPlugins": ["typescript", "decorators-legacy"], + "plugins": ["@trivago/prettier-plugin-sort-imports"] } diff --git a/package-lock.json b/package-lock.json index d0cd1474..bc049bbd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "dotenv": "^16.1.4", "ethers": "^6.5.1", "pg": "^8.11.0", + "type-graphql": "^1.2.0-rc.1", "typeorm": "^0.3.16", "uuid": "^9.0.0", "viem": "^1.10.13" @@ -1388,6 +1389,15 @@ "integrity": "sha512-najjVq5KN2vsH2U/xyh2opaSEz6cZMR2SetLIlxlj08nOcmPOemJmUK2o4kUzfLqfrWE0PIrNeE16XhYDd3nqg==", "license": "MIT" }, + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, "node_modules/@types/http-errors": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.1.tgz", @@ -1406,6 +1416,11 @@ "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "license": "MIT" }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==" + }, "node_modules/@types/node": { "version": "18.17.15", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.15.tgz", @@ -1424,6 +1439,11 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "license": "MIT" }, + "node_modules/@types/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==" + }, "node_modules/@types/send": { "version": "0.17.1", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", @@ -1470,6 +1490,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/validator": { + "version": "13.11.2", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.2.tgz", + "integrity": "sha512-nIKVVQKT6kGKysnNt+xLobr+pFJNssJRi2s034wgWeFBUx01fI8BeHTW2TcRp7VcFu9QCYG8IlChTuovcm0oKQ==", + "peer": true + }, "node_modules/@types/ws": { "version": "8.5.5", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", @@ -2022,6 +2048,17 @@ "node": ">=4" } }, + "node_modules/class-validator": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.0.tgz", + "integrity": "sha512-ct3ltplN8I9fOwUd8GrP8UQixwff129BkEtuWDKL5W45cQuLd19xqmTLu5ge78YDm/fdje6FMt0hGOhl0lii3A==", + "peer": true, + "dependencies": { + "@types/validator": "^13.7.10", + "libphonenumber-js": "^1.10.14", + "validator": "^13.7.0" + } + }, "node_modules/cli-highlight": { "version": "2.1.11", "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", @@ -2169,6 +2206,11 @@ "node": ">=16" } }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -2853,6 +2895,28 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "license": "MIT" }, + "node_modules/graphql-query-complexity": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/graphql-query-complexity/-/graphql-query-complexity-0.7.2.tgz", + "integrity": "sha512-+VgmrfxGEjHI3zuojWOR8bsz7Ycz/BZjNjxnlUieTz5DsB92WoIrYCSZdWG7UWZ3rfcA1Gb2Nf+wB80GsaZWuQ==", + "dependencies": { + "lodash.get": "^4.4.2" + }, + "peerDependencies": { + "graphql": "^0.13.0 || ^14.0.0 || ^15.0.0" + } + }, + "node_modules/graphql-subscriptions": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/graphql-subscriptions/-/graphql-subscriptions-1.2.1.tgz", + "integrity": "sha512-95yD/tKi24q8xYa7Q9rhQN16AYj5wPbrb8tmHGM3WRc9EBmWrG/0kkMl+tQG8wcEuE9ibR4zyOM31p5Sdr2v4g==", + "dependencies": { + "iterall": "^1.3.0" + }, + "peerDependencies": { + "graphql": "^0.10.5 || ^0.11.3 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0" + } + }, "node_modules/graphql-tag": { "version": "2.12.6", "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz", @@ -3355,6 +3419,11 @@ "ws": "*" } }, + "node_modules/iterall": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz", + "integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==" + }, "node_modules/javascript-natural-sort": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", @@ -3397,6 +3466,12 @@ "json-buffer": "3.0.1" } }, + "node_modules/libphonenumber-js": { + "version": "1.10.45", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.45.tgz", + "integrity": "sha512-eeHcvGafEYCaKB4fo2uBINfG7j7PcGwBHUaTVfbwl/6KcjCgIKNlIOsSXVRp9BH10NQwmvvk+nQ1e/Yp4BGB7w==", + "peer": true + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -3410,6 +3485,11 @@ "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", "license": "MIT" }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" + }, "node_modules/lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", @@ -3740,6 +3820,14 @@ "node": ">= 0.8" } }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -4050,6 +4138,31 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -4318,6 +4431,72 @@ "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", "license": "ISC" }, + "node_modules/type-graphql": { + "version": "1.2.0-rc.1", + "resolved": "https://registry.npmjs.org/type-graphql/-/type-graphql-1.2.0-rc.1.tgz", + "integrity": "sha512-W1p51DN+n/zX4ilunMC6/FcyGlx/ND3hreQ0ARDhfhyR9oGtfKzQNnkHhk8uXlYm2zzyTEd1LkRHJr8bbnRlIA==", + "hasInstallScript": true, + "dependencies": { + "@types/glob": "^7.1.3", + "@types/node": "*", + "@types/semver": "^7.3.4", + "glob": "^7.1.6", + "graphql-query-complexity": "^0.7.2", + "graphql-subscriptions": "^1.2.0", + "semver": "^7.3.4", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">= 10.13" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typegraphql" + }, + "peerDependencies": { + "class-validator": ">=0.12.0", + "graphql": "^15.5.0" + } + }, + "node_modules/type-graphql/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/type-graphql/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/type-graphql/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -4555,6 +4734,15 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/validator": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", + "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==", + "peer": true, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/value-or-promise": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.11.tgz", diff --git a/package.json b/package.json index 948e0d20..ad6c7152 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "dotenv": "^16.1.4", "ethers": "^6.5.1", "pg": "^8.11.0", + "type-graphql": "^1.2.0-rc.1", "typeorm": "^0.3.16", "uuid": "^9.0.0", "viem": "^1.10.13" diff --git a/src/server-extension/resolver.ts b/src/server-extension/resolver.ts new file mode 100644 index 00000000..8df0dfa7 --- /dev/null +++ b/src/server-extension/resolver.ts @@ -0,0 +1,128 @@ +import { + Arg, + Field, + ObjectType, + Query, + Resolver, + registerEnumType, +} from 'type-graphql' +import type { EntityManager } from 'typeorm' + +import { OETH } from '../model' + +// Define custom GraphQL ObjectType of the query result +@ObjectType() +export class ProofOfYieldResult { + @Field(() => String, { nullable: false }) + id!: string + + @Field(() => Date, { nullable: false }) + timestamp!: Date + + @Field(() => Number, { nullable: false }) + apy!: number + + @Field(() => BigInt, { nullable: false }) + yield!: bigint + + @Field(() => BigInt, { nullable: false }) + rebasingSupply!: bigint + + constructor(props: Partial) { + Object.assign(this, props) + } +} + +export enum OrderBy { + id_ASC = 'id_ASC', + id_DESC = 'id_DESC', + timestamp_ASC = 'timestamp_ASC', + timestamp_DESC = 'timestamp_DESC', +} + +registerEnumType(OrderBy, { name: 'OrderBy' }) + +@Resolver() +export class ProofOfYieldResolver { + constructor(private tx: () => Promise) {} + + @Query(() => [ProofOfYieldResult]) + async proofOfYields( + @Arg('limit', { nullable: true, defaultValue: 20 }) limit: number, + @Arg('offset', { nullable: true, defaultValue: 0 }) offset: number, + @Arg('orderBy', (type) => OrderBy, { + nullable: true, + defaultValue: OrderBy.timestamp_DESC, + }) + orderBy: OrderBy, + ): Promise { + const manager = await this.tx() + + let orderClause = '' + switch (orderBy) { + case 'id_ASC': + orderClause = 'o.date ASC' + break + case 'id_DESC': + orderClause = 'o.date DESC' + break + case 'timestamp_ASC': + orderClause = 'o.date ASC' + break + case 'timestamp_DESC': + orderClause = 'o.date DESC' + break + default: + throw new Error('Invalid orderBy value') + } + + const sql = `WITH + oeth_aggregated AS ( + SELECT + DATE(timestamp) AS date, + MAX(rebasing_supply) AS max_rebasing_supply + FROM + oeth + GROUP BY + DATE(timestamp) + ), + + apy_aggregated AS ( + SELECT + DATE(timestamp) AS date, + MAX(apy7_day_avg) AS max_apy7_day_avg + FROM + apy + GROUP BY + DATE(timestamp) + ), + + rebase_aggregated AS ( + SELECT + DATE(timestamp) AS date, + SUM(yield - fee) AS total_yield + FROM + rebase + GROUP BY + DATE(timestamp) + ) + + SELECT + TO_CHAR(o.date, 'YYYY-MM-DD') as id, + o.date as timestamp, + a.max_apy7_day_avg as apy, + o.max_rebasing_supply as "rebasingSupply", + r.total_yield as yield + FROM + oeth_aggregated o + JOIN + apy_aggregated a ON o.date = a.date + LEFT JOIN + rebase_aggregated r ON o.date = r.date + ORDER BY ${orderClause} + LIMIT $1 OFFSET $2;` + + const result = await manager.getRepository(OETH).query(sql, [limit, offset]) + return result + } +} diff --git a/src/server-extension/resolvers/index.ts b/src/server-extension/resolvers/index.ts new file mode 100644 index 00000000..ff464062 --- /dev/null +++ b/src/server-extension/resolvers/index.ts @@ -0,0 +1 @@ +export { ProofOfYieldResolver } from '../resolver' \ No newline at end of file From 7315f9f897114d4bb5fca176f667280ff3a6f2b0 Mon Sep 17 00:00:00 2001 From: Nick Poulden Date: Wed, 4 Oct 2023 09:09:39 -0600 Subject: [PATCH 2/3] Proof of yield by ID --- src/server-extension/resolvers/index.ts | 3 +- .../resolvers/proof-of-yield-by-id.ts | 98 +++++++++++++++++++ .../proof-of-yields.ts} | 2 +- 3 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 src/server-extension/resolvers/proof-of-yield-by-id.ts rename src/server-extension/{resolver.ts => resolvers/proof-of-yields.ts} (98%) diff --git a/src/server-extension/resolvers/index.ts b/src/server-extension/resolvers/index.ts index ff464062..1fa13d97 100644 --- a/src/server-extension/resolvers/index.ts +++ b/src/server-extension/resolvers/index.ts @@ -1 +1,2 @@ -export { ProofOfYieldResolver } from '../resolver' \ No newline at end of file +export { ProofOfYieldResolver } from './proof-of-yields' +export { ProofOfYieldByIdResolver } from './proof-of-yield-by-id' \ No newline at end of file diff --git a/src/server-extension/resolvers/proof-of-yield-by-id.ts b/src/server-extension/resolvers/proof-of-yield-by-id.ts new file mode 100644 index 00000000..ebeede4f --- /dev/null +++ b/src/server-extension/resolvers/proof-of-yield-by-id.ts @@ -0,0 +1,98 @@ +import { + Arg, + Field, + ObjectType, + Query, + Resolver, + registerEnumType, +} from 'type-graphql' +import type { EntityManager } from 'typeorm' + +import { OETH } from '../../model' + +// Define custom GraphQL ObjectType of the query result +@ObjectType() +export class ProofOfYieldByIdResult { + @Field(() => String, { nullable: false }) + id!: string + + @Field(() => Date, { nullable: false }) + timestamp!: Date + + @Field(() => Number, { nullable: false }) + apy!: number + + @Field(() => BigInt, { nullable: false }) + yield!: bigint + + @Field(() => BigInt, { nullable: false }) + rebasingSupply!: bigint + + constructor(props: Partial) { + Object.assign(this, props) + } +} + +@Resolver() +export class ProofOfYieldByIdResolver { + constructor(private tx: () => Promise) {} + + @Query(() => ProofOfYieldByIdResult, { nullable: true }) + async proofOfYieldById( + @Arg('id') id: string, + ): Promise { + if (!id) { + return null + } + + const manager = await this.tx() + + const sql = `WITH + oeth_aggregated AS ( + SELECT + DATE(timestamp) AS date, + MAX(rebasing_supply) AS max_rebasing_supply + FROM + oeth + GROUP BY + DATE(timestamp) + ), + + apy_aggregated AS ( + SELECT + DATE(timestamp) AS date, + MAX(apy7_day_avg) AS max_apy7_day_avg + FROM + apy + GROUP BY + DATE(timestamp) + ), + + rebase_aggregated AS ( + SELECT + DATE(timestamp) AS date, + SUM(yield - fee) AS total_yield + FROM + rebase + GROUP BY + DATE(timestamp) + ) + + SELECT + TO_CHAR(o.date, 'YYYY-MM-DD') as id, + o.date as timestamp, + a.max_apy7_day_avg as apy, + o.max_rebasing_supply as "rebasingSupply", + r.total_yield as yield + FROM + oeth_aggregated o + JOIN + apy_aggregated a ON o.date = a.date + LEFT JOIN + rebase_aggregated r ON o.date = r.date + WHERE o.date = $1;` + + const result = await manager.getRepository(OETH).query(sql, [id]) + return result?.[0] + } +} diff --git a/src/server-extension/resolver.ts b/src/server-extension/resolvers/proof-of-yields.ts similarity index 98% rename from src/server-extension/resolver.ts rename to src/server-extension/resolvers/proof-of-yields.ts index 8df0dfa7..7712b116 100644 --- a/src/server-extension/resolver.ts +++ b/src/server-extension/resolvers/proof-of-yields.ts @@ -8,7 +8,7 @@ import { } from 'type-graphql' import type { EntityManager } from 'typeorm' -import { OETH } from '../model' +import { OETH } from '../../model' // Define custom GraphQL ObjectType of the query result @ObjectType() From ed128fb47e43f5f7a8737e8871d3c169d9a05ca6 Mon Sep 17 00:00:00 2001 From: Nick Poulden Date: Thu, 5 Oct 2023 15:58:08 -0600 Subject: [PATCH 3/3] Proof of yield --- .../resolvers/proof-of-yield-by-id.ts | 92 ++++++++++--------- 1 file changed, 50 insertions(+), 42 deletions(-) diff --git a/src/server-extension/resolvers/proof-of-yield-by-id.ts b/src/server-extension/resolvers/proof-of-yield-by-id.ts index ebeede4f..de454ee0 100644 --- a/src/server-extension/resolvers/proof-of-yield-by-id.ts +++ b/src/server-extension/resolvers/proof-of-yield-by-id.ts @@ -25,9 +25,21 @@ export class ProofOfYieldByIdResult { @Field(() => BigInt, { nullable: false }) yield!: bigint + @Field(() => BigInt, { nullable: false }) + fees!: bigint + + @Field(() => BigInt, { nullable: false }) + totalSupply!: bigint + @Field(() => BigInt, { nullable: false }) rebasingSupply!: bigint + @Field(() => BigInt, { nullable: false }) + nonRebasingSupply!: bigint + + @Field(() => BigInt, { nullable: false }) + amoSupply!: bigint + constructor(props: Partial) { Object.assign(this, props) } @@ -47,50 +59,46 @@ export class ProofOfYieldByIdResolver { const manager = await this.tx() - const sql = `WITH - oeth_aggregated AS ( - SELECT - DATE(timestamp) AS date, - MAX(rebasing_supply) AS max_rebasing_supply - FROM - oeth - GROUP BY - DATE(timestamp) - ), - - apy_aggregated AS ( - SELECT - DATE(timestamp) AS date, - MAX(apy7_day_avg) AS max_apy7_day_avg - FROM - apy - GROUP BY - DATE(timestamp) - ), - - rebase_aggregated AS ( + const sql = `SELECT + $1 as timestamp, + oeth_data.rebasing_supply AS "rebasingSupply", + oeth_data.total_supply AS "totalSupply", + oeth_data.non_rebasing_supply AS "nonRebasingSupply", + apy_data.apy7_day_avg as apy, + curve_data.oeth_owned AS "amoSupply", + rebase_data.total_yield as yield, + rebase_data.total_fees as fees + FROM + (SELECT 1) AS dummy -- A dummy table to ensure we always get a row + LEFT JOIN LATERAL ( + SELECT oeth.rebasing_supply, oeth.total_supply, oeth.non_rebasing_supply + FROM oeth + WHERE DATE(oeth.timestamp) <= $1 + ORDER BY oeth.timestamp DESC + LIMIT 1 + ) AS oeth_data ON TRUE + LEFT JOIN LATERAL ( + SELECT apy.apy7_day_avg + FROM apy + WHERE DATE(apy.timestamp) <= $1 + ORDER BY apy.timestamp DESC + LIMIT 1 + ) AS apy_data ON TRUE + LEFT JOIN LATERAL ( + SELECT c.oeth_owned + FROM curve_lp c + WHERE DATE(c.timestamp) <= $1 + ORDER BY c.timestamp DESC + LIMIT 1 + ) AS curve_data ON TRUE + LEFT JOIN ( SELECT DATE(timestamp) AS date, - SUM(yield - fee) AS total_yield - FROM - rebase - GROUP BY - DATE(timestamp) - ) - - SELECT - TO_CHAR(o.date, 'YYYY-MM-DD') as id, - o.date as timestamp, - a.max_apy7_day_avg as apy, - o.max_rebasing_supply as "rebasingSupply", - r.total_yield as yield - FROM - oeth_aggregated o - JOIN - apy_aggregated a ON o.date = a.date - LEFT JOIN - rebase_aggregated r ON o.date = r.date - WHERE o.date = $1;` + SUM(yield - fee) AS total_yield, + SUM(fee) AS total_fees + FROM rebase + GROUP BY DATE(timestamp) + ) AS rebase_data ON rebase_data.date = $1;` const result = await manager.getRepository(OETH).query(sql, [id]) return result?.[0]