Transaction Hash:
Block:
20810386 at Sep-23-2024 02:45:35 AM +UTC
Transaction Fee:
0.001244417652643938 ETH
$2.82
Gas Used:
112,566 Gas / 11.055004643 Gwei
Emitted Events:
190 |
NodeStaking.RewardPaid( user=[Sender] 0x2ff2b2b034a7e31f5f325271d54d72bb2ff74ed7, reward=559906316948603 )
|
191 |
NODEAI.Transfer( from=[Receiver] NodeStaking, to=[Sender] 0x2ff2b2b034a7e31f5f325271d54d72bb2ff74ed7, value=200000000000000000000 )
|
192 |
NodeStaking.Unstaked( user=[Sender] 0x2ff2b2b034a7e31f5f325271d54d72bb2ff74ed7, amount=200000000000000000000, index=0 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x1258D60B...FCFb7e870 | |||||
0x2Ff2b2B0...b2Ff74ED7 |
0.064467725274860746 Eth
Nonce: 82
|
0.063783213939165411 Eth
Nonce: 83
| 0.000684511335695335 | ||
0x4838B106...B0BAD5f97
Miner
| (Titan Builder) | 13.937128564360648373 Eth | 13.937340391059448373 Eth | 0.0002118266988 | |
0xF4dA8857...e2eeA6C85 | 26.745175952829077287 Eth | 26.744616046512128684 Eth | 0.000559906316948603 |
Execution Trace
unstake[NodeStaking (ln:389)]
_claimRewards[NodeStaking (ln:397)]
calculateReward[NodeStaking (ln:454)]
call[NodeStaking (ln:399)]
payable[NodeStaking (ln:399)]
RewardPaid[NodeStaking (ln:401)]
removeStake[NodeStaking (ln:406)]
transfer[NodeStaking (ln:408)]
Unstaked[NodeStaking (ln:410)]
File 1 of 2: NodeStaking
File 2 of 2: NODEAI
// 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.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) (utils/Pausable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { bool private _paused; /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); /** * @dev The operation failed because the contract is paused. */ error EnforcedPause(); /** * @dev The operation failed because the contract is not paused. */ error ExpectedPause(); /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { if (paused()) { revert EnforcedPause(); } } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { if (!paused()) { revert ExpectedPause(); } } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; /** * @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; /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); 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 if (_status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // 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; } } // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.24; import '@openzeppelin/contracts/utils/ReentrancyGuard.sol'; import '@openzeppelin/contracts/access/Ownable.sol'; import '@openzeppelin/contracts/utils/Pausable.sol'; 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); function approve(address spender, uint256 value) external returns (bool); } contract NodeStaking is ReentrancyGuard, Ownable, Pausable { IERC20 public stakingToken; struct Stake { uint256 amount; uint256 startTime; uint256 rewardPaid; } mapping(address => Stake[]) public stakes; mapping(address => uint256) public totalUserRewards; address[] public stakers; mapping(address => bool) public isStaker; uint256 public totalRewards = 0; uint256 public totalStaked; uint256 public earlyUnstakePenality = 30; uint256 public maxTotalStaked = 10_000_000 * (10 ** 18); // Example: 10 million tokens uint256 public maxPerWallet = 1_000 * (10 ** 18); // Example: 1,000 tokens per wallet uint256 public constant stakingPeriod = 30 days; address public constant deadWallet = 0x000000000000000000000000000000000000dEaD; event Staked(address indexed user, uint256 amount, uint256 index); event Unstaked(address indexed user, uint256 amount, uint256 index); event RewardPaid(address indexed user, uint256 reward); event Migrated( address indexed newStakingContract, uint256 tokenAmount, uint256 ethAmount ); /* Initializes the constructure with the staking token set and owner */ constructor(address _stakingToken) Ownable(_msgSender()) { stakingToken = IERC20(_stakingToken); } /* Sets the staking token */ function setStakingToken(address _stakingToken) external onlyOwner { require(_stakingToken != address(0), 'Invalid address'); stakingToken = IERC20(_stakingToken); } /* Sets the maximum total staked amount */ function setMaxTotalStaked(uint256 _maxTotalStaked) external onlyOwner { maxTotalStaked = _maxTotalStaked; } /* Sets the maximum staked amount per wallet */ function setMaxPerWallet(uint256 _maxPerWallet) external onlyOwner { maxPerWallet = _maxPerWallet; } /* Sets the pause state of the contract */ function setPaused(bool _paused) external onlyOwner { require(_paused != paused(), 'Already in the requested state'); if (_paused) { _pause(); } else { _unpause(); } } /* Migrates the staking contract to a new contract */ function migrate(address _newStakingContract) external onlyOwner { require(_newStakingContract != address(0), 'Invalid address'); uint256 contractTokenBalance = stakingToken.balanceOf(address(this)); require( stakingToken.transfer(_newStakingContract, contractTokenBalance), 'Failed to transfer tokens to owner' ); uint256 contractETHBalance = address(this).balance; (bool sent, ) = _newStakingContract.call{value: contractETHBalance}(''); require(sent, 'Failed to transfer ETH'); emit Migrated( _newStakingContract, contractTokenBalance, contractETHBalance ); } function stake(uint256 _amount) external nonReentrant whenNotPaused { require(_amount > 0, 'Amount must be greater than 0'); require(totalStaked + _amount <= maxTotalStaked, 'Staking limit exceeded'); uint256 walletStaked = getWalletStaked(msg.sender); require(walletStaked + _amount <= maxPerWallet, 'Staking limit exceeded'); if(!isStaker[msg.sender]) { stakers.push(msg.sender); isStaker[msg.sender] = true; } bool success = stakingToken.transferFrom(msg.sender, address(this), _amount); require(success, 'Failed to transfer tokens'); stakes[msg.sender].push(Stake(_amount, block.timestamp, 0)); totalStaked += _amount; emit Staked(msg.sender, _amount, stakes[msg.sender].length - 1); } function unstake(uint256 _index, uint256 _amount) external nonReentrant { require(_index < stakes[msg.sender].length, 'Invalid stake index'); Stake storage userStake = stakes[msg.sender][_index]; require( block.timestamp >= userStake.startTime + stakingPeriod, 'Stake is still locked' ); require(userStake.amount >= _amount, 'Insufficient staked amount'); uint256 reward = _claimRewards(msg.sender, _index); if(reward > 0) { (bool sent, ) = payable(msg.sender).call{value: reward}(''); require(sent, 'Failed to send Ether'); emit RewardPaid(msg.sender, reward); } userStake.amount -= _amount; totalStaked -= _amount; if (userStake.amount == 0) { removeStake(msg.sender, _index); } bool success = stakingToken.transfer(msg.sender, _amount); require(success, 'Failed to transfer tokens'); emit Unstaked(msg.sender, _amount, _index); } function earlyUnstake(uint256 _index, uint256 _amount) external nonReentrant { require(_index < stakes[msg.sender].length, 'Invalid stake index'); Stake storage userStake = stakes[msg.sender][_index]; require(userStake.amount >= _amount, 'Insufficient staked amount'); uint256 timeElapsed = block.timestamp - userStake.startTime; require( timeElapsed < stakingPeriod, 'Stake is not in early unstake period' ); uint256 reward = _claimRewards(msg.sender, _index); if(reward > 0) { (bool sent, ) = payable(msg.sender).call{value: reward}(''); require(sent, 'Failed to send Ether'); emit RewardPaid(msg.sender, reward); } // Calculate the penalty fee, which linearly decreases from 50% to 0% over the lock-up period uint256 penaltyPercentage = earlyUnstakePenality - ((timeElapsed * earlyUnstakePenality) / stakingPeriod); uint256 penaltyAmount = (_amount * penaltyPercentage) / 100; // Apply the penalty uint256 returnAmount = _amount - penaltyAmount; // Update the stake and total staked amount userStake.amount -= _amount; totalStaked -= _amount; // Burn the penalty amount bool successBurn = stakingToken.transfer(deadWallet, penaltyAmount); require(successBurn, 'Failed to burn tokens'); // Return the remaining tokens to the user bool sucessUnstake = stakingToken.transfer(msg.sender, returnAmount); require(sucessUnstake, 'Failed to transfer tokens'); // Remove the stake if it's fully unstaked if (userStake.amount == 0) { removeStake(msg.sender, _index); } emit Unstaked(msg.sender, returnAmount, _index); } function _claimRewards( address user, uint256 index ) private returns (uint256) { require(index < stakes[user].length, 'Invalid stake index'); Stake storage userStake = stakes[user][index]; uint256 reward = calculateReward(user, index); if (reward > 0) { userStake.rewardPaid += reward; totalUserRewards[user] += reward; totalRewards += reward; } return reward; } function claimRewards() external nonReentrant { uint256 stakeCount = stakes[msg.sender].length; require(stakeCount > 0, 'No stakes available'); uint256 totalReward = 0; for (uint256 i = 0; i < stakeCount; i++) { totalReward += _claimRewards(msg.sender, i); // Aggregate rewards } if(totalReward <= 0) { return; } (bool sent, ) = payable(msg.sender).call{value: totalReward}(''); require(sent, 'Failed to send Ether'); emit RewardPaid(msg.sender, totalReward); } function getWalletStaked(address _user) public view returns (uint256) { uint256 walletStaked = 0; for (uint256 i = 0; i < stakes[_user].length; i++) { walletStaked += stakes[_user][i].amount; } return walletStaked; } function getWalletReward(address _user) public view returns (uint256) { uint256 walletReward = 0; for (uint256 i = 0; i < stakes[_user].length; i++) { walletReward += stakes[_user][i].rewardPaid; } return walletReward; } function getWalletStakes(address _user) public view returns (Stake[] memory) { return stakes[_user]; } function getWalletClaimableRewards( address _user ) public view returns (uint256 totalClaimable) { totalClaimable = 0; for (uint256 i = 0; i < stakes[_user].length; i++) { uint256 reward = calculateReward(_user, i); totalClaimable += reward; } } function calculateAllPendingRewards() public view returns (uint256 totalClaimable) { totalClaimable = 0; for (uint256 i = 0; i < stakers.length; i++) { address staker = stakers[i]; totalClaimable += getWalletClaimableRewards(staker); } } function calculateReward( address _user, uint256 _index ) public view returns (uint256) { Stake storage userStake = stakes[_user][_index]; uint256 stakeDuration = block.timestamp - userStake.startTime; if (stakeDuration > stakingPeriod) { stakeDuration = stakingPeriod; // Cap the stake duration to the lock-up period for reward calculation } // Scale the numerator before dividing uint256 scaledReward = (address(this).balance * userStake.amount * stakeDuration) / stakingPeriod; uint256 reward = scaledReward / totalStaked; if(userStake.rewardPaid > reward) { return 0; } return reward - userStake.rewardPaid; // Assuming rewardPaid is correctly managed elsewhere } function getUserStakingDetails( address _user ) public view returns ( uint256 _totalStaked, uint256 totalRewardsInEth, uint256[] memory timeElapsedPerStake ) { _totalStaked = 0; totalRewardsInEth = 0; timeElapsedPerStake = new uint256[](stakes[_user].length); for (uint256 i = 0; i < stakes[_user].length; i++) { _totalStaked += stakes[_user][i].amount; totalRewardsInEth += calculateReward(_user, i); // This should return ETH rewards timeElapsedPerStake[i] = block.timestamp - stakes[_user][i].startTime; } } function removeStake(address _user, uint256 _index) private { require(_index < stakes[_user].length, 'Invalid stake index'); stakes[_user][_index] = stakes[_user][stakes[_user].length - 1]; stakes[_user].pop(); } receive() external payable {} }
File 2 of 2: NODEAI
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.19; /* /$$$$$$ /$$$$$$$ /$$ /$$ /$$__ $$| $$__ $$| $$ | $$ | $$ \__/| $$ \ $$| $$ | $$ | $$ /$$$$| $$$$$$$/| $$ | $$ | $$|_ $$| $$____/ | $$ | $$ | $$ \ $$| $$ | $$ | $$ | $$$$$$/| $$ | $$$$$$/ \______/ |__/ \______/ Website: https://nodeai.app Twitter: https://twitter.com/NodeAIETH Telegram: https://t.me/nodeaieth Rent or lend GPU power, and earn rewards with $GPU. We generate revenue by powering AI with GPUs. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } } interface IERC20 { function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer( address recipient, uint256 amount ) external returns (bool); function allowance( address owner, address spender ) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval( address indexed owner, address indexed spender, uint256 value ); } /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require( address(this).balance >= amount, "Address: insufficient balance" ); (bool success, ) = recipient.call{value: amount}(""); require( success, "Address: unable to send value, recipient may have reverted" ); } /** * @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, it is bubbled up by this * function (like regular Solidity function calls). * * 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. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data ) internal returns (bytes memory) { return functionCallWithValue( target, data, 0, "Address: low-level call failed" ); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @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`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue( target, data, value, "Address: low-level call with value failed" ); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require( address(this).balance >= value, "Address: insufficient balance for call" ); (bool success, bytes memory returndata) = target.call{value: value}( data ); return verifyCallResultFromTarget( target, success, returndata, errorMessage ); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data ) internal view returns (bytes memory) { return functionStaticCall( target, data, "Address: low-level static call failed" ); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget( target, success, returndata, errorMessage ); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data ) internal returns (bytes memory) { return functionDelegateCall( target, data, "Address: low-level delegate call failed" ); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget( target, success, returndata, errorMessage ); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert( bytes memory returndata, string memory errorMessage ) 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(errorMessage); } } } /** * @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. * * By default, the owner account will be the one that deploys the contract. 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; event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @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 { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing 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 { require( newOwner != address(0), "Ownable: new owner is the zero address" ); _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); } } interface IUniswapV2Factory { event PairCreated( address indexed token0, address indexed token1, address pair, uint256 ); function feeTo() external view returns (address); function feeToSetter() external view returns (address); function getPair( address tokenA, address tokenB ) external view returns (address pair); function allPairs(uint256) external view returns (address pair); function allPairsLength() external view returns (uint256); function createPair( address tokenA, address tokenB ) external returns (address pair); function setFeeTo(address) external; function setFeeToSetter(address) external; } interface IUniswapV2Pair { event Approval( address indexed owner, address indexed spender, uint256 value ); event Transfer(address indexed from, address indexed to, uint256 value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint256); function balanceOf(address owner) external view returns (uint256); function allowance( address owner, address spender ) external view returns (uint256); function approve(address spender, uint256 value) external returns (bool); function transfer(address to, uint256 value) external returns (bool); function transferFrom( address from, address to, uint256 value ) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint256); function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; event Burn( address indexed sender, uint256 amount0, uint256 amount1, address indexed to ); event Swap( address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint256); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function price0CumulativeLast() external view returns (uint256); function price1CumulativeLast() external view returns (uint256); function kLast() external view returns (uint256); function burn( address to ) external returns (uint256 amount0, uint256 amount1); function swap( uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data ) external; function skim(address to) external; function sync() external; function initialize(address, address) external; } interface IUniswapV2Router01 { function factory() external pure returns (address); function WETH() external pure returns (address); function addLiquidity( address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline ) external returns (uint256 amountA, uint256 amountB, uint256 liquidity); function addLiquidityETH( address token, uint256 amountTokenDesired, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external payable returns (uint256 amountToken, uint256 amountETH, uint256 liquidity); function removeLiquidity( address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline ) external returns (uint256 amountA, uint256 amountB); function removeLiquidityETH( address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external returns (uint256 amountToken, uint256 amountETH); function removeLiquidityWithPermit( address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint256 amountA, uint256 amountB); function removeLiquidityETHWithPermit( address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint256 amountToken, uint256 amountETH); function swapExactTokensForTokens( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapTokensForExactTokens( uint256 amountOut, uint256 amountInMax, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapExactETHForTokens( uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external payable returns (uint256[] memory amounts); function swapTokensForExactETH( uint256 amountOut, uint256 amountInMax, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapExactTokensForETH( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapETHForExactTokens( uint256 amountOut, address[] calldata path, address to, uint256 deadline ) external payable returns (uint256[] memory amounts); function quote( uint256 amountA, uint256 reserveA, uint256 reserveB ) external pure returns (uint256 amountB); function getAmountOut( uint256 amountIn, uint256 reserveIn, uint256 reserveOut ) external pure returns (uint256 amountOut); function getAmountIn( uint256 amountOut, uint256 reserveIn, uint256 reserveOut ) external pure returns (uint256 amountIn); function getAmountsOut( uint256 amountIn, address[] calldata path ) external view returns (uint256[] memory amounts); function getAmountsIn( uint256 amountOut, address[] calldata path ) external view returns (uint256[] memory amounts); } interface IUniswapV2Router02 is IUniswapV2Router01 { function removeLiquidityETHSupportingFeeOnTransferTokens( address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external returns (uint256 amountETH); function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint256 amountETH); function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external; function swapExactETHForTokensSupportingFeeOnTransferTokens( uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external payable; function swapExactTokensForETHSupportingFeeOnTransferTokens( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external; } contract NODEAI is Context, IERC20, Ownable { using Address for address; //Mapping section for better tracking. mapping(address => uint256) private _tOwned; mapping(address => mapping(address => uint256)) private _allowances; mapping(address => bool) private _isExcludedFromFee; //Loging and Event Information for better troubleshooting. event Log(string, uint256); event AuditLog(string, address); event RewardLiquidityProviders(uint256 tokenAmount); event SwapAndLiquifyEnabledUpdated(bool enabled); event SwapAndLiquify( uint256 tokensSwapped, uint256 ethReceived, uint256 tokensIntoLiqudity ); event SwapTokensForETH(uint256 amountIn, address[] path); //Supply Definition. uint256 private _tTotal = 100_000_000 ether; uint256 private _tFeeTotal; //Token Definition. string public constant name = "NodeAI"; string public constant symbol = "GPU"; uint8 public constant decimals = 18; //Definition of Wallets for Marketing or team. address payable public marketingWallet = payable(0xD335c5E36F1B19AECE98b78e9827a9DF76eE29E6); address payable public revenueWallet = payable(0xE4eEc0C7e825f988aEEe7d05BE579519532E94E5); //Dead Wallet for SAFU Contract address public constant deadWallet = 0x000000000000000000000000000000000000dEaD; //Taxes Definition. uint public buyFee = 4; uint256 public sellFee = 4; uint public revenueFee = 1; uint public marketingFee = 3; uint256 public marketingTokensCollected = 0; uint256 public totalMarketingTokensCollected = 0; uint256 public minimumTokensBeforeSwap = 10_000 ether; //Oracle Price Update, Manual Process. uint256 public swapOutput = 0; //Router and Pair Configuration. IUniswapV2Router02 public immutable uniswapV2Router; address public immutable uniswapV2Pair; address private immutable WETH; //Tracking of Automatic Swap vs Manual Swap. bool public inSwapAndLiquify; bool public swapAndLiquifyEnabled = true; modifier lockTheSwap() { inSwapAndLiquify = true; _; inSwapAndLiquify = false; } constructor() { _tOwned[_msgSender()] = _tTotal; address currentRouter; //Adding Variables for all the routers for easier deployment for our customers. if (block.chainid == 56) { currentRouter = 0x10ED43C718714eb63d5aA57B78B54704E256024E; // PCS Router } else if (block.chainid == 97) { currentRouter = 0xD99D1c33F9fC3444f8101754aBC46c52416550D1; // PCS Testnet } else if (block.chainid == 43114) { currentRouter = 0x60aE616a2155Ee3d9A68541Ba4544862310933d4; //Avax Mainnet } else if (block.chainid == 137) { currentRouter = 0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff; //Polygon Ropsten } else if (block.chainid == 6066) { currentRouter = 0x4169Db906fcBFB8b12DbD20d98850Aee05B7D889; //Tres Leches Chain } else if (block.chainid == 250) { currentRouter = 0xF491e7B69E4244ad4002BC14e878a34207E38c29; //SpookySwap FTM } else if (block.chainid == 42161) { currentRouter = 0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506; //Arbitrum Sushi } else if ( block.chainid == 1 || block.chainid == 4 || block.chainid == 5 ) { currentRouter = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D; //Mainnet } else { revert("You're not Blade"); } //End of Router Variables. //Create Pair in the contructor, this may fail on some blockchains and can be done in a separate line if needed. IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(currentRouter); WETH = _uniswapV2Router.WETH(); uniswapV2Pair = IUniswapV2Factory(_uniswapV2Router.factory()) .createPair(address(this), WETH); uniswapV2Router = _uniswapV2Router; _isExcludedFromFee[owner()] = true; _isExcludedFromFee[address(this)] = true; emit Transfer(address(0), _msgSender(), _tTotal); } //Readable Functions. function totalSupply() public view override returns (uint256) { return _tTotal; } function balanceOf(address account) public view override returns (uint256) { return _tOwned[account]; } //ERC 20 Standard Transfer Functions function transfer( address recipient, uint256 amount ) public override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } //ERC 20 Standard Allowance Function function allowance( address _owner, address spender ) public view override returns (uint256) { return _allowances[_owner][spender]; } //ERC 20 Standard Approve Function function approve( address spender, uint256 amount ) public override returns (bool) { _approve(_msgSender(), spender, amount); return true; } //ERC 20 Standard Transfer From function transferFrom( address sender, address recipient, uint256 amount ) public override returns (bool) { uint currentAllowance = _allowances[sender][_msgSender()]; require( currentAllowance >= amount, "ERC20: transfer amount exceeds allowance" ); _transfer(sender, recipient, amount); _approve(sender, _msgSender(), currentAllowance - amount); return true; } //ERC 20 Standard increase Allowance function increaseAllowance( address spender, uint256 addedValue ) public virtual returns (bool) { _approve( _msgSender(), spender, _allowances[_msgSender()][spender] + addedValue ); return true; } //ERC 20 Standard decrease Allowance function decreaseAllowance( address spender, uint256 subtractedValue ) public virtual returns (bool) { _approve( _msgSender(), spender, _allowances[_msgSender()][spender] - subtractedValue ); return true; } //Approve Function function _approve(address _owner, address spender, uint256 amount) private { require(_owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[_owner][spender] = amount; emit Approval(_owner, spender, amount); } //Transfer function, validate correct wallet structure, take fees, and other custom taxes are done during the transfer. function _transfer(address from, address to, uint256 amount) private { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); require(amount > 0, "Transfer amount must be greater than zero"); require( _tOwned[from] >= amount, "ERC20: transfer amount exceeds balance" ); //Adding logic for automatic swap. uint256 contractTokenBalance = balanceOf(address(this)); bool overMinimumTokenBalance = contractTokenBalance >= minimumTokensBeforeSwap; uint fee = 0; //if any account belongs to _isExcludedFromFee account then remove the fee if ( !inSwapAndLiquify && from != uniswapV2Pair && overMinimumTokenBalance && swapAndLiquifyEnabled ) { swapAndLiquify(); } if (to == uniswapV2Pair && !_isExcludedFromFee[from]) { fee = (sellFee * amount) / 100; } if (from == uniswapV2Pair && !_isExcludedFromFee[to]) { fee = (buyFee * amount) / 100; } amount -= fee; if (fee > 0) { _tokenTransfer(from, address(this), fee); marketingTokensCollected += fee; totalMarketingTokensCollected += fee; } _tokenTransfer(from, to, amount); } //Swap Tokens for BNB or to add liquidity either automatically or manual, by default this is set to manual. //Corrected newBalance bug, it sending bnb to wallet and any remaining is on contract and can be recoverred. function swapAndLiquify() public lockTheSwap { uint256 totalTokens = balanceOf(address(this)); swapTokensForEth(totalTokens); uint ethBalance = address(this).balance; uint totalFees = revenueFee + marketingFee; if (totalFees == 0) totalFees = 1; uint revenueAmount = (ethBalance * revenueFee) / totalFees; ethBalance -= revenueAmount; transferToAddressETH(revenueWallet, revenueAmount); transferToAddressETH(marketingWallet, ethBalance); marketingTokensCollected = 0; } //swap for eth is to support the converstion of tokens to weth during swapandliquify this is a supporting function function swapTokensForEth(uint256 tokenAmount) private { // generate the uniswap pair path of token -> weth address[] memory path = new address[](2); path[0] = address(this); path[1] = WETH; _approve(address(this), address(uniswapV2Router), tokenAmount); // make the swap uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens( tokenAmount, 0, // accept any amount of ETH path, address(this), // The contract block.timestamp ); emit SwapTokensForETH(tokenAmount, path); } //ERC 20 standard transfer, only added if taking fees to countup the amount of fees for better tracking and split purpose. function _tokenTransfer( address sender, address recipient, uint256 amount ) private { _tOwned[sender] -= amount; _tOwned[recipient] += amount; emit Transfer(sender, recipient, amount); } function isExcludedFromFee(address account) external view returns (bool) { return _isExcludedFromFee[account]; } //exclude wallets from fees, this is needed for launch or other contracts. function excludeFromFee(address account) external onlyOwner { _isExcludedFromFee[account] = true; emit AuditLog( "We have excluded the following walled in fees:", account ); } //include wallet back in fees. function includeInFee(address account) external onlyOwner { _isExcludedFromFee[account] = false; emit AuditLog( "We have including the following walled in fees:", account ); } //Automatic Swap Configuration. function setTokensToSwap( uint256 _minimumTokensBeforeSwap ) external onlyOwner { require( _minimumTokensBeforeSwap >= 100 ether, "You need to enter more than 100 tokens." ); minimumTokensBeforeSwap = _minimumTokensBeforeSwap; emit Log( "We have updated minimunTokensBeforeSwap to:", minimumTokensBeforeSwap ); } function setSwapAndLiquifyEnabled(bool _enabled) external onlyOwner { require(swapAndLiquifyEnabled != _enabled, "Value already set"); swapAndLiquifyEnabled = _enabled; emit SwapAndLiquifyEnabledUpdated(_enabled); } //set a new marketing wallet. function setMarketingWallet(address _marketingWallet) external onlyOwner { require(_marketingWallet != address(0), "setMarketingWallet: ZERO"); marketingWallet = payable(_marketingWallet); emit AuditLog("We have Updated the MarketingWallet:", marketingWallet); } //set a new team wallet. function setRevenueWallet(address _revenueWallet) external onlyOwner { require(_revenueWallet != address(0), "setRevenueWallet: ZERO"); revenueWallet = payable(_revenueWallet); emit AuditLog("We have Updated the RarketingWallet:", revenueWallet); } function transferToAddressETH( address payable recipient, uint256 amount ) private { if (amount == 0) return; (bool succ, ) = recipient.call{value: amount}(""); require(succ, "Transfer failed."); } //to recieve ETH from uniswapV2Router when swaping receive() external payable {} /////---fallback--//// //This cannot be removed as is a fallback to the swapAndLiquify event SwapETHForTokens(uint256 amountIn, address[] path); function swapETHForTokens(uint256 amount) private { // generate the uniswap pair path of token -> weth address[] memory path = new address[](2); path[0] = WETH; path[1] = address(this); // make the swap uniswapV2Router.swapExactETHForTokensSupportingFeeOnTransferTokens{ value: amount }( swapOutput, // accept any amount of Tokens path, deadWallet, // Burn address block.timestamp + 300 ); emit SwapETHForTokens(amount, path); } // Withdraw ETH that's potentially stuck in the Contract function recoverETHfromContract() external onlyOwner { uint ethBalance = address(this).balance; (bool succ, ) = payable(marketingWallet).call{value: ethBalance}(""); require(succ, "Transfer failed"); emit AuditLog( "We have recover the stock eth from contract.", marketingWallet ); } // Withdraw ERC20 tokens that are potentially stuck in Contract function recoverTokensFromContract( address _tokenAddress, uint256 _amount ) external onlyOwner { require( _tokenAddress != address(this), "Owner can't claim contract's balance of its own tokens" ); bool succ = IERC20(_tokenAddress).transfer(marketingWallet, _amount); require(succ, "Transfer failed"); emit Log("We have recovered tokens from contract:", _amount); } //Final Dev notes, this code has been tested and audited, last update to code was done to re-add swapandliquify function to the transfer as option, is recommended to be used manually instead of automatic. }