Skip to content
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

Temporarily add v2 contracts to the toolkit #183

Merged
merged 4 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading