# GAS WAR
# 检测到相同LP的pending，就增加gas，gas=别人的gas+1
# 如果gas大于maxprice ，就跳过。 maxprice = tradeTimes - 1e6
# 主角是 我的HASH 对方的HASH
# 我的HASH是唯一的，只能用一次，就丢弃
# 我的hash和对方hash的和是唯一的，只能用一次，就丢弃


from web3Tools import *
import sqlTools as  sql
#pending filter
id = w3.eth.filter('pending')
print(id.filter_id)
myTradeInfo = {}
botTradeIfno = {}
blockInfo = {}
initHsS = []
initBlockNumber = w3.eth.blockNumber
# 我的hash和对方hash的和 避免同一个hash 一直加手续费
hashUesdSum2 = []
gasUpHash = []
baseGasPrice = w3.eth.getBlock('pending').baseFeePerGas
while True:
    try:
        # 拉pending hash
        hsArry = id.get_new_entries()
        if len(initHsS) > 1e4:
            initHsS = []
        if hsArry:
            block = w3.eth.blockNumber
            if block!= initBlockNumber:
                # 如果区块更新了，就初始化某些变量
                # 因为区块变化了，交易内容就失效了
                #printTime(block)
                gasUpHash = []
                myTradeInfo = {}
                botTradeIfno = {}
                blockInfo = {}
                initBlockNumber = block
                baseGasPrice = w3.eth.getBlock('pending').baseFeePerGas
            # 从所有PENDING HASH中，找出 我的hash 和 与我相关的hash = 别人的hash
            for hsi in hsArry:
                hash = hsi.hex()
                if hash in initHsS:
                    continue
                initHsS.append(hash)

                try:
                    # 拉交易信息
                    x = (w3.eth.getTransaction(hsi))
                except BaseException as err:
                    continue

                input = x['input']
                nonce = x['nonce']  # 对比nonce
                fromAdd = x['from'].lower()
                function = input[:10]
                toAdd = str(x['to']).lower()
                hash = x['hash'].hex()
                value = x['value']
                gasLimit = int(x['gas'])
                if x['type'] == '0x2' :
                    gasPrice = baseGasPrice + x['maxPriorityFeePerGas']
                    if gasPrice > x['maxFeePerGas']:
                        gasPrice = x['maxFeePerGas']
                elif x['type'] == '0x0':
                    gasPrice = x['gasPrice']

                # 这里面的continue ，只是为了简单过滤，绝对和我无关的hash
                if function in swapFunction:
                    continue

                if gasPrice < baseGasPrice * 0.2:
                    continue

                if function in ddosFunction:
                    continue
                if len(input) > 64*64:
                    continue
                if len(input) < 73:
                    continue
                if hash in myTradeInfo:
                    continue

                if toAdd in ddosAddress:
                    continue

                if toAdd == v5Address.lower():
                    continue

                #找出我的hash
                if toAdd == v4Address.lower() :
                    # 大于1E6的是交易hash、
                    if gasLimit <= 1e6:
                        continue
                    if hash in myTradeInfo:
                        continue

                    myTradeInfo[hash] = {}
                    myTradeInfo[hash]['LP0'] = input[34:74]
                    myTradeInfo[hash]['LP1'] = input[34 + 64:74 + 64]
                    myTradeInfo[hash]['LP2'] = input[34 + 64 *2 :74 + 64 * 2 ]
                    myTradeInfo[hash]['fromAddress'] = fromAdd
                    myTradeInfo[hash]['toAddress'] = toAdd
                    myTradeInfo[hash]['gasPrice'] = gasPrice
                    myTradeInfo[hash]['nonce'] = nonce
                    myTradeInfo[hash]['gasMaxPrice'] = gasLimit - 1e6
                    myTradeInfo[hash]['gasLimit'] = gasLimit
                    #printTime(block, myTradeInfo[hash]['fromAddress'], 'nowGasPrice', gasPrice, 'maxGasPrice', myTradeInfo[hash]['gasMaxPrice'], myTradeInfo[hash])
                    myTradeInfo[hash]['inputData'] = input
                    continue

                # 经过所有能想到的过滤后，和过滤自己的hash后。剩下的hash，都要进行破解。
                #trade Info decode

                # traceCall 的目的是为了检查出，input里面没有LP信息的交易

                r = w3.debug.traceCall(fromAdd, toAdd, input, value, block)
                if not r:
                    printTime('err', fromAdd, toAdd, input, value, block)
                    continue
                if 'error' in r:
                    continue
                if 'calls' not in r:
                    continue

                tradeInfo = w3.debug.transferDecodeFromCalldata(r['calls'])
                # lp.swap ? 

                # [{
                #         'token': ,
                #         'from':,
                #         'to': ',
                #         'amount':)})]


                if tradeInfo:
                    # 判断进行了token交易或者转账两次
                    if len(tradeInfo) >= 2:
                        # 是否来来回交易
                        tokenAyyay = []
                        tradeLaihui = False
                        for tradeI in tradeInfo:
                            token = tradeI['token']
                            fromAdd = tradeI['from']
                            to = tradeI['to']

                            # 不管from to 是什么地址，都放入这里，就可以被后面检查出来。
                            input = input + to[2:]

                            if token not in tokenAyyay:
                                tokenAyyay.append(token)
                            for tradeII in tradeInfo:
                                fromAddI = tradeII['from']
                                toI = tradeII['to']
                                if fromAdd == toI or to == fromAddI:
                                    tradeLaihui = True
                                    break

                        # 有进出交易
                        if not tradeLaihui:
                            continue

                        # 是否有两个币交易过
                        if len(tokenAyyay) < 2:
                            continue
                        

     
                


                blockInfo[hash] = {}
                blockInfo[hash]['input'] = input
                blockInfo[hash]['nonce'] = nonce
                blockInfo[hash]['fromAddress'] = fromAdd
                blockInfo[hash]['toAddress'] = toAdd
                blockInfo[hash]['hash'] = hash
                blockInfo[hash]['value'] = value
                blockInfo[hash]['gasLimit'] = gasLimit
                blockInfo[hash]['gasPrice'] = gasPrice

            # 循环我的hash，我只用一次
            for myHash in myTradeInfo:
                # 如果HASH已经被加速了，就跳过
                if myHash in gasUpHash:
                    continue
                myGasPrice = myTradeInfo[myHash]['gasPrice']
                # 我的LP数组
                lpArray = []
                LP0 = myTradeInfo[myHash]['LP0']
                LP1 = myTradeInfo[myHash]['LP1']
                LP2 = myTradeInfo[myHash]['LP2']
                lpArray.append(LP0)
                lpArray.append(LP1)
                if LP2 != '0000000000000000000000000000000000000000':
                    lpArray.append(LP2)


                # 循环相关LP，相关用每一次
                for hashI in blockInfo:

                    if hashI in myTradeInfo:
                        continue

                    # 如果HASH已经被加速了，就跳过
                    if myHash in gasUpHash:
                        continue

                    # 只配对一次
                    sumValue = hex(int(myHash, 16) + int(hashI, 16))
                    if sumValue in hashUesdSum2:
                        continue
                    hashUesdSum2.append(sumValue)

                    input = blockInfo[hashI]['input']
                    gasPrice = blockInfo[hashI]['gasPrice']

                    for lpI in lpArray:
                        #找出是否相关，并不快。
                        if lpI in input:
                            # 如果对方gas 大于我的 maxPrice，就投降
                            if gasPrice / 1e9 > myTradeInfo[myHash]['gasMaxPrice']:
                                printTime(block, 'bei la bao', gasPrice/1e9, myTradeInfo[myHash]['gasMaxPrice'])
                                gasUpHash.append(myHash)
                                break

                            # 如果对方gas大于我，我就加gas
                            if gasPrice > myGasPrice:
                                printTime(block, 'Find  BOT', 'gasPrice', gasPrice/1e9, hashI)
                                maxGasPrice = gasPrice * 1.13
                                #只是geth的过滤，确定
                                if maxGasPrice < myGasPrice * 1.11:
                                    maxGasPrice = myGasPrice * 1.12
                                
                                printTime(block, 'gasPrice UP', myGasPrice/1e9, '>', maxGasPrice/1e9, '<', myTradeInfo[myHash]['gasMaxPrice'], myHash)
                                params = {}
                                try:
                                    params['method'] = 'sendAddress'
                                    params['params'] = {'nonce': myTradeInfo[myHash]['nonce'],
                                                        'fromAddress': myTradeInfo[myHash]['fromAddress'],
                                                        'toAddress': myTradeInfo[myHash]['toAddress'],
                                                        'inputData': myTradeInfo[myHash]['inputData'],
                                                        'gasPrice': maxGasPrice,
                                                        'gasLimit': myTradeInfo[myHash]['gasLimit']}

                                    hs = requests.post(url='http://127.0.0.1:410/operation', json=params).text
                                    if hs !='None':
                                        gasUpHash.append(myHash)
                                        printTime(block, 'https://www.oklink.com/en/ethw/tx/' + str(hs))
                                        #printTime(myTradeInfo[myHash])
                                        printTime('-' * 80)
                                        break

                                except BaseException as err:
                                    printTime('send err', err)
                                    printTime(myTradeInfo)
                                    hs = 'err seed'


        time.sleep(0.001)

    except BaseException as err:
        print(traceback.format_exc())
        print(err)
        time.sleep(10)
        try:
            id = w3.eth.filter('pending')
        except:
            time.sleep(10)
        continue
