Repository: horizontalsystems/unstoppable-wallet-android
Issue: Send Controller : The fee for ERC20 transfers should be shown in ETH

At the moment the fee shown in ERC20 amount which is somewhat incorrect because the fee is actually paid in ETH (as indicated in the error alert when the ETH balance is 0)

Changed files:
app/src/main/java/io/horizontalsystems/bankwallet/modules/send/SendInteractor.kt
app/src/test/java/io/horizontalsystems/bankwallet/modules/send/SendInteractorTest.kt

diff --git a/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/SendInteractor.kt b/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/SendInteractor.kt
index d1114a8a4..220b22ddb 100644
--- a/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/SendInteractor.kt
+++ b/app/src/main/java/io/horizontalsystems/bankwallet/modules/send/SendInteractor.kt
@@ -38,6 +38,7 @@ class SendInteractor(private val currencyManager: ICurrencyManager,
         get() = clipboardManager.getCopiedText()
 
     private var rate: Rate? = null
+    private var feeRate: Rate? = null
     private val disposables = CompositeDisposable()
 
     override fun retrieveRate() {
@@ -53,6 +54,21 @@ class SendInteractor(private val currencyManager: ICurrencyManager,
                             }
                         }
         )
+
+        adapter.feeCoinCode?.let{
+            disposables.add(
+                    rateStorage.latestRateObservable(it, currencyManager.baseCurrency.code)
+                            .take(1)
+                            .subscribeOn(Schedulers.io())
+                            .observeOn(AndroidSchedulers.mainThread())
+                            .subscribe { fetchedRate ->
+                                feeRate = if (fetchedRate.expired) null else fetchedRate
+                                if (feeRate != null) {
+                                    delegate?.didRateRetrieve()
+                                }
+                            }
+            )
+        }
     }
 
     override fun parsePaymentAddress(address: String): PaymentRequestAddress {
@@ -122,16 +138,24 @@ class SendInteractor(private val currencyManager: ICurrencyManager,
         }
 
         state.coinValue?.let { coinValue ->
+            val coinCode = adapter.feeCoinCode ?: adapter.coin.code
             if ((state.coinValue?.value ?: BigDecimal.ZERO) > BigDecimal.ZERO) {
-                state.feeCoinValue = CoinValue(coin, adapter.fee(coinValue.value, input.address))
+                state.feeCoinValue = CoinValue(coinCode, adapter.fee(coinValue.value, input.address))
             } else {
-                state.feeCoinValue = CoinValue(coin, BigDecimal.ZERO)
+                state.feeCoinValue = CoinValue(coinCode, BigDecimal.ZERO)
             }
         }
 
-        rateValue?.let {
+        var feeCurrencyRate: BigDecimal? = null
+        adapter.feeCoinCode?.let {
+            feeCurrencyRate = feeRate?.value
+        } ?:run {
+            feeCurrencyRate = rateValue
+        }
+
+        feeCurrencyRate?.let { feeRate ->
             state.feeCoinValue?.let { feeCoinValue ->
-                state.feeCurrencyValue = CurrencyValue(baseCurrency, feeCoinValue.value.times(rateValue))
+                state.feeCurrencyValue = CurrencyValue(baseCurrency, feeCoinValue.value.times(feeRate))
             }
         }
 
diff --git a/app/src/test/java/io/horizontalsystems/bankwallet/modules/send/SendInteractorTest.kt b/app/src/test/java/io/horizontalsystems/bankwallet/modules/send/SendInteractorTest.kt
index 0cc02656b..d9707b4e2 100644
--- a/app/src/test/java/io/horizontalsystems/bankwallet/modules/send/SendInteractorTest.kt
+++ b/app/src/test/java/io/horizontalsystems/bankwallet/modules/send/SendInteractorTest.kt
@@ -26,7 +26,9 @@ class SendInteractorTest {
 
     private val currency = Currency("USD", symbol = "\\u0024")
     private val coinCode = CoinCode()
+    private val feeCoinCode = "ETH"
     private val rate = mock(Rate::class.java)
+    private val feeRate = mock(Rate::class.java)
     private val userInput = mock(SendModule.UserInput::class.java)
     private val balance = BigDecimal(123)
     private val zero = BigDecimal.ZERO
@@ -43,9 +45,12 @@ class SendInteractorTest {
         whenever(userInput.inputType).thenReturn(SendModule.InputType.COIN)
         whenever(rate.value).thenReturn(BigDecimal("0.1"))
         whenever(rate.expired).thenReturn(false)
+        whenever(feeRate.value).thenReturn(BigDecimal("0.4"))
+        whenever(feeRate.expired).thenReturn(false)
         whenever(coin.code).thenReturn(coinCode)
         whenever(currencyManager.baseCurrency).thenReturn(currency)
         whenever(rateStorage.latestRateObservable(coinCode, currency.code)).thenReturn(Flowable.just(rate))
+        whenever(rateStorage.latestRateObservable(feeCoinCode, currency.code)).thenReturn(Flowable.just(feeRate))
         whenever(adapter.coin).thenReturn(coin)
         whenever(adapter.balance).thenReturn(balance)
         whenever(adapter.decimal).thenReturn(fiatDecimal)
@@ -249,6 +254,25 @@ class SendInteractorTest {
         Assert.assertEquals(state.feeCurrencyValue, CurrencyValue(currency, value = fee * rate.value))
     }
 
+    @Test
+    fun stateForUserInput_setCurrencyFee_forErc20() {
+        val feeCoinCode = "ETH"
+
+        val fee = BigDecimal("0.000547")
+        val input = SendModule.UserInput()
+        input.address = "address"
+        input.amount = BigDecimal(654)
+        input.inputType = SendModule.InputType.CURRENCY
+
+        whenever(adapter.feeCoinCode).thenReturn(feeCoinCode)
+        whenever(adapter.fee(any(), any())).thenReturn(fee)
+
+        interactor.retrieveRate()
+        val state = interactor.stateForUserInput(input)
+
+        Assert.assertEquals(state.feeCurrencyValue, CurrencyValue(currency, value = fee * feeRate.value))
+    }
+
     @Test
     fun stateForUserInput_setCurrencyFee_InsufficientAmountError() {
         val fee = BigDecimal("0.123")
@@ -373,4 +397,49 @@ class SendInteractorTest {
         Assert.assertEquals(expectedDecimal, state.decimal)
     }
 
+    @Test
+    fun testState_erc20_feeCoinCode(){
+        val decimal = 8
+        val fee = BigDecimal("0.0000044")
+
+        val erc20CoinCode = "TNT"
+        val erc20Coin = Coin("trinitrotoluene", erc20CoinCode, type = CoinType.Erc20("some_address", 3))
+
+        val coinValue = CoinValue(feeCoinCode, fee)
+
+        whenever(adapter.decimal).thenReturn(decimal)
+        whenever(adapter.feeCoinCode).thenReturn(feeCoinCode)
+        whenever(adapter.fee(any(), any())).thenReturn(fee)
+        whenever(adapter.coin).thenReturn(erc20Coin)
+
+        val input = SendModule.UserInput()
+        input.address = "address"
+        input.amount = BigDecimal("0.044")
+        input.inputType = SendModule.InputType.COIN
+
+        val state = interactor.stateForUserInput(input)
+
+        Assert.assertEquals(coinValue, state.feeCoinValue)
+    }
+
+    @Test
+    fun testFetchFeeRate() {
+        whenever(adapter.feeCoinCode).thenReturn(feeCoinCode)
+
+        interactor.retrieveRate()
+
+        verify(delegate, atLeast(2)).didRateRetrieve()
+    }
+
+    @Test
+    fun testFetchFeeRate_noFeeCoinCode() {
+        val feeCoinCode = null
+
+        whenever(adapter.feeCoinCode).thenReturn(feeCoinCode)
+
+        interactor.retrieveRate()
+
+        verify(delegate, atLeastOnce()).didRateRetrieve()
+    }
+
 }