Created
September 15, 2023 17:21
-
-
Save WPSmartContracts/a0714805c19fe633168fc258b5d7acf8 to your computer and use it in GitHub Desktop.
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
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.2; | |
import "./Dependencies.sol"; | |
/** | |
* @title CoconutVault | |
* @dev A smart contract for securely storing and managing native coins, ERC-20 tokens, | |
* ERC-721 NFTs, and ERC-1155 NFTs. It includes functionalities for deposits, | |
* withdrawals, and trusted account management in case of emergencies. | |
*/ | |
contract CoconutVault is Ownable, ReentrancyGuard { | |
using SafeERC20 for IERC20; | |
// Timestamp of the last owner activity | |
uint256 public lastActivity; | |
// Expiration time in seconds since the last owner activity | |
uint256 public expirationLapse; | |
// Mapping of trusted accounts that can withdraw the vault assets in case of expiration | |
mapping(address => bool) public trustedAccounts; | |
// Event last owner activity log | |
event LastActivityUpdate(uint256 timestamp); | |
// Events for asset deposits | |
event CoinsReceived(address indexed sender, uint256 value); | |
event ERC20Received(address indexed sender, address indexed token, uint256 amount); | |
event ERC721Received(address indexed sender, address indexed nft, uint256 id); | |
event ERC1155Received(address indexed sender, address indexed nft, uint256 id, uint256 qty); | |
// Events for asset withdrawals | |
event CoinsWithdrawn(address indexed beneficiary, uint256 value); | |
event ERC20Withdrawn(address indexed beneficiary, address indexed token, uint256 amount); | |
event ERC721Withdrawn(address indexed beneficiary, address indexed nft, uint256 indexed id); | |
event ERC1155Withdrawn(address indexed beneficiary, address indexed nft, uint256 indexed id, uint256 qty); | |
event TrustedAccountChanged(address indexed trustedAccount, bool trusted); | |
/** | |
* @dev Constructor for CoconutVault. | |
* @param owner_ The address of the owner of the contract. | |
*/ | |
constructor (address owner_) Ownable() { | |
lastActivity = block.timestamp; | |
// The default expiration lapse is one year (in seconds) | |
expirationLapse = 31536000; | |
transferOwnership(owner_); | |
} | |
// Owner methods: | |
/** | |
* @dev Owner method to manually set the expiration time. | |
* @param lapse The new expiration time in seconds. | |
*/ | |
function setExpiration(uint256 lapse) external onlyOwner { | |
require(lapse > 0, "Expiration time has to be positive"); | |
_updateActivity(); | |
expirationLapse = lapse; | |
} | |
/** | |
* @dev Owner method to manually update the last activity timestamp. | |
*/ | |
function keepAlive() external onlyOwner { | |
_updateActivity(); | |
} | |
// Deposit functions: | |
/** | |
* @dev Allows anyone to deposit native coins into the vault. | |
* Update the last activity in the contract if the sender is the owner | |
*/ | |
function deposit() public payable nonReentrant { | |
emit CoinsReceived(msg.sender, msg.value); | |
_updateActivity(); | |
} | |
/** | |
* @dev Fallback function to handle transfers of Ether. | |
* Update the last activity in the contract if the sender is the owner | |
*/ | |
receive() external payable { | |
deposit(); | |
} | |
/** | |
* @dev Allows users to deposit ERC-20 tokens into the vault. | |
* @param token_ The ERC-20 token contract address. | |
* @param amount_ The amount of tokens to deposit. | |
* Update the last activity in the contract if the sender is the owner | |
* Token transfer directly to the contract can be done, but the last activity will not be updated if such transfers are made by the owner | |
*/ | |
function tokenDeposit(IERC20 token_, uint256 amount_) external nonReentrant { | |
require(amount_ > 0, "Transfer amount has to be positive"); | |
_updateActivity(); | |
emit ERC20Received(msg.sender, address(token_), amount_); | |
token_.safeTransferFrom(msg.sender, address(this), amount_); | |
} | |
/** | |
* @dev Allows users to deposit NFT ERC-721 tokens into the vault. | |
* @param token_ The ERC-721 token contract address. | |
* @param id_ The NFT ID to deposit. | |
* Update the last activity in the contract if the sender is the owner | |
* Token transfer directly to the contract can be done, but the last activity will not be updated if such transfers are made by the owner | |
*/ | |
function erc721Deposit(IERC721 token_, uint256 id_) external nonReentrant { | |
require(id_ > 0, "NFT ID has to be positive"); | |
_updateActivity(); | |
emit ERC721Received(msg.sender, address(token_), id_); | |
token_.safeTransferFrom(msg.sender, address(this), id_); | |
} | |
/** | |
* @dev Allows users to deposit NFT ERC-1155 tokens into the vault. | |
* @param token_ The ERC-1155 token contract address. | |
* @param id_ The NFT ID to deposit. | |
* @param qty_ The number of NFT items to deposit. | |
* Update the last activity in the contract if the sender is the owner | |
* Token transfer directly to the contract can be done, but the last activity will not be updated if such transfers are made by the owner | |
*/ | |
function erc1155Deposit(IERC1155 token_, uint256 id_, uint256 qty_) external nonReentrant { | |
require(id_ > 0, "NFT ID has to be positive"); | |
require(qty_ > 0, "Quatity has to be positive"); | |
_updateActivity(); | |
emit ERC1155Received(msg.sender, address(token_), id_, qty_); | |
token_.safeTransferFrom(msg.sender, address(this), id_, qty_, '0x'); | |
} | |
// Withdraw fundtions: | |
/** | |
* @dev Allows the owner or a trusted account after expiration to withdraw native coins. | |
* @param value_ The amount of native coins to withdraw. | |
* Update the last activity in the contract if the sender is the owner | |
*/ | |
function withdraw(uint256 value_) external nonReentrant canWithdraw { | |
require(value_ > 0, "Transfer value has to be positive"); | |
_updateActivity(); | |
emit CoinsWithdrawn(msg.sender, value_); | |
(bool success, ) = msg.sender.call{value:value_}(""); | |
require(success, "Transfer failed."); | |
} | |
/** | |
* @dev Allows the owner or a trusted account after expiration to withdraw ERC-20 tokens | |
* @param token_ The ERC-20 token to withdraw. | |
* @param amount_ The amount of tokens to withdraw. | |
* Update the last activity in the contract if the sender is the owner | |
*/ | |
function tokenWithdraw(IERC20 token_, uint256 amount_) external nonReentrant canWithdraw { | |
require(amount_ > 0, "Transfer amount has to be positive"); | |
_updateActivity(); | |
emit ERC20Withdrawn(msg.sender, address(token_), amount_); | |
token_.safeTransfer(msg.sender, amount_); | |
} | |
/** | |
* @dev Allows the owner or a trusted account after expiration to withdraw ERC-721 tokens | |
* @param token_ The ERC-721 token to withdraw. | |
* @param id_ The NFT ID of tokens to withdraw. | |
* Update the last activity in the contract if the sender is the owner | |
*/ | |
function erc721Withdraw(IERC721 token_, uint256 id_) external nonReentrant canWithdraw { | |
require(id_ > 0, "NFT ID has to be positive"); | |
_updateActivity(); | |
emit ERC721Withdrawn(msg.sender, address(token_), id_); | |
token_.safeTransferFrom(address(this), msg.sender, id_); | |
} | |
/** | |
* @dev Allows the owner or a trusted account after expiration to withdraw ERC-1155 tokens | |
* @param token_ The ERC-1155 token to withdraw. | |
* @param id_ The NFT ID of tokens to withdraw. | |
* @param qty_ The number of NFT Items to withdraw. | |
* Update the last activity in the contract if the sender is the owner | |
*/ | |
function erc1155Withdraw(IERC1155 token_, uint256 id_, uint256 qty_) external nonReentrant canWithdraw { | |
require(id_ > 0, "NFT ID has to be positive"); | |
require(qty_ > 0, "Quatity has to be positive"); | |
_updateActivity(); | |
emit ERC1155Withdrawn(msg.sender, address(token_), id_, qty_); | |
token_.safeTransferFrom(address(this), msg.sender, id_, qty_, "0x"); | |
} | |
// Manage trusted accounts: | |
/** | |
* @dev Add or update a trusted account to withdraw Coins, ERC-20, ERC-721 or ERC-1155 in case of emergency | |
* @param account_ The address of the beneficiary. | |
* @param trusted_ is the account trusted or not | |
*/ | |
function changeTrustedAccount(address account_, bool trusted_) external onlyOwner { | |
require(account_ != address(0), "Trusted account cannot be the zero address"); | |
_updateActivity(); | |
emit TrustedAccountChanged(account_, trusted_); | |
trustedAccounts[account_] = trusted_; | |
} | |
/** | |
* @dev Internal function to update the last activity timestamp. | |
*/ | |
function _updateActivity() internal { | |
if (msg.sender == this.owner()) { | |
lastActivity = block.timestamp; | |
emit LastActivityUpdate(block.timestamp); | |
} | |
} | |
/** | |
* @dev Modifier to check if caller is owner or a trusted account and the contract has expired | |
*/ | |
modifier canWithdraw() { | |
require(msg.sender == this.owner() || (trustedAccounts[msg.sender] && block.timestamp - lastActivity > expirationLapse), "Caller cannot withdraw"); | |
_; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment