Skip to content

Commit

Permalink
feat: Write a zetatokenconsumer for zevm (#146)
Browse files Browse the repository at this point in the history
Co-authored-by: Denis Fadeev <denis@fadeev.org>
  • Loading branch information
andresaiello and fadeev authored Jun 17, 2024
1 parent 44edae0 commit 7467348
Show file tree
Hide file tree
Showing 17 changed files with 2,408 additions and 44 deletions.
149 changes: 149 additions & 0 deletions contracts/evm/tools/ZetaTokenConsumerZEVM.strategy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;

import "@openzeppelin/contracts/interfaces/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";

import "../interfaces/ZetaInterfaces.sol";
import "../../zevm/interfaces/IWZETA.sol";

interface ZetaTokenConsumerZEVMErrors {
error InputCantBeZero();

error ErrorSendingETH();

error ReentrancyError();

error NotEnoughValue();

error InputCantBeZeta();

error OutputCantBeZeta();

error OnlyWZETAAllowed();

error InvalidForZEVM();
}

/**
* @dev ZetaTokenConsumer for ZEVM
*/
contract ZetaTokenConsumerZEVM is ZetaTokenConsumer, ZetaTokenConsumerZEVMErrors {
using SafeERC20 for IERC20;
uint256 internal constant MAX_DEADLINE = 200;

address public immutable WETH9Address;

IUniswapV2Router02 internal immutable uniswapV2Router;

constructor(address WETH9Address_, address uniswapV2Router_) {
if (WETH9Address_ == address(0) || uniswapV2Router_ == address(0)) revert ZetaCommonErrors.InvalidAddress();

WETH9Address = WETH9Address_;
uniswapV2Router = IUniswapV2Router02(uniswapV2Router_);
}

function getZetaFromEth(
address destinationAddress,
uint256 minAmountOut
) external payable override returns (uint256) {
if (destinationAddress == address(0)) revert ZetaCommonErrors.InvalidAddress();
if (msg.value == 0) revert InputCantBeZero();
if (msg.value < minAmountOut) revert NotEnoughValue();

IWETH9(WETH9Address).deposit{value: msg.value}();
IERC20(WETH9Address).safeTransfer(destinationAddress, msg.value);
emit EthExchangedForZeta(msg.value, msg.value);
return msg.value;
}

function getZetaFromToken(
address destinationAddress,
uint256 minAmountOut,
address inputToken,
uint256 inputTokenAmount
) external override returns (uint256) {
if (destinationAddress == address(0) || inputToken == address(0)) revert ZetaCommonErrors.InvalidAddress();
if (inputTokenAmount == 0) revert InputCantBeZero();
if (inputToken == WETH9Address) revert InputCantBeZeta();

IERC20(inputToken).safeTransferFrom(msg.sender, address(this), inputTokenAmount);
IERC20(inputToken).safeApprove(address(uniswapV2Router), inputTokenAmount);

address[] memory path = new address[](2);
path[0] = inputToken;
path[1] = WETH9Address;

uint256[] memory amounts = uniswapV2Router.swapExactTokensForTokens(
inputTokenAmount,
minAmountOut,
path,
destinationAddress,
block.timestamp + MAX_DEADLINE
);
uint256 amountOut = amounts[path.length - 1];

emit TokenExchangedForZeta(inputToken, inputTokenAmount, amountOut);
return amountOut;
}

function getEthFromZeta(
address destinationAddress,
uint256 minAmountOut,
uint256 zetaTokenAmount
) external override returns (uint256) {
if (destinationAddress == address(0)) revert ZetaCommonErrors.InvalidAddress();
if (zetaTokenAmount == 0) revert InputCantBeZero();
if (zetaTokenAmount < minAmountOut) revert NotEnoughValue();

IERC20(WETH9Address).safeTransferFrom(msg.sender, address(this), zetaTokenAmount);
IWETH9(WETH9Address).withdraw(zetaTokenAmount);

emit ZetaExchangedForEth(zetaTokenAmount, zetaTokenAmount);

(bool sent, ) = destinationAddress.call{value: zetaTokenAmount}("");
if (!sent) revert ErrorSendingETH();

return zetaTokenAmount;
}

function getTokenFromZeta(
address destinationAddress,
uint256 minAmountOut,
address outputToken,
uint256 zetaTokenAmount
) external override returns (uint256) {
if (destinationAddress == address(0) || outputToken == address(0)) revert ZetaCommonErrors.InvalidAddress();
if (zetaTokenAmount == 0) revert InputCantBeZero();
if (outputToken == WETH9Address) revert OutputCantBeZeta();

IERC20(WETH9Address).safeTransferFrom(msg.sender, address(this), zetaTokenAmount);
IERC20(WETH9Address).safeApprove(address(uniswapV2Router), zetaTokenAmount);

address[] memory path = new address[](2);
path[0] = WETH9Address;
path[1] = outputToken;

uint256[] memory amounts = uniswapV2Router.swapExactTokensForTokens(
zetaTokenAmount,
minAmountOut,
path,
destinationAddress,
block.timestamp + MAX_DEADLINE
);

uint256 amountOut = amounts[path.length - 1];

emit ZetaExchangedForToken(outputToken, zetaTokenAmount, amountOut);
return amountOut;
}

function hasZetaLiquidity() external view override returns (bool) {
revert InvalidForZEVM();
}

receive() external payable {
if (msg.sender != WETH9Address) revert OnlyWZETAAllowed();
}
}
49 changes: 7 additions & 42 deletions data/addresses.testnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@
"chain_name": "zeta_testnet",
"type": "zetaToken"
},
{
"address": "0x48C4475B7A9A6E9c384dDF3eb30c56761a2bc37e",
"category": "messaging",
"chain_id": 7001,
"chain_name": "zeta_testnet",
"type": "zetaTokenConsumerUniV3"
},
{
"address": "0x05BA149A7bd6dC1F937fA9046A9e05C05f3b18b0",
"asset": "",
Expand Down Expand Up @@ -256,41 +263,6 @@
"chain_name": "btc_testnet",
"type": "tss"
},
{
"address": "0x0000ecb8cdd25a18f12daa23f6422e07fbf8b9e1",
"category": "messaging",
"chain_id": 80001,
"chain_name": "mumbai_testnet",
"type": "connector"
},
{
"address": "0x0000a7db254145767262c6a81a7ee1650684258e",
"category": "omnichain",
"chain_id": 80001,
"chain_name": "mumbai_testnet",
"type": "erc20Custody"
},
{
"address": "0x55122f7590164Ac222504436943FAB17B62F5d7d",
"category": "messaging",
"chain_id": 80001,
"chain_name": "mumbai_testnet",
"type": "pauser"
},
{
"address": "0x8531a5aB847ff5B22D855633C25ED1DA3255247e",
"category": "omnichain",
"chain_id": 80001,
"chain_name": "mumbai_testnet",
"type": "tss"
},
{
"address": "0x55122f7590164Ac222504436943FAB17B62F5d7d",
"category": "omnichain",
"chain_id": 80001,
"chain_name": "mumbai_testnet",
"type": "tssUpdater"
},
{
"address": "0x5757371414417b8C6CAad45bAeF941aBc7d3Ab32",
"category": "messaging",
Expand Down Expand Up @@ -326,13 +298,6 @@
"chain_name": "mumbai_testnet",
"type": "weth9"
},
{
"address": "0x0000c9ec4042283e8139c74f4c64bcd1e0b9b54f",
"category": "messaging",
"chain_id": 80001,
"chain_name": "mumbai_testnet",
"type": "zetaToken"
},
{
"address": "0x7e792f3736751e168864106AdbAC50152641A927",
"category": "messaging",
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,16 @@
"license": "MIT",
"main": "./dist/lib/index.js",
"name": "@zetachain/protocol-contracts",
"packageManager": "yarn@1.22.21+sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
},
"scripts": {
"build": "yarn compile && npx del-cli dist abi && npx tsc || true && npx del-cli './dist/typechain-types/**/*.js' && npx cpx './data/**/*' dist/data && npx cpx './artifacts/contracts/**/*' ./abi && npx del-cli './abi/**/*.dbg.json'",
"compile": "npx hardhat compile --force",
"generate": "yarn compile && ./scripts/generate_go.sh || true && ./scripts/generate_addresses.sh && yarn lint:fix",
"docs": "forge doc",
"generate": "yarn compile && ./scripts/generate_go.sh || true && ./scripts/generate_addresses.sh && yarn lint:fix",
"lint": "npx eslint . --ext .js,.ts",
"lint:fix": "npx eslint . --ext .js,.ts,.json --fix",
"prepublishOnly": "yarn build",
Expand All @@ -81,4 +82,4 @@
},
"types": "./dist/lib/index.d.ts",
"version": "0.0.8"
}
}

Large diffs are not rendered by default.

Loading

0 comments on commit 7467348

Please sign in to comment.