文件 1 的 7:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
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");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
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");
}
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");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 7:AggregatorV3Interface.sol
pragma solidity ^0.8.0;
interface AggregatorV3Interface {
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function version() external view returns (uint256);
function getRoundData(
uint80 _roundId
) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
function latestRoundData()
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}
文件 3 的 7:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 4 的 7:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, 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 from,
address to,
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);
}
文件 5 的 7:Injex.sol
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract Injex is Ownable {
using SafeERC20 for IERC20;
mapping(address => uint256) public injxBalances;
mapping(uint256 => uint256) public roundPrice;
mapping(uint256 => bool) public isRoundInProgress;
address public adminAddress;
address public devAddress;
address public ethUsdPriceFeed;
address public usdtUsdPriceFeed;
address public usdtAddress;
uint256 public currentRound;
uint256 public currentRoundEndTime;
uint256 public minUsdThreshold;
uint256 public totalInjxSold;
uint256 public maxInjxToSell;
uint256 public totalUsdAmount;
uint256 public devUsdTotalAmount;
event Buy(address indexed injxUserAddress, uint256 indexed amount);
error InsufficientUsdAmount(uint256 transfered, uint256 requiredMinimum);
error RoundIsNotInProgress();
error ExceededInjxMaxAmount();
error NotADev();
error ExceededMaxWithdrawal(uint256 expectedInUsd, uint256 devUsdAmount);
error DevAmountIsNotAZero();
constructor(
address _adminAddress,
address _devAddress,
address _ethUsdPriceFeed,
address _usdtUsdPriceFeed,
address _usdtAddress,
uint256 _minUsdThreshold,
uint256 _maxInjxToSell,
uint256 _devUsdTotalAmount
) Ownable() {
adminAddress = _adminAddress;
devAddress = _devAddress;
ethUsdPriceFeed = _ethUsdPriceFeed;
usdtUsdPriceFeed = _usdtUsdPriceFeed;
usdtAddress = _usdtAddress;
minUsdThreshold = _minUsdThreshold;
maxInjxToSell = _maxInjxToSell;
devUsdTotalAmount = _devUsdTotalAmount;
}
modifier isCurrentRoundInProgress() {
if (
!(block.timestamp < currentRoundEndTime &&
isRoundInProgress[currentRound])
) revert RoundIsNotInProgress();
_;
}
modifier isADev() {
if (msg.sender != devAddress) revert NotADev();
_;
}
function manageAdminAddress(address _newAdminAddress) external onlyOwner {
adminAddress = _newAdminAddress;
}
function manageDevAddress(address _newDevAddress) external isADev {
devAddress = _newDevAddress;
}
function clearTotalDevUsd() external isADev {
devUsdTotalAmount = 0;
}
function manageEthUsdPriceFeed(address _newEthUsdPriceFeed)
external
onlyOwner
{
ethUsdPriceFeed = _newEthUsdPriceFeed;
}
function manageUsdtUsdPriceFeed(address _newUsdtUsdPriceFeed)
external
onlyOwner
{
usdtUsdPriceFeed = _newUsdtUsdPriceFeed;
}
function manageUsdtAddress(address _newUsdtAddress) external onlyOwner {
usdtAddress = _newUsdtAddress;
}
function manageMinUsdThreshold(uint256 _newUsdThreshold)
external
onlyOwner
{
minUsdThreshold = _newUsdThreshold;
}
function manageMaxInjxToSell(uint256 _newAmount) external onlyOwner {
maxInjxToSell = _newAmount;
}
function newRound(uint256 _newRoundPrice, uint256 _roundEndTime)
external
onlyOwner
{
currentRound++;
roundPrice[currentRound] = _newRoundPrice;
currentRoundEndTime = _roundEndTime;
isRoundInProgress[currentRound] = true;
}
function stopRound() external onlyOwner isCurrentRoundInProgress {
isRoundInProgress[currentRound] = false;
}
function _withdraw(
uint256 _usdAmount,
bool _inEth,
address _recipient
) private {
uint256 currency;
if (_inEth) {
currency = uint256(getCurrency(ethUsdPriceFeed));
uint256 expectedTransferInEth = (_usdAmount * 10**26) / currency;
payable(_recipient).transfer(expectedTransferInEth);
} else {
currency = uint256(getCurrency(usdtUsdPriceFeed));
uint256 expectedTransferInUsdt = (_usdAmount * 10**14) / currency;
IERC20(usdtAddress).safeTransfer(
_recipient,
expectedTransferInUsdt
);
}
}
function withdrawDev(uint256 _usdAmount, bool _inEth) external isADev {
if (_usdAmount > devUsdTotalAmount)
revert ExceededMaxWithdrawal(_usdAmount, devUsdTotalAmount);
devUsdTotalAmount -= _usdAmount;
_withdraw(_usdAmount, _inEth, devAddress);
}
function withdrawOwner(uint256 _usdAmount, bool _inEth) external onlyOwner {
if (devUsdTotalAmount == 0) {
_withdraw(_usdAmount, _inEth, adminAddress);
} else {
revert DevAmountIsNotAZero();
}
}
function getCurrency(address _priceFeed) public view returns (int256) {
AggregatorV3Interface localDataFeed = AggregatorV3Interface(_priceFeed);
(, int256 currency, , , ) = localDataFeed.latestRoundData();
return currency;
}
function _setInjxAmount(
address _userInjxAddress,
address _priceFeed,
uint256 _amount
) internal returns (uint256) {
uint256 currency = uint256(getCurrency(_priceFeed));
uint256 usdAmount = currency * _amount;
if (usdAmount < minUsdThreshold)
revert InsufficientUsdAmount({
transfered: usdAmount,
requiredMinimum: minUsdThreshold
});
uint256 injxAmount = (usdAmount * 10**18) / roundPrice[currentRound];
if (totalInjxSold + injxAmount > maxInjxToSell)
revert ExceededInjxMaxAmount();
totalUsdAmount += usdAmount;
totalInjxSold += injxAmount;
injxBalances[_userInjxAddress] += injxAmount;
return injxAmount;
}
function buyInjxTokens(address _userInjxAddress)
external
payable
isCurrentRoundInProgress
{
uint256 injxAmount = _setInjxAmount(
_userInjxAddress,
ethUsdPriceFeed,
msg.value
);
emit Buy(_userInjxAddress, injxAmount);
}
function buyInjxTokens(address _userInjxAddress, uint256 _usdtAmount)
external
isCurrentRoundInProgress
{
uint256 formatDigits = _usdtAmount * 10**12;
IERC20(usdtAddress).safeTransferFrom(
msg.sender,
address(this),
_usdtAmount
);
uint256 injxAmount = _setInjxAmount(
_userInjxAddress,
usdtUsdPriceFeed,
formatDigits
);
emit Buy(_userInjxAddress, injxAmount);
}
}
文件 6 的 7:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_transferOwnership(_msgSender());
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 7 的 7:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
{
"compilationTarget": {
"contracts/Injex.sol": "Injex"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_adminAddress","type":"address"},{"internalType":"address","name":"_devAddress","type":"address"},{"internalType":"address","name":"_ethUsdPriceFeed","type":"address"},{"internalType":"address","name":"_usdtUsdPriceFeed","type":"address"},{"internalType":"address","name":"_usdtAddress","type":"address"},{"internalType":"uint256","name":"_minUsdThreshold","type":"uint256"},{"internalType":"uint256","name":"_maxInjxToSell","type":"uint256"},{"internalType":"uint256","name":"_devUsdTotalAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DevAmountIsNotAZero","type":"error"},{"inputs":[],"name":"ExceededInjxMaxAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"expectedInUsd","type":"uint256"},{"internalType":"uint256","name":"devUsdAmount","type":"uint256"}],"name":"ExceededMaxWithdrawal","type":"error"},{"inputs":[{"internalType":"uint256","name":"transfered","type":"uint256"},{"internalType":"uint256","name":"requiredMinimum","type":"uint256"}],"name":"InsufficientUsdAmount","type":"error"},{"inputs":[],"name":"NotADev","type":"error"},{"inputs":[],"name":"RoundIsNotInProgress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"injxUserAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Buy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"adminAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_userInjxAddress","type":"address"},{"internalType":"uint256","name":"_usdtAmount","type":"uint256"}],"name":"buyInjxTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_userInjxAddress","type":"address"}],"name":"buyInjxTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"clearTotalDevUsd","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentRound","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentRoundEndTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"devAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"devUsdTotalAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ethUsdPriceFeed","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_priceFeed","type":"address"}],"name":"getCurrency","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"injxBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"isRoundInProgress","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newAdminAddress","type":"address"}],"name":"manageAdminAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newDevAddress","type":"address"}],"name":"manageDevAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newEthUsdPriceFeed","type":"address"}],"name":"manageEthUsdPriceFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newAmount","type":"uint256"}],"name":"manageMaxInjxToSell","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newUsdThreshold","type":"uint256"}],"name":"manageMinUsdThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newUsdtAddress","type":"address"}],"name":"manageUsdtAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newUsdtUsdPriceFeed","type":"address"}],"name":"manageUsdtUsdPriceFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxInjxToSell","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minUsdThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newRoundPrice","type":"uint256"},{"internalType":"uint256","name":"_roundEndTime","type":"uint256"}],"name":"newRound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"roundPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stopRound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalInjxSold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalUsdAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"usdtAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"usdtUsdPriceFeed","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_usdAmount","type":"uint256"},{"internalType":"bool","name":"_inEth","type":"bool"}],"name":"withdrawDev","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_usdAmount","type":"uint256"},{"internalType":"bool","name":"_inEth","type":"bool"}],"name":"withdrawOwner","outputs":[],"stateMutability":"nonpayable","type":"function"}]