Updated on 2026-08-14
This commit is contained in:
parent
e83c9bc495
commit
2b768f1b00
784 changed files with 2066 additions and 106417 deletions
2
.idea/.gitignore
generated
vendored
2
.idea/.gitignore
generated
vendored
|
|
@ -1,2 +0,0 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
7
.idea/dictionaries/.xml
generated
7
.idea/dictionaries/.xml
generated
|
|
@ -1,7 +0,0 @@
|
|||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="Денис">
|
||||
<words>
|
||||
<w>blockchains</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
||||
16
.idea/dictionaries/tangem.xml
generated
16
.idea/dictionaries/tangem.xml
generated
|
|
@ -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
4
.idea/encodings.xml
generated
|
|
@ -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
40
.idea/misc.xml
generated
|
|
@ -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>
|
||||
|
|
|
|||
149
app/build.gradle
149
app/build.gradle
|
|
@ -2,24 +2,15 @@ apply plugin: 'com.android.application'
|
|||
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.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())
|
||||
//apply plugin: 'com.google.firebase.crashlytics'
|
||||
//apply plugin: 'com.google.firebase.firebase-perf'
|
||||
//apply plugin: 'com.google.gms.google-services'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
compileSdkVersion 29
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 28
|
||||
targetSdkVersion 29
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
androidExtensions {
|
||||
|
|
@ -44,26 +35,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 +55,45 @@ 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.0'
|
||||
implementation 'com.google.android.material:material:1.2.0'
|
||||
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.25.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'
|
||||
//koin - di
|
||||
// implementation "org.koin:koin-android:2.1.5"
|
||||
// implementation "org.koin:koin-android-scope:2.1.5"
|
||||
// implementation "org.koin:koin-android-viewmodel:2.1.5"
|
||||
|
||||
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'
|
||||
// //Firebase
|
||||
// implementation 'com.google.firebase:firebase-analytics:17.5.0'
|
||||
// implementation 'com.google.firebase:firebase-crashlytics:17.2.1'
|
||||
// implementation 'com.google.firebase:firebase-perf:19.0.8'
|
||||
|
||||
implementation "org.rekotlin:rekotlin:1.0.4"
|
||||
|
||||
// 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'
|
||||
testImplementation 'junit:junit:4.13'
|
||||
testImplementation "com.google.truth:truth:1.0.1"
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
|
||||
//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'
|
||||
|
||||
//dependencies for EOS
|
||||
implementation 'io.jafka:jeos:0.9.15'
|
||||
// implementation 'one.block:eosiojava:0.1.0'
|
||||
implementation 'org.bouncycastle:bcpkix-jdk15on:1.61'
|
||||
|
||||
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'
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
package com.tangem;
|
||||
|
||||
public class Test {
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
<?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>
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
<?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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -20,7 +20,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 +30,11 @@
|
|||
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:screenOrientation="portrait">
|
||||
<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>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
|
|
@ -1,128 +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"),
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
||||
|
|
@ -1,33 +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.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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
package com.tangem.data.network
|
||||
|
||||
enum class BlockcypherToken(val token: String) {
|
||||
T_001("aa8184b0e0894b88a5688e01b3dc1e82"),
|
||||
T_002("56c4ca23c6484c8f8864c32fde4def8d"),
|
||||
T_003("66a8a37c5e9d4d2c9bb191acfe7f93aa")
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 );
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,74 +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: 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
class ServerURL {
|
||||
static final String API_TANGEM = "https://verify.tangem.com/";
|
||||
static final String API_COINMARKETCAP = "https://pro-api.coinmarketcap.com/";
|
||||
static final String API_INFURA = "https://mainnet.infura.io/";
|
||||
static final String API_INFURA_TESTNET = "https://rinkeby.infura.io/";
|
||||
static final String API_INFURA_ROPSTEN = "https://ropsten.infura.io/";
|
||||
static final String API_SOCHAIN_V2 = "https://chain.so/";
|
||||
static final String API_ESTIMATEFEE = "https://estimatefee.com/";
|
||||
static final String API_UPDATE_VERSION = "https://raw.githubusercontent.com/";
|
||||
static final String API_ROOTSTOCK = "https://public-node.rsk.co/";
|
||||
static final String API_BLOCKCYPHER = "https://api.blockcypher.com/";
|
||||
static final String API_BINANCE = "https://dex.binance.org/";
|
||||
static final String API_BINANCE_TESTNET = "https://testnet-dex.binance.org/";
|
||||
static final String API_MATIC_TESTNET = "https://testnet2.matic.network/";
|
||||
static final String API_STELLAR = "https://horizon.stellar.org/";
|
||||
static final String API_STELLAR_RESERVE = "https://horizon.sui.li/";
|
||||
static final String API_STELLAR_TESTNET = "https://horizon-testnet.stellar.org/";
|
||||
static final String API_BLOCKCHAIN_INFO = "https://blockchain.info/";
|
||||
static final String API_DUCATUS = "https://ducapi.rocknblock.io/";
|
||||
static final String API_BLOCKCHAIR = "https://api.blockchair.com/";
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
|
||||
import com.tangem.data.network.model.SoChain;
|
||||
|
||||
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 SoChainApi {
|
||||
@GET(Server.ApiSoChain.Method.ADDRESS_BALANCE)
|
||||
Call<SoChain.Response.AddressBalance> getAddressBalance(@Path("network") String network, @Path("address") String address);
|
||||
|
||||
@GET(Server.ApiSoChain.Method.UNSPENT_TX)
|
||||
Call<SoChain.Response.TxUnspent> getUnspentTx(@Path("network") String network, @Path("address") String address);
|
||||
|
||||
@GET(Server.ApiSoChain.Method.GET_TX)
|
||||
Call<SoChain.Response.GetTx> getTx(@Path("network") String network, @Path("txid") String txId);
|
||||
|
||||
@Headers("Content-Type: application/json")
|
||||
@POST(Server.ApiSoChain.Method.SEND_TRANSACTION)
|
||||
Call<SoChain.Response.SendTx> sendTransaction(@Path("network") String network, @Body SoChain.Request.SendTx body);
|
||||
}
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
import org.stellar.sdk.KeyPair;
|
||||
import org.stellar.sdk.Server;
|
||||
import org.stellar.sdk.Transaction;
|
||||
import org.stellar.sdk.requests.ErrorResponse;
|
||||
import org.stellar.sdk.requests.RequestBuilder;
|
||||
import org.stellar.sdk.responses.AccountResponse;
|
||||
import org.stellar.sdk.responses.LedgerResponse;
|
||||
import org.stellar.sdk.responses.Page;
|
||||
import org.stellar.sdk.responses.SubmitTransactionResponse;
|
||||
import org.stellar.sdk.responses.operations.OperationResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by dvol on 7.01.2019.
|
||||
*/
|
||||
|
||||
public class StellarRequest {
|
||||
|
||||
public static abstract class Base {
|
||||
public ErrorResponse errorResponse;
|
||||
private String error = null;
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public void setError(String error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public abstract void process(Server server) throws IOException;
|
||||
}
|
||||
|
||||
public static class Balance extends Base {
|
||||
KeyPair accountKeyPair;
|
||||
public AccountResponse accountResponse;
|
||||
|
||||
public Balance(String walletAddress) {
|
||||
accountKeyPair = KeyPair.fromAccountId(walletAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(Server server) throws IOException {
|
||||
accountResponse = server.accounts().account(accountKeyPair);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SubmitTransaction extends Base {
|
||||
public Transaction transaction;
|
||||
public SubmitTransactionResponse response;
|
||||
|
||||
public SubmitTransaction(Transaction transaction) {
|
||||
this.transaction = transaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(Server server) throws IOException {
|
||||
// // First, check to make sure that the destination account exists.
|
||||
// // You could skip this, but if the account does not exist, you will be charged
|
||||
// // the transaction fee when the transaction fails.
|
||||
// // It will throw HttpResponseException if account does not exist or there was another error.
|
||||
// server.accounts().account(targetAccount);
|
||||
//
|
||||
// // If there was no error, load up-to-date information on your account.
|
||||
// AccountResponse sourceAccount = server.accounts().account(sourceAccount);
|
||||
|
||||
// And finally, send it off to Stellar!
|
||||
response = server.submitTransaction(transaction);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Ledgers extends Base {
|
||||
public LedgerResponse ledgerResponse;
|
||||
|
||||
public Ledgers() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(Server server) throws IOException {
|
||||
int latestLedger = server.root().getHistoryLatestLedger();
|
||||
ledgerResponse = server.ledgers().ledger(latestLedger);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Operations extends Base {
|
||||
KeyPair accountKeyPair;
|
||||
public List<OperationResponse> operationsList;
|
||||
int limit = 200;
|
||||
|
||||
public Operations(String walletAddress) {
|
||||
accountKeyPair = KeyPair.fromAccountId(walletAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(Server server) throws IOException {
|
||||
Page<OperationResponse> operationsResponse = server.operations().forAccount(accountKeyPair).limit(limit).order(RequestBuilder.Order.DESC).execute();
|
||||
operationsList = operationsResponse.getRecords();
|
||||
while (operationsResponse.getRecords().size() == limit) {
|
||||
try {
|
||||
operationsResponse = operationsResponse.getNextPage(server.getHttpClient());
|
||||
operationsList.addAll(operationsResponse.getRecords());
|
||||
} catch (URISyntaxException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
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 java.util.List;
|
||||
|
||||
import io.reactivex.Single;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.Path;
|
||||
|
||||
public interface TezosApi {
|
||||
@GET(ServerApiTezos.TEZOS_ADDRESS)
|
||||
Single<TezosAccountResponse> getAccount(@Path("address") String address);
|
||||
|
||||
@GET(ServerApiTezos.TEZOS_HEADER)
|
||||
Call<TezosHeaderResponse> getHeader();
|
||||
|
||||
@GET(ServerApiTezos.TEZOS_MANAGER_KEY)
|
||||
Single<String> getManagerKey(@Path("address") String address);
|
||||
|
||||
@POST(ServerApiTezos.TEZOS_FORGE_OPERATIONS)
|
||||
Call<String> forgeOperations(@Body TezosForgeBody tezosForgeBody);
|
||||
|
||||
@POST(ServerApiTezos.TEZOS_PREAPPLY_OPERATIONS)
|
||||
Call<Void> preapplyOperations(@Body List<TezosPreapplyBody> tezosPreapplyBodyList);
|
||||
|
||||
@POST(ServerApiTezos.TEZOS_INJECT_OPERATIONS)
|
||||
Single<Object> injectOperations(@Body String txForSend);
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
package com.tangem.data.network
|
||||
|
||||
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 io.reactivex.Completable
|
||||
import io.reactivex.Single
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.POST
|
||||
|
||||
interface TokenEmvApi {
|
||||
@POST("./card/transfer")
|
||||
fun transfer(@Body tokenEmvTransferBody: TokenEmvTransferBody): Single<TokenEmvTransferAnswer>
|
||||
@POST("./card/transfer/fee")
|
||||
fun getTransferFee(@Body tokenEmvGetTransferFeeBody: TokenEmvGetTransferFeeBody): Single<TokenEmvGetTransferFeeAnswer>
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.GET;
|
||||
|
||||
public interface UpdateVersionApi {
|
||||
@GET(Server.ApiUpdateVersion.Method.LAST_VERSION)
|
||||
Call<ResponseBody> getLastVersion();
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/**
|
||||
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.tangem.data.network.exception
|
||||
|
||||
/**
|
||||
* Base Class for handling errors/failures/exceptions.
|
||||
* Every feature specific failure should extend [FeatureFailure] class.
|
||||
*/
|
||||
sealed class Failure {
|
||||
class ApplicationError(val message: String) : Failure()
|
||||
class NotFound : FeatureFailure()
|
||||
class NetworkConnection : Failure()
|
||||
class ServerError : Failure()
|
||||
class Unauthorized : Failure() // 401
|
||||
|
||||
/** * Extend this class for feature specific failures.*/
|
||||
abstract class FeatureFailure : Failure()
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
package com.tangem.data.network.model;
|
||||
|
||||
public class AdaliteBody {
|
||||
private String signedTx;
|
||||
|
||||
public AdaliteBody(String signedTx) {
|
||||
this.signedTx = signedTx;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class AdaliteResponse(
|
||||
@SerializedName("Right")
|
||||
var right: AdaliteAddressData? = null
|
||||
)
|
||||
|
||||
data class AdaliteResponseUtxo(
|
||||
@SerializedName("Right")
|
||||
var right: List<AdaliteUtxoData>
|
||||
)
|
||||
|
||||
data class AdaliteAddressData(
|
||||
@SerializedName("caAddress")
|
||||
var caAddress: String? = null,
|
||||
|
||||
@SerializedName("caBalance")
|
||||
var caBalance: AdaliteCoins? = null,
|
||||
|
||||
@SerializedName("caTxList")
|
||||
var caTxList: List<AdaliteTxData>
|
||||
)
|
||||
|
||||
data class AdaliteCoins(
|
||||
@SerializedName("getCoin")
|
||||
var getCoin: Long? = null
|
||||
)
|
||||
|
||||
data class AdaliteUtxoData(
|
||||
@SerializedName("cuId")
|
||||
var cuId: String? = null,
|
||||
|
||||
@SerializedName("cuOutIndex")
|
||||
var cuOutIndex: Int? = null,
|
||||
|
||||
@SerializedName("cuCoins")
|
||||
var cuCoins: AdaliteCoins? = null
|
||||
)
|
||||
|
||||
data class AdaliteTxData(
|
||||
@SerializedName("ctbId")
|
||||
var ctbId: String? = null
|
||||
)
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class BinanceFees(
|
||||
@SerializedName("fixed_fee_params")
|
||||
var fixed_fee_params: BinanceFixedFee? = null
|
||||
)
|
||||
|
||||
data class BinanceFixedFee(
|
||||
@SerializedName("msg_type")
|
||||
var msg_type: String? = null,
|
||||
|
||||
@SerializedName("fee")
|
||||
var fee: Int? = null
|
||||
)
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class BitcoreBalance(
|
||||
@SerializedName("confirmed")
|
||||
var confirmed: Long? = null,
|
||||
|
||||
@SerializedName("unconfirmed")
|
||||
var unconfirmed: Long? = null
|
||||
)
|
||||
|
||||
data class BitcoreUtxo(
|
||||
@SerializedName("mintTxid")
|
||||
var mintTxid: String? = null,
|
||||
|
||||
@SerializedName("mintIndex")
|
||||
var mintIndex: Int? = null,
|
||||
|
||||
@SerializedName("value")
|
||||
var value: Long? = null,
|
||||
|
||||
@SerializedName("script")
|
||||
var script: String? = null
|
||||
)
|
||||
|
||||
data class BitcoreBalanceAndUnspents(
|
||||
var balance: BitcoreBalance,
|
||||
var unspents: List<BitcoreUtxo>
|
||||
)
|
||||
|
||||
data class BitcoreSendResponse(
|
||||
var txid: String? = null
|
||||
)
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package com.tangem.data.network.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BitcoreSendBody {
|
||||
private List<String> rawTx;
|
||||
|
||||
public BitcoreSendBody(String tx) {
|
||||
List<String> txList = new ArrayList<>();
|
||||
txList.add(tx);
|
||||
rawTx = txList;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class BlockchainInfoAddress(
|
||||
@SerializedName("final_balance")
|
||||
var final_balance: Long? = null,
|
||||
|
||||
@SerializedName("txs")
|
||||
var txs: List<BlockchainInfoTransaction>? = null
|
||||
)
|
||||
|
||||
data class BlockchainInfoTransaction(
|
||||
@SerializedName("hash")
|
||||
var hash: String? = null,
|
||||
|
||||
@SerializedName("block_height")
|
||||
var block_height: Long? = null,
|
||||
|
||||
@SerializedName("inputs")
|
||||
var inputs: List<BlockchainInfoInput>
|
||||
)
|
||||
|
||||
data class BlockchainInfoUnspents(
|
||||
@SerializedName("unspent_outputs")
|
||||
var unspent_outputs: List<BlockchainInfoUtxo>
|
||||
)
|
||||
|
||||
data class BlockchainInfoUtxo(
|
||||
@SerializedName("tx_hash_big_endian")
|
||||
var tx_hash_big_endian: String? = null,
|
||||
|
||||
@SerializedName("tx_output_n")
|
||||
var tx_output_n: Int? = null,
|
||||
|
||||
@SerializedName("value")
|
||||
var value: Long? = null,
|
||||
|
||||
@SerializedName("script")
|
||||
var script: String? = null
|
||||
)
|
||||
|
||||
data class BlockchainInfoInput(
|
||||
@SerializedName("prev_out")
|
||||
var prev_out: BlockchainInfoOutput
|
||||
)
|
||||
|
||||
data class BlockchainInfoOutput(
|
||||
@SerializedName("addr")
|
||||
var addr: String? = null
|
||||
)
|
||||
|
||||
data class BlockchainInfoAddressAndUnspents(
|
||||
var address: BlockchainInfoAddress,
|
||||
var unspents: BlockchainInfoUnspents
|
||||
)
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class BlockchairAddressResponse(
|
||||
@SerializedName("data")
|
||||
val data: Map<String, BlockchairAddressData>? = null
|
||||
)
|
||||
|
||||
data class BlockchairAddressData(
|
||||
@SerializedName("address")
|
||||
val address: BlockchairAddressInfo? = null,
|
||||
|
||||
@SerializedName("utxo")
|
||||
val unspentOutputs: List<BlockchairUnspentOutput>? = null,
|
||||
|
||||
@SerializedName("transactions")
|
||||
val transactions: List<String>
|
||||
)
|
||||
|
||||
data class BlockchairAddressInfo(
|
||||
@SerializedName("balance")
|
||||
val balance: Long? = null,
|
||||
|
||||
@SerializedName("output_count")
|
||||
val outputCount: Int? = null,
|
||||
|
||||
@SerializedName("unspent_output_count")
|
||||
val unspentOutputCount: Int? = null
|
||||
)
|
||||
|
||||
data class BlockchairUnspentOutput(
|
||||
@SerializedName("block_id")
|
||||
val block: Int? = null,
|
||||
|
||||
@SerializedName("transaction_hash")
|
||||
val transactionHash: String? = null,
|
||||
|
||||
@SerializedName("index")
|
||||
val index: Int? = null,
|
||||
|
||||
@SerializedName("value")
|
||||
val amount: Long? = null
|
||||
)
|
||||
|
||||
data class BlockchairTransactionResponse(
|
||||
@SerializedName("data")
|
||||
val data: Map<String, BlockchairTransactionData>? = null
|
||||
)
|
||||
|
||||
data class BlockchairTransactionData(
|
||||
@SerializedName("transaction")
|
||||
val transaction: BlockchairTransactionInfo? = null
|
||||
)
|
||||
|
||||
data class BlockchairTransactionInfo(
|
||||
@SerializedName("block_id")
|
||||
val block: Int? = null
|
||||
)
|
||||
|
||||
data class BlockchairStatsResponse(
|
||||
@SerializedName("data")
|
||||
val data: BlockchairStatsData? = null
|
||||
)
|
||||
|
||||
data class BlockchairStatsData(
|
||||
@SerializedName("suggested_transaction_fee_per_byte_sat")
|
||||
val feePerByte: Int? = null
|
||||
)
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
package com.tangem.data.network.model;
|
||||
|
||||
public class BlockchairSendBody {
|
||||
private String data;
|
||||
|
||||
public BlockchairSendBody(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
package com.tangem.data.network.model;
|
||||
|
||||
public class BlockcypherBody {
|
||||
private String tx;
|
||||
|
||||
public BlockcypherBody(String tx) {
|
||||
this.tx = tx;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class BlockcypherResponse(
|
||||
@SerializedName("address")
|
||||
var address: String? = null,
|
||||
|
||||
@SerializedName("balance")
|
||||
var balance: Long? = null,
|
||||
|
||||
@SerializedName("unconfirmed_balance")
|
||||
var unconfirmed_balance: Long? = null,
|
||||
|
||||
@SerializedName("txrefs")
|
||||
var txrefs: List<BlockcypherTxref>? = null,
|
||||
|
||||
@SerializedName("unconfirmed_txrefs")
|
||||
var unconfirmed_txrefs: List<BlockcypherTxref>? = null,
|
||||
|
||||
@SerializedName("hasMore")
|
||||
var hasMore: Boolean? = null
|
||||
)
|
||||
|
||||
data class BlockcypherTxref(
|
||||
@SerializedName("tx_hash")
|
||||
var tx_hash: String? = null,
|
||||
|
||||
@SerializedName("tx_input_n")
|
||||
var tx_input_n: Int? = null,
|
||||
|
||||
@SerializedName("tx_output_n")
|
||||
var tx_output_n: Int? = null,
|
||||
|
||||
@SerializedName("value")
|
||||
var value: Long? = null,
|
||||
|
||||
@SerializedName("confirmations")
|
||||
var confirmations: Long? = null,
|
||||
|
||||
@SerializedName("script")
|
||||
var script: String? = null,
|
||||
|
||||
@SerializedName("spent")
|
||||
var spent: Boolean? = null
|
||||
)
|
||||
|
||||
data class BlockcypherTx(
|
||||
@SerializedName("hex")
|
||||
var hex: String? = null,
|
||||
|
||||
@SerializedName("addresses")
|
||||
var addesses: List<String>? = null
|
||||
)
|
||||
|
||||
data class BlockcypherFee(
|
||||
@SerializedName("low_fee_per_kb")
|
||||
var low_fee_per_kb: Long? = null,
|
||||
|
||||
@SerializedName("medium_fee_per_kb")
|
||||
var medium_fee_per_kb: Long? = null,
|
||||
|
||||
@SerializedName("high_fee_per_kb")
|
||||
var high_fee_per_kb: Long? = null
|
||||
)
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
package com.tangem.data.network.model;
|
||||
|
||||
public class InfuraBody {
|
||||
private String method;
|
||||
private Object[] params;
|
||||
private int id;
|
||||
private String jsonrpc = "2.0";
|
||||
|
||||
public InfuraBody() {
|
||||
}
|
||||
|
||||
// body for eth gasPrice
|
||||
public InfuraBody(String method, int id) {
|
||||
this.method = method;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
// body for eth getBalance, eth getTransactionCount, eth sendRawTransaction
|
||||
public InfuraBody(String method, String[] params, int id) {
|
||||
this.method = method;
|
||||
this.params = params;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
// body for eth call
|
||||
public InfuraBody(String method, Object[] params, int id) {
|
||||
this.method = method;
|
||||
this.params = params;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public static class EthCallParams {
|
||||
private String data;
|
||||
private String to;
|
||||
|
||||
public EthCallParams(String data, String to) {
|
||||
this.data = data;
|
||||
this.to = to;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class InfuraResponse(
|
||||
@SerializedName("jsonrpc")
|
||||
var jsonrpc: String = "",
|
||||
|
||||
@SerializedName("id")
|
||||
var id: Int? = null,
|
||||
|
||||
@SerializedName("result")
|
||||
var result: String? = null,
|
||||
|
||||
@SerializedName("error")
|
||||
var error: Object
|
||||
)
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
package com.tangem.data.network.model;
|
||||
|
||||
public class InsightBody {
|
||||
private String rawtx;
|
||||
|
||||
public InsightBody(String rawtx){
|
||||
this.rawtx = rawtx;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class InsightResponse(
|
||||
@SerializedName("balanceSat")
|
||||
var balanceSat: Long? = null,
|
||||
|
||||
@SerializedName("unconfirmedBalanceSat")
|
||||
var unconfirmedBalanceSat: Long? = null,
|
||||
|
||||
@SerializedName("addrStr")
|
||||
var addrStr: String = "",
|
||||
|
||||
// @SerializedName("2")
|
||||
// var fee2: String = "",
|
||||
//
|
||||
// @SerializedName("3")
|
||||
// var fee3: String = "",
|
||||
//
|
||||
// @SerializedName("6")
|
||||
// var fee6: String = "",
|
||||
|
||||
@SerializedName("error")
|
||||
var error: String = ""
|
||||
)
|
||||
|
||||
data class InsightUtxo(
|
||||
@SerializedName("txid")
|
||||
var txid: String = "",
|
||||
|
||||
@SerializedName("satoshis")
|
||||
var satoshis: Long? = null,
|
||||
|
||||
@SerializedName("vout")
|
||||
var vout: Int? = null,
|
||||
|
||||
@SerializedName("scriptPubKey")
|
||||
var scriptPubKey: String? = null
|
||||
)
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class PayIdResponse(
|
||||
@SerializedName("addresses")
|
||||
var addresses: List<PayIdAddress>? = null
|
||||
)
|
||||
|
||||
data class PayIdAddress(
|
||||
@SerializedName("paymentNetwork")
|
||||
var paymentNetwork: String? = null,
|
||||
|
||||
@SerializedName("environment")
|
||||
var environment: String? = null,
|
||||
|
||||
@SerializedName("addressDetails")
|
||||
var addressDetails: PayIdAddressDetails? = null
|
||||
)
|
||||
|
||||
data class PayIdAddressDetails(
|
||||
@SerializedName("address")
|
||||
var address: String? = null,
|
||||
|
||||
@SerializedName("tag")
|
||||
var tag: String? = null
|
||||
)
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class RateInfoResponse(
|
||||
@SerializedName("data")
|
||||
var data: RateData? = null
|
||||
)
|
||||
|
||||
data class RateData(
|
||||
@SerializedName("quote")
|
||||
var quote: Quote? = null
|
||||
)
|
||||
|
||||
data class Quote(
|
||||
@SerializedName("USD")
|
||||
var usd: CurrencyRate? = null
|
||||
)
|
||||
|
||||
data class CurrencyRate(
|
||||
@SerializedName("price")
|
||||
var price: Float? = null
|
||||
)
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
package com.tangem.data.network.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class RippleBody {
|
||||
private String method;
|
||||
private ArrayList<HashMap<String,String>> params;
|
||||
|
||||
public RippleBody() {
|
||||
}
|
||||
|
||||
//for RIPPLE_FEE
|
||||
public RippleBody(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public RippleBody(String method, HashMap<String,String> paramsMap) {
|
||||
this.method = method;
|
||||
ArrayList<HashMap<String, String>> paramsList = new ArrayList<>();
|
||||
paramsList.add(paramsMap);
|
||||
this.params = paramsList;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class RippleResponse(
|
||||
@SerializedName("result")
|
||||
var result: RippleResult? = null
|
||||
)
|
||||
|
||||
data class RippleResult(
|
||||
@SerializedName("account_data")
|
||||
var account_data: RippleAccountData? = null,
|
||||
|
||||
@SerializedName("validated")
|
||||
var validated: Boolean? = null,
|
||||
|
||||
//for RIPPLE_FEE
|
||||
@SerializedName("drops")
|
||||
var drops: RippleFeeDrops? = null,
|
||||
|
||||
//for RIPPLE_SUBMIT
|
||||
@SerializedName("engine_result_code")
|
||||
var engine_result_code: Int? = null,
|
||||
|
||||
//for RIPPLE_SUBMIT
|
||||
@SerializedName ("engine_result_message")
|
||||
var engine_result_message: String? = null,
|
||||
|
||||
//for RIPPLE_SUBMIT
|
||||
@SerializedName("error")
|
||||
var error: String? = null,
|
||||
|
||||
//for RIPPLE_SUBMIT
|
||||
@SerializedName("error_exception")
|
||||
var error_exception: String? = null,
|
||||
|
||||
//for RIPPLE_SERVER_STATE
|
||||
@SerializedName("state")
|
||||
var state: RippleState? = null,
|
||||
|
||||
//for "Account not found error"
|
||||
@SerializedName("error_code")
|
||||
var error_code: Int? = null
|
||||
)
|
||||
|
||||
data class RippleAccountData(
|
||||
@SerializedName("Account")
|
||||
var account: String? = null,
|
||||
|
||||
@SerializedName("Balance")
|
||||
var balance: String? = null,
|
||||
|
||||
@SerializedName("Sequence")
|
||||
var sequence: Long? = null
|
||||
)
|
||||
|
||||
data class RippleFeeDrops(
|
||||
//enough to put tx to queue
|
||||
@SerializedName("minimum_fee")
|
||||
var minimum_fee: String? = null,
|
||||
|
||||
//enough to put tx to current ledger
|
||||
@SerializedName("open_ledger_fee")
|
||||
var open_ledger_fee: String? = null,
|
||||
|
||||
@SerializedName("median_fee")
|
||||
var median_fee: String? = null
|
||||
)
|
||||
|
||||
data class RippleState(
|
||||
@SerializedName("validated_ledger")
|
||||
var validated_ledger: RippleLedger? = null
|
||||
)
|
||||
|
||||
data class RippleLedger(
|
||||
@SerializedName("reserve_base")
|
||||
var reserve_base: Long? = null
|
||||
)
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
class SoChain {
|
||||
class Request {
|
||||
class SendTx{
|
||||
var tx_hex: String? = null
|
||||
}
|
||||
}
|
||||
|
||||
class Response {
|
||||
class AddressBalance {
|
||||
class Data {
|
||||
var network: String? = null
|
||||
var address: String? = null
|
||||
var confirmed_balance: String? = null
|
||||
var unconfirmed_balance: String? = null
|
||||
var confirmations: String? = null
|
||||
}
|
||||
|
||||
var status: String? = null
|
||||
var data: Data? = null
|
||||
}
|
||||
|
||||
class TxUnspent {
|
||||
class Data {
|
||||
class Tx {
|
||||
var txid: String? = null //"9b5c8fbeb1e42bb2a6da40e2eab49c368d1a205707a1ec88aa13f0f2ecdfe944",
|
||||
var output_no: Int? = null // 0,
|
||||
var script_asm: String? = null // "OP_DUP OP_HASH160 8541eb0593bb19c3755198e7d2a71e134da21a97 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
var script_hex: String? = null // "76a9148541eb0593bb19c3755198e7d2a71e134da21a9788ac",
|
||||
var value: String? = null // "11.38404832",
|
||||
var confirmations: Long? = null
|
||||
var time: Long? = null// : 1555509495
|
||||
}
|
||||
|
||||
var network: String? = null
|
||||
var address: String? = null
|
||||
var txs: Array<Tx>? = null
|
||||
}
|
||||
|
||||
var status: String? = null
|
||||
var data: Data? = null
|
||||
|
||||
}
|
||||
|
||||
class SendTx {
|
||||
class Data {
|
||||
var network: String? = null
|
||||
var txid: String? = null
|
||||
var tx_hex: String? = null
|
||||
}
|
||||
var status: String? = null
|
||||
var data: Data? = null
|
||||
}
|
||||
|
||||
class GetTx {
|
||||
class Data {
|
||||
// restricted data
|
||||
var network: String? = null
|
||||
var address: String? = null
|
||||
var txid: String? = null
|
||||
var tx_hex: String? = null
|
||||
}
|
||||
|
||||
var status: String? = null
|
||||
var data: Data? = null
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
data class TezosForgeBody(
|
||||
val branch: String,
|
||||
val contents: List<TezosOperationContent>
|
||||
)
|
||||
|
||||
data class TezosOperationContent(
|
||||
val kind: String,
|
||||
val source: String,
|
||||
val fee: String,
|
||||
val counter: String,
|
||||
val gas_limit: String,
|
||||
val storage_limit: String,
|
||||
val public_key: String? = null,
|
||||
val destination: String? = null,
|
||||
val amount: String? = null
|
||||
)
|
||||
|
||||
data class TezosPreapplyBody(
|
||||
val protocol: String,
|
||||
val branch: String,
|
||||
val contents: List<TezosOperationContent>,
|
||||
val signature: String
|
||||
)
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class TezosAccountResponse(
|
||||
@SerializedName("balance")
|
||||
var balance: Long? = null,
|
||||
|
||||
@SerializedName("counter")
|
||||
var counter: Long? = null
|
||||
)
|
||||
|
||||
data class TezosHeaderResponse(
|
||||
@SerializedName("protocol")
|
||||
var protocol: String? = null,
|
||||
|
||||
@SerializedName("hash")
|
||||
var hash: String? = null
|
||||
)
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class TokenEmvTransferBody(
|
||||
val CID: String,
|
||||
val publicKey: String,
|
||||
val amount: String,
|
||||
val currency: String,
|
||||
val recipient: String,
|
||||
@SerializedName("fee_limit")
|
||||
val feeLimit: String,
|
||||
val sequence: Int,
|
||||
val signature: String
|
||||
)
|
||||
|
||||
data class TokenEmvTransferAnswer(
|
||||
val error: String?,
|
||||
val errorCode: Int?,
|
||||
val success: Boolean?,
|
||||
val tx_id: String?,
|
||||
val blockchain_tx_id: String?
|
||||
)
|
||||
|
||||
data class TokenEmvGetTransferFeeBody(
|
||||
val CID: String,
|
||||
val publicKey: String
|
||||
)
|
||||
|
||||
data class TokenEmvGetTransferFeeAnswer(
|
||||
val error: String?,
|
||||
val errorCode: Int?,
|
||||
val success: Boolean?,
|
||||
val fee: String?,
|
||||
val currency: String?
|
||||
)
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package com.tangem.di
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import dagger.Module
|
||||
import javax.inject.Singleton
|
||||
import dagger.Provides
|
||||
|
||||
@Module
|
||||
class AppModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideContext(application: Application): Context {
|
||||
return application
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
package com.tangem.di
|
||||
|
||||
import com.tangem.ui.dialog.WaitSecurityDelayDialogNew
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
internal class NavigatorModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideToastHelper(): ToastHelper {
|
||||
return ToastHelper()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideWaitSecurityDelayDialogNew(): WaitSecurityDelayDialogNew {
|
||||
return WaitSecurityDelayDialogNew()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
package com.tangem.di
|
||||
|
||||
import com.tangem.data.network.Server
|
||||
import dagger.Component
|
||||
import retrofit2.Retrofit
|
||||
import java.net.Socket
|
||||
import javax.inject.Named
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Component(modules = [NetworkModule::class])
|
||||
interface NetworkComponent {
|
||||
|
||||
@get:Named(Server.ApiInfura.URL_INFURA)
|
||||
val retrofitInfura: Retrofit
|
||||
|
||||
@get:Named(Server.ApiInfuraTestnet.URL_INFURA_TESTNET)
|
||||
val retrofitInfuraTestnet: Retrofit
|
||||
|
||||
@get:Named(Server.ApiInfuraRopsten.URL_INFURA_ROPSTEN)
|
||||
val retrofitInfuraRopsten: Retrofit
|
||||
|
||||
@get:Named(Server.ApiMaticTesnet.URL_MATIC_TESTNET)
|
||||
val retrofitMaticTesnet: Retrofit
|
||||
|
||||
@get:Named(Server.ApiEstimatefee.URL_ESTIMATEFEE)
|
||||
val retrofitEstimatefee: Retrofit
|
||||
|
||||
@get:Named(Server.ApiCoinmarket.URL_COINMARKET)
|
||||
val retrofitCoinmarketcap: Retrofit
|
||||
|
||||
@get:Named(Server.ApiUpdateVersion.URL_UPDATE_VERSION)
|
||||
val retrofitGitHubUserContent: Retrofit
|
||||
|
||||
@get:Named(Server.ApiRootstock.URL_ROOTSTOCK)
|
||||
val retrofitRootstock: Retrofit
|
||||
|
||||
@get:Named(Server.ApiBlockcypher.URL_BLOCKCYPHER)
|
||||
val retrofitBlockcypher: Retrofit
|
||||
|
||||
@get:Named(Server.ApiSoChain.URL)
|
||||
val retrofitSoChain: Retrofit
|
||||
|
||||
@get:Named(Server.ApiBlockchainInfo.URL_BLOCKCHAININFO)
|
||||
val retrofitBlockchainInfo: Retrofit
|
||||
|
||||
@get:Named(Server.ApiDucatus.URL_DUCATUS)
|
||||
val retrofitDucatus: Retrofit
|
||||
|
||||
@get:Named(Server.ApiBlockchair.URL_BLOCKCHAIR)
|
||||
val retrofitBlockchair: Retrofit
|
||||
|
||||
@get:Named("socket")
|
||||
val socket: Socket
|
||||
}
|
||||
|
|
@ -1,216 +0,0 @@
|
|||
package com.tangem.di
|
||||
|
||||
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
|
||||
import com.tangem.data.network.Server
|
||||
import com.tangem.wallet.BuildConfig
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import retrofit2.converter.scalars.ScalarsConverterFactory
|
||||
import java.io.IOException
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.Socket
|
||||
import java.net.SocketException
|
||||
import javax.inject.Named
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
internal class NetworkModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@Named(Server.ApiInfura.URL_INFURA)
|
||||
fun provideRetrofitInfura(): Retrofit {
|
||||
val builder = Retrofit.Builder()
|
||||
.baseUrl(Server.ApiInfura.URL_INFURA)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
if (BuildConfig.DEBUG)
|
||||
builder.client(createOkHttpClient())
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@Named(Server.ApiInfuraTestnet.URL_INFURA_TESTNET)
|
||||
fun provideRetrofitInfuraTestnet(): Retrofit {
|
||||
val builder = Retrofit.Builder()
|
||||
.baseUrl(Server.ApiInfuraTestnet.URL_INFURA_TESTNET)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
if (BuildConfig.DEBUG)
|
||||
builder.client(createOkHttpClient())
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@Named(Server.ApiInfuraRopsten.URL_INFURA_ROPSTEN)
|
||||
fun provideRetrofitInfuraRopsten(): Retrofit {
|
||||
val builder = Retrofit.Builder()
|
||||
.baseUrl(Server.ApiInfuraRopsten.URL_INFURA_ROPSTEN)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
if (BuildConfig.DEBUG)
|
||||
builder.client(createOkHttpClient())
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@Named(Server.ApiRootstock.URL_ROOTSTOCK)
|
||||
fun provideRetrofitRootstock(): Retrofit {
|
||||
val builder = Retrofit.Builder()
|
||||
.baseUrl(Server.ApiRootstock.URL_ROOTSTOCK)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
if (BuildConfig.DEBUG)
|
||||
builder.client(createOkHttpClient())
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@Named(Server.ApiMaticTesnet.URL_MATIC_TESTNET)
|
||||
fun provideRetrofitMaticTestnet(): Retrofit {
|
||||
val builder = Retrofit.Builder()
|
||||
.baseUrl(Server.ApiMaticTesnet.URL_MATIC_TESTNET)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
if (BuildConfig.DEBUG)
|
||||
builder.client(createOkHttpClient())
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@Named(Server.ApiEstimatefee.URL_ESTIMATEFEE)
|
||||
fun provideRetrofitEstimatefee(): Retrofit {
|
||||
val builder = Retrofit.Builder()
|
||||
.baseUrl(Server.ApiEstimatefee.URL_ESTIMATEFEE)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
if (BuildConfig.DEBUG)
|
||||
builder.client(createOkHttpClient())
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@Named(Server.ApiUpdateVersion.URL_UPDATE_VERSION)
|
||||
fun provideGithubusercontent(): Retrofit {
|
||||
val builder = Retrofit.Builder()
|
||||
.baseUrl(Server.ApiUpdateVersion.URL_UPDATE_VERSION)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.client(createOkHttpClient())
|
||||
if (BuildConfig.DEBUG)
|
||||
builder.client(createOkHttpClient())
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@Named(Server.ApiCoinmarket.URL_COINMARKET)
|
||||
fun provideRetrofitCoinmarketcap(): Retrofit {
|
||||
val builder = Retrofit.Builder()
|
||||
.baseUrl(Server.ApiCoinmarket.URL_COINMARKET)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
|
||||
// if (BuildConfig.DEBUG)
|
||||
// builder.client(createOkHttpClient())
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@Named(Server.ApiBlockcypher.URL_BLOCKCYPHER)
|
||||
fun provideRetrofitBlockcypher(): Retrofit {
|
||||
val builder = Retrofit.Builder()
|
||||
.baseUrl(Server.ApiBlockcypher.URL_BLOCKCYPHER)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.client(createOkHttpClient())
|
||||
if (BuildConfig.DEBUG)
|
||||
builder.client(createOkHttpClient())
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@Named(Server.ApiSoChain.URL)
|
||||
fun provideRetrofitSoChain(): Retrofit {
|
||||
val builder = Retrofit.Builder()
|
||||
.baseUrl(Server.ApiSoChain.URL)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
if (BuildConfig.DEBUG)
|
||||
builder.client(createOkHttpClient())
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@Named(Server.ApiBlockchainInfo.URL_BLOCKCHAININFO)
|
||||
fun provideRetrofitBlockchainInfo(): Retrofit {
|
||||
val builder = Retrofit.Builder()
|
||||
.baseUrl(Server.ApiBlockchainInfo.URL_BLOCKCHAININFO)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.addConverterFactory(ScalarsConverterFactory.create())
|
||||
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
|
||||
if (BuildConfig.DEBUG)
|
||||
builder.client(createOkHttpClient())
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@Named(Server.ApiDucatus.URL_DUCATUS)
|
||||
fun provideRetrofitDucatus(): Retrofit {
|
||||
val builder = Retrofit.Builder()
|
||||
.baseUrl(Server.ApiDucatus.URL_DUCATUS)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.addConverterFactory(ScalarsConverterFactory.create())
|
||||
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
|
||||
if (BuildConfig.DEBUG)
|
||||
builder.client(createOkHttpClient())
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
@Named(Server.ApiBlockchair.URL_BLOCKCHAIR)
|
||||
fun provideRetrofitBlockchair(): Retrofit {
|
||||
val builder = Retrofit.Builder()
|
||||
.baseUrl(Server.ApiBlockchair.URL_BLOCKCHAIR)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
|
||||
if (BuildConfig.DEBUG)
|
||||
builder.client(createOkHttpClient())
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
private fun createOkHttpClient(): OkHttpClient {
|
||||
return OkHttpClient.Builder().addInterceptor(createHttpLoggingInterceptor()).build()
|
||||
}
|
||||
|
||||
private fun createHttpLoggingInterceptor(): HttpLoggingInterceptor {
|
||||
val logging = HttpLoggingInterceptor()
|
||||
logging.level = HttpLoggingInterceptor.Level.BODY
|
||||
return logging
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Named("socket")
|
||||
fun provideSocket(): Socket {
|
||||
val socket = Socket()
|
||||
try {
|
||||
socket.soTimeout = 2000
|
||||
try {
|
||||
socket.bind(InetSocketAddress(0))
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
} catch (e: SocketException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
return socket
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
package com.tangem.di
|
||||
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tangem.Constant
|
||||
import com.tangem.wallet.R
|
||||
import java.util.*
|
||||
|
||||
class ToastHelper {
|
||||
fun showSnackbarUpdateVersion(context: Context, vg: ViewGroup, versionName: String) {
|
||||
Snackbar.make(vg, String.format(context.getString(R.string.main_screen_new_version_toast), versionName), Snackbar.LENGTH_INDEFINITE)
|
||||
.setAction(R.string.main_screen_btn_update) {
|
||||
try {
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
intent.data = Uri.parse(Constant.URL_TANGEM)
|
||||
context.startActivity(intent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
|
||||
fun showSnackbarSuccess(context: Context, vg: ViewGroup, message: String) {
|
||||
val snackbar = Snackbar.make(vg, message, Snackbar.LENGTH_INDEFINITE)
|
||||
val snackView = snackbar.view
|
||||
snackView.setBackgroundColor(context.resources.getColor(R.color.msg_okay))
|
||||
snackbar.setAction(R.string.general_ok) {
|
||||
snackbar.dismiss()
|
||||
}
|
||||
snackbar.show()
|
||||
}
|
||||
|
||||
fun showSnackbarError(context: Context, vg: ViewGroup, message: String) {
|
||||
val snackbar = Snackbar.make(vg, message, Snackbar.LENGTH_INDEFINITE)
|
||||
val snackView = snackbar.view
|
||||
snackView.setBackgroundColor(context.resources.getColor(R.color.msg_err))
|
||||
snackbar.setAction(R.string.general_ok) {
|
||||
snackbar.dismiss()
|
||||
}
|
||||
snackbar.show()
|
||||
}
|
||||
|
||||
fun showSnackbarWarning(context: Context, vg: ViewGroup, message: String) {
|
||||
val snackbar = Snackbar.make(vg, message, Snackbar.LENGTH_LONG)
|
||||
val snackView = snackbar.view
|
||||
snackView.setBackgroundColor(context.resources.getColor(R.color.msg_err))
|
||||
snackbar.show()
|
||||
}
|
||||
|
||||
private var singleToast: Toast? = null
|
||||
private var showTime: Date = Date()
|
||||
|
||||
fun showSingleToast(context: Context?, text: String) {
|
||||
if (singleToast == null || !singleToast!!.view.isShown || showTime.time + 2000 < Date().time) {
|
||||
if (singleToast != null)
|
||||
singleToast!!.cancel()
|
||||
if (context != null) {
|
||||
singleToast = Toast.makeText(context, text, Toast.LENGTH_LONG)
|
||||
singleToast!!.show()
|
||||
showTime = Date()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
package com.tangem.di
|
||||
|
||||
import com.tangem.ui.activity.MainActivity
|
||||
import dagger.Component
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Component(modules = [NavigatorModule::class])
|
||||
interface ToastHelperComponent {
|
||||
|
||||
fun inject(activity: MainActivity)
|
||||
|
||||
}
|
||||
70
app/src/main/java/com/tangem/tap/MainActivity.kt
Normal file
70
app/src/main/java/com/tangem/tap/MainActivity.kt
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
package com.tangem.tap
|
||||
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.tangem.CardFilter
|
||||
import com.tangem.Config
|
||||
import com.tangem.TangemSdk
|
||||
import com.tangem.common.extensions.CardType
|
||||
import com.tangem.tangem_sdk_new.extensions.init
|
||||
import com.tangem.tap.common.redux.NotificationsHandler
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.domain.TangemSdkManager
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
lateinit var tangemSdk: TangemSdk
|
||||
lateinit var tangemSdkManager: TangemSdkManager
|
||||
var notificationsHandler: NotificationsHandler? = null
|
||||
|
||||
private val coroutineContext: CoroutineContext
|
||||
get() = Job() + Dispatchers.IO + initCoroutineExceptionHandler()
|
||||
val scope = CoroutineScope(coroutineContext)
|
||||
|
||||
|
||||
private fun initCoroutineExceptionHandler(): CoroutineExceptionHandler {
|
||||
return CoroutineExceptionHandler { _, throwable -> throw throwable }
|
||||
}
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
|
||||
store.dispatch(NavigationAction.ActivityCreated(WeakReference(this)))
|
||||
|
||||
tangemSdk = TangemSdk.init(
|
||||
this, Config(cardFilter = CardFilter(EnumSet.allOf(CardType::class.java)))
|
||||
)
|
||||
tangemSdkManager = TangemSdkManager(this)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
notificationsHandler = NotificationsHandler(fragment_container)
|
||||
if (supportFragmentManager.backStackEntryCount == 0) {
|
||||
store.dispatch(
|
||||
NavigationAction.NavigateTo(AppScreen.Home)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
notificationsHandler = null
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
store.dispatch(NavigationAction.ActivityDestroyed)
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue