Skip to content

Commit

Permalink
feat: fix selling and add sell slippage
Browse files Browse the repository at this point in the history
  • Loading branch information
JayArrowz committed Sep 1, 2021
1 parent 4e367e1 commit 5eba183
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 26 deletions.
5 changes: 5 additions & 0 deletions Handlers/RugHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ private async Task<bool> CheckMinLiquidity(PairCreatedEvent pairCreatedEvent, st
{
var tokenAmountInPool = otherPairIdx == 1 ? reserves.Reserve1 : reserves.Reserve0;
var totalTokenAmount = await _bscWeb3.Eth.GetContract(_erc20Abi, pairCreatedEvent.Pair).GetFunction("totalSupply").CallAsync<BigInteger>();
if(totalTokenAmount == 0)
{
Serilog.Log.Logger.Error("Token {0} contract is giving a invalid supply", pairCreatedEvent.Pair);
return false;
}
var percentageInPool = new Fraction(tokenAmountInPool).Divide(totalTokenAmount).Multiply(100);
result = ((decimal)percentageInPool) > _sniperConfig.MinimumPercentageOfTokenInLiquidityPool;
Serilog.Log.Logger.Information("Token {0} Token Amount in Pool: {1} Total Supply: {2} Total Percentage in pool: {3}% Min Percentage Liquidity Check Status: {4}", pairCreatedEvent.Pair, tokenAmountInPool, totalTokenAmount, percentageInPool.ToDouble(), result);
Expand Down
50 changes: 31 additions & 19 deletions Handlers/TradeHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,31 +88,38 @@ public TokensOwned GetOwnedTokens(string tokenAddress)
return _ownedTokenList.FirstOrDefault(t => t.Address == tokenAddress);
}

public async Task<bool> Sell(string tokenAddress, int tokenIdx, BigInteger amount, BigInteger outAmount)
public async Task<bool> Approve(string tokenAddress)
{
try
{
var gas = new HexBigInteger(_sniperConfig.GasAmount);
var pairContract = _bscWeb3.Eth.GetContract(_pairAbi, tokenAddress);

var approveFunction = pairContract.GetFunction<ApproveFunction>();
var approve = await approveFunction.SendTransactionAndWaitForReceiptAsync(new ApproveFunction
{
Spender = _sniperConfig.PancakeswapRouterAddress,
Value = Max
}, _sniperConfig.WalletAddress, gas, new HexBigInteger(BigInteger.Zero));
}
catch (Exception e)
{
Serilog.Log.Logger.Warning("Could not approve sell for {0}", tokenAddress);
}
return true;
}

public async Task<bool> Sell(string tokenAddress, BigInteger amount, BigInteger outAmount, double slippage)
{
try
{
var sellFunction = _pancakeContract.GetFunction<SwapExactTokensForETHSupportingFeeOnTransferTokensFunction>();

var gas = new HexBigInteger(_sniperConfig.GasAmount);
var transactionAmount = new BigInteger((decimal)amount).ToHexBigInteger();
try
{
var approve = await approveFunction.SendTransactionAndWaitForReceiptAsync(new ApproveFunction
{
Spender = _sniperConfig.PancakeswapRouterAddress,
Value = Max
}, _sniperConfig.WalletAddress, gas, new HexBigInteger(BigInteger.Zero));
} catch(Exception e)
{
Serilog.Log.Logger.Warning("Could not approve sell for {0}", tokenAddress);
}

var txId = await sellFunction.SendTransactionAsync(new SwapExactTokensForETHSupportingFeeOnTransferTokensFunction
{
AmountOutMin = outAmount,
AmountOutMin = slippage == 0 ? outAmount : (new Fraction(outAmount).Subtract(new Fraction(slippage/100.0).Multiply(outAmount)).ToBigInteger()),
AmountIn = amount,
Path = new List<string>() { tokenAddress, _sniperConfig.LiquidityPairAddress },
To = _sniperConfig.WalletAddress,
Expand All @@ -139,15 +146,16 @@ public async Task<bool> Sell(string tokenAddress, int tokenIdx, BigInteger amoun
}
}

public async Task<BigInteger> GetMarketPrice(TokensOwned ownedToken)
public async Task<BigInteger> GetMarketPrice(TokensOwned ownedToken, BigInteger amount)
{
var price = await _rugChecker.GetReserves(ownedToken.PairAddress);
if(price.Reserve0 == 0 || price.Reserve1 == 0)
{
return BigInteger.Zero;
}
var pricePerLiquidityToken = ownedToken.TokenIdx == 1 ? new Fraction(price.Reserve1).Divide(price.Reserve0).ToDouble() : new Fraction(price.Reserve0).Divide(price.Reserve1).ToDouble();
return new Fraction(pricePerLiquidityToken).Multiply(ownedToken.Amount).ToBigInteger();
var pricePerLiquidityToken = ownedToken.TokenIdx == 1 ? new Fraction(price.Reserve0).Divide(price.Reserve1) : new Fraction(price.Reserve1).Divide(price.Reserve0);

return ((BigInteger)pricePerLiquidityToken.Multiply(amount));
}

public void Start()
Expand All @@ -167,16 +175,20 @@ private void MonitorPrices()
continue;
}
var price = _rugChecker.GetReserves(ownedToken.PairAddress).Result;
if(price.Reserve0 == 0 || price.Reserve1 == 0)
{
continue;
}
var pricePerLiquidityToken = ownedToken.TokenIdx == 1 ? new Fraction(price.Reserve1).Divide(price.Reserve0).ToDouble() : new Fraction(price.Reserve0).Divide(price.Reserve1).ToDouble();
var profitPerc = 100.0 - ((100.0 / ownedToken.SinglePrice) * pricePerLiquidityToken);
var profitPerc = ((100.0 / ownedToken.SinglePrice) * pricePerLiquidityToken) - 100.0;
Log.Logger.Information("Token: {0} Price bought: {1} Current Price: {2} Current Profit: {3}%",
ownedToken.Address, ownedToken.SinglePrice, pricePerLiquidityToken, profitPerc);

if (profitPerc > _sniperConfig.ProfitPercentageMargin)
{
try
{
ownedToken.FailedSell = !Sell(ownedToken.Address, ownedToken.TokenIdx, ownedToken.Amount, new Fraction(pricePerLiquidityToken).Multiply(ownedToken.Amount).ToBigInteger()).Result;
ownedToken.FailedSell = !Sell(ownedToken.Address, ownedToken.Amount - 1, GetMarketPrice(ownedToken, ownedToken.Amount - 1).Result, _sniperConfig.SellSlippage).Result;
} catch(Exception e)
{
Serilog.Log.Logger.Error(nameof(MonitorPrices), e);
Expand Down
1 change: 1 addition & 0 deletions Models/SniperConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ public class SniperConfiguration
public decimal MinimumPercentageOfTokenInLiquidityPool { get; set; }
public bool HoneypotCheck { get; set; }
public double HoneypotCheckAmount { get; set; }
public double SellSlippage { get; set; }
}
}
1 change: 1 addition & 0 deletions Models/SwapTokensForExactEthFunction.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Nethereum.ABI.FunctionEncoding.Attributes;
using Nethereum.Contracts;
using Nethereum.Util;
using System.Collections.Generic;
using System.Numerics;

Expand Down
10 changes: 6 additions & 4 deletions SniperService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Numerics;
using System.Threading;
using System.Threading.Tasks;

Expand Down Expand Up @@ -98,7 +99,7 @@ private async Task PairCreated(EventLog<PairCreatedEvent> pairCreated)
var otherTokenIdx = pair.Token0.Equals(_sniperConfig.LiquidityPairAddress, StringComparison.InvariantCultureIgnoreCase) ? 1 : 0;
var honeypotCheck = _sniperConfig.HoneypotCheck;

Log.Logger.Information("Discovered Token Pair {0} Rug check Result: {1}", symbol, rugCheckPassed);
Log.Logger.Information("Discovered Token Pair {0} Rug check Result: {1} Contract address: {2}", symbol, rugCheckPassed, otherPairAddress);
if (!rugCheckPassed)
{
Log.Logger.Warning("Rug Check failed for {0}", symbol);
Expand All @@ -119,12 +120,13 @@ private async Task PairCreated(EventLog<PairCreatedEvent> pairCreated)
return;
}
var ownedToken = _tradeHandler.GetOwnedTokens(otherPairAddress);
var marketPrice = await _tradeHandler.GetMarketPrice(ownedToken);
await _tradeHandler.Approve(otherPairAddress);
var marketPrice = await _tradeHandler.GetMarketPrice(ownedToken, ownedToken.Amount - 1);
var sellSuccess = false;

try
{
sellSuccess = await _tradeHandler.Sell(otherPairAddress, otherTokenIdx, ownedToken.Amount, marketPrice);
sellSuccess = await _tradeHandler.Sell(otherPairAddress, ownedToken.Amount - 1, marketPrice, _sniperConfig.SellSlippage);
} catch(Exception e)
{
Serilog.Log.Error("Error Sell", e);
Expand All @@ -135,7 +137,7 @@ private async Task PairCreated(EventLog<PairCreatedEvent> pairCreated)
return;
}

Log.Logger.Fatal("Honeypot check PASSED buying token: {0}", pair.Symbol);
Log.Logger.Information("Honeypot check PASSED buying token: {0}", pair.Symbol);
await _tradeHandler.Buy(otherPairAddress, otherTokenIdx, pair.Pair, _sniperConfig.AmountToSnipe);
}
catch (Exception e)
Expand Down
7 changes: 4 additions & 3 deletions appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,17 @@
"PancakeswapRouterAddress": "0x10ED43C718714eb63d5aA57B78B54704E256024E",
"ChainId": "56",
"AmountToSnipe": 0.0001,
"ProfitPercentageMargin": 10,
"ProfitPercentageMargin": 20,
"TransactionRevertTimeSeconds": 10000,
"GasAmount": 300000,
"BscHttpApi": "https://speedy-nodes-nyc.moralis.io/xxx/bsc/mainnet",
"BscNode": "wss://speedy-nodes-nyc.moralis.io/xxx/bsc/mainnet/ws",
"BscScanApiKey": "xxx",
"MinLiquidityAmount": 0.7,
"MinimumPercentageOfTokenInLiquidityPool": 95,
"MinLiquidityAmount": 0.5,
"MinimumPercentageOfTokenInLiquidityPool": 50,
"RugCheckEnabled": true,
"RenounceOwnershipCheck": true,
"SellSlippage": 0.5,
"ContractRugCheckStrings": [
"function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool)",
"function _approve(address owner, address spender, uint256 amount) internal",
Expand Down

0 comments on commit 5eba183

Please sign in to comment.