Skip to content

Commit 382d7e6

Browse files
committed
test(security): migrate Allowlist suite to async simulator
The merge of OpenZeppelin#620 moved every unit suite to the async, backend-aware @openzeppelin/compact-simulator@0.2.0 API, but the Allowlist suite added on this branch still used the synchronous createSimulator path, so its spec fails to load against 0.2.0 and breaks the test workflow on OpenZeppelin#625. * AllowlistSimulator: drop the sync constructor for `static async create`, add `artifactName: 'MockAllowlist'`, and return `Promise<R>` from every impure pass-through (assertAllowed/allow/disallow return `Promise<[]>`, isAllowed returns `Promise<boolean>`). * Allowlist.test.ts: create the simulator in the async `beforeEach`, await every circuit call and `getPublicState`, and assert the not-allowed path with `await expect(...).rejects.toThrow(...)`. No behavioral change; mechanical, mirrors the OpenZeppelin#620 migration pattern.
1 parent d4d6c74 commit 382d7e6

2 files changed

Lines changed: 75 additions & 69 deletions

File tree

contracts/src/security/test/Allowlist.test.ts

Lines changed: 61 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -14,110 +14,114 @@ const BOB = account('BOB');
1414
let allowlist: AllowlistSimulator;
1515

1616
describe('Allowlist', () => {
17-
beforeEach(() => {
18-
allowlist = new AllowlistSimulator();
17+
beforeEach(async () => {
18+
allowlist = await AllowlistSimulator.create();
1919
});
2020

2121
describe('default state', () => {
22-
it('is empty: no account is allowed', () => {
23-
expect(allowlist.isAllowed(ALICE)).toBe(false);
24-
expect(allowlist.isAllowed(BOB)).toBe(false);
22+
it('is empty: no account is allowed', async () => {
23+
expect(await allowlist.isAllowed(ALICE)).toBe(false);
24+
expect(await allowlist.isAllowed(BOB)).toBe(false);
2525
});
2626

27-
it('assertAllowed throws for a non-member', () => {
28-
expect(() => allowlist.assertAllowed(ALICE)).toThrow(
27+
it('assertAllowed throws for a non-member', async () => {
28+
await expect(allowlist.assertAllowed(ALICE)).rejects.toThrow(
2929
'Allowlist: account not allowed',
3030
);
3131
});
3232
});
3333

3434
describe('allow', () => {
35-
it('adds an account to the allowlist', () => {
36-
allowlist.allow(ALICE);
37-
expect(allowlist.isAllowed(ALICE)).toBe(true);
35+
it('adds an account to the allowlist', async () => {
36+
await allowlist.allow(ALICE);
37+
expect(await allowlist.isAllowed(ALICE)).toBe(true);
3838
});
3939

40-
it('does not affect other accounts', () => {
41-
allowlist.allow(ALICE);
42-
expect(allowlist.isAllowed(BOB)).toBe(false);
40+
it('does not affect other accounts', async () => {
41+
await allowlist.allow(ALICE);
42+
expect(await allowlist.isAllowed(BOB)).toBe(false);
4343
});
4444

45-
it('assertAllowed passes for a member', () => {
46-
allowlist.allow(ALICE);
47-
expect(() => allowlist.assertAllowed(ALICE)).not.toThrow();
45+
it('assertAllowed passes for a member', async () => {
46+
await allowlist.allow(ALICE);
47+
await allowlist.assertAllowed(ALICE);
4848
});
4949

50-
it('is idempotent', () => {
51-
allowlist.allow(ALICE);
52-
allowlist.allow(ALICE);
53-
expect(allowlist.isAllowed(ALICE)).toBe(true);
50+
it('is idempotent', async () => {
51+
await allowlist.allow(ALICE);
52+
await allowlist.allow(ALICE);
53+
expect(await allowlist.isAllowed(ALICE)).toBe(true);
5454
});
5555

56-
it('clears with a single disallow after being allowed multiple times', () => {
57-
allowlist.allow(ALICE);
58-
allowlist.allow(ALICE);
59-
expect(allowlist.isAllowed(ALICE)).toBe(true);
60-
allowlist.disallow(ALICE);
56+
it('clears with a single disallow after being allowed multiple times', async () => {
57+
await allowlist.allow(ALICE);
58+
await allowlist.allow(ALICE);
59+
expect(await allowlist.isAllowed(ALICE)).toBe(true);
60+
await allowlist.disallow(ALICE);
6161
// Membership is binary, not a counter: one disallow clears it regardless
6262
// of how many times it was allowed.
63-
expect(allowlist.isAllowed(ALICE)).toBe(false);
63+
expect(await allowlist.isAllowed(ALICE)).toBe(false);
6464
});
6565
});
6666

6767
describe('disallow', () => {
68-
it('removes an account from the allowlist', () => {
69-
allowlist.allow(ALICE);
70-
allowlist.disallow(ALICE);
71-
expect(allowlist.isAllowed(ALICE)).toBe(false);
68+
it('removes an account from the allowlist', async () => {
69+
await allowlist.allow(ALICE);
70+
await allowlist.disallow(ALICE);
71+
expect(await allowlist.isAllowed(ALICE)).toBe(false);
7272
});
7373

74-
it('assertAllowed throws again after disallow', () => {
75-
allowlist.allow(ALICE);
76-
allowlist.disallow(ALICE);
77-
expect(() => allowlist.assertAllowed(ALICE)).toThrow(
74+
it('assertAllowed throws again after disallow', async () => {
75+
await allowlist.allow(ALICE);
76+
await allowlist.disallow(ALICE);
77+
await expect(allowlist.assertAllowed(ALICE)).rejects.toThrow(
7878
'Allowlist: account not allowed',
7979
);
8080
});
8181

82-
it('is a no-op for a non-member', () => {
83-
allowlist.disallow(BOB);
84-
expect(allowlist.isAllowed(BOB)).toBe(false);
82+
it('is a no-op for a non-member', async () => {
83+
await allowlist.disallow(BOB);
84+
expect(await allowlist.isAllowed(BOB)).toBe(false);
8585
});
8686
});
8787

8888
describe('multiple operations', () => {
89-
it('handles allow -> disallow -> allow', () => {
90-
allowlist.allow(ALICE);
91-
expect(allowlist.isAllowed(ALICE)).toBe(true);
89+
it('handles allow -> disallow -> allow', async () => {
90+
await allowlist.allow(ALICE);
91+
expect(await allowlist.isAllowed(ALICE)).toBe(true);
9292

93-
allowlist.disallow(ALICE);
94-
expect(allowlist.isAllowed(ALICE)).toBe(false);
93+
await allowlist.disallow(ALICE);
94+
expect(await allowlist.isAllowed(ALICE)).toBe(false);
9595

96-
allowlist.allow(ALICE);
97-
expect(allowlist.isAllowed(ALICE)).toBe(true);
96+
await allowlist.allow(ALICE);
97+
expect(await allowlist.isAllowed(ALICE)).toBe(true);
9898
});
9999

100-
it('tracks several accounts independently', () => {
101-
allowlist.allow(ALICE);
102-
expect(allowlist.isAllowed(ALICE)).toBe(true);
103-
expect(allowlist.isAllowed(BOB)).toBe(false);
100+
it('tracks several accounts independently', async () => {
101+
await allowlist.allow(ALICE);
102+
expect(await allowlist.isAllowed(ALICE)).toBe(true);
103+
expect(await allowlist.isAllowed(BOB)).toBe(false);
104104

105-
allowlist.allow(BOB);
106-
allowlist.disallow(ALICE);
107-
expect(allowlist.isAllowed(ALICE)).toBe(false);
108-
expect(allowlist.isAllowed(BOB)).toBe(true);
105+
await allowlist.allow(BOB);
106+
await allowlist.disallow(ALICE);
107+
expect(await allowlist.isAllowed(ALICE)).toBe(false);
108+
expect(await allowlist.isAllowed(BOB)).toBe(true);
109109
});
110110
});
111111

112112
describe('simulator wiring', () => {
113-
it('exposes the public ledger via getPublicState', () => {
114-
const sim = new AllowlistSimulator();
113+
it('exposes the public ledger via getPublicState', async () => {
114+
const sim = await AllowlistSimulator.create();
115115

116-
expect(sim.getPublicState().Allowlist__allowed.member(ALICE)).toBe(false);
116+
expect(
117+
(await sim.getPublicState()).Allowlist__allowed.member(ALICE),
118+
).toBe(false);
117119

118-
sim.allow(ALICE);
120+
await sim.allow(ALICE);
119121

120-
expect(sim.getPublicState().Allowlist__allowed.member(ALICE)).toBe(true);
122+
expect(
123+
(await sim.getPublicState()).Allowlist__allowed.member(ALICE),
124+
).toBe(true);
121125
});
122126
});
123127
});

contracts/src/security/test/simulators/AllowlistSimulator.ts

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {
2-
type BaseSimulatorOptions,
32
createSimulator,
3+
type SimulatorOptions,
44
} from '@openzeppelin/compact-simulator';
55
import {
66
ledger,
@@ -29,47 +29,49 @@ const AllowlistSimulatorBase = createSimulator<
2929
contractArgs: () => [],
3030
ledgerExtractor: (state) => ledger(state),
3131
witnessesFactory: () => AllowlistWitnesses(),
32+
artifactName: 'MockAllowlist',
3233
});
3334

3435
/**
3536
* Allowlist Simulator
3637
*/
3738
export class AllowlistSimulator extends AllowlistSimulatorBase {
38-
constructor(
39-
options: BaseSimulatorOptions<
39+
static async create(
40+
options: SimulatorOptions<
4041
AllowlistPrivateState,
4142
ReturnType<typeof AllowlistWitnesses>
4243
> = {},
43-
) {
44-
super([], options);
44+
): Promise<AllowlistSimulator> {
45+
// biome-ignore lint/complexity/noThisInStatic: super.create must keep the subclass `this`
46+
return super.create([], options) as Promise<AllowlistSimulator>;
4547
}
4648

4749
/**
4850
* @description Returns whether `account` is currently allowed.
4951
* @returns True if `account` is a member of the allowlist.
5052
*/
51-
public isAllowed(account: Uint8Array): boolean {
53+
public isAllowed(account: Uint8Array): Promise<boolean> {
5254
return this.circuits.impure.isAllowed(account);
5355
}
5456

5557
/**
5658
* @description Asserts that `account` is allowed.
5759
*/
58-
public assertAllowed(account: Uint8Array) {
59-
this.circuits.impure.assertAllowed(account);
60+
public assertAllowed(account: Uint8Array): Promise<[]> {
61+
return this.circuits.impure.assertAllowed(account);
6062
}
6163

6264
/**
6365
* @description Adds `account` to the allowlist.
6466
*/
65-
public allow(account: Uint8Array) {
66-
this.circuits.impure.allow(account);
67+
public allow(account: Uint8Array): Promise<[]> {
68+
return this.circuits.impure.allow(account);
6769
}
6870

6971
/**
7072
* @description Removes `account` from the allowlist.
7173
*/
72-
public disallow(account: Uint8Array) {
73-
this.circuits.impure.disallow(account);
74+
public disallow(account: Uint8Array): Promise<[]> {
75+
return this.circuits.impure.disallow(account);
7476
}
7577
}

0 commit comments

Comments
 (0)