-
Notifications
You must be signed in to change notification settings - Fork 50
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
ERC-20 token transfer example and improvements to NFT #209
Changes from all commits
55c7031
012c5e6
72ff65b
2715a72
b4f8749
e360b47
95914a5
ee7ad2f
7d73ae0
bdacd74
0f5ad41
9108b37
8affa13
e959412
c01dac3
49dbabc
a26a56d
ee5ce68
5de7d5f
0adfb61
3bbcab0
e5f9b6f
fb8e5a8
fbed6dc
726f485
246361d
a98517d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -59,4 +59,4 @@ | |
"@solana/web3.js": "^1.95.2", | ||
"@zetachain/protocol-contracts": "10.0.0-rc11" | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2434,6 +2434,16 @@ | |
"@zetachain/networks" "^10.0.0" | ||
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" | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -65,7 +65,7 @@ contract Connected is | |||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
string memory uri = tokenURI(tokenId); | ||||||||||||||||||||||||||||||||||||||||
_burn(tokenId); | ||||||||||||||||||||||||||||||||||||||||
bytes memory message = abi.encode(tokenId, receiver, uri, destination); | ||||||||||||||||||||||||||||||||||||||||
bytes memory message = abi.encode(destination, receiver, tokenId, uri); | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
RevertOptions memory revertOptions = RevertOptions( | ||||||||||||||||||||||||||||||||||||||||
address(this), | ||||||||||||||||||||||||||||||||||||||||
|
@@ -85,7 +85,7 @@ contract Connected is | |||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
emit TokenTransfer(tokenId, receiver, destination, uri); | ||||||||||||||||||||||||||||||||||||||||
emit TokenTransfer(destination, receiver, tokenId, uri); | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
function onCall( | ||||||||||||||||||||||||||||||||||||||||
|
@@ -94,26 +94,26 @@ contract Connected is | |||||||||||||||||||||||||||||||||||||||
) external payable onlyGateway returns (bytes4) { | ||||||||||||||||||||||||||||||||||||||||
if (context.sender != counterparty) revert Unauthorized(); | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
(uint256 tokenId, address receiver, string memory uri) = abi.decode( | ||||||||||||||||||||||||||||||||||||||||
(address receiver, uint256 tokenId, string memory uri) = abi.decode( | ||||||||||||||||||||||||||||||||||||||||
message, | ||||||||||||||||||||||||||||||||||||||||
(uint256, address, string) | ||||||||||||||||||||||||||||||||||||||||
(address, uint256, string) | ||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
_safeMint(receiver, tokenId); | ||||||||||||||||||||||||||||||||||||||||
_setTokenURI(tokenId, uri); | ||||||||||||||||||||||||||||||||||||||||
emit TokenTransferReceived(tokenId, receiver, uri); | ||||||||||||||||||||||||||||||||||||||||
emit TokenTransferReceived(receiver, tokenId, uri); | ||||||||||||||||||||||||||||||||||||||||
return ""; | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
function onRevert(RevertContext calldata context) external onlyGateway { | ||||||||||||||||||||||||||||||||||||||||
(uint256 tokenId, address sender, string memory uri) = abi.decode( | ||||||||||||||||||||||||||||||||||||||||
(address sender, uint256 tokenId, string memory uri) = abi.decode( | ||||||||||||||||||||||||||||||||||||||||
context.revertMessage, | ||||||||||||||||||||||||||||||||||||||||
(uint256, address, string) | ||||||||||||||||||||||||||||||||||||||||
(address, uint256, string) | ||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
_safeMint(sender, tokenId); | ||||||||||||||||||||||||||||||||||||||||
_setTokenURI(tokenId, uri); | ||||||||||||||||||||||||||||||||||||||||
emit TokenTransferReverted(tokenId, sender, uri); | ||||||||||||||||||||||||||||||||||||||||
emit TokenTransferReverted(sender, tokenId, uri); | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
+109
to
+116
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐ ๏ธ Refactor suggestion Add address validation in onRevert function. For consistency with onCall and other functions, add validation for the decoded sender address. (address sender, uint256 tokenId, string memory uri) = abi.decode(
context.revertMessage,
(address, uint256, string)
);
+if (sender == address(0)) revert InvalidAddress();
_safeMint(sender, tokenId); ๐ Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
receive() external payable {} | ||||||||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -79,7 +79,7 @@ contract Universal is | |
!IZRC20(destination).transferFrom(msg.sender, address(this), gasFee) | ||
) revert TransferFailed(); | ||
IZRC20(destination).approve(address(gateway), gasFee); | ||
bytes memory message = abi.encode(tokenId, receiver, uri); | ||
bytes memory message = abi.encode(receiver, tokenId, uri); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐ก Codebase verification Parameter ordering inconsistency detected between Universal and Connected contracts The parameter ordering differs between the contracts:
This inconsistency in message encoding could lead to cross-chain transfer failures. The Connected contract expects an additional ๐ Analysis chainParameter reordering looks good, verify cross-chain compatibility. The reordering of parameters in message encoding and event emission maintains internal consistency. The sequence (receiver, tokenId, uri) is now uniform throughout the contract. Let's verify the parameter order consistency in connected contracts: Also applies to: 102-102 ๐ Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Search for message encoding patterns in connected contracts
rg -A 2 "abi\.encode.*receiver.*tokenId.*uri" --type sol
Length of output: 86 Script: #!/bin/bash
# Search for message encoding patterns in all files
rg -A 2 "abi\.encode.*receiver.*tokenId.*uri"
# Also search for message decoding patterns
rg -A 2 "abi\.decode.*receiver.*tokenId.*uri"
# Search for any abi.encode patterns to analyze parameter ordering
rg -A 2 "abi\.encode"
Length of output: 3355 |
||
|
||
CallOptions memory callOptions = CallOptions(gasLimit, false); | ||
|
||
|
@@ -99,7 +99,7 @@ contract Universal is | |
revertOptions | ||
); | ||
|
||
emit TokenTransfer(tokenId, receiver, destination, uri); | ||
emit TokenTransfer(receiver, destination, tokenId, uri); | ||
} | ||
|
||
function safeMint(address to, string memory uri) public onlyOwner { | ||
|
@@ -125,16 +125,16 @@ contract Universal is | |
revert("Unauthorized"); | ||
|
||
( | ||
uint256 tokenId, | ||
address destination, | ||
address sender, | ||
string memory uri, | ||
address destination | ||
) = abi.decode(message, (uint256, address, string, address)); | ||
uint256 tokenId, | ||
string memory uri | ||
) = abi.decode(message, (address, address, uint256, string)); | ||
|
||
if (destination == address(0)) { | ||
_safeMint(sender, tokenId); | ||
_setTokenURI(tokenId, uri); | ||
emit TokenTransferReceived(tokenId, sender, uri); | ||
emit TokenTransferReceived(sender, tokenId, uri); | ||
} else { | ||
(, uint256 gasFee) = IZRC20(destination).withdrawGasFeeWithGasLimit( | ||
gasLimit | ||
|
@@ -152,23 +152,23 @@ contract Universal is | |
gateway.call( | ||
counterparty[destination], | ||
destination, | ||
abi.encode(tokenId, sender, uri), | ||
abi.encode(sender, tokenId, uri), | ||
CallOptions(gasLimit, false), | ||
RevertOptions(address(0), false, address(0), "", 0) | ||
); | ||
emit TokenTransferToDestination(tokenId, sender, destination, uri); | ||
emit TokenTransferToDestination(sender, destination, tokenId, uri); | ||
} | ||
} | ||
|
||
function onRevert(RevertContext calldata context) external onlyGateway { | ||
(uint256 tokenId, address sender, string memory uri) = abi.decode( | ||
(address sender, uint256 tokenId, string memory uri) = abi.decode( | ||
context.revertMessage, | ||
(uint256, address, string) | ||
(address, uint256, string) | ||
); | ||
|
||
_safeMint(sender, tokenId); | ||
_setTokenURI(tokenId, uri); | ||
emit TokenTransferReverted(tokenId, sender, uri); | ||
emit TokenTransferReverted(sender, tokenId, uri); | ||
} | ||
|
||
// The following functions are overrides required by Solidity. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,26 +5,26 @@ contract Events { | |
event SetCounterparty(address indexed newCounterparty); | ||
event TokenMinted(address indexed to, uint256 indexed tokenId, string uri); | ||
event TokenTransfer( | ||
uint256 indexed tokenId, | ||
address indexed receiver, | ||
address indexed destination, | ||
address indexed receiver, | ||
uint256 indexed tokenId, | ||
string uri | ||
); | ||
event TokenTransferReceived( | ||
uint256 indexed tokenId, | ||
address indexed receiver, | ||
uint256 indexed tokenId, | ||
string uri | ||
); | ||
event TokenTransferReverted( | ||
uint256 indexed tokenId, | ||
address indexed sender, | ||
uint256 indexed tokenId, | ||
string uri | ||
); | ||
event CounterpartySet(address indexed zrc20, bytes indexed contractAddress); | ||
event TokenTransferToDestination( | ||
uint256 indexed tokenId, | ||
address indexed sender, | ||
address indexed destination, | ||
address indexed sender, | ||
uint256 indexed tokenId, | ||
string uri | ||
); | ||
Comment on lines
8
to
29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐ก Codebase verification Parameter mismatch detected in TokenTransfer event between declaration and usage The verification reveals inconsistencies in event parameter ordering:
This mismatch could lead to incorrect event handling by external listeners and should be corrected to maintain consistency with the event declaration in ๐ Analysis chainVerify event parameter alignment with external contracts. The parameter reordering appears to align with changes in the Connected and Universal contracts mentioned in the summary. However, it's crucial to verify this alignment to prevent any potential event handling issues. Let me gather more information about the event declarations to complete the verification. ๐ Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Description: Verify event parameter ordering consistency across related contracts
# Expected: Parameter ordering should match in event emissions and declarations
# Search for event emissions in related contracts
echo "Checking event emissions in contracts:"
rg -A 2 "emit Token(Transfer|TransferReceived|TransferReverted|TransferToDestination)"
# Search for interface definitions that might be listening to these events
echo "Checking interface definitions:"
ast-grep --pattern 'interface $_ {
$$$
event Token$_(address indexed $_, $$$);
$$$
}'
Length of output: 2702 Script: #!/bin/bash
# Search for event declarations in all contracts
echo "Checking event declarations in contracts:"
rg -A 3 "event Token(Transfer|TransferReceived|TransferReverted|TransferToDestination)" --type sol
# Search specifically in the shared Events.sol files
echo -e "\nChecking Events.sol files:"
fd "Events.sol" --exec cat {}
Length of output: 1911 |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2172,6 +2172,16 @@ | |
"@zetachain/networks" "^10.0.0" | ||
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" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
.yarn | ||
artifacts | ||
cache | ||
coverage | ||
node_modules | ||
typechain-types |
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", | ||
], | ||
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", | ||
}, | ||
fadeev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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"), | ||
}, | ||
}, | ||
}, | ||
}; |
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 |
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. |
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. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.26; | ||
|
||
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | ||
import "@openzeppelin/contracts/access/Ownable2Step.sol"; | ||
import "@zetachain/protocol-contracts/contracts/evm/GatewayEVM.sol"; | ||
import {RevertContext} from "@zetachain/protocol-contracts/contracts/Revert.sol"; | ||
import "./shared/Events.sol"; | ||
|
||
contract Connected is ERC20, Ownable2Step, Events { | ||
GatewayEVM public immutable gateway; | ||
address public counterparty; | ||
|
||
error InvalidAddress(); | ||
error Unauthorized(); | ||
|
||
modifier onlyGateway() { | ||
require(msg.sender == address(gateway), "Caller is not the gateway"); | ||
_; | ||
} | ||
|
||
function setCounterparty(address contractAddress) external onlyOwner { | ||
counterparty = contractAddress; | ||
emit CounterpartySet(contractAddress); | ||
} | ||
Comment on lines
+22
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐ ๏ธ Refactor suggestion Add address validation and improve event emission. The function should validate the new counterparty address and include the old value in the event for better traceability. Apply this improvement: function setCounterparty(address contractAddress) external onlyOwner {
+ if (contractAddress == address(0)) revert InvalidAddress("counterparty address is zero");
+ address oldCounterparty = counterparty;
counterparty = contractAddress;
- emit CounterpartySet(contractAddress);
+ emit CounterpartySet(oldCounterparty, contractAddress);
}
|
||
|
||
constructor( | ||
address payable gatewayAddress, | ||
address owner, | ||
string memory name, | ||
string memory symbol | ||
) ERC20(name, symbol) Ownable(owner) { | ||
if (gatewayAddress == address(0) || owner == address(0)) | ||
revert InvalidAddress(); | ||
gateway = GatewayEVM(gatewayAddress); | ||
} | ||
|
||
function mint(address to, uint256 amount) public onlyOwner { | ||
_mint(to, amount); | ||
} | ||
|
||
function transferCrossChain( | ||
address destination, | ||
address receiver, | ||
uint256 amount | ||
) external payable { | ||
_burn(msg.sender, amount); | ||
bytes memory message = abi.encode(destination, receiver, amount); | ||
|
||
RevertOptions memory revertOptions = RevertOptions( | ||
address(this), | ||
true, | ||
address(0), | ||
message, | ||
0 | ||
); | ||
|
||
if (destination == address(0)) { | ||
gateway.call(counterparty, message, revertOptions); | ||
} else { | ||
gateway.depositAndCall{value: msg.value}( | ||
counterparty, | ||
message, | ||
revertOptions | ||
); | ||
} | ||
emit TokenTransfer(destination, receiver, amount); | ||
} | ||
Comment on lines
+42
to
+68
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add security checks and follow CEI pattern. The function has several security considerations that should be addressed:
Apply these security improvements: function transferCrossChain(
address destination,
address receiver,
uint256 amount
) external payable {
+ if (counterparty == address(0)) revert InvalidAddress("counterparty not set");
+ if (receiver == address(0)) revert InvalidAddress("receiver is zero");
+ if (amount == 0) revert("amount cannot be zero");
+
+ // Cache msg.value to follow CEI pattern
+ uint256 value = msg.value;
_burn(msg.sender, amount);
bytes memory message = abi.encode(destination, receiver, amount);
RevertOptions memory revertOptions = RevertOptions(
address(this),
true,
address(0),
message,
0
);
if (destination == address(0)) {
gateway.call(counterparty, message, revertOptions);
} else {
- gateway.depositAndCall{value: msg.value}(
+ gateway.depositAndCall{value: value}(
counterparty,
message,
revertOptions
);
}
emit TokenTransfer(destination, receiver, amount);
}
|
||
|
||
function onCall( | ||
MessageContext calldata context, | ||
bytes calldata message | ||
) external payable onlyGateway returns (bytes4) { | ||
if (context.sender != counterparty) revert Unauthorized(); | ||
(address receiver, uint256 amount) = abi.decode( | ||
message, | ||
(address, uint256) | ||
); | ||
_mint(receiver, amount); | ||
emit TokenTransferReceived(receiver, amount); | ||
return ""; | ||
} | ||
Comment on lines
+70
to
+82
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐ ๏ธ Refactor suggestion Add amount validation in onCall function. The function should validate the minting amount to prevent potential issues. Apply this improvement: function onCall(
MessageContext calldata context,
bytes calldata message
) external payable onlyGateway returns (bytes4) {
if (context.sender != counterparty) revert Unauthorized();
(address receiver, uint256 amount) = abi.decode(
message,
(address, uint256)
);
+ if (receiver == address(0)) revert InvalidAddress("receiver is zero");
+ if (amount == 0) revert("amount cannot be zero");
_mint(receiver, amount);
emit TokenTransferReceived(receiver, amount);
return "";
}
|
||
|
||
function onRevert(RevertContext calldata context) external onlyGateway {} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implement revert handling logic. The empty Would you like me to provide an implementation for handling cross-chain transfer reverts? |
||
|
||
receive() external payable {} | ||
|
||
fallback() external payable {} | ||
} | ||
fadeev marked this conversation as resolved.
Show resolved
Hide resolved
|
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
Add address validation in onCall function.
While the parameter reordering is correct, consider adding validation for the decoded receiver address to maintain consistency with other functions that check for zero addresses.
(address receiver, uint256 tokenId, string memory uri) = abi.decode( message, (address, uint256, string) ); +if (receiver == address(0)) revert InvalidAddress(); _safeMint(receiver, tokenId);