def test_personal_sendTransaction_deprecated( self, web3: "Web3", unlockable_account_dual_type: ChecksumAddress, unlockable_account_pw: str, ) -> None: with pytest.warns(DeprecationWarning): assert web3.eth.getBalance( unlockable_account_dual_type) > web3.toWei(1, 'ether') txn_params: TxParams = { 'from': unlockable_account_dual_type, 'to': unlockable_account_dual_type, 'gas': Wei(21000), 'value': Wei(1), 'gasPrice': web3.toWei(1, 'gwei'), } txn_hash = web3.parity.personal.sendTransaction( txn_params, unlockable_account_pw) assert txn_hash transaction = web3.eth.getTransaction(txn_hash) assert is_same_address(transaction['from'], cast(ChecksumAddress, txn_params['from'])) assert is_same_address(transaction['to'], cast(ChecksumAddress, txn_params['to'])) assert transaction['gas'] == txn_params['gas'] assert transaction['value'] == txn_params['value'] assert transaction['gasPrice'] == txn_params['gasPrice']
def gas_price_strategy_eth_gas_station_or_with_margin( web3: Web3, transaction_params): # FIXME: This is a temporary fix to speed up gas price generation # by fetching from eth_gas_station if possible. # Once we have a reliable gas price calculation this can be removed if int(web3.net.version) == 1: try: response = requests.get(ETH_GAS_STATION_API) if response and response.status_code == 200: data = response.json() log.debug( f"fetched gas price: {Wei(int(data['fast'] * 10e7 * 1.1))} Wei" ) return Wei(int(data["fast"] * 10e7 * 1.1)) except (TimeoutError, ConnectionError, KeyError): log.debug( "Could not fetch from ethgasstation. Falling back to web3 gas estimation." ) gas_price_strategy = construct_time_based_gas_price_strategy( max_wait_seconds=15, sample_size=25) gas_price = Wei( int( gas_price_strategy(web3, transaction_params) * GAS_PRICE_MARGIN)) return gas_price
def test_eth_modifyTransaction(self, web3: "Web3", unlocked_account: ChecksumAddress) -> None: txn_params: TxParams = { 'from': unlocked_account, 'to': unlocked_account, 'value': Wei(1), 'gas': Wei(21000), 'gasPrice': web3.eth.gasPrice, } txn_hash = web3.eth.sendTransaction(txn_params) modified_txn_hash = web3.eth.modifyTransaction( txn_hash, gasPrice=(cast(int, txn_params['gasPrice']) * 2), value=2) modified_txn = web3.eth.getTransaction(modified_txn_hash) assert is_same_address(modified_txn['from'], cast(ChecksumAddress, txn_params['from'])) assert is_same_address(modified_txn['to'], cast(ChecksumAddress, txn_params['to'])) assert modified_txn['value'] == 2 assert modified_txn['gas'] == 21000 assert modified_txn['gasPrice'] == cast(int, txn_params['gasPrice']) * 2
def approve(self, token_address: ChecksumAddress, v2: bool = False, max_approval: Optional[int] = None) -> bool: max_approval = self.max_approval_int if not max_approval else max_approval token_contract = self.get_token_contract(token_address=token_address) router_address = self.addr.router_v2 if v2 else self.addr.router_v1 func = token_contract.functions.approve(router_address, max_approval) logger.info( f'Approving {self.get_token_symbol(token_address=token_address)} - {token_address}...' ) try: gas_limit = Wei( int( Decimal( func.estimateGas({ 'from': self.wallet, 'value': Wei(0) })) * Decimal(1.5))) except Exception: gas_limit = Wei(100000) tx_params = self.get_tx_params(gas=gas_limit) tx = self.build_and_send_tx(func, tx_params=tx_params) receipt = self.w3.eth.wait_for_transaction_receipt(tx, timeout=6000) if receipt['status'] == 0: # fail logger.error( f'Approval call failed at tx {Web3.toHex(primitive=receipt["transactionHash"])}' ) return False self.approved.add((str(token_address), v2)) time.sleep(10) # let tx propagate logger.success('Approved wallet for trading.') return True
def test_personal_send_transaction( self, web3: "Web3", unlockable_account_dual_type: ChecksumAddress, unlockable_account_pw: str, ) -> None: assert web3.eth.get_balance( unlockable_account_dual_type) > constants.WEI_PER_ETHER txn_params: TxParams = { 'from': unlockable_account_dual_type, 'to': unlockable_account_dual_type, 'gas': Wei(21000), 'value': Wei(1), 'gasPrice': web3.toWei(1, 'gwei'), } txn_hash = web3.geth.personal.send_transaction(txn_params, unlockable_account_pw) assert txn_hash transaction = web3.eth.get_transaction(txn_hash) assert is_same_address(transaction['from'], cast(ChecksumAddress, txn_params['from'])) assert is_same_address(transaction['to'], cast(ChecksumAddress, txn_params['to'])) assert transaction['gas'] == txn_params['gas'] assert transaction['value'] == txn_params['value'] assert transaction['gasPrice'] == txn_params['gasPrice']
def _get_initial_setup_safe_data(self, owners: List[str], threshold: int, fallback_handler: str = NULL_ADDRESS, payment_token: str = NULL_ADDRESS, payment: int = 0, payment_receiver: str = NULL_ADDRESS) -> bytes: empty_params: TxParams = { 'gas': Wei(1), 'gasPrice': Wei(1), } if self.safe_version == '1.1.1': return HexBytes(self.master_copy_contract.functions.setup( owners, threshold, NULL_ADDRESS, # Contract address for optional delegate call b'', # Data payload for optional delegate call fallback_handler, # Handler for fallback calls to this contract payment_token, payment, payment_receiver ).buildTransaction(empty_params)['data']) elif self.safe_version == '1.0.0': return HexBytes(self.master_copy_contract.functions.setup( owners, threshold, NULL_ADDRESS, # Contract address for optional delegate call b'', # Data payload for optional delegate call payment_token, payment, payment_receiver ).buildTransaction(empty_params)['data']) else: raise ValueError('Safe version must be 1.1.1 or 1.0.0')
def get_token_balance_wei(self, token_address: ChecksumAddress) -> Wei: token_contract = self.get_token_contract(token_address) try: return Wei(token_contract.functions.balanceOf(self.wallet).call()) except (ABIFunctionNotFound, ContractLogicError): logger.error( f'Contract {token_address} does not have function "balanceOf"') return Wei(0)
async def get_partners_rewards(network: str, from_block: BlockNumber, to_block: BlockNumber, total_reward: Wei) -> Tuple[Rewards, Wei]: """Fetches partners rewards.""" result: Dict = await execute_sw_gql_query( network=network, query=PARTNERS_QUERY, variables=dict(block_number=to_block, ), ) partners = result["partners"] reward_token_address = NETWORKS[network]["REWARD_TOKEN_CONTRACT_ADDRESS"] # process partners points: Dict[ChecksumAddress, int] = {} total_points = 0 total_contributed = 0 for partner in partners: account = Web3.toChecksumAddress(partner["id"]) if account == EMPTY_ADDR_HEX: continue contributed_amount = Wei(int(partner["contributedAmount"])) total_contributed += contributed_amount revenue_share = int(partner["revenueShare"]) prev_account_points = int(partner["distributorPoints"]) updated_at_block = BlockNumber(int(partner["updatedAtBlock"])) if from_block > updated_at_block: updated_at_block = from_block prev_account_points = 0 account_points = prev_account_points + (contributed_amount * revenue_share * (to_block - updated_at_block)) if account_points <= 0: continue points[account] = account_points total_points += account_points if total_contributed <= 0: return {}, total_reward partners_reward = Wei( (total_reward * total_points) // (total_contributed * 10000 * (to_block - from_block))) if partners_reward <= 0: return {}, total_reward partners_reward = min(total_reward, partners_reward) rewards = calculate_points_based_rewards( total_reward=partners_reward, points=points, total_points=total_points, reward_token=reward_token_address, ) return rewards, Wei(total_reward - partners_reward)
def _get_tx_params(self, value: Wei = Wei(0), gas: Wei = Wei(250000)) -> TxParams: """Get generic transaction parameters.""" return { "from": _addr_to_str(self.address), "value": value, "gas": gas, "nonce": max( self.last_nonce, self.w3.eth.getTransactionCount(self.address) ), }
def buy_tokens( self, token_address: ChecksumAddress, amount_bnb: Wei, slippage_percent: int, gas_price: Optional[str], v2: bool = True, ) -> Tuple[bool, Decimal, str]: balance_bnb = self.w3.eth.get_balance(self.wallet) if amount_bnb > balance_bnb - Wei( 2000000000000000): # leave 0.002 BNB for future gas fees logger.error('Not enough BNB balance') return False, Decimal(0), 'Not enough BNB balance' slippage_ratio = (Decimal(100) - Decimal(slippage_percent)) / Decimal(100) final_gas_price = self.w3.eth.gas_price if gas_price is not None and gas_price.startswith('+'): offset = Web3.toWei(Decimal(gas_price) * Decimal(10**9), unit='wei') final_gas_price = Wei(final_gas_price + offset) elif gas_price is not None: final_gas_price = Web3.toWei(gas_price, unit='wei') router_contract = self.contracts.router_v2 if v2 else self.contracts.router_v1 predicted_out = router_contract.functions.getAmountsOut( amount_bnb, [self.addr.wbnb, token_address]).call()[-1] min_output_tokens = Web3.toWei(slippage_ratio * predicted_out, unit='wei') receipt = self.buy_tokens_with_params( token_address=token_address, amount_bnb=amount_bnb, min_output_tokens=min_output_tokens, gas_price=final_gas_price, v2=v2, ) if receipt is None: logger.error('Can\'t get gas estimate') return False, Decimal(0), 'Can\'t get gas estimate' txhash = Web3.toHex(primitive=receipt["transactionHash"]) if receipt['status'] == 0: # fail logger.error(f'Buy transaction failed at tx {txhash}') return False, Decimal(0), txhash amount_out = Decimal(0) logs = self.get_token_contract( token_address=token_address).events.Transfer().processReceipt( receipt) for log in reversed(logs): # only get last withdrawal call if log['address'] != token_address: continue if log['args']['to'] != self.wallet: continue amount_out = Decimal(log['args']['value']) / Decimal( 10**self.get_token_decimals(token_address)) break logger.success(f'Buy transaction succeeded at tx {txhash}') return True, amount_out, txhash
def test_eth_getTransactionReceipt_unmined( self, web3: "Web3", unlocked_account_dual_type: ChecksumAddress) -> None: txn_hash = web3.eth.sendTransaction({ 'from': unlocked_account_dual_type, 'to': unlocked_account_dual_type, 'value': Wei(1), 'gas': Wei(21000), 'gasPrice': web3.eth.gasPrice, }) with pytest.raises(TransactionNotFound): web3.eth.getTransactionReceipt(txn_hash)
def get_tx_params(value: Wei = Wei(0), gas: Wei = Wei(250000)) -> TxParams: """ Get generic transaction parameters. """ logging.info('get_tx_params function was called.') return { "from": addr_to_str(WALLET_ADDRESS), "value": value, "gas": gas, "nonce": w3.eth.getTransactionCount(WALLET_ADDRESS), }
def get_tx_params(self, value: Wei = Wei(0), gas: Wei = Wei(100000), gas_price: Optional[Wei] = None) -> TxParams: # 100000 gas is OK for approval tx, so it's the default params: TxParams = { 'from': self.wallet, 'value': value, 'gas': gas, 'nonce': self.last_nonce, } if gas_price: params['gasPrice'] = gas_price return params
def test_eth_replaceTransaction_gas_price_too_low( self, web3: "Web3", unlocked_account_dual_type: ChecksumAddress) -> None: txn_params: TxParams = { 'from': unlocked_account_dual_type, 'to': unlocked_account_dual_type, 'value': Wei(1), 'gas': Wei(21000), 'gasPrice': Wei(10), } txn_hash = web3.eth.sendTransaction(txn_params) txn_params['gasPrice'] = Wei(9) with pytest.raises(ValueError): web3.eth.replaceTransaction(txn_hash, txn_params)
def test_eth_replaceTransaction_non_existing_transaction( self, web3: "Web3", unlocked_account_dual_type: ChecksumAddress) -> None: txn_params: TxParams = { 'from': unlocked_account_dual_type, 'to': unlocked_account_dual_type, 'value': Wei(1), 'gas': Wei(21000), 'gasPrice': web3.eth.gasPrice, } with pytest.raises(TransactionNotFound): web3.eth.replaceTransaction( HexStr( '0x98e8cc09b311583c5079fa600f6c2a3bea8611af168c52e4b60b5b243a441997' ), txn_params)
def get_buffered_gas_estimate( web3: "Web3", transaction: TxParams, gas_buffer: Wei = Wei(100000)) -> Wei: gas_estimate_transaction = cast(TxParams, dict(**transaction)) gas_estimate = web3.eth.estimateGas(gas_estimate_transaction) gas_limit = get_block_gas_limit(web3) if gas_estimate > gas_limit: raise ValueError( "Contract does not appear to be deployable within the " "current network gas limits. Estimated: {0}. Current gas " "limit: {1}".format(gas_estimate, gas_limit)) return Wei(min(gas_limit, gas_estimate + gas_buffer))
def get_balance(address: str, network: str = config["network"], provider: str = config["provider"], token: Optional[str] = None) -> Wei: """ Get Ethereum balance. :param address: Ethereum address. :type address: str :param network: Ethereum network, defaults to ``mainnet``. :type network: str :param provider: Ethereum network provider, defaults to ``http``. :type provider: str :param token: Infura API endpoint token, defaults to ``4414fea5f7454211956b1627621450b4``. :type token: str :returns: Wei -- Ethereum balance (Wei). >>> from swap.providers.ethereum.rpc import get_balance >>> get_balance("0x70c1eb09363603a3b6391deb2daa6d2561a62f52", "ropsten") 25800000 """ # Check parameter instances if not is_address(address=address): raise AddressError(f"Invalid Ethereum '{address}' address.") web3: Web3 = get_web3(network=network, provider=provider, token=token) balance: int = web3.eth.get_balance(to_checksum_address(address=address)) return Wei(balance)
def __init__(self, order_record: Order, net: Network, dispatcher: Dispatcher, chat_id: int): self.order_record = order_record self.token_record: Token = order_record.token self.net = net self.dispatcher = dispatcher self.chat_id = chat_id self.type = order_record.type # buy (tokens for BNB) or sell (tokens for BNB) self.limit_price: Optional[Decimal] = (Decimal( order_record.limit_price) if order_record.limit_price else None ) # decimal stored as string self.above = order_record.above # Above = True, below = False self.trailing_stop: Optional[ int] = order_record.trailing_stop # in percent self.amount = Wei( int(order_record.amount) ) # in wei, either BNB (buy) or token (sell) depending on "type" self.slippage = order_record.slippage # in percent # gas price in wei or offset from default in gwei (starts with +), if null then use network gas price self.gas_price: Optional[str] = order_record.gas_price self.created = order_record.created self.active = True self.finished = False self.min_price: Optional[Decimal] = None self.max_price: Optional[Decimal] = None
def get_balance(address: str, network: str = config["network"], provider: str = config["provider"], token: Optional[str] = None) -> Wei: """ Get Ethereum balance. :param address: Ethereum address. :type address: str :param network: Ethereum network, defaults to ``mainnet``. :type network: str :param provider: Ethereum network provider, defaults to ``http``. :type provider: str :param token: Infura API endpoint token, defaults to ``4414fea5f7454211956b1627621450b4``. :type token: str :returns: Wei -- Ethereum balance (Wei). >>> from swap.providers.ethereum.rpc import get_balance >>> get_balance(address="0xbaF2Fc3829B6D25739BeDC18a5A83bF519c6Fe8c", network="testnet") 99937915760000000000 """ # Check parameter instances if not is_address(address=address): raise AddressError(f"Invalid Ethereum '{address}' address.") web3: Web3 = get_web3(network=network, provider=provider, token=token) balance: int = web3.eth.get_balance( to_checksum_address(address=address) ) return Wei(balance)
def test_eth_replaceTransaction_incorrect_nonce( self, web3: "Web3", unlocked_account: ChecksumAddress) -> None: txn_params: TxParams = { 'from': unlocked_account, 'to': unlocked_account, 'value': Wei(1), 'gas': Wei(21000), 'gasPrice': web3.eth.gasPrice, } txn_hash = web3.eth.sendTransaction(txn_params) txn = web3.eth.getTransaction(txn_hash) txn_params['gasPrice'] = Wei(web3.eth.gasPrice * 2) txn_params['nonce'] = Nonce(txn['nonce'] + 1) with pytest.raises(ValueError): web3.eth.replaceTransaction(txn_hash, txn_params)
def test_eth_replaceTransaction_already_mined( self, web3: "Web3", unlocked_account_dual_type: ChecksumAddress) -> None: txn_params: TxParams = { 'from': unlocked_account_dual_type, 'to': unlocked_account_dual_type, 'value': Wei(1), 'gas': Wei(21000), 'gasPrice': web3.eth.gasPrice, } txn_hash = web3.eth.sendTransaction(txn_params) web3.eth.waitForTransactionReceipt(txn_hash) txn_params['gasPrice'] = Wei(web3.eth.gasPrice * 2) with pytest.raises(ValueError, match="Supplied transaction with hash"): web3.eth.replaceTransaction(txn_hash, txn_params)
def get_balance(address: str, network: str = config["network"], provider: str = config["provider"]) -> Wei: """ Get XinFin balance. :param address: XinFin address. :type address: str :param network: XinFin network, defaults to ``mainnet``. :type network: str :param provider: XinFin network provider, defaults to ``http``. :type provider: str :returns: Wei -- XinFin balance (Wei). >>> from swap.providers.xinfin.rpc import get_balance >>> get_balance("xdc70c1eb09363603a3b6391deb2daa6d2561a62f52", "mainnet") 71560900 """ # Check parameter instances if not is_address(address=address): raise AddressError(f"Invalid XinFin '{address}' address.") web3: Web3 = get_web3(network=network, provider=provider) balance: int = web3.eth.get_balance( to_checksum_address(address=address, prefix="0x")) return Wei(balance)
class Economics: _default_min_authorization = TToken(40_000, 'T').to_units() _default_min_operator_seconds = 60 * 60 * 24 # one day in seconds _default_fee_rate = Wei(Web3.toWei(1, 'gwei')) # TODO: Reintroduce Adjudicator # Slashing parameters # HASH_ALGORITHM_KECCAK256 = 0 # HASH_ALGORITHM_SHA256 = 1 # HASH_ALGORITHM_RIPEMD160 = 2 # _default_hash_algorithm = HASH_ALGORITHM_SHA256 # _default_base_penalty = 2 # _default_penalty_history_coefficient = 0 # _default_percentage_penalty_coefficient = 100000 # 0.001% # _default_reward_coefficient = 2 def __init__( self, min_operator_seconds: int = _default_min_operator_seconds, min_authorization: int = _default_min_authorization, fee_rate: Wei = _default_fee_rate, # Adjudicator # hash_algorithm: int = _default_hash_algorithm, # base_penalty: int = _default_base_penalty, # penalty_history_coefficient: int = _default_penalty_history_coefficient, # percentage_penalty_coefficient: int = _default_percentage_penalty_coefficient, # reward_coefficient: int = _default_reward_coefficient ): """ :param min_operator_seconds: Min amount of seconds while an operator can't be changed :param min_authorization: Amount of minimum allowable authorization """ # TODO: Reintroduce Adjudicator # :param hash_algorithm: Hashing algorithm # :param base_penalty: Base for the penalty calculation # :param penalty_history_coefficient: Coefficient for calculating the penalty depending on the history # :param percentage_penalty_coefficient: Coefficient for calculating the percentage penalty # :param reward_coefficient: Coefficient for calculating the reward # self.hash_algorithm = hash_algorithm # self.base_penalty = base_penalty # self.penalty_history_coefficient = penalty_history_coefficient # self.percentage_penalty_coefficient = percentage_penalty_coefficient # self.reward_coefficient = reward_coefficient self.min_operator_seconds = min_operator_seconds self.min_authorization = min_authorization self.fee_rate = fee_rate @property def pre_application_deployment_parameters(self) -> Tuple[int, ...]: """Cast coefficient attributes to uint256 compatible type for solidity+EVM""" deploy_parameters = ( # note: order-sensitive self.min_authorization, self.min_operator_seconds, ) return tuple(map(int, deploy_parameters))
def make_trade( self, input_token: AddressLike, output_token: AddressLike, qty: Union[int, Wei], gwei, my_address, my_pk, recipient: AddressLike = None, ) -> HexBytes: """Make a trade by defining the qty of the input token.""" if input_token == ETH_ADDRESS: return self._eth_to_token_swap_input(gwei, my_address, my_pk, output_token, Wei(qty), recipient) else: balance = self.get_token_balance(input_token) if balance < qty: raise InsufficientBalance(balance, qty) if output_token == ETH_ADDRESS: return self._token_to_eth_swap_input( gwei, my_address, my_pk, input_token, qty, recipient) else: return self._token_to_token_swap_input( gwei, my_address, my_pk, input_token, qty, output_token, recipient)
def make_trade_output( self, input_token: AddressLike, output_token: AddressLike, qty: Union[int, Wei], recipient: AddressLike = None, fee: int = None, slippage: float = None, ) -> HexBytes: """Make a trade by defining the qty of the output token.""" if fee is None: fee = 3000 if self.version == 3: logger.warning("No fee set, assuming 0.3%") if slippage is None: slippage = self.default_slippage if input_token == ETH_ADDRESS: balance = self.get_eth_balance() need = self._get_eth_token_output_price(output_token, qty) if balance < need: raise InsufficientBalance(balance, need) return self._eth_to_token_swap_output(output_token, qty, recipient, fee, slippage) elif output_token == ETH_ADDRESS: qty = Wei(qty) return self._token_to_eth_swap_output(input_token, qty, recipient, fee, slippage) else: return self._token_to_token_swap_output(input_token, output_token, qty, recipient, fee, slippage)
def test_eth_replaceTransaction_gas_price_defaulting_minimum( self, web3: "Web3", unlocked_account: ChecksumAddress) -> None: txn_params: TxParams = { 'from': unlocked_account, 'to': unlocked_account, 'value': Wei(1), 'gas': Wei(21000), 'gasPrice': Wei(10), } txn_hash = web3.eth.sendTransaction(txn_params) txn_params.pop('gasPrice') replace_txn_hash = web3.eth.replaceTransaction(txn_hash, txn_params) replace_txn = web3.eth.getTransaction(replace_txn_hash) assert replace_txn['gasPrice'] == 12 # minimum gas price
def create(ethereum_client: EthereumClient, deployer_account: LocalAccount, master_copy_address: str, owners: List[str], threshold: int, fallback_handler: str = NULL_ADDRESS, proxy_factory_address: Optional[str] = None, payment_token: str = NULL_ADDRESS, payment: int = 0, payment_receiver: str = NULL_ADDRESS) -> EthereumTxSent: """ Deploy new Safe proxy pointing to the specified `master_copy` address and configured with the provided `owners` and `threshold`. By default, payment for the deployer of the tx will be `0`. If `proxy_factory_address` is set deployment will be done using the proxy factory instead of calling the `constructor` of a new `DelegatedProxy` Using `proxy_factory_address` is recommended, as it takes less gas. (Testing with `Ganache` and 1 owner 261534 without proxy vs 229022 with Proxy) """ assert owners, 'At least one owner must be set' assert threshold >= len(owners), 'Threshold=%d must be >= %d' % (threshold, len(owners)) initializer = get_safe_contract(ethereum_client.w3, NULL_ADDRESS).functions.setup( owners, threshold, NULL_ADDRESS, # Contract address for optional delegate call b'', # Data payload for optional delegate call fallback_handler, # Handler for fallback calls to this contract, payment_token, payment, payment_receiver ).buildTransaction({'gas': Wei(1), 'gasPrice': Wei(1)})['data'] if proxy_factory_address: proxy_factory = ProxyFactory(proxy_factory_address, ethereum_client) return proxy_factory.deploy_proxy_contract(deployer_account, master_copy_address, initializer=HexBytes(initializer)) proxy_contract = get_delegate_constructor_proxy_contract(ethereum_client.w3) tx = proxy_contract.constructor(master_copy_address, initializer).buildTransaction({'from': deployer_account.address}) tx['gas'] = tx['gas'] * 100000 tx_hash = ethereum_client.send_unsigned_transaction(tx, private_key=deployer_account.key) tx_receipt = ethereum_client.get_transaction_receipt(tx_hash, timeout=60) assert tx_receipt assert tx_receipt['status'] contract_address = tx_receipt['contractAddress'] return EthereumTxSent(tx_hash, tx, contract_address)
def test_eth_signTransaction(self, web3: "Web3", unlocked_account: ChecksumAddress) -> None: txn_params: TxParams = { 'from': unlocked_account, 'to': unlocked_account, 'value': Wei(1), 'gas': Wei(21000), 'gasPrice': web3.eth.gasPrice, 'nonce': Nonce(0), } result = web3.eth.signTransaction(txn_params) signatory_account = web3.eth.account.recover_transaction(result['raw']) assert unlocked_account == signatory_account assert result['tx']['to'] == txn_params['to'] assert result['tx']['value'] == txn_params['value'] assert result['tx']['gas'] == txn_params['gas'] assert result['tx']['gasPrice'] == txn_params['gasPrice'] assert result['tx']['nonce'] == txn_params['nonce']
def sell_tokens_with_params( self, token_address: ChecksumAddress, amount_tokens: Wei, min_output_bnb: Wei, gas_price: Wei, v2: bool, ) -> Optional[TxReceipt]: router_contract = self.contracts.router_v2 if v2 else self.contracts.router_v1 func = router_contract.functions.swapExactTokensForETHSupportingFeeOnTransferTokens( amount_tokens, min_output_bnb, [token_address, self.addr.wbnb], self.wallet, self.deadline(60)) try: gas_limit = Wei( int( Decimal( func.estimateGas({ 'from': self.wallet, 'value': Wei(0) })) * Decimal(1.5))) except Exception as e: logger.warning( f'Error estimating gas price, trying again with older method: {e}' ) func = router_contract.functions.swapExactTokensForETH( amount_tokens, min_output_bnb, [token_address, self.addr.wbnb], self.wallet, self.deadline(60)) try: gas_limit = Wei( int( Decimal( func.estimateGas({ 'from': self.wallet, 'value': Wei(0) })) * Decimal(1.5))) except Exception: logger.error( 'Can\'t get gas estimate, cancelling transaction.') return None if gas_limit > GAS_LIMIT_FAILSAFE: gas_limit = GAS_LIMIT_FAILSAFE params = self.get_tx_params(value=Wei(0), gas=gas_limit, gas_price=gas_price) tx = self.build_and_send_tx(func=func, tx_params=params) return self.w3.eth.wait_for_transaction_receipt(tx, timeout=60)
def validate_price(self, value: Wei, duration: Wei, shares: int, *args, **kwargs) -> bool: expected_price = Wei(shares * duration * self.rate) if value != expected_price: raise ValueError( f"Policy value ({value}) doesn't match expected value ({expected_price})" ) return True