Last active
September 25, 2023 19:54
-
-
Save WPSmartContracts/9f6c26b918acfde0bf86a5a31f42079a 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; | |
// Standard OpenZeppelin Contracts | |
import "../utils/Context.sol"; | |
import "../access/Ownable.sol"; | |
import "../security/ReentrancyGuard.sol"; | |
import "../token/ERC20/IERC20.sol"; | |
import "../token/ERC721/IERC721.sol"; | |
import "../token/ERC1155/IERC1155.sol"; | |
import "../utils/Address.sol"; | |
import "../token/ERC20/utils/SafeERC20.sol"; | |
import "../token/ERC721/utils/ERC721Holder.sol"; | |
import "../token/ERC1155/utils/ERC1155Holder.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 ERC721Holder, ERC1155Holder, 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 for recording the last owner activity timestamp | |
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 for changing trusted accounts | |
event TrustedAccountChanged(address indexed trustedAccount, bool trusted); | |
/** | |
* @dev Constructor for CoconutVault. | |
* @param expirationTime_ Default expiration lapse in seconds | |
* @param owner_ The address of the owner of the contract. | |
*/ | |
constructor (uint256 expirationTime_, address owner_) Ownable() { | |
require(expirationTime_ > 0, "Expiration time must be positive"); | |
lastActivity = block.timestamp; | |
expirationLapse = expirationTime_; | |
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) public onlyOwner { | |
require(lapse > 0, "Expiration time must 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. | |
* Updates the last activity in the contract if the sender is the owner. | |
*/ | |
function deposit() public payable nonReentrant { | |
require(msg.value > 0, "Transfer value must be positive"); | |
emit CoinsReceived(msg.sender, msg.value); | |
_updateActivity(); | |
} | |
/** | |
* @dev Fallback function to handle transfers of Ether. | |
* Updates 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. | |
* Updates the last activity in the contract if the sender is the owner. | |
* Token transfers 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 must 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. | |
* Updates the last activity in the contract if the sender is the owner. | |
* Token transfers 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 must 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. | |
* Updates the last activity in the contract if the sender is the owner. | |
* Token transfers 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 must be positive"); | |
require(qty_ > 0, "Quantity must be positive"); | |
_updateActivity(); | |
emit ERC1155Received(msg.sender, address(token_), id_, qty_); | |
token_.safeTransferFrom(msg.sender, address(this), id_, qty_, '0x'); | |
} | |
// Withdraw functions: | |
/** | |
* @dev Allows the owner or a trusted account after expiration to withdraw native coins. | |
* @param value_ The amount of native coins to withdraw. | |
* Updates the last activity in the contract if the sender is the owner. | |
*/ | |
function withdraw(uint256 value_) external nonReentrant canWithdraw { | |
require(value_ > 0, "Transfer value must 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. | |
* Updates 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 must 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. | |
* Updates 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 must 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. | |
* Updates 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 must be positive"); | |
require(qty_ > 0, "Quantity must 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_ Whether the account is 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 == owner()) { | |
lastActivity = block.timestamp; | |
emit LastActivityUpdate(block.timestamp); | |
} | |
} | |
/** | |
* @dev Modifier to check if the caller is the owner or a trusted account and the contract has expired. | |
*/ | |
modifier canWithdraw() { | |
require(msg.sender == 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