Updated on 2026-08-14

This commit is contained in:
Tangem 2020-10-01 05:09:09 +00:00
commit 68877f8b16
964 changed files with 10040 additions and 107352 deletions

2
.idea/.gitignore generated vendored
View file

@ -1,2 +0,0 @@
# Default ignored files
/shelf/

View file

@ -1,7 +0,0 @@
<component name="ProjectDictionaryState">
<dictionary name="Денис">
<words>
<w>blockchains</w>
</words>
</dictionary>
</component>

9
.idea/dictionaries/romanpotapov.xml generated Normal file
View file

@ -0,0 +1,9 @@
<component name="ProjectDictionaryState">
<dictionary name="romanpotapov">
<words>
<w>blockchain</w>
<w>passcode</w>
<w>tangem</w>
</words>
</dictionary>
</component>

View file

@ -1,16 +0,0 @@
<component name="ProjectDictionaryState">
<dictionary name="tangem">
<words>
<w>binance</w>
<w>blockchain</w>
<w>cardano</w>
<w>ducatus</w>
<w>ethereum</w>
<w>litecoin</w>
<w>matic</w>
<w>tangem</w>
<w>testnet</w>
<w>tezos</w>
</words>
</dictionary>
</component>

4
.idea/encodings.xml generated
View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
</project>

40
.idea/misc.xml generated
View file

@ -1,45 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeSettings">
<configurations>
<configuration PROFILE_NAME="Debug" CONFIG_NAME="Debug" />
</configurations>
</component>
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="androidx.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="10">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="9">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
<item index="6" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
</list>
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>

View file

@ -3,23 +3,15 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'com.google.firebase.crashlytics'
apply plugin: 'com.google.firebase.firebase-perf'
//apply plugin: 'com.google.firebase.firebase-perf'
apply plugin: 'com.google.gms.google-services'
static def generateVersionName() {
def gitCommitsCount = "git rev-list HEAD --count".execute().text.trim()
// def gitCurrentBranch = "git rev-parse --abbrev-ref HEAD".execute().text.trim()
return gitCommitsCount.toInteger() + 831// + "\\n" + gitCurrentBranch
}
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
android {
compileSdkVersion 28
compileSdkVersion 29
defaultConfig {
applicationId "com.tangem.wallet"
minSdkVersion 21
targetSdkVersion 28
targetSdkVersion 29
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
androidExtensions {
@ -44,26 +36,19 @@ android {
applicationIdSuffix ".debug"
}
}
flavorDimensions ""
productFlavors {
tangemAccess {
versionCode project.hasProperty('versionCode') ? project.property('versionCode') as int : 116
versionName project.hasProperty('versionName') ? project.property('versionName') : "0.1.0.-SNAPSHOT"
applicationId "com.tangem.wallet"
signingConfig signingConfigs.debug
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
coreLibraryDesugaringEnabled true
}
packagingOptions {
pickFirst('META-INF/proguard/okhttp3.pro')
// for one.block:eosiojava:0.1.0
exclude 'lib/x86_64/darwin/libscrypt.dylib'
exclude 'lib/x86_64/freebsd/libscrypt.so'
exclude 'lib/x86_64/linux/libscrypt.so'
exclude 'org.slf4j:slf4j-jdk14:1.7.25'
}
buildToolsVersion '29.0.3'
}
@ -71,100 +56,43 @@ android {
repositories {
maven { url "https://jitpack.io" }
}
configurations {
all*.exclude group: 'com.google.guava', module: 'listenablefuture'
implementation.exclude module:'protobuf-lite'
}
dependencies {
implementation project(':tangem-card-old')
implementation project(':tangem-sdk-old')
implementation project(':server-android')
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin"
implementation 'androidx.core:core-ktx:1.3.1'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
implementation 'com.google.android.material:material:1.2.1'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.10'
implementation 'androidx.navigation:navigation-fragment:2.2.2'
implementation 'androidx.navigation:navigation-ui-ktx:2.2.2'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'com.tangem:blockchain:1.70.0'
implementation 'com.tangem:core:1.63.0'
implementation 'com.tangem:sdk:1.63.0'
//lifecycle
implementation "androidx.lifecycle:lifecycle-runtime:2.2.0"
implementation "androidx.lifecycle:lifecycle-common-java8:2.2.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.fragment:fragment:1.2.4'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation "androidx.preference:preference:1.1.1"
implementation 'androidx.biometric:biometric:1.0.1'
implementation 'androidx.core:core-ktx:1.3.0'
implementation 'com.google.android.material:material:1.1.0'
implementation "org.rekotlin:rekotlin:1.0.4"
implementation 'com.google.dagger:dagger:2.24'
kapt 'com.google.dagger:dagger-compiler:2.21'
annotationProcessor 'com.google.dagger:dagger-compiler:2.21'
implementation 'com.google.zxing:core:3.3.3' // Do not update to 3.4.0, it requires minSdk 24
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.madgag.spongycastle:core:1.56.0.0'
implementation 'com.madgag.spongycastle:prov:1.56.0.0'
implementation 'com.scottyab:rootbeer-lib:0.0.7'
implementation 'com.squareup.retrofit2:converter-gson:2.6.0'
implementation 'com.squareup.retrofit2:retrofit:2.6.0'
implementation 'com.squareup.retrofit2:converter-scalars:2.6.0'
implementation 'com.squareup.retrofit2:converter-jackson:2.6.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.11.0'
implementation "com.squareup.okhttp3:okhttp-sse:3.11.0"
implementation 'com.skyfishjy.ripplebackground:library:1.0.1'
implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
implementation "com.orhanobut:hawk:2.0.1"
implementation 'co.nstant.in:cbor:0.8'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$versions.kotlin"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3"
// implementation 'org.bitcoinj:bitcoinj-parent:0.14.7' //TODO: is this needed?
implementation 'org.bitcoinj:bitcoinj-core:0.15.2'
implementation 'org.greenrobot:eventbus:3.1.1'
// QR
implementation 'com.google.zxing:core:3.3.3'
implementation 'me.dm7.barcodescanner:zxing:1.9.8'
implementation 'info.hoang8f:android-segmented:1.0.6'
implementation 'io.reactivex.rxjava2:rxjava:2.2.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0'
// implementation 'com.github.stellar:java-stellar-sdk:0.4.1'
implementation 'net.i2p.crypto:eddsa:0.3.0'
implementation 'com.google.firebase:firebase-analytics:17.3.0'
implementation 'com.google.firebase:firebase-crashlytics:17.0.0-beta04'
implementation 'com.google.firebase:firebase-perf:19.0.6'
// Camera
implementation 'com.otaliastudios:cameraview:2.6.3'
//dependencies for XRP
implementation files('libs/ripple-core-0.0.1.jar')
//4 dependencies for ripple-core TODO: move to module?
implementation 'net.i2p.crypto:eddsa:0.3.0'
implementation 'org.bouncycastle:bcprov-jdk15on:1.61'
//noinspection DuplicatePlatformClasses
implementation 'org.json:json:20180813'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
// Image Loading - Picasso
implementation 'com.squareup.picasso:picasso:2.71828'
//dependencies for binance
implementation 'com.google.protobuf:protobuf-java:3.11.4'
implementation 'io.grpc:grpc-protobuf:1.17.1'
implementation 'io.grpc:grpc-stub:1.17.1'
implementation 'commons-codec:commons-codec:1.10'
implementation 'org.apache.commons:commons-lang3:3.6'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-joda:2.9.8'
implementation 'joda-time:joda-time:2.10.1'
testImplementation 'junit:junit:4.12'
// Firebase
implementation 'com.google.firebase:firebase-crashlytics:17.2.2'
//dependencies for EOS
implementation 'io.jafka:jeos:0.9.15'
// implementation 'one.block:eosiojava:0.1.0'
implementation 'org.bouncycastle:bcpkix-jdk15on:1.61'
testImplementation 'junit:junit:4.13'
testImplementation "com.google.truth:truth:1.0.1"
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'io.fotoapparat:fotoapparat:2.6.1'
implementation 'com.otaliastudios:cameraview:2.6.1'
//dependencies for flow demo
implementation 'io.grpc:grpc-okhttp:1.28.0'
implementation 'io.grpc:grpc-stub:1.28.0'
//dependencies for TokenEmvEngine
implementation 'com.github.walleth.kethereum:extensions_kotlin:0.81.4'
}

View file

@ -1,18 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
<manifest xmlns:tools="http://schemas.android.com/tools"
package="com.tangem.wallet">
<application
tools:ignore="GoogleAppIndexingWarning">
<provider
android:name="com.tangem.data.LogFileProvider"
android:authorities="@string/log_file_provider_authorities"
android:enabled="true"
android:exported="false"
android:grantUriPermissions="true" />
<!-- <provider-->
<!-- android:name="com.tangem.data.LogFileProvider"-->
<!-- android:authorities="@string/log_file_provider_authorities"-->
<!-- android:enabled="true"-->
<!-- android:exported="false"-->
<!-- android:grantUriPermissions="true" />-->
</application>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View file

@ -1,4 +0,0 @@
package com.tangem;
public class Test {
}

View file

@ -1,74 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
android:height="108dp"
android:width="108dp"
android:viewportHeight="108"
android:viewportWidth="108"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#008577"
android:pathData="M0,0h108v108h-108z"/>
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
</vector>

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View file

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">DEBUG</string>
<string name="log_file_provider_authorities">com.tangem.debug.data.LogFileProvider</string>
<string name="app_name" translatable="false">DEBUG</string>
</resources>

View file

@ -1,18 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
<manifest xmlns:tools="http://schemas.android.com/tools"
package="com.tangem.wallet">
<application
tools:ignore="GoogleAppIndexingWarning">
<provider
android:name="com.tangem.data.LogFileProvider"
android:authorities="@string/log_file_provider_authorities"
android:enabled="true"
android:exported="false"
android:grantUriPermissions="true" />
<!-- <provider-->
<!-- android:name="com.tangem.data.LogFileProvider"-->
<!-- android:authorities="@string/log_file_provider_authorities"-->
<!-- android:enabled="true"-->
<!-- android:exported="false"-->
<!-- android:grantUriPermissions="true" />-->
</application>

View file

@ -1,74 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
android:height="108dp"
android:width="108dp"
android:viewportHeight="108"
android:viewportWidth="108"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#008577"
android:pathData="M0,0h108v108h-108z"/>
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
</vector>

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

View file

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View file

@ -7,7 +7,6 @@
android:name="android.hardware.nfc"
android:required="true" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.USE_BIOMETRICT" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.NFC" />
@ -20,7 +19,7 @@
<uses-feature android:name="android.hardware.camera.autofocus" />
<application
android:name="com.tangem.App"
android:name="com.tangem.tap.TapApplication"
android:allowBackup="true"
android:fullBackupContent="true"
android:icon="@mipmap/ic_launcher"
@ -30,18 +29,12 @@
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<!--<provider-->
<!--android:name="com.tangem.data.LogFileProvider"-->
<!--android:authorities="@string/log_file_provider_authorities"-->
<!--android:enabled="true"-->
<!--android:exported="false"-->
<!--android:grantUriPermissions="true" />-->
<activity
android:name="com.tangem.ui.activity.MainActivity"
android:name="com.tangem.tap.MainActivity"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar">
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -50,6 +43,7 @@
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="www.tangem.com"
android:scheme="http" />
@ -71,9 +65,9 @@
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:scheme="vnd.android.nfc"
android:host="ext"
android:pathPrefix="/android.com:pkg"/>
android:pathPrefix="/android.com:pkg"
android:scheme="vnd.android.nfc" />
</intent-filter>
<intent-filter>
@ -84,6 +78,8 @@
android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="@xml/nfc_tech_filter" />
</activity>
<activity android:name="com.tangem.tap.common.qrCodeScan.ScanQrCodeActivity" />
</application>
</manifest>

View file

@ -1,119 +0,0 @@
[
{
"id": "TANGEM SDK",
"dataKey": {
"privateKey": "11121314151617184771ED81F2BACF57479E4735EB1405083927372D40DA9E92"
},
"transactionKey": {
"privateKey": "11121314151617184771ED81F2BACF57479E4735EB1405081918171615141312"
}
},
{
"id": "TANGEM",
"dataKey": {
"publicKey": "048196AA4B410AC44A3B9CCE18E7BE226AEA070ACC83A9CF67540FAC49AF25129F6A538A28AD6341358E3C4F9963064F7E365372A651D374E5C23CDD37FD099BF2"
},
"transactionKey": {
"publicKey": "04343D40496CBE1FE8A8C026575C435A29141EA3BC335DA5549AB6C64685A646848036D481CF9A989390A8B034B229D99BD49E6F07D2FF02746EA265EF99380A80"
}
},
{
"id": "SUPERBLOOM",
"dataKey": {
"publicKey": "04EAB7F2444CFFA2E9CB4AA01CF1CA3694888811BDF0F8E0CDBCCFB5F497F14A5B86655FEF0C7E8F86841B0C14660E09F28DDFB9690F7302DA56F661A6A064564E"
},
"transactionKey": {
"publicKey": "04D292BFC802FFA70ABB1C094A19F6C6766DD353114C25415871BE4586129648CFD77B22FBC1AF3C612497732A04CF845B41D760AFDD820051AB250798503DB340"
}
},
{
"id": "Qlear Protocol",
"dataKey": {
"publicKey": "048B02F0D912B74294E296654E7A008946A0F51E8B4F1141BCB302716C4D868BADCB495681BEA670FFB125C62816CEB3B3AA4AB5EE7336F9ACEC18955493C40058"
},
"transactionKey": {
"publicKey": "04CBC1131BB4BB717C22CCF91C716A8BDACFB09D962A34FBFCE923B6070A40A35CC4E417B2E5ECC19EC78FA372CFF5A1D937D152981E4F0AFFDC1E60F9F0945272"
}
},
{
"id": "CYCLE[bit]",
"dataKey": {
"publicKey": "04F743D0CFA3D3B7A01F9224ECA40A2F0E09558555D0961417A7B00964ECD0FA3338784C89363A695742AF2B13D73BB30B6E0B4E59CA0A14490ED73DCECE3BCF52"
},
"transactionKey": {
"publicKey": "04ECA685AFD135EF2AB24D07BED71ED82CC1882C282976616DAC655ED3E5B8E75487C131F5D79A87895ECDE89AC58CD1BB220A0C29DD544D8D9AD5156184456F3F"
}
},
{
"id": "Whirl",
"dataKey": {
"publicKey": "040B3484CB923DAB12915B7B4FC174543C242A4E49AD9046B2816F03DAFC344E7570CBCC245F5D82FAFDB7E413538238EDE2C196EEC2F9F91911AFC9C37F757810"
},
"transactionKey": {
"publicKey": "042EC0898ADF5AF4883D2F077E89CE464766E8E47FA03612F5248494C88A923CA2C444EE71D3A2BE67F13FD65C19E114B577F2B12CE856F1AA80DEBB406F325171"
}
},
{
"id": "D1",
"dataKey": {
"publicKey": "046F1155C3E75C2E0A4B816F53B739BA9DB3FC27C4CDE20E634AF09CA2D88A5199F97AE474B5833E69AD5A43FFB2F62E4E9B7A8BCC271805A5DD19A7AB9C9888D6"
},
"transactionKey": {
"publicKey": "04AE9E9C50073ABCF3219A96806BE8B95DCA97A12A0DE3516C25959266F5DFD032B75E1CC926DAAC274EE0E638A2BDB717C4B9C6F28808D6BEAB2F4CBF91E2DD52"
}
},
{
"id": "Coinstruction",
"dataKey": {
"publicKey": "042D6D305E2927FE18762CF2E74B207B3D7239279248450C31C88C4FEBDBC62D07976D10F7838CA52AF5A7ACB052D09EC8C513E7AC204673D2D3D078DBD859DF49"
},
"transactionKey": {
"publicKey": "045B0561BD9E089E54D730D75F5205A1A3E094A2209D0F11002F2423D63F508BFD161F8BBA8FBAC441AD893287D67141BBEE39E403C43D12A9FE1A25BCF3A144E9"
}
},
{
"id": "EvenToken",
"dataKey": {
"publicKey": "040FB60B37682AED10AB8B9DB324BBB10D7CEDF9D189332212C36A641CF81314E6CC8C219245DF04813DBB26931C547B6A4D55A10B5FFB163F54643A97213276F8"
},
"transactionKey": {
"publicKey": "044CEB1A3C2931F55441B39EB06F938542309DDD436DA486DE605187418163B777684C15D10EE5029CDEFB73DBA2BF90173D27CACEBF4CABFD4553C63021ABBEBB"
}
},
{
"id": "CARDANO",
"dataKey": {
"publicKey": "0445C312089E57A6952F96D74FF75C962E1E2C2DDA5FB4195661B92E2744791350FE6C60E1A1D145C6A34D8BEAD57506A90FE4A149A9AA43CFF3C6CAE0748B771E"
},
"transactionKey": {
"publicKey": "04969A008E8A61F92EF8D380DB7BB7B8F6F667CA169934371F544F6697D1D2AF97FB87B8D75F550CD782472D46BFCADF354AF17D807C1D2EB82E184C367CACF1FC"
}
},
{
"id": "RSK",
"dataKey": {
"publicKey": "04997C29B1158D5A5B7EDCF7A7844EA76C630C80CD326C83F2983C2EF0E632B37282D69CEEDB6445B79B26D73073122E22AB0FE1E9A1CA41D991C45057D9DF0F24"
},
"transactionKey": {
"publicKey": "040E9DDC53387F1006F39451AF11EBD377B98484FC81D24A96A55DEFDDF6F1EE35F07B089EFD05E4E93BDE20372171274ECD8D8805D0CB1FFEF012673F4E330C95"
}
},
{
"id": "DIGIX",
"dataKey": {
"publicKey": "049533C082D074ACC285E9B7E97F50F0883DF0308871232ED2370F19CA8993F01C5D4ABAF848949C7628D48F60F68DA3E5726A53C394619179D42D7F20D347001E"
},
"transactionKey": {
"publicKey": "04346D597CBE34A409C4CC77AED4DB2332D18C181DD6EB0A695FEA8672FF790B1C2518DF3A357484BB1EC89BCB1C3F2A962B2781DF094C8EE0F9C45D98BBA92610"
}
},
{
"id": "Start2Coin",
"dataKey": {
"publicKey": "043D21AFD0E20468F210547079819CB947031F4A31E591A4193E98DEE84AFB5976066CDD43F94820E0B5F82C063603B48C9A84B4C28C3B6DD9E54BB66A1C75036F"
},
"transactionKey": {
"publicKey": "0442C6413C81FCCF6FA18318ECEA270F7B7242E82863A9208253A85BEC394E5F58E6A12F9FE8A708BD05B73862C8833EB0634FF98E527277F625D4AB139B86AEAC"
}
}
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -1,106 +0,0 @@
package com.tangem
import android.app.Application
import androidx.appcompat.app.AppCompatDelegate
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.tangem.data.dp.PrefsManager
import com.tangem.data.local.PendingTransactionsStorage
import com.tangem.di.DaggerNetworkComponent
import com.tangem.di.DaggerToastHelperComponent
import com.tangem.di.NetworkComponent
import com.tangem.di.ToastHelperComponent
import com.tangem.server_android.data.LocalStorage
import com.tangem.tangem_card.data.Issuer
import com.tangem.tangem_sdk.android.data.Firmwares
import com.tangem.tangem_sdk.android.data.PINStorage
import com.tangem.util.Analytics
import com.tangem.wallet.BuildConfig
import java.io.InputStreamReader
import java.nio.charset.StandardCharsets
class App : Application() {
companion object {
@get:Synchronized
var instance: App? = null
private set
init {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
}
lateinit var networkComponent: NetworkComponent
lateinit var toastHelperComponent: ToastHelperComponent
lateinit var firmwaresStorage: Firmwares
lateinit var localStorage: LocalStorage
lateinit var pinStorage: PINStorage
lateinit var pendingTransactionsStorage: PendingTransactionsStorage
}
override fun onCreate() {
super.onCreate()
// initialize the singleton
instance = this
networkComponent = DaggerNetworkComponent.create()
toastHelperComponent = buildToastHelperComponent()
PrefsManager.getInstance().init(this)
// common init
if (PINStorage.needInit())
PINStorage.init(applicationContext)
initIssuers()
firmwaresStorage = Firmwares(applicationContext)
localStorage = LocalStorage(applicationContext)
pinStorage = PINStorage()
pendingTransactionsStorage = PendingTransactionsStorage(applicationContext)
if (BuildConfig.DEBUG) {
Runtime.getRuntime().exec("logcat -G 16M")
com.tangem.tangem_card.util.Log.setLogger(
object : com.tangem.tangem_card.util.LoggerInterface {
override fun i(logTag: String, message: String) {
android.util.Log.i(logTag, message)
}
override fun e(logTag: String, message: String) {
android.util.Log.e(logTag, message)
}
override fun v(logTag: String, message: String) {
android.util.Log.v(logTag, message)
}
}
)
}
Analytics.setFirebaseEnabled(this)
}
private fun buildToastHelperComponent(): ToastHelperComponent {
return DaggerToastHelperComponent.builder()
.build()
}
private fun initIssuers() {
try {
applicationContext.assets.open("issuers.json").use { `is` ->
InputStreamReader(`is`, StandardCharsets.UTF_8).use { reader ->
val listType = object : TypeToken<List<Issuer>>() {
}.type
Issuer.fillIssuers(Gson().fromJson(reader, listType))
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}

View file

@ -1,102 +0,0 @@
package com.tangem
import android.app.Activity
object Constant {
const val FLAVOR_TANGEM_ACCESS = "tangemAccess"
const val FLAVOR_TANGEM_CARDANO = "tangemCardano"
const val PREF_LAST_WALLET_ADDRESS = "last_wallet_address"
const val URL_TANGEM = "https://play.google.com/store/apps/details?id=com.tangem.wallet"
const val EXTRA_BLOCKCHAIN_DATA = "BLOCKCHAIN_DATA"
const val WALLET_ADDRESS = "Wallet address"
const val EXTRA_MESSAGE = "message"
const val EXTRA_MODIFICATION = "modification"
const val EXTRA_MODIFICATION_DELETE = "delete"
const val EXTRA_MODIFICATION_UPDATE = "update"
const val EXTRA_MODE = "mode"
const val INTENT_TYPE_TEXT_PLAIN = "text/plain"
// LoadedWalletFragment, VerifyCardFragment
const val REQUEST_CODE_SEND_TRANSACTION = "REQUEST_CODE_SEND_TRANSACTION"
const val REQUEST_CODE_PURGE = "REQUEST_CODE_PURGE"
const val REQUEST_CODE_REQUEST_PIN2_FOR_PURGE = "REQUEST_CODE_REQUEST_PIN2_FOR_PURGE"
const val REQUEST_CODE_VERIFY_CARD = "REQUEST_CODE_VERIFY_CARD"
const val REQUEST_CODE_ENTER_NEW_PIN = "REQUEST_CODE_ENTER_NEW_PIN"
const val REQUEST_CODE_ENTER_NEW_PIN2 = "REQUEST_CODE_ENTER_NEW_PIN2"
const val REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN = "REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN"
const val REQUEST_CODE_SWAP_PIN = "REQUEST_CODE_SWAP_PIN"
const val REQUEST_CODE_RECEIVE_TRANSACTION = "REQUEST_CODE_RECEIVE_TRANSACTION"
// MainFragment
const val REQUEST_CODE_SHOW_CARD_ACTIVITY = "REQUEST_CODE_SHOW_CARD_ACTIVITY"
const val REQUEST_CODE_ENTER_PIN_ACTIVITY = "REQUEST_CODE_ENTER_PIN_ACTIVITY"
const val REQUEST_CODE_SEND_EMAIL = "REQUEST_CODE_SEND_EMAIL"
const val REQUEST_CODE_REQUEST_CAMERA_PERMISSIONS = 3
const val EXTRA_LAST_DISCOVERED_TAG = "extra_last_tag"
const val EXTRA_PIN2 = "PIN2"
// LogoFragment
const val EXTRA_AUTO_HIDE = "extra_auto_hide"
const val MILLIS_AUTO_HIDE = 1000
// PinRequestFragment
const val KEY_ALIAS = "pinKey"
const val KEYSTORE = "AndroidKeyStore"
// QrScanFragment
const val EXTRA_QR_CODE = "QRCode"
// PinSwapFragment
const val EXTRA_CONFIRM_PIN = "confirmPIN"
const val EXTRA_CONFIRM_PIN_2 = "confirmPIN2"
const val EXTRA_NEW_PIN = "newPIN"
const val EXTRA_NEW_PIN_2 = "newPIN2"
// CreateNewWalletFragment
const val RESULT_INVALID_PIN = Activity.RESULT_FIRST_USER
// EmptyWalletFragment
const val REQUEST_CODE_CREATE_NEW_WALLET_ACTIVITY = "REQUEST_CODE_CREATE_NEW_WALLET_ACTIVITY"
const val REQUEST_CODE_REQUEST_PIN2 = "REQUEST_CODE_REQUEST_PIN2"
// ConfirmTransactionFragment
const val REQUEST_CODE_SIGN_TRANSACTION = "REQUEST_CODE_SIGN_TRANSACTION"
const val REQUEST_CODE_REQUEST_PIN2_ = "REQUEST_CODE_REQUEST_PIN2_"
// SendTransactionFragment
const val EXTRA_TX: String = "TX"
// SignTransactionFragment
const val EXTRA_AMOUNT = "Amount"
const val EXTRA_AMOUNT_CURRENCY = "AmountCurrency"
const val EXTRA_FEE = "Fee"
const val EXTRA_FEE_CURRENCY = "FeeCurrency"
const val EXTRA_FEE_INCLUDED = "FeeIncluded"
const val EXTRA_TARGET_ADDRESS = "TargetAddress"
const val REQUEST_CODE_SEND_TRANSACTION_ = "REQUEST_CODE_SEND_TRANSACTION_"
const val RESULT_INVALID_PIN_ = Activity.RESULT_FIRST_USER
// PrepareTransactionFragment
const val REQUEST_CODE_SCAN_QR = "REQUEST_CODE_SCAN_QR"
const val REQUEST_CODE_SEND_TRANSACTION__ = "REQUEST_CODE_SEND_TRANSACTION__"
// PrepareCryptonitOtherApiWithdrawalFragment
const val REQUEST_CODE_SCAN_QR_KEY = "REQUEST_CODE_SCAN_QR_KEY"
const val REQUEST_CODE_SCAN_QR_SECRET = "REQUEST_CODE_SCAN_QR_SECRET"
const val REQUEST_CODE_SCAN_QR_USER_ID = "REQUEST_CODE_SCAN_QR_USER_ID"
const val TERMINAL_PRIVATE_KEY = "terminalPrivateKey"
const val TERMINAL_PUBLIC_KEY = "terminalPublicKey"
}

View file

@ -1,129 +0,0 @@
package com.tangem.data;
import com.tangem.tangem_sdk.R;
/**
* Created by dvol on 06.08.2017.
*/
public enum Blockchain {
Unknown("", "", 1.0, R.drawable.ic_logo_unknown, "Unknown"),
Bitcoin("BTC", "BTC", 100000000.0, R.drawable.ic_logo_bitcoin, "Bitcoin"),
BitcoinTestNet("BTC/test", "BTC", 100000000.0, R.drawable.ic_logo_bitcoin_testnet, "Bitcoin Testnet"),
BitcoinDual("BTC/dual", "BTC", 100000000.0, R.drawable.ic_logo_bitcoin, "Bitcoin"),
Ethereum("ETH", "ETH", 1.0, R.drawable.ic_logo_ethereum, "Ethereum"),
EthereumId("ETH/ID", "ETH", 1.0, R.drawable.ic_logo_ethereum, "Ethereum"),
EthereumTestNet("ETH/test", "ETH", 1.0, R.drawable.ic_logo_ethereum_testnet, "Ethereum Testnet"),
Token("Token", "ETH", 1.0, R.drawable.ic_logo_ethereum, "Ethereum"),
NftToken("NftToken", "", 1.0, R.drawable.ic_logo_ethereum, "Ethereum"),
BitcoinCash("BCH", "BCH", 100000000.0, R.drawable.ic_logo_bitcoin_cash, "Bitcoin Cash"),
Litecoin("LTC", "LTC", 100000000.0, R.drawable.ic_logo_litecoin, "Litecoin"),
Rootstock("RSK", "RBTC", 1.0, R.drawable.tangem2, "RSK"),
RootstockToken("RskToken", "RBTC", 1.0, R.drawable.tangem2, "RSK"),
Cardano("CARDANO", "ADA", 1000000.0, R.drawable.tangem2, "Cardano"),
CardanoShelley("CARDANO-S", "ADA", 1000000.0, R.drawable.tangem2, "Cardano"),
Ripple("XRP", "XRP", 1000000.0, R.drawable.ic_logo_xrp, "XRP Ledger"),
Binance("BINANCE", "BNB", 100000000.0, R.drawable.ic_logo_binance, "Binance"),
BinanceTestNet("BINANCE/test", "BNB", 100000000.0, R.drawable.ic_logo_binance, "Binance Testnet"),
BinanceAsset("BinanceAsset", "BNB", 100000000.0, R.drawable.ic_logo_binance, "Binance"),
Matic("MATIC", "MTX", 1.0, R.drawable.tangem2, "Matic"),
MaticTestNet("MATIC/test", "MTX", 1.0, R.drawable.tangem2, "Matic Testnet"),
Stellar("XLM", "XLM", 10000000.0, R.drawable.ic_logo_stellar, "Stellar"),
StellarTestNet("XLM/test", "XLM", 10000000.0, R.drawable.ic_logo_stellar, "Stellar Testnet"),
StellarAsset("Asset", "XLM", 10000000.0, R.drawable.ic_logo_stellar, "Stellar"),
StellarTag("XLM-Tag", "XLM", 1000000.0, R.drawable.ic_logo_stellar, "Stellar"),
Eos("EOS", "EOS", 10000.0, R.drawable.tangem2, "EOS"),
Ducatus("DUC", "DUC", 100000000.0, R.drawable.tangem2, "Ducatus"),
Tezos("TEZOS", "XTZ", 10000000.0, R.drawable.ic_logo_tezos, "Tezos"),
FlowDemo("FLOW/demo", "", 1.0, R.drawable.tangem2, "Flow demo"),
TokenEmv("TTW", "ETH", 1.0, R.drawable.ic_logo_ethereum, "Ethereum");
Blockchain(String ID, String currency, double multiplier, int imageResource, String officialName) {
mID = ID;
mCurrency = currency;
// mMultiplier = multiplier;
mImageResource = imageResource;
mOfficialName = officialName;
}
private String mID, mOfficialName;
//private double mMultiplier;
private String mCurrency;
private int mImageResource;
public String getID() {
return mID;
}
public String getOfficialName() {
return mOfficialName;
}
// public double getMultiplier() {
// return mMultiplier;
// }
public String getCurrency() {
return mCurrency;
}
public static Blockchain fromId(String id) {
for (Blockchain blockchain : values()) {
if (blockchain.getID().equals(id)) return blockchain;
}
return Blockchain.Unknown;
}
public static Blockchain fromCurrency(String currency) {
for (Blockchain blockchain : values()) {
if (blockchain.getCurrency() == currency) return blockchain;
}
return null;
}
public static String[] getCurrencies() {
String[] result = new String[values().length - 1];
for (int i = 0; i < result.length - 1; i++) {
result[i] = values()[i + 1].getCurrency();
}
return result;
}
private int getImageResource() {
return mImageResource;
}
public int getLogoImageResource(String symbolName) {
switch (this) {
case Token:
if (symbolName.equals("SEED"))
return R.drawable.ic_logo_seed;
break;
case RootstockToken:
if (symbolName.equals("RIF"))
return R.drawable.ic_logo_rif;
}
return getImageResource();
}
public String getUriScheme() {
String scheme = null;
switch (this) {
case Bitcoin:
case BitcoinDual:
scheme = "bitcoin";
break;
case Ethereum:
case Token:
case TokenEmv:
scheme = "ethereum";
break;
case Litecoin:
scheme = "litecoin";
break;
case Ripple:
scheme = "ripple";
}
return scheme;
}
}

View file

@ -1,103 +0,0 @@
package com.tangem.data;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import com.tangem.wallet.R;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Objects;
/**
* Created by dvol on 15.02.2018.
*/
public class LogFileProvider extends ContentProvider {
private static final String TAG = LogFileProvider.class.getSimpleName() + "-oF";
// UriMatcher used to match against incoming requests
private UriMatcher uriMatcher;
@Override
public boolean onCreate() {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// Add a URI to the matcher which will match against the form
// 'content://it.my.app.LogFileProvider/*'
// and return 1 in the case that the incoming Uri matches this pattern
uriMatcher.addURI(Objects.requireNonNull(getContext()).getString(R.string.log_file_provider_authorities), "*", 1);
return true;
}
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
Log.v(TAG, "Called with uri: '" + uri + "'." + uri.getLastPathSegment());
// check incoming Uri against the matcher
switch (uriMatcher.match(uri)) {
// If it returns 1 - then it matches the Uri defined in onCreate
case 1:
// The desired file name is specified by the last segment of the
// path
// E.g.
// 'content://it.my.app.LogFileProvider/Test1.txt'
// Take this and build the path to the file
String fileLocation = getContext().getCacheDir() + File.separator
+ uri.getLastPathSegment();
// Create & return a ParcelFileDescriptor pointing to the file
// Note: I don't care what mode they ask for - they're only getting
// read only
ParcelFileDescriptor pfd = ParcelFileDescriptor.open(new File(fileLocation), ParcelFileDescriptor.MODE_READ_ONLY);
return pfd;
// Otherwise unrecognised Uri
default:
Log.v(TAG, "Unsupported uri: '" + uri + "'.");
throw new FileNotFoundException("Unsupported uri: " + uri.toString());
}
}
// //////////////////////////////////////////////////////////////
// Not supported / used / required for this example
// //////////////////////////////////////////////////////////////
@Override
public int update(Uri uri, ContentValues contentvalues, String s,
String[] as) {
return 0;
}
@Override
public int delete(Uri uri, String s, String[] as) {
return 0;
}
@Override
public Uri insert(Uri uri, ContentValues contentvalues) {
return null;
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Cursor query(Uri uri, String[] projection, String s, String[] as1,
String s1) {
return null;
}
}

View file

@ -1,285 +0,0 @@
package com.tangem.data;
import android.content.Context;
import android.util.Log;
import com.tangem.tangem_card.util.Util;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Date;
public class Logger {
public static File collectLogs(Context context) {
File f = new File(context.getCacheDir().getAbsolutePath() + "/Wallet_" + Util.formatDateTimeToFileName(new Date()) + ".log");
try {
if (f.createNewFile()) {
f.setReadable(true);
FileWriter fileWriter = new FileWriter(f, true);
Process process = Runtime.getRuntime().exec("logcat -d -v time");
try {
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader bufferedReader = new BufferedReader(isr);
BufferedWriter buf = new BufferedWriter(fileWriter);
buf.append("Tangem Wallet logs");
buf.newLine();
int i = 0;
String line;
while ((line = bufferedReader.readLine()) != null) {
buf.append(line);
buf.newLine();
i++;
}
Log.e("Logger", String.format("%d log lines collected", i));
buf.newLine();
buf.flush();
buf.close();
} finally {
process.destroy();
}
return f;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
//public class Logger {
//
// public static File[] getLastLogFiles() {
// File path = new File(Environment.getExternalStorageDirectory(), "Tangem/logs");
// if (!path.exists()) {
// return null;
// }
// File[] files = path.listFiles();
// Arrays.sort(files, new Comparator<File>() {
// @Override
// public int compare(File o1, File o2) {
// if (o1.lastModified() < o2.lastModified()) {
// return -1;
// } else if (o1.lastModified() > o2.lastModified()) {
// return 1;
// }
// return 0;
// }
// });
// if (files.length < 5) return files;
// return Arrays.copyOfRange(files, files.length - 5, files.length);
// }
//
// private static File logFile = null;
//
// private static void initLogFile(Context context) {
// try {
// File path = new File(Environment.getExternalStorageDirectory(), "Tangem/logs");
// if (!path.exists()) {
// path.mkdirs();
// MediaScannerConnection.scanFile(context, new String[]{path.getParentFile().toString()}, null, null);
// }
// logFile = new File(path, String.format("wallet_%s.log", Util.formatDateTimeToFileName(new Date())));
// logFile.createNewFile();
// logFile.setReadable(true);
//
// // initiate media scan and put the new things into the path array to
// // make the scanner aware of the location and the files you want to see
// MediaScannerConnection.scanFile(context, new String[]{logFile.getAbsolutePath()}, null, null);
// } catch (IOException e) {
// e.printStackTrace();
// }
//
// }
//
// public static boolean isCurrent(File f) {
// if (f == null || logFile == null) return false;
// return f.getAbsolutePath().equals(logFile.getAbsolutePath());
// }
//
//
// private static class LogCatThread extends Thread {
// private boolean Terminated;
//
// private static final Object oSync = new Object();
//
// public void Terminate() {
// Terminated = true;
// synchronized (oSync) {
// oSync.notifyAll();
// }
// try {
// join(1000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// interrupt();
// }
// }
//
// public void collectLogs(Writer out) {
// try {
// Process process = Runtime.getRuntime().exec("logcat -d -b main -v time");
// try {
// InputStream is = process.getInputStream();
// InputStreamReader isr = new InputStreamReader(is);
// BufferedReader bufferedReader = new BufferedReader(isr);
// try {
//
// try {
// //BufferedWriter for performance, true to set append to file flag
// BufferedWriter buf = new BufferedWriter(out);
//
// while (!Terminated && isr.ready()) {
// String line = bufferedReader.readLine();
// buf.append(line);
// buf.newLine();
// }
// //Log.i("Logger",String.format("%d lines added",i));
// buf.newLine();
// buf.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
//
//
// } catch (Exception e) {
// e.printStackTrace();
// }
//
// } finally {
// process.destroy();
// }
// } catch (IOException e) {
// e.printStackTrace();
// }
//
// }
//
// @Override
// public void run() {
// Process process = null;
// try {
// if (logFile == null) return;
// process = Runtime.getRuntime().exec("logcat -b main -v time");
// try {
// InputStream is = process.getInputStream();
// InputStreamReader isr = new InputStreamReader(is);
// BufferedReader bufferedReader = new BufferedReader(isr);
// while (!Terminated) {
// try {
// synchronized (oSync) {
// oSync.wait(1000);
// }
// if (!logFile.exists()) {
// try {
// logFile.createNewFile();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
// try {
// //BufferedWriter for performance, true to set append to file flag
// BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true));
//
// while (isr.ready()) {
// String line = bufferedReader.readLine();
// buf.append(line);
// buf.newLine();
// }
// //Log.i("Logger",String.format("%d lines added",i));
// buf.newLine();
// buf.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
//
//
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// } finally {
// process.destroy();
// }
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
// }
//
// static LogCatThread t = new LogCatThread();
//
// public static void StartSaveToFile(Activity activity) {
// try {
// if (logFile != null) return;
//
// verifyStoragePermissions(activity);
// initLogFile(activity.getApplicationContext());
// t.init();
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
//
// public static void StopSaveToFile(Context context) {
// final Object oSync = new Object();
// if (t.isAlive()) {
// t.Terminate();
// }
// if (logFile != null) {
// MediaScannerConnection.scanFile(context, new String[]{logFile.getAbsolutePath().toString()}, null, new MediaScannerConnection.OnScanCompletedListener() {
// @Override
// public void onScanCompleted(String path, Uri uri) {
//// synchronized (oSync) {
//// oSync.notifyAll();
//// }
// }
// });
//// try {
//// synchronized (oSync) {
//// oSync.wait(10000);
// logFile = null;
//// }
//// } catch (InterruptedException e) {
//// e.printStackTrace();
//// }
// }
//
// }
//
// // Storage Permissions
// private static final int REQUEST_EXTERNAL_STORAGE = 1;
// private static String[] PERMISSIONS_STORAGE = {
// Manifest.permission.READ_EXTERNAL_STORAGE,
// Manifest.permission.WRITE_EXTERNAL_STORAGE
// };
//
// //Checks if the app has permission to write to device storage
// //If the app does not has permission then the user will be prompted to grant permissions
// public static void verifyStoragePermissions(Activity activity) {
// // check if we have write permission
// int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
//
// if (permission != PackageManager.PERMISSION_GRANTED) {
// // We don't have permission so prompt the user
// ActivityCompat.requestPermissions(
// activity,
// PERMISSIONS_STORAGE,
// REQUEST_EXTERNAL_STORAGE
// );
// }
// }
//
//}

View file

@ -1,34 +0,0 @@
package com.tangem.data
import java.util.*
private val payIdSupported = EnumSet.of(
Blockchain.Ripple,
Blockchain.Ethereum,
Blockchain.Bitcoin,
Blockchain.Token,
Blockchain.Litecoin,
Blockchain.Stellar,
Blockchain.StellarAsset,
Blockchain.Cardano,
Blockchain.CardanoShelley,
Blockchain.Ducatus,
Blockchain.BitcoinCash,
Blockchain.Binance,
Blockchain.BinanceAsset,
Blockchain.Rootstock,
Blockchain.RootstockToken
)
fun Blockchain.isPayIdSupported(): Boolean {
return payIdSupported.contains(this)
}
fun Blockchain.getPayIdNetwork(): String {
return when (this) {
Blockchain.Ripple -> "XRPL"
Blockchain.Rootstock, Blockchain.RootstockToken -> "RSK"
else -> this.currency
}
}

View file

@ -1,71 +0,0 @@
package com.tangem.data.dp
import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import androidx.preference.PreferenceManager
import com.orhanobut.hawk.Hawk
import com.tangem.Constant
import com.tangem.tangem_card.reader.CardCrypto
class PrefsManager {
companion object {
const val PREF_NAME = "tangem_access"
@SuppressLint("StaticFieldLeak")
private var instance: PrefsManager? = null
fun getInstance(): PrefsManager {
if (instance == null) {
instance = PrefsManager()
}
return instance as PrefsManager
}
}
private lateinit var context: Context
private lateinit var preferences: SharedPreferences
fun init(context: Context) {
this.context = context
preferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
Hawk.init(context).build()
}
val lastWalletAddress: String
get() = Hawk.get(Constant.PREF_LAST_WALLET_ADDRESS, "")
fun saveLastWalletAddress(value: String) {
Hawk.put(Constant.PREF_LAST_WALLET_ADDRESS, value)
}
fun clearLastWalletAddress() {
Hawk.delete(Constant.PREF_LAST_WALLET_ADDRESS)
}
fun getSettingsBoolean(key: Int, default: Boolean): Boolean {
return PreferenceManager.getDefaultSharedPreferences(context)
.getBoolean(context.getString(key), default)
}
fun appendCid(newCid: String) {
val prevCids: String = Hawk.get("CID_Key", "")
if (!prevCids.contains(newCid)) Hawk.put("CID_Key", "$prevCids$newCid, ")
}
fun getAllCids(): String = Hawk.get("CID_Key", "")
val terminalKeys: Map<String, ByteArray>
get() {
val privateKey = Hawk.get<ByteArray>(Constant.TERMINAL_PRIVATE_KEY) ?: byteArrayOf()
val publicKey = Hawk.get<ByteArray>(Constant.TERMINAL_PUBLIC_KEY) ?: byteArrayOf()
return if (privateKey.isNotEmpty() && publicKey.isNotEmpty()) {
mapOf(Constant.TERMINAL_PRIVATE_KEY to privateKey, Constant.TERMINAL_PUBLIC_KEY to publicKey)
} else {
val keys = CardCrypto.generateTerminalKeys()
Hawk.put(Constant.TERMINAL_PRIVATE_KEY, keys[Constant.TERMINAL_PRIVATE_KEY])
Hawk.put(Constant.TERMINAL_PUBLIC_KEY, keys[Constant.TERMINAL_PUBLIC_KEY])
keys
}
}
}

View file

@ -1,61 +0,0 @@
package com.tangem.data.fingerprint;
import android.os.AsyncTask;
import android.widget.Toast;
import com.tangem.ui.fragment.pin.PinSaveFragment;
import com.tangem.wallet.R;
import java.lang.ref.WeakReference;
import javax.crypto.Cipher;
public class ConfirmWithFingerprintTask extends AsyncTask<Void, Void, Boolean> {
private WeakReference<PinSaveFragment> reference;
public ConfirmWithFingerprintTask(PinSaveFragment context) {
reference = new WeakReference<>(context);
reference.get().setFingerprintHelper(new FingerprintHelper(reference.get()));
}
@Override
protected Boolean doInBackground(Void... params) {
PinSaveFragment pinSaveFragment = reference.get();
if (!pinSaveFragment.getKeyStore())
return false;
if (!pinSaveFragment.createNewKey(false))
return false;
if (!pinSaveFragment.getCipher())
return false;
return pinSaveFragment.initCipher(Cipher.ENCRYPT_MODE) && pinSaveFragment.initCryptObject();
}
@Override
protected void onPostExecute(final Boolean success) {
PinSaveFragment pinSaveFragment = reference.get();
onCancelled();
if (!success) {
Toast.makeText(pinSaveFragment.getContext(), R.string.pin_save_notification_failed, Toast.LENGTH_LONG).show();
} else {
pinSaveFragment.getFingerprintHelper().startAuth(pinSaveFragment.getFingerprintManager(), pinSaveFragment.getCryptoObject());
}
}
@Override
protected void onCancelled() {
PinSaveFragment pinSaveFragment = reference.get();
if (pinSaveFragment.getDFingerPrintConfirmation() != null) {
pinSaveFragment.getDFingerPrintConfirmation().cancel();
}
}
}

View file

@ -1,62 +0,0 @@
package com.tangem.data.fingerprint;
import android.annotation.TargetApi;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Build;
import android.os.CancellationSignal;
/**
* Created by dtaka on 8/20/2016.
*/
@TargetApi(Build.VERSION_CODES.M)
public class FingerprintHelper extends FingerprintManager.AuthenticationCallback {
private FingerprintHelperListener listener;
public FingerprintHelper(FingerprintHelperListener listener) {
this.listener = listener;
}
private CancellationSignal cancellationSignal;
public void startAuth(FingerprintManager manager, FingerprintManager.CryptoObject cryptoObject) {
cancellationSignal = new CancellationSignal();
try {
manager.authenticate(cryptoObject, cancellationSignal, 0, this, null);
} catch (SecurityException ex) {
listener.authenticationFailed("An error occurred:\n" + ex.getMessage());
} catch (Exception ex) {
listener.authenticationFailed("An error occurred\n" + ex.getMessage());
}
}
public void cancel() {
if (cancellationSignal != null)
cancellationSignal.cancel();
}
public interface FingerprintHelperListener {
public void authenticationFailed(String error);
public void authenticationSucceeded(FingerprintManager.AuthenticationResult result);
}
@Override
public void onAuthenticationError(int errMsgId, CharSequence errString) {
listener.authenticationFailed("Authentication error\n" + errString);
}
@Override
public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
listener.authenticationFailed("Authentication help\n" + helpString);
}
@Override
public void onAuthenticationFailed() {
listener.authenticationFailed("Authentication failed.");
}
@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
listener.authenticationSucceeded(result);
}
}

View file

@ -1,193 +0,0 @@
package com.tangem.data.fingerprint;
import android.annotation.TargetApi;
import android.hardware.fingerprint.FingerprintManager;
import android.os.AsyncTask;
import android.os.Build;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import com.tangem.Constant;
import com.tangem.tangem_sdk.android.data.PINStorage;
import com.tangem.ui.fragment.pin.PinRequestFragment;
import com.tangem.util.LOG;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
public class StartFingerprintReaderTask extends AsyncTask<Void, Void, Boolean> {
public static final String TAG = StartFingerprintReaderTask.class.getSimpleName();
private WeakReference<PinRequestFragment> reference;
private KeyStore keyStore;
private Cipher cipher;
private FingerprintManager.CryptoObject cryptoObject;
FingerprintManager fingerprintManager;
FingerprintHelper fingerprintHelper;
PinRequestFragment fragment;
public StartFingerprintReaderTask(PinRequestFragment fragment, FingerprintManager fingerprintManager, FingerprintHelper fingerprintHelper) {
reference = new WeakReference<>(fragment);
this.fingerprintManager = fingerprintManager;
this.fingerprintHelper = fingerprintHelper;
this.fragment = fragment;
}
@Override
protected Boolean doInBackground(Void... params) {
if (!getKeyStore())
return false;
if (!createNewKey(false))
return false;
if (!getCipher())
return false;
if (!initCipher(Cipher.DECRYPT_MODE))
return false;
return initCryptObject();
}
@Override
protected void onPostExecute(final Boolean success) {
onCancelled();
if (!success) {
LOG.i(TAG, "Authentication failed!");
} else {
fingerprintHelper.startAuth(fingerprintManager, cryptoObject);
LOG.i(TAG, "Authenticate using fingerprint!");
}
}
@Override
protected void onCancelled() {
PinRequestFragment fragment = reference.get();
fragment.setStartFingerprintReaderTask(null);
}
private boolean getKeyStore() {
LOG.i(TAG, "Getting keystore...");
try {
keyStore = KeyStore.getInstance(Constant.KEYSTORE);
keyStore.load(null); // Create empty keystore
return true;
} catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException e) {
e.printStackTrace();
}
return false;
}
@TargetApi(Build.VERSION_CODES.M)
public boolean createNewKey(boolean forceCreate) {
LOG.i(TAG, "Creating new key...");
try {
if (forceCreate)
keyStore.deleteEntry(Constant.KEY_ALIAS);
if (!keyStore.containsAlias(Constant.KEY_ALIAS)) {
KeyGenerator generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, Constant.KEYSTORE);
generator.init(new KeyGenParameterSpec.Builder(Constant.KEY_ALIAS,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.setUserAuthenticationRequired(true)
.build()
);
generator.generateKey();
LOG.i(TAG, "Key created.");
} else
LOG.i(TAG, "Key exists.");
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
private boolean getCipher() {
LOG.i(TAG, "Getting cipher...");
try {
cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7);
return true;
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
e.printStackTrace();
}
return false;
}
@TargetApi(Build.VERSION_CODES.M)
private boolean initCipher(int mode) {
PinRequestFragment fragment = reference.get();
LOG.i(TAG, "Initializing cipher...");
try {
keyStore.load(null);
SecretKey keyspec = (SecretKey) keyStore.getKey(Constant.KEY_ALIAS, null);
if (mode == Cipher.ENCRYPT_MODE) {
cipher.init(mode, keyspec);
} else {
byte[] iv = null;
if (fragment.getMode() == PinRequestFragment.Mode.RequestPIN ||
fragment.getMode() == PinRequestFragment.Mode.RequestNewPIN ||
fragment.getMode() == PinRequestFragment.Mode.ConfirmNewPIN) {
iv = PINStorage.loadEncryptedIV();
} else if (fragment.getMode() == PinRequestFragment.Mode.RequestPIN2 ||
fragment.getMode() == PinRequestFragment.Mode.RequestNewPIN2 ||
fragment.getMode() == PinRequestFragment.Mode.ConfirmNewPIN2) {
iv = PINStorage.loadEncryptedIV2();
}
IvParameterSpec ivspec = new IvParameterSpec(iv);
cipher.init(mode, keyspec, ivspec);
}
return true;
} catch (KeyPermanentlyInvalidatedException e) {
e.printStackTrace();
createNewKey(true); // Retry after clearing entry
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
@TargetApi(Build.VERSION_CODES.M)
private boolean initCryptObject() {
LOG.i(TAG, "Initializing crypt object...");
try {
cryptoObject = new FingerprintManager.CryptoObject(cipher);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}

View file

@ -1,106 +0,0 @@
package com.tangem.data.local
import android.content.Context
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.tangem.tangem_card.data.TangemCard
import java.io.File
import java.util.*
import kotlin.collections.HashMap
class PendingTransactionsStorage
(
val context: Context
) {
private lateinit var cardTransactions: MutableMap<String, CardTransactionsInfo>
private val transactionsFile: File = File(context.filesDir, "transactions.json")
private var cacheDir: File? = null
init {
cacheDir = File(context.filesDir, "artworks")
if (!cacheDir!!.exists())
cacheDir!!.mkdirs()
if (transactionsFile.exists()) {
try {
transactionsFile.bufferedReader().use { cardTransactions = Gson().fromJson(it, object : TypeToken<HashMap<String, CardTransactionsInfo>>() {}.type) }
} catch (e: Exception) {
e.printStackTrace()
cardTransactions = HashMap()
}
} else {
cardTransactions = HashMap()
}
}
private fun clearExpired()
{
for(cardId in cardTransactions.keys) {
cardTransactions[cardId]!!.transactions.removeAll { it.isExpired() }
}
cardTransactions.entries.removeAll { it.value.isEmpty() }
}
fun save() {
clearExpired()
val sTransactions = Gson().toJson(cardTransactions)
transactionsFile.bufferedWriter().use { it.write(sTransactions) }
}
fun putTransaction(card: TangemCard, txId: String, expireTimeoutInSeconds: Int) {
val sendDate=Date()
val calendar=Calendar.getInstance()
calendar.time=sendDate
calendar.add(Calendar.SECOND, expireTimeoutInSeconds)
val expireDate=calendar.time
putTransaction(card.cidDescription, txId, sendDate, expireDate)
}
private fun putTransaction(cardId: String, txId: String, sendDate: Date, expireDate: Date) {
val transactionInfo = TransactionInfo(
txId, sendDate, expireDate
)
if (cardTransactions[cardId] == null) {
cardTransactions[cardId] = CardTransactionsInfo(arrayListOf())
}
cardTransactions[cardId]?.transactions?.add(transactionInfo)
save()
}
fun getTransactions(card: TangemCard): CardTransactionsInfo? {
clearExpired()
return cardTransactions[card.cidDescription]
}
fun hasTransactions(card: TangemCard): Boolean {
val cardTransactionsInfo=getTransactions(card)
if( cardTransactionsInfo!=null ) return cardTransactionsInfo.transactions.count()>0
return false
}
fun removeTransaction(card: TangemCard, txId: String)
{
cardTransactions[card.cidDescription]?.transactions?.removeAll { it.tx==txId }
save()
}
data class TransactionInfo(
val tx: String,
val sendDate: Date,
val expireDate: Date
) {
fun isExpired(): Boolean {
return Date().after(expireDate)
}
}
data class CardTransactionsInfo(
var transactions: MutableList<TransactionInfo>
) {
fun isEmpty(): Boolean {
return transactions.count()==0
}
}
}

View file

@ -1,30 +0,0 @@
package com.tangem.data.network;
import com.tangem.data.network.model.AdaliteBody;
import com.tangem.data.network.model.AdaliteResponse;
import com.tangem.data.network.model.AdaliteResponseUtxo;
import java.util.List;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Headers;
import retrofit2.http.POST;
import retrofit2.http.Path;
public interface AdaliteApi {
@GET(ServerApiAdalite.ADALITE_ADDRESS)
Call<AdaliteResponse> adaliteAddress(@Path("address") String address);
@Headers("Content-Type: application/json")
@POST(ServerApiAdalite.ADALITE_UNSPENT_OUTPUTS)
Call<AdaliteResponseUtxo> adaliteUnspent(@Body String address);
// @GET(ServerApiAdalite.ADALITE_TRANSACTION)
// Call<AdaliteResponse> adaliteTransaction(@Path("txId") String txId);
@Headers("Content-Type: application/json")
@POST(ServerApiAdalite.ADALITE_SEND)
Call<String> adaliteSend(@Body AdaliteBody adaliteBody);
}

View file

@ -1,13 +0,0 @@
package com.tangem.data.network;
import com.tangem.data.network.model.BinanceFees;
import java.util.List;
import retrofit2.Call;
import retrofit2.http.GET;
public interface BinanceApi {
@GET("fees")
Call<List<BinanceFees>> binanceFees();
}

View file

@ -1,25 +0,0 @@
package com.tangem.data.network;
import com.tangem.data.network.model.BlockchainInfoAddress;
import com.tangem.data.network.model.BlockchainInfoUnspents;
import io.reactivex.Single;
import okhttp3.ResponseBody;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Path;
import retrofit2.http.Query;
public interface BlockchainInfoApi {
@GET(Server.ApiBlockchainInfo.Method.ADDRESS)
Single<BlockchainInfoAddress> blockchainInfoAddress(@Path("address") String address, @Query("offset") Integer offset);
@GET(Server.ApiBlockchainInfo.Method.UTXO)
Single<BlockchainInfoUnspents> blockchainInfoUnspents(@Query("active") String address);
@FormUrlEncoded
@POST(Server.ApiBlockchainInfo.Method.PUSH)
Single<ResponseBody> blockchainInfoPush(@Field("tx") String tx);
}

View file

@ -1,27 +0,0 @@
package com.tangem.data.network;
import com.tangem.data.network.model.BlockchairAddressResponse;
import com.tangem.data.network.model.BlockchairSendBody;
import com.tangem.data.network.model.BlockchairStatsResponse;
import com.tangem.data.network.model.BlockchairTransactionResponse;
import io.reactivex.Completable;
import io.reactivex.Single;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Path;
public interface BlockchairApi {
@GET(Server.ApiBlockchair.Method.ADDRESS)
Single<BlockchairAddressResponse> getAddress(@Path("blockchain") String blockchain, @Path("address") String address);
@GET(Server.ApiBlockchair.Method.TRANSACTION)
Single<BlockchairTransactionResponse> getTransaction(@Path("blockchain") String blockchain, @Path("transaction") String transaction);
@GET(Server.ApiBlockchair.Method.STATS)
Single<BlockchairStatsResponse> getStats(@Path("blockchain") String blockchain);
@POST(Server.ApiBlockchair.Method.PUSH)
Completable sendTransaction(@Path("blockchain") String blockchain, @Body BlockchairSendBody body);
}

View file

@ -1,29 +0,0 @@
package com.tangem.data.network;
import com.tangem.data.network.model.BlockcypherBody;
import com.tangem.data.network.model.BlockcypherResponse;
import com.tangem.data.network.model.BlockcypherFee;
import com.tangem.data.network.model.BlockcypherTx;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Headers;
import retrofit2.http.POST;
import retrofit2.http.Path;
import retrofit2.http.Query;
public interface BlockcypherApi {
@GET(Server.ApiBlockcypher.Method.MAIN)
Call<BlockcypherFee> blockcypherMain(@Path("blockchain") String blockchain, @Path("network") String network, @Query("token") String token);
@GET(Server.ApiBlockcypher.Method.ADDRESS)
Call<BlockcypherResponse> blockcypherAddress(@Path("blockchain") String blockchain, @Path("network") String network, @Path("address") String address, @Query("token") String token);
@GET(Server.ApiBlockcypher.Method.TXS)
Call<BlockcypherTx> blockcypherTxs(@Path("blockchain") String blockchain, @Path("network") String network, @Path("txHash") String txHash, @Query("token") String token);
@Headers("Content-Type: application/json")
@POST(Server.ApiBlockcypher.Method.PUSH)
Call<BlockcypherResponse> blockcypherPush(@Path("blockchain") String blockchain, @Path("network") String network, @Body BlockcypherBody blockcypherBody, @Query("token") String token);
}

View file

@ -1,7 +0,0 @@
package com.tangem.data.network
enum class BlockcypherToken(val token: String) {
T_001("aa8184b0e0894b88a5688e01b3dc1e82"),
T_002("56c4ca23c6484c8f8864c32fde4def8d"),
T_003("66a8a37c5e9d4d2c9bb191acfe7f93aa")
}

View file

@ -1,14 +0,0 @@
package com.tangem.data.network;
import com.tangem.data.network.model.RateInfoResponse;
import io.reactivex.Observable;
import retrofit2.http.GET;
import retrofit2.http.Headers;
import retrofit2.http.Query;
public interface CoinmarketApi {
@Headers("X-CMC_PRO_API_KEY: f6622117-c043-47a0-8975-9d673ce484de")
@GET(Server.ApiCoinmarket.Method.PRICE_CONVERSION)
Observable<RateInfoResponse> getRateInfo(@Query("amount") int amount, @Query("symbol") String cryptoId);
}

View file

@ -1,317 +0,0 @@
package com.tangem.data.network;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.internal.LinkedTreeMap;
import com.jakewharton.retrofit2.adapter.rxjava2.HttpException;
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import com.tangem.wallet.R;
import java.io.IOException;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
//import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.Body;
import retrofit2.http.Header;
import retrofit2.http.Headers;
import retrofit2.http.POST;
/**
* HTTP
* Used in Cryptonit service
*/
public class Cryptonit {
private static final String SERVER_URL = "https://www.cryptonit.net:443/gateway/";
private static class Method {
public static final String AUTHENTICATE = SERVER_URL + "public/authenticate";
public static final String BALANCE = SERVER_URL + "private/balance";
public static final String WITHDRAW_COINS = SERVER_URL + "private/withdrawCoins";
}
public static class Model {
static class Authenticate
{
public static class Request
{
public String username;
public String password;
}
public static class Response
{
boolean success;
String[] missing_authenticators;
public Object[] infos;
public Object[] warnings;
public Object[] errors;
AuthenticationResult results;
}
static class AuthenticationResult {
// token (string): authentication token,
// nick (string),
// stayLoggedIn (boolean),
// integer lastLogin (integer): JavaScript time OR NEVER for first login,
// preferredLanguage (string) = ['en' or 'de']
}
}
public static class Balance {
static class Request {
String[] currencies;
}
public static class Response {
public boolean success;
public Object[] infos;
public Object[] warnings;
public Object[] errors;
public BalanceResult[] results;
public static class BalanceResult {
public String currency;
public double balance;
public String receiveAddress; //the current address to receive funds for this account, if available,
public boolean fiat; // Is this a FIAT currency? If false, this is a CRYPTO currency.,
public Object[] unprocessedTransactions; // (array, optional): list of unprocessed transactions, if pass field withTransactions
}
}
}
public static class WithdrawCoins {
public static class Request {
public String currency;
public Double amount;
String toAddress;
Double includeMinerFee;
String password;
}
public static class Response {
public Boolean success;
public String[] missing_authenticators;
public Object[] infos;
public Object[] warnings;
public Object[] errors;
}
}
}
public interface Api {
@Headers("Content-Type: application/json")
@POST(Method.AUTHENTICATE)
Call<Model.Authenticate.Response> authenticate(@Body Model.Authenticate.Request request);
@Headers("Content-Type: application/json")
@POST(Method.BALANCE)
Observable<Model.Balance.Response> getBalance(@Header("Auth-Token") String authToken, @Body Model.Balance.Request request);
@Headers("Content-Type: application/json")
@POST(Method.WITHDRAW_COINS)
Observable<Model.WithdrawCoins.Response> withdrawCoins(@Header("Auth-Token") String authToken, @Body Model.WithdrawCoins.Request request);
}
private Api api = null;
private BalanceListener balanceListener;
private WithdrawalListener withdrawalListener;
private ErrorListener errorListener;
private Context context;
private String authToken;
public Cryptonit(Context context) {
this.context = context;
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
username = sp.getString(context.getResources().getString(R.string.key_cryptonit_username), "");
password = sp.getString(context.getResources().getString(R.string.key_cryptonit_password), "");
fee = sp.getString(context.getResources().getString(R.string.key_cryptonit_fee), "0.0");
}
public String username;
public String password;
private String fee;
public String getFee() {
return fee;
}
public void setFee(String value)
{
fee=value;
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
sp.edit()
.putString(context.getResources().getString(R.string.key_cryptonit_fee), fee)
.apply();
}
public Boolean haveAccountInfo() {
return !username.isEmpty() && !password.isEmpty();
}
public void saveAccountInfo() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
sp.edit()
.putString(context.getResources().getString(R.string.key_cryptonit_username), username)
.putString(context.getResources().getString(R.string.key_cryptonit_password), password)
.apply();
}
public interface BalanceListener {
void onBalanceData(Model.Balance.Response response);
}
public interface WithdrawalListener {
void onWithdrawalComplete(Model.WithdrawCoins.Response response);
}
public interface ErrorListener {
void onError(Throwable throwable);
}
public void setBalanceListener(BalanceListener listener) {
balanceListener = listener;
}
public void setWithdrawalListener(WithdrawalListener listener) {
withdrawalListener = listener;
}
public void setErrorListener(ErrorListener listener) {
errorListener = listener;
}
@SuppressLint("CheckResult")
public void requestBalance(String currency) {
initApi();
// Log.e("CRYPTONIT2", "username: " + username);
// Log.e("CRYPTONIT2", "password: " + password);
// Log.e("CRYPTONIT2", "auth-token: " + authToken);
Model.Balance.Request request=new Model.Balance.Request();
request.currencies=new String[] {currency};
api.getBalance(authToken, request)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(balanceModel -> balanceListener.onBalanceData(balanceModel),
// handle error
this::FireError
);
}
@SuppressLint("CheckResult")
public void requestWithdrawCoins(String currency, Double amount, String address) {
initApi();
// Log.e("CRYPTONIT2", "username: " + username);
// Log.e("CRYPTONIT2", "password: " + password);
// Log.e("CRYPTONIT2", "auth-token: " + authToken);
Model.WithdrawCoins.Request request=new Model.WithdrawCoins.Request();
request.currency=currency;
request.amount=amount;
request.toAddress=address;
request.includeMinerFee=Double.parseDouble(fee);
request.password=password;
api.withdrawCoins(authToken, request)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> {
if (response.success != null && response.success)
withdrawalListener.onWithdrawalComplete(response);
else {
errorListener.onError(new Exception(((LinkedTreeMap) response.errors[0]).entrySet().toArray()[0].toString()));
}
},
// handle error
this::FireError
);
}
private void FireError(Throwable e) throws IOException {
if (e.getClass() == HttpException.class && ((HttpException) e).code() == 500) {
JsonObject jsonObject = new JsonParser().parse(((HttpException) e).response().errorBody().string()).getAsJsonObject();
errorListener.onError(new Exception(e.getMessage() + ": " + jsonObject.get("errors").getAsString()));
// if (jsonObject.get("reason").getAsString().equals("Invalid nonce")) nonce += 1000;
} else {
errorListener.onError(e);
}
}
private void initApi() {
if (api != null) return;
// HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
// logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient httpClient = new OkHttpClient.Builder().
// addInterceptor(logging).
addInterceptor(new AuthorizationInterceptor()).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(SERVER_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(httpClient)
.build();
api = retrofit.create(Api.class);
}
public class AuthorizationInterceptor implements Interceptor {
AuthorizationInterceptor() {
}
@Override
public Response intercept(Chain chain) throws IOException {
Request mainRequest=chain.request();
if( !mainRequest.url().toString().endsWith("authenticate")&& authToken==null )
{
Model.Authenticate.Request authRequest=new Model.Authenticate.Request();
authRequest.username=username;
authRequest.password=password;
retrofit2.Response<Model.Authenticate.Response> authResponse=api.authenticate(authRequest).execute();
if( authResponse.isSuccessful() && authResponse.body().success)
{
String newToken = authResponse.headers().get("auth-token");
if (newToken != null) {
authToken = newToken;
}
}else{
throw new IOException("Authentication error: "+authResponse.message());
}
}
if( authToken!=null ) {
mainRequest = mainRequest.newBuilder().addHeader("auth-token", authToken).build();
}
Response mainResponse = chain.proceed(mainRequest);
if (!mainResponse.isSuccessful()) {
authToken=null;
}
return mainResponse;
}
}
}

View file

@ -1,283 +0,0 @@
package com.tangem.data.network;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.annotations.SerializedName;
import com.google.gson.internal.LinkedTreeMap;
import com.jakewharton.retrofit2.adapter.rxjava2.HttpException;
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import com.tangem.tangem_card.util.Util;
import com.tangem.wallet.R;
import java.io.IOException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.Headers;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;
import retrofit2.http.Path;
//import okhttp3.logging.HttpLoggingInterceptor;
/**
* HTTP
* Used in CryptonitOtherApi service
*/
public class CryptonitOtherApi {
private static final String SERVER_URL = "https://api.cryptonit.net/api/";
private static class Method {
public static final String BALANCE = SERVER_URL + "balance/{cryptoCurrency}%2F{fiatCurrency}";
public static final String CRYPTO_WITHDRAWAL = SERVER_URL + "crypto_withdrawal/";
}
public static class Response {
public static class Balance{
@SerializedName("btc_balance")
public String btc_balance;
@SerializedName("eur_balance")
public String eur_balance;
@SerializedName("eth_balance")
public String eth_balance;
@SerializedName("etn_balance")
public String etn_balance;
@SerializedName("btc_reserved")
public String btc_reserved;
@SerializedName("eur_reserved")
public String eur_reserved;
@SerializedName("eth_reserved")
public String eth_reserved;
@SerializedName("etn_reserved")
public String etn_reserved;
@SerializedName("btc_available")
public String btc_available;
@SerializedName("eur_available")
public String eur_available;
@SerializedName("eth_available")
public String eth_available;
@SerializedName("etn_available")
public String etn_available;
@SerializedName("btceur_fee")
public String btceur_fee;
@SerializedName("etheur_fee")
public String etheur_fee;
@SerializedName("etnbtc_fee")
public String etnbtc_fee;
@SerializedName("fee")
public String fee;
}
public static class CryptoWithdrawal {
@SerializedName("success")
public Boolean success;
@SerializedName("status")
public String status;
@SerializedName("reason")
public Object reason;
}
}
public interface Api {
@Multipart
@Headers("accept: multipart/form-data")
@POST(Method.BALANCE)
Observable<Response.Balance> getBalance(
@Path("cryptoCurrency") String cryptoCurrency, @Path("fiatCurrency") String fiatCurrency,
@Part(value = "key") RequestBody key, @Part("signature") RequestBody signature, @Part("nonce") RequestBody nonce);
@Multipart
@Headers("accept: multipart/form-data")
@POST(Method.CRYPTO_WITHDRAWAL)
Observable<Response.CryptoWithdrawal> cryptoWithdrawal(
@Part(value = "currency") RequestBody currency, @Part("amount") RequestBody amount, @Part("address") RequestBody address,
@Part(value = "key") RequestBody key, @Part("signature") RequestBody signature, @Part("nonce") RequestBody nonce);
}
private Api api = null;
private BalanceListener balanceListener;
private WithdrawalListener withdrawalListener;
private ErrorListener errorListener;
private Context context;
public CryptonitOtherApi(Context context) {
this.context = context;
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
key = sp.getString(context.getResources().getString(R.string.key_cryptonit_key), "");
userId = sp.getString(context.getResources().getString(R.string.key_cryptonit_user_id), "");
secret = sp.getString(context.getResources().getString(R.string.key_cryptonit_secret), "");
nonce = sp.getInt(context.getResources().getString(R.string.key_cryptonit_nonce), 0);
}
public String key;
public String userId;
public String secret;
private Integer nonce;
public String getSecretDescription() {
if (secret == null || secret.isEmpty()) return "";
return secret.substring(0, 3) + "..." + secret.substring(secret.length() - 3, secret.length());
}
public Boolean havaAccountInfo() {
return (!userId.isEmpty() && !key.isEmpty() && !secret.isEmpty());
}
public void saveAccountInfo() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
nonce = 1;
sp.edit()
.putString(context.getResources().getString(R.string.key_cryptonit_key), key)
.putString(context.getResources().getString(R.string.key_cryptonit_user_id), userId)
.putString(context.getResources().getString(R.string.key_cryptonit_secret), secret)
.putInt(context.getResources().getString(R.string.key_cryptonit_nonce), nonce)
.apply();
}
private void incNonce() {
nonce++;
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
sp.edit().putInt(context.getResources().getString(R.string.key_cryptonit_nonce), nonce).apply();
}
public interface BalanceListener {
void onBalanceData(Response.Balance response);
}
public interface WithdrawalListener {
void onWithdrawalComplete(Response.CryptoWithdrawal response);
}
public interface ErrorListener {
void onError(Throwable throwable);
}
public void setBalanceListener(BalanceListener listener) {
balanceListener = listener;
}
public void setWithdrawalListener(WithdrawalListener listener) {
withdrawalListener = listener;
}
public void setErrorListener(ErrorListener listener) {
errorListener = listener;
}
private String calcSignature() throws Exception {
incNonce();
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256");
sha256_HMAC.init(secret_key);
String data = nonce.toString() + userId + key;
return Util.bytesToHex(sha256_HMAC.doFinal(data.getBytes("UTF-8")));
}
@SuppressLint("CheckResult")
public void requestBalance(String cryptoCurrency, String fiatCurrency) throws Exception {
initApi();
String signature = calcSignature();
// Log.e("CRYPTONIT", "user: " + userId);
// Log.e("CRYPTONIT", "key: " + key);
// Log.e("CRYPTONIT", "secret: " + secret);
// Log.e("CRYPTONIT", "nonce: " + nonce);
// Log.e("CRYPTONIT", "signature: " + signature);
api.getBalance(cryptoCurrency, fiatCurrency,
RequestBody.create(MediaType.parse("text/plain"), key),
RequestBody.create(MediaType.parse("text/plain"), signature),
RequestBody.create(MediaType.parse("text/plain"), nonce.toString()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(balanceModel -> balanceListener.onBalanceData(balanceModel),
// handle error
this::FireError
);
}
@SuppressLint("CheckResult")
public void requestCryptoWithdrawal(String currency, String amount, String address) throws Exception {
initApi();
String signature = calcSignature();
// Log.e("CRYPTONIT", "user: " + userId);
// Log.e("CRYPTONIT", "key: " + key);
// Log.e("CRYPTONIT", "secret: " + secret);
// Log.e("CRYPTONIT", "nonce: " + nonce);
// Log.e("CRYPTONIT", "signature: " + signature);
//
api.cryptoWithdrawal(
RequestBody.create(MediaType.parse("text/plain"), currency),
RequestBody.create(MediaType.parse("text/plain"), amount),
RequestBody.create(MediaType.parse("text/plain"), address),
RequestBody.create(MediaType.parse("text/plain"), key),
RequestBody.create(MediaType.parse("text/plain"), signature),
RequestBody.create(MediaType.parse("text/plain"), nonce.toString()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> {
if (response.success != null && response.success)
withdrawalListener.onWithdrawalComplete(response);
else {
LinkedTreeMap reason = (LinkedTreeMap) response.reason;
errorListener.onError(new Exception(reason.entrySet().toArray()[0].toString()));
}
},
// handle error
this::FireError
);
}
private void FireError(Throwable e) throws IOException {
if (e.getClass() == HttpException.class && ((HttpException) e).code() == 500) {
JsonObject jsonObject = new JsonParser().parse(((HttpException) e).response().errorBody().string()).getAsJsonObject();
errorListener.onError(new Exception(e.getMessage() + ": " + jsonObject.get("reason").getAsString()));
if (jsonObject.get("reason").getAsString().equals("Invalid nonce")) nonce += 1000;
} else {
errorListener.onError(e);
}
}
private void initApi() {
if (api != null) return;
// HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
// logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient httpClient = new OkHttpClient.Builder().
// addInterceptor(logging).
build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(SERVER_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(httpClient)
.build();
api = retrofit.create(Api.class);
}
}

View file

@ -1,25 +0,0 @@
package com.tangem.data.network;
import com.tangem.data.network.model.BitcoreBalance;
import com.tangem.data.network.model.BitcoreSendBody;
import com.tangem.data.network.model.BitcoreSendResponse;
import com.tangem.data.network.model.BitcoreUtxo;
import java.util.List;
import io.reactivex.Single;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Path;
public interface DucatusApi {
@GET(Server.ApiDucatus.Method.BALANCE)
Single<BitcoreBalance> ducatusBalance(@Path("address") String address);
@GET(Server.ApiDucatus.Method.UTXO)
Single<List<BitcoreUtxo>> ducatusUnspents(@Path("address") String address);
@POST(Server.ApiDucatus.Method.SEND)
Single<BitcoreSendResponse> ducatusSend(@Body BitcoreSendBody body);
}

View file

@ -1,193 +0,0 @@
package com.tangem.data.network;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Created by dvol on 16.07.2017.
*/
public class ElectrumRequest {
public static final String METHOD_GetBalance = "blockchain.address.get_balance";
public static final String METHOD_ListUnspent = "blockchain.address.listunspent";
public static final String METHOD_GetHistory = "blockchain.address.get_history";
public static final String METHOD_GetTransaction = "blockchain.transaction.get";
public static final String METHOD_GetHeader = "blockchain.block.get_header";
public static final String METHOD_SendTransaction = "blockchain.transaction.broadcast";
public static final String METHOD_GetFee = "blockchain.estimatefee";
private JSONObject jsRequestData;
String answerData;
private String error = null;
private String walletAddress;
public String txHash;
private String TX;
String host;
int port;
private ElectrumRequest() {
}
public ElectrumRequest(JSONObject jsRequest) {
try {
jsRequestData = new JSONObject(jsRequest.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
public JSONObject getAnswer() {
try {
return new JSONObject(answerData);
} catch (Exception e) {
try {
return new JSONObject(String.format("[\"Error\":\"%s\"]", e.getMessage()));
} catch (JSONException e1) {
e1.printStackTrace();
return null;
}
}
}
public String getAsString() {
return jsRequestData.toString();
}
public void setID(int value) {
try {
jsRequestData.put("id", String.format("%d", value));
} catch (JSONException e) {
e.printStackTrace();
}
}
public int getID() {
try {
return jsRequestData.getInt("id");
} catch (JSONException e) {
e.printStackTrace();
return 0;
}
}
public static ElectrumRequest checkBalance(String wallet) {
ElectrumRequest request = new ElectrumRequest();
try {
request.walletAddress = wallet;
request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_GetBalance + "\", \"params\":[\"" + wallet + "\"] }");
} catch (JSONException e) {
e.printStackTrace();
request.error = e.toString();
}
return request;
}
public static ElectrumRequest getFee() {
ElectrumRequest request = new ElectrumRequest();
try {
request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_GetFee + "\", \"params\":[\"" + 6 + "\"] }");
} catch (JSONException e) {
e.printStackTrace();
request.error = e.toString();
}
return request;
}
public static ElectrumRequest listUnspent(String wallet) {
ElectrumRequest request = new ElectrumRequest();
try {
request.walletAddress = wallet;
request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_ListUnspent + "\", \"params\":[\"" + wallet + "\"] }");
} catch (JSONException e) {
e.printStackTrace();
request.error = e.toString();
}
return request;
}
public static ElectrumRequest broadcast(String wallet, String tx) {
ElectrumRequest request = new ElectrumRequest();
try {
request.walletAddress = wallet;
request.TX = tx;
request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_SendTransaction + "\", \"params\":[\"" + tx + "\"] }");
} catch (JSONException e) {
e.printStackTrace();
request.error = e.toString();
}
return request;
}
public static ElectrumRequest getTransaction(String wallet, String tx_hash) {
ElectrumRequest request = new ElectrumRequest();
try {
request.walletAddress = wallet;
request.txHash = tx_hash;
request.jsRequestData = new JSONObject("{ \"method\":\"" + METHOD_GetTransaction + "\", \"params\":[\"" + tx_hash + "\"] }");
} catch (JSONException e) {
e.printStackTrace();
request.error = e.toString();
}
return request;
}
public String getMethod() {
try {
return jsRequestData.getString("method");
} catch (JSONException e) {
e.printStackTrace();
}
return "";
}
public boolean isMethod(String methodName) {
return getMethod().equals(methodName);
}
public JSONArray getParams() throws JSONException {
return jsRequestData.getJSONArray("params");
}
public JSONObject getResult() throws JSONException {
return getAnswer().getJSONObject("result");
}
public String getError() {
if( answerData!=null ) {
// answer received - return error from it
JSONObject answer = getAnswer();
if (answer.has("error")) {
try {
return getAnswer().getJSONObject("error").toString();
} catch (JSONException e) {
e.printStackTrace();
return null;
}
} else {
return null;
}
}else{
// no answer received - return saved error reason
return error;
}
}
public void setError(String error) {
this.error = error;
}
public String getResultString() throws JSONException {
if (getAnswer().has("result")) {
return getAnswer().getString("result");
} else {
return null;
}
}
public JSONArray getResultArray() throws JSONException {
return getAnswer().getJSONArray("result");
}
}

View file

@ -1,15 +0,0 @@
package com.tangem.data.network;
import retrofit2.Call;
import retrofit2.http.GET;
public interface EstimatefeeApi {
@GET(Server.ApiEstimatefee.Method.N_2)
Call<String> getEstimateFeePriority();
@GET(Server.ApiEstimatefee.Method.N_3)
Call<String> getEstimateFeeNormal();
@GET(Server.ApiEstimatefee.Method.N_6)
Call<String> getEstimateFeeMinimal();
}

View file

@ -1,15 +0,0 @@
package com.tangem.data.network;
import com.tangem.data.network.model.InfuraBody;
import com.tangem.data.network.model.InfuraResponse;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Headers;
import retrofit2.http.POST;
public interface InfuraApi {
@Headers("Content-Type: application/json")
@POST(Server.ApiInfura.Method.MAIN)
Call<InfuraResponse> infura(@Body InfuraBody body);
}

View file

@ -1,33 +0,0 @@
package com.tangem.data.network;
import com.tangem.data.network.model.InsightBody;
import com.tangem.data.network.model.InsightResponse;
import com.tangem.data.network.model.InsightUtxo;
import java.util.List;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Headers;
import retrofit2.http.POST;
import retrofit2.http.Path;
import retrofit2.http.Query;
public interface InsightApi {
@GET(ServerApiInsight.INSIGHT_ADDRESS)
Call<InsightResponse> insightAddress(@Path("address") String address);
@GET(ServerApiInsight.INSIGHT_UNSPENT_OUTPUTS)
Call<List<InsightUtxo>> insightUnspent(@Path("address") String address);
@GET(ServerApiInsight.INSIGHT_TRANSACTION)
Call<InsightResponse> insightTransaction(@Path("txId") String txId);
@GET(ServerApiInsight.INSIGHT_FEE)
Call<InsightResponse> insightFee();
@Headers("Content-Type: application/json")
@POST(ServerApiInsight.INSIGHT_SEND)
Call<InsightResponse> insightSend(@Body InsightBody body );
}

View file

@ -1,358 +0,0 @@
package com.tangem.data.network;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import com.tangem.tangem_card.util.Util;
import com.tangem.wallet.R;
import org.spongycastle.util.encoders.Base64;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;
//import okhttp3.logging.HttpLoggingInterceptor;
/**
* HTTP
* Used in Kraken service
*/
public class Kraken {
private static final String SERVER_URL = "https://api.kraken.com";
private static class Method {
public static final String BALANCE = SERVER_URL + "/0/private/Balance";
public static final String WITHDRAW_INFO = SERVER_URL + "/0/private/WithdrawInfo";
public static final String WITHDRAW = SERVER_URL + "/0/private/Withdraw";
}
public static class Model {
public static class Balance {
public static class Response {
public String[] error;
public Result result;
public static class Result {
public String XXBT;
public String XETH;
public String BCH;
}
}
}
public static class WithdrawInfo {
public static class Response {
public String[] error;
public Result result;
public static class Result {
public String fee;
public String amount;
}
}
}
public static class Withdraw {
public static class Response {
public String[] error;
public Result result;
public static class Result {
public String refid;
}
}
}
}
public interface Api {
@FormUrlEncoded
@POST(Method.BALANCE)
Observable<Model.Balance.Response> getBalance(@Field("nonce") String nonce);
@FormUrlEncoded
@POST(Method.WITHDRAW_INFO)
Observable<Model.WithdrawInfo.Response> WithdrawInfo(@Field("nonce") String nonce, @Field("asset") String asset, @Field("key") String key, @Field("amount") String amount);
@FormUrlEncoded
@POST(Method.WITHDRAW)
Observable<Model.Withdraw.Response> Withdraw(@Field("nonce") String nonce, @Field("asset") String asset, @Field("key") String key, @Field("amount") String amount);
}
private Api api = null;
private BalanceListener balanceListener;
private WithdrawalListener withdrawalListener;
private WithdrawalInfoListener withdrawalInfoListener;
private ErrorListener errorListener;
private Context context;
public Kraken(Context context) {
this.context = context;
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
key = sp.getString(context.getResources().getString(R.string.key_kraken_key), "");
secret = sp.getString(context.getResources().getString(R.string.key_kraken_secret), "");
nonce = sp.getInt(context.getResources().getString(R.string.key_kraken_nonce), 0);
}
public String key;
public String secret;
private Integer nonce;
public String getSecretDescription() {
if (secret == null || secret.isEmpty()) return "";
return secret.substring(0, 3) + "..." + secret.substring(secret.length() - 3, secret.length());
}
public Boolean haveAccountInfo() {
return (!key.isEmpty() && !secret.isEmpty());
}
public void saveAccountInfo() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
sp.edit()
.putString(context.getResources().getString(R.string.key_kraken_key), key)
.putString(context.getResources().getString(R.string.key_kraken_secret), secret)
.putInt(context.getResources().getString(R.string.key_kraken_nonce), nonce)
.apply();
}
private void incNonce() {
nonce++;
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
sp.edit().putInt(context.getResources().getString(R.string.key_kraken_nonce), nonce).apply();
}
public interface BalanceListener {
void onBalanceData(Model.Balance.Response response);
}
public interface WithdrawalInfoListener {
void onWithdrawalInfoComplete(Model.WithdrawInfo.Response response);
}
public interface WithdrawalListener {
void onWithdrawalComplete(Model.Withdraw.Response response);
}
public interface ErrorListener {
void onError(Throwable throwable);
}
public void setBalanceListener(BalanceListener listener) {
balanceListener = listener;
}
public void setWithdrawalListener(WithdrawalListener listener) {
withdrawalListener = listener;
}
public void setWithdrawalInfoListener(WithdrawalInfoListener listener) {
withdrawalInfoListener = listener;
}
public void setErrorListener(ErrorListener listener) {
errorListener = listener;
}
private static final String HMAC_SHA512 = "HmacSHA512";
private String bodyToString(final RequestBody request){
try {
final RequestBody copy = request;
final Buffer buffer = new Buffer();
if(copy != null)
copy.writeTo(buffer);
else
return "";
return buffer.readUtf8();
}
catch (final IOException e) {
return "did not work";
}
}
private String calcSignature(String url, RequestBody requestBody) throws NoSuchAlgorithmException, InvalidKeyException, IOException {
String postData=bodyToString(requestBody);
// create SHA-256 hash of the nonce and the POST data
String s=nonce+postData;
byte[] sha256 = Util.calculateSHA256(s);
// set the API method and retrieve the path
byte[] path = url.getBytes(StandardCharsets.UTF_8);
// decode the API secret, it's the HMAC key
byte[] hmacKey = Base64.decode(secret);
// create the HMAC message from the path and the previous hash
ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
outputStream.write(path);
outputStream.write(sha256);
byte[] hmacMessage = outputStream.toByteArray();//concatArrays(path, sha256);
Mac mac = Mac.getInstance(HMAC_SHA512);
mac.init(new SecretKeySpec(hmacKey, HMAC_SHA512));
byte[] hmacSignature=mac.doFinal(hmacMessage);
byte[] b64Signature = Base64.encode(hmacSignature);
return new String(b64Signature, StandardCharsets.UTF_8);
}
@SuppressLint("CheckResult")
public void requestBalance() throws Exception {
initApi();
// Log.e("kraken", "key: " + key);
// Log.e("kraken", "secret: " + secret);
// Log.e("kraken", "nonce: " + nonce);
api.getBalance(nonce.toString())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> balanceListener.onBalanceData(response),
// handle error
this::FireError
);
}
@SuppressLint("CheckResult")
public void requestWithdrawInfo(String currency, String amount, String withdrawKey) throws Exception {
initApi();
// Log.e("kraken", "key: " + key);
// Log.e("kraken", "secret: " + secret);
// Log.e("kraken", "nonce: " + nonce);
String asset=CurrencyToAsset(currency);
// withdrawKey = "test";
api.WithdrawInfo(nonce.toString(), asset, withdrawKey, amount)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> withdrawalInfoListener.onWithdrawalInfoComplete(response),
// handle error
this::FireError
);
}
private static String CurrencyToAsset(String currency) throws Exception {
switch (currency)
{
case "BTC": return "XXBT";
case "BCH": return "BCH";
case "ETH": return "XETH";
default:
throw new Exception("Unsupported currency!");
}
}
@SuppressLint("CheckResult")
public void requestWithdraw(String currency, String amount, String withdrawKey) throws Exception {
initApi();
// Log.e("kraken", "key: " + key);
// Log.e("kraken", "secret: " + secret);
// Log.e("kraken", "nonce: " + nonce);
String asset=CurrencyToAsset(currency);
// withdrawKey = "test";
api.Withdraw(nonce.toString(), asset, withdrawKey, amount)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> withdrawalListener.onWithdrawalComplete(response),
// handle error
this::FireError
);
}
private void FireError(Throwable e) throws IOException {
// if (e.getClass() == HttpException.class && ((HttpException) e).code() == 500) {
// JsonObject jsonObject = new JsonParser().parse(((HttpException) e).response().errorBody().string()).getAsJsonObject();
// errorListener.onError(new Exception(e.getMessage() + ": " + jsonObject.get("reason").getAsString()));
// if (jsonObject.get("reason").getAsString().equals("Invalid nonce")) nonce += 1000;
// } else {
errorListener.onError(e);
// }
}
private void initApi() {
if (api != null) return;
// HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
// logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient httpClient = new OkHttpClient.Builder().
addInterceptor(new AuthorizationInterceptor()).
// addInterceptor(logging).
build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(SERVER_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(httpClient)
.build();
api = retrofit.create(Api.class);
}
public class AuthorizationInterceptor implements Interceptor {
AuthorizationInterceptor() {
}
@Override
public Response intercept(Chain chain) throws IOException {
Request mainRequest=chain.request();
try {
mainRequest = mainRequest.newBuilder().
addHeader("API-Key", key).
addHeader("API-Sign", calcSignature(mainRequest.url().toString().substring(SERVER_URL.length()), mainRequest.body())).
build();
incNonce();
} catch (Exception e) {
e.printStackTrace();
throw new IOException("Can't calculate signature: "+e.getMessage());
}
return chain.proceed(mainRequest);
}
}
}

View file

@ -1,15 +0,0 @@
package com.tangem.data.network;
import com.tangem.data.network.model.InfuraBody;
import com.tangem.data.network.model.InfuraResponse;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Headers;
import retrofit2.http.POST;
public interface MaticApi {
@Headers("Content-Type: application/json")
@POST(Server.ApiMaticTesnet.Method.MAIN)
Call<InfuraResponse> matic(@Body InfuraBody body);
}

View file

@ -1,15 +0,0 @@
package com.tangem.data.network;
import com.tangem.data.network.model.PayIdResponse;
import io.reactivex.Single;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.Headers;
import retrofit2.http.Path;
public interface PayIdApi {
@Headers("PayID-Version: 1.0")
@GET("{user}")
Single<PayIdResponse> getAddress(@Path("user") String user, @Header("Accept") String acceptHeader);
}

View file

@ -1,15 +0,0 @@
package com.tangem.data.network;
import com.tangem.data.network.model.RippleBody;
import com.tangem.data.network.model.RippleResponse;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Headers;
import retrofit2.http.POST;
public interface RippleApi {
@Headers("Content-Type: application/json")
@POST("./")
Call<RippleResponse> ripple(@Body RippleBody body);
}

View file

@ -1,15 +0,0 @@
package com.tangem.data.network;
import com.tangem.data.network.model.InfuraBody;
import com.tangem.data.network.model.InfuraResponse;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Headers;
import retrofit2.http.POST;
public interface RootstockApi {
@Headers("Content-Type: application/json")
@POST(Server.ApiRootstock.Method.MAIN)
Call<InfuraResponse> rootstock(@Body InfuraBody body);
}

View file

@ -1,170 +0,0 @@
package com.tangem.data.network;
public class Server {
public static class ApiUpdateVersion {
public static final String URL_UPDATE_VERSION = ServerURL.API_UPDATE_VERSION;
public static class Method {
static final String LAST_VERSION = URL_UPDATE_VERSION + "TangemCash/tangem-binaries/master/apk-version.txt";
}
}
/**
* https://coinmarketcap.com/api/
*/
public static class ApiCoinmarket {
public static final String URL_COINMARKET = ServerURL.API_COINMARKETCAP;
public static class Method {
static final String PRICE_CONVERSION = URL_COINMARKET + "v1/tools/price-conversion";
}
}
/**
* https://infura.io/
*/
public static class ApiInfura {
public static final String URL_INFURA = ServerURL.API_INFURA;
public static class Method {
public static final String MAIN = "v3/613a0b14833145968b1f656240c7d245";
}
}
public static class ApiInfuraTestnet {
public static final String URL_INFURA_TESTNET = ServerURL.API_INFURA_TESTNET;
public static class Method {
public static final String MAIN = "v3/613a0b14833145968b1f656240c7d245";
}
}
public static class ApiInfuraRopsten {
public static final String URL_INFURA_ROPSTEN = ServerURL.API_INFURA_ROPSTEN;
public static class Method {
public static final String MAIN = "v3/613a0b14833145968b1f656240c7d245";
}
}
public static class ApiSoChain {
public static final String URL = ServerURL.API_SOCHAIN_V2;
public static class Method {
public static final String ADDRESS_BALANCE = "api/v2/get_address_balance/{network}/{address}";
public static final String UNSPENT_TX = "api/v2/get_tx_unspent/{network}/{address}";
public static final String GET_TX = "api/v2/get_tx/{network}/{txid}";
public static final String SEND_TRANSACTION = "api/v2/send_tx/{network}";
}
}
/**
* https://public-node.rsk.co/
*/
public static class ApiRootstock {
public static final String URL_ROOTSTOCK = ServerURL.API_ROOTSTOCK;
public static class Method {
static final String MAIN = URL_ROOTSTOCK;
}
}
/**
* https://testnet2.matic.network
*/
public static class ApiMaticTesnet {
public static final String URL_MATIC_TESTNET = ServerURL.API_MATIC_TESTNET ;
public static class Method {
static final String MAIN = URL_MATIC_TESTNET;
}
}
/**
* https://estimatefee.com/
*/
public static class ApiEstimatefee {
public static final String URL_ESTIMATEFEE = ServerURL.API_ESTIMATEFEE;
public static class Method {
static final String N_2 = URL_ESTIMATEFEE + "n/2";
static final String N_3 = URL_ESTIMATEFEE + "n/3";
static final String N_6 = URL_ESTIMATEFEE + "n/6";
}
}
/**
* https://dex.binance.org/
*/
public static class ApiBinance {
public static final String URL_BINANCE = ServerURL.API_BINANCE;
public static class Method {
public static final String API_V1 = URL_BINANCE + "api/v1/";
}
}
/**
* https://testnet-dex.binance.org/
*/
public static class ApiBinanceTestnet {
public static final String URL_BINANCE_TESTNET = ServerURL.API_BINANCE_TESTNET;
public static class Method {
public static final String API_V1 = URL_BINANCE_TESTNET + "api/v1/";
}
}
/**
* https://api.blockcypher.com/
*/
public static class ApiBlockcypher {
public static final String URL_BLOCKCYPHER = ServerURL.API_BLOCKCYPHER;
static final String V1_MAIN = "v1/{blockchain}/{network}";
public static class Method {
static final String MAIN = URL_BLOCKCYPHER + V1_MAIN;
static final String ADDRESS = MAIN + "/addrs/{address}?includeScript=true&limit=2000";
static final String TXS = MAIN + "/txs/{txHash}?includeHex=true";
static final String PUSH = MAIN + "/txs/push";
}
}
public static class ApiBlockchainInfo {
public static final String URL_BLOCKCHAININFO = ServerURL.API_BLOCKCHAIN_INFO;
public static class Method {
static final String ADDRESS = URL_BLOCKCHAININFO + "rawaddr/{address}";
static final String UTXO = URL_BLOCKCHAININFO + "unspent";
// static final String TX = URL_BLOCKCHAININFO + "rawtx/{txHash}";
static final String PUSH = URL_BLOCKCHAININFO + "pushtx";
}
}
public static class ApiDucatus {
public static final String URL_DUCATUS = ServerURL.API_DUCATUS + "api/DUC/mainnet/";
public static class Method {
static final String BALANCE = URL_DUCATUS + "address/{address}/balance";
static final String UTXO = URL_DUCATUS + "address/{address}/?unspent=true";
static final String SEND = URL_DUCATUS + "tx/send";
}
}
public static class ApiBlockchair {
public static final String URL_BLOCKCHAIR = ServerURL.API_BLOCKCHAIR + "{blockchain}/";
private static final String API_KEY = "?key=A___0Shpsu4KagE7oSabrw20DfXAqWlT";
public static class Method {
static final String ADDRESS = URL_BLOCKCHAIR + "dashboards/address/{address}" + API_KEY;
static final String TRANSACTION = URL_BLOCKCHAIR + "dashboards/transaction/{transaction}" + API_KEY;
static final String STATS = URL_BLOCKCHAIR + "stats" + API_KEY;
static final String PUSH = URL_BLOCKCHAIR + "push/transaction" + API_KEY;
}
}
}

View file

@ -1,196 +0,0 @@
package com.tangem.data.network;
import android.util.Log;
import androidx.annotation.NonNull;
import com.tangem.data.network.model.AdaliteBody;
import com.tangem.data.network.model.AdaliteResponse;
import com.tangem.data.network.model.AdaliteResponseUtxo;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;
public class ServerApiAdalite {
private static String TAG = ServerApiAdalite.class.getSimpleName();
public static final String ADALITE_ADDRESS = "/api/addresses/summary/{address}";
public static final String ADALITE_UNSPENT_OUTPUTS = "/api/bulk/addresses/utxo";
// public static final String ADALITE_TRANSACTION = "/api/txs/raw/{txId}}";
public static final String ADALITE_SEND = "/api/v2/txs/signed";
private int requestsCount = 0;
private final String adaliteURL1 = "https://explorer2.adalite.io"; //TODO: make random selection, add more?, move
private final String adaliteURL2 = "https://nodes.southeastasia.cloudapp.azure.com";
private String currentURL = adaliteURL1;
public String getCurrentURL() {
return currentURL;
}
public boolean isRequestsSequenceCompleted() {
Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount));
return requestsCount <= 0;
}
private ResponseListener responseListener;
public interface ResponseListener {
void onSuccess(String method, AdaliteResponse adaliteResponse);
void onSuccess(String method, AdaliteResponseUtxo adaliteResponseUtxo);
void onSuccess(String method, String stringResponse);
void onFail(String method, String message);
}
public void setResponseListener(ResponseListener listener) {
responseListener = listener;
}
public void requestData(String method, String wallet, String tx) {
requestData(method, wallet, tx, false);
}
public void requestData(String method, String wallet, String tx, boolean isRetry) {
requestsCount++;
Retrofit retrofitAdalite = new Retrofit.Builder()
.baseUrl(currentURL)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
AdaliteApi adaliteApi = retrofitAdalite.create(AdaliteApi.class);
switch (method) {
case ADALITE_ADDRESS:
Call<AdaliteResponse> addressCall = adaliteApi.adaliteAddress(wallet);
addressCall.enqueue(new Callback<AdaliteResponse>() {
@Override
public void onResponse(@NonNull Call<AdaliteResponse> call, @NonNull Response<AdaliteResponse> response) {
requestsCount--;
if (response.code() == 200) {
responseListener.onSuccess(method, response.body());
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
} else {
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
if (!isRetry) {
retryRequest(method, wallet, tx);
} else {
responseListener.onFail(method, String.valueOf(response.code()));
}
}
}
@Override
public void onFailure(@NonNull Call<AdaliteResponse> call, @NonNull Throwable t) {
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
requestsCount--;
if (!isRetry) {
retryRequest(method, wallet, tx);
} else {
responseListener.onFail(method, String.valueOf(t.getMessage()));
}
}
});
break;
case ADALITE_UNSPENT_OUTPUTS:
Call<AdaliteResponseUtxo> outputsCall = adaliteApi.adaliteUnspent("[\"" + wallet + "\"]");
outputsCall.enqueue(new Callback<AdaliteResponseUtxo>() {
@Override
public void onResponse(@NonNull Call<AdaliteResponseUtxo> call, @NonNull Response<AdaliteResponseUtxo> response) {
requestsCount--;
if (response.code() == 200) {
responseListener.onSuccess(method, response.body());
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
} else {
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
if (!isRetry) {
retryRequest(method, wallet, tx);
} else {
responseListener.onFail(method, String.valueOf(response.code()));
}
}
}
@Override
public void onFailure(@NonNull Call<AdaliteResponseUtxo> call, @NonNull Throwable t) {
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
requestsCount--;
if (!isRetry) {
retryRequest(method, wallet, tx);
} else {
responseListener.onFail(method, String.valueOf(t.getMessage()));
}
}
});
break;
case ADALITE_SEND:
Call<String> sendCall = adaliteApi.adaliteSend(new AdaliteBody(tx));
sendCall.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
requestsCount--;
if (response.code() == 200) {
responseListener.onSuccess(method, response.body());
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
} else {
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
if (!isRetry) {
retryRequest(method, wallet, tx);
} else {
responseListener.onFail(method, String.valueOf(response.code()));
}
}
}
@Override
public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
requestsCount--;
if (!isRetry) {
retryRequest(method, wallet, tx);
} else {
responseListener.onFail(method, String.valueOf(t.getMessage()));
}
}
});
break;
default:
requestsCount--;
responseListener.onFail(method, "undeclared method");
Log.e(TAG, "requestData " + method + " onFailure - undeclared method");
break;
}
}
private void retryRequest(String method, String wallet, String tx) {
// currentURL = adaliteURL2;
requestData(method, wallet, tx, true);
}
}

View file

@ -1,137 +0,0 @@
package com.tangem.data.network;
import android.util.Log;
import com.tangem.wallet.TangemContext;
import com.tangem.wallet.Transaction;
import com.tangem.wallet.binance.BinanceAssetData;
import com.tangem.wallet.binance.BinanceData;
import com.tangem.wallet.binance.client.BinanceDexApiRestClient;
import com.tangem.wallet.binance.client.domain.Account;
import com.tangem.wallet.binance.client.domain.Balance;
import com.tangem.wallet.binance.client.domain.TransactionMetadata;
import com.tangem.wallet.binance.client.encoding.message.TransactionRequestAssemblerExtSign;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.observers.DefaultObserver;
import io.reactivex.schedulers.Schedulers;
import okhttp3.RequestBody;
public class ServerApiBinance {
private static String TAG = ServerApiBinance.class.getSimpleName();
private ResponseListener responseListener;
public interface ResponseListener {
void onSuccess();
void onFail();
}
public void setResponseListener(ResponseListener listener) {
responseListener = listener;
}
public void getBalance(TangemContext ctx, BinanceDexApiRestClient client) {
Log.i(TAG, "new getBalance request");
Observable<Account> balanceObservable = Observable.just(new Account())
.map(account -> client.getAccount(ctx.getCoinData().getWallet()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
balanceObservable.subscribe(new DefaultObserver<Account>() {
@Override
public void onNext(Account account) {
Log.i(TAG, "getBalance onNext");
// account = client.getAccount(ctx.getCoinData().getWallet());
BinanceData binanceData = (BinanceData) ctx.getCoinData();
for (Balance balance : account.getBalances()) {
if (balance.getSymbol().equals("BNB")) {
binanceData.setBalanceReceived(true);
binanceData.setBalance(balance.getFree());
break;
}
}
if (binanceData instanceof BinanceAssetData) {
BinanceAssetData binanceAssetData = (BinanceAssetData) binanceData;
for (Balance balance : account.getBalances()) {
if (balance.getSymbol().equals(ctx.getCard().getContractAddress())) {
binanceAssetData.setAssetBalance(balance.getFree());
break;
}
}
}
if (!binanceData.isBalanceReceived()) {
binanceData.setBalanceReceived(true);
binanceData.setBalance("0");
}
binanceData.setAccountNumber(account.getAccountNumber());
binanceData.setSequence(account.getSequence());
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "getBalance onError" + e.getMessage());
if (e.getMessage().contains("account not found")) {
((BinanceData)ctx.getCoinData()).setError404(true);
responseListener.onFail();
} else {
e.printStackTrace();
ctx.setError(e.getMessage());
responseListener.onFail();
}
}
@Override
public void onComplete() {
Log.i(TAG, "getBalance onComplete");
responseListener.onSuccess();
}
});
}
public void sendTransaction (byte[] txForSend, BinanceDexApiRestClient client) {
Log.i(TAG, "new sendTransaction request");
RequestBody requestBody = TransactionRequestAssemblerExtSign.createRequestBody(txForSend);
Observable<List<TransactionMetadata>> sendObservable = Observable.just(new ArrayList<>())
.map(metadatas -> client.broadcastNoWallet(requestBody, true))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
sendObservable.subscribe(new DefaultObserver<List<TransactionMetadata>>() {
@Override
public void onNext(List<TransactionMetadata> metadatas ) {
// RequestBody requestBody = TransactionRequestAssemblerExtSign.createRequestBody(txForSend);
// List<TransactionMetadata> metadatas = client.broadcastNoWallet(requestBody, true);
if (!metadatas.isEmpty() && metadatas.get(0).isOk()) {
responseListener.onSuccess();
} else {
Log.e(TAG, "Transaction send error");
responseListener.onFail();
}
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "sendTransaction onError" + e.getMessage());
e.printStackTrace();
responseListener.onFail();
}
@Override
public void onComplete() {
Log.i(TAG, "sendTransaction onComplete");
}
});
}
}

View file

@ -1,47 +0,0 @@
package com.tangem.data.network;
import com.tangem.App;
import com.tangem.data.network.model.BitcoreBalance;
import com.tangem.data.network.model.BitcoreBalanceAndUnspents;
import com.tangem.data.network.model.BitcoreSendBody;
import com.tangem.data.network.model.BitcoreSendResponse;
import com.tangem.data.network.model.BitcoreUtxo;
import com.tangem.tangem_card.util.Log;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.Single;
import io.reactivex.SingleObserver;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
public class ServerApiBitcore {
private static String TAG = ServerApiBitcore.class.getSimpleName();
public void getBalanceAndUnspents(String wallet, SingleObserver<BitcoreBalanceAndUnspents> balanceAndUnspentsObserver) {
Log.i(TAG, "new getAddressAndUnspents request");
DucatusApi api = App.Companion.getNetworkComponent().getRetrofitDucatus().create(DucatusApi.class);
Single<BitcoreBalance> balanceObservable = api.ducatusBalance(wallet);
Single<List<BitcoreUtxo>> unspentsObservable = api.ducatusUnspents(wallet)
.onErrorReturnItem(new ArrayList<>());
Single.zip(balanceObservable, unspentsObservable, BitcoreBalanceAndUnspents::new)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(balanceAndUnspentsObserver);
}
public void sendTransaction(String tx, SingleObserver<BitcoreSendResponse> sendObserver) {
Log.i(TAG, "new getAddress request");
DucatusApi api = App.Companion.getNetworkComponent().getRetrofitDucatus().create(DucatusApi.class);
Single<BitcoreSendResponse> sendObservable = api.ducatusSend(new BitcoreSendBody(tx))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
sendObservable.subscribe(sendObserver);
}
}

View file

@ -1,62 +0,0 @@
package com.tangem.data.network;
import android.util.Log;
import com.tangem.App;
import com.tangem.data.network.model.BlockchainInfoAddress;
import com.tangem.data.network.model.BlockchainInfoAddressAndUnspents;
import com.tangem.data.network.model.BlockchainInfoTransaction;
import com.tangem.data.network.model.BlockchainInfoUnspents;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.Single;
import io.reactivex.SingleObserver;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.ResponseBody;
public class ServerApiBlockchainInfo {
private static String TAG = ServerApiBlockchainInfo.class.getSimpleName();
private int page = 1;
public void getAddressAndUnspents(String wallet, SingleObserver<BlockchainInfoAddressAndUnspents> addressAndUnspentsObserver) {
Log.i(TAG, "new getAddressAndUnspents request");
BlockchainInfoApi api = App.Companion.getNetworkComponent().getRetrofitBlockchainInfo().create(BlockchainInfoApi.class);
Single<BlockchainInfoAddress> addressObservable = api.blockchainInfoAddress(wallet, null);
Single<BlockchainInfoUnspents> unspentsObservable = api.blockchainInfoUnspents(wallet)
.onErrorReturnItem(new BlockchainInfoUnspents(new ArrayList<>()));
Single.zip(addressObservable, unspentsObservable, BlockchainInfoAddressAndUnspents::new)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(addressAndUnspentsObserver);
}
public void sendTransaction(String tx, SingleObserver<ResponseBody> sendObserver) {
Log.i(TAG, "new getAddress request");
BlockchainInfoApi api = App.Companion.getNetworkComponent().getRetrofitBlockchainInfo().create(BlockchainInfoApi.class);
Single<ResponseBody> sendObservable = api.blockchainInfoPush(tx)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
sendObservable.subscribe(sendObserver);
}
public Single<List<BlockchainInfoTransaction>> getMoreAddressTxs(String wallet) {
Log.i(TAG, "new getAddress request");
BlockchainInfoApi api = App.Companion.getNetworkComponent().getRetrofitBlockchainInfo().create(BlockchainInfoApi.class);
Single<List<BlockchainInfoTransaction>> addressObservable = api.blockchainInfoAddress(wallet, page * 50)
.map(BlockchainInfoAddress::getTxs)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
page++;
return addressObservable;
}
}

View file

@ -1,73 +0,0 @@
package com.tangem.data.network;
import com.tangem.App;
import com.tangem.data.Blockchain;
import com.tangem.data.network.model.BlockchairAddressResponse;
import com.tangem.data.network.model.BlockchairSendBody;
import com.tangem.data.network.model.BlockchairStatsResponse;
import com.tangem.data.network.model.BlockchairTransactionResponse;
import com.tangem.tangem_card.util.Log;
import io.reactivex.Completable;
import io.reactivex.CompletableObserver;
import io.reactivex.Single;
import io.reactivex.SingleObserver;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
public class ServerApiBlockchair {
private static String TAG = ServerApiBlockchair.class.getSimpleName();
private String blockchain;
public ServerApiBlockchair(Blockchain blockchain) {
if (blockchain == Blockchain.BitcoinCash) this.blockchain = "bitcoin-cash";
}
public void getAddress(String wallet, SingleObserver<BlockchairAddressResponse> addressObserver) {
Log.i(TAG, "new getAddress request");
BlockchairApi api = App.Companion.getNetworkComponent().getRetrofitBlockchair().create(BlockchairApi.class);
Single<BlockchairAddressResponse> addressSingle = api.getAddress(blockchain, wallet)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
addressSingle.subscribe(addressObserver);
}
public void getTransaction(String transaction, SingleObserver<BlockchairTransactionResponse> transactionObserver) {
Log.i(TAG, "new getAddress request");
BlockchairApi api = App.Companion.getNetworkComponent().getRetrofitBlockchair().create(BlockchairApi.class);
Single<BlockchairTransactionResponse> transactionSingle = api.getTransaction(blockchain, transaction)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
transactionSingle.subscribe(transactionObserver);
}
public void getStats(SingleObserver<BlockchairStatsResponse> statsObserver) {
Log.i(TAG, "new getStats request");
BlockchairApi api = App.Companion.getNetworkComponent().getRetrofitBlockchair().create(BlockchairApi.class);
Single<BlockchairStatsResponse> statsSingle = api.getStats(blockchain)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
statsSingle.subscribe(statsObserver);
}
public void sendTransaction(String tx, CompletableObserver sendObserver) {
Log.i(TAG, "new getAddress request");
BlockchairApi api = App.Companion.getNetworkComponent().getRetrofitDucatus().create(BlockchairApi.class);
Completable sendCompletable = api.sendTransaction(blockchain, new BlockchairSendBody(tx))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
sendCompletable.subscribe(sendObserver);
}
public String getUrl() {
return ServerURL.API_BLOCKCHAIR;
}
}

View file

@ -1,212 +0,0 @@
package com.tangem.data.network;
import android.util.Log;
import androidx.annotation.NonNull;
import com.tangem.App;
import com.tangem.data.Blockchain;
import com.tangem.data.network.model.BlockcypherBody;
import com.tangem.data.network.model.BlockcypherFee;
import com.tangem.data.network.model.BlockcypherResponse;
import com.tangem.data.network.model.BlockcypherTx;
import java.util.Random;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class ServerApiBlockcypher {
private static String TAG = ServerApiBlockcypher.class.getSimpleName();
public static final String BLOCKCYPHER_ADDRESS = "blockcypher_address";
public static final String BLOCKCYPHER_FEE = "blockcypher_fee";
public static final String BLOCKCYPHER_TXS = "blockcypher_txs";
public static final String BLOCKCYPHER_SEND = "blockcypher_send";
private int requestsCount = 0;
public boolean isRequestsSequenceCompleted() {
Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount));
return requestsCount <= 0;
}
private String apiKey = null;
private ResponseListener responseListener;
private TxResponseListener txResponseListener;
public interface ResponseListener {
void onSuccess(String method, BlockcypherResponse blockcypherResponse);
void onSuccess(String method, BlockcypherFee blockcypherFee);
void onFail(String method, String message);
}
public interface TxResponseListener {
void onSuccess(BlockcypherTx blockcypherTx);
void onFail(String message);
}
public void setResponseListener(ResponseListener listener) {
responseListener = listener;
}
public void setTxResponseListener(TxResponseListener txListener) {
txResponseListener = txListener;
}
public void requestData(String blockchainID, String method, String wallet, String tx) {
requestsCount++;
String blockchain = blockchainID.toLowerCase();
BlockcypherApi blockcypherApi = App.Companion.getNetworkComponent().getRetrofitBlockcypher().create(BlockcypherApi.class);
String network = "main";
if (blockchainID.equals(Blockchain.BitcoinTestNet.getID())) {
blockchain = "btc";
network = "test3";
}
if (blockchainID.equals(Blockchain.Token.getID())) blockchain = "eth";
if (blockchainID.equals(Blockchain.BitcoinDual.getID())) blockchain = "btc";
switch (method) {
case BLOCKCYPHER_ADDRESS:
Call<BlockcypherResponse> addressCall = blockcypherApi.blockcypherAddress(blockchain, network, wallet, apiKey);
addressCall.enqueue(new Callback<BlockcypherResponse>() {
@Override
public void onResponse(@NonNull Call<BlockcypherResponse> call, @NonNull Response<BlockcypherResponse> response) {
requestsCount--;
switch (response.code()) {
case 200:
responseListener.onSuccess(method, response.body());
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
break;
case 429:
apiKey = getRandomApiKey();
requestData(blockchainID, method, wallet, tx);
break;
default:
responseListener.onFail(method, String.valueOf(response.code()));
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
break;
}
}
@Override
public void onFailure(@NonNull Call<BlockcypherResponse> call, @NonNull Throwable t) {
requestsCount--;
responseListener.onFail(method, String.valueOf(t.getMessage()));
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
}
});
break;
case BLOCKCYPHER_FEE:
Call<BlockcypherFee> feeCall = blockcypherApi.blockcypherMain(blockchain, network, apiKey);
feeCall.enqueue(new Callback<BlockcypherFee>() {
@Override
public void onResponse(@NonNull Call<BlockcypherFee> call, @NonNull Response<BlockcypherFee> response) {
requestsCount--;
switch (response.code()) {
case 200:
responseListener.onSuccess(method, response.body());
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
break;
case 429:
apiKey = getRandomApiKey();
requestData(blockchainID, method, wallet, tx);
break;
default:
responseListener.onFail(method, String.valueOf(response.code()));
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
break;
}
}
@Override
public void onFailure(@NonNull Call<BlockcypherFee> call, @NonNull Throwable t) {
requestsCount--;
responseListener.onFail(method, String.valueOf(t.getMessage()));
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
}
});
break;
case BLOCKCYPHER_TXS:
Call<BlockcypherTx> txsCall = blockcypherApi.blockcypherTxs(blockchain, network, tx, apiKey);
txsCall.enqueue(new Callback<BlockcypherTx>() {
@Override
public void onResponse(@NonNull Call<BlockcypherTx> call,@NonNull Response<BlockcypherTx> response) {
requestsCount--;
switch (response.code()) {
case 200:
txResponseListener.onSuccess(response.body());
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
break;
case 429:
apiKey = getRandomApiKey();
requestData(blockchainID, method, wallet, tx);
break;
default:
txResponseListener.onFail(String.valueOf(response.code()));
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
break;
}
}
@Override
public void onFailure(@NonNull Call<BlockcypherTx> call, @NonNull Throwable t) {
requestsCount--;
txResponseListener.onFail(String.valueOf(t.getMessage()));
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
}
});
break;
case BLOCKCYPHER_SEND:
Call<BlockcypherResponse> sendCall = blockcypherApi.blockcypherPush(blockchain, network, new BlockcypherBody(tx), apiKey);
sendCall.enqueue(new Callback<BlockcypherResponse>() {
@Override
public void onResponse(@NonNull Call<BlockcypherResponse> call, @NonNull Response<BlockcypherResponse> response) {
requestsCount--;
switch (response.code()) {
case 201:
responseListener.onSuccess(method, response.body());
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
break;
case 429:
apiKey = getRandomApiKey();
requestData(blockchainID, method, wallet, tx);
break;
default:
responseListener.onFail(method, String.valueOf(response.code()));
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
break;
}
}
@Override
public void onFailure(@NonNull Call<BlockcypherResponse> call, @NonNull Throwable t) {
requestsCount--;
responseListener.onFail(method, String.valueOf(t.getMessage()));
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
}
});
break;
default:
requestsCount--;
responseListener.onFail(method, "undeclared method");
Log.e(TAG, "requestData " + method + " onFailure - undeclared method");
break;
}
}
private String getRandomApiKey() {
return BlockcypherToken
.values()[new Random().nextInt(BlockcypherToken.values().length)].getToken();
}
}

View file

@ -1,172 +0,0 @@
package com.tangem.data.network;
import android.annotation.SuppressLint;
import androidx.annotation.NonNull;
import android.util.Log;
import com.tangem.App;
import com.tangem.data.network.model.RateInfoResponse;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class ServerApiCommon {
private static String TAG = ServerApiCommon.class.getSimpleName();
/**
* HTTP
* Estimate fee
*/
public static final int ESTIMATE_FEE_PRIORITY = 2;
public static final int ESTIMATE_FEE_NORMAL = 3;
public static final int ESTIMATE_FEE_MINIMAL = 6;
private EstimatedFeeListener estimatedFeeListener;
public interface EstimatedFeeListener {
void onSuccess(int blockCount, String estimateFeeResponse);
void onFail(int blockCount, String message);
}
public void setBtcEstimatedFeeListener(EstimatedFeeListener listener) {
estimatedFeeListener = listener;
}
public void requestBtcEstimatedFee(int blockCount) {
EstimatefeeApi estimatefeeApi = App.Companion.getNetworkComponent().getRetrofitEstimatefee().create(EstimatefeeApi.class);
Call<String> call;
switch (blockCount) {
case ESTIMATE_FEE_PRIORITY:
call = estimatefeeApi.getEstimateFeePriority();
break;
case ESTIMATE_FEE_NORMAL:
call = estimatefeeApi.getEstimateFeeNormal();
break;
case ESTIMATE_FEE_MINIMAL:
call = estimatefeeApi.getEstimateFeeMinimal();
break;
default:
call = estimatefeeApi.getEstimateFeeNormal();
}
call.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
if (response.code() == 200) {
estimatedFeeListener.onSuccess(blockCount, response.body());
Log.i(TAG, "requestBtcEstimatedFee onResponse " + response.code() + " " + response.body());
} else
estimatedFeeListener.onFail(blockCount, response.body());
Log.e(TAG, "requestBtcEstimatedFee onResponse " + response.code());
}
@Override
public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
estimatedFeeListener.onFail(blockCount, t.getMessage());
Log.e(TAG, "requestBtcEstimatedFee onFailure " + t.getMessage());
}
});
}
/**
* HTTP
* Used in Crypto-currency course
*/
private RateInfoListener rateInfoListener;
public interface RateInfoListener {
void onSuccess(RateInfoResponse rateInfoResponse);
void onFail(String message);
}
public void setRateInfoListener(RateInfoListener listener) {
rateInfoListener = listener;
}
public void requestRateInfo(String cryptoId) {
CoinmarketApi coinmarketApi = App.Companion.getNetworkComponent().getRetrofitCoinmarketcap().create(CoinmarketApi.class);
// Call<RateInfoResponse> call = coinmarketApi.getRateInfo(1, cryptoId);
//
// call.enqueue(new Callback<RateInfoResponse>() {
// @Override
// public void onResponse(@NonNull Call<RateInfoResponse> call, @NonNull Response<RateInfoResponse> response) {
// if (response.code() == 200) {
// rateInfoListener.onSuccess(response.body());
// Log.i(TAG, "coinmarketcap onResponse " + response.code());
// } else {
// rateInfoListener.onFail("Rate info error:" + String.valueOf(response.code()));
// Log.e(TAG, "coinmarketcap onResponse " + response.code());
// }
// }
//
// @Override
// public void onFailure(@NonNull Call<RateInfoResponse> call, @NonNull Throwable t) {
// rateInfoListener.onFail(String.valueOf(t.getMessage()));
// Log.e(TAG, "coinmarketcap onFailure " + t.getMessage());
// }
// });
coinmarketApi.getRateInfo(1, cryptoId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(rateInfoResponse -> {
if (rateInfoResponse.getData().getQuote().getUsd().getPrice() != null) {
rateInfoListener.onSuccess(rateInfoResponse);
Log.i(TAG, "coinmarketcap onResponse " + 200);
} else {
rateInfoListener.onFail("Rate info error: wrong response");
}
},
// handle error
Throwable::printStackTrace);
}
/**
* HTTP
* Last version request from GitHub
*/
private LastVersionListener lastVersionListener;
public interface LastVersionListener {
void onSuccess(String lastVersion);
}
public void setLastVersionListener(LastVersionListener listener) {
lastVersionListener = listener;
}
public void requestLastVersion() {
UpdateVersionApi updateVersionApi = App.Companion.getNetworkComponent().getRetrofitGitHubUserContent().create(UpdateVersionApi.class);
Call<ResponseBody> call = updateVersionApi.getLastVersion();
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(@NonNull Call<ResponseBody> call, @NonNull Response<ResponseBody> response) {
Log.i(TAG, "requestLastVersion onResponse " + response.code());
if (response.code() == 200) {
String stringResponse;
try {
stringResponse = response.body() != null ? response.body().string() : null;
lastVersionListener.onSuccess(stringResponse);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) {
Log.e(TAG, "lastVersion onFailure " + t.getMessage());
}
});
}
}

View file

@ -1,386 +0,0 @@
package com.tangem.data.network;
import android.util.Log;
import com.tangem.App;
import com.tangem.data.Blockchain;
import com.tangem.wallet.R;
import com.tangem.wallet.TangemContext;
import com.tangem.wallet.bch.BitcoinCashNode;
import com.tangem.wallet.btc.BitcoinNode;
import com.tangem.wallet.btc.BitcoinNodeTestNet;
import com.tangem.wallet.ltc.LitecoinNode;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.observers.DefaultObserver;
import io.reactivex.schedulers.Schedulers;
/**
* Request processor for Electrum Api
* Every request live cycle:
* 1. In application create request and call {@link ServerApiElectrum}.requestData(..)
* 2. Try send every request for max 4 times,
* 3. If all 4 times fail call DefaultObserver<ElectrumRequest>.onError (defined in .requestData(..)) and than
* {@link ResponseListener}.onFail(...) callback
* Error can be acquired with {@link ElectrumRequest}.getError() method
* 4. If request network communication finished successfully then call DefaultObserver<ElectrumRequest>.onComplete (defined in .requestData) and than
* {@link ResponseListener}.onSuccess(...) callback
*/
public class ServerApiElectrum {
public static final String ERROR_STARTS_WITH_CODE_32601 = "{\"code\":-32601,";
private static String TAG = ServerApiElectrum.class.getSimpleName();
/**
* TCP, SSL
* Used in BTC, BCH
*/
private ResponseListener responseListener;
private String host;
private int port;
private int requestsCount=0;
public boolean isRequestsSequenceCompleted() {
Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount));
return requestsCount <= 0;
}
/**
* Interface for notification every request result
*/
public interface ResponseListener {
/**
* Notify that request processing was successful
* @param electrumRequest - processed request containing received answer {@see electrumRequest.getAnswer() method}
*/
void onSuccess(ElectrumRequest electrumRequest);
/**
* Notify that request processing was successful
* @param electrumRequest - processed request containing occurred error {@see electrumRequest.getError() method}
*/
void onFail(ElectrumRequest electrumRequest);
}
/**
* Set notificaion listener
* @param listener
*/
public void setResponseListener(ResponseListener listener) {
responseListener = listener;
}
/**
* Start process request
* @param ctx
* @param electrumRequest
*/
public void requestData(TangemContext ctx, ElectrumRequest electrumRequest) {
requestsCount++;
Log.i(TAG, String.format("New request[%d]: %s", requestsCount,electrumRequest.getMethod()));
Observable<ElectrumRequest> checkElectrumDataObserver = Observable.just(electrumRequest)
.doOnNext(electrumRequest1 -> doElectrumRequest(ctx, electrumRequest))
.flatMap(electrumRequest1 -> {
if (electrumRequest1.answerData == null) {
Log.e(TAG, "NullPointerException " + electrumRequest.getMethod());
return Observable.error(new NullPointerException());
} else
return Observable.just(electrumRequest1);
})
.retryWhen(errors -> errors
.filter(throwable -> throwable instanceof NullPointerException)
.zipWith(Observable.range(1, 4), (n, i) -> i))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
checkElectrumDataObserver.subscribe(new DefaultObserver<ElectrumRequest>() {
//TODO remove onNext
@Override
public void onNext(ElectrumRequest v) {
if (electrumRequest.answerData != null) {
Log.i(TAG, "requestData " + electrumRequest.getMethod() + " onNext != null");
} else {
Log.e(TAG, "requestData " + electrumRequest.getMethod() + " onNext == null");
}
}
@Override
public void onError(Throwable e) {
requestsCount--;
Log.e(TAG, "requestData " + electrumRequest.getMethod() + " onError " + e.getMessage());
Log.e(TAG, String.format("%d requests left in processing",requestsCount));
electrumRequest.setError(ctx.getString(R.string.loaded_wallet_error_obtaining_blockchain_data));
//setErrorOccurred(e.getMessage());//;
responseListener.onFail(electrumRequest);
}
/**
* Called after completion request processing
*/
@Override
public void onComplete() {
requestsCount--;
if (electrumRequest.answerData != null) {
Log.i(TAG, "requestData " + electrumRequest.getMethod() + " onComplete, answerData!=null");
} else {
Log.e(TAG, "requestData " + electrumRequest.getMethod() + " onComplete, answerData==null");
}
Log.e(TAG, String.format("%d requests left in processing",requestsCount));
if (electrumRequest.answerData != null && electrumRequest.getError()==null) {
responseListener.onSuccess(electrumRequest);
} else {
// if( error==null || error.isEmpty() ) setErrorOccurred(ctx.getString(R.string.cannot_obtain_data_from_blockchain));
responseListener.onFail(electrumRequest);
}
}
});
}
private void doElectrumRequest(TangemContext ctx, ElectrumRequest electrumRequest) {
String host;
int port;
String proto;
electrumRequest.setError(null);
// todo - get available URL list from coinEngine, remove if( ctx.getBlockchain()==...)
if (ctx.getBlockchain() == Blockchain.BitcoinTestNet) {
BitcoinNodeTestNet bitcoinNodeTestNet = BitcoinNodeTestNet.values()[new Random().nextInt(BitcoinNodeTestNet.values().length)];
host = bitcoinNodeTestNet.getHost();
port = bitcoinNodeTestNet.getPort();
this.host = host;
this.port = port;
doElectrumRequestTcp(electrumRequest, host, port);
} else if (ctx.getBlockchain() == Blockchain.BitcoinCash) {
BitcoinCashNode bitcoinCashNode = BitcoinCashNode.values()[new Random().nextInt(BitcoinCashNode.values().length)];
host = bitcoinCashNode.getHost();
port = bitcoinCashNode.getPort();
proto = bitcoinCashNode.getProto();
this.host = host;
this.port = port;
if (proto.equals("tcp")) {
doElectrumRequestTcp(electrumRequest, host, port);
} else {
doElectrumRequestSsl(electrumRequest, host, port);
}
} else if (ctx.getBlockchain() == Blockchain.Bitcoin) {
BitcoinNode bitcoinNode = BitcoinNode.values()[new Random().nextInt(BitcoinNode.values().length)];
host = bitcoinNode.getHost();
port = bitcoinNode.getPort();
proto = bitcoinNode.getProto();
this.host = host;
this.port = port;
if (proto.equals("tcp")) {
doElectrumRequestTcp(electrumRequest, host, port);
} else {
doElectrumRequestSsl(electrumRequest, host, port);
}
} else if (ctx.getBlockchain() == Blockchain.Litecoin) {
LitecoinNode litecoinNode = LitecoinNode.values()[new Random().nextInt(LitecoinNode.values().length)];
host = litecoinNode.getHost();
port = litecoinNode.getPort();
proto = litecoinNode.getProto();
this.host = host;
this.port = port;
if (proto.equals("tcp")) {
doElectrumRequestTcp(electrumRequest, host, port);
} else {
doElectrumRequestSsl(electrumRequest, host, port);
}
}
}
private void doElectrumRequestTcp(ElectrumRequest electrumRequest, String host, int port) {
try {
Socket socket = App.Companion.getNetworkComponent().getSocket();
socket.setSoTimeout(3000);
Log.i(TAG, "Start process "+electrumRequest.getMethod()+" @ "+host + ":" + port);
socket.connect(new InetSocketAddress(InetAddress.getByName(host), port));
try {
OutputStream os = socket.getOutputStream();
OutputStreamWriter out = new OutputStreamWriter(os, "UTF-8");
InputStream is = socket.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(is));
electrumRequest.setID(1);
out.write(electrumRequest.getAsString() + "\n");
out.flush();
electrumRequest.answerData = in.readLine();
electrumRequest.host = host;
electrumRequest.port = port;
if (electrumRequest.answerData != null) {
Log.i(TAG, ">> " + electrumRequest.answerData);
if( (electrumRequest.getError()!=null && electrumRequest.getError().startsWith(ERROR_STARTS_WITH_CODE_32601)) )
{
// method unknown error???
electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_obtaining_blockchain_data));
electrumRequest.answerData=null;
}
} else {
electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_blockchain_empty_answer));
Log.i(TAG, ">> <NULL>");
}
} catch (ConnectException e) {
//e.printStackTrace();
//responseListener.onFail(e.getMessage());
electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_blockchain_connection_refused));
Log.e(TAG, "doElectrumRequestTcp " + electrumRequest.getMethod() + " ConnectException " + e.getMessage());
} finally {
Log.i(TAG, "doElectrumRequestTcp " + electrumRequest.getMethod() + " socket.close");
try {
if( socket.isConnected() ) socket.close();
}
catch (Exception e)
{
e.printStackTrace();
Log.e(TAG,"Can't close socket");
electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_blockchain_communication_error));
}
}
} catch (IOException e) {
//e.printStackTrace();
//responseListener.onFail(e.getMessage());
electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_blockchain_communication_error));
Log.e(TAG, "doElectrumRequestTcp " + electrumRequest.getMethod() + " IOException " + e.getMessage());
}
}
private void doElectrumRequestSsl(ElectrumRequest electrumRequest, String host, int port) {
try {
// create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}};
// install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
SSLSocketFactory sf = sc.getSocketFactory();
HttpsURLConnection.setDefaultSSLSocketFactory(sf);
// create all-trusting host name verifier
HostnameVerifier allHostsValid = (hostname, session) -> true;
// install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
Socket sslSocket = new Socket();
List<ElectrumRequest> result = new ArrayList<>();
Collections.addAll(result, electrumRequest);
try {
Log.i(TAG, host + " " + port);
sslSocket.connect(new InetSocketAddress(host,port), 3000);
sslSocket.setSoTimeout(3000);
sslSocket = sf.createSocket(sslSocket, host, port, true);
try {
OutputStream os = sslSocket.getOutputStream();
OutputStreamWriter out = new OutputStreamWriter(os, "UTF-8");
InputStream is = sslSocket.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(is));
electrumRequest.setID(1);
out.write(electrumRequest.getAsString() + "\n");
out.flush();
electrumRequest.answerData = in.readLine();
if (electrumRequest.answerData != null) {
Log.i(TAG, ">> " + electrumRequest.answerData);
if( (electrumRequest.getError()!=null && electrumRequest.getError().startsWith(ERROR_STARTS_WITH_CODE_32601)) )
{
// method unknown error???
electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_obtaining_blockchain_data));
electrumRequest.answerData=null;
}
} else {
electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_blockchain_empty_answer));
Log.i(TAG, ">> <NULL>");
}
} catch (ConnectException e) {
e.printStackTrace();
electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_blockchain_connection_refused));
Log.e(TAG, "doElectrumRequestSsl " + electrumRequest.getMethod() + " ConnectException " + e.getMessage());
} finally {
Log.i(TAG, "doElectrumRequestSsl " + electrumRequest.getMethod() + " socket.close");
try {
if( sslSocket.isConnected() ) sslSocket.close();
}
catch (Exception e)
{
electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_blockchain_communication_error));
e.printStackTrace();
Log.e(TAG, "Can't close ssl socket");
}
}
} catch (IOException e) {
e.printStackTrace();
electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_blockchain_communication_error));
Log.e(TAG, "doElectrumRequestSsl " + electrumRequest.getMethod() + " IOException " + e.getMessage());
}
} catch (NoSuchAlgorithmException | KeyManagementException e) {
electrumRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_obtaining_blockchain_data));
Log.e(TAG, e.getMessage());
}
}
public String getValidationNodeDescription() {
return "Electrum, " + host + ":" + String.valueOf(port);
}
}

View file

@ -1,46 +0,0 @@
package com.tangem.data.network;
import android.util.Log;
import com.tangem.wallet.eos.EosApiPush;
import com.tangem.wallet.eos.EosPushTransactionRequest;
import io.jafka.jeos.EosApi;
import io.jafka.jeos.EosApiFactory;
import io.jafka.jeos.core.response.chain.account.Account;
import io.jafka.jeos.core.response.chain.transaction.PushedTransaction;
import io.jafka.jeos.impl.EosApiServiceGenerator;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
public class ServerApiEos {
private static String TAG = ServerApiEos.class.getSimpleName();
public static void getBalance(String wallet, Observer<Account> accountObserver) {
Log.i(TAG, "new getBalance request");
EosApi eosApi = EosApiFactory.create("https://api.eosdetroit.io:443"); //TODO: add random server request
Observable<Account> accountObservable = Observable.just(new Account())
.map(account -> eosApi.getAccount(wallet))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
accountObservable.subscribe(accountObserver);
}
public static void sendTransaction(EosPushTransactionRequest req, Observer<PushedTransaction> sendObserver) {
Log.i(TAG, "new getBalance request");
// EosApi eosApi = EosApiFactory.create("https://api.eosdetroit.io:443"); //TODO: add random server request
EosApiPush eosApiPush = EosApiServiceGenerator.createService(EosApiPush.class, "https://api.eosdetroit.io:443"); //TODO: add random server request
Observable<PushedTransaction> sendObservable = Observable.just(new PushedTransaction())
.map(pushedTransaction -> EosApiServiceGenerator.executeSync(eosApiPush.pushTransaction(req)))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
sendObservable.subscribe(sendObserver);
}
}

View file

@ -1,121 +0,0 @@
package com.tangem.data.network;
import android.util.Log;
import androidx.annotation.NonNull;
import com.tangem.App;
import com.tangem.data.Blockchain;
import com.tangem.data.network.model.InfuraBody;
import com.tangem.data.network.model.InfuraResponse;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class ServerApiInfura {
private static String TAG = ServerApiInfura.class.getSimpleName();
/**
* HTTP
* Infura
* <p>
* eth_getBalance
* eth_getTransactionCount
* eth_call
* eth_sendRawTransaction
* eth_gasPrice
*/
public static final String INFURA_ETH_GET_BALANCE = "eth_getBalance";
public static final String INFURA_ETH_GET_TRANSACTION_COUNT = "eth_getTransactionCount";
public static final String INFURA_ETH_GET_PENDING_COUNT = "eth_getPendingCount";
public static final String INFURA_ETH_CALL = "eth_call";
public static final String INFURA_ETH_SEND_RAW_TRANSACTION = "eth_sendRawTransaction";
public static final String INFURA_ETH_GAS_PRICE = "eth_gasPrice";
private int requestsCount=0;
private InfuraApi infuraApi = App.Companion.getNetworkComponent().getRetrofitInfura().create(InfuraApi.class);
public ServerApiInfura() {}
public ServerApiInfura(Blockchain blockchain) {
if (blockchain == Blockchain.EthereumTestNet) {
infuraApi = App.Companion.getNetworkComponent().getRetrofitInfuraTestnet().create(InfuraApi.class);
} else if (blockchain == Blockchain.TokenEmv) {
infuraApi = App.Companion.getNetworkComponent().getRetrofitInfuraRopsten().create(InfuraApi.class);
}
}
public boolean isRequestsSequenceCompleted() {
Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount));
return requestsCount <= 0;
}
private ResponseListener responseListener;
public interface ResponseListener {
void onSuccess(String method, InfuraResponse infuraResponse);
void onFail(String method, String message);
}
public void setResponseListener(ResponseListener listener) {
responseListener = listener;
}
public void requestData(String method, int id, String wallet, String contract, String tx) {
requestsCount++;
InfuraBody infuraBody;
switch (method) {
case INFURA_ETH_GET_BALANCE:
case INFURA_ETH_GET_TRANSACTION_COUNT:
infuraBody = new InfuraBody(method, new String[]{wallet, "latest"}, id);
break;
case INFURA_ETH_GET_PENDING_COUNT:
infuraBody = new InfuraBody(INFURA_ETH_GET_TRANSACTION_COUNT, new String[]{wallet, "pending"}, id);
break;
case INFURA_ETH_CALL:
String address = wallet.substring(2);
infuraBody = new InfuraBody(method, new Object[]{new InfuraBody.EthCallParams("0x70a08231000000000000000000000000" + address, contract), "latest"}, id);
break;
case INFURA_ETH_SEND_RAW_TRANSACTION:
infuraBody = new InfuraBody(method, new String[]{tx}, id);
break;
case INFURA_ETH_GAS_PRICE:
infuraBody = new InfuraBody(method, id);
break;
default:
infuraBody = new InfuraBody();
}
Call<InfuraResponse> call = infuraApi.infura(infuraBody);
call.enqueue(new Callback<InfuraResponse>() {
@Override
public void onResponse(@NonNull Call<InfuraResponse> call, @NonNull Response<InfuraResponse> response) {
requestsCount--;
if (response.code() == 200) {
responseListener.onSuccess(method, response.body());
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
} else {
responseListener.onFail(method, String.valueOf(response.code()));
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
}
}
@Override
public void onFailure(@NonNull Call<InfuraResponse> call, @NonNull Throwable t) {
requestsCount--;
responseListener.onFail(method, String.valueOf(t.getMessage()));
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
}
});
}
}

View file

@ -1,131 +0,0 @@
package com.tangem.data.network;
import android.util.Log;
import androidx.annotation.NonNull;
import com.tangem.data.network.model.InsightBody;
import com.tangem.data.network.model.InsightResponse;
import com.tangem.data.network.model.InsightUtxo;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class ServerApiInsight {
private static String TAG = ServerApiInsight.class.getSimpleName();
public static final String INSIGHT_ADDRESS = "addr/{address}";
public static final String INSIGHT_UNSPENT_OUTPUTS = "addr/{address}/utxo";
public static final String INSIGHT_TRANSACTION = "rawtx/{txId}";
public static final String INSIGHT_FEE = "utils/estimatefee?nbBlocks=2,3,6";
public static final String INSIGHT_SEND = "tx/send";
private int requestsCount = 0;
public static String lastNode;
public boolean isRequestsSequenceCompleted() {
Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount));
return requestsCount <= 0;
}
private ResponseListener responseListener;
public interface ResponseListener {
void onSuccess(String method, InsightResponse insightResponse);
void onSuccess(String method, List<InsightUtxo> utxoList);
void onFail(String method, String message);
}
public void setResponseListener(ResponseListener listener) {
responseListener = listener;
}
public void requestData(String method, String wallet, String tx) {
requestsCount++;
String insightURL = "https://insight.ducatus.io/insight-lite-api/"; //TODO: make random selection
this.lastNode = insightURL; //TODO: show node instead of URL
Retrofit retrofitInsight = new Retrofit.Builder()
.baseUrl(insightURL)
.addConverterFactory(GsonConverterFactory.create())
.build();
// InsightApi insightApi = App.getNetworkComponent().getRetrofitInsight(insightURL).create(InsightApi.class);
InsightApi insightApi = retrofitInsight.create(InsightApi.class);
if (method.equals(INSIGHT_UNSPENT_OUTPUTS)) {
Call<List<InsightUtxo>> call = insightApi.insightUnspent(wallet);
call.enqueue(new Callback<List<InsightUtxo>>() {
@Override
public void onResponse(@NonNull Call<List<InsightUtxo>> call, @NonNull Response<List<InsightUtxo>> response) {
requestsCount--;
if (response.code() == 200) {
responseListener.onSuccess(method, response.body());
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
} else {
responseListener.onFail(method, String.valueOf(response.code()));
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
}
}
@Override
public void onFailure(@NonNull Call<List<InsightUtxo>> call, @NonNull Throwable t) {
requestsCount--;
responseListener.onFail(method, String.valueOf(t.getMessage()));
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
}
});
} else {
Call<InsightResponse> call;
switch (method) {
case INSIGHT_ADDRESS:
call = insightApi.insightAddress(wallet);
break;
// case INSIGHT_FEE:
// call = insightApi.insightFee();
// break;
case INSIGHT_SEND:
call = insightApi.insightSend(new InsightBody(tx));
break;
default:
call = insightApi.insightAddress(wallet);
break;
}
call.enqueue(new Callback<InsightResponse>() {
@Override
public void onResponse(@NonNull Call<InsightResponse> call, @NonNull Response<InsightResponse> response) {
requestsCount--;
if (response.code() == 200) {
responseListener.onSuccess(method, response.body());
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
} else {
responseListener.onFail(method, String.valueOf(response.code()));
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
}
}
@Override
public void onFailure(@NonNull Call<InsightResponse> call, @NonNull Throwable t) {
requestsCount--;
responseListener.onFail(method, String.valueOf(t.getMessage()));
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
}
});
}
}
}

View file

@ -1,108 +0,0 @@
package com.tangem.data.network;
import android.util.Log;
import androidx.annotation.NonNull;
import com.tangem.App;
import com.tangem.data.network.model.InfuraBody;
import com.tangem.data.network.model.InfuraResponse;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class ServerApiMatic {
private static String TAG = ServerApiMatic.class.getSimpleName();
/**
* HTTP
* Infura
* <p>
* eth_getBalance
* eth_getTransactionCount
* eth_call
* eth_sendRawTransaction
* eth_gasPrice
*/
public static final String MATIC_ETH_GET_BALANCE = "eth_getBalance";
public static final String MATIC_ETH_GET_TRANSACTION_COUNT = "eth_getTransactionCount";
public static final String MATIC_ETH_GET_PENDING_COUNT = "eth_getPendingCount";
public static final String MATIC_ETH_CALL = "eth_call";
public static final String MATIC_ETH_SEND_RAW_TRANSACTION = "eth_sendRawTransaction";
public static final String MATIC_ETH_GAS_PRICE = "eth_gasPrice";
private int requestsCount=0;
public boolean isRequestsSequenceCompleted() {
Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount));
return requestsCount <= 0;
}
private ResponseListener responseListener;
public interface ResponseListener {
void onSuccess(String method, InfuraResponse infuraResponse);
void onFail(String method, String message);
}
public void setResponseListener(ResponseListener listener) {
responseListener = listener;
}
public void requestData(String method, int id, String wallet, String contract, String tx) {
requestsCount++;
MaticApi maticApi = App.Companion.getNetworkComponent().getRetrofitMaticTesnet().create(MaticApi.class);
InfuraBody infuraBody;
switch (method) {
case MATIC_ETH_GET_BALANCE:
case MATIC_ETH_GET_TRANSACTION_COUNT:
infuraBody = new InfuraBody(method, new String[]{wallet, "latest"}, id);
break;
case MATIC_ETH_GET_PENDING_COUNT:
infuraBody = new InfuraBody(MATIC_ETH_GET_TRANSACTION_COUNT, new String[]{wallet, "pending"}, id);
break;
case MATIC_ETH_CALL:
String address = wallet.substring(2);
infuraBody = new InfuraBody(method, new Object[]{new InfuraBody.EthCallParams("0x70a08231000000000000000000000000" + address, contract), "latest"}, id);
break;
case MATIC_ETH_SEND_RAW_TRANSACTION:
infuraBody = new InfuraBody(method, new String[]{tx}, id);
break;
case MATIC_ETH_GAS_PRICE:
infuraBody = new InfuraBody(method, id);
break;
default:
infuraBody = new InfuraBody();
}
Call<InfuraResponse> call = maticApi.matic(infuraBody);
call.enqueue(new Callback<InfuraResponse>() {
@Override
public void onResponse(@NonNull Call<InfuraResponse> call, @NonNull Response<InfuraResponse> response) {
requestsCount--;
if (response.code() == 200) {
responseListener.onSuccess(method, response.body());
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
} else {
responseListener.onFail(method, String.valueOf(response.code()));
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
}
}
@Override
public void onFailure(@NonNull Call<InfuraResponse> call, @NonNull Throwable t) {
requestsCount--;
responseListener.onFail(method, String.valueOf(t.getMessage()));
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
}
});
}
}

View file

@ -1,76 +0,0 @@
package com.tangem.data.network;
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import com.tangem.data.Blockchain;
import com.tangem.data.network.model.PayIdResponse;
import com.tangem.tangem_card.util.Log;
import java.security.InvalidParameterException;
import io.reactivex.Single;
import io.reactivex.SingleObserver;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class ServerApiPayId {
private static String TAG = ServerApiPayId.class.getSimpleName();
private int requestsCount = 0;
public String getAcceptHeader(Blockchain blockchain) throws InvalidParameterException {
switch (blockchain) {
case Ripple: return "application/xrpl-mainnet+json";
case Bitcoin: return "application/btc-mainnet+json";
case Litecoin: return "application/ltc-mainnet+json";
case Cardano:
case CardanoShelley:
return "application/ada-mainnet+json";
case Ducatus: return "application/duc-mainnet+json";
case BitcoinCash: return "application/bch-mainnet+json";
case Ethereum:
case Token:
return "application/eth-mainnet+json";
case Stellar:
case StellarAsset:
return "application/xlm-mainnet+json";
case Binance:
case BinanceAsset:
return "application/bnb-mainnet+json";
case Rootstock:
case RootstockToken:
return "application/rsk-mainnet+json";
default: throw new InvalidParameterException("PayID is not supported for " + blockchain.getOfficialName());
}
}
public boolean isRequestsSequenceCompleted() {
Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount));
return requestsCount <= 0;
}
public void getAddress(String payID, Blockchain blockchain, SingleObserver<PayIdResponse> addressObserver) throws InvalidParameterException {
requestsCount++;
Log.i(TAG, "new getAddress request");
String[] addressParts = payID.split("\\$");
String user = addressParts[0];
String domain = addressParts[1];
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://" + domain + "/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
PayIdApi api = retrofit.create(PayIdApi.class);
Single<PayIdResponse> addressSingle = api.getAddress(user, getAcceptHeader(blockchain))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnEvent((object, throwable) -> requestsCount--);
addressSingle.subscribe(addressObserver);
}
}

View file

@ -1,157 +0,0 @@
package com.tangem.data.network;
import android.util.Log;
import androidx.annotation.NonNull;
import com.tangem.data.network.model.RippleBody;
import com.tangem.data.network.model.RippleResponse;
import java.util.HashMap;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class ServerApiRipple {
private static String TAG = ServerApiRipple.class.getSimpleName();
public static final String RIPPLE_ACCOUNT_INFO = "account_info";
public static final String RIPPLE_ACCOUNT_UNCONFIRMED = "account_unconfirmed";
public static final String RIPPLE_SUBMIT = "submit";
public static final String RIPPLE_FEE = "fee";
public static final String RIPPLE_SERVER_STATE = "server_state";
private int requestsCount = 0;
private final String rippleURL1 = "https://s1.ripple.com:51234"; //TODO: make random selection, add more?, move
private final String rippleURL2 = "https://s2.ripple.com:51234";
private String currentURL = rippleURL1;
public String getCurrentURL() {
return currentURL;
}
public boolean isRequestsSequenceCompleted() {
Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount));
return requestsCount <= 0;
}
private ResponseListener responseListener;
public interface ResponseListener {
void onSuccess(String method, RippleResponse rippleResponse);
void onFail(String method, String message);
}
public void setResponseListener(ResponseListener listener) {
responseListener = listener;
}
public void requestData(String method, String wallet, String tx) {
requestsCount++;
Retrofit retrofitRipple = new Retrofit.Builder()
.baseUrl(currentURL)
.addConverterFactory(GsonConverterFactory.create())
.build();
RippleApi rippleApi = retrofitRipple.create(RippleApi.class);
RippleBody rippleBody;
HashMap<String, String> paramsMap;
switch (method) {
case RIPPLE_ACCOUNT_INFO:
paramsMap = new HashMap<>();
paramsMap.put("account", wallet);
paramsMap.put("ledger_index", "validated");
rippleBody = new RippleBody(method, paramsMap);
break;
case RIPPLE_ACCOUNT_UNCONFIRMED:
paramsMap = new HashMap<>();
paramsMap.put("account", wallet);
paramsMap.put("ledger_index", "current");
// paramsMap.put("queue", "true"); TODO: make queue check if needed
rippleBody = new RippleBody(RIPPLE_ACCOUNT_INFO, paramsMap);
break;
case RIPPLE_SERVER_STATE:
rippleBody = new RippleBody(method, new HashMap<>());
break;
case RIPPLE_FEE:
rippleBody = new RippleBody(method, new HashMap<>());
break;
case RIPPLE_SUBMIT:
paramsMap = new HashMap<>();
paramsMap.put("tx_blob", tx);
rippleBody = new RippleBody(method, paramsMap);
break;
default:
rippleBody = new RippleBody();
}
Call<RippleResponse> call = rippleApi.ripple(rippleBody);
call.enqueue(new Callback<RippleResponse>() {
@Override
public void onResponse(@NonNull Call<RippleResponse> call, @NonNull Response<RippleResponse> response) {
if (response.code() == 200) {
requestsCount--;
responseListener.onSuccess(method, response.body());
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
} else {
retryRequest(method, rippleBody);
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
}
}
@Override
public void onFailure(@NonNull Call<RippleResponse> call, @NonNull Throwable t) {
retryRequest(method, rippleBody);
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
}
});
}
private void retryRequest(String method, RippleBody rippleBody) {
currentURL = rippleURL2;
Retrofit retrofitRipple = new Retrofit.Builder()
.baseUrl(currentURL)
.addConverterFactory(GsonConverterFactory.create())
.build();
RippleApi rippleApi = retrofitRipple.create(RippleApi.class);
Call<RippleResponse> call = rippleApi.ripple(rippleBody);
call.enqueue(new Callback<RippleResponse>() {
@Override
public void onResponse(@NonNull Call<RippleResponse> call, @NonNull Response<RippleResponse> response) {
requestsCount--;
if (response.code() == 200) {
responseListener.onSuccess(method, response.body());
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
} else {
responseListener.onFail(method, String.valueOf(response.code()));
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
}
}
@Override
public void onFailure(@NonNull Call<RippleResponse> call, @NonNull Throwable t) {
requestsCount--;
responseListener.onFail(method, String.valueOf(t.getMessage()));
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
}
});
}
}

View file

@ -1,108 +0,0 @@
package com.tangem.data.network;
import android.util.Log;
import androidx.annotation.NonNull;
import com.tangem.App;
import com.tangem.data.network.model.InfuraBody;
import com.tangem.data.network.model.InfuraResponse;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class ServerApiRootstock {
private static String TAG = ServerApiRootstock.class.getSimpleName();
/**
* HTTP
* Rootstock
* <p>
* eth_getBalance
* eth_getTransactionCount
* eth_call
* eth_sendRawTransaction
* eth_gasPrice
*/
public static final String ROOTSTOCK_ETH_GET_BALANCE = "eth_getBalance";
public static final String ROOTSTOCK_ETH_GET_TRANSACTION_COUNT = "eth_getTransactionCount";
public static final String ROOTSTOCK_ETH_GET_PENDING_COUNT = "eth_getPendingCount";
public static final String ROOTSTOCK_ETH_CALL = "eth_call";
public static final String ROOTSTOCK_ETH_SEND_RAW_TRANSACTION = "eth_sendRawTransaction";
public static final String ROOTSTOCK_ETH_GAS_PRICE = "eth_gasPrice";
private int requestsCount=0;
public boolean isRequestsSequenceCompleted() {
Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount));
return requestsCount <= 0;
}
private ResponseListener responseListener;
public interface ResponseListener {
void onSuccess(String method, InfuraResponse infuraResponse);
void onFail(String method, String message);
}
public void setResponseListener(ResponseListener listener) {
responseListener = listener;
}
public void requestData(String method, int id, String wallet, String contract, String tx) {
requestsCount++;
RootstockApi rootstockApi = App.Companion.getNetworkComponent().getRetrofitRootstock().create(RootstockApi.class);
InfuraBody infuraBody;
switch (method) {
case ROOTSTOCK_ETH_GET_BALANCE:
case ROOTSTOCK_ETH_GET_TRANSACTION_COUNT:
infuraBody = new InfuraBody(method, new String[]{wallet, "latest"}, id);
break;
case ROOTSTOCK_ETH_GET_PENDING_COUNT:
infuraBody = new InfuraBody(ROOTSTOCK_ETH_GET_TRANSACTION_COUNT, new String[]{wallet, "pending"}, id);
break;
case ROOTSTOCK_ETH_CALL:
String address = wallet.substring(2);
infuraBody = new InfuraBody(method, new Object[]{new InfuraBody.EthCallParams("0x70a08231000000000000000000000000" + address, contract), "latest"}, id);
break;
case ROOTSTOCK_ETH_SEND_RAW_TRANSACTION:
infuraBody = new InfuraBody(method, new String[]{tx}, id);
break;
case ROOTSTOCK_ETH_GAS_PRICE:
infuraBody = new InfuraBody(method, id);
break;
default:
infuraBody = new InfuraBody();
}
Call<InfuraResponse> call = rootstockApi.rootstock(infuraBody);
call.enqueue(new Callback<InfuraResponse>() {
@Override
public void onResponse(@NonNull Call<InfuraResponse> call, @NonNull Response<InfuraResponse> response) {
requestsCount--;
if (response.code() == 200) {
responseListener.onSuccess(method, response.body());
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
} else {
responseListener.onFail(method, String.valueOf(response.code()));
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
}
}
@Override
public void onFailure(@NonNull Call<InfuraResponse> call, @NonNull Throwable t) {
requestsCount--;
responseListener.onFail(method, String.valueOf(t.getMessage()));
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
}
});
}
}

View file

@ -1,186 +0,0 @@
package com.tangem.data.network;
import android.util.Log;
import androidx.annotation.NonNull;
import com.tangem.App;
import com.tangem.data.Blockchain;
import com.tangem.data.network.model.SoChain;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class ServerApiSoChain {
private static String TAG = ServerApiSoChain.class.getSimpleName();
private int requestsCount = 0;
public boolean isRequestsSequenceCompleted() {
Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount));
return requestsCount <= 0;
}
public interface AddressInfoListener {
void onSuccess(SoChain.Response.AddressBalance response);
void onSuccess(SoChain.Response.TxUnspent response);
void onFail(String message);
}
private AddressInfoListener addressInfoListener;
public void setAddressInfoListener(AddressInfoListener listener) {
addressInfoListener = listener;
}
public interface SendTxListener {
void onSuccess(SoChain.Response.SendTx response);
void onFail(String message);
}
private SendTxListener sendTxListener;
public void setSendTxListener(SendTxListener listener) {
sendTxListener = listener;
}
public interface TransactionInfoListener {
void onSuccess(SoChain.Response.GetTx response);
void onFail(String message);
}
private TransactionInfoListener txInfoListener;
public void setTransactionInfoListener(TransactionInfoListener listener) {
txInfoListener=listener;
}
private String getNetwork(Blockchain blockchain) throws Exception {
switch (blockchain) {
case Bitcoin:
return "BTC";
case BitcoinTestNet:
return "BTCTEST";
case Litecoin:
return "LTC";
default:
throw new Exception("SoChainAPI don't support blockchain " + blockchain.getID());
}
}
public void requestAddressBalance(Blockchain blockchain, String wallet) throws Exception {
requestsCount++;
SoChainApi api = App.Companion.getNetworkComponent().getRetrofitSoChain().create(SoChainApi.class);
Call<SoChain.Response.AddressBalance> call = api.getAddressBalance(getNetwork(blockchain), wallet);
call.enqueue(new Callback<SoChain.Response.AddressBalance>() {
@Override
public void onResponse(@NonNull Call<SoChain.Response.AddressBalance> call, @NonNull Response<SoChain.Response.AddressBalance> response) {
requestsCount--;
Log.i(TAG, "requestAddressBalance onResponse " + response.code());
if (response.code() == 200) {
addressInfoListener.onSuccess(response.body());
} else {
addressInfoListener.onFail(String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<SoChain.Response.AddressBalance> call, @NonNull Throwable t) {
requestsCount--;
Log.e(TAG, "requestAddressBalance onFailure " + t.getMessage());
addressInfoListener.onFail(String.valueOf(t.getMessage()));
}
});
}
public void requestUnspentTx(Blockchain blockchain, String wallet) throws Exception {
requestsCount++;
SoChainApi api = App.Companion.getNetworkComponent().getRetrofitSoChain().create(SoChainApi.class);
Call<SoChain.Response.TxUnspent> call = api.getUnspentTx(getNetwork(blockchain), wallet);
call.enqueue(new Callback<SoChain.Response.TxUnspent>() {
@Override
public void onResponse(@NonNull Call<SoChain.Response.TxUnspent> call, @NonNull Response<SoChain.Response.TxUnspent> response) {
requestsCount--;
Log.i(TAG, "requestAddressBalance onResponse " + response.code());
if (response.code() == 200) {
addressInfoListener.onSuccess(response.body());
} else {
addressInfoListener.onFail(String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<SoChain.Response.TxUnspent> call, @NonNull Throwable t) {
requestsCount--;
Log.e(TAG, "requestAddressBalance onFailure " + t.getMessage());
addressInfoListener.onFail(String.valueOf(t.getMessage()));
}
});
}
public void requestSendTransaction(Blockchain blockchain, String txHEX) throws Exception {
requestsCount++;
SoChainApi api = App.Companion.getNetworkComponent().getRetrofitSoChain().create(SoChainApi.class);
SoChain.Request.SendTx tx=new SoChain.Request.SendTx();
tx.setTx_hex(txHEX);
Call<SoChain.Response.SendTx> call = api.sendTransaction(getNetwork(blockchain), tx);
call.enqueue(new Callback<SoChain.Response.SendTx>() {
@Override
public void onResponse(@NonNull Call<SoChain.Response.SendTx> call, @NonNull Response<SoChain.Response.SendTx> response) {
requestsCount--;
Log.i(TAG, "requestAddressBalance onResponse " + response.code());
if (response.code() == 200) {
sendTxListener.onSuccess(response.body());
} else {
sendTxListener.onFail(String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<SoChain.Response.SendTx> call, @NonNull Throwable t) {
requestsCount--;
Log.e(TAG, "requestAddressBalance onFailure " + t.getMessage());
sendTxListener.onFail(String.valueOf(t.getMessage()));
}
});
}
public void requestTransactionInfo(Blockchain blockchain, String txId) throws Exception {
requestsCount++;
SoChainApi api = App.Companion.getNetworkComponent().getRetrofitSoChain().create(SoChainApi.class);
Call<SoChain.Response.GetTx> call = api.getTx(getNetwork(blockchain), txId);
call.enqueue(new Callback<SoChain.Response.GetTx>() {
@Override
public void onResponse(@NonNull Call<SoChain.Response.GetTx> call, @NonNull Response<SoChain.Response.GetTx> response) {
requestsCount--;
Log.i(TAG, "requestAddressBalance onResponse " + response.code());
if (response.code() == 200) {
txInfoListener.onSuccess(response.body());
} else {
txInfoListener.onFail(String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<SoChain.Response.GetTx> call, @NonNull Throwable t) {
requestsCount--;
Log.e(TAG, "requestAddressBalance onFailure " + t.getMessage());
txInfoListener.onFail(String.valueOf(t.getMessage()));
}
});
}
}

View file

@ -1,206 +0,0 @@
package com.tangem.data.network;
import com.tangem.App;
import com.tangem.data.Blockchain;
import com.tangem.util.LOG;
import com.tangem.wallet.R;
import com.tangem.wallet.TangemContext;
import org.stellar.sdk.Network;
import org.stellar.sdk.Server;
import org.stellar.sdk.requests.ErrorResponse;
import java.io.IOException;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.observers.DefaultObserver;
import io.reactivex.schedulers.Schedulers;
/**
* Created by dvol on 7.01.2019.
* <p>
* Request processor for Stellar Horizon Rest Api
* Every request live cycle:
* 1. In application create request and call {@link ServerApiStellar}.requestData(..)
* 2. Try send every request for max 4 times,
* 3. If all 4 times fail call DefaultObserver<StellarRequest>.onError (defined in .requestData(..)) and than
* {@link Listener}.onFail(...) callback
* Error can be acquired with {@link StellarRequest}.getError() method
* 4. If request network communication finished successfully then call DefaultObserver<StellarRequest.Base>.onComplete (defined in .requestData) and than
* {@link Listener}.onSuccess(...) callback
*/
public class ServerApiStellar {
public ServerApiStellar(Blockchain blockchain) {
if (blockchain == Blockchain.Stellar || blockchain == Blockchain.StellarAsset || blockchain == Blockchain.StellarTag) {
currentURL = ServerURL.API_STELLAR;
} else {
currentURL = ServerURL.API_STELLAR_TESTNET;
}
}
private static String TAG = ServerApiStellar.class.getSimpleName();
/**
* TCP, SSL
* Used in BTC, BCH
*/
private Listener listener;
private int requestsCount = 0;
private String currentURL;
public String getCurrentURL() {
return currentURL;
}
public boolean isRequestsSequenceCompleted() {
LOG.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount));
return requestsCount <= 0;
}
/**
* Interface for notification every request result
*/
public interface Listener {
/**
* Notify that request processing was successful
*
* @param stellarRequest - processed request containing received answer {@see stellarRequest.getAnswer() method}
*/
void onSuccess(StellarRequest.Base stellarRequest);
/**
* Notify that request processing was successful
*
* @param stellarRequest - processed request containing occurred error {@see stellarRequest.getError() method}
*/
void onFail(StellarRequest.Base stellarRequest);
}
/**
* Set notificaion listener
*
* @param listener
*/
public void setListener(Listener listener) {
this.listener = listener;
}
/**
* Start process request
*
* @param ctx
* @param stellarRequest
*/
public void requestData(TangemContext ctx, StellarRequest.Base stellarRequest) {
requestData(ctx, stellarRequest, false);
}
public void requestData(TangemContext ctx, StellarRequest.Base stellarRequest, boolean isRetry) {
requestsCount++;
LOG.i(TAG, String.format("New request[%d]: %s", requestsCount, stellarRequest.getClass().getSimpleName()));
Observable<StellarRequest.Base> stellarObserver = Observable.just(stellarRequest)
.doOnEach(stellarRequest1 -> doStellarRequest(ctx, stellarRequest))
.flatMap(stellarRequest1 -> {
if (stellarRequest1.errorResponse != null) {
LOG.e(TAG, "Error response on " + stellarRequest.getClass().getSimpleName());
return Observable.error(stellarRequest.errorResponse);
} else
return Observable.just(stellarRequest1);
}
)
// .retryWhen(errors -> errors
// .filter(throwable -> (throwable instanceof IOException) || (throwable instanceof ErrorResponse))
// .zipWith(Observable.range(1, 4), (n, i) -> i))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
stellarObserver.subscribe(new DefaultObserver<StellarRequest.Base>() {
@Override
public void onNext(StellarRequest.Base stellarRequest) {
LOG.e(TAG, "requestData " + stellarRequest.getClass().getSimpleName() + " onNext ");
}
@Override
public void onError(Throwable e) {
requestsCount--;
LOG.e(TAG, "requestData " + stellarRequest.getClass().getSimpleName() + " onError " + e.getMessage());
LOG.e(TAG, String.format("%d requests left in processing", requestsCount));
if (isRetry || (stellarRequest.errorResponse != null && stellarRequest.errorResponse.getCode() == 404)) {
stellarRequest.setError(e.getMessage());
//setErrorOccurred(e.getMessage());//;
listener.onFail(stellarRequest);
} else {
retryRequest(ctx, stellarRequest);
}
}
/**
* Called after completion request processing
*/
@Override
public void onComplete() {
requestsCount--;
LOG.e(TAG, String.format("%d requests left in processing", requestsCount));
if (stellarRequest.getError() != null) {
LOG.i(TAG, "requestData " + stellarRequest.getClass().getSimpleName() + " onComplete, error!=null");
if (isRetry || (stellarRequest.errorResponse != null && stellarRequest.errorResponse.getCode() == 404)) {
listener.onFail(stellarRequest);
} else {
retryRequest(ctx, stellarRequest);
}
} else {
LOG.e(TAG, "requestData " + stellarRequest.getClass().getSimpleName() + " onComplete, error==null");
listener.onSuccess(stellarRequest);
}
}
});
}
public void doStellarRequest(TangemContext ctx, StellarRequest.Base stellarRequest) throws IOException {
stellarRequest.setError(null);
try {
Server server;
Blockchain blockchain = ctx.getBlockchain();
if (blockchain == Blockchain.Stellar || blockchain == Blockchain.StellarAsset || blockchain == Blockchain.StellarTag) {
Network.usePublicNetwork();
server = new Server(currentURL);
} else if (blockchain == Blockchain.StellarTestNet) {
Network.useTestNetwork();
server = new Server(currentURL);
} else {
throw new IOException("Wrong blockchain for ServerApiStellar");
}
try {
LOG.e(TAG, "--- request " + stellarRequest.getClass().getSimpleName());
stellarRequest.process(server);
} catch (ErrorResponse errorResponse) {
LOG.e(TAG, "--- error response: " + errorResponse.getMessage());
stellarRequest.errorResponse = errorResponse;
stellarRequest.setError(errorResponse.getMessage());
}
} catch (Exception e) {
e.printStackTrace();
stellarRequest.setError(App.Companion.getInstance().getString(R.string.loaded_wallet_error_blockchain_communication_error));
throw e;
}
}
public void retryRequest (TangemContext ctx, StellarRequest.Base stellarRequest) {
currentURL = ServerURL.API_STELLAR_RESERVE;
requestData(ctx, stellarRequest, true);
}
}

View file

@ -1,139 +0,0 @@
package com.tangem.data.network;
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import com.tangem.data.network.model.TezosAccountResponse;
import com.tangem.data.network.model.TezosForgeBody;
import com.tangem.data.network.model.TezosHeaderResponse;
import com.tangem.data.network.model.TezosPreapplyBody;
import com.tangem.tangem_card.util.Log;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.Single;
import io.reactivex.SingleObserver;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;
public class ServerApiTezos {
private static String TAG = ServerApiTezos.class.getSimpleName();
private final String letzbakeURI = "https://teznode.letzbake.com";
private final String tezrpcURI = "https://mainnet.tezrpc.me";
static final String TEZOS_ADDRESS = "chains/main/blocks/head/context/contracts/{address}";
static final String TEZOS_HEADER = "chains/main/blocks/head/header";
static final String TEZOS_MANAGER_KEY = "chains/main/blocks/head/context/contracts/{address}/manager_key";
static final String TEZOS_FORGE_OPERATIONS = "chains/main/blocks/head/helpers/forge/operations";
static final String TEZOS_PREAPPLY_OPERATIONS = "chains/main/blocks/head/helpers/preapply/operations";
static final String TEZOS_RUN_OPERATION = "chains/main/blocks/head/helpers/scripts/run_operation";
static final String TEZOS_INJECT_OPERATIONS = "injection/operation";
private Retrofit retrofitTezos = new Retrofit.Builder()
.baseUrl(letzbakeURI)
.addConverterFactory(GsonConverterFactory.create())
.addConverterFactory(ScalarsConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
//logging for testing
.client(new OkHttpClient.Builder().addInterceptor(
new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
).build())
.build();
private TezosApi tezosApi = retrofitTezos.create(TezosApi.class);
private int requestsCount = 0;
public boolean isRequestsSequenceCompleted() {
Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount));
return requestsCount <= 0;
}
public void getAddress(String wallet, SingleObserver<TezosAccountResponse> accountObserver) {
requestsCount++;
Log.i(TAG, "new getAddress request");
Single<TezosAccountResponse> accountSingle = tezosApi.getAccount(wallet)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnEvent((object, throwable) -> requestsCount--);
accountSingle.subscribe(accountObserver);
}
public void getMangerKey(String wallet, SingleObserver<String> accountObserver) {
requestsCount++;
Log.i(TAG, "new getManagerKey request");
Single<String> managerKeySingle = tezosApi.getManagerKey(wallet)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnEvent((object, throwable) -> requestsCount--);
managerKeySingle.subscribe(accountObserver);
}
public TezosHeaderResponse getHeader() throws Exception { // TODO? not async
requestsCount++;
Log.i(TAG, "new getHeader request");
Response<TezosHeaderResponse> headerResponse = tezosApi.getHeader().execute();
requestsCount--;
if (headerResponse.code() == 200) {
return headerResponse.body();
} else {
throw new Exception("Wrong header response, code: " + headerResponse.code());
}
}
public String forgeOperations(TezosForgeBody tezosForgeBody) throws Exception { // TODO? not async
requestsCount++;
Log.i(TAG, "new forgeOperations request");
Response<String> forgeResponse = tezosApi.forgeOperations(tezosForgeBody).execute();
requestsCount--;
if (forgeResponse.code() == 200) {
return forgeResponse.body();
} else {
throw new Exception("Wrong forge response, code: " + forgeResponse.code());
}
}
public void peapplyOperations(TezosPreapplyBody tezosPreapplyBody) throws Exception {
Log.i(TAG, "new peapplyOperations request");
List<TezosPreapplyBody> tezosPreapplyBodyList = new ArrayList<>();
tezosPreapplyBodyList.add(tezosPreapplyBody);
Response<Void> preapplyResponse = tezosApi.preapplyOperations(tezosPreapplyBodyList).execute();
if (preapplyResponse.code() != 200) {
String error = "Preapply error: unknown error";
if (preapplyResponse.errorBody() != null) {
error = "Preapply error: " + preapplyResponse.errorBody().string();
}
Log.e(TAG, error);
throw new Exception(error);
}
}
public void injectOperations(String txForSend, SingleObserver<Object> injectObserver) {
requestsCount++;
Log.i(TAG, "new injectOperations request");
Single<Object> injectSingle = tezosApi.injectOperations(txForSend)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnEvent((object, throwable) -> requestsCount--);
injectSingle.subscribe(injectObserver);
}
}

View file

@ -1,53 +0,0 @@
package com.tangem.data.network
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import com.tangem.data.network.model.TokenEmvGetTransferFeeAnswer
import com.tangem.data.network.model.TokenEmvGetTransferFeeBody
import com.tangem.data.network.model.TokenEmvTransferAnswer
import com.tangem.data.network.model.TokenEmvTransferBody
import com.tangem.tangem_card.util.Log
import io.reactivex.SingleObserver
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.converter.scalars.ScalarsConverterFactory
import java.util.concurrent.TimeUnit
class ServerApiTokenEmv {
private val TAG = ServerApiTokenEmv::class.java.simpleName
private val tangemServer = "https://emvsupport.appspot.com/"
private val tokenEmvApi = Retrofit.Builder()
.baseUrl(tangemServer)
.addConverterFactory(GsonConverterFactory.create())
.addConverterFactory(ScalarsConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) //logging for testing
.client(OkHttpClient.Builder().addInterceptor(
HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
).build())
.build()
.create(TokenEmvApi::class.java)
fun transfer(tokenEmvTransferBody: TokenEmvTransferBody, transferObserver: SingleObserver<TokenEmvTransferAnswer>) {
Log.i(TAG, "new transfer request")
tokenEmvApi.transfer(tokenEmvTransferBody)
.timeout(30, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(transferObserver)
}
fun getTransferFee(tokenEmvGetTransferFeeBody: TokenEmvGetTransferFeeBody, transferObserver: SingleObserver<TokenEmvGetTransferFeeAnswer>) {
Log.i(TAG, "new get transfer fee request")
tokenEmvApi.getTransferFee(tokenEmvGetTransferFeeBody)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(transferObserver)
}
}

Some files were not shown because too many files have changed in this diff Show more