1
1
from typing import Union , Optional
2
2
from math import floor
3
3
4
- from ..util import get_entry_prices , get_web3_provider , get_vault_addresses
4
+ from ..util import get_entry_prices , get_web3_provider , get_vault_addresses , checksum
5
5
from ._config import DEFAULT_BSC_RPC_URL
6
6
from .receipt import TransactionReceipt , build_receipt
7
7
from .contracts import DeltaNeutralVault , DeltaNeutralOracle , AutomatedVaultController , DeltaNeutralVaultGateway
10
10
import requests
11
11
import web3 .contract
12
12
from web3 import Web3
13
+ from web3 .constants import MAX_INT
13
14
from attrdict import AttrDict
14
15
from bep20 import BEP20Token
15
16
@@ -47,18 +48,33 @@ def __init__(self, position_key: str, owner_wallet_address: str, owner_wallet_ke
47
48
48
49
""" ------------------ Transactional Methods (Requires private wallet key) ------------------ """
49
50
50
- def do_invest (self , stable_token_amt : int = 0 , asset_token_amt : int = 0 ) -> TransactionReceipt :
51
+ def do_invest (self , stable_token_amt : int = 0 , asset_token_amt : int = 0 , _approve = False ) -> TransactionReceipt :
51
52
"""
52
53
Invest the specified amount of each token into the Automated Vault.
53
54
Use self.asset_token and self.stable_token to identify the underlying assets.
54
55
55
56
:param stable_token_amt: The amount of stable token to deposit
56
57
:param asset_token_amt: The amount of asset token to deposit
58
+ :param _approve: If True, approves the deposit token for spending by the vault token
57
59
:return:
58
60
"""
59
61
assert stable_token_amt > 0 or asset_token_amt > 0 , \
60
62
"Please provide an investment value for either the stable or asset tokens"
61
63
64
+ # Ensure that allowances match desired investment amount
65
+ if stable_token_amt > 0 :
66
+ token_bal = self .stable_token .balanceOf (self .owner_address )
67
+ assert token_bal >= stable_token_amt , \
68
+ f"Insufficient funds to invest { stable_token_amt } { self .stable_token .symbol ()} ({ token_bal } Owned)"
69
+ if _approve :
70
+ self .do_approve_token (self .stable_token )
71
+ if asset_token_amt > 0 :
72
+ token_bal = self .asset_token .balanceOf (self .owner_address )
73
+ assert token_bal >= asset_token_amt , \
74
+ f"Insufficient funds to invest { asset_token_amt } { self .asset_token .symbol ()} ({ token_bal } Owned)"
75
+ if _approve :
76
+ self .do_approve_token (self .asset_token )
77
+
62
78
return self ._execute (self .vault .invest (stable_token_amt , asset_token_amt , shareReceiver = self .owner_address ))
63
79
64
80
def do_withdraw (self , shares : int , pct_stable : float = None , strategy : str = "Minimize Trading" ) -> TransactionReceipt :
@@ -68,14 +84,23 @@ def do_withdraw(self, shares: int, pct_stable: float = None, strategy: str = "Mi
68
84
:param shares: The amount of share to withdraw from the vault (in share tokens) (self.shares()[0] = close position)
69
85
:param pct_stable: The percentage of stable token returned to the owner (.50 = 50% stable and 50% asset returned)
70
86
:param strategy: The strategy to use to withdraw, as shown on the webapp (Minimize Trading, Convert All)
87
+ (NOT IN USE) :param _approve: If True, force approves the vault token to be spent by either the gateway or the vault contract
71
88
"""
72
89
assert self .shares ()[0 ] >= shares , f"Shares owned insufficient to withdraw { shares } " \
73
90
f"({ self .from_wei (shares , self .bep20_vault_token .decimals ())} ) shares"
74
91
75
92
if strategy .lower () == "minimize trading" :
93
+ # assert self.bep20_vault_token.allowance(self.owner_address, self.vault.address) >= shares, \
94
+ # f"Insufficient approval amount - Spender ({self.vault.address}) requires an allowance of {shares} " \
95
+ # f"{self.bep20_vault_token.symbol()} ({self.bep20_vault_token.address})"
96
+
76
97
return self ._execute (self .vault .withdraw (shares ))
77
98
elif strategy .lower () == "convert all" :
78
99
assert pct_stable is not None , "Please provide a stable token percentage to determine token swap"
100
+ assert self .bep20_vault_token .allowance (self .owner_address , self .gateway .address ) >= shares , \
101
+ f"Insufficient approval amount - Spender ({ self .gateway .address } ) requires an allowance of { shares } " \
102
+ f"{ self .bep20_vault_token .symbol ()} ({ self .bep20_vault_token .address } )"
103
+
79
104
assert 0.0 < pct_stable <= 1.0 , "Invalid value for pct_stable parameter, must follow 0.0 < pct_stable <= 1.0"
80
105
81
106
stable_return_bps = floor (pct_stable * 10000 )
@@ -93,17 +118,26 @@ def do_close(self, pct_stable: float = None, strategy: str = "Minimize Trading")
93
118
"""
94
119
return self .do_withdraw (shares = self .shares ()[0 ], pct_stable = pct_stable , strategy = strategy )
95
120
96
- def do_approve_deposit_token (self , token : Union [BEP20Token , str ], amount : int = None ) -> TransactionReceipt :
121
+ def do_approve_token (self , token : Union [BEP20Token , str ], amount : int = None , _spender : str = None ) -> TransactionReceipt :
97
122
"""
98
- Approves the given token for deposit into an Automated Vault.
123
+ Approves the given token for usage by the Automated Vault.
99
124
100
125
:param token: Optional - either the BEP20Token object, or the token address (str)
101
126
:param amount: The amount of token to approve, default = maximum
127
+ :param _spender: (Should not be changed by the caller) The address to give token spending access to
102
128
"""
103
129
if type (token ) != BEP20Token :
104
130
token = BEP20Token (token )
105
131
106
- func_call = token .prepare_approve (self .address , amount )
132
+ if amount is None :
133
+ # Use maximum approval amount if no amount is specified
134
+ amount = 2 ** 256 - 1
135
+
136
+ if _spender is None :
137
+ _spender = self .address
138
+
139
+ func_call = token .prepare_approve (checksum (_spender ), amount )
140
+
107
141
return self ._execute (func_call )
108
142
109
143
0 commit comments