Skip to content

Commit

Permalink
Temporarily add v2 contracts to the toolkit (#183)
Browse files Browse the repository at this point in the history
  • Loading branch information
fadeev authored Sep 19, 2024
1 parent 8dafc40 commit e8bb021
Show file tree
Hide file tree
Showing 77 changed files with 5,852 additions and 716 deletions.
2 changes: 1 addition & 1 deletion contracts/BytesHelperLib.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.7;
pragma solidity 0.8.26;

library BytesHelperLib {
error OffsetOutOfBounds();
Expand Down
2 changes: 1 addition & 1 deletion contracts/EthZetaMock.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;
pragma solidity 0.8.26;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
Expand Down
34 changes: 34 additions & 0 deletions contracts/Revert.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

/// @notice Struct containing revert options
/// @param revertAddress Address to receive revert.
/// @param callOnRevert Flag if onRevert hook should be called.
/// @param abortAddress Address to receive funds if aborted.
/// @param revertMessage Arbitrary data sent back in onRevert.
/// @param onRevertGasLimit Gas limit for revert tx, unused on GatewayZEVM methods
struct RevertOptions {
address revertAddress;
bool callOnRevert;
address abortAddress;
bytes revertMessage;
uint256 onRevertGasLimit;
}

/// @notice Struct containing revert context passed to onRevert.
/// @param asset Address of asset, empty if it's gas token.
/// @param amount Amount specified with the transaction.
/// @param revertMessage Arbitrary data sent back in onRevert.
struct RevertContext {
address asset;
uint64 amount;
bytes revertMessage;
}

/// @title Revertable
/// @notice Interface for contracts that support revertable calls.
interface Revertable {
/// @notice Called when a revertable call is made.
/// @param revertContext Revert context to pass to onRevert.
function onRevert(RevertContext calldata revertContext) external;
}
6 changes: 3 additions & 3 deletions contracts/SwapHelperLib.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.7;
pragma solidity 0.8.26;

import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router01.sol";
import "@zetachain/protocol-contracts/contracts/zevm/interfaces/IZRC20.sol";
import "@zetachain/protocol-contracts/contracts/zevm/SystemContract.sol";
import "./shared/interfaces/IZRC20.sol";
import "./SystemContract.sol";
import "./shared/libraries/UniswapV2Library.sol";

library SwapHelperLib {
Expand Down
200 changes: 200 additions & 0 deletions contracts/SystemContract.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import "./UniversalContract.sol";

// import "./interfaces/zContract.sol";
import "./shared/interfaces/IZRC20.sol";

/**
* @dev Custom errors for SystemContract
*/
interface SystemContractErrors {
error CallerIsNotFungibleModule();
error InvalidTarget();
error CantBeIdenticalAddresses();
error CantBeZeroAddress();
error ZeroAddress();
}

/**
* @dev The system contract it's called by the protocol to interact with the blockchain.
* Also includes a lot of tools to make easier to interact with ZetaChain.
*/
contract SystemContract is SystemContractErrors {
/// @notice Map to know the gas price of each chain given a chain id.
mapping(uint256 => uint256) public gasPriceByChainId;
/// @notice Map to know the ZRC20 address of a token given a chain id, ex zETH, zBNB etc.
mapping(uint256 => address) public gasCoinZRC20ByChainId;
// @dev: Map to know uniswap V2 pool of ZETA/ZRC20 given a chain id. This refer to the build in uniswap deployed at genesis.
mapping(uint256 => address) public gasZetaPoolByChainId;

/// @notice Fungible address is always the same, it's on protocol level.
address public constant FUNGIBLE_MODULE_ADDRESS =
0x735b14BB79463307AAcBED86DAf3322B1e6226aB;
/// @notice Uniswap V2 addresses.
address public immutable uniswapv2FactoryAddress;
address public immutable uniswapv2Router02Address;
/// @notice Address of the wrapped ZETA to interact with Uniswap V2.
address public wZetaContractAddress;
/// @notice Address of ZEVM Zeta Connector.
address public zetaConnectorZEVMAddress;

/// @notice Custom SystemContract errors.
event SystemContractDeployed();
event SetGasPrice(uint256, uint256);
event SetGasCoin(uint256, address);
event SetGasZetaPool(uint256, address);
event SetWZeta(address);
event SetConnectorZEVM(address);

/**
* @dev Only fungible module can deploy a system contract.
*/
constructor(
address wzeta_,
address uniswapv2Factory_,
address uniswapv2Router02_
) {
if (msg.sender != FUNGIBLE_MODULE_ADDRESS)
revert CallerIsNotFungibleModule();
wZetaContractAddress = wzeta_;
uniswapv2FactoryAddress = uniswapv2Factory_;
uniswapv2Router02Address = uniswapv2Router02_;
emit SystemContractDeployed();
}

/**
* @dev Deposit foreign coins into ZRC20 and call user specified contract on zEVM.
* @param context, context data for deposit.
* @param zrc20, zrc20 address for deposit.
* @param amount, amount to deposit.
* @param target, contract address to make a call after deposit.
* @param message, calldata for a call.
*/
function depositAndCall(
zContext calldata context,
address zrc20,
uint256 amount,
address target,
bytes calldata message
) external {
if (msg.sender != FUNGIBLE_MODULE_ADDRESS)
revert CallerIsNotFungibleModule();
if (target == FUNGIBLE_MODULE_ADDRESS || target == address(this))
revert InvalidTarget();

IZRC20(zrc20).deposit(target, amount);
zContract(target).onCrossChainCall(context, zrc20, amount, message);
}

/**
* @dev Sort token addresses lexicographically. Used to handle return values from pairs sorted in the order.
* @param tokenA, tokenA address.
* @param tokenB, tokenB address.
* @return token0 token1, returns sorted token addresses,.
*/
function sortTokens(
address tokenA,
address tokenB
) internal pure returns (address token0, address token1) {
if (tokenA == tokenB) revert CantBeIdenticalAddresses();
(token0, token1) = tokenA < tokenB
? (tokenA, tokenB)
: (tokenB, tokenA);
if (token0 == address(0)) revert CantBeZeroAddress();
}

/**
* @dev Calculates the CREATE2 address for a pair without making any external calls.
* @param factory, factory address.
* @param tokenA, tokenA address.
* @param tokenB, tokenB address.
* @return pair tokens pair address.
*/
function uniswapv2PairFor(
address factory,
address tokenA,
address tokenB
) public pure returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = address(
uint160(
uint256(
keccak256(
abi.encodePacked(
hex"ff",
factory,
keccak256(abi.encodePacked(token0, token1)),
hex"96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f" // init code hash
)
)
)
)
);
}

/**
* @dev Fungible module updates the gas price oracle periodically.
* @param chainID, chain id.
* @param price, new gas price.
*/
function setGasPrice(uint256 chainID, uint256 price) external {
if (msg.sender != FUNGIBLE_MODULE_ADDRESS)
revert CallerIsNotFungibleModule();
gasPriceByChainId[chainID] = price;
emit SetGasPrice(chainID, price);
}

/**
* @dev Setter for gasCoinZRC20ByChainId map.
* @param chainID, chain id.
* @param zrc20, ZRC20 address.
*/
function setGasCoinZRC20(uint256 chainID, address zrc20) external {
if (msg.sender != FUNGIBLE_MODULE_ADDRESS)
revert CallerIsNotFungibleModule();
gasCoinZRC20ByChainId[chainID] = zrc20;
emit SetGasCoin(chainID, zrc20);
}

/**
* @dev Set the pool wzeta/erc20 address.
* @param chainID, chain id.
* @param erc20, pair for uniswap wzeta/erc20.
*/
function setGasZetaPool(uint256 chainID, address erc20) external {
if (msg.sender != FUNGIBLE_MODULE_ADDRESS)
revert CallerIsNotFungibleModule();
address pool = uniswapv2PairFor(
uniswapv2FactoryAddress,
wZetaContractAddress,
erc20
);
gasZetaPoolByChainId[chainID] = pool;
emit SetGasZetaPool(chainID, pool);
}

/**
* @dev Setter for wrapped ZETA address.
* @param addr, wzeta new address.
*/
function setWZETAContractAddress(address addr) external {
if (msg.sender != FUNGIBLE_MODULE_ADDRESS)
revert CallerIsNotFungibleModule();
if (addr == address(0)) revert ZeroAddress();
wZetaContractAddress = addr;
emit SetWZeta(wZetaContractAddress);
}

/**
* @dev Setter for zetaConnector ZEVM Address
* @param addr, zeta connector new address.
*/
function setConnectorZEVMAddress(address addr) external {
if (msg.sender != FUNGIBLE_MODULE_ADDRESS)
revert CallerIsNotFungibleModule();
if (addr == address(0)) revert ZeroAddress();
zetaConnectorZEVMAddress = addr;
emit SetConnectorZEVM(zetaConnectorZEVMAddress);
}
}
2 changes: 1 addition & 1 deletion contracts/TestZRC20.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity =0.8.7;
pragma solidity 0.8.26;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
Expand Down
32 changes: 32 additions & 0 deletions contracts/UniversalContract.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {RevertContext} from "./Revert.sol";

struct zContext {
bytes origin;
address sender;
uint256 chainID;
}

/// @custom:deprecated should be removed once v2 SystemContract is not used anymore.
/// UniversalContract should be used
interface zContract {
function onCrossChainCall(
zContext calldata context,
address zrc20,
uint256 amount,
bytes calldata message
) external;
}

interface UniversalContract {
function onCrossChainCall(
zContext calldata context,
address zrc20,
uint256 amount,
bytes calldata message
) external;

function onRevert(RevertContext calldata revertContext) external;
}
2 changes: 1 addition & 1 deletion contracts/shared/MockZRC20.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity =0.8.7;
pragma solidity 0.8.26;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
Expand Down
2 changes: 1 addition & 1 deletion contracts/shared/TestUniswapRouter.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;
pragma solidity 0.8.26;

import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol";
import "@uniswap/lib/contracts/libraries/TransferHelper.sol";
Expand Down
Loading

0 comments on commit e8bb021

Please sign in to comment.