Simple Uni V2 Tree - On-chain TestNet Simulations
- Assumptions:
- Uses Simple Tree
- Uses stablecoins (ie, USDC and USDT) to control for impermanent loss
- Pre-minted supply of index tokens
- LPs include:
- USDC-USDT
- USDC-iUSDC
import os
import json
import subprocess
from pprint import pprint
import time
import numpy as np
import pandas as pd
from uniswappy import *
from pachira import *
import seaborn as sns
import statsmodels.api as sm
import datetime
from time import sleep
import matplotlib.pyplot as plt
base_dir = os.getcwd().replace("pachira_refactor/python/notebook","")
os.chdir(base_dir)
Contract paths
deploy_tree_path = 'script/simulate/SimTestNetDeployTree.s.sol'
check_amounts_path = 'script/simulate/SimTestNetCheckAmounts.s.sol'
invest_path = 'script/simulate/SimTestNetInvest.s.sol'
parent_arbitrage_path = 'script/simulate/SimTestNetParentArbitrage.s.sol'
child_arbitrage_path = 'script/simulate/SimTestNetChildArbitrage.s.sol'
swap_path = 'script/simulate/SimTestNetSwap.s.sol'
rebalance_path = 'script/simulate/SimTestNetRebalance.s.sol'
Script Functions
rpc_url = 'http://127.0.0.1:8545'
test_contract_dir = '/pachira_refactor/'
output_dir = '/pachira_refactor/test/output/'
def exe_cmd(script_path, rpc_url, verbose = True, skip_sim = True, args = []):
silent_cmd = '--silent' if not verbose else ''
skip_sim_cmd = '--skip-simulation' if skip_sim else ''
deploy_sig = [] if len(args) == 0 else ['--sig']
deploy_arg_type = [] if len(args) == 0 else ['run('+','.join('uint256' for e in args)+')']
deploy_args = [] if len(args) == 0 else [str(e) for e in args]
shell_cmd1 = ['forge', 'script', script_path]
shell_cmd2 = deploy_args + deploy_sig + deploy_arg_type
shell_cmd3 = [ '--ignored-error-codes', '2072',
'--ignored-error-codes', '6321',
'--ignored-error-codes', '5667',
'--ignored-error-codes', '5574',
'--ignored-error-codes', '2018']
shell_cmd4 = ['--rpc-url', rpc_url, '--broadcast', silent_cmd, skip_sim_cmd]
shell_cmd = shell_cmd1 + shell_cmd2 + shell_cmd3 + shell_cmd4
return shell_cmd
def execute_script(script_path, rpc_url, args = [], verbose = True, skip_sim = True):
shell_cmd = exe_cmd(script_path, rpc_url, args=args, verbose=verbose, skip_sim=skip_sim)
test_directory = base_dir+test_contract_dir
p = subprocess.Popen(shell_cmd, cwd=test_directory)
p.wait()
def calc_arb(lp, sDel, tkn_x, tkn_y, user_nm, p):
swap_dx, swap_dy = sDel.calc(p, 1, 1)
direction = 0;
if(swap_dx >= 0):
expected_amount_dep = SwapDeposit().apply(lp, tkn_x, user_nm, abs(swap_dx))
expected_amount_out = WithdrawSwap().apply(lp, tkn_y, user_nm, abs(swap_dy))
dep_tkn_x = abs(swap_dx); wd_tkn_x = 0
wd_tkn_y = abs(swap_dy); dep_tkn_y = 0
direction = 0
elif(swap_dy >= 0):
expected_amount_dep = SwapDeposit().apply(lp, tkn_y, user_nm, abs(swap_dy))
expected_amount_out = WithdrawSwap().apply(lp, tkn_x, user_nm, abs(swap_dx))
dep_tkn_y = abs(swap_dy); wd_tkn_y = 0
wd_tkn_x = abs(swap_dx); dep_tkn_x = 0
direction = 1
dep_tkn_x = UniV3Helper().dec2gwei(dep_tkn_x)
dep_tkn_y = UniV3Helper().dec2gwei(dep_tkn_y)
wd_tkn_x = UniV3Helper().dec2gwei(wd_tkn_x)
wd_tkn_y = UniV3Helper().dec2gwei(wd_tkn_y)
return (dep_tkn_x, dep_tkn_y, wd_tkn_x, wd_tkn_y, direction)
def calc_arb_contract(lp, sDel, tkn_x, tkn_y, user_nm, p):
swap_dx, swap_dy = sDel.calc(p, 1, 1)
direction = 0;
if(swap_dx >= 0):
dep_tkn_x = abs(swap_dx); wd_tkn_x = 0
wd_tkn_y = abs(swap_dy); dep_tkn_y = 0
direction = 0
elif(swap_dy >= 0):
dep_tkn_y = abs(swap_dy); wd_tkn_y = 0
wd_tkn_x = abs(swap_dx); dep_tkn_x = 0
direction = 1
dep_tkn_x = UniV3Helper().dec2gwei(dep_tkn_x)
dep_tkn_y = UniV3Helper().dec2gwei(dep_tkn_y)
wd_tkn_x = UniV3Helper().dec2gwei(wd_tkn_x)
wd_tkn_y = UniV3Helper().dec2gwei(wd_tkn_y)
return (dep_tkn_x, dep_tkn_y, wd_tkn_x, wd_tkn_y, direction)
def pool_state(pool_contract, verbose=False):
reserves = pool_contract.functions.getReserves().call()
lp_amt = pool_contract.functions.totalSupply().call()
if(verbose): print(f'TKN0 {UniV3Helper().gwei2dec(reserves[0]):.2f} / TKN1 {UniV3Helper().gwei2dec(reserves[1]):.2f} / Liquidity {UniV3Helper().gwei2dec(lp_amt):.2f}')
return (reserves[0], reserves[1], lp_amt)
Simulate price data
tkn_nm = 'USDC'
itkn_nm = 'iUSDC'
usdt_nm = 'USDT'
iusdt_nm = 'iUSDT'
# *************************
# *** Simulation
# *************************
n_sim_runs = 1000
seconds_year = 31536000
shape = 2000
scale = 0.0005
saved_prices = True
if(saved_prices):
price_df = pd.read_csv('pachira_refactor/python/resources/price_df.csv')
p_arr = price_df['price'].values
else:
p_arr = np.random.gamma(shape = shape, scale = scale, size = n_sim_runs)
if(not saved_prices):
price_dic = {'price': p_arr}
price_df = pd.DataFrame(price_dic)
price_df.to_csv('pachira_refactor/python/resources/price_df.csv', encoding='utf-8', index=False)
n_runs = len(p_arr)-1
dt = datetime.timedelta(seconds=seconds_year/n_sim_runs)
dates = [datetime.datetime.strptime("2024-09-01", '%Y-%m-%d') + k*dt for k in range(n_sim_runs)]
x_val = np.arange(0,len(p_arr))
fig, (USD_ax) = plt.subplots(nrows=1, sharex=False, sharey=False, figsize=(18, 5))
USD_ax.plot(dates, p_arr, color = 'r',linestyle = 'dashdot', label='initial invest')
USD_ax.set_title(f'Price Chart ({tkn_nm}/{usdt_nm})', fontsize=20)
USD_ax.set_ylabel('Price (USD)', size=20)
USD_ax.set_xlabel('Date', size=20)
Text(0.5, 0, 'Date')
Pool configuration - Contracts & Python
tkn0_amt_usd = 1000000
invest_amt_usd = 100
exe_contract = True
skip_sim = True
contract_time_lapse = 0.5
tkn0_amt = UniV3Helper().dec2gwei(tkn0_amt_usd)
tkn1_amt = int(p_arr[0]*tkn0_amt)
deploy_amt = UniV3Helper().dec2gwei(tkn0_amt_usd/5)
mint_amt = UniV3Helper().dec2gwei(tkn0_amt_usd/10)
invest_amt = UniV3Helper().dec2gwei(invest_amt_usd)
mrk_cap = UniV3Helper().gwei2dec(tkn0_amt)
#TKN_amt = TokenDeltaModel(0.05*mrk_cap, shape=2, scale=0.1)
TKN_amt = TokenDeltaModel(0.1*mrk_cap) # validated model
swap_arr = np.array([TKN_amt.delta() for k in range(1000)])
fig, ax = plt.subplots(1, 1, figsize=(12,5))
sns.distplot(swap_arr, hist=True, kde=False, bins=int(50), color = 'darkblue',
hist_kws={'edgecolor':'black'}, kde_kws={'linewidth': 2}, ax=ax)
ax.set_title('Histogram: Unit Swap Volume (USD)')
np.median(swap_arr)
14003.127419022314
Deploy simple tree - Contracts
deploy_args = [tkn0_amt, tkn1_amt, deploy_amt, mint_amt]
execute_script(deploy_tree_path, rpc_url, verbose=True, args=deploy_args, skip_sim=False)
No files changed, compilation skipped
EIP-3855 is not supported in one or more of the RPCs used.
Unsupported Chain IDs: 31337.
Contracts deployed with a Solidity version equal or higher than 0.8.20 might not work properly.
For more information, please see https://eips.ethereum.org/EIPS/eip-3855
Script ran successfully.
== Logs ==
tkn0Amt = 1000000000000000000000000
tkn1Amt = 1005580071821577923067904
deployAmt = 200000000000000000000000
token0Bal = 200000000000000000000000
synthTkn0Addr = 0xcf11f6D694E1B2467a3AdA680B2703a69d8d98Eb
synthTkn1Addr = 0xf2670B9B15baeA490900B2549Dc1CD41F41E3972
baseTokenIn = 0x6F46D679aB36ebc8a36AC0D0F5B50C7eA399FC66
indexToken = 0xf2670B9B15baeA490900B2549Dc1CD41F41E3972
proceedsAmount = 46730061042074311691695
childLPAddr = 0xd847C8dCCDD067C0e2484c091CdfE91177A22dBF
address(this) = 0x63e1DF6430Ac34f72Cf8Ce19Ae6414B32020a4B2
mintedLiquidity = 69908019701168269768338
proceedsAmount = 42748875875872662696036
proceedsAmount = 55476592623908026948897
Balance synthTkn0 = 99931198511720447407864
Parent totalSupply = 1151588665279221008599431
Parent Actual totalSupply = 1151588665279221008599431
Parent baseReserve0 = 1200000000000000000000000
Parent baseReserve1 = 1105580071821577923067904
Child totalSupply = 69908019701168269768338
Child Actual totalSupply = 69908019701168269768338
Child baseReserve0 = 100000000000000000000000
Child baseReserve1 = 48871312185389309419612
## Setting up 1 EVM.
==========================
Chain 31337
Estimated gas price: 0.000000017 gwei
Estimated total gas used for script: 41331203
Estimated amount required: 0.000000000702630451 ETH
==========================
==========================
ONCHAIN EXECUTION COMPLETE & SUCCESSFUL.
Transactions saved to: /Users/ian_moore/repos/pachira_refactor/broadcast/SimTestNetDeployTree.s.sol/31337/run-latest.json
Sensitive values saved to: /Users/ian_moore/repos/pachira_refactor/cache_forge/SimTestNetDeployTree.s.sol/31337/run-latest.json
Retrieve pool configurations from contracts
test_net_addresses_path = '/Users/ian_moore/repos/pachira_refactor/script/deployments/SimTestNet-addresses.json'
f = open(test_net_addresses_path)
test_net_addresses = json.load(f)
base_pool_addr = test_net_addresses['parentPool']
child_pool_addr = test_net_addresses['childPool1']
tkn0_addr = test_net_addresses['tkn0']
tkn1_addr = test_net_addresses['tkn1']
uniV2Factory_addr = test_net_addresses['uniV2Factory']
abi = ABILoad(Platform.PACHIRA, JSONContract.UniswapV2Pair)
contract_interface = abi.get_abi_by_filename(abi.get_abi_path())
connect = ConnectW3(Net.LOCALHOST)
connect.apply()
w3 = connect.get_w3()
base_pool_contract = w3.eth.contract(address=w3.to_checksum_address(base_pool_addr), abi=contract_interface['abi'])
child_pool_contract = w3.eth.contract(address=w3.to_checksum_address(child_pool_addr), abi=contract_interface['abi'])
base_pool_contract = w3.eth.contract(address=w3.to_checksum_address(base_pool_addr), abi=contract_interface['abi'])
child_pool_contract = w3.eth.contract(address=w3.to_checksum_address(child_pool_addr), abi=contract_interface['abi'])
base_reserves = base_pool_contract.functions.getReserves().call()
base_lp_amt = base_pool_contract.functions.totalSupply().call()
child_reserves = child_pool_contract.functions.getReserves().call()
child_lp_amt = child_pool_contract.functions.totalSupply().call()
Deploy simple tree (using contract amounts) - Python
user_nm = 'user_machine_check'
token0Addr = '0x01'
token1Addr = '0x02'
basePoolAddr = '0x05'
tkn_nm = 'USDC'
itkn_nm = 'iUSDC'
usdt_nm = 'USDT'
iusdt_nm = 'iUSDT'
(base_res0, base_res1, base_lp_amt) = pool_state(base_pool_contract)
(child_res0, child_res1, child_lp_amt) = pool_state(child_pool_contract)
tkn1 = ERC20(tkn_nm, "0x09")
usdt1 = ERC20(usdt_nm, "0x111")
exchg_data = UniswapExchangeData(tkn0 = tkn1, tkn1 = usdt1, symbol="LP", address="0x011")
iVault1 = IndexVault('iVault1', "0x7")
factory = UniswapFactory(f"{tkn_nm} pool factory", "0x2")
base_lp = factory.deploy(exchg_data)
Join().apply(base_lp, user_nm, UniV3Helper().gwei2dec(base_res0), UniV3Helper().gwei2dec(base_res1))
tkn2 = ERC20(tkn_nm, "0x09")
itkn1 = IndexERC20(itkn_nm, "0x09", tkn1, base_lp)
exchg_data1 = UniswapExchangeData(tkn0 = tkn2, tkn1 = itkn1, symbol="LP1", address="0x012")
child1_lp = factory.deploy(exchg_data1)
Join().apply(child1_lp, user_nm, UniV3Helper().gwei2dec(child_res0), UniV3Helper().gwei2dec(child_res1))
(100000000000000000000000, 48871312185389310000000)
Rebalance base pool - Python
# Re-balance LP price after JoinTree
if(base_lp.get_reserve(usdt1) > base_lp.get_reserve(tkn1)):
SwapDeposit().apply(base_lp, tkn1, user_nm, base_lp.get_reserve(usdt1) - base_lp.get_reserve(tkn1))
else:
SwapDeposit().apply(base_lp, usdt1, user_nm, base_lp.get_reserve(tkn1) - base_lp.get_reserve(usdt1))
sDel_base = SolveDeltas(base_lp)
sDel_child = SolveDeltas(child1_lp)
base_lp.summary()
child1_lp.summary()
Exchange USDC-USDT (LP)
Reserves: USDC = 1200000.0, USDT = 1200000.0
Liquidity: 1199927.6280287034
Exchange USDC-iUSDC (LP1)
Reserves: USDC = 100000.0, iUSDC = 48871.31218538931
Liquidity: 69908.01970116828
Rebalance base pool - Contracts
execute_script(rebalance_path, rpc_url, verbose=True, skip_sim=False)
No files changed, compilation skipped
EIP-3855 is not supported in one or more of the RPCs used.
Unsupported Chain IDs: 31337.
Contracts deployed with a Solidity version equal or higher than 0.8.20 might not work properly.
For more information, please see https://eips.ethereum.org/EIPS/eip-3855
Script ran successfully.
== Logs ==
parentPoolAddr = 0xACf9FAce714149942D1837165ed4Fe6AE24C9bbC
iParentPoolAddr = 0x7553e3118AE2921dc8aCE684bA74ee2a883D3FeB
childPool1Addr = 0xd847C8dCCDD067C0e2484c091CdfE91177A22dBF
iChildPool1Addr = 0x6a2b245136520FE4d7B93B63735808ADee8D4088
tkn0Addr = 0x6F46D679aB36ebc8a36AC0D0F5B50C7eA399FC66
tkn1Addr = 0x0D93968496Ef4D115a4c20586ED23aE75F0FF355
proceedsAmount = 48107588929307396742759
Parent totalSupply = 1199683568581351176009583
Parent baseReserve0 = 1200000000000000000000000
Parent baseReserve1 = 1200000000000000000000000
## Setting up 1 EVM.
==========================
Chain 31337
Estimated gas price: 0.000000017 gwei
Estimated total gas used for script: 375209
Estimated amount required: 0.000000000006378553 ETH
==========================
==========================
ONCHAIN EXECUTION COMPLETE & SUCCESSFUL.
Transactions saved to: /Users/ian_moore/repos/pachira_refactor/broadcast/SimTestNetRebalance.s.sol/31337/run-latest.json
Sensitive values saved to: /Users/ian_moore/repos/pachira_refactor/cache_forge/SimTestNetRebalance.s.sol/31337/run-latest.json
Take an investment position - Contracts
invest_args = [invest_amt]
execute_script(invest_path, rpc_url, args=invest_args, verbose=True, skip_sim=False)
output_dir = '/pachira_refactor/script/deployments/'
output_file = 'SimTestNet-investment.json'
output_file_path = os.getcwd()+output_dir+output_file
with open(output_file_path) as f:
contract_output = json.loads(f.read())
lp1_invest_track_contract = UniV3Helper().gwei2dec(contract_output['treeYieldOut'])
No files changed, compilation skipped
EIP-3855 is not supported in one or more of the RPCs used.
Unsupported Chain IDs: 31337.
Contracts deployed with a Solidity version equal or higher than 0.8.20 might not work properly.
For more information, please see https://eips.ethereum.org/EIPS/eip-3855
Script ran successfully.
== Logs ==
parentPoolAddr = 0xACf9FAce714149942D1837165ed4Fe6AE24C9bbC
iParentPoolAddr = 0x7553e3118AE2921dc8aCE684bA74ee2a883D3FeB
childPool1Addr = 0xd847C8dCCDD067C0e2484c091CdfE91177A22dBF
iChildPool1Addr = 0x6a2b245136520FE4d7B93B63735808ADee8D4088
tkn0Addr = 0x6F46D679aB36ebc8a36AC0D0F5B50C7eA399FC66
tkn1Addr = 0x0D93968496Ef4D115a4c20586ED23aE75F0FF355
devs = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
proceedsAmount = 49921770369159820657
proceedsAmount = 50947683786753511943
Parent totalSupply = 1199733479264064520838179
Parent totalSupply = 1199733479264064520838179
Parent baseReserve0 = 1200000000000000000000000
Parent baseReserve1 = 1200100000000000000000000
Child totalSupply = 69943654373027139429999
Child totalSupply = 69943654373027139429999
Child baseReserve0 = 100000000000000000000000
Child baseReserve1 = 48921222868102654248208
treeYieldOut = 35634671858869661661
## Setting up 1 EVM.
==========================
Chain 31337
Estimated gas price: 0.000000017 gwei
Estimated total gas used for script: 9698240
Estimated amount required: 0.00000000016487008 ETH
==========================
==========================
ONCHAIN EXECUTION COMPLETE & SUCCESSFUL.
Transactions saved to: /Users/ian_moore/repos/pachira_refactor/broadcast/SimTestNetInvest.s.sol/31337/run-latest.json
Sensitive values saved to: /Users/ian_moore/repos/pachira_refactor/cache_forge/SimTestNetInvest.s.sol/31337/run-latest.json
Take an investment position - Python
invested_user_nm = 'invested_user'
tkn_invest_amt = UniV3Helper().gwei2dec(invest_amt)
SwapIndexMint(iVault1, opposing = False).apply(base_lp, tkn1, invested_user_nm, tkn_invest_amt)
mint_itkn1_deposit = child1_lp.convert_to_human(iVault1.index_tokens[itkn_nm]['last_lp_deposit'])
SwapDeposit().apply(child1_lp, itkn1, invested_user_nm, mint_itkn1_deposit)
base_lp.summary()
child1_lp.summary()
lp_invest_track = base_lp.get_liquidity_from_provider(invested_user_nm)
lp1_invest_track = child1_lp.get_liquidity_from_provider(invested_user_nm)
# Redeem from parent
tkn_redeem_parent = LPQuote(False).get_amount_from_lp(base_lp, tkn1, lp_invest_track)
# Redeem from tree (child + parent)
itkn_redeem_child = LPQuote(False).get_amount_from_lp(child1_lp, itkn1, lp1_invest_track)
tkn_redeem_tree = LPQuote(False).get_amount_from_lp(base_lp, tkn1, itkn_redeem_child)
print(f'{tkn_redeem_parent:.3f} USDC redeemed from {lp_invest_track:.3f} LP tokens if {UniV3Helper().gwei2dec(invest_amt):.1f} invested USDC immediately pulled from parent')
print(f'{tkn_redeem_tree:.3f} USDC redeemed from {lp1_invest_track:.3f} LP1 tokens if {UniV3Helper().gwei2dec(invest_amt):.1f} invested USDC immediately pulled from tree')
Exchange USDC-USDT (LP)
Reserves: USDC = 1200100.0, USDT = 1200000.0
Liquidity: 1199977.5488650722
Exchange USDC-iUSDC (LP1)
Reserves: USDC = 100000.0, iUSDC = 48921.23302175813
Liquidity: 69943.66162057084
99.700 USDC redeemed from 49.921 LP tokens if 100.0 invested USDC immediately pulled from parent
99.401 USDC redeemed from 35.642 LP1 tokens if 100.0 invested USDC immediately pulled from tree
Check tree - Contracts
execute_script(check_amounts_path, rpc_url, verbose=True, skip_sim=False)
No files changed, compilation skipped
EIP-3855 is not supported in one or more of the RPCs used.
Unsupported Chain IDs: 31337.
Contracts deployed with a Solidity version equal or higher than 0.8.20 might not work properly.
For more information, please see https://eips.ethereum.org/EIPS/eip-3855
Script ran successfully.
== Logs ==
parentPoolAddr = 0xACf9FAce714149942D1837165ed4Fe6AE24C9bbC
iParentPoolAddr = 0x7553e3118AE2921dc8aCE684bA74ee2a883D3FeB
childPool1Addr = 0xd847C8dCCDD067C0e2484c091CdfE91177A22dBF
iChildPool1Addr = 0x6a2b245136520FE4d7B93B63735808ADee8D4088
tkn0Addr = 0x6F46D679aB36ebc8a36AC0D0F5B50C7eA399FC66
tkn1Addr = 0x0D93968496Ef4D115a4c20586ED23aE75F0FF355
Parent totalSupply = 1199733479264064520838179
Parent totalSupply = 1199733479264064520838179
Parent baseReserve0 = 1200000000000000000000000
Parent baseReserve1 = 1200100000000000000000000
Child totalSupply = 69943654373027139429999
Child totalSupply = 69943654373027139429999
Child baseReserve0 = 100000000000000000000000
Child baseReserve1 = 48921222868102654248208
## Setting up 1 EVM.
==========================
Chain 31337
Estimated gas price: 0.000000017 gwei
Estimated total gas used for script: 81176
Estimated amount required: 0.000000000001379992 ETH
==========================
==========================
ONCHAIN EXECUTION COMPLETE & SUCCESSFUL.
Transactions saved to: /Users/ian_moore/repos/pachira_refactor/broadcast/SimTestNetCheckAmounts.s.sol/31337/run-latest.json
Sensitive values saved to: /Users/ian_moore/repos/pachira_refactor/cache_forge/SimTestNetCheckAmounts.s.sol/31337/run-latest.json
Begin simulation - Python & Contracts
p_sim_arr1 = []; p_python_arr1 = []; p_contract_arr1 = []
p_sim_arr2 = []; p_python_arr2 = []; p_contract_arr2 = []
lp_direct_invest_arr = []; lp1_direct_invest_arr = []; lp1_tree_invest_arr = [];
print('Begin liquidity tree simulation\n')
for k in range(n_sim_runs):
amt_swap = TKN_amt.delta()
# ****************************************
# ***** Calculate Arbitrage Amounts ******
# ****************************************
p_sim1 = p_arr[k]
if(exe_contract):
(dep_tkn_x1, dep_tkn_y1, wd_tkn_x1, wd_tkn_y1, direction1) = calc_arb_contract(base_lp, sDel_base, tkn1, usdt1, user_nm, p_sim1)
else:
(dep_tkn_x1, dep_tkn_y1, wd_tkn_x1, wd_tkn_y1, direction1) = calc_arb(base_lp, sDel_base, tkn1, usdt1, user_nm, p_sim1)
p_sim2 = LPQuote().get_lp_from_amount(base_lp, usdt1, child1_lp.get_reserve(tkn2))/child1_lp.get_reserve(tkn2)
if(exe_contract):
(dep_tkn_x2, dep_tkn_y2, wd_tkn_x2, wd_tkn_y2, direction2) = calc_arb_contract(child1_lp, sDel_child, tkn2, itkn1, user_nm, p_sim2)
else:
(dep_tkn_x2, dep_tkn_y2, wd_tkn_x2, wd_tkn_y2, direction2) = calc_arb(child1_lp, sDel_child, tkn2, itkn1, user_nm, p_sim2)
# *****************************
# **** Contract Arbitrage *****
# *****************************
if(exe_contract):
arb_args1 = [dep_tkn_x1, dep_tkn_y1, wd_tkn_x1, wd_tkn_y1, direction1]
execute_script(parent_arbitrage_path, rpc_url, args=arb_args1, verbose=False, skip_sim=skip_sim)
(base_res0, base_res1, base_lp_amt) = pool_state(base_pool_contract, verbose=False)
price_tkn0_contract1 = base_res1/base_res0
sleep(contract_time_lapse)
arb_args2 = [dep_tkn_x2, dep_tkn_y2, wd_tkn_x2, wd_tkn_y2, direction2]
execute_script(child_arbitrage_path, rpc_url, args=arb_args2, verbose=False, skip_sim=skip_sim)
(child_res0, child_res1, base_lp_amt) = pool_state(child_pool_contract, verbose=False)
price_tkn0_contract2 = child_res1/child_res0
sleep(contract_time_lapse)
# **************************************
# ** Recalibrate Pool State - Python ***
# **************************************
(base_res0, base_res1, base_lp_amt) = pool_state(base_pool_contract)
(child_res0, child_res1, child_lp_amt) = pool_state(child_pool_contract)
base_lp.reserve0 = base_res0; base_lp.reserve1 = base_res1; base_lp.total_supply = base_lp_amt
child1_lp.reserve0 = child_res0; child1_lp.reserve1 = child_res1; child1_lp.total_supply = child_lp_amt
price_tkn0_python1 = base_lp.get_price(tkn1)
price_tkn0_python2 = child1_lp.get_price(tkn2)
# ************************************
# ** Induce Trade Volume - Contract **
# ************************************
if(exe_contract):
arb_args = [UniV3Helper().dec2gwei(amt_swap), 0]
execute_script(swap_path, rpc_url, args=arb_args, verbose=False, skip_sim=skip_sim)
sleep(contract_time_lapse)
arb_args = [UniV3Helper().dec2gwei(amt_swap), 1]
execute_script(swap_path, rpc_url, args=arb_args, verbose=False, skip_sim=skip_sim)
sleep(contract_time_lapse)
# **************************************
# ** Recalibrate Pool State - Python ***
# **************************************
(base_res0, base_res1, base_lp_amt) = pool_state(base_pool_contract)
(child_res0, child_res1, child_lp_amt) = pool_state(child_pool_contract)
base_lp.reserve0 = base_res0; base_lp.reserve1 = base_res1; base_lp.total_supply = base_lp_amt
child1_lp.reserve0 = child_res0; child1_lp.reserve1 = child_res1; child1_lp.total_supply = child_lp_amt
# ***********************************
# *** Induce Trade Volume - Python **
# ***********************************
if(not exe_contract):
Swap().apply(base_lp, tkn1, user_nm, amt_swap)
Swap().apply(base_lp, usdt1, user_nm, amt_swap)
Swap().apply(child1_lp, tkn2, user_nm, 0.2*amt_swap)
Swap().apply(child1_lp, itkn1, user_nm, LPQuote().get_lp_from_amount(base_lp, usdt1, 0.2*amt_swap))
# *****************************
# ***** Data Collection *******
# *****************************
p_sim_arr1.append(p_sim1)
p_python_arr1.append(price_tkn0_python1)
p_sim_arr2.append(p_sim2)
p_python_arr2.append(price_tkn0_python2)
if(exe_contract):
p_contract_arr1.append(price_tkn0_contract1)
p_contract_arr2.append(price_tkn0_contract2)
# investment performance
tkn_redeem_parent = LPQuote(False).get_amount_from_lp(base_lp, tkn1, lp_invest_track)
itkn_redeem_child = LPQuote(False).get_amount_from_lp(child1_lp, itkn1, lp1_invest_track_contract)
tkn_redeem_tree = LPQuote(False).get_amount_from_lp(base_lp, tkn1, itkn_redeem_child)
lp_direct_invest_arr.append(tkn_redeem_parent)
lp1_direct_invest_arr.append(LPQuote(False).get_amount_from_lp(child1_lp, tkn2, lp1_invest_track))
lp1_tree_invest_arr.append(tkn_redeem_tree)
if((exe_contract) and (k % int(n_sim_runs/10)) == 0):
print(f'[Parent: step {k}] Actual price {p_sim1:.5f} / Python price {price_tkn0_python1:.5f} / Contract price {price_tkn0_contract1:.5f}')
print(f'[Child: step {k}] Actual price {p_sim2:.5f} / Python price {price_tkn0_python2:.5f} / Contract price {price_tkn0_contract2:.5f}')
print()
elif ((not exe_contract) and (k % int(n_sim_runs/10)) == 0):
print(f'[Parent: step {k}] Actual price {p_sim1:.5f} / Python price {price_tkn0_python1:.5f}')
print(f'[Child: step {k}] Actual price {p_sim2:.5f} / Python price {price_tkn0_python2:.5f}')
print()
base_lp.summary()
child1_lp.summary()
# Redeem from parent
tkn_redeem_parent = LPQuote(False).get_amount_from_lp(base_lp, tkn1, lp_invest_track)
# Redeem from tree (child + parent)
itkn_redeem_child = LPQuote(False).get_amount_from_lp(child1_lp, itkn1, lp1_invest_track_contract)
tkn_redeem_tree = LPQuote(False).get_amount_from_lp(base_lp, tkn1, itkn_redeem_child)
print(f'{tkn_redeem_parent:.3f} USDC redeemed from {lp_invest_track:.3f} LP tokens if {UniV3Helper().gwei2dec(invest_amt):.1f} invested USDC pulled from parent (lp)')
print(f'{tkn_redeem_tree:.3f} USDC redeemed from {lp1_invest_track_contract:.3f} LP1 tokens if {UniV3Helper().gwei2dec(invest_amt):.1f} invested USDC pulled from tree (lp + lp1)')
Begin liquidity tree simulation
[Parent: step 0] Actual price 1.00558 / Python price 1.00573 / Contract price 1.00573
[Child: step 0] Actual price 0.51160 / Python price 0.51132 / Contract price 0.51132
[Parent: step 100] Actual price 0.99577 / Python price 0.99575 / Contract price 0.99575
[Child: step 100] Actual price 0.50987 / Python price 0.50987 / Contract price 0.50987
[Parent: step 200] Actual price 1.04163 / Python price 1.04164 / Contract price 1.04164
[Child: step 200] Actual price 0.49199 / Python price 0.49219 / Contract price 0.49219
[Parent: step 300] Actual price 0.97814 / Python price 0.97861 / Contract price 0.97861
[Child: step 300] Actual price 0.49221 / Python price 0.49231 / Contract price 0.49231
[Parent: step 400] Actual price 0.96791 / Python price 0.96805 / Contract price 0.96805
[Child: step 400] Actual price 0.49928 / Python price 0.49927 / Contract price 0.49927
[Parent: step 500] Actual price 1.00374 / Python price 1.00370 / Contract price 1.00370
[Child: step 500] Actual price 0.49661 / Python price 0.49661 / Contract price 0.49661
[Parent: step 600] Actual price 1.04946 / Python price 1.04893 / Contract price 1.04893
[Child: step 600] Actual price 0.49043 / Python price 0.49040 / Contract price 0.49040
[Parent: step 700] Actual price 0.97452 / Python price 0.97461 / Contract price 0.97461
[Child: step 700] Actual price 0.49008 / Python price 0.49008 / Contract price 0.49008
[Parent: step 800] Actual price 1.00885 / Python price 1.00920 / Contract price 1.00920
[Child: step 800] Actual price 0.47213 / Python price 0.47223 / Contract price 0.47223
[Parent: step 900] Actual price 1.01132 / Python price 1.01096 / Contract price 1.01096
[Child: step 900] Actual price 0.48866 / Python price 0.48868 / Contract price 0.48868
Exchange USDC-USDT (LP)
Reserves: USDC = 1542808.4758102486, USDT = 1589101.571632045
Liquidity: 1470257.625638831
Exchange USDC-iUSDC (LP1)
Reserves: USDC = 119743.29568975396, iUSDC = 58604.79369967114
Liquidity: 74475.62736035028
104.610 USDC redeemed from 49.921 LP tokens if 100.0 invested USDC pulled from parent (lp)
117.339 USDC redeemed from 35.635 LP1 tokens if 100.0 invested USDC pulled from tree (lp + lp1)
Plot results
lp_direct_invest_arr = np.array(lp_direct_invest_arr)
lp1_direct_invest_arr = np.array(lp1_direct_invest_arr)
lp1_tree_invest_arr = np.array(lp1_tree_invest_arr)
lp_direct_invest_arr = np.array(lp_direct_invest_arr)-(lp_direct_invest_arr[0]-lp1_tree_invest_arr[0])
lp1_direct_invest_arr = np.array(lp1_direct_invest_arr)-(lp1_direct_invest_arr[0]-lp1_tree_invest_arr[0])
lp1_tree_invest_arr = np.array(lp1_tree_invest_arr)
lowess = sm.nonparametric.lowess
x = range(0,n_sim_runs)
res = lowess(lp_direct_invest_arr, x, frac=1/15); sm_lp_direct = res[:,1]
res = lowess(lp1_direct_invest_arr, x, frac=1/15); sm_lp1_direct = res[:,1]
res = lowess(lp1_tree_invest_arr, x, frac=1/15); sm_lp1_tree= res[:,1]
parent_return = 100*sm_lp_direct[-1]/invest_amt_usd-100
child_return = 100*sm_lp1_direct[-1]/invest_amt_usd-100
tree_return = 100*sm_lp1_tree[-1]/invest_amt_usd-100
strt_ind = 0
fig, (p_ax) = plt.subplots(nrows=1, sharex=True, sharey=False, figsize=(15, 8))
fig.suptitle('On-chain performance of Stablecoin Tree (USDC / USDT) via simulation', fontsize=20)
p_ax.plot(dates[strt_ind:n_sim_runs], lp_direct_invest_arr[strt_ind:], linestyle='dashed', linewidth=0.5, color = 'g', label = 'Parent token')
p_ax.plot(dates[strt_ind:n_sim_runs], sm_lp_direct[strt_ind:], color = 'g', label = 'Expected return from parent (LP)')
p_ax.plot(dates[strt_ind:n_sim_runs], lp1_tree_invest_arr[strt_ind:], linestyle='dashed', linewidth=0.5, color = 'r', label = 'Tree token')
p_ax.plot(dates[strt_ind:n_sim_runs], sm_lp1_tree[strt_ind:], color = 'r', label = 'Expected return from tree (LP+LP1)')
p_ax.text(0.7, 0.1, f'Parent LP token return: {parent_return:.4}%', fontsize=18, color='g', horizontalalignment='left',verticalalignment='center',transform=ax.transAxes)
p_ax.text(0.7, 0.2, f'Tree LP token return: {tree_return:.4}%', fontsize=18, color='r', horizontalalignment='left',verticalalignment='center',transform=ax.transAxes)
p_ax.set_ylim(UniV3Helper().gwei2dec(invest_amt)*95/100, UniV3Helper().gwei2dec(invest_amt)*125/100)
p_ax.set_ylabel("$100 USD Investment", fontsize=14)
p_ax.legend(fontsize=12, loc='upper left')
<matplotlib.legend.Legend at 0x17f615fc0>
Check parent and child pool - Contracts
execute_script(check_amounts_path, rpc_url, verbose=True, skip_sim=False)
No files changed, compilation skipped
EIP-3855 is not supported in one or more of the RPCs used.
Unsupported Chain IDs: 31337.
Contracts deployed with a Solidity version equal or higher than 0.8.20 might not work properly.
For more information, please see https://eips.ethereum.org/EIPS/eip-3855
Script ran successfully.
== Logs ==
parentPoolAddr = 0x5baBe4182Fff652BFf47631d848A6b3ccC765F80
iParentPoolAddr = 0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9
childPool1Addr = 0x147f014B5a4636459335A4d72fa28603FC6da960
iChildPool1Addr = 0x0165878A594ca255338adfa4d48449f69242Eb8F
tkn0Addr = 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
tkn1Addr = 0xB424592A971c77dfa282D55419f9e45e9bC60da6
Parent totalSupply = 1470257625638830897462917
Parent totalSupply = 1470257625638830897462917
Parent baseReserve0 = 1542808475810248665182342
Parent baseReserve1 = 1589101571632045074422045
Child totalSupply = 74475627360350270540225
Child totalSupply = 74475627360350270540225
Child baseReserve0 = 119743295689753956639654
Child baseReserve1 = 58604793699671142761629
## Setting up 1 EVM.
==========================
Chain 31337
Estimated gas price: 0.000000017 gwei
Estimated total gas used for script: 81176
Estimated amount required: 0.000000000001379992 ETH
==========================
==========================
ONCHAIN EXECUTION COMPLETE & SUCCESSFUL.
Transactions saved to: /Users/ian_moore/repos/pachira_refactor/broadcast/SimTestNetCheckAmounts.s.sol/31337/run-latest.json
Sensitive values saved to: /Users/ian_moore/repos/pachira_refactor/cache_forge/SimTestNetCheckAmounts.s.sol/31337/run-latest.json
Check parent and child pool - Python
base_lp.summary()
child1_lp.summary()
Exchange USDC-USDT (LP)
Reserves: USDC = 1542808.4758102486, USDT = 1589101.571632045
Liquidity: 1470257.625638831
Exchange USDC-iUSDC (LP1)
Reserves: USDC = 119743.29568975396, iUSDC = 58604.79369967114
Liquidity: 74475.62736035028