@boostxyz/sdk 0.0.0-alpha.2 → 0.0.0-alpha.21

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 (271) hide show
  1. package/dist/Actions/Action.cjs +2 -1
  2. package/dist/Actions/Action.cjs.map +1 -0
  3. package/dist/Actions/Action.d.ts +1 -1
  4. package/dist/Actions/Action.d.ts.map +1 -1
  5. package/dist/Actions/Action.js +14 -12
  6. package/dist/Actions/Action.js.map +1 -0
  7. package/dist/Actions/ContractAction.d.ts +57 -14
  8. package/dist/Actions/ContractAction.d.ts.map +1 -1
  9. package/dist/Actions/ERC721MintAction.d.ts +50 -23
  10. package/dist/Actions/ERC721MintAction.d.ts.map +1 -1
  11. package/dist/Actions/EventAction.cjs +2 -1
  12. package/dist/Actions/EventAction.cjs.map +1 -0
  13. package/dist/Actions/EventAction.d.ts +405 -36
  14. package/dist/Actions/EventAction.d.ts.map +1 -1
  15. package/dist/Actions/EventAction.js +15 -209
  16. package/dist/Actions/EventAction.js.map +1 -0
  17. package/dist/AllowLists/AllowList.cjs +2 -1
  18. package/dist/AllowLists/AllowList.cjs.map +1 -0
  19. package/dist/AllowLists/AllowList.d.ts +6 -5
  20. package/dist/AllowLists/AllowList.d.ts.map +1 -1
  21. package/dist/AllowLists/AllowList.js +46 -22
  22. package/dist/AllowLists/AllowList.js.map +1 -0
  23. package/dist/AllowLists/OpenAllowList.d.ts +423 -0
  24. package/dist/AllowLists/OpenAllowList.d.ts.map +1 -0
  25. package/dist/AllowLists/SimpleAllowList.cjs +2 -1
  26. package/dist/AllowLists/SimpleAllowList.cjs.map +1 -0
  27. package/dist/AllowLists/SimpleAllowList.d.ts +124 -40
  28. package/dist/AllowLists/SimpleAllowList.d.ts.map +1 -1
  29. package/dist/AllowLists/SimpleAllowList.js +76 -76
  30. package/dist/AllowLists/SimpleAllowList.js.map +1 -0
  31. package/dist/AllowLists/SimpleDenyList.cjs +2 -1
  32. package/dist/AllowLists/SimpleDenyList.cjs.map +1 -0
  33. package/dist/AllowLists/SimpleDenyList.d.ts +234 -13
  34. package/dist/AllowLists/SimpleDenyList.d.ts.map +1 -1
  35. package/dist/AllowLists/SimpleDenyList.js +12 -200
  36. package/dist/AllowLists/SimpleDenyList.js.map +1 -0
  37. package/dist/Auth/Auth.cjs +1 -0
  38. package/dist/Auth/Auth.cjs.map +1 -0
  39. package/dist/Auth/Auth.js +1 -0
  40. package/dist/Auth/Auth.js.map +1 -0
  41. package/dist/Auth/PassthroughAuth.cjs +2 -1
  42. package/dist/Auth/PassthroughAuth.cjs.map +1 -0
  43. package/dist/Auth/PassthroughAuth.js +5 -4
  44. package/dist/Auth/PassthroughAuth.js.map +1 -0
  45. package/dist/Boost.cjs +2 -1
  46. package/dist/Boost.cjs.map +1 -0
  47. package/dist/Boost.d.ts +105 -14
  48. package/dist/Boost.d.ts.map +1 -1
  49. package/dist/Boost.js +138 -5
  50. package/dist/Boost.js.map +1 -0
  51. package/dist/BoostCore-DolmDuXW.cjs +3 -0
  52. package/dist/BoostCore-DolmDuXW.cjs.map +1 -0
  53. package/dist/BoostCore-Z97KVu4V.js +1448 -0
  54. package/dist/BoostCore-Z97KVu4V.js.map +1 -0
  55. package/dist/BoostCore.cjs +2 -2
  56. package/dist/BoostCore.cjs.map +1 -0
  57. package/dist/BoostCore.d.ts +788 -79
  58. package/dist/BoostCore.d.ts.map +1 -1
  59. package/dist/BoostCore.js +30 -1103
  60. package/dist/BoostCore.js.map +1 -0
  61. package/dist/BoostRegistry.cjs +2 -1
  62. package/dist/BoostRegistry.cjs.map +1 -0
  63. package/dist/BoostRegistry.d.ts +95 -26
  64. package/dist/BoostRegistry.d.ts.map +1 -1
  65. package/dist/BoostRegistry.js +183 -89
  66. package/dist/BoostRegistry.js.map +1 -0
  67. package/dist/Budgets/Budget.cjs +2 -1
  68. package/dist/Budgets/Budget.cjs.map +1 -0
  69. package/dist/Budgets/Budget.d.ts +1 -1
  70. package/dist/Budgets/Budget.d.ts.map +1 -1
  71. package/dist/Budgets/Budget.js +15 -13
  72. package/dist/Budgets/Budget.js.map +1 -0
  73. package/dist/Budgets/ManagedBudget.cjs +2 -1
  74. package/dist/Budgets/ManagedBudget.cjs.map +1 -0
  75. package/dist/Budgets/ManagedBudget.d.ts +112 -192
  76. package/dist/Budgets/ManagedBudget.d.ts.map +1 -1
  77. package/dist/Budgets/ManagedBudget.js +91 -291
  78. package/dist/Budgets/ManagedBudget.js.map +1 -0
  79. package/dist/Budgets/VestingBudget.d.ts +277 -91
  80. package/dist/Budgets/VestingBudget.d.ts.map +1 -1
  81. package/dist/Deployable/Contract.cjs +2 -1
  82. package/dist/Deployable/Contract.cjs.map +1 -0
  83. package/dist/Deployable/Contract.d.ts +4 -5
  84. package/dist/Deployable/Contract.d.ts.map +1 -1
  85. package/dist/Deployable/Contract.js +7 -8
  86. package/dist/Deployable/Contract.js.map +1 -0
  87. package/dist/Deployable/Deployable.cjs +1 -0
  88. package/dist/Deployable/Deployable.cjs.map +1 -0
  89. package/dist/Deployable/Deployable.d.ts +9 -3
  90. package/dist/Deployable/Deployable.d.ts.map +1 -1
  91. package/dist/Deployable/Deployable.js +10 -5
  92. package/dist/Deployable/Deployable.js.map +1 -0
  93. package/dist/Deployable/DeployableTarget.cjs +2 -1
  94. package/dist/Deployable/DeployableTarget.cjs.map +1 -0
  95. package/dist/Deployable/DeployableTarget.d.ts +16 -15
  96. package/dist/Deployable/DeployableTarget.d.ts.map +1 -1
  97. package/dist/Deployable/DeployableTarget.js +49 -42
  98. package/dist/Deployable/DeployableTarget.js.map +1 -0
  99. package/dist/Deployable/DeployableTargetWithRBAC.cjs +2 -0
  100. package/dist/Deployable/DeployableTargetWithRBAC.cjs.map +1 -0
  101. package/dist/Deployable/DeployableTargetWithRBAC.d.ts +179 -0
  102. package/dist/Deployable/DeployableTargetWithRBAC.d.ts.map +1 -0
  103. package/dist/Deployable/DeployableTargetWithRBAC.js +222 -0
  104. package/dist/Deployable/DeployableTargetWithRBAC.js.map +1 -0
  105. package/dist/EventAction-CBKzuNoN.cjs +2 -0
  106. package/dist/EventAction-CBKzuNoN.cjs.map +1 -0
  107. package/dist/EventAction-DWuuc_Qy.js +1528 -0
  108. package/dist/EventAction-DWuuc_Qy.js.map +1 -0
  109. package/dist/Incentive-BxzEtN26.js +298 -0
  110. package/dist/Incentive-BxzEtN26.js.map +1 -0
  111. package/dist/Incentive-CrF3-ayL.cjs +2 -0
  112. package/dist/Incentive-CrF3-ayL.cjs.map +1 -0
  113. package/dist/Incentives/AllowListIncentive.cjs +2 -1
  114. package/dist/Incentives/AllowListIncentive.cjs.map +1 -0
  115. package/dist/Incentives/AllowListIncentive.d.ts +65 -21
  116. package/dist/Incentives/AllowListIncentive.d.ts.map +1 -1
  117. package/dist/Incentives/AllowListIncentive.js +52 -36
  118. package/dist/Incentives/AllowListIncentive.js.map +1 -0
  119. package/dist/Incentives/CGDAIncentive.cjs +2 -1
  120. package/dist/Incentives/CGDAIncentive.cjs.map +1 -0
  121. package/dist/Incentives/CGDAIncentive.d.ts +315 -26
  122. package/dist/Incentives/CGDAIncentive.d.ts.map +1 -1
  123. package/dist/Incentives/CGDAIncentive.js +64 -39
  124. package/dist/Incentives/CGDAIncentive.js.map +1 -0
  125. package/dist/Incentives/ERC1155Incentive.d.ts +291 -43
  126. package/dist/Incentives/ERC1155Incentive.d.ts.map +1 -1
  127. package/dist/Incentives/ERC20Incentive.cjs +2 -1
  128. package/dist/Incentives/ERC20Incentive.cjs.map +1 -0
  129. package/dist/Incentives/ERC20Incentive.d.ts +270 -33
  130. package/dist/Incentives/ERC20Incentive.d.ts.map +1 -1
  131. package/dist/Incentives/ERC20Incentive.js +69 -46
  132. package/dist/Incentives/ERC20Incentive.js.map +1 -0
  133. package/dist/{Budgets/SimpleBudget.d.ts → Incentives/ERC20VariableCriteriaIncentive.d.ts} +338 -421
  134. package/dist/Incentives/ERC20VariableCriteriaIncentive.d.ts.map +1 -0
  135. package/dist/Incentives/ERC20VariableIncentive.d.ts +262 -32
  136. package/dist/Incentives/ERC20VariableIncentive.d.ts.map +1 -1
  137. package/dist/Incentives/Incentive.cjs +2 -1
  138. package/dist/Incentives/Incentive.cjs.map +1 -0
  139. package/dist/Incentives/Incentive.d.ts +5 -8
  140. package/dist/Incentives/Incentive.d.ts.map +1 -1
  141. package/dist/Incentives/Incentive.js +17 -278
  142. package/dist/Incentives/Incentive.js.map +1 -0
  143. package/dist/Incentives/PointsIncentive.cjs +2 -1
  144. package/dist/Incentives/PointsIncentive.cjs.map +1 -0
  145. package/dist/Incentives/PointsIncentive.d.ts +81 -23
  146. package/dist/Incentives/PointsIncentive.d.ts.map +1 -1
  147. package/dist/Incentives/PointsIncentive.js +57 -36
  148. package/dist/Incentives/PointsIncentive.js.map +1 -0
  149. package/dist/SimpleDenyList-BUR17Tt1.cjs +2 -0
  150. package/dist/SimpleDenyList-BUR17Tt1.cjs.map +1 -0
  151. package/dist/SimpleDenyList-CGaWjuld.js +132 -0
  152. package/dist/SimpleDenyList-CGaWjuld.js.map +1 -0
  153. package/dist/Validators/SignerValidator.cjs +2 -1
  154. package/dist/Validators/SignerValidator.cjs.map +1 -0
  155. package/dist/Validators/SignerValidator.d.ts +310 -17
  156. package/dist/Validators/SignerValidator.d.ts.map +1 -1
  157. package/dist/Validators/SignerValidator.js +165 -36
  158. package/dist/Validators/SignerValidator.js.map +1 -0
  159. package/dist/Validators/Validator.cjs +2 -1
  160. package/dist/Validators/Validator.cjs.map +1 -0
  161. package/dist/Validators/Validator.d.ts +2 -2
  162. package/dist/Validators/Validator.d.ts.map +1 -1
  163. package/dist/Validators/Validator.js +10 -8
  164. package/dist/Validators/Validator.js.map +1 -0
  165. package/dist/claiming.cjs +2 -0
  166. package/dist/claiming.cjs.map +1 -0
  167. package/dist/claiming.d.ts +43 -0
  168. package/dist/claiming.d.ts.map +1 -0
  169. package/dist/claiming.js +17 -0
  170. package/dist/claiming.js.map +1 -0
  171. package/dist/componentInterfaces-BBCFkrZv.js +14 -0
  172. package/dist/componentInterfaces-BBCFkrZv.js.map +1 -0
  173. package/dist/componentInterfaces-DRI_dQ-P.cjs +2 -0
  174. package/dist/componentInterfaces-DRI_dQ-P.cjs.map +1 -0
  175. package/dist/deployments-DVXioW2i.cjs +2 -0
  176. package/dist/deployments-DVXioW2i.cjs.map +1 -0
  177. package/dist/deployments-oykLv3_Z.js +43 -0
  178. package/dist/deployments-oykLv3_Z.js.map +1 -0
  179. package/dist/deployments.json +44 -0
  180. package/dist/errors.cjs +2 -1
  181. package/dist/errors.cjs.map +1 -0
  182. package/dist/errors.d.ts +421 -1
  183. package/dist/errors.d.ts.map +1 -1
  184. package/dist/errors.js +297 -39
  185. package/dist/errors.js.map +1 -0
  186. package/dist/{generated-x_abr3Yv.js → generated-CKt2yCQd.js} +3143 -3002
  187. package/dist/generated-CKt2yCQd.js.map +1 -0
  188. package/dist/generated-CyTNlOwM.cjs +3 -0
  189. package/dist/generated-CyTNlOwM.cjs.map +1 -0
  190. package/dist/index.cjs +2 -1
  191. package/dist/index.cjs.map +1 -0
  192. package/dist/index.d.ts +10 -9
  193. package/dist/index.d.ts.map +1 -1
  194. package/dist/index.js +144 -1353
  195. package/dist/index.js.map +1 -0
  196. package/dist/transfers.cjs +2 -0
  197. package/dist/transfers.cjs.map +1 -0
  198. package/dist/transfers.d.ts +198 -0
  199. package/dist/transfers.d.ts.map +1 -0
  200. package/dist/transfers.js +84 -0
  201. package/dist/transfers.js.map +1 -0
  202. package/dist/utils.cjs +2 -1
  203. package/dist/utils.cjs.map +1 -0
  204. package/dist/utils.d.ts +26 -1350
  205. package/dist/utils.d.ts.map +1 -1
  206. package/dist/utils.js +38 -636
  207. package/dist/utils.js.map +1 -0
  208. package/package.json +37 -11
  209. package/src/Actions/Action.test.ts +79 -0
  210. package/src/Actions/Action.ts +61 -0
  211. package/src/Actions/ContractAction.test.ts +197 -0
  212. package/src/Actions/ContractAction.ts +300 -0
  213. package/src/Actions/ERC721MintAction.test.ts +112 -0
  214. package/src/Actions/ERC721MintAction.ts +291 -0
  215. package/src/Actions/EventAction.test.ts +787 -0
  216. package/src/Actions/EventAction.ts +1218 -0
  217. package/src/AllowLists/AllowList.test.ts +64 -0
  218. package/src/AllowLists/AllowList.ts +62 -0
  219. package/src/AllowLists/OpenAllowList.test.ts +40 -0
  220. package/src/AllowLists/OpenAllowList.ts +45 -0
  221. package/src/AllowLists/SimpleAllowList.test.ts +52 -0
  222. package/src/AllowLists/SimpleAllowList.ts +262 -0
  223. package/src/AllowLists/SimpleDenyList.test.ts +52 -0
  224. package/src/AllowLists/SimpleDenyList.ts +250 -0
  225. package/src/Auth/Auth.ts +11 -0
  226. package/src/Auth/PassthroughAuth.test.ts +12 -0
  227. package/src/Auth/PassthroughAuth.ts +80 -0
  228. package/src/Boost.ts +287 -0
  229. package/src/BoostCore.test.ts +894 -0
  230. package/src/BoostCore.ts +1438 -0
  231. package/src/BoostRegistry.test.ts +53 -0
  232. package/src/BoostRegistry.ts +588 -0
  233. package/src/Budgets/Budget.test.ts +27 -0
  234. package/src/Budgets/Budget.ts +60 -0
  235. package/src/Budgets/ManagedBudget.test.ts +217 -0
  236. package/src/Budgets/ManagedBudget.ts +534 -0
  237. package/src/Budgets/VestingBudget.test.ts +123 -0
  238. package/src/Budgets/VestingBudget.ts +530 -0
  239. package/src/Deployable/Contract.ts +228 -0
  240. package/src/Deployable/Deployable.ts +250 -0
  241. package/src/Deployable/DeployableTarget.ts +234 -0
  242. package/src/Deployable/DeployableTargetWithRBAC.ts +323 -0
  243. package/src/Incentives/AllowListIncentive.test.ts +143 -0
  244. package/src/Incentives/AllowListIncentive.ts +336 -0
  245. package/src/Incentives/CGDAIncentive.test.ts +135 -0
  246. package/src/Incentives/CGDAIncentive.ts +476 -0
  247. package/src/Incentives/ERC1155Incentive.test.ts +87 -0
  248. package/src/Incentives/ERC1155Incentive.ts +465 -0
  249. package/src/Incentives/ERC20Incentive.test.ts +133 -0
  250. package/src/Incentives/ERC20Incentive.ts +490 -0
  251. package/src/Incentives/ERC20VariableCriteriaIncentive.test.ts +184 -0
  252. package/src/Incentives/ERC20VariableCriteriaIncentive.ts +309 -0
  253. package/src/Incentives/ERC20VariableIncentive.test.ts +139 -0
  254. package/src/Incentives/ERC20VariableIncentive.ts +428 -0
  255. package/src/Incentives/Incentive.test.ts +95 -0
  256. package/src/Incentives/Incentive.ts +86 -0
  257. package/src/Incentives/PointsIncentive.test.ts +138 -0
  258. package/src/Incentives/PointsIncentive.ts +367 -0
  259. package/src/Validators/SignerValidator.test.ts +159 -0
  260. package/src/Validators/SignerValidator.ts +683 -0
  261. package/src/Validators/Validator.test.ts +21 -0
  262. package/src/Validators/Validator.ts +55 -0
  263. package/src/claiming.ts +56 -0
  264. package/src/errors.ts +866 -0
  265. package/src/index.test.ts +122 -0
  266. package/src/index.ts +58 -0
  267. package/src/transfers.ts +284 -0
  268. package/src/utils.test.ts +44 -0
  269. package/src/utils.ts +247 -0
  270. package/dist/Budgets/SimpleBudget.d.ts.map +0 -1
  271. package/dist/generated-BaaleHW-.cjs +0 -2
@@ -0,0 +1,138 @@
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
+ import type { MockPoints } from "@boostxyz/test/MockPoints";
6
+ import { accounts } from "@boostxyz/test/accounts";
7
+ import {
8
+ type Fixtures,
9
+ defaultOptions,
10
+ deployFixtures,
11
+ freshBoost,
12
+ freshPoints,
13
+ } from "@boostxyz/test/helpers";
14
+ import { bytes4 } from "../utils";
15
+ import { PointsIncentive } from "./PointsIncentive";
16
+
17
+ let fixtures: Fixtures, points: MockPoints;
18
+
19
+ describe("PointsIncentive", () => {
20
+ beforeAll(async () => {
21
+ fixtures = await loadFixture(deployFixtures(defaultOptions));
22
+ });
23
+
24
+ beforeEach(async () => {
25
+ points = await loadFixture(freshPoints);
26
+ });
27
+
28
+ test("can successfully be deployed", async () => {
29
+ const action = new PointsIncentive(defaultOptions, {
30
+ venue: zeroAddress,
31
+ selector: "0xdeadb33f",
32
+ reward: 1n,
33
+ limit: 1n,
34
+ });
35
+ await action.deploy();
36
+ expect(isAddress(action.assertValidAddress())).toBe(true);
37
+ });
38
+
39
+ test("can claim", async () => {
40
+ // biome-ignore lint/style/noNonNullAssertion: we know this is defined
41
+ const referrer = accounts.at(1)!.account!;
42
+ // biome-ignore lint/style/noNonNullAssertion: we know this is defined
43
+ const trustedSigner = accounts.at(0)!;
44
+ const pointsIncentive = fixtures.core.PointsIncentive({
45
+ venue: points.assertValidAddress(),
46
+ selector: bytes4("issue(address,uint256)"),
47
+ reward: 1n,
48
+ limit: 10n,
49
+ });
50
+ const boost = await freshBoost(fixtures, {
51
+ incentives: [pointsIncentive],
52
+ });
53
+
54
+ const claimant = trustedSigner.account;
55
+ const incentiveData = pad("0xdef456232173821931823712381232131391321934");
56
+ const incentiveQuantity = 1;
57
+ const claimDataPayload = await boost.validator.encodeClaimData({
58
+ signer: trustedSigner,
59
+ incentiveData,
60
+ chainId: defaultOptions.config.chains[0].id,
61
+ incentiveQuantity,
62
+ claimant,
63
+ boostId: boost.id,
64
+ });
65
+
66
+ await writePointsGrantRoles(defaultOptions.config, {
67
+ address: points.assertValidAddress(),
68
+ args: [pointsIncentive.assertValidAddress(), 2n],
69
+ account: defaultOptions.account,
70
+ });
71
+ await fixtures.core.claimIncentive(
72
+ boost.id,
73
+ 0n,
74
+ referrer,
75
+ claimDataPayload
76
+ );
77
+ expect(
78
+ await readPointsBalanceOf(defaultOptions.config, {
79
+ address: points.assertValidAddress(),
80
+ args: [defaultOptions.account.address],
81
+ }),
82
+ ).toBe(1n);
83
+ });
84
+
85
+ test("cannot claim twice", async () => {
86
+ const reward = 1n;
87
+ // biome-ignore lint/style/noNonNullAssertion: we know this is defined
88
+ const referrer = accounts.at(1)!.account!;
89
+ // biome-ignore lint/style/noNonNullAssertion: we know this is defined
90
+ const trustedSigner = accounts.at(0)!;
91
+
92
+ const pointsIncentive = fixtures.core.PointsIncentive({
93
+ venue: points.assertValidAddress(),
94
+ selector: bytes4("issue(address,uint256)"),
95
+ reward,
96
+ limit: 10n,
97
+ });
98
+ const boost = await freshBoost(fixtures, {
99
+ incentives: [pointsIncentive],
100
+ });
101
+
102
+ const claimant = trustedSigner.account;
103
+ const incentiveData = pad("0xdef456232173821931823712381232131391321934");
104
+ const incentiveQuantity = 1;
105
+ const claimDataPayload = await boost.validator.encodeClaimData({
106
+ signer: trustedSigner,
107
+ incentiveData,
108
+ chainId: defaultOptions.config.chains[0].id,
109
+ incentiveQuantity,
110
+ claimant,
111
+ boostId: boost.id,
112
+ });
113
+
114
+ await writePointsGrantRoles(defaultOptions.config, {
115
+ address: points.assertValidAddress(),
116
+ args: [pointsIncentive.assertValidAddress(), 2n],
117
+ account: defaultOptions.account,
118
+ });
119
+ await fixtures.core.claimIncentive(
120
+ boost.id,
121
+ 0n,
122
+ referrer,
123
+ claimDataPayload,
124
+ { value: parseEther("0.000075") },
125
+ );
126
+ try {
127
+ await fixtures.core.claimIncentive(
128
+ boost.id,
129
+ 0n,
130
+ referrer,
131
+ claimDataPayload,
132
+ { value: parseEther("0.000075") },
133
+ );
134
+ } catch (e) {
135
+ expect(e).toBeInstanceOf(Error);
136
+ }
137
+ });
138
+ });
@@ -0,0 +1,367 @@
1
+ import {
2
+ pointsIncentiveAbi,
3
+ readPointsIncentiveClaimed,
4
+ readPointsIncentiveClaims,
5
+ readPointsIncentiveCurrentReward,
6
+ readPointsIncentiveIsClaimable,
7
+ readPointsIncentiveLimit,
8
+ readPointsIncentiveReward,
9
+ readPointsIncentiveSelector,
10
+ readPointsIncentiveVenue,
11
+ simulatePointsIncentiveClaim,
12
+ writePointsIncentiveClaim,
13
+ } from '@boostxyz/evm';
14
+ import { bytecode } from '@boostxyz/evm/artifacts/contracts/incentives/PointsIncentive.sol/PointsIncentive.json';
15
+ import {
16
+ type Address,
17
+ type ContractEventName,
18
+ type Hex,
19
+ encodeAbiParameters,
20
+ } from 'viem';
21
+ import { PointsIncentive as PointsIncentiveBases } from '../../dist/deployments.json';
22
+ import type {
23
+ DeployableOptions,
24
+ GenericDeployableParams,
25
+ } from '../Deployable/Deployable';
26
+ import { DeployableTarget } from '../Deployable/DeployableTarget';
27
+ import { type ClaimPayload, prepareClaimPayload } from '../claiming';
28
+ import {
29
+ type GenericLog,
30
+ type ReadParams,
31
+ RegistryType,
32
+ type WriteParams,
33
+ } from '../utils';
34
+
35
+ export { pointsIncentiveAbi };
36
+
37
+ /**
38
+ * The object representation of a `PointsIncentive.InitPayload`
39
+ *
40
+ * @export
41
+ * @interface PointsIncentivePayload
42
+ * @typedef {PointsIncentivePayload}
43
+ */
44
+ export interface PointsIncentivePayload {
45
+ /**
46
+ * The address of the points contract
47
+ *
48
+ * @type {Address}
49
+ */
50
+ venue: Address;
51
+ /**
52
+ * The selector for the issuance function on the points contract
53
+ *
54
+ * @type {Hex}
55
+ */
56
+ selector: Hex;
57
+ /**
58
+ * The reward amount issued for each claim
59
+ *
60
+ * @type {bigint}
61
+ */
62
+ reward: bigint;
63
+ /**
64
+ * The maximum number of claims that can be made (one per address)
65
+ *
66
+ * @type {bigint}
67
+ */
68
+ limit: bigint;
69
+ }
70
+
71
+ /**
72
+ * A generic `viem.Log` event with support for `PointsIncentive` event types.
73
+ *
74
+ * @export
75
+ * @typedef {PointsIncentiveLog}
76
+ * @template {ContractEventName<
77
+ * typeof pointsIncentiveAbi
78
+ * >} [event=ContractEventName<typeof pointsIncentiveAbi>]
79
+ */
80
+ export type PointsIncentiveLog<
81
+ event extends ContractEventName<
82
+ typeof pointsIncentiveAbi
83
+ > = ContractEventName<typeof pointsIncentiveAbi>,
84
+ > = GenericLog<typeof pointsIncentiveAbi, event>;
85
+
86
+ /**
87
+ * A simple on-chain points incentive implementation that allows claiming of soulbound tokens.
88
+ *
89
+ * In order for any claim to be successful:
90
+ * - The claimer must not have already claimed the incentive; and
91
+ * - The maximum number of claims must not have been reached; and
92
+ * - This contract must be authorized to operate the points contract's issuance function
93
+ *
94
+ * @export
95
+ * @class PointsIncentive
96
+ * @typedef {PointsIncentive}
97
+ * @extends {DeployableTarget<PointsIncentivePayload>}
98
+ */
99
+ export class PointsIncentive extends DeployableTarget<
100
+ PointsIncentivePayload,
101
+ typeof pointsIncentiveAbi
102
+ > {
103
+ public override readonly abi = pointsIncentiveAbi;
104
+ /**
105
+ * @inheritdoc
106
+ *
107
+ * @public
108
+ * @static
109
+ * @type {Record<number, Address>}
110
+ */
111
+ public static override bases: Record<number, Address> = {
112
+ ...(PointsIncentiveBases as Record<number, Address>),
113
+ };
114
+ /**
115
+ * @inheritdoc
116
+ *
117
+ * @public
118
+ * @static
119
+ * @type {RegistryType}
120
+ */
121
+ public static override registryType: RegistryType = RegistryType.INCENTIVE;
122
+
123
+ /**
124
+ * The number of claims that have been made
125
+ *
126
+ * @public
127
+ * @async
128
+ * @param {?ReadParams} [params]
129
+ * @returns {Promise<bigint>}
130
+ */
131
+ public async claims(
132
+ params?: ReadParams<typeof pointsIncentiveAbi, 'claims'>,
133
+ ) {
134
+ return await readPointsIncentiveClaims(this._config, {
135
+ address: this.assertValidAddress(),
136
+ args: [],
137
+ // biome-ignore lint/suspicious/noExplicitAny: Accept any shape of valid wagmi/viem parameters, wagmi does the same thing internally
138
+ ...(params as any),
139
+ });
140
+ }
141
+
142
+ /**
143
+ * The current reward
144
+ *
145
+ * @public
146
+ * @async
147
+ * @param {?ReadParams} [params]
148
+ * @returns {Promise<bigint>} - The current reward
149
+ */
150
+ public async currentReward(
151
+ params?: ReadParams<typeof pointsIncentiveAbi, 'currentReward'>,
152
+ ) {
153
+ return await readPointsIncentiveCurrentReward(this._config, {
154
+ address: this.assertValidAddress(),
155
+ args: [],
156
+ // biome-ignore lint/suspicious/noExplicitAny: Accept any shape of valid wagmi/viem parameters, wagmi does the same thing internally
157
+ ...(params as any),
158
+ });
159
+ }
160
+
161
+ /**
162
+ * The reward amount issued for each claim
163
+ *
164
+ * @public
165
+ * @async
166
+ * @param {?ReadParams} [params]
167
+ * @returns {Promise<bigint>} The reward amount issued for each claim
168
+ */
169
+ public async reward(
170
+ params?: ReadParams<typeof pointsIncentiveAbi, 'reward'>,
171
+ ) {
172
+ return await readPointsIncentiveReward(this._config, {
173
+ address: this.assertValidAddress(),
174
+ args: [],
175
+ // biome-ignore lint/suspicious/noExplicitAny: Accept any shape of valid wagmi/viem parameters, wagmi does the same thing internally
176
+ ...(params as any),
177
+ });
178
+ }
179
+
180
+ /**
181
+ * A mapping of address to claim status
182
+ *
183
+ * @public
184
+ * @async
185
+ * @param {Address} address
186
+ * @param {?ReadParams} [params]
187
+ * @returns {Promise<boolean>}
188
+ */
189
+ public async claimed(
190
+ address: Address,
191
+ params?: ReadParams<typeof pointsIncentiveAbi, 'claimed'>,
192
+ ) {
193
+ return await readPointsIncentiveClaimed(this._config, {
194
+ address: this.assertValidAddress(),
195
+ args: [address],
196
+ // biome-ignore lint/suspicious/noExplicitAny: Accept any shape of valid wagmi/viem parameters, wagmi does the same thing internally
197
+ ...(params as any),
198
+ });
199
+ }
200
+
201
+ /**
202
+ * The address of the points contract
203
+ *
204
+ * @public
205
+ * @async
206
+ * @param {?ReadParams} [params]
207
+ * @returns {Promise<Address>}
208
+ */
209
+ public async venue(params?: ReadParams<typeof pointsIncentiveAbi, 'venue'>) {
210
+ return await readPointsIncentiveVenue(this._config, {
211
+ address: this.assertValidAddress(),
212
+ // biome-ignore lint/suspicious/noExplicitAny: Accept any shape of valid wagmi/viem parameters, wagmi does the same thing internally
213
+ ...(params as any),
214
+ });
215
+ }
216
+
217
+ /**
218
+ * The maximum number of claims that can be made (one per address)
219
+ *
220
+ * @public
221
+ * @async
222
+ * @param {?ReadParams} [params]
223
+ * @returns {Promise<bigint>}
224
+ */
225
+ public async limit(params?: ReadParams<typeof pointsIncentiveAbi, 'limit'>) {
226
+ return await readPointsIncentiveLimit(this._config, {
227
+ address: this.assertValidAddress(),
228
+ // biome-ignore lint/suspicious/noExplicitAny: Accept any shape of valid wagmi/viem parameters, wagmi does the same thing internally
229
+ ...(params as any),
230
+ });
231
+ }
232
+
233
+ /**
234
+ * The selector for the issuance function on the points contract
235
+ *
236
+ * @public
237
+ * @async
238
+ * @param {?ReadParams} [params]
239
+ * @returns {Promise<Hex>}
240
+ */
241
+ public async selector(
242
+ params?: ReadParams<typeof pointsIncentiveAbi, 'selector'>,
243
+ ) {
244
+ return await readPointsIncentiveSelector(this._config, {
245
+ address: this.assertValidAddress(),
246
+ // biome-ignore lint/suspicious/noExplicitAny: Accept any shape of valid wagmi/viem parameters, wagmi does the same thing internally
247
+ ...(params as any),
248
+ });
249
+ }
250
+
251
+ /**
252
+ * Claim the incentive
253
+ *
254
+ * @public
255
+ * @async
256
+ * @param {ClaimPayload} payload
257
+ * @param {?WriteParams} [params]
258
+ * @returns {Promise<boolean>} - True if the incentive was successfully claimed
259
+ */
260
+ protected async claim(
261
+ payload: ClaimPayload,
262
+ params?: WriteParams<typeof pointsIncentiveAbi, 'claim'>,
263
+ ) {
264
+ return await this.awaitResult(this.claimRaw(payload, params));
265
+ }
266
+
267
+ /**
268
+ * Claim the incentive
269
+ *
270
+ * @public
271
+ * @async
272
+ * @param {ClaimPayload} payload
273
+ * @param {?WriteParams} [params]
274
+ * @returns {Promise<{ hash: `0x${string}`; result: boolean; }>} - True if the incentive was successfully claimed
275
+ */
276
+ protected async claimRaw(
277
+ payload: ClaimPayload,
278
+ params?: WriteParams<typeof pointsIncentiveAbi, 'claim'>,
279
+ ) {
280
+ const { request, result } = await simulatePointsIncentiveClaim(
281
+ this._config,
282
+ {
283
+ address: this.assertValidAddress(),
284
+ args: [prepareClaimPayload(payload)],
285
+ ...this.optionallyAttachAccount(),
286
+ // biome-ignore lint/suspicious/noExplicitAny: Accept any shape of valid wagmi/viem parameters, wagmi does the same thing internally
287
+ ...(params as any),
288
+ },
289
+ );
290
+ const hash = await writePointsIncentiveClaim(this._config, request);
291
+ return { hash, result };
292
+ }
293
+
294
+ /**
295
+ * Check if an incentive is claimable.
296
+ * For the POOL strategy, the `bytes data` portion of the payload ignored.
297
+ * The recipient must not have already claimed the incentive.
298
+ *
299
+ * @public
300
+ * @async
301
+ * @param {ClaimPayload} payload
302
+ * @param {?ReadParams} [params]
303
+ * @returns {Promise<boolean>} - True if the incentive is claimable based on the data payload
304
+ */
305
+ public async isClaimable(
306
+ payload: ClaimPayload,
307
+ params?: ReadParams<typeof pointsIncentiveAbi, 'isClaimable'>,
308
+ ) {
309
+ return await readPointsIncentiveIsClaimable(this._config, {
310
+ address: this.assertValidAddress(),
311
+ args: [prepareClaimPayload(payload)],
312
+ // biome-ignore lint/suspicious/noExplicitAny: Accept any shape of valid wagmi/viem parameters, wagmi does the same thing internally
313
+ ...(params as any),
314
+ });
315
+ }
316
+
317
+ /**
318
+ * @inheritdoc
319
+ *
320
+ * @public
321
+ * @param {?PointsIncentivePayload} [_payload]
322
+ * @param {?DeployableOptions} [_options]
323
+ * @returns {GenericDeployableParams}
324
+ */
325
+ public override buildParameters(
326
+ _payload?: PointsIncentivePayload,
327
+ _options?: DeployableOptions,
328
+ ): GenericDeployableParams {
329
+ const [payload, options] = this.validateDeploymentConfig(
330
+ _payload,
331
+ _options,
332
+ );
333
+ return {
334
+ abi: pointsIncentiveAbi,
335
+ bytecode: bytecode as Hex,
336
+ args: [preparePointsIncentivePayload(payload)],
337
+ ...this.optionallyAttachAccount(options.account),
338
+ };
339
+ }
340
+ }
341
+
342
+ /**
343
+ * Given a {@link PointsIncentivePayload}, properly encode a `PointsIncentive.InitPayload` for use with {@link PointsIncentive} initialization.
344
+ *
345
+ * @param {PointsIncentivePayload} param0
346
+ * @param {Address} param0.venue - The address of the points contract
347
+ * @param {Hex} param0.selector - The selector for the issuance function on the points contract
348
+ * @param {bigint} param0.reward - The reward amount issued for each claim
349
+ * @param {bigint} param0.limit - The maximum number of claims that can be made (one per address)
350
+ * @returns {*}
351
+ */
352
+ export const preparePointsIncentivePayload = ({
353
+ venue,
354
+ selector,
355
+ reward,
356
+ limit,
357
+ }: PointsIncentivePayload) => {
358
+ return encodeAbiParameters(
359
+ [
360
+ { type: 'address', name: 'venue' },
361
+ { type: 'bytes4', name: 'selector' },
362
+ { type: 'uint256', name: 'reward' },
363
+ { type: 'uint256', name: 'limit' },
364
+ ],
365
+ [venue, selector, reward, limit],
366
+ );
367
+ };
@@ -0,0 +1,159 @@
1
+ import { loadFixture } from '@nomicfoundation/hardhat-network-helpers';
2
+ import { isAddress, pad } from 'viem';
3
+ import { beforeAll, describe, expect, test } from 'vitest';
4
+ import { accounts } from '@boostxyz/test/accounts';
5
+ import {
6
+ type Fixtures,
7
+ defaultOptions,
8
+ deployFixtures,
9
+ } from '@boostxyz/test/helpers';
10
+ import { testAccount } from '@boostxyz/test/viem';
11
+ import { SignerValidator } from './SignerValidator';
12
+
13
+ let fixtures: Fixtures;
14
+
15
+ function freshValidator(fixtures: Fixtures) {
16
+ return function freshValidator() {
17
+ // biome-ignore lint/style/noNonNullAssertion: this will never be undefined
18
+ const account = accounts.at(1)!.account;
19
+ return fixtures.registry.initialize(
20
+ crypto.randomUUID(),
21
+ fixtures.core.SignerValidator({
22
+ signers: [defaultOptions.account.address, account],
23
+ validatorCaller: testAccount.address,
24
+ }),
25
+ );
26
+ };
27
+ }
28
+
29
+ describe('SignerValidator', () => {
30
+ beforeAll(async () => {
31
+ fixtures = await loadFixture(deployFixtures(defaultOptions));
32
+ });
33
+
34
+ test('can successfully be deployed', async () => {
35
+ const action = new SignerValidator(defaultOptions, {
36
+ signers: [testAccount.address],
37
+ validatorCaller: testAccount.address,
38
+ });
39
+ await action.deploy();
40
+ expect(isAddress(action.assertValidAddress())).toBe(true);
41
+ });
42
+
43
+ test('initializes successfully', async () => {
44
+ const validator = await loadFixture(freshValidator(fixtures));
45
+ expect(await validator.signers(defaultOptions.account.address)).toBe(true);
46
+ // biome-ignore lint/style/noNonNullAssertion: this will never be undefined
47
+ expect(await validator.signers(accounts.at(1)!.account)).toBe(true);
48
+ // biome-ignore lint/style/noNonNullAssertion: this will never be undefined
49
+ expect(await validator.signers(accounts.at(2)!.account)).toBe(false);
50
+ });
51
+
52
+ test('can validate hashes', async () => {
53
+ const validator = await loadFixture(freshValidator(fixtures));
54
+
55
+ // Define the input data
56
+ const boostId = 5n;
57
+ const incentiveQuantity = 1;
58
+ const incentiveId = 0n;
59
+ const claimant = '0x24582544C98a86eE59687c4D5B55D78f4FffA666';
60
+ const incentiveData = pad('0xdef456232173821931823712381232131391321934');
61
+
62
+ // biome-ignore lint/style/noNonNullAssertion: this will never be undefined
63
+ const trustedSigner = accounts.at(0)!;
64
+ // biome-ignore lint/style/noNonNullAssertion: this will never be undefined
65
+ const untrustedSigner = accounts.at(2)!;
66
+
67
+ const claimDataPayload = await validator.encodeClaimData({
68
+ signer: trustedSigner,
69
+ incentiveData,
70
+ chainId: defaultOptions.config.chains[0].id,
71
+ incentiveQuantity,
72
+ claimant,
73
+ boostId: boostId,
74
+ });
75
+
76
+ const badClaimDataPayload = await validator.encodeClaimData({
77
+ signer: untrustedSigner,
78
+ incentiveData,
79
+ chainId: defaultOptions.config.chains[0].id,
80
+ incentiveQuantity,
81
+ claimant,
82
+ boostId: boostId,
83
+ });
84
+
85
+ // Validation using trusted signer
86
+ expect(
87
+ await validator.validate({
88
+ boostId: boostId,
89
+ incentiveId: incentiveId,
90
+ claimData: claimDataPayload,
91
+ claimant: claimant,
92
+ }),
93
+ ).toBe(true);
94
+
95
+ // Validation using untrusted signer should throw an error
96
+ try {
97
+ await validator.validate({
98
+ boostId: boostId,
99
+ incentiveId: incentiveId,
100
+ claimData: badClaimDataPayload,
101
+ claimant: claimant,
102
+ });
103
+ } catch (e) {
104
+ expect(e).toBeInstanceOf(Error);
105
+ }
106
+ });
107
+ test('will not revalidate the same hash', async () => {
108
+ const validator = await loadFixture(freshValidator(fixtures));
109
+
110
+ // Define the input data
111
+ const boostId = 5n;
112
+ const incentiveQuantity = 1;
113
+ const incentiveId = 0n;
114
+ const claimant = '0x24582544C98a86eE59687c4D5B55D78f4FffA666';
115
+ const incentiveData = pad('0xdef456232173821931823712381232131391321934');
116
+
117
+ // biome-ignore lint/style/noNonNullAssertion: this will never be undefined
118
+ const trustedSigner = accounts.at(0)!;
119
+
120
+ const claimDataPayload = await validator.encodeClaimData({
121
+ signer: trustedSigner,
122
+ incentiveData,
123
+ chainId: defaultOptions.config.chains[0].id,
124
+ incentiveQuantity,
125
+ claimant,
126
+ boostId: boostId,
127
+ });
128
+
129
+ expect(
130
+ await validator.validate({
131
+ boostId,
132
+ incentiveId,
133
+ claimant,
134
+ claimData: claimDataPayload,
135
+ }),
136
+ ).toBe(true);
137
+
138
+ // Attempt to validate the same hash again (should throw an error)
139
+ try {
140
+ await validator.validate({
141
+ boostId,
142
+ incentiveId,
143
+ claimData: claimDataPayload,
144
+ claimant,
145
+ });
146
+ } catch (e) {
147
+ expect(e).toBeInstanceOf(Error);
148
+ }
149
+ });
150
+
151
+ test('can set authorized', async () => {
152
+ const validator = await loadFixture(freshValidator(fixtures));
153
+ // biome-ignore lint/style/noNonNullAssertion: this will never be undefined
154
+ const newSigner = accounts.at(2)!.account;
155
+ expect(await validator.signers(newSigner)).toBe(false);
156
+ await validator.setAuthorized([newSigner], [true]);
157
+ expect(await validator.signers(newSigner)).toBe(true);
158
+ });
159
+ });