From 69821bf3c7e3f5406f1fee05411e94807b63b5ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=B1=E5=A4=A9=E6=9D=B0?= <835919358@qq.com> Date: Thu, 15 Apr 2021 16:18:00 +0800 Subject: [PATCH 1/2] rebase From 9b9f190cd357625fb885565a4ca7150c8469afc8 Mon Sep 17 00:00:00 2001 From: KSlashh <835919358@qq.com> Date: Tue, 22 Aug 2023 11:23:48 +0800 Subject: [PATCH 2/2] add wrapper_v4 --- src/eth-no-truffle/PolyWrapper_v1.sol | 2 +- src/eth-no-truffle/PolyWrapper_v2.sol | 2 +- src/eth-no-truffle/PolyWrapper_v3.sol | 2 +- src/eth-no-truffle/PolyWrapper_v4.sol | 180 ++++++++++++++++++++++++++ 4 files changed, 183 insertions(+), 3 deletions(-) create mode 100644 src/eth-no-truffle/PolyWrapper_v4.sol diff --git a/src/eth-no-truffle/PolyWrapper_v1.sol b/src/eth-no-truffle/PolyWrapper_v1.sol index 1e61916..2f31c93 100644 --- a/src/eth-no-truffle/PolyWrapper_v1.sol +++ b/src/eth-no-truffle/PolyWrapper_v1.sol @@ -10,7 +10,7 @@ import "./libs/lifecycle/Pausable.sol"; import "./interfaces/ILockProxy.sol"; -contract PolyWrapper is Ownable, Pausable, ReentrancyGuard { +contract PolyWrapperV1 is Ownable, Pausable, ReentrancyGuard { using SafeMath for uint; using SafeERC20 for IERC20; diff --git a/src/eth-no-truffle/PolyWrapper_v2.sol b/src/eth-no-truffle/PolyWrapper_v2.sol index 3bb5fab..19e25e2 100644 --- a/src/eth-no-truffle/PolyWrapper_v2.sol +++ b/src/eth-no-truffle/PolyWrapper_v2.sol @@ -10,7 +10,7 @@ import "./libs/lifecycle/Pausable.sol"; import "./interfaces/ILockProxy.sol"; -contract PolyWrapper is Ownable, Pausable, ReentrancyGuard { +contract PolyWrapperV2 is Ownable, Pausable, ReentrancyGuard { using SafeMath for uint; using SafeERC20 for IERC20; diff --git a/src/eth-no-truffle/PolyWrapper_v3.sol b/src/eth-no-truffle/PolyWrapper_v3.sol index 73e1ce9..099c003 100644 --- a/src/eth-no-truffle/PolyWrapper_v3.sol +++ b/src/eth-no-truffle/PolyWrapper_v3.sol @@ -10,7 +10,7 @@ import "./libs/lifecycle/Pausable.sol"; import "./interfaces/ILockProxy.sol"; -contract PolyWrapper is Ownable, Pausable, ReentrancyGuard { +contract PolyWrapperV3 is Ownable, Pausable, ReentrancyGuard { using SafeMath for uint; using SafeERC20 for IERC20; diff --git a/src/eth-no-truffle/PolyWrapper_v4.sol b/src/eth-no-truffle/PolyWrapper_v4.sol new file mode 100644 index 0000000..321a48d --- /dev/null +++ b/src/eth-no-truffle/PolyWrapper_v4.sol @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.6.0; + +import "./libs/token/ERC20/SafeERC20.sol"; +import "./libs/token/ERC20/IERC20.sol"; +import "./libs/access/Ownable.sol"; +import "./libs/utils/ReentrancyGuard.sol"; +import "./libs/math/SafeMath.sol"; +import "./libs/lifecycle/Pausable.sol"; + +import "./interfaces/ILockProxy.sol"; + +contract PolyWrapperV4 is Ownable, Pausable, ReentrancyGuard { + using SafeMath for uint; + using SafeERC20 for IERC20; + + uint public maxLockProxyIndex = 0; + uint public chainId; + address public feeCollector; + + mapping(uint => address) public lockProxyIndexMap; + + constructor(address _owner, uint _chainId) public { + require(_chainId != 0, "!legal"); + transferOwnership(_owner); + chainId = _chainId; + } + + function setFeeCollector(address collector) external onlyOwner { + require(collector != address(0), "emtpy address"); + feeCollector = collector; + } + + function resetLockProxy(uint index, address _lockProxy) external onlyOwner { + require(_lockProxy != address(0)); + require(lockProxyIndexMap[index] != address(0), "no lockproxy exsist in given index"); + lockProxyIndexMap[index] = _lockProxy; + require(ILockProxy(_lockProxy).managerProxyContract() != address(0), "not lockproxy"); + } + + function addLockProxy(address _lockProxy) external onlyOwner { + require(_lockProxy != address(0)); + lockProxyIndexMap[maxLockProxyIndex++] = _lockProxy; + require(ILockProxy(_lockProxy).managerProxyContract() != address(0), "not lockproxy"); + } + + function pause() external onlyOwner { + _pause(); + } + + function unpause() external onlyOwner { + _unpause(); + } + + function extractFee(address token) external { + require(msg.sender == feeCollector, "!feeCollector"); + if (token == address(0)) { + payable(msg.sender).transfer(address(this).balance); + } else { + IERC20(token).safeTransfer(feeCollector, IERC20(token).balanceOf(address(this))); + } + } + + function lock(address fromAsset, uint64 toChainId, bytes memory toAddress, uint amount, uint fee, uint id) external payable nonReentrant whenNotPaused { + + require(toChainId != chainId && toChainId != 0, "!toChainId"); + require(toAddress.length !=0, "empty toAddress"); + address addr; + assembly { addr := mload(add(toAddress,0x14)) } + require(addr != address(0),"zero toAddress"); + + _pull(fromAsset, amount); + + amount = _checkoutFee(fromAsset, amount, fee); + + address lockProxy = _getSupportLockProxy(fromAsset, toChainId); + _push(fromAsset, toChainId, toAddress, amount, lockProxy); + + _collectFee(); + + emit PolyWrapperLock(fromAsset, msg.sender, toChainId, toAddress, amount, fee, id); + } + + function specifiedLock(address fromAsset, uint64 toChainId, bytes memory toAddress, uint amount, uint fee, uint id, address lockProxy) external payable nonReentrant whenNotPaused { + + require(toChainId != chainId && toChainId != 0, "!toChainId"); + require(toAddress.length !=0, "empty toAddress"); + address addr; + assembly { addr := mload(add(toAddress,0x14)) } + require(addr != address(0),"zero toAddress"); + + _pull(fromAsset, amount); + + amount = _checkoutFee(fromAsset, amount, fee); + + require(isValidLockProxy(lockProxy),"invalid lockProxy"); + _push(fromAsset, toChainId, toAddress, amount, lockProxy); + + _collectFee(); + + emit PolyWrapperLock(fromAsset, msg.sender, toChainId, toAddress, amount, fee, id); + } + + function speedUp(address fromAsset, bytes memory txHash, uint fee) external payable nonReentrant whenNotPaused { + _pull(fromAsset, fee); + emit PolyWrapperSpeedUp(fromAsset, txHash, msg.sender, fee); + } + + function _pull(address fromAsset, uint amount) internal { + if (fromAsset == address(0)) { + require(msg.value == amount, "insufficient ether"); + } else { + IERC20(fromAsset).safeTransferFrom(msg.sender, address(this), amount); + } + } + + function _collectFee() internal { + if (feeCollector != address(0)) { + payable(feeCollector).transfer(address(this).balance); + } + } + + // take fee in the form of ether + function _checkoutFee(address fromAsset, uint amount, uint fee) internal view returns (uint) { + if (fromAsset == address(0)) { + require(msg.value >= amount, "insufficient ether"); + require(amount > fee, "amount less than fee"); + return amount.sub(fee); + } else { + require(msg.value >= fee, "insufficient ether"); + return amount; + } + } + + function _push(address fromAsset, uint64 toChainId, bytes memory toAddress, uint amount, address lockProxyAddress) internal { + ILockProxy lockProxy = ILockProxy(lockProxyAddress); + if (fromAsset == address(0)) { + require(lockProxy.lock{value: amount}(fromAsset, toChainId, toAddress, amount), "lock ether fail"); + } else { + IERC20(fromAsset).safeApprove(address(lockProxy), 0); + IERC20(fromAsset).safeApprove(address(lockProxy), amount); + require(lockProxy.lock(fromAsset, toChainId, toAddress, amount), "lock erc20 fail"); + } + } + + function isValidLockProxy(address lockProxy) public view returns(bool) { + for (uint i=0;i