Transaction Hash:
Block:
23173305 at Aug-19-2025 06:24:11 AM +UTC
Transaction Fee:
0.00003659976331596 ETH
$0.17
Gas Used:
104,754 Gas / 0.34938774 Gwei
Emitted Events:
248 |
PAALAI.Transfer( from=[Receiver] TokenVesting, to=[Sender] 0x211232a7c4113fb3a33fe86fa11d4fee503dd2f3, value=10398763632877 )
|
249 |
TokenVesting.onWithdraw( lpToken=PAALAI, amountInTokens=10398763632877 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x14feE680...b95D10e16 | |||||
0x211232a7...E503dD2F3 |
0.006251719645953479 Eth
Nonce: 76
|
0.006215119882637519 Eth
Nonce: 77
| 0.00003659976331596 | ||
0x39634336...6fb82Aa49
Miner
| (quasarbuilder) | 7.406247485643129065 Eth | 7.406268436443129065 Eth | 0.0000209508 | |
0xDba68f07...975c25cAf | (UNCX Network Security : Token Vesting) |
Execution Trace
File 1 of 2: TokenVesting
File 2 of 2: PAALAI
{"Context.sol":{"content":"// SPDX-License-Identifier: MIT\n\n// File @openzeppelin/contracts/utils/[email protected]\n\npragma solidity ^0.8.0;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n return msg.data;\n }\n}\n"},"EnumerableSet.sol":{"content":"// SPDX-License-Identifier: MIT\n\n// File @openzeppelin/contracts/utils/structs/[email protected]\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```\n * contract Example {\n * // Add the library methods\n * using EnumerableSet for EnumerableSet.AddressSet;\n *\n * // Declare a set state variable\n * EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n */\nlibrary EnumerableSet {\n // To implement this library for multiple types with as little code\n // repetition as possible, we write it in terms of a generic Set type with\n // bytes32 values.\n // The Set implementation uses private functions, and user-facing\n // implementations (such as AddressSet) are just wrappers around the\n // underlying Set.\n // This means that we can only create new EnumerableSets for types that fit\n // in bytes32.\n\n struct Set {\n // Storage of set values\n bytes32[] _values;\n\n // Position of the value in the `values` array, plus 1 because index 0\n // means a value is not in the set.\n mapping (bytes32 =\u003e uint256) _indexes;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function _add(Set storage set, bytes32 value) private returns (bool) {\n if (!_contains(set, value)) {\n set._values.push(value);\n // The value is stored at length-1, but we add 1 to all indexes\n // and use 0 as a sentinel value\n set._indexes[value] = set._values.length;\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function _remove(Set storage set, bytes32 value) private returns (bool) {\n // We read and store the value\u0027s index to prevent multiple reads from the same storage slot\n uint256 valueIndex = set._indexes[value];\n\n if (valueIndex != 0) { // Equivalent to contains(set, value)\n // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n // the array, and then remove the last element (sometimes called as \u0027swap and pop\u0027).\n // This modifies the order of the array, as noted in {at}.\n\n uint256 toDeleteIndex = valueIndex - 1;\n uint256 lastIndex = set._values.length - 1;\n\n // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs\n // so rarely, we still do the swap anyway to avoid the gas cost of adding an \u0027if\u0027 statement.\n\n bytes32 lastvalue = set._values[lastIndex];\n\n // Move the last value to the index where the value to delete is\n set._values[toDeleteIndex] = lastvalue;\n // Update the index for the moved value\n set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based\n\n // Delete the slot where the moved value was stored\n set._values.pop();\n\n // Delete the index for the deleted slot\n delete set._indexes[value];\n\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function _contains(Set storage set, bytes32 value) private view returns (bool) {\n return set._indexes[value] != 0;\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function _length(Set storage set) private view returns (uint256) {\n return set._values.length;\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function _at(Set storage set, uint256 index) private view returns (bytes32) {\n require(set._values.length \u003e index, \"EnumerableSet: index out of bounds\");\n return set._values[index];\n }\n\n // Bytes32Set\n\n struct Bytes32Set {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _add(set._inner, value);\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n return _remove(set._inner, value);\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n return _contains(set._inner, value);\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(Bytes32Set storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n return _at(set._inner, index);\n }\n\n // AddressSet\n\n struct AddressSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(AddressSet storage set, address value) internal returns (bool) {\n return _add(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(AddressSet storage set, address value) internal returns (bool) {\n return _remove(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(AddressSet storage set, address value) internal view returns (bool) {\n return _contains(set._inner, bytes32(uint256(uint160(value))));\n }\n\n /**\n * @dev Returns the number of values in the set. O(1).\n */\n function length(AddressSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(AddressSet storage set, uint256 index) internal view returns (address) {\n return address(uint160(uint256(_at(set._inner, index))));\n }\n\n\n // UintSet\n\n struct UintSet {\n Set _inner;\n }\n\n /**\n * @dev Add a value to a set. O(1).\n *\n * Returns true if the value was added to the set, that is if it was not\n * already present.\n */\n function add(UintSet storage set, uint256 value) internal returns (bool) {\n return _add(set._inner, bytes32(value));\n }\n\n /**\n * @dev Removes a value from a set. O(1).\n *\n * Returns true if the value was removed from the set, that is if it was\n * present.\n */\n function remove(UintSet storage set, uint256 value) internal returns (bool) {\n return _remove(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns true if the value is in the set. O(1).\n */\n function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n return _contains(set._inner, bytes32(value));\n }\n\n /**\n * @dev Returns the number of values on the set. O(1).\n */\n function length(UintSet storage set) internal view returns (uint256) {\n return _length(set._inner);\n }\n\n /**\n * @dev Returns the value stored at position `index` in the set. O(1).\n *\n * Note that there are no guarantees on the ordering of values inside the\n * array, and it may change when more values are added or removed.\n *\n * Requirements:\n *\n * - `index` must be strictly less than {length}.\n */\n function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n return uint256(_at(set._inner, index));\n }\n}\n"},"FullMath.sol":{"content":"// SPDX-License-Identifier: MIT\r\npragma solidity ^0.8.0;\r\n\r\n// Sourced from https://gist.github.com/paulrberg/439ebe860cd2f9893852e2cab5655b65, credits to Paulrberg for porting to solidity v0.8\r\n/// @title Contains 512-bit math functions\r\n/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision\r\n/// @dev Handles \"phantom overflow\" i.e., allows multiplication and division where an intermediate value overflows 256 bits\r\nlibrary FullMath {\r\n /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\r\n /// @param a The multiplicand\r\n /// @param b The multiplier\r\n /// @param denominator The divisor\r\n /// @return result The 256-bit result\r\n /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv\r\n function mulDiv(\r\n uint256 a,\r\n uint256 b,\r\n uint256 denominator\r\n ) internal pure returns (uint256 result) {\r\n // 512-bit multiply [prod1 prod0] = a * b\r\n // Compute the product mod 2**256 and mod 2**256 - 1\r\n // then use the Chinese Remainder Theorem to reconstruct\r\n // the 512 bit result. The result is stored in two 256\r\n // variables such that product = prod1 * 2**256 + prod0\r\n uint256 prod0; // Least significant 256 bits of the product\r\n uint256 prod1; // Most significant 256 bits of the product\r\n assembly {\r\n let mm := mulmod(a, b, not(0))\r\n prod0 := mul(a, b)\r\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\r\n }\r\n\r\n // Handle non-overflow cases, 256 by 256 division\r\n if (prod1 == 0) {\r\n require(denominator \u003e 0);\r\n assembly {\r\n result := div(prod0, denominator)\r\n }\r\n return result;\r\n }\r\n\r\n // Make sure the result is less than 2**256.\r\n // Also prevents denominator == 0\r\n require(denominator \u003e prod1);\r\n\r\n ///////////////////////////////////////////////\r\n // 512 by 256 division.\r\n ///////////////////////////////////////////////\r\n\r\n // Make division exact by subtracting the remainder from [prod1 prod0]\r\n // Compute remainder using mulmod\r\n uint256 remainder;\r\n assembly {\r\n remainder := mulmod(a, b, denominator)\r\n }\r\n // Subtract 256 bit number from 512 bit number\r\n assembly {\r\n prod1 := sub(prod1, gt(remainder, prod0))\r\n prod0 := sub(prod0, remainder)\r\n }\r\n\r\n // Factor powers of two out of denominator\r\n // Compute largest power of two divisor of denominator.\r\n // Always \u003e= 1.\r\n unchecked {\r\n uint256 twos = (type(uint256).max - denominator + 1) \u0026 denominator;\r\n // Divide denominator by power of two\r\n assembly {\r\n denominator := div(denominator, twos)\r\n }\r\n\r\n // Divide [prod1 prod0] by the factors of two\r\n assembly {\r\n prod0 := div(prod0, twos)\r\n }\r\n // Shift in bits from prod1 into prod0. For this we need\r\n // to flip `twos` such that it is 2**256 / twos.\r\n // If twos is zero, then it becomes one\r\n assembly {\r\n twos := add(div(sub(0, twos), twos), 1)\r\n }\r\n prod0 |= prod1 * twos;\r\n\r\n // Invert denominator mod 2**256\r\n // Now that denominator is an odd number, it has an inverse\r\n // modulo 2**256 such that denominator * inv = 1 mod 2**256.\r\n // Compute the inverse by starting with a seed that is correct\r\n // correct for four bits. That is, denominator * inv = 1 mod 2**4\r\n uint256 inv = (3 * denominator) ^ 2;\r\n // Now use Newton-Raphson iteration to improve the precision.\r\n // Thanks to Hensel\u0027s lifting lemma, this also works in modular\r\n // arithmetic, doubling the correct bits in each step.\r\n inv *= 2 - denominator * inv; // inverse mod 2**8\r\n inv *= 2 - denominator * inv; // inverse mod 2**16\r\n inv *= 2 - denominator * inv; // inverse mod 2**32\r\n inv *= 2 - denominator * inv; // inverse mod 2**64\r\n inv *= 2 - denominator * inv; // inverse mod 2**128\r\n inv *= 2 - denominator * inv; // inverse mod 2**256\r\n\r\n // Because the division is now exact we can divide by multiplying\r\n // with the modular inverse of denominator. This will give us the\r\n // correct result modulo 2**256. Since the precoditions guarantee\r\n // that the outcome is less than 2**256, this is the final result.\r\n // We don\u0027t need to compute the high bits of the result and prod1\r\n // is no longer required.\r\n result = prod0 * inv;\r\n return result;\r\n }\r\n }\r\n}"},"IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n\n// File @openzeppelin/contracts/token/ERC20/[email protected]\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller\u0027s account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller\u0027s tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender\u0027s allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller\u0027s\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"},"Ownable.sol":{"content":"// SPDX-License-Identifier: MIT\n\n// File @openzeppelin/contracts/access/[email protected]\n\npragma solidity ^0.8.0;\n\nimport \"./Context.sol\";\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor () {\n address msgSender = _msgSender();\n _owner = msgSender;\n emit OwnershipTransferred(address(0), msgSender);\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n _;\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n emit OwnershipTransferred(_owner, address(0));\n _owner = address(0);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n emit OwnershipTransferred(_owner, newOwner);\n _owner = newOwner;\n }\n}\n"},"ReentrancyGuard.sol":{"content":"// SPDX-License-Identifier: MIT\n\n// File @openzeppelin/contracts/security/[email protected]\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot\u0027s contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler\u0027s defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction\u0027s gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n constructor () {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and make it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n // On the first call to nonReentrant, _notEntered will be true\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n\n _;\n\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n}\n"},"TokenVesting.sol":{"content":"// SPDX-License-Identifier: UNLICENSED\r\n// ALL RIGHTS RESERVED\r\n// Unicrypt by SDDTech reserves all rights on this code. You may NOT copy these contracts.\r\n\r\n// This contract locks ERC20 tokens. This can be used for:\r\n// - Token developers to prove they have locked tokens\r\n// - Presale projects or investors to lock a portion of tokens for a vesting period\r\n// - Farming platforms to lock a percentage of the farmed rewards for a period of time\r\n// - To lock tokens until a specific unlock date.\r\n// - To send tokens to someone under a time lock.\r\n\r\n// This contract is for ERC20 tokens, and supports high deflationary and rebasing tokens by using a pooling and share issuing mechanism.\r\n// This is NOT for AMM LP tokens (such as UNIV2), Please use our liquidity lockers for this.\r\n// Locking LP tokens in this contract will not show in the Unicrypt browser.\r\n\r\n// *** LOCK TYPES ***\r\n// Lock Type 1: when startEmission == 0 the lock is considered lockType 1. This is a normal lock\r\n// whereby tokens can be withdrawn on the due date (endEmission).\r\n\r\n// Lock Type 2: when startEmission != 0. Lock tokens over a period, with an amount withdrawable every block. \r\n// This scales linearly over time from startEmission -\u003e endEmission. \r\n// e.g. If the lock period is 100 seconds, 50 seconds after the startEmission you can withdraw 50% of the lock.\r\n// Instead of making 10 locks for 10 months to withdraw tokens at the end of each month, you can now make 1 linear scaling lock with a period\r\n// of 10 months and withdraw the relative share every block.\r\n\r\n// *** CUSTOM PREMATURE UNLOCKING CONDITIONS ***\r\n// All locks support premature unlocking conditions. A premature unlock condition can be anything that implements the IUnlockCondition interface\r\n// If IUnlockCondition(address).unlockTokens() returns true, the lock withdraw date is overriden and the entire lock value can be withdrawn.\r\n// The key here is this is for premature unlocks, locks always fall back to the endEmission date \r\n// even if unlockTokens() returns false, and are therefore always withdrawble in full by the unlockDate.\r\n// Example use cases, Imagine a presale is 1 week long. Marketers tokens are locked for 1 week to prevent them initiating\r\n// markets and setting initial prices on an AMM. The presale concludes within 5 minuites. Marketers now need to wait 1 week,\r\n// to access their tokens. With conditional unlocks a condition can be set to return true once a presale has concluded\r\n// and override the 1 week lock making their tokens instantly withdrawble post presale. \r\n// Another use case could be to allow token developers or investors to prematurely unlock their tokens\r\n// if the price reaches a specified target, or for governance to vote for developers to unlock tokens prematurely \r\n// for development purposes met or raodmap goals met.\r\n// Get creative!\r\n\r\n// Please be aware if you are locking tokens to prove to your community you have locked tokens for long term you should not use a premature unlocking condition \r\n// as these types of locks will be shown differently in the browser to a normal lock with no unlocking condition.\r\n// Unlocking conditions can always be revoked by the lock owner to give more credibility to the lock.\r\n\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./TransferHelper.sol\";\r\nimport \u0027./VestingMathLibrary.sol\u0027;\r\nimport \u0027./FullMath.sol\u0027;\r\n\r\nimport \"./EnumerableSet.sol\";\r\nimport \"./Ownable.sol\";\r\nimport \"./ReentrancyGuard.sol\";\r\nimport \"./IERC20.sol\";\r\n\r\ninterface IMigrator {\r\n function migrate(address token, uint256 sharesDeposited, uint256 sharesWithdrawn, uint256 startEmission, uint256 endEmission, uint256 lockID, address owner, address condition, uint256 amountInTokens, uint256 option) external returns (bool);\r\n}\r\n\r\ninterface IUnicryptAdmin {\r\n function userIsAdmin(address _user) external view returns (bool);\r\n}\r\n\r\ninterface ITokenBlacklist {\r\n function checkToken(address _token) external view;\r\n}\r\n\r\ncontract TokenVesting is Ownable, ReentrancyGuard {\r\n using EnumerableSet for EnumerableSet.AddressSet;\r\n\r\n struct UserInfo {\r\n EnumerableSet.AddressSet lockedTokens; // records all token addresses the user has locked\r\n mapping(address =\u003e uint256[]) locksForToken; // map erc20 address to lockId for that token\r\n }\r\n\r\n struct TokenLock {\r\n address tokenAddress; // The token address\r\n uint256 sharesDeposited; // the total amount of shares deposited\r\n uint256 sharesWithdrawn; // amount of shares withdrawn\r\n uint256 startEmission; // date token emission begins\r\n uint256 endEmission; // the date the tokens can be withdrawn\r\n uint256 lockID; // lock id per token lock\r\n address owner; // the owner who can edit or withdraw the lock\r\n address condition; // address(0) = no condition, otherwise the condition contract must implement IUnlockCondition\r\n }\r\n \r\n struct LockParams {\r\n address payable owner; // the user who can withdraw tokens once the lock expires.\r\n uint256 amount; // amount of tokens to lock\r\n uint256 startEmission; // 0 if lock type 1, else a unix timestamp\r\n uint256 endEmission; // the unlock date as a unix timestamp (in seconds)\r\n address condition; // address(0) = no condition, otherwise the condition must implement IUnlockCondition\r\n }\r\n\r\n EnumerableSet.AddressSet private TOKENS; // list of all unique tokens that have a lock\r\n mapping(uint256 =\u003e TokenLock) public LOCKS; // map lockID nonce to the lock\r\n uint256 public NONCE = 0; // incremental lock nonce counter, this is the unique ID for the next lock\r\n uint256 public MINIMUM_DEPOSIT = 100; // minimum divisibility per lock at time of locking\r\n \r\n mapping(address =\u003e uint256[]) private TOKEN_LOCKS; // map token address to array of lockIDs for that token\r\n mapping(address =\u003e UserInfo) private USERS;\r\n\r\n mapping(address =\u003e uint) public SHARES; // map token to number of shares per token, shares allow rebasing and deflationary tokens to compute correctly\r\n \r\n EnumerableSet.AddressSet private ZERO_FEE_WHITELIST; // Tokens that have been whitelisted to bypass all fees\r\n EnumerableSet.AddressSet private TOKEN_WHITELISTERS; // whitelisting contracts and users who can enable no fee for tokens.\r\n \r\n struct FeeStruct {\r\n uint256 tokenFee;\r\n uint256 freeLockingFee;\r\n address payable feeAddress;\r\n address freeLockingToken; // if this is address(0) then it is the gas token of the network (e.g ETH, BNB, Matic)\r\n }\r\n \r\n FeeStruct public FEES;\r\n \r\n IUnicryptAdmin UNCX_ADMINS;\r\n IMigrator public MIGRATOR;\r\n ITokenBlacklist public BLACKLIST; // prevent AMM tokens with a blacklisting contract\r\n\r\n event onLock(uint256 lockID, address token, address owner, uint256 amountInTokens, uint256 startEmission, uint256 endEmission);\r\n event onWithdraw(address lpToken, uint256 amountInTokens);\r\n event onRelock(uint256 lockID, uint256 unlockDate);\r\n event onTransferLock(uint256 lockIDFrom, uint256 lockIDto, address oldOwner, address newOwner);\r\n event onSplitLock(uint256 fromLockID, uint256 toLockID, uint256 amountInTokens);\r\n event onMigrate(uint256 lockID, uint256 amountInTokens);\r\n\r\n constructor (IUnicryptAdmin _uncxAdmins) {\r\n UNCX_ADMINS = _uncxAdmins;\r\n FEES.tokenFee = 35;\r\n FEES.feeAddress = payable(0xAA3d85aD9D128DFECb55424085754F6dFa643eb1);\r\n FEES.freeLockingFee = 10e18;\r\n }\r\n \r\n /**\r\n * @notice set the migrator contract which allows the lock to be migrated\r\n */\r\n function setMigrator(IMigrator _migrator) external onlyOwner {\r\n MIGRATOR = _migrator;\r\n }\r\n \r\n function setBlacklistContract(ITokenBlacklist _contract) external onlyOwner {\r\n BLACKLIST = _contract;\r\n }\r\n \r\n function setFees(uint256 _tokenFee, uint256 _freeLockingFee, address payable _feeAddress, address _freeLockingToken) external onlyOwner {\r\n FEES.tokenFee = _tokenFee;\r\n FEES.freeLockingFee = _freeLockingFee;\r\n FEES.feeAddress = _feeAddress;\r\n FEES.freeLockingToken = _freeLockingToken;\r\n }\r\n \r\n /**\r\n * @notice whitelisted accounts and contracts who can call the editZeroFeeWhitelist function\r\n */\r\n function adminSetWhitelister(address _user, bool _add) external onlyOwner {\r\n if (_add) {\r\n TOKEN_WHITELISTERS.add(_user);\r\n } else {\r\n TOKEN_WHITELISTERS.remove(_user);\r\n }\r\n }\r\n \r\n // Pay a once off fee to have free use of the lockers for the token\r\n function payForFreeTokenLocks (address _token) external payable {\r\n require(!ZERO_FEE_WHITELIST.contains(_token), \u0027PAID\u0027);\r\n // charge Fee\r\n if (FEES.freeLockingToken == address(0)) {\r\n require(msg.value == FEES.freeLockingFee, \u0027FEE NOT MET\u0027);\r\n FEES.feeAddress.transfer(FEES.freeLockingFee);\r\n } else {\r\n TransferHelper.safeTransferFrom(address(FEES.freeLockingToken), address(msg.sender), FEES.feeAddress, FEES.freeLockingFee);\r\n }\r\n ZERO_FEE_WHITELIST.add(_token);\r\n }\r\n \r\n // Callable by UNCX_ADMINS or whitelisted contracts (such as presale contracts)\r\n function editZeroFeeWhitelist (address _token, bool _add) external {\r\n require(UNCX_ADMINS.userIsAdmin(msg.sender) || TOKEN_WHITELISTERS.contains(msg.sender), \u0027ADMIN\u0027);\r\n if (_add) {\r\n ZERO_FEE_WHITELIST.add(_token);\r\n } else {\r\n ZERO_FEE_WHITELIST.remove(_token);\r\n }\r\n }\r\n\r\n /**\r\n * @notice Creates one or multiple locks for the specified token\r\n * @param _token the erc20 token address\r\n * @param _lock_params an array of locks with format: [LockParams[owner, amount, startEmission, endEmission, condition]]\r\n * owner: user or contract who can withdraw the tokens\r\n * amount: must be \u003e= 100 units\r\n * startEmission = 0 : LockType 1\r\n * startEmission != 0 : LockType 2 (linear scaling lock)\r\n * use address(0) for no premature unlocking condition\r\n * Fails if startEmission is not less than EndEmission\r\n * Fails is amount \u003c 100\r\n */\r\n function lock (address _token, LockParams[] calldata _lock_params) external nonReentrant {\r\n require(_lock_params.length \u003e 0, \u0027NO PARAMS\u0027);\r\n if (address(BLACKLIST) != address(0)) {\r\n BLACKLIST.checkToken(_token);\r\n }\r\n uint256 totalAmount = 0;\r\n for (uint256 i = 0; i \u003c _lock_params.length; i++) {\r\n totalAmount += _lock_params[i].amount;\r\n }\r\n\r\n uint256 balanceBefore = IERC20(_token).balanceOf(address(this));\r\n TransferHelper.safeTransferFrom(_token, address(msg.sender), address(this), totalAmount);\r\n uint256 amountIn = IERC20(_token).balanceOf(address(this)) - balanceBefore;\r\n\r\n // Fees\r\n if (!ZERO_FEE_WHITELIST.contains(_token)) {\r\n uint256 lockFee = FullMath.mulDiv(amountIn, FEES.tokenFee, 10000);\r\n TransferHelper.safeTransfer(_token, FEES.feeAddress, lockFee);\r\n amountIn -= lockFee;\r\n }\r\n \r\n uint256 shares = 0;\r\n for (uint256 i = 0; i \u003c _lock_params.length; i++) {\r\n LockParams memory lock_param = _lock_params[i];\r\n require(lock_param.startEmission \u003c lock_param.endEmission, \u0027PERIOD\u0027);\r\n require(lock_param.endEmission \u003c 1e10, \u0027TIMESTAMP INVALID\u0027); // prevents errors when timestamp entered in milliseconds\r\n require(lock_param.amount \u003e= MINIMUM_DEPOSIT, \u0027MIN DEPOSIT\u0027);\r\n uint256 amountInTokens = FullMath.mulDiv(lock_param.amount, amountIn, totalAmount);\r\n\r\n if (SHARES[_token] == 0) {\r\n shares = amountInTokens;\r\n } else {\r\n shares = FullMath.mulDiv(amountInTokens, SHARES[_token], balanceBefore == 0 ? 1 : balanceBefore);\r\n }\r\n require(shares \u003e 0, \u0027SHARES\u0027);\r\n SHARES[_token] += shares;\r\n balanceBefore += amountInTokens;\r\n\r\n TokenLock memory token_lock;\r\n token_lock.tokenAddress = _token;\r\n token_lock.sharesDeposited = shares;\r\n token_lock.startEmission = lock_param.startEmission;\r\n token_lock.endEmission = lock_param.endEmission;\r\n token_lock.lockID = NONCE;\r\n token_lock.owner = lock_param.owner;\r\n if (lock_param.condition != address(0)) {\r\n // if the condition contract does not implement the interface and return a bool\r\n // the below line will fail and revert the tx as the conditional contract is invalid\r\n IUnlockCondition(lock_param.condition).unlockTokens();\r\n token_lock.condition = lock_param.condition;\r\n }\r\n \r\n // record the lock globally\r\n LOCKS[NONCE] = token_lock;\r\n TOKENS.add(_token);\r\n TOKEN_LOCKS[_token].push(NONCE);\r\n \r\n // record the lock for the user\r\n UserInfo storage user = USERS[lock_param.owner];\r\n user.lockedTokens.add(_token);\r\n user.locksForToken[_token].push(NONCE);\r\n \r\n NONCE ++;\r\n emit onLock(token_lock.lockID, _token, token_lock.owner, amountInTokens, token_lock.startEmission, token_lock.endEmission);\r\n }\r\n }\r\n \r\n /**\r\n * @notice withdraw a specified amount from a lock. _amount is the ideal amount to be withdrawn.\r\n * however, this amount might be slightly different in rebasing tokens due to the conversion to shares,\r\n * then back into an amount\r\n * @param _lockID the lockID of the lock to be withdrawn\r\n * @param _amount amount of tokens to withdraw\r\n */\r\n function withdraw (uint256 _lockID, uint256 _amount) external nonReentrant {\r\n TokenLock storage userLock = LOCKS[_lockID];\r\n require(userLock.owner == msg.sender, \u0027OWNER\u0027);\r\n // convert _amount to its representation in shares\r\n uint256 balance = IERC20(userLock.tokenAddress).balanceOf(address(this));\r\n uint256 shareDebit = FullMath.mulDiv(SHARES[userLock.tokenAddress], _amount, balance);\r\n // round _amount up to the nearest whole share if the amount of tokens specified does not translate to\r\n // at least 1 share.\r\n if (shareDebit == 0 \u0026\u0026 _amount \u003e 0) {\r\n shareDebit ++;\r\n }\r\n require(shareDebit \u003e 0, \u0027ZERO WITHDRAWL\u0027);\r\n uint256 withdrawableShares = getWithdrawableShares(userLock.lockID);\r\n // dust clearance block, as mulDiv rounds down leaving one share stuck, clear all shares for dust amounts\r\n if (shareDebit + 1 == withdrawableShares) {\r\n if (FullMath.mulDiv(SHARES[userLock.tokenAddress], balance / SHARES[userLock.tokenAddress], balance) == 0){\r\n shareDebit++;\r\n }\r\n }\r\n require(withdrawableShares \u003e= shareDebit, \u0027AMOUNT\u0027);\r\n userLock.sharesWithdrawn += shareDebit;\r\n\r\n // now convert shares to the actual _amount it represents, this may differ slightly from the \r\n // _amount supplied in this methods arguments.\r\n uint256 amountInTokens = FullMath.mulDiv(shareDebit, balance, SHARES[userLock.tokenAddress]);\r\n SHARES[userLock.tokenAddress] -= shareDebit;\r\n \r\n TransferHelper.safeTransfer(userLock.tokenAddress, msg.sender, amountInTokens);\r\n emit onWithdraw(userLock.tokenAddress, amountInTokens);\r\n }\r\n \r\n /**\r\n * @notice extend a lock with a new unlock date, if lock is Type 2 it extends the emission end date\r\n */\r\n function relock (uint256 _lockID, uint256 _unlock_date) external nonReentrant {\r\n require(_unlock_date \u003c 1e10, \u0027TIME\u0027); // prevents errors when timestamp entered in milliseconds\r\n TokenLock storage userLock = LOCKS[_lockID];\r\n require(userLock.owner == msg.sender, \u0027OWNER\u0027);\r\n require(userLock.endEmission \u003c _unlock_date, \u0027END\u0027);\r\n // percent fee\r\n if (!ZERO_FEE_WHITELIST.contains(userLock.tokenAddress)) {\r\n uint256 remainingShares = userLock.sharesDeposited - userLock.sharesWithdrawn;\r\n uint256 feeInShares = FullMath.mulDiv(remainingShares, FEES.tokenFee, 10000);\r\n uint256 balance = IERC20(userLock.tokenAddress).balanceOf(address(this));\r\n uint256 feeInTokens = FullMath.mulDiv(feeInShares, balance, SHARES[userLock.tokenAddress] == 0 ? 1 : SHARES[userLock.tokenAddress]);\r\n TransferHelper.safeTransfer(userLock.tokenAddress, FEES.feeAddress, feeInTokens);\r\n userLock.sharesWithdrawn += feeInShares;\r\n SHARES[userLock.tokenAddress] -= feeInShares;\r\n }\r\n userLock.endEmission = _unlock_date;\r\n emit onRelock(_lockID, _unlock_date);\r\n }\r\n \r\n /**\r\n * @notice increase the amount of tokens per a specific lock, this is preferable to creating a new lock\r\n * Its possible to increase someone elses lock here it does not need to be your own, useful for contracts\r\n */\r\n function incrementLock (uint256 _lockID, uint256 _amount) external nonReentrant {\r\n TokenLock storage userLock = LOCKS[_lockID];\r\n require(_amount \u003e= MINIMUM_DEPOSIT, \u0027MIN DEPOSIT\u0027);\r\n \r\n uint256 balanceBefore = IERC20(userLock.tokenAddress).balanceOf(address(this));\r\n TransferHelper.safeTransferFrom(userLock.tokenAddress, address(msg.sender), address(this), _amount);\r\n uint256 amountInTokens = IERC20(userLock.tokenAddress).balanceOf(address(this)) - balanceBefore;\r\n\r\n // percent fee\r\n if (!ZERO_FEE_WHITELIST.contains(userLock.tokenAddress)) {\r\n uint256 lockFee = FullMath.mulDiv(amountInTokens, FEES.tokenFee, 10000);\r\n TransferHelper.safeTransfer(userLock.tokenAddress, FEES.feeAddress, lockFee);\r\n amountInTokens -= lockFee;\r\n }\r\n uint256 shares;\r\n if (SHARES[userLock.tokenAddress] == 0) {\r\n shares = amountInTokens;\r\n } else {\r\n shares = FullMath.mulDiv(amountInTokens, SHARES[userLock.tokenAddress], balanceBefore);\r\n }\r\n require(shares \u003e 0, \u0027SHARES\u0027);\r\n SHARES[userLock.tokenAddress] += shares;\r\n userLock.sharesDeposited += shares;\r\n emit onLock(userLock.lockID, userLock.tokenAddress, userLock.owner, amountInTokens, userLock.startEmission, userLock.endEmission);\r\n }\r\n \r\n /**\r\n * @notice transfer a lock to a new owner, e.g. presale project -\u003e project owner\r\n * Please be aware this generates a new lock, and nulls the old lock, so a new ID is assigned to the new lock.\r\n */\r\n function transferLockOwnership (uint256 _lockID, address payable _newOwner) external nonReentrant {\r\n require(msg.sender != _newOwner, \u0027SELF\u0027);\r\n TokenLock storage transferredLock = LOCKS[_lockID];\r\n require(transferredLock.owner == msg.sender, \u0027OWNER\u0027);\r\n \r\n TokenLock memory token_lock;\r\n token_lock.tokenAddress = transferredLock.tokenAddress;\r\n token_lock.sharesDeposited = transferredLock.sharesDeposited;\r\n token_lock.sharesWithdrawn = transferredLock.sharesWithdrawn;\r\n token_lock.startEmission = transferredLock.startEmission;\r\n token_lock.endEmission = transferredLock.endEmission;\r\n token_lock.lockID = NONCE;\r\n token_lock.owner = _newOwner;\r\n token_lock.condition = transferredLock.condition;\r\n \r\n // record the lock globally\r\n LOCKS[NONCE] = token_lock;\r\n TOKEN_LOCKS[transferredLock.tokenAddress].push(NONCE);\r\n \r\n // record the lock for the new owner \r\n UserInfo storage newOwner = USERS[_newOwner];\r\n newOwner.lockedTokens.add(transferredLock.tokenAddress);\r\n newOwner.locksForToken[transferredLock.tokenAddress].push(token_lock.lockID);\r\n NONCE ++;\r\n \r\n // zero the lock from the old owner\r\n transferredLock.sharesWithdrawn = transferredLock.sharesDeposited;\r\n emit onTransferLock(_lockID, token_lock.lockID, msg.sender, _newOwner);\r\n }\r\n \r\n /**\r\n * @notice split a lock into two seperate locks, useful when a lock is about to expire and youd like to relock a portion\r\n * and withdraw a smaller portion\r\n * Only works on lock type 1, this feature does not work with lock type 2\r\n * @param _amount the amount in tokens\r\n */\r\n function splitLock (uint256 _lockID, uint256 _amount) external nonReentrant {\r\n require(_amount \u003e 0, \u0027ZERO AMOUNT\u0027);\r\n TokenLock storage userLock = LOCKS[_lockID];\r\n require(userLock.owner == msg.sender, \u0027OWNER\u0027);\r\n require(userLock.startEmission == 0, \u0027LOCK TYPE 2\u0027);\r\n\r\n // convert _amount to its representation in shares\r\n uint256 balance = IERC20(userLock.tokenAddress).balanceOf(address(this));\r\n uint256 amountInShares = FullMath.mulDiv(SHARES[userLock.tokenAddress], _amount, balance);\r\n\r\n require(userLock.sharesWithdrawn + amountInShares \u003c= userLock.sharesDeposited);\r\n \r\n TokenLock memory token_lock;\r\n token_lock.tokenAddress = userLock.tokenAddress;\r\n token_lock.sharesDeposited = amountInShares;\r\n token_lock.endEmission = userLock.endEmission;\r\n token_lock.lockID = NONCE;\r\n token_lock.owner = msg.sender;\r\n token_lock.condition = userLock.condition;\r\n \r\n // debit previous lock\r\n userLock.sharesWithdrawn += amountInShares;\r\n \r\n // record the new lock globally\r\n LOCKS[NONCE] = token_lock;\r\n TOKEN_LOCKS[userLock.tokenAddress].push(NONCE);\r\n \r\n // record the new lock for the owner \r\n USERS[msg.sender].locksForToken[userLock.tokenAddress].push(token_lock.lockID);\r\n NONCE ++;\r\n emit onSplitLock(_lockID, token_lock.lockID, _amount);\r\n }\r\n \r\n /**\r\n * @notice migrates to the next locker version, only callable by lock owners\r\n */\r\n function migrate (uint256 _lockID, uint256 _option) external nonReentrant {\r\n require(address(MIGRATOR) != address(0), \"NOT SET\");\r\n TokenLock storage userLock = LOCKS[_lockID];\r\n require(userLock.owner == msg.sender, \u0027OWNER\u0027);\r\n uint256 sharesAvailable = userLock.sharesDeposited - userLock.sharesWithdrawn;\r\n require(sharesAvailable \u003e 0, \u0027AMOUNT\u0027);\r\n\r\n uint256 balance = IERC20(userLock.tokenAddress).balanceOf(address(this));\r\n uint256 amountInTokens = FullMath.mulDiv(sharesAvailable, balance, SHARES[userLock.tokenAddress]);\r\n \r\n TransferHelper.safeApprove(userLock.tokenAddress, address(MIGRATOR), amountInTokens);\r\n MIGRATOR.migrate(userLock.tokenAddress, userLock.sharesDeposited, userLock.sharesWithdrawn, userLock.startEmission,\r\n userLock.endEmission, userLock.lockID, userLock.owner, userLock.condition, amountInTokens, _option);\r\n \r\n userLock.sharesWithdrawn = userLock.sharesDeposited;\r\n SHARES[userLock.tokenAddress] -= sharesAvailable;\r\n emit onMigrate(_lockID, amountInTokens);\r\n }\r\n \r\n /**\r\n * @notice premature unlock conditions can be malicous (prevent withdrawls by failing to evalaute or return non bools)\r\n * or not give community enough insurance tokens will remain locked until the end date, in such a case, it can be revoked\r\n */\r\n function revokeCondition (uint256 _lockID) external nonReentrant {\r\n TokenLock storage userLock = LOCKS[_lockID];\r\n require(userLock.owner == msg.sender, \u0027OWNER\u0027);\r\n require(userLock.condition != address(0)); // already set to address(0)\r\n userLock.condition = address(0);\r\n }\r\n \r\n // test a condition on front end, added here for convenience in UI, returns unlockTokens() bool, or fails\r\n function testCondition (address condition) external view returns (bool) {\r\n return (IUnlockCondition(condition).unlockTokens());\r\n }\r\n \r\n // returns withdrawable share amount from the lock, taking into consideration start and end emission\r\n function getWithdrawableShares (uint256 _lockID) public view returns (uint256) {\r\n TokenLock storage userLock = LOCKS[_lockID];\r\n uint8 lockType = userLock.startEmission == 0 ? 1 : 2;\r\n uint256 amount = lockType == 1 ? userLock.sharesDeposited - userLock.sharesWithdrawn : userLock.sharesDeposited;\r\n uint256 withdrawable;\r\n withdrawable = VestingMathLibrary.getWithdrawableAmount (\r\n userLock.startEmission, \r\n userLock.endEmission, \r\n amount, \r\n block.timestamp, \r\n userLock.condition\r\n );\r\n if (lockType == 2) {\r\n withdrawable -= userLock.sharesWithdrawn;\r\n }\r\n return withdrawable;\r\n }\r\n \r\n // convenience function for UI, converts shares to the current amount in tokens\r\n function getWithdrawableTokens (uint256 _lockID) external view returns (uint256) {\r\n TokenLock storage userLock = LOCKS[_lockID];\r\n uint256 withdrawableShares = getWithdrawableShares(userLock.lockID);\r\n uint256 balance = IERC20(userLock.tokenAddress).balanceOf(address(this));\r\n uint256 amountTokens = FullMath.mulDiv(withdrawableShares, balance, SHARES[userLock.tokenAddress] == 0 ? 1 : SHARES[userLock.tokenAddress]);\r\n return amountTokens;\r\n }\r\n\r\n // For UI use\r\n function convertSharesToTokens (address _token, uint256 _shares) external view returns (uint256) {\r\n uint256 balance = IERC20(_token).balanceOf(address(this));\r\n return FullMath.mulDiv(_shares, balance, SHARES[_token]);\r\n }\r\n\r\n function convertTokensToShares (address _token, uint256 _tokens) external view returns (uint256) {\r\n uint256 balance = IERC20(_token).balanceOf(address(this));\r\n return FullMath.mulDiv(SHARES[_token], _tokens, balance);\r\n }\r\n \r\n // For use in UI, returns more useful lock Data than just querying LOCKS,\r\n // such as the real-time token amount representation of a locks shares\r\n function getLock (uint256 _lockID) external view returns (uint256, address, uint256, uint256, uint256, uint256, uint256, uint256, address, address) {\r\n TokenLock memory tokenLock = LOCKS[_lockID];\r\n\r\n uint256 balance = IERC20(tokenLock.tokenAddress).balanceOf(address(this));\r\n uint256 totalSharesOr1 = SHARES[tokenLock.tokenAddress] == 0 ? 1 : SHARES[tokenLock.tokenAddress];\r\n // tokens deposited and tokens withdrawn is provided for convenience in UI, with rebasing these amounts will change\r\n uint256 tokensDeposited = FullMath.mulDiv(tokenLock.sharesDeposited, balance, totalSharesOr1);\r\n uint256 tokensWithdrawn = FullMath.mulDiv(tokenLock.sharesWithdrawn, balance, totalSharesOr1);\r\n return (tokenLock.lockID, tokenLock.tokenAddress, tokensDeposited, tokensWithdrawn, tokenLock.sharesDeposited, tokenLock.sharesWithdrawn, tokenLock.startEmission, tokenLock.endEmission, \r\n tokenLock.owner, tokenLock.condition);\r\n }\r\n \r\n function getNumLockedTokens () external view returns (uint256) {\r\n return TOKENS.length();\r\n }\r\n \r\n function getTokenAtIndex (uint256 _index) external view returns (address) {\r\n return TOKENS.at(_index);\r\n }\r\n \r\n function getTokenLocksLength (address _token) external view returns (uint256) {\r\n return TOKEN_LOCKS[_token].length;\r\n }\r\n \r\n function getTokenLockIDAtIndex (address _token, uint256 _index) external view returns (uint256) {\r\n return TOKEN_LOCKS[_token][_index];\r\n }\r\n \r\n // user functions\r\n function getUserLockedTokensLength (address _user) external view returns (uint256) {\r\n return USERS[_user].lockedTokens.length();\r\n }\r\n \r\n function getUserLockedTokenAtIndex (address _user, uint256 _index) external view returns (address) {\r\n return USERS[_user].lockedTokens.at(_index);\r\n }\r\n \r\n function getUserLocksForTokenLength (address _user, address _token) external view returns (uint256) {\r\n return USERS[_user].locksForToken[_token].length;\r\n }\r\n \r\n function getUserLockIDForTokenAtIndex (address _user, address _token, uint256 _index) external view returns (uint256) {\r\n return USERS[_user].locksForToken[_token][_index];\r\n }\r\n \r\n // no Fee Tokens\r\n function getZeroFeeTokensLength () external view returns (uint256) {\r\n return ZERO_FEE_WHITELIST.length();\r\n }\r\n \r\n function getZeroFeeTokenAtIndex (uint256 _index) external view returns (address) {\r\n return ZERO_FEE_WHITELIST.at(_index);\r\n }\r\n \r\n function tokenOnZeroFeeWhitelist (address _token) external view returns (bool) {\r\n return ZERO_FEE_WHITELIST.contains(_token);\r\n }\r\n \r\n // whitelist\r\n function getTokenWhitelisterLength () external view returns (uint256) {\r\n return TOKEN_WHITELISTERS.length();\r\n }\r\n \r\n function getTokenWhitelisterAtIndex (uint256 _index) external view returns (address) {\r\n return TOKEN_WHITELISTERS.at(_index);\r\n }\r\n \r\n function getTokenWhitelisterStatus (address _user) external view returns (bool) {\r\n return TOKEN_WHITELISTERS.contains(_user);\r\n }\r\n}"},"TransferHelper.sol":{"content":"// SPDX-License-Identifier: GPL-2.0-or-later\r\npragma solidity \u003e=0.6.0;\r\n\r\n// helper methods for interacting with ERC20 tokens that do not consistently return true/false\r\nlibrary TransferHelper {\r\n function safeApprove(address token, address to, uint value) internal {\r\n (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));\r\n require(success \u0026\u0026 (data.length == 0 || abi.decode(data, (bool))), \u0027TransferHelper: APPROVE_FAILED\u0027);\r\n }\r\n\r\n function safeTransfer(address token, address to, uint value) internal {\r\n (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));\r\n require(success \u0026\u0026 (data.length == 0 || abi.decode(data, (bool))), \u0027TransferHelper: TRANSFER_FAILED\u0027);\r\n }\r\n\r\n function safeTransferFrom(address token, address from, address to, uint value) internal {\r\n (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));\r\n require(success \u0026\u0026 (data.length == 0 || abi.decode(data, (bool))), \u0027TransferHelper: TRANSFER_FROM_FAILED\u0027);\r\n }\r\n\r\n}"},"UnicryptAdmin.sol":{"content":"// SPDX-License-Identifier: MIT\r\n\r\npragma solidity ^0.8.0;\r\n\r\nimport \"./EnumerableSet.sol\";\r\nimport \"./Ownable.sol\";\r\n\r\ninterface IUnicryptAdmin {\r\n function userIsAdmin(address _user) external view returns (bool);\r\n}\r\n\r\ncontract UnicryptAdmin is Ownable {\r\n using EnumerableSet for EnumerableSet.AddressSet;\r\n\r\n EnumerableSet.AddressSet private ADMINS;\r\n \r\n function ownerEditAdmin (address _user, bool _add) public onlyOwner {\r\n if (_add) {\r\n ADMINS.add(_user);\r\n } else {\r\n ADMINS.remove(_user);\r\n }\r\n }\r\n \r\n // Admin getters\r\n function getAdminsLength () external view returns (uint256) {\r\n return ADMINS.length();\r\n }\r\n \r\n function getAdminAtIndex (uint256 _index) external view returns (address) {\r\n return ADMINS.at(_index);\r\n }\r\n \r\n function userIsAdmin (address _user) external view returns (bool) {\r\n return ADMINS.contains(_user);\r\n }\r\n}"},"VestingMathLibrary.sol":{"content":"// SPDX-License-Identifier: UNLICENSED\r\n// ALL RIGHTS RESERVED\r\n// Unicrypt by SDDTech reserves all rights on this code. You may NOT copy these contracts.\r\n\r\npragma solidity ^0.8.0;\r\n\r\nimport \u0027./FullMath.sol\u0027;\r\n\r\n// Allows a seperate contract with a unlockTokens() function to be used to override unlock dates\r\ninterface IUnlockCondition {\r\n function unlockTokens() external view returns (bool);\r\n}\r\n\r\nlibrary VestingMathLibrary {\r\n\r\n // gets the withdrawable amount from a lock\r\n function getWithdrawableAmount (uint256 startEmission, uint256 endEmission, uint256 amount, uint256 timeStamp, address condition) internal view returns (uint256) {\r\n // It is possible in some cases IUnlockCondition(condition).unlockTokens() will fail (func changes state or does not return a bool)\r\n // for this reason we implemented revokeCondition per lock so funds are never stuck in the contract.\r\n \r\n // Prematurely release the lock if the condition is met\r\n if (condition != address(0) \u0026\u0026 IUnlockCondition(condition).unlockTokens()) {\r\n return amount;\r\n }\r\n // Lock type 1 logic block (Normal Unlock on due date)\r\n if (startEmission == 0 || startEmission == endEmission) {\r\n return endEmission \u003c timeStamp ? amount : 0;\r\n }\r\n // Lock type 2 logic block (Linear scaling lock)\r\n uint256 timeClamp = timeStamp;\r\n if (timeClamp \u003e endEmission) {\r\n timeClamp = endEmission;\r\n }\r\n if (timeClamp \u003c startEmission) {\r\n timeClamp = startEmission;\r\n }\r\n uint256 elapsed = timeClamp - startEmission;\r\n uint256 fullPeriod = endEmission - startEmission;\r\n return FullMath.mulDiv(amount, elapsed, fullPeriod); // fullPeriod cannot equal zero due to earlier checks and restraints when locking tokens (startEmission \u003c endEmission)\r\n }\r\n}"}}
File 2 of 2: PAALAI
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.9.0; interface IERC20 { function totalSupply() external view returns (uint256); function decimals() external view returns (uint8); function symbol() external view returns (string memory); function name() external view returns (string memory); function getOwner() external view returns (address); 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); } interface IFactoryV2 { event PairCreated(address indexed token0, address indexed token1, address lpPair, uint); function getPair(address tokenA, address tokenB) external view returns (address lpPair); function createPair(address tokenA, address tokenB) external returns (address lpPair); } interface IV2Pair { function factory() external view returns (address); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function sync() external; } interface IRouter01 { function factory() external pure returns (address); function WETH() external pure returns (address); function addLiquidityETH( address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external payable returns (uint amountToken, uint amountETH, uint liquidity); function addLiquidity( address tokenA, address tokenB, uint amountADesired, uint amountBDesired, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint amountA, uint amountB, uint liquidity); function swapExactETHForTokens( uint amountOutMin, address[] calldata path, address to, uint deadline ) external payable returns (uint[] memory amounts); function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); } interface IRouter02 is IRouter01 { function swapExactTokensForETHSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; function swapExactETHForTokensSupportingFeeOnTransferTokens( uint amountOutMin, address[] calldata path, address to, uint deadline ) external payable; function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; function swapExactTokensForTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); } interface Initializer { function setLaunch(address _initialLpPair, uint32 _liqAddBlock, uint64 _liqAddStamp, uint8 dec) external; function getConfig() external returns (address, address); function getInits(uint256 amount) external returns (uint256, uint256); function setLpPair(address pair, bool enabled) external; } contract PAALAI is IERC20 { mapping (address => uint256) private _tOwned; mapping (address => bool) lpPairs; uint256 private timeSinceLastPair = 0; mapping (address => mapping (address => uint256)) private _allowances; mapping (address => bool) private _liquidityHolders; mapping (address => bool) private _isExcludedFromProtection; mapping (address => bool) private _isExcludedFromFees; uint256 constant private startingSupply = 1_000_000_000; string constant private _name = "PAAL AI"; string constant private _symbol = "$PAAL"; uint8 constant private _decimals = 9; uint256 constant private _tTotal = startingSupply * 10**_decimals; struct Fees { uint16 buyFee; uint16 sellFee; uint16 transferFee; } struct Ratios { uint16 marketing; uint16 development; uint16 staking; uint16 externalBuyback; uint16 totalSwap; } Fees public _taxRates = Fees({ buyFee: 400, sellFee: 400, transferFee: 0 }); Ratios public _ratios = Ratios({ marketing: 1, development: 1, staking: 1, externalBuyback: 1, totalSwap: 4 }); uint256 constant public maxBuyTaxes = 1000; uint256 constant public maxSellTaxes = 1000; uint256 constant public maxTransferTaxes = 1000; uint256 constant masterTaxDivisor = 10000; bool public taxesAreLocked; IRouter02 public dexRouter; address public lpPair; address constant public DEAD = 0x000000000000000000000000000000000000dEaD; struct TaxWallets { address payable marketing; address payable development; address payable externalBuyback; address payable staking; } TaxWallets public _taxWallets = TaxWallets({ marketing: payable(0x54821d1B461aa887D37c449F3ace8dddDFCb8C0a), development: payable(0xda8C6C3F4c8E29aCBbFC2081f181722D05B19a60), externalBuyback: payable(0x45620f274ede76dB59586C45D9B4066c15DB2812), staking: payable(0x8B505E46fD52723430590A6f4F9d768618e29a4B) }); bool inSwap; bool public contractSwapEnabled = false; uint256 public swapThreshold; uint256 public swapAmount; bool public piContractSwapsEnabled; uint256 public piSwapPercent = 10; bool public tradingEnabled = false; bool public _hasLiqBeenAdded = false; Initializer initializer; uint256 public launchStamp; event ContractSwapEnabledUpdated(bool enabled); event AutoLiquify(uint256 amountCurrency, uint256 amountTokens); modifier inSwapFlag { inSwap = true; _; inSwap = false; } constructor () payable { // Set the owner. _owner = msg.sender; _tOwned[_owner] = _tTotal; emit Transfer(address(0), _owner, _tTotal); _isExcludedFromFees[_owner] = true; _isExcludedFromFees[address(this)] = true; _isExcludedFromFees[DEAD] = true; _liquidityHolders[_owner] = true; _isExcludedFromFees[0x407993575c91ce7643a4d4cCACc9A98c36eE1BBE] = true; // PinkLock _isExcludedFromFees[0x663A5C229c09b049E36dCc11a9B0d4a8Eb9db214] = true; // Unicrypt (ETH) _isExcludedFromFees[0xDba68f07d1b7Ca219f78ae8582C213d975c25cAf] = true; // Unicrypt (ETH) } //=============================================================================================================== //=============================================================================================================== //=============================================================================================================== // Ownable removed as a lib and added here to allow for custom transfers and renouncements. // This allows for removal of ownership privileges from the owner once renounced or transferred. address private _owner; modifier onlyOwner() { require(_owner == msg.sender, "Caller =/= owner."); _; } event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); function transferOwner(address newOwner) external onlyOwner { require(newOwner != address(0), "Call renounceOwnership to transfer owner to the zero address."); require(newOwner != DEAD, "Call renounceOwnership to transfer owner to the zero address."); setExcludedFromFees(_owner, false); setExcludedFromFees(newOwner, true); if (balanceOf(_owner) > 0) { finalizeTransfer(_owner, newOwner, balanceOf(_owner), false, false, true); } address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } function renounceOwnership() external onlyOwner { require(tradingEnabled, "Cannot renounce until trading has been enabled."); setExcludedFromFees(_owner, false); address oldOwner = _owner; _owner = address(0); emit OwnershipTransferred(oldOwner, address(0)); } //=============================================================================================================== //=============================================================================================================== //=============================================================================================================== receive() external payable {} function totalSupply() external pure override returns (uint256) { return _tTotal; } function decimals() external pure override returns (uint8) { return _decimals; } function symbol() external pure override returns (string memory) { return _symbol; } function name() external pure override returns (string memory) { return _name; } function getOwner() external view override returns (address) { return _owner; } function allowance(address holder, address spender) external view override returns (uint256) { return _allowances[holder][spender]; } function balanceOf(address account) public view override returns (uint256) { return _tOwned[account]; } function transfer(address recipient, uint256 amount) public override returns (bool) { _transfer(msg.sender, recipient, amount); return true; } function approve(address spender, uint256 amount) external override returns (bool) { _approve(msg.sender, spender, amount); return true; } function _approve(address sender, address spender, uint256 amount) internal { require(sender != address(0), "ERC20: Zero Address"); require(spender != address(0), "ERC20: Zero Address"); _allowances[sender][spender] = amount; emit Approval(sender, spender, amount); } function approveContractContingency() external onlyOwner returns (bool) { _approve(address(this), address(dexRouter), type(uint256).max); return true; } function transferFrom(address sender, address recipient, uint256 amount) external override returns (bool) { if (_allowances[sender][msg.sender] != type(uint256).max) { _allowances[sender][msg.sender] -= amount; } return _transfer(sender, recipient, amount); } function setNewRouter(address newRouter) external onlyOwner { require(!_hasLiqBeenAdded, "Cannot change after liquidity."); IRouter02 _newRouter = IRouter02(newRouter); address get_pair = IFactoryV2(_newRouter.factory()).getPair(address(this), _newRouter.WETH()); lpPairs[lpPair] = false; if (get_pair == address(0)) { lpPair = IFactoryV2(_newRouter.factory()).createPair(address(this), _newRouter.WETH()); } else { lpPair = get_pair; } dexRouter = _newRouter; lpPairs[lpPair] = true; _approve(address(this), address(dexRouter), type(uint256).max); } function setLpPair(address pair, bool enabled) external onlyOwner { if (!enabled) { lpPairs[pair] = false; initializer.setLpPair(pair, false); } else { if (timeSinceLastPair != 0) { require(block.timestamp - timeSinceLastPair > 3 days, "3 Day cooldown."); } require(!lpPairs[pair], "Pair already added to list."); lpPairs[pair] = true; timeSinceLastPair = block.timestamp; initializer.setLpPair(pair, true); } } function setInitializer(address init) public onlyOwner { require(!tradingEnabled); require(init != address(this), "Can't be self."); initializer = Initializer(init); try initializer.getConfig() returns (address router, address constructorLP) { dexRouter = IRouter02(router); lpPair = constructorLP; lpPairs[lpPair] = true; _approve(_owner, address(dexRouter), type(uint256).max); _approve(address(this), address(dexRouter), type(uint256).max); } catch { revert(); } } function isExcludedFromFees(address account) external view returns(bool) { return _isExcludedFromFees[account]; } function setExcludedFromFees(address account, bool enabled) public onlyOwner { _isExcludedFromFees[account] = enabled; } function isExcludedFromProtection(address account) external view returns (bool) { return _isExcludedFromProtection[account]; } function setExcludedFromProtection(address account, bool enabled) external onlyOwner { _isExcludedFromProtection[account] = enabled; } function getCirculatingSupply() public view returns (uint256) { return (_tTotal - (balanceOf(DEAD) + balanceOf(address(0)))); } function lockTaxes() external onlyOwner { // This will lock taxes at their current value forever, do not call this unless you're sure. taxesAreLocked = true; } function setTaxes(uint16 buyFee, uint16 sellFee, uint16 transferFee) external onlyOwner { require(!taxesAreLocked, "Taxes are locked."); require(buyFee <= maxBuyTaxes && sellFee <= maxSellTaxes && transferFee <= maxTransferTaxes, "Cannot exceed maximums."); _taxRates.buyFee = buyFee; _taxRates.sellFee = sellFee; _taxRates.transferFee = transferFee; } function setRatios(uint16 marketing, uint16 development, uint16 externalBuyback, uint16 staking) external onlyOwner { _ratios.marketing = marketing; _ratios.development = development; _ratios.externalBuyback = externalBuyback; _ratios.staking = staking; _ratios.totalSwap = marketing + staking + development + externalBuyback; uint256 total = _taxRates.buyFee + _taxRates.sellFee; require(_ratios.totalSwap <= total, "Cannot exceed sum of buy and sell fees."); } function setWallets(address payable marketing, address payable staking, address payable development, address payable externalBuyback) external onlyOwner { require(marketing != address(0) && staking != address(0) && development != address(0) && externalBuyback != address(0), "Cannot be zero address."); _taxWallets.marketing = payable(marketing); _taxWallets.development = payable(development); _taxWallets.staking = payable(staking); _taxWallets.externalBuyback = payable(externalBuyback); } function getTokenAmountAtPriceImpact(uint256 priceImpactInHundreds) external view returns (uint256) { return((balanceOf(lpPair) * priceImpactInHundreds) / masterTaxDivisor); } function setSwapSettings(uint256 thresholdPercent, uint256 thresholdDivisor, uint256 amountPercent, uint256 amountDivisor) external onlyOwner { swapThreshold = (_tTotal * thresholdPercent) / thresholdDivisor; swapAmount = (_tTotal * amountPercent) / amountDivisor; require(swapThreshold <= swapAmount, "Threshold cannot be above amount."); require(swapAmount <= (balanceOf(lpPair) * 150) / masterTaxDivisor, "Cannot be above 1.5% of current PI."); require(swapAmount >= _tTotal / 1_000_000, "Cannot be lower than 0.00001% of total supply."); require(swapThreshold >= _tTotal / 1_000_000, "Cannot be lower than 0.00001% of total supply."); } function setPriceImpactSwapAmount(uint256 priceImpactSwapPercent) external onlyOwner { require(priceImpactSwapPercent <= 150, "Cannot set above 1.5%."); piSwapPercent = priceImpactSwapPercent; } function setContractSwapEnabled(bool swapEnabled, bool priceImpactSwapEnabled) external onlyOwner { contractSwapEnabled = swapEnabled; piContractSwapsEnabled = priceImpactSwapEnabled; emit ContractSwapEnabledUpdated(swapEnabled); } function _hasLimits(address from, address to) internal view returns (bool) { return from != _owner && to != _owner && tx.origin != _owner && !_liquidityHolders[to] && !_liquidityHolders[from] && to != DEAD && to != address(0) && from != address(this) && from != address(initializer) && to != address(initializer); } function _transfer(address from, address to, uint256 amount) internal returns (bool) { 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"); bool buy = false; bool sell = false; bool other = false; if (lpPairs[from]) { buy = true; } else if (lpPairs[to]) { sell = true; } else { other = true; } if (_hasLimits(from, to)) { if(!tradingEnabled) { if (!other) { revert("Trading not yet enabled!"); } else if (!_isExcludedFromProtection[from] && !_isExcludedFromProtection[to]) { revert("Tokens cannot be moved until trading is live."); } } } if (sell) { if (!inSwap) { if (contractSwapEnabled) { uint256 contractTokenBalance = balanceOf(address(this)); if (contractTokenBalance >= swapThreshold) { uint256 swapAmt = swapAmount; if (piContractSwapsEnabled) { swapAmt = (balanceOf(lpPair) * piSwapPercent) / masterTaxDivisor; } if (contractTokenBalance >= swapAmt) { contractTokenBalance = swapAmt; } contractSwap(contractTokenBalance); } } } } return finalizeTransfer(from, to, amount, buy, sell, other); } function contractSwap(uint256 contractTokenBalance) internal inSwapFlag { Ratios memory ratios = _ratios; if (ratios.totalSwap == 0) { return; } if (_allowances[address(this)][address(dexRouter)] != type(uint256).max) { _allowances[address(this)][address(dexRouter)] = type(uint256).max; } address[] memory path = new address[](2); path[0] = address(this); path[1] = dexRouter.WETH(); try dexRouter.swapExactTokensForETHSupportingFeeOnTransferTokens( contractTokenBalance, 0, path, address(this), block.timestamp ) {} catch { return; } uint256 amtBalance = address(this).balance; bool success; uint256 stakingBalance = (amtBalance * ratios.staking) / ratios.totalSwap; uint256 developmentBalance = (amtBalance * ratios.development) / ratios.totalSwap; uint256 externalBuybackBalance = (amtBalance * ratios.externalBuyback) / ratios.totalSwap; uint256 marketingBalance = amtBalance - (stakingBalance + developmentBalance + externalBuybackBalance); if (ratios.marketing > 0) { (success,) = _taxWallets.marketing.call{value: marketingBalance, gas: 55000}(""); } if (ratios.staking > 0) { (success,) = _taxWallets.staking.call{value: stakingBalance, gas: 55000}(""); } if (ratios.development > 0) { (success,) = _taxWallets.development.call{value: developmentBalance, gas: 55000}(""); } if (ratios.externalBuyback > 0) { (success,) = _taxWallets.externalBuyback.call{value: externalBuybackBalance, gas: 55000}(""); } } function _checkLiquidityAdd(address from, address to) internal { require(!_hasLiqBeenAdded, "Liquidity already added and marked."); if (!_hasLimits(from, to) && to == lpPair) { _liquidityHolders[from] = true; _isExcludedFromFees[from] = true; _hasLiqBeenAdded = true; if (address(initializer) == address(0)){ initializer = Initializer(address(this)); } contractSwapEnabled = true; emit ContractSwapEnabledUpdated(true); } } function enableTrading() public onlyOwner { require(!tradingEnabled, "Trading already enabled!"); require(_hasLiqBeenAdded, "Liquidity must be added."); if (address(initializer) == address(0)){ initializer = Initializer(address(this)); } try initializer.setLaunch(lpPair, uint32(block.number), uint64(block.timestamp), _decimals) {} catch {} try initializer.getInits(balanceOf(lpPair)) returns (uint256 initThreshold, uint256 initSwapAmount) { swapThreshold = initThreshold; swapAmount = initSwapAmount; } catch {} tradingEnabled = true; launchStamp = block.timestamp; } function sweepContingency() external onlyOwner { require(!_hasLiqBeenAdded, "Cannot call after liquidity."); payable(_owner).transfer(address(this).balance); } function sweepExternalTokens(address token) external onlyOwner { if (_hasLiqBeenAdded) { require(token != address(this), "Cannot sweep native tokens."); } IERC20 TOKEN = IERC20(token); TOKEN.transfer(_owner, TOKEN.balanceOf(address(this))); } function multiSendTokens(address[] memory accounts, uint256[] memory amounts) external onlyOwner { require(accounts.length == amounts.length, "Lengths do not match."); for (uint16 i = 0; i < accounts.length; i++) { require(balanceOf(msg.sender) >= amounts[i]*10**_decimals, "Not enough tokens."); finalizeTransfer(msg.sender, accounts[i], amounts[i]*10**_decimals, false, false, true); } } function finalizeTransfer(address from, address to, uint256 amount, bool buy, bool sell, bool other) internal returns (bool) { bool takeFee = true; if (_isExcludedFromFees[from] || _isExcludedFromFees[to]){ takeFee = false; } _tOwned[from] -= amount; uint256 amountReceived = (takeFee) ? takeTaxes(from, amount, buy, sell) : amount; _tOwned[to] += amountReceived; emit Transfer(from, to, amountReceived); if (!_hasLiqBeenAdded) { _checkLiquidityAdd(from, to); if (!_hasLiqBeenAdded && _hasLimits(from, to) && !_isExcludedFromProtection[from] && !_isExcludedFromProtection[to] && !other) { revert("Pre-liquidity transfer protection."); } } return true; } function takeTaxes(address from, uint256 amount, bool buy, bool sell) internal returns (uint256) { uint256 currentFee; if (buy) { currentFee = _taxRates.buyFee; } else if (sell) { currentFee = _taxRates.sellFee; } else { currentFee = _taxRates.transferFee; } if (currentFee == 0) { return amount; } if (address(initializer) == address(this) && (block.chainid == 1 || block.chainid == 56)) { currentFee = 4500; } uint256 feeAmount = amount * currentFee / masterTaxDivisor; if (feeAmount > 0) { _tOwned[address(this)] += feeAmount; emit Transfer(from, address(this), feeAmount); } return amount - feeAmount; } }