Go up to the CCC HW page (md) | view tabbed version
In this assignment you are going to create a Python program to perform arbitrage trading on the blockchain. Your trading will be between a number of different DEX instances from the DEX (md) assignment. This program must be written in Python in a file called arbitrage_trading.py
. We provide a number of DEXes for you to use on the course blockchain.
Beyond general experience with programming Solidity (which you have at this point it the course), this assignment requires:
In addition to your source code, you will submit an edited version of arbitrage.py (src).
Any changes to this page will be put here for easy reference. Typo fixes and minor clarifications are not listed here.
You will need to read the introduction to web3.py (md). While you do not need to have all of that memorized, you do need to understand it all! The intent is that you will use that page as a reference while you write this assignment.
The following code will handle the connection based on the values in the arbitrage_config.py
file, which is introduced below. After reading this part, you may want to come back to it again once the arbitrage_config.py
file has been introduced.
from web3 import Web3
from web3.middleware import geth_poa_middleware
import arbitrage_config
if arbitrage_config.config['connection_is_ipc']:
w3 = Web3(Web3.IPCProvider(arbitrage_config.config['connection_uri']))
else:
w3 = Web3(Web3.WebsocketProvider(arbitrage_config.config['connection_uri']))
w3.middleware_onion.inject(geth_poa_middleware, layer=0)
print(w3.is_connected())
The code above will connect either through a local geth.ipc endpoint or a server’s wss://
connection based on the values in the arbitrage_config.py
file:
connection_is_ipc
value is True
, then the connection_uri
value will have the form /path/to/geth.ipc
connection_is_ipc
value is False
, then the connection_uri
value will have the form wss://server.univeristy.edu/path/to/geth
The value for the second one is provided on the Canvas landing page, and in the provided arbitrage_config.py
file.
Your program will need to compute it’s holdings, which is the dollar amount of all the ETH and TC that it has. You will use some fixed price for ETH (say, $100) and for TC (say, $10) for initial testing – this value is provided in the arbitrage_config.py
file, which is described below.
You will first need to obtain the various information (prices, x/y/k values at each DEX, etc.). Then you will need to make a profitable trade. A profitable trade is defined here as a trade where the overall value of holdings, in USD, increases. You must account for gas fees when determining this! The formula to determine if you will make a profit is whether:
ethAmountAfter * ethPrice + tcAmountAfter * tcPrice − gasFees > ethAmountBefore * ethPrice + tcAmountBefore * tcPrice
The gasFees is just the amount Ethereum charges for a transaction; DEX fees are not part of that value (the DEX pays out less, to the two amount-after variables will be less as a result, and thus will take DEX fees into account).
Note: there are other reasonable ways to determine “profit”. In particular, if one believes that the price of the currency will grow, then the total amount of that currency (not the total USD value) would be another metric. For our purposes, we will just use the USD value of the holdings.
This formula also accounts for the DEX fees (the amount after is lower as a result of those).
Although the price of our (fake) ether will vary, you don’t know if it will go up or down – thus, the value for ethPrice should be the current price, and thus will be the same on each side of the equation above.
We are going to call this a single trade. This is when you make one transaction at a single DEX to increase your holdings.
For each DEX, and for each of the two directions (ETH -> TC and TC -> ETH), find the (DEX,currency,amount) combination that maximizes your profit.
Consider the most profitable such transaction among all the available DEXes. If that transaction increases your holdings in USD, then take that action. It’s also possible that a double trade would yield a profit, where as a single trade would not (for example, exchanging some ETH for some TC in one DEX, and then trading that TC back for more ETH at a different DEX). We are not considering double trades for this assignment.
We can formulaically determine how much to trade. The full derivation of the formulas in this section is being omitted here, but you can see that full derivation here (md). First we need to define a number of variables:
The above values are all fixed for each time the program runs – either from the config file (described below) or by querying the DEXes. Different DEXes will have different values for xd, yd, and kd, of course. The only values that the program chooses are the amount of ETH that we trade in (we’ll call this δe) or the amount of TC that we trade in (we’ll call this δt). As we are only considering a single trade, only one of them will be non-zero.
The formulas that we need are (derivations here (md)):
For a single trade, want to find the maximum profit for the two hafter formulas for each DEX. We take the derivative, then set it equal to zero to find the roots (details here (md), if you are interested). The roots will give us the maximum and/or minimum points. This gives us:
A few notes on those:
Your assignment is to create a program that attempts to make a profit by arbitrage trading. For the purposes of this assignment, a profit means an increase in the value of your holdings in USD; the holdings are computed from the amount of ETH and TC your program controls as well as the current price of each.
You must take gas estimation into account! Otherwise, if you were only to make 0.001 ETH, but it costs 0.002 ETH in gas, you are losing money. How to estimate gas fees is discussed on the introduction to web3.py (md) page – once you create a transaction, you call eth.estimate_gas()
. The expected gas values will be in the tens of thousands of gwei – 36,000 to 65,000 is a reasonable guess, but yours may be higher or lower.
When providing a transaction, you also have to supply the gasPrice. For this assignment, you should use the value is in the arbitrage_config.py
file (described below), which will typically be set to 10 gwei. This gas estimate times the gas cost (10 gwei) will allow you to compute the cost of gas in ether, which is the g variable in the formulas above.
Your program must be in Python. It must be named arbitrage_trading.py
.
In practice, your program would listen for events from any of the DEXes, and any time the exchange rate of any of the DEXes changed, it would re-run the analysis. In order to make this assignment gradable, we are going to ignore events, and your program will consider all trade possibilities each time it is run.
Each DEX will have to be queried to get values for x, y, and k; from this, you can determine the exchange rate (y/x or x/y). You will also have to query the DEXes for the fee amount (feeNumerator()
and feeDenominator()
). Note that different DEXes, even for the same coin, can have different exchange rates and different fee amounts.
The program will import an arbitrage_config.py
file to provide many of the values, a sample of which is shown below. The correct file for this semester is available on the Canvas landing page.
config = {
# you will have to change these values for it to work
'account_address': '0x123456789ABcdEf0123456789aBCDeF123456789',
'account_private_key': hexbytes.HexBytes('0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'),
'connection_uri': '/path/to/geth.ipc',
'connection_is_ipc': True, # set to false if it's a ws:// connection
# once set, these should only be changed as necessary as you are testing your code
'price_eth': 100.00,
'price_tc': 10.0,
'max_eth_to_trade': 10.0,
'max_tc_to_trade': 100.0,
'gas_price': 10, # in gwei
# once set, you should not have to change these
'dex_addrs': [
'0x123456789abcdef0123456789abcdef123456789',
'0x123456789abcdef0123456789abcdef123456789',
'0x123456789abcdef0123456789abcdef123456789',
'0x123456789abcdef0123456789abcdef123456789',
'0x123456789abcdef0123456789abcdef123456789',
'0x123456789abcdef0123456789abcdef123456789'
],
'tokencc_addr': '0x123456789abcdef0123456789abcdef123456789',
'chainId': 12345678,
}
The output()
function, below, will also be in the arbitrage_config.py (src) file, a getTXNResult()
function for you to use, and the relevant ABIs.
You may assume that the arbitrage_config.py will always be present and properly structured, and that all values will be valid. The parts of the config
dictionary are:
account_address
: the address of your Ethereum account that this program is controlling – it is the balance that this account has, in both ETH and TC, that constitutes the holdings of this account. You are welcome to create a different account for this assignment – just be sure to use that account as the eth_coinbase
value when you submit the required arbitrage.py
file.account_private_key
: the (decrypted) private key for that account, used to initiate transactions; this must be in the exact format shown above
b'0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
– just copy the hex code (meaning without the leading b'
and trailing '
) into the HexBytes()
constructor to make it the same format as the code above.connection_is_ipc
: whether the connection URI (which is on the next line in this file) is a geth.ipc file or a URL – this will determine how the web3 provider is created
connection_uri
: how to connect to the blockchain – this will either be the path to a geth.ipc file or a URL to the course server; see the introduction to web3.py (md) for details – you either have to pass it to a Web3.IPCProvider()
call or a Web3.WebsocketProvider()
callprice_eth
: the current price of ETH, in USD, as a float – this is without all the extra decimal placesprice_tc
: the current price of TC, in USD, as a float – this is without all the extra decimal placesmax_eth_to_trade
: the maximum amount of ether to send for a given transaction. Your code needs to explicitly check this, otherwise you are going to trade your entire quota in one go (see below for quota issues). This is also meant to allow you to limit your trade to a reasonable value (say, 10 ether) rather than accidentally trading everything you have by mistake.max_tc_to_grade
: same as the previous, but for TCCgas_price
: the gas price, in gwei, of a single gas stepdex_addrs
: the smart contract addresses of the various DEX smart contracts; you can assume that there will be at least two in this listtokencc_addr
: the smart address of the TokenCC smart contractchainId
: the chainID for the course blockchainYou will need to edit some those values in arbitrage_config.py for your particular situation.
We provide a few other things in arbitrage_config.py: the ABI for IDEX and ITokenCC for you to use. We also provide a function called getTXNResult()
that will attempt to figure out what happened on a transaction function call (the return value or revert reason). You can see these in the arbitrage_config.py (src) file.
Your program will analyze the various values at the different DEXes, and make a change (or not). Your output must be in the exact format shown below. If no profitable trades are possible, then you should output No profitable arbitrage trades available
. If an trade is made, then the output should be of the exact form:
Exchanged -123.0000 ETH for 2.3400 TC; fees: 1.23 USD; prices: ETH 12.30 USD, TC: 1.23 USD; holdings: 34.30 USD
To ensure you output in the correct format, we provide a function that will print the appropriate lines in the required format. This function is also provided in the arbitrage_config.py (src) file.
def output(ethDelta, tccDelta, fees, holdings_after):
if ethDelta == 0 and tccDelta == 0:
print("No profitable arbitrage trades available")
return
assert ethDelta * tccDelta < 0, f"Exactly one of ethDelta {ethDelta} and tccDelta {tccDelta} should be negative, the other positive"
if ethDelta < 0:
print("Exchanged %.4f ETH for %.4f TC; fees: %.2f USD; prices: ETH %.2f USD, TC: %.2f USD; holdings: %.2f USD" %
(abs(ethDelta), abs(tccDelta), fees, config['price_eth'], config['price_tc'], holdings_after))
else:
print("Exchanged %.4f TC for %.4f ETH; fees: %.2f USD; prices: ETH %.2f USD, TC: %.2f USD; holdings: %.2f USD" %
(abs(tccDelta), abs(ethDelta), fees, config['price_eth'], config['price_tc'], holdings_after))
YOUR FINAL PROGRAM SHOULD PRODUCE NO OTHER OUTPUT other than the result of calling the output()
function, above.
If there are no profitable transactions available, then pass in 0 for the first two parameters; the values of the last two parameters do not matter in this case. When a transaction is made, then one of ethDelta
or tccDelta
should be negative – that’s the one that is being sold. The other should be positive, and is how much of the other you received for that exchange. These values should be the amount of coin being bought or sold as a floating-point number, and without all the decimals (so 1.5 TC rather than 15000000000 TC). The prices for ETH and TC are pulled from config
dictionary in arbitrage_config.py
, so they do not have to be passed into this function. The fees
and holdings_after
parameters should be in USD.
The fees
value that you are reporting is just the USD value of the Ethereum transaction fees. The DEX fees were deducted from the amount obtained.
To see if your program makes the right decision, you can hard-code the x, y, and k values in your arbitrage_trading.py program and print out the results to see if it computed the correct values to trade.
The geth-config.toml file that you used in the HW S4: Private Ethereum Blockchain (md) assignment opens up a web socket. Thus, you can connect in two ways:
ws://localhost:8546
; you have to set connection_is_ipc
to False
for thisconnection_is_ipc
to True
.Which one you use must be read from the arbitrage_config.py
file so that we can modify them when we test your submission.
To help you in your testing, we have deployed six DEXes that all trade the same coin, but at different rates. The coin is Dragon Dice Coin (DDC), whose image is shown to the right. The six different DEXes all trade at a fixed exchange rate (but still uses CPAMM!) – which means that multiple trades will not change their x, y, or k values. This is not realistic in a real-world situation, of course, but it is useful for testing. The six different DEXes have the icons of different sided dice, which correspond to their exchange rates:
Just to clarify: all six of these DEXes exchange the same DDC coin, but at different exchange rates. The individual dice images are used for the images of the DEXes; the multi-die image to the right is the image of the coin. The DEXes all follow the IDEX.sol (src) interface, and the DDC coin follows the ITokenCC.sol (src) interface.
IMPORTANT NOTE: These DEXes follow CPAMM, so the amount they give you will depend on the x, y, and k values that they report. Thus, you will not get exactly a 1:4 trade from the d4 DEX, but instead will get what a CPAMM trade will provide.
The addresses of all these DEXes, as well as DDC, are on the Canvas landing page and are provided in an arbitrage_config.py
file, which is available in Canvas’ Files.
The ITokenCC.sol (src) interface has a requestFunds()
function, which you just had revert in the dApp Tokens (md) assignment. For DDC, that function will pay you 100 DDC on each call. This will allow you to obtain DDC for use in your exchange testing.
Of course, you can also exchange ether for DDC with any of the DEXes to obtain DDC.
The problem with fixed exchange rates is that it is easy to deplete the DEX of funds – one could exchange 1 ETH for 20 TC via the D20 DEX, then back for 5 ETH via the D4 DEX, and repeat forever. This would deplete the reserves of the DEXes and also cause the blockchain size to balloon. It would also prevent other students from using the DEXes. For this reason, there are three limiters in effect for DDC and these DEXes:
block.timestamp()
behavior”). This time limit is for any DEX, so if you exchange with one DEX, you have to wait to exchange with any of the others.max_eth_to_trade
value in arbitrage_config.py
.These values can be changed by the course instructor, although that may take some time (i.e., it’s not instantaneous). However, you should use smaller amounts in your testing – don’t start by trading in a huge amount of ether, or all of your DDC, as this will cause you to hit your limits very quickly.
Keep in mind that the difficult part of this assignment is making the calculations. During testing you can have your code make those calculations, print out the result (and lots of intermediate values), but not make the actual trade on the blockchain. Once you think you have it working, then call the code to actually make the trade.
When you finally submit your solution, it should print out exactly one line, as described above, and make the trade.
Lastly, these DEXes have the ability to be “turned off” so that any attempt at a transaction will revert with an appropriate error message (either “trading not currently enabled” or “this DEX has been destructed”). In the former case, it will be turned on again soon. In the latter case, the DEXes were likely replaced – check the Canvas landing page for new DEX (and DDC) addresses.
The different DEX addresses are available from the Canvas landing page, in the arbitrage_config.py
file in Canvas’ Files. The intent is for you to comment out different DEXes in that file so that you can test it with different pairs. The version of arbitrage_config.py (src) in the github repo does not have the addresses of the six DEXes deployed on the course-wide blockchain, but the version linked to from the Canvas landing page does.
Let’s assume a standard price ratio of 1:10 (ETH:DDC). This means that the arbitrage_config.py file might have lines such as:
'price_eth': 100.00,
'price_tc': 10.0,
This is as is provided in the arbitrage_config.py file on the Canvas landing page. Furthermore, the provided file has the dex_addrs
list formatted as follows:
'dex_addrs': [
'0x123456789abcdef0123456789abcdef123456789', # d4 dex
'0x123456789abcdef0123456789abcdef123456789', # d6 dex
'0x123456789abcdef0123456789abcdef123456789', # d8 dex
'0x123456789abcdef0123456789abcdef123456789', # d10 dex
'0x123456789abcdef0123456789abcdef123456789', # d12 dex
'0x123456789abcdef0123456789abcdef123456789', # d20 dex
],
You can easily comment out different DEXes for your testing. The following three examples assume the prices listed above ($10 for DDC and $100 for ETH).
We assume that the prices in arbitrage_config.py
are set to the standard 100 for ether and 10 for TC. There are four specific examples below; these are the visible Gradescope submission tests. These examples were from an account that started with 11 ether, but was not allowed to trade for than 10 ether (as per the arbitrage_config.py
file).
Exchanged -10.0000 ETH for 180.9091 TC; fees: 0.11 USD; prices: ETH 100.00 USD, TC: 10.00 USD; holdings: 1908.87 USD
Exchanged -10.0000 ETH for 180.9091 TC; fees: 0.11 USD; prices: ETH 100.00 USD, TC: 10.00 USD; holdings: 2908.82 USD
Exchanged -100.0000 TC for 19.8988 ETH; fees: 0.12 USD; prices: ETH 100.00 USD, TC: 10.00 USD; holdings: 3089.75 USD
No profitable arbitrage trades available
Could you use this program in the real world with real ETH?
Well, sorta.
The concepts are the same. But you would have to make a few changes:
But the concepts are certainly the same!
chainId
value in each transaction that you call from Python – things don’t always work well otherwise. The sample transactions on the introduction to web3.py (md) page all have this value present. Be sure to set it to the correct value for the course blockchain!wss://
start of the URI), if you get an error such as: ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED]
, try running going into your application/python_3.11 directory (might be different on your machine) and running the “Install Certificates.command” script'status'
field of the transaction receipt (w3.eth.wait_for_transaction_receipt()
), and the provided getTXNResult()
function in the arbitrage_config.py file will return both the success (or failure) and, if it fails, the reversion message.w3.eth.estimate_gas()
. If that is causing problems, then the estimated gas amounts can be posted to Piazza. In either case, the actual gas used is not likely to be the exact amount as the estimate, so you will have to get the ether balance after the transaction.estimate_gas()
, make sure you call it on the unsigned version of the transaction, not the signed version.Below are some sample executions. Note that these runs print a lot of output so that you can understand what is going on. Your program should only print the one line via the output()
function.
For the execution runs, do not pay attention to the DEX addresses, as they will be different than what you are dealing with. Also, ignore the starting amount of ether or TCC – it is either sufficient for that transaction or zero, depending on the execution run.
If all DEXes are enabled, and the account has sufficient ether but no TCC, the following is an example execution run. In particular, given sufficient funds and the availability of the D20 DEX, it will always choose that to exchange.
Connected: True
Account: 0x15b6d9ACa8b6B09745653F36b193c612a824d16D
TokenCC decimals: 10
ETH balance: 601.1629454504019 with price: $100.0
TCC balance: 0.0 with price: $10.0
Holdings: 60,116.29 USD
DEX 0 @ 0x3270c4e2712a094773f360223268737b4f76d4db, symbol: D4C
k = 40000.0, x = 100.0, y = 400.0, f = 0.995
trading in TC minima/maxima: 0.00 minima/maxima is not positive, so ignoring
trading in TC minima/maxima: -1030.87 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: -36.91 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: -163.09 minima/maxima is not positive, so ignoring
DEX 1 @ 0x08942ee9050f1bfd446298e0a36c45b61df951a3, symbol: D6C
k = 60000.0, x = 100.0, y = 600.0, f = 0.995
trading in TC minima/maxima: 0.00 minima/maxima is not positive, so ignoring
trading in TC minima/maxima: -1372.66 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: -22.73 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: -177.27 minima/maxima is not positive, so ignoring
DEX 2 @ 0xb48cff2e10bab7a40eed8e795b47abe4031c2057, symbol: D8C
k = 80000.0, x = 100.0, y = 800.0, f = 0.995
trading in TC minima/maxima: 0.00 minima/maxima is not positive, so ignoring
trading in TC minima/maxima: -1692.19 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: -10.78 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: -189.22 minima/maxima is not positive, so ignoring
DEX 3 @ 0xd53a424d33d254d08dc88d86b7636423941805d7, symbol: D10C
k = 100000.0, x = 100.0, y = 1000.0, f = 0.995
trading in TC minima/maxima: -2.50 minima/maxima is not positive, so ignoring
trading in TC minima/maxima: -1997.50 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: -0.25 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: -199.75 minima/maxima is not positive, so ignoring
DEX 4 @ 0x897d3fb345ce0a3c54cbba807e7188a8ea1452bd, symbol: D12C
k = 120000.0, x = 100.0, y = 1200.0, f = 0.995
trading in TC minima/maxima: -107.30 minima/maxima is not positive, so ignoring
trading in TC minima/maxima: -2292.70 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: 9.27 ETH; holdings after: 60202.22 USD; difference: 85.93
trading in ETH minima/maxima: -209.27 minima/maxima is not positive, so ignoring
DEX 5 @ 0x6b2c410bd8c822e5e8ccebd27bf3af4c7cd8409c, symbol: D20C
k = 200000.0, x = 100.0, y = 2000.0, f = 0.995
trading in TC minima/maxima: -589.33 minima/maxima is not positive, so ignoring
trading in TC minima/maxima: -3410.67 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: 41.07 ETH; holdings after: 61802.81 USD; difference: 1686.52
trading in ETH minima/maxima: -241.07 minima/maxima is not positive, so ignoring
Best amount of 41.06735979665885 exceeds ETH max of 10.0
Best transaction: DEX # 5, trading in ETH: True, ETH transacted: 10.0, TCC transacted: 61802.81188570843
Trading in 10.0 ETH: 10000000000000000000 wei at DEX 0x6b2c410bd8c822e5e8ccebd27bf3af4c7cd8409c symbol D20C
Gas estimate (gwei): 124424
ETH & TCC before: 601.1629454504019 0.0
waiting for eth->tcc txn to be mined; txn 0x10c481d1a45aa9637ecf7cb943a40cc5219bf8b6c496c50b8c2e843549a4b8a0
The TXN was mined successfully
ETH & TCC after: 591.1617580804019 180.9090909092
Exchanged 10.0000 ETH for 180.9091 TC; fees: 0.12 USD; prices: ETH 100.00 USD, TC: 10.00 USD; holdings: 60925.27 USD
Final ETH balance: 591.1617580804019
Final TC balance: 180.9090909092
Holdings before: $60,116.29 USD
Holdings after: $60,925.27 USD
If only the lower three DEXes are available (D4, D6, and D8), and there is sufficient TCC, then the trade will be TCC -> ETH.
Connected: True
Account: 0x15b6d9ACa8b6B09745653F36b193c612a824d16D
TokenCC decimals: 10
ETH balance: 571.1597253404019 with price: $100.0
TCC balance: 542.7272727276 with price: $10.0
Holdings: 62,543.25 USD
DEX 0 @ 0x3270c4e2712a094773f360223268737b4f76d4db, symbol: D4C
k = 40000.0, x = 100.0, y = 400.0, f = 0.995
trading in TC minima/maxima: 230.87 TC; holdings after: 63875.79 USD; difference: 1332.54
trading in TC minima/maxima: -1030.87 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: -36.91 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: -163.09 minima/maxima is not positive, so ignoring
DEX 1 @ 0x08942ee9050f1bfd446298e0a36c45b61df951a3, symbol: D6C
k = 60000.0, x = 100.0, y = 600.0, f = 0.995
trading in TC minima/maxima: 172.66 TC; holdings after: 63040.08 USD; difference: 496.83
trading in TC minima/maxima: -1372.66 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: -22.73 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: -177.27 minima/maxima is not positive, so ignoring
DEX 2 @ 0xb48cff2e10bab7a40eed8e795b47abe4031c2057, symbol: D8C
k = 80000.0, x = 100.0, y = 800.0, f = 0.995
trading in TC minima/maxima: 92.19 TC; holdings after: 62649.47 USD; difference: 106.22
trading in TC minima/maxima: -1692.19 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: -10.78 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: -189.22 minima/maxima is not positive, so ignoring
Best amount of 230.87241182350022 exceeds TC max of 100.0
Best transaction: DEX # 0, trading in ETH: False, ETH transacted: 100.0, TCC transacted: 63875.78532484618
Trading in 100.0 TC: 1000000000000 tcc_wei at DEX 0x3270c4e2712a094773f360223268737b4f76d4db D4C
Gas estimate (gwei): 115873
ETH & TCC before: 571.1597253404019 542.7272727276
waiting for tcc->eth txn to be mined; txn 0xb0e7fc84a26eeee39b312529302ad792deceafdd014e1896913f7e834deb0004
The TXN was mined successfully
ETH & TCC after: 591.0586033704019 442.7272727276
Exchanged 100.0000 TC for 19.8989 ETH; fees: 0.12 USD; prices: ETH 100.00 USD, TC: 10.00 USD; holdings: 63533.13 USD
Final ETH balance: 591.0586033704019
Final TC balance: 442.7272727276
Holdings before: $62,543.25 USD
Holdings after: $63,533.13 USD
The D10 DEX exchanges the assets at the same amount as the price ratio (1:10 for the DEX, and the default prices are 10:100 USD), so with gas fees, there cannot be a profitable trade.
Connected: True
Account: 0x15b6d9ACa8b6B09745653F36b193c612a824d16D
TokenCC decimals: 10
ETH balance: 591.0586033704019 with price: $100.0
TCC balance: 442.7272727276 with price: $10.0
Holdings: 63,533.13 USD
DEX 0 @ 0xd53a424d33d254d08dc88d86b7636423941805d7, symbol: D10C
k = 100000.0, x = 100.0, y = 1000.0, f = 0.995
trading in TC minima/maxima: -2.50 minima/maxima is not positive, so ignoring
trading in TC minima/maxima: -1997.50 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: -0.25 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: -199.75 minima/maxima is not positive, so ignoring
Best transaction: DEX # 0, trading in ETH: 0, ETH transacted: 0, TCC transacted: 0
No profitable arbitrage trades available
If the middle DEXes are available (D8, D10, and D12), and there is sufficient ETH and TCC, it will exchange TCC for ETH at the D8 DEX. However, the maxima is not at 100 TCC, but a bit less.
Connected: True
Account: 0x15b6d9ACa8b6B09745653F36b193c612a824d16D
TokenCC decimals: 10
ETH balance: 591.0586033704019 with price: $100.0
TCC balance: 442.7272727276 with price: $10.0
Holdings: 63,533.13 USD
DEX 0 @ 0xb48cff2e10bab7a40eed8e795b47abe4031c2057, symbol: D8C
k = 80000.0, x = 100.0, y = 800.0, f = 0.995
trading in TC minima/maxima: 92.19 TC; holdings after: 63639.35 USD; difference: 106.22
trading in TC minima/maxima: -1692.19 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: -10.78 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: -189.22 minima/maxima is not positive, so ignoring
DEX 1 @ 0xd53a424d33d254d08dc88d86b7636423941805d7, symbol: D10C
k = 100000.0, x = 100.0, y = 1000.0, f = 0.995
trading in TC minima/maxima: -2.50 minima/maxima is not positive, so ignoring
trading in TC minima/maxima: -1997.50 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: -0.25 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: -199.75 minima/maxima is not positive, so ignoring
DEX 2 @ 0x897d3fb345ce0a3c54cbba807e7188a8ea1452bd, symbol: D12C
k = 120000.0, x = 100.0, y = 1200.0, f = 0.995
trading in TC minima/maxima: -107.30 minima/maxima is not positive, so ignoring
trading in TC minima/maxima: -2292.70 minima/maxima is not positive, so ignoring
trading in ETH minima/maxima: 9.27 ETH; holdings after: 63619.06 USD; difference: 85.93
trading in ETH minima/maxima: -209.27 minima/maxima is not positive, so ignoring
Best transaction: DEX # 0, trading in ETH: False, ETH transacted: 92.1883209278185, TCC transacted: 63639.35494575981
Trading in 92.1883209278185 TC: 921883209278 tcc_wei at DEX 0xb48cff2e10bab7a40eed8e795b47abe4031c2057 D8C
Gas estimate (gwei): 115885
ETH & TCC before: 591.0586033704019 442.7272727276
waiting for tcc->eth txn to be mined; txn 0x4bc3a3c56be6fdb28786eba8c7fde730f0b284d1e2da950a558f029a73b1652d
The TXN was mined successfully
ETH & TCC after: 601.3386491876182 350.5389517998
Exchanged 92.1883 TC for 10.2800 ETH; fees: 0.12 USD; prices: ETH 100.00 USD, TC: 10.00 USD; holdings: 63639.25 USD
Final ETH balance: 601.3386491876182
Final TC balance: 350.5389517998
Holdings before: $63,533.13 USD
Holdings after: $63,639.25 USD
You will need to fill in the various values from this assignment into the arbitrage.py (src) file. That file clearly indicates all the values that need to be filled in. That file, along with your Python source code, are the only files that must be submitted. The ‘sanity_checks’ dictionary is intended to be a checklist to ensure that you perform the various other aspects to ensure this assignment is fully submitted.
The submission will take some time to run! It executes a number of runs of your program, and that can take a few minutes to complete.
There is only one submission for this assignment.
Submission 1: Submit your arbitrage_trading.py
source code file, along with your completed arbitrage.py
file, to Gradescope. You should not submit the arbitrage_config.py file.
The submission will make three execution runs, all on the same account. The account will start with 10 ether and 0 TCC. For all the execution runs, the following value are set:
Each run assumes the state from the previous run. The trades are:
Exchanged 10.0000 ETH for 180.9091 TC; fees: 0.16 USD; prices: ETH 100.00 USD, TC: 10.00 USD; holdings: 1908.94 USD
Exchanged 100.0000 TC for 19.8987 ETH; fees: 0.15 USD; prices: ETH 100.00 USD, TC: 10.00 USD; holdings: 3089.78 USD
No profitable arbitrage trades available
These should happen fairly quickly, as the Gradescope auto-grader can bypass the 60-second DEX waiting period.