Skip to content
This repository has been archived by the owner on Jan 6, 2023. It is now read-only.

Commit

Permalink
Merge pull request #1 from binance-chain/bsc_swap
Browse files Browse the repository at this point in the history
[R4R] Prepare the initial release of BSC Swap
  • Loading branch information
yutianwu committed Feb 26, 2021
2 parents 49234ae + e9e227d commit 0c32cc7
Show file tree
Hide file tree
Showing 34 changed files with 6,609 additions and 435 deletions.
8 changes: 6 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
.idea
node_modules
.idea/*
node_modules
build
contracts/flattened/*.sol
coverage
coverage.json
8 changes: 0 additions & 8 deletions .idea/eth-bsc-swap-contracts.iml

This file was deleted.

8 changes: 0 additions & 8 deletions .idea/modules.xml

This file was deleted.

6 changes: 0 additions & 6 deletions .idea/vcs.xml

This file was deleted.

50 changes: 0 additions & 50 deletions .idea/workspace.xml

This file was deleted.

55 changes: 55 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# ETH BSC Swap Contracts

## Overview
ETH BSC Swap Contracts are responsible for registering swap pairs and swapping assets between ETH and BSC.

![](./assets/eth-bsc-swap.png)

### Register swap pair

1. Users register swap pair for erc20 token on ETH via ETHSwapAgent(`createSwapPair`) if token is not registered.
2. Swap service will monitor the `SwapPairRegister` event and create swap pair on BSC:

1. create an BEP20 token on BSC
2. record the relation between erc20 token and bep20 token.

### Swap from ETH to BSC

Once swap pair is registered, users can swap tokens from ETH to BSC.

1. Users call `swapBSC2ETH` via ETHSwapAgent and specify erc20 token address, amount and swap fee.
2. Swap service will monitor the `SwapStarted` event and call `fillETH2BSCSwap` via BSCSwapAgent to mint corresponding bep20
tokens to the same address that initiate the swap.

### Swap from BSC to ETH

Once swap pair is registered, users can swap tokens from BSC to ETH.

1. Users call `swapBSC2ETH` via BSCSwapAgent and specify bep20 token address, amount and swap fee. Bep20 tokens will be burned.
2. Swap service will monitor the `SwapStarted` event and call `fillBSC2ETHSwap` via BSCSwapAgent to transfer corresponding erc20
tokens to the same address that initiate the swap.

## Generate contracts from templates

```javascript
npm run generate
```

## Test

Generate test contracts from templates:
```javascript
npm run generate-test
```

Run tests:

```javascript
npm run truffle:test
```

Run coverage:

```javascript
npm run coverage
```
Binary file added assets/eth-bsc-swap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
137 changes: 137 additions & 0 deletions contracts/BSCSwapAgentImpl.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
pragma solidity 0.6.4;

import "./interfaces/ISwap.sol";
import "./bep20/BEP20UpgradeableProxy.sol";
import './interfaces/IProxyInitialize.sol';
import "openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol";
import "openzeppelin-solidity/contracts/proxy/Initializable.sol";
import "openzeppelin-solidity/contracts/GSN/Context.sol";

contract BSCSwapAgentImpl is Context, Initializable {


using SafeERC20 for IERC20;

mapping(address => address) public swapMappingETH2BSC;
mapping(address => address) public swapMappingBSC2ETH;
mapping(bytes32 => bool) public filledETHTx;

address payable public owner;
address public bep20ProxyAdmin;
address public bep20Implementation;
uint256 public swapFee;

event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
event SwapPairCreated(bytes32 indexed ethRegisterTxHash, address indexed bep20Addr, address indexed erc20Addr, string symbol, string name, uint8 decimals);
event SwapStarted(address indexed bep20Addr, address indexed erc20Addr, address indexed fromAddr, uint256 amount, uint256 feeAmount);
event SwapFilled(address indexed bep20Addr, bytes32 indexed ethTxHash, address indexed toAddress, uint256 amount);

constructor() public {
}

/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner == _msgSender(), "Ownable: caller is not the owner");
_;
}

modifier notContract() {
require(!isContract(msg.sender), "contract is not allowed to swap");
require(msg.sender == tx.origin, "no proxy contract is allowed");
_;
}



function initialize(address bep20Impl, uint256 fee, address payable ownerAddr, address bep20ProxyAdminAddr) public initializer {
bep20Implementation = bep20Impl;
swapFee = fee;
owner = ownerAddr;
bep20ProxyAdmin = bep20ProxyAdminAddr;
}

function isContract(address addr) internal view returns (bool) {
uint size;
assembly { size := extcodesize(addr) }
return size > 0;
}

/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(owner, address(0));
owner = address(0);
}

/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address payable newOwner) public onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}

/**
* @dev Returns set minimum swap fee from BEP20 to ERC20
*/
function setSwapFee(uint256 fee) onlyOwner external {
swapFee = fee;
}

/**
* @dev createSwapPair
*/
function createSwapPair(bytes32 ethTxHash, address erc20Addr, string calldata name, string calldata symbol, uint8 decimals) onlyOwner external returns (address) {
require(swapMappingETH2BSC[erc20Addr] == address(0x0), "duplicated swap pair");

BEP20UpgradeableProxy proxyToken = new BEP20UpgradeableProxy(bep20Implementation, bep20ProxyAdmin, "");
IProxyInitialize token = IProxyInitialize(address(proxyToken));
token.initialize(name, symbol, decimals, 0, true, address(this));

swapMappingETH2BSC[erc20Addr] = address(token);
swapMappingBSC2ETH[address(token)] = erc20Addr;

emit SwapPairCreated(ethTxHash, address(token), erc20Addr, symbol, name, decimals);
return address(token);
}

/**
* @dev fillETH2BSCSwap
*/
function fillETH2BSCSwap(bytes32 ethTxHash, address erc20Addr, address toAddress, uint256 amount) onlyOwner external returns (bool) {
require(!filledETHTx[ethTxHash], "eth tx filled already");
address bscTokenAddr = swapMappingETH2BSC[erc20Addr];
require(bscTokenAddr != address(0x0), "no swap pair for this token");
filledETHTx[ethTxHash] = true;
ISwap(bscTokenAddr).mintTo(amount, toAddress);
emit SwapFilled(bscTokenAddr, ethTxHash, toAddress, amount);

return true;
}
/**
* @dev swapBSC2ETH
*/
function swapBSC2ETH(address bep20Addr, uint256 amount) payable external notContract returns (bool) {
address erc20Addr = swapMappingBSC2ETH[bep20Addr];
require(erc20Addr != address(0x0), "no swap pair for this token");
require(msg.value == swapFee, "swap fee not equal");

IERC20(bep20Addr).safeTransferFrom(msg.sender, address(this), amount);
ISwap(bep20Addr).burn(amount);
if (msg.value != 0) {
owner.transfer(msg.value);
}

emit SwapStarted(bep20Addr, erc20Addr, msg.sender, amount, msg.value);
return true;
}
}
Loading

0 comments on commit 0c32cc7

Please sign in to comment.