Code Monkey home page Code Monkey logo

repos1's People

Contributors

rydamez avatar

Stargazers

 avatar  avatar

Watchers

 avatar

repos1's Issues

Hash and nonce from litecoin

https://github.com/BusyMistake/litecoin/blob/master/contrib/pyminer/pyminer.py#L1-L251
#!/usr/bin/python

# Copyright (c) 2011 The Bitcoin developers
# Distributed under the MIT/X11 software license, see the accompanying
# file license.txt or http://www.opensource.org/licenses/mit-license.php.

import time
import json
import pprint
import hashlib
import struct
import re
import base64
import httplib
import sys
from multiprocessing import Process

ERR_SLEEP = 15
MAX_NONCE = 1000000L

settings = {}
pp = pprint.PrettyPrinter(indent=4)

class BitcoinRPC:
        OBJID = 1

        def init(self, host, port, username, password):
                authpair = "%s:%s" % (username, password)
                self.authhdr = "Basic %s" % (base64.b64encode(authpair))
                self.conn = httplib.HTTPConnection(host, port, False, 30)
        def rpc(self, method, params=None):
                self.OBJID += 1
                obj = { 'version' : '1.1',
                        'method' : method,
                        'id' : self.OBJID }
                if params is None:
                        obj['params'] = []
                else:
                        obj['params'] = params
                self.conn.request('POST', '/', json.dumps(obj),
                        { 'Authorization' : self.authhdr,
                          'Content-type' : 'application/json' })

                resp = self.conn.getresponse()
                if resp is None:
                        print "JSON-RPC: no response"
                        return None

                body = resp.read()
                resp_obj = json.loads(body)
                if resp_obj is None:
                        print "JSON-RPC: cannot JSON-decode body"
                        return None
                if 'error' in resp_obj and resp_obj['error'] != None:
                        return resp_obj['error']
                if 'result' not in resp_obj:
                        print "JSON-RPC: no result in object"
                        return None

                return resp_obj['result']
        def getblockcount(self):
                return self.rpc('getblockcount')
        def getwork(self, data=None):
                return self.rpc('getwork', data)

def uint32(x):
        return x & 0xffffffffL

def bytereverse(x):
        return uint32(( ((x) << 24) | (((x) << 8) & 0x00ff0000) |
                        (((x) >> 8) & 0x0000ff00) | ((x) >> 24) ))

def bufreverse(in_buf):
        out_words = []
        for i in range(0, len(in_buf), 4):
                word = struct.unpack('@i', in_buf[i:i+4])[0]
                out_words.append(struct.pack('@i', bytereverse(word)))
        return ''.join(out_words)

def wordreverse(in_buf):
        out_words = []
        for i in range(0, len(in_buf), 4):
                out_words.append(in_buf[i:i+4])
        out_words.reverse()
        return ''.join(out_words)

class Miner:
        def init(self, id):
                self.id = id
                self.max_nonce = MAX_NONCE

        def work(self, datastr, targetstr):
                # decode work data hex string to binary
                static_data = datastr.decode('hex')
                static_data = bufreverse(static_data)

                # the first 76b of 80b do not change
                blk_hdr = static_data[:76]

                # decode 256-bit target value
                targetbin = targetstr.decode('hex')
                targetbin = targetbin[::-1]        # byte-swap and dword-swap
                targetbin_str = targetbin.encode('hex')
                target = long(targetbin_str, 16)

                # pre-hash first 76b of block header
                static_hash = hashlib.sha256()
                static_hash.update(blk_hdr)

                for nonce in xrange(self.max_nonce):

                        # encode 32-bit nonce value
                        nonce_bin = struct.pack("<I", nonce)

                        # hash final 4b, the nonce value
                        hash1_o = static_hash.copy()
                        hash1_o.update(nonce_bin)
                        hash1 = hash1_o.digest()

                        # sha256 hash of sha256 hash
                        hash_o = hashlib.sha256()
                        hash_o.update(hash1)
                        hash = hash_o.digest()

                        # quick test for winning solution: high 32 bits zero?
                        if hash[-4:] != '\0\0\0\0':
                                continue

                        # convert binary hash to 256-bit Python long
                        hash = bufreverse(hash)
                        hash = wordreverse(hash)

                        hash_str = hash.encode('hex')
                        l = long(hash_str, 16)

                        # proof-of-work test:  hash < target
                        if l < target:
                                print time.asctime(), "PROOF-OF-WORK found: %064x" % (l,)
                                return (nonce + 1, nonce_bin)
                        else:
                                print time.asctime(), "PROOF-OF-WORK false positive %064x" % (l,)
#                                return (nonce + 1, nonce_bin)

                return (nonce + 1, None)

        def submit_work(self, rpc, original_data, nonce_bin):
                nonce_bin = bufreverse(nonce_bin)
                nonce = nonce_bin.encode('hex')
                solution = original_data[:152] + nonce + original_data[160:256]
                param_arr = [ solution ]
                result = rpc.getwork(param_arr)
                print time.asctime(), "--> Upstream RPC result:", result

        def iterate(self, rpc):
                work = rpc.getwork()
                if work is None:
                        time.sleep(ERR_SLEEP)
                        return
                if 'data' not in work or 'target' not in work:
                        time.sleep(ERR_SLEEP)
                        return

                time_start = time.time()

                (hashes_done, nonce_bin) = self.work(work['data'],
                                                     work['target'])

                time_end = time.time()
                time_diff = time_end - time_start

                self.max_nonce = long(
                        (hashes_done * settings['scantime']) / time_diff)
                if self.max_nonce > 0xfffffffaL:
                        self.max_nonce = 0xfffffffaL

                if settings['hashmeter']:
                        print "HashMeter(%d): %d hashes, %.2f Khash/sec" % (
                              self.id, hashes_done,
                              (hashes_done / 1000.0) / time_diff)

                if nonce_bin is not None:
                        self.submit_work(rpc, work['data'], nonce_bin)

        def loop(self):
                rpc = BitcoinRPC(settings['host'], settings['port'],
                                 settings['rpcuser'], settings['rpcpass'])
                if rpc is None:
                        return

                while True:
                        self.iterate(rpc)

def miner_thread(id):
        miner = Miner(id)
        miner.loop()

if name == 'main':
        if len(sys.argv) != 2:
                print "Usage: pyminer.py CONFIG-FILE"
                sys.exit(1)

        f = open(sys.argv[1])
        for line in f:
                # skip comment lines
                m = re.search('^\s*#', line)
                if m:
                        continue

                # parse key=value lines
                m = re.search('^(\w+)\s*=\s*(\S.*)$', line)
                if m is None:
                        continue
                settings[m.group(1)] = m.group(2)
        f.close()

        if 'host' not in settings:
                settings['host'] = '127.0.0.1'
        if 'port' not in settings:
                settings['port'] = 8332
        if 'threads' not in settings:
                settings['threads'] = 1
        if 'hashmeter' not in settings:
                settings['hashmeter'] = 0
        if 'scantime' not in settings:
                settings['scantime'] = 30L
        if 'rpcuser' not in settings or 'rpcpass' not in settings:
                print "Missing username and/or password in cfg file"
                sys.exit(1)

        settings['port'] = int(settings['port'])
        settings['threads'] = int(settings['threads'])
        settings['hashmeter'] = int(settings['hashmeter'])
        settings['scantime'] = long(settings['scantime'])

        thr_list = []
        for thr_id in range(settings['threads']):
                p = Process(target=miner_thread, args=(thr_id,))
                p.start()
                thr_list.append(p)
                time.sleep(1)                        # stagger threads

        print settings['threads'], "mining threads started"

        print time.asctime(), "Miner Starts - %s:%s" % (settings['host'], settings['port'])
        try:
                for thr_proc in thr_list:
                        thr_proc.join()
        except KeyboardInterrupt:
                pass
        print time.asctime(), "Miner Stops - %s:%s" % (settings['host'], settings['port'])

Pangolindex

​// SPDX-License-Identifier: MIT

​pragma solidity​ ​0.8.13​;

​import​ ​"@openzeppelin/contracts/access/AccessControl.sol"​;
​import​ ​"@openzeppelin/contracts/security/Pausable.sol"​;
​import​ ​"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"​;

​interface​ ​IPangolinPair​ {
​    ​function​ token0​() ​external​ ​view​ ​returns​ (​address​);
​    ​function​ token1​() ​external​ ​view​ ​returns​ (​address​);
​    ​function​ burn​(​address​ ​to​) ​external​ ​returns​ (​uint​ ​amount0​, ​uint​ ​amount1​);
​    ​function​ swap​(​uint​ ​amount0Out​, ​uint​ ​amount1Out​, ​address​ ​to​, ​bytes​ ​calldata​ ​data​) ​external​;
​    ​function​ getReserves​() ​external​ ​view​ ​returns​ (​uint112​ ​reserve0​, ​uint112​ ​reserve1​, ​uint32​ ​blockTimestampLast​);
​    ​function​ balanceOf​(​address​ ​owner​) ​external​ ​view​ ​returns​ (​uint​);
​}

​interface​ ​IMiniChef​ {
​    ​function​ harvest​(​uint256​ ​pid​, ​address​ ​to​) ​external​;
​}

​interface​ ​IStakingRewards​ {
​    ​function​ rewardsToken​() ​external​ ​view​ ​returns​ (​address​);
​    ​function​ notifyRewardAmount​(​uint256​ ​reward​) ​external​;
​    ​function​ setRewardsDuration​(​uint256​ ​_rewardsDuration​) ​external​;
​    ​function​ transferOwnership​(​address​ ​newOwner​) ​external​;
​}

​contract​ ​FeeCollector​ ​is​ ​AccessControl​, ​Pausable​ {

​    ​using​ SafeERC20​ ​for​ IERC20;

​    ​address​ ​public​ ​immutable​ FACTORY;
​    ​bytes32​ ​public​ ​immutable​ PAIR_INIT_HASH; ​// Specified as hex
​    ​address​ ​public​ ​immutable​ WRAPPED_TOKEN;

​    ​bytes32​ ​public constant ​HARVEST_ROLE ​=​ ​keccak256​(​"HARVEST_ROLE"​);
​    ​bytes32​ ​public constant ​PAUSE_ROLE ​=​ ​keccak256​(​"PAUSE_ROLE"​);
​    ​bytes32​ ​public constant ​RECOVERY_ROLE ​=​ ​keccak256​(​"RECOVERY_ROLE"​);
​    ​bytes32​ ​public constant ​GOVERNOR_ROLE ​=​ ​keccak256​(​"GOVERNOR_ROLE"​);

​    ​uint256​ ​public constant ​FEE_DENOMINATOR ​=​ ​10_000​;
​    ​uint256​ ​public constant ​MAX_HARVEST_INCENTIVE ​=​ ​200​; ​// 2%

​    ​address​ ​public​ stakingRewards;
​    ​address​ ​public​ stakingRewardsRewardToken;

​    ​address​ ​public​ treasury;
​    ​uint256​ ​public ​treasuryFee ​=​ ​1500​; ​// 15%
​    ​uint256​ ​public ​harvestIncentive ​=​ ​10​; ​// 0.1%

​    ​address​ ​public​ miniChef;
​    ​uint256​ ​public​ miniChefPoolId;

​    ​mapping​(​address​ ​=>​ ​bool​) ​public​ isRecoverable;

​    ​constructor​(
​        ​address​ ​_wrappedToken​,
​        ​address​ ​_factory​,
​        ​bytes32​ ​_initHash​,
​        ​address​ ​_stakingRewards​,
​        ​address​ ​_miniChef​,
​        ​uint256​ ​_pid​,
​        ​address​ ​_treasury​,
​        ​address​ ​_governor​,
​        ​address​ ​_admin
​    ) {
​        WRAPPED_TOKEN ​=​ _wrappedToken;
​        FACTORY ​=​ _factory;
​        PAIR_INIT_HASH ​=​ _initHash;

​        ​require​(_stakingRewards ​!=​ ​address​(​0​), ​"Invalid address"​);
​        ​address​ _stakingRewardsRewardToken ​=​ ​IStakingRewards​(_stakingRewards).​rewardsToken​();
​        ​require​(_stakingRewardsRewardToken ​!=​ ​address​(​0​), ​"Invalid staking reward"​);
​        stakingRewards ​=​ _stakingRewards;
​        stakingRewardsRewardToken ​=​ _stakingRewardsRewardToken;

​        miniChef ​=​ _miniChef;
​        miniChefPoolId ​=​ _pid;
​        treasury ​=​ _treasury;

​        ​_grantRole​(DEFAULT_ADMIN_ROLE, _admin);
​        ​_grantRole​(HARVEST_ROLE, _admin);
​        ​_grantRole​(PAUSE_ROLE, _admin);
​        ​_grantRole​(RECOVERY_ROLE, _admin);
​        ​_setRoleAdmin​(RECOVERY_ROLE, RECOVERY_ROLE); ​// RECOVERY_ROLE is self-managed
​        ​_grantRole​(GOVERNOR_ROLE, _governor);
​        ​_setRoleAdmin​(GOVERNOR_ROLE, GOVERNOR_ROLE); ​// GOVERNOR_ROLE is self-managed
​    }

​    ​/// @notice Change staking rewards contract address
​    ​/// @param _stakingRewards - New contract address
​    ​function​ setRewardsContract​(​address​ ​_stakingRewards​) ​external​ ​onlyRole​(DEFAULT_ADMIN_ROLE) {
​        ​require​(_stakingRewards ​!=​ ​address​(​0​), ​"Invalid address"​);
​        ​address​ _stakingRewardsRewardToken ​=​ ​IStakingRewards​(_stakingRewards).​rewardsToken​();
​        ​require​(_stakingRewardsRewardToken ​!=​ ​address​(​0​), ​"Invalid staking reward"​);
​        stakingRewards ​=​ _stakingRewards;
​        stakingRewardsRewardToken ​=​ _stakingRewardsRewardToken;
​    }

​    ​/// @notice Change the percentage of each harvest that goes to the caller
​    ​/// @param _harvestIncentive - New incentive ratio in bips
​    ​function​ setHarvestIncentive​(​uint256​ ​_harvestIncentive​) ​external​ ​onlyRole​(DEFAULT_ADMIN_ROLE) {
​        ​require​(_harvestIncentive ​<=​ MAX_HARVEST_INCENTIVE, ​"Incentive too large"​);
​        ​require​(_harvestIncentive ​+​ treasuryFee ​<=​ FEE_DENOMINATOR, ​"Total fees must <= 100"​);
​        harvestIncentive ​=​ _harvestIncentive;
​    }

​    ​/// @notice Disable the harvest and recover functions
​    ​function​ pause​() ​external​ ​onlyRole​(PAUSE_ROLE) {
​        ​_pause​();
​    }

​    ​/// @notice Re-enable the harvest and recover functions
​    ​function​ unpause​() ​external​ ​onlyRole​(PAUSE_ROLE) {
​        ​_unpause​();
​    }

​    ​/// @notice Allows a liquidity token to be withdrawn fully without a buyback
​    ​/// @dev Intended for recovering LP involving a token with fees on transfer
​    ​function​ setRecoverable​(​address​ ​token​, ​bool​ ​allowed​) ​external​ ​onlyRole​(RECOVERY_ROLE) {
​        isRecoverable[token] ​=​ allowed;
​    }

​    ​/// @notice Change the percentage of each harvest that goes to the treasury
​    ​/// @param _treasuryFee - New ratio in bips
​    ​function​ setTreasuryFee​(​uint256​ ​_treasuryFee​) ​external​ ​onlyRole​(GOVERNOR_ROLE) {
​        ​require​(harvestIncentive ​+​ _treasuryFee ​<=​ FEE_DENOMINATOR, ​"Total fees must <= 100"​);
​        treasuryFee ​=​ _treasuryFee;
​    }

​    ​/// @notice Updates the recipient of treasury fees
​    ​/// @param _treasury - New treasury wallet
​    ​function​ setTreasury​(​address​ ​_treasury​) ​external​ ​onlyRole​(DEFAULT_ADMIN_ROLE) {
​        ​require​(_treasury ​!=​ ​address​(​0​));
​        treasury ​=​ _treasury;
​    }

​    ​/// @notice Sets the MiniChef address to collect rewards from
​    ​/// @param _miniChef - New MiniChef address
​    ​function​ setMiniChef​(​address​ ​_miniChef​) ​external​ ​onlyRole​(DEFAULT_ADMIN_ROLE) {
​        ​require​(_miniChef ​!=​ ​address​(​0​));
​        miniChef ​=​ _miniChef;
​    }

​    ​/// @notice Sets the MiniChef pool used to accumulate rewards from emissions
​    ​/// @param _pid - ID of the pool on MiniChef
​    ​function​ setMiniChefPool​(​uint256​ ​_pid​) ​external​ ​onlyRole​(DEFAULT_ADMIN_ROLE) {
​        miniChefPoolId ​=​ _pid;
​    }

​    ​/// @notice Proxy function to set reward duration on the staking contract
​    ​/// @param _rewardsDuration - the duration of the new period
​    ​function​ setRewardsDuration​(​uint256​ ​_rewardsDuration​) ​external​ ​onlyRole​(DEFAULT_ADMIN_ROLE) {
​        ​IStakingRewards​(stakingRewards).​setRewardsDuration​(_rewardsDuration);
​    }

​    ​/// @notice Proxy function to change ownership of the staking contract
​    ​/// @param _newOwner - address to transfer ownership to
​    ​function​ transferStakingOwnership​(​address​ ​_newOwner​) ​external​ ​onlyRole​(DEFAULT_ADMIN_ROLE) {
​        ​IStakingRewards​(stakingRewards).​transferOwnership​(_newOwner);
​    }

​    ​/// @notice Remove liquidity associated with a pair
​    ​/// @param pair - The pair from which to retrieve liquidity
​    ​/// @param balance - The amount to pull
​    ​/// @return token0 - token0 address of the pair
​    ​/// @return amount0 - Amount of token0 received via burn
​    ​/// @return token1 - token1 address of the pair
​    ​/// @return amount1 - Amount of token1 received via burn
​    ​function​ _pullLiquidity​(
​        ​address​ ​pair​,
​        ​uint256​ ​balance
​    ) ​private​ ​returns​ (
​        ​address​ ​token0​,
​        ​uint256​ ​amount0​,
​        ​address​ ​token1​,
​        ​uint256​ ​amount1
​    ) {
​        token0 ​=​ ​IPangolinPair​(pair).​token0​();
​        token1 ​=​ ​IPangolinPair​(pair).​token1​();

​        ​require​(​pairFor​(token0, token1) ​==​ pair, ​"Invalid pair"​);

​        ​IERC20​(pair).​safeTransfer​(pair, balance);
​        (amount0, amount1) ​=​ ​IPangolinPair​(pair).​burn​(​address​(​this​));
​    }

​    ​/// @notice Swap a token for the specified output token
​    ​/// @param token - address of the token to swap
​    ​/// @param amount - amount of the token to swap
​    ​/// @dev Swaps are executed directly against pairs with infinite slippage tolerance
​    ​function​ _swap​(​address​ ​token​, ​address​ ​outputToken​, ​uint256​ ​amount​) ​private​ {
​        ​if​ (token ​==​ WRAPPED_TOKEN ​||​ outputToken ​==​ WRAPPED_TOKEN) {
​            ​direct2Swap​(amount, token, outputToken);
​        } ​else​ {
​            ​direct3Swap​(amount, token, WRAPPED_TOKEN, outputToken);
​        }
​    }

​    ​/// @notice For a list of liquidity pairs, withdraws all liquidity and swaps it to a specified token
​    ​/// @param liquidityPairs - list of all the pairs to pull
​    ​/// @param outputToken - the token into which all liquidity will be swapped
​    ​function​ _convertLiquidity​(IPangolinPair[] ​memory​ ​liquidityPairs​, ​address​ ​outputToken​) ​private​ {
​        ​for​ (​uint256​ i; i ​<​ liquidityPairs.length; ​++​i) {
​            IPangolinPair liquidityPair ​=​ liquidityPairs[i];
​            ​uint256​ pglBalance ​=​ liquidityPair.​balanceOf​(​address​(​this​));
​            ​if​ (pglBalance ​>​ ​0​) {
​                (
​                    ​address​ ​token0​,
​                    ​uint256​ ​token0Pulled​,
​                    ​address​ ​token1​,
​                    ​uint256​ ​token1Pulled
​                ) ​=​ ​_pullLiquidity​(​address​(liquidityPair), pglBalance);
​                ​if​ (token0 ​!=​ outputToken) {
​                    ​_swap​(token0, outputToken, token0Pulled);
​                }
​                ​if​ (token1 ​!=​ outputToken) {
​                    ​_swap​(token1, outputToken, token1Pulled);
​                }
​            }
​        }
​    }

​    ​/// @notice - Converts all the LP tokens specified to the rewards token and
​    ​/// transfers it to the staking contract, treasury, and caller
​    ​/// @param liquidityPairs - list of all the pairs to harvest
​    ​/// @param claimMiniChef - whether to also harvest additional rewards accrued via MiniChef
​    ​/// @param minFinalBalance - required min png balance after the buybacks (slippage control)
​    ​function​ harvest​(
​        IPangolinPair[] ​calldata​ ​liquidityPairs​,
​        ​bool​ ​claimMiniChef​,
​        ​uint256​ ​minFinalBalance
​    ) ​external​ whenNotPaused ​onlyRole​(HARVEST_ROLE) {
​        ​address​ _stakingRewardsRewardToken ​=​ stakingRewardsRewardToken; ​// Gas savings

​        ​if​ (liquidityPairs.length ​>​ ​0​) {
​            ​_convertLiquidity​(liquidityPairs, _stakingRewardsRewardToken);
​        }

​        ​if​ (claimMiniChef) {
​            ​IMiniChef​(miniChef).​harvest​(miniChefPoolId, ​address​(​this​));
​        }

​        ​uint256​ finalBalance ​=​ ​IERC20​(_stakingRewardsRewardToken).​balanceOf​(​address​(​this​));
​        ​require​(finalBalance ​>=​ minFinalBalance, ​"High Slippage"​);

​        ​uint256​ _callIncentive ​=​ finalBalance ​​ harvestIncentive ​/​ FEE_DENOMINATOR;
​        ​uint256​ _treasuryFee ​=​ finalBalance ​
​ treasuryFee ​/​ FEE_DENOMINATOR;
​        ​uint256​ _totalRewards ​=​ finalBalance ​-​ _callIncentive ​-​ _treasuryFee;

​        ​if​ (_totalRewards ​>​ ​0​) {
​            ​address​ _stakingRewards ​=​ stakingRewards;
​            ​IERC20​(_stakingRewardsRewardToken).​safeTransfer​(_stakingRewards, _totalRewards);
​            ​IStakingRewards​(_stakingRewards).​notifyRewardAmount​(_totalRewards);
​        }
​        ​if​ (_treasuryFee ​>​ ​0​) {
​            ​IERC20​(_stakingRewardsRewardToken).​safeTransfer​(treasury, _treasuryFee);
​        }
​        ​if​ (_callIncentive ​>​ ​0​) {
​            ​IERC20​(_stakingRewardsRewardToken).​safeTransfer​(​msg​.​sender​, _callIncentive);
​        }
​    }

​    ​/// @notice Recovers LP tokens to the treasury. Requires LP is whitelisted by the RECOVERY_ROLE
​    ​/// @param liquidityPairs - list of all the pairs to recover
​    ​/// @dev Intended to recover LP involving a token with fees on transfer
​    ​function​ recoverLP​(​address​[] ​calldata​ ​liquidityPairs​) ​external​ whenNotPaused ​onlyRole​(DEFAULT_ADMIN_ROLE) {
​        ​address​ _treasury ​=​ treasury;
​        ​uint256​ len ​=​ liquidityPairs.length;
​        ​for​ (​uint256​ i; i ​<​ len; ​++​i) {
​            ​require​(isRecoverable[liquidityPairs[i]], ​"Cannot recover"​);
​            IERC20 liquidityPair ​=​ ​IERC20​(liquidityPairs[i]);
​            liquidityPair.​safeTransfer​(_treasury, liquidityPair.​balanceOf​(​address​(​this​)));
​        }
​    }

​    ​function​ direct2Swap​(​uint256​ ​amountIn​, ​address​ ​tokenA​, ​address​ ​tokenB​) ​internal​ {
​        ​address​ pairAB ​=​ ​pairFor​(tokenA, tokenB);

​        ​uint256​ amountOutAB ​=​ ​getAmountOut​(amountIn, pairAB, tokenA, tokenB);

​        ​IERC20​(tokenA).​safeTransfer​(pairAB, amountIn);

​        ​if​ (tokenA ​<​ tokenB) {
​            ​IPangolinPair​(pairAB).​swap​(​0​, amountOutAB, ​address​(​this​), ​new​ ​bytes​(​0​));
​        } ​else​ {
​            ​IPangolinPair​(pairAB).​swap​(amountOutAB, ​0​, ​address​(​this​), ​new​ ​bytes​(​0​));
​        }
​    }

​    ​function​ direct3Swap​(​uint256​ ​amountIn​, ​address​ ​tokenA​, ​address​ ​tokenB​, ​address​ ​tokenC​) ​internal​ {
​        ​address​ pairAB ​=​ ​pairFor​(tokenA, tokenB);
​        ​address​ pairBC ​=​ ​pairFor​(tokenB, tokenC);

​        ​uint256​ amountOutAB ​=​ ​getAmountOut​(amountIn, pairAB, tokenA, tokenB);
​        ​uint256​ amountOutBC ​=​ ​getAmountOut​(amountOutAB, pairBC, tokenB, tokenC);

​        ​IERC20​(tokenA).​safeTransfer​(pairAB, amountIn);

​        ​if​ (tokenA ​<​ tokenB) {
​            ​IPangolinPair​(pairAB).​swap​(​0​, amountOutAB, pairBC, ​new​ ​bytes​(​0​));
​        } ​else​ {
​            ​IPangolinPair​(pairAB).​swap​(amountOutAB, ​0​, pairBC, ​new​ ​bytes​(​0​));
​        }

​        ​if​ (tokenB ​<​ tokenC) {
​            ​IPangolinPair​(pairBC).​swap​(​0​, amountOutBC, ​address​(​this​), ​new​ ​bytes​(​0​));
​        } ​else​ {
​            ​IPangolinPair​(pairBC).​swap​(amountOutBC, ​0​, ​address​(​this​), ​new​ ​bytes​(​0​));
​        }
​    }

​    ​// Simplified from PangolinLibrary
​    ​// Combines PangolinLibrary.getAmountOut and PangolinLibrary.getReserves
​    ​function​ getAmountOut​(
​        ​uint256​ ​amountIn​,
​        ​address​ ​pair​,
​        ​address​ ​tokenA​,
​        ​address​ ​tokenB
​    ) ​internal​ ​view​ ​returns​ (​uint256​ ​amountOut​) {
​        (​uint256​ ​reserve0​, ​uint256​ ​reserve1​,) ​=​ ​IPangolinPair​(pair).​getReserves​();
​        (​uint256​ ​reserveIn​, ​uint256​ ​reserveOut​) ​=​ tokenA ​<​ tokenB ​?​ (reserve0, reserve1)​ : ​(reserve1, reserve0);

​        ​uint256​ amountInWithFee ​=​ amountIn ​​ ​997​;
​        ​uint256​ numerator ​=​ amountInWithFee ​
​ reserveOut;
​        ​uint256​ denominator ​=​ (reserveIn ​*​ ​1000​) ​+​ amountInWithFee;
​        amountOut ​=​ numerator ​/​ denominator;
​    }

​    ​// Migrated from PangolinLibrary
​    ​// calculates the CREATE2 address for a Pangolin pair without making any external calls
​    ​function​ pairFor​(​address​ ​tokenA​, ​address​ ​tokenB​) ​private​ ​view​ ​returns​ (​address​ ​pair​) {
​        (​address​ ​token0​, ​address​ ​token1​) ​=​ tokenA ​<​ tokenB ​?​ (tokenA, tokenB)​ : ​(tokenB, tokenA);
​        pair ​=​ ​address​(​uint160​(​uint256​(​keccak256​(​abi.encodePacked​(
​            ​hex​'ff'​,
​            FACTORY,
​            ​keccak256​(​abi.encodePacked​(token0, token1)),
​            PAIR_INIT_HASH
​        )))));
​    }
​}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.