Skip to content

Commit

Permalink
fix rewards queries (#913)
Browse files Browse the repository at this point in the history
fix rewards queries for erc20 addresses to filter by those that have the secondary market activated
  • Loading branch information
oveddan authored Nov 14, 2024
1 parent 2e4461f commit 330f113
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 27 deletions.
5 changes: 5 additions & 0 deletions .changeset/famous-humans-cry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@zoralabs/protocol-sdk": patch
---

Fix royalties queries to filter by erc20z that have secondary activated
1 change: 1 addition & 0 deletions packages/protocol-sdk/src/anvil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export const makeAnvilTest = ({
export const forkUrls = {
zoraMainnet: `https://rpc.zora.energy/${process.env.VITE_CONDUIT_KEY}`,
zoraSepolia: `https://sepolia.rpc.zora.energy/${process.env.VITE_CONDUIT_KEY}`,
baseMainnet: `https://base-mainnet.g.alchemy.com/v2/${process.env.VITE_ALCHEMY_KEY}`,
};

export const anvilTest = makeAnvilTest({
Expand Down
11 changes: 9 additions & 2 deletions packages/protocol-sdk/src/fixtures/rewards-query-results.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,17 @@ import {
CreatorERC20zQueryResult,
} from "../rewards/subgraph-queries";

const mockResult = (erz20z: Address): RewardsToken => ({
const mockResult = ({
erz20z,
secondaryActivated,
}: {
erz20z: Address;
secondaryActivated: boolean;
}): RewardsToken => ({
salesStrategies: [
{
zoraTimedMinter: {
secondaryActivated,
erc20Z: {
id: erz20z,
},
Expand All @@ -19,7 +26,7 @@ const mockResult = (erz20z: Address): RewardsToken => ({
export const mockRewardsQueryResults = ({
erc20z,
}: {
erc20z: Address[];
erc20z: { secondaryActivated: boolean; erz20z: Address }[];
}): CreatorERC20zQueryResult => ({
zoraCreateTokens: erc20z.map(mockResult),
});
50 changes: 41 additions & 9 deletions packages/protocol-sdk/src/rewards/rewards-client.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { describe, expect, vi } from "vitest";
import { encodeAbiParameters, erc20Abi, parseEther } from "viem";
import { zoraSepolia } from "viem/chains";
import { zoraSepolia, base } from "viem/chains";
import {
forkUrls,
makeAnvilTest,
simulateAndWriteContractWithRetries,
} from "src/anvil";
import { createCollectorClient } from "src/sdk";
import { createCollectorClient, createCreatorClient } from "src/sdk";
import { new1155ContractVersion } from "src/create/contract-setup";
import { ISubgraphQuerier } from "src/apis/subgraph-querier";
import { mockTimedSaleStrategyTokenQueryResult } from "src/fixtures/mint-query-results";
Expand All @@ -16,11 +16,32 @@ import {
zoraCreator1155ImplABI,
} from "@zoralabs/protocol-deployments";
import { makeContractParameters } from "src/utils";
import { mockRewardsQueryResults } from "src/fixtures/rewards-query-results";
import { setupContractAndToken } from "src/fixtures/contract-setup";
import { advanceToSaleAndAndLaunchMarket } from "src/fixtures/secondary";
import { CreatorERC20zQueryResult } from "./subgraph-queries";

describe("rewardsClient", () => {
makeAnvilTest({
forkBlockNumber: 22375202,
forkUrl: forkUrls.baseMainnet,
anvilChainId: base.id,
})(
"it can query rewards balances where there are multiple minters",
async ({ viemClients: { publicClient, chain } }) => {
const creatorClient = createCreatorClient({
chainId: chain.id,
publicClient,
});
const rewardsBalance = await creatorClient.getRewardsBalances({
account: "0x129F04B140Acc1AA350be2F9f048C178103c62f3",
});

const erc20zKeys = Object.keys(rewardsBalance.secondaryRoyalties.erc20);

expect(erc20zKeys.length).toBeGreaterThan(0);
},
20_000,
);
makeAnvilTest({
forkBlockNumber: 14653556,
forkUrl: forkUrls.zoraSepolia,
Expand Down Expand Up @@ -251,20 +272,31 @@ describe("rewardsClient", () => {

// now we should be able to get rewards balances for these royalties

const mockResult: CreatorERC20zQueryResult = {
zoraCreateTokens: [
{
salesStrategies: [
{
zoraTimedMinter: {
secondaryActivated: true,
erc20Z: { id: erc20z },
},
},
],
},
],
};

// we need to stub the subgraph return
rewardsGetter.subgraphQuerier.query = vi
.fn<ISubgraphQuerier["query"]>()
.mockResolvedValue(
mockRewardsQueryResults({
erc20z: [erc20z],
}),
);
.mockResolvedValue(mockResult);

const rewardsBalance = await creatorClient.getRewardsBalances({
account: creatorAccount,
});

expect(rewardsBalance.secondaryRoyalties.eth).toBeGreaterThan(0);
expect(rewardsBalance.protocolRewards).toBeGreaterThan(0n);
expect(rewardsBalance.secondaryRoyalties.erc20[erc20z]).toBeGreaterThan(
0,
);
Expand Down
20 changes: 15 additions & 5 deletions packages/protocol-sdk/src/rewards/rewards-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,13 @@ export const getRewardsBalance = async ({
rewardsGetter: IRewardsGetter;
}): Promise<RewardsBalance> => {
const address = typeof account === "string" ? account : account.address;
const erc20Zs = await rewardsGetter.getErc20ZzForCreator({ address });
const erc20ZsAndSecondaryActivated = await rewardsGetter.getErc20ZzForCreator(
{ address },
);

const validErc20Zs = erc20ZsAndSecondaryActivated
.filter(({ secondaryActivated }) => secondaryActivated)
.map(({ erc20z }) => erc20z);

// Perform multicall to get protocol rewards balance and unclaimed fees
const result = await (publicClient as PublicClientWithMulticall).multicall({
Expand All @@ -98,7 +104,7 @@ export const getRewardsBalance = async ({
],
abi: erc20ZRoyaltiesABI,
functionName: "getUnclaimedFeesBatch",
args: [erc20Zs],
args: [validErc20Zs],
},
],
multicallAddress: multicall3Address,
Expand Down Expand Up @@ -147,9 +153,13 @@ const makeClaimSecondaryRoyaltiesCalls = async ({
chainId: number;
rewardsGetter: IRewardsGetter;
}) => {
const erc20z = await rewardsGetter.getErc20ZzForCreator({
address: claimFor,
});
const erc20ZsAndSecondaryActivated = await rewardsGetter.getErc20ZzForCreator(
{ address: claimFor },
);

const erc20z = erc20ZsAndSecondaryActivated
.filter(({ secondaryActivated }) => secondaryActivated)
.map(({ erc20z }) => erc20z);

const royaltiesAddress =
erc20ZRoyaltiesAddress[chainId as keyof typeof erc20ZRoyaltiesAddress];
Expand Down
4 changes: 3 additions & 1 deletion packages/protocol-sdk/src/rewards/subgraph-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { Address } from "viem";
export type RewardsToken = {
salesStrategies: [
{
zoraTimedMinter: {
zoraTimedMinter?: {
secondaryActivated: boolean;
erc20Z: {
id: Address;
};
Expand Down Expand Up @@ -33,6 +34,7 @@ export function buildCreatorERC20zs({
}
salesStrategies {
zoraTimedMinter {
secondaryActivated
erc20Z {
id
}
Expand Down
34 changes: 24 additions & 10 deletions packages/protocol-sdk/src/rewards/subgraph-rewards-getter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import { Address } from "viem";
import { buildCreatorERC20zs } from "./subgraph-queries";

export interface IRewardsGetter {
getErc20ZzForCreator: (params: { address: Address }) => Promise<Address[]>;
getErc20ZzForCreator: (params: {
address: Address;
}) => Promise<{ secondaryActivated: boolean; erc20z: Address }[]>;
}

export class SubgraphRewardsGetter
Expand All @@ -15,19 +17,31 @@ export class SubgraphRewardsGetter
super(chainId, subgraphQuerier);
}

async getErc20ZzForCreator({
address,
}: {
address: Address;
}): Promise<Address[]> {
async getErc20ZzForCreator({ address }: { address: Address }) {
const queryResults = await this.querySubgraphWithRetries(
buildCreatorERC20zs({ address }),
);

return (
queryResults?.map(
(result) => result.salesStrategies[0].zoraTimedMinter.erc20Z.id,
) || []
const results = (
queryResults?.map((result) => {
const timedMinter = result.salesStrategies[0].zoraTimedMinter;

if (!timedMinter) {
return null;
}

return {
secondaryActivated: timedMinter.secondaryActivated,
erc20z: timedMinter.erc20Z.id,
};
}) || []
).filter(
(
idAndActivated,
): idAndActivated is { secondaryActivated: boolean; erc20z: Address } =>
!!idAndActivated,
);

return results;
}
}

0 comments on commit 330f113

Please sign in to comment.