diff --git a/packages/sdk/src/AllowLists/AllowList.ts b/packages/sdk/src/AllowLists/AllowList.ts index 0ce9c797..4baa2bc9 100644 --- a/packages/sdk/src/AllowLists/AllowList.ts +++ b/packages/sdk/src/AllowLists/AllowList.ts @@ -7,10 +7,11 @@ import { readContract } from '@wagmi/core'; import type { Address, Hex } from 'viem'; import type { DeployableOptions } from '../Deployable/Deployable'; import { InvalidComponentInterfaceError } from '../errors'; +import { OpenAllowList } from './OpenAllowList'; import { SimpleAllowList } from './SimpleAllowList'; import { SimpleDenyList } from './SimpleDenyList'; -export { SimpleAllowList, SimpleDenyList }; +export { OpenAllowList, SimpleAllowList, SimpleDenyList }; /** * A union type representing all valid protocol AllowList implementations @@ -18,7 +19,7 @@ export { SimpleAllowList, SimpleDenyList }; * @export * @typedef {AllowList} */ -export type AllowList = SimpleAllowList | SimpleDenyList; +export type AllowList = OpenAllowList | SimpleAllowList | SimpleDenyList; /** * A map of AllowList component interfaces to their constructors. @@ -32,6 +33,7 @@ export const AllowListByComponentInterface = { /** * A function that will read a contract's component interface using `getComponentInterface` and return the correct instantiated instance. + * This function will never return an instance of {@link OpenAllowList} because it has the same component interface as {@link SimpleDenyList} * * @export * @async @@ -56,5 +58,5 @@ export async function allowListFromAddress( interfaceId as Hex, ); } - return new Ctor(options, address); + return new Ctor(options, address) as SimpleDenyList | SimpleAllowList; } diff --git a/packages/sdk/src/AllowLists/OpenAllowList.test.ts b/packages/sdk/src/AllowLists/OpenAllowList.test.ts new file mode 100644 index 00000000..3862ca46 --- /dev/null +++ b/packages/sdk/src/AllowLists/OpenAllowList.test.ts @@ -0,0 +1,40 @@ +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers'; +import { isAddress, zeroAddress } from 'viem'; +import { beforeAll, describe, expect, test } from 'vitest'; +import { accounts } from '../../test/accounts'; +import { + type Fixtures, + defaultOptions, + deployFixtures, +} from '../../test/helpers'; +import { OpenAllowList } from './OpenAllowList'; + +let fixtures: Fixtures; + +beforeAll(async () => { + fixtures = await loadFixture(deployFixtures); +}); + +function freshOpenAllowList(fixtures: Fixtures) { + return function freshOpenAllowList() { + return fixtures.registry.clone( + crypto.randomUUID(), + new fixtures.bases.OpenAllowList(defaultOptions), + ); + }; +} + +describe('OpenAllowList', () => { + test('can successfully be deployed', async () => { + const denyList = new OpenAllowList(defaultOptions); + await denyList.deploy(); + expect(isAddress(denyList.assertValidAddress())).toBe(true); + }); + + test('allows anyone', async () => { + const denyList = await loadFixture(freshOpenAllowList(fixtures)); + expect(await denyList.isAllowed(defaultOptions.account.address)).toBe(true); + expect(await denyList.isAllowed(zeroAddress)).toBe(true); + expect(await denyList.isAllowed(accounts.at(1)!.account)).toBe(true); + }); +}); diff --git a/packages/sdk/src/AllowLists/OpenAllowList.ts b/packages/sdk/src/AllowLists/OpenAllowList.ts new file mode 100644 index 00000000..f60b32cb --- /dev/null +++ b/packages/sdk/src/AllowLists/OpenAllowList.ts @@ -0,0 +1,65 @@ +import { simpleDenyListAbi } from '@boostxyz/evm'; +import { bytecode } from '@boostxyz/evm/artifacts/contracts/allowlists/SimpleDenyList.sol/SimpleDenyList.json'; +import { type Address, type Hex, zeroAddress } from 'viem'; +import type { + DeployableOptions, + GenericDeployableParams, +} from '../Deployable/Deployable'; +import { RegistryType } from '../utils'; +import { + SimpleDenyList, + type SimpleDenyListPayload, + prepareSimpleDenyListPayload, +} from './SimpleDenyList'; + +export const openAllowListAbi = simpleDenyListAbi; + +/** + * A simple AllowList, extending {@link DenyList}, that is ownerless and allows anyone to claim. + * + * @export + * @class OpenAllowList + * @typedef {OpenAllowList} + * @extends {DeployableTarget} + */ +export class OpenAllowList extends SimpleDenyList { + public override readonly abi = openAllowListAbi; + /** + * @inheritdoc + * + * @public + * @static + * @type {Address} + */ + public static override base: Address = import.meta.env + .VITE_SIMPLE_DENYLIST_BASE; + /** + * @inheritdoc + * + * @public + * @static + * @type {RegistryType} + */ + public static override registryType: RegistryType = RegistryType.ALLOW_LIST; + + /** + * @inheritdoc + * + * @public + * @param {?SimpleDenyListPayload} [_payload] + * @param {?DeployableOptions} [_options] + * @returns {GenericDeployableParams} + */ + public override buildParameters( + _payload?: SimpleDenyListPayload, + _options?: DeployableOptions, + ): GenericDeployableParams { + const [_, options] = this.validateDeploymentConfig({}, _options); + return { + abi: openAllowListAbi, + bytecode: bytecode as Hex, + args: [prepareSimpleDenyListPayload({ owner: zeroAddress, denied: [] })], + ...this.optionallyAttachAccount(options.account), + }; + } +} diff --git a/packages/sdk/src/AllowLists/SimpleDenyList.ts b/packages/sdk/src/AllowLists/SimpleDenyList.ts index afbed500..3b18a2fd 100644 --- a/packages/sdk/src/AllowLists/SimpleDenyList.ts +++ b/packages/sdk/src/AllowLists/SimpleDenyList.ts @@ -74,10 +74,9 @@ export type SimpleDenyListLog< * @typedef {SimpleDenyList} * @extends {DeployableTarget} */ -export class SimpleDenyList extends DeployableTarget< - SimpleDenyListPayload, - typeof simpleDenyListAbi -> { +export class SimpleDenyList< + Payload = SimpleDenyListPayload, +> extends DeployableTarget { public override readonly abi = simpleDenyListAbi; /** * @inheritdoc @@ -177,13 +176,11 @@ export class SimpleDenyList extends DeployableTarget< * @returns {GenericDeployableParams} */ public override buildParameters( - _payload?: SimpleDenyListPayload, + _payload?: Payload, _options?: DeployableOptions, ): GenericDeployableParams { - const [payload, options] = this.validateDeploymentConfig( - _payload, - _options, - ); + const [p, options] = this.validateDeploymentConfig(_payload, _options); + const payload = p as SimpleDenyListPayload; if (!payload.owner || payload.owner === zeroAddress) { const owner = options.account ? options.account.address diff --git a/packages/sdk/src/BoostCore.ts b/packages/sdk/src/BoostCore.ts index 6c4af650..987c40ce 100644 --- a/packages/sdk/src/BoostCore.ts +++ b/packages/sdk/src/BoostCore.ts @@ -34,6 +34,7 @@ import { import { type Action, actionFromAddress } from './Actions/Action'; import { EventAction, type EventActionPayload } from './Actions/EventAction'; import { type AllowList, allowListFromAddress } from './AllowLists/AllowList'; +import { OpenAllowList } from './AllowLists/OpenAllowList'; import { SimpleAllowList, type SimpleAllowListPayload, @@ -1008,6 +1009,24 @@ export class BoostCore extends Deployable< // isBase, // ); // } + /** + * Bound {@link OpenAllowList} constructor that reuses the same configuration as the Boost Core instance. + * + * @example + * ```ts + * const list = core.OpenAllowList('0x') // is roughly equivalent to + * const list = new OpenAllowList({ config: core._config, account: core._account }, '0x') + * ``` + * @param {?boolean} [isBase] + * @returns {OpenAllowList} + */ + OpenAllowList(isBase?: boolean) { + return new OpenAllowList( + { config: this._config, account: this._account }, + undefined, + isBase, + ); + } /** * Bound {@link SimpleAllowList} constructor that reuses the same configuration as the Boost Core instance. * diff --git a/packages/sdk/src/Deployable/DeployableTarget.ts b/packages/sdk/src/Deployable/DeployableTarget.ts index d3b3ecb4..5d02d437 100644 --- a/packages/sdk/src/Deployable/DeployableTarget.ts +++ b/packages/sdk/src/Deployable/DeployableTarget.ts @@ -75,7 +75,7 @@ export class DeployableTarget< */ constructor( options: DeployableOptions, - payload: DeployablePayloadOrAddress, + payload?: DeployablePayloadOrAddress, isBase?: boolean, ) { super(options, payload); diff --git a/packages/sdk/test/helpers.ts b/packages/sdk/test/helpers.ts index f2e5ac95..ab4993c6 100644 --- a/packages/sdk/test/helpers.ts +++ b/packages/sdk/test/helpers.ts @@ -40,6 +40,7 @@ import { type EventActionPayload, FilterType, ManagedBudget, + OpenAllowList, PointsIncentive, type PointsIncentivePayload, PrimitiveType, @@ -299,6 +300,9 @@ export async function deployFixtures( SimpleDenyList: class TSimpleDenyList extends SimpleDenyList { public static override base = simpleDenyListBase; }, + OpenAllowList: class TOpenAllowList extends OpenAllowList { + public static override base = simpleDenyListBase; + }, SimpleBudget: class TSimpleBudget extends SimpleBudget { public static override base = simpleBudgetBase; },