Updated on 2026-08-14
This commit is contained in:
parent
e239275ca8
commit
6d7042f24c
14 changed files with 3748 additions and 1 deletions
1
libs/visa/.gitignore
vendored
Normal file
1
libs/visa/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
17
libs/visa/build.gradle.kts
Normal file
17
libs/visa/build.gradle.kts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
plugins {
|
||||
alias(deps.plugins.kotlin.jvm)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
/** Project */
|
||||
implementation(projects.core.utils)
|
||||
|
||||
/** Libs - Other */
|
||||
implementation(deps.web3j.core)
|
||||
implementation(deps.kotlin.coroutines)
|
||||
implementation(deps.arrow.fx)
|
||||
implementation(deps.jodatime)
|
||||
implementation(deps.okHttp.prettyLogging)
|
||||
}
|
||||
270
libs/visa/src/main/java/com/tangem/lib/visa/ERC20.java
Normal file
270
libs/visa/src/main/java/com/tangem/lib/visa/ERC20.java
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
package com.tangem.lib.visa;
|
||||
|
||||
import org.web3j.abi.EventEncoder;
|
||||
import org.web3j.abi.TypeReference;
|
||||
import org.web3j.abi.datatypes.Address;
|
||||
import org.web3j.abi.datatypes.Event;
|
||||
import org.web3j.abi.datatypes.Function;
|
||||
import org.web3j.abi.datatypes.Utf8String;
|
||||
import org.web3j.abi.datatypes.generated.Uint256;
|
||||
import org.web3j.abi.datatypes.generated.Uint8;
|
||||
import org.web3j.crypto.Credentials;
|
||||
import org.web3j.protocol.Web3j;
|
||||
import org.web3j.protocol.core.DefaultBlockParameter;
|
||||
import org.web3j.protocol.core.RemoteFunctionCall;
|
||||
import org.web3j.protocol.core.methods.request.EthFilter;
|
||||
import org.web3j.protocol.core.methods.response.BaseEventResponse;
|
||||
import org.web3j.protocol.core.methods.response.Log;
|
||||
import org.web3j.protocol.core.methods.response.TransactionReceipt;
|
||||
import org.web3j.tx.Contract;
|
||||
import org.web3j.tx.TransactionManager;
|
||||
import org.web3j.tx.gas.ContractGasProvider;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Flowable;
|
||||
|
||||
/**
|
||||
* <p>Auto generated code.
|
||||
* <p><strong>Do not modify!</strong>
|
||||
* <p>Please use the <a href="https://docs.web3j.io/command_line.html">web3j command line tools</a>,
|
||||
* or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the
|
||||
* <a href="https://github.com/web3j/web3j/tree/master/codegen">codegen module</a> to update.
|
||||
*
|
||||
* <p>Generated with web3j version 1.5.0.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
class ERC20 extends Contract {
|
||||
public static final String BINARY = "Bin file was not provided";
|
||||
|
||||
public static final String FUNC_ALLOWANCE = "allowance";
|
||||
|
||||
public static final String FUNC_APPROVE = "approve";
|
||||
|
||||
public static final String FUNC_BALANCEOF = "balanceOf";
|
||||
|
||||
public static final String FUNC_DECIMALS = "decimals";
|
||||
|
||||
public static final String FUNC_NAME = "name";
|
||||
|
||||
public static final String FUNC_SYMBOL = "symbol";
|
||||
|
||||
public static final String FUNC_TOTALSUPPLY = "totalSupply";
|
||||
|
||||
public static final String FUNC_TRANSFER = "transfer";
|
||||
|
||||
public static final String FUNC_TRANSFERFROM = "transferFrom";
|
||||
|
||||
public static final Event APPROVAL_EVENT = new Event("Approval",
|
||||
Arrays.asList(new TypeReference<Address>(true) {
|
||||
}, new TypeReference<Address>(true) {
|
||||
}, new TypeReference<Uint256>() {
|
||||
}));
|
||||
|
||||
public static final Event TRANSFER_EVENT = new Event("Transfer",
|
||||
Arrays.asList(new TypeReference<Address>(true) {
|
||||
}, new TypeReference<Address>(true) {
|
||||
}, new TypeReference<Uint256>() {
|
||||
}));
|
||||
|
||||
@Deprecated
|
||||
protected ERC20(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
|
||||
super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit);
|
||||
}
|
||||
|
||||
protected ERC20(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) {
|
||||
super(BINARY, contractAddress, web3j, credentials, contractGasProvider);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
protected ERC20(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) {
|
||||
super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit);
|
||||
}
|
||||
|
||||
protected ERC20(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) {
|
||||
super(BINARY, contractAddress, web3j, transactionManager, contractGasProvider);
|
||||
}
|
||||
|
||||
public static List<ApprovalEventResponse> getApprovalEvents(TransactionReceipt transactionReceipt) {
|
||||
List<EventValuesWithLog> valueList = staticExtractEventParametersWithLog(APPROVAL_EVENT, transactionReceipt);
|
||||
ArrayList<ApprovalEventResponse> responses = new ArrayList<ApprovalEventResponse>(valueList.size());
|
||||
for (EventValuesWithLog eventValues : valueList) {
|
||||
ApprovalEventResponse typedResponse = new ApprovalEventResponse();
|
||||
typedResponse.log = eventValues.getLog();
|
||||
typedResponse.owner = (String) eventValues.getIndexedValues().get(0).getValue();
|
||||
typedResponse.spender = (String) eventValues.getIndexedValues().get(1).getValue();
|
||||
typedResponse.value = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue();
|
||||
responses.add(typedResponse);
|
||||
}
|
||||
return responses;
|
||||
}
|
||||
|
||||
public static ApprovalEventResponse getApprovalEventFromLog(Log log) {
|
||||
EventValuesWithLog eventValues = staticExtractEventParametersWithLog(APPROVAL_EVENT, log);
|
||||
ApprovalEventResponse typedResponse = new ApprovalEventResponse();
|
||||
typedResponse.log = log;
|
||||
typedResponse.owner = (String) eventValues.getIndexedValues().get(0).getValue();
|
||||
typedResponse.spender = (String) eventValues.getIndexedValues().get(1).getValue();
|
||||
typedResponse.value = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue();
|
||||
return typedResponse;
|
||||
}
|
||||
|
||||
public static List<TransferEventResponse> getTransferEvents(TransactionReceipt transactionReceipt) {
|
||||
List<EventValuesWithLog> valueList = staticExtractEventParametersWithLog(TRANSFER_EVENT, transactionReceipt);
|
||||
ArrayList<TransferEventResponse> responses = new ArrayList<TransferEventResponse>(valueList.size());
|
||||
for (EventValuesWithLog eventValues : valueList) {
|
||||
TransferEventResponse typedResponse = new TransferEventResponse();
|
||||
typedResponse.log = eventValues.getLog();
|
||||
typedResponse.from = (String) eventValues.getIndexedValues().get(0).getValue();
|
||||
typedResponse.to = (String) eventValues.getIndexedValues().get(1).getValue();
|
||||
typedResponse.value = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue();
|
||||
responses.add(typedResponse);
|
||||
}
|
||||
return responses;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static ERC20 load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
|
||||
return new ERC20(contractAddress, web3j, credentials, gasPrice, gasLimit);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static ERC20 load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) {
|
||||
return new ERC20(contractAddress, web3j, transactionManager, gasPrice, gasLimit);
|
||||
}
|
||||
|
||||
public static TransferEventResponse getTransferEventFromLog(Log log) {
|
||||
EventValuesWithLog eventValues = staticExtractEventParametersWithLog(TRANSFER_EVENT, log);
|
||||
TransferEventResponse typedResponse = new TransferEventResponse();
|
||||
typedResponse.log = log;
|
||||
typedResponse.from = (String) eventValues.getIndexedValues().get(0).getValue();
|
||||
typedResponse.to = (String) eventValues.getIndexedValues().get(1).getValue();
|
||||
typedResponse.value = (BigInteger) eventValues.getNonIndexedValues().get(0).getValue();
|
||||
return typedResponse;
|
||||
}
|
||||
|
||||
public static ERC20 load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) {
|
||||
return new ERC20(contractAddress, web3j, credentials, contractGasProvider);
|
||||
}
|
||||
|
||||
public static ERC20 load(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) {
|
||||
return new ERC20(contractAddress, web3j, transactionManager, contractGasProvider);
|
||||
}
|
||||
|
||||
public Flowable<TransferEventResponse> transferEventFlowable(EthFilter filter) {
|
||||
return web3j.ethLogFlowable(filter).map(log -> getTransferEventFromLog(log));
|
||||
}
|
||||
|
||||
public Flowable<TransferEventResponse> transferEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) {
|
||||
EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress());
|
||||
filter.addSingleTopic(EventEncoder.encode(TRANSFER_EVENT));
|
||||
return transferEventFlowable(filter);
|
||||
}
|
||||
|
||||
public Flowable<ApprovalEventResponse> approvalEventFlowable(EthFilter filter) {
|
||||
return web3j.ethLogFlowable(filter).map(log -> getApprovalEventFromLog(log));
|
||||
}
|
||||
|
||||
public Flowable<ApprovalEventResponse> approvalEventFlowable(DefaultBlockParameter startBlock, DefaultBlockParameter endBlock) {
|
||||
EthFilter filter = new EthFilter(startBlock, endBlock, getContractAddress());
|
||||
filter.addSingleTopic(EventEncoder.encode(APPROVAL_EVENT));
|
||||
return approvalEventFlowable(filter);
|
||||
}
|
||||
|
||||
public RemoteFunctionCall<BigInteger> allowance(String owner, String spender) {
|
||||
final Function function = new Function(FUNC_ALLOWANCE,
|
||||
Arrays.asList(new Address(160, owner),
|
||||
new Address(160, spender)),
|
||||
List.of(new TypeReference<Uint256>() {
|
||||
}));
|
||||
return executeRemoteCallSingleValueReturn(function, BigInteger.class);
|
||||
}
|
||||
|
||||
public RemoteFunctionCall<TransactionReceipt> approve(String spender, BigInteger value) {
|
||||
final Function function = new Function(
|
||||
FUNC_APPROVE,
|
||||
Arrays.asList(new Address(160, spender),
|
||||
new Uint256(value)),
|
||||
Collections.emptyList());
|
||||
return executeRemoteCallTransaction(function);
|
||||
}
|
||||
|
||||
public RemoteFunctionCall<BigInteger> balanceOf(String account) {
|
||||
final Function function = new Function(FUNC_BALANCEOF,
|
||||
List.of(new Address(160, account)),
|
||||
List.of(new TypeReference<Uint256>() {
|
||||
}));
|
||||
return executeRemoteCallSingleValueReturn(function, BigInteger.class);
|
||||
}
|
||||
|
||||
public RemoteFunctionCall<BigInteger> decimals() {
|
||||
final Function function = new Function(FUNC_DECIMALS,
|
||||
List.of(),
|
||||
List.of(new TypeReference<Uint8>() {
|
||||
}));
|
||||
return executeRemoteCallSingleValueReturn(function, BigInteger.class);
|
||||
}
|
||||
|
||||
public RemoteFunctionCall<String> name() {
|
||||
final Function function = new Function(FUNC_NAME,
|
||||
List.of(),
|
||||
List.of(new TypeReference<Utf8String>() {
|
||||
}));
|
||||
return executeRemoteCallSingleValueReturn(function, String.class);
|
||||
}
|
||||
|
||||
public RemoteFunctionCall<String> symbol() {
|
||||
final Function function = new Function(FUNC_SYMBOL,
|
||||
List.of(),
|
||||
List.of(new TypeReference<Utf8String>() {
|
||||
}));
|
||||
return executeRemoteCallSingleValueReturn(function, String.class);
|
||||
}
|
||||
|
||||
public RemoteFunctionCall<BigInteger> totalSupply() {
|
||||
final Function function = new Function(FUNC_TOTALSUPPLY,
|
||||
List.of(),
|
||||
List.of(new TypeReference<Uint256>() {
|
||||
}));
|
||||
return executeRemoteCallSingleValueReturn(function, BigInteger.class);
|
||||
}
|
||||
|
||||
public RemoteFunctionCall<TransactionReceipt> transfer(String to, BigInteger value) {
|
||||
final Function function = new Function(
|
||||
FUNC_TRANSFER,
|
||||
Arrays.asList(new Address(160, to),
|
||||
new Uint256(value)),
|
||||
Collections.emptyList());
|
||||
return executeRemoteCallTransaction(function);
|
||||
}
|
||||
|
||||
public RemoteFunctionCall<TransactionReceipt> transferFrom(String from, String to, BigInteger value) {
|
||||
final Function function = new Function(
|
||||
FUNC_TRANSFERFROM,
|
||||
Arrays.asList(new Address(160, from),
|
||||
new Address(160, to),
|
||||
new Uint256(value)),
|
||||
Collections.emptyList());
|
||||
return executeRemoteCallTransaction(function);
|
||||
}
|
||||
|
||||
public static class ApprovalEventResponse extends BaseEventResponse {
|
||||
public String owner;
|
||||
|
||||
public String spender;
|
||||
|
||||
public BigInteger value;
|
||||
}
|
||||
|
||||
public static class TransferEventResponse extends BaseEventResponse {
|
||||
public String from;
|
||||
|
||||
public String to;
|
||||
|
||||
public BigInteger value;
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,139 @@
|
|||
package com.tangem.lib.visa
|
||||
|
||||
import arrow.fx.coroutines.parZip
|
||||
import com.tangem.lib.visa.model.BalancesAndLimits
|
||||
import com.tangem.lib.visa.model.BalancesAndLimits.Balances
|
||||
import com.tangem.lib.visa.model.BalancesAndLimits.Limits
|
||||
import com.tangem.lib.visa.utils.toBigDecimal
|
||||
import com.tangem.lib.visa.utils.toInstant
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.joda.time.Instant
|
||||
import org.web3j.protocol.Web3j
|
||||
import org.web3j.tx.TransactionManager
|
||||
import org.web3j.tx.gas.ContractGasProvider
|
||||
|
||||
internal class DefaultVisaContractInfoProvider(
|
||||
private val web3j: Web3j,
|
||||
private val transactionManager: TransactionManager,
|
||||
private val gasProvider: ContractGasProvider,
|
||||
private val bridgeProcessorAddress: String,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : VisaContractInfoProvider {
|
||||
|
||||
override suspend fun getBalancesAndLimits(walletAddress: String): BalancesAndLimits = withContext(dispatchers.io) {
|
||||
val tangemBridgeProcessor = TangemBridgeProcessor.load(
|
||||
/* contractAddress = */ bridgeProcessorAddress,
|
||||
/* web3j = */ web3j,
|
||||
/* transactionManager = */ transactionManager,
|
||||
/* contractGasProvider = */ gasProvider,
|
||||
)
|
||||
|
||||
parZip(
|
||||
dispatchers.io,
|
||||
{ loadPaymentAccount(walletAddress, tangemBridgeProcessor) },
|
||||
{ loadPaymentTokenInfo(tangemBridgeProcessor) },
|
||||
{ paymentAccount, paymentToken ->
|
||||
fetchBalancesAndLimits(paymentAccount, paymentToken)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun loadPaymentAccount(
|
||||
walletAddress: String,
|
||||
tangemBridgeProcessor: TangemBridgeProcessor,
|
||||
): TangemPaymentAccount {
|
||||
val paymentAccountAddress = tangemBridgeProcessor.getPaymentAccount(walletAddress).send()
|
||||
|
||||
return TangemPaymentAccount.load(paymentAccountAddress, web3j, transactionManager, gasProvider)
|
||||
}
|
||||
|
||||
private fun loadPaymentTokenInfo(tangemBridgeProcessor: TangemBridgeProcessor): PaymentTokenInfo {
|
||||
val paymentTokenContractAddress = tangemBridgeProcessor.paymentToken().send()
|
||||
val paymentTokenContract = ERC20.load(paymentTokenContractAddress, web3j, transactionManager, gasProvider)
|
||||
val paymentTokenDecimals = paymentTokenContract.decimals().send()
|
||||
|
||||
return PaymentTokenInfo(
|
||||
decimals = paymentTokenDecimals.toInt(),
|
||||
contract = paymentTokenContract,
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun fetchBalancesAndLimits(
|
||||
paymentAccount: TangemPaymentAccount,
|
||||
paymentToken: PaymentTokenInfo,
|
||||
): BalancesAndLimits = parZip(
|
||||
dispatchers.io,
|
||||
{ fetchBalances(paymentAccount, paymentToken) },
|
||||
{ fetchLimits(paymentAccount, paymentToken) },
|
||||
{ balances, (oldLimit, newLimit, changeDate) ->
|
||||
BalancesAndLimits(balances, oldLimit, newLimit, changeDate)
|
||||
},
|
||||
)
|
||||
|
||||
private suspend fun fetchBalances(paymentAccount: TangemPaymentAccount, paymentToken: PaymentTokenInfo): Balances {
|
||||
return parZip(
|
||||
dispatchers.io,
|
||||
{ paymentToken.contract.balanceOf(paymentAccount.contractAddress).send() },
|
||||
{ paymentAccount.verifiedBalance().send() },
|
||||
{ paymentAccount.availableForPayment().send() },
|
||||
{ paymentAccount.availableForWithdrawal().send() },
|
||||
{ paymentAccount.availableForDebtPayment().send() },
|
||||
{ paymentAccount.blockedAmount().send() },
|
||||
{ paymentAccount.debtAmount().send() },
|
||||
{ paymentAccount.pendingRefundTotal().send() },
|
||||
) { total, verified, payment, withdrawal, debtPayment, blocked, debt, refund ->
|
||||
val decimals = paymentToken.decimals
|
||||
|
||||
Balances(
|
||||
total = total.toBigDecimal(decimals),
|
||||
verified = verified.toBigDecimal(decimals),
|
||||
available = Balances.Available(
|
||||
forPayment = payment.toBigDecimal(decimals),
|
||||
forWithdrawal = withdrawal.toBigDecimal(decimals),
|
||||
forDebtPayment = debtPayment.toBigDecimal(decimals),
|
||||
),
|
||||
blocked = blocked.toBigDecimal(decimals),
|
||||
debt = debt.toBigDecimal(decimals),
|
||||
pendingRefund = refund.toBigDecimal(decimals),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchLimits(
|
||||
paymentAccount: TangemPaymentAccount,
|
||||
paymentToken: PaymentTokenInfo,
|
||||
): Triple<Limits, Limits, Instant> {
|
||||
val (
|
||||
oldLimit,
|
||||
newLimit,
|
||||
changeDateSeconds,
|
||||
) = paymentAccount.limits().send()
|
||||
|
||||
return Triple(
|
||||
first = getLimits(oldLimit, paymentToken),
|
||||
second = getLimits(newLimit, paymentToken),
|
||||
third = changeDateSeconds.toInstant(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun getLimits(limit: TangemPaymentAccount.Limits, paymentToken: PaymentTokenInfo): Limits = Limits(
|
||||
spendLimit = limit._01_spendLimit.toLimit(paymentToken.decimals),
|
||||
noOtpLimit = limit._02_noOtpSpendLimit.toLimit(paymentToken.decimals),
|
||||
singleTransactionLimit = limit._00_singleTransactionLimit.toBigDecimal(paymentToken.decimals),
|
||||
expirationDate = limit._03_spendLimitsTimer.expireTimestamp.toInstant(),
|
||||
spendPeriodSeconds = limit._04_spendLimitsPeriod,
|
||||
)
|
||||
|
||||
private fun TangemPaymentAccount.Limit.toLimit(decimals: Int): Limits.Limit {
|
||||
return Limits.Limit(
|
||||
limit = _00_limit.toBigDecimal(decimals),
|
||||
spent = _01_spent.toBigDecimal(decimals),
|
||||
)
|
||||
}
|
||||
|
||||
private data class PaymentTokenInfo(
|
||||
val decimals: Int,
|
||||
val contract: ERC20,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
package com.tangem.lib.visa
|
||||
|
||||
import com.ihsanbal.logging.Level
|
||||
import com.ihsanbal.logging.LoggingInterceptor
|
||||
import com.tangem.lib.visa.model.BalancesAndLimits
|
||||
import com.tangem.lib.visa.utils.VisaConfig
|
||||
import com.tangem.lib.visa.utils.VisaConfig.NETWORK_LOGS_TAG
|
||||
import com.tangem.lib.visa.utils.toHexString
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import okhttp3.OkHttpClient
|
||||
import org.web3j.crypto.Credentials
|
||||
import org.web3j.protocol.Web3j
|
||||
import org.web3j.protocol.http.HttpService
|
||||
import org.web3j.tx.FastRawTransactionManager
|
||||
import org.web3j.tx.TransactionManager
|
||||
import org.web3j.tx.gas.ContractGasProvider
|
||||
import org.web3j.tx.gas.StaticEIP1559GasProvider
|
||||
import java.math.BigDecimal
|
||||
import java.math.BigInteger
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
interface VisaContractInfoProvider {
|
||||
|
||||
suspend fun getBalancesAndLimits(walletAddress: String): BalancesAndLimits
|
||||
|
||||
class Builder(
|
||||
private val isNetworkLoggingEnabled: Boolean,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val baseUrl: String = VisaConfig.BASE_RPC_URL,
|
||||
private val bridgeProcessorAddress: String = VisaConfig.BRIDGE_PROCESSOR_CONTRACT_ADDRESS,
|
||||
private val chainId: Long = VisaConfig.CHAIN_ID,
|
||||
private val networkTimeoutSeconds: Long = VisaConfig.NETWORK_TIMEOUT_SECONDS,
|
||||
private val decimals: Int = VisaConfig.DECIMALS,
|
||||
private val gasLimit: Long = VisaConfig.GAS_LIMIT,
|
||||
private val privateKey: String = ByteArray(VisaConfig.PRIVATE_KEY_LENGTH).toHexString(),
|
||||
) {
|
||||
|
||||
fun build(): VisaContractInfoProvider {
|
||||
val web3j = createWeb3J()
|
||||
val gasProvider = createGasProvider()
|
||||
val transactionManager = createTransactionManager(web3j)
|
||||
|
||||
return DefaultVisaContractInfoProvider(
|
||||
web3j = web3j,
|
||||
transactionManager = transactionManager,
|
||||
gasProvider = gasProvider,
|
||||
bridgeProcessorAddress = bridgeProcessorAddress,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createWeb3J(): Web3j {
|
||||
val httpClient = OkHttpClient.Builder().apply {
|
||||
connectTimeout(networkTimeoutSeconds, TimeUnit.SECONDS)
|
||||
readTimeout(networkTimeoutSeconds, TimeUnit.SECONDS)
|
||||
writeTimeout(networkTimeoutSeconds, TimeUnit.SECONDS)
|
||||
|
||||
if (isNetworkLoggingEnabled) {
|
||||
addInterceptor(
|
||||
LoggingInterceptor.Builder()
|
||||
.setLevel(Level.BODY)
|
||||
.tag(NETWORK_LOGS_TAG)
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
}.build()
|
||||
|
||||
val web3jService = HttpService(
|
||||
/* url = */ baseUrl,
|
||||
/* httpClient = */ httpClient,
|
||||
/* includeRawResponses = */ false,
|
||||
)
|
||||
|
||||
return Web3j.build(web3jService)
|
||||
}
|
||||
|
||||
private fun createGasProvider(): ContractGasProvider = StaticEIP1559GasProvider(
|
||||
/* chainId = */ chainId,
|
||||
/* maxFeePerGas = */ BigDecimal.ONE.movePointLeft(decimals).toBigInteger(),
|
||||
/* maxPriorityFeePerGas = */ BigDecimal.ONE.movePointLeft(decimals).toBigInteger(),
|
||||
/* gasLimit = */ BigInteger.valueOf(gasLimit),
|
||||
)
|
||||
|
||||
private fun createTransactionManager(web3j: Web3j): TransactionManager = FastRawTransactionManager(
|
||||
/* web3j = */ web3j,
|
||||
/* credentials = */ Credentials.create(privateKey),
|
||||
/* chainId = */ chainId,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.tangem.lib.visa.model
|
||||
|
||||
import org.joda.time.Instant
|
||||
import java.math.BigDecimal
|
||||
import java.math.BigInteger
|
||||
|
||||
data class BalancesAndLimits(
|
||||
val balances: Balances,
|
||||
val oldLimits: Limits,
|
||||
val newLimits: Limits,
|
||||
val limitsChangeDate: Instant,
|
||||
) {
|
||||
|
||||
data class Balances(
|
||||
val total: BigDecimal,
|
||||
val verified: BigDecimal,
|
||||
val available: Available,
|
||||
val blocked: BigDecimal,
|
||||
val debt: BigDecimal,
|
||||
val pendingRefund: BigDecimal,
|
||||
) {
|
||||
|
||||
data class Available(
|
||||
val forPayment: BigDecimal,
|
||||
val forWithdrawal: BigDecimal,
|
||||
val forDebtPayment: BigDecimal,
|
||||
)
|
||||
}
|
||||
|
||||
data class Limits(
|
||||
val spendLimit: Limit,
|
||||
val noOtpLimit: Limit,
|
||||
val singleTransactionLimit: BigDecimal,
|
||||
val expirationDate: Instant,
|
||||
val spendPeriodSeconds: BigInteger,
|
||||
) {
|
||||
|
||||
data class Limit(
|
||||
val limit: BigDecimal,
|
||||
val spent: BigDecimal,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.lib.visa.utils
|
||||
|
||||
import org.joda.time.Instant
|
||||
import java.math.BigDecimal
|
||||
import java.math.BigInteger
|
||||
|
||||
internal fun BigInteger.toBigDecimal(decimals: Int): BigDecimal {
|
||||
return BigDecimal(this).movePointLeft(decimals)
|
||||
}
|
||||
|
||||
internal fun BigInteger.toInstant(): Instant {
|
||||
return Instant.ofEpochSecond(toLong())
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package com.tangem.lib.visa.utils
|
||||
|
||||
internal fun ByteArray.toHexString(): String = joinToString("") { "%02X".format(it) }
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.tangem.lib.visa.utils
|
||||
|
||||
internal object VisaConfig {
|
||||
|
||||
const val BASE_RPC_URL = "https://rpc-mumbai.maticvigil.com/"
|
||||
const val BRIDGE_PROCESSOR_CONTRACT_ADDRESS = "0x62119697e78178512bfcc456ae6d1b7dee9fbaa6"
|
||||
const val CHAIN_ID = 80_001L
|
||||
const val DECIMALS = 9
|
||||
const val GAS_LIMIT = 500_000_000L
|
||||
const val PRIVATE_KEY_LENGTH = 32
|
||||
|
||||
const val NETWORK_TIMEOUT_SECONDS = 65L
|
||||
const val NETWORK_LOGS_TAG = "VisaNetworkLogs"
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue