From dce15a5b5c73cb3283f14080add34bae68cd3260 Mon Sep 17 00:00:00 2001 From: Akash Gianchandani Date: Wed, 4 Oct 2023 19:22:50 +0530 Subject: [PATCH] feat(contracts): add new forwarder contracts WIN-506 --- contracts/CloneFactory.sol | 2 +- contracts/ERC20Interface.sol | 2 +- contracts/IForwarder.sol | 2 +- contracts/NewForwarder.sol | 332 ------------------------------ contracts/NewForwarderFactory.sol | 50 ----- contracts/TransferHelper.sol | 2 +- 6 files changed, 4 insertions(+), 386 deletions(-) delete mode 100644 contracts/NewForwarder.sol delete mode 100644 contracts/NewForwarderFactory.sol diff --git a/contracts/CloneFactory.sol b/contracts/CloneFactory.sol index ea3e7a8..3609ea4 100644 --- a/contracts/CloneFactory.sol +++ b/contracts/CloneFactory.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // from https://github.com/optionality/clone-factory -pragma solidity 0.8.15; +pragma solidity 0.8.10; /* The MIT License (MIT) diff --git a/contracts/ERC20Interface.sol b/contracts/ERC20Interface.sol index 5684924..350dd5c 100644 --- a/contracts/ERC20Interface.sol +++ b/contracts/ERC20Interface.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.15; +pragma solidity 0.8.10; /** * Contract that exposes the needed erc20 token functions diff --git a/contracts/IForwarder.sol b/contracts/IForwarder.sol index 3a9ab74..ff33e71 100644 --- a/contracts/IForwarder.sol +++ b/contracts/IForwarder.sol @@ -1,4 +1,4 @@ -pragma solidity 0.8.15; +pragma solidity ^0.8.0; import '@openzeppelin/contracts/utils/introspection/IERC165.sol'; diff --git a/contracts/NewForwarder.sol b/contracts/NewForwarder.sol deleted file mode 100644 index 0fd1d0a..0000000 --- a/contracts/NewForwarder.sol +++ /dev/null @@ -1,332 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.15; -import '@openzeppelin/contracts/token/ERC1155/IERC1155.sol'; -import '@openzeppelin/contracts/token/ERC721/IERC721.sol'; -import '@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol'; -import '@openzeppelin/contracts/token/ERC1155/utils/ERC1155Receiver.sol'; -import './ERC20Interface.sol'; -import './TransferHelper.sol'; -import './IForwarder.sol'; - -/** - * Contract that will forward any incoming Ether to the parent address of the contract - * - */ -contract NewForwarder is IERC721Receiver, ERC1155Receiver, IForwarder { - // Address to which any funds sent to this contract will be forwarded - address public parentAddress; - address public feeAddress; - mapping(address => bool) public whiteListedAddresses; - bool public autoFlush721 = true; - bool public autoFlush1155 = true; - - event ForwarderDeposited(address from, uint256 value, bytes data); - - /** - * Initialize the contract, and sets the destination address to that of the parent address - */ - function init ( - address _parentAddress, - address _feeAddress, - bool _autoFlush721, - bool _autoFlush1155 - ) external onlyUninitialized { - parentAddress = _parentAddress; - feeAddress = _feeAddress; - - whiteListedAddresses[parentAddress] = true; - whiteListedAddresses[feeAddress] = true; - uint256 value = address(this).balance; - - // set whether we want to automatically flush erc721/erc1155 tokens or not - autoFlush721 = _autoFlush721; - autoFlush1155 = _autoFlush1155; - - if (value == 0) { - return; - } - - (bool success, ) = parentAddress.call{ value: value }(''); - require(success, 'Flush failed'); - - // NOTE: since we are forwarding on initialization, - // we don't have the context of the original sender. - // We still emit an event about the forwarding but set - // the sender to the forwarder itself - emit ForwarderDeposited(address(this), value, msg.data); - } - - /** - * Modifier that will execute internal code block only if the sender is the whitelisted address - */ - modifier onlyWhitelistedAddress { - require(whiteListedAddresses[msg.sender], 'Address not in whitelist'); - _; - } - - /** - * Modifier that will execute internal code block only if the contract has not been initialized yet - */ - modifier onlyUninitialized { - require(parentAddress == address(0x0), 'Already initialized'); - _; - } - - /** - * Default function; Gets called when data is sent but does not match any other function - */ - fallback() external payable { - flush(); - } - - /** - * Default function; Gets called when Ether is deposited with no data, and forwards it to the parent address - */ - receive() external payable { - flush(); - } - - /** - * @inheritdoc IForwarder - */ - function setAutoFlush721(bool autoFlush) - external - virtual - override - onlyWhitelistedAddress - { - autoFlush721 = autoFlush; - } - - /** - * @inheritdoc IForwarder - */ - function setAutoFlush1155(bool autoFlush) - external - virtual - override - onlyWhitelistedAddress - { - autoFlush1155 = autoFlush; - } - - /** - * ERC721 standard callback function for when a ERC721 is transfered. The forwarder will send the nft - * to the base wallet once the nft contract invokes this method after transfering the nft. - * - * @param _operator The address which called `safeTransferFrom` function - * @param _from The address of the sender - * @param _tokenId The token id of the nft - * @param data Additional data with no specified format, sent in call to `_to` - */ - function onERC721Received( - address _operator, - address _from, - uint256 _tokenId, - bytes memory data - ) external virtual override returns (bytes4) { - if (autoFlush721) { - IERC721 instance = IERC721(msg.sender); - require( - instance.supportsInterface(type(IERC721).interfaceId), - 'The caller does not support the ERC721 interface' - ); - // this won't work for ERC721 re-entrancy - instance.safeTransferFrom(address(this), parentAddress, _tokenId, data); - } - - return this.onERC721Received.selector; - } - - function callFromWhitelistedAddress( - address target, - uint256 value, - bytes calldata data - ) external onlyWhitelistedAddress returns (bytes memory) { - (bool success, bytes memory returnedData) = target.call{ value: value }( - data - ); - require(success, 'Whitelisted address call execution failed'); - - return returnedData; - } - - /** - * @inheritdoc IERC1155Receiver - */ - function onERC1155Received( - address _operator, - address _from, - uint256 id, - uint256 value, - bytes calldata data - ) external virtual override returns (bytes4) { - IERC1155 instance = IERC1155(msg.sender); - require( - instance.supportsInterface(type(IERC1155).interfaceId), - 'The caller does not support the IERC1155 interface' - ); - - if (autoFlush1155) { - instance.safeTransferFrom(address(this), parentAddress, id, value, data); - } - - return this.onERC1155Received.selector; - } - - /** - * @inheritdoc IERC1155Receiver - */ - function onERC1155BatchReceived( - address _operator, - address _from, - uint256[] calldata ids, - uint256[] calldata values, - bytes calldata data - ) external virtual override returns (bytes4) { - IERC1155 instance = IERC1155(msg.sender); - require( - instance.supportsInterface(type(IERC1155).interfaceId), - 'The caller does not support the IERC1155 interface' - ); - - if (autoFlush1155) { - instance.safeBatchTransferFrom( - address(this), - parentAddress, - ids, - values, - data - ); - } - - return this.onERC1155BatchReceived.selector; - } - - /** - * @inheritdoc IForwarder - */ - function flushTokens(address tokenContractAddress) - external - virtual - override - onlyWhitelistedAddress - { - ERC20Interface instance = ERC20Interface(tokenContractAddress); - address forwarderAddress = address(this); - uint256 forwarderBalance = instance.balanceOf(forwarderAddress); - if (forwarderBalance == 0) { - return; - } - - TransferHelper.safeTransfer( - tokenContractAddress, - parentAddress, - forwarderBalance - ); - } - - /** - * @inheritdoc IForwarder - */ - function flushERC721Token(address tokenContractAddress, uint256 tokenId) - external - virtual - override - onlyWhitelistedAddress - { - IERC721 instance = IERC721(tokenContractAddress); - require( - instance.supportsInterface(type(IERC721).interfaceId), - 'The tokenContractAddress does not support the ERC721 interface' - ); - - address ownerAddress = instance.ownerOf(tokenId); - instance.transferFrom(ownerAddress, parentAddress, tokenId); - } - - /** - * @inheritdoc IForwarder - */ - function flushERC1155Tokens(address tokenContractAddress, uint256 tokenId) - external - virtual - override - onlyWhitelistedAddress - { - IERC1155 instance = IERC1155(tokenContractAddress); - require( - instance.supportsInterface(type(IERC1155).interfaceId), - 'The caller does not support the IERC1155 interface' - ); - - address forwarderAddress = address(this); - uint256 forwarderBalance = instance.balanceOf(forwarderAddress, tokenId); - - instance.safeTransferFrom( - forwarderAddress, - parentAddress, - tokenId, - forwarderBalance, - '' - ); - } - - /** - * @inheritdoc IForwarder - */ - function batchFlushERC1155Tokens( - address tokenContractAddress, - uint256[] calldata tokenIds - ) external virtual override onlyWhitelistedAddress { - IERC1155 instance = IERC1155(tokenContractAddress); - require( - instance.supportsInterface(type(IERC1155).interfaceId), - 'The caller does not support the IERC1155 interface' - ); - - address forwarderAddress = address(this); - uint256[] memory amounts = new uint256[](tokenIds.length); - for (uint256 i = 0; i < tokenIds.length; i++) { - amounts[i] = instance.balanceOf(forwarderAddress, tokenIds[i]); - } - - instance.safeBatchTransferFrom( - forwarderAddress, - parentAddress, - tokenIds, - amounts, - '' - ); - } - - /** - * Flush the entire balance of the contract to the parent address. - */ - function flush() public { - uint256 value = address(this).balance; - - if (value == 0) { - return; - } - - (bool success, ) = parentAddress.call{ value: value }(''); - require(success, 'Flush failed'); - emit ForwarderDeposited(msg.sender, value, msg.data); - } - - /** - * @inheritdoc IERC165 - */ - function supportsInterface(bytes4 interfaceId) - public - virtual - override(ERC1155Receiver, IERC165) - view - returns (bool) - { - return - interfaceId == type(IForwarder).interfaceId || - super.supportsInterface(interfaceId); - } -} \ No newline at end of file diff --git a/contracts/NewForwarderFactory.sol b/contracts/NewForwarderFactory.sol deleted file mode 100644 index b81a076..0000000 --- a/contracts/NewForwarderFactory.sol +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.15; -import './NewForwarder.sol'; -import './CloneFactory.sol'; - -contract ForwarderFactory1 is CloneFactory { - address public implementationAddress; - - event ForwarderCreated( - address newForwarderAddress, - address parentAddress, - address feeAddress, - bool shouldAutoFlushERC721, - bool shouldAutoFlushERC1155 - ); - - constructor(address _implementationAddress) { - implementationAddress = _implementationAddress; - } - - function createForwarder(address parent, address feeAddress, bytes32 salt) external { - this.createForwarder(parent, feeAddress, salt, true, true); - } - - function createForwarder( - address parent, - address feeAddress, - bytes32 salt, - bool shouldAutoFlushERC721, - bool shouldAutoFlushERC1155 - ) external { - // include the signers in the salt so any contract deployed to a given address must have the same signers - bytes32 finalSalt = keccak256(abi.encodePacked(parent, salt)); - - address payable clone = createClone(implementationAddress, finalSalt); - Forwarder(clone).init( - parent, - feeAddress, - shouldAutoFlushERC721, - shouldAutoFlushERC1155 - ); - emit ForwarderCreated( - clone, - parent, - feeAddress, - shouldAutoFlushERC721, - shouldAutoFlushERC1155 - ); - } -} diff --git a/contracts/TransferHelper.sol b/contracts/TransferHelper.sol index e4e2961..d83159e 100644 --- a/contracts/TransferHelper.sol +++ b/contracts/TransferHelper.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later // source: https://github.com/Uniswap/solidity-lib/blob/master/contracts/libraries/TransferHelper.sol -pragma solidity 0.8.15; +pragma solidity 0.8.10; import '@openzeppelin/contracts/utils/Address.sol';