@boostxyz/sdk 2.0.0-alpha.34 → 2.0.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/dist/Incentives/AllowListIncentive.cjs +1 -1
- package/dist/Incentives/AllowListIncentive.cjs.map +1 -1
- package/dist/Incentives/AllowListIncentive.d.ts +18 -0
- package/dist/Incentives/AllowListIncentive.d.ts.map +1 -1
- package/dist/Incentives/AllowListIncentive.js +46 -20
- package/dist/Incentives/AllowListIncentive.js.map +1 -1
- package/dist/Incentives/CGDAIncentive.cjs +1 -1
- package/dist/Incentives/CGDAIncentive.cjs.map +1 -1
- package/dist/Incentives/CGDAIncentive.d.ts +18 -0
- package/dist/Incentives/CGDAIncentive.d.ts.map +1 -1
- package/dist/Incentives/CGDAIncentive.js +55 -24
- package/dist/Incentives/CGDAIncentive.js.map +1 -1
- package/dist/Incentives/ERC20Incentive.cjs +1 -1
- package/dist/Incentives/ERC20Incentive.cjs.map +1 -1
- package/dist/Incentives/ERC20Incentive.d.ts +18 -0
- package/dist/Incentives/ERC20Incentive.d.ts.map +1 -1
- package/dist/Incentives/ERC20Incentive.js +46 -20
- package/dist/Incentives/ERC20Incentive.js.map +1 -1
- package/dist/Incentives/ERC20VariableIncentive.cjs +1 -1
- package/dist/Incentives/ERC20VariableIncentive.cjs.map +1 -1
- package/dist/Incentives/ERC20VariableIncentive.d.ts +28 -1
- package/dist/Incentives/ERC20VariableIncentive.d.ts.map +1 -1
- package/dist/Incentives/ERC20VariableIncentive.js +45 -8
- package/dist/Incentives/ERC20VariableIncentive.js.map +1 -1
- package/dist/Incentives/PointsIncentive.cjs +1 -1
- package/dist/Incentives/PointsIncentive.cjs.map +1 -1
- package/dist/Incentives/PointsIncentive.d.ts +18 -0
- package/dist/Incentives/PointsIncentive.d.ts.map +1 -1
- package/dist/Incentives/PointsIncentive.js +41 -15
- package/dist/Incentives/PointsIncentive.js.map +1 -1
- package/dist/Validators/SignerValidator.cjs.map +1 -1
- package/dist/Validators/SignerValidator.d.ts.map +1 -1
- package/dist/Validators/SignerValidator.js.map +1 -1
- package/dist/Validators/Validator.cjs +1 -1
- package/dist/Validators/Validator.cjs.map +1 -1
- package/dist/Validators/Validator.d.ts +12 -1
- package/dist/Validators/Validator.d.ts.map +1 -1
- package/dist/Validators/Validator.js +37 -20
- package/dist/Validators/Validator.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +80 -78
- package/dist/utils.cjs +1 -1
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.ts +12 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +64 -35
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/Incentives/AllowListIncentive.test.ts +52 -4
- package/src/Incentives/AllowListIncentive.ts +28 -0
- package/src/Incentives/CGDAIncentive.test.ts +48 -3
- package/src/Incentives/CGDAIncentive.ts +34 -0
- package/src/Incentives/ERC20Incentive.test.ts +42 -0
- package/src/Incentives/ERC20Incentive.ts +28 -0
- package/src/Incentives/ERC20VariableIncentive.test.ts +74 -0
- package/src/Incentives/ERC20VariableIncentive.ts +41 -0
- package/src/Incentives/PointsIncentive.test.ts +47 -3
- package/src/Incentives/PointsIncentive.ts +28 -0
- package/src/Validators/SignerValidator.ts +0 -1
- package/src/Validators/Validator.ts +24 -1
- package/src/utils.ts +46 -0
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
zeroAddress
|
|
17
17
|
} from "viem";
|
|
18
18
|
import { beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
19
|
+
import { decodeClaimData } from "../Validators/Validator";
|
|
19
20
|
import { ERC20VariableIncentive } from "./ERC20VariableIncentive";
|
|
20
21
|
|
|
21
22
|
|
|
@@ -83,6 +84,46 @@ describe("ERC20VariableIncentive", () => {
|
|
|
83
84
|
).toBe(1n);
|
|
84
85
|
});
|
|
85
86
|
|
|
87
|
+
test("can test claimability", async () => {
|
|
88
|
+
// biome-ignore lint/style/noNonNullAssertion: we know this is defined
|
|
89
|
+
const referrer = accounts.at(1)!.account!,
|
|
90
|
+
// biome-ignore lint/style/noNonNullAssertion: we know this is defined
|
|
91
|
+
trustedSigner = accounts.at(0)!;
|
|
92
|
+
const erc20VariableIncentive = new fixtures.bases.ERC20VariableIncentive(
|
|
93
|
+
defaultOptions,
|
|
94
|
+
{
|
|
95
|
+
asset: budgets.erc20.assertValidAddress(),
|
|
96
|
+
reward: 1n,
|
|
97
|
+
limit: 1n,
|
|
98
|
+
manager: zeroAddress,
|
|
99
|
+
},
|
|
100
|
+
);
|
|
101
|
+
const boost = await freshBoost(fixtures, {
|
|
102
|
+
budget: budgets.budget,
|
|
103
|
+
incentives: [erc20VariableIncentive],
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const claimant = trustedSigner.account;
|
|
107
|
+
const claimDataPayload = await boost.validator.encodeClaimData({
|
|
108
|
+
signer: trustedSigner,
|
|
109
|
+
incentiveData: erc20VariableIncentive.buildClaimData(parseEther("1")),
|
|
110
|
+
chainId: defaultOptions.config.chains[0].id,
|
|
111
|
+
incentiveQuantity: boost.incentives.length,
|
|
112
|
+
claimant,
|
|
113
|
+
boostId: boost.id,
|
|
114
|
+
});
|
|
115
|
+
expect(await boost.incentives.at(0)!.getRemainingClaimPotential()).toBeGreaterThan(0n)
|
|
116
|
+
expect(await boost.incentives.at(0)!.canBeClaimed()).toBe(true)
|
|
117
|
+
await fixtures.core.claimIncentive(
|
|
118
|
+
boost.id,
|
|
119
|
+
0n,
|
|
120
|
+
referrer,
|
|
121
|
+
claimDataPayload,
|
|
122
|
+
);
|
|
123
|
+
expect(await boost.incentives.at(0)!.getRemainingClaimPotential()).toBe(0n)
|
|
124
|
+
expect(await boost.incentives.at(0)!.canBeClaimed()).toBe(false)
|
|
125
|
+
});
|
|
126
|
+
|
|
86
127
|
test("cannot claim twice", async () => {
|
|
87
128
|
// biome-ignore lint/style/noNonNullAssertion: we know this is defined
|
|
88
129
|
const referrer = accounts.at(1)!.account!;
|
|
@@ -130,6 +171,39 @@ describe("ERC20VariableIncentive", () => {
|
|
|
130
171
|
}
|
|
131
172
|
});
|
|
132
173
|
|
|
174
|
+
test("can decode a claimed amount from claim data", async () => {
|
|
175
|
+
// biome-ignore lint/style/noNonNullAssertion: we know this is defined
|
|
176
|
+
const referrer = accounts.at(1)!.account!;
|
|
177
|
+
// biome-ignore lint/style/noNonNullAssertion: we know this is defined
|
|
178
|
+
const trustedSigner = accounts.at(0)!;
|
|
179
|
+
const erc20VariableIncentive = new fixtures.bases.ERC20VariableIncentive(
|
|
180
|
+
defaultOptions,
|
|
181
|
+
{
|
|
182
|
+
asset: budgets.erc20.assertValidAddress(),
|
|
183
|
+
reward: 1n,
|
|
184
|
+
limit: 1n,
|
|
185
|
+
manager: zeroAddress,
|
|
186
|
+
},
|
|
187
|
+
);
|
|
188
|
+
const boost = await freshBoost(fixtures, {
|
|
189
|
+
budget: budgets.budget,
|
|
190
|
+
incentives: [erc20VariableIncentive],
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
const claimant = trustedSigner.account;
|
|
194
|
+
const claimDataPayload = await boost.validator.encodeClaimData({
|
|
195
|
+
signer: trustedSigner,
|
|
196
|
+
incentiveData: erc20VariableIncentive.buildClaimData(parseEther("1")),
|
|
197
|
+
chainId: defaultOptions.config.chains[0].id,
|
|
198
|
+
incentiveQuantity: boost.incentives.length,
|
|
199
|
+
claimant,
|
|
200
|
+
boostId: boost.id,
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
const { incentiveData } = decodeClaimData(claimDataPayload)
|
|
204
|
+
expect(erc20VariableIncentive.decodeClaimData(incentiveData)).toBe(parseEther("1"))
|
|
205
|
+
});
|
|
206
|
+
|
|
133
207
|
test("can properly encode a uint256", () => {
|
|
134
208
|
//@ts-ignore
|
|
135
209
|
const incentive = fixtures.core.ERC20VariableIncentive();
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
type Address,
|
|
21
21
|
type ContractEventName,
|
|
22
22
|
type Hex,
|
|
23
|
+
decodeAbiParameters,
|
|
23
24
|
encodeAbiParameters,
|
|
24
25
|
} from 'viem';
|
|
25
26
|
import { ERC20VariableIncentive as ERC20VariableIncentiveBases } from '../../dist/deployments.json';
|
|
@@ -366,6 +367,34 @@ export class ERC20VariableIncentive<
|
|
|
366
367
|
return await this.limit(params);
|
|
367
368
|
}
|
|
368
369
|
|
|
370
|
+
/**
|
|
371
|
+
* Check if any claims remain by comparing the incentive's total claimed amount against its limit. Does not take requesting user's elligibility into account.
|
|
372
|
+
*
|
|
373
|
+
* @public
|
|
374
|
+
* @async
|
|
375
|
+
* @param {?ReadParams} [params]
|
|
376
|
+
* @returns {Promise<boolean>} - True if limit minus total claimed is greater than 0
|
|
377
|
+
*/
|
|
378
|
+
public async canBeClaimed(params?: ReadParams) {
|
|
379
|
+
return (await this.getRemainingClaimPotential(params)) > 0n;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Check how much of the underlying asset remains by comparing the the limit against the total amount claimed. Does not take requesting user's elligibility into account.
|
|
384
|
+
*
|
|
385
|
+
* @public
|
|
386
|
+
* @async
|
|
387
|
+
* @param {?ReadParams} [params]
|
|
388
|
+
* @returns {Promise<bigint>} - Limit minus total claimed
|
|
389
|
+
*/
|
|
390
|
+
public async getRemainingClaimPotential(params?: ReadParams) {
|
|
391
|
+
const [totalClaimed, limit] = await Promise.all([
|
|
392
|
+
this.totalClaimed(params),
|
|
393
|
+
this.limit(params),
|
|
394
|
+
]);
|
|
395
|
+
return limit - totalClaimed;
|
|
396
|
+
}
|
|
397
|
+
|
|
369
398
|
/**
|
|
370
399
|
* Builds the claim data for the ERC20VariableIncentive.
|
|
371
400
|
*
|
|
@@ -381,6 +410,18 @@ export class ERC20VariableIncentive<
|
|
|
381
410
|
);
|
|
382
411
|
}
|
|
383
412
|
|
|
413
|
+
/**
|
|
414
|
+
* Decodes claim data for the ERC20VariableIncentive, returning the encoded claim amount.
|
|
415
|
+
* Useful when deriving amount claimed from logs.
|
|
416
|
+
*
|
|
417
|
+
* @public
|
|
418
|
+
* @param {Hex} claimData
|
|
419
|
+
* @returns {BigInt} Returns the reward amount from a claim data payload
|
|
420
|
+
*/
|
|
421
|
+
public decodeClaimData(data: Hex) {
|
|
422
|
+
return BigInt(decodeAbiParameters([{ type: 'uint256' }], data)[0]);
|
|
423
|
+
}
|
|
424
|
+
|
|
384
425
|
/**
|
|
385
426
|
* Encodes an amount to clawback from the incentive
|
|
386
427
|
*
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import { readPointsBalanceOf, writePointsGrantRoles } from "@boostxyz/evm";
|
|
2
|
-
import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
|
|
3
|
-
import { isAddress, pad, parseEther, zeroAddress } from "viem";
|
|
4
|
-
import { beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
5
2
|
import type { MockPoints } from "@boostxyz/test/MockPoints";
|
|
6
3
|
import { accounts } from "@boostxyz/test/accounts";
|
|
7
4
|
import {
|
|
@@ -11,6 +8,9 @@ import {
|
|
|
11
8
|
freshBoost,
|
|
12
9
|
freshPoints,
|
|
13
10
|
} from "@boostxyz/test/helpers";
|
|
11
|
+
import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
|
|
12
|
+
import { isAddress, pad, parseEther, zeroAddress } from "viem";
|
|
13
|
+
import { beforeAll, beforeEach, describe, expect, test } from "vitest";
|
|
14
14
|
import { bytes4 } from "../utils";
|
|
15
15
|
import { PointsIncentive } from "./PointsIncentive";
|
|
16
16
|
|
|
@@ -81,6 +81,50 @@ describe("PointsIncentive", () => {
|
|
|
81
81
|
).toBe(1n);
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
+
test("can test claimability", async () => {
|
|
85
|
+
// biome-ignore lint/style/noNonNullAssertion: we know this is defined
|
|
86
|
+
const referrer = accounts.at(1)!.account!;
|
|
87
|
+
// biome-ignore lint/style/noNonNullAssertion: we know this is defined
|
|
88
|
+
const trustedSigner = accounts.at(0)!;
|
|
89
|
+
const pointsIncentive = fixtures.core.PointsIncentive({
|
|
90
|
+
venue: points.assertValidAddress(),
|
|
91
|
+
selector: bytes4("issue(address,uint256)"),
|
|
92
|
+
reward: 1n,
|
|
93
|
+
limit: 1n,
|
|
94
|
+
});
|
|
95
|
+
const boost = await freshBoost(fixtures, {
|
|
96
|
+
incentives: [pointsIncentive],
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const claimant = trustedSigner.account;
|
|
100
|
+
const incentiveData = pad("0xdef456232173821931823712381232131391321934");
|
|
101
|
+
const claimDataPayload = await boost.validator.encodeClaimData({
|
|
102
|
+
signer: trustedSigner,
|
|
103
|
+
incentiveData,
|
|
104
|
+
chainId: defaultOptions.config.chains[0].id,
|
|
105
|
+
incentiveQuantity: boost.incentives.length,
|
|
106
|
+
claimant,
|
|
107
|
+
boostId: boost.id,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
expect(await boost.incentives.at(0)!.getRemainingClaimPotential()).toBeGreaterThan(0n)
|
|
111
|
+
expect(await boost.incentives.at(0)!.canBeClaimed()).toBe(true)
|
|
112
|
+
|
|
113
|
+
await writePointsGrantRoles(defaultOptions.config, {
|
|
114
|
+
address: points.assertValidAddress(),
|
|
115
|
+
args: [pointsIncentive.assertValidAddress(), 2n],
|
|
116
|
+
account: defaultOptions.account,
|
|
117
|
+
});
|
|
118
|
+
await fixtures.core.claimIncentive(
|
|
119
|
+
boost.id,
|
|
120
|
+
0n,
|
|
121
|
+
referrer,
|
|
122
|
+
claimDataPayload,
|
|
123
|
+
);
|
|
124
|
+
expect(await boost.incentives.at(0)!.getRemainingClaimPotential()).toBe(0n)
|
|
125
|
+
expect(await boost.incentives.at(0)!.canBeClaimed()).toBe(false)
|
|
126
|
+
});
|
|
127
|
+
|
|
84
128
|
test("cannot claim twice", async () => {
|
|
85
129
|
const reward = 1n;
|
|
86
130
|
// biome-ignore lint/style/noNonNullAssertion: we know this is defined
|
|
@@ -296,6 +296,34 @@ export class PointsIncentive extends DeployableTarget<
|
|
|
296
296
|
});
|
|
297
297
|
}
|
|
298
298
|
|
|
299
|
+
/**
|
|
300
|
+
* Check if any claims remain by comparing the incentive's total claims against its limit. Does not take requesting user's elligibility into account.
|
|
301
|
+
*
|
|
302
|
+
* @public
|
|
303
|
+
* @async
|
|
304
|
+
* @param {?ReadParams} [params]
|
|
305
|
+
* @returns {Promise<boolean>} - True if total claims is less than limit
|
|
306
|
+
*/
|
|
307
|
+
public async canBeClaimed(params?: ReadParams) {
|
|
308
|
+
return (await this.getRemainingClaimPotential(params)) > 0n;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Check how many claims remain by comparing the incentive's total claims against its limit. Does not take requesting user's elligibility into account.
|
|
313
|
+
*
|
|
314
|
+
* @public
|
|
315
|
+
* @async
|
|
316
|
+
* @param {?ReadParams} [params]
|
|
317
|
+
* @returns {Promise<bigint>} - True if total claims is less than limit
|
|
318
|
+
*/
|
|
319
|
+
public async getRemainingClaimPotential(params?: ReadParams) {
|
|
320
|
+
const [claims, limit] = await Promise.all([
|
|
321
|
+
this.claims(params),
|
|
322
|
+
this.limit(params),
|
|
323
|
+
]);
|
|
324
|
+
return limit - claims;
|
|
325
|
+
}
|
|
326
|
+
|
|
299
327
|
/**
|
|
300
328
|
* @inheritdoc
|
|
301
329
|
*
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
// ALimitedSignerValidator,
|
|
6
6
|
} from '@boostxyz/evm/deploys/componentInterfaces.json';
|
|
7
7
|
import { readContract } from '@wagmi/core';
|
|
8
|
-
import type
|
|
8
|
+
import { type Address, type Hex, decodeAbiParameters } from 'viem';
|
|
9
9
|
import type { DeployableOptions } from '../Deployable/Deployable';
|
|
10
10
|
import { InvalidComponentInterfaceError } from '../errors';
|
|
11
11
|
import { LimitedSignerValidator } from './LimitedSignerValidator';
|
|
@@ -80,3 +80,26 @@ export const BoostValidatorEOA = {
|
|
|
80
80
|
MAINNET: import.meta.env.VITE_BOOST_MAINNET_SIGNER_EOA as Address,
|
|
81
81
|
TESTNET: import.meta.env.VITE_BOOST_TESTNET_SIGNER_EOA as Address,
|
|
82
82
|
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Decodes a claim data hex string into its validator data and incentive data components.
|
|
86
|
+
*
|
|
87
|
+
* @export
|
|
88
|
+
* @param {Hex} data - The hex-encoded claim data to decode
|
|
89
|
+
* @returns {{ validatorData: Hex; incentiveData: Hex }} The decoded claim data components
|
|
90
|
+
*/
|
|
91
|
+
export function decodeClaimData(data: Hex) {
|
|
92
|
+
return decodeAbiParameters(
|
|
93
|
+
[
|
|
94
|
+
{
|
|
95
|
+
type: 'tuple',
|
|
96
|
+
name: 'BoostClaimData',
|
|
97
|
+
components: [
|
|
98
|
+
{ type: 'bytes', name: 'validatorData' },
|
|
99
|
+
{ type: 'bytes', name: 'incentiveData' },
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
data,
|
|
104
|
+
)[0];
|
|
105
|
+
}
|
package/src/utils.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
type WatchContractEventParameters,
|
|
6
6
|
getAccount,
|
|
7
7
|
getChainId,
|
|
8
|
+
readContract,
|
|
8
9
|
waitForTransactionReceipt,
|
|
9
10
|
} from '@wagmi/core';
|
|
10
11
|
import type { ExtractAbiEvent } from 'abitype';
|
|
@@ -255,3 +256,48 @@ export function assertValidAddressByChainId(
|
|
|
255
256
|
// biome-ignore lint/style/noNonNullAssertion: this type should be narrowed by the above statement but isn't?
|
|
256
257
|
return { chainId, address: addressByChainId[chainId]! };
|
|
257
258
|
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Check an ERC20's balance for a given asset and
|
|
262
|
+
*
|
|
263
|
+
* @public
|
|
264
|
+
* @async
|
|
265
|
+
* @param {Config} [config]
|
|
266
|
+
* @param {Address} [asset]
|
|
267
|
+
* @param {Address} [owner]
|
|
268
|
+
* @param {?ReadParams} [params]
|
|
269
|
+
* @returns {Promise<bigint>} - The erc20 balance
|
|
270
|
+
*/
|
|
271
|
+
export async function getErc20Balance(
|
|
272
|
+
config: Config,
|
|
273
|
+
asset: Address,
|
|
274
|
+
owner: Address,
|
|
275
|
+
params?: ReadParams,
|
|
276
|
+
) {
|
|
277
|
+
return await readContract(config, {
|
|
278
|
+
...params,
|
|
279
|
+
functionName: 'balanceOf',
|
|
280
|
+
address: asset,
|
|
281
|
+
args: [owner],
|
|
282
|
+
abi: [
|
|
283
|
+
{
|
|
284
|
+
constant: true,
|
|
285
|
+
inputs: [
|
|
286
|
+
{
|
|
287
|
+
name: '_owner',
|
|
288
|
+
type: 'address',
|
|
289
|
+
},
|
|
290
|
+
],
|
|
291
|
+
name: 'balanceOf',
|
|
292
|
+
outputs: [
|
|
293
|
+
{
|
|
294
|
+
name: 'balance',
|
|
295
|
+
type: 'uint256',
|
|
296
|
+
},
|
|
297
|
+
],
|
|
298
|
+
stateMutability: 'view',
|
|
299
|
+
type: 'function',
|
|
300
|
+
},
|
|
301
|
+
],
|
|
302
|
+
});
|
|
303
|
+
}
|