-
Notifications
You must be signed in to change notification settings - Fork 21
ERC7984Freezable extension behave like ERC7984 #181
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
ERC7984Freezable extension behave like ERC7984 #181
Conversation
…l-freezable-token
Co-authored-by: Arr00 <[email protected]>
Co-authored-by: James Toussaint <[email protected]>
…oken' into feature/confidential-freezable-token-behave-like-erc7984
…l-freezable-token-behave-like-erc7984
✅ Deploy Preview for confidential-tokens ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
WalkthroughAdjusted multiple mock contracts' inheritance override targets, added owner-only helper access functions, changed FHESafeMath.tryDecrease to handle uninitialized values, modified ERC7984Freezable.confidentialAvailable to use a named return and rely on tryDecrease's second value, and refactored ERC7984 tests into a shared behavior suite with updated fixtures and access calls. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Owner
participant Token as ERC7984Mock / ERC7984VotesMock
participant FHE as FHE.allow
rect rgba(200,230,255,0.18)
note over Owner,Token: Owner explicitly grants read access
Owner->>Token: confidentialTotalSupplyAccess()
Token->>FHE: allow(confidentialTotalSupply(), Owner)
FHE-->>Token: granted
Token-->>Owner: done
end
rect rgba(220,255,220,0.18)
note over Owner,Token: Grant access for historical supply
Owner->>Token: getPastTotalSupplyAccess(timepoint)
Token->>FHE: allow(getPastTotalSupply(timepoint), Owner)
FHE-->>Token: granted
Token-->>Owner: done
end
sequenceDiagram
participant Caller as ERC7984Freezable/others
participant Lib as FHESafeMath
Caller->>Lib: tryDecrease(oldValue, delta)
alt oldValue uninitialized
Lib-->>Caller: (success=false, updated=0)
else delta uninitialized
Lib-->>Caller: (success=true, updated=oldValue)
else both initialized
alt oldValue >= delta
Lib-->>Caller: (success=true, updated=oldValue - delta)
else
Lib-->>Caller: (success=false, updated=oldValue)
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (8)
contracts/utils/FHESafeMath.sol (1)
33-43
: Clarify failure semantics and align NatSpec with behaviorWhen oldValue is uninitialized, you now return (false, 0). This intentionally returns an initialized zero handle (useful for downstream decryption/allowance flows), but it contradicts the function comment that says “updated will be the original value.” Recommend documenting this special-case to prevent misuse at call sites that rely on the “original value” invariant.
Proposed NatSpec/doc tweak:
- * `success` will be true and `updated` will be the new value. Otherwise, `success` will be false - * and `updated` will be the original value. + * `success` will be true and `updated` will be the new value. Otherwise, `success` will be false. + * Failure cases: + * - If `oldValue` is initialized and `oldValue < delta`, `updated` equals `oldValue` (preserve). + * - If `oldValue` is NOT initialized, `updated` is an initialized zero (to provide a decryptable handle).test/token/ERC7984/ERC7984Votes.test.ts (2)
264-266
: Make the owner context explicit for access helpergetPastTotalSupplyAccess is owner-gated in the mock. This call currently relies on the deployer being the default signer of the contract instance. Make it explicit to avoid future brittleness if the test refactors signer usage.
- await this.token.getPastTotalSupplyAccess(afterFirstMintBlock); + await this.token.connect(this.holder).getPastTotalSupplyAccess(afterFirstMintBlock);
271-275
: Repeat explicit owner context for consistencySame rationale as above.
- await this.token.getPastTotalSupplyAccess(afterSecondMintBlock); + await this.token.connect(this.holder).getPastTotalSupplyAccess(afterSecondMintBlock);test/token/ERC7984/extensions/ERC7984Freezable.test.ts (1)
61-63
: Avoid creating an unused encrypted amount (no-proof path)The first transaction call to createEncryptedAmount is unused; only the staticCall result is passed to setConfidentialFrozen. Drop the transaction to reduce noise and test time.
- await token.connect(freezer).createEncryptedAmount(amount); - params.push(await token.connect(freezer).createEncryptedAmount.staticCall(amount)); + params.push(await token.connect(freezer).createEncryptedAmount.staticCall(amount));contracts/mocks/token/ERC7984VotesMock.sol (1)
33-36
: Use an explicit revert reason or a custom error for owner-gateThe bare require hampers debugging. Prefer a custom error (cheaper) or a revert string.
+ error UnauthorizedCaller(); function getPastTotalSupplyAccess(uint256 timepoint) public { - require(msg.sender == _OWNER); + if (msg.sender != _OWNER) revert UnauthorizedCaller(); FHE.allow(getPastTotalSupply(timepoint), msg.sender); }contracts/mocks/token/ERC7984Mock.sol (1)
20-22
: Use a custom error (and/or modifier) for owner check; avoid bare require.Saves gas and improves diagnostics; behavior unchanged.
Apply:
function confidentialTotalSupplyAccess() public { - require(msg.sender == _OWNER); + if (msg.sender != _OWNER) revert ERC7984MockUnauthorized(); FHE.allow(confidentialTotalSupply(), msg.sender); }Add outside this hunk (near the contract header):
error ERC7984MockUnauthorized(); // optionally: // modifier onlyOwner() { if (msg.sender != _OWNER) revert ERC7984MockUnauthorized(); _; }contracts/token/ERC7984/extensions/ERC7984Freezable.sol (2)
10-10
: Nit: docstring grammar.“allows implementing” reads better than “allows to implement”.
- * @dev Extension of {ERC7984} that allows to implement a confidential + * @dev Extension of {ERC7984} that allows implementing a confidential
34-36
: Mark confidentialAvailable as view (if FHE ops permit) and confirm ignoring success is intended.Returning the second value from tryDecrease makes sense with the new three-branch logic; please confirm that the boolean is not needed anywhere. Also consider declaring the function view for clarity/perf if compatible.
- function confidentialAvailable(address account) public virtual returns (euint64 unfrozen) { + function confidentialAvailable(address account) public view virtual returns (euint64 unfrozen) { (, unfrozen) = FHESafeMath.tryDecrease(confidentialBalanceOf(account), confidentialFrozen(account)); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (10)
contracts/mocks/token/ERC7984FreezableMock.sol
(1 hunks)contracts/mocks/token/ERC7984Mock.sol
(1 hunks)contracts/mocks/token/ERC7984ObserverAccessMock.sol
(2 hunks)contracts/mocks/token/ERC7984VotesMock.sol
(1 hunks)contracts/token/ERC7984/extensions/ERC7984Freezable.sol
(2 hunks)contracts/utils/FHESafeMath.sol
(1 hunks)test/token/ERC7984/ERC7984.behaviour.ts
(1 hunks)test/token/ERC7984/ERC7984.test.ts
(1 hunks)test/token/ERC7984/ERC7984Votes.test.ts
(1 hunks)test/token/ERC7984/extensions/ERC7984Freezable.test.ts
(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
test/token/ERC7984/ERC7984.behaviour.ts (2)
test/token/ERC7984/ERC7984.test.ts (1)
deployFixture
(32-32)test/helpers/accounts.ts (1)
allowHandle
(17-24)
test/token/ERC7984/extensions/ERC7984Freezable.test.ts (2)
test/token/ERC7984/ERC7984.test.ts (1)
deployFixture
(32-32)test/token/ERC7984/ERC7984.behaviour.ts (1)
shouldBehaveLikeERC7984
(596-596)
test/token/ERC7984/ERC7984.test.ts (1)
test/token/ERC7984/ERC7984.behaviour.ts (1)
shouldBehaveLikeERC7984
(596-596)
🪛 Gitleaks (8.27.2)
test/token/ERC7984/ERC7984.behaviour.ts
100-100: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
247-247: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
484-484: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🪛 Biome (2.1.2)
test/token/ERC7984/ERC7984.test.ts
[error] 31-32: Do not export from a test file.
(lint/suspicious/noExportsInTest)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: boostsecurity - boostsecurityio/semgrep-pro
- GitHub Check: tests
- GitHub Check: coverage
- GitHub Check: slither
🔇 Additional comments (11)
contracts/utils/FHESafeMath.sol (1)
37-41
: Delta-uninitialized branch is sensibleTreating an uninitialized delta as a no-op (success = true, updated = oldValue) matches expected “subtract zero” semantics and avoids handle churn. LGTM.
test/token/ERC7984/ERC7984Votes.test.ts (1)
262-270
: Assumption on handle stability across callsThe pattern “read handle, then grant access by recomputing the handle internally” assumes getPastTotalSupply returns the same handle on each call. If implementation ever returns a fresh handle per call, access won’t apply to the originally fetched handle.
Two safer options:
- Call the access helper first, then fetch the handle.
- Or have the helper accept a handle and call FHE.allow on that handle directly.
test/token/ERC7984/extensions/ERC7984Freezable.test.ts (2)
242-245
: Good call: reuse shared ERC7984 behavior suitePulling in shouldBehaveLikeERC7984 for the Freezable mock increases coverage and keeps behavior parity. LGTM.
18-31
: Fixture setup is consistent and helpfulPre-minting to the holder simplifies later availability/freeze scenarios and doesn’t interfere with the shared suite (which deploys its own fixture). Looks good.
contracts/mocks/token/ERC7984FreezableMock.sol (3)
31-33
: Override resolution updated correctlyUsing override(ERC7984, ERC7984Freezable) matches the current inheritance and preserves the linearization. LGTM.
35-38
: Helper is fine for testsReturning an allowed euint64 via createEncryptedAmount and granting both this and msg.sender access is appropriate for test utilities.
40-44
: Access helper aligns with new available semanticsconfidentialAvailableAccess correctly grants contract and recipient access to the returned handle, which pairs with tryDecrease’s “initialized zero on missing” behavior to ensure decryptability. LGTM.
contracts/mocks/token/ERC7984VotesMock.sol (1)
42-44
: Override target updated correctlyoverride(ERC7984, ERC7984Votes) matches the new base resolution. No issues spotted.
contracts/mocks/token/ERC7984ObserverAccessMock.sol (2)
7-7
: Importing ERC7984 directly is correct for override resolution.Good change; aligns this mock with the real base implementing _update.
22-22
: Override specifier is correctERC7984ObserverAccessMock properly overrides
_update
and lists only the two bases—ERC7984ObserverAccess and ERC7984—that define_update
. ERC7984Mock does not override_update
, so no changes to the override specifier are needed.test/token/ERC7984/ERC7984.test.ts (1)
18-25
: Initial mint via encrypted input looks solid.The explicit selector usage and input proof handling are correct.
import { ERC7984ReceiverMock } from '../../../types'; | ||
import { $ERC7984Mock } from '../../../types/contracts-exposed/mocks/token/ERC7984Mock.sol/$ERC7984Mock'; | ||
import { allowHandle } from '../../helpers/accounts'; | ||
import { deployERC7984Fixture } from './ERC7984.test'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Avoid importing fixtures from a test file; import from a helper instead.
Update import once the fixture is moved out of the test file.
-import { deployERC7984Fixture } from './ERC7984.test';
+import { deployERC7984Fixture } from './fixtures';
🤖 Prompt for AI Agents
In test/token/ERC7984/ERC7984.behaviour.ts around line 4 the test currently
imports deployERC7984Fixture from './ERC7984.test'; move the fixture out of the
test file into a shared helper/fixtures module (e.g. test/helpers/fixtures.ts or
test/fixtures/index.ts) and update this import to point at that helper path;
ensure the fixture is exported with the same name and adjust the relative import
path accordingly.
// Verify event contents | ||
expect(tx).to.emit(recipientContract, 'ConfidentialTransferCallback').withArgs(callbackSuccess); | ||
const transferEvents = (await tx.wait()).logs.filter((log: any) => log.address === token.target); | ||
|
||
const outboundTransferEvent = transferEvents[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Await the event assertion.
Without await, the assertion may not execute reliably.
- expect(tx).to.emit(recipientContract, 'ConfidentialTransferCallback').withArgs(callbackSuccess);
+ await expect(tx).to.emit(recipientContract, 'ConfidentialTransferCallback').withArgs(callbackSuccess);
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
// Verify event contents | |
expect(tx).to.emit(recipientContract, 'ConfidentialTransferCallback').withArgs(callbackSuccess); | |
const transferEvents = (await tx.wait()).logs.filter((log: any) => log.address === token.target); | |
const outboundTransferEvent = transferEvents[0]; | |
// Verify event contents | |
await expect(tx).to.emit(recipientContract, 'ConfidentialTransferCallback').withArgs(callbackSuccess); | |
const transferEvents = (await tx.wait()).logs.filter((log: any) => log.address === token.target); | |
const outboundTransferEvent = transferEvents[0]; |
🤖 Prompt for AI Agents
In test/token/ERC7984/ERC7984.behaviour.ts around lines 452 to 456, the event
assertion using expect(tx).to.emit(...) is not awaited which can make the
assertion flaky; change it to await the assertion (e.g. await
expect(tx).to.emit(recipientContract,
'ConfidentialTransferCallback').withArgs(callbackSuccess)) so the test waits for
the event check to complete before proceeding.
function generateReencryptionErrorMessage(handle: string, account: string): string { | ||
return `User ${account} is not authorized to user decrypt handle ${handle}`; | ||
} | ||
export { deployFixture as deployERC7984Fixture }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix: remove export from test file to satisfy linter and avoid circular test deps.
Biome flags noExportsInTest. Move the fixture to a dedicated helper and import it where needed.
Minimal change here:
-export { deployFixture as deployERC7984Fixture };
Create a new helper (outside this file), e.g., test/token/ERC7984/fixtures.ts:
import { $ERC7984Mock } from '../../../types/contracts-exposed/mocks/token/ERC7984Mock.sol/$ERC7984Mock';
import { ethers, fhevm } from 'hardhat';
const contract = '$ERC7984Mock';
const name = 'ConfidentialFungibleToken';
const symbol = 'CFT';
const uri = 'https://example.com/metadata';
export async function deployERC7984Fixture(_contract?: string, extraDeploymentArgs: any[] = []) {
const [holder, recipient, operator, anyone] = await ethers.getSigners();
const token = (await ethers.deployContract(_contract ?? contract, [name, symbol, uri, ...extraDeploymentArgs])) as any as $ERC7984Mock;
const encryptedInput = await fhevm.createEncryptedInput(await token.getAddress(), holder.address).add64(1000).encrypt();
await token.connect(holder)['$_mint(address,bytes32,bytes)'](holder, encryptedInput.handles[0], encryptedInput.inputProof);
return { token, holder, recipient, operator, anyone };
}
🧰 Tools
🪛 Biome (2.1.2)
[error] 31-32: Do not export from a test file.
(lint/suspicious/noExportsInTest)
🤖 Prompt for AI Agents
In test/token/ERC7984/ERC7984.test.ts around line 32, remove the exported
fixture to satisfy the linter and avoid circular test deps; delete the line
"export { deployFixture as deployERC7984Fixture }" from this test file, create a
new helper file test/token/ERC7984/fixtures.ts that defines and exports
deployERC7984Fixture (implementing the deployment and initial mint logic shown
in the review comment), and update any tests that imported the fixture from the
test file to instead import it from test/token/ERC7984/fixtures.ts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (3)
test/token/ERC7984/ERC7984.behaviour.ts (2)
4-4
: Fix circular test dependency: import fixture from a helper, not a test.This import creates a cycle with ERC7984.test.ts and violates linter rules. Move the fixture to a helper (e.g., test/token/ERC7984/fixtures.ts) and import from there.
-import { deployERC7984Fixture } from './ERC7984.test'; +import { deployERC7984Fixture } from './fixtures';Outside this hunk, add a fixtures helper that exports deployERC7984Fixture, and remove the export from ERC7984.test.ts (see comments in that file).
360-360
: Await the event assertion to avoid flakiness.Not awaiting can skip the assertion under race.
- expect(tx).to.emit(recipientContract, 'ConfidentialTransferCallback').withArgs(callbackSuccess); + await expect(tx).to.emit(recipientContract, 'ConfidentialTransferCallback').withArgs(callbackSuccess);test/token/ERC7984/ERC7984.test.ts (1)
196-196
: Remove export from test file (Biome: noExportsInTest).Exporting from a test violates the linter and worsens the cycle with behaviour.ts. Export the fixture from a helper instead.
-export { deployFixture as deployERC7984Fixture }; +// Moved to test/token/ERC7984/fixtures.ts: +// export async function deployERC7984Fixture(...) { ... }Helper (new file) example:
// test/token/ERC7984/fixtures.ts import { $ERC7984Mock } from '../../../types/contracts-exposed/mocks/token/ERC7984Mock.sol/$ERC7984Mock'; import { ethers, fhevm } from 'hardhat'; const contract = '$ERC7984Mock'; const name = 'ConfidentialFungibleToken'; const symbol = 'CFT'; const uri = 'https://example.com/metadata'; export async function deployERC7984Fixture(_contract?: string, extraDeploymentArgs: any[] = []) { const [holder, recipient, operator, anyone] = await ethers.getSigners(); const token = (await ethers.deployContract(_contract ?? contract, [name, symbol, uri, ...extraDeploymentArgs])) as any as $ERC7984Mock; const encryptedInput = await fhevm.createEncryptedInput(await token.getAddress(), holder.address).add64(1000).encrypt(); await token.connect(holder)['$_mint(address,bytes32,bytes)'](holder.address, encryptedInput.handles[0], encryptedInput.inputProof); return { token, holder, recipient, operator, anyone }; }
🧹 Nitpick comments (4)
test/token/ERC7984/ERC7984.behaviour.ts (2)
187-194
: Prefer typed event parsing over index-based selection.Selecting the first log by address is brittle. Decode with the contract interface for clarity and resilience.
Example (outside this hunk):
const receipt = await tx.wait(); const parsed = receipt.logs .map(l => { try { return token.interface.parseLog(l); } catch { return undefined; } }) .filter(Boolean);
429-431
: Nit: fix error message grammar.“authorized to user decrypt” → “authorized to user-decrypt” or “authorized to decrypt”.
- return `User ${account} is not authorized to user decrypt handle ${handle}`; + return `User ${account} is not authorized to user-decrypt handle ${handle}`;test/token/ERC7984/ERC7984.test.ts (2)
25-28
: Pass addresses to contract methods expecting address.Be consistent and explicit; Signer objects are not AddressLike in all contexts.
- await token - .connect(holder) - ['$_mint(address,bytes32,bytes)'](holder, encryptedInput.handles[0], encryptedInput.inputProof); + await token + .connect(holder) + ['$_mint(address,bytes32,bytes)'](holder.address, encryptedInput.handles[0], encryptedInput.inputProof);
150-154
: Pass recipient address, not Signer, for clarity and type-safety.- const tx = await token['confidentialTransfer(address,bytes32,bytes)']( - recipient, + const tx = await token['confidentialTransfer(address,bytes32,bytes)']( + recipient.address, encryptedInput.handles[0], encryptedInput.inputProof, );
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
test/token/ERC7984/ERC7984.behaviour.ts
(1 hunks)test/token/ERC7984/ERC7984.test.ts
(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
test/token/ERC7984/ERC7984.behaviour.ts (2)
test/token/ERC7984/ERC7984.test.ts (1)
deployFixture
(196-196)test/helpers/accounts.ts (1)
allowHandle
(17-24)
🪛 Gitleaks (8.27.2)
test/token/ERC7984/ERC7984.test.ts
73-73: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
test/token/ERC7984/ERC7984.behaviour.ts
154-154: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
391-391: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🪛 Biome (2.1.2)
test/token/ERC7984/ERC7984.test.ts
[error] 195-196: Do not export from a test file.
(lint/suspicious/noExportsInTest)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: boostsecurity - boostsecurityio/semgrep-pro
- GitHub Check: slither
- GitHub Check: tests
- GitHub Check: coverage
🔇 Additional comments (1)
test/token/ERC7984/ERC7984.test.ts (1)
193-194
: OK: behaviour delegation is clear.Delegating to the shared behaviour keeps tests DRY.
it('without operator approval should fail', async function () { | ||
await token.$_setOperator(holder, operator, 0); | ||
|
||
await expect( | ||
token |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type mismatch: pass addresses to $_setOperator.
Passing Signer objects will mis-encode params; the function expects addresses.
- await token.$_setOperator(holder, operator, 0);
+ await token.$_setOperator(holder.address, operator.address, 0);
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
it('without operator approval should fail', async function () { | |
await token.$_setOperator(holder, operator, 0); | |
await expect( | |
token | |
it('without operator approval should fail', async function () { | |
await token.$_setOperator(holder.address, operator.address, 0); | |
await expect( | |
token |
🤖 Prompt for AI Agents
In test/token/ERC7984/ERC7984.behaviour.ts around lines 89 to 93, the call to
token.$_setOperator is being passed Signer objects which causes ABI mis-encoding
because the function expects address strings; change the arguments to address
values by calling await holder.getAddress() and await operator.getAddress() (or
use the signer.address field if available) so the function receives plain
addresses, and update any other test calls similarly to ensure addresses — not
Signer instances — are passed.
import { $ERC7984Mock } from '../../../types/contracts-exposed/mocks/token/ERC7984Mock.sol/$ERC7984Mock'; | ||
import { shouldBehaveLikeERC7984 } from './ERC7984.behaviour'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Circular dependency with behaviour suite.
This file imports the behaviour, while the behaviour imports a fixture from this file, causing a cycle and undefined exports at runtime. Move the fixture to a helper module and update both imports.
Planned changes:
- Create test/token/ERC7984/fixtures.ts exporting deployERC7984Fixture.
- Update behaviour.ts to import from './fixtures'.
- Keep a local deployFixture here (non-export) or import from the helper.
🤖 Prompt for AI Agents
In test/token/ERC7984/ERC7984.test.ts around lines 1 to 2, there is a circular
dependency because this test imports the behaviour which in turn imports a
fixture from this file; extract the shared fixture into a new module
test/token/ERC7984/fixtures.ts that exports deployERC7984Fixture, update
test/token/ERC7984/ERC7984.behaviour.ts to import deployERC7984Fixture from
'./fixtures', and update this test file to either import the fixture from
'./fixtures' or keep a local (non-exported) deployFixture helper — ensure no
exports from this test file that the behaviour relies on so the cycle is broken.
Summary by CodeRabbit
New Features
Bug Fixes
Tests
Documentation