-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: copy indexer deposits data to scraper db #506
base: master
Are you sure you want to change the base?
WIP: copy indexer deposits data to scraper db #506
Conversation
networks: | ||
test-network: | ||
external: true | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This network can be renamed.
I still have to check that both the indexer and scraper work fine using this network.
Indexer draft PR configuring the network: across-protocol/indexer#142
@@ -27,21 +33,26 @@ services: | |||
POSTGRES_PASSWORD: ${DB_PASSWORD} | |||
POSTGRES_DB: ${DB_DATABASE_NAME} | |||
PG_DATA: /var/lib/postgresql/data | |||
command: ["postgres", "-c", "log_statement=all"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just to debug the auth issue I am having. Can be deleted after
ports: | ||
- 5432:5432 | ||
- 5433:5432 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is needed to avoid port collisions between indexer and scraper
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is mainly a copy of the precious service but adapted to the new deposits and rewards table structures.
public async getEarnedRewards(userAddress: string) { | ||
userAddress = assertValidAddress(userAddress); | ||
|
||
const baseQuery = this.buildBaseQuery(this.rewardRepository.createQueryBuilder("r"), userAddress); | ||
const { opRewards } = await baseQuery | ||
.select("SUM(CAST(r.amount as DECIMAL))", "opRewards") | ||
.where("r.isClaimed = :isClaimed", { isClaimed: true }) | ||
.getRawOne<{ opRewards: string }>(); | ||
|
||
return opRewards; | ||
} | ||
|
||
public async getOpRebatesSummary(userAddress: string) { | ||
userAddress = assertValidAddress(userAddress); | ||
|
||
const baseQuery = this.buildBaseQuery(this.rewardRepository.createQueryBuilder("r"), userAddress); | ||
baseQuery.andWhere("r.isClaimed = :isClaimed", { isClaimed: false }); | ||
const [{ depositsCount }, { unclaimedRewards }, { volumeUsd }] = await Promise.all([ | ||
baseQuery.select("COUNT(DISTINCT r.depositPrimaryKey)", "depositsCount").getRawOne<{ | ||
depositsCount: string; | ||
}>(), | ||
baseQuery.select("SUM(CAST(r.amount as DECIMAL))", "unclaimedRewards").getRawOne<{ | ||
unclaimedRewards: number; | ||
}>(), | ||
baseQuery | ||
.leftJoinAndSelect("r.deposit", "d") | ||
.leftJoinAndSelect("d.token", "t") | ||
.leftJoinAndSelect("d.price", "p") | ||
.select(`COALESCE(SUM(d.amount / power(10, t.decimals) * p.usd), 0)`, "volumeUsd") | ||
.getRawOne<{ | ||
volumeUsd: number; | ||
}>(), | ||
// TODO: add claimable rewards | ||
]); | ||
|
||
return { | ||
depositsCount: parseInt(depositsCount), | ||
unclaimedRewards, | ||
volumeUsd, | ||
claimableRewards: "0", | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't tested this functions still work as expected.
// public async getOpRebateRewards(query: GetRewardsQuery) { | ||
// const limit = parseInt(query.limit ?? "10"); | ||
// const offset = parseInt(query.offset ?? "0"); | ||
// const userAddress = assertValidAddress(query.userAddress); | ||
|
||
// const baseQuery = this.buildBaseQuery(this.rewardRepository.createQueryBuilder("r"), userAddress); | ||
|
||
// const rewardsQuery = baseQuery.orderBy("r.depositDate", "DESC").limit(limit).offset(offset); | ||
// const [rewards, total] = await rewardsQuery.getManyAndCount(); | ||
|
||
// // JOIN instead of query deposits separately | ||
// const depositPrimaryKeys = rewards.map((reward) => reward.depositPrimaryKey); | ||
// const deposits = await this.depositRepository.find({ | ||
// where: { id: In(depositPrimaryKeys) }, | ||
// }); | ||
|
||
// return { | ||
// rewards: rewards.map((reward) => ({ | ||
// ...reward, | ||
// deposit: deposits.find((deposit) => deposit.id === reward.depositPrimaryKey), | ||
// })), | ||
// pagination: { | ||
// limit, | ||
// offset, | ||
// total, | ||
// }, | ||
// }; | ||
// } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be rewritten to use JOIN instead of separate queries now that the FK between rewards and deposits is a composite key (depositId, originChainId).
@OneToOne(() => RewardedDeposit) | ||
@JoinColumn([ | ||
{ name: "depositId", referencedColumnName: "depositId", foreignKeyConstraintName: "FK_op_reward_deposit" }, | ||
{ name: "originChainId", referencedColumnName: "originChainId", foreignKeyConstraintName: "FK_op_reward_deposit" }, | ||
]) | ||
deposit: RewardedDeposit; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This relation used to be ManyToOne, but I think it's ok to set it to OneToOne.
// We use the `from` address of the deposit transaction as the reward receiver | ||
// to also take into accounts deposits routed through the SpokePoolVerifier contract. | ||
const provider = this.ethProvidersService.getProvider(deposit.originChainId); | ||
const depositTransaction = await provider.getTransaction(deposit.depositTxHash); // This could also be part of the indexer data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we could fetch this in the indexer as we are already retrieving the transaction.
const inputToken = await this.ethProvidersService.getCachedToken(deposit.originChainId, deposit.inputToken); | ||
const outputToken = await this.ethProvidersService.getCachedToken(deposit.originChainId, deposit.outputToken); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we no longer have the token relation, we have to get token details using the addresses.
This is erroring locally for me with some chains though. It fails with:
Error: call revert exception [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ] (method="symbol()", data="0x", errorArgs=null, errorName=null, errorSignature=null, reason=null, code=CALL_EXCEPTION, version=abi/5.7.0)
const inputToken = await this.ethProvidersService.getCachedToken(deposit.originChainId, deposit.inputToken); | ||
const outputToken = await this.ethProvidersService.getCachedToken(deposit.originChainId, deposit.outputToken); | ||
|
||
const inputTokenPrice = await this.getInputTokenPrice(deposit, inputToken, outputToken); // This could also be part of the indexer data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could also be part of the indexer data, but for now I'm fetching it here too.
This is needed to calculate the MAX reward amount for each deposit.
WHERE | ||
indexer_rhi."status" = 'filled' | ||
AND indexer_deposit_events.finalised is true | ||
AND indexer_fills.finalised is true | ||
AND indexer_rhi."destinationChainId" in (${eligibleDestinationChains}) | ||
LIMIT 5000 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could also add a condition here to fetch only deposits starting from 2025.
performance.mark("query-start"); | ||
const newFilledDeposits = await this.dataSource.query(newFilledDepositsQuery) as RewardedDeposit[]; | ||
performance.mark("query-end"); | ||
performance.measure("query", "query-start", "query-end"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
performance marks can be deleted before merging
Configuration steps to use both databases from the indexer can be found here: https://linear.app/uma/issue/ACX-3496/copy-indexer-deposits-data-to-scraper-db