Skip to content

Commit

Permalink
Add zetainteractor and errors to examples (#24)
Browse files Browse the repository at this point in the history
* Add zetainteractor and errors to examples

* remove unused error

* remove _crossChainId from examples

* rename
  • Loading branch information
andresaiello authored Jul 1, 2022
1 parent 0035046 commit 58c7f41
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 181 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,29 @@
pragma solidity 0.8.7;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@zetachain/protocol-contracts/contracts/ZetaInteractor.sol";
import "@zetachain/protocol-contracts/contracts/interfaces/ZetaInterfaces.sol";

contract CrossChainCounter is Ownable, ZetaReceiver {
bytes32 public constant CROSS_CHAIN_INCREMENT_MESSAGE = keccak256("CROSS_CHAIN_INCREMENT");
interface CrossChainCounterErrors {
error InvalidMessageType();

address public connectorAddress;
ZetaConnector internal connector;
error DecrementOverflow();
}

uint256 internal immutable currentChainId;
uint256 internal _crossChainId;
bytes internal _crossChainAddress;
contract CrossChainCounter is ZetaInteractor, ZetaReceiver, CrossChainCounterErrors {
bytes32 public constant CROSS_CHAIN_INCREMENT_MESSAGE = keccak256("CROSS_CHAIN_INCREMENT");

mapping(address => uint256) public counter;

constructor(address connectorAddress_) {
currentChainId = block.chainid;

connectorAddress = connectorAddress_;
connector = ZetaConnector(connectorAddress_);
}

function setCrossChainAddress(bytes calldata ccAddress) public onlyOwner {
_crossChainAddress = ccAddress;
}

function setCrossChainId(uint256 ccId) public onlyOwner {
_crossChainId = ccId;
}
constructor(address connectorAddress_) ZetaInteractor(connectorAddress_) {}

function crossChainCount() external {
require(_crossChainAddress.length != 0, "Cross-chain address is not set");
require(_crossChainId != 0, "Cross-chain id is not set");
function crossChainCount(uint256 destinationChainId) external {
if (!_isValidChainId(destinationChainId)) revert InvalidDestinationChainId();

connector.send(
ZetaInterfaces.SendInput({
destinationChainId: _crossChainId,
destinationAddress: _crossChainAddress,
destinationChainId: destinationChainId,
destinationAddress: interactorsByChainId[destinationChainId],
destinationGasLimit: 2500000,
message: abi.encode(CROSS_CHAIN_INCREMENT_MESSAGE, msg.sender),
zetaValueAndGas: 0,
Expand All @@ -47,30 +33,27 @@ contract CrossChainCounter is Ownable, ZetaReceiver {
);
}

function onZetaMessage(ZetaInterfaces.ZetaMessage calldata zetaMessage) external override {
require(msg.sender == connectorAddress, "This function can only be called by the Connector contract");
require(
keccak256(zetaMessage.zetaTxSenderAddress) == keccak256(_crossChainAddress),
"Cross-chain address doesn't match"
);
require(zetaMessage.sourceChainId == _crossChainId, "Cross-chain id doesn't match");

function onZetaMessage(ZetaInterfaces.ZetaMessage calldata zetaMessage)
external
override
isValidMessageCall(zetaMessage)
{
(bytes32 messageType, address messageFrom) = abi.decode(zetaMessage.message, (bytes32, address));

require(messageType == CROSS_CHAIN_INCREMENT_MESSAGE, "Invalid message type");
if (messageType != CROSS_CHAIN_INCREMENT_MESSAGE) revert InvalidMessageType();

counter[messageFrom]++;
}

function onZetaRevert(ZetaInterfaces.ZetaRevert calldata zetaRevert) external override {
require(msg.sender == connectorAddress, "This function can only be called by the Connector contract");
require(zetaRevert.zetaTxSenderAddress == address(this), "Invalid zetaTxSenderAddress");
require(zetaRevert.sourceChainId == currentChainId, "Invalid sourceChainId");

function onZetaRevert(ZetaInterfaces.ZetaRevert calldata zetaRevert)
external
override
isValidRevertCall(zetaRevert)
{
(bytes32 messageType, address messageFrom) = abi.decode(zetaRevert.message, (bytes32, address));

require(messageType == CROSS_CHAIN_INCREMENT_MESSAGE, "Invalid message type");
require(counter[messageFrom] > 0, "Decrement overflow");
if (messageType != CROSS_CHAIN_INCREMENT_MESSAGE) revert InvalidMessageType();
if (counter[messageFrom] <= 0) revert DecrementOverflow();

counter[messageFrom]--;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,33 @@
pragma solidity 0.8.7;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@zetachain/protocol-contracts/contracts/ZetaInteractor.sol";
import "@zetachain/protocol-contracts/contracts/interfaces/ZetaInterfaces.sol";

interface CrossChainMessageErrors {
error InvalidMessageType();
}

/**
* @dev A simple contract able to send and receive Hello World messages from other chains.
* Emits a HelloWorldEvent on successful messages
* Emits a RevertedHelloWorldEvent on failed messages
*/
contract CrossChainMessage is Ownable {
contract CrossChainMessage is ZetaInteractor, ZetaReceiver, CrossChainMessageErrors {
bytes32 public constant HELLO_WORLD_MESSAGE_TYPE = keccak256("CROSS_CHAIN_HELLO_WORLD");

event HelloWorldEvent(string messageData);
event RevertedHelloWorldEvent(string messageData);

address internal _zetaConnectorAddress;
ZetaConnector internal _zeta;

uint256 internal immutable _currentChainId;
bytes internal _crossChainAddress;
uint256 internal _crossChainId;

constructor(address _zetaConnectorInputAddress) {
_currentChainId = block.chainid;

_zetaConnectorAddress = _zetaConnectorInputAddress;
_zeta = ZetaConnector(_zetaConnectorInputAddress);
}

/**
* @dev The cross-chain address cannot be set on the constructor since it depends on the deployment of the contract on the other chain.
*/
function setCrossChainAddress(bytes calldata _ccAddress) public onlyOwner {
_crossChainAddress = _ccAddress;
}

/**
* @dev Can be set on the constructor, but we favor this pattern for more flexibility.
*/
function setCrossChainId(uint256 _ccId) public onlyOwner {
_crossChainId = _ccId;
}
constructor(address connectorAddress_) ZetaInteractor(connectorAddress_) {}

function sendHelloWorld() external {
require(_crossChainAddress.length != 0, "Cross-chain address is not set");
require(_crossChainId != 0, "Cross-chain id is not set");
function sendHelloWorld(uint256 destinationChainId) external {
if (!_isValidChainId(destinationChainId)) revert InvalidDestinationChainId();

_zeta.send(
connector.send(
ZetaInterfaces.SendInput({
destinationChainId: _crossChainId,
destinationAddress: _crossChainAddress,
destinationChainId: destinationChainId,
destinationAddress: interactorsByChainId[destinationChainId],
destinationGasLimit: 2500000,
message: abi.encode(HELLO_WORLD_MESSAGE_TYPE, "Hello, Cross-Chain World!"),
zetaValueAndGas: 0,
Expand All @@ -59,23 +37,20 @@ contract CrossChainMessage is Ownable {
);
}

function onZetaMessage(ZetaInterfaces.ZetaMessage calldata _zetaMessage) external {
require(msg.sender == _zetaConnectorAddress, "This function can only be called by the Zeta Connector contract");
require(
keccak256(_zetaMessage.zetaTxSenderAddress) == keccak256(_crossChainAddress),
"Cross-chain address doesn't match"
);
require(_zetaMessage.sourceChainId == _crossChainId, "Cross-chain id doesn't match");

function onZetaMessage(ZetaInterfaces.ZetaMessage calldata zetaMessage)
external
override
isValidMessageCall(zetaMessage)
{
/**
* @dev Decode should follow the signature of the message provided to zeta.send.
*/
(bytes32 messageType, string memory helloWorldMessage) = abi.decode(_zetaMessage.message, (bytes32, string));
(bytes32 messageType, string memory helloWorldMessage) = abi.decode(zetaMessage.message, (bytes32, string));

/**
* @dev Setting a message type is a useful pattern to distinguish between different messages.
*/
require(messageType == HELLO_WORLD_MESSAGE_TYPE, "Invalid message type");
if (messageType != HELLO_WORLD_MESSAGE_TYPE) revert InvalidMessageType();

emit HelloWorldEvent(helloWorldMessage);
}
Expand All @@ -85,14 +60,14 @@ contract CrossChainMessage is Ownable {
* Useful to cleanup and leave the application on its initial state.
* Note that the require statements and the functionality are similar to onZetaMessage.
*/
function onZetaRevert(ZetaInterfaces.ZetaRevert calldata _zetaRevert) external {
require(msg.sender == _zetaConnectorAddress, "This function can only be called by the Zeta Connector contract");
require(_zetaRevert.zetaTxSenderAddress == address(this), "Invalid zetaTxSenderAddress");
require(_zetaRevert.sourceChainId == _currentChainId, "Invalid sourceChainId");

(bytes32 messageType, string memory helloWorldMessage) = abi.decode(_zetaRevert.message, (bytes32, string));

require(messageType == HELLO_WORLD_MESSAGE_TYPE, "Invalid message type");
function onZetaRevert(ZetaInterfaces.ZetaRevert calldata zetaRevert)
external
override
isValidRevertCall(zetaRevert)
{
(bytes32 messageType, string memory helloWorldMessage) = abi.decode(zetaRevert.message, (bytes32, string));

if (messageType != HELLO_WORLD_MESSAGE_TYPE) revert InvalidMessageType();

emit RevertedHelloWorldEvent(helloWorldMessage);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,27 @@ import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@zetachain/protocol-contracts/contracts/interfaces/ZetaInterfaces.sol";
import "@zetachain/protocol-contracts/contracts/ZetaInteractor.sol";

contract CrossChainWarriors is ERC721("CrossChainWarriors", "CCWAR"), Ownable, ZetaReceiver {
interface CrossChainWarriorsErrors {
error InvalidMessageType();

error InvalidTransferCaller();

error ErrorApprovingZeta();
}

contract CrossChainWarriors is
ERC721("CrossChainWarriors", "CCWAR"),
ZetaInteractor,
ZetaReceiver,
CrossChainWarriorsErrors
{
using Counters for Counters.Counter;
using Strings for uint256;

bytes32 public constant CROSS_CHAIN_TRANSFER_MESSAGE = keccak256("CROSS_CHAIN_TRANSFER");

uint256 internal immutable _currentChainId;
uint256 internal _crossChainId;
bytes internal _crossChainAddress;

address public connectorAddress;
ZetaConnector internal connector;

address public zetaTokenAddress;
IERC20 internal _zetaToken;

string public baseURI;
Expand All @@ -29,16 +35,10 @@ contract CrossChainWarriors is ERC721("CrossChainWarriors", "CCWAR"), Ownable, Z

constructor(
address connectorAddress_,
address zetaTokenAddress_,
address zetaTokenAddress,
bool useEven
) {
_currentChainId = block.chainid;

connectorAddress = connectorAddress_;
connector = ZetaConnector(connectorAddress_);

zetaTokenAddress = zetaTokenAddress_;
_zetaToken = IERC20(zetaTokenAddress_);
) ZetaInteractor(connectorAddress_) {
_zetaToken = IERC20(zetaTokenAddress);

/**
* @dev A simple way to prevent collisions between cross-chain token ids
Expand All @@ -48,14 +48,6 @@ contract CrossChainWarriors is ERC721("CrossChainWarriors", "CCWAR"), Ownable, Z
if (useEven) tokenIds.increment();
}

function setCrossChainAddress(bytes calldata ccAddress) public onlyOwner {
_crossChainAddress = ccAddress;
}

function setCrossChainId(uint256 ccId) public onlyOwner {
_crossChainId = ccId;
}

function setBaseURI(string memory baseURIParam) public onlyOwner {
baseURI = baseURIParam;
}
Expand Down Expand Up @@ -93,22 +85,27 @@ contract CrossChainWarriors is ERC721("CrossChainWarriors", "CCWAR"), Ownable, Z
* @dev Cross-chain functions
*/

function crossChainTransfer(address to, uint256 tokenId) external {
require(_isApprovedOrOwner(_msgSender(), tokenId), "Transfer caller is not owner nor approved");
function crossChainTransfer(
uint256 crossChainId,
address to,
uint256 tokenId
) external {
if (!_isValidChainId(crossChainId)) revert InvalidDestinationChainId();
if (!_isApprovedOrOwner(_msgSender(), tokenId)) revert InvalidTransferCaller();

uint256 crossChainGas = 18000000000000000000;

{
bool success = _zetaToken.transferFrom(msg.sender, connectorAddress, crossChainGas);
require(success == true, "CrossChainWarriors: error approving zeta");
bool success = _zetaToken.transferFrom(msg.sender, address(connector), crossChainGas);
if (!success) revert ErrorApprovingZeta();
}

_burnWarrior(tokenId);

connector.send(
ZetaInterfaces.SendInput({
destinationChainId: _crossChainId,
destinationAddress: _crossChainAddress,
destinationChainId: crossChainId,
destinationAddress: interactorsByChainId[crossChainId],
destinationGasLimit: 500000,
message: abi.encode(CROSS_CHAIN_TRANSFER_MESSAGE, tokenId, msg.sender, to),
zetaValueAndGas: crossChainGas,
Expand All @@ -117,14 +114,11 @@ contract CrossChainWarriors is ERC721("CrossChainWarriors", "CCWAR"), Ownable, Z
);
}

function onZetaMessage(ZetaInterfaces.ZetaMessage calldata zetaMessage) external override {
require(msg.sender == connectorAddress, "This function can only be called by the Connector contract");
require(
keccak256(zetaMessage.zetaTxSenderAddress) == keccak256(_crossChainAddress),
"Cross-chain address doesn't match"
);
require(zetaMessage.sourceChainId == _crossChainId, "Cross-chain id doesn't match");

function onZetaMessage(ZetaInterfaces.ZetaMessage calldata zetaMessage)
external
override
isValidMessageCall(zetaMessage)
{
(
bytes32 messageType,
uint256 tokenId,
Expand All @@ -135,22 +129,22 @@ contract CrossChainWarriors is ERC721("CrossChainWarriors", "CCWAR"), Ownable, Z
address to
) = abi.decode(zetaMessage.message, (bytes32, uint256, address, address));

require(messageType == CROSS_CHAIN_TRANSFER_MESSAGE, "Invalid message type");
if (messageType != CROSS_CHAIN_TRANSFER_MESSAGE) revert InvalidMessageType();

_mintId(to, tokenId);
}

function onZetaRevert(ZetaInterfaces.ZetaRevert calldata zetaRevert) external override {
require(msg.sender == connectorAddress, "This function can only be called by the Connector contract");
require(zetaRevert.zetaTxSenderAddress == address(this), "Invalid zetaTxSenderAddress");
require(zetaRevert.sourceChainId == _currentChainId, "Invalid sourceChainId");

function onZetaRevert(ZetaInterfaces.ZetaRevert calldata zetaRevert)
external
override
isValidRevertCall(zetaRevert)
{
(bytes32 messageType, uint256 tokenId, address from) = abi.decode(
zetaRevert.message,
(bytes32, uint256, address)
);

require(messageType == CROSS_CHAIN_TRANSFER_MESSAGE, "Invalid message type");
if (messageType != CROSS_CHAIN_TRANSFER_MESSAGE) revert InvalidMessageType();

_mintId(from, tokenId);
}
Expand Down
Loading

0 comments on commit 58c7f41

Please sign in to comment.