Skip to content

Commit

Permalink
Develop cross chain swap (#53)
Browse files Browse the repository at this point in the history
* Develop cross chain swap

* add deploy script

* improve swap

* deploy to athens2

* remove unsed code

* renames

* update readme
  • Loading branch information
andresaiello authored Nov 8, 2022
1 parent 16b56c7 commit 07e33f1
Show file tree
Hide file tree
Showing 19 changed files with 599 additions and 8 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ ZetaChain is a public, decentralized blockchain and smart contract platform buil

#### [Protocol contracts](packages/example-contracts)

#### [ZEVM contracts](packages/zevm-contracts)

### Cross-repo commands

#### Package-specific commands
Expand Down
2 changes: 2 additions & 0 deletions packages/addresses-tools/src/addresses.helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const getScanVariable = ({ customNetworkName }: { customNetworkName?: str
dotenv.config();

const v = {
"athens-v2": "",
"bsc-localnet": "",
"bsc-testnet": process.env.BSCSCAN_API_KEY || "",
"eth-localnet": "",
Expand All @@ -61,6 +62,7 @@ export const getExplorerUrl = ({ customNetworkName }: { customNetworkName?: stri
dotenv.config();

const v = {
"athens-v2": "",
"bsc-localnet": "",
"bsc-testnet": "https://testnet.bscscan.com/",
"eth-localnet": "",
Expand Down
9 changes: 8 additions & 1 deletion packages/addresses-tools/src/networks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import type { NetworksUserConfig } from "hardhat/types";

export const getHardhatConfigNetworks = (PRIVATE_KEYS: string[]): NetworksUserConfig => ({
"athens-v2": {
accounts: PRIVATE_KEYS,
// chainId: 8666,
gas: 5000000,
gasPrice: 80000000000,
url: `http://3.132.197.22:8545`,
},
"bsc-localnet": {
gas: 5000000,
gasPrice: 80000000000,
Expand All @@ -10,7 +17,7 @@ export const getHardhatConfigNetworks = (PRIVATE_KEYS: string[]): NetworksUserCo
accounts: PRIVATE_KEYS,
gas: 5000000,
gasPrice: 80000000000,
url: `https://data-seed-prebsc-2-s3.binance.org:8545`,
url: `https://data-seed-prebsc-1-s1.binance.org:8545`,
},
"eth-localnet": {
gas: 2100000,
Expand Down
35 changes: 30 additions & 5 deletions packages/addresses/src/addresses.athens.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"weth9": "",
"zetaToken": "0x000080383847bd75f91c168269aa74004877592f",
"zetaTokenConsumerUniV2": "0xa67b03930eb53d0462dCc0835e97964C062042fb",
"immutableCreate2Factory": "0x095a03c6a68137fE9a566bBc3e552F299d8b886d"
"immutableCreate2Factory": "0x095a03c6a68137fE9a566bBc3e552F299d8b886d",
"zetaSwap": ""
},
"goerli": {
"connector": "0x00007d0BA516a2bA02D77907d3a1348C1187Ae62",
Expand All @@ -35,7 +36,8 @@
"weth9": "",
"zetaToken": "0xCc7bb2D219A0FC08033E130629C2B854b7bA9195",
"zetaTokenConsumerUniV2": "0xDDB1C86c69f258F6d33377a8725404E4393326bB",
"immutableCreate2Factory": "0x095a03c6a68137fE9a566bBc3e552F299d8b886d"
"immutableCreate2Factory": "0x095a03c6a68137fE9a566bBc3e552F299d8b886d",
"zetaSwap": ""
},
"polygon-mumbai": {
"connector": "0x000054d3A0Bc83Ec7808F52fCdC28A96c89F6C5c",
Expand All @@ -54,7 +56,8 @@
"zetaToken": "0x000080383847bd75f91c168269aa74004877592f",
"zetaTokenConsumerUniV2": "",
"immutableCreate2Factory": "0x095a03c6a68137fE9a566bBc3e552F299d8b886d",
"multiChainSwap": "0xaf28cb0d9E045170E1642321B964740784E7dC64"
"multiChainSwap": "0xaf28cb0d9E045170E1642321B964740784E7dC64",
"zetaSwap": ""
},
"ropsten": {
"connector": "0x000054d3A0Bc83Ec7808F52fCdC28A96c89F6C5c",
Expand All @@ -72,7 +75,8 @@
"weth9": "",
"zetaToken": "0x000080383847bd75f91c168269aa74004877592f",
"zetaTokenConsumerUniV2": "0x197bC8e7e813DfB95dEf0DAA44399648bC86f329",
"immutableCreate2Factory": "0x095a03c6a68137fE9a566bBc3e552F299d8b886d"
"immutableCreate2Factory": "0x095a03c6a68137fE9a566bBc3e552F299d8b886d",
"zetaSwap": ""
},
"klaytn-baobab": {
"connector": "0x000054d3A0Bc83Ec7808F52fCdC28A96c89F6C5c",
Expand All @@ -90,6 +94,27 @@
"weth9": "",
"zetaToken": "0x000080383847bD75F91c168269Aa74004877592f",
"zetaTokenConsumerUniV2": "",
"immutableCreate2Factory": "0x095a03c6a68137fE9a566bBc3e552F299d8b886d"
"immutableCreate2Factory": "0x095a03c6a68137fE9a566bBc3e552F299d8b886d",
"zetaSwap": ""
},
"athens-v2": {
"connector": "",
"crossChainCounter": "",
"crossChainNft": "",
"dai": "",
"multiChainSwap": "",
"multiChainValue": "",
"tss": "",
"tssUpdater": "",
"uniswapV2Router02": "",
"uniswapV3NftManager": "",
"uniswapV3Quoter": "",
"uniswapV3Router": "",
"usdc": "",
"weth9": "",
"zetaToken": "",
"zetaTokenConsumerUniV2": "",
"immutableCreate2Factory": "",
"zetaSwap": "0x8FeAf1BD718E4e6f82d0FE808f44f431B24b47DF"
}
}
14 changes: 12 additions & 2 deletions packages/addresses/src/addresses.helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export type ZetaAddress =
| "uniswapV3Router"
| "usdc"
| "weth9"
| "zetaSwap"
| "zetaToken"
| "zetaTokenConsumerUniV2";

Expand All @@ -40,6 +41,7 @@ const zetaAddresses: Record<ZetaAddress, boolean> = {
uniswapV3Router: true,
usdc: true,
weth9: true,
zetaSwap: true,
zetaToken: true,
zetaTokenConsumerUniV2: true
};
Expand Down Expand Up @@ -69,15 +71,22 @@ export const getLocalnetList = (): Record<ZetaLocalNetworkName, LocalnetAddressG
* @description Testnet
*/

export type TestnetNetworkName = "bsc-testnet" | "goerli" | "klaytn-baobab" | "polygon-mumbai" | "ropsten";
export type TestnetNetworkName =
| "athens-v2"
| "bsc-testnet"
| "goerli"
| "klaytn-baobab"
| "polygon-mumbai"
| "ropsten";
export type ZetaTestnetNetworkName = "athens";
export type TestnetAddressGroup = Record<TestnetNetworkName, NetworkAddresses>;
export const isTestnetNetworkName = (networkName: string): networkName is TestnetNetworkName =>
networkName === "goerli" ||
networkName === "bsc-testnet" ||
networkName === "polygon-mumbai" ||
networkName === "ropsten" ||
networkName === "klaytn-baobab";
networkName === "klaytn-baobab" ||
networkName === "athens-v2";
export const isZetaTestnet = (networkName: string | undefined): networkName is ZetaTestnetNetworkName =>
networkName === "athens";

Expand Down Expand Up @@ -110,6 +119,7 @@ export type ZetaNetworkName = ZetaLocalNetworkName | ZetaMainnetNetworkName | Ze

export const getChainId = (networkName: NetworkName) => {
const chainIds: Record<NetworkName, number> = {
"athens-v2": 101,
"bsc-localnet": 97,
"bsc-testnet": 97,
"eth-localnet": 5,
Expand Down
Empty file.
23 changes: 23 additions & 0 deletions packages/zevm-contracts/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const path = require("path");

const OFF = 0;

module.exports = {
env: {
browser: false,
es2021: true,
mocha: true,
node: true,
},
extends: ["../../.eslintrc.js"],
rules: {
"no-console": OFF,
},
settings: {
"import/resolver": {
typescript: {
project: path.join(__dirname, "tsconfig.json"),
},
},
},
};
16 changes: 16 additions & 0 deletions packages/zevm-contracts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# ZetaEVM contracts

> ⚠️ The contracts **are not audited yet**, use at your own risk.
## Environment variables

Follow the template in `.env.example`.

* The private key should **not** include `0x`.
* To verify your contracts, you'll need api keys both in BSCScan and Etherscan.

## Running Tests

```bash
yarn test
```
31 changes: 31 additions & 0 deletions packages/zevm-contracts/contracts/interfaces/IZRC4.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;

interface IZRC4 {
function totalSupply() external view returns (uint256);

function balanceOf(address account) external view returns (uint256);

function transfer(address recipient, uint256 amount) external returns (bool);

function allowance(address owner, address spender) external view returns (uint256);

function approve(address spender, uint256 amount) external returns (bool);

function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);

function deposit(address to, uint256 amount) external returns (bool);

function withdraw(bytes memory to, uint256 amount) external returns (bool);

function withdrawGasFee() external view returns (address, uint256);

event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
event Deposit(bytes from, address indexed to, uint256 value);
event Withdrawal(address indexed from, bytes to, uint256 value);
}
10 changes: 10 additions & 0 deletions packages/zevm-contracts/contracts/interfaces/zContract.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;

interface zContract {
function onCrossChainCall(
address zrc4,
uint256 amount,
bytes calldata message
) external;
}
115 changes: 115 additions & 0 deletions packages/zevm-contracts/contracts/system/SystemContract.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;

import "../interfaces/zContract.sol";
import "../interfaces/IZRC4.sol";

interface SystemContractErrors {
error CallerIsNotFungibleModule();

error InvalidTarget();

error CantBeIdenticalAddresses();

error CantBeZeroAddress();
}

contract SystemContract is SystemContractErrors {
mapping(uint256 => uint256) public gasPriceByChainId;
mapping(uint256 => address) public gasCoinZRC4ByChainId;
mapping(uint256 => address) public gasZetaPoolByChainId;

address public constant FUNGIBLE_MODULE_ADDRESS = 0x735b14BB79463307AAcBED86DAf3322B1e6226aB;
address public wZetaContractAddress;
address public uniswapv2FactoryAddress;
address public uniswapv2Router02Address;

event SystemContractDeployed();
event SetGasPrice(uint256, uint256);
event SetGasCoin(uint256, address);
event SetGasZetaPool(uint256, address);
event SetWZeta(address);

constructor(
address wzeta_,
address uniswapv2Factory_,
address uniswapv2Router02_
) {
if (msg.sender != FUNGIBLE_MODULE_ADDRESS) revert CallerIsNotFungibleModule();
wZetaContractAddress = wzeta_;
uniswapv2FactoryAddress = uniswapv2Factory_;
uniswapv2Router02Address = uniswapv2Router02_;
emit SystemContractDeployed();
}

// deposit foreign coins into ZRC4 and call user specified contract on zEVM
function depositAndCall(
address zrc4,
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();

IZRC4(zrc4).deposit(target, amount);
zContract(target).onCrossChainCall(zrc4, amount, message);
}

// returns sorted token addresses, used to handle return values from pairs sorted in this order
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();
}

// calculates the CREATE2 address for a pair without making any external calls
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
)
)
)
)
);
}

// fungible module updates the gas price oracle periodically
function setGasPrice(uint256 chainID, uint256 price) external {
if (msg.sender != FUNGIBLE_MODULE_ADDRESS) revert CallerIsNotFungibleModule();
gasPriceByChainId[chainID] = price;
emit SetGasPrice(chainID, price);
}

function setGasCoinZRC4(uint256 chainID, address zrc4) external {
if (msg.sender != FUNGIBLE_MODULE_ADDRESS) revert CallerIsNotFungibleModule();
gasCoinZRC4ByChainId[chainID] = zrc4;
emit SetGasCoin(chainID, zrc4);
}

// set the pool wzeta/erc20 address
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);
}

function setWZETAContractAddress(address addr) external {
if (msg.sender != FUNGIBLE_MODULE_ADDRESS) revert CallerIsNotFungibleModule();
wZetaContractAddress = addr;
emit SetWZeta(wZetaContractAddress);
}
}
Loading

0 comments on commit 07e33f1

Please sign in to comment.