Description:
ERC20 token contract with Factory capabilities. Standard implementation for fungible tokens on Ethereum.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"ERC20TimelockEitherBeneficiary_3min.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
library SafeERC20 {
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
(bool success, bytes memory returndata) = address(token).call(data);
require(success, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 op failed");
}
}
}
/**
* @title ERC20TimelockEitherBeneficiary
* @notice Locks ERC20 tokens for 3 minutes from deployment. After release time,
* EITHER beneficiaryA or beneficiaryB can withdraw ALL tokens to themselves.
* Anyone can deposit via the owner-controlled fund() function (requires allowance).
*/
contract ERC20TimelockEitherBeneficiary {
using SafeERC20 for IERC20;
IERC20 public immutable token;
address public immutable owner;
address public immutable beneficiaryA;
address public immutable beneficiaryB;
uint64 public immutable releaseTime; // deploy + 3 minutes
event Funded(address indexed from, uint256 amount);
event Released(address indexed to, uint256 amount);
error NotOwner();
error NotBeneficiary();
error NotYetReleased();
error ZeroAmount();
constructor(IERC20 _token, address _beneficiaryA, address _beneficiaryB) {
require(address(_token) != address(0), "token=0");
require(_beneficiaryA != address(0), "beneficiaryA=0");
require(_beneficiaryB != address(0), "beneficiaryB=0");
require(_beneficiaryA != _beneficiaryB, "beneficiaries must differ");
token = _token;
owner = msg.sender;
beneficiaryA = _beneficiaryA;
beneficiaryB = _beneficiaryB;
releaseTime = uint64(block.timestamp + 3 minutes); // 部署后3分钟解锁
}
// Owner funds the contract with amount of tokens. Requires prior approve(owner -> this, amount).
function fund(uint256 amount) external {
if (msg.sender != owner) revert NotOwner();
if (amount == 0) revert ZeroAmount();
token.safeTransferFrom(msg.sender, address(this), amount);
emit Funded(msg.sender, amount);
}
function balance() public view returns (uint256) {
return token.balanceOf(address(this));
}
// Either beneficiary can withdraw ALL tokens to themselves once time passes.
function release() external {
if (block.timestamp < releaseTime) revert NotYetReleased();
if (msg.sender != beneficiaryA && msg.sender != beneficiaryB) revert NotBeneficiary();
uint256 amt = token.balanceOf(address(this));
require(amt > 0, "nothing to release");
token.safeTransfer(msg.sender, amt);
emit Released(msg.sender, amt);
}
// (Optional convenience) Anyone can trigger a view to see time left.
function timeLeft() external view returns (uint256) {
if (block.timestamp >= releaseTime) return 0;
return uint256(releaseTime) - block.timestamp;
}
}
"
}
},
"settings": {
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"remappings": []
}
}}
Submitted on: 2025-11-05 11:44:21
Comments
Log in to comment.
No comments yet.