@boostxyz/sdk 0.0.0-alpha.5 → 0.0.0-alpha.6
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.
- package/dist/Actions/Action.cjs +1 -0
- package/dist/Actions/Action.cjs.map +1 -0
- package/dist/Actions/Action.js +1 -0
- package/dist/Actions/Action.js.map +1 -0
- package/dist/Actions/EventAction.cjs +1 -0
- package/dist/Actions/EventAction.cjs.map +1 -0
- package/dist/Actions/EventAction.js +1 -0
- package/dist/Actions/EventAction.js.map +1 -0
- package/dist/AllowLists/AllowList.cjs +1 -0
- package/dist/AllowLists/AllowList.cjs.map +1 -0
- package/dist/AllowLists/AllowList.js +1 -0
- package/dist/AllowLists/AllowList.js.map +1 -0
- package/dist/AllowLists/SimpleAllowList.cjs +1 -0
- package/dist/AllowLists/SimpleAllowList.cjs.map +1 -0
- package/dist/AllowLists/SimpleAllowList.js +1 -0
- package/dist/AllowLists/SimpleAllowList.js.map +1 -0
- package/dist/AllowLists/SimpleDenyList.cjs +1 -0
- package/dist/AllowLists/SimpleDenyList.cjs.map +1 -0
- package/dist/AllowLists/SimpleDenyList.js +1 -0
- package/dist/AllowLists/SimpleDenyList.js.map +1 -0
- package/dist/Auth/Auth.cjs +1 -0
- package/dist/Auth/Auth.cjs.map +1 -0
- package/dist/Auth/Auth.js +1 -0
- package/dist/Auth/Auth.js.map +1 -0
- package/dist/Auth/PassthroughAuth.cjs +1 -0
- package/dist/Auth/PassthroughAuth.cjs.map +1 -0
- package/dist/Auth/PassthroughAuth.js +1 -0
- package/dist/Auth/PassthroughAuth.js.map +1 -0
- package/dist/Boost.cjs +1 -0
- package/dist/Boost.cjs.map +1 -0
- package/dist/Boost.js +1 -0
- package/dist/Boost.js.map +1 -0
- package/dist/BoostCore.cjs +1 -0
- package/dist/BoostCore.cjs.map +1 -0
- package/dist/BoostCore.js +1 -0
- package/dist/BoostCore.js.map +1 -0
- package/dist/BoostRegistry.cjs +1 -0
- package/dist/BoostRegistry.cjs.map +1 -0
- package/dist/BoostRegistry.js +1 -0
- package/dist/BoostRegistry.js.map +1 -0
- package/dist/Budgets/Budget.cjs +1 -0
- package/dist/Budgets/Budget.cjs.map +1 -0
- package/dist/Budgets/Budget.js +1 -0
- package/dist/Budgets/Budget.js.map +1 -0
- package/dist/Budgets/ManagedBudget.cjs +1 -0
- package/dist/Budgets/ManagedBudget.cjs.map +1 -0
- package/dist/Budgets/ManagedBudget.js +1 -0
- package/dist/Budgets/ManagedBudget.js.map +1 -0
- package/dist/Deployable/Contract.cjs +1 -0
- package/dist/Deployable/Contract.cjs.map +1 -0
- package/dist/Deployable/Contract.js +1 -0
- package/dist/Deployable/Contract.js.map +1 -0
- package/dist/Deployable/Deployable.cjs +1 -0
- package/dist/Deployable/Deployable.cjs.map +1 -0
- package/dist/Deployable/Deployable.js +1 -0
- package/dist/Deployable/Deployable.js.map +1 -0
- package/dist/Deployable/DeployableTarget.cjs +1 -0
- package/dist/Deployable/DeployableTarget.cjs.map +1 -0
- package/dist/Deployable/DeployableTarget.js +1 -0
- package/dist/Deployable/DeployableTarget.js.map +1 -0
- package/dist/Incentives/AllowListIncentive.cjs +1 -0
- package/dist/Incentives/AllowListIncentive.cjs.map +1 -0
- package/dist/Incentives/AllowListIncentive.js +1 -0
- package/dist/Incentives/AllowListIncentive.js.map +1 -0
- package/dist/Incentives/CGDAIncentive.cjs +1 -0
- package/dist/Incentives/CGDAIncentive.cjs.map +1 -0
- package/dist/Incentives/CGDAIncentive.js +1 -0
- package/dist/Incentives/CGDAIncentive.js.map +1 -0
- package/dist/Incentives/ERC20Incentive.cjs +1 -0
- package/dist/Incentives/ERC20Incentive.cjs.map +1 -0
- package/dist/Incentives/ERC20Incentive.js +1 -0
- package/dist/Incentives/ERC20Incentive.js.map +1 -0
- package/dist/Incentives/Incentive.cjs +1 -0
- package/dist/Incentives/Incentive.cjs.map +1 -0
- package/dist/Incentives/Incentive.js +1 -0
- package/dist/Incentives/Incentive.js.map +1 -0
- package/dist/Incentives/PointsIncentive.cjs +1 -0
- package/dist/Incentives/PointsIncentive.cjs.map +1 -0
- package/dist/Incentives/PointsIncentive.js +1 -0
- package/dist/Incentives/PointsIncentive.js.map +1 -0
- package/dist/Validators/SignerValidator.cjs +1 -0
- package/dist/Validators/SignerValidator.cjs.map +1 -0
- package/dist/Validators/SignerValidator.js +1 -0
- package/dist/Validators/SignerValidator.js.map +1 -0
- package/dist/Validators/Validator.cjs +1 -0
- package/dist/Validators/Validator.cjs.map +1 -0
- package/dist/Validators/Validator.js +1 -0
- package/dist/Validators/Validator.js.map +1 -0
- package/dist/componentInterfaces-CKCBwG16.cjs +1 -0
- package/dist/componentInterfaces-CKCBwG16.cjs.map +1 -0
- package/dist/componentInterfaces-DYkaxBda.js +1 -0
- package/dist/componentInterfaces-DYkaxBda.js.map +1 -0
- package/dist/errors.cjs +1 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.js +1 -0
- package/dist/errors.js.map +1 -0
- package/dist/generated-Cd-Fe7W7.cjs +1 -0
- package/dist/generated-Cd-Fe7W7.cjs.map +1 -0
- package/dist/generated-DGpIVcv5.js +1 -0
- package/dist/generated-DGpIVcv5.js.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -0
- package/dist/utils.cjs +1 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.js +1 -0
- package/dist/utils.js.map +1 -0
- package/package.json +3 -2
- package/src/Actions/Action.test.ts +77 -0
- package/src/Actions/Action.ts +61 -0
- package/src/Actions/ContractAction.test.ts +199 -0
- package/src/Actions/ContractAction.ts +238 -0
- package/src/Actions/ERC721MintAction.test.ts +112 -0
- package/src/Actions/ERC721MintAction.ts +238 -0
- package/src/Actions/EventAction.test.ts +182 -0
- package/src/Actions/EventAction.ts +382 -0
- package/src/AllowLists/AllowList.test.ts +64 -0
- package/src/AllowLists/AllowList.ts +60 -0
- package/src/AllowLists/SimpleAllowList.test.ts +52 -0
- package/src/AllowLists/SimpleAllowList.ts +240 -0
- package/src/AllowLists/SimpleDenyList.test.ts +52 -0
- package/src/AllowLists/SimpleDenyList.ts +289 -0
- package/src/Auth/Auth.ts +11 -0
- package/src/Auth/PassthroughAuth.test.ts +12 -0
- package/src/Auth/PassthroughAuth.ts +80 -0
- package/src/Boost.ts +155 -0
- package/src/BoostCore.test.ts +846 -0
- package/src/BoostCore.ts +1192 -0
- package/src/BoostRegistry.ts +449 -0
- package/src/Budgets/Budget.test.ts +27 -0
- package/src/Budgets/Budget.ts +61 -0
- package/src/Budgets/ManagedBudget.test.ts +154 -0
- package/src/Budgets/ManagedBudget.ts +743 -0
- package/src/Budgets/SimpleBudget.test.ts +152 -0
- package/src/Budgets/SimpleBudget.ts +521 -0
- package/src/Budgets/VestingBudget.test.ts +123 -0
- package/src/Budgets/VestingBudget.ts +532 -0
- package/src/Deployable/Contract.ts +229 -0
- package/src/Deployable/Deployable.ts +244 -0
- package/src/Deployable/DeployableTarget.ts +210 -0
- package/src/Incentives/AllowListIncentive.test.ts +146 -0
- package/src/Incentives/AllowListIncentive.ts +290 -0
- package/src/Incentives/CGDAIncentive.test.ts +136 -0
- package/src/Incentives/CGDAIncentive.ts +364 -0
- package/src/Incentives/ERC1155Incentive.test.ts +98 -0
- package/src/Incentives/ERC1155Incentive.ts +384 -0
- package/src/Incentives/ERC20Incentive.test.ts +141 -0
- package/src/Incentives/ERC20Incentive.ts +417 -0
- package/src/Incentives/ERC20VariableIncentive.test.ts +156 -0
- package/src/Incentives/ERC20VariableIncentive.ts +368 -0
- package/src/Incentives/Incentive.test.ts +92 -0
- package/src/Incentives/Incentive.ts +85 -0
- package/src/Incentives/PointsIncentive.test.ts +142 -0
- package/src/Incentives/PointsIncentive.ts +303 -0
- package/src/Validators/SignerValidator.test.ts +163 -0
- package/src/Validators/SignerValidator.ts +272 -0
- package/src/Validators/Validator.test.ts +21 -0
- package/src/Validators/Validator.ts +55 -0
- package/src/errors.ts +524 -0
- package/src/index.test.ts +40 -0
- package/src/index.ts +50 -0
- package/src/utils.test.ts +44 -0
- package/src/utils.ts +2247 -0
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
import {
|
|
2
|
+
eventActionAbi,
|
|
3
|
+
readEventActionGetActionClaimant,
|
|
4
|
+
readEventActionGetActionStep,
|
|
5
|
+
readEventActionGetActionSteps,
|
|
6
|
+
readEventActionGetActionStepsCount,
|
|
7
|
+
simulateEventActionExecute,
|
|
8
|
+
writeEventActionExecute,
|
|
9
|
+
} from '@boostxyz/evm';
|
|
10
|
+
import { bytecode } from '@boostxyz/evm/artifacts/contracts/actions/EventAction.sol/EventAction.json';
|
|
11
|
+
import events from '@boostxyz/signatures/events';
|
|
12
|
+
import {
|
|
13
|
+
type Abi,
|
|
14
|
+
type AbiEvent,
|
|
15
|
+
type Address,
|
|
16
|
+
type ContractEventName,
|
|
17
|
+
type Hex,
|
|
18
|
+
type Log,
|
|
19
|
+
isAddressEqual,
|
|
20
|
+
} from 'viem';
|
|
21
|
+
import { getLogs } from 'viem/actions';
|
|
22
|
+
import type {
|
|
23
|
+
DeployableOptions,
|
|
24
|
+
GenericDeployableParams,
|
|
25
|
+
} from '../Deployable/Deployable';
|
|
26
|
+
import { DeployableTarget } from '../Deployable/DeployableTarget';
|
|
27
|
+
import {
|
|
28
|
+
FieldValueNotComparableError,
|
|
29
|
+
FieldValueUndefinedError,
|
|
30
|
+
InvalidNumericalCriteriaError,
|
|
31
|
+
NoEventActionStepsProvidedError,
|
|
32
|
+
TooManyEventActionStepsProvidedError,
|
|
33
|
+
UnrecognizedFilterTypeError,
|
|
34
|
+
} from '../errors';
|
|
35
|
+
import {
|
|
36
|
+
type ActionClaimant,
|
|
37
|
+
type ActionStep,
|
|
38
|
+
type Criteria,
|
|
39
|
+
type EventActionPayload,
|
|
40
|
+
type EventActionPayloadRaw,
|
|
41
|
+
FilterType,
|
|
42
|
+
type GetLogsParams,
|
|
43
|
+
PrimitiveType,
|
|
44
|
+
type ReadParams,
|
|
45
|
+
RegistryType,
|
|
46
|
+
type WriteParams,
|
|
47
|
+
dedupeActionSteps,
|
|
48
|
+
isEventActionPayloadSimple,
|
|
49
|
+
prepareEventActionPayload,
|
|
50
|
+
} from '../utils';
|
|
51
|
+
|
|
52
|
+
export type { EventActionPayload };
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* A generic event action
|
|
56
|
+
*
|
|
57
|
+
* @export
|
|
58
|
+
* @class EventAction
|
|
59
|
+
* @typedef {EventAction}
|
|
60
|
+
* @extends {DeployableTarget<EventActionPayload>}
|
|
61
|
+
*/
|
|
62
|
+
export class EventAction extends DeployableTarget<
|
|
63
|
+
EventActionPayload,
|
|
64
|
+
typeof eventActionAbi
|
|
65
|
+
> {
|
|
66
|
+
/**
|
|
67
|
+
* @inheritdoc
|
|
68
|
+
*
|
|
69
|
+
* @public
|
|
70
|
+
* @readonly
|
|
71
|
+
* @type {*}
|
|
72
|
+
*/
|
|
73
|
+
public override readonly abi = eventActionAbi;
|
|
74
|
+
/**
|
|
75
|
+
* @inheritdoc
|
|
76
|
+
*
|
|
77
|
+
* @public
|
|
78
|
+
* @static
|
|
79
|
+
* @type {Address}
|
|
80
|
+
*/
|
|
81
|
+
public static override base: Address = import.meta.env.VITE_EVENT_ACTION_BASE;
|
|
82
|
+
/**
|
|
83
|
+
* @inheritdoc
|
|
84
|
+
*
|
|
85
|
+
* @public
|
|
86
|
+
* @static
|
|
87
|
+
* @type {RegistryType}
|
|
88
|
+
*/
|
|
89
|
+
public static override registryType: RegistryType = RegistryType.ACTION;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Gets a specific action event by index
|
|
93
|
+
*
|
|
94
|
+
* @public
|
|
95
|
+
* @async
|
|
96
|
+
* @param {number} index The index of the action event to retrieve
|
|
97
|
+
* @param {?ReadParams<typeof eventActionAbi, 'getActionStep'>} [params]
|
|
98
|
+
* @returns {Promise<ActionStep>}
|
|
99
|
+
*/
|
|
100
|
+
public async getActionStep(
|
|
101
|
+
index: number,
|
|
102
|
+
params?: ReadParams<typeof eventActionAbi, 'getActionStep'>,
|
|
103
|
+
) {
|
|
104
|
+
const steps = await this.getActionSteps(params);
|
|
105
|
+
return steps.at(index);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Gets all action events
|
|
110
|
+
*
|
|
111
|
+
* @public
|
|
112
|
+
* @async
|
|
113
|
+
* @param {?ReadParams<typeof eventActionAbi, 'getActionSteps'>} [params]
|
|
114
|
+
* @returns {Promise<ActionStep[]>}
|
|
115
|
+
*/
|
|
116
|
+
public async getActionSteps(
|
|
117
|
+
params?: ReadParams<typeof eventActionAbi, 'getActionSteps'>,
|
|
118
|
+
) {
|
|
119
|
+
const steps = (await readEventActionGetActionSteps(this._config, {
|
|
120
|
+
address: this.assertValidAddress(),
|
|
121
|
+
...this.optionallyAttachAccount(),
|
|
122
|
+
// biome-ignore lint/suspicious/noExplicitAny: Accept any shape of valid wagmi/viem parameters, wagmi does the same thing internally
|
|
123
|
+
...(params as any),
|
|
124
|
+
})) as ActionStep[];
|
|
125
|
+
return dedupeActionSteps(steps);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Gets the count of action events
|
|
130
|
+
*
|
|
131
|
+
* @public
|
|
132
|
+
* @async
|
|
133
|
+
* @param {?ReadParams<typeof eventActionAbi, 'getActionStepsCount'>} [params]
|
|
134
|
+
* @returns {Promise<bigint>}
|
|
135
|
+
*/
|
|
136
|
+
public async getActionStepsCount(
|
|
137
|
+
params?: ReadParams<typeof eventActionAbi, 'getActionStepsCount'>,
|
|
138
|
+
) {
|
|
139
|
+
const steps = await this.getActionSteps(params);
|
|
140
|
+
return steps.length;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Retrieves the payload describing how claimants can be identified from logs or function calls.
|
|
145
|
+
*
|
|
146
|
+
* @public
|
|
147
|
+
* @async
|
|
148
|
+
* @param {?ReadParams<typeof eventActionAbi, 'getActionClaimant'>} [params]
|
|
149
|
+
* @returns {Promise<ActionClaimant>}
|
|
150
|
+
*/
|
|
151
|
+
public async getActionClaimant(
|
|
152
|
+
params?: ReadParams<typeof eventActionAbi, 'getActionClaimant'>,
|
|
153
|
+
) {
|
|
154
|
+
return readEventActionGetActionClaimant(this._config, {
|
|
155
|
+
address: this.assertValidAddress(),
|
|
156
|
+
...this.optionallyAttachAccount(),
|
|
157
|
+
// biome-ignore lint/suspicious/noExplicitAny: Accept any shape of valid wagmi/viem parameters, wagmi does the same thing internally
|
|
158
|
+
...(params as any),
|
|
159
|
+
}) as Promise<ActionClaimant>;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Executes a prepared event action
|
|
164
|
+
*
|
|
165
|
+
* @public
|
|
166
|
+
* @async
|
|
167
|
+
* @param {Hex} data
|
|
168
|
+
* @param {?WriteParams<typeof eventActionAbi, 'execute'>} [params]
|
|
169
|
+
* @returns {Promise<readonly [boolean, `0x${string}`]>}
|
|
170
|
+
*/
|
|
171
|
+
public async execute(
|
|
172
|
+
data: Hex,
|
|
173
|
+
params?: WriteParams<typeof eventActionAbi, 'execute'>,
|
|
174
|
+
) {
|
|
175
|
+
return this.awaitResult(this.executeRaw(data, params));
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Executes a prepared event action
|
|
180
|
+
*
|
|
181
|
+
* @public
|
|
182
|
+
* @async
|
|
183
|
+
* @param {Hex} data
|
|
184
|
+
* @param {?WriteParams<typeof eventActionAbi, 'execute'>} [params]
|
|
185
|
+
* @returns {unknown}
|
|
186
|
+
*/
|
|
187
|
+
public async executeRaw(
|
|
188
|
+
data: Hex,
|
|
189
|
+
params?: WriteParams<typeof eventActionAbi, 'execute'>,
|
|
190
|
+
) {
|
|
191
|
+
const { request, result } = await simulateEventActionExecute(this._config, {
|
|
192
|
+
address: this.assertValidAddress(),
|
|
193
|
+
...this.optionallyAttachAccount(),
|
|
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
|
+
args: [data],
|
|
197
|
+
});
|
|
198
|
+
const hash = await writeEventActionExecute(this._config, request);
|
|
199
|
+
return { hash, result };
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Retrieves action steps, and uses them to validate against, and optionally fetch logs that match the step's signature.
|
|
204
|
+
* If logs are provided in the optional `params` argument, then those logs will be used instead of fetched with the configured client.
|
|
205
|
+
*
|
|
206
|
+
* @public
|
|
207
|
+
* @async
|
|
208
|
+
* @param {?ReadParams<typeof eventActionAbi, 'getActionSteps'> &
|
|
209
|
+
* GetLogsParams<Abi, ContractEventName<Abi>> & {
|
|
210
|
+
* knownEvents?: Record<Hex, AbiEvent>;
|
|
211
|
+
* logs?: Log[];
|
|
212
|
+
* }} [params]
|
|
213
|
+
* @returns {Promise<boolean>}
|
|
214
|
+
*/
|
|
215
|
+
public async validateActionSteps(
|
|
216
|
+
params?: ReadParams<typeof eventActionAbi, 'getActionSteps'> &
|
|
217
|
+
GetLogsParams<Abi, ContractEventName<Abi>> & {
|
|
218
|
+
knownEvents?: Record<Hex, AbiEvent>;
|
|
219
|
+
logs?: Log[];
|
|
220
|
+
},
|
|
221
|
+
) {
|
|
222
|
+
const actionSteps = await this.getActionSteps(params);
|
|
223
|
+
for (const actionStep of actionSteps) {
|
|
224
|
+
if (!(await this.isActionStepValid(actionStep, params))) {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Validates a single action step with a given criteria against logs.
|
|
233
|
+
* If logs are provided in the optional `params` argument, then those logs will be used instead of fetched with the configured client.
|
|
234
|
+
*
|
|
235
|
+
* @public
|
|
236
|
+
* @async
|
|
237
|
+
* @param {ActionStep} actionStep
|
|
238
|
+
* @param {?GetLogsParams<Abi, ContractEventName<Abi>> & {
|
|
239
|
+
* knownEvents?: Record<Hex, AbiEvent>;
|
|
240
|
+
* logs?: Log[];
|
|
241
|
+
* }} [params]
|
|
242
|
+
* @returns {Promise<boolean>}
|
|
243
|
+
*/
|
|
244
|
+
public async isActionStepValid(
|
|
245
|
+
actionStep: ActionStep,
|
|
246
|
+
params?: GetLogsParams<Abi, ContractEventName<Abi>> & {
|
|
247
|
+
knownEvents?: Record<Hex, AbiEvent>;
|
|
248
|
+
logs?: Log[];
|
|
249
|
+
},
|
|
250
|
+
) {
|
|
251
|
+
const criteria = actionStep.actionParameter;
|
|
252
|
+
const signature = actionStep.signature;
|
|
253
|
+
let event: AbiEvent;
|
|
254
|
+
// Lookup ABI based on event signature
|
|
255
|
+
if (params?.knownEvents) {
|
|
256
|
+
event = params.knownEvents[signature] as AbiEvent;
|
|
257
|
+
} else {
|
|
258
|
+
event = (events.abi as Record<Hex, AbiEvent>)[signature] as AbiEvent;
|
|
259
|
+
}
|
|
260
|
+
if (!event) {
|
|
261
|
+
throw new Error(`No known ABI for given event signature: ${signature}`);
|
|
262
|
+
}
|
|
263
|
+
const targetContract = actionStep.targetContract;
|
|
264
|
+
// Get all logs matching the event signature from the target contract
|
|
265
|
+
const logs =
|
|
266
|
+
params?.logs ||
|
|
267
|
+
(await getLogs(this._config.getClient({ chainId: params?.chainId }), {
|
|
268
|
+
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
269
|
+
...(params as any),
|
|
270
|
+
address: targetContract,
|
|
271
|
+
event,
|
|
272
|
+
}));
|
|
273
|
+
if (!logs.length) return false;
|
|
274
|
+
for (let log of logs) {
|
|
275
|
+
if (!this.validateLogAgainstCriteria(criteria, log)) {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Validates a {@link Log} against a given criteria.
|
|
284
|
+
*
|
|
285
|
+
* @param {Criteria} criteria - The criteria to validate against.
|
|
286
|
+
* @param {Log} log - The Viem event log.
|
|
287
|
+
* @returns {Promise<boolean>} - Returns true if the log passes the criteria, false otherwise.
|
|
288
|
+
*/
|
|
289
|
+
public async validateLogAgainstCriteria(criteria: Criteria, log: Log) {
|
|
290
|
+
const fieldValue = log.topics.at(criteria.fieldIndex);
|
|
291
|
+
if (fieldValue === undefined) {
|
|
292
|
+
throw new FieldValueUndefinedError({ log, criteria, fieldValue });
|
|
293
|
+
}
|
|
294
|
+
// Type narrow based on criteria.filterType
|
|
295
|
+
switch (criteria.filterType) {
|
|
296
|
+
case FilterType.EQUAL:
|
|
297
|
+
if (criteria.fieldType === PrimitiveType.ADDRESS) {
|
|
298
|
+
return isAddressEqual(
|
|
299
|
+
criteria.filterData,
|
|
300
|
+
`0x${fieldValue.slice(-40)}`,
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
return fieldValue === criteria.filterData;
|
|
304
|
+
|
|
305
|
+
case FilterType.NOT_EQUAL:
|
|
306
|
+
return fieldValue !== criteria.filterData;
|
|
307
|
+
|
|
308
|
+
case FilterType.GREATER_THAN:
|
|
309
|
+
if (criteria.fieldType === PrimitiveType.UINT) {
|
|
310
|
+
return BigInt(fieldValue) > BigInt(criteria.filterData);
|
|
311
|
+
}
|
|
312
|
+
throw new InvalidNumericalCriteriaError({ log, criteria, fieldValue });
|
|
313
|
+
|
|
314
|
+
case FilterType.LESS_THAN:
|
|
315
|
+
if (criteria.fieldType === PrimitiveType.UINT) {
|
|
316
|
+
return BigInt(fieldValue) < BigInt(criteria.filterData);
|
|
317
|
+
}
|
|
318
|
+
throw new InvalidNumericalCriteriaError({ log, criteria, fieldValue });
|
|
319
|
+
|
|
320
|
+
case FilterType.CONTAINS:
|
|
321
|
+
if (
|
|
322
|
+
criteria.fieldType === PrimitiveType.BYTES ||
|
|
323
|
+
criteria.fieldType === PrimitiveType.STRING
|
|
324
|
+
) {
|
|
325
|
+
return fieldValue.includes(criteria.filterData);
|
|
326
|
+
}
|
|
327
|
+
throw new FieldValueNotComparableError({ log, criteria, fieldValue });
|
|
328
|
+
|
|
329
|
+
default:
|
|
330
|
+
throw new UnrecognizedFilterTypeError({ log, criteria, fieldValue });
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* @inheritdoc
|
|
336
|
+
*
|
|
337
|
+
* @public
|
|
338
|
+
* @param {?EventActionPayload} [_payload]
|
|
339
|
+
* @param {?DeployableOptions} [_options]
|
|
340
|
+
* @returns {GenericDeployableParams}
|
|
341
|
+
*/
|
|
342
|
+
public override buildParameters(
|
|
343
|
+
_payload?: EventActionPayload,
|
|
344
|
+
_options?: DeployableOptions,
|
|
345
|
+
): GenericDeployableParams {
|
|
346
|
+
const [payload, options] = this.validateDeploymentConfig(
|
|
347
|
+
_payload,
|
|
348
|
+
_options,
|
|
349
|
+
);
|
|
350
|
+
let rawPayload: EventActionPayloadRaw;
|
|
351
|
+
if (isEventActionPayloadSimple(payload)) {
|
|
352
|
+
// filter out any falsy potential values
|
|
353
|
+
let tmpSteps = payload.actionSteps.filter((step) => !!step);
|
|
354
|
+
if (tmpSteps.length === 0) {
|
|
355
|
+
throw new NoEventActionStepsProvidedError();
|
|
356
|
+
}
|
|
357
|
+
if (tmpSteps.length > 4) {
|
|
358
|
+
throw new TooManyEventActionStepsProvidedError();
|
|
359
|
+
}
|
|
360
|
+
let steps: ActionStep[] = Array.from({ length: 4 }, (_, i) => {
|
|
361
|
+
// use either the provided step at the given index, or reuse the previous step
|
|
362
|
+
// should aways exist
|
|
363
|
+
return tmpSteps.at(i)! || tmpSteps.slice(0, i).at(-1)!;
|
|
364
|
+
});
|
|
365
|
+
rawPayload = {
|
|
366
|
+
actionClaimant: payload.actionClaimant,
|
|
367
|
+
actionStepOne: steps.at(0)!,
|
|
368
|
+
actionStepTwo: steps.at(1)!,
|
|
369
|
+
actionStepThree: steps.at(2)!,
|
|
370
|
+
actionStepFour: steps.at(3)!,
|
|
371
|
+
};
|
|
372
|
+
} else {
|
|
373
|
+
rawPayload = payload;
|
|
374
|
+
}
|
|
375
|
+
return {
|
|
376
|
+
abi: eventActionAbi,
|
|
377
|
+
bytecode: bytecode as Hex,
|
|
378
|
+
args: [prepareEventActionPayload(rawPayload)],
|
|
379
|
+
...this.optionallyAttachAccount(options.account),
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { loadFixture } from '@nomicfoundation/hardhat-network-helpers';
|
|
2
|
+
import { beforeAll, describe, expect, test } from 'vitest';
|
|
3
|
+
import {
|
|
4
|
+
type Fixtures,
|
|
5
|
+
defaultOptions,
|
|
6
|
+
deployFixtures,
|
|
7
|
+
} from '../../test/helpers';
|
|
8
|
+
import {
|
|
9
|
+
SimpleAllowList,
|
|
10
|
+
SimpleDenyList,
|
|
11
|
+
allowListFromAddress,
|
|
12
|
+
} from './AllowList';
|
|
13
|
+
|
|
14
|
+
let fixtures: Fixtures;
|
|
15
|
+
|
|
16
|
+
beforeAll(async () => {
|
|
17
|
+
fixtures = await loadFixture(deployFixtures);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
function freshAllowList(fixtures: Fixtures) {
|
|
21
|
+
return function freshAllowList() {
|
|
22
|
+
return fixtures.registry.clone(
|
|
23
|
+
crypto.randomUUID(),
|
|
24
|
+
new fixtures.bases.SimpleAllowList(defaultOptions, {
|
|
25
|
+
owner: defaultOptions.account.address,
|
|
26
|
+
allowed: [defaultOptions.account.address],
|
|
27
|
+
}),
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function freshDenyList(fixtures: Fixtures) {
|
|
33
|
+
return function freshDenyList() {
|
|
34
|
+
return fixtures.registry.clone(
|
|
35
|
+
crypto.randomUUID(),
|
|
36
|
+
new fixtures.bases.SimpleDenyList(defaultOptions, {
|
|
37
|
+
owner: defaultOptions.account.address,
|
|
38
|
+
denied: [defaultOptions.account.address],
|
|
39
|
+
}),
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
describe('AllowList', () => {
|
|
45
|
+
test('can automatically instantiate SimpleAllowList given an address', async () => {
|
|
46
|
+
const _allowList = await loadFixture(freshAllowList(fixtures));
|
|
47
|
+
expect(
|
|
48
|
+
await allowListFromAddress(
|
|
49
|
+
defaultOptions,
|
|
50
|
+
_allowList.assertValidAddress(),
|
|
51
|
+
),
|
|
52
|
+
).toBeInstanceOf(SimpleAllowList);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('can automatically instantiate SimpleAllowList given an address', async () => {
|
|
56
|
+
const _allowList = await loadFixture(freshDenyList(fixtures));
|
|
57
|
+
expect(
|
|
58
|
+
await allowListFromAddress(
|
|
59
|
+
defaultOptions,
|
|
60
|
+
_allowList.assertValidAddress(),
|
|
61
|
+
),
|
|
62
|
+
).toBeInstanceOf(SimpleDenyList);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { aAllowListAbi } from '@boostxyz/evm';
|
|
2
|
+
import {
|
|
3
|
+
ASimpleAllowList,
|
|
4
|
+
ASimpleDenyList,
|
|
5
|
+
} from '@boostxyz/evm/deploys/componentInterfaces.json';
|
|
6
|
+
import { readContract } from '@wagmi/core';
|
|
7
|
+
import type { Address, Hex } from 'viem';
|
|
8
|
+
import type { DeployableOptions } from '../Deployable/Deployable';
|
|
9
|
+
import { InvalidComponentInterfaceError } from '../errors';
|
|
10
|
+
import { SimpleAllowList } from './SimpleAllowList';
|
|
11
|
+
import { SimpleDenyList } from './SimpleDenyList';
|
|
12
|
+
|
|
13
|
+
export { SimpleAllowList, SimpleDenyList };
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A union type representing all valid protocol AllowList implementations
|
|
17
|
+
*
|
|
18
|
+
* @export
|
|
19
|
+
* @typedef {AllowList}
|
|
20
|
+
*/
|
|
21
|
+
export type AllowList = SimpleAllowList | SimpleDenyList;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A map of AllowList component interfaces to their constructors.
|
|
25
|
+
*
|
|
26
|
+
* @type {{ "0x2bc9016b": SimpleAllowList; "0x9d585f63": SimpleDenyList; }}
|
|
27
|
+
*/
|
|
28
|
+
export const AllowListByComponentInterface = {
|
|
29
|
+
[ASimpleAllowList as Hex]: SimpleAllowList,
|
|
30
|
+
[ASimpleDenyList as Hex]: SimpleDenyList,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A function that will read a contract's component interface using `getComponentInterface` and return the correct instantiated instance.
|
|
35
|
+
*
|
|
36
|
+
* @export
|
|
37
|
+
* @async
|
|
38
|
+
* @param {DeployableOptions} options
|
|
39
|
+
* @param {Address} address
|
|
40
|
+
* @returns {Promise<SimpleAllowList | SimpleDenyList>}
|
|
41
|
+
* @throws {@link InvalidComponentInterfaceError}
|
|
42
|
+
*/
|
|
43
|
+
export async function allowListFromAddress(
|
|
44
|
+
options: DeployableOptions,
|
|
45
|
+
address: Address,
|
|
46
|
+
) {
|
|
47
|
+
const interfaceId = (await readContract(options.config, {
|
|
48
|
+
abi: aAllowListAbi,
|
|
49
|
+
functionName: 'getComponentInterface',
|
|
50
|
+
address,
|
|
51
|
+
})) as keyof typeof AllowListByComponentInterface;
|
|
52
|
+
const Ctor = AllowListByComponentInterface[interfaceId];
|
|
53
|
+
if (!Ctor) {
|
|
54
|
+
throw new InvalidComponentInterfaceError(
|
|
55
|
+
Object.keys(AllowListByComponentInterface) as Hex[],
|
|
56
|
+
interfaceId as Hex,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return new Ctor(options, address);
|
|
60
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { loadFixture } from '@nomicfoundation/hardhat-network-helpers';
|
|
2
|
+
import { isAddress, zeroAddress } from 'viem';
|
|
3
|
+
import { beforeAll, describe, expect, test } from 'vitest';
|
|
4
|
+
import {
|
|
5
|
+
type Fixtures,
|
|
6
|
+
defaultOptions,
|
|
7
|
+
deployFixtures,
|
|
8
|
+
} from '../../test/helpers';
|
|
9
|
+
import { SimpleAllowList } from './SimpleAllowList';
|
|
10
|
+
|
|
11
|
+
let fixtures: Fixtures;
|
|
12
|
+
|
|
13
|
+
beforeAll(async () => {
|
|
14
|
+
fixtures = await loadFixture(deployFixtures);
|
|
15
|
+
});
|
|
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: [defaultOptions.account.address],
|
|
24
|
+
}),
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe('SimpleAllowList', () => {
|
|
30
|
+
test('can successfully be deployed', async () => {
|
|
31
|
+
const allowList = new SimpleAllowList(defaultOptions, {
|
|
32
|
+
owner: defaultOptions.account.address,
|
|
33
|
+
allowed: [],
|
|
34
|
+
});
|
|
35
|
+
await allowList.deploy();
|
|
36
|
+
expect(isAddress(allowList.assertValidAddress())).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('can check is allowed', async () => {
|
|
40
|
+
const allowList = await loadFixture(freshAllowList(fixtures));
|
|
41
|
+
expect(await allowList.isAllowed(defaultOptions.account.address)).toBe(
|
|
42
|
+
true,
|
|
43
|
+
);
|
|
44
|
+
expect(await allowList.isAllowed(zeroAddress)).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('can set allowed', async () => {
|
|
48
|
+
const allowList = await loadFixture(freshAllowList(fixtures));
|
|
49
|
+
await allowList.setAllowed([zeroAddress], [true]);
|
|
50
|
+
expect(await allowList.isAllowed(zeroAddress)).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
});
|