@boostxyz/sdk 0.0.0-alpha.10

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