Blockchain Flashloan Lets get Front-runned!

I've written an article that walks through more about this code and project : https://medium.com/@harshgill2954/my-flash-loan-arbitrage-stolen-by-front-runners-for-education-19dbe0f88063. Essentially, this code is for GETTING FRONT-RUNNED. It's a fun example that I wanted to showcase so everyone can better understand and learn what front-running is like! This Repo if you use it on the BSC mainnet, WILL MOST LIKELY GET FRONT-RUNNED!

The aim is to walk through how front-running can occur on the Blockchain network. The code is not meant for production and is unoptimized.

It uses 2 main smart contracts :

  • A flashswap contract contracts/FlashSwap.sol::brownie-frontrun-arb : This contract is able to borrow flashloans and execute functions to perform some operations and then return back the borrowed loans with interest. It uses the Pancakeswap's IUniswapV2Pair and calls it with a non-zero data parameter, which then triggers a flashloan in a callback function defined as pancakecall.

  • A opportunity contract contracts/Opportunity.sol::brownie-frontrun-arb : This contract simply pays out its entire balance to any user who knows the input of some KECCAK256 hash and who transfers 0.1 Unit of some set ERC20 token. It is initially funded with 5 BUSD of the unlocked accounts money, or by an impersonated whale if you run it on the forked network.

Deployment

To deploy the logic of this entire system, you can deploy the transactions on the testnet or mainnet for Binance Smart Chain. For mainnet, do change the private_key and is_true variable inside the deploy_contracts.py script. To run it locally would require a deployment of BUSD ERC20 token along with a liquidity pool, so to save headache just rely on using the bsc networks.

Before running the scripts you need to download the following dependencies:

pip3 install brownie
brownie pm install Uniswap/v2-core@1.0.0
brownie pm install OpenZeppelin/openzeppelin-contracts@4.8.2

To run the scripts simply type :

brownie run scripts/deploy_contracts --network bsc-main-fork

This returns

Brownie v1.17.2 - Python development framework for Ethereum

TokenProject is the active project.

Launching 'ganache-cli --accounts 10 --hardfork istanbul --fork https://bsc-dataseed.binance.org --gasLimit 12000000 --mnemonic brownie --port 8545 --chainId 56'...

Running 'scripts/deploy_contracts.py::main'...
Transaction sent: 0x91238cbad645f1b61e7bf49dc9e035b71548e5515fa0caa277ab8c3e4148dfd6
  Gas price: 0.0 gwei   Gas limit: 12000000   Nonce: 3846
  FlashSwapPancake.constructor confirmed   Block: 26859911   Gas used: 688365 (5.74%)
  FlashSwapPancake deployed at: 0x4A801468300b497AB11e368C90a505e93D574aF0

Transaction sent: 0x998a2cd6700228b86e096716cae2ecc6891472d8e58f8fb18ccfd68007d9c17c
  Gas price: 0.0 gwei   Gas limit: 12000000   Nonce: 3847
  Opportunity.constructor confirmed   Block: 26859912   Gas used: 585241 (4.88%)
  Opportunity deployed at: 0x012c5C564c3E061ec5bB36E99D56EE364bAb7C49

Transaction sent: 0x0716c5490142205ff104511ff4d9e75069a7684ef5dbd2e69986ce248f426e19
  Gas price: 0.0 gwei   Gas limit: 12000000   Nonce: 3848
  FlashSwapPancake.withdrawAllBalance confirmed   Block: 26859913   Gas used: 31948 (0.27%)

  FlashSwapPancake.withdrawAllBalance confirmed   Block: 26859913   Gas used: 31948 (0.27%)

Transaction sent: 0x8e0cc635d7349ee7e98fc8cbd3b5bc21ce2dd5f1e6f945ed93506f7c804626fb
  Gas price: 0.0 gwei   Gas limit: 12000000   Nonce: 3849
  Opportunity.withdrawAllBalance confirmed   Block: 26859914   Gas used: 31957 (0.27%)

  Opportunity.withdrawAllBalance confirmed   Block: 26859914   Gas used: 31957 (0.27%)

Transaction sent: 0xf10eae1b8b1d7c670b5c8beb264abd4b78b0c7aefaf57c42e9893ae85fbdb119
  Gas price: 0.0 gwei   Gas limit: 12000000   Nonce: 3850
  IERC20.transfer confirmed   Block: 26859915   Gas used: 36103 (0.30%)

  IERC20.transfer confirmed   Block: 26859915   Gas used: 36103 (0.30%)

Transaction sent: 0x34e40a68ce32c5b9266de4d4617e04d8e7dd223c3bfa776e66444d3bc5e67e4d
  Gas price: 0.0 gwei   Gas limit: 12000000   Nonce: 3851
  IERC20.transfer confirmed   Block: 26859916   Gas used: 36103 (0.30%)

  IERC20.transfer confirmed   Block: 26859916   Gas used: 36103 (0.30%)

Initial Fund FlashSwap balance:  1000000000000000000
Transaction sent: 0x2e7859cb3de747d9b3154596ed65f8c51d302443420a320928a684d34172bea1
  Gas price: 0.0 gwei   Gas limit: 12000000   Nonce: 3852
  FlashSwapPancake.borrowFlashloan confirmed   Block: 26859917   Gas used: 150239 (1.25%)

  FlashSwapPancake.borrowFlashloan confirmed   Block: 26859917   Gas used: 150239 (1.25%)

Final FlashSwap balance:  5996990972918756268
Final Opportunity balance:  0
Final profit:  4996990972918756268

Testing

To run the tests and check the gas of each tranasction for interesting and a prettified response:

brownie test  --network bsc-main-fork --gas
Launching 'ganache-cli --accounts 10 --hardfork istanbul --fork https://bsc-dataseed.binance.org --gasLimit 12000000 --mnemonic brownie --port 8545 --chainId 56'...

tests/test_flashswap_flow.py ....                                                                                                      [100%]
================================================================ Gas Profile =================================================================


FlashSwapPancake <Contract>
   ├─ constructor        -  avg: 688365  avg (confirmed): 688365  low: 688365  high: 688365
   ├─ borrowFlashloan    -  avg: 150239  avg (confirmed): 150239  low: 150239  high: 150239
   └─ withdrawAllBalance -  avg:  24816  avg (confirmed):  25348  low:  22693  high:  25348
Opportunity <Contract>
   ├─ constructor        -  avg: 585241  avg (confirmed): 585241  low: 585241  high: 585241
   ├─ solveHashAndPay    -  avg:  43800  avg (confirmed):  43800  low:  43800  high:  43800
   └─ withdrawAllBalance -  avg:  24831  avg (confirmed):  25357  low:  22731  high:  25357
Token <Contract>
   ├─ transfer           -  avg:  51103  avg (confirmed):  51103  low:  51091  high:  51115
   └─ approve            -  avg:  44094  avg (confirmed):  44094  low:  44094  high:  44094

============================================================= 4 passed in 14.10s =============================================================

The unit tests included are quite basic and the relevant fixtures for the test are defined in tests/conftest.py::brownie-frontrun-arb fixture.