Skip to content

Instantly share code, notes, and snippets.

@koeppelmann
Created April 4, 2024 09:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save koeppelmann/2cbbd386bb1b862b7c1585907c313448 to your computer and use it in GitHub Desktop.
Save koeppelmann/2cbbd386bb1b862b7c1585907c313448 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.8.25+commit.b61c2a91.js&optimize=false&runs=200&gist=
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC20 {
function transfer(address recipient, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function balanceOf(address account) external view returns (uint256);
}
contract DelayTokenWrapper {
IERC20 public immutable wrappedToken;
string public constant symbol = "WTOKEN";
uint8 public constant decimals = 18;
mapping(address => uint256) private balances;
mapping(address => uint256) public dailyLimits;
struct NewLimit {
uint256 amount;
uint256 effectiveTimestamp;
}
mapping(address => NewLimit) private newDailyLimits;
mapping(address => uint256) private lastWithdrawalDay;
mapping(address => uint256) private withdrawnToday;
struct WithdrawalRequest {
uint256 amount;
uint256 timestamp;
}
mapping(address => WithdrawalRequest) private withdrawalRequests;
address public operator;
uint256 public constant delay = 2 minutes;
event Deposit(address indexed user, uint256 amount);
event WithdrawalRequested(address indexed user, uint256 amount);
event Withdraw(address indexed user, uint256 amount);
event WithdrawalCancelled(address indexed user);
event OperatorWithdraw(address indexed operator, address indexed user, uint256 amount);
constructor(address _tokenAddress) {
operator = msg.sender; // The deployer is the initial operator
wrappedToken = IERC20(_tokenAddress);
}
modifier onlyOperator() {
require(msg.sender == operator, "Caller is not the operator");
_;
}
function deposit(uint256 amount) external {
require(wrappedToken.transferFrom(msg.sender, address(this), amount), "Transfer failed");
balances[msg.sender] += amount;
emit Deposit(msg.sender, amount);
// Emit an event indicating the transfer of wrapped tokens from the zero address to the user
emit Transfer(address(0), msg.sender, amount);
}
function requestWithdrawal(uint256 amount) external {
require(balances[msg.sender] >= amount, "Insufficient balance.");
withdrawalRequests[msg.sender] = WithdrawalRequest({
amount: amount,
timestamp: block.timestamp
});
emit WithdrawalRequested(msg.sender, amount);
}
function completeWithdrawal() external {
WithdrawalRequest storage request = withdrawalRequests[msg.sender];
require(request.amount > 0, "No withdrawal requested.");
require(block.timestamp >= request.timestamp + delay, "Withdrawal request is still pending.");
if(balances[msg.sender] < request.amount) {
emit WithdrawalCancelled(msg.sender);
delete withdrawalRequests[msg.sender];
return;
}
balances[msg.sender] -= request.amount;
require(wrappedToken.transfer(msg.sender, request.amount), "Transfer failed");
emit Withdraw(msg.sender, request.amount);
// Reset the withdrawal request
delete withdrawalRequests[msg.sender];
}
function setDailyLimit(uint256 limit) external {
if (limit < dailyLimits[msg.sender]) {
newDailyLimits[msg.sender] = NewLimit({
amount: limit,
effectiveTimestamp: block.timestamp + delay
});
} else {
dailyLimits[msg.sender] = limit;
newDailyLimits[msg.sender] = NewLimit({amount: 0, effectiveTimestamp: 0});
}
}
function operatorWithdraw(address user, uint256 amount) external onlyOperator {
require(balances[user] >= amount, "Insufficient balance.");
// Check and apply new daily limit if applicable
if (newDailyLimits[user].amount != 0 && block.timestamp >= newDailyLimits[user].effectiveTimestamp) {
dailyLimits[user] = newDailyLimits[user].amount;
newDailyLimits[user] = NewLimit({amount: 0, effectiveTimestamp: 0}); // Reset the new limit
}
uint256 currentDay = block.timestamp / 1 days;
if(currentDay > lastWithdrawalDay[user]) {
withdrawnToday[user] = 0; // Reset daily withdrawn amount for the new day
lastWithdrawalDay[user] = currentDay;
}
require(withdrawnToday[user] + amount <= dailyLimits[user], "Withdrawal amount exceeds daily limit.");
withdrawnToday[user] += amount;
balances[user] -= amount;
require(wrappedToken.transfer(operator, amount), "Failed to transfer tokens to operator.");
emit OperatorWithdraw(operator, user, amount);
}
function getBalance(address user) external view returns (uint256) {
return balances[user];
}
// The ERC20 Transfer event for compliance
event Transfer(address indexed from, address indexed to, uint256 value);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment