Copy //SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/access/Ownable.sol";
import "../utils/NFT.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "../utils/LPToken.sol";
interface IWEbdEXManagerV3 {
struct Bot {
string name;
address token;
address wallet;
address seller;
}
struct Display {
address wallet;
address manager;
bool status;
bool passExpired;
bool haveFreeTrial;
uint256 expirationTime;
}
function getUserInfoByWallet(
address to
) external view returns (Display memory);
function getBot() external view returns (Bot memory);
function owner() external view returns (address);
}
contract WEbdEXStrategiesV3 is Ownable {
Strategy[] internal strategies;
IWEbdEXManagerV3 public webDexManagerV3;
address public webDexPaymentsV3;
address public webDexNetworkPoolV3;
address public webDexPass;
mapping(address => bool) internal strategyExistsByToken;
mapping(string => bool) internal strategyExistsByName;
mapping(address => User) internal users;
mapping(address => Coin) internal listCoins;
struct User {
mapping(address => StrategyBalance) strategies;
address[] coins;
uint256 gasBalance;
}
struct StrategyBalance {
mapping(address => BalanceStrategy) balance;
}
struct BalanceStrategy {
uint256 amount;
address token;
uint256 decimals;
string ico;
string name;
bool status;
bool paused;
}
struct Display {
address wallet;
uint256 gasBalance;
UserDisplay[] strategies;
}
struct UserDisplay {
BalanceStrategy[] balance;
string strategy;
address strategyToken;
}
struct Coin {
bool status;
LPToken lp;
}
struct Strategy {
string name;
address token;
}
event ExtractLogs(
address indexed from,
string method,
uint256 timeStamp,
address to,
uint256 value
);
constructor(
IWEbdEXManagerV3 webDexManagerV3_,
address webDexPaymentsV3_,
address webDexNetworkPoolV3_,
address webDexPass_
) {
webDexManagerV3 = webDexManagerV3_;
webDexPaymentsV3 = webDexPaymentsV3_;
webDexNetworkPoolV3 = webDexNetworkPoolV3_;
webDexPass = webDexPass_;
}
modifier onlyWebDexPayments() {
require(msg.sender == webDexPaymentsV3, "You must the WebDexPayments");
_;
}
modifier onlyWebDexPaymentsOrWebDexPass() {
require(
msg.sender == webDexPaymentsV3 || msg.sender == webDexPass,
"You must the WebDexPayments or the webDexPass"
);
_;
}
modifier onlyWebDexNetworkPoolOrWebDexPayments() {
require(
msg.sender == webDexNetworkPoolV3 || msg.sender == webDexPaymentsV3,
"You must the WebDexNetworkPool or the WebDexPayments"
);
_;
}
modifier onlyBotWalletOrOwner() {
IWEbdEXManagerV3.Bot memory bot = webDexManagerV3.getBot();
require(
msg.sender == bot.wallet || msg.sender == owner(),
"You must own the contract or the bot"
);
_;
}
function changeWEbdEXPaymentsV3(
address newWebDexPaymentsV3
) public onlyOwner {
webDexPaymentsV3 = newWebDexPaymentsV3;
}
function addStrategy(
string memory name,
string memory symbol
) public onlyBotWalletOrOwner {
require(
!_strategyExistsByName(name),
"Name already in use in another strategy"
);
NFT newNFT = new NFT(name, symbol);
address tokenAddress = address(newNFT);
Strategy memory newStrategy = Strategy(name, tokenAddress);
strategies.push(newStrategy);
strategyExistsByToken[tokenAddress] = true;
strategyExistsByName[name] = true;
}
function addGasInBot() public payable {
IWEbdEXManagerV3.Display memory user = webDexManagerV3
.getUserInfoByWallet(msg.sender);
require(user.status, "Unregistered user");
require(msg.value >= 0, "Insufficient value");
users[msg.sender].gasBalance += msg.value;
emit ExtractLogs(
msg.sender,
"Add Gas In Bot",
block.timestamp,
address(0),
msg.value
);
}
function removeGasInBot(uint256 amount) public payable {
IWEbdEXManagerV3.Display memory user = webDexManagerV3
.getUserInfoByWallet(msg.sender);
require(user.status, "Unregistered user");
require(msg.value >= 0, "Insufficient value");
require(
users[msg.sender].gasBalance >= amount,
"Insufficient gas balance"
);
users[msg.sender].gasBalance -= amount;
payable(msg.sender).transfer(amount);
emit ExtractLogs(
msg.sender,
"Remove Gas In Bot",
block.timestamp,
address(0),
msg.value
);
}
function addLiquidyInStrategy(
address strategyToken,
uint256 amount,
address coin
) public {
IWEbdEXManagerV3.Display memory user = webDexManagerV3
.getUserInfoByWallet(msg.sender);
require(user.status, "Unregistered user");
require(_strategyExistsByToken(strategyToken), "Strategy not found");
require(coin != address(0), "Invalid contract address");
ERC20 erc20 = ERC20(coin);
if (!listCoins[coin].status) {
listCoins[coin] = Coin(
true,
new LPToken(
erc20.name(),
erc20.symbol(),
erc20.decimals(),
coin
)
);
}
erc20.transferFrom(msg.sender, address(this), amount);
_lpMint(msg.sender, coin, amount);
if (!users[msg.sender].strategies[strategyToken].balance[coin].status) {
users[msg.sender].strategies[strategyToken].balance[
coin
] = BalanceStrategy(
0,
coin,
erc20.decimals(),
erc20.symbol(),
erc20.name(),
true,
false
);
users[msg.sender].coins.push(coin);
}
users[msg.sender]
.strategies[strategyToken]
.balance[coin]
.amount += amount;
emit ExtractLogs(
msg.sender,
"Add Liquidy In Strategy",
block.timestamp,
coin,
amount
);
}
function removeLiquidyInStrategy(
address strategyToken,
uint256 amount,
address coin
) public {
require(
users[msg.sender].strategies[strategyToken].balance[coin].paused,
"You need to pause to remove liquidity"
);
require(_strategyExistsByToken(strategyToken), "Strategy not found");
require(listCoins[coin].status, "Invalid contract address");
require(
users[msg.sender].strategies[strategyToken].balance[coin].amount >=
amount,
"Insufficient funds"
);
listCoins[coin].lp.burnFrom(msg.sender, amount);
users[msg.sender]
.strategies[strategyToken]
.balance[coin]
.amount -= amount;
_erc20Transf(coin, msg.sender, amount);
emit ExtractLogs(
msg.sender,
"Remove Liquidy In Strategy",
block.timestamp,
coin,
amount
);
}
function changePaused(
address strategyToken,
address coin,
bool paused
) public {
IWEbdEXManagerV3.Display memory user = webDexManagerV3
.getUserInfoByWallet(msg.sender);
require(user.status, "Unregistered user");
require(_strategyExistsByToken(strategyToken), "Strategy not found");
require(coin != address(0), "Invalid contract address");
require(
paused !=
users[msg.sender]
.strategies[strategyToken]
.balance[coin]
.paused,
"The paused must be different"
);
users[msg.sender]
.strategies[strategyToken]
.balance[coin]
.paused = paused;
}
function getUserInfo() public view returns (Display memory) {
return _getUser(msg.sender);
}
function getUserInfoByWallet(
address to
) public view onlyOwner returns (Display memory) {
return _getUser(to);
}
function getStrategies() public view returns (Strategy[] memory) {
return strategies;
}
function getLpByCoin(address coin) public view returns (address) {
return address(listCoins[coin].lp);
}
function updateCoinBalanceAndGasBalance(
address to,
address strategyToken,
address coin,
int256 amount,
int256 gas
) external onlyWebDexPayments {
users[to].strategies[strategyToken].balance[coin].amount = uint256(
int256(users[to].strategies[strategyToken].balance[coin].amount) +
amount
);
users[to].gasBalance -= uint256(gas);
address owner = webDexManagerV3.owner();
payable(owner).transfer(uint256(gas));
emit ExtractLogs(
to,
"Discount gas operation",
block.timestamp,
address(0),
uint256(gas)
);
}
function lpMint(
address to,
address coin,
uint256 amount
) external onlyWebDexPaymentsOrWebDexPass returns (address) {
return _lpMint(to, coin, amount);
}
function lpBurnFrom(
address to,
address coin,
uint256 amount
) external onlyWebDexNetworkPoolOrWebDexPayments {
listCoins[coin].lp.burnFrom(to, amount);
}
function erc20Transf(
address coin,
address to,
uint256 amount
) external onlyWebDexPayments returns (bool) {
return _erc20Transf(coin, to, amount);
}
function _strategyExistsByName(
string memory name
) internal view returns (bool) {
return strategyExistsByName[name];
}
function _strategyExistsByToken(
address token
) internal view returns (bool) {
return strategyExistsByToken[token];
}
function _lpMint(
address to,
address coin,
uint256 amount
) internal returns (address) {
listCoins[coin].lp.mint(to, amount);
return address(listCoins[coin].lp);
}
function _erc20Transf(
address coin,
address to,
uint256 amount
) internal returns (bool) {
if (coin == address(0) || to == address(0) || amount == 0) {
return false;
}
return ERC20(coin).transfer(to, amount);
}
function _getUser(address to) internal view returns (Display memory) {
uint256 numCoins = users[to].coins.length;
UserDisplay[] memory strategy = new UserDisplay[](strategies.length);
for (uint256 i = 0; i < strategies.length; i++) {
address currentStrategyToken = strategies[i].token;
BalanceStrategy[] memory balances = new BalanceStrategy[](numCoins);
for (uint256 c = 0; c < numCoins; c++) {
address currentCoin = users[to].coins[c];
balances[c] = users[to]
.strategies[currentStrategyToken]
.balance[currentCoin];
}
strategy[i] = UserDisplay(
balances,
strategies[i].name,
currentStrategyToken
);
}
return Display(to, users[to].gasBalance, strategy);
}
}