@boostxyz/sdk 6.0.3 → 6.1.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.
@@ -17,7 +17,7 @@ import { StrategyType } from "./claiming";
17
17
  import { BoostNotFoundError, IncentiveNotCloneableError } from "./errors";
18
18
  import type { ERC20Incentive } from "./Incentives/ERC20Incentive";
19
19
  import { bytes4 } from "./utils";
20
- import { BoostValidatorEOA } from "./Validators/Validator";
20
+ import { BoostValidatorEOA } from './Validators/Validator';
21
21
  import { AssetType } from "./transfers";
22
22
  import { waitForTransactionReceipt } from "@wagmi/core";
23
23
  import { SignatureType } from "./Actions/EventAction";
@@ -1279,3 +1279,84 @@ describe("ERC20PeggedVariableCriteriaIncentive Top-Ups", () => {
1279
1279
  expect(newLimit).toBe(originalLimit + expectedNetTopup);
1280
1280
  });
1281
1281
  });
1282
+
1283
+ describe("ERC20PeggedVariableCriteriaIncentive with LimitedSignerValidator", () => {
1284
+ test("enforces validator claim limit", async () => {
1285
+ const referrer = accounts[1].account!;
1286
+ const signer = accounts[0];
1287
+ const { core } = fixtures;
1288
+ const { budget, erc20 } = budgets;
1289
+
1290
+ const erc721 = await loadFixture(fundErc721(defaultOptions));
1291
+ const incentive = core.ERC20PeggedVariableCriteriaIncentive({
1292
+ asset: erc20.assertValidAddress(),
1293
+ peg: erc20.assertValidAddress(),
1294
+ reward: parseEther("1"),
1295
+ limit: parseEther("10"),
1296
+ maxReward: parseEther("2"),
1297
+ manager: budget.assertValidAddress(),
1298
+ criteria: {
1299
+ criteriaType: SignatureType.FUNC,
1300
+ signature: pad(bytes4("transferFrom(address,address,uint256)")),
1301
+ fieldIndex: 2,
1302
+ targetContract: erc721.assertValidAddress(),
1303
+ },
1304
+ });
1305
+ await erc20.mint(defaultOptions.account.address, parseEther("110"));
1306
+ await erc20.approve(budget.assertValidAddress(), parseEther("110"));
1307
+ await budget.allocate({
1308
+ amount: parseEther("110"),
1309
+ asset: erc20.assertValidAddress(),
1310
+ target: defaultOptions.account.address,
1311
+ });
1312
+
1313
+ const boost = await core.createBoost({
1314
+ protocolFee: 0n,
1315
+ maxParticipants: 5n,
1316
+ budget,
1317
+ action: core.EventAction(
1318
+ makeMockEventActionPayload(
1319
+ core.assertValidAddress(),
1320
+ erc20.assertValidAddress(),
1321
+ ),
1322
+ ),
1323
+ allowList: core.SimpleAllowList({
1324
+ owner: defaultOptions.account.address,
1325
+ allowed: [defaultOptions.account.address],
1326
+ }),
1327
+ incentives: [incentive],
1328
+ });
1329
+
1330
+ const claimant = defaultOptions.account.address;
1331
+ const signedAmount = parseEther("1");
1332
+ const incentiveData = incentive.buildClaimData(signedAmount);
1333
+
1334
+ // First claim
1335
+ const firstClaimPayload = await boost.validator.encodeClaimData({
1336
+ signer: signer,
1337
+ incentiveData,
1338
+ chainId: defaultOptions.config.chains[0].id,
1339
+ incentiveQuantity: boost.incentives.length,
1340
+ claimant,
1341
+ boostId: boost.id,
1342
+ });
1343
+
1344
+ // First claim should succeed
1345
+ await core.claimIncentive(boost.id, 0n, referrer, firstClaimPayload);
1346
+
1347
+ // Generate new signature for second claim
1348
+ const secondClaimPayload = await boost.validator.encodeClaimData({
1349
+ signer: signer,
1350
+ incentiveData,
1351
+ chainId: defaultOptions.config.chains[0].id,
1352
+ incentiveQuantity: boost.incentives.length,
1353
+ claimant,
1354
+ boostId: boost.id,
1355
+ });
1356
+
1357
+ // Second claim should fail due to validator limit (specific error code)
1358
+ await expect(
1359
+ core.claimIncentive(boost.id, 0n, referrer, secondClaimPayload)
1360
+ ).rejects.toThrow("0x059b7045"); // BoostError.MaximumClaimed
1361
+ });
1362
+ });
package/src/BoostCore.ts CHANGED
@@ -527,13 +527,22 @@ export class BoostCore extends Deployable<
527
527
  Object.keys(this.addresses).map(Number),
528
528
  );
529
529
  const testnet = chain.testnet || chain.id === 31337;
530
- payload.validator = this.SignerValidator({
531
- signers: [
532
- (testnet
533
- ? BoostValidatorEOA.TESTNET
534
- : BoostValidatorEOA.MAINNET) as unknown as Address,
535
- ],
530
+ const signers = [
531
+ (testnet
532
+ ? BoostValidatorEOA.TESTNET
533
+ : BoostValidatorEOA.MAINNET) as unknown as Address,
534
+ ];
535
+
536
+ // This seemed like the best approach - I didn't want to use the testnet PK even in local testing
537
+ // May be another approach but this works for now and is pretty well isolated
538
+ if (chain.id === 31337) {
539
+ signers.push('0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266');
540
+ }
541
+
542
+ payload.validator = this.LimitedSignerValidator({
543
+ signers,
536
544
  validatorCaller: coreAddress,
545
+ maxClaimCount: 1,
537
546
  });
538
547
  }
539
548