Transaction Hash:
Block:
20493187 at Aug-09-2024 07:39:11 PM +UTC
Transaction Fee:
0.000222704675066775 ETH
$0.57
Gas Used:
72,105 Gas / 3.088616255 Gwei
Emitted Events:
183 |
HARAMBEToken.Transfer( from=[Receiver] Claiming, to=[Sender] 0xc1b6562ba5c6447b7239fea3e546d61b072c18c3, tokens=60000000000000000000 )
|
184 |
Claiming.Claimed( user=[Sender] 0xc1b6562ba5c6447b7239fea3e546d61b072c18c3, beneficiary=[Sender] 0xc1b6562ba5c6447b7239fea3e546d61b072c18c3, amount=60000000000000000000, time=1723232351 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x4838B106...B0BAD5f97
Miner
| (Titan Builder) | 10.919843143123713789 Eth | 10.919915248123713789 Eth | 0.000072105 | |
0x541F2DdB...04A7a67aB | |||||
0x54845810...1f71DB3C2 | |||||
0xc1b6562b...B072C18C3 |
0.004898823713959502 Eth
Nonce: 3
|
0.004676119038892727 Eth
Nonce: 4
| 0.000222704675066775 |
Execution Trace
claim[Claiming (ln:230)]
getClaimableAmount[Claiming (ln:237)]
getClaimaVestingAmount[Claiming (ln:300)]
safeTransfer[Claiming (ln:240)]
Claimed[Claiming (ln:241)]
File 1 of 2: Claiming
File 2 of 2: HARAMBEToken
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.20; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "./interfaces/IStaking.sol"; contract Claiming is Ownable { using SafeERC20 for IERC20; // presale token IERC20 public token; // staking contract address public staking; // liquidity mining contract address public liquidityMining; // claiming start time uint256 public claimStart; // maximum array length for set batch claim info uint256 public MAX_BATCH_SET_CLAIM = 1_000; // vesting percent uint256 public VESTING_PER_MONTH = 2_500; uint256 public DENOMINATOR = 10_000; struct ClaimInfo { address user; // address of presale buyer uint256 amount; // initial claimable amount of user uint256 claimed; // claimed amount of user (by only claiming) uint256 remain; // remaining amount } // claim info array ClaimInfo[] private claimInfos; // claim info index mapping(address => uint256) private claimInfoIndex; /* ========== EVENTS ========== */ // Event emitted when owner deposits token event Deposited(address indexed user, uint256 amount, uint256 time); // Event emitted when owner withdraws token event Withdrawed(address indexed user, uint256 amount, uint256 time); // Event emiited when owner updates the staking contract address event StakingContractAddressUpdated(address indexed user, address staking, uint256 time); // Event emiited when owner updates the liquidityMining contract address event LiquidityMiningContractAddressUpdated(address indexed user, address liquidityMining, uint256 time); // Event emitted when owner updates the time to start claiming event ClaimStartTimeUpdated(address indexed user, uint256 claimStartTime); // Event emitted when owner updates the time to start claiming event ClaimInfoUpdated(address indexed user, uint256 previousAmount, uint256 amount, uint256 time); // Event emitted when a user claimed his token event Claimed(address indexed user, address indexed beneficiary, uint256 amount, uint256 time); // Event emitted whan a user stake directly without event Staked(address indexed user, uint256 amount, uint256 time); // Event emitted when token is transferred to liquidityMining for adding liquidity event TokenTransferedToLiquidityMining(address indexed user, uint256 amount, uint256 time); modifier whenClaimStarted() { // verify the claiming was started require(claimStart != 0 && block.timestamp >= claimStart, "Claiming is not able now."); // execute the rest of the function _; } modifier onlyOwnerOrLiquidityMiningContract() { if( ( liquidityMining == address(0) || liquidityMining != _msgSender() ) && (owner() != _msgSender()) ) { revert("Invalid permission to call this function"); } _; } constructor(address _token) Ownable(msg.sender) { // verify input argument require(_token != address(0), "Token address cannot be zero."); token = IERC20(_token); // add empty element into claim info array for comfortable index claimInfos.push(ClaimInfo({ user: address(0), amount: 0, remain: 0, claimed: 0 })); } /****************************************************** Setter ******************************************************/ /** * @notice Set the address of staking contract * * @param _staking The address of the staking contract */ function setStakingContract(address _staking) external onlyOwner { // verify input argument require(address(_staking) != address(0), "Staking contract cannot be zero address."); staking = _staking; emit StakingContractAddressUpdated(msg.sender, staking, block.timestamp); } /** * @notice Set the address of liquidity mining contract * * @param _liquidityMining The address of the staking contract */ function setLiquidityMiningContract(address _liquidityMining) external onlyOwner { // verify input argument require(address(_liquidityMining) != address(0), "Liquidity mining contract cannot be zero address."); liquidityMining = _liquidityMining; emit LiquidityMiningContractAddressUpdated(msg.sender, liquidityMining, block.timestamp); } /** * @notice Set the time to start claiming * * @param _claimStart The time to start claiming */ function setClaimStart(uint256 _claimStart) external onlyOwnerOrLiquidityMiningContract { // verify input argument require(_claimStart >= block.timestamp, "Invalid time for start claiming."); claimStart = _claimStart; emit ClaimStartTimeUpdated(msg.sender, _claimStart); } /** * @notice Set the detail of entry that can claim token * * @dev allow claim 0 amount * * @param user address of the user * @param amount amount of the claim */ function setClaim(address user, uint256 amount) external onlyOwnerOrLiquidityMiningContract { // verify input argument require(user != address(0), "User address cannot be zero."); uint256 previousAmount; uint256 index = claimInfoIndex[user]; if (index > 0) { // update previous claim data ClaimInfo storage claimInfo = claimInfos[index]; previousAmount = claimInfo.amount; claimInfo.amount = amount; claimInfo.claimed = 0; claimInfo.remain = amount; } else { // push new user's claim info previousAmount = 0; claimInfoIndex[user] = claimInfos.length; claimInfos.push(ClaimInfo({ user: user, amount: amount, claimed: 0, remain: amount })); } emit ClaimInfoUpdated(user, previousAmount, amount, block.timestamp); } /** * @notice Set the batch of entry that can claim token * * @param users array of users' address * @param amounts array of users' claimable token amount */ function setClaimBatch(address[] calldata users, uint256[] calldata amounts) external onlyOwner { // verify input argment arrays' length require(users.length != 0, "Invalid input array's length."); require(users.length <= MAX_BATCH_SET_CLAIM, "Invalid input array's length."); require(users.length == amounts.length, "The length of arrays for users and amounts should be same."); for(uint256 i = 0; i < users.length; ) { address user = users[i]; // verify user's address is valid require(user != address(0), "User address cannot be zero."); uint256 amount = amounts[i]; uint256 previousAmount; uint256 index = claimInfoIndex[user]; if (index > 0) { // update previous claim data ClaimInfo storage claimInfo = claimInfos[index]; previousAmount = claimInfo.amount; claimInfo.amount = amount; claimInfo.claimed = 0; claimInfo.remain = amount; } else { // push new user's claim info previousAmount = 0; claimInfoIndex[user] = claimInfos.length; claimInfos.push(ClaimInfo({ user: user, amount: amount, claimed: 0, remain: amount })); } unchecked { ++i; } emit ClaimInfoUpdated(user, previousAmount, amount, block.timestamp); } } /***************************************************** external *****************************************************/ /** * @notice Deposit token so that user can claim their token from this contract * * @dev only owner can call this function * * @param amount the amount to be deposited */ function deposit(uint256 amount) external onlyOwner { // verify input argument require(amount > 0, "Cannot deposit zero amount"); token.safeTransferFrom(msg.sender, address(this), amount); emit Deposited(msg.sender, amount, block.timestamp); } /** * @notice Withdraw deposited token back * * @dev only owner can call this function * * @param amount the amount to be withdrawn */ function withdraw(uint256 amount) external onlyOwner { // verify input argument require(amount > 0, "Cannot withdraw zero amount"); token.safeTransfer(owner(), amount); emit Withdrawed(owner(), amount, block.timestamp); } /** * @notice User claims their purchased token to the particular address * * @dev users can claim only after claim is started * * @param beneficiary the address that will receives claimed token * @param amount the amount to be claimed */ function claim(address beneficiary, uint256 amount) external whenClaimStarted { // verify input argument require(amount != 0, "Cannot claim zero amount"); require(beneficiary != address(0), "Cannot claim to zero address"); // verify claimable amount uint256 index = claimInfoIndex[msg.sender]; ClaimInfo storage claimInfo = claimInfos[index]; require(amount <= getClaimableAmount(msg.sender), "Insufficient claimable amount"); claimInfo.remain -= amount; claimInfo.claimed += amount; token.safeTransfer(beneficiary, amount); emit Claimed(msg.sender, beneficiary, amount, block.timestamp); } /** * @notice User can stake their claimable token to the staking contract directly * * @dev users can stake their token even when staking is disabled through this function * * @param amount the amount to be staken * @param durationInMonths the duration to be staken in months */ function stake(uint256 amount, uint256 durationInMonths) external { // verify input argument require(amount != 0, "Cannot claim zero amount"); // verify staking contract address is valid require(staking != address(0), "Invalid staking address"); // verify claimable amount uint256 index = claimInfoIndex[msg.sender]; ClaimInfo storage claimInfo = claimInfos[index]; require(amount <= claimInfo.remain, "Insufficient claimable amount"); claimInfo.remain -= amount; bool success = token.approve(staking, amount); require(success, "Approve failed"); IStaking(staking).stakeFromClaiming(msg.sender, amount, durationInMonths); emit Staked(msg.sender, amount, block.timestamp); } /** * @notice transfer sale tokens to liquidity mining contract for adding liquidity * * @dev callable only from liquidity minig contract itself * * @param amount token amount to be transferred */ function transferTokenToLiquidityMining(uint256 amount) external { // verify input argument require(amount != 0, "Cannot transfer zero amount"); // verify liquidity mining contract require(liquidityMining != address(0) && liquidityMining == msg.sender, "Only liquidity mining contract can call this function"); token.safeTransfer(liquidityMining, amount); emit TokenTransferedToLiquidityMining(msg.sender, amount, block.timestamp); } /***************************************************** Getter *****************************************************/ /** * @notice Get the total deposited amount of token by the owner */ function getTotalDeposits() public view returns(uint256) { return token.balanceOf(address(this)); } /** * @notice Get the claimable amount of particular user * * @param user the address of user to need to get the claimable amount */ function getClaimableAmount(address user) public view returns(uint256 amount) { uint256 index = claimInfoIndex[user]; ClaimInfo memory claimInfo = claimInfos[index]; uint256 vestingAmount = getClaimaVestingAmount(user); amount = vestingAmount > claimInfo.remain ? claimInfo.remain : vestingAmount; } /** * @notice Get the claimable vesting amount of particular user * * @param user the address of user to need to get the detail */ function getClaimaVestingAmount(address user) public view returns(uint256) { uint256 index = claimInfoIndex[user]; ClaimInfo memory claimInfo = claimInfos[index]; // return zero value if claiming is unable if (claimStart == 0 || block.timestamp < claimStart) return 0; uint256 monthIndex = (block.timestamp - claimStart) / 30 days + 1; monthIndex = monthIndex <= 4 ? monthIndex : 4; uint256 vestingAvailable = claimInfo.amount * monthIndex * VESTING_PER_MONTH / DENOMINATOR; if (vestingAvailable <= claimInfo.claimed) return 0; return vestingAvailable - claimInfo.claimed; } /** * @notice get the actual claims array length * * @dev avoid first empty element of the array */ function getClaimInfoLength() public view returns(uint256) { return claimInfos.length - 1; } /** * @notice get the index in claim info array of particular user * * @param user address to get the index of claim info */ function getClaimInfoIndex(address user) public view returns(uint256) { return claimInfoIndex[user]; } /** * @notice get the claim info of particular user address * * @param user address of user to get the info */ function getClaimInfo(address user) public view returns(uint256 amount, uint256 claimed, uint256 remain) { uint256 index = claimInfoIndex[user]; amount = claimInfos[index].amount; claimed = claimInfos[index].claimed; remain = claimInfos[index].remain; } /** * @notice get the claim info at the particular index * * @dev avoid first empty element of the array * * @param index index to get the claim info */ function getClaimInfoAtIndex(uint256 index) public view returns(address user, uint256 amount, uint256 claimed, uint256 remain) { require(index != 0, "Invalid start index"); // should avoid first empty element require(index < claimInfos.length, "Invalid index value"); return ( claimInfos[index].user, claimInfos[index].amount, claimInfos[index].claimed, claimInfos[index].remain ); } /** * @notice get the array of claim info between particular indexes * * @dev avoid first empty element of the array * * @param fromIndex start index; should be greater than 0 (to avoid first empty element) * @param toIndex end index */ function getClaimInfoArray(uint256 fromIndex, uint256 toIndex) public view returns(ClaimInfo[] memory) { uint256 length = claimInfos.length; require(fromIndex > 0, "Invalid start index"); // should avoid first empty element require(fromIndex <= toIndex, "Invalid indexes."); require(toIndex < length, "Index cannot be over the length of staking"); ClaimInfo[] memory returnClaimInfo = new ClaimInfo[](toIndex - fromIndex + 1); for (uint256 i = fromIndex; i <= toIndex; ) { returnClaimInfo[i - fromIndex] = claimInfos[i]; unchecked { ++i; } } return returnClaimInfo; } }// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 standard as defined in the ERC. */ 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); } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC1363} from "../../../interfaces/IERC1363.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC-20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev An operation with an ERC-20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { safeTransfer(token, to, value); } else if (!token.transferAndCall(to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * Reverts if the returned value is other than `true`. */ function transferFromAndCallRelaxed( IERC1363 token, address from, address to, uint256 value, bytes memory data ) internal { if (to.code.length == 0) { safeTransferFrom(token, from, to, value); } else if (!token.transferFromAndCall(from, to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when * targeting contracts. * * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}. * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall} * once without retrying, and relies on the returned value to be true. * * Reverts if the returned value is other than `true`. */ function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal { if (to.code.length == 0) { forceApprove(token, to, value); } else if (!token.approveAndCall(to, value, data)) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data); if (returndata.length != 0 && !abi.decode(returndata, (bool))) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0; } } pragma solidity ^0.8.20; interface IStaking { function stakeFromClaiming(address, uint256, uint256) external; } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1363.sol) pragma solidity ^0.8.20; import {IERC20} from "./IERC20.sol"; import {IERC165} from "./IERC165.sol"; /** * @title IERC1363 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363]. * * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction. */ interface IERC1363 is IERC20, IERC165 { /* * Note: the ERC-165 identifier for this interface is 0xb0202a11. * 0xb0202a11 === * bytes4(keccak256('transferAndCall(address,uint256)')) ^ * bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^ * bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^ * bytes4(keccak256('approveAndCall(address,uint256)')) ^ * bytes4(keccak256('approveAndCall(address,uint256,bytes)')) */ /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from the caller's account to `to` * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism * and then calls {IERC1363Receiver-onTransferReceived} on `to`. * @param from The address which you want to send tokens from. * @param to The address which you want to transfer to. * @param value The amount of tokens to be transferred. * @param data Additional data with no specified format, sent in call to `to`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value) external returns (bool); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`. * @param spender The address which will spend the funds. * @param value The amount of tokens to be spent. * @param data Additional data with no specified format, sent in call to `spender`. * @return A boolean value indicating whether the operation succeeded unless throwing. */ function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool); } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; import {Errors} from "./Errors.sol"; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert Errors.InsufficientBalance(address(this).balance, amount); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert Errors.FailedCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {Errors.FailedCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert Errors.InsufficientBalance(address(this).balance, value); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case * of an unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {Errors.FailedCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert Errors.FailedCall(); } } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../token/ERC20/IERC20.sol"; // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol"; // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /** * @dev Collection of common custom errors used in multiple contracts * * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library. * It is recommended to avoid relying on the error API for critical functionality. */ library Errors { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error InsufficientBalance(uint256 balance, uint256 needed); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedCall(); /** * @dev The deployment failed. */ error FailedDeployment(); } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
File 2 of 2: HARAMBEToken
pragma solidity ^0.8.10; contract SafeMath { function safeAdd(uint a, uint b) internal pure returns (uint) { uint c = a + b; require(c >= a, "Addition overflow"); return c; } function safeSub(uint a, uint b) internal pure returns (uint) { require(b <= a, "Subtraction underflow"); uint c = a - b; return c; } function safeMul(uint a, uint b) internal pure returns (uint) { if (a == 0) return 0; uint c = a * b; require(c / a == b, "Multiplication overflow"); return c; } function safeDiv(uint a, uint b) internal pure returns (uint) { require(b > 0, "Division by zero"); uint c = a / b; return c; } } //ERC Token Standard #20 Interface interface ERC20Interface { function totalSupply() external view returns (uint); function balanceOf(address tokenOwner) external view returns (uint balance); function allowance(address tokenOwner, address spender) external view returns (uint remaining); function transfer(address to, uint tokens) external returns (bool success); function approve(address spender, uint tokens) external returns (bool success); function transferFrom(address from, address to, uint tokens) external returns (bool success); event Transfer(address indexed from, address indexed to, uint tokens); event Approval(address indexed tokenOwner, address indexed spender, uint tokens); } //Contract function to receive approval and execute function in one call interface ApproveAndCallFallBack { function receiveApproval(address from, uint256 tokens, address token, bytes calldata data) external; } //Actual token contract contract HARAMBEToken is ERC20Interface, SafeMath { string public symbol; string public name; uint8 public decimals; uint public _totalSupply; mapping(address => uint) balances; mapping(address => mapping(address => uint)) allowed; constructor() public { symbol = "HARAMBEAI"; name = "Harambe AI Token"; decimals = 18; _totalSupply = 690000000000000000000000000; balances[0x06D344b9ada316c83C30110Ca6029d49961eC907] = _totalSupply; emit Transfer(address(0), 0x06D344b9ada316c83C30110Ca6029d49961eC907, _totalSupply); } function totalSupply() public view returns (uint) { return _totalSupply - balances[address(0)]; } function balanceOf(address tokenOwner) public view returns (uint balance) { return balances[tokenOwner]; } function transfer(address to, uint tokens) public returns (bool success) { balances[msg.sender] = safeSub(balances[msg.sender], tokens); balances[to] = safeAdd(balances[to], tokens); emit Transfer(msg.sender, to, tokens); return true; } function approve(address spender, uint tokens) public returns (bool success) { allowed[msg.sender][spender] = tokens; emit Approval(msg.sender, spender, tokens); return true; } function transferFrom(address from, address to, uint tokens) public returns (bool success) { balances[from] = safeSub(balances[from], tokens); allowed[from][msg.sender] = safeSub(allowed[from][msg.sender], tokens); balances[to] = safeAdd(balances[to], tokens); emit Transfer(from, to, tokens); return true; } function allowance(address tokenOwner, address spender) public view returns (uint remaining) { return allowed[tokenOwner][spender]; } function approveAndCall(address spender, uint tokens, bytes calldata data) public returns (bool success) { allowed[msg.sender][spender] = tokens; emit Approval(msg.sender, spender, tokens); ApproveAndCallFallBack(spender).receiveApproval(msg.sender, tokens, address(this), data); return true; } fallback () external { revert(); } receive() external payable { // React to receiving ether; currently, your fallback just reverts, so: revert("ETH not accepted"); } }