Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/more util contracts #10

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .solhint.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
"extends": "solhint:recommended",
"plugins": [],
"rules": {
"compiler-version": [ "error", "^0.8.0" ],
"compiler-version": ["error", ">=0.6.0 <0.9.0"],
"avoid-suicide": "error",
"avoid-sha3": "warn",
"func-visibility": ["warn",{"ignoreConstructors":true}]
"func-visibility": ["warn", { "ignoreConstructors": true }]
}
}
}
34 changes: 34 additions & 0 deletions contracts/interfaces/IContractWhitelist.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

/*
______ ______
/ \ / \
| ▓▓▓▓▓▓\ ______ ______ | ▓▓▓▓▓▓\__ __ __ ______ ______
| ▓▓__| ▓▓/ \ / \| ▓▓___\▓▓ \ | \ | \| \ / \
| ▓▓ ▓▓ ▓▓▓▓▓▓\ ▓▓▓▓▓▓\\▓▓ \| ▓▓ | ▓▓ | ▓▓ \▓▓▓▓▓▓\ ▓▓▓▓▓▓\
| ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ ▓▓ ▓▓_\▓▓▓▓▓▓\ ▓▓ | ▓▓ | ▓▓/ ▓▓ ▓▓ | ▓▓
| ▓▓ | ▓▓ ▓▓__/ ▓▓ ▓▓▓▓▓▓▓▓ \__| ▓▓ ▓▓_/ ▓▓_/ ▓▓ ▓▓▓▓▓▓▓ ▓▓__/ ▓▓
| ▓▓ | ▓▓ ▓▓ ▓▓\▓▓ \\▓▓ ▓▓\▓▓ ▓▓ ▓▓\▓▓ ▓▓ ▓▓ ▓▓
\▓▓ \▓▓ ▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓\▓▓▓▓ \▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓
| ▓▓ | ▓▓
| ▓▓ | ▓▓
\▓▓ \▓▓
* App: https://ApeSwap.finance
* Medium: https://ape-swap.medium.com
* Twitter: https://twitter.com/ape_swap
* Telegram: https://t.me/ape_swap
* Announcements: https://t.me/ape_swap_news
* Discord: https://discord.com/ApeSwap
* Reddit: https://reddit.com/r/ApeSwap
* Instagram: https://instagram.com/ApeSwap.finance
* GitHub: https://github.com/ApeSwapFinance
*/

interface IContractWhitelist {
function toggleWhitelist() external;

function setContractWhitelist(address _address, bool _enabled) external;

function setBatchContractWhitelist(address[] memory _addresses, bool[] memory _enabled) external;
}
2 changes: 1 addition & 1 deletion contracts/mocks/SweeperMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pragma solidity ^0.8.0;
* GitHub: https://github.com/ApeSwapFinance
*/

import "../utils/Sweeper.sol";
import "../utils/v0.8/Sweeper.sol";

contract SweeperMock is Sweeper {
address[] empty;
Expand Down
2 changes: 1 addition & 1 deletion contracts/mocks/SweeperUpgradeableMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pragma solidity ^0.8.0;
* GitHub: https://github.com/ApeSwapFinance
*/

import "../utils/SweeperUpgradeable.sol";
import "../utils/v0.8/SweeperUpgradeable.sol";

contract SweeperUpgradeableMock is SweeperUpgradeable {
constructor() {}
Expand Down
83 changes: 83 additions & 0 deletions contracts/utils/ContractWhitelist.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

/*
______ ______
/ \ / \
| ▓▓▓▓▓▓\ ______ ______ | ▓▓▓▓▓▓\__ __ __ ______ ______
| ▓▓__| ▓▓/ \ / \| ▓▓___\▓▓ \ | \ | \| \ / \
| ▓▓ ▓▓ ▓▓▓▓▓▓\ ▓▓▓▓▓▓\\▓▓ \| ▓▓ | ▓▓ | ▓▓ \▓▓▓▓▓▓\ ▓▓▓▓▓▓\
| ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ ▓▓ ▓▓_\▓▓▓▓▓▓\ ▓▓ | ▓▓ | ▓▓/ ▓▓ ▓▓ | ▓▓
| ▓▓ | ▓▓ ▓▓__/ ▓▓ ▓▓▓▓▓▓▓▓ \__| ▓▓ ▓▓_/ ▓▓_/ ▓▓ ▓▓▓▓▓▓▓ ▓▓__/ ▓▓
| ▓▓ | ▓▓ ▓▓ ▓▓\▓▓ \\▓▓ ▓▓\▓▓ ▓▓ ▓▓\▓▓ ▓▓ ▓▓ ▓▓
\▓▓ \▓▓ ▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓\▓▓▓▓ \▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓
| ▓▓ | ▓▓
| ▓▓ | ▓▓
\▓▓ \▓▓
* App: https://ApeSwap.finance
* Medium: https://ape-swap.medium.com
* Twitter: https://twitter.com/ape_swap
* Telegram: https://t.me/ape_swap
* Announcements: https://t.me/ape_swap_news
* Discord: https://discord.com/ApeSwap
* Reddit: https://reddit.com/r/ApeSwap
* Instagram: https://instagram.com/ApeSwap.finance
* GitHub: https://github.com/ApeSwapFinance
*/

import "@openzeppelin/contracts/access/Ownable.sol";
import "../interfaces/IContractWhitelist.sol";

abstract contract ContractWhitelist is IContractWhitelist, Ownable {
/// @notice marks if a contract whitelist is enabled.
bool public whitelistEnabled;
/// @notice mapping of whitelisted contracts.
mapping(address => bool) public whitelist;

event UpdateWhitelistStatus(bool whitelistEnabled);
event UpdateContractWhitelist(address indexed whitelistAddress, bool whitelistEnabled);

/// @dev checks if whitelist is enabled and if contract is whitelisted
modifier checkEOAorWhitelist() {
// If whitelist is enabled and sender is not EOA
if (whitelistEnabled && msg.sender != tx.origin) {
require(whitelist[msg.sender], "checkWhitelist: not in whitelist");
}
_;
}

/// @notice enables smart contract whitelist
function toggleWhitelist() external override onlyOwner {
whitelistEnabled = !whitelistEnabled;
emit UpdateWhitelistStatus(whitelistEnabled);
}

/// @notice Enable or disable a contract address on the whitelist
/// @param _address Address to update on whitelist
/// @param _enabled Set if the whitelist is enabled or disabled
function setContractWhitelist(address _address, bool _enabled) external override onlyOwner {
_setContractWhitelist(_address, _enabled);
}

/// @notice Enable or disable contract addresses on the whitelist
/// @param _addresses Addressed to update on whitelist
/// @param _enabled Set if the whitelist is enabled or disabled for each address passed
function setBatchContractWhitelist(address[] memory _addresses, bool[] memory _enabled)
external
override
onlyOwner
{
require(_addresses.length == _enabled.length, "array mismatch");
for (uint256 i = 0; i < _addresses.length; i++) {
_setContractWhitelist(_addresses[i], _enabled[i]);
}
}

/// @notice Enable or disable a contract address on the whitelist
/// @param _address Address to update on whitelist
/// @param _enabled Set if the whitelist is enabled or disabled
function _setContractWhitelist(address _address, bool _enabled) private {
whitelist[_address] = _enabled;
emit UpdateContractWhitelist(_address, _enabled);
}
}
47 changes: 47 additions & 0 deletions contracts/utils/PendingOwnable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";

contract PendingOwnable is Ownable {
address private _pendingOwner;

event SetPendingOwner(address indexed pendingOwner);

constructor() Ownable() {}

/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}

/**
* @dev This function is disabled to in place of setPendingOwner()
*/
function transferOwnership(
address /*newOwner*/
) public view override onlyOwner {
revert("PendingOwnable: MUST setPendingOwner()");
}

/**
* @dev Sets an account as the pending owner (`newPendingOwner`).
* Can only be called by the current owner.
*/
function setPendingOwner(address newPendingOwner) public virtual onlyOwner {
_pendingOwner = newPendingOwner;
emit SetPendingOwner(_pendingOwner);
}

/**
* @dev Transfers ownership to the pending owner
* Can only be called by the pending owner.
*/
function acceptOwnership() public virtual {
require(msg.sender == _pendingOwner, "PendingOwnable: MUST be pendingOwner");
_pendingOwner = address(0);
_transferOwnership(msg.sender);
}
}
139 changes: 139 additions & 0 deletions contracts/utils/v0.6/Sweeper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;

/*
______ ______
/ \ / \
| ▓▓▓▓▓▓\ ______ ______ | ▓▓▓▓▓▓\__ __ __ ______ ______
| ▓▓__| ▓▓/ \ / \| ▓▓___\▓▓ \ | \ | \| \ / \
| ▓▓ ▓▓ ▓▓▓▓▓▓\ ▓▓▓▓▓▓\\▓▓ \| ▓▓ | ▓▓ | ▓▓ \▓▓▓▓▓▓\ ▓▓▓▓▓▓\
| ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ ▓▓ ▓▓_\▓▓▓▓▓▓\ ▓▓ | ▓▓ | ▓▓/ ▓▓ ▓▓ | ▓▓
| ▓▓ | ▓▓ ▓▓__/ ▓▓ ▓▓▓▓▓▓▓▓ \__| ▓▓ ▓▓_/ ▓▓_/ ▓▓ ▓▓▓▓▓▓▓ ▓▓__/ ▓▓
| ▓▓ | ▓▓ ▓▓ ▓▓\▓▓ \\▓▓ ▓▓\▓▓ ▓▓ ▓▓\▓▓ ▓▓ ▓▓ ▓▓
\▓▓ \▓▓ ▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓\▓▓▓▓ \▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓
| ▓▓ | ▓▓
| ▓▓ | ▓▓
\▓▓ \▓▓
* App: https://ApeSwap.finance
* Medium: https://ape-swap.medium.com
* Twitter: https://twitter.com/ape_swap
* Telegram: https://t.me/ape_swap
* Announcements: https://t.me/ape_swap_news
* Discord: https://discord.com/ApeSwap
* Reddit: https://reddit.com/r/ApeSwap
* Instagram: https://instagram.com/ApeSwap.finance
* GitHub: https://github.com/ApeSwapFinance
*/

import "@openzeppelin/contracts-v0.7/access/Ownable.sol";
import "@openzeppelin/contracts-v0.7/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts-v0.7/token/ERC721/IERC721.sol";

/**
* @dev Sweep any ERC20 token.
* Sometimes people accidentally send tokens to a contract without any way to retrieve them.
* This contract makes sure any erc20 tokens can be removed from the contract.
*/
contract Sweeper is Ownable {
struct NFT {
IERC721 nftaddress;
uint256[] ids;
}
mapping(address => bool) public lockedTokens;
bool public allowNativeSweep;

event SweepWithdrawToken(address indexed receiver, IERC20 indexed token, uint256 balance);

event SweepWithdrawNFTs(address indexed receiver, NFT[] indexed nfts);

event SweepWithdrawNative(address indexed receiver, uint256 balance);

constructor(address[] memory _lockedTokens, bool _allowNativeSweep) public {
lockTokens(_lockedTokens);
allowNativeSweep = _allowNativeSweep;
}

/**
* @dev Transfers erc20 tokens to owner
* Only owner of contract can call this function
*/
function sweepTokens(IERC20[] memory tokens, address to) external onlyOwner {
NFT[] memory empty;
sweepTokensAndNFTs(tokens, empty, to);
}

/**
* @dev Transfers NFT to owner
* Only owner of contract can call this function
*/
function sweepNFTs(NFT[] memory nfts, address to) external onlyOwner {
IERC20[] memory empty;
sweepTokensAndNFTs(empty, nfts, to);
}

/**
* @dev Transfers ERC20 and NFT to owner
* Only owner of contract can call this function
*/
function sweepTokensAndNFTs(
IERC20[] memory tokens,
NFT[] memory nfts,
address to
) public onlyOwner {
for (uint256 i = 0; i < tokens.length; i++) {
IERC20 token = tokens[i];
require(!lockedTokens[address(token)], "Tokens can't be sweeped");
uint256 balance = token.balanceOf(address(this));
token.transfer(to, balance);
emit SweepWithdrawToken(to, token, balance);
}

for (uint256 i = 0; i < nfts.length; i++) {
IERC721 nftaddress = nfts[i].nftaddress;
require(!lockedTokens[address(nftaddress)], "Tokens can't be sweeped");
uint256[] memory ids = nfts[i].ids;
for (uint256 j = 0; j < ids.length; j++) {
nftaddress.safeTransferFrom(address(this), to, ids[j]);
}
}
emit SweepWithdrawNFTs(to, nfts);
}

/// @notice Sweep native coin
/// @param _to address the native coins should be transferred to
function sweepNative(address payable _to) external onlyOwner {
require(allowNativeSweep, "Not allowed");
uint256 balance = address(this).balance;
// solhint-disable-next-line avoid-low-level-calls
(bool success, ) = _to.call{value: balance}("");
require(success, "Failed to transfer native");
emit SweepWithdrawNative(_to, balance);
}

/**
* @dev Refuse native sweep.
* Once refused can't be allowed again
*/
function refuseNativeSweep() public onlyOwner {
allowNativeSweep = false;
}

/**
* @dev Lock single token so they can't be transferred from the contract.
* Once locked it can't be unlocked
*/
function lockToken(address token) public onlyOwner {
lockedTokens[token] = true;
}

/**
* @dev Lock multiple tokens so they can't be transferred from the contract.
* Once locked it can't be unlocked
*/
function lockTokens(address[] memory tokens) public onlyOwner {
for (uint256 i = 0; i < tokens.length; i++) {
lockToken(tokens[i]);
}
}
}
Loading