-
Notifications
You must be signed in to change notification settings - Fork 137
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1delta proxy functions for Aave (#185)
Proxy functions to interact with Aave: - Supply collateral - Withdraw collateral Part of tradingstrategy-ai/trade-executor#678
- Loading branch information
Showing
4 changed files
with
288 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
"""1delta proxy functions to interact with lending pool. | ||
- Supply collateral to lending pool | ||
- Withdraw collateral from lending pool | ||
""" | ||
|
||
from web3.contract.contract import Contract, ContractFunction | ||
|
||
from eth_defi.aave_v3.constants import MAX_AMOUNT, AaveV3InterestRateMode | ||
from eth_defi.aave_v3.deployment import AaveV3Deployment | ||
from eth_defi.one_delta.deployment import OneDeltaDeployment | ||
|
||
|
||
def supply( | ||
one_delta_deployment: OneDeltaDeployment, | ||
*, | ||
token: Contract, | ||
amount: int, | ||
wallet_address: str, | ||
) -> ContractFunction: | ||
"""Supply collateral to Aave | ||
:param one_delta_deployment: 1delta deployment | ||
:param token: collateral token contract proxy | ||
:param collateral_amount: amount of collateral to be supplied | ||
:param wallet_address: wallet address of the user | ||
:return: multicall contract function to supply collateral | ||
""" | ||
|
||
calls = _build_supply_multicall( | ||
one_delta_deployment=one_delta_deployment, | ||
token=token, | ||
amount=amount, | ||
wallet_address=wallet_address, | ||
) | ||
return one_delta_deployment.broker_proxy.functions.multicall(calls) | ||
|
||
|
||
def _build_supply_multicall( | ||
one_delta_deployment, | ||
*, | ||
token: Contract, | ||
amount: int, | ||
wallet_address: str, | ||
) -> list[str]: | ||
"""Build multicall to supply collateral to Aave | ||
:param one_delta_deployment: 1delta deployment | ||
:param token: collateral token contract proxy | ||
:param collateral_amount: amount of collateral to be supplied | ||
:param wallet_address: wallet address of the user | ||
:return: list of encoded ABI calls | ||
""" | ||
call_transfer = one_delta_deployment.flash_aggregator.encodeABI( | ||
fn_name="transferERC20In", | ||
args=[ | ||
token.address, | ||
amount, | ||
], | ||
) | ||
|
||
call_deposit = one_delta_deployment.flash_aggregator.encodeABI( | ||
fn_name="deposit", | ||
args=[ | ||
token.address, | ||
wallet_address, | ||
], | ||
) | ||
|
||
return [call_transfer, call_deposit] | ||
|
||
|
||
def withdraw( | ||
one_delta_deployment: OneDeltaDeployment, | ||
*, | ||
token: Contract, | ||
atoken: Contract, | ||
amount: int, | ||
wallet_address: str, | ||
) -> ContractFunction: | ||
"""Withdraw collateral from Aave | ||
:param one_delta_deployment: 1delta deployment | ||
:param token: collateral token contract proxy | ||
:param atoken: aToken contract proxy | ||
:param collateral_amount: amount of collateral to be withdrawn | ||
:param wallet_address: wallet address of the user | ||
:return: multicall contract function to withdraw collateral | ||
""" | ||
|
||
calls = _build_withdraw_multicall( | ||
one_delta_deployment=one_delta_deployment, | ||
token=token, | ||
atoken=atoken, | ||
amount=amount, | ||
wallet_address=wallet_address, | ||
) | ||
return one_delta_deployment.broker_proxy.functions.multicall(calls) | ||
|
||
|
||
def _build_withdraw_multicall( | ||
one_delta_deployment, | ||
*, | ||
token: Contract, | ||
atoken: Contract, | ||
amount: int, | ||
wallet_address: str, | ||
) -> list[str]: | ||
"""Build multicall to withdraw collateral from Aave | ||
:param one_delta_deployment: 1delta deployment | ||
:param token: collateral token contract proxy | ||
:param atoken: aToken contract proxy | ||
:param collateral_amount: amount of collateral to be withdrawn, use MAX_AMOUNT to withdraw all collateral | ||
:param wallet_address: wallet address of the user | ||
:return: list of encoded ABI calls | ||
""" | ||
if amount == MAX_AMOUNT: | ||
# use MAX_AMOUNT to make sure the whole balane is swept | ||
call_transfer = one_delta_deployment.flash_aggregator.encodeABI( | ||
fn_name="transferERC20AllIn", | ||
args=[atoken.address], | ||
) | ||
else: | ||
call_transfer = one_delta_deployment.flash_aggregator.encodeABI( | ||
fn_name="transferERC20In", | ||
args=[atoken.address, amount], | ||
) | ||
|
||
call_withdraw = one_delta_deployment.flash_aggregator.encodeABI( | ||
fn_name="withdraw", | ||
args=[ | ||
token.address, | ||
wallet_address, | ||
], | ||
) | ||
return [call_transfer, call_withdraw] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
"""Test 1delta lending functions using forked Polygon.""" | ||
import logging | ||
import os | ||
import shutil | ||
|
||
import flaky | ||
import pytest | ||
from eth_account import Account | ||
from eth_account.signers.local import LocalAccount | ||
from eth_typing import HexAddress, HexStr | ||
|
||
from eth_defi.aave_v3.constants import MAX_AMOUNT | ||
from eth_defi.hotwallet import HotWallet | ||
from eth_defi.one_delta.deployment import OneDeltaDeployment | ||
from eth_defi.one_delta.deployment import fetch_deployment as fetch_1delta_deployment | ||
from eth_defi.one_delta.lending import supply, withdraw | ||
from eth_defi.one_delta.position import approve | ||
from eth_defi.provider.anvil import fork_network_anvil, mine | ||
from eth_defi.provider.multi_provider import create_multi_provider_web3 | ||
from eth_defi.token import fetch_erc20_details | ||
from eth_defi.trace import assert_transaction_success_with_explanation | ||
|
||
from .utils import _execute_tx, _print_current_balances | ||
|
||
# https://docs.pytest.org/en/latest/how-to/skipping.html#skip-all-test-functions-of-a-class-or-module | ||
pytestmark = pytest.mark.skipif( | ||
(os.environ.get("JSON_RPC_POLYGON") is None) or (shutil.which("anvil") is None), | ||
reason="Set JSON_RPC_POLYGON env install anvil command to run these tests", | ||
) | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def test_one_delta_supply( | ||
web3, | ||
hot_wallet, | ||
one_delta_deployment, | ||
aave_v3_deployment, | ||
usdc, | ||
ausdc, | ||
weth, | ||
vweth, | ||
): | ||
"""Test supply to Aave via 1delta proxy""" | ||
for fn in approve( | ||
one_delta_deployment=one_delta_deployment, | ||
collateral_token=usdc.contract, | ||
borrow_token=weth.contract, | ||
atoken=ausdc.contract, | ||
vtoken=vweth.contract, | ||
aave_v3_deployment=aave_v3_deployment, | ||
): | ||
_execute_tx(web3, hot_wallet, fn) | ||
|
||
wallet_original_balance = 100_000 * 10**6 | ||
usdc_supply_amount = 10_000 * 10**6 | ||
|
||
supply_fn = supply( | ||
one_delta_deployment=one_delta_deployment, | ||
token=usdc.contract, | ||
amount=usdc_supply_amount, | ||
wallet_address=hot_wallet.address, | ||
) | ||
_execute_tx(web3, hot_wallet, supply_fn, 500_000) | ||
|
||
assert usdc.contract.functions.balanceOf(hot_wallet.address).call() == pytest.approx(wallet_original_balance - usdc_supply_amount) | ||
assert ausdc.contract.functions.balanceOf(hot_wallet.address).call() == pytest.approx(usdc_supply_amount) | ||
|
||
|
||
def test_one_delta_withdraw( | ||
web3, | ||
hot_wallet, | ||
one_delta_deployment, | ||
aave_v3_deployment, | ||
usdc, | ||
ausdc, | ||
weth, | ||
vweth, | ||
): | ||
"""Test withdraw from Aave via 1delta proxy""" | ||
for fn in approve( | ||
one_delta_deployment=one_delta_deployment, | ||
collateral_token=usdc.contract, | ||
borrow_token=weth.contract, | ||
atoken=ausdc.contract, | ||
vtoken=vweth.contract, | ||
aave_v3_deployment=aave_v3_deployment, | ||
): | ||
_execute_tx(web3, hot_wallet, fn) | ||
|
||
wallet_original_balance = 100_000 * 10**6 | ||
usdc_supply_amount = 10_000 * 10**6 | ||
|
||
supply_fn = supply( | ||
one_delta_deployment=one_delta_deployment, | ||
token=usdc.contract, | ||
amount=usdc_supply_amount, | ||
wallet_address=hot_wallet.address, | ||
) | ||
_execute_tx(web3, hot_wallet, supply_fn, 500_000) | ||
|
||
assert usdc.contract.functions.balanceOf(hot_wallet.address).call() == pytest.approx(wallet_original_balance - usdc_supply_amount) | ||
assert ausdc.contract.functions.balanceOf(hot_wallet.address).call() == pytest.approx(usdc_supply_amount) | ||
|
||
# test partial withdrawal | ||
usdc_partial_withdraw_amount = 4_000 * 10**6 | ||
|
||
withdraw_fn = withdraw( | ||
one_delta_deployment=one_delta_deployment, | ||
token=usdc.contract, | ||
atoken=ausdc.contract, | ||
amount=usdc_partial_withdraw_amount, | ||
wallet_address=hot_wallet.address, | ||
) | ||
_execute_tx(web3, hot_wallet, withdraw_fn, 500_000) | ||
|
||
assert usdc.contract.functions.balanceOf(hot_wallet.address).call() == pytest.approx(wallet_original_balance - usdc_supply_amount + usdc_partial_withdraw_amount) | ||
assert ausdc.contract.functions.balanceOf(hot_wallet.address).call() == pytest.approx(usdc_supply_amount - usdc_partial_withdraw_amount) | ||
|
||
# test full withdrawal | ||
withdraw_fn = withdraw( | ||
one_delta_deployment=one_delta_deployment, | ||
token=usdc.contract, | ||
atoken=ausdc.contract, | ||
amount=MAX_AMOUNT, | ||
wallet_address=hot_wallet.address, | ||
) | ||
_execute_tx(web3, hot_wallet, withdraw_fn, 500_000) | ||
|
||
assert usdc.contract.functions.balanceOf(hot_wallet.address).call() == pytest.approx(wallet_original_balance) | ||
assert ausdc.contract.functions.balanceOf(hot_wallet.address).call() == 0 |