This repository has been archived by the owner on Jan 6, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 93
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from binance-chain/bsc_swap
[R4R] Prepare the initial release of BSC Swap
- Loading branch information
Showing
34 changed files
with
6,609 additions
and
435 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
``` |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
Oops, something went wrong.