Skip to content

✨ exa: add crosschain mint and burn support#797

Open
itofarina wants to merge 10 commits intomainfrom
exa-crosschain
Open

✨ exa: add crosschain mint and burn support#797
itofarina wants to merge 10 commits intomainfrom
exa-crosschain

Conversation

@itofarina
Copy link
Member

@itofarina itofarina commented Feb 25, 2026

Summary by CodeRabbit

  • New Features

    • EXA gains bridge-controlled cross-chain minting/burning and a v2 initialization path with upgraded access control and interface support.
  • Tests

    • Comprehensive EXA test suite added covering initialization, bridge access, mint/burn flows, interface support; many test entries were renamed and gas snapshot metrics updated.
  • Dependencies

    • OpenZeppelin packages updated.
  • Chores

    • Added release metadata for a patch release.

Open with Devin

@changeset-bot
Copy link

changeset-bot bot commented Feb 25, 2026

🦋 Changeset detected

Latest commit: 07bdc21

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@exactly/protocol Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@gemini-code-assist
Copy link

Summary of Changes

Hello @itofarina, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly upgrades the EXA token contract by incorporating ERC-7802 support, which standardizes cross-chain interactions for minting and burning tokens. The changes include a robust access control system to secure these operations, alongside essential dependency updates and a new, comprehensive test suite to ensure the reliability and correctness of the new features.

Highlights

  • ERC-7802 Support: The EXA token contract now implements the ERC-7802 standard, enabling standardized cross-chain minting and burning capabilities.
  • Access Control Integration: OpenZeppelin's AccessControlUpgradeable has been integrated into the EXA contract, introducing a BRIDGE_ROLE to manage permissions for cross-chain operations.
  • Dependency Updates: OpenZeppelin contract dependencies have been upgraded to version 5.4.0 across package.json and pnpm-lock.yaml.
  • Comprehensive Testing: A new dedicated test file, test/EXA.t.sol, has been added to thoroughly validate the ERC-7802 implementation, access control mechanisms, and core mint/burn functionalities.
  • Gas Snapshot Updates: Gas consumption values in .gas-snapshot have been updated to reflect the changes introduced by the new features and contract logic.
Changelog
  • .gas-snapshot
    • Updated gas consumption values for numerous tests.
  • contracts/periphery/EXA.sol
    • Implemented ERC-7802 interface.
    • Integrated AccessControl for managing bridge roles.
    • Introduced initializeV2 for admin role setup.
    • Added mint, burn, crosschainMint, and crosschainBurn functions with event emissions.
    • Updated supportsInterface to reflect new interfaces.
  • package.json
    • Updated OpenZeppelin contract dependencies to version 5.4.0.
  • pnpm-lock.yaml
    • Updated OpenZeppelin contract dependencies to version 5.4.0.
  • test/EXA.t.sol
    • Added new test suite for the EXA contract.
    • Covered initialization, role management, mint/burn operations, and interface support.
Activity
  • itofarina created this pull request.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link

coderabbitai bot commented Feb 25, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds bridge-controlled cross-chain mint/burn to EXA (BRIDGE_ROLE, crosschainMint/crosschainBurn, IERC7802 support), proxy reinitializer via initialize2, Forge tests for proxy/bridge flows and interface checks, OpenZeppelin dependency bumps, and test/gas-snapshot renames and updates.

Changes

Cohort / File(s) Summary
Core Contract
contracts/periphery/EXA.sol
Adds BRIDGE_ROLE, inherits AccessControlUpgradeable and IERC7802, disables initializers in constructor, adds initialize2(address) reinitializer, mint/burn wrappers, crosschainMint/crosschainBurn guarded by BRIDGE_ROLE, new events/errors, and updates supportsInterface.
New Tests
test/EXA.t.sol
New Forge test suite deploying EXA behind an ERC1967Proxy/ProxyAdmin, exercising initialize/initialize2, BRIDGE_ROLE behavior, mint/burn and cross-chain flows, event emissions, and interface checks.
Test Updates / Gas Snapshot
.gas-snapshot, test/EscrowedEXA.t.sol
Renames many tests (EscrowedEXATest → EXATest equivalents) and updates gas/timing metrics; test/EscrowedEXA.t.sol switched to proxy-based initialization in setUp.
Dependencies
package.json
Bumps @openzeppelin/contracts and @openzeppelin/contracts-upgradeable from ^5.0.2 to ^5.4.0.
Release Metadata
.changeset/silent-chefs-marry.md
Adds a changeset entry noting a patch release and cross-chain mint/burn support.

Sequence Diagram(s)

mermaid
sequenceDiagram
rect rgba(220,220,255,0.5)
participant Admin
end
rect rgba(200,255,200,0.5)
participant Proxy as ERC1967Proxy
end
rect rgba(255,240,200,0.5)
participant EXA
end
rect rgba(255,200,200,0.5)
participant Bridge
end

Admin->>Proxy: deploy proxy pointing to EXA implementation
Admin->>Proxy: call initialize(...)
Admin->>Proxy: call initialize2(admin_)
Proxy->>EXA: delegatecall initialize / initialize2
Admin->>EXA: grantRole(BRIDGE_ROLE, Bridge)
Bridge->>EXA: crosschainMint(to, amount)
EXA-->>Bridge: emit CrosschainMint; update balances
Bridge->>EXA: crosschainBurn(from, amount)
EXA-->>Bridge: emit CrosschainBurn; update balances

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding cross-chain mint and burn support to the EXA contract, which is accurately reflected in the PR's substantial modifications to contracts/periphery/EXA.sol.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch exa-crosschain

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

gemini-code-assist[bot]

This comment was marked as resolved.

@openzeppelin-code
Copy link

openzeppelin-code bot commented Feb 25, 2026

✨ exa: add crosschain mint and burn support

Generated at commit: 07bdc212b58519926254d88eb8df4e9a6ee00951

🚨 Report Summary

Severity Level Results
Contracts Critical
High
Medium
Low
Note
Total
2
4
0
7
26
39
Dependencies Critical
High
Medium
Low
Note
Total
0
0
0
0
0
0

For more details view the full report in OpenZeppelin Code Inspector

coderabbitai[bot]

This comment was marked as resolved.

@itofarina itofarina force-pushed the exa-crosschain branch 2 times, most recently from 5edfce9 to df5529c Compare February 25, 2026 15:46
@itofarina itofarina changed the title ✨ exa: add ERC-7802 support ✨ exa: add crosschain mint and burn support Feb 25, 2026
coderabbitai[bot]

This comment was marked as resolved.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
contracts/periphery/EXA.sol (1)

26-29: ⚠️ Potential issue | 🟠 Major

Validate admin_ in initialize2 to prevent irreversible admin lockout.

Line 28 grants DEFAULT_ADMIN_ROLE without validating admin_. Passing address(0) would leave admin control effectively unusable.

🛠️ Proposed fix
 contract EXA is ERC20VotesUpgradeable, AccessControlUpgradeable, IERC7802 {
   bytes32 public constant BRIDGE_ROLE = keccak256("BRIDGE_ROLE");
+  error InvalidAdmin();
@@
   function initialize2(address admin_) external reinitializer(2) {
+    if (admin_ == address(0)) revert InvalidAdmin();
     __AccessControl_init();
     _grantRole(DEFAULT_ADMIN_ROLE, admin_);
   }
#!/bin/bash
set -euo pipefail

echo "== Verify EXA.initialize2 has/hasn't zero-address guard =="
rg -n -C3 'function initialize2|admin_ == address\(0\)|_grantRole\(DEFAULT_ADMIN_ROLE, admin_\)' contracts/periphery/EXA.sol

echo
echo "== Inspect OZ AccessControlUpgradeable _grantRole behavior =="
fd -HI '^AccessControlUpgradeable\.sol$' | while read -r f; do
  echo "-- $f"
  rg -n -C3 'function _grantRole|address\(0\)' "$f"
done

Expected result: no admin_ == address(0) guard in initialize2, and _grantRole itself does not enforce non-zero accounts.


ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between df5529c and be4bd71.

📒 Files selected for processing (5)
  • .changeset/silent-chefs-marry.md
  • .gas-snapshot
  • contracts/periphery/EXA.sol
  • test/EXA.t.sol
  • test/EscrowedEXA.t.sol

@itofarina itofarina force-pushed the exa-crosschain branch 2 times, most recently from 0c63b60 to ebde601 Compare February 26, 2026 16:40
coderabbitai[bot]

This comment was marked as resolved.

@itofarina itofarina force-pushed the exa-crosschain branch 2 times, most recently from 87bb3d8 to 62e1258 Compare March 5, 2026 13:40
@itofarina itofarina marked this pull request as ready for review March 5, 2026 15:45
@itofarina itofarina requested a review from cruzdanilo as a code owner March 5, 2026 15:45
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 62e12585f7

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +32 to +38
function initialize2(address admin_) external reinitializer(2) {
if (msg.sender != StorageSlotUpgradeable.getAddressSlot(ADMIN_SLOT).value) revert NotProxyAdmin();
if (admin_ == address(0)) revert ZeroAddress();
if (bytes(name()).length == 0) revert NotInitialized();

__AccessControl_init();
_grantRole(DEFAULT_ADMIN_ROLE, admin_);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Initialize access control in the default EXA deployment flow

DEFAULT_ADMIN_ROLE is only granted inside initialize2, but the repository’s deploy flow still initializes EXA with only initialize (see deploy/EXA.ts), so fresh deployments/upgrades end up with no admin account able to grant BRIDGE_ROLE. In that state, all new bridge mint/burn entry points guarded by onlyRole(BRIDGE_ROLE) are unusable until an extra manual upgradeAndCall(..., initialize2(...)) step is performed.

Useful? React with 👍 / 👎.

__ERC20Permit_init("exactly");
__ERC20Votes_init();
_mint(msg.sender, 10_000_000e18);
if (block.chainid == 10) _mint(msg.sender, 10_000_000e18);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Mint premine to a recoverable address on delayed initialize

On chain 10, initialize mints the full 10M supply to msg.sender, but this function can now be executed post-deploy only via proxy-admin-driven upgrade calls; in that path, msg.sender inside delegatecall is the ProxyAdmin contract. That means delayed initialization mints the premine to ProxyAdmin, and those tokens are effectively stuck because ProxyAdmin has no generic ERC20 transfer method.

Useful? React with 👍 / 👎.

Copy link

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 5 additional findings.

Open in Devin Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants