@zoralabs/protocol-sdk 0.9.6 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +7 -7
- package/CHANGELOG.md +6 -0
- package/dist/anvil.d.ts +11 -1
- package/dist/anvil.d.ts.map +1 -1
- package/dist/apis/multicall3.d.ts +9 -0
- package/dist/apis/multicall3.d.ts.map +1 -0
- package/dist/apis/subgraph-getter.d.ts +9 -0
- package/dist/apis/subgraph-getter.d.ts.map +1 -0
- package/dist/create/contract-getter.d.ts +3 -6
- package/dist/create/contract-getter.d.ts.map +1 -1
- package/dist/fixtures/mint-query-results.d.ts +10 -0
- package/dist/fixtures/mint-query-results.d.ts.map +1 -0
- package/dist/fixtures/rewards-query-results.d.ts +6 -0
- package/dist/fixtures/rewards-query-results.d.ts.map +1 -0
- package/dist/index.cjs +402 -161
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +408 -161
- package/dist/index.js.map +1 -1
- package/dist/mint/subgraph-mint-getter.d.ts +3 -5
- package/dist/mint/subgraph-mint-getter.d.ts.map +1 -1
- package/dist/rewards/rewards-client.d.ts +34 -0
- package/dist/rewards/rewards-client.d.ts.map +1 -0
- package/dist/rewards/rewards-queries.d.ts +34 -0
- package/dist/rewards/rewards-queries.d.ts.map +1 -0
- package/dist/rewards/subgraph-queries.d.ts +20 -0
- package/dist/rewards/subgraph-queries.d.ts.map +1 -0
- package/dist/rewards/subgraph-rewards-getter.d.ts +15 -0
- package/dist/rewards/subgraph-rewards-getter.d.ts.map +1 -0
- package/dist/sdk.d.ts +5 -0
- package/dist/sdk.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/apis/multicall3.ts +19 -0
- package/src/apis/subgraph-getter.ts +33 -0
- package/src/create/1155-create-helper.test.ts +18 -18
- package/src/create/contract-getter.ts +7 -29
- package/src/fixtures/mint-query-results.ts +55 -0
- package/src/fixtures/rewards-query-results.ts +25 -0
- package/src/mint/mint-client.test.ts +18 -46
- package/src/mint/subgraph-mint-getter.ts +7 -27
- package/src/rewards/rewards-client.test.ts +406 -0
- package/src/rewards/rewards-client.ts +67 -0
- package/src/rewards/rewards-queries.ts +253 -0
- package/src/rewards/subgraph-queries.ts +49 -0
- package/src/rewards/subgraph-rewards-getter.ts +33 -0
- package/src/sdk.ts +18 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import {
|
|
2
|
+
protocolRewardsABI,
|
|
3
|
+
protocolRewardsAddress,
|
|
4
|
+
erc20ZRoyaltiesABI,
|
|
5
|
+
erc20ZRoyaltiesAddress,
|
|
6
|
+
wethAddress,
|
|
7
|
+
} from "@zoralabs/protocol-deployments";
|
|
8
|
+
import { makeContractParameters, PublicClient } from "src/utils";
|
|
9
|
+
import { PublicClient as PublicClientWithMulticall } from "viem";
|
|
10
|
+
import { Account, Address, encodeFunctionData, parseAbi } from "viem";
|
|
11
|
+
import { IRewardsGetter } from "./subgraph-rewards-getter";
|
|
12
|
+
import {
|
|
13
|
+
multicall3Abi,
|
|
14
|
+
multicall3Address,
|
|
15
|
+
Multicall3Call3,
|
|
16
|
+
} from "src/apis/multicall3";
|
|
17
|
+
|
|
18
|
+
// Aggregates unclaimed fees and separates ETH from other ERC20 tokens
|
|
19
|
+
function aggregateUnclaimedFees(
|
|
20
|
+
unclaimedFees: readonly {
|
|
21
|
+
token0: `0x${string}`;
|
|
22
|
+
token1: `0x${string}`;
|
|
23
|
+
token0Amount: bigint;
|
|
24
|
+
token1Amount: bigint;
|
|
25
|
+
}[],
|
|
26
|
+
wethAddress: Address,
|
|
27
|
+
) {
|
|
28
|
+
let ethBalance = 0n;
|
|
29
|
+
// Aggregate unclaimed fees by token address
|
|
30
|
+
const unclaimedFeesAggregate = unclaimedFees.reduce(
|
|
31
|
+
(acc, fee) => {
|
|
32
|
+
const addFee = (token: `0x${string}`, amount: bigint) => {
|
|
33
|
+
if (token === wethAddress) {
|
|
34
|
+
ethBalance += amount;
|
|
35
|
+
} else if (acc[token]) {
|
|
36
|
+
acc[token] += amount;
|
|
37
|
+
} else {
|
|
38
|
+
acc[token] = amount;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
// Apply 75% fee to each token amount
|
|
42
|
+
addFee(fee.token0, (fee.token0Amount * 75n) / 100n);
|
|
43
|
+
addFee(fee.token1, (fee.token1Amount * 75n) / 100n);
|
|
44
|
+
return acc;
|
|
45
|
+
},
|
|
46
|
+
{} as Record<string, bigint>,
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
eth: (ethBalance * 75n) / 100n, // Apply 75% fee to ETH balance
|
|
51
|
+
erc20: unclaimedFeesAggregate,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Define the return type for getRewardsBalance
|
|
56
|
+
type RewardsBalance = {
|
|
57
|
+
// The total balance, in eth of protocol rewards
|
|
58
|
+
protocolRewards: bigint;
|
|
59
|
+
// The secondary royalties balance.
|
|
60
|
+
secondaryRoyalties: {
|
|
61
|
+
// The balance, in eth, of secondary royalties
|
|
62
|
+
eth: bigint;
|
|
63
|
+
// The balance, aggregated by erc20 address, of secondary royalties
|
|
64
|
+
erc20: Record<Address, bigint>;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const getRewardsBalance = async ({
|
|
69
|
+
account, // The account to check rewards for (Address or Account object)
|
|
70
|
+
publicClient, // The public client for making blockchain queries
|
|
71
|
+
chainId, // The ID of the blockchain network
|
|
72
|
+
rewardsGetter, // Interface for getting ERC20Z tokens for a creator
|
|
73
|
+
}: {
|
|
74
|
+
account: Account | Address;
|
|
75
|
+
publicClient: PublicClient;
|
|
76
|
+
chainId: number;
|
|
77
|
+
rewardsGetter: IRewardsGetter;
|
|
78
|
+
}): Promise<RewardsBalance> => {
|
|
79
|
+
const address = typeof account === "string" ? account : account.address;
|
|
80
|
+
const erc20Zs = await rewardsGetter.getErc20ZzForCreator({ address });
|
|
81
|
+
|
|
82
|
+
// Perform multicall to get protocol rewards balance and unclaimed fees
|
|
83
|
+
const result = await (publicClient as PublicClientWithMulticall).multicall({
|
|
84
|
+
contracts: [
|
|
85
|
+
{
|
|
86
|
+
address:
|
|
87
|
+
protocolRewardsAddress[
|
|
88
|
+
chainId as keyof typeof protocolRewardsAddress
|
|
89
|
+
],
|
|
90
|
+
abi: protocolRewardsABI,
|
|
91
|
+
functionName: "balanceOf",
|
|
92
|
+
args: [address],
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
address:
|
|
96
|
+
erc20ZRoyaltiesAddress[
|
|
97
|
+
chainId as keyof typeof erc20ZRoyaltiesAddress
|
|
98
|
+
],
|
|
99
|
+
abi: erc20ZRoyaltiesABI,
|
|
100
|
+
functionName: "getUnclaimedFeesBatch",
|
|
101
|
+
args: [erc20Zs],
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
multicallAddress: multicall3Address,
|
|
105
|
+
allowFailure: false,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const protocolRewardsBalance = result[0];
|
|
109
|
+
|
|
110
|
+
const wethAddressForChain = wethAddress[chainId as keyof typeof wethAddress];
|
|
111
|
+
|
|
112
|
+
// Aggregate unclaimed fees
|
|
113
|
+
const unclaimedFeesAggregate = aggregateUnclaimedFees(
|
|
114
|
+
result[1],
|
|
115
|
+
wethAddressForChain,
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
protocolRewards: protocolRewardsBalance,
|
|
120
|
+
secondaryRoyalties: unclaimedFeesAggregate,
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export const withdrawProtocolRewards = ({
|
|
125
|
+
withdrawFor,
|
|
126
|
+
chainId,
|
|
127
|
+
}: {
|
|
128
|
+
// Account to execute the transaction
|
|
129
|
+
withdrawFor: Address;
|
|
130
|
+
chainId: number;
|
|
131
|
+
}) => {
|
|
132
|
+
return makeContractParameters({
|
|
133
|
+
abi: protocolRewardsABI,
|
|
134
|
+
functionName: "withdrawFor",
|
|
135
|
+
address:
|
|
136
|
+
protocolRewardsAddress[chainId as keyof typeof protocolRewardsAddress],
|
|
137
|
+
args: [withdrawFor, 0n],
|
|
138
|
+
});
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const makeClaimSecondaryRoyaltiesCalls = async ({
|
|
142
|
+
claimFor,
|
|
143
|
+
chainId,
|
|
144
|
+
rewardsGetter,
|
|
145
|
+
}: {
|
|
146
|
+
claimFor: Address;
|
|
147
|
+
chainId: number;
|
|
148
|
+
rewardsGetter: IRewardsGetter;
|
|
149
|
+
}) => {
|
|
150
|
+
const erc20z = await rewardsGetter.getErc20ZzForCreator({
|
|
151
|
+
address: claimFor,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
const royaltiesAddress =
|
|
155
|
+
erc20ZRoyaltiesAddress[chainId as keyof typeof erc20ZRoyaltiesAddress];
|
|
156
|
+
|
|
157
|
+
if (erc20z.length === 0) {
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return erc20z.map((erc20z) => ({
|
|
162
|
+
target: royaltiesAddress,
|
|
163
|
+
callData: encodeFunctionData({
|
|
164
|
+
abi: erc20ZRoyaltiesABI,
|
|
165
|
+
functionName: "claimFor",
|
|
166
|
+
args: [erc20z],
|
|
167
|
+
}),
|
|
168
|
+
allowFailure: false,
|
|
169
|
+
}));
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
export async function withdrawSecondaryRoyalties({
|
|
173
|
+
claimFor,
|
|
174
|
+
chainId,
|
|
175
|
+
rewardsGetter,
|
|
176
|
+
}: {
|
|
177
|
+
claimFor: Address;
|
|
178
|
+
chainId: number;
|
|
179
|
+
rewardsGetter: IRewardsGetter;
|
|
180
|
+
}) {
|
|
181
|
+
const calls = await makeClaimSecondaryRoyaltiesCalls({
|
|
182
|
+
claimFor,
|
|
183
|
+
chainId,
|
|
184
|
+
rewardsGetter,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
return makeContractParameters({
|
|
188
|
+
abi: multicall3Abi,
|
|
189
|
+
functionName: "aggregate3",
|
|
190
|
+
address: multicall3Address,
|
|
191
|
+
args: [calls],
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Extract protocol rewards withdrawal call creation
|
|
196
|
+
const createProtocolRewardsCall = (
|
|
197
|
+
chainId: number,
|
|
198
|
+
withdrawFor: Address,
|
|
199
|
+
): Multicall3Call3 => ({
|
|
200
|
+
target:
|
|
201
|
+
protocolRewardsAddress[chainId as keyof typeof protocolRewardsAddress],
|
|
202
|
+
callData: encodeFunctionData({
|
|
203
|
+
abi: protocolRewardsABI,
|
|
204
|
+
functionName: "withdrawFor",
|
|
205
|
+
args: [withdrawFor, 0n],
|
|
206
|
+
}),
|
|
207
|
+
allowFailure: false,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Extract multicall parameters creation
|
|
211
|
+
const createMulticallParameters = (
|
|
212
|
+
calls: Multicall3Call3[],
|
|
213
|
+
account: Address | Account,
|
|
214
|
+
) =>
|
|
215
|
+
makeContractParameters({
|
|
216
|
+
abi: parseAbi(multicall3Abi),
|
|
217
|
+
functionName: "aggregate3",
|
|
218
|
+
address: multicall3Address,
|
|
219
|
+
args: [calls],
|
|
220
|
+
account,
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// Main withdrawRewards function
|
|
224
|
+
export const withdrawRewards = async ({
|
|
225
|
+
account,
|
|
226
|
+
withdrawFor,
|
|
227
|
+
claimSecondaryRoyalties = true,
|
|
228
|
+
chainId,
|
|
229
|
+
rewardsGetter,
|
|
230
|
+
}: {
|
|
231
|
+
account: Address | Account;
|
|
232
|
+
withdrawFor: Address;
|
|
233
|
+
claimSecondaryRoyalties?: boolean;
|
|
234
|
+
chainId: number;
|
|
235
|
+
rewardsGetter: IRewardsGetter;
|
|
236
|
+
}) => {
|
|
237
|
+
if (!claimSecondaryRoyalties) {
|
|
238
|
+
return {
|
|
239
|
+
...withdrawProtocolRewards({ chainId, withdrawFor }),
|
|
240
|
+
account,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const protocolRewardsCall = createProtocolRewardsCall(chainId, withdrawFor);
|
|
245
|
+
const secondaryRoyaltiesCalls = await makeClaimSecondaryRoyaltiesCalls({
|
|
246
|
+
chainId,
|
|
247
|
+
claimFor: withdrawFor,
|
|
248
|
+
rewardsGetter,
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
const allCalls = [protocolRewardsCall, ...secondaryRoyaltiesCalls];
|
|
252
|
+
return createMulticallParameters(allCalls, account);
|
|
253
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ISubgraphQuery } from "src/apis/subgraph-querier";
|
|
2
|
+
import { Address } from "viem";
|
|
3
|
+
|
|
4
|
+
export type RewardsToken = {
|
|
5
|
+
salesStrategies: [
|
|
6
|
+
{
|
|
7
|
+
zoraTimedMinter: {
|
|
8
|
+
erc20Z: {
|
|
9
|
+
id: Address;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
},
|
|
13
|
+
];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type CreatorERC20zQueryResult = {
|
|
17
|
+
zoraCreateTokens: RewardsToken[];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export function buildCreatorERC20zs({
|
|
21
|
+
address,
|
|
22
|
+
}: {
|
|
23
|
+
address: Address;
|
|
24
|
+
}): ISubgraphQuery<CreatorERC20zQueryResult["zoraCreateTokens"]> {
|
|
25
|
+
return {
|
|
26
|
+
query: `
|
|
27
|
+
query ($address: Bytes!) {
|
|
28
|
+
zoraCreateTokens(
|
|
29
|
+
where: { royalties_: { user: $address }, salesStrategies_: { type: "ZORA_TIMED" } }
|
|
30
|
+
) {
|
|
31
|
+
royalties {
|
|
32
|
+
user
|
|
33
|
+
}
|
|
34
|
+
salesStrategies {
|
|
35
|
+
zoraTimedMinter {
|
|
36
|
+
erc20Z {
|
|
37
|
+
id
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
`,
|
|
44
|
+
variables: { address },
|
|
45
|
+
parseResponseData: (responseData: any | undefined) => {
|
|
46
|
+
return responseData?.zoraCreateTokens;
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { SubgraphGetter } from "src/apis/subgraph-getter";
|
|
2
|
+
import { ISubgraphQuerier } from "src/apis/subgraph-querier";
|
|
3
|
+
import { Address } from "viem";
|
|
4
|
+
import { buildCreatorERC20zs } from "./subgraph-queries";
|
|
5
|
+
|
|
6
|
+
export interface IRewardsGetter {
|
|
7
|
+
getErc20ZzForCreator: (params: { address: Address }) => Promise<Address[]>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class SubgraphRewardsGetter
|
|
11
|
+
extends SubgraphGetter
|
|
12
|
+
implements IRewardsGetter
|
|
13
|
+
{
|
|
14
|
+
constructor(chainId: number, subgraphQuerier?: ISubgraphQuerier) {
|
|
15
|
+
super(chainId, subgraphQuerier);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async getErc20ZzForCreator({
|
|
19
|
+
address,
|
|
20
|
+
}: {
|
|
21
|
+
address: Address;
|
|
22
|
+
}): Promise<Address[]> {
|
|
23
|
+
const queryResults = await this.querySubgraphWithRetries(
|
|
24
|
+
buildCreatorERC20zs({ address }),
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
queryResults?.map(
|
|
29
|
+
(result) => result.salesStrategies[0].zoraTimedMinter.erc20Z.id,
|
|
30
|
+
) || []
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
}
|
package/src/sdk.ts
CHANGED
|
@@ -12,6 +12,11 @@ import {
|
|
|
12
12
|
IContractGetter,
|
|
13
13
|
SubgraphContractGetter,
|
|
14
14
|
} from "./create/contract-getter";
|
|
15
|
+
import { RewardsClient } from "./rewards/rewards-client";
|
|
16
|
+
import {
|
|
17
|
+
IRewardsGetter,
|
|
18
|
+
SubgraphRewardsGetter,
|
|
19
|
+
} from "./rewards/subgraph-rewards-getter";
|
|
15
20
|
|
|
16
21
|
export type CreatorClient = {
|
|
17
22
|
createPremint: PremintClient["createPremint"];
|
|
@@ -19,6 +24,8 @@ export type CreatorClient = {
|
|
|
19
24
|
deletePremint: PremintClient["deletePremint"];
|
|
20
25
|
create1155: Create1155Client["createNew1155"];
|
|
21
26
|
create1155OnExistingContract: Create1155Client["createNew1155OnExistingContract"];
|
|
27
|
+
withdrawRewards: RewardsClient["withdrawRewards"];
|
|
28
|
+
getRewardsBalances: RewardsClient["getRewardsBalances"];
|
|
22
29
|
};
|
|
23
30
|
|
|
24
31
|
export type CollectorClient = {
|
|
@@ -34,6 +41,7 @@ export type CreatorClientConfig = ClientConfig & {
|
|
|
34
41
|
/** API for submitting and getting premints. Defaults to the Zora Premint API */
|
|
35
42
|
premintApi?: IPremintAPI;
|
|
36
43
|
contractGetter?: IContractGetter;
|
|
44
|
+
rewardsGetter?: IRewardsGetter;
|
|
37
45
|
};
|
|
38
46
|
|
|
39
47
|
/**
|
|
@@ -60,6 +68,14 @@ export function createCreatorClient(
|
|
|
60
68
|
new SubgraphContractGetter(clientConfig.chainId),
|
|
61
69
|
});
|
|
62
70
|
|
|
71
|
+
const rewardsClient = new RewardsClient({
|
|
72
|
+
chainId: clientConfig.chainId,
|
|
73
|
+
publicClient: clientConfig.publicClient,
|
|
74
|
+
rewardsGetter:
|
|
75
|
+
clientConfig.rewardsGetter ||
|
|
76
|
+
new SubgraphRewardsGetter(clientConfig.chainId),
|
|
77
|
+
});
|
|
78
|
+
|
|
63
79
|
return {
|
|
64
80
|
createPremint: (p) => premintClient.createPremint(p),
|
|
65
81
|
updatePremint: (p) => premintClient.updatePremint(p),
|
|
@@ -67,6 +83,8 @@ export function createCreatorClient(
|
|
|
67
83
|
create1155: (p) => create1155CreatorClient.createNew1155(p),
|
|
68
84
|
create1155OnExistingContract: (p) =>
|
|
69
85
|
create1155CreatorClient.createNew1155OnExistingContract(p),
|
|
86
|
+
getRewardsBalances: (p) => rewardsClient.getRewardsBalances(p),
|
|
87
|
+
withdrawRewards: (p) => rewardsClient.withdrawRewards(p),
|
|
70
88
|
};
|
|
71
89
|
}
|
|
72
90
|
|