From 7e3786b4d4ff625c64cf13b1a8067fa3efe99fb3 Mon Sep 17 00:00:00 2001 From: huyhuynh3103 Date: Sat, 30 Dec 2023 15:17:53 +0700 Subject: [PATCH] feat: add ron transfer libs --- src/interfaces/IWRON.sol | 16 +++ src/interfaces/IWRONHelper.sol | 10 ++ src/transfers/LibRONTransfer.sol | 37 +++++++ src/transfers/LibRONTransferExtended.sol | 122 +++++++++++++++++++++++ 4 files changed, 185 insertions(+) create mode 100644 src/interfaces/IWRON.sol create mode 100644 src/interfaces/IWRONHelper.sol create mode 100644 src/transfers/LibRONTransfer.sol create mode 100644 src/transfers/LibRONTransferExtended.sol diff --git a/src/interfaces/IWRON.sol b/src/interfaces/IWRON.sol new file mode 100644 index 0000000..c1d4f18 --- /dev/null +++ b/src/interfaces/IWRON.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IWRON { + function deposit() external payable; + + function transfer(address to, uint256 value) external returns (bool); + + function transferFrom(address src, address dst, uint256 wad) external returns (bool); + + function withdraw(uint256) external; + + function balanceOf(address) external view returns (uint256); + + function approve(address guy, uint256 wad) external returns (bool); +} diff --git a/src/interfaces/IWRONHelper.sol b/src/interfaces/IWRONHelper.sol new file mode 100644 index 0000000..370b47e --- /dev/null +++ b/src/interfaces/IWRONHelper.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IWRONHelper { + function WRON() external view returns (address); + + function withdraw(uint256 _amount) external; + + function withdrawTo(address payable _to, uint256 _amount) external; +} diff --git a/src/transfers/LibRONTransfer.sol b/src/transfers/LibRONTransfer.sol new file mode 100644 index 0000000..035a3f0 --- /dev/null +++ b/src/transfers/LibRONTransfer.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/utils/Strings.sol"; + +/** + * @title RONTransferHelper + */ +library LibRONTransfer { + /** + * @dev Transfers RON and wraps result for the method caller to a recipient. + */ + function safeTransfer(address payable _to, uint256 _value) internal { + bool _success = send(_to, _value); + + if (!_success) { + revert( + string( + abi.encodePacked( + "RONTransferHelper: could not transfer RON to ", + Strings.toHexString(uint160(address(_to)), 20), + " value ", + Strings.toHexString(_value) + ) + ) + ); + } + } + + /** + * @dev Returns whether the call was success. + * Note: this function should use with the `ReentrancyGuard`. + */ + function send(address payable _to, uint256 _value) internal returns (bool _success) { + (_success,) = _to.call{ value: _value }(new bytes(0)); + } +} diff --git a/src/transfers/LibRONTransferExtended.sol b/src/transfers/LibRONTransferExtended.sol new file mode 100644 index 0000000..50b5ba7 --- /dev/null +++ b/src/transfers/LibRONTransferExtended.sol @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../interfaces/IWRON.sol"; +import "../interfaces/IWRONHelper.sol"; +import "./LibRONTransfer.sol"; +import "./LibTokenTransferFrom.sol"; +import "./LibTokenTransfer.sol"; + +library LibRONTransferExtended { + /** + * @dev Safely unwraps tokens if it is WRON token and transfers them to a specified recipient. + * @param _wron Address of the WRON contract. + * @param _token Address of the ERC20 token to unwrap and transfer. + * @param _to Address of the recipient to transfer the tokens to. + * @param _amount Amount of tokens to transfer. + * + * Note: This function may cause a revert if the consumer contract is a proxy, consider using the method + * `safeUnwrapTokenAndTransferWithHelper` instead. + */ + function safeUnwrapTokenAndTransfer(IWRON _wron, address _token, address payable _to, uint256 _amount) internal { + if (_token == address(_wron)) { + // Check whether the recipient receives RON + if (LibRONTransfer.send(_to, 0)) { + _wron.withdraw(_amount); + LibRONTransfer.safeTransfer(_to, _amount); + return; + } + } + + LibTokenTransfer.safeTransfer(_token, _to, _amount); + } + + /** + * @dev See `safeUnwrapTokenAndTransfer`. + * + * Requirements: + * - The consumer contract must approve the contract `_wronHelper`. + * + * Note: This function supports the use of a proxy contract by using the WRONHelper contract to unwrap WRON and + * transfer RON. + */ + function safeUnwrapTokenAndTransferWithHelper( + IWRON _wron, + IWRONHelper _wronHelper, + address _token, + address payable _to, + uint256 _amount + ) internal { + if (_token == address(_wron)) { + // Check whether the recipient receives RON + if (LibRONTransfer.send(_to, 0)) { + _wron.approve(address(_wronHelper), _amount); + _wronHelper.withdrawTo(_to, _amount); + return; + } + } + + LibTokenTransfer.safeTransfer(_token, _to, _amount); + } + + /** + * @dev Safely unwraps tokens if it is WRON token from specified sender, and transfers them to a specified recipient. + * @param _wron Address of the WRON contract. + * @param _token Address of the ERC20 token to unwrap and transfer. + * @param _from Address of the sender on whose behalf the tokens will be unwrapped and transferred. + * @param _to Address of the recipient to transfer the tokens to. + * @param _amount Amount of tokens to transfer. + * + * Note: This function may cause a revert if the consumer contract is a proxy, consider using the method + * `safeUnwrapTokenAndTransferFromWithHelper` instead. + */ + function safeUnwrapTokenAndTransferFrom( + IWRON _wron, + address _token, + address _from, + address payable _to, + uint256 _amount + ) internal { + if (_token == address(_wron)) { + // Check whether the recipient receives RON + if (LibRONTransfer.send(_to, 0)) { + LibTokenTransferFrom.safeTransferFrom(_token, _from, address(this), _amount); + IWRON(_wron).withdraw(_amount); + LibRONTransfer.safeTransfer(_to, _amount); + return; + } + } + + LibTokenTransferFrom.safeTransferFrom(_token, _from, _to, _amount); + } + + /** + * @dev See `safeUnwrapTokenAndTransfer`. + * + * Requirements: + * - The consumer contract must approve the contract `_wronHelper`. + * + * Note: This function supports the use of a proxy contract by using the WRONHelper contract to unwrap WRON and + * transfer RON. + */ + function safeUnwrapTokenAndTransferFromWithHelper( + IWRON _wron, + IWRONHelper _wronHelper, + address _token, + address _from, + address payable _to, + uint256 _amount + ) internal { + if (_token == address(_wron)) { + // Check whether the recipient receives RON + if (LibRONTransfer.send(_to, 0)) { + LibTokenTransferFrom.safeTransferFrom(_token, _from, address(this), _amount); + _wron.approve(address(_wronHelper), _amount); + _wronHelper.withdrawTo(_to, _amount); + return; + } + } + + LibTokenTransferFrom.safeTransferFrom(_token, _from, _to, _amount); + } +}