Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .github/workflows/ci-unit-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Unit Tests
on:
push:
branches:
- master
- "feature/**"
pull_request:
branches:
- master
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Create local.properties
run: touch local.properties
- name: set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: gradle
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Run Unit tests
run: ./gradlew :tronkit:testDebugUnitTest
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1'

implementation 'com.github.piratecash:hd-wallet-kit-android:a74b51f'
implementation 'com.github.piratecash:hd-wallet-kit-android:8f873a1'

implementation 'androidx.activity:activity-compose:1.7.1'
implementation "androidx.compose.ui:ui:$compose_version"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,17 @@ fun Balance(viewModel: MainViewModel) {
}) {
Text(text = "TEST BUTTON")
}
Spacer(modifier = Modifier.height(10.dp))
Button(onClick = {
viewModel.estimateEnergyTest()
}) {
Text(text = "TEST estimateEnergy")
}

Spacer(modifier = Modifier.height(16.dp))
SelectionContainer {
Text(text = viewModel.estimateEnergyTestResult, fontSize = 18.sp)
}
}
}

Expand Down Expand Up @@ -174,4 +185,4 @@ fun Transactions(viewModel: MainViewModel) {
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,18 @@ import androidx.lifecycle.viewModelScope
import com.google.gson.Gson
import io.horizontalsystems.hdwalletkit.Mnemonic
import io.horizontalsystems.tronkit.TronKit
import io.horizontalsystems.tronkit.contracts.ContractMethodHelper
import io.horizontalsystems.tronkit.contracts.trc20.TransferMethod
import io.horizontalsystems.tronkit.models.Address
import io.horizontalsystems.tronkit.models.FullTransaction
import io.horizontalsystems.tronkit.models.TriggerSmartContract
import io.horizontalsystems.tronkit.network.CreatedTransaction
import io.horizontalsystems.tronkit.network.Network
import io.horizontalsystems.tronkit.rpc.JsonRpc
import io.horizontalsystems.tronkit.rpc.Trc20Provider
import io.horizontalsystems.tronkit.transaction.Fee
import io.horizontalsystems.tronkit.transaction.Signer
import io.horizontalsystems.tronkit.toRawHexString
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.math.BigInteger
Expand All @@ -27,6 +32,13 @@ class MainViewModel(
private val trc20Provider: Trc20Provider
) : ViewModel() {

companion object {
private val testUsdtContractAddress = Address.fromBase58("TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t")
private val testUsdtHolderAddress = Address.fromBase58("TB1WQmj63bHV9Qmuhp39WABzutphMAetSc")
private val testRecipientAddress = Address.fromBase58("TDoRr9CQsGoVb66CJRBsaWbBLRaZmLpfMr")
private val testUsdtAmount = BigInteger.valueOf(12_000_000)
}

var balance: String by mutableStateOf(kit.trxBalance.toBigDecimal().movePointLeft(6).toPlainString())
private set

Expand All @@ -39,7 +51,12 @@ class MainViewModel(
var transactions: List<FullTransaction> by mutableStateOf(listOf())
private set

var estimateEnergyTestResult: String by mutableStateOf("Not started")
private set

init {
Log.e("e", "walletAddress: ${kit.address.base58} / ${kit.address.hex}")

viewModelScope.launch {
kit.start()
}
Expand Down Expand Up @@ -95,11 +112,7 @@ class MainViewModel(
}

private suspend fun sendTrc20() {
val triggerSmartContract = kit.transferTrc20TriggerSmartContract(
contractAddress = Address.fromBase58("TXLAQ63Xg1NAzckPwKHvzw7CSEmLMEqcdj"),
toAddress = Address.fromBase58("TDoRr9CQsGoVb66CJRBsaWbBLRaZmLpfMr"),
amount = BigInteger.valueOf(12_000_000)
)
val triggerSmartContract = usdtTransferTriggerSmartContract()

val fees = kit.estimateFee(triggerSmartContract)
Log.e("e", "fees: ${fees.size}")
Expand All @@ -121,6 +134,61 @@ class MainViewModel(
Log.e("e", "sendResult: $sendResult")
}

private fun usdtTransferTriggerSmartContract(): TriggerSmartContract =
kit.transferTrc20TriggerSmartContract(
contractAddress = testUsdtContractAddress,
toAddress = testRecipientAddress,
amount = testUsdtAmount
)

private fun estimateUsdtTransferTriggerSmartContract(): TriggerSmartContract {
val transferMethod = TransferMethod(testRecipientAddress, testUsdtAmount)

return TriggerSmartContract(
data = transferMethod.encodedABI().toRawHexString(),
ownerAddress = testUsdtHolderAddress,
contractAddress = testUsdtContractAddress,
callTokenValue = null,
callValue = null,
tokenId = null,
functionSelector = TransferMethod.methodSignature,
parameter = ContractMethodHelper
.encodedABI(methodId = byteArrayOf(), arguments = transferMethod.getArguments())
.toRawHexString()
)
}

fun estimateEnergyTest() {
viewModelScope.launch(Dispatchers.Default) {
estimateEnergyTestResult = "Running..."

try {
val triggerSmartContract = estimateUsdtTransferTriggerSmartContract()
val fees = kit.estimateFee(triggerSmartContract)
val energyFee = fees.find { it is Fee.Energy } as? Fee.Energy
val totalFee = fees.sumOf { it.feeInSuns }

estimateEnergyTestResult = buildString {
appendLine("Success")
appendLine("Fees count: ${fees.size}")
appendLine("Energy: ${energyFee?.required ?: "none"}")
appendLine("Energy fee: ${energyFee?.feeInSuns ?: "none"}")
append("Total fee: $totalFee")
}
} catch (error: Throwable) {
Log.e("e", "estimateEnergyTest error", error)
estimateEnergyTestResult = buildString {
appendLine("Failed")
appendLine(error.javaClass.simpleName)
when (error) {
is JsonRpc.ResponseError.RpcError -> append("code=${error.error.code}, message=${error.error.message}")
else -> append(error.message ?: "No message")
}
}
}
}
}

fun sendTrxTest() {
viewModelScope.launch {
try {
Expand Down
5 changes: 4 additions & 1 deletion tronkit/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,17 @@ android {

dependencies {

implementation 'com.github.piratecash:hd-wallet-kit-android:a74b51f'
implementation 'com.github.piratecash:hd-wallet-kit-android:b7599f6'

implementation 'org.bouncycastle:bcpkix-jdk15on:1.70'

implementation 'androidx.core:core-ktx:1.10.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
testImplementation 'junit:junit:4.13.2'
testImplementation 'com.squareup.okhttp3:mockwebserver:4.11.0'
testImplementation 'io.mockk:mockk:1.13.8'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,23 @@ import io.horizontalsystems.tronkit.contracts.trc20.AllowanceMethod
import io.horizontalsystems.tronkit.contracts.trc20.ApproveMethod
import io.horizontalsystems.tronkit.models.Address
import io.horizontalsystems.tronkit.models.TriggerSmartContract
import io.horizontalsystems.tronkit.network.TronGridService
import io.horizontalsystems.tronkit.network.IRpcApiProvider
import io.horizontalsystems.tronkit.rpc.CallJsonRpc
import io.horizontalsystems.tronkit.rpc.DefaultBlockParameter
import java.math.BigInteger

class AllowanceManager(
private val owner: Address,
private val tronGridService: TronGridService
private val rpcApiProvider: IRpcApiProvider
) {

suspend fun allowance(contract: Address, spender: Address): BigInteger {
val response = tronGridService.ethCall(
val rpc = CallJsonRpc(
contractAddress = "0x${contract.hex}",
data = AllowanceMethod(owner, spender).encodedABI().toHexString()
data = AllowanceMethod(owner, spender).encodedABI().toHexString(),
defaultBlockParameter = DefaultBlockParameter.Latest.raw
)
val response = rpcApiProvider.fetch(rpc)
if (response.isEmpty()) throw IllegalStateException()

return BigInteger(response.sliceArray(0..31).toRawHexString(), 16)
Expand Down
Loading
Loading