-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathCalculateSendFeesUseCase.kt
145 lines (132 loc) · 5.61 KB
/
CalculateSendFeesUseCase.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package org.p2p.wallet.send.interactor.usecase
import timber.log.Timber
import java.math.BigInteger
import kotlin.coroutines.cancellation.CancellationException
import org.p2p.core.crypto.toBase58Instance
import org.p2p.core.token.Token
import org.p2p.core.utils.Constants
import org.p2p.core.utils.isZeroOrLess
import org.p2p.solanaj.core.FeeAmount
import org.p2p.token.service.converter.TokenServiceAmountsConverter
import org.p2p.wallet.feerelayer.model.FeeCalculationState
import org.p2p.wallet.feerelayer.model.FeeRelayerFee
import org.p2p.wallet.infrastructure.network.provider.TokenKeyProvider
import org.p2p.wallet.send.model.SearchResult
import org.p2p.wallet.send.repository.SendServiceRepository
import org.p2p.wallet.send.repository.SendServiceTransactionError
class CalculateSendFeesUseCase(
private val sendServiceRepository: SendServiceRepository,
private val tokenKeyProvider: TokenKeyProvider,
private val amountsConverter: TokenServiceAmountsConverter,
) {
suspend fun execute(
sourceToken: Token.Active,
feePayerToken: Token.Active,
sourceTokenAmount: BigInteger,
searchResult: SearchResult,
@Suppress("UNUSED_PARAMETER") useCache: Boolean = true
): FeeCalculationState {
try {
val rentExemptionInSol = sendServiceRepository.getTokenRentExemption(
tokenMint = Constants.WRAPPED_SOL_MINT.toBase58Instance()
)
val fees = try {
sendServiceRepository.estimateFees(
userWallet = tokenKeyProvider.publicKeyBase58,
recipient = searchResult.address.toBase58Instance(),
sourceToken = sourceToken,
feePayerToken = feePayerToken,
amount = if (sourceToken.isSOL) {
maxOf(rentExemptionInSol, sourceTokenAmount)
} else {
sourceTokenAmount
},
)
} catch (e: SendServiceTransactionError) {
val feesInSol = FeeAmount(
transactionFee = BigInteger.ZERO,
accountCreationFee = rentExemptionInSol
)
return FeeCalculationState.PoolsNotFound(
feeInSol = FeeRelayerFee(
feesInSol = feesInSol,
feesInFeePayerToken = FeeAmount(
transactionFee = BigInteger.ZERO,
accountCreationFee = convertFromSol(feePayerToken, rentExemptionInSol)
),
feesInSourceToken = FeeAmount(
transactionFee = BigInteger.ZERO,
accountCreationFee = convertFromSol(sourceToken, rentExemptionInSol)
),
expectedFee = feesInSol
),
)
}
if (fees.tokenAccountRent.amount.amount.isZeroOrLess()) {
return FeeCalculationState.NoFees
}
val networkFee = BigInteger.ZERO
val accountCreationFeeInFeePayerToken = fees.tokenAccountRent.amount.amount
val feesInSol = FeeAmount(
transactionFee = networkFee,
accountCreationFee = convertToSol(feePayerToken, accountCreationFeeInFeePayerToken)
)
val feesInFeePayerToken = FeeAmount(
transactionFee = networkFee,
accountCreationFee = accountCreationFeeInFeePayerToken
)
val feesInSourceToken = FeeAmount(
transactionFee = networkFee,
accountCreationFee = convertAmount(
from = feePayerToken,
to = sourceToken,
amount = accountCreationFeeInFeePayerToken
)
)
return FeeCalculationState.Success(
fee = FeeRelayerFee(
feesInSol = feesInSol,
feesInFeePayerToken = feesInFeePayerToken,
feesInSourceToken = feesInSourceToken,
expectedFee = feesInSol
)
)
} catch (e: CancellationException) {
Timber.i("Fee calculation cancelled")
return FeeCalculationState.Cancelled
} catch (e: Throwable) {
Timber.i(e, "Failed to calculateFeesForFeeRelayer")
return FeeCalculationState.Error(e)
}
}
private suspend fun convertToSol(
token: Token.Active,
amount: BigInteger,
): BigInteger {
if (token.isSOL) return amount
return amountsConverter.convertAmount(
amountFrom = token.mintAddressB58 to amount,
mintsToConvertTo = listOf(Constants.WRAPPED_SOL_MINT.toBase58Instance())
)[Constants.WRAPPED_SOL_MINT.toBase58Instance()] ?: BigInteger.ZERO
}
private suspend fun convertFromSol(
token: Token.Active,
amount: BigInteger,
): BigInteger {
if (token.isSOL) return amount
return amountsConverter.convertAmount(
amountFrom = Constants.WRAPPED_SOL_MINT.toBase58Instance() to amount,
mintsToConvertTo = listOf(token.mintAddressB58)
)[token.mintAddressB58] ?: BigInteger.ZERO
}
private suspend fun convertAmount(
from: Token.Active,
to: Token.Active,
amount: BigInteger,
): BigInteger {
return amountsConverter.convertAmount(
amountFrom = from.mintAddressB58 to amount,
mintsToConvertTo = listOf(to.mintAddressB58)
)[to.mintAddressB58] ?: BigInteger.ZERO
}
}