Skip to content

Commit

Permalink
nft: refactor to extract transferCrossChain into an abstract contract
Browse files Browse the repository at this point in the history
  • Loading branch information
fadeev committed Dec 23, 2024
1 parent 785f106 commit f0e314d
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 42 deletions.
58 changes: 16 additions & 42 deletions contracts/nft/contracts/evm/UniversalNFT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/U
import {ERC721PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721PausableUpgradeable.sol";

import "../shared/UniversalNFTEvents.sol";
import "./UniversalNFTTransferrable.sol";

contract UniversalNFT is
Initializable,
Expand All @@ -24,14 +25,14 @@ contract UniversalNFT is
OwnableUpgradeable,
ERC721BurnableUpgradeable,
UUPSUpgradeable,
UniversalNFTEvents
UniversalNFTEvents,
UniversalNFTTransferrable
{
GatewayEVM public gateway;
uint256 private _nextTokenId;
GatewayEVM public gateway;
address public universal;
uint256 public gasLimitAmount;

error InvalidAddress();
error Unauthorized();
error InvalidGasLimit();
error GasTokenTransferFailed();
Expand Down Expand Up @@ -65,6 +66,18 @@ contract UniversalNFT is
gateway = GatewayEVM(gatewayAddress);
}

function getGateway() public view override returns (GatewayEVM) {
return gateway;
}

function getUniversal() public view override returns (address) {
return universal;
}

function getGasLimitAmount() public view override returns (uint256) {
return gasLimitAmount;
}

function setGasLimit(uint256 gas) external onlyOwner {
if (gas == 0) revert InvalidGasLimit();
gasLimitAmount = gas;
Expand Down Expand Up @@ -93,45 +106,6 @@ contract UniversalNFT is
emit TokenMinted(to, tokenId, uri);
}

function transferCrossChain(
uint256 tokenId,
address receiver,
address destination
) external payable whenNotPaused {
if (receiver == address(0)) revert InvalidAddress();

string memory uri = tokenURI(tokenId);
_burn(tokenId);
bytes memory message = abi.encode(
destination,
receiver,
tokenId,
uri,
msg.sender
);
if (destination == address(0)) {
gateway.call(
universal,
message,
RevertOptions(address(this), false, address(0), message, 0)
);
} else {
gateway.depositAndCall{value: msg.value}(
universal,
message,
RevertOptions(
address(this),
true,
address(0),
abi.encode(receiver, tokenId, uri, msg.sender),
gasLimitAmount
)
);
}

emit TokenTransfer(destination, receiver, tokenId, uri);
}

function onCall(
MessageContext calldata context,
bytes calldata message
Expand Down
70 changes: 70 additions & 0 deletions contracts/nft/contracts/evm/UniversalNFTTransferrable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import "@zetachain/protocol-contracts/contracts/evm/GatewayEVM.sol";
import {RevertOptions} from "@zetachain/protocol-contracts/contracts/evm/GatewayEVM.sol";
import "../shared/UniversalNFTEvents.sol";
import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";

abstract contract UniversalNFTTransferrable is
ERC721Upgradeable,
UniversalNFTEvents
{
error InvalidAddress();

function getGateway() public view virtual returns (GatewayEVM);

function getUniversal() public view virtual returns (address);

function getGasLimitAmount() public view virtual returns (uint256);

/**
* @notice Transfers an NFT to another chain.
* @dev Burns the NFT locally, then sends an encoded message to the
* Gateway to recreate it on the destination chain (or revert if needed).
* @param tokenId The ID of the NFT to transfer.
* @param receiver The address on the destination chain that will receive the NFT.
* @param destination The contract address on the destination chain (or address(0) if same chain).
*/
function transferCrossChain(
uint256 tokenId,
address receiver,
address destination
) external payable virtual {
if (receiver == address(0)) revert InvalidAddress();

string memory uri = tokenURI(tokenId);

_burn(tokenId);

bytes memory message = abi.encode(
destination,
receiver,
tokenId,
uri,
msg.sender
);

if (destination == address(0)) {
getGateway().call(
getUniversal(),
message,
RevertOptions(address(this), false, address(0), message, 0)
);
} else {
getGateway().depositAndCall{value: msg.value}(
getUniversal(),
message,
RevertOptions(
address(this),
true,
address(0),
abi.encode(receiver, tokenId, uri, msg.sender),
getGasLimitAmount()
)
);
}

emit TokenTransfer(destination, receiver, tokenId, uri);
}
}

0 comments on commit f0e314d

Please sign in to comment.