def estimate_tx(self, safe_address: str, to: str, value: int, data: bytes, operation: int,
                    gas_token: Optional[str]) -> TransactionEstimationWithNonce:
        """
        :return: TransactionEstimation with costs using the provided gas token and last used nonce of the Safe
        :raises: InvalidGasToken: If Gas Token is not valid
        """
        if not self._is_valid_gas_token(gas_token):
            raise InvalidGasToken(gas_token)

        last_used_nonce = self.get_last_used_nonce(safe_address)
        safe = Safe(safe_address, self.ethereum_client)
        safe_tx_gas = safe.estimate_tx_gas(to, value, data, operation)
        safe_tx_base_gas = safe.estimate_tx_base_gas(to, value, data, operation, gas_token, safe_tx_gas)

        # For Safe contracts v1.0.0 operational gas is not used (`base_gas` has all the related costs already)
        safe_version = safe.retrieve_version()
        if Version(safe_version) >= Version('1.0.0'):
            safe_tx_operational_gas = 0
        else:
            safe_tx_operational_gas = safe.estimate_tx_operational_gas(len(data) if data else 0)

        # Can throw RelayServiceException
        gas_price = self._estimate_tx_gas_price(self._get_configured_gas_price(), gas_token)
        return TransactionEstimationWithNonce(safe_tx_gas, safe_tx_base_gas, safe_tx_base_gas, safe_tx_operational_gas,
                                              gas_price, gas_token or NULL_ADDRESS, last_used_nonce,
                                              self.tx_sender_account.address)
    def estimate_tx_for_all_tokens(self, safe_address: str, to: str, value: int, data: bytes,
                                   operation: int) -> TransactionEstimationWithNonceAndGasTokens:
        """
        :return: TransactionEstimation with costs using ether and every gas token supported by the service,
        with the last used nonce of the Safe
        :raises: InvalidGasToken: If Gas Token is not valid
        """
        safe = Safe(safe_address, self.ethereum_client)
        last_used_nonce = self.get_last_used_nonce(safe_address)
        safe_tx_gas = safe.estimate_tx_gas(to, value, data, operation)

        safe_version = safe.retrieve_version()
        if Version(safe_version) >= Version('1.0.0'):
            safe_tx_operational_gas = 0
        else:
            safe_tx_operational_gas = safe.estimate_tx_operational_gas(len(data) if data else 0)

        # Calculate `base_gas` for ether and calculate for tokens using the ether token price
        ether_safe_tx_base_gas = safe.estimate_tx_base_gas(to, value, data, operation, NULL_ADDRESS, safe_tx_gas)
        base_gas_price = self._get_configured_gas_price()
        gas_price = self._estimate_tx_gas_price(base_gas_price, NULL_ADDRESS)
        gas_token_estimations = [TransactionGasTokenEstimation(ether_safe_tx_base_gas, gas_price, NULL_ADDRESS)]
        token_gas_difference = 50000  # 50K gas more expensive than ether
        for token in Token.objects.gas_tokens():
            try:
                gas_price = self._estimate_tx_gas_price(base_gas_price, token.address)
                gas_token_estimations.append(
                    TransactionGasTokenEstimation(ether_safe_tx_base_gas + token_gas_difference,
                                                  gas_price, token.address)
                )
            except CannotGetTokenPriceFromApi:
                logger.error('Cannot get price for token=%s', token.address)

        return TransactionEstimationWithNonceAndGasTokens(last_used_nonce, safe_tx_gas, safe_tx_operational_gas,
                                                          gas_token_estimations)
예제 #3
0
    def estimate_tx_for_all_tokens(self, safe_address: str, to: str, value: int, data: str,
                                   operation: int) -> TransactionEstimationWithNonceAndGasTokens:
        last_used_nonce = SafeMultisigTx.objects.get_last_nonce_for_safe(safe_address)
        safe = Safe(safe_address, self.ethereum_client)
        safe_tx_gas = safe.estimate_tx_gas(to, value, data, operation)

        safe_version = safe.retrieve_version()
        if Version(safe_version) >= Version('1.0.0'):
            safe_tx_operational_gas = 0
        else:
            safe_tx_operational_gas = safe.estimate_tx_operational_gas(len(data) if data else 0)

        # Calculate `base_gas` for ether and calculate for tokens using the ether token price
        ether_safe_tx_base_gas = safe.estimate_tx_base_gas(to, value, data, operation, NULL_ADDRESS, safe_tx_gas)
        gas_price = self._estimate_tx_gas_price(NULL_ADDRESS)
        gas_token_estimations = [TransactionGasTokenEstimation(ether_safe_tx_base_gas, gas_price, NULL_ADDRESS)]
        token_gas_difference = 50000  # 50K gas more expensive than ether
        for token in Token.objects.gas_tokens():
            try:
                gas_price = self._estimate_tx_gas_price(token.address)
                gas_token_estimations.append(
                    TransactionGasTokenEstimation(ether_safe_tx_base_gas + token_gas_difference,
                                                  gas_price, token.address)
                )
            except CannotGetTokenPriceFromApi:
                logger.error('Cannot get price for token=%s', token.address)

        return TransactionEstimationWithNonceAndGasTokens(last_used_nonce, safe_tx_gas, safe_tx_operational_gas,
                                                          gas_token_estimations)