Skip to content

Conversation

@fadeev
Copy link
Member

@fadeev fadeev commented Oct 22, 2025

Imports UniversalContract.sol.

Advantages:

  • Less clutter: Only a single import is required, instead of importing multiple contracts.
  • Smaller contract size: UniversalContract.sol contains everything a developer needs, and nothing they don’t.
  • No onlyGateway modifier needed: The permission logic is already built in.
  • No constructor parameter for the Gateway: The address is automatically fetched from the registry on mainnet, testnet, or localnet.

Depends on:

Related docs:

Summary by CodeRabbit

  • Refactor
    • Simplified and standardized contract initialization across examples: removed gateway-related parameters/state, consolidated access control into shared base contracts, and adjusted initializer argument ordering where needed.
  • Chores
    • Bumped example dependency versions; added Cancun EVM compiler setting in Hardhat and removed Foundry EVM pins.
    • Consolidated shell flags, removed gateway/uniswap CLI/deploy options, and streamlined local deployment scripts and tests.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 22, 2025

📝 Walkthrough

Walkthrough

This PR removes direct gateway state and constructor parameters from multiple example contracts, reorders/simplifies initialize signatures and test calls, updates toolchain configs and dependency versions, and consolidates shell scripts and deployment argument handling across examples.

Changes

Cohort / File(s) Change Summary
Universal / Swap gateway removal
examples/call/contracts/Universal.sol, examples/hello/contracts/Universal.sol, examples/swap/contracts/Swap.sol
Removed public gateway state, Unauthorized() error, onlyGateway() modifier, and constructors that accepted gateway addresses; replaced gateway imports with UniversalContract interface where applicable.
Connected import removal
examples/call/contracts/Connected.sol
Removed {RevertContext} import from @zetachain/protocol-contracts/contracts/Revert.sol while leaving onRevert(RevertContext ...) signature unchanged.
Constructor / initialize updates in tests
examples/call/test/CallTest.t.sol, examples/hello/test/Universal.t.sol, examples/swap/test/SwapTest.t.sol
Tests updated to instantiate Universal/Swap without gateway argument and to match new initialize signatures.
Initialize parameter reorder (EVM examples)
examples/nft/contracts/EVMUniversalNFT.sol, examples/token/contracts/EVMUniversalToken.sol, examples/nft/test/UniversalNFTTest.t.sol, examples/token/test/UniversalTokenTest.t.sol
Moved gas parameter before gatewayAddress in EVM initialize signatures; tests and proxy initialization calls updated to match new ordering.
ZetaChain initialize simplification
examples/nft/contracts/ZetaChainUniversalNFT.sol, examples/token/contracts/ZetaChainUniversalToken.sol, examples/nft/test/UniversalNFTTest.t.sol, examples/token/test/UniversalTokenTest.t.sol
Removed gatewayAddress and uniswapRouterAddress from ZetaChain initialize signatures; core init calls reduced to accept gas only; tests updated accordingly.
Deploy command / CLI option removals
examples/swap/commands/deploy.ts
Removed CLI options --gateway and --uniswap-router; updated initData encoding to drop gateway/uniswapRouter values.
Foundry config: evm_version removed
examples/call/foundry.toml, examples/hello/foundry.toml, examples/nft/foundry.toml, examples/swap/foundry.toml, examples/token/foundry.toml
Deleted evm_version = "paris" from example Foundry profiles.
Hardhat config: evmVersion added
examples/call/hardhat.config.ts, examples/nft/hardhat.config.ts, examples/token/hardhat.config.ts
Added evmVersion: "cancun" to Solidity compiler settings (and explicit version: "0.8.26" in call example).
Package dependency updates
examples/call/package.json, examples/hello/package.json, examples/messaging/package.json, examples/nft/package.json, examples/swap/package.json, examples/token/package.json
Bumped example dependencies: @zetachain/protocol-contracts14.1.0-rc1/^14.1.0, @zetachain/toolkit^16.2.2, zetachain^7.2.0, and @zetachain/standard-contracts where applicable.
Foundry remappings added
examples/swap/foundry.toml
Added remappings for @zetachain/protocol-contracts and @zetachain/toolkit to node_modules paths.
Shell script consolidation & env lookups
examples/call/scripts/localnet.sh, examples/hello/scripts/localnet.sh, examples/nft/scripts/localnet.sh, examples/swap/scripts/localnet.sh, examples/token/scripts/localnet.sh
Consolidated set flags to set -exo pipefail; added registry lookups (USDC_ETHEREUM, GATEWAY_ETHEREUM, GATEWAY_ZETACHAIN, WZETA) in some scripts; removed --uniswap-router/--gateway deployment flags.
Localnet deployment command simplifications
examples/call/scripts/localnet.sh, examples/swap/scripts/localnet.sh, examples/nft/scripts/localnet.sh, examples/token/scripts/localnet.sh
Streamlined JSON extraction from forge output and removed explicit gateway/uniswap arguments from deployment commands.

Sequence Diagram(s)

sequenceDiagram
    participant Test
    participant Contract
    participant Parent as UniversalContract
    Note over Test,Contract: Prior flow — contract stored gateway locally
    Test->>Contract: new Contract(payable(gateway))
    Contract->>Contract: store gateway
    Test->>Contract: onCall(...)
    Contract->>Contract: onlyGateway() local check

    Note over Test,Contract: New flow — no local gateway, rely on inherited access control
    Test->>Contract: new Contract()
    Test->>Contract: onCall(...)
    Contract->>Parent: delegate authorization (onlyGateway)
    Parent-->>Contract: authorization result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~45 minutes

  • Areas needing focused review:
    • Parameter reordering in EVMUniversalNFT/EVMUniversalToken and all call sites (scripts/tests/proxies).
    • Removal of gateway state/constructor in Universal/Swap — ensure inherited onlyGateway() provides equivalent authorization and imports/ancestry are correct.
    • examples/call/contracts/Connected.sol: RevertContext import removed but still referenced in onRevert signature — verify definition/source or update signature.
    • Shell scripts and deploy command changes — validate JSON paths and that removed CLI flags do not break automated deployments.
    • Dependency bumps and Hardhat/Foundry EVM settings — confirm compiler and EVM compatibility across examples.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "chore: update contracts to use abstract universal contract" directly and accurately summarizes the primary objective of the changeset. The PR systematically refactors multiple example contracts across the repository to inherit from or utilize the UniversalContract interface rather than managing gateway access control independently, which is reflected consistently across all file modifications. The title is concise, avoids vague terminology or noise, and provides sufficient specificity for a developer reviewing commit history to immediately understand the nature of the change.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch abstract-universal-contract

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0174162 and b37db41.

⛔ Files ignored due to path filters (1)
  • examples/call/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (1)
  • examples/call/package.json (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • examples/call/package.json
⏰ 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). (13)
  • GitHub Check: test (examples/call)
  • GitHub Check: test (examples/swap)
  • GitHub Check: test (examples/token)
  • GitHub Check: test (examples/nft)
  • GitHub Check: test (examples/hello)
  • GitHub Check: test (examples/call)
  • GitHub Check: test (examples/token)
  • GitHub Check: test (examples/nft)
  • GitHub Check: test (examples/swap)
  • GitHub Check: test (examples/hello)
  • GitHub Check: slither (examples/hello, hello.sarif)
  • GitHub Check: slither (examples/call, call.sarif)
  • GitHub Check: slither (examples/swap, swap.sarif)

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.

@fadeev fadeev marked this pull request as ready for review October 27, 2025 10:03
@fadeev fadeev requested a review from a team as a code owner October 27, 2025 10:03
Copy link
Contributor

@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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (6)
examples/nft/scripts/localnet.sh (1)

35-39: Missing required --gateway parameter for ZetaChainUniversalNFT deployment.

The deploy command requires the --gateway parameter for all Universal NFT deployments. The ZetaChainUniversalNFT deployment at lines 35–39 is missing this parameter despite GATEWAY_ZETACHAIN being fetched at line 28. The Ethereum and BNB deployments correctly pass --gateway at lines 48–54 and 56–62 respectively.

Add --gateway "$GATEWAY_ZETACHAIN" to the ZetaChainUniversalNFT deployment command (lines 35–39):

CONTRACT_ZETACHAIN=$(npx tsx commands deploy \
  --rpc "$RPC" \
  --private-key "$PRIVATE_KEY" \
  --name ZetaChainUniversalNFT \
  --gateway "$GATEWAY_ZETACHAIN" \
  --gas-limit 1000000 | jq -r '.contractAddress')
examples/messaging/package.json (1)

2-4: Package metadata appears inconsistent with directory structure.

The package name is "nft" and the description references "Universal NFT", but this file is located in examples/messaging/package.json. This suggests either incorrect package metadata or a file organization issue.

Verify that the package name and description accurately reflect the purpose of this example. If this is indeed a messaging example, update the metadata accordingly:

-  "name": "nft",
+  "name": "messaging",
   "version": "1.0.0",
-  "description": "Universal NFT enables non-fungible ERC-721 tokens to minted and transferred between connected chains.",
+  "description": "Messaging example for cross-chain communication.",
examples/swap/commands/deploy.ts (1)

83-86: Remove unused gateway CLI option.

The --gateway option is defined in the CLI interface but is no longer used in the deployment logic after removing the gateway parameter from the initialize function. This dead code should be removed to avoid confusion.

-  .option(
-    "-g, --gateway <address>",
-    "Gateway address (default: testnet)",
-    "0x6c533f7fe93fae114d0954697069df33c9b74fd7"
-  )
   .option("--gas-limit <number>", "Gas limit for the transaction", "1000000")
examples/nft/contracts/EVMUniversalNFT.sol (1)

48-48: Fix EVMUniversalNFT.sol line 48: incorrect number of parameters passed to __UniversalNFTCore_init.

The initializer signature accepts a single uint256 gasLimit parameter, but the current call passes three arguments: gatewayAddress, address(this), and gas. This will cause a compilation error.

Correct the call to:

__UniversalNFTCore_init(gas);

This aligns with the correct implementation already present in ZetaChainUniversalNFT.sol (line 47) and matches the external contract specification.

examples/swap/contracts/Swap.sol (1)

197-241: Swap.sol is missing the gateway variable and onlyGateway modifier declarations, causing compilation errors.

The withdraw() function references gateway on lines 207, 211, 214, and 218, and the onCall() function uses the onlyGateway modifier, but neither the variable nor the modifier are declared in Swap.sol. UniversalContract provides only the onCall() method and does not supply a gateway property.

The Connected.sol example demonstrates the correct pattern:

GatewayZEVM public immutable gateway;

constructor(address payable gatewayAddress) {
    gateway = GatewayEVM(gatewayAddress);
}

modifier onlyGateway() {
    if (msg.sender != address(gateway)) revert Unauthorized();
}

Add the gateway state variable and onlyGateway modifier to Swap.sol. Initialize gateway in the initialize() function to align with the upgradeable proxy pattern used in this contract, or add a constructor parameter and initialization step as appropriate for your architecture.

examples/hello/contracts/Universal.sol (1)

4-18: ---

The onlyGateway modifier must be defined locally in the Universal contract.

The contract uses the onlyGateway modifier on line 14 (the onCall function), but neither the Universal contract nor its parent UniversalContract interface define this modifier. The UniversalContract interface does not provide an onlyGateway modifier — example contracts define onlyGateway themselves.

Add the missing modifier definition to the Universal contract:

modifier onlyGateway() {
    require(msg.sender == gateway, "Only gateway");
    _;
}

Adjust the gateway address reference as appropriate for your implementation (this may require storing the gateway address as a state variable or reading it from elsewhere in the UniversalContract interface).

🧹 Nitpick comments (3)
examples/nft/scripts/localnet.sh (1)

23-30: Standardize jq key notation for consistency.

The environment variable lookups mix two jq syntax styles: ."key" (lines 23–25, 27, 29–30) and .["key"] (lines 26, 28). While both are functionally equivalent, the inconsistency degrades readability. Standardize all lookups to use a single convention (e.g., .["key"] for explicit bracket notation with quoted keys).

Apply this diff to standardize to bracket notation:

-ZRC20_BNB=$(jq -r '."98".zrc20Tokens[] | select(.coinType == "gas" and .originChainId == "98") | .address' ~/.zetachain/localnet/registry.json) && echo $ZRC20_BNB
-ZRC20_ETHEREUM=$(jq -r '."11155112".zrc20Tokens[] | select(.coinType == "gas" and .originChainId == "11155112") | .address' ~/.zetachain/localnet/registry.json) && echo $ZRC20_ETHEREUM
-USDC_ETHEREUM=$(jq -r '."11155112".zrc20Tokens[] | select(.symbol == "USDC.ETH") | .address' ~/.zetachain/localnet/registry.json) && echo $USDC_ETHEREUM
-GATEWAY_BNB=$(jq -r '."98".contracts[] | select(.contractType == "gateway") | .address' ~/.zetachain/localnet/registry.json) && echo $GATEWAY_BNB
-UNISWAP_ROUTER=$(jq -r '."31337".contracts[] | select(.contractType == "uniswapV2Router02") | .address' ~/.zetachain/localnet/registry.json) && echo $UNISWAP_ROUTER
-WZETA=$(jq -r '."31337".contracts[] | select(.contractType == "zetaToken") | .address' ~/.zetachain/localnet/registry.json) && echo $WZETA
+ZRC20_BNB=$(jq -r '.["98"].zrc20Tokens[] | select(.coinType == "gas" and .originChainId == "98") | .address' ~/.zetachain/localnet/registry.json) && echo $ZRC20_BNB
+ZRC20_ETHEREUM=$(jq -r '.["11155112"].zrc20Tokens[] | select(.coinType == "gas" and .originChainId == "11155112") | .address' ~/.zetachain/localnet/registry.json) && echo $ZRC20_ETHEREUM
+USDC_ETHEREUM=$(jq -r '.["11155112"].zrc20Tokens[] | select(.symbol == "USDC.ETH") | .address' ~/.zetachain/localnet/registry.json) && echo $USDC_ETHEREUM
+GATEWAY_BNB=$(jq -r '.["98"].contracts[] | select(.contractType == "gateway") | .address' ~/.zetachain/localnet/registry.json) && echo $GATEWAY_BNB
+UNISWAP_ROUTER=$(jq -r '.["31337"].contracts[] | select(.contractType == "uniswapV2Router02") | .address' ~/.zetachain/localnet/registry.json) && echo $UNISWAP_ROUTER
+WZETA=$(jq -r '.["31337"].contracts[] | select(.contractType == "zetaToken") | .address' ~/.zetachain/localnet/registry.json) && echo $WZETA
examples/nft/contracts/ZetaChainUniversalNFT.sol (1)

34-48: Consider validating the gas parameter.

The gas parameter is accepted without validation. If UniversalNFTCore does not validate it internally, a value of zero or an excessively large value could lead to failed cross-chain operations or unexpected behavior.

Consider adding validation:

 function initialize(
     address initialOwner,
     string memory name,
     string memory symbol,
     uint256 gas // Set gas limit for universal NFT calls
 ) public initializer {
+    if (gas == 0) revert InvalidGasLimit();
     __ERC721_init(name, symbol);
     __ERC721Enumerable_init();
     __ERC721URIStorage_init();
     __ERC721Pausable_init();
     __Ownable_init(initialOwner);
     __ERC721Burnable_init();
     __UUPSUpgradeable_init();
     __UniversalNFTCore_init(gas); // Initialize universal NFT core
 }

Note: If UniversalNFTCore already performs this validation, this suggestion can be disregarded.

examples/swap/contracts/Swap.sol (1)

42-51: Add validation for initialize parameters.

The initialize function accepts uniswapRouterAddress and gasLimitAmount without validation. Zero values could cause transaction failures or unexpected behavior in swap operations.

Consider adding validation:

 function initialize(
     address uniswapRouterAddress,
     uint256 gasLimitAmount,
     address owner
 ) external initializer {
+    if (uniswapRouterAddress == address(0)) revert InvalidAddress();
+    if (gasLimitAmount == 0) revert InvalidGasLimit();
     __UUPSUpgradeable_init();
     __Ownable_init(owner);
     uniswapRouter = uniswapRouterAddress;
     gasLimit = gasLimitAmount;
 }

Note: You may need to add an InvalidGasLimit error declaration if not already present.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 11e5c24 and 3814912.

⛔ Files ignored due to path filters (6)
  • examples/call/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
  • examples/hello/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
  • examples/messaging/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
  • examples/nft/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
  • examples/swap/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
  • examples/token/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (33)
  • examples/call/contracts/Connected.sol (0 hunks)
  • examples/call/contracts/Universal.sol (0 hunks)
  • examples/call/foundry.toml (0 hunks)
  • examples/call/hardhat.config.ts (1 hunks)
  • examples/call/package.json (2 hunks)
  • examples/call/scripts/localnet.sh (2 hunks)
  • examples/call/test/CallTest.t.sol (1 hunks)
  • examples/hello/contracts/Universal.sol (1 hunks)
  • examples/hello/foundry.toml (0 hunks)
  • examples/hello/package.json (1 hunks)
  • examples/hello/scripts/localnet.sh (1 hunks)
  • examples/hello/test/Universal.t.sol (1 hunks)
  • examples/messaging/package.json (1 hunks)
  • examples/nft/contracts/EVMUniversalNFT.sol (1 hunks)
  • examples/nft/contracts/ZetaChainUniversalNFT.sol (2 hunks)
  • examples/nft/foundry.toml (0 hunks)
  • examples/nft/hardhat.config.ts (1 hunks)
  • examples/nft/package.json (1 hunks)
  • examples/nft/scripts/localnet.sh (2 hunks)
  • examples/nft/test/UniversalNFTTest.t.sol (3 hunks)
  • examples/swap/commands/deploy.ts (1 hunks)
  • examples/swap/contracts/Swap.sol (2 hunks)
  • examples/swap/foundry.toml (1 hunks)
  • examples/swap/package.json (1 hunks)
  • examples/swap/scripts/localnet.sh (1 hunks)
  • examples/swap/test/SwapTest.t.sol (0 hunks)
  • examples/token/contracts/EVMUniversalToken.sol (1 hunks)
  • examples/token/contracts/ZetaChainUniversalToken.sol (1 hunks)
  • examples/token/foundry.toml (0 hunks)
  • examples/token/hardhat.config.ts (1 hunks)
  • examples/token/package.json (1 hunks)
  • examples/token/scripts/localnet.sh (2 hunks)
  • examples/token/test/UniversalTokenTest.t.sol (6 hunks)
💤 Files with no reviewable changes (7)
  • examples/nft/foundry.toml
  • examples/swap/test/SwapTest.t.sol
  • examples/token/foundry.toml
  • examples/hello/foundry.toml
  • examples/call/contracts/Universal.sol
  • examples/call/foundry.toml
  • examples/call/contracts/Connected.sol
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-18T17:59:04.889Z
Learnt from: hernan-clich
PR: zeta-chain/example-contracts#280
File: examples/hello/frontend/src/utils/ethersHelpers.ts:1-6
Timestamp: 2025-09-18T17:59:04.889Z
Learning: Commit 1c6cffd3d29499bf0544987a9116c7c6571ff895 in zeta-chain/example-contracts resolves the noble/hashes esbuild build failure by adding resolutions for "noble/hashes": "1.8.0" and "noble/curves": "1.9.7" to examples/hello/frontend/package.json.

Applied to files:

  • examples/nft/package.json
  • examples/token/package.json
  • examples/hello/package.json
📚 Learning: 2025-09-18T18:00:10.177Z
Learnt from: hernan-clich
PR: zeta-chain/example-contracts#280
File: examples/hello/frontend/src/ConnectedContent.tsx:3-10
Timestamp: 2025-09-18T18:00:10.177Z
Learning: Commit 1c6cffd3d29499bf0544987a9116c7c6571ff895 in zeta-chain/example-contracts#280 successfully resolved the noble/hashes "anumber" export error by adding resolutions in examples/hello/frontend/package.json to pin noble/hashes to 1.8.0 and noble/curves to 1.9.7, eliminating the version conflicts that were causing esbuild build failures.

Applied to files:

  • examples/nft/package.json
⏰ 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). (3)
  • GitHub Check: slither (examples/swap, swap.sarif)
  • GitHub Check: slither (examples/call, call.sarif)
  • GitHub Check: slither (examples/hello, hello.sarif)
🔇 Additional comments (29)
examples/hello/scripts/localnet.sh (1)

3-3: Shell option consolidation is syntactically sound and maintains semantic equivalence.

The change combines three separate shell option commands into a single set -exo pipefail invocation, which is valid bash syntax and produces identical behavior: exit on error (-e), print commands (-x), and pipeline failure propagation (-o pipefail). This aligns well with the PR's simplification objectives.

examples/token/scripts/localnet.sh (4)

3-3: Shell options consolidation follows best practices.

Combining shell options into set -exo pipefail is more concise and maintains proper error handling with pipe failure propagation.


25-31: Registry lookups are well-structured.

The new environment variable extractions for USDC_ETHEREUM, GATEWAY_ETHEREUM, GATEWAY_ZETACHAIN, and WZETA follow consistent jq patterns and correctly target the appropriate chain identifiers (11155112 for Sepolia, 31337 for localnet).


40-40: Verify JSON extraction field consistency across deployment commands.

Line 47 extracts .deployedTo, while lines 40, 54, and 62 extract .contractAddress. This discrepancy suggests either different deployment tool versions or output schemas. Confirm that all extraction paths are correct for the current tool version and that they return the expected contract addresses.

Also applies to: 47-47, 54-54, 62-62


49-55: Verify gateway parameter necessity given PR objectives.

The deployment commands on lines 53 and 61 still pass --gateway parameters (--gateway "$GATEWAY_ETHEREUM" and --gateway "$GATEWAY_BNB"), despite the PR objectives stating that gateway addresses are now "fetched automatically from the registry." Clarify whether:

  1. These parameters are intentionally retained because the deployment tool (as opposed to the contract) requires them for target chain specification, or
  2. These parameters should be removed to align with the stated refactor goals.

Additionally, verify that the ZetaChainUniversalToken deployment (lines 36–40) has correctly removed any gateway or router parameters as intended by this PR.

Also applies to: 57-63

examples/token/hardhat.config.ts (1)

18-18: LGTM: Cancun EVM version targeting added.

The explicit evmVersion: "cancun" setting aligns with the broader PR objective to standardize EVM targeting across examples. This configuration, combined with optimizer and IR settings, ensures production-grade compilation.

examples/nft/hardhat.config.ts (1)

18-18: LGTM: Cancun EVM version targeting added.

The configuration mirrors the token example and correctly targets the Cancun EVM version with appropriate optimizer settings.

examples/call/hardhat.config.ts (1)

11-16: Verify structural inconsistency with other example configurations.

The claim is verified: examples/call/hardhat.config.ts uses a flat configuration structure with settings and version directly under solidity, whereas both examples/token/hardhat.config.ts and examples/nft/hardhat.config.ts employ the compilers array format. The call example is missing the optimizer configuration (enabled: true, runs: 1000) and viaIR: true setting present in both token and nft examples. These omissions will result in suboptimal contract bytecode size and reduced gas efficiency.

Determine whether this structural deviation is intentional for the call example or should be aligned with the token and nft examples. If alignment is required, apply the proposed diff to adopt the production-grade configuration.

examples/messaging/package.json (1)

62-66: Dependency updates align with PR objectives.

The version bumps to @ZetaChain packages (standard-contracts ^4.1.0, toolkit ^16.2.2, zetachain ^7.2.0) are consistent with the broader refactoring to use UniversalContract.sol.

examples/swap/package.json (2)

60-62: Dependency updates support the UniversalContract refactoring.

The protocol-contracts upgrade to 14.1.0-rc1 and toolkit to ^16.2.2 align with the broader changes to consolidate gateway access control through UniversalContract.


60-62: The original review comment is based on an incorrect assumption and should be disregarded.

Swap.sol imports UniversalContract directly from @zetachain/protocol-contracts/contracts/zevm/interfaces/UniversalContract.sol (line 12), not from standard-contracts. The required dependency—protocol-contracts—is already present in the swap example's package.json. While other examples (messaging, nft, token) depend on standard-contracts, the swap example's omission of that package is architecturally correct and intentional, as it imports the interface from protocol-contracts instead.

Likely an incorrect or invalid review comment.

examples/swap/foundry.toml (1)

12-13: Configuration updates align with dependency changes.

The updated remappings correctly point to the new versions of @zetachain/protocol-contracts and @zetachain/toolkit in node_modules. The removal of the EVM version constraint (as noted in the summary) allows the contracts to compile with the default/latest EVM version, which is appropriate for the UniversalContract refactoring.

examples/hello/package.json (1)

58-60: Dependency updates are consistent across examples.

The version bumps match the coordinated upgrade across all examples, supporting the migration to UniversalContract-based initialization and removing gateway parameters.

examples/call/package.json (1)

31-31: Dependency updates align with UniversalContract migration.

The version bumps are consistent with other examples. Note that @zetachain/toolkit is placed in devDependencies here (line 31) while other examples have it in dependencies, which may be intentional based on this example's usage patterns.

Also applies to: 61-65

examples/nft/package.json (1)

59-64: Comprehensive dependency updates support the refactoring.

All four Zetachain packages are updated consistently. Notable: @zetachain/standard-contracts moved from release candidate (4.0.0-rc9) to stable (4.1.0), indicating production readiness of the UniversalContract abstraction.

examples/token/package.json (1)

60-64: Dependency updates mirror NFT example pattern.

The version bumps are identical to the NFT example, with @zetachain/standard-contracts reaching stable 4.1.0. This consistency across examples ensures uniform behavior with the new UniversalContract pattern.

examples/swap/commands/deploy.ts (1)

23-26: Gateway parameter successfully removed from initialization.

The initialize call now correctly excludes the gateway address, aligning with the PR's objective to use UniversalContract's built-in permission logic. The remaining parameters (uniswapRouter, gasLimit, owner) are properly ordered.

examples/call/scripts/localnet.sh (2)

3-3: LGTM: Shell options consolidated.

Consolidating shell options into a single set -exo pipefail command improves readability and follows standard bash best practices.


21-25: LGTM: Universal deployment simplified.

The Universal contract deployment correctly reflects the parameterless constructor, aligning with the PR's objective to remove explicit gateway parameters.

examples/call/test/CallTest.t.sol (1)

24-24: LGTM: Universal instantiation updated correctly.

The parameterless Universal constructor invocation aligns with the refactored Universal.sol that no longer requires explicit gateway initialization.

examples/token/contracts/ZetaChainUniversalToken.sol (1)

33-45: LGTM: Initialization simplified for ZetaChain deployment.

The removal of gatewayAddress and uniswapRouterAddress parameters, with core initialization now requiring only gas, aligns with the PR's objective to eliminate explicit gateway parameters and fetch addresses automatically from the registry.

examples/nft/contracts/EVMUniversalNFT.sol (1)

34-48: Verify parameter order consistency.

Similar to EVMUniversalToken, the initialize signature has reordered parameters. Ensure that the __UniversalNFTCore_init call on Line 48 matches the expected parameter order in the core contract.

examples/token/test/UniversalTokenTest.t.sol (1)

16-69: LGTM: Test setup updated for new initialization signatures.

The test correctly reflects the updated initialize signatures for both ZetaChainUniversalToken (gas-only) and EVMUniversalToken (reordered parameters), ensuring test coverage aligns with the refactored contracts.

examples/swap/scripts/localnet.sh (1)

3-3: LGTM: Shell options consolidated.

Consolidating shell options into a single set -exo pipefail command follows bash best practices and improves script readability.

examples/hello/test/Universal.t.sol (1)

14-14: LGTM: Universal instantiation simplified.

The parameterless constructor invocation correctly reflects the refactored Universal contract that no longer requires explicit gateway initialization.

examples/token/contracts/EVMUniversalToken.sol (1)

28-41: Verify that the parameter order in the __UniversalTokenCore_init call matches the external contract's expected signature.

Parameter order discrepancy detected: the initialize function signature declares parameters as (address initialOwner, string memory name, string memory symbol, uint256 gas, address payable gatewayAddress), but line 40 calls __UniversalTokenCore_init(gatewayAddress, address(this), gas) with a different parameter sequence. Confirm the actual function signature in @zetachain/standard-contracts v4.1.0's EVM UniversalTokenCore contract to ensure the call parameters are passed in the correct order.

examples/nft/test/UniversalNFTTest.t.sol (1)

21-57: Test initialization updates are consistent with contract changes.

The test setup correctly reflects the new initialize signatures:

  • ZetaChainUniversalNFT.initialize now accepts 4 parameters (removed gateway/router addresses, added gas)
  • EVMUniversalNFT.initialize accepts 5 parameters (gas added, gateway retained as last parameter)

The gas value of 500000 is used consistently and appears reasonable for cross-chain operations.

examples/swap/contracts/Swap.sol (2)

247-271: onRevert function also relies on UniversalContract.

The onRevert function (line 247) uses the onlyGateway modifier and references the gateway variable (line 259), consistent with the pattern in onCall and withdraw. The same verification comments above apply here.


62-67: No changes required to the onCall function signature.

The onlyGateway modifier is part of ZetaChain's UniversalContract interface and restricts execution so only the Gateway contract can invoke the function. The Swap.sol implementation correctly inherits from UniversalContract (imported from @zetachain/protocol-contracts), and the function signature at lines 62–67 properly applies both the override keyword and the onlyGateway modifier. This pattern is consistent across multiple contracts in the codebase (e.g., examples/hello/contracts/Universal.sol, examples/call/contracts/Universal.sol) and aligns with ZetaChain's cross-chain execution model.

GATEWAY_ZETACHAIN=$(jq -r '."31337".contracts[] | select(.contractType == "gateway") | .address' ~/.zetachain/localnet/registry.json) && echo $GATEWAY_ZETACHAIN
GATEWAY_ETHEREUM=$(jq -r '."11155112".contracts[] | select(.contractType == "gateway") | .address' ~/.zetachain/localnet/registry.json) && echo $GATEWAY_ETHEREUM
ZRC20_ETHEREUM=$(jq -r '."11155112".zrc20Tokens[] | select(.coinType == "gas" and .originChainId == "11155112") | .address' ~/.zetachain/localnet/registry.json) && echo $ZRC20_ETHEREUM
USDC_ETHEREUM=$(jq -r '."11155112".zrc20Tokens[] | select(.symbol == "USDC.ETH") | .address' ~/.zetachain/localnet/registry.json) && echo $USDC_ETHEREUM
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify that newly introduced variables are actively used.

The script now fetches USDC_ETHEREUM (line 25), GATEWAY_ZETACHAIN (line 28), and WZETA (line 30), but these variables are not visibly referenced in the provided script section. Confirm whether these are intended for external tool consumption, future expansion, or if they represent dead code that should be removed.

Run the following script to verify usage of these variables:

Also applies to: 28-28, 30-30


🏁 Script executed:

#!/bin/bash
# Description: Check if USDC_ETHEREUM, GATEWAY_ZETACHAIN, and WZETA are used anywhere in the script.

# Search for usages of the new variables
grep -n 'USDC_ETHEREUM\|GATEWAY_ZETACHAIN\|WZETA' examples/nft/scripts/localnet.sh | grep -v '^[0-9]*:[A-Z_]*=.*#\|^[0-9]*:[A-Z_]*=.*$'

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Display the entire localnet.sh file to inspect all variable usages
cat examples/nft/scripts/localnet.sh

Length of output: 6220


🏁 Script executed:

#!/bin/bash
# Search for all occurrences of the three variables with line numbers and context
echo "=== All occurrences of USDC_ETHEREUM ==="
grep -n "USDC_ETHEREUM" examples/nft/scripts/localnet.sh

echo "=== All occurrences of GATEWAY_ZETACHAIN ==="
grep -n "GATEWAY_ZETACHAIN" examples/nft/scripts/localnet.sh

echo "=== All occurrences of WZETA ==="
grep -n "WZETA" examples/nft/scripts/localnet.sh

Length of output: 582


Remove unused variable assignments at lines 25, 28, and 30.

The variables USDC_ETHEREUM, GATEWAY_ZETACHAIN, and WZETA are assigned and immediately echoed but never referenced in subsequent script operations. These represent dead code and should be removed. In contrast, actively used variables like ZRC20_ETHEREUM, GATEWAY_ETHEREUM, and GATEWAY_BNB appear in actual command invocations (e.g., cast send calls and deployment parameters), confirming this is genuine unused code rather than forward-looking declarations. Additionally, UNISWAP_ROUTER (line 29) follows the same unused pattern and should likewise be removed.

@fadeev
Copy link
Member Author

fadeev commented Oct 27, 2025

@hernan-clich please, review.

Copy link
Member

@hernan-clich hernan-clich left a comment

Choose a reason for hiding this comment

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

Concept ACK

Tested deploying a Hello example contract and using in the example frontend, works perfectly fine.

"@solana/web3.js": "^1.95.8",
"@zetachain/networks": "13.0.0-rc1",
"@zetachain/protocol-contracts": "13.0.0",
"@zetachain/protocol-contracts": "14.1.0-rc1",
Copy link
Member

Choose a reason for hiding this comment

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

Can we use a stable release for these examples?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good call! b37db41

"@zetachain/protocol-contracts": "13.0.0",
"@zetachain/standard-contracts": "3.0.0",
"@zetachain/toolkit": "^16.0.0",
"@zetachain/standard-contracts": "^4.1.0",
Copy link
Member

Choose a reason for hiding this comment

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

Is this a typo? Other examples use v14.1.0 so I assume there's a 1 missing before the 4

Copy link
Member Author

Choose a reason for hiding this comment

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

These are "standard" contracts, which are 4.1.0 (not protocol contracts, which are 14.1.0).

@fadeev fadeev merged commit 3c74e59 into main Oct 27, 2025
21 checks passed
@fadeev fadeev deleted the abstract-universal-contract branch October 27, 2025 16:15
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.

3 participants