- Contract name:
- DecentLocker
- Optimization enabled
- true
- Compiler version
- v0.8.24+commit.e11b9ed9
- Optimization runs
- 200
- EVM Version
- london
- Verified at
- 2024-09-16T11:12:19.954106Z
Constructor Arguments
000000000000000000000000e785e1f0f48ee8ac4553f39618e230d8cff45ba3
Arg [0] (address) : 0xe785e1f0f48ee8ac4553f39618e230d8cff45ba3
Contract source code
// SPDX-License-Identifier: MIT // File: @openzeppelin/contracts/token/ERC20/IERC20.sol // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.24; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); } // File: @openzeppelin/contracts/utils/math/SafeMath.sol // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol) pragma solidity ^0.8.0; // CAUTION // This version of SafeMath should only be used with Solidity 0.8 or later, // because it relies on the compiler's built in overflow checks. /** * @dev Wrappers over Solidity's arithmetic operations. * * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler * now has built in overflow checking. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { return a + b; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { return a * b; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b <= a, errorMessage); return a - b; } } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a / b; } } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a % b; } } } // File: @openzeppelin/contracts/security/ReentrancyGuard.sol // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } } // File: DecentLocker.sol pragma solidity ^0.8.24; contract DecentLocker is ReentrancyGuard { using SafeMath for uint256; struct LockInfo { address tokenAddress; uint256 amount; uint256 unlockTime; } address public feeRecipient; // Wallet to receive the fees uint256 public feePercentage = 1; // 1% fee mapping(address => LockInfo[]) public lockedTokens; event TokensLocked(address indexed user, address tokenAddress, uint256 amount, uint256 unlockTime); event TokensWithdrawn(address indexed user, address tokenAddress, uint256 amount); event FeePaid(address indexed user, address tokenAddress, uint256 feeAmount); constructor(address _feeRecipient) { require(_feeRecipient != address(0), "Invalid fee recipient address"); feeRecipient = _feeRecipient; } function lockTokens(address tokenAddress, uint256 amount, uint256 timeInSeconds) external nonReentrant { require(amount > 0, "Amount must be greater than 0"); require(timeInSeconds > 0, "Time must be greater than 0"); require(IERC20(tokenAddress).balanceOf(msg.sender) >= amount, "Insufficient token balance"); require(IERC20(tokenAddress).allowance(msg.sender, address(this)) >= amount, "Allowance not set for token"); // Calculate the fee and amount after fee uint256 fee = amount.mul(feePercentage).div(100); uint256 amountAfterFee = amount.sub(fee); // Transfer the fee to the feeRecipient bool feeTransferSuccess = IERC20(tokenAddress).transferFrom(msg.sender, feeRecipient, fee); require(feeTransferSuccess, "Fee transfer failed"); // Transfer the remaining amount to the contract bool success = IERC20(tokenAddress).transferFrom(msg.sender, address(this), amountAfterFee); require(success, "Token transfer failed"); uint256 unlockTime = block.timestamp.add(timeInSeconds); lockedTokens[msg.sender].push(LockInfo(tokenAddress, amountAfterFee, unlockTime)); emit TokensLocked(msg.sender, tokenAddress, amountAfterFee, unlockTime); emit FeePaid(msg.sender, tokenAddress, fee); } function withdrawTokens(uint256 index) external nonReentrant { require(index < lockedTokens[msg.sender].length, "Invalid index"); LockInfo memory lockInfo = lockedTokens[msg.sender][index]; require(block.timestamp >= lockInfo.unlockTime, "Tokens are still locked"); _removeLockedToken(msg.sender, index); bool success = IERC20(lockInfo.tokenAddress).transfer(msg.sender, lockInfo.amount); require(success, "Token transfer failed"); emit TokensWithdrawn(msg.sender, lockInfo.tokenAddress, lockInfo.amount); } function _removeLockedToken(address user, uint256 index) internal { require(index < lockedTokens[user].length, "Invalid index"); lockedTokens[user][index] = lockedTokens[user][lockedTokens[user].length - 1]; lockedTokens[user].pop(); } function getLockCount(address user) external view returns (uint256) { return lockedTokens[user].length; } function getLockInfo(address user, uint256 index) external view returns (address tokenAddress, uint256 amount, uint256 unlockTime) { require(index < lockedTokens[user].length, "Invalid index"); LockInfo memory lockInfo = lockedTokens[user][index]; return (lockInfo.tokenAddress, lockInfo.amount, lockInfo.unlockTime); } }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_feeRecipient","internalType":"address"}]},{"type":"event","name":"FeePaid","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"address","name":"tokenAddress","internalType":"address","indexed":false},{"type":"uint256","name":"feeAmount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"TokensLocked","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"address","name":"tokenAddress","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"unlockTime","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"TokensWithdrawn","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"address","name":"tokenAddress","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"feePercentage","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"feeRecipient","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getLockCount","inputs":[{"type":"address","name":"user","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"unlockTime","internalType":"uint256"}],"name":"getLockInfo","inputs":[{"type":"address","name":"user","internalType":"address"},{"type":"uint256","name":"index","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"lockTokens","inputs":[{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"timeInSeconds","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"unlockTime","internalType":"uint256"}],"name":"lockedTokens","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawTokens","inputs":[{"type":"uint256","name":"index","internalType":"uint256"}]}]
Deployed ByteCode
0x608060405234801561001057600080fd5b506004361061007d5760003560e01c8063469048401161005b578063469048401461010b57806353719b6e14610136578063a001ecdd14610149578063a25983e51461015257600080fd5b806315b9672c1461008257806323c1ee43146100bf578063315a095d146100f6575b600080fd5b610095610090366004610bc4565b610165565b604080516001600160a01b0390941684526020840192909252908201526060015b60405180910390f35b6100e86100cd366004610bee565b6001600160a01b031660009081526003602052604090205490565b6040519081526020016100b6565b610109610104366004610c09565b610224565b005b60015461011e906001600160a01b031681565b6040516001600160a01b0390911681526020016100b6565b610095610144366004610bc4565b610433565b6100e860025481565b610109610160366004610c22565b61047f565b6001600160a01b0382166000908152600360205260408120548190819084106101a95760405162461bcd60e51b81526004016101a090610c55565b60405180910390fd5b6001600160a01b03851660009081526003602052604081208054869081106101d3576101d3610c7c565b60009182526020918290206040805160608101825260039390930290910180546001600160a01b03168084526001820154948401859052600290910154929091018290529891975095509350505050565b61022c6109d2565b33600090815260036020526040902054811061025a5760405162461bcd60e51b81526004016101a090610c55565b33600090815260036020526040812080548390811061027b5761027b610c7c565b600091825260209182902060408051606081018252600390930290910180546001600160a01b03168352600181015493830193909352600290920154918101829052915042101561030e5760405162461bcd60e51b815260206004820152601760248201527f546f6b656e7320617265207374696c6c206c6f636b656400000000000000000060448201526064016101a0565b6103183383610a2b565b8051602082015160405163a9059cbb60e01b815233600482015260248101919091526000916001600160a01b03169063a9059cbb906044016020604051808303816000875af115801561036f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103939190610c92565b9050806103da5760405162461bcd60e51b8152602060048201526015602482015274151bdad95b881d1c985b9cd9995c8819985a5b1959605a1b60448201526064016101a0565b8151602080840151604080516001600160a01b0390941684529183015233917f6337ed398c0e8467698c581374fdce4db14922df487b5a39483079f5f59b60a4910160405180910390a250506104306001600055565b50565b6003602052816000526040600020818154811061044f57600080fd5b60009182526020909120600390910201805460018201546002909201546001600160a01b03909116935090915083565b6104876109d2565b600082116104d75760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e203000000060448201526064016101a0565b600081116105275760405162461bcd60e51b815260206004820152601b60248201527f54696d65206d7573742062652067726561746572207468616e2030000000000060448201526064016101a0565b6040516370a0823160e01b815233600482015282906001600160a01b038516906370a0823190602401602060405180830381865afa15801561056d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105919190610cbb565b10156105df5760405162461bcd60e51b815260206004820152601a60248201527f496e73756666696369656e7420746f6b656e2062616c616e636500000000000060448201526064016101a0565b604051636eb1769f60e11b815233600482015230602482015282906001600160a01b0385169063dd62ed3e90604401602060405180830381865afa15801561062b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061064f9190610cbb565b101561069d5760405162461bcd60e51b815260206004820152601b60248201527f416c6c6f77616e6365206e6f742073657420666f7220746f6b656e000000000060448201526064016101a0565b60006106bf60646106b960025486610b6f90919063ffffffff16565b90610b84565b905060006106cd8483610b90565b6001546040516323b872dd60e01b81523360048201526001600160a01b03918216602482015260448101859052919250600091908716906323b872dd906064016020604051808303816000875af115801561072c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107509190610c92565b9050806107955760405162461bcd60e51b8152602060048201526013602482015272119959481d1c985b9cd9995c8819985a5b1959606a1b60448201526064016101a0565b6040516323b872dd60e01b8152336004820152306024820152604481018390526000906001600160a01b038816906323b872dd906064016020604051808303816000875af11580156107eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061080f9190610c92565b9050806108565760405162461bcd60e51b8152602060048201526015602482015274151bdad95b881d1c985b9cd9995c8819985a5b1959605a1b60448201526064016101a0565b60006108624287610b9c565b905060036000336001600160a01b03166001600160a01b0316815260200190815260200160002060405180606001604052808a6001600160a01b0316815260200186815260200183815250908060018154018082558091505060019003906000526020600020906003020160009091909190915060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160010155604082015181600201555050336001600160a01b03167fc8b76441f0c994977de3f73de32b3573a68b94e5d786ffd899638438754c9de9898684604051610972939291906001600160a01b039390931683526020830191909152604082015260600190565b60405180910390a2604080516001600160a01b038a1681526020810187905233917fbf6afbaffb3b955bebbf43430bbf8eecb8d34ff86f293f592203ab5ed79c5268910160405180910390a250505050506109cd6001600055565b505050565b600260005403610a245760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016101a0565b6002600055565b6001600160a01b0382166000908152600360205260409020548110610a625760405162461bcd60e51b81526004016101a090610c55565b6001600160a01b03821660009081526003602052604090208054610a8890600190610cea565b81548110610a9857610a98610c7c565b906000526020600020906003020160036000846001600160a01b03166001600160a01b031681526020019081526020016000208281548110610adc57610adc610c7c565b600091825260208083208454600393840290910180546001600160a01b0319166001600160a01b0392831617815560018087015490820155600295860154950194909455928516825290915260409020805480610b3b57610b3b610cfd565b60008281526020812060036000199093019283020180546001600160a01b0319168155600181018290556002015590555050565b6000610b7b8284610d13565b90505b92915050565b6000610b7b8284610d2a565b6000610b7b8284610cea565b6000610b7b8284610d4c565b80356001600160a01b0381168114610bbf57600080fd5b919050565b60008060408385031215610bd757600080fd5b610be083610ba8565b946020939093013593505050565b600060208284031215610c0057600080fd5b610b7b82610ba8565b600060208284031215610c1b57600080fd5b5035919050565b600080600060608486031215610c3757600080fd5b610c4084610ba8565b95602085013595506040909401359392505050565b6020808252600d908201526c092dcecc2d8d2c840d2dcc8caf609b1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215610ca457600080fd5b81518015158114610cb457600080fd5b9392505050565b600060208284031215610ccd57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610b7e57610b7e610cd4565b634e487b7160e01b600052603160045260246000fd5b8082028115828204841417610b7e57610b7e610cd4565b600082610d4757634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115610b7e57610b7e610cd456fea2646970667358221220d397fb3daff05b16bf247adedd81387196dfde617712b1d4ebe76195d143e27564736f6c63430008180033