diff --git a/db/migrations/1703090085308-Data.js b/db/migrations/1703286033214-Data.js similarity index 96% rename from db/migrations/1703090085308-Data.js rename to db/migrations/1703286033214-Data.js index 3348cb56..732e2819 100644 --- a/db/migrations/1703090085308-Data.js +++ b/db/migrations/1703286033214-Data.js @@ -1,5 +1,5 @@ -module.exports = class Data1703090085308 { - name = 'Data1703090085308' +module.exports = class Data1703286033214 { + name = 'Data1703286033214' async up(db) { await db.query(`CREATE TABLE "exchange_rate" ("id" character varying NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "block_number" integer NOT NULL, "pair" text NOT NULL, "base" text NOT NULL, "quote" text NOT NULL, "rate" numeric NOT NULL, CONSTRAINT "PK_5c5d27d2b900ef6cdeef0398472" PRIMARY KEY ("id"))`) @@ -22,21 +22,28 @@ module.exports = class Data1703090085308 { await db.query(`CREATE TABLE "erc20_balance" ("id" character varying NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "block_number" integer NOT NULL, "address" text NOT NULL, "account" text NOT NULL, "balance" numeric NOT NULL, CONSTRAINT "PK_069b6549e7a9938cc89f32063a6" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_c9fbe21a3411d93ea586af2a4c" ON "erc20_balance" ("timestamp") `) await db.query(`CREATE INDEX "IDX_d1f50dc39003331b76fad8a640" ON "erc20_balance" ("block_number") `) + await db.query(`CREATE TABLE "curve_pool" ("id" character varying NOT NULL, "address" text NOT NULL, "name" text NOT NULL, "token_count" integer NOT NULL, "token0" text NOT NULL, "token1" text NOT NULL, "token2" text, CONSTRAINT "PK_c04bba36a8aa877d6efa4eafd6c" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_76c9202c1160ce818f7a29d131" ON "curve_pool" ("address") `) await db.query(`CREATE TABLE "curve_pool_balance" ("id" character varying NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "block_number" integer NOT NULL, "address" text NOT NULL, "balance0" numeric NOT NULL, "balance1" numeric NOT NULL, "balance2" numeric NOT NULL, CONSTRAINT "PK_40412750bb910ca560aa084dd88" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_ffb0d0f86f03faacef7cb3e092" ON "curve_pool_balance" ("timestamp") `) await db.query(`CREATE INDEX "IDX_db5522c865eb8ed76fa7aeb4a8" ON "curve_pool_balance" ("block_number") `) await db.query(`CREATE TABLE "curve_pool_rate" ("id" character varying NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "block_number" integer NOT NULL, "address" text NOT NULL, "name" text NOT NULL, "rate" numeric NOT NULL, CONSTRAINT "PK_91a04fe55298abe8abd8da1b813" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_561faf9883f4bb00ae6df34cc1" ON "curve_pool_rate" ("timestamp") `) await db.query(`CREATE INDEX "IDX_cefe6315e78e235fa4ab3de663" ON "curve_pool_rate" ("block_number") `) + await db.query(`CREATE TABLE "balancer_pool" ("id" character varying NOT NULL, "address" text NOT NULL, "name" text NOT NULL, "token_count" integer NOT NULL, "token0" text NOT NULL, "token1" text NOT NULL, "token2" text, "token3" text, CONSTRAINT "PK_d7d096bf445ae226ec938f8bb6a" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_0c5b4cc12b9d8b80ac5d983848" ON "balancer_pool" ("address") `) await db.query(`CREATE TABLE "balancer_pool_balance" ("id" character varying NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "block_number" integer NOT NULL, "address" text NOT NULL, "balance0" numeric NOT NULL, "balance1" numeric NOT NULL, "balance2" numeric NOT NULL, "balance3" numeric NOT NULL, CONSTRAINT "PK_441c7de293266414608c8e9de4c" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_642115282f1c3026edbc4bc2a7" ON "balancer_pool_balance" ("timestamp") `) await db.query(`CREATE INDEX "IDX_eecdc2d6132041e3806d77c7b4" ON "balancer_pool_balance" ("block_number") `) await db.query(`CREATE TABLE "balancer_pool_rate" ("id" character varying NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "block_number" integer NOT NULL, "address" text NOT NULL, "rate0" numeric NOT NULL, "rate1" numeric NOT NULL, "rate2" numeric NOT NULL, "rate3" numeric NOT NULL, CONSTRAINT "PK_3ca9825db8d15c7850b715d9121" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_b1656f8d048f72b38bb637ea24" ON "balancer_pool_rate" ("timestamp") `) await db.query(`CREATE INDEX "IDX_c55345ef048232dfe36e60e4c5" ON "balancer_pool_rate" ("block_number") `) + await db.query(`CREATE TABLE "maverick_pool" ("id" character varying NOT NULL, "address" text NOT NULL, "name" text NOT NULL, "token_a" text NOT NULL, "token_b" text NOT NULL, CONSTRAINT "PK_17580e27fedc439b0c145f11510" PRIMARY KEY ("id"))`) + await db.query(`CREATE INDEX "IDX_f04c4b9133d5c21af35b6f23d3" ON "maverick_pool" ("address") `) await db.query(`CREATE TABLE "maverick_pool_balance" ("id" character varying NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "block_number" integer NOT NULL, "address" text NOT NULL, "bin_balance_a" numeric NOT NULL, "bin_balance_b" numeric NOT NULL, CONSTRAINT "PK_e3c7008ecb64838c320f82e7036" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_e8046e8a298610b97bea2e6241" ON "maverick_pool_balance" ("timestamp") `) await db.query(`CREATE INDEX "IDX_6034a437728a8ccb3b49f4a348" ON "maverick_pool_balance" ("block_number") `) + await db.query(`CREATE TABLE "liquidity_source" ("id" character varying NOT NULL, "address" text NOT NULL, "type" character varying(12) NOT NULL, "token" text NOT NULL, CONSTRAINT "PK_5d25173fd367a0a7a901ee2f738" PRIMARY KEY ("id"))`) await db.query(`CREATE TABLE "oeth" ("id" character varying NOT NULL, "timestamp" TIMESTAMP WITH TIME ZONE NOT NULL, "block_number" integer NOT NULL, "total_supply" numeric NOT NULL, "rebasing_supply" numeric NOT NULL, "non_rebasing_supply" numeric NOT NULL, CONSTRAINT "PK_de1d885501070dbd1ab6f8577ba" PRIMARY KEY ("id"))`) await db.query(`CREATE INDEX "IDX_5b81a67229bac2d68e0dc92cc4" ON "oeth" ("timestamp") `) await db.query(`CREATE INDEX "IDX_408e5f79f83093aa5cf2b0ea32" ON "oeth" ("block_number") `) @@ -224,21 +231,28 @@ module.exports = class Data1703090085308 { await db.query(`DROP TABLE "erc20_balance"`) await db.query(`DROP INDEX "public"."IDX_c9fbe21a3411d93ea586af2a4c"`) await db.query(`DROP INDEX "public"."IDX_d1f50dc39003331b76fad8a640"`) + await db.query(`DROP TABLE "curve_pool"`) + await db.query(`DROP INDEX "public"."IDX_76c9202c1160ce818f7a29d131"`) await db.query(`DROP TABLE "curve_pool_balance"`) await db.query(`DROP INDEX "public"."IDX_ffb0d0f86f03faacef7cb3e092"`) await db.query(`DROP INDEX "public"."IDX_db5522c865eb8ed76fa7aeb4a8"`) await db.query(`DROP TABLE "curve_pool_rate"`) await db.query(`DROP INDEX "public"."IDX_561faf9883f4bb00ae6df34cc1"`) await db.query(`DROP INDEX "public"."IDX_cefe6315e78e235fa4ab3de663"`) + await db.query(`DROP TABLE "balancer_pool"`) + await db.query(`DROP INDEX "public"."IDX_0c5b4cc12b9d8b80ac5d983848"`) await db.query(`DROP TABLE "balancer_pool_balance"`) await db.query(`DROP INDEX "public"."IDX_642115282f1c3026edbc4bc2a7"`) await db.query(`DROP INDEX "public"."IDX_eecdc2d6132041e3806d77c7b4"`) await db.query(`DROP TABLE "balancer_pool_rate"`) await db.query(`DROP INDEX "public"."IDX_b1656f8d048f72b38bb637ea24"`) await db.query(`DROP INDEX "public"."IDX_c55345ef048232dfe36e60e4c5"`) + await db.query(`DROP TABLE "maverick_pool"`) + await db.query(`DROP INDEX "public"."IDX_f04c4b9133d5c21af35b6f23d3"`) await db.query(`DROP TABLE "maverick_pool_balance"`) await db.query(`DROP INDEX "public"."IDX_e8046e8a298610b97bea2e6241"`) await db.query(`DROP INDEX "public"."IDX_6034a437728a8ccb3b49f4a348"`) + await db.query(`DROP TABLE "liquidity_source"`) await db.query(`DROP TABLE "oeth"`) await db.query(`DROP INDEX "public"."IDX_5b81a67229bac2d68e0dc92cc4"`) await db.query(`DROP INDEX "public"."IDX_408e5f79f83093aa5cf2b0ea32"`) diff --git a/schema-base.graphql b/schema-base.graphql index 868aea9d..37b7165e 100644 --- a/schema-base.graphql +++ b/schema-base.graphql @@ -116,6 +116,16 @@ type ERC20Balance @entity { balance: BigInt! } +type CurvePool @entity { + id: ID! + address: String! @index + name: String! + tokenCount: Int! + token0: String! + token1: String! + token2: String +} + type CurvePoolBalance @entity { id: ID! timestamp: DateTime! @index @@ -135,6 +145,17 @@ type CurvePoolRate @entity { rate: BigInt! } +type BalancerPool @entity { + id: ID! + address: String! @index + name: String! + tokenCount: Int! + token0: String! + token1: String! + token2: String + token3: String +} + type BalancerPoolBalance @entity { id: ID! timestamp: DateTime! @index @@ -157,6 +178,14 @@ type BalancerPoolRate @entity { rate3: BigInt! } +type MaverickPool @entity { + id: ID! + address: String! @index + name: String! + tokenA: String! + tokenB: String! +} + type MaverickPoolBalance @entity { id: ID! timestamp: DateTime! @index @@ -165,3 +194,20 @@ type MaverickPoolBalance @entity { binBalanceA: BigInt! binBalanceB: BigInt! } + +enum LiquiditySourceType { + CurvePool + BalancerPool + MaverickPool + UniswapPool + Aave + Compound +} + +type LiquiditySource @entity { + id: ID! + address: String! + type: LiquiditySourceType! + token: String! +} + diff --git a/schema.graphql b/schema.graphql index 890523da..3d4a0f4f 100644 --- a/schema.graphql +++ b/schema.graphql @@ -118,6 +118,16 @@ type ERC20Balance @entity { balance: BigInt! } +type CurvePool @entity { + id: ID! + address: String! @index + name: String! + tokenCount: Int! + token0: String! + token1: String! + token2: String +} + type CurvePoolBalance @entity { id: ID! timestamp: DateTime! @index @@ -137,6 +147,17 @@ type CurvePoolRate @entity { rate: BigInt! } +type BalancerPool @entity { + id: ID! + address: String! @index + name: String! + tokenCount: Int! + token0: String! + token1: String! + token2: String + token3: String +} + type BalancerPoolBalance @entity { id: ID! timestamp: DateTime! @index @@ -159,6 +180,14 @@ type BalancerPoolRate @entity { rate3: BigInt! } +type MaverickPool @entity { + id: ID! + address: String! @index + name: String! + tokenA: String! + tokenB: String! +} + type MaverickPoolBalance @entity { id: ID! timestamp: DateTime! @index @@ -167,6 +196,23 @@ type MaverickPoolBalance @entity { binBalanceA: BigInt! binBalanceB: BigInt! } + +enum LiquiditySourceType { + CurvePool + BalancerPool + MaverickPool + UniswapPool + Aave + Compound +} + +type LiquiditySource @entity { + id: ID! + address: String! + type: LiquiditySourceType! + token: String! +} + """ The OETH entity tracks the change in total supply of OETH over time. """ diff --git a/src/main-other.ts b/src/main-other.ts index c557dc44..0af10d6e 100644 --- a/src/main-other.ts +++ b/src/main-other.ts @@ -3,10 +3,12 @@ import * as exchangeRates from './shared/post-processors/exchange-rates' import * as balancer from './shared/processors/balancer' import * as curve from './shared/processors/curve' import { erc20s } from './shared/processors/erc20s' +import * as liquiditySources from './shared/processors/liquidity-sources' +import * as maverick from './shared/processors/maverick' export const processor = { stateSchema: 'other-processor', - processors: [balancer, curve, ...erc20s], + processors: [balancer, curve, maverick, ...erc20s, liquiditySources], postProcessors: [exchangeRates], validators: [], } diff --git a/src/model/generated/_liquiditySourceType.ts b/src/model/generated/_liquiditySourceType.ts new file mode 100644 index 00000000..4fc05eeb --- /dev/null +++ b/src/model/generated/_liquiditySourceType.ts @@ -0,0 +1,8 @@ +export enum LiquiditySourceType { + CurvePool = "CurvePool", + BalancerPool = "BalancerPool", + MaverickPool = "MaverickPool", + UniswapPool = "UniswapPool", + Aave = "Aave", + Compound = "Compound", +} diff --git a/src/model/generated/balancerPool.model.ts b/src/model/generated/balancerPool.model.ts new file mode 100644 index 00000000..b28784ae --- /dev/null +++ b/src/model/generated/balancerPool.model.ts @@ -0,0 +1,33 @@ +import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, Index as Index_} from "typeorm" + +@Entity_() +export class BalancerPool { + constructor(props?: Partial) { + Object.assign(this, props) + } + + @PrimaryColumn_() + id!: string + + @Index_() + @Column_("text", {nullable: false}) + address!: string + + @Column_("text", {nullable: false}) + name!: string + + @Column_("int4", {nullable: false}) + tokenCount!: number + + @Column_("text", {nullable: false}) + token0!: string + + @Column_("text", {nullable: false}) + token1!: string + + @Column_("text", {nullable: true}) + token2!: string | undefined | null + + @Column_("text", {nullable: true}) + token3!: string | undefined | null +} diff --git a/src/model/generated/curvePool.model.ts b/src/model/generated/curvePool.model.ts new file mode 100644 index 00000000..efeaeefd --- /dev/null +++ b/src/model/generated/curvePool.model.ts @@ -0,0 +1,30 @@ +import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, Index as Index_} from "typeorm" + +@Entity_() +export class CurvePool { + constructor(props?: Partial) { + Object.assign(this, props) + } + + @PrimaryColumn_() + id!: string + + @Index_() + @Column_("text", {nullable: false}) + address!: string + + @Column_("text", {nullable: false}) + name!: string + + @Column_("int4", {nullable: false}) + tokenCount!: number + + @Column_("text", {nullable: false}) + token0!: string + + @Column_("text", {nullable: false}) + token1!: string + + @Column_("text", {nullable: true}) + token2!: string | undefined | null +} diff --git a/src/model/generated/index.ts b/src/model/generated/index.ts index 3fd7cb72..b4442947 100644 --- a/src/model/generated/index.ts +++ b/src/model/generated/index.ts @@ -6,11 +6,16 @@ export * from "./erc20.model" export * from "./erc20Holder.model" export * from "./erc20State.model" export * from "./erc20Balance.model" +export * from "./curvePool.model" export * from "./curvePoolBalance.model" export * from "./curvePoolRate.model" +export * from "./balancerPool.model" export * from "./balancerPoolBalance.model" export * from "./balancerPoolRate.model" +export * from "./maverickPool.model" export * from "./maverickPoolBalance.model" +export * from "./liquiditySource.model" +export * from "./_liquiditySourceType" export * from "./oeth.model" export * from "./oethAsset.model" export * from "./oethAddress.model" diff --git a/src/model/generated/liquiditySource.model.ts b/src/model/generated/liquiditySource.model.ts new file mode 100644 index 00000000..dd5a89e0 --- /dev/null +++ b/src/model/generated/liquiditySource.model.ts @@ -0,0 +1,21 @@ +import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_} from "typeorm" +import {LiquiditySourceType} from "./_liquiditySourceType" + +@Entity_() +export class LiquiditySource { + constructor(props?: Partial) { + Object.assign(this, props) + } + + @PrimaryColumn_() + id!: string + + @Column_("text", {nullable: false}) + address!: string + + @Column_("varchar", {length: 12, nullable: false}) + type!: LiquiditySourceType + + @Column_("text", {nullable: false}) + token!: string +} diff --git a/src/model/generated/maverickPool.model.ts b/src/model/generated/maverickPool.model.ts new file mode 100644 index 00000000..d1744e63 --- /dev/null +++ b/src/model/generated/maverickPool.model.ts @@ -0,0 +1,24 @@ +import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, Index as Index_} from "typeorm" + +@Entity_() +export class MaverickPool { + constructor(props?: Partial) { + Object.assign(this, props) + } + + @PrimaryColumn_() + id!: string + + @Index_() + @Column_("text", {nullable: false}) + address!: string + + @Column_("text", {nullable: false}) + name!: string + + @Column_("text", {nullable: false}) + tokenA!: string + + @Column_("text", {nullable: false}) + tokenB!: string +} diff --git a/src/oeth/validators/validate-oeth/validate-oeth.ts b/src/oeth/validators/validate-oeth/validate-oeth.ts index a8810b6d..a9f4066d 100644 --- a/src/oeth/validators/validate-oeth/validate-oeth.ts +++ b/src/oeth/validators/validate-oeth/validate-oeth.ts @@ -121,7 +121,7 @@ const expectations = { apr: 0.1176475, apy: 0.12482622, apy14DayAvg: 0.13925279, - apy30DayAvg: 23.49825734, + apy30DayAvg: 24.47691924, apy7DayAvg: 0.13852897, rebasingCreditsPerToken: '973558594004638273359591150', txHash: diff --git a/src/ogv/post-processors/governance.ts b/src/ogv/post-processors/governance.ts index aca35091..c6183057 100644 --- a/src/ogv/post-processors/governance.ts +++ b/src/ogv/post-processors/governance.ts @@ -38,6 +38,23 @@ export const setup = (processor: EvmBatchProcessor) => { ], range: { from }, }) + processor.includeAllBlocks({ from }) +} + +let pendingProposals: OGVProposal[] = [] +let activeProposals: OGVProposal[] = [] +let goActiveBlock = 0 +let goFinishedBlock = 0 + +export const initialize = async (ctx: Context) => { + const pending = await ctx.store.findBy(OGVProposal, { + status: OGVProposalState.Pending, + }) + const active = await ctx.store.findBy(OGVProposal, { + status: OGVProposalState.Active, + }) + pendingProposals.push(...pending) + activeProposals.push(...active) } export const process = async (ctx: Context) => { @@ -50,6 +67,7 @@ export const process = async (ctx: Context) => { votes: [], } + _updateStatusBlocks() for (const block of ctx.blocks) { for (const log of block.logs) { if (log.address !== GOVERNANCE_ADDRESS) continue @@ -83,6 +101,13 @@ export const process = async (ctx: Context) => { ctx.log.error('Could not process governance event') } } + await _updateProposalStatuses( + ctx, + result, + block, + goActiveBlock, + goFinishedBlock, + ) } await ctx.store.upsert(Array.from(result.addresses.values())) @@ -127,6 +152,8 @@ const _processProposalCreated = async ( scores: [], }) + pendingProposals.push(proposal) + const proposalTxLog = new OGVProposalTxLog({ id: `${proposalId}:${log.transactionHash}:${log.logIndex}`, proposal, @@ -174,6 +201,77 @@ const eventMapper = { }, } +const _updateStatusBlocks = () => { + goActiveBlock = Number( + pendingProposals.reduce( + (min, p) => (p.startBlock < min ? p.startBlock : min), + BigInt(Number.MAX_SAFE_INTEGER), + ), + ) + goFinishedBlock = Number( + activeProposals.reduce( + (min, p) => (p.endBlock < min ? p.endBlock : min), + BigInt(Number.MAX_SAFE_INTEGER), + ), + ) +} + +const _updateProposalStatuses = async ( + ctx: Context, + result: IProcessResult, + block: Block, + goActiveBlock: number, + goFinishedBlock: number, +) => { + // Update for Active and post-Active statuses. + if (block.header.height > goActiveBlock) { + ctx.log.info('block.header.height > goActiveBlock') + for (const proposal of pendingProposals.filter( + (p) => block.header.height > Number(p.startBlock), + )) { + await _updateProposalStatus(ctx, result, block, proposal.id) + } + pendingProposals = pendingProposals.filter( + (p) => block.header.height <= Number(p.startBlock), + ) + } + if (block.header.height > goFinishedBlock) { + ctx.log.info('block.header.height > goFinishedBlock') + for (const proposal of activeProposals.filter( + (p) => block.header.height > Number(p.endBlock), + )) { + await _updateProposalStatus(ctx, result, block, proposal.id) + } + activeProposals = activeProposals.filter( + (p) => block.header.height <= Number(p.endBlock), + ) + } + _updateStatusBlocks() +} + +const _updateProposalStatus = async ( + ctx: Context, + result: IProcessResult, + block: Block, + proposalId: string, +) => { + const proposal = await _getProposal(ctx, proposalId, result) + proposal.status = await _getProposalState(ctx, block, BigInt(proposalId)) + ctx.log.info({ status: proposal.status }, '_updateProposalStatus') + if ( + proposal.status === OGVProposalState.Pending && + !pendingProposals.find((p) => p.id === proposal.id) + ) { + pendingProposals.push(proposal) + } + if ( + proposal.status === OGVProposalState.Active && + !activeProposals.find((p) => p.id === proposal.id) + ) { + activeProposals.push(proposal) + } +} + const _processProposalEvents = async ( ctx: Context, result: IProcessResult, @@ -187,7 +285,7 @@ const _processProposalEvents = async ( const blockTimestamp = new Date(block.header.timestamp) const proposal = await _getProposal(ctx, proposalId.toString(), result) - proposal.status = status + await _updateProposalStatus(ctx, result, block, proposalId.toString()) const proposalTxLog = new OGVProposalTxLog({ id: `${proposalId}:${log.transactionHash}:${log.logIndex}`, @@ -213,7 +311,7 @@ const _processProposalExtended = async ( const proposal = await _getProposal(ctx, proposalId.toString(), result) proposal.endBlock = extendedDeadline - proposal.status = await _getProposalState(ctx, block, proposalId) + await _updateProposalStatus(ctx, result, block, proposalId.toString()) const proposalTxLog = new OGVProposalTxLog({ id: `${proposalId}:${log.transactionHash}:${log.logIndex}`, diff --git a/src/ousd/processors/strategies/strategies.ts b/src/ousd/processors/strategies/strategies.ts index f296a91e..dd04f90f 100644 --- a/src/ousd/processors/strategies/strategies.ts +++ b/src/ousd/processors/strategies/strategies.ts @@ -1,9 +1,7 @@ import { EvmBatchProcessor } from '@subsquid/evm-processor' -import * as abstractStrategyAbi from '../../../abi/initializable-abstract-strategy' import { OETHRewardTokenCollected } from '../../../model' import { Context } from '../../../processor' -import { currencies } from '../../../shared/post-processors/exchange-rates/currencies' import { IStrategyData, createStrategyProcessor, @@ -13,8 +11,6 @@ import { createStrategyRewardProcessor, createStrategyRewardSetup, } from '../../../shared/processor-templates/strategy-rewards' -import { OUSD_ADDRESS } from '../../../utils/addresses' -import { traceFilter } from '../../../utils/traceFilter' import { aaveStrategy } from './aave-strategy' import { convexMetaStrategy } from './convex-meta-strategy' import { fluxStrategy } from './flux-strategy' @@ -29,7 +25,7 @@ const ousdStrategies: readonly IStrategyData[] = [ morphoAave, fluxStrategy, makerDsrStrategy, - + // Deprecated // { // from: 13369299, diff --git a/src/processor.ts b/src/processor.ts index c1eea534..1f186045 100644 --- a/src/processor.ts +++ b/src/processor.ts @@ -32,21 +32,21 @@ export const createSquidProcessor = () => 'http://localhost:8545', // Alchemy is deprecating `eth_getBlockReceipts` https://docs.alchemy.com/reference/eth-getblockreceipts // so we need to set `maxBatchCallSize` 1 to avoid using this method - maxBatchCallSize: 1, + maxBatchCallSize: 10, }, }) .setFinalityConfirmation(10) .setFields({ transaction: { - from: true, + // from: true, to: true, hash: true, - gasUsed: true, - gas: true, - value: true, - sighash: true, + // gasUsed: true, + // gas: true, + // value: true, + // sighash: true, input: true, - status: true, + // status: true, }, log: { transactionHash: true, @@ -81,7 +81,7 @@ export const run = ({ }: { stateSchema?: string processors: Processor[] - postProcessors?: Pick[] + postProcessors?: Processor[] validators?: Pick[] }) => { assert( @@ -132,15 +132,22 @@ export const run = ({ initialized = true ctx.log.info(`initializing`) start = Date.now() - const times = await Promise.all( - processors + const times = await Promise.all([ + ...processors .filter((p) => p.initialize) .map((p, index) => p.initialize!(ctx).then( time(p.name ?? `initializing processor-${index}`), ), ), - ) + ...(postProcessors ?? []) + .filter((p) => p.initialize) + .map((p, index) => + p.initialize!(ctx).then( + time(p.name ?? `initializing postProcessors-${index}`), + ), + ), + ]) times.forEach((t) => t()) } diff --git a/src/shared/processor-templates/balancer/balancer.ts b/src/shared/processor-templates/balancer/balancer.ts index 29459c36..441e71ca 100644 --- a/src/shared/processor-templates/balancer/balancer.ts +++ b/src/shared/processor-templates/balancer/balancer.ts @@ -5,12 +5,19 @@ import * as balancerMetaStablePoolAbi from '../../../abi/balancer-meta-stable-po import * as balancerRateProvider from '../../../abi/balancer-rate-provider' import * as balancerVaultAbi from '../../../abi/balancer-vault' import * as balancerWeightedPool from '../../../abi/balancer-weighted-pool-2-token' -import { BalancerPoolBalance, BalancerPoolRate } from '../../../model' +import { + BalancerPool, + BalancerPoolBalance, + BalancerPoolRate, + LiquiditySource, + LiquiditySourceType, +} from '../../../model' import { Context } from '../../../processor' import { ADDRESS_ZERO, BALANCER_VAULT } from '../../../utils/addresses' import { blockFrequencyUpdater } from '../../../utils/blockFrequencyUpdater' import { ensureExchangeRates } from '../../post-processors/exchange-rates' import { Currency } from '../../post-processors/exchange-rates/currencies' +import { registerLiquiditySource } from '../../processors/liquidity-sources' const eth1 = BigInt('1000000000000000000') @@ -26,6 +33,44 @@ export const createBalancerSetup = ( processor.includeAllBlocks({ from }) } +export const createBalancerInitializer = ({ + name, + poolAddress, + tokens, +}: { + name: string + poolAddress: string + tokens: + | [string, string] + | [string, string, string] + | [string, string, string, string] +}) => { + for (const token of tokens) { + registerLiquiditySource( + poolAddress, + LiquiditySourceType.BalancerPool, + token, + ) + } + return async (ctx: Context) => { + const pool = await ctx.store.findOneBy(BalancerPool, { id: poolAddress }) + if (!pool) { + await ctx.store.insert( + new BalancerPool({ + id: poolAddress, + address: poolAddress, + name, + tokenCount: tokens.length, + token0: tokens[0], + token1: tokens[1], + token2: tokens[2], + token3: tokens[3], + }), + ) + } + } +} + export const createBalancerProcessor = ( poolAddress: string, poolId: string, diff --git a/src/shared/processor-templates/curve/curve.ts b/src/shared/processor-templates/curve/curve.ts index d464aa05..bb9badd5 100644 --- a/src/shared/processor-templates/curve/curve.ts +++ b/src/shared/processor-templates/curve/curve.ts @@ -1,10 +1,17 @@ import { EvmBatchProcessor } from '@subsquid/evm-processor' import * as curveLpToken from '../../../abi/curve-lp-token' -import { CurvePoolBalance, CurvePoolRate } from '../../../model' +import { + CurvePool, + CurvePoolBalance, + CurvePoolRate, + LiquiditySource, + LiquiditySourceType, +} from '../../../model' import { Context } from '../../../processor' import { blockFrequencyUpdater } from '../../../utils/blockFrequencyUpdater' import { range } from '../../../utils/range' +import { registerLiquiditySource } from '../../processors/liquidity-sources' interface ProcessResult { curvePoolBalances: CurvePoolBalance[] @@ -18,17 +25,47 @@ export const createCurveSetup = ( processor.includeAllBlocks({ from }) } +export const createCurveInitializer = ({ + name, + address, + tokens, +}: { + name: string + address: string + tokens: [string, string] | [string, string, string] +}) => { + for (const token of tokens) { + registerLiquiditySource(address, LiquiditySourceType.CurvePool, token) + } + return async (ctx: Context) => { + const pool = await ctx.store.findOneBy(CurvePool, { id: address }) + if (!pool) { + await ctx.store.insert( + new CurvePool({ + id: address, + address, + name, + tokenCount: tokens.length, + token0: tokens[0], + token1: tokens[1], + token2: tokens[2], + }), + ) + } + } +} + export const createCurveProcessor = ({ name, address, - count, from, + tokens, ratesToPull, }: { name: string address: string - count: number from: number + tokens: string[] ratesToPull?: { i: bigint; j: bigint; dx: bigint }[] | undefined }) => { const update = blockFrequencyUpdater({ from }) @@ -44,7 +81,9 @@ export const createCurveProcessor = ({ // TODO: use `get_balances()` where possible const [balances, rates] = await Promise.all([ - Promise.all(range(count).map((n) => contract.balances(BigInt(n)))), + Promise.all( + range(tokens.length).map((n) => contract.balances(BigInt(n))), + ), Promise.all( (ratesToPull ?? []).map(async ({ i, j, dx }) => { return { diff --git a/src/shared/processor-templates/maverick/maverick.ts b/src/shared/processor-templates/maverick/maverick.ts index 5148f0c8..38bcc726 100644 --- a/src/shared/processor-templates/maverick/maverick.ts +++ b/src/shared/processor-templates/maverick/maverick.ts @@ -1,9 +1,16 @@ import { EvmBatchProcessor } from '@subsquid/evm-processor' +import { add } from 'lodash' import * as maverickPool from '../../../abi/maverick-pool' -import { MaverickPoolBalance } from '../../../model' +import { + LiquiditySource, + LiquiditySourceType, + MaverickPool, + MaverickPoolBalance, +} from '../../../model' import { Context } from '../../../processor' import { blockFrequencyUpdater } from '../../../utils/blockFrequencyUpdater' +import { registerLiquiditySource } from '../../processors/liquidity-sources' // Maverick Pool Reference: https://docs.mav.xyz/guides/technical-reference/pool @@ -18,6 +25,34 @@ export const createMaverickSetup = ( processor.includeAllBlocks({ from }) } +export const createMaverickInitializer = ({ + name, + address, + tokens, +}: { + name: string + address: string + tokens: [string, string] +}) => { + for (const token of tokens) { + registerLiquiditySource(address, LiquiditySourceType.MaverickPool, token) + } + return async (ctx: Context) => { + const pool = await ctx.store.findOneBy(MaverickPool, { id: address }) + if (!pool) { + await ctx.store.insert( + new MaverickPool({ + id: address, + address, + name, + tokenA: tokens[0], + tokenB: tokens[1], + }), + ) + } + } +} + export const createMaverickProcessor = ({ name, address, diff --git a/src/shared/processor-templates/otoken/otoken.ts b/src/shared/processor-templates/otoken/otoken.ts index 5a35682a..35e2457b 100644 --- a/src/shared/processor-templates/otoken/otoken.ts +++ b/src/shared/processor-templates/otoken/otoken.ts @@ -28,6 +28,7 @@ import { Context } from '../../../processor' import { type Transaction, activityFromTx } from '../../../utils/activityFromTx' import { ADDRESS_ZERO } from '../../../utils/addresses' import { DECIMALS_18 } from '../../../utils/constants' +import { multicall } from '../../../utils/multicall' import { EntityClassT, InstanceTypeOfConstructor } from '../../../utils/type' import { getLatestEntity } from '../../../utils/utils' import { ensureExchangeRate } from '../../post-processors/exchange-rates' @@ -218,74 +219,85 @@ export const createOTokenProcessor = (params: { otokenObject.totalSupply -= data.value } - // Bind the token contract to the block number - const token = new otoken.Contract( - ctx, - block.header, - params.OTOKEN_ADDRESS, - ) - // Transfer events - let addressSub = owners!.get(data.from) - let addressAdd = owners!.get(data.to) - - if (addressSub == null) { - addressSub = await createAddress(params.OTokenAddress, ctx, data.from) - owners!.set(addressSub.id, addressSub) - } - if (addressAdd == null) { - addressAdd = await createAddress(params.OTokenAddress, ctx, data.to) - owners!.set(addressAdd.id, addressAdd) + const ensureAddress = async (address: string) => { + let entity = owners!.get(address) + if (!entity) { + entity = await createAddress(params.OTokenAddress, ctx, address) + owners!.set(entity.id, entity) + } + entity.lastUpdated = new Date(block.header.timestamp) + return entity } - addressSub.lastUpdated = new Date(block.header.timestamp) - addressAdd.lastUpdated = new Date(block.header.timestamp) + const afterHighResUpgrade = + block.header.height >= (params.Upgrade_CreditsBalanceOfHighRes ?? 0) + const [ + addressSub, + addressAdd, + [fromCreditsBalanceOf, toCreditsBalanceOf], + ] = await Promise.all([ + ensureAddress(data.from), + ensureAddress(data.to), + multicall( + ctx, + block.header, + afterHighResUpgrade + ? otoken.functions.creditsBalanceOfHighres + : (otoken.functions + .creditsBalanceOf as unknown as typeof otoken.functions.creditsBalanceOfHighres), + params.OTOKEN_ADDRESS, + [[data.from], [data.to]], + ).then((results) => { + if (afterHighResUpgrade) { + return results.map((r) => [r[0], r[1]]) + } else { + return results.map((r) => [r[0] * 1000000000n, r[1] * 1000000000n]) + } + }) as Promise<[bigint, bigint][]>, + ]) /** * "0017708038-000327-29fec:0xd2cdf18b60a5cdb634180d5615df7a58a597247c:Sent","0","49130257489166670","2023-07-16T19:50:11.000Z",17708038,"0x0e3ac28945d45993e3d8e1f716b6e9ec17bfc000418a1091a845b7a00c7e3280","Sent","0xd2cdf18b60a5cdb634180d5615df7a58a597247c", * "0017708038-000327-29fec:0xd2cdf18b60a5cdb634180d5615df7a58a597247c:Sent","0","49130257489166670","2023-07-16T19:50:11.000Z",17708038,"0x0e3ac28945d45993e3d8e1f716b6e9ec17bfc000418a1091a845b7a00c7e3280","Sent","0xd2cdf18b60a5cdb634180d5615df7a58a597247c", */ - // update the address balance - await Promise.all( - [addressSub, addressAdd].map(async (address) => { - let credits: [bigint, bigint] - let newBalance: bigint - let change: bigint - if ( - block.header.height >= (params.Upgrade_CreditsBalanceOfHighRes ?? 0) - ) { - credits = await token - .creditsBalanceOfHighres(address.id) - .then((r) => [r[0], r[1]]) - newBalance = (credits[0] * DECIMALS_18) / credits[1] - change = newBalance - address.balance - } else { - credits = await token - .creditsBalanceOf(address.id) - .then((r) => [r[0] * 1000000000n, r[1] * 1000000000n]) - newBalance = (credits[0] * DECIMALS_18) / credits[1] - change = newBalance - address.balance - } - if (change === 0n) return - const type = - addressSub === address ? HistoryType.Sent : HistoryType.Received - result.history.push( - new params.OTokenHistory({ - // we can't use {t.id} because it's not unique - id: getUniqueId(`${log.id}-${address.id}`), - address: address, - value: change, - balance: newBalance, - timestamp: new Date(block.header.timestamp), - blockNumber: block.header.height, - txHash: log.transactionHash, - type, - }), - ) - address.credits = BigInt(credits[0]) // token credits - address.balance = newBalance // token balance - }), - ) + const updateAddressBalance = ({ + address, + credits, + }: { + address: InstanceTypeOfConstructor + credits: [bigint, bigint] + }) => { + const newBalance = (credits[0] * DECIMALS_18) / credits[1] + const change = newBalance - address.balance + if (change === 0n) return + const type = + addressSub === address ? HistoryType.Sent : HistoryType.Received + result.history.push( + new params.OTokenHistory({ + // we can't use {t.id} because it's not unique + id: getUniqueId(`${log.id}-${address.id}`), + address: address, + value: change, + balance: newBalance, + timestamp: new Date(block.header.timestamp), + blockNumber: block.header.height, + txHash: log.transactionHash, + type, + }), + ) + address.credits = BigInt(credits[0]) // token credits + address.balance = newBalance // token balance + } + + updateAddressBalance({ + address: addressSub, + credits: fromCreditsBalanceOf, + }) + updateAddressBalance({ + address: addressAdd, + credits: toCreditsBalanceOf, + }) if ( addressAdd.rebasingOption === RebasingOption.OptOut && diff --git a/src/shared/processor-templates/otoken/utils.ts b/src/shared/processor-templates/otoken/utils.ts index 6c64de46..272525ad 100644 --- a/src/shared/processor-templates/otoken/utils.ts +++ b/src/shared/processor-templates/otoken/utils.ts @@ -69,6 +69,8 @@ export async function createRebaseAPY< let feeUSD = 0n let yieldUSD = 0n const rate = exchangeRate.rate + const generateId = (date: dayjs.Dayjs | string | Date | number) => + dayjs.utc(date).toISOString().substring(0, 10) if (OTokenAPY.name === 'OUSDAPY') { feeUSD = lastYieldDistributionEvent.fee @@ -98,7 +100,7 @@ export async function createRebaseAPY< // use date as id for APY const date = new Date(block.header.timestamp) - const dateId = date.toISOString().substring(0, 10) + const dateId = generateId(date) // get last APY to compare with current one let lastApy = @@ -163,36 +165,38 @@ export async function createRebaseAPY< const last7daysDateId = { key: 'apy7DayAvg' as const, - value: dayjs.utc(date).subtract(6, 'days').toISOString().substring(0, 10), + value: generateId(dayjs.utc(date).subtract(6, 'days')), days: 7, } const last14daysDateId = { key: 'apy14DayAvg' as const, - value: dayjs.utc(date).subtract(13, 'days').toISOString().substring(0, 10), + value: generateId(dayjs.utc(date).subtract(13, 'days')), days: 14, } const last30daysDateId = { key: 'apy30DayAvg' as const, - value: dayjs.utc(date).subtract(29, 'days').toISOString().substring(0, 10), + value: generateId(dayjs.utc(date).subtract(29, 'days')), days: 30, } - // calculate average APY for the last 7, 14 and 30 days - await Promise.all( - [last7daysDateId, last14daysDateId, last30daysDateId].map(async (i) => { - const pastAPYs = await ctx.store - .find(OTokenAPY, { - where: { - id: MoreThanOrEqual(i.value), - }, - order: { id: 'asc' }, - }) - .then((r) => r.slice(0, i.days - 1)) - apy![i.key] = - pastAPYs.reduce((acc, cur) => acc + cur.apy, apy!.apy) / - (pastAPYs.length + 1) - }), - ) + const last30daysAPYs = await ctx.store.find(OTokenAPY, { + where: { + id: MoreThanOrEqual(last30daysDateId.value), + }, + order: { id: 'asc' }, + }) + + const blockDateId = generateId(block.header.timestamp) + for (const i of [last7daysDateId, last14daysDateId, last30daysDateId]) { + const pastAPYs = last30daysAPYs.filter((a) => { + const dateId = generateId(a.timestamp) + return dateId >= i.value && dateId < blockDateId + }) + // console.log(i.days, pastAPYs.length) + apy![i.key] = + pastAPYs.reduce((acc, cur) => acc + cur.apy, apy!.apy) / + (pastAPYs.length + 1) + } return rebase } diff --git a/src/shared/processors/balancer/balancer.ts b/src/shared/processors/balancer/balancer.ts index 00cb3faf..45e3f18d 100644 --- a/src/shared/processors/balancer/balancer.ts +++ b/src/shared/processors/balancer/balancer.ts @@ -1,7 +1,10 @@ import { EvmBatchProcessor } from '@subsquid/evm-processor' import { Context } from '../../../processor' +import { tokens } from '../../../utils/addresses' +import { CurrencyAddress } from '../../post-processors/exchange-rates/currencies' import { + createBalancerInitializer, createBalancerProcessor, createBalancerSetup, } from '../../processor-templates/balancer' @@ -9,7 +12,19 @@ import { const ousdResetFrom = 11585978 const oethDeployFrom = 16933090 -const pools = [ +const pools: { + name: string + poolSymbol: string + poolType: 'MetaStable' | 'ComposableStable' | 'Weighted' | 'Gyroscope' + poolAddress: string + poolId: string + from: number + tokens: + | [string, string] + | [string, string, string] + | [string, string, string, string] + rates?: [CurrencyAddress, CurrencyAddress][] +}[] = [ { name: 'Balancer rETH Stable Pool', poolSymbol: 'B-rETH-STABLE', @@ -17,6 +32,7 @@ const pools = [ poolAddress: '0x1e19cf2d73a72ef1332c882f20534b6519be0276', poolId: '0x1e19cf2d73a72ef1332c882f20534b6519be0276000200000000000000000112', + tokens: [tokens.rETH, tokens.WETH], from: Math.max(13850000, oethDeployFrom), }, { @@ -26,6 +42,12 @@ const pools = [ poolAddress: '0x42ed016f826165c2e5976fe5bc3df540c5ad0af7', poolId: '0x42ed016f826165c2e5976fe5bc3df540c5ad0af700000000000000000000058b', + tokens: [ + '0x42ed016f826165c2e5976fe5bc3df540c5ad0af7', + tokens.wstETH, + tokens.sfrxETH, + tokens.rETH, + ], from: Math.max(17680000, oethDeployFrom), }, { @@ -35,6 +57,11 @@ const pools = [ poolAddress: '0x93d199263632a4ef4bb438f1feb99e57b4b5f0bd', poolId: '0x93d199263632a4ef4bb438f1feb99e57b4b5f0bd0000000000000000000005c2', + tokens: [ + tokens.wstETH, + '0x93d199263632a4EF4Bb438F1feB99e57b4b5f0BD', + tokens.WETH, + ], from: Math.max(17920000, oethDeployFrom), }, { @@ -45,6 +72,8 @@ const pools = [ poolId: '0x5c6ee304399dbdb9c8ef030ab642b10820db8f56000200000000000000000014', from: Math.max(12370000, oethDeployFrom), + tokens: [tokens.BAL, tokens.WETH], + rates: [[tokens.BAL, tokens.ETH] as [CurrencyAddress, CurrencyAddress]], }, { name: 'Gyroscope ECLP wstETH/wETH', @@ -54,8 +83,9 @@ const pools = [ '0xf01b0684c98cd7ada480bfdf6e43876422fa1fc10002000000000000000005de', poolType: 'Gyroscope', from: Math.max(18015100, oethDeployFrom), + tokens: [tokens.wstETH, tokens.WETH], }, -] as const +] export const from = Math.min(...pools.map((p) => p.from)) @@ -65,18 +95,19 @@ export const setup = (processor: EvmBatchProcessor) => { } } +const initializers = pools.map((pool) => createBalancerInitializer(pool)) + +export const initialize = async (ctx: Context) => { + await Promise.all(initializers.map((p) => p(ctx))) +} + const processors = pools.map((pool) => createBalancerProcessor( pool.poolAddress.toLowerCase(), pool.poolId.toLowerCase(), pool.poolType, pool.from, - [ - [ - '0xba100000625a3754423978a60c9317c58a424e3d', - '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', - ], - ], + pool.rates, ), ) diff --git a/src/shared/processors/curve/curve.ts b/src/shared/processors/curve/curve.ts index cc7c56c5..b85ee935 100644 --- a/src/shared/processors/curve/curve.ts +++ b/src/shared/processors/curve/curve.ts @@ -1,7 +1,9 @@ import { EvmBatchProcessor } from '@subsquid/evm-processor' import { Context } from '../../../processor' +import { tokens } from '../../../utils/addresses' import { + createCurveInitializer, createCurveProcessor, createCurveSetup, } from '../../processor-templates/curve' @@ -11,96 +13,97 @@ const oethDeployFrom = 16933090 export const from = Math.min(ousdResetFrom, oethDeployFrom) -const pools = [ +const pools: (Parameters['0'] & + Parameters['0'])[] = [ // Curve (OUSD) { name: 'ThreePool', address: '0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7'.toLowerCase(), from: Math.max(10809473, ousdResetFrom), - count: 3, + tokens: [tokens.DAI, tokens.USDC, tokens.USDT], }, { name: 'OUSDMetapool', address: '0x87650d7bbfc3a9f10587d7778206671719d9910d'.toLowerCase(), from: Math.max(12860905, ousdResetFrom), - count: 2, + tokens: [tokens.OUSD, tokens.CRV3], }, { name: 'LUSDMetapool', address: '0xed279fdd11ca84beef15af5d39bb4d4bee23f0ca'.toLowerCase(), from: Math.max(12184843, ousdResetFrom), - count: 2, + tokens: [tokens.LUSD, tokens.CRV3], }, // Curve (OETH) { - name: 'OEthEthPool', + name: 'factory-v2-298: ETH/OETH', address: '0x94B17476A93b3262d87B9a326965D1E91f9c13E7'.toLowerCase(), from: Math.max(17130500, oethDeployFrom), - count: 2, + tokens: [tokens.ETH, tokens.OETH], ratesToPull: [{ i: 1n, j: 0n, dx: 1000000000000000000n }], }, { - name: 'factory-crvusd-15: frxETH/WETH', + name: 'factory-crvusd-15: WETH/frxETH', address: '0x9c3b46c0ceb5b9e304fcd6d88fc50f7dd24b31bc', from: Math.max(17922938, oethDeployFrom), - count: 2, + tokens: [tokens.WETH, tokens.frxETH], }, { name: 'steth: ETH/stETH', address: '0xdc24316b9ae028f1497c275eb9192a3ea0f67022', from: Math.max(11592551, oethDeployFrom), - count: 2, + tokens: [tokens.ETH, tokens.stETH], }, { name: 'stETH-ng: ETH/stETH', address: '0x21e27a5e5513d6e65c4f830167390997aa84843a', from: Math.max(17272519, oethDeployFrom), - count: 2, + tokens: [tokens.ETH, tokens.stETH], }, { name: 'frxeth: ETH/frxETH', address: '0xa1f8a6807c402e4a15ef4eba36528a3fed24e577', from: Math.max(15741010, oethDeployFrom), - count: 2, + tokens: [tokens.ETH, tokens.frxETH], }, { name: 'factory-crypto-210: ETH/rETH', address: '0x0f3159811670c117c372428d4e69ac32325e4d0f', from: Math.max(16615906, oethDeployFrom), - count: 2, + tokens: [tokens.ETH, tokens.rETH], }, { name: 'factory-v2-274: stETH/frxETH', address: '0x4d9f9d15101eec665f77210cb999639f760f831e', from: Math.max(16683219, oethDeployFrom), - count: 2, + tokens: [tokens.stETH, tokens.frxETH], }, { name: 'factory-v2-117: WETH/stETH', address: '0x828b154032950c8ff7cf8085d841723db2696056', from: Math.max(14759666, oethDeployFrom), - count: 2, + tokens: [tokens.WETH, tokens.stETH], }, { name: 'factory-v2-89: rETH/wstETH', address: '0x447ddd4960d9fdbf6af9a790560d0af76795cb08', from: Math.max(14258216, oethDeployFrom), - count: 2, + tokens: [tokens.rETH, tokens.wstETH], }, { name: 'factory-crypto-218: rETH/frxETH', address: '0xe7c6e0a739021cdba7aac21b4b728779eef974d9', from: Math.max(16684327, oethDeployFrom), - count: 2, + tokens: [tokens.rETH, tokens.frxETH], }, { name: 'factory-tricrypto-14: wstETH/rETH/sfrxETH', address: '0x2570f1bd5d2735314fc102eb12fc1afe9e6e7193', from: Math.max(18084222, oethDeployFrom), - count: 3, + tokens: [tokens.wstETH, tokens.rETH, tokens.sfrxETH], }, -] as Parameters['0'][] +] export const setup = (processor: EvmBatchProcessor) => { for (const pool of pools) { @@ -108,6 +111,12 @@ export const setup = (processor: EvmBatchProcessor) => { } } +const initializers = pools.map((pool) => createCurveInitializer(pool)) + +export const initialize = async (ctx: Context) => { + await Promise.all(initializers.map((p) => p(ctx))) +} + const processors = pools.map((pool) => createCurveProcessor(pool)) export const process = async (ctx: Context) => { diff --git a/src/shared/processors/erc20s.ts b/src/shared/processors/erc20s.ts index f7f9d200..e2ec4fb9 100644 --- a/src/shared/processors/erc20s.ts +++ b/src/shared/processors/erc20s.ts @@ -1,9 +1,15 @@ import * as otoken from '../../abi/otoken' +import { LiquiditySourceType } from '../../model' import { OETH_ADDRESS } from '../../utils/addresses' import { logFilter } from '../../utils/logFilter' import { createERC20Tracker } from '../processor-templates/erc20' +import { registerLiquiditySource } from './liquidity-sources' + +// TODO: Would be nice if interested parties could register their desires here from other parts of the code, +// allowing multiple declarations of need without issue. const tracks: Parameters[0][] = [ + // Origin Specific { from: 15350225, // 6436154, address: '0x8207c1ffc5b6804f6024322ccf34f29c3541ae26', // OGN @@ -20,6 +26,7 @@ const tracks: Parameters[0][] = [ ], intervalTracking: true, }, + // OUSD Related { from: 11362821, address: '0xdac17f958d2ee523a2206206994597c13d831ec7', // USDT @@ -47,6 +54,32 @@ const tracks: Parameters[0][] = [ ], intervalTracking: true, }, + // OETH Related + { + from: 16933090, // oeth deploy date + address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', // WETH + accountFilter: [ + '0xa4e0faA58465A2D369aa21B3e42d43374c6F9613', // Uniswap wstETH/WETH + '0x109830a1aaad605bbf02a9dfa7b0b92ec2fb7daa', // Uniswap rETH/WETH + ], + intervalTracking: true, + }, + { + from: 16933090, // oeth deploy date + address: '0xae78736cd615f374d3085123a210448e74fc6393', // rETH + accountFilter: [ + '0xa4e0faA58465A2D369aa21B3e42d43374c6F9613', // Uniswap rETH/WETH + ], + intervalTracking: true, + }, + { + from: 16933090, // oeth deploy date + address: '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0', // wstETH + accountFilter: [ + '0x109830a1aaad605bbf02a9dfa7b0b92ec2fb7daa', // Uniswap wstETH/WETH + ], + intervalTracking: true, + }, ] export const erc20s = [ diff --git a/src/shared/processors/liquidity-sources.ts b/src/shared/processors/liquidity-sources.ts new file mode 100644 index 00000000..80cca953 --- /dev/null +++ b/src/shared/processors/liquidity-sources.ts @@ -0,0 +1,68 @@ +import { LiquiditySource, LiquiditySourceType } from '../../model' +import { Context } from '../../processor' + +const sources = new Map() + +export const registerLiquiditySource = ( + address: string, + type: LiquiditySourceType, + token: string, +) => { + const id = `${address}-${token}` + sources.set(id, new LiquiditySource({ id, address, type, token })) +} + +export const from = Number.MAX_SAFE_INTEGER // does not apply here +export const initialize = async (ctx: Context) => { + await ctx.store.upsert([...sources.values()]) +} +export const process = () => Promise.resolve() + +// Liquidity Source Definitions +registerLiquiditySource( + '0x3ed3b47dd13ec9a98b44e6204a523e766b225811', // aUSDT + LiquiditySourceType.Aave, + '0xdac17f958d2ee523a2206206994597c13d831ec7', // USDT +) + +registerLiquiditySource( + '0xbcca60bb61934080951369a648fb03df4f96263c', // aUSDC + LiquiditySourceType.Aave, + '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC +) + +registerLiquiditySource( + '0x028171bca77440897b824ca71d1c56cac55b68a3', // aDAI + LiquiditySourceType.Aave, + '0x6b175474e89094c44da98b954eedeac495271d0f', // DAI +) + +registerLiquiditySource( + '0xf650c3d88d12db855b8bf7d11be6c55a4e07dcc9', // cUSDT + LiquiditySourceType.Compound, + '0xdac17f958d2ee523a2206206994597c13d831ec7', // USDT +) + +registerLiquiditySource( + '0x39aa39c021dfbae8fac545936693ac917d5e7563', // cUSDC + LiquiditySourceType.Compound, + '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // USDC +) + +registerLiquiditySource( + '0x5d3a536e4d6dbd6114cc1ead35777bab948e3643', // cDAI + LiquiditySourceType.Compound, + '0x6b175474e89094c44da98b954eedeac495271d0f', // DAI +) + +registerLiquiditySource( + '0xa4e0faA58465A2D369aa21B3e42d43374c6F9613', // Uniswap rETH/WETH + LiquiditySourceType.UniswapPool, + '0xae78736cd615f374d3085123a210448e74fc6393', // rETH +) + +registerLiquiditySource( + '0x109830a1aaad605bbf02a9dfa7b0b92ec2fb7daa', // Uniswap wstETH/WETH + LiquiditySourceType.UniswapPool, + '0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0', // wstETH +) diff --git a/src/shared/processors/maverick.ts b/src/shared/processors/maverick.ts index 1cabc547..3d6bf2cc 100644 --- a/src/shared/processors/maverick.ts +++ b/src/shared/processors/maverick.ts @@ -1,7 +1,9 @@ import { EvmBatchProcessor } from '@subsquid/evm-processor' import { Context } from '../../processor' +import { tokens } from '../../utils/addresses' import { + createMaverickInitializer, createMaverickProcessor, createMaverickSetup, } from '../processor-templates/maverick' @@ -10,18 +12,21 @@ const oethDeployFrom = 16933090 export const from = Math.min(oethDeployFrom) -const pools = [ +const pools: (Parameters['0'] & + Parameters['0'])[] = [ { name: 'wstETH-ETH', address: '0x0eb1c92f9f5ec9d817968afddb4b46c564cdedbe', from: Math.max(17216724, oethDeployFrom), + tokens: [tokens.wstETH, tokens.ETH], }, { name: 'rETH-ETH', address: '0xeb061a4e1ad3f1983655281cb8019ebbf8b30b29', from: Math.max(17216790, oethDeployFrom), + tokens: [tokens.rETH, tokens.ETH], }, -] as Parameters['0'][] +] export const setup = (processor: EvmBatchProcessor) => { for (const pool of pools) { @@ -29,6 +34,12 @@ export const setup = (processor: EvmBatchProcessor) => { } } +const initializers = pools.map((pool) => createMaverickInitializer(pool)) + +export const initialize = async (ctx: Context) => { + await Promise.all(initializers.map((p) => p(ctx))) +} + const processors = pools.map((pool) => createMaverickProcessor(pool)) export const process = async (ctx: Context) => { diff --git a/src/utils/addresses.ts b/src/utils/addresses.ts index 4b3cfd80..6a88a30b 100644 --- a/src/utils/addresses.ts +++ b/src/utils/addresses.ts @@ -9,6 +9,8 @@ export const OUSD_ADDRESS = '0x2a8e1e676ec238d8a992307b495b45b3feaa5e86' export const DAI_ADDRESS = '0x6b175474e89094c44da98b954eedeac495271d0f' export const USDT_ADDRESS = '0xdac17f958d2ee523a2206206994597c13d831ec7' export const USDC_ADDRESS = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' +export const CRV3_ADDRESS = '0x6c3f90f043a72fa612cbac8115ee7e52bde6e490' +export const LUSD_ADDRESS = '0x5f98805a4e8be255a32880fdec7f6728c6568ba0' export const OUSD_VAULT_ADDRESS = '0xe75d77b1865ae93c7eaa3040b038d7aa7bc02f70' export const OUSD_HARVESTER_ADDRESS = '0x21fb5812d70b3396880d30e90d9e5c1202266c89' @@ -27,6 +29,26 @@ export const RETH_ADDRESS = '0xae78736cd615f374d3085123a210448e74fc6393' export const FRXETH_ADDRESS = '0x5e8422345238f34275888049021821e8e08caa1f' export const SFRXETH_ADDRESS = '0xac3e018457b222d93114458476f3e3416abbe38f' +export const BAL_ADDRESS = '0xba100000625a3754423978a60c9317c58a424e3d' + +export const tokens = { + ETH: ETH_ADDRESS, + OUSD: OUSD_ADDRESS, + DAI: DAI_ADDRESS, + USDT: USDT_ADDRESS, + USDC: USDC_ADDRESS, + LUSD: LUSD_ADDRESS, + CRV3: CRV3_ADDRESS, + OETH: OETH_ADDRESS, + WETH: WETH_ADDRESS, + stETH: STETH_ADDRESS, + wstETH: WSTETH_ADDRESS, + rETH: RETH_ADDRESS, + frxETH: FRXETH_ADDRESS, + sfrxETH: SFRXETH_ADDRESS, + BAL: BAL_ADDRESS, +} + export const OUSD_VAULT_ERC20_ADDRESSES = [ DAI_ADDRESS, USDC_ADDRESS,