@boostxyz/sdk 5.5.0 → 6.0.1

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.
Files changed (178) hide show
  1. package/dist/Actions/Action.cjs +1 -1
  2. package/dist/Actions/Action.js +4 -4
  3. package/dist/Actions/EventAction.cjs +1 -1
  4. package/dist/Actions/EventAction.cjs.map +1 -1
  5. package/dist/Actions/EventAction.d.ts +2 -1
  6. package/dist/Actions/EventAction.d.ts.map +1 -1
  7. package/dist/Actions/EventAction.js +110 -105
  8. package/dist/Actions/EventAction.js.map +1 -1
  9. package/dist/AllowLists/AllowList.cjs +1 -1
  10. package/dist/AllowLists/AllowList.js +3 -3
  11. package/dist/AllowLists/SimpleAllowList.cjs +1 -1
  12. package/dist/AllowLists/SimpleAllowList.cjs.map +1 -1
  13. package/dist/AllowLists/SimpleAllowList.d.ts +2 -2
  14. package/dist/AllowLists/SimpleAllowList.d.ts.map +1 -1
  15. package/dist/AllowLists/SimpleAllowList.js +25 -25
  16. package/dist/AllowLists/SimpleAllowList.js.map +1 -1
  17. package/dist/AllowLists/SimpleDenyList.cjs +1 -1
  18. package/dist/AllowLists/SimpleDenyList.js +3 -3
  19. package/dist/Auth/PassthroughAuth.cjs +1 -1
  20. package/dist/Auth/PassthroughAuth.cjs.map +1 -1
  21. package/dist/Auth/PassthroughAuth.js +14 -14
  22. package/dist/Boost.cjs.map +1 -1
  23. package/dist/Boost.js.map +1 -1
  24. package/dist/BoostCore.cjs +2 -2
  25. package/dist/BoostCore.cjs.map +1 -1
  26. package/dist/BoostCore.d.ts +261 -0
  27. package/dist/BoostCore.d.ts.map +1 -1
  28. package/dist/BoostCore.js +442 -262
  29. package/dist/BoostCore.js.map +1 -1
  30. package/dist/BoostRegistry.cjs +1 -1
  31. package/dist/BoostRegistry.cjs.map +1 -1
  32. package/dist/BoostRegistry.js +43 -43
  33. package/dist/BoostRegistry.js.map +1 -1
  34. package/dist/Budget-CsqSI4NH.cjs +2 -0
  35. package/dist/Budget-CsqSI4NH.cjs.map +1 -0
  36. package/dist/Budget-bMiAGF8s.js +922 -0
  37. package/dist/Budget-bMiAGF8s.js.map +1 -0
  38. package/dist/Budgets/Budget.cjs +1 -1
  39. package/dist/Budgets/Budget.d.ts +5 -4
  40. package/dist/Budgets/Budget.d.ts.map +1 -1
  41. package/dist/Budgets/Budget.js +3 -3
  42. package/dist/Budgets/ManagedBudget.cjs +1 -1
  43. package/dist/Budgets/ManagedBudget.cjs.map +1 -1
  44. package/dist/Budgets/ManagedBudget.js +53 -53
  45. package/dist/Budgets/ManagedBudgetWithFees.d.ts +26 -0
  46. package/dist/Budgets/ManagedBudgetWithFees.d.ts.map +1 -1
  47. package/dist/Budgets/ManagedBudgetWithFeesV2.d.ts +1331 -0
  48. package/dist/Budgets/ManagedBudgetWithFeesV2.d.ts.map +1 -0
  49. package/dist/Deployable/DeployableTarget.cjs +1 -1
  50. package/dist/Deployable/DeployableTarget.js +1 -1
  51. package/dist/Deployable/DeployableTargetWithRBAC.cjs +1 -1
  52. package/dist/Deployable/DeployableTargetWithRBAC.js +15 -15
  53. package/dist/Incentive-DZLG6T1-.js +1036 -0
  54. package/dist/Incentive-DZLG6T1-.js.map +1 -0
  55. package/dist/Incentive-DvNdIJ_x.cjs +2 -0
  56. package/dist/Incentive-DvNdIJ_x.cjs.map +1 -0
  57. package/dist/Incentives/AllowListIncentive.cjs +1 -1
  58. package/dist/Incentives/AllowListIncentive.cjs.map +1 -1
  59. package/dist/Incentives/AllowListIncentive.d.ts +9 -1
  60. package/dist/Incentives/AllowListIncentive.d.ts.map +1 -1
  61. package/dist/Incentives/AllowListIncentive.js +64 -47
  62. package/dist/Incentives/AllowListIncentive.js.map +1 -1
  63. package/dist/Incentives/CGDAIncentive.cjs +1 -1
  64. package/dist/Incentives/CGDAIncentive.cjs.map +1 -1
  65. package/dist/Incentives/CGDAIncentive.d.ts +12 -1
  66. package/dist/Incentives/CGDAIncentive.d.ts.map +1 -1
  67. package/dist/Incentives/CGDAIncentive.js +64 -33
  68. package/dist/Incentives/CGDAIncentive.js.map +1 -1
  69. package/dist/Incentives/ERC20Incentive.cjs +1 -1
  70. package/dist/Incentives/ERC20Incentive.cjs.map +1 -1
  71. package/dist/Incentives/ERC20Incentive.d.ts +37 -1
  72. package/dist/Incentives/ERC20Incentive.d.ts.map +1 -1
  73. package/dist/Incentives/ERC20Incentive.js +73 -49
  74. package/dist/Incentives/ERC20Incentive.js.map +1 -1
  75. package/dist/Incentives/ERC20PeggedIncentive.d.ts +35 -0
  76. package/dist/Incentives/ERC20PeggedIncentive.d.ts.map +1 -1
  77. package/dist/Incentives/ERC20PeggedVariableCriteriaIncentive.d.ts +35 -0
  78. package/dist/Incentives/ERC20PeggedVariableCriteriaIncentive.d.ts.map +1 -1
  79. package/dist/Incentives/ERC20VariableCriteriaIncentive.cjs +1 -1
  80. package/dist/Incentives/ERC20VariableCriteriaIncentive.cjs.map +1 -1
  81. package/dist/Incentives/ERC20VariableCriteriaIncentive.d.ts +25 -0
  82. package/dist/Incentives/ERC20VariableCriteriaIncentive.d.ts.map +1 -1
  83. package/dist/Incentives/ERC20VariableCriteriaIncentive.js +24 -24
  84. package/dist/Incentives/ERC20VariableCriteriaIncentive.js.map +1 -1
  85. package/dist/Incentives/ERC20VariableIncentive.cjs +1 -1
  86. package/dist/Incentives/ERC20VariableIncentive.cjs.map +1 -1
  87. package/dist/Incentives/ERC20VariableIncentive.d.ts +35 -0
  88. package/dist/Incentives/ERC20VariableIncentive.d.ts.map +1 -1
  89. package/dist/Incentives/ERC20VariableIncentive.js +55 -38
  90. package/dist/Incentives/ERC20VariableIncentive.js.map +1 -1
  91. package/dist/Incentives/Incentive.cjs +1 -1
  92. package/dist/Incentives/Incentive.d.ts +25 -0
  93. package/dist/Incentives/Incentive.d.ts.map +1 -1
  94. package/dist/Incentives/Incentive.js +3 -3
  95. package/dist/Incentives/PointsIncentive.cjs +1 -1
  96. package/dist/Incentives/PointsIncentive.cjs.map +1 -1
  97. package/dist/Incentives/PointsIncentive.d.ts +8 -0
  98. package/dist/Incentives/PointsIncentive.d.ts.map +1 -1
  99. package/dist/Incentives/PointsIncentive.js +50 -28
  100. package/dist/Incentives/PointsIncentive.js.map +1 -1
  101. package/dist/SimpleDenyList-BAIrFBAW.cjs +2 -0
  102. package/dist/{SimpleDenyList-CsRXJPwm.cjs.map → SimpleDenyList-BAIrFBAW.cjs.map} +1 -1
  103. package/dist/SimpleDenyList-C734XLxt.js +133 -0
  104. package/dist/{SimpleDenyList-ByAr4X1r.js.map → SimpleDenyList-C734XLxt.js.map} +1 -1
  105. package/dist/Validators/LimitedSignerValidator.cjs +1 -1
  106. package/dist/Validators/LimitedSignerValidator.cjs.map +1 -1
  107. package/dist/Validators/LimitedSignerValidator.d.ts +1 -1
  108. package/dist/Validators/LimitedSignerValidator.d.ts.map +1 -1
  109. package/dist/Validators/LimitedSignerValidator.js +33 -33
  110. package/dist/Validators/LimitedSignerValidator.js.map +1 -1
  111. package/dist/Validators/SignerValidator.cjs +1 -1
  112. package/dist/Validators/SignerValidator.cjs.map +1 -1
  113. package/dist/Validators/SignerValidator.d.ts +1 -1
  114. package/dist/Validators/SignerValidator.d.ts.map +1 -1
  115. package/dist/Validators/SignerValidator.js +26 -26
  116. package/dist/Validators/SignerValidator.js.map +1 -1
  117. package/dist/Validators/Validator.cjs +1 -1
  118. package/dist/Validators/Validator.js +4 -4
  119. package/dist/componentInterfaces-5Ezh3Pvx.js +19 -0
  120. package/dist/componentInterfaces-5Ezh3Pvx.js.map +1 -0
  121. package/dist/componentInterfaces-Cm4Zfn1v.cjs +2 -0
  122. package/dist/componentInterfaces-Cm4Zfn1v.cjs.map +1 -0
  123. package/dist/{deployments-D0fs26TV.js → deployments-3RHH-eW7.js} +47 -47
  124. package/dist/{deployments-D0fs26TV.js.map → deployments-3RHH-eW7.js.map} +1 -1
  125. package/dist/deployments-CIXw_WKk.cjs +2 -0
  126. package/dist/deployments-CIXw_WKk.cjs.map +1 -0
  127. package/dist/deployments.json +24 -24
  128. package/dist/errors.cjs +1 -1
  129. package/dist/errors.cjs.map +1 -1
  130. package/dist/errors.js +1 -1
  131. package/dist/errors.js.map +1 -1
  132. package/dist/generated-BPiHi7W2.cjs +3 -0
  133. package/dist/generated-BPiHi7W2.cjs.map +1 -0
  134. package/dist/{generated-Cyvr_Tjx.js → generated-CElkFqkY.js} +1510 -608
  135. package/dist/generated-CElkFqkY.js.map +1 -0
  136. package/dist/index.cjs +1 -1
  137. package/dist/index.d.ts +1 -0
  138. package/dist/index.d.ts.map +1 -1
  139. package/dist/index.js +153 -150
  140. package/package.json +2 -2
  141. package/src/Actions/EventAction.ts +25 -6
  142. package/src/AllowLists/SimpleAllowList.ts +2 -2
  143. package/src/BoostCore.test.ts +124 -2
  144. package/src/BoostCore.ts +259 -0
  145. package/src/Budgets/Budget.ts +8 -2
  146. package/src/Budgets/ManagedBudgetWithFees.test.ts +0 -1
  147. package/src/Budgets/ManagedBudgetWithFeesV2.test.ts +327 -0
  148. package/src/Budgets/ManagedBudgetWithFeesV2.ts +713 -0
  149. package/src/Incentives/AllowListIncentive.ts +17 -0
  150. package/src/Incentives/CGDAIncentive.ts +31 -0
  151. package/src/Incentives/ERC20Incentive.ts +27 -0
  152. package/src/Incentives/ERC20PeggedIncentive.ts +18 -0
  153. package/src/Incentives/ERC20PeggedVariableCriteriaIncentive.ts +26 -0
  154. package/src/Incentives/ERC20VariableIncentive.ts +18 -0
  155. package/src/Incentives/PointsIncentive.ts +22 -0
  156. package/src/Validators/LimitedSignerValidator.ts +1 -1
  157. package/src/Validators/SignerValidator.ts +1 -1
  158. package/src/errors.ts +1 -1
  159. package/src/index.ts +1 -0
  160. package/dist/Budget-AoNx7uFd.cjs +0 -2
  161. package/dist/Budget-AoNx7uFd.cjs.map +0 -1
  162. package/dist/Budget-DYIV9iNK.js +0 -463
  163. package/dist/Budget-DYIV9iNK.js.map +0 -1
  164. package/dist/Incentive-BbkfwGOb.cjs +0 -2
  165. package/dist/Incentive-BbkfwGOb.cjs.map +0 -1
  166. package/dist/Incentive-qlnv5kQB.js +0 -991
  167. package/dist/Incentive-qlnv5kQB.js.map +0 -1
  168. package/dist/SimpleDenyList-ByAr4X1r.js +0 -133
  169. package/dist/SimpleDenyList-CsRXJPwm.cjs +0 -2
  170. package/dist/componentInterfaces-D7r9xJmt.cjs +0 -2
  171. package/dist/componentInterfaces-D7r9xJmt.cjs.map +0 -1
  172. package/dist/componentInterfaces-PR3ijhgZ.js +0 -18
  173. package/dist/componentInterfaces-PR3ijhgZ.js.map +0 -1
  174. package/dist/deployments-DoIOqxco.cjs +0 -2
  175. package/dist/deployments-DoIOqxco.cjs.map +0 -1
  176. package/dist/generated-Cyvr_Tjx.js.map +0 -1
  177. package/dist/generated-DtYPHhtX.cjs +0 -3
  178. package/dist/generated-DtYPHhtX.cjs.map +0 -1
@@ -765,8 +765,8 @@ describe("BoostCore", () => {
765
765
  await new Promise((resolve) => {
766
766
  setTimeout(resolve, 500);
767
767
  });
768
-
769
- expect(subscription).toHaveBeenCalledTimes(1);
768
+ // This should be called once for each event
769
+ expect(subscription).toHaveBeenCalledTimes(2);
770
770
  });
771
771
 
772
772
  test("can set a passthrough auth scheme", async () => {
@@ -953,3 +953,125 @@ describe("BoostCore", () => {
953
953
  expect(feesInfo.asset.toLowerCase()).toBe(erc20.assertValidAddress());
954
954
  });
955
955
  });
956
+
957
+ describe("Top-Up Incentives", () => {
958
+ let incentive: ReturnType<typeof fixtures.core.ERC20Incentive>;
959
+ let boostId: bigint;
960
+
961
+ beforeAll(async () => {
962
+ const { core } = fixtures;
963
+ const { budget, erc20 } = budgets;
964
+
965
+ incentive = core.ERC20Incentive({
966
+ asset: erc20.assertValidAddress(),
967
+ strategy: StrategyType.POOL,
968
+ reward: parseEther("1"),
969
+ limit: 5n,
970
+ manager: budget.assertValidAddress(),
971
+ });
972
+ await erc20.mint(defaultOptions.account.address, parseEther("110"));
973
+ await erc20.approve(budget.assertValidAddress(), parseEther("110"));
974
+ await budget.allocate({
975
+ amount: parseEther("110"),
976
+ asset: erc20.assertValidAddress(),
977
+ target: defaultOptions.account.address,
978
+ });
979
+
980
+
981
+ const createdBoost = await core.createBoost({
982
+ protocolFee: 0n,
983
+ maxParticipants: 5n,
984
+ budget,
985
+ action: core.EventAction(
986
+ makeMockEventActionPayload(
987
+ core.assertValidAddress(),
988
+ erc20.assertValidAddress(),
989
+ ),
990
+ ),
991
+ validator: core.SignerValidator({
992
+ signers: [defaultOptions.account.address],
993
+ validatorCaller: defaultOptions.account.address,
994
+ }),
995
+ allowList: core.SimpleAllowList({
996
+ owner: defaultOptions.account.address,
997
+ allowed: [defaultOptions.account.address],
998
+ }),
999
+ incentives: [incentive],
1000
+ });
1001
+ boostId = createdBoost.id;
1002
+ });
1003
+
1004
+ test("can top up from a budget (pre-fee)", async () => {
1005
+ const { core } = fixtures;
1006
+ const { budget, erc20 } = budgets;
1007
+
1008
+ console.log("budget", budget.assertValidAddress());
1009
+
1010
+ const netTopup = parseEther("5");
1011
+
1012
+ await core.topupIncentiveFromBudgetPreFee(boostId, 0n, netTopup, budget.assertValidAddress());
1013
+ console.log("topup done");
1014
+
1015
+ expect(await incentive.limit()).toBe(5n + 5n); // original limit 5 + topup 5
1016
+ });
1017
+
1018
+ test("can top up from a budget (post-fee)", async () => {
1019
+ const { core } = fixtures;
1020
+ const { budget } = budgets;
1021
+
1022
+ const total = parseEther("5.5");
1023
+ await core.topupIncentiveFromBudgetPostFee(boostId, 0n, total, budget.assertValidAddress());
1024
+
1025
+ expect(await incentive.limit()).toBe(10n + 5n);
1026
+ });
1027
+
1028
+ test("pre-fee and post-fee top-ups lead to the same net top-up", async () => {
1029
+ const { core } = fixtures;
1030
+ const { budget } = budgets;
1031
+
1032
+ const net = parseEther("2");
1033
+ const netPlusFee = parseEther("2.2");
1034
+
1035
+ await core.topupIncentiveFromBudgetPreFee(boostId, 0n, net, budget.assertValidAddress());
1036
+
1037
+ await core.topupIncentiveFromBudgetPostFee(boostId, 0n, netPlusFee, budget.assertValidAddress());
1038
+
1039
+ expect(await incentive.limit()).toBe(15n + 4n);
1040
+ });
1041
+
1042
+ test("can top up from sender (pre-fee)", async () => {
1043
+ const { core } = fixtures;
1044
+ const { erc20 } = budgets;
1045
+
1046
+ const netTopup = parseEther("10");
1047
+ const netPlusFee = parseEther("11");
1048
+ await erc20.mint(defaultOptions.account.address, netPlusFee);
1049
+ await erc20.approve(core.assertValidAddress(), netPlusFee);
1050
+
1051
+ await core.topupIncentiveFromSenderPreFee(boostId, 0n, netTopup);
1052
+
1053
+ expect(await incentive.limit()).toBe(19n + 10n);
1054
+ });
1055
+
1056
+ test("can top up from sender (post-fee)", async () => {
1057
+ const { core } = fixtures;
1058
+ const { erc20 } = budgets;
1059
+
1060
+ const totalWithFee = parseEther("5.5");
1061
+ await erc20.mint(defaultOptions.account.address, totalWithFee);
1062
+ await erc20.approve(core.assertValidAddress(), totalWithFee);
1063
+
1064
+ await core.topupIncentiveFromSenderPostFee(boostId, 0n, totalWithFee);
1065
+
1066
+ expect(await incentive.limit()).toBe(29n + 5n);
1067
+ });
1068
+
1069
+ test("throws if net top-up is zero", async () => {
1070
+ const { core } = fixtures;
1071
+ const { budget } = budgets;
1072
+
1073
+ await expect(async () => {
1074
+ await core.topupIncentiveFromBudgetPreFee(boostId, 0n, 0n, budget.assertValidAddress());
1075
+ }).rejects.toThrowError();
1076
+ });
1077
+ });
package/src/BoostCore.ts CHANGED
@@ -12,11 +12,15 @@ import {
12
12
  simulateBoostCoreCreateBoost,
13
13
  simulateBoostCoreSetCreateBoostAuth,
14
14
  simulateBoostCoreSetProtocolFeeReceiver,
15
+ simulateBoostCoreTopupIncentiveFromBudget,
16
+ simulateBoostCoreTopupIncentiveFromSender,
15
17
  writeBoostCoreClaimIncentive,
16
18
  writeBoostCoreClaimIncentiveFor,
17
19
  writeBoostCoreCreateBoost,
18
20
  writeBoostCoreSetCreateBoostAuth,
19
21
  writeBoostCoreSetProtocolFeeReceiver,
22
+ writeBoostCoreTopupIncentiveFromBudget,
23
+ writeBoostCoreTopupIncentiveFromSender,
20
24
  } from '@boostxyz/evm';
21
25
  import { bytecode } from '@boostxyz/evm/artifacts/contracts/BoostCore.sol/BoostCore.json';
22
26
  import {
@@ -24,6 +28,7 @@ import {
24
28
  getAccount,
25
29
  getChains,
26
30
  getTransactionReceipt,
31
+ readContract,
27
32
  waitForTransactionReceipt,
28
33
  } from '@wagmi/core';
29
34
  import { createWriteContract } from '@wagmi/core/codegen';
@@ -31,6 +36,8 @@ import {
31
36
  type Address,
32
37
  type ContractEventName,
33
38
  type Hex,
39
+ decodeAbiParameters,
40
+ encodeAbiParameters,
34
41
  encodePacked,
35
42
  keccak256,
36
43
  parseEventLogs,
@@ -67,6 +74,10 @@ import {
67
74
  ManagedBudgetWithFees,
68
75
  type ManagedBudgetWithFeesPayload,
69
76
  } from './Budgets/ManagedBudgetWithFees';
77
+ import {
78
+ ManagedBudgetWithFeesV2,
79
+ type ManagedBudgetWithFeesV2Payload,
80
+ } from './Budgets/ManagedBudgetWithFeesV2';
70
81
  import {
71
82
  Deployable,
72
83
  type DeployableOptions,
@@ -1394,6 +1405,34 @@ export class BoostCore extends Deployable<
1394
1405
  options,
1395
1406
  );
1396
1407
  }
1408
+ /**
1409
+ * Bound {@link ManagedBudgetWithFeesV2} constructor that reuses the same configuration as the Boost Core instance.
1410
+ * Prepends the BoostCore address to the authorized list because it's structurally critical to calculating payouts.
1411
+ *
1412
+ * @example
1413
+ * ```ts
1414
+ * const budget = core.ManagedBudgetWithFeesV2('0x') // is roughly equivalent to
1415
+ * const budget = new ManagedBudgetWithFeesV2({ config: core._config, account: core._account }, '0x')
1416
+ * ```
1417
+ * @param {DeployablePayloadOrAddress<ManagedBudgetWithFeesV2Payload>} options
1418
+ * @returns {ManagedBudgetWithFeesV2}
1419
+ */
1420
+ ManagedBudgetWithFeesV2(
1421
+ options: DeployablePayloadOrAddress<ManagedBudgetWithFeesV2Payload>,
1422
+ ) {
1423
+ if (
1424
+ typeof options !== 'string' &&
1425
+ !options.authorized.includes(this.assertValidAddress())
1426
+ ) {
1427
+ options.authorized = [this.assertValidAddress(), ...options.authorized];
1428
+ options.roles = [Roles.MANAGER, ...options.roles];
1429
+ }
1430
+
1431
+ return new ManagedBudgetWithFeesV2(
1432
+ { config: this._config, account: this._account },
1433
+ options,
1434
+ );
1435
+ }
1397
1436
  // /**
1398
1437
  // * Bound {@link VestingBudget} constructor that reuses the same configuration as the Boost Core instance.
1399
1438
  // *
@@ -1654,4 +1693,224 @@ export class BoostCore extends Deployable<
1654
1693
  ...this.optionallyAttachAccount(options.account),
1655
1694
  };
1656
1695
  }
1696
+ /**
1697
+ * Prepares and executes a top-up from a Budget, specifying the net top-up amount
1698
+ * that should land in the incentive (the protocol fee is added automatically).
1699
+ *
1700
+ * @public
1701
+ * @async
1702
+ * @param {bigint} boostId The ID of the Boost
1703
+ * @param {bigint} incentiveId The ID of the incentive within that Boost
1704
+ * @param {any} topupPayload A typed struct for the incentive’s top-up parameters
1705
+ * @param {Address} [budget] Optional override budget address (otherwise uses the Boost’s budget)
1706
+ * @param {?WriteParams} [params] Additional transaction overrides
1707
+ * @returns {Promise<{ hash: Hex; result: void }>} The transaction hash and simulation result
1708
+ */
1709
+ public async topupIncentiveFromBudgetPreFee(
1710
+ boostId: bigint,
1711
+ incentiveId: bigint,
1712
+ topupAmount: bigint,
1713
+ budget?: Address,
1714
+ params?: WriteParams,
1715
+ ) {
1716
+ const boost = await this.getBoost(boostId, params as ReadParams);
1717
+ if (incentiveId >= boost.incentives.length) {
1718
+ throw new Error(`Incentive ID ${incentiveId} out of range`);
1719
+ }
1720
+ const incentive = boost.incentives[Number(incentiveId)];
1721
+ if (!incentive) {
1722
+ throw new Error(`Incentive with ID ${incentiveId} not found`);
1723
+ }
1724
+
1725
+ const incentiveData = await incentive.getTopupPayload(topupAmount);
1726
+
1727
+ if (!(topupAmount > 0)) {
1728
+ throw new Error('Top-up amount must be greater than zero');
1729
+ }
1730
+
1731
+ return await this.topupIncentiveFromBudgetRaw(
1732
+ boostId,
1733
+ incentiveId,
1734
+ incentiveData,
1735
+ budget,
1736
+ params,
1737
+ );
1738
+ }
1739
+
1740
+ /**
1741
+ * Prepares and executes a top-up from a Budget, specifying the entire total tokens
1742
+ * (incentive + fee) you want to disburse. We'll back-calculate how many tokens land
1743
+ * in the incentive.
1744
+ *
1745
+ * @public
1746
+ * @async
1747
+ * @param {bigint} boostId The ID of the Boost
1748
+ * @param {bigint} incentiveId The ID of the incentive within that Boost
1749
+ * @param {any} topupPayload A typed struct for the incentive’s top-up parameters
1750
+ * @param {bigint} totalAmount The total tokens to disburse
1751
+ * @param {Address} [budget] Optional override budget address
1752
+ * @param {?WriteParams} [params] Additional transaction overrides
1753
+ * @returns {Promise<{ hash: Hex; result: void }>}
1754
+ */
1755
+ public async topupIncentiveFromBudgetPostFee(
1756
+ boostId: bigint,
1757
+ incentiveId: bigint,
1758
+ totalAmount: bigint,
1759
+ budget?: Address,
1760
+ params?: WriteParams,
1761
+ ) {
1762
+ const feeBps = await this.protocolFee(params as ReadParams);
1763
+ const topupAmount =
1764
+ (totalAmount * FEE_DENOMINATOR) / (FEE_DENOMINATOR + feeBps);
1765
+ return this.topupIncentiveFromBudgetPreFee(
1766
+ boostId,
1767
+ incentiveId,
1768
+ topupAmount,
1769
+ budget,
1770
+ params,
1771
+ );
1772
+ }
1773
+
1774
+ /**
1775
+ * Prepares and executes a top-up from the caller (msg.sender), specifying the net top-up
1776
+ * to land in the incentive. We'll add the protocol fee on top automatically.
1777
+ *
1778
+ * @public
1779
+ * @async
1780
+ * @param {bigint} boostId The ID of the Boost
1781
+ * @param {bigint} incentiveId The ID of the incentive within that Boost
1782
+ * @param {any} topupPayload A typed struct for the incentive’s top-up parameters
1783
+ * @param {?WriteParams} [params]
1784
+ * @returns {Promise<{ hash: Hex; result: void }>}
1785
+ */
1786
+ public async topupIncentiveFromSenderPreFee(
1787
+ boostId: bigint,
1788
+ incentiveId: bigint,
1789
+ topupAmount: bigint,
1790
+ params?: WriteParams,
1791
+ ) {
1792
+ const boost = await this.getBoost(boostId, params as ReadParams);
1793
+ if (incentiveId >= boost.incentives.length) {
1794
+ throw new Error(`Incentive ID ${incentiveId} out of range`);
1795
+ }
1796
+ const incentive = boost.incentives[Number(incentiveId)];
1797
+ if (!incentive) {
1798
+ throw new Error(`Incentive with ID ${incentiveId} not found`);
1799
+ }
1800
+
1801
+ if (!(topupAmount > 0)) {
1802
+ throw new Error('Top-up amount must be greater than zero');
1803
+ }
1804
+
1805
+ const incentiveData = await incentive.getTopupPayload(topupAmount);
1806
+
1807
+ return await this.topupIncentiveFromSenderRaw(
1808
+ boostId,
1809
+ incentiveId,
1810
+ incentiveData,
1811
+ params,
1812
+ );
1813
+ }
1814
+
1815
+ /**
1816
+ * Prepares and executes a top-up from the caller (msg.sender), specifying the total
1817
+ * tokens you’re willing to provide (including fee). We'll back-calculate the net
1818
+ * top-up for the incentive.
1819
+ *
1820
+ * @public
1821
+ * @async
1822
+ * @param {bigint} boostId The ID of the Boost
1823
+ * @param {bigint} incentiveId The ID of the incentive within that Boost
1824
+ * @param {any} topupPayload A typed struct for the incentive’s top-up parameters
1825
+ * @param {bigint} totalAmount The entire tokens (top-up + fee)
1826
+ * @param {?WriteParams} [params]
1827
+ * @returns {Promise<{ hash: Hex; result: void }>}
1828
+ */
1829
+ public async topupIncentiveFromSenderPostFee(
1830
+ boostId: bigint,
1831
+ incentiveId: bigint,
1832
+ totalAmount: bigint,
1833
+ params?: WriteParams,
1834
+ ) {
1835
+ const feeBps = await this.protocolFee(params as ReadParams);
1836
+ const topupAmount =
1837
+ (totalAmount * FEE_DENOMINATOR) / (FEE_DENOMINATOR + feeBps);
1838
+
1839
+ return this.topupIncentiveFromSenderPreFee(
1840
+ boostId,
1841
+ incentiveId,
1842
+ topupAmount,
1843
+ params,
1844
+ );
1845
+ }
1846
+
1847
+ /**
1848
+ * A lower-level function that actually calls `topupIncentiveFromSender` on-chain,
1849
+ * passing the final total. The contract modifies its internal logic to split net top-up vs. fee.
1850
+ *
1851
+ * @private
1852
+ * @param {bigint} boostId
1853
+ * @param {bigint} incentiveId
1854
+ * @param {Hex} preflightData The raw ABudget.Transfer data from preflight
1855
+ * @param {?WriteParams} [params]
1856
+ * @returns {Promise<{ hash: Hex; result: void }>}
1857
+ */
1858
+ private async topupIncentiveFromSenderRaw(
1859
+ boostId: bigint,
1860
+ incentiveId: bigint,
1861
+ preflightData: Hex,
1862
+ params?: WriteParams,
1863
+ ) {
1864
+ const { request, result } = await simulateBoostCoreTopupIncentiveFromSender(
1865
+ this._config,
1866
+ {
1867
+ ...this.optionallyAttachAccount(),
1868
+ ...(params as object),
1869
+ address: this.assertValidAddress(),
1870
+ args: [boostId, incentiveId, preflightData],
1871
+ },
1872
+ );
1873
+ const hash = await writeBoostCoreTopupIncentiveFromSender(
1874
+ this._config,
1875
+ request,
1876
+ );
1877
+ return { hash, result };
1878
+ }
1879
+
1880
+ /**
1881
+ * A lower-level function that actually calls `topupIncentiveFromBudget` on-chain,
1882
+ * passing the preflight data plus the final total. The contract itself modifies
1883
+ * the amount to (topup + fee).
1884
+ *
1885
+ * @private
1886
+ * @param {bigint} boostId
1887
+ * @param {bigint} incentiveId
1888
+ * @param {Hex} preflightData The raw ABudget.Transfer (encoded) from preflight
1889
+ * @param {Address} [budget] Optional override for the budget
1890
+ * @param {?WriteParams} [params]
1891
+ * @returns {Promise<{ hash: Hex; result: void }>}
1892
+ */
1893
+ private async topupIncentiveFromBudgetRaw(
1894
+ boostId: bigint,
1895
+ incentiveId: bigint,
1896
+ preflightData: Hex,
1897
+ budget?: Address,
1898
+ params?: WriteParams,
1899
+ ) {
1900
+ // e.g. run "simulate + write" pattern
1901
+ const { request, result } = await simulateBoostCoreTopupIncentiveFromBudget(
1902
+ this._config,
1903
+ {
1904
+ ...this.optionallyAttachAccount(),
1905
+ ...(params as object),
1906
+ address: this.assertValidAddress(),
1907
+ args: [boostId, incentiveId, preflightData, budget ?? zeroAddress],
1908
+ },
1909
+ );
1910
+ const hash = await writeBoostCoreTopupIncentiveFromBudget(
1911
+ this._config,
1912
+ request,
1913
+ );
1914
+ return { hash, result };
1915
+ }
1657
1916
  }
@@ -2,6 +2,7 @@ import { aBudgetAbi } from '@boostxyz/evm';
2
2
  import {
3
3
  AManagedBudget,
4
4
  AManagedBudgetWithFees,
5
+ AManagedBudgetWithFeesV2,
5
6
  } from '@boostxyz/evm/deploys/componentInterfaces.json';
6
7
  import { readContract } from '@wagmi/core';
7
8
  import type { Address, Hex } from 'viem';
@@ -10,6 +11,7 @@ import { InvalidComponentInterfaceError } from '../errors';
10
11
  import type { ReadParams } from '../utils';
11
12
  import { ManagedBudget } from './ManagedBudget';
12
13
  import { ManagedBudgetWithFees } from './ManagedBudgetWithFees';
14
+ import { ManagedBudgetWithFeesV2 } from './ManagedBudgetWithFeesV2';
13
15
 
14
16
  export {
15
17
  // VestingBudget,
@@ -22,7 +24,10 @@ export {
22
24
  * @export
23
25
  * @typedef {Budget}
24
26
  */
25
- export type Budget = ManagedBudget | ManagedBudgetWithFees; // | VestingBudget
27
+ export type Budget =
28
+ | ManagedBudget
29
+ | ManagedBudgetWithFees
30
+ | ManagedBudgetWithFeesV2; // | VestingBudget
26
31
 
27
32
  /**
28
33
  * A map of Budget component interfaces to their constructors.
@@ -34,6 +39,7 @@ export const BudgetByComponentInterface = {
34
39
  // ['0x2929d19c']: SimpleBudget,
35
40
  [AManagedBudget as Hex]: ManagedBudget,
36
41
  [AManagedBudgetWithFees as Hex]: ManagedBudgetWithFees,
42
+ [AManagedBudgetWithFeesV2 as Hex]: ManagedBudgetWithFeesV2,
37
43
  };
38
44
 
39
45
  /**
@@ -43,7 +49,7 @@ export const BudgetByComponentInterface = {
43
49
  * @async
44
50
  * @param {DeployableOptions} options
45
51
  * @param {Address} address
46
- * @returns {Promise<ManagedBudget | ManagedBudgetWithFees>}
52
+ * @returns {Promise<ManagedBudget | ManagedBudgetWithFees | ManagedBudgetWithFeesV2>}
47
53
  * @throws {@link InvalidComponentInterfaceError}
48
54
  */
49
55
  export async function budgetFromAddress(
@@ -12,7 +12,6 @@ import {
12
12
  freshManagedBudgetWithFees,
13
13
  fundErc20,
14
14
  fundErc1155,
15
- fundManagedBudget,
16
15
  freshBoost,
17
16
  fundManagedBudgetWithFees,
18
17
  } from "@boostxyz/test/helpers";