@boostxyz/sdk 0.0.0-alpha.5 → 0.0.0-alpha.7

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 (165) hide show
  1. package/dist/Actions/Action.cjs +1 -0
  2. package/dist/Actions/Action.cjs.map +1 -0
  3. package/dist/Actions/Action.js +1 -0
  4. package/dist/Actions/Action.js.map +1 -0
  5. package/dist/Actions/EventAction.cjs +2 -1
  6. package/dist/Actions/EventAction.cjs.map +1 -0
  7. package/dist/Actions/EventAction.d.ts.map +1 -1
  8. package/dist/Actions/EventAction.js +39 -40
  9. package/dist/Actions/EventAction.js.map +1 -0
  10. package/dist/AllowLists/AllowList.cjs +1 -0
  11. package/dist/AllowLists/AllowList.cjs.map +1 -0
  12. package/dist/AllowLists/AllowList.js +1 -0
  13. package/dist/AllowLists/AllowList.js.map +1 -0
  14. package/dist/AllowLists/SimpleAllowList.cjs +1 -0
  15. package/dist/AllowLists/SimpleAllowList.cjs.map +1 -0
  16. package/dist/AllowLists/SimpleAllowList.js +1 -0
  17. package/dist/AllowLists/SimpleAllowList.js.map +1 -0
  18. package/dist/AllowLists/SimpleDenyList.cjs +1 -0
  19. package/dist/AllowLists/SimpleDenyList.cjs.map +1 -0
  20. package/dist/AllowLists/SimpleDenyList.js +1 -0
  21. package/dist/AllowLists/SimpleDenyList.js.map +1 -0
  22. package/dist/Auth/Auth.cjs +1 -0
  23. package/dist/Auth/Auth.cjs.map +1 -0
  24. package/dist/Auth/Auth.js +1 -0
  25. package/dist/Auth/Auth.js.map +1 -0
  26. package/dist/Auth/PassthroughAuth.cjs +1 -0
  27. package/dist/Auth/PassthroughAuth.cjs.map +1 -0
  28. package/dist/Auth/PassthroughAuth.js +1 -0
  29. package/dist/Auth/PassthroughAuth.js.map +1 -0
  30. package/dist/Boost.cjs +1 -0
  31. package/dist/Boost.cjs.map +1 -0
  32. package/dist/Boost.js +1 -0
  33. package/dist/Boost.js.map +1 -0
  34. package/dist/BoostCore.cjs +1 -0
  35. package/dist/BoostCore.cjs.map +1 -0
  36. package/dist/BoostCore.js +1 -0
  37. package/dist/BoostCore.js.map +1 -0
  38. package/dist/BoostRegistry.cjs +1 -0
  39. package/dist/BoostRegistry.cjs.map +1 -0
  40. package/dist/BoostRegistry.js +1 -0
  41. package/dist/BoostRegistry.js.map +1 -0
  42. package/dist/Budgets/Budget.cjs +1 -0
  43. package/dist/Budgets/Budget.cjs.map +1 -0
  44. package/dist/Budgets/Budget.js +1 -0
  45. package/dist/Budgets/Budget.js.map +1 -0
  46. package/dist/Budgets/ManagedBudget.cjs +1 -0
  47. package/dist/Budgets/ManagedBudget.cjs.map +1 -0
  48. package/dist/Budgets/ManagedBudget.js +1 -0
  49. package/dist/Budgets/ManagedBudget.js.map +1 -0
  50. package/dist/Deployable/Contract.cjs +1 -0
  51. package/dist/Deployable/Contract.cjs.map +1 -0
  52. package/dist/Deployable/Contract.js +1 -0
  53. package/dist/Deployable/Contract.js.map +1 -0
  54. package/dist/Deployable/Deployable.cjs +1 -0
  55. package/dist/Deployable/Deployable.cjs.map +1 -0
  56. package/dist/Deployable/Deployable.js +1 -0
  57. package/dist/Deployable/Deployable.js.map +1 -0
  58. package/dist/Deployable/DeployableTarget.cjs +1 -0
  59. package/dist/Deployable/DeployableTarget.cjs.map +1 -0
  60. package/dist/Deployable/DeployableTarget.js +1 -0
  61. package/dist/Deployable/DeployableTarget.js.map +1 -0
  62. package/dist/Incentives/AllowListIncentive.cjs +1 -0
  63. package/dist/Incentives/AllowListIncentive.cjs.map +1 -0
  64. package/dist/Incentives/AllowListIncentive.js +1 -0
  65. package/dist/Incentives/AllowListIncentive.js.map +1 -0
  66. package/dist/Incentives/CGDAIncentive.cjs +1 -0
  67. package/dist/Incentives/CGDAIncentive.cjs.map +1 -0
  68. package/dist/Incentives/CGDAIncentive.js +1 -0
  69. package/dist/Incentives/CGDAIncentive.js.map +1 -0
  70. package/dist/Incentives/ERC20Incentive.cjs +1 -0
  71. package/dist/Incentives/ERC20Incentive.cjs.map +1 -0
  72. package/dist/Incentives/ERC20Incentive.js +1 -0
  73. package/dist/Incentives/ERC20Incentive.js.map +1 -0
  74. package/dist/Incentives/Incentive.cjs +1 -0
  75. package/dist/Incentives/Incentive.cjs.map +1 -0
  76. package/dist/Incentives/Incentive.js +1 -0
  77. package/dist/Incentives/Incentive.js.map +1 -0
  78. package/dist/Incentives/PointsIncentive.cjs +1 -0
  79. package/dist/Incentives/PointsIncentive.cjs.map +1 -0
  80. package/dist/Incentives/PointsIncentive.js +1 -0
  81. package/dist/Incentives/PointsIncentive.js.map +1 -0
  82. package/dist/Validators/SignerValidator.cjs +1 -0
  83. package/dist/Validators/SignerValidator.cjs.map +1 -0
  84. package/dist/Validators/SignerValidator.js +1 -0
  85. package/dist/Validators/SignerValidator.js.map +1 -0
  86. package/dist/Validators/Validator.cjs +1 -0
  87. package/dist/Validators/Validator.cjs.map +1 -0
  88. package/dist/Validators/Validator.js +1 -0
  89. package/dist/Validators/Validator.js.map +1 -0
  90. package/dist/componentInterfaces-CKCBwG16.cjs +1 -0
  91. package/dist/componentInterfaces-CKCBwG16.cjs.map +1 -0
  92. package/dist/componentInterfaces-DYkaxBda.js +1 -0
  93. package/dist/componentInterfaces-DYkaxBda.js.map +1 -0
  94. package/dist/errors.cjs +1 -0
  95. package/dist/errors.cjs.map +1 -0
  96. package/dist/errors.js +1 -0
  97. package/dist/errors.js.map +1 -0
  98. package/dist/generated-Cd-Fe7W7.cjs +1 -0
  99. package/dist/generated-Cd-Fe7W7.cjs.map +1 -0
  100. package/dist/generated-DGpIVcv5.js +1 -0
  101. package/dist/generated-DGpIVcv5.js.map +1 -0
  102. package/dist/index.cjs +1 -0
  103. package/dist/index.cjs.map +1 -0
  104. package/dist/index.js +1 -0
  105. package/dist/index.js.map +1 -0
  106. package/dist/utils.cjs +1 -0
  107. package/dist/utils.cjs.map +1 -0
  108. package/dist/utils.js +1 -0
  109. package/dist/utils.js.map +1 -0
  110. package/package.json +3 -2
  111. package/src/Actions/Action.test.ts +77 -0
  112. package/src/Actions/Action.ts +61 -0
  113. package/src/Actions/ContractAction.test.ts +199 -0
  114. package/src/Actions/ContractAction.ts +238 -0
  115. package/src/Actions/ERC721MintAction.test.ts +112 -0
  116. package/src/Actions/ERC721MintAction.ts +238 -0
  117. package/src/Actions/EventAction.test.ts +182 -0
  118. package/src/Actions/EventAction.ts +380 -0
  119. package/src/AllowLists/AllowList.test.ts +64 -0
  120. package/src/AllowLists/AllowList.ts +60 -0
  121. package/src/AllowLists/SimpleAllowList.test.ts +52 -0
  122. package/src/AllowLists/SimpleAllowList.ts +240 -0
  123. package/src/AllowLists/SimpleDenyList.test.ts +52 -0
  124. package/src/AllowLists/SimpleDenyList.ts +289 -0
  125. package/src/Auth/Auth.ts +11 -0
  126. package/src/Auth/PassthroughAuth.test.ts +12 -0
  127. package/src/Auth/PassthroughAuth.ts +80 -0
  128. package/src/Boost.ts +155 -0
  129. package/src/BoostCore.test.ts +846 -0
  130. package/src/BoostCore.ts +1192 -0
  131. package/src/BoostRegistry.ts +449 -0
  132. package/src/Budgets/Budget.test.ts +27 -0
  133. package/src/Budgets/Budget.ts +61 -0
  134. package/src/Budgets/ManagedBudget.test.ts +154 -0
  135. package/src/Budgets/ManagedBudget.ts +743 -0
  136. package/src/Budgets/SimpleBudget.test.ts +152 -0
  137. package/src/Budgets/SimpleBudget.ts +521 -0
  138. package/src/Budgets/VestingBudget.test.ts +123 -0
  139. package/src/Budgets/VestingBudget.ts +532 -0
  140. package/src/Deployable/Contract.ts +229 -0
  141. package/src/Deployable/Deployable.ts +244 -0
  142. package/src/Deployable/DeployableTarget.ts +210 -0
  143. package/src/Incentives/AllowListIncentive.test.ts +146 -0
  144. package/src/Incentives/AllowListIncentive.ts +290 -0
  145. package/src/Incentives/CGDAIncentive.test.ts +136 -0
  146. package/src/Incentives/CGDAIncentive.ts +364 -0
  147. package/src/Incentives/ERC1155Incentive.test.ts +98 -0
  148. package/src/Incentives/ERC1155Incentive.ts +384 -0
  149. package/src/Incentives/ERC20Incentive.test.ts +141 -0
  150. package/src/Incentives/ERC20Incentive.ts +417 -0
  151. package/src/Incentives/ERC20VariableIncentive.test.ts +156 -0
  152. package/src/Incentives/ERC20VariableIncentive.ts +368 -0
  153. package/src/Incentives/Incentive.test.ts +92 -0
  154. package/src/Incentives/Incentive.ts +85 -0
  155. package/src/Incentives/PointsIncentive.test.ts +142 -0
  156. package/src/Incentives/PointsIncentive.ts +303 -0
  157. package/src/Validators/SignerValidator.test.ts +163 -0
  158. package/src/Validators/SignerValidator.ts +272 -0
  159. package/src/Validators/Validator.test.ts +21 -0
  160. package/src/Validators/Validator.ts +55 -0
  161. package/src/errors.ts +524 -0
  162. package/src/index.test.ts +40 -0
  163. package/src/index.ts +50 -0
  164. package/src/utils.test.ts +44 -0
  165. package/src/utils.ts +2247 -0
@@ -0,0 +1,146 @@
1
+ import { loadFixture } from '@nomicfoundation/hardhat-network-helpers';
2
+ import { isAddress, pad, parseEther, zeroAddress } 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
+ freshBoost,
10
+ } from '../../test/helpers';
11
+ import { LIST_MANAGER_ROLE } from '../AllowLists/SimpleAllowList';
12
+ import { prepareSignerValidatorClaimDataPayload } from '../utils';
13
+ import { PointsIncentive } from './PointsIncentive';
14
+
15
+ let fixtures: Fixtures;
16
+
17
+ function freshAllowList(fixtures: Fixtures) {
18
+ return function freshAllowList() {
19
+ return fixtures.registry.clone(
20
+ crypto.randomUUID(),
21
+ new fixtures.bases.SimpleAllowList(defaultOptions, {
22
+ owner: defaultOptions.account.address,
23
+ allowed: [],
24
+ }),
25
+ );
26
+ };
27
+ }
28
+
29
+ describe('AllowListIncentive', () => {
30
+ beforeAll(async () => {
31
+ fixtures = await loadFixture(deployFixtures);
32
+ });
33
+
34
+ test('can successfully be deployed', async () => {
35
+ const action = new PointsIncentive(defaultOptions, {
36
+ venue: zeroAddress,
37
+ selector: '0xdeadb33f',
38
+ reward: 1n,
39
+ limit: 1n,
40
+ });
41
+ await action.deploy();
42
+ expect(isAddress(action.assertValidAddress())).toBe(true);
43
+ });
44
+
45
+ test('can claim', async () => {
46
+ // biome-ignore lint/style/noNonNullAssertion: we know this is defined
47
+ const referrer = accounts.at(1)?.account!;
48
+ // biome-ignore lint/style/noNonNullAssertion: we know this is defined
49
+ const trustedSigner = accounts.at(0)!;
50
+ const allowList = await loadFixture(freshAllowList(fixtures));
51
+ const allowListIncentive = new fixtures.bases.AllowListIncentive(
52
+ defaultOptions,
53
+ {
54
+ allowList: allowList.assertValidAddress(),
55
+ limit: 3n,
56
+ },
57
+ );
58
+ const boost = await freshBoost(fixtures, {
59
+ incentives: [allowListIncentive],
60
+ });
61
+ await allowList.grantRoles(
62
+ allowListIncentive.assertValidAddress(),
63
+ LIST_MANAGER_ROLE,
64
+ );
65
+
66
+ const claimant = trustedSigner.account;
67
+ const incentiveData = pad('0xdef456232173821931823712381232131391321934');
68
+ console.log(claimant);
69
+
70
+ const incentiveQuantity = 1;
71
+ const claimDataPayload = await prepareSignerValidatorClaimDataPayload({
72
+ signer: trustedSigner,
73
+ incentiveData,
74
+ chainId: defaultOptions.config.chains[0].id,
75
+ validator: boost.validator.assertValidAddress(),
76
+ incentiveQuantity,
77
+ claimant,
78
+ boostId: boost.id,
79
+ });
80
+
81
+ //await boost.validator.setValidatorCaller(boost.assertValidAddress());
82
+ await fixtures.core.claimIncentive(
83
+ boost.id,
84
+ 0n,
85
+ referrer,
86
+ claimDataPayload,
87
+ { value: parseEther('0.000075'), account: trustedSigner.privateKey },
88
+ );
89
+ expect(await allowList.isAllowed(trustedSigner.account)).toBe(true);
90
+ });
91
+
92
+ test('cannot claim twice', async () => {
93
+ // biome-ignore lint/style/noNonNullAssertion: we know this is defined
94
+ const referrer = accounts.at(1)?.account!;
95
+ // biome-ignore lint/style/noNonNullAssertion: we know this is defined
96
+ const trustedSigner = accounts.at(0)!;
97
+ const allowList = await loadFixture(freshAllowList(fixtures));
98
+ const allowListIncentive = new fixtures.bases.AllowListIncentive(
99
+ defaultOptions,
100
+ {
101
+ allowList: allowList.assertValidAddress(),
102
+ limit: 3n,
103
+ },
104
+ );
105
+ const boost = await freshBoost(fixtures, {
106
+ incentives: [allowListIncentive],
107
+ });
108
+ await allowList.grantRoles(
109
+ allowListIncentive.assertValidAddress(),
110
+ LIST_MANAGER_ROLE,
111
+ );
112
+ const incentiveQuantity = 1;
113
+ const claimant = trustedSigner.account;
114
+ const incentiveData = pad('0xdef456232173821931823712381232131391321934');
115
+ console.log(claimant);
116
+
117
+ const claimDataPayload = await prepareSignerValidatorClaimDataPayload({
118
+ signer: trustedSigner,
119
+ incentiveData,
120
+ chainId: defaultOptions.config.chains[0].id,
121
+ validator: boost.validator.assertValidAddress(),
122
+ incentiveQuantity,
123
+ claimant,
124
+ boostId: boost.id,
125
+ });
126
+
127
+ await fixtures.core.claimIncentive(
128
+ boost.id,
129
+ 0n,
130
+ referrer,
131
+ claimDataPayload,
132
+ { value: parseEther('0.000075'), account: trustedSigner.privateKey },
133
+ );
134
+ try {
135
+ await fixtures.core.claimIncentive(
136
+ boost.id,
137
+ 0n,
138
+ referrer,
139
+ claimDataPayload,
140
+ { value: parseEther('0.000075'), account: trustedSigner.privateKey },
141
+ );
142
+ } catch (e) {
143
+ expect(e).toBeInstanceOf(Error);
144
+ }
145
+ });
146
+ });
@@ -0,0 +1,290 @@
1
+ import {
2
+ allowListIncentiveAbi,
3
+ readAllowListIncentiveAllowList,
4
+ readAllowListIncentiveClaimed,
5
+ readAllowListIncentiveClaims,
6
+ readAllowListIncentiveIsClaimable,
7
+ readAllowListIncentiveLimit,
8
+ readAllowListIncentiveOwner,
9
+ readAllowListIncentiveReward,
10
+ simulateAllowListIncentiveClaim,
11
+ writeAllowListIncentiveClaim,
12
+ } from '@boostxyz/evm';
13
+ import { bytecode } from '@boostxyz/evm/artifacts/contracts/incentives/AllowListIncentive.sol/AllowListIncentive.json';
14
+ import type { Address, ContractEventName, Hex } from 'viem';
15
+ import { SimpleAllowList } from '../AllowLists/AllowList';
16
+ import type {
17
+ DeployableOptions,
18
+ GenericDeployableParams,
19
+ } from '../Deployable/Deployable';
20
+ import { DeployableTarget } from '../Deployable/DeployableTarget';
21
+ import {
22
+ type AllowListIncentivePayload,
23
+ type ClaimPayload,
24
+ type GenericLog,
25
+ type ReadParams,
26
+ RegistryType,
27
+ type WriteParams,
28
+ prepareAllowListIncentivePayload,
29
+ prepareClaimPayload,
30
+ } from '../utils';
31
+
32
+ export { allowListIncentiveAbi };
33
+ export type { AllowListIncentivePayload };
34
+
35
+ /**
36
+ * A generic `viem.Log` event with support for `AllowListIncentive` event types.
37
+ *
38
+ * @export
39
+ * @typedef {AllowListIncentiveLog}
40
+ * @template {ContractEventName<
41
+ * typeof allowListIncentiveAbi
42
+ * >} [event=ContractEventName<typeof allowListIncentiveAbi>]
43
+ */
44
+ export type AllowListIncentiveLog<
45
+ event extends ContractEventName<
46
+ typeof allowListIncentiveAbi
47
+ > = ContractEventName<typeof allowListIncentiveAbi>,
48
+ > = GenericLog<typeof allowListIncentiveAbi, event>;
49
+
50
+ /**
51
+ * An incentive implementation that grants the claimer a slot on an {SimpleAllowList}
52
+ * In order for any claim to be successful:
53
+ * - The claimer must not already be on the allow list; and
54
+ * - The maximum number of claims must not have been reached; and
55
+ * - This contract must be authorized to modify the allow list
56
+ *
57
+ * @export
58
+ * @class AllowListIncentive
59
+ * @typedef {AllowListIncentive}
60
+ * @extends {DeployableTarget<AllowListIncentivePayload>}
61
+ */
62
+ export class AllowListIncentive extends DeployableTarget<
63
+ AllowListIncentivePayload,
64
+ typeof allowListIncentiveAbi
65
+ > {
66
+ public override readonly abi = allowListIncentiveAbi;
67
+ /**
68
+ * @inheritdoc
69
+ *
70
+ * @public
71
+ * @static
72
+ * @type {Address}
73
+ */
74
+ public static override base: Address = import.meta.env
75
+ .VITE_ALLOWLIST_INCENTIVE_BASE;
76
+ /**
77
+ * @inheritdoc
78
+ *
79
+ * @public
80
+ * @static
81
+ * @type {RegistryType}
82
+ */
83
+ public static override registryType: RegistryType = RegistryType.INCENTIVE;
84
+
85
+ /**
86
+ * The owner of the allowList
87
+ *
88
+ * @public
89
+ * @async
90
+ * @param {?ReadParams<typeof allowListIncentiveAbi, 'owner'>} [params]
91
+ * @returns {unknown}
92
+ */
93
+ public async owner(
94
+ params?: ReadParams<typeof allowListIncentiveAbi, 'owner'>,
95
+ ) {
96
+ return readAllowListIncentiveOwner(this._config, {
97
+ address: this.assertValidAddress(),
98
+ args: [],
99
+ // biome-ignore lint/suspicious/noExplicitAny: Accept any shape of valid wagmi/viem parameters, wagmi does the same thing internally
100
+ ...(params as any),
101
+ });
102
+ }
103
+
104
+ /**
105
+ * The number of claims that have been made
106
+ *
107
+ * @public
108
+ * @async
109
+ * @param {?ReadParams<typeof allowListIncentiveAbi, 'claims'>} [params]
110
+ * @returns {Promise<bigint>}
111
+ */
112
+ public async claims(
113
+ params?: ReadParams<typeof allowListIncentiveAbi, 'claims'>,
114
+ ) {
115
+ return readAllowListIncentiveClaims(this._config, {
116
+ address: this.assertValidAddress(),
117
+ args: [],
118
+ // biome-ignore lint/suspicious/noExplicitAny: Accept any shape of valid wagmi/viem parameters, wagmi does the same thing internally
119
+ ...(params as any),
120
+ });
121
+ }
122
+
123
+ /**
124
+ * The reward amount issued for each claim
125
+ *
126
+ * @public
127
+ * @async
128
+ * @param {?ReadParams<typeof allowListIncentiveAbi, 'reward'>} [params]
129
+ * @returns {Promise<bigint>}
130
+ */
131
+ public async reward(
132
+ params?: ReadParams<typeof allowListIncentiveAbi, 'reward'>,
133
+ ) {
134
+ return readAllowListIncentiveReward(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
+ * Get the claim status for a user
144
+ *
145
+ * @public
146
+ * @async
147
+ * @param {Address} address
148
+ * @param {?ReadParams<typeof allowListIncentiveAbi, 'claimed'>} [params]
149
+ * @returns {Promise<boolean>}
150
+ */
151
+ public async claimed(
152
+ address: Address,
153
+ params?: ReadParams<typeof allowListIncentiveAbi, 'claimed'>,
154
+ ) {
155
+ return readAllowListIncentiveClaimed(this._config, {
156
+ address: this.assertValidAddress(),
157
+ args: [address],
158
+ // biome-ignore lint/suspicious/noExplicitAny: Accept any shape of valid wagmi/viem parameters, wagmi does the same thing internally
159
+ ...(params as any),
160
+ });
161
+ }
162
+
163
+ /**
164
+ * The {@link SimpleAllowList} contract
165
+ *
166
+ * @public
167
+ * @async
168
+ * @param {?ReadParams<typeof allowListIncentiveAbi, 'allowList'>} [params]
169
+ * @returns {Promise<SimpleAllowList>}
170
+ */
171
+ public async allowList(
172
+ params?: ReadParams<typeof allowListIncentiveAbi, 'allowList'>,
173
+ ): Promise<SimpleAllowList> {
174
+ const address = await readAllowListIncentiveAllowList(this._config, {
175
+ address: this.assertValidAddress(),
176
+ // biome-ignore lint/suspicious/noExplicitAny: Accept any shape of valid wagmi/viem parameters, wagmi does the same thing internally
177
+ ...(params as any),
178
+ });
179
+ return new SimpleAllowList(
180
+ { config: this._config, account: this._account },
181
+ address,
182
+ );
183
+ }
184
+
185
+ /**
186
+ * The maximum number of claims that can be made (one per address)
187
+ *
188
+ * @public
189
+ * @async
190
+ * @param {?ReadParams<typeof allowListIncentiveAbi, 'limit'>} [params]
191
+ * @returns {unknown}
192
+ */
193
+ public async limit(
194
+ params?: ReadParams<typeof allowListIncentiveAbi, 'limit'>,
195
+ ) {
196
+ return readAllowListIncentiveLimit(this._config, {
197
+ address: this.assertValidAddress(),
198
+ // biome-ignore lint/suspicious/noExplicitAny: Accept any shape of valid wagmi/viem parameters, wagmi does the same thing internally
199
+ ...(params as any),
200
+ });
201
+ }
202
+
203
+ /**
204
+ * Claim a slot on the {@link SimpleAllowList}
205
+ *
206
+ * @public
207
+ * @async
208
+ * @param {Pick<ClaimPayload, 'target'>} payload
209
+ * @param {?WriteParams<typeof allowListIncentiveAbi, 'claim'>} [params]
210
+ * @returns {Promise<true>} - return true if successful, otherwise revert
211
+ */
212
+ public async claim(
213
+ payload: Pick<ClaimPayload, 'target'>,
214
+ params?: WriteParams<typeof allowListIncentiveAbi, 'claim'>,
215
+ ) {
216
+ return this.awaitResult(this.claimRaw(payload, params));
217
+ }
218
+
219
+ /**
220
+ * Claim a slot on the {@link SimpleAllowList}
221
+ *
222
+ * @public
223
+ * @async
224
+ * @param {Pick<ClaimPayload, 'target'>} payload
225
+ * @param {?WriteParams<typeof allowListIncentiveAbi, 'claim'>} [params]
226
+ * @returns {Promise<true>} - return true if successful, otherwise revert
227
+ */
228
+ public async claimRaw(
229
+ payload: Pick<ClaimPayload, 'target'>,
230
+ params?: WriteParams<typeof allowListIncentiveAbi, 'claim'>,
231
+ ) {
232
+ const { request, result } = await simulateAllowListIncentiveClaim(
233
+ this._config,
234
+ {
235
+ address: this.assertValidAddress(),
236
+ args: [prepareClaimPayload(payload)],
237
+ ...this.optionallyAttachAccount(),
238
+ // biome-ignore lint/suspicious/noExplicitAny: Accept any shape of valid wagmi/viem parameters, wagmi does the same thing internally
239
+ ...(params as any),
240
+ },
241
+ );
242
+ const hash = await writeAllowListIncentiveClaim(this._config, request);
243
+ return { hash, result };
244
+ }
245
+
246
+ /**
247
+ * Check if an incentive is claimable
248
+ *
249
+ * @public
250
+ * @async
251
+ * @param {Pick<ClaimPayload, 'target'>} payload
252
+ * @param {?ReadParams<typeof allowListIncentiveAbi, 'isClaimable'>} [params]
253
+ * @returns {Promise<boolean>} - True if the incentive is claimable based on the data payload
254
+ */
255
+ public async isClaimable(
256
+ payload: Pick<ClaimPayload, 'target'>,
257
+ params?: ReadParams<typeof allowListIncentiveAbi, 'isClaimable'>,
258
+ ) {
259
+ return readAllowListIncentiveIsClaimable(this._config, {
260
+ address: this.assertValidAddress(),
261
+ args: [prepareClaimPayload(payload)],
262
+ // biome-ignore lint/suspicious/noExplicitAny: Accept any shape of valid wagmi/viem parameters, wagmi does the same thing internally
263
+ ...(params as any),
264
+ });
265
+ }
266
+
267
+ /**
268
+ * @inheritdoc
269
+ *
270
+ * @public
271
+ * @param {?AllowListIncentivePayload} [_payload]
272
+ * @param {?DeployableOptions} [_options]
273
+ * @returns {GenericDeployableParams}
274
+ */
275
+ public override buildParameters(
276
+ _payload?: AllowListIncentivePayload,
277
+ _options?: DeployableOptions,
278
+ ): GenericDeployableParams {
279
+ const [payload, options] = this.validateDeploymentConfig(
280
+ _payload,
281
+ _options,
282
+ );
283
+ return {
284
+ abi: allowListIncentiveAbi,
285
+ bytecode: bytecode as Hex,
286
+ args: [prepareAllowListIncentivePayload(payload)],
287
+ ...this.optionallyAttachAccount(options.account),
288
+ };
289
+ }
290
+ }
@@ -0,0 +1,136 @@
1
+ import { readMockErc20BalanceOf } from '@boostxyz/evm';
2
+ import { loadFixture } from '@nomicfoundation/hardhat-network-helpers';
3
+ import { signMessage } from '@wagmi/core';
4
+ import { encodePacked, isAddress, keccak256, pad, parseEther } from 'viem';
5
+ import { beforeAll, beforeEach, describe, expect, test } from 'vitest';
6
+ import { accounts } from '../../test/accounts';
7
+ import {
8
+ type BudgetFixtures,
9
+ type Fixtures,
10
+ defaultOptions,
11
+ deployFixtures,
12
+ freshBoost,
13
+ fundBudget,
14
+ } from '../../test/helpers';
15
+ import { prepareSignerValidatorClaimDataPayload } from '../utils';
16
+ import { CGDAIncentive } from './CGDAIncentive';
17
+
18
+ let fixtures: Fixtures, budgets: BudgetFixtures;
19
+
20
+ describe('CGDAIncentive', () => {
21
+ beforeAll(async () => {
22
+ fixtures = await loadFixture(deployFixtures);
23
+ });
24
+
25
+ beforeEach(async () => {
26
+ budgets = await loadFixture(fundBudget(defaultOptions, fixtures));
27
+ });
28
+
29
+ test('can successfully be deployed', async () => {
30
+ const action = new CGDAIncentive(defaultOptions, {
31
+ asset: budgets.erc20.assertValidAddress(),
32
+ initialReward: 1n,
33
+ totalBudget: 10n,
34
+ rewardBoost: 1n,
35
+ rewardDecay: 1n,
36
+ });
37
+ await action.deploy();
38
+ expect(isAddress(action.assertValidAddress())).toBe(true);
39
+ });
40
+
41
+ test('can claim', async () => {
42
+ // biome-ignore lint/style/noNonNullAssertion: we know this is defined
43
+ const referrer = accounts.at(1)!.account!;
44
+ // biome-ignore lint/style/noNonNullAssertion: we know this is defined
45
+ const trustedSigner = accounts.at(0)!;
46
+ const erc20Incentive = new fixtures.bases.CGDAIncentive(defaultOptions, {
47
+ asset: budgets.erc20.assertValidAddress(),
48
+ initialReward: 1n,
49
+ totalBudget: 10n,
50
+ rewardBoost: 1n,
51
+ rewardDecay: 1n,
52
+ });
53
+ const boost = await freshBoost(fixtures, {
54
+ budget: budgets.budget,
55
+ incentives: [erc20Incentive],
56
+ });
57
+
58
+ const claimant = trustedSigner.account;
59
+ const incentiveData = pad('0xdef456232173821931823712381232131391321934');
60
+
61
+ const incentiveQuantity = 1;
62
+ const claimDataPayload = await prepareSignerValidatorClaimDataPayload({
63
+ signer: trustedSigner,
64
+ incentiveData,
65
+ chainId: defaultOptions.config.chains[0].id,
66
+ validator: boost.validator.assertValidAddress(),
67
+ incentiveQuantity,
68
+ claimant,
69
+ boostId: boost.id,
70
+ });
71
+
72
+ await fixtures.core.claimIncentive(
73
+ boost.id,
74
+ 0n,
75
+ referrer,
76
+ claimDataPayload,
77
+ { value: parseEther('0.000075') },
78
+ );
79
+ expect(
80
+ await readMockErc20BalanceOf(defaultOptions.config, {
81
+ address: budgets.erc20.assertValidAddress(),
82
+ args: [defaultOptions.account.address],
83
+ }),
84
+ ).toBe(1n);
85
+ });
86
+
87
+ test('cannot claim twice', async () => {
88
+ // biome-ignore lint/style/noNonNullAssertion: we know this is defined
89
+ const referrer = accounts.at(1)!.account!;
90
+ // biome-ignore lint/style/noNonNullAssertion: we know this is defined
91
+ const trustedSigner = accounts.at(0)!;
92
+ const erc20Incentive = new fixtures.bases.CGDAIncentive(defaultOptions, {
93
+ asset: budgets.erc20.assertValidAddress(),
94
+ initialReward: 1n,
95
+ totalBudget: 10n,
96
+ rewardBoost: 1n,
97
+ rewardDecay: 1n,
98
+ });
99
+ const boost = await freshBoost(fixtures, {
100
+ budget: budgets.budget,
101
+ incentives: [erc20Incentive],
102
+ });
103
+
104
+ const claimant = trustedSigner.account;
105
+ const incentiveData = pad('0xdef456232173821931823712381232131391321934');
106
+ const incentiveQuantity = 1;
107
+ const claimDataPayload = await prepareSignerValidatorClaimDataPayload({
108
+ signer: trustedSigner,
109
+ incentiveData,
110
+ chainId: defaultOptions.config.chains[0].id,
111
+ validator: boost.validator.assertValidAddress(),
112
+ incentiveQuantity,
113
+ claimant,
114
+ boostId: boost.id,
115
+ });
116
+
117
+ await fixtures.core.claimIncentive(
118
+ boost.id,
119
+ 0n,
120
+ referrer,
121
+ claimDataPayload,
122
+ { value: parseEther('0.000075') },
123
+ );
124
+ try {
125
+ await fixtures.core.claimIncentive(
126
+ boost.id,
127
+ 0n,
128
+ referrer,
129
+ claimDataPayload,
130
+ { value: parseEther('0.000075') },
131
+ );
132
+ } catch (e) {
133
+ expect(e).toBeInstanceOf(Error);
134
+ }
135
+ });
136
+ });