For Developers
Last updated
Last updated
Objectives
The aim of this section is to equip developers, auditors, and technology enthusiasts with the necessary resources to explore, understand, and potentially build upon the existing infrastructure of WEbdEX. We hope this fosters a community of ongoing collaboration and innovation.
Contributions
We encourage the community to contribute improvements, suggest additional functionalities, or provide feedback on potential security issues. This is a collaborative effort to ensure that the WEbdEX platform remains at the forefront of DeFi technology, offering a robust, secure, and innovative environment.
Scripts are available directly in this section, viewable online or downloadable for study and local use. They are formatted for easy reading and accompanied by clear instructions for those wishing to implement or test the contracts in a local or test environment.
Security and Auditing
We reiterate the importance of continuous review and auditing, as security is paramount in smart contract development. The WEbdEX platform commits to maintaining high standards of security and transparency, inviting independent experts and the community to audit and verify our code.
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/access/Ownable.sol";
import "../utils/NFT.sol";
interface IWEbdEXPassV3 {
struct User {
bool passExpired;
bool haveFreeTrial;
uint256 expirationTime;
}
function getUserInfoByWallet(
address to
) external view returns (User memory);
}
contract WEbdEXManagerV3 is Ownable {
Bot public bot;
IWEbdEXPassV3 public webDexPassV3;
Register[] internal registers;
address public webDexStrategiesV3;
mapping(address => User) internal users;
struct User {
address manager;
bool status;
}
struct Bot {
string name;
address token;
address wallet;
address seller;
}
struct Register {
address wallet;
address manager;
}
struct Display {
address wallet;
address manager;
bool status;
bool passExpired;
bool haveFreeTrial;
uint256 expirationTime;
}
event Transaction(
address indexed from,
string method,
uint256 timeStamp,
address to,
uint256 value
);
constructor(
string memory name_,
string memory symbol_,
address wallet_,
IWEbdEXPassV3 webDexPassV3_,
address seller_
) {
bot = Bot(
name_,
address(
new NFT(string(abi.encodePacked(name_, " Affiliated")), symbol_)
),
wallet_,
seller_
);
webDexPassV3 = webDexPassV3_;
}
modifier onlyWebDexStrategiesOrOwner() {
require(
msg.sender == webDexStrategiesV3 ||
(msg.sender == owner() && webDexStrategiesV3 != address(0)),
"You must own the contract or the WebDexStrategies"
);
_;
}
function changeWEbdEXStrategiesV3(
address newWebDexStrategiesV3
) public onlyOwner {
webDexStrategiesV3 = newWebDexStrategiesV3;
}
function registerInBot(address manager) public {
if (manager != address(0)) {
require(users[manager].status, "Unregistered manager");
}
require(!users[msg.sender].status, "User already registered");
users[msg.sender].manager = manager;
users[msg.sender].status = true;
NFT(bot.token).safeMint(msg.sender);
registers.push(Register(msg.sender, manager));
emit Transaction(
msg.sender,
manager == address(0)
? "Register In Bot With Manager"
: "Register In Bot",
block.timestamp,
address(this),
0
);
}
function getUserInfo() public view returns (Display memory) {
return _getUser(msg.sender);
}
function getUserInfoByWallet(
address to
) public view onlyWebDexStrategiesOrOwner returns (Display memory) {
return _getUser(to);
}
function getBot() public view returns (Bot memory) {
return bot;
}
function getRegisters() public view returns (Register[] memory) {
return registers;
}
function _getUser(address to) internal view returns (Display memory) {
IWEbdEXPassV3.User memory userInfo = webDexPassV3.getUserInfoByWallet(
to
);
return
Display(
to,
users[to].manager,
users[to].status,
userInfo.passExpired,
userInfo.haveFreeTrial,
userInfo.expirationTime
);
}
}
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
interface IWEbdEXStrategiesV3 {
function lpMint(
address to,
address coin,
uint256 amount
) external returns (address);
}
interface IWEbdEXNetworkPoolV3 {
function addBalance(
address to,
address coin,
uint256 amount,
address lpToken,
address user,
string memory method
) external;
}
contract WEbdEXPassV3 is Ownable {
ERC20 public erc20;
uint256 public monthlyPassValue;
uint256 public quarterlyPassValue;
uint256 public semesterPassValue;
uint256 public annualPassValue;
uint256 internal constant monthlyExpirationTime = 30 days;
uint256 internal constant quarterlyExpirationTime = 90 days;
uint256 internal constant semesterExpirationTime = 180 days;
uint256 internal constant annualExpirationTime = 365 days;
uint256 public freeTrialExpirationTime;
mapping(address => uint256) internal expirationTimes;
mapping(address => uint256) internal freeTrials;
enum PassType {
MONTHLY,
QUARTERLY,
SEMESTER,
ANNUAL
}
struct User {
bool passExpired;
bool haveFreeTrial;
uint256 expirationTime;
}
event PayFee(address indexed wallet, address indexed coin, uint256 amount);
event ExtractLogs(
address indexed from,
string method,
uint256 timeStamp,
address to,
uint256 value
);
event PayPass(address indexed from, address coin, uint256 value);
struct NetworkData {
address wallet;
uint256 amount;
}
struct PayFeesAmount {
NetworkData[] network;
uint256 seller;
uint256 bot;
uint256 manager;
address token;
address user;
string transaction;
}
struct PayComissions {
PayFeesAmount list;
address seller;
address bot;
address manager;
IWEbdEXStrategiesV3 webDexStrategiesV3;
IWEbdEXNetworkPoolV3 webDexNetworkPoolV3;
}
mapping(string => bool) private listPayments;
mapping(address => bool) private privilegedWallets;
constructor(
ERC20 erc20_,
uint256 monthlyPassValue_,
uint256 quarterlyPassValue_,
uint256 semesterPassValue_,
uint256 annualPassValue_,
uint256 freeTrialExpirationTime_
) {
erc20 = erc20_;
monthlyPassValue = monthlyPassValue_;
quarterlyPassValue = quarterlyPassValue_;
semesterPassValue = semesterPassValue_;
annualPassValue = annualPassValue_;
freeTrialExpirationTime = freeTrialExpirationTime_;
}
modifier onlyWalletPrivileged() {
require(
msg.sender == owner() || privilegedWallets[msg.sender],
"You must the owner or the privilegedWallets"
);
_;
}
modifier onlyHaveFreeTrial() {
require(
_haveFreeTrial(msg.sender),
// "Have you already used your free trial"
"Free trial is disabled"
);
_;
}
function comissionPass(PayComissions memory payments) public onlyOwner {
require(
!listPayments[payments.list.transaction],
"payment has already been made"
);
for (uint256 i = 0; i < payments.list.network.length; i++) {
_payFee(
payments.list.token,
payments.list.network[i].amount,
payments.list.network[i].wallet,
payments.list.user,
payments.webDexStrategiesV3,
payments.webDexNetworkPoolV3
);
}
_payFee(
payments.list.token,
payments.list.seller,
payments.seller,
payments.list.user,
payments.webDexStrategiesV3,
payments.webDexNetworkPoolV3
);
_payFee(
payments.list.token,
payments.list.bot,
payments.bot,
payments.list.user,
payments.webDexStrategiesV3,
payments.webDexNetworkPoolV3
);
_payFee(
payments.list.token,
payments.list.manager,
payments.manager,
payments.list.user,
payments.webDexStrategiesV3,
payments.webDexNetworkPoolV3
);
listPayments[payments.list.transaction] = true;
}
function _payFee(
address coin,
uint256 amount,
address to,
address user,
IWEbdEXStrategiesV3 webDexStrategiesV3,
IWEbdEXNetworkPoolV3 webDexNetworkPoolV3
) internal {
if (to != address(0) && amount > 0) {
erc20.transfer(address(webDexNetworkPoolV3), amount);
address lpToken = webDexStrategiesV3.lpMint(to, coin, amount);
webDexNetworkPoolV3.addBalance(
to,
coin,
amount,
lpToken,
user,
"Pay comission Pass"
);
emit PayFee(to, coin, amount);
}
}
function changeFreeTrialExpirationTime(
uint256 newExpirationTime
) public onlyWalletPrivileged {
require(newExpirationTime > 0, "The value must be greater than 0");
freeTrialExpirationTime = newExpirationTime;
emit ExtractLogs(
msg.sender,
"Change Free Trial Expiration Time",
block.timestamp,
address(erc20),
0
);
}
function changePassValue(
PassType passType,
uint256 value
) public onlyWalletPrivileged {
require(value > 0, "The value must be greater than 0");
if (passType == PassType.MONTHLY) {
monthlyPassValue = value;
} else if (passType == PassType.QUARTERLY) {
quarterlyPassValue = value;
} else if (passType == PassType.SEMESTER) {
semesterPassValue = value;
} else if (passType == PassType.ANNUAL) {
annualPassValue = value;
}
emit ExtractLogs(
msg.sender,
"Change Pass Value",
block.timestamp,
address(erc20),
0
);
}
function payPass(PassType passType) public {
uint256 passValue;
uint256 expirationTime;
if (passType == PassType.MONTHLY) {
passValue = monthlyPassValue;
expirationTime = monthlyExpirationTime;
} else if (passType == PassType.QUARTERLY) {
passValue = quarterlyPassValue;
expirationTime = quarterlyExpirationTime;
} else if (passType == PassType.SEMESTER) {
passValue = semesterPassValue;
expirationTime = semesterExpirationTime;
} else {
passValue = annualPassValue;
expirationTime = annualExpirationTime;
}
if (expirationTimes[msg.sender] == 0) {
expirationTimes[msg.sender] = block.timestamp + expirationTime;
} else {
expirationTimes[msg.sender] =
expirationTimes[msg.sender] +
expirationTime;
}
erc20.transferFrom(msg.sender, address(this), passValue);
emit ExtractLogs(
msg.sender,
"Pay Pass",
block.timestamp,
address(erc20),
passValue
);
emit PayPass(msg.sender, address(erc20), passValue);
}
function getFreeTrial() public onlyHaveFreeTrial {
if (expirationTimes[msg.sender] == 0) {
expirationTimes[msg.sender] =
block.timestamp +
freeTrialExpirationTime;
} else {
expirationTimes[msg.sender] =
expirationTimes[msg.sender] +
freeTrialExpirationTime;
}
++freeTrials[msg.sender];
emit ExtractLogs(
msg.sender,
"Get Free Trial",
block.timestamp,
address(erc20),
0
);
}
function sendPass(
PassType passType,
address to
) public onlyWalletPrivileged {
uint256 passValue;
uint256 expirationTime;
if (passType == PassType.MONTHLY) {
passValue = monthlyPassValue;
expirationTime = monthlyExpirationTime;
} else if (passType == PassType.QUARTERLY) {
passValue = quarterlyPassValue;
expirationTime = quarterlyExpirationTime;
} else if (passType == PassType.SEMESTER) {
passValue = semesterPassValue;
expirationTime = semesterExpirationTime;
} else {
passValue = annualPassValue;
expirationTime = annualExpirationTime;
}
expirationTimes[to] = block.timestamp + expirationTime;
emit ExtractLogs(
to,
"Send Pass",
block.timestamp,
address(erc20),
passValue
);
}
function addWalletPrivilege(address wallet) public onlyOwner {
privilegedWallets[wallet] = true;
}
function revokeWalletPrivilege(address wallet) public onlyOwner {
privilegedWallets[wallet] = false;
}
function getUserInfo() public view returns (User memory) {
return _getUserInfo(msg.sender);
}
function getUserInfoByWallet(address to) public view returns (User memory) {
return _getUserInfo(to);
}
function _getUserInfo(address to) internal view returns (User memory) {
return User(_passExpired(to), _haveFreeTrial(to), expirationTimes[to]);
}
function _passExpired(address to) internal view returns (bool) {
return block.timestamp >= expirationTimes[to];
}
// function _haveFreeTrial(address to) internal view returns (bool) {
// return freeTrials[to] == 0;
// }
function _haveFreeTrial(address to) internal pure returns (bool) {
address(to);
return false;
}
}
//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);
}
}
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
interface IWEbdEXStrategiesV3 {
function lpBurnFrom(address to, address coin, uint256 amount) external;
}
contract WEbdEXNetworkPoolV3 is Ownable {
address public webDexPaymentsV3;
address public webDexPass;
uint16 public fee_withdraw;
mapping(address => mapping(address => LPToken)) internal balances;
struct LPToken {
address coin;
uint256 balance;
}
event ExtractLogs(
address indexed from,
address indexed to,
string method,
uint256 timeStamp,
uint256 value,
uint256 fee,
address user
);
constructor(address webDexPaymentsV3_, address webDexPass_) {
webDexPaymentsV3 = webDexPaymentsV3_;
webDexPass = webDexPass_;
fee_withdraw = 5;
}
modifier onlyWebDexPaymentsOrWebDexPass() {
require(
msg.sender == webDexPaymentsV3 || msg.sender == webDexPass,
"You must the WebDexPayments or the webDexPass"
);
_;
}
function changeFeeWithdraw(uint16 amount) public onlyOwner {
require(
amount > 0 && amount <= 100,
"The value must be above 0 and below 100"
);
fee_withdraw = amount;
}
function addBalance(
address to,
address coin,
uint256 amount,
address lpToken,
address user,
string memory method
) external onlyWebDexPaymentsOrWebDexPass {
uint256 currentBalance = balances[to][lpToken].balance;
balances[to][lpToken] = LPToken(coin, currentBalance + amount);
emit ExtractLogs(to, coin, method, block.timestamp, amount, 0, user);
}
function withdraw(
address lpToken,
uint256 amount,
IWEbdEXStrategiesV3 webDexStrategiesV3
) public {
require(
amount <= balances[msg.sender][lpToken].balance,
"The amount must be less than or equal to the balance"
);
uint256 fee = (amount * fee_withdraw) / 100;
address coin = balances[msg.sender][lpToken].coin;
webDexStrategiesV3.lpBurnFrom(msg.sender, coin, amount);
ERC20(coin).transfer(msg.sender, amount - fee);
ERC20(coin).transfer(owner(), fee);
uint256 currentBalance = balances[msg.sender][lpToken].balance;
balances[msg.sender][lpToken] = LPToken(coin, currentBalance - amount);
emit ExtractLogs(
msg.sender,
coin,
"withdraw",
block.timestamp,
amount,
fee,
address(0)
);
}
function getBalance(address lpToken) public view returns (uint256) {
return _getBalance(msg.sender, lpToken);
}
function getBalanceByWallet(
address to,
address lpToken
) public view onlyOwner returns (uint256) {
return _getBalance(to, lpToken);
}
function _getBalance(
address to,
address lpToken
) internal view returns (uint256) {
return balances[to][lpToken].balance;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
// Interface Contract
interface IReveal {
function storeFactoryPlusBytes(address _owner, address _factory, bytes32 _byteCode) external;
}
// Interface WETH
interface IWETH {
function deposit() external payable;
function withdraw(uint) external;
}
// Interface UniswapV2
interface IUniswap {
function swapETHForExactTokens(uint, address[] calldata, address, uint) external payable;
function getAmountsOut(uint, address[] memory) external returns (uint[] memory);
}
// Inter
// Submarine Contract
contract Submarine {
// Store Owner
address payable private owner;
// Store Reveal Contract
address private revealContractAddr;
// Store Uniswap V3 Router
address constant uniswapRouterAddr = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
// Store WETH address
// Testnet 0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6
// Mainnet 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
address constant WETHAddr = 0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6;
// Contract constructor
constructor(address payable _owner, address _revealContract) payable {
owner = _owner;
revealContractAddr = _revealContract;
}
// Function to receive Ether. msg.data must be empty
receive() external payable {}
// Fallback function is called when msg.data is not empty
fallback() external payable {}
// Check is owner
function _checkOwner() private view {
require(msg.sender == owner, "Not called by owner");
}
// Get owner
function getOwner() external view returns (address) {
require(msg.sender == revealContractAddr, "Reveal contract only");
return owner;
}
// Perform Swap or Arbitrage
function performSwap(address _tokenSwap) external payable {
require(msg.sender == revealContractAddr, "Not allowed caller for swap");
//...perform swap
_executeTrade(_tokenSwap);
_destroy();
}
// Execute
function _executeTrade(address _tokenSwap) private {
// Define deadline
uint deadline = block.timestamp + 3000;
// Structure addresses
address[] memory addressPath = new address[](2);
addressPath[0] = WETHAddr;
addressPath[1] = _tokenSwap;
// Get amounts out
uint[] memory amountsOut = IUniswap(uniswapRouterAddr).getAmountsOut(address(this).balance, addressPath);
// Send Swap
IUniswap(uniswapRouterAddr).swapETHForExactTokens{ value: address(this).balance }(
amountsOut[1],
addressPath,
owner,
deadline
);
// Destroy Submarine Contract
_destroy();
}
// Destroy smart contract
function _destroy() public payable {
require(msg.sender == revealContractAddr, "Not allowed caller for destroy");
address payable addr = payable(address(owner));
selfdestruct(addr);
}
}
// Factory Contract
contract FactoryLive {
// Store Reveal Contract
address private revealContractAddr;
// Store Submarine Addresses
mapping(address => address) private submarines;
// Contract constructor
constructor(address _revealContract) payable {
revealContractAddr = _revealContract;
}
// Create Sub Contract
function createSubContract(bytes32 _salt, address payable _owner) public {
// Get byteCode for storing in the reveal contract
bytes32 byteCode = keccak256(abi.encodePacked(type(Submarine).creationCode, abi.encode(_owner, revealContractAddr)));
// Create Submarine Contract with Salt
Submarine sub = new Submarine{salt: _salt}(_owner, revealContractAddr);
// Create bytecode
// Owner, Factory, Bytes
IReveal(revealContractAddr).storeFactoryPlusBytes(_owner, address(this), byteCode);
// Store address
submarines[_owner] = address(sub);
}
// Get ByteCode
function _getByteCode (address _owner) private view returns (bytes memory) {
bytes memory bytecode = type(Submarine).creationCode;
return abi.encodePacked(bytecode, abi.encode(_owner, revealContractAddr));
}
// Get Stored Submarine Address
function getActualSubAddress() public view returns (address) {
return submarines[msg.sender];
}
// Get Submarine Address
function getPredictedSubAddress (bytes32 _salt, address _owner) public view returns (address) {
address predictedAddress = address(uint160(uint(keccak256(abi.encodePacked(
bytes1(0xff),
address(this),
_salt,
keccak256(abi.encodePacked(
type(Submarine).creationCode,
abi.encode(_owner, revealContractAddr)
))
)))));
return predictedAddress;
}
// Get Reveal Contract Address
function getRevealContractAddress () public view returns (address) {
return revealContractAddr;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
// Submarine swap
interface ISubmarine {
function getOwner() external view returns (address);
function performSwap(address _tokenSwap) external payable;
}
// Reveal Contract
contract Reveal {
// Store factory
mapping(address => address) private factories;
// Store byteCode
mapping(address => bytes32) private byteCodes;
// Store Factory Plus Bytes
function storeFactoryPlusBytes(address _owner, address _factory, bytes32 _byteCode) external {
factories[_owner] = _factory;
byteCodes[_owner] = _byteCode;
}
// Get Submarine address
function getSubmarineAddress(bytes32 _salt) public view returns (address) {
address factory = factories[msg.sender];
bytes32 byteCode = byteCodes[msg.sender];
address submarineAddress = address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), factory, _salt, byteCode)))));
return submarineAddress;
}
// Reveal Execution
function revealExecution(bytes32 _salt, address _tokenSwap) public {
address factory = factories[msg.sender];
bytes32 byteCode = byteCodes[msg.sender];
// Get predicted address
address submarineAddress = address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), factory, _salt, byteCode)))));
// Get submaine contract owner
address subOwner = ISubmarine(submarineAddress).getOwner();
// Ensure owner of submarine contract is also the message sender
require (subOwner == msg.sender, "Owner error");
// Perform swap
ISubmarine(submarineAddress).performSwap(_tokenSwap);
}
}