Skip to content
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

Gateway testnet #207

Merged
merged 14 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/hello/contracts/Hello.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ contract Hello is UniversalContract {
gateway = GatewayZEVM(gatewayAddress);
}

function onCrossChainCall(
zContext calldata context,
function onCall(
MessageContext calldata context,
Comment on lines +20 to +21
Copy link

Choose a reason for hiding this comment

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

πŸ’‘ Codebase verification

API Evolution Requires Attention: Legacy Contracts Found

The verification reveals that legacy contracts in the omnichain/swap/ directory still use the old onCrossChainCall function with zContext parameter type. Specifically:

  • omnichain/swap/contracts/Swap.sol
  • omnichain/swap/contracts/SwapToAnyToken.sol

This indicates a breaking change in the contract interface from zContract to UniversalContract, where newer examples use the updated onCall with MessageContext. To maintain protocol consistency:

  1. Update the legacy contracts in omnichain/swap/ to use the new interface
  2. Update corresponding test files that call onCrossChainCall
  3. Consider deprecating the zContract interface in favor of UniversalContract
πŸ”— Analysis chain

Verify migration steps for onCall function signature change.

The function signature change from onCrossChainCall to onCall with MessageContext parameter type might impact existing deployments. Ensure that:

  1. Protocol documentation is updated to reflect this change
  2. Migration guide is provided for existing implementations
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other contracts that might need similar updates
rg -l "onCrossChainCall" --type sol

# Check if there are any remaining references to zContext
rg -l "zContext" --type sol

Length of output: 119


Script:

#!/bin/bash
# Search for Solidity files first
fd -e sol

# Then search for function and type references without file type filter
rg "onCrossChainCall" 
rg "zContext"

# Look for any interface definitions that might show the evolution of the API
rg "interface.*Contract" -A 5

Length of output: 4767

address zrc20,
uint256 amount,
bytes calldata message
Expand Down
6 changes: 3 additions & 3 deletions examples/hello/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"test": "echo \"Error: no test specified\" && exit 1",
"lint:fix": "npx eslint . --ext .js,.ts --fix",
"lint": "npx eslint . --ext .js,.ts",
"deploy": "npx hardhat compile --force && npx hardhat deploy --network localhost && npx hardhat deploy --name Echo --network localhost --gateway 0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0"
"deploy:localnet": "npx hardhat compile --force && npx hardhat deploy --network localhost --gateway 0x9A676e781A523b5d0C0e43731313A708CB607508 && npx hardhat deploy --name Echo --network localhost --gateway 0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0"
Copy link

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

Add deployment scripts for testnets mentioned in PR objectives.

The current script only handles localhost deployment. Consider adding separate scripts for Base Sepolia, Polygon Amoy, and ZetaChain testnet deployments to align with the PR objectives.

 "scripts": {
   "deploy:localnet": "npx hardhat compile --force && npx hardhat deploy --network localhost --gateway 0x9A676e781A523b5d0C0e43731313A708CB607508 && npx hardhat deploy --name Echo --network localhost --gateway 0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0",
+  "deploy:base-sepolia": "npx hardhat compile --force && npx hardhat deploy --network base-sepolia",
+  "deploy:polygon-amoy": "npx hardhat compile --force && npx hardhat deploy --network polygon-amoy",
+  "deploy:zeta-testnet": "npx hardhat compile --force && npx hardhat deploy --network zeta-testnet"
 }

Committable suggestion was skipped due to low confidence.

},
"keywords": [],
"author": "",
Expand Down Expand Up @@ -57,6 +57,6 @@
"@solana-developers/helpers": "^2.4.0",
"@solana/spl-memo": "^0.2.5",
"@solana/web3.js": "^1.95.2",
"@zetachain/protocol-contracts": "10.0.0-rc10"
"@zetachain/protocol-contracts": "10.0.0-rc11"
}
}
}
4 changes: 2 additions & 2 deletions examples/hello/tasks/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ task("deploy", "Deploy the contract", main)
.addOptionalParam("name", "Contract to deploy", "Hello")
.addOptionalParam(
"gateway",
"Gateway address (default: ZetaChain Gateway)",
"0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0"
"Gateway address (default: ZetaChain Gateway on testnet)",
"0x6c533f7fe93fae114d0954697069df33c9b74fd7"
Comment on lines +34 to +35
Copy link

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

Consider using environment-specific gateway addresses

While the updated gateway address is correct for the testnet, hardcoding it directly in the task definition might cause issues when deploying to different environments. Consider implementing a more flexible configuration approach.

Here's a suggested implementation using network-specific configuration:

+ const GATEWAY_ADDRESSES = {
+   baseSepolia: "0x6c533f7fe93fae114d0954697069df33c9b74fd7",
+   polygonAmoy: "0x...", // Add Polygon Amoy gateway address
+   zetaChainTestnet: "0x...", // Add ZetaChain testnet gateway address
+ };

task("deploy", "Deploy the contract", main)
  .addFlag("json", "Output in JSON")
  .addOptionalParam("name", "Contract to deploy", "Hello")
  .addOptionalParam(
    "gateway",
-   "Gateway address (default: ZetaChain Gateway on testnet)",
-   "0x6c533f7fe93fae114d0954697069df33c9b74fd7"
+   "Gateway address (defaults to network-specific gateway address)",
+   undefined,
    types.string
  );

Then update the main function to use network-specific addresses:

const main = async (args: any, hre: HardhatRuntimeEnvironment) => {
  const network = hre.network.name;
  const gatewayAddress = args.gateway || GATEWAY_ADDRESSES[network];
  
  if (!gatewayAddress) {
    throw new Error(`No gateway address configured for network: ${network}`);
  }
  
  // ... rest of the deployment logic
  const contract = await (factory as any).deploy(gatewayAddress);

πŸ’‘ Codebase verification

Different gateway addresses detected across examples

The hello and NFT examples are using different gateway addresses:

  • Hello example: 0x6c533f7fe93fae114d0954697069df33c9b74fd7
  • NFT example: 0x5FC8d32690cc91D4c39d9d3abcBD16989F875707

This inconsistency in gateway addresses between examples should be addressed to prevent confusion. Consider:

  • Using the same gateway address across examples if they target the same network
  • Adding clear documentation about which network each gateway address corresponds to
  • Using environment variables or configuration files to manage network-specific addresses
πŸ”— Analysis chain

Verify gateway address usage across networks

Let's verify how this gateway address is being used across different networks to ensure consistency.


Let me check the gateway address configuration in the NFT example to get a complete picture.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for gateway address usage across the codebase
echo "Searching for gateway address references..."
rg -i "0x6c533f7fe93fae114d0954697069df33c9b74fd7"

echo "\nSearching for potential gateway configurations..."
rg -l "gateway.*address" --type ts

Length of output: 406


Script:

#!/bin/bash
# Check the gateway address configuration in the NFT example
echo "Content of examples/nft/tasks/deploy.ts:"
cat examples/nft/tasks/deploy.ts

Length of output: 1498

);
10 changes: 10 additions & 0 deletions examples/hello/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2433,6 +2433,16 @@
"@openzeppelin/contracts-upgradeable" "^5.0.2"
ethers "^6.13.1"

"@zetachain/[email protected]":
version "10.0.0-rc11"
resolved "https://registry.yarnpkg.com/@zetachain/protocol-contracts/-/protocol-contracts-10.0.0-rc11.tgz#53f55ead492f7b5802b1feae4e51abc75730af33"
integrity sha512-qWazjqnIGRngf4OmyeSIv7sHICQRdMQ1CKPIQIqxA8qFR+gHhDHSfvMdRAvgWbsfkimXOIFiHVIATypyWhviJw==
dependencies:
"@openzeppelin/contracts" "^5.0.2"
"@openzeppelin/contracts-upgradeable" "^5.0.2"
"@zetachain/networks" "^10.0.0"
ethers "^6.13.1"

"@zetachain/[email protected]":
version "9.0.0"
resolved "https://registry.yarnpkg.com/@zetachain/protocol-contracts/-/protocol-contracts-9.0.0.tgz#c20ad5da43f6f3676f31556b303d1cb4ea17357e"
Expand Down
6 changes: 6 additions & 0 deletions examples/nft/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.yarn
artifacts
cache
coverage
node_modules
typechain-types
47 changes: 47 additions & 0 deletions examples/nft/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const path = require("path");

/**
* @type {import("eslint").Linter.Config}
*/
module.exports = {
env: {
browser: false,
es2021: true,
mocha: true,
node: true,
},
extends: ["plugin:prettier/recommended"],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 12,
},
plugins: [
"@typescript-eslint",
"prettier",
"simple-import-sort",
"sort-keys-fix",
"typescript-sort-keys",
],
Comment on lines +18 to +24
Copy link

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

Consider adding error prevention plugins

While the current plugins focus on code organization and formatting, consider adding plugins for error prevention:

  plugins: [
    "@typescript-eslint",
    "prettier",
    "simple-import-sort",
    "sort-keys-fix",
    "typescript-sort-keys",
+   "eslint-plugin-import",
+   "eslint-plugin-promise",
+   "eslint-plugin-security"
  ],
πŸ“ 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.

Suggested change
plugins: [
"@typescript-eslint",
"prettier",
"simple-import-sort",
"sort-keys-fix",
"typescript-sort-keys",
],
plugins: [
"@typescript-eslint",
"prettier",
"simple-import-sort",
"sort-keys-fix",
"typescript-sort-keys",
"eslint-plugin-import",
"eslint-plugin-promise",
"eslint-plugin-security"
],

rules: {
"@typescript-eslint/sort-type-union-intersection-members": "error",
camelcase: "off",
"simple-import-sort/exports": "error",
"simple-import-sort/imports": "error",
"sort-keys-fix/sort-keys-fix": "error",
"typescript-sort-keys/interface": "error",
"typescript-sort-keys/string-enum": "error",
},
Comment on lines +25 to +33
Copy link

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

Consider strengthening TypeScript-specific rules

The current rules focus on sorting and formatting. Consider adding stricter TypeScript-specific rules for better type safety.

  rules: {
    "@typescript-eslint/sort-type-union-intersection-members": "error",
+   "@typescript-eslint/explicit-function-return-type": "error",
+   "@typescript-eslint/no-explicit-any": "error",
+   "@typescript-eslint/strict-boolean-expressions": "error",
    camelcase: "off",
    "simple-import-sort/exports": "error",
    "simple-import-sort/imports": "error",
    "sort-keys-fix/sort-keys-fix": "error",
    "typescript-sort-keys/interface": "error",
    "typescript-sort-keys/string-enum": "error",
  },
πŸ“ 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.

Suggested change
rules: {
"@typescript-eslint/sort-type-union-intersection-members": "error",
camelcase: "off",
"simple-import-sort/exports": "error",
"simple-import-sort/imports": "error",
"sort-keys-fix/sort-keys-fix": "error",
"typescript-sort-keys/interface": "error",
"typescript-sort-keys/string-enum": "error",
},
rules: {
"@typescript-eslint/sort-type-union-intersection-members": "error",
"@typescript-eslint/explicit-function-return-type": "error",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/strict-boolean-expressions": "error",
camelcase: "off",
"simple-import-sort/exports": "error",
"simple-import-sort/imports": "error",
"sort-keys-fix/sort-keys-fix": "error",
"typescript-sort-keys/interface": "error",
"typescript-sort-keys/string-enum": "error",
},

settings: {
"import/parsers": {
"@typescript-eslint/parser": [".js", ".jsx", ".ts", ".tsx", ".d.ts"],
},
"import/resolver": {
node: {
extensions: [".js", ".jsx", ".ts", ".tsx", ".d.ts"],
},
typescript: {
project: path.join(__dirname, "tsconfig.json"),
},
},
},
};
17 changes: 17 additions & 0 deletions examples/nft/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
node_modules
.env
coverage
coverage.json
typechain
typechain-types
dependencies

# Hardhat files
cache
artifacts

# Foundry files
out
cache_forge

access_token
21 changes: 21 additions & 0 deletions examples/nft/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2023 ZetaChain

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
4 changes: 4 additions & 0 deletions examples/nft/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# NFT Example

This example currently only works with localnet `v4.0.0-rc*`, which supports
authenticated calls and multiple EVM chains.
136 changes: 136 additions & 0 deletions examples/nft/contracts/Connected.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
Copy link

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

Remove unused import of ERC721Burnable.sol

The import statement for ERC721Burnable.sol is unnecessary since the contract does not inherit from ERC721Burnable. Removing it will clean up the code and avoid confusion.

Apply this diff to remove the unused import:

- import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
πŸ“ 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.

Suggested change
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";

import "@zetachain/protocol-contracts/contracts/evm/GatewayEVM.sol";
import {RevertContext} from "@zetachain/protocol-contracts/contracts/Revert.sol";

contract Connected is ERC721, ERC721Enumerable, ERC721URIStorage, Ownable {
GatewayEVM public immutable gateway;
uint256 private _nextTokenId;
address public counterparty;

function setCounterparty(address contractAddress) external onlyOwner {
counterparty = contractAddress;
}

constructor(
address payable gatewayAddress,
address initialOwner
) ERC721("MyToken", "MTK") Ownable(initialOwner) {
gateway = GatewayEVM(gatewayAddress);
}

function safeMint(address to, string memory uri) public onlyOwner {
uint256 hash = uint256(
keccak256(
abi.encodePacked(address(this), block.number, _nextTokenId++)
)
);

uint256 tokenId = hash & 0x00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}
Comment on lines +28 to +39
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Review the token ID generation method for potential collisions

The safeMint function generates a token ID using a hash of the contract address, block number, and an incrementing _nextTokenId, then applies a mask. While this approach aims to create unique token IDs, there is a possibility of collisions due to the masking operation.

Suggestion:

  • Consider using the incrementing _nextTokenId directly as the tokenId. This approach is simple, efficient, and ensures uniqueness without the risk of collisions.
  • If a more complex token ID is required, ensure that the hashing and masking mechanism provides sufficient entropy and collision resistance.

Apply this diff to use _nextTokenId directly:

function safeMint(address to, string memory uri) public onlyOwner {
-     uint256 hash = uint256(
-         keccak256(
-             abi.encodePacked(address(this), block.number, _nextTokenId++)
-         )
-     );
-
-     uint256 tokenId = hash & 0x00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
+     uint256 tokenId = _nextTokenId++;
      _safeMint(to, tokenId);
      _setTokenURI(tokenId, uri);
}
πŸ“ 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.

Suggested change
function safeMint(address to, string memory uri) public onlyOwner {
uint256 hash = uint256(
keccak256(
abi.encodePacked(address(this), block.number, _nextTokenId++)
)
);
uint256 tokenId = hash & 0x00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}
function safeMint(address to, string memory uri) public onlyOwner {
uint256 tokenId = _nextTokenId++;
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}


function transferCrossChain(
uint256 tokenId,
address receiver,
address destination
) external payable {
string memory uri = tokenURI(tokenId);
_burn(tokenId);
bytes memory encodedData = abi.encode(
tokenId,
msg.sender,
uri,
destination
);

RevertOptions memory revertOptions = RevertOptions(
address(this),
true,
address(0),
encodedData,
0
);

if (destination == address(0)) {
gateway.call(receiver, encodedData, revertOptions);
} else {
gateway.depositAndCall{value: msg.value}(
receiver,
encodedData,
revertOptions
);
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add ownership check to prevent unauthorized token transfers

The transferCrossChain function lacks a check to verify that the caller owns the tokenId. Without this verification, any user could potentially transfer and burn tokens they do not own, leading to security vulnerabilities.

Apply this diff to include an ownership check:

function transferCrossChain(
    uint256 tokenId,
    address receiver,
    address destination
) external payable {
+     require(ownerOf(tokenId) == msg.sender, "Caller is not the token owner");
      string memory uri = tokenURI(tokenId);
      _burn(tokenId);
      // ...
}

Committable suggestion was skipped due to low confidence.


function onCall(
MessageContext calldata messageContext,
bytes calldata message
) external payable returns (bytes4) {
if (messageContext.sender != counterparty) revert("Unauthorized");

(uint256 tokenId, address sender, string memory uri) = abi.decode(
message,
(uint256, address, string)
);
_safeMint(sender, tokenId);
_setTokenURI(tokenId, uri);
return "";
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Restrict onCall to be callable only by the trusted gateway

The onCall function checks messageContext.sender against counterparty but does not verify that msg.sender is the gateway contract. This omission could allow unauthorized contracts to call onCall and bypass the intended access control.

Apply this diff to ensure only the gateway can invoke onCall:

function onCall(
    MessageContext calldata messageContext,
    bytes calldata message
) external payable returns (bytes4) {
+     require(msg.sender == address(gateway), "Caller is not the gateway");
      if (messageContext.sender != counterparty) revert("Unauthorized");
      // ...
}
πŸ“ 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.

Suggested change
function onCall(
MessageContext calldata messageContext,
bytes calldata message
) external payable returns (bytes4) {
if (messageContext.sender != counterparty) revert("Unauthorized");
(uint256 tokenId, address sender, string memory uri) = abi.decode(
message,
(uint256, address, string)
);
_safeMint(sender, tokenId);
_setTokenURI(tokenId, uri);
return "";
}
function onCall(
MessageContext calldata messageContext,
bytes calldata message
) external payable returns (bytes4) {
require(msg.sender == address(gateway), "Caller is not the gateway");
if (messageContext.sender != counterparty) revert("Unauthorized");
(uint256 tokenId, address sender, string memory uri) = abi.decode(
message,
(uint256, address, string)
);
_safeMint(sender, tokenId);
_setTokenURI(tokenId, uri);
return "";
}


function onRevert(RevertContext calldata context) external {
(uint256 tokenId, address sender, string memory uri) = abi.decode(
context.revertMessage,
(uint256, address, string)
);

_safeMint(sender, tokenId);
_setTokenURI(tokenId, uri);
}
Comment on lines +89 to +97
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Restrict onRevert to be callable only by the trusted gateway

Similar to onCall, the onRevert function does not check if msg.sender is the gateway contract. This could allow malicious actors to trigger onRevert, causing unintended minting of tokens.

Apply this diff to enforce that only the gateway can call onRevert:

function onRevert(RevertContext calldata context) external {
+     require(msg.sender == address(gateway), "Caller is not the gateway");
      // ...
}
πŸ“ 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.

Suggested change
function onRevert(RevertContext calldata context) external {
(uint256 tokenId, address sender, string memory uri) = abi.decode(
context.revertMessage,
(uint256, address, string)
);
_safeMint(sender, tokenId);
_setTokenURI(tokenId, uri);
}
function onRevert(RevertContext calldata context) external {
require(msg.sender == address(gateway), "Caller is not the gateway");
(uint256 tokenId, address sender, string memory uri) = abi.decode(
context.revertMessage,
(uint256, address, string)
);
_safeMint(sender, tokenId);
_setTokenURI(tokenId, uri);
}


receive() external payable {}

fallback() external payable {}

// The following functions are overrides required by Solidity.

function _update(
address to,
uint256 tokenId,
address auth
) internal override(ERC721, ERC721Enumerable) returns (address) {
return super._update(to, tokenId, auth);
}

function _increaseBalance(
address account,
uint128 value
) internal override(ERC721, ERC721Enumerable) {
super._increaseBalance(account, value);
}

function tokenURI(
uint256 tokenId
) public view override(ERC721, ERC721URIStorage) returns (string memory) {
return super.tokenURI(tokenId);
}

function supportsInterface(
bytes4 interfaceId
)
public
view
override(ERC721, ERC721Enumerable, ERC721URIStorage)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}
Loading
Loading