Skip to content

Commit

Permalink
base contract
Browse files Browse the repository at this point in the history
  • Loading branch information
fadeev committed Nov 20, 2024
1 parent 58c95da commit 5ee524f
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 101 deletions.
111 changes: 21 additions & 90 deletions examples/router/contracts/Connected.sol
Original file line number Diff line number Diff line change
@@ -1,107 +1,38 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@zetachain/protocol-contracts/contracts/evm/GatewayEVM.sol";
import {RevertContext} from "@zetachain/protocol-contracts/contracts/Revert.sol";
import {CallOptions} from "@zetachain/protocol-contracts/contracts/zevm/interfaces/IGatewayZEVM.sol";
import "./ConnectedRouter.sol";

contract Connected is Ownable {
GatewayEVM public immutable gateway;
uint256 private _nextTokenId;
address public counterparty;
address public router;
contract Connected is ConnectedRouter {
event OnMessageReceiveEvent();
event OnMessageRevertEvent();

event HelloEvent(string, string);
event OnCallEvent(string);
event OnRevertEvent(string, RevertContext);

error Unauthorized();

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

function setRouter(address contractAddress) external onlyOwner {
router = contractAddress;
}
constructor(
address payable gateway,
address owner,
address router
) ConnectedRouter(gateway, owner, router) {}

modifier onlyGateway() {
if (msg.sender != address(gateway)) revert Unauthorized();
_;
function onMessageReceive(
bytes memory data,
address sender
) internal override {
emit OnMessageReceiveEvent();
}

constructor(
address payable gatewayAddress,
address initialOwner
) Ownable(initialOwner) {
gateway = GatewayEVM(gatewayAddress);
function onMessageRevert(
bytes memory data,
address sender
) internal override {
emit OnMessageRevertEvent();
}

function transferCrossChain(
function sendMessage(
address destination,
bytes memory data,
CallOptions memory callOptions,
RevertOptions memory revertOptions
) external payable {
bytes memory message = abi.encode(
abi.encodePacked(counterparty),
destination,
data,
callOptions,
revertOptions
);
gateway.depositAndCall{value: msg.value}(
router,
message,
revertOptions
);
}

function hello(string memory message) external payable {
emit HelloEvent("Event from hello()", message);
}

function onCall(
MessageContext calldata context,
bytes calldata message
) external payable onlyGateway returns (bytes4) {
if (context.sender != router) revert Unauthorized();
(bytes memory data, address sender, bool isCall) = abi.decode(
message,
(bytes, address, bool)
);

if (sender != counterparty) revert Unauthorized();

if (isCall) {
// Handle a call from another connected chain
emit OnCallEvent("regular call");
} else {
// Handle revert
emit OnCallEvent("revert");
}
return "";
}

// onRevert is executed when router's onCall reverts
function onRevert(
RevertContext calldata context
) external payable onlyGateway {
if (context.sender != router) revert("Unauthorized");
emit OnRevertEvent("Event from onRevert()", context);
}

receive() external payable {}

fallback() external payable {}

function bytesToAddress(
bytes memory b
) internal pure returns (address addr) {
require(b.length == 20, "Invalid bytes length for address");
assembly {
addr := mload(add(b, 20))
}
gatewaySendMessage(destination, data, callOptions, revertOptions);
}
}
113 changes: 113 additions & 0 deletions examples/router/contracts/ConnectedRouter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@zetachain/protocol-contracts/contracts/evm/GatewayEVM.sol";
import {RevertContext} from "@zetachain/protocol-contracts/contracts/Revert.sol";
import {CallOptions} from "@zetachain/protocol-contracts/contracts/zevm/interfaces/IGatewayZEVM.sol";

contract ConnectedRouter is Ownable {
GatewayEVM public immutable gateway;
uint256 private _nextTokenId;
address public counterparty;
address public router;

event HelloEvent(string, string);
event OnCallEvent(string);
event OnRevertEvent(string, RevertContext);

error Unauthorized();

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

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

constructor(
address payable gatewayAddress,
address ownerAddress,
address routerAddress
) Ownable(ownerAddress) {
gateway = GatewayEVM(gatewayAddress);
router = routerAddress;
}

function gatewaySendMessage(
address destination,
bytes memory data,
CallOptions memory callOptions,
RevertOptions memory revertOptions
) public payable {
bytes memory message = abi.encode(
abi.encodePacked(counterparty),
destination,
data,
callOptions,
revertOptions
);
gateway.depositAndCall{value: msg.value}(
router,
message,
revertOptions
);
}

function onCall(
MessageContext calldata context,
bytes calldata message
) external payable onlyGateway returns (bytes4) {
if (context.sender != router) revert Unauthorized();
(bytes memory data, address sender, bool isCall) = abi.decode(
message,
(bytes, address, bool)
);

if (sender != counterparty) revert Unauthorized();

if (isCall) {
onMessageReceive(data, sender);
} else {
onMessageRevert(data, sender);
}
return "";
}

// onRevert is executed when router's onCall reverts
function onRevert(
RevertContext calldata context
) external payable onlyGateway {
if (context.sender != router) revert("Unauthorized");
emit OnRevertEvent("Event from onRevert()", context);
}

function onMessageReceive(
bytes memory data,
address sender
) internal virtual {
// To be overridden in the child contract
}

function onMessageRevert(
bytes memory data,
address sender
) internal virtual {
// To be overridden in the child contract
}

receive() external payable {}

fallback() external payable {}

function bytesToAddress(
bytes memory b
) internal pure returns (address addr) {
require(b.length == 20, "Invalid bytes length for address");
assembly {
addr := mload(add(b, 20))
}
}
}
14 changes: 6 additions & 8 deletions examples/router/scripts/localnet.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,29 @@ GATEWAY_BNB=$(jq -r '.addresses[] | select(.type=="gatewayEVM" and .chain=="bnb"
UNISWAP_ROUTER=$(jq -r '.addresses[] | select(.type=="uniswapRouterInstance" and .chain=="zetachain") | .address' localnet.json)
SENDER=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266

CONTRACT_ZETACHAIN=$(npx hardhat deploy --network localhost --uniswap-router "$UNISWAP_ROUTER" --json | jq -r '.contractAddress')
CONTRACT_ZETACHAIN=$(npx hardhat deploy --name Universal --network localhost --uniswap-router "$UNISWAP_ROUTER" --json | jq -r '.contractAddress')
echo -e "\n🚀 Deployed contract on ZetaChain: $CONTRACT_ZETACHAIN"

CONTRACT_ETHEREUM=$(npx hardhat deploy --name Connected --json --network localhost --gateway "$GATEWAY_ETHEREUM" | jq -r '.contractAddress')
CONTRACT_ETHEREUM=$(npx hardhat deploy --name Connected --json --network localhost --gateway "$GATEWAY_ETHEREUM" --router "$CONTRACT_ZETACHAIN" | jq -r '.contractAddress')
echo -e "🚀 Deployed contract on EVM chain: $CONTRACT_ETHEREUM"

CONTRACT_BNB=$(npx hardhat deploy --name Connected --json --network localhost --gateway "$GATEWAY_BNB" | jq -r '.contractAddress')
CONTRACT_BNB=$(npx hardhat deploy --name Connected --json --network localhost --gateway "$GATEWAY_BNB" --router "$CONTRACT_ZETACHAIN" | jq -r '.contractAddress')
echo -e "🚀 Deployed contract on BNB chain: $CONTRACT_BNB"

echo -e "\n📮 User Address: $SENDER"

echo -e "\n🔗 Setting counterparty contracts..."
npx hardhat connected-set-counterparty --network localhost --contract "$CONTRACT_ETHEREUM" --counterparty "$CONTRACT_BNB" --json &>/dev/null
npx hardhat connected-set-counterparty --network localhost --contract "$CONTRACT_BNB" --counterparty "$CONTRACT_ETHEREUM" --json &>/dev/null
npx hardhat connected-set-router --network localhost --contract "$CONTRACT_ETHEREUM" --counterparty "$CONTRACT_ZETACHAIN" --json &>/dev/null
npx hardhat connected-set-router --network localhost --contract "$CONTRACT_BNB" --counterparty "$CONTRACT_ZETACHAIN" --json &>/dev/null

echo -e "\nMaking an authenticated call..."
npx hardhat transfer --network localhost --json --from "$CONTRACT_ETHEREUM" --to "$ZRC20_BNB" --gas-amount 1 --call-on-revert --revert-address "$CONTRACT_ETHEREUM" --revert-message "hello" --types '["string"]' alice

npx hardhat localnet-check

echo -e "\nMaking an arbitrary call..."
npx hardhat transfer --network localhost --json --from "$CONTRACT_ETHEREUM" --to "$ZRC20_BNB" --gas-amount 1 --call-options-is-arbitrary-call --function "hello(string)" --revert-address "$CONTRACT_ETHEREUM" --revert-message "hello" --types '["string"]' alice
# echo -e "\nMaking an arbitrary call..."
# npx hardhat transfer --network localhost --json --from "$CONTRACT_ETHEREUM" --to "$ZRC20_BNB" --gas-amount 1 --call-options-is-arbitrary-call --function "hello(string)" --revert-address "$CONTRACT_ETHEREUM" --revert-message "hello" --types '["string"]' alice

npx hardhat localnet-check
# npx hardhat localnet-check

if [ "$1" = "start" ]; then npx hardhat localnet-stop; fi
6 changes: 4 additions & 2 deletions examples/router/tasks/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => {
const contract = await factory.deploy(
args.gateway,
signer.address,
...(args.uniswapRouter ? [args.uniswapRouter] : [])
...(args.uniswapRouter ? [args.uniswapRouter] : []),
...(args.router ? [args.router] : [])
);
await contract.deployed();

Expand Down Expand Up @@ -43,4 +44,5 @@ task("deploy", "Deploy the NFT contract", main)
"Gateway address (default: ZetaChain Gateway)",
"0x5FC8d32690cc91D4c39d9d3abcBD16989F875707"
)
.addOptionalParam("uniswapRouter", "Uniswap v2 Router address");
.addOptionalParam("uniswapRouter", "Uniswap v2 Router address")
.addOptionalParam("router", "Router address");
2 changes: 1 addition & 1 deletion examples/router/tasks/transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => {

const gasAmount = ethers.utils.parseUnits(args.gasAmount, 18);

tx = await (contract as any).transferCrossChain(
tx = await (contract as any).sendMessage(
args.to,
message,
callOptions,
Expand Down

0 comments on commit 5ee524f

Please sign in to comment.