Updated on 2026-08-14

This commit is contained in:
Tangem 2020-04-19 16:20:25 +03:00
commit 364ef1e165
205 changed files with 17463 additions and 627 deletions

View file

@ -3,6 +3,7 @@ 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() {
@ -72,6 +73,7 @@ repositories {
}
configurations {
all*.exclude group: 'com.google.guava', module: 'listenablefuture'
implementation.exclude module:'protobuf-lite'
}
dependencies {
@ -79,22 +81,22 @@ dependencies {
implementation project(':tangem-sdk-old')
implementation project(':server-android')
implementation 'androidx.navigation:navigation-fragment:2.1.0'
implementation 'androidx.navigation:navigation-ui-ktx:2.1.0'
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.1.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
implementation "androidx.lifecycle:lifecycle-runtime:2.1.0"
implementation "androidx.lifecycle:lifecycle-common-java8:2.1.0"
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation "androidx.lifecycle:lifecycle-runtime:2.2.0"
implementation "androidx.lifecycle:lifecycle-common-java8:2.2.0"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.fragment:fragment:1.1.0'
implementation 'androidx.fragment:fragment:1.2.4'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation "androidx.preference:preference:1.1.0"
implementation 'androidx.biometric:biometric:1.0.0-beta01'
implementation 'androidx.core:core-ktx:1.1.0'
implementation 'com.google.android.material:material:1.1.0-beta01'
implementation "androidx.preference:preference:1.1.1"
implementation 'androidx.biometric:biometric:1.0.1'
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'com.google.android.material:material:1.1.0'
implementation 'com.google.dagger:dagger:2.21'
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.4.0'
@ -113,8 +115,8 @@ dependencies {
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.2.2'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.2.2"
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'
@ -126,8 +128,9 @@ dependencies {
// 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.2.3'
implementation 'com.google.firebase:firebase-crashlytics:17.0.0-beta02'
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'
implementation files('libs/ripple-core-0.0.1.jar')
//4 dependencies for ripple-core TODO: move to module?
@ -158,4 +161,7 @@ dependencies {
//dependencies for flow demo
implementation 'io.grpc:grpc-okhttp:1.28.0'
implementation 'io.grpc:grpc-stub:1.28.0'
//dependencies for TokenEmvEngine
implementation 'com.github.walleth.kethereum:extensions_kotlin:0.81.4'
}

View file

@ -2,8 +2,6 @@ package com.tangem
import android.app.Application
import androidx.appcompat.app.AppCompatDelegate
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.tangem.data.dp.PrefsManager
@ -80,10 +78,7 @@ class App : Application() {
)
}
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(Analytics.isEnabled())
FirebaseAnalytics.getInstance(this).setAnalyticsCollectionEnabled(
Analytics.isEnabled() && !BuildConfig.DEBUG
)
Analytics.setFirebaseEnabled(this)
}
private fun buildToastHelperComponent(): ToastHelperComponent {

View file

@ -32,7 +32,8 @@ public enum Blockchain {
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");
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;

View file

@ -40,6 +40,14 @@ public class Server {
}
}
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;

View file

@ -42,6 +42,8 @@ public class 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);
}
}

View file

@ -0,0 +1,53 @@
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)
}
}

View file

@ -5,6 +5,7 @@ class ServerURL {
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/";

View file

@ -0,0 +1,17 @@
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>
}

View file

@ -0,0 +1,36 @@
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?
)

View file

@ -17,6 +17,9 @@ interface NetworkComponent {
@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

View file

@ -44,6 +44,18 @@ internal class NetworkModule {
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)

View file

@ -22,6 +22,8 @@ import androidx.core.os.bundleOf
import androidx.lifecycle.ViewModelProviders
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.google.firebase.perf.FirebasePerformance
import com.google.firebase.perf.metrics.Trace
import com.tangem.App
import com.tangem.Constant
import com.tangem.data.Blockchain
@ -77,6 +79,7 @@ class MainFragment : BaseFragment(), NavigationResultListener, NfcAdapter.Reader
override val layoutId = R.layout.fragment_main
private lateinit var viewModel: MainViewModel
private lateinit var nfcDeviceAntenna: NfcDeviceAntennaLocation
private var tapTimerTrace: Trace? = null
private var unsuccessReadCount = 0
private var task: CustomReadCardTask? = null
private var lastTag: Tag? = null
@ -156,6 +159,9 @@ class MainFragment : BaseFragment(), NavigationResultListener, NfcAdapter.Reader
}
override fun onResume() {
tapTimerTrace = FirebasePerformance.getInstance()
.newTrace(AnalyticsEvent.CARD_TAP_USER_TIMER.event)
tapTimerTrace?.start()
super.onResume()
nfcDeviceAntenna.animate()
}
@ -167,6 +173,7 @@ class MainFragment : BaseFragment(), NavigationResultListener, NfcAdapter.Reader
override fun onStop() {
task?.cancel(true)
tapTimerTrace = null
super.onStop()
}
@ -248,6 +255,7 @@ class MainFragment : BaseFragment(), NavigationResultListener, NfcAdapter.Reader
}
override fun onReadFinish(cardProtocol: CardProtocol?) {
tapTimerTrace?.stop()
task = null
if (cardProtocol != null) {
if (cardProtocol.error == null) {
@ -338,7 +346,7 @@ class MainFragment : BaseFragment(), NavigationResultListener, NfcAdapter.Reader
lastTag = null
ReadCardInfoTask.resetLastReadInfo()
(activity as MainActivity).nfcManager.notifyReadResult(false)
(activity as? MainActivity)?.nfcManager?.notifyReadResult(false)
}
}
}

View file

@ -11,7 +11,6 @@ import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceFragmentCompat
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.tangem.util.Analytics
import com.tangem.util.AnalyticsEvent
import com.tangem.wallet.BuildConfig
@ -48,15 +47,13 @@ class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedP
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
if (key == getString(R.string.pref_analytics)) {
activity?.let {
val analytics = FirebaseAnalytics.getInstance(it)
activity?.let {activity ->
val analytics = FirebaseAnalytics.getInstance(activity)
if (!Analytics.isEnabled()) {
analytics.logEvent(AnalyticsEvent.ANALYTICS_TURNED_OFF.event, bundleOf())
}
analytics.setAnalyticsCollectionEnabled(Analytics.isEnabled() && !BuildConfig.DEBUG)
Analytics.setFirebaseEnabled(activity)
}
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(Analytics.isEnabled())
}
}

View file

@ -1,8 +1,13 @@
package com.tangem.util
import android.content.Context
import android.os.Bundle
import androidx.core.os.bundleOf
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.google.firebase.perf.FirebasePerformance
import com.tangem.data.dp.PrefsManager
import com.tangem.wallet.BuildConfig
import com.tangem.wallet.R
import com.tangem.wallet.TangemContext
@ -13,6 +18,7 @@ enum class AnalyticsEvent(val event: String) {
READY_TO_SIGN("ready_to_sign"),
SIGNED("signed"),
ANALYTICS_TURNED_OFF("analytics_turned_off"),
CARD_TAP_USER_TIMER("CardTapUserTimer"),
;
}
@ -36,5 +42,13 @@ class Analytics {
fun isEnabled(): Boolean {
return PrefsManager.getInstance().getSettingsBoolean(R.string.pref_analytics, true)
}
fun setFirebaseEnabled(context: Context, enable: Boolean = isEnabled()) {
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(enable)
FirebaseAnalytics.getInstance(context).setAnalyticsCollectionEnabled(
enable && !BuildConfig.DEBUG
)
FirebasePerformance.getInstance().isPerformanceCollectionEnabled = enable
}
}
}

View file

@ -20,6 +20,7 @@ import com.tangem.wallet.rsk.RskEngine
import com.tangem.wallet.rsk.RskTokenEngine
import com.tangem.wallet.token.TokenEngine
import com.tangem.wallet.tezos.TezosEngine
import com.tangem.wallet.tokenEmv.TokenEmvEngine
import com.tangem.wallet.xlm.XlmAssetEngine
import com.tangem.wallet.xlm.XlmEngine
import com.tangem.wallet.xlmTag.XlmTagEngine
@ -60,6 +61,7 @@ object CoinEngineFactory {
Blockchain.Tezos -> TezosEngine()
Blockchain.BitcoinDual -> BtcMultisigEngine()
Blockchain.FlowDemo -> FlowDemoEngine()
Blockchain.TokenEmv -> TokenEmvEngine()
else -> null
}
}
@ -109,6 +111,8 @@ object CoinEngineFactory {
BtcMultisigEngine(context)
else if (Blockchain.FlowDemo == context.blockchain)
FlowDemoEngine(context)
else if (Blockchain.TokenEmv == context.blockchain)
TokenEmvEngine(context)
else
return null
} catch (e: Exception) {

View file

@ -110,7 +110,7 @@ public class EthTransaction {
return kec.digest(plainMsg);
}
public int BruteRecoveryID2(ECDSASignatureETH sig, byte[] messageHash, byte[] thisKey) {
public static int BruteRecoveryID2(ECDSASignatureETH sig, byte[] messageHash, byte[] thisKey) {
Log.e("ETH_KZ", BTCUtils.toHex(thisKey));
int recId = -1;
for (int i = 0; i < 4; i++) {

View file

@ -8,31 +8,46 @@ import com.tangem.wallet.eth.EthData;
public class TokenData extends EthData {
private CoinEngine.InternalAmount balanceAlter = null;
// private Integer sequence = null;
@Override
public void clearInfo() {
super.clearInfo();
balanceAlter = null;
// sequence = null;
}
public CoinEngine.InternalAmount getBalanceAlterInInternalUnits() {
return balanceAlter;
}
public void setBalanceAlterInInternalUnits(CoinEngine.InternalAmount value) {
balanceAlter = value;
}
// public Integer getSequence() {
// return sequence;
// }
//
// public void setSequence(Integer sequence) {
// this.sequence = sequence;
// }
@Override
public void loadFromBundle(Bundle B) {
super.loadFromBundle(B);
if( B.containsKey("BalanceDecimalAlter" )) {
if (B.containsKey("BalanceDecimalAlter")) {
balanceAlter = new CoinEngine.InternalAmount(B.getString("BalanceDecimalAlter"), "wei");
}else{
balanceAlter=null;
} else {
balanceAlter = null;
}
// if (B.containsKey("Sequence")) {
// sequence = B.getInt("Sequence");
// } else {
// sequence = null;
// }
}
@Override
@ -40,9 +55,12 @@ public class TokenData extends EthData {
super.saveToBundle(B);
try {
if( balanceAlter!=null ) {
if (balanceAlter != null) {
B.putString("BalanceDecimalAlter", balanceAlter.toString());
}
// if (sequence != null) {
// B.putInt("Sequence", sequence);
// }
} catch (Exception e) {
Log.e("Can't save to bundle ", e.getMessage());
}

View file

@ -0,0 +1,349 @@
package com.tangem.wallet.tokenEmv
import android.net.Uri
import android.text.InputFilter
import android.util.Log
import com.google.gson.Gson
import com.tangem.data.Blockchain
import com.tangem.data.network.ServerApiInfura
import com.tangem.data.network.ServerApiTokenEmv
import com.tangem.data.network.model.*
import com.tangem.tangem_card.data.TangemCard
import com.tangem.tangem_card.reader.CardProtocol.TangemException
import com.tangem.tangem_card.reader.TLV
import com.tangem.tangem_card.reader.TLVList
import com.tangem.tangem_card.tasks.SignTask
import com.tangem.tangem_card.util.Util
import com.tangem.util.DecimalDigitsInputFilter
import com.tangem.wallet.EthTransaction
import com.tangem.wallet.Keccak256
import com.tangem.wallet.R
import com.tangem.wallet.TangemContext
import com.tangem.wallet.token.TokenEngine
import io.reactivex.observers.DisposableSingleObserver
import org.apache.commons.lang3.SerializationUtils
import org.kethereum.extensions.toBytesPadded
import java.math.BigInteger
class TokenEmvEngine : TokenEngine {
constructor() : super()
constructor(context: TangemContext) : super(context)
private val TAG = TokenEmvEngine::class.java.simpleName
private fun hasLinkedContract(): Boolean {
return ctx.card.issuerData != null && ctx.card.issuerData.size == 44
}
override fun getBlockchain(): Blockchain {
return Blockchain.TokenEmv
}
override fun getChainIdNum(): Int {
return EthTransaction.ChainEnum.Ropsten.value
}
override fun getBalance(): Amount? {
return if (!hasBalanceInfo()) {
null
} else {
convertToAmount(coinData.balanceInInternalUnits)
}
}
override fun getBalanceHTML(): String? {
return if (hasLinkedContract()) {
if (balance != null) {
balance!!.toDescriptionString(tokenDecimals)
} else {
""
}
} else {
"NO LINKED CONTRACT"
}
}
override fun getBalanceCurrency(): String? {
return ctx.card.getTokenSymbol()
}
override fun getAmountInputFilters(): Array<InputFilter>? {
return arrayOf(DecimalDigitsInputFilter(tokenDecimals))
}
override fun getFeeCurrency(): String? {
return balanceCurrency
}
override fun isBalanceNotZero(): Boolean {
if (coinData == null) return false
return if (coinData.balanceInInternalUnits == null) {
false
} else {
coinData.balanceInInternalUnits.notZero()
}
}
override fun getBalanceEquivalent(): String? {
return ""
}
override fun evaluateFeeEquivalent(fee: String?): String? {
return ""
}
override fun defineWallet() {
try {
if (hasLinkedContract()) {
ctx.coinData.wallet = TLVList.fromBytes(ctx.card.issuerData).getTLV(TLV.Tag.TAG_Token_Contract_Address).asString
} else {
ctx.coinData.wallet = calculateAddress(ctx.card.walletPublicKey)
}
} catch (e: Exception) {
ctx.coinData.wallet = "ERROR"
throw TangemException("Can't define wallet address")
}
}
override fun hasBalanceInfo(): Boolean {
return coinData.balanceInInternalUnits != null
}
override fun getWalletExplorerUri(): Uri {
return Uri.parse("https://ropsten.etherscan.io/token/" + getContractAddress(ctx.card) + "?a=" + ctx.coinData.wallet)
}
override fun isExtractPossible(): Boolean {
if (!hasBalanceInfo()) {
ctx.setMessage(R.string.loaded_wallet_error_obtaining_blockchain_data)
} else if (!isBalanceNotZero) {
ctx.setMessage(R.string.general_wallet_empty)
} else if (awaitingConfirmation()) {
ctx.setMessage(R.string.loaded_wallet_message_wait)
} else {
return true
}
return false
}
override fun checkNewTransactionAmountAndFee(amount: Amount, fee: Amount?, isFeeIncluded: Boolean): Boolean {
try {
if (isFeeIncluded && (amount > balance || amount < fee)) return false
if (!isFeeIncluded && amount.add(fee) > balance) return false
} catch (e: NumberFormatException) {
e.printStackTrace()
}
return true
}
override fun constructTransaction(amountValue: Amount, feeValue: Amount?, IncFee: Boolean, targetAddress: String?): SignTask.TransactionToSign? {
val functionBytes = "transfer".toByteArray()
val contractHex = coinData.wallet.substring(2)
val contractBytes = Util.hexToBytes(contractHex)
val recipientHex = targetAddress!!.substring(2)
val recipientBytes = Util.hexToBytes(recipientHex)
val amountBytes = convertToInternalAmount(amountValue).toBigInteger().toBytesPadded(32)
val feeLimitBytes = convertToInternalAmount(feeValue).toBigInteger().toBytesPadded(32)
val sequence = ctx.card.SignedHashes
val sequenceBytes = sequence.toBigInteger().toBytesPadded(4)
val hashToSign = Keccak256().digest(contractBytes + functionBytes + amountBytes + recipientBytes + feeLimitBytes + sequenceBytes)
return object : SignTask.TransactionToSign {
override fun isSigningMethodSupported(signingMethod: TangemCard.SigningMethod): Boolean {
return signingMethod == TangemCard.SigningMethod.Sign_Hash
}
override fun getHashesToSign(): Array<ByteArray> {
return arrayOf(hashToSign)
}
@Throws(java.lang.Exception::class)
override fun getRawDataToSign(): ByteArray {
throw java.lang.Exception("Signing of raw transaction not supported for " + this.javaClass.simpleName)
}
@Throws(java.lang.Exception::class)
override fun getHashAlgToSign(): String {
throw java.lang.Exception("Signing of raw transaction not supported for " + this.javaClass.simpleName)
}
@Throws(java.lang.Exception::class)
override fun getIssuerTransactionSignature(dataToSignByIssuer: ByteArray): ByteArray {
throw java.lang.Exception("Transaction validation by issuer not supported in this version")
}
@Throws(java.lang.Exception::class)
override fun onSignCompleted(signFromCard: ByteArray): ByteArray {
// val r = BigInteger(1, Arrays.copyOfRange(signFromCard, 0, 32))
// var s: BigInteger? = BigInteger(1, Arrays.copyOfRange(signFromCard, 32, 64))
// s = CryptoUtil.toCanonicalised(s)
//
// val publicKey = ctx.getCard().getWalletPublicKey()
//
// val verified = ECKey.verify(hashToSign, ECKey.ECDSASignature(r, s), publicKey)
// if (!verified) {
// Log.e(this.javaClass.simpleName + "-CHECK", "sign Failed.")
// }
//
// val v = BruteRecoveryID2(ECDSASignatureETH(r, s), hashToSign, publicKey)
// if (v != 27 && v != 28) {
// Log.e(TAG, "invalid v")
// throw java.lang.Exception("Error in " + this.javaClass.simpleName + " - invalid v")
// }
// Log.e(TAG, this.javaClass.simpleName + " V: " + v.toString())
//
// var rBytes = r.toByteArray()
// if (rBytes.size == 33) {
// rBytes = rBytes.copyOfRange(1,33)
// }
// val sBytes = s.toByteArray()
//
// val tokenEmvTransferBody = TokenEmvTransferBody(
// CID = Util.bytesToHex(ctx.card.cid),
// publicKey = Util.bytesToHex(ctx.card.walletPublicKey),
// contract = contractHex,
// amount = Util.byteArrayToHexString(amountBytes),
// recipient = recipientHex,
// feeLimit = Util.byteArrayToHexString(feeLimitBytes),
// sequence = sequence,
// r = Util.byteArrayToHexString(rBytes),
// s = Util.byteArrayToHexString(sBytes),
// v = v
// )
val tokenEmvTransferBody = TokenEmvTransferBody(
CID = Util.bytesToHex(ctx.card.cid),
publicKey = Util.bytesToHex(ctx.card.walletPublicKey),
amount = amountValue.toValueString(),
currency = amountValue.currency,
recipient = targetAddress,
feeLimit = feeValue!!.toValueString(),
sequence = sequence,
signature = Util.bytesToHex(signFromCard)
)
val jsonBody = Gson().toJson(tokenEmvTransferBody)
val serializedBody = SerializationUtils.serialize(jsonBody)
notifyOnNeedSendTransaction(serializedBody)
return serializedBody
}
}
}
override fun requestBalanceAndUnspentTransactions(blockchainRequestsCallbacks: BlockchainRequestsCallbacks) {
val serverApiInfura = ServerApiInfura(ctx.blockchain)
val responseListener: ServerApiInfura.ResponseListener = object : ServerApiInfura.ResponseListener {
override fun onSuccess(method: String, infuraResponse: InfuraResponse) {
try {
var balanceCap = infuraResponse.result
balanceCap = balanceCap!!.substring(2)
val l = BigInteger(balanceCap, 16)
coinData.balanceInInternalUnits = InternalAmount(l, ctx.card.tokenSymbol)
coinData.isBalanceReceived = true
// Log.i("$TAG eth_call", balanceCap)
} catch (e: java.lang.Exception) {
onFail(method, e.message ?: "invalid response")
}
blockchainRequestsCallbacks.onComplete(true)
}
override fun onFail(method: String, message: String) {
Log.e(TAG, "onFail: $method $message")
ctx.error = message
blockchainRequestsCallbacks.onComplete(false)
}
}
serverApiInfura.setResponseListener(responseListener)
if (validateAddress(getContractAddress(ctx.card))) {
serverApiInfura.requestData(ServerApiInfura.INFURA_ETH_CALL, 67, coinData.wallet, getContractAddress(ctx.card), "")
} else {
ctx.error = "Smart contract address not defined"
blockchainRequestsCallbacks.onComplete(false)
}
}
override fun requestFee(blockchainRequestsCallbacks: BlockchainRequestsCallbacks, targetAddress: String?, amount: Amount) {
val tokenEmvTransferBody = TokenEmvGetTransferFeeBody(
CID = Util.bytesToHex(ctx.card.cid),
publicKey = Util.bytesToHex(ctx.card.walletPublicKey)
)
val observer = object : DisposableSingleObserver<TokenEmvGetTransferFeeAnswer>() {
override fun onError(e: Throwable) {
ctx.error = "Can't get transfer fee, ${e.message}"
blockchainRequestsCallbacks.onComplete(false)
}
override fun onSuccess(t: TokenEmvGetTransferFeeAnswer) {
if (t.success != null && t.success) {
ctx.error = null
coinData.minFee = Amount(t.fee, t.currency)
coinData.normalFee = Amount(t.fee, t.currency)
coinData.maxFee = Amount(t.fee, t.currency)
blockchainRequestsCallbacks.onComplete(true)
} else {
if (t.error != null) {
ctx.error = t.error
} else {
ctx.error = "Can't get transfer fee, code ${t.errorCode}"
}
blockchainRequestsCallbacks.onComplete(false)
}
}
}
ServerApiTokenEmv().getTransferFee(tokenEmvTransferBody, observer)
blockchainRequestsCallbacks.onComplete(true)
}
override fun requestSendTransaction(blockchainRequestsCallbacks: BlockchainRequestsCallbacks, txForSend: ByteArray?) {
val jsonBody = SerializationUtils.deserialize<String>(txForSend)
Log.e(TAG, jsonBody)
val tokenEmvTransferBody = Gson().fromJson(jsonBody, TokenEmvTransferBody::class.java)
val observer = object : DisposableSingleObserver<TokenEmvTransferAnswer>() {
override fun onError(e: Throwable) {
ctx.error = "Can't send transfer, ${e.message}"
blockchainRequestsCallbacks.onComplete(false)
}
override fun onSuccess(t: TokenEmvTransferAnswer) {
if (t.success != null && t.success) {
ctx.error = null
blockchainRequestsCallbacks.onComplete(true)
} else {
if (t.error != null) {
ctx.error = t.error
} else {
ctx.error = "Can't send transfer, code ${t.errorCode}"
}
blockchainRequestsCallbacks.onComplete(false)
}
}
}
ServerApiTokenEmv().transfer(tokenEmvTransferBody, observer)
}
override fun allowSelectFeeLevel(): Boolean {
return false
}
override fun pendingTransactionTimeoutInSeconds(): Int {
return 60
}
}

View file

@ -24,6 +24,10 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
@ -80,6 +84,17 @@ dependencies {
implementation 'org.json:json:20180813'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
//dependencies for binance
implementation 'com.google.protobuf:protobuf-java:3.6.1'
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'
implementation 'com.squareup.retrofit2:converter-jackson:2.6.0'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.5.2'
testImplementation "com.google.truth:truth:1.0"
androidTestImplementation 'androidx.test.ext:junit:1.1.1'

View file

@ -0,0 +1,37 @@
package com.tangem.blockchain.binance
import com.tangem.blockchain.binance.client.encoding.Crypto
import com.tangem.common.extensions.calculateRipemd160
import com.tangem.common.extensions.calculateSha256
import com.tangem.common.extensions.toCompressedPublicKey
import org.bitcoinj.core.Bech32
class BinanceAddressFactory {
companion object {
fun makeAddress(walletPublicKey: ByteArray, testNet: Boolean = false): String {
val publicKeyHash = walletPublicKey.toCompressedPublicKey().calculateSha256().calculateRipemd160()
return if (testNet) {
Bech32.encode("tbnb", Crypto.convertBits(publicKeyHash, 0, publicKeyHash.size, 8, 5, false))
} else {
Bech32.encode("bnb", Crypto.convertBits(publicKeyHash, 0, publicKeyHash.size, 8, 5, false))
}
}
}
}
class BinanceAddressValidator {
companion object {
fun validate(address: String, testNet: Boolean = false): Boolean {
return try {
Crypto.decodeAddress(address)
if (testNet) {
address.startsWith("tbnb1")
} else {
address.startsWith("bnb1")
}
} catch (exception: Exception) {
false
}
}
}
}

View file

@ -0,0 +1,67 @@
package com.tangem.blockchain.binance
import com.tangem.blockchain.binance.client.BinanceDexApiClientFactory
import com.tangem.blockchain.binance.client.BinanceDexEnvironment
import com.tangem.blockchain.binance.client.domain.broadcast.TransactionOption
import com.tangem.blockchain.binance.client.domain.broadcast.Transfer
import com.tangem.blockchain.binance.client.encoding.message.MessageType
import com.tangem.blockchain.binance.client.encoding.message.TransactionRequestAssemblerExtSign
import com.tangem.blockchain.binance.client.encoding.message.TransferMessage
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.TransactionData
import com.tangem.common.extensions.calculateSha256
import com.tangem.common.extensions.toCompressedPublicKey
import org.bitcoinj.core.ECKey
import org.bitcoinj.core.Utils
import java.math.BigInteger
class BinanceTransactionBuilder(publicKey: ByteArray, isTestNet: Boolean) {
val chainId = if (isTestNet) "Binance-Chain-Nile" else "Binance-Chain-Tigris"
val prefixedPubKey = MessageType.PubKey.typePrefixBytes + 33.toByte() + publicKey.toCompressedPublicKey()
val client = BinanceDexApiClientFactory.newInstance().newRestClient(
if (isTestNet) BinanceDexEnvironment.PROD.baseUrl else BinanceDexEnvironment.TEST_NET.baseUrl
)
var accountNumber: Long? = null
var sequence: Long? = null
var transactionAssembler: TransactionRequestAssemblerExtSign? = null
var transferMessage: TransferMessage? = null
fun buildToSign(transactionData: TransactionData): ByteArray {
val transfer = Transfer()
transfer.coin = transactionData.amount.currencySymbol
transfer.fromAddress = transactionData.sourceAddress
transfer.toAddress = transactionData.destinationAddress
transfer.amount = transactionData.amount.value!!
.setScale(Blockchain.Binance.decimals.toInt()).toPlainString()
val options = TransactionOption.DEFAULT_INSTANCE
val accountData = BinanceAccountData(chainId, accountNumber!!, sequence!!)
transactionAssembler = client.prepareTransfer(transfer, accountData, prefixedPubKey, options, true)
transferMessage = transactionAssembler!!.createTransferMessage(transfer)
return transactionAssembler!!.prepareForSign(transferMessage).calculateSha256()
}
fun buildToSend(signature: ByteArray): ByteArray {
val r = BigInteger(1, signature.copyOfRange(0, 32))
val s = BigInteger(1, signature.copyOfRange(32, 64))
val canonicalS = ECKey.ECDSASignature(r, s).toCanonicalised().s
//bigIntegerToBytes cuts leading zero if present
val canonicalSignature = Utils.bigIntegerToBytes(r, 32) + Utils.bigIntegerToBytes(canonicalS, 32)
val encodedSignature = transactionAssembler!!.encodeSignature(canonicalSignature)
val encodedTransferMessage = transactionAssembler!!.encodeTransferMessage(transferMessage)
return transactionAssembler!!.encodeStdTx(encodedTransferMessage, encodedSignature)
}
}
data class BinanceAccountData(
val chainId: String,
val accountNumber: Long,
val sequence: Long
)

View file

@ -0,0 +1,71 @@
package com.tangem.blockchain.binance
import android.util.Log
import com.tangem.blockchain.binance.network.BinanceInfoResponse
import com.tangem.blockchain.binance.network.BinanceNetworkManager
import com.tangem.blockchain.common.*
import com.tangem.blockchain.common.extensions.Result
import com.tangem.blockchain.common.extensions.SimpleResult
import com.tangem.blockchain.wallets.CurrencyWallet
import com.tangem.common.CompletionResult
class BinanceWalletManager(
private val cardId: String,
walletPublicKey: ByteArray,
override var wallet: CurrencyWallet,
isTestNet: Boolean = false
) : WalletManager,
TransactionSender,
FeeProvider {
override val blockchain = if (isTestNet) Blockchain.BinanceTestnet else Blockchain.Binance
private val address = blockchain.makeAddress(walletPublicKey)
private val transactionBuilder = BinanceTransactionBuilder(walletPublicKey, isTestNet)
private val networkManager = BinanceNetworkManager(isTestNet)
init {
wallet.balances[AmountType.Coin] = Amount(null, blockchain, address)
}
override suspend fun update() {
val result = networkManager.getInfo(address)
when (result) {
is Result.Success -> updateWallet(result.data)
is Result.Failure -> updateError(result.error)
}
}
private fun updateWallet(response: BinanceInfoResponse) {
Log.d(this::class.java.simpleName, "Balance is ${response.balance}")
wallet.balances[AmountType.Coin]?.value = response.balance
transactionBuilder.accountNumber = response.accountNumber
transactionBuilder.sequence = response.sequence
}
private fun updateError(error: Throwable?) {
Log.e(this::class.java.simpleName, error?.message ?: "")
if (error != null) throw error
}
override suspend fun send(transactionData: TransactionData, signer: TransactionSigner): SimpleResult {
val transactionHash = transactionBuilder.buildToSign(transactionData)
when (val signerResponse = signer.sign(arrayOf(transactionHash), cardId)) {
is CompletionResult.Success -> {
val transactionToSend = transactionBuilder.buildToSend(signerResponse.data.signature)
return networkManager.sendTransaction(transactionToSend)
}
is CompletionResult.Failure -> return SimpleResult.Failure(signerResponse.error)
}
}
override suspend fun getFee(amount: Amount, destination: String): Result<List<Amount>> {
when (val result = networkManager.getFee()) {
is Result.Success -> return Result.Success(listOf(Amount(result.data, blockchain)))
is Result.Failure -> return result
}
}
}

View file

@ -0,0 +1,84 @@
package com.tangem.blockchain.binance.client;
import java.util.List;
import com.tangem.blockchain.binance.client.domain.*;
import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.http.*;
import java.util.List;
public interface BinanceDexApi {
@GET("/api/v1/time")
Call<Time> getTime();
@GET("/api/v1/node-info")
Call<Infos> getNodeInfo();
@GET("/api/v1/validators")
Call<Validators> getValidators();
@GET("/api/v1/peers")
Call<List<Peer>> getPeers();
@GET("/api/v1/account/{address}")
Call<Account> getAccount(@Path("address") String address);
@GET("/api/v1/account/{address}/sequence")
Call<AccountSequence> getAccountSequence(@Path("address") String address);
@GET("/api/v1/tx/{hash}")
Call<TransactionMetadata> getTransactionMetadata(@Path("hash") String hash);
@GET("/api/v1/tokens")
Call<List<Token>> getTokens();
@GET("/api/v1/markets")
Call<List<Market>> getMarkets();
@GET("/api/v1/depth")
Call<OrderBook> getOrderBook(@Query("symbol") String symbol, @Query("limit") Integer limit);
@GET("/api/v1/klines")
Call<List<Candlestick>> getCandlestickBars(@Query("symbol") String symbol, @Query("interval") String interval,
@Query("limit") Integer limit, @Query("startTime") Long startTime,
@Query("endTime") Long endTime);
@GET("/api/v1/orders/open")
Call<OrderList> getOpenOrders(@Query("address") String address, @Query("limit") Integer limit,
@Query("offset") Integer offset, @Query("symbol") String symbol,
@Query("total") Integer total);
@GET("/api/v1/orders/closed")
Call<OrderList> getClosedOrders(@Query("address") String address, @Query("end") Long end,
@Query("limit") Integer limit, @Query("offset") Integer offset,
@Query("side") String side, @Query("start") Long start,
@Query("status") List<String> status, @Query("symbol") String symbol,
@Query("total") Integer total);
@GET("/api/v1/orders/{id}")
Call<Order> getOrder(@Path("id") String id);
@GET("/api/v1/ticker/24hr")
Call<List<TickerStatistics>> get24HrPriceStatistics();
@GET("/api/v1/trades")
Call<TradePage> getTrades(@Query("address") String address,
@Query("buyerOrderId") String buyerOrderId, @Query("end") Long end,
@Query("height") Long height, @Query("limit") Integer limit,
@Query("offset") Integer offset, @Query("quoteAsset") String quoteAsset,
@Query("sellerOrderId") String sellerOrderId, @Query("side") String side,
@Query("start") Long start, @Query("symbol") String symbol, @Query("total") Integer total);
@GET("/api/v1/transactions")
Call<TransactionPage> getTransactions(@Query("address") String address, @Query("blockHeight") Long blockHeight,
@Query("endTime") Long endTime, @Query("limit") Integer limit,
@Query("offset") Integer offset, @Query("side") String side,
@Query("startTime") Long startTime, @Query("txAsset") String txAsset,
@Query("txType") String txType);
@POST("/api/v1/broadcast")
Call<List<TransactionMetadata>> broadcast(@Query("sync") boolean sync, @Body RequestBody transaction);
}

View file

@ -0,0 +1,59 @@
package com.tangem.blockchain.binance.client;
import com.tangem.blockchain.binance.client.domain.*;
import com.tangem.blockchain.binance.client.domain.request.ClosedOrdersRequest;
import com.tangem.blockchain.binance.client.domain.request.OpenOrdersRequest;
import com.tangem.blockchain.binance.client.domain.request.TradesRequest;
import com.tangem.blockchain.binance.client.domain.request.TransactionsRequest;
import java.util.List;
public interface BinanceDexApiAsyncRestClient {
void getTime(BinanceDexApiCallback<Time> callback);
void getNodeInfo(BinanceDexApiCallback<Infos> callback);
void getValidators(BinanceDexApiCallback<Validators> callback);
void getPeers(BinanceDexApiCallback<List<Peer>> callback);
void getMarkets(BinanceDexApiCallback<List<Market>> callback);
void getAccount(String address, BinanceDexApiCallback<Account> callback);
void getAccountSequence(String address, BinanceDexApiCallback<AccountSequence> callback);
void getTransactionMetadata(String hash, BinanceDexApiCallback<TransactionMetadata> callback);
void getTokens(BinanceDexApiCallback<List<Token>> callback);
void getOrderBook(String symbol, Integer limit, BinanceDexApiCallback<OrderBook> callback);
void getCandleStickBars(String symbol, CandlestickInterval interval,
BinanceDexApiCallback<List<Candlestick>> callback);
void getCandleStickBars(String symbol, CandlestickInterval interval, Integer limit, Long startTime, Long endTime,
BinanceDexApiCallback<List<Candlestick>> callback);
void getOpenOrders(String address, BinanceDexApiCallback<OrderList> callback);
void getOpenOrders(OpenOrdersRequest request, BinanceDexApiCallback<OrderList> callback);
void getClosedOrders(String address, BinanceDexApiCallback<OrderList> callback);
void getClosedOrders(ClosedOrdersRequest request, BinanceDexApiCallback<OrderList> callback);
void getOrder(String id, BinanceDexApiCallback<Order> callback);
void get24HrPriceStatistics(BinanceDexApiCallback<List<TickerStatistics>> callback);
void getTrades(BinanceDexApiCallback<TradePage> callback);
void getTrades(TradesRequest request, BinanceDexApiCallback<TradePage> callback);
void getTransactions(String address, BinanceDexApiCallback<TransactionPage> callback);
void getTransactions(TransactionsRequest request, BinanceDexApiCallback<TransactionPage> callback);
// Do not support async broadcast due to account sequence
}

View file

@ -0,0 +1,25 @@
package com.tangem.blockchain.binance.client;
/**
* BinanceDexApiCallback is a functional interface used together with the BinanceApiAsyncClient to provide a non-blocking REST client.
*
* @param <T> the return type from the callback
*/
@FunctionalInterface
public interface BinanceDexApiCallback<T> {
/**
* Called whenever a response comes back from the Binance API.
*
* @param response the expected response object
*/
void onResponse(T response);
/**
* Called whenever an error occurs.
*
* @param cause the cause of the failure
*/
default void onFailure(Throwable cause) {
}
}

View file

@ -0,0 +1,48 @@
package com.tangem.blockchain.binance.client;
import java.io.IOException;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import static com.tangem.blockchain.binance.client.BinanceDexApiClientGenerator.getBinanceApiError;
/**
* An adapter/wrapper which transforms a Callback from Retrofit into a BinanceDexApiCallback which is exposed to the client.
*/
public class BinanceDexApiCallbackAdapter<T> implements Callback<T> {
private final BinanceDexApiCallback<T> callback;
public BinanceDexApiCallbackAdapter(BinanceDexApiCallback<T> callback) {
this.callback = callback;
}
public void onResponse(Call<T> call, Response<T> response) {
if (response.isSuccessful()) {
callback.onResponse(response.body());
} else {
if (response.code() == 504) {
// HTTP 504 return code is used when the API successfully sent the message but not get a response within the timeout period.
// It is important to NOT treat this as a failure; the execution status is UNKNOWN and could have been a success.
return;
}
try {
BinanceDexApiError apiError = getBinanceApiError(response);
onFailure(call, new BinanceDexApiException(apiError));
} catch (IOException e) {
onFailure(call, new BinanceDexApiException(e));
}
}
}
@Override
public void onFailure(Call<T> call, Throwable throwable) {
if (throwable instanceof BinanceDexApiException) {
callback.onFailure(throwable);
} else {
callback.onFailure(new BinanceDexApiException(throwable));
}
}
}

View file

@ -0,0 +1,30 @@
package com.tangem.blockchain.binance.client;
import com.tangem.blockchain.binance.client.impl.BinanceDexApiAsyncRestClientImpl;
import com.tangem.blockchain.binance.client.impl.BinanceDexApiRestClientImpl;
public class BinanceDexApiClientFactory {
private BinanceDexApiClientFactory() {
}
public static BinanceDexApiClientFactory newInstance() {
return new BinanceDexApiClientFactory();
}
public BinanceDexApiRestClient newRestClient() {
return newRestClient(BinanceDexEnvironment.PROD.getBaseUrl());
}
public BinanceDexApiRestClient newRestClient(String baseUrl) {
return new BinanceDexApiRestClientImpl(baseUrl);
}
public BinanceDexApiAsyncRestClient newAsyncRestClient() {
return newAsyncRestClient(BinanceDexEnvironment.PROD.getBaseUrl());
}
public BinanceDexApiAsyncRestClient newAsyncRestClient(String baseUrl) {
return new BinanceDexApiAsyncRestClientImpl(baseUrl);
}
}

View file

@ -0,0 +1,77 @@
package com.tangem.blockchain.binance.client;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.joda.JodaModule;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Converter;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.jackson.JacksonConverterFactory;
public class BinanceDexApiClientGenerator {
private static final OkHttpClient sharedClient = new OkHttpClient.Builder()
.pingInterval(20, TimeUnit.SECONDS)
.build();
private static final Converter.Factory converterFactory =
JacksonConverterFactory.create(new ObjectMapper().registerModule(new JodaModule()));
@SuppressWarnings("unchecked")
private static final Converter<ResponseBody, BinanceDexApiError> errorBodyConverter =
(Converter<ResponseBody, BinanceDexApiError>) converterFactory.responseBodyConverter(
BinanceDexApiError.class, new Annotation[0], null);
public static <S> S createService(Class<S> serviceClass, String baseUrl) {
Retrofit.Builder retrofitBuilder = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(converterFactory);
retrofitBuilder.client(sharedClient);
Retrofit retrofit = retrofitBuilder.build();
return retrofit.create(serviceClass);
}
/**
* Execute a REST call and block until the response is received.
*/
public static <T> T executeSync(Call<T> call) {
try {
Response<T> response = call.execute();
if (response.isSuccessful()) {
return response.body();
} else {
try {
BinanceDexApiError apiError = getBinanceApiError(response);
throw new BinanceDexApiException(apiError);
} catch (IOException e) {
throw new BinanceDexApiException(response.toString(), e);
}
}
} catch (IOException e) {
throw new BinanceDexApiException(e);
}
}
/**
* Extracts and converts the response error body into an object.
*/
public static BinanceDexApiError getBinanceApiError(Response<?> response) throws IOException {
return errorBodyConverter.convert(response.errorBody());
}
/**
* Returns the shared OkHttpClient instance.
*/
public static OkHttpClient getSharedClient() {
return sharedClient;
}
}

View file

@ -0,0 +1,36 @@
package com.tangem.blockchain.binance.client;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
@JsonIgnoreProperties(ignoreUnknown = true)
public class BinanceDexApiError {
private int code;
private String message;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("code", code)
.append("message", message)
.toString();
}
}

View file

@ -0,0 +1,31 @@
package com.tangem.blockchain.binance.client;
public class BinanceDexApiException extends RuntimeException {
private static final long serialVersionUID = 3788669840036201041L;
private BinanceDexApiError error;
public BinanceDexApiException(BinanceDexApiError error) {
this.error = error;
}
public BinanceDexApiException(Throwable cause) {
super(cause);
}
public BinanceDexApiException(String message, Throwable cause) {
super(message, cause);
}
public BinanceDexApiError getError() {
return error;
}
@Override
public String getMessage() {
if (error != null) {
return error.getMessage();
}
return super.getMessage();
}
}

View file

@ -0,0 +1,103 @@
package com.tangem.blockchain.binance.client;
import com.tangem.blockchain.binance.BinanceAccountData;
import com.tangem.blockchain.binance.client.domain.Account;
import com.tangem.blockchain.binance.client.domain.AccountSequence;
import com.tangem.blockchain.binance.client.domain.Candlestick;
import com.tangem.blockchain.binance.client.domain.CandlestickInterval;
import com.tangem.blockchain.binance.client.domain.Infos;
import com.tangem.blockchain.binance.client.domain.Market;
import com.tangem.blockchain.binance.client.domain.Order;
import com.tangem.blockchain.binance.client.domain.OrderBook;
import com.tangem.blockchain.binance.client.domain.OrderList;
import com.tangem.blockchain.binance.client.domain.Peer;
import com.tangem.blockchain.binance.client.domain.TickerStatistics;
import com.tangem.blockchain.binance.client.domain.Time;
import com.tangem.blockchain.binance.client.domain.Token;
import com.tangem.blockchain.binance.client.domain.TradePage;
import com.tangem.blockchain.binance.client.domain.TransactionMetadata;
import com.tangem.blockchain.binance.client.domain.TransactionPage;
import com.tangem.blockchain.binance.client.domain.Validators;
import com.tangem.blockchain.binance.client.domain.broadcast.CancelOrder;
import com.tangem.blockchain.binance.client.domain.broadcast.NewOrder;
import com.tangem.blockchain.binance.client.domain.broadcast.TokenFreeze;
import com.tangem.blockchain.binance.client.domain.broadcast.TokenUnfreeze;
import com.tangem.blockchain.binance.client.domain.broadcast.TransactionOption;
import com.tangem.blockchain.binance.client.domain.broadcast.Transfer;
import com.tangem.blockchain.binance.client.domain.request.ClosedOrdersRequest;
import com.tangem.blockchain.binance.client.domain.request.OpenOrdersRequest;
import com.tangem.blockchain.binance.client.domain.request.TradesRequest;
import com.tangem.blockchain.binance.client.domain.request.TransactionsRequest;
import com.tangem.blockchain.binance.client.encoding.message.TransactionRequestAssemblerExtSign;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import okhttp3.RequestBody;
public interface BinanceDexApiRestClient {
Time getTime();
Infos getNodeInfo();
Validators getValidators();
List<Peer> getPeers();
List<Market> getMarkets();
Account getAccount(String address);
AccountSequence getAccountSequence(String address);
TransactionMetadata getTransactionMetadata(String hash);
List<Token> getTokens();
OrderBook getOrderBook(String symbol, Integer limit);
List<Candlestick> getCandleStickBars(String symbol, CandlestickInterval interval);
List<Candlestick> getCandleStickBars(String symbol, CandlestickInterval interval, Integer limit, Long startTime, Long endTime);
OrderList getOpenOrders(String address);
OrderList getOpenOrders(OpenOrdersRequest request);
OrderList getClosedOrders(String address);
OrderList getClosedOrders(ClosedOrdersRequest request);
Order getOrder(String id);
List<TickerStatistics> get24HrPriceStatistics();
TradePage getTrades();
TradePage getTrades(TradesRequest request);
TransactionPage getTransactions(String address);
TransactionPage getTransactions(TransactionsRequest request);
public List<TransactionMetadata> broadcastNoWallet(RequestBody requestBody, boolean sync) throws BinanceDexApiException;
List<TransactionMetadata> newOrder(NewOrder newOrder, Wallet wallet, TransactionOption options, boolean sync)
throws IOException, NoSuchAlgorithmException;
List<TransactionMetadata> cancelOrder(CancelOrder cancelOrder, Wallet wallet, TransactionOption options, boolean sync)
throws IOException, NoSuchAlgorithmException;
List<TransactionMetadata> transfer(Transfer transfer, Wallet wallet, TransactionOption options, boolean sync)
throws IOException, NoSuchAlgorithmException;
TransactionRequestAssemblerExtSign prepareTransfer(Transfer transfer, BinanceAccountData binanceAccountData, byte[] pubKeyForSign, TransactionOption options, boolean sync)
throws IOException, NoSuchAlgorithmException;
List<TransactionMetadata> freeze(TokenFreeze freeze, Wallet wallet, TransactionOption options, boolean sync)
throws IOException, NoSuchAlgorithmException;
List<TransactionMetadata> unfreeze(TokenUnfreeze unfreeze, Wallet wallet, TransactionOption options, boolean sync)
throws IOException, NoSuchAlgorithmException;
}

View file

@ -0,0 +1,18 @@
package com.tangem.blockchain.binance.client;
import org.apache.commons.lang3.builder.ToStringStyle;
public class BinanceDexConstants {
/**
* Identifier of this client.
*/
public static final long BINANCE_DEX_API_CLIENT_JAVA_SOURCE = 3L;
/**
* Default ToStringStyle used by toString methods.
* Override this to change the output format of the overridden toString methods.
* - Example ToStringStyle.JSON_STYLE
*/
public static final ToStringStyle BINANCE_DEX_TO_STRING_STYLE = ToStringStyle.SHORT_PREFIX_STYLE;
}

View file

@ -0,0 +1,38 @@
package com.tangem.blockchain.binance.client;
public enum BinanceDexEnvironment {
PROD(
"https://dex.binance.org",
"wss://dex.binance.org/api/",
"bnb"
),
TEST_NET(
"https://testnet-dex.binance.org",
"wss://testnet-dex.binance.org/api/",
"tbnb"
);
// Rest API base URL
private String baseUrl;
// Websocket API base URL
private String wsBaseUrl;
// Address human readable part prefix
private String hrp;
private BinanceDexEnvironment(String baseUrl, String wsBaseUrl, String hrp) {
this.baseUrl = baseUrl;
this.wsBaseUrl = wsBaseUrl;
this.hrp = hrp;
}
public String getBaseUrl() {
return baseUrl;
}
public String getWsBaseUrl() {
return wsBaseUrl;
}
public String getHrp() {
return hrp;
}
}

View file

@ -0,0 +1,167 @@
package com.tangem.blockchain.binance.client;
import com.tangem.blockchain.binance.client.domain.Account;
import com.tangem.blockchain.binance.client.domain.AccountSequence;
import com.tangem.blockchain.binance.client.domain.Infos;
import com.tangem.blockchain.binance.client.encoding.Crypto;
import com.tangem.blockchain.binance.client.encoding.message.MessageType;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.bitcoinj.core.ECKey;
import java.io.IOException;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Wallet {
private final static Map<BinanceDexEnvironment, String> CHAIN_IDS = new HashMap<>();
private String privateKey;
private String address;
private ECKey ecKey;
private byte[] addressBytes;
private byte[] pubKeyForSign;
private Integer accountNumber;
private Long sequence = null;
private BinanceDexEnvironment env;
private String chainId;
public Wallet(String privateKey, BinanceDexEnvironment env) {
if (!StringUtils.isEmpty(privateKey)) {
this.privateKey = privateKey;
this.env = env;
this.ecKey = ECKey.fromPrivate(new BigInteger(privateKey, 16));
this.address = Crypto.getAddressFromECKey(this.ecKey, env.getHrp());
this.addressBytes = Crypto.decodeAddress(this.address);
byte[] pubKey = ecKey.getPubKeyPoint().getEncoded(true);
byte[] pubKeyPrefix = MessageType.PubKey.getTypePrefixBytes();
this.pubKeyForSign = new byte[pubKey.length + pubKeyPrefix.length + 1];
System.arraycopy(pubKeyPrefix, 0, this.pubKeyForSign, 0, pubKeyPrefix.length);
pubKeyForSign[pubKeyPrefix.length] = (byte) 33;
System.arraycopy(pubKey, 0, this.pubKeyForSign, pubKeyPrefix.length + 1, pubKey.length);
} else {
throw new IllegalArgumentException("Private key cannot be empty.");
}
}
public static Wallet createRandomWallet(BinanceDexEnvironment env) throws IOException {
return createWalletFromMnemonicCode(Crypto.generateMnemonicCode(), env);
}
public static Wallet createWalletFromMnemonicCode(List<String> words, BinanceDexEnvironment env) throws IOException {
String privateKey = Crypto.getPrivateKeyFromMnemonicCode(words);
return new Wallet(privateKey, env);
}
public synchronized void initAccount(BinanceDexApiRestClient client) {
Account account = client.getAccount(this.address);
if (account != null) {
this.accountNumber = account.getAccountNumber();
this.sequence = account.getSequence();
} else {
throw new IllegalStateException("Cannot get account information for address " + this.address);
}
}
public synchronized void reloadAccountSequence(BinanceDexApiRestClient client) {
AccountSequence accountSequence = client.getAccountSequence(this.address);
this.sequence = accountSequence.getSequence();
}
public synchronized void increaseAccountSequence() {
if (this.sequence != null)
this.sequence++;
}
public synchronized void decreaseAccountSequence() {
if (this.sequence != null)
this.sequence--;
}
public synchronized long getSequence() {
if (sequence == null)
throw new IllegalStateException("Account sequence is not initialized.");
return sequence;
}
public synchronized void setAccountNumber(Integer accountNumber) {
this.accountNumber = accountNumber;
}
public synchronized void setSequence(Long sequence) {
this.sequence = sequence;
}
public synchronized void setChainId(String chainId) {
this.chainId = chainId;
}
public synchronized void invalidAccountSequence() {
this.sequence = null;
}
public synchronized void ensureWalletIsReady(BinanceDexApiRestClient client) {
if (accountNumber == null) {
initAccount(client);
} else if (sequence == null) {
reloadAccountSequence(client);
}
if (chainId == null) {
chainId = CHAIN_IDS.get(chainId);
if (chainId == null) {
initChainId(client);
}
}
}
public synchronized void initChainId(BinanceDexApiRestClient client) {
Infos info = client.getNodeInfo();
chainId = info.getNodeInfo().getNetwork();
CHAIN_IDS.put(env, chainId);
}
public String getPrivateKey() {
return privateKey;
}
public String getAddress() {
return address;
}
public ECKey getEcKey() {
return ecKey;
}
public byte[] getPubKeyForSign() {
return pubKeyForSign;
}
public int getAccountNumber() {
return accountNumber;
}
public String getChainId() {
return chainId;
}
public byte[] getAddressBytes() {
return addressBytes;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("addressBytes", addressBytes)
.append("address", address)
.append("ecKey", ecKey)
.append("pubKeyForSign", pubKeyForSign)
.append("accountNumber", accountNumber)
.append("sequence", sequence)
.append("chainId", chainId)
.toString();
}
}

View file

@ -0,0 +1,71 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Account {
@JsonProperty("account_number")
private Integer accountNumber;
private String address;
private List<Balance> balances;
@JsonProperty("public_key")
private List<Integer> publicKey;
private Long sequence;
public Integer getAccountNumber() {
return accountNumber;
}
public void setAccountNumber(Integer accountNumber) {
this.accountNumber = accountNumber;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public List<Balance> getBalances() {
return balances;
}
public void setBalances(List<Balance> balances) {
this.balances = balances;
}
public List<Integer> getPublicKey() {
return publicKey;
}
public void setPublicKey(List<Integer> publicKey) {
this.publicKey = publicKey;
}
public Long getSequence() {
return sequence;
}
public void setSequence(Long sequence) {
this.sequence = sequence;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("accountNumber", accountNumber)
.append("address", address)
.append("balances", balances)
.append("publicKey", publicKey)
.append("sequence", sequence)
.toString();
}
}

View file

@ -0,0 +1,26 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
@JsonIgnoreProperties(ignoreUnknown = true)
public class AccountSequence {
private Long sequence;
public Long getSequence() {
return sequence;
}
public void setSequence(Long sequence) {
this.sequence = sequence;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("sequence", sequence)
.toString();
}
}

View file

@ -0,0 +1,56 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Balance {
private String symbol;
private String free;
private String locked;
private String frozen;
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public String getFree() {
return free;
}
public void setFree(String free) {
this.free = free;
}
public String getLocked() {
return locked;
}
public void setLocked(String locked) {
this.locked = locked;
}
public String getFrozen() {
return frozen;
}
public void setFrozen(String frozen) {
this.frozen = frozen;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("symbol", symbol)
.append("free", free)
.append("locked", locked)
.append("frozen", frozen)
.toString();
}
}

View file

@ -0,0 +1,122 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
/**
* Kline/Candlestick bars for a symbol. Klines are uniquely identified by their open time.
*/
@JsonFormat(shape = JsonFormat.Shape.ARRAY)
@JsonPropertyOrder()
@JsonIgnoreProperties(ignoreUnknown = true)
public class Candlestick {
private Long openTime;
private String open;
private String high;
private String low;
private String close;
private String volume;
private Long closeTime;
private String quoteAssetVolume;
private Long numberOfTrades;
public Long getOpenTime() {
return openTime;
}
public void setOpenTime(Long openTime) {
this.openTime = openTime;
}
public String getOpen() {
return open;
}
public void setOpen(String open) {
this.open = open;
}
public String getHigh() {
return high;
}
public void setHigh(String high) {
this.high = high;
}
public String getLow() {
return low;
}
public void setLow(String low) {
this.low = low;
}
public String getClose() {
return close;
}
public void setClose(String close) {
this.close = close;
}
public String getVolume() {
return volume;
}
public void setVolume(String volume) {
this.volume = volume;
}
public Long getCloseTime() {
return closeTime;
}
public void setCloseTime(Long closeTime) {
this.closeTime = closeTime;
}
public String getQuoteAssetVolume() {
return quoteAssetVolume;
}
public void setQuoteAssetVolume(String quoteAssetVolume) {
this.quoteAssetVolume = quoteAssetVolume;
}
public Long getNumberOfTrades() {
return numberOfTrades;
}
public void setNumberOfTrades(Long numberOfTrades) {
this.numberOfTrades = numberOfTrades;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("openTime", openTime)
.append("open", open)
.append("high", high)
.append("low", low)
.append("close", close)
.append("volume", volume)
.append("closeTime", closeTime)
.append("quoteAssetVolume", quoteAssetVolume)
.append("numberOfTrades", numberOfTrades)
.toString();
}
}

View file

@ -0,0 +1,49 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
/**
* Kline/Candlestick intervals.
* m -> minutes; h -> hours; d -> days; w -> weeks; M -> months
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public enum CandlestickInterval {
ONE_MINUTE("1m"),
THREE_MINUTES("3m"),
FIVE_MINUTES("5m"),
FIFTEEN_MINUTES("15m"),
HALF_HOURLY("30m"),
HOURLY("1h"),
TWO_HOURLY("2h"),
FOUR_HOURLY("4h"),
SIX_HOURLY("6h"),
EIGHT_HOURLY("8h"),
TWELVE_HOURLY("12h"),
DAILY("1d"),
THREE_DAILY("3d"),
WEEKLY("1w"),
MONTHLY("1M");
private final String intervalId;
CandlestickInterval(String intervalId) {
this.intervalId = intervalId;
}
public String getIntervalId() {
return intervalId;
}
public static CandlestickInterval fromIntervalId(String intervalId) {
if (intervalId == null) {
throw new IllegalArgumentException("Null interval id");
}
String id = intervalId.toLowerCase();
for (CandlestickInterval interval : values()) {
if (id.equals(interval.getIntervalId())) {
return interval;
}
}
throw new IllegalArgumentException("Unknown interval id: " + intervalId);
}
}

View file

@ -0,0 +1,50 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Infos {
@JsonProperty("node_info")
private NodeInfo nodeInfo;
@JsonProperty("sync_info")
private SyncInfo syncInfo;
@JsonProperty("validator_info")
private ValidatorInfo validatorInfo;
public NodeInfo getNodeInfo() {
return nodeInfo;
}
public void setNodeInfo(NodeInfo nodeInfo) {
this.nodeInfo = nodeInfo;
}
public SyncInfo getSyncInfo() {
return syncInfo;
}
public void setSyncInfo(SyncInfo syncInfo) {
this.syncInfo = syncInfo;
}
public ValidatorInfo getValidatorInfo() {
return validatorInfo;
}
public void setValidatorInfo(ValidatorInfo validatorInfo) {
this.validatorInfo = validatorInfo;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("nodeInfo", nodeInfo)
.append("syncInfo", syncInfo)
.append("validatorInfo", validatorInfo)
.toString();
}
}

View file

@ -0,0 +1,72 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Market {
public String baseAssetSymbol;
public String quoteAssetSymbol;
public String price;
public String tickSize;
public String lotSize;
@JsonProperty("base_asset_symbol")
public String getBaseAssetSymbol() {
return baseAssetSymbol;
}
public void setBaseAssetSymbol(String baseAssetSymbol) {
this.baseAssetSymbol = baseAssetSymbol;
}
@JsonProperty("quote_asset_symbol")
public String getQuoteAssetSymbol() {
return quoteAssetSymbol;
}
public void setQuoteAssetSymbol(String quoteAssetSymbol) {
this.quoteAssetSymbol = quoteAssetSymbol;
}
@JsonProperty("price")
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
@JsonProperty("tick_size")
public String getTickSize() {
return tickSize;
}
public void setTickSize(String tickSize) {
this.tickSize = tickSize;
}
@JsonProperty("lot_size")
public String getLotSize() {
return lotSize;
}
public void setLotSize(String lotSize) {
this.lotSize = lotSize;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("baseAssetSymbol", baseAssetSymbol)
.append("quoteAssetSymbol", quoteAssetSymbol)
.append("price", price)
.append("tickSize", tickSize)
.append("lotSize", lotSize)
.toString();
}
}

View file

@ -0,0 +1,90 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.util.Map;
@JsonIgnoreProperties(ignoreUnknown = true)
public class NodeInfo {
private String id;
@JsonProperty("listen_addr")
private String listenAddr;
private String network;
private String version;
private String channels;
private String moniker;
private Map<String, Object> other;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getListenAddr() {
return listenAddr;
}
public void setListenAddr(String listenAddr) {
this.listenAddr = listenAddr;
}
public String getNetwork() {
return network;
}
public void setNetwork(String network) {
this.network = network;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getChannels() {
return channels;
}
public void setChannels(String channels) {
this.channels = channels;
}
public String getMoniker() {
return moniker;
}
public void setMoniker(String moniker) {
this.moniker = moniker;
}
public Map<String, Object> getOther() {
return other;
}
public void setOther(Map<String, Object> other) {
this.other = other;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("id", id)
.append("listenAddr", listenAddr)
.append("network", network)
.append("version", version)
.append("channels", channels)
.append("moniker", moniker)
.append("other", other)
.toString();
}
}

View file

@ -0,0 +1,187 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.joda.time.DateTime;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Order {
private String orderId;
private String symbol;
private String owner;
private String price;
private String quantity;
private String cumulateQuantity;
private String fee;
private DateTime orderCreateTime;
private DateTime transactionTime;
private OrderStatus status;
private TimeInForce timeInForce;
private OrderSide side;
private OrderType type;
private String tradeId;
private String lastExecutedPrice;
private String lastExecutedQuantity;
private String transactionHash;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getQuantity() {
return quantity;
}
public void setQuantity(String quantity) {
this.quantity = quantity;
}
public String getCumulateQuantity() {
return cumulateQuantity;
}
public void setCumulateQuantity(String cumulateQuantity) {
this.cumulateQuantity = cumulateQuantity;
}
public String getFee() {
return fee;
}
public void setFee(String fee) {
this.fee = fee;
}
public DateTime getOrderCreateTime() {
return orderCreateTime;
}
public void setOrderCreateTime(DateTime orderCreateTime) {
this.orderCreateTime = orderCreateTime;
}
public DateTime getTransactionTime() {
return transactionTime;
}
public void setTransactionTime(DateTime transactionTime) {
this.transactionTime = transactionTime;
}
public OrderStatus getStatus() {
return status;
}
public void setStatus(OrderStatus status) {
this.status = status;
}
public TimeInForce getTimeInForce() {
return timeInForce;
}
public void setTimeInForce(TimeInForce timeInForce) {
this.timeInForce = timeInForce;
}
public OrderSide getSide() {
return side;
}
public void setSide(OrderSide side) {
this.side = side;
}
public OrderType getType() {
return type;
}
public void setType(OrderType type) {
this.type = type;
}
public String getTradeId() {
return tradeId;
}
public void setTradeId(String tradeId) {
this.tradeId = tradeId;
}
public String getLastExecutedPrice() {
return lastExecutedPrice;
}
public void setLastExecutedPrice(String lastExecutedPrice) {
this.lastExecutedPrice = lastExecutedPrice;
}
public String getLastExecutedQuantity() {
return lastExecutedQuantity;
}
public void setLastExecutedQuantity(String lastExecutedQuantity) {
this.lastExecutedQuantity = lastExecutedQuantity;
}
public String getTransactionHash() {
return transactionHash;
}
public void setTransactionHash(String transactionHash) {
this.transactionHash = transactionHash;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("orderId", orderId)
.append("symbol", symbol)
.append("owner", owner)
.append("price", price)
.append("quantity", quantity)
.append("cumulateQuantity", cumulateQuantity)
.append("fee", fee)
.append("orderCreateTime", orderCreateTime)
.append("transactionTime", transactionTime)
.append("status", status)
.append("timeInForce", timeInForce)
.append("side", side)
.append("type", type)
.append("tradeId", tradeId)
.append("lastExecutedPrice", lastExecutedPrice)
.append("lastExecutedQuantity", lastExecutedQuantity)
.append("transactionHash", transactionHash)
.toString();
}
}

View file

@ -0,0 +1,48 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public class OrderBook {
private List<OrderBookEntry> asks;
private List<OrderBookEntry> bids;
private long height;
public List<OrderBookEntry> getAsks() {
return asks;
}
public void setAsks(List<OrderBookEntry> asks) {
this.asks = asks;
}
public List<OrderBookEntry> getBids() {
return bids;
}
public void setBids(List<OrderBookEntry> bids) {
this.bids = bids;
}
public long getHeight() {
return height;
}
public void setHeight(long height) {
this.height = height;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("asks", asks)
.append("bids", bids)
.append("height", height)
.toString();
}
}

View file

@ -0,0 +1,40 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
@JsonDeserialize(using = OrderBookEntryDeserializer.class)
@JsonSerialize(using = OrderBookEntrySerializer.class)
@JsonIgnoreProperties(ignoreUnknown = true)
public class OrderBookEntry {
private String price;
private String quantity;
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getQuantity() {
return quantity;
}
public void setQuantity(String quantity) {
this.quantity = quantity;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("price", price)
.append("quantity", quantity)
.toString();
}
}

View file

@ -0,0 +1,24 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import java.io.IOException;
public class OrderBookEntryDeserializer extends JsonDeserializer<OrderBookEntry> {
@Override
public OrderBookEntry deserialize(JsonParser jp, DeserializationContext ctx) throws IOException {
ObjectCodec oc = jp.getCodec();
JsonNode node = oc.readTree(jp);
final String price = node.get(0).asText();
final String qty = node.get(1).asText();
OrderBookEntry orderBookEntry = new OrderBookEntry();
orderBookEntry.setPrice(price);
orderBookEntry.setQuantity(qty);
return orderBookEntry;
}
}

View file

@ -0,0 +1,17 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
public class OrderBookEntrySerializer extends JsonSerializer<OrderBookEntry> {
@Override
public void serialize(OrderBookEntry orderBookEntry, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartArray();
gen.writeString(orderBookEntry.getPrice());
gen.writeString(orderBookEntry.getQuantity());
gen.writeEndArray();
}
}

View file

@ -0,0 +1,38 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public class OrderList {
private List<Order> order;
private Long total;
public List<Order> getOrder() {
return order;
}
public void setOrder(List<Order> order) {
this.order = order;
}
public Long getTotal() {
return total;
}
public void setTotal(Long total) {
this.total = total;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("order", order)
.append("total", total)
.toString();
}
}

View file

@ -0,0 +1,30 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
public enum OrderSide {
BUY(1L), SELL(2L);
private long value;
OrderSide(long value) {
this.value = value;
}
@JsonCreator
public static OrderSide fromValue(long value) {
for (OrderSide os : OrderSide.values()) {
if (os.value == value) {
return os;
}
}
return null;
}
@JsonValue
public long toValue() {
return this.value;
}
}

View file

@ -0,0 +1,11 @@
package com.tangem.blockchain.binance.client.domain;
public enum OrderStatus {
Ack,
PartialFill,
IocNoFill,
FullyFill,
Canceled,
Expired,
Unknown
}

View file

@ -0,0 +1,29 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
public enum OrderType {
LIMIT(2L);
private long value;
OrderType(long value) {
this.value = value;
}
@JsonCreator
public static OrderType fromValue(long value) {
for (OrderType ot : OrderType.values()) {
if (ot.value == value) {
return ot;
}
}
return null;
}
@JsonValue
public long toValue() {
return this.value;
}
}

View file

@ -0,0 +1,112 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Peer {
private Boolean accelerated;
@JsonProperty("access_addr")
private String accessAddress;
private List<String> capabilities;
private String id;
@JsonProperty("listen_addr")
private String listenAddress;
private String moniker;
private String network;
@JsonProperty("stream_addr")
private String streamAddress;
private String version;
public Boolean getAccelerated() {
return accelerated;
}
public void setAccelerated(Boolean accelerated) {
this.accelerated = accelerated;
}
public String getAccessAddress() {
return accessAddress;
}
public void setAccessAddress(String accessAddress) {
this.accessAddress = accessAddress;
}
public List<String> getCapabilities() {
return capabilities;
}
public void setCapabilities(List<String> capabilities) {
this.capabilities = capabilities;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getListenAddress() {
return listenAddress;
}
public void setListenAddress(String listenAddress) {
this.listenAddress = listenAddress;
}
public String getMoniker() {
return moniker;
}
public void setMoniker(String moniker) {
this.moniker = moniker;
}
public String getNetwork() {
return network;
}
public void setNetwork(String network) {
this.network = network;
}
public String getStreamAddress() {
return streamAddress;
}
public void setStreamAddress(String streamAddress) {
this.streamAddress = streamAddress;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("accelerated", accelerated)
.append("accessAddress", accessAddress)
.append("capabilities", capabilities)
.append("id", id)
.append("listenAddress", listenAddress)
.append("moniker", moniker)
.append("network", network)
.append("streamAddress", streamAddress)
.append("version", version)
.toString();
}
}

View file

@ -0,0 +1,74 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.joda.time.DateTime;
@JsonIgnoreProperties(ignoreUnknown = true)
public class SyncInfo {
@JsonProperty("latest_block_hash")
private String latestBlockHash;
@JsonProperty("latest_app_hash")
private String latestAppHash;
@JsonProperty("latest_block_height")
private Long latestBlockHeight;
@JsonProperty("latest_block_time")
private DateTime latestBlockTime;
@JsonProperty("catching_up")
private Boolean catchingUp;
public String getLatestBlockHash() {
return latestBlockHash;
}
public void setLatestBlockHash(String latestBlockHash) {
this.latestBlockHash = latestBlockHash;
}
public String getLatestAppHash() {
return latestAppHash;
}
public void setLatestAppHash(String latestAppHash) {
this.latestAppHash = latestAppHash;
}
public Long getLatestBlockHeight() {
return latestBlockHeight;
}
public void setLatestBlockHeight(Long latestBlockHeight) {
this.latestBlockHeight = latestBlockHeight;
}
public DateTime getLatestBlockTime() {
return latestBlockTime;
}
public void setLatestBlockTime(DateTime latestBlockTime) {
this.latestBlockTime = latestBlockTime;
}
public Boolean getCatchingUp() {
return catchingUp;
}
public void setCatchingUp(Boolean catchingUp) {
this.catchingUp = catchingUp;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("latestBlockHash", latestBlockHash)
.append("latestAppHash", latestAppHash)
.append("latestBlockHeight", latestBlockHeight)
.append("latestBlockTime", latestBlockTime)
.append("catchingUp", catchingUp)
.toString();
}
}

View file

@ -0,0 +1,226 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
@JsonIgnoreProperties(ignoreUnknown = true)
public class TickerStatistics {
private String symbol;
private String priceChange;
private String priceChangePercent;
private String prevClosePrice;
private String lastPrice;
private String lastQuantity;
private String openPrice;
private String highPrice;
private String lowPrice;
private Long openTime;
private Long closeTime;
private String firstId;
private String lastId;
private String bidPrice;
private String bidQuantity;
private String askPrice;
private String askQuantity;
private String weightedAvgPrice;
private String volume;
private String quoteVolume;
private Long count;
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public String getPriceChange() {
return priceChange;
}
public void setPriceChange(String priceChange) {
this.priceChange = priceChange;
}
public String getPriceChangePercent() {
return priceChangePercent;
}
public void setPriceChangePercent(String priceChangePercent) {
this.priceChangePercent = priceChangePercent;
}
public String getPrevClosePrice() {
return prevClosePrice;
}
public void setPrevClosePrice(String prevClosePrice) {
this.prevClosePrice = prevClosePrice;
}
public String getLastPrice() {
return lastPrice;
}
public void setLastPrice(String lastPrice) {
this.lastPrice = lastPrice;
}
public String getLastQuantity() {
return lastQuantity;
}
public void setLastQuantity(String lastQuantity) {
this.lastQuantity = lastQuantity;
}
public String getOpenPrice() {
return openPrice;
}
public void setOpenPrice(String openPrice) {
this.openPrice = openPrice;
}
public String getHighPrice() {
return highPrice;
}
public void setHighPrice(String highPrice) {
this.highPrice = highPrice;
}
public String getLowPrice() {
return lowPrice;
}
public void setLowPrice(String lowPrice) {
this.lowPrice = lowPrice;
}
public Long getOpenTime() {
return openTime;
}
public void setOpenTime(Long openTime) {
this.openTime = openTime;
}
public Long getCloseTime() {
return closeTime;
}
public void setCloseTime(Long closeTime) {
this.closeTime = closeTime;
}
public String getFirstId() {
return firstId;
}
public void setFirstId(String firstId) {
this.firstId = firstId;
}
public String getLastId() {
return lastId;
}
public void setLastId(String lastId) {
this.lastId = lastId;
}
public String getBidPrice() {
return bidPrice;
}
public void setBidPrice(String bidPrice) {
this.bidPrice = bidPrice;
}
public String getBidQuantity() {
return bidQuantity;
}
public void setBidQuantity(String bidQuantity) {
this.bidQuantity = bidQuantity;
}
public String getAskPrice() {
return askPrice;
}
public void setAskPrice(String askPrice) {
this.askPrice = askPrice;
}
public String getAskQuantity() {
return askQuantity;
}
public void setAskQuantity(String askQuantity) {
this.askQuantity = askQuantity;
}
public String getWeightedAvgPrice() {
return weightedAvgPrice;
}
public void setWeightedAvgPrice(String weightedAvgPrice) {
this.weightedAvgPrice = weightedAvgPrice;
}
public String getVolume() {
return volume;
}
public void setVolume(String volume) {
this.volume = volume;
}
public String getQuoteVolume() {
return quoteVolume;
}
public void setQuoteVolume(String quoteVolume) {
this.quoteVolume = quoteVolume;
}
public Long getCount() {
return count;
}
public void setCount(Long count) {
this.count = count;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("symbol", symbol)
.append("priceChange", priceChange)
.append("priceChangePercent", priceChangePercent)
.append("prevClosePrice", prevClosePrice)
.append("lastPrice", lastPrice)
.append("lastQuantity", lastQuantity)
.append("openPrice", openPrice)
.append("highPrice", highPrice)
.append("lowPrice", lowPrice)
.append("openTime", openTime)
.append("closeTime", closeTime)
.append("firstId", firstId)
.append("lastId", lastId)
.append("bidPrice", bidPrice)
.append("bidQuantity", bidQuantity)
.append("askPrice", askPrice)
.append("askQuantity", askQuantity)
.append("weightedAvgPrice", weightedAvgPrice)
.append("volume", volume)
.append("quoteVolume", quoteVolume)
.append("count", count)
.toString();
}
}

View file

@ -0,0 +1,40 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.joda.time.DateTime;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Time {
@JsonProperty("ap_time")
private DateTime apTime;
@JsonProperty("block_time")
private DateTime blockTime;
public DateTime getApTime() {
return apTime;
}
public void setApTime(DateTime apTime) {
this.apTime = apTime;
}
public DateTime getBlockTime() {
return blockTime;
}
public void setBlockTime(DateTime blockTime) {
this.blockTime = blockTime;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("apTime", apTime)
.append("blockTime", blockTime)
.toString();
}
}

View file

@ -0,0 +1,29 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
public enum TimeInForce {
GTE(1L), IOC(3L);
private long value;
TimeInForce(long value) {
this.value = value;
}
@JsonCreator
public static TimeInForce fromValue(long value) {
for (TimeInForce tif : TimeInForce.values()) {
if (tif.value == value) {
return tif;
}
}
return null;
}
@JsonValue
public long toValue() {
return this.value;
}
}

View file

@ -0,0 +1,79 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Token {
private String name;
private String symbol;
@JsonProperty("original_symbol")
private String originalSymbol;
@JsonProperty("total_supply")
private String totalSupply;
private String owner;
private boolean mintable;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public String getOriginalSymbol() {
return originalSymbol;
}
public void setOriginalSymbol(String originalSymbol) {
this.originalSymbol = originalSymbol;
}
public String getTotalSupply() {
return totalSupply;
}
public void setTotalSupply(String totalSupply) {
this.totalSupply = totalSupply;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public boolean isMintable() {
return mintable;
}
public void setMintable(boolean mintable) {
this.mintable = mintable;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("name", name)
.append("symbol", symbol)
.append("originalSymbol", originalSymbol)
.append("totalSupply", totalSupply)
.append("owner", owner)
.append("mintable", mintable)
.toString();
}
}

View file

@ -0,0 +1,156 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Trade {
private String baseAsset;
private Long blockHeight;
private String buyFee;
private String buyerId;
private String buyerOrderId;
private String price;
private String quantity;
private String quoteAsset;
private String sellFee;
private String sellerId;
private String sellerOrderId;
private String symbol;
private Long time;
private String tradeId;
public String getBaseAsset() {
return baseAsset;
}
public void setBaseAsset(String baseAsset) {
this.baseAsset = baseAsset;
}
public Long getBlockHeight() {
return blockHeight;
}
public void setBlockHeight(Long blockHeight) {
this.blockHeight = blockHeight;
}
public String getBuyFee() {
return buyFee;
}
public void setBuyFee(String buyFee) {
this.buyFee = buyFee;
}
public String getBuyerId() {
return buyerId;
}
public void setBuyerId(String buyerId) {
this.buyerId = buyerId;
}
public String getBuyerOrderId() {
return buyerOrderId;
}
public void setBuyerOrderId(String buyerOrderId) {
this.buyerOrderId = buyerOrderId;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getQuantity() {
return quantity;
}
public void setQuantity(String quantity) {
this.quantity = quantity;
}
public String getQuoteAsset() {
return quoteAsset;
}
public void setQuoteAsset(String quoteAsset) {
this.quoteAsset = quoteAsset;
}
public String getSellFee() {
return sellFee;
}
public void setSellFee(String sellFee) {
this.sellFee = sellFee;
}
public String getSellerId() {
return sellerId;
}
public void setSellerId(String sellerId) {
this.sellerId = sellerId;
}
public String getSellerOrderId() {
return sellerOrderId;
}
public void setSellerOrderId(String sellerOrderId) {
this.sellerOrderId = sellerOrderId;
}
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public Long getTime() {
return time;
}
public void setTime(Long time) {
this.time = time;
}
public String getTradeId() {
return tradeId;
}
public void setTradeId(String tradeId) {
this.tradeId = tradeId;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("baseAsset", baseAsset)
.append("blockHeight", blockHeight)
.append("buyFee", buyFee)
.append("buyerId", buyerId)
.append("buyerOrderId", buyerOrderId)
.append("price", price)
.append("quantity", quantity)
.append("quoteAsset", quoteAsset)
.append("sellFee", sellFee)
.append("sellerId", sellerId)
.append("sellerOrderId", sellerOrderId)
.append("symbol", symbol)
.append("time", time)
.append("tradeId", tradeId)
.toString();
}
}

View file

@ -0,0 +1,38 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public class TradePage {
private Long total;
private List<Trade> trade;
public Long getTotal() {
return total;
}
public void setTotal(Long total) {
this.total = total;
}
public List<Trade> getTrade() {
return trade;
}
public void setTrade(List<Trade> trade) {
this.trade = trade;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("total", total)
.append("trade", trade)
.toString();
}
}

View file

@ -0,0 +1,8 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public class TradeStatistics {
}

View file

@ -0,0 +1,157 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Transaction {
private Long blockHeight;
private Integer code;
private Long confirmBlocks;
private String data;
private String fromAddr;
private String orderId;
private String timeStamp;
private String toAddr;
private Long txAge;
private String txAsset;
private String txFee;
private String txHash;
private String txType;
private String value;
public Long getBlockHeight() {
return blockHeight;
}
public void setBlockHeight(Long blockHeight) {
this.blockHeight = blockHeight;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public Long getConfirmBlocks() {
return confirmBlocks;
}
public void setConfirmBlocks(Long confirmBlocks) {
this.confirmBlocks = confirmBlocks;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public String getFromAddr() {
return fromAddr;
}
public void setFromAddr(String fromAddr) {
this.fromAddr = fromAddr;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getTimeStamp() {
return timeStamp;
}
public void setTimeStamp(String timeStamp) {
this.timeStamp = timeStamp;
}
public String getToAddr() {
return toAddr;
}
public void setToAddr(String toAddr) {
this.toAddr = toAddr;
}
public Long getTxAge() {
return txAge;
}
public void setTxAge(Long txAge) {
this.txAge = txAge;
}
public String getTxAsset() {
return txAsset;
}
public void setTxAsset(String txAsset) {
this.txAsset = txAsset;
}
public String getTxFee() {
return txFee;
}
public void setTxFee(String txFee) {
this.txFee = txFee;
}
public String getTxHash() {
return txHash;
}
public void setTxHash(String txHash) {
this.txHash = txHash;
}
public String getTxType() {
return txType;
}
public void setTxType(String txType) {
this.txType = txType;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("blockHeight", blockHeight)
.append("code", code)
.append("confirmBlocks", confirmBlocks)
.append("data", data)
.append("fromAddr", fromAddr)
.append("orderId", orderId)
.append("timeStamp", timeStamp)
.append("toAddr", toAddr)
.append("txAge", txAge)
.append("txAsset", txAsset)
.append("txFee", txFee)
.append("txHash", txHash)
.append("txType", txType)
.append("value", value)
.toString();
}
}

View file

@ -0,0 +1,46 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
@JsonIgnoreProperties(ignoreUnknown = true)
public class TransactionMetadata {
private int code;
private String data;
private String hash;
private String log;
private boolean ok;
public int getCode() {
return code;
}
public String getData() {
return data;
}
public String getHash() {
return hash;
}
public String getLog() {
return log;
}
public boolean isOk() {
return ok;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("code", code)
.append("data", data)
.append("hash", hash)
.append("log", log)
.append("ok", ok)
.toString();
}
}

View file

@ -0,0 +1,38 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public class TransactionPage {
private Long total;
private List<Transaction> tx;
public Long getTotal() {
return total;
}
public void setTotal(Long total) {
this.total = total;
}
public List<Transaction> getTx() {
return tx;
}
public void setTx(List<Transaction> tx) {
this.tx = tx;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("total", total)
.append("tx", tx)
.toString();
}
}

View file

@ -0,0 +1,14 @@
package com.tangem.blockchain.binance.client.domain;
public enum TransactionType {
NEW_ORDER,
ISSUE_TOKEN,
BURN_TOKEN,
LIST_TOKEN,
CANCEL_ORDER,
FREEZE_TOKEN,
UN_FREEZE_TOKEN,
TRANSFER,
PROPOSAL,
VOTE;
}

View file

@ -0,0 +1,51 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ValidatorInfo {
private String address;
@JsonProperty("pub_key")
private List<Integer> pubKey;
@JsonProperty("voting_power")
private Long votingPower;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public List<Integer> getPubKey() {
return pubKey;
}
public void setPubKey(List<Integer> pubKey) {
this.pubKey = pubKey;
}
public Long getVotingPower() {
return votingPower;
}
public void setVotingPower(Long votingPower) {
this.votingPower = votingPower;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("address", address)
.append("pubKey", pubKey)
.append("votingPower", votingPower)
.toString();
}
}

View file

@ -0,0 +1,40 @@
package com.tangem.blockchain.binance.client.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public class Validators {
@JsonProperty("block_height")
private Long blockHeight;
private List<ValidatorInfo> validators;
public Long getBlockHeight() {
return blockHeight;
}
public void setBlockHeight(Long blockHeight) {
this.blockHeight = blockHeight;
}
public List<ValidatorInfo> getValidators() {
return validators;
}
public void setValidators(List<ValidatorInfo> validators) {
this.validators = validators;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("blockHeight", blockHeight)
.append("validators", validators)
.toString();
}
}

View file

@ -0,0 +1,36 @@
package com.tangem.blockchain.binance.client.domain.broadcast;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
public class CancelOrder {
private String symbol;
@JsonProperty("refid")
private String refId;
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public String getRefId() {
return refId;
}
public void setRefId(String refId) {
this.refId = refId;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("symbol", symbol)
.append("refId", refId)
.toString();
}
}

View file

@ -0,0 +1,77 @@
package com.tangem.blockchain.binance.client.domain.broadcast;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import com.tangem.blockchain.binance.client.domain.OrderSide;
import com.tangem.blockchain.binance.client.domain.OrderType;
import com.tangem.blockchain.binance.client.domain.TimeInForce;
import org.apache.commons.lang3.builder.ToStringBuilder;
public class NewOrder {
private String symbol;
private OrderType orderType;
private OrderSide side;
private String price;
private String quantity;
private TimeInForce timeInForce;
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public OrderType getOrderType() {
return orderType;
}
public void setOrderType(OrderType orderType) {
this.orderType = orderType;
}
public OrderSide getSide() {
return side;
}
public void setSide(OrderSide side) {
this.side = side;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getQuantity() {
return quantity;
}
public void setQuantity(String quantity) {
this.quantity = quantity;
}
public TimeInForce getTimeInForce() {
return timeInForce;
}
public void setTimeInForce(TimeInForce timeInForce) {
this.timeInForce = timeInForce;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("symbol", symbol)
.append("orderType", orderType)
.append("side", side)
.append("price", price)
.append("quantity", quantity)
.append("timeInForce", timeInForce)
.toString();
}
}

View file

@ -0,0 +1,34 @@
package com.tangem.blockchain.binance.client.domain.broadcast;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
public class TokenFreeze {
private String symbol;
private String amount;
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public String getAmount() {
return amount;
}
public void setAmount(String amount) {
this.amount = amount;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("symbol", symbol)
.append("amount", amount)
.toString();
}
}

View file

@ -0,0 +1,34 @@
package com.tangem.blockchain.binance.client.domain.broadcast;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
public class TokenUnfreeze {
private String symbol;
private String amount;
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public String getAmount() {
return amount;
}
public void setAmount(String amount) {
this.amount = amount;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("symbol", symbol)
.append("amount", amount)
.toString();
}
}

View file

@ -0,0 +1,58 @@
package com.tangem.blockchain.binance.client.domain.broadcast;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
/**
* Optional fields for Bianace DEX standard transaction
*/
public class TransactionOption {
public static final TransactionOption DEFAULT_INSTANCE =
new TransactionOption("", BinanceDexConstants.BINANCE_DEX_API_CLIENT_JAVA_SOURCE, null);
private String memo;
private long source;
private byte[] data;
public TransactionOption(String memo, long source, byte[] data) {
this.memo = memo;
this.source = source;
this.data = data;
}
public String getMemo() {
return memo;
}
public void setMemo(String memo) {
this.memo = memo;
}
public long getSource() {
return source;
}
public void setSource(long source) {
this.source = source;
}
public byte[] getData() {
return data;
}
public void setData(byte[] data) {
this.data = data;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("memo", memo)
.append("source", source)
.append("data", data)
.toString();
}
}

View file

@ -0,0 +1,54 @@
package com.tangem.blockchain.binance.client.domain.broadcast;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
public class Transfer {
private String fromAddress;
private String toAddress;
private String coin;
private String amount;
public String getFromAddress() {
return fromAddress;
}
public void setFromAddress(String fromAddress) {
this.fromAddress = fromAddress;
}
public String getToAddress() {
return toAddress;
}
public void setToAddress(String toAddress) {
this.toAddress = toAddress;
}
public String getCoin() {
return coin;
}
public void setCoin(String coin) {
this.coin = coin;
}
public String getAmount() {
return amount;
}
public void setAmount(String amount) {
this.amount = amount;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("fromAddress", fromAddress)
.append("toAddress", toAddress)
.append("coin", coin)
.append("amount", amount)
.toString();
}
}

View file

@ -0,0 +1,108 @@
package com.tangem.blockchain.binance.client.domain.request;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import com.tangem.blockchain.binance.client.domain.OrderSide;
import com.tangem.blockchain.binance.client.domain.OrderStatus;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.util.List;
public class ClosedOrdersRequest {
private String address;
private Long end;
private Integer limit;
private Integer offset;
private OrderSide side;
private Long start;
private List<OrderStatus> status;
private String symbol;
private Integer total;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Long getEnd() {
return end;
}
public void setEnd(Long end) {
this.end = end;
}
public Integer getLimit() {
return limit;
}
public void setLimit(Integer limit) {
this.limit = limit;
}
public Integer getOffset() {
return offset;
}
public void setOffset(Integer offset) {
this.offset = offset;
}
public OrderSide getSide() {
return side;
}
public void setSide(OrderSide side) {
this.side = side;
}
public Long getStart() {
return start;
}
public void setStart(Long start) {
this.start = start;
}
public List<OrderStatus> getStatus() {
return status;
}
public void setStatus(List<OrderStatus> status) {
this.status = status;
}
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public Integer getTotal() {
return total;
}
public void setTotal(Integer total) {
this.total = total;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("address", address)
.append("end", end)
.append("limit", limit)
.append("offset", offset)
.append("side", side)
.append("start", start)
.append("status", status)
.append("symbol", symbol)
.append("total", total)
.toString();
}
}

View file

@ -0,0 +1,64 @@
package com.tangem.blockchain.binance.client.domain.request;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
public class OpenOrdersRequest {
private String address;
private Integer limit;
private Integer offset;
private String symbol;
private Integer total;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Integer getLimit() {
return limit;
}
public void setLimit(Integer limit) {
this.limit = limit;
}
public Integer getOffset() {
return offset;
}
public void setOffset(Integer offset) {
this.offset = offset;
}
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public Integer getTotal() {
return total;
}
public void setTotal(Integer total) {
this.total = total;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("address", address)
.append("limit", limit)
.append("offset", offset)
.append("symbol", symbol)
.append("total", total)
.toString();
}
}

View file

@ -0,0 +1,135 @@
package com.tangem.blockchain.binance.client.domain.request;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import com.tangem.blockchain.binance.client.domain.OrderSide;
import org.apache.commons.lang3.builder.ToStringBuilder;
public class TradesRequest {
private String address;
private String buyerOrderId;
private Long end;
private Long height;
private Integer limit;
private Integer offset;
private String quoteAsset;
private String sellerOrderId;
private OrderSide side;
private Long start;
private String symbol;
private Integer total;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getBuyerOrderId() {
return buyerOrderId;
}
public void setBuyerOrderId(String buyerOrderId) {
this.buyerOrderId = buyerOrderId;
}
public Long getEnd() {
return end;
}
public void setEnd(Long end) {
this.end = end;
}
public Long getHeight() {
return height;
}
public void setHeight(Long height) {
this.height = height;
}
public Integer getLimit() {
return limit;
}
public void setLimit(Integer limit) {
this.limit = limit;
}
public Integer getOffset() {
return offset;
}
public void setOffset(Integer offset) {
this.offset = offset;
}
public String getQuoteAsset() {
return quoteAsset;
}
public void setQuoteAsset(String quoteAsset) {
this.quoteAsset = quoteAsset;
}
public String getSellerOrderId() {
return sellerOrderId;
}
public void setSellerOrderId(String sellerOrderId) {
this.sellerOrderId = sellerOrderId;
}
public OrderSide getSide() {
return side;
}
public void setSide(OrderSide side) {
this.side = side;
}
public Long getStart() {
return start;
}
public void setStart(Long start) {
this.start = start;
}
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public Integer getTotal() {
return total;
}
public void setTotal(Integer total) {
this.total = total;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("address", address)
.append("buyerOrderId", buyerOrderId)
.append("end", end)
.append("height", height)
.append("limit", limit)
.append("offset", offset)
.append("quoteAsset", quoteAsset)
.append("sellerOrderId", sellerOrderId)
.append("side", side)
.append("start", start)
.append("symbol", symbol)
.append("total", total)
.toString();
}
}

View file

@ -0,0 +1,106 @@
package com.tangem.blockchain.binance.client.domain.request;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import com.tangem.blockchain.binance.client.domain.OrderSide;
import com.tangem.blockchain.binance.client.domain.TransactionType;
import org.apache.commons.lang3.builder.ToStringBuilder;
public class TransactionsRequest {
private String address;
private Long blockHeight;
private Long endTime;
private Integer limit;
private Integer offset;
private OrderSide side;
private Long startTime;
private String txAsset;
private TransactionType txType;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Long getBlockHeight() {
return blockHeight;
}
public void setBlockHeight(Long blockHeight) {
this.blockHeight = blockHeight;
}
public Long getEndTime() {
return endTime;
}
public void setEndTime(Long endTime) {
this.endTime = endTime;
}
public Integer getLimit() {
return limit;
}
public void setLimit(Integer limit) {
this.limit = limit;
}
public Integer getOffset() {
return offset;
}
public void setOffset(Integer offset) {
this.offset = offset;
}
public OrderSide getSide() {
return side;
}
public void setSide(OrderSide side) {
this.side = side;
}
public Long getStartTime() {
return startTime;
}
public void setStartTime(Long startTime) {
this.startTime = startTime;
}
public String getTxAsset() {
return txAsset;
}
public void setTxAsset(String txAsset) {
this.txAsset = txAsset;
}
public TransactionType getTxType() {
return txType;
}
public void setTxType(TransactionType txType) {
this.txType = txType;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("address", address)
.append("blockHeight", blockHeight)
.append("endTime", endTime)
.append("limit", limit)
.append("offset", offset)
.append("side", side)
.append("startTime", startTime)
.append("txAsset", txAsset)
.append("txType", txType)
.toString();
}
}

View file

@ -0,0 +1,109 @@
/*
* Copyright 2011 Google Inc.
* Copyright 2015 Andreas Schildbach
*
* 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.blockchain.binance.client.encoding;
import org.bitcoinj.core.Base58;
@SuppressWarnings("serial")
// TODO: Copied from https://github.com/bitcoinj/bitcoinj. Remove these files after they are included in a new bitconj release
public class AddressFormatException extends IllegalArgumentException {
public AddressFormatException() {
super();
}
public AddressFormatException(String message) {
super(message);
}
/**
* This exception is thrown by {@link Base58}, {@link Bech32} and the {@link PrefixedChecksummedBytes} hierarchy of
* classes when you try to decode data and a character isn't valid. You shouldn't allow the user to proceed in this
* case.
*/
public static class InvalidCharacter extends AddressFormatException {
public final char character;
public final int position;
public InvalidCharacter(char character, int position) {
super("Invalid character '" + Character.toString(character) + "' at position " + position);
this.character = character;
this.position = position;
}
}
/**
* This exception is thrown by {@link Base58}, {@link Bech32} and the {@link PrefixedChecksummedBytes} hierarchy of
* classes when you try to decode data and the data isn't of the right size. You shouldn't allow the user to proceed
* in this case.
*/
public static class InvalidDataLength extends AddressFormatException {
public InvalidDataLength() {
super();
}
public InvalidDataLength(String message) {
super(message);
}
}
/**
* This exception is thrown by {@link Base58}, {@link Bech32} and the {@link PrefixedChecksummedBytes} hierarchy of
* classes when you try to decode data and the checksum isn't valid. You shouldn't allow the user to proceed in this
* case.
*/
public static class InvalidChecksum extends AddressFormatException {
public InvalidChecksum() {
super("Checksum does not validate");
}
public InvalidChecksum(String message) {
super(message);
}
}
/**
* This exception is thrown by the {@link PrefixedChecksummedBytes} hierarchy of classes when you try and decode an
* address or private key with an invalid prefix (version header or human-readable part). You shouldn't allow the
* user to proceed in this case.
*/
public static class InvalidPrefix extends AddressFormatException {
public InvalidPrefix() {
super();
}
public InvalidPrefix(String message) {
super(message);
}
}
/**
* This exception is thrown by the {@link PrefixedChecksummedBytes} hierarchy of classes when you try and decode an
* address with a prefix (version header or human-readable part) that used by another network (usually: mainnet vs
* testnet). You shouldn't allow the user to proceed in this case as they are trying to send money across different
* chains, an operation that is guaranteed to destroy the money.
*/
public static class WrongNetwork extends InvalidPrefix {
public WrongNetwork(int versionHeader) {
super("Version code of address did not match acceptable versions for network: " + versionHeader);
}
public WrongNetwork(String hrp) {
super("Human readable part of address did not match acceptable HRPs for network: " + hrp);
}
}
}

View file

@ -0,0 +1,187 @@
/*
* Copyright 2018 Coinomi Ltd
*
* 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.blockchain.binance.client.encoding;
import java.util.Arrays;
import java.util.Locale;
import static com.google.common.base.Preconditions.checkArgument;
// TODO: Copied from https://github.com/bitcoinj/bitcoinj. Remove these files after they are included in a new bitconj release
public class Bech32 {
/**
* The io.nayuki.bitcoin.crypto.Bech32 character set for encoding.
*/
private static final String CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
/**
* The io.nayuki.bitcoin.crypto.Bech32 character set for decoding.
*/
private static final byte[] CHARSET_REV = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
};
public static class Bech32Data {
final String hrp;
final byte[] data;
private Bech32Data(final String hrp, final byte[] data) {
this.hrp = hrp;
this.data = data;
}
public String getHrp() {
return hrp;
}
public byte[] getData() {
return data;
}
}
/**
* Find the polynomial with value coefficients mod the generator as 30-bit.
*/
private static int polymod(final byte[] values) {
int c = 1;
for (byte v_i : values) {
int c0 = (c >>> 25) & 0xff;
c = ((c & 0x1ffffff) << 5) ^ (v_i & 0xff);
if ((c0 & 1) != 0) c ^= 0x3b6a57b2;
if ((c0 & 2) != 0) c ^= 0x26508e6d;
if ((c0 & 4) != 0) c ^= 0x1ea119fa;
if ((c0 & 8) != 0) c ^= 0x3d4233dd;
if ((c0 & 16) != 0) c ^= 0x2a1462b3;
}
return c;
}
/**
* Expand a HRP for use in checksum computation.
*/
private static byte[] expandHrp(final String hrp) {
int hrpLength = hrp.length();
byte ret[] = new byte[hrpLength * 2 + 1];
for (int i = 0; i < hrpLength; ++i) {
int c = hrp.charAt(i) & 0x7f; // Limit to standard 7-bit ASCII
ret[i] = (byte) ((c >>> 5) & 0x07);
ret[i + hrpLength + 1] = (byte) (c & 0x1f);
}
ret[hrpLength] = 0;
return ret;
}
/**
* Verify a checksum.
*/
private static boolean verifyChecksum(final String hrp, final byte[] values) {
byte[] hrpExpanded = expandHrp(hrp);
byte[] combined = new byte[hrpExpanded.length + values.length];
System.arraycopy(hrpExpanded, 0, combined, 0, hrpExpanded.length);
System.arraycopy(values, 0, combined, hrpExpanded.length, values.length);
return polymod(combined) == 1;
}
/**
* Create a checksum.
*/
private static byte[] createChecksum(final String hrp, final byte[] values) {
byte[] hrpExpanded = expandHrp(hrp);
byte[] enc = new byte[hrpExpanded.length + values.length + 6];
System.arraycopy(hrpExpanded, 0, enc, 0, hrpExpanded.length);
System.arraycopy(values, 0, enc, hrpExpanded.length, values.length);
int mod = polymod(enc) ^ 1;
byte[] ret = new byte[6];
for (int i = 0; i < 6; ++i) {
ret[i] = (byte) ((mod >>> (5 * (5 - i))) & 31);
}
return ret;
}
/**
* Encode a io.nayuki.bitcoin.crypto.Bech32 string.
*/
public static String encode(final Bech32Data bech32) {
return encode(bech32.hrp, bech32.data);
}
/**
* Encode a io.nayuki.bitcoin.crypto.Bech32 string.
*/
public static String encode(String hrp, final byte[] values) {
checkArgument(hrp.length() >= 1, "Human-readable part is too short");
checkArgument(hrp.length() <= 83, "Human-readable part is too long");
hrp = hrp.toLowerCase(Locale.ROOT);
byte[] checksum = createChecksum(hrp, values);
byte[] combined = new byte[values.length + checksum.length];
System.arraycopy(values, 0, combined, 0, values.length);
System.arraycopy(checksum, 0, combined, values.length, checksum.length);
StringBuilder sb = new StringBuilder(hrp.length() + 1 + combined.length);
sb.append(hrp);
sb.append('1');
for (byte b : combined) {
sb.append(CHARSET.charAt(b));
}
return sb.toString();
}
/**
* Decode a io.nayuki.bitcoin.crypto.Bech32 string.
*/
public static Bech32Data decode(final String str) throws AddressFormatException {
boolean lower = false, upper = false;
if (str.length() < 8)
throw new AddressFormatException.InvalidDataLength("Input too short: " + str.length());
if (str.length() > 90)
throw new AddressFormatException.InvalidDataLength("Input too long: " + str.length());
for (int i = 0; i < str.length(); ++i) {
char c = str.charAt(i);
if (c < 33 || c > 126) throw new AddressFormatException.InvalidCharacter(c, i);
if (c >= 'a' && c <= 'z') {
if (upper)
throw new AddressFormatException.InvalidCharacter(c, i);
lower = true;
}
if (c >= 'A' && c <= 'Z') {
if (lower)
throw new AddressFormatException.InvalidCharacter(c, i);
upper = true;
}
}
final int pos = str.lastIndexOf('1');
if (pos < 1) throw new AddressFormatException.InvalidPrefix("Missing human-readable part");
final int dataPartLength = str.length() - 1 - pos;
if (dataPartLength < 6)
throw new AddressFormatException.InvalidDataLength("Data part too short: " + dataPartLength);
byte[] values = new byte[dataPartLength];
for (int i = 0; i < dataPartLength; ++i) {
char c = str.charAt(i + pos + 1);
if (CHARSET_REV[c] == -1) throw new AddressFormatException.InvalidCharacter(c, i + pos + 1);
values[i] = CHARSET_REV[c];
}
String hrp = str.substring(0, pos).toLowerCase(Locale.ROOT);
if (!verifyChecksum(hrp, values)) throw new AddressFormatException.InvalidChecksum();
return new Bech32Data(hrp, Arrays.copyOfRange(values, 0, values.length - 6));
}
}

View file

@ -0,0 +1,120 @@
package com.tangem.blockchain.binance.client.encoding;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.core.Utils;
import org.bitcoinj.crypto.ChildNumber;
import org.bitcoinj.crypto.DeterministicKey;
import org.bitcoinj.crypto.HDKeyDerivation;
import org.bitcoinj.crypto.HDUtils;
import org.bitcoinj.crypto.MnemonicCode;
import org.bitcoinj.crypto.MnemonicException;
import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.List;
public class Crypto {
private static final String HD_PATH = "44H/714H/0H/0/0";
public static byte[] sign(byte[] msg, String privateKey) throws NoSuchAlgorithmException {
ECKey k = ECKey.fromPrivate(new BigInteger(privateKey, 16));
return sign(msg, k);
}
public static byte[] sign(byte[] msg, ECKey k) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] msgHash = digest.digest(msg);
ECKey.ECDSASignature signature = k.sign(Sha256Hash.wrap(msgHash));
byte[] result = new byte[64];
System.arraycopy(Utils.bigIntegerToBytes(signature.r, 32), 0, result, 0, 32);
System.arraycopy(Utils.bigIntegerToBytes(signature.s, 32), 0, result, 32, 32);
return result;
}
public static byte[] decodeAddress(String address) throws SegwitAddressException {
byte[] dec = Bech32.decode(address).getData();
return convertBits(dec, 0, dec.length, 5, 8, false);
}
public static String getAddressFromPrivateKey(String privateKey, String hrp) {
ECKey ecKey = ECKey.fromPrivate(new BigInteger(privateKey, 16));
return getAddressFromECKey(ecKey, hrp);
}
public static String getAddressFromECKey(ECKey ecKey, String hrp) {
byte[] hash = ecKey.getPubKeyHash();
return Bech32.encode(hrp, convertBits(hash, 0, hash.length, 8, 5, false));
}
public static String getPrivateKeyFromMnemonicCode(List<String> words) {
byte[] seed = MnemonicCode.INSTANCE.toSeed(words, "");
DeterministicKey key = HDKeyDerivation.createMasterPrivateKey(seed);
List<ChildNumber> childNumbers = HDUtils.parsePath(HD_PATH);
for (ChildNumber cn : childNumbers) {
key = HDKeyDerivation.deriveChildKey(key, cn);
}
return key.getPrivateKeyAsHex();
}
public static List<String> generateMnemonicCode() {
byte[] entrophy = new byte[256 / 8];
new SecureRandom().nextBytes(entrophy);
try {
return MnemonicCode.INSTANCE.toMnemonic(entrophy);
} catch (MnemonicException.MnemonicLengthException e) {
return null;
}
}
public static class SegwitAddressException extends IllegalArgumentException {
SegwitAddressException(Exception e) {
super(e);
}
SegwitAddressException(String s) {
super(s);
}
}
/**
* see https://github.com/sipa/bech32/pull/40/files
*/
public static byte[] convertBits(final byte[] in, final int inStart, final int inLen,
final int fromBits, final int toBits, final boolean pad)
throws SegwitAddressException {
int acc = 0;
int bits = 0;
ByteArrayOutputStream out = new ByteArrayOutputStream(64);
final int maxv = (1 << toBits) - 1;
final int max_acc = (1 << (fromBits + toBits - 1)) - 1;
for (int i = 0; i < inLen; i++) {
int value = in[i + inStart] & 0xff;
if ((value >>> fromBits) != 0) {
throw new SegwitAddressException(String.format(
"Input value '%X' exceeds '%d' bit size", value, fromBits));
}
acc = ((acc << fromBits) | value) & max_acc;
bits += fromBits;
while (bits >= toBits) {
bits -= toBits;
out.write((acc >>> bits) & maxv);
}
}
if (pad) {
if (bits > 0) out.write((acc << (toBits - bits)) & maxv);
} else if (bits >= fromBits || ((acc << (toBits - bits)) & maxv) != 0) {
throw new SegwitAddressException("Could not convert bits, invalid padding");
}
return out.toByteArray();
}
}

View file

@ -0,0 +1,51 @@
package com.tangem.blockchain.binance.client.encoding;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.google.protobuf.CodedOutputStream;
import org.spongycastle.util.encoders.Hex;
import java.io.IOException;
import java.nio.charset.Charset;
public class EncodeUtils {
private static final ObjectWriter OBJECT_WRITER;
static {
ObjectMapper mapper = new ObjectMapper();
OBJECT_WRITER = mapper.writer();
}
public static byte[] hexStringToByteArray(String s) {
return Hex.decode(s);
}
public static String bytesToHex(byte[] bytes) {
return Hex.toHexString(bytes);
}
public static String toJsonStringSortKeys(Object object) throws JsonProcessingException {
return OBJECT_WRITER.writeValueAsString(object);
}
public static byte[] toJsonEncodeBytes(Object object) throws JsonProcessingException {
return toJsonStringSortKeys(object).getBytes(Charset.forName("UTF-8"));
}
public static byte[] aminoWrap(byte[] raw, byte[] typePrefix, boolean isPrefixLength) throws IOException {
int totalLen = raw.length + typePrefix.length;
if (isPrefixLength)
totalLen += CodedOutputStream.computeUInt64SizeNoTag(totalLen);
byte[] msg = new byte[totalLen];
CodedOutputStream cos = CodedOutputStream.newInstance(msg);
if (isPrefixLength)
cos.writeUInt64NoTag(raw.length + typePrefix.length);
cos.write(typePrefix, 0, typePrefix.length);
cos.write(raw, 0, raw.length);
cos.flush();
return msg;
}
}

View file

@ -0,0 +1,4 @@
package com.tangem.blockchain.binance.client.encoding.message;
public interface BinanceDexTransactionMessage {
}

View file

@ -0,0 +1,50 @@
package com.tangem.blockchain.binance.client.encoding.message;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder(alphabetic = true)
public class CancelOrderMessage implements BinanceDexTransactionMessage {
private String sender;
private String symbol;
@JsonProperty("refid")
private String refId;
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public String getRefId() {
return refId;
}
public void setRefId(String refId) {
this.refId = refId;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("sender", sender)
.append("symbol", symbol)
.append("refId", refId)
.toString();
}
}

View file

@ -0,0 +1,40 @@
package com.tangem.blockchain.binance.client.encoding.message;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder(alphabetic = true)
public class InputOutput {
private String address;
private List<Token> coins;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public List<Token> getCoins() {
return coins;
}
public void setCoins(List<Token> coins) {
this.coins = coins;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("address", address)
.append("coins", coins)
.toString();
}
}

View file

@ -0,0 +1,31 @@
package com.tangem.blockchain.binance.client.encoding.message;
import com.tangem.blockchain.binance.client.encoding.EncodeUtils;
/**
* Binance dex standard transactiont types.
*/
public enum MessageType {
Send("2A2C87FA"),
NewOrder("CE6DC043"),
CancelOrder("166E681B"),
TokenFreeze("E774B32D"),
TokenUnfreeze("6515FF0D"),
StdSignature(null),
PubKey("EB5AE987"),
StdTx("F0625DEE");
private byte[] typePrefixBytes;
MessageType(String typePrefix) {
if (typePrefix == null) {
this.typePrefixBytes = new byte[0];
} else
this.typePrefixBytes = EncodeUtils.hexStringToByteArray(typePrefix);
}
public byte[] getTypePrefixBytes() {
return typePrefixBytes;
}
}

View file

@ -0,0 +1,222 @@
package com.tangem.blockchain.binance.client.encoding.message;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.tangem.blockchain.binance.client.domain.OrderSide;
import com.tangem.blockchain.binance.client.domain.OrderType;
import com.tangem.blockchain.binance.client.domain.TimeInForce;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder(alphabetic = true)
public class NewOrderMessage implements BinanceDexTransactionMessage {
private String id;
@JsonProperty("ordertype")
private OrderType orderType;
private long price;
private long quantity;
private String sender;
private OrderSide side;
private String symbol;
@JsonProperty("timeinforce")
private TimeInForce timeInForce;
private NewOrderMessage() {
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public OrderType getOrderType() {
return orderType;
}
public void setOrderType(OrderType orderType) {
this.orderType = orderType;
}
public OrderSide getSide() {
return side;
}
public void setSide(OrderSide side) {
this.side = side;
}
public long getPrice() {
return price;
}
public void setPrice(long price) {
this.price = price;
}
public long getQuantity() {
return quantity;
}
public void setQuantity(long quantity) {
this.quantity = quantity;
}
public TimeInForce getTimeInForce() {
return timeInForce;
}
public void setTimeInForce(TimeInForce timeInForce) {
this.timeInForce = timeInForce;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("sender", sender)
.append("id", id)
.append("symbol", symbol)
.append("orderType", orderType)
.append("side", side)
.append("price", price)
.append("quantity", quantity)
.append("timeInForce", timeInForce)
.toString();
}
public static NewOrderBuilder newBuilder() {
return new NewOrderBuilder();
}
public NewOrderBuilder toBuilder() {
return newBuilder()
.setSender(this.sender)
.setId(this.id)
.setSymbol(this.symbol)
.setOrderType(this.orderType)
.setSide(this.side)
.setPrice(TransactionRequestAssembler.longToDouble(this.price))
.setQuantity(TransactionRequestAssembler.longToDouble(this.quantity))
.setTimeInForce(this.timeInForce);
}
/**
* Builder class for NewOrderMessage transaction. It handles price/quantity conversion from double to long.
*/
public static class NewOrderBuilder {
private String id;
private OrderType orderType;
private String price;
private String quantity;
private String sender;
private OrderSide side;
private String symbol;
private TimeInForce timeInForce;
public NewOrderMessage build() {
NewOrderMessage newOrder = new NewOrderMessage();
newOrder.setId(id);
newOrder.setOrderType(orderType);
newOrder.setPrice(TransactionRequestAssembler.doubleToLong(price));
newOrder.setQuantity(TransactionRequestAssembler.doubleToLong(quantity));
newOrder.setSender(sender);
newOrder.setSide(side);
newOrder.setSymbol(symbol);
newOrder.setTimeInForce(timeInForce);
return newOrder;
}
public String getId() {
return id;
}
public NewOrderBuilder setId(String id) {
this.id = id;
return this;
}
public OrderType getOrderType() {
return orderType;
}
public NewOrderBuilder setOrderType(OrderType orderType) {
this.orderType = orderType;
return this;
}
public String getPrice() {
return price;
}
public NewOrderBuilder setPrice(String price) {
this.price = price;
return this;
}
public String getQuantity() {
return quantity;
}
public NewOrderBuilder setQuantity(String quantity) {
this.quantity = quantity;
return this;
}
public String getSender() {
return sender;
}
public NewOrderBuilder setSender(String sender) {
this.sender = sender;
return this;
}
public OrderSide getSide() {
return side;
}
public NewOrderBuilder setSide(OrderSide side) {
this.side = side;
return this;
}
public String getSymbol() {
return symbol;
}
public NewOrderBuilder setSymbol(String symbol) {
this.symbol = symbol;
return this;
}
public TimeInForce getTimeInForce() {
return timeInForce;
}
public NewOrderBuilder setTimeInForce(TimeInForce timeInForce) {
this.timeInForce = timeInForce;
return this;
}
}
}

View file

@ -0,0 +1,91 @@
package com.tangem.blockchain.binance.client.encoding.message;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder(alphabetic = true)
public class SignData {
@JsonProperty("chain_id")
private String chainId;
@JsonProperty("account_number")
private String accountNumber;
private String sequence;
private String memo;
private BinanceDexTransactionMessage[] msgs;
private String source;
private byte[] data;
public String getChainId() {
return chainId;
}
public void setChainId(String chainId) {
this.chainId = chainId;
}
public String getAccountNumber() {
return accountNumber;
}
public void setAccountNumber(String accountNumber) {
this.accountNumber = accountNumber;
}
public String getSequence() {
return sequence;
}
public void setSequence(String sequence) {
this.sequence = sequence;
}
public String getMemo() {
return memo;
}
public void setMemo(String memo) {
this.memo = memo;
}
public BinanceDexTransactionMessage[] getMsgs() {
return msgs;
}
public void setMsgs(BinanceDexTransactionMessage[] msgs) {
this.msgs = msgs;
}
public String getSource() {
return source;
}
public void setSource(String source) {
this.source = source;
}
public byte[] getData() {
return data;
}
public void setData(byte[] data) {
this.data = data;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("chainId", chainId)
.append("accountNumber", accountNumber)
.append("sequence", sequence)
.append("memo", memo)
.append("msgs", msgs)
.append("source", source)
.append("data", data)
.toString();
}
}

View file

@ -0,0 +1,38 @@
package com.tangem.blockchain.binance.client.encoding.message;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder(alphabetic = true)
public class Token {
private String denom;
private Long amount;
public String getDenom() {
return denom;
}
public void setDenom(String denom) {
this.denom = denom;
}
public Long getAmount() {
return amount;
}
public void setAmount(Long amount) {
this.amount = amount;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("denom", denom)
.append("amount", amount)
.toString();
}
}

View file

@ -0,0 +1,48 @@
package com.tangem.blockchain.binance.client.encoding.message;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder(alphabetic = true)
public class TokenFreezeMessage implements BinanceDexTransactionMessage {
private String from;
private String symbol;
private long amount;
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public long getAmount() {
return amount;
}
public void setAmount(long amount) {
this.amount = amount;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("from", from)
.append("symbol", symbol)
.append("amount", amount)
.toString();
}
}

View file

@ -0,0 +1,49 @@
package com.tangem.blockchain.binance.client.encoding.message;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder(alphabetic = true)
public class TokenUnfreezeMessage implements BinanceDexTransactionMessage {
private String from;
private String symbol;
private long amount;
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public long getAmount() {
return amount;
}
public void setAmount(long amount) {
this.amount = amount;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("from", from)
.append("symbol", symbol)
.append("amount", amount)
.toString();
}
}

View file

@ -0,0 +1,302 @@
package com.tangem.blockchain.binance.client.encoding.message;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.annotations.VisibleForTesting;
import com.google.protobuf.ByteString;
import com.tangem.blockchain.binance.client.Wallet;
import com.tangem.blockchain.binance.client.domain.broadcast.TokenFreeze;
import com.tangem.blockchain.binance.client.domain.broadcast.TokenUnfreeze;
import com.tangem.blockchain.binance.client.domain.broadcast.TransactionOption;
import com.tangem.blockchain.binance.client.domain.broadcast.Transfer;
import com.tangem.blockchain.binance.client.encoding.Crypto;
import com.tangem.blockchain.binance.client.encoding.EncodeUtils;
import com.tangem.blockchain.binance.proto.StdSignature;
import com.tangem.blockchain.binance.proto.StdTx;
import java.io.IOException;
import java.math.BigDecimal;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.List;
import okhttp3.RequestBody;
/**
* Assemble a transaction message body.
* https://testnet-dex.binance.org/doc/encoding.html
*/
public class TransactionRequestAssembler {
private static final okhttp3.MediaType MEDIA_TYPE = okhttp3.MediaType.parse("text/plain; charset=utf-8");
private static final BigDecimal MULTIPLY_FACTOR = BigDecimal.valueOf(1e8);
private static final BigDecimal MAX_NUMBER = new BigDecimal(Long.MAX_VALUE);
private Wallet wallet;
private TransactionOption options;
public TransactionRequestAssembler(Wallet wallet, TransactionOption options) {
this.wallet = wallet;
this.options = options;
}
public static long doubleToLong(String d) {
BigDecimal encodeValue = new BigDecimal(d).multiply(MULTIPLY_FACTOR);
if (encodeValue.compareTo(MAX_NUMBER) > 0) {
throw new IllegalArgumentException(d + " is too large.");
}
return encodeValue.longValue();
}
public static String longToDouble(long l) {
return BigDecimal.valueOf(l).divide(MULTIPLY_FACTOR).toString();
}
@VisibleForTesting
byte[] sign(BinanceDexTransactionMessage msg)
throws JsonProcessingException, NoSuchAlgorithmException {
SignData sd = new SignData();
sd.setChainId(wallet.getChainId());
sd.setAccountNumber(String.valueOf(wallet.getAccountNumber()));
sd.setSequence(String.valueOf(wallet.getSequence()));
sd.setMsgs(new BinanceDexTransactionMessage[]{msg});
sd.setMemo(options.getMemo());
sd.setSource(String.valueOf(options.getSource()));
sd.setData(options.getData());
return Crypto.sign(EncodeUtils.toJsonEncodeBytes(sd), wallet.getEcKey());
}
@VisibleForTesting
byte[] encodeSignature(byte[] signatureBytes) throws IOException {
StdSignature stdSignature = StdSignature.newBuilder().setPubKey(ByteString.copyFrom(wallet.getPubKeyForSign()))
.setSignature(ByteString.copyFrom(signatureBytes))
.setAccountNumber(wallet.getAccountNumber())
.setSequence(wallet.getSequence())
.build();
return EncodeUtils.aminoWrap(
stdSignature.toByteArray(), MessageType.StdSignature.getTypePrefixBytes(), false);
}
@VisibleForTesting
byte[] encodeStdTx(byte[] msg, byte[] signature) throws IOException {
StdTx.Builder stdTxBuilder = StdTx.newBuilder()
.addMsgs(ByteString.copyFrom(msg))
.addSignatures(ByteString.copyFrom(signature))
.setMemo(options.getMemo())
.setSource(options.getSource());
if (options.getData() != null) {
stdTxBuilder = stdTxBuilder.setData(ByteString.copyFrom(options.getData()));
}
StdTx stdTx = stdTxBuilder.build();
return EncodeUtils.aminoWrap(stdTx.toByteArray(), MessageType.StdTx.getTypePrefixBytes(), true);
}
private RequestBody createRequestBody(byte[] stdTx) {
return RequestBody.create(MEDIA_TYPE, EncodeUtils.bytesToHex(stdTx));
}
private String generateOrderId() {
return EncodeUtils.bytesToHex(wallet.getAddressBytes()).toUpperCase() + "-" + (wallet.getSequence() + 1);
}
@VisibleForTesting
NewOrderMessage createNewOrderMessage(
com.tangem.blockchain.binance.client.domain.broadcast.NewOrder newOrder) {
return NewOrderMessage.newBuilder()
.setId(generateOrderId())
.setOrderType(newOrder.getOrderType())
.setPrice(newOrder.getPrice())
.setQuantity(newOrder.getQuantity())
.setSender(wallet.getAddress())
.setSide(newOrder.getSide())
.setSymbol(newOrder.getSymbol())
.setTimeInForce(newOrder.getTimeInForce())
.build();
}
@VisibleForTesting
byte[] encodeNewOrderMessage(NewOrderMessage newOrder)
throws IOException {
com.tangem.blockchain.binance.proto.NewOrder proto = com.tangem.blockchain.binance.proto.NewOrder.newBuilder()
.setSender(ByteString.copyFrom(wallet.getAddressBytes()))
.setId(newOrder.getId())
.setSymbol(newOrder.getSymbol())
.setOrdertype(newOrder.getOrderType().toValue())
.setSide(newOrder.getSide().toValue())
.setPrice(newOrder.getPrice())
.setQuantity(newOrder.getQuantity())
.setTimeinforce(newOrder.getTimeInForce().toValue())
.build();
return EncodeUtils.aminoWrap(proto.toByteArray(), MessageType.NewOrder.getTypePrefixBytes(), false);
}
public RequestBody buildNewOrder(com.tangem.blockchain.binance.client.domain.broadcast.NewOrder newOrder)
throws IOException, NoSuchAlgorithmException {
NewOrderMessage msgBean = createNewOrderMessage(newOrder);
byte[] msg = encodeNewOrderMessage(msgBean);
byte[] signature = encodeSignature(sign(msgBean));
byte[] stdTx = encodeStdTx(msg, signature);
return createRequestBody(stdTx);
}
@VisibleForTesting
CancelOrderMessage createCancelOrderMessage(
com.tangem.blockchain.binance.client.domain.broadcast.CancelOrder cancelOrder) {
CancelOrderMessage bean =
new CancelOrderMessage();
bean.setRefId(cancelOrder.getRefId());
bean.setSymbol(cancelOrder.getSymbol());
bean.setSender(wallet.getAddress());
return bean;
}
@VisibleForTesting
byte[] encodeCancelOrderMessage(CancelOrderMessage cancelOrder)
throws IOException {
com.tangem.blockchain.binance.proto.CancelOrder proto = com.tangem.blockchain.binance.proto.CancelOrder.newBuilder()
.setSender(ByteString.copyFrom(wallet.getAddressBytes()))
.setSymbol(cancelOrder.getSymbol())
.setRefid(cancelOrder.getRefId())
.build();
return EncodeUtils.aminoWrap(proto.toByteArray(), MessageType.CancelOrder.getTypePrefixBytes(), false);
}
public RequestBody buildCancelOrder(com.tangem.blockchain.binance.client.domain.broadcast.CancelOrder cancelOrder)
throws IOException, NoSuchAlgorithmException {
CancelOrderMessage msgBean = createCancelOrderMessage(cancelOrder);
byte[] msg = encodeCancelOrderMessage(msgBean);
byte[] signature = encodeSignature(sign(msgBean));
byte[] stdTx = encodeStdTx(msg, signature);
return createRequestBody(stdTx);
}
@VisibleForTesting
TransferMessage createTransferMessage(Transfer transfer) {
Token token = new Token();
token.setDenom(transfer.getCoin());
token.setAmount(doubleToLong(transfer.getAmount()));
List<Token> coins = Collections.singletonList(token);
InputOutput input = new InputOutput();
input.setAddress(transfer.getFromAddress());
input.setCoins(coins);
InputOutput output = new InputOutput();
output.setAddress(transfer.getToAddress());
output.setCoins(coins);
TransferMessage msgBean = new TransferMessage();
msgBean.setInputs(Collections.singletonList(input));
msgBean.setOutputs(Collections.singletonList(output));
return msgBean;
}
private com.tangem.blockchain.binance.proto.Send.Input toProtoInput(InputOutput input) {
byte[] address = Crypto.decodeAddress(input.getAddress());
com.tangem.blockchain.binance.proto.Send.Input.Builder builder =
com.tangem.blockchain.binance.proto.Send.Input.newBuilder().setAddress(ByteString.copyFrom(address));
for (Token coin : input.getCoins()) {
com.tangem.blockchain.binance.proto.Send.Token protCoin =
com.tangem.blockchain.binance.proto.Send.Token.newBuilder().setAmount(coin.getAmount())
.setDenom(coin.getDenom()).build();
builder.addCoins(protCoin);
}
return builder.build();
}
private com.tangem.blockchain.binance.proto.Send.Output toProtoOutput(InputOutput output) {
byte[] address = Crypto.decodeAddress(output.getAddress());
com.tangem.blockchain.binance.proto.Send.Output.Builder builder =
com.tangem.blockchain.binance.proto.Send.Output.newBuilder().setAddress(ByteString.copyFrom(address));
for (Token coin : output.getCoins()) {
com.tangem.blockchain.binance.proto.Send.Token protCoin =
com.tangem.blockchain.binance.proto.Send.Token.newBuilder().setAmount(coin.getAmount())
.setDenom(coin.getDenom()).build();
builder.addCoins(protCoin);
}
return builder.build();
}
@VisibleForTesting
byte[] encodeTransferMessage(TransferMessage msg)
throws IOException {
com.tangem.blockchain.binance.proto.Send.Builder builder = com.tangem.blockchain.binance.proto.Send.newBuilder();
for (InputOutput input : msg.getInputs()) {
builder.addInputs(toProtoInput(input));
}
for (InputOutput output : msg.getOutputs()) {
builder.addOutputs(toProtoOutput(output));
}
com.tangem.blockchain.binance.proto.Send proto = builder.build();
return EncodeUtils.aminoWrap(proto.toByteArray(), MessageType.Send.getTypePrefixBytes(), false);
}
public RequestBody buildTransfer(Transfer transfer)
throws IOException, NoSuchAlgorithmException {
TransferMessage msgBean = createTransferMessage(transfer);
byte[] msg = encodeTransferMessage(msgBean);
byte[] signature = encodeSignature(sign(msgBean));
byte[] stdTx = encodeStdTx(msg, signature);
return createRequestBody(stdTx);
}
@VisibleForTesting
TokenFreezeMessage createTokenFreezeMessage(TokenFreeze freeze) {
TokenFreezeMessage msg = new TokenFreezeMessage();
msg.setAmount(doubleToLong(freeze.getAmount()));
msg.setFrom(wallet.getAddress());
msg.setSymbol(freeze.getSymbol());
return msg;
}
@VisibleForTesting
byte[] encodeTokenFreezeMessage(TokenFreezeMessage freeze) throws IOException {
byte[] address = Crypto.decodeAddress(freeze.getFrom());
com.tangem.blockchain.binance.proto.TokenFreeze proto =
com.tangem.blockchain.binance.proto.TokenFreeze.newBuilder().setFrom(ByteString.copyFrom(address))
.setAmount(freeze.getAmount())
.setSymbol(freeze.getSymbol())
.build();
return EncodeUtils.aminoWrap(proto.toByteArray(), MessageType.TokenFreeze.getTypePrefixBytes(), false);
}
public RequestBody buildTokenFreeze(TokenFreeze freeze)
throws IOException, NoSuchAlgorithmException {
TokenFreezeMessage msgBean = createTokenFreezeMessage(freeze);
byte[] msg = encodeTokenFreezeMessage(msgBean);
byte[] signature = encodeSignature(sign(msgBean));
byte[] stdTx = encodeStdTx(msg, signature);
return createRequestBody(stdTx);
}
@VisibleForTesting
TokenUnfreezeMessage createTokenUnfreezeMessage(TokenUnfreeze unfreeze) {
TokenUnfreezeMessage msg = new TokenUnfreezeMessage();
msg.setAmount(doubleToLong(unfreeze.getAmount()));
msg.setFrom(wallet.getAddress());
msg.setSymbol(unfreeze.getSymbol());
return msg;
}
@VisibleForTesting
byte[] encodeTokenUnfreezeMessage(TokenUnfreezeMessage unfreeze) throws IOException {
byte[] address = Crypto.decodeAddress(unfreeze.getFrom());
com.tangem.blockchain.binance.proto.TokenUnfreeze proto =
com.tangem.blockchain.binance.proto.TokenUnfreeze.newBuilder().setFrom(ByteString.copyFrom(address))
.setAmount(unfreeze.getAmount())
.setSymbol(unfreeze.getSymbol())
.build();
return EncodeUtils.aminoWrap(proto.toByteArray(), MessageType.TokenUnfreeze.getTypePrefixBytes(), false);
}
public RequestBody buildTokenUnfreeze(TokenUnfreeze unfreeze)
throws IOException, NoSuchAlgorithmException {
TokenUnfreezeMessage msgBean = createTokenUnfreezeMessage(unfreeze);
byte[] msg = encodeTokenUnfreezeMessage(msgBean);
byte[] signature = encodeSignature(sign(msgBean));
byte[] stdTx = encodeStdTx(msg, signature);
return createRequestBody(stdTx);
}
}

View file

@ -0,0 +1,160 @@
package com.tangem.blockchain.binance.client.encoding.message;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.protobuf.ByteString;
import com.tangem.blockchain.binance.BinanceAccountData;
import com.tangem.blockchain.binance.client.domain.broadcast.TransactionOption;
import com.tangem.blockchain.binance.client.domain.broadcast.Transfer;
import com.tangem.blockchain.binance.client.encoding.Crypto;
import com.tangem.blockchain.binance.client.encoding.EncodeUtils;
import com.tangem.blockchain.binance.proto.StdSignature;
import com.tangem.blockchain.binance.proto.StdTx;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import okhttp3.RequestBody;
/**
* Assemble a transaction message body with external signature
* https://testnet-dex.binance.org/doc/encoding.html
*/
public class TransactionRequestAssemblerExtSign {
private static final okhttp3.MediaType MEDIA_TYPE = okhttp3.MediaType.parse("text/plain; charset=utf-8");
private static final BigDecimal MULTIPLY_FACTOR = BigDecimal.valueOf(1e8);
private static final BigDecimal MAX_NUMBER = new BigDecimal(Long.MAX_VALUE);
//private Wallet wallet;
private BinanceAccountData binanceAccountData;
private byte[] pubKeyForSign;
private TransactionOption options;
public TransactionRequestAssemblerExtSign(BinanceAccountData binanceAccountData, byte[] pubKeyForSign, TransactionOption options) {
this.binanceAccountData = binanceAccountData;
this.pubKeyForSign = pubKeyForSign;
this.options = options;
}
private static long doubleToLong(String d) {
BigDecimal encodeValue = new BigDecimal(d).multiply(MULTIPLY_FACTOR);
if (encodeValue.compareTo(MAX_NUMBER) > 0) {
throw new IllegalArgumentException(d + " is too large.");
}
return encodeValue.longValue();
}
public byte[] prepareForSign(BinanceDexTransactionMessage msg)
throws JsonProcessingException {
SignData sd = new SignData();
sd.setChainId(binanceAccountData.getChainId());
sd.setAccountNumber(String.valueOf(binanceAccountData.getAccountNumber()));
sd.setSequence(String.valueOf(binanceAccountData.getSequence()));
sd.setMsgs(new BinanceDexTransactionMessage[]{msg});
sd.setMemo(options.getMemo());
sd.setSource(String.valueOf(options.getSource()));
sd.setData(options.getData());
return EncodeUtils.toJsonEncodeBytes(sd);
}
public byte[] encodeSignature(byte[] signatureBytes) throws IOException {
StdSignature stdSignature = StdSignature.newBuilder().setPubKey(ByteString.copyFrom(pubKeyForSign))
.setSignature(ByteString.copyFrom(signatureBytes))
.setAccountNumber(binanceAccountData.getAccountNumber())
.setSequence(binanceAccountData.getSequence())
.build();
return EncodeUtils.aminoWrap(
stdSignature.toByteArray(), MessageType.StdSignature.getTypePrefixBytes(), false);
}
public byte[] encodeStdTx(byte[] msg, byte[] signature) throws IOException {
StdTx.Builder stdTxBuilder = StdTx.newBuilder()
.addMsgs(ByteString.copyFrom(msg))
.addSignatures(ByteString.copyFrom(signature))
.setMemo(options.getMemo())
.setSource(options.getSource());
if (options.getData() != null) {
stdTxBuilder = stdTxBuilder.setData(ByteString.copyFrom(options.getData()));
}
StdTx stdTx = stdTxBuilder.build();
return EncodeUtils.aminoWrap(stdTx.toByteArray(), MessageType.StdTx.getTypePrefixBytes(), true);
}
public static RequestBody createRequestBody(byte[] stdTx) {
return RequestBody.create(MEDIA_TYPE, EncodeUtils.bytesToHex(stdTx));
}
public TransferMessage createTransferMessage(Transfer transfer) {
Token token = new Token();
token.setDenom(transfer.getCoin());
token.setAmount(doubleToLong(transfer.getAmount()));
List<Token> coins = Collections.singletonList(token);
InputOutput input = new InputOutput();
input.setAddress(transfer.getFromAddress());
input.setCoins(coins);
InputOutput output = new InputOutput();
output.setAddress(transfer.getToAddress());
output.setCoins(coins);
TransferMessage msgBean = new TransferMessage();
msgBean.setInputs(Collections.singletonList(input));
msgBean.setOutputs(Collections.singletonList(output));
return msgBean;
}
private com.tangem.blockchain.binance.proto.Send.Input toProtoInput(InputOutput input) {
byte[] address = Crypto.decodeAddress(input.getAddress());
com.tangem.blockchain.binance.proto.Send.Input.Builder builder =
com.tangem.blockchain.binance.proto.Send.Input.newBuilder().setAddress(ByteString.copyFrom(address));
for (Token coin : input.getCoins()) {
com.tangem.blockchain.binance.proto.Send.Token protCoin =
com.tangem.blockchain.binance.proto.Send.Token.newBuilder().setAmount(coin.getAmount())
.setDenom(coin.getDenom()).build();
builder.addCoins(protCoin);
}
return builder.build();
}
private com.tangem.blockchain.binance.proto.Send.Output toProtoOutput(InputOutput output) {
byte[] address = Crypto.decodeAddress(output.getAddress());
com.tangem.blockchain.binance.proto.Send.Output.Builder builder =
com.tangem.blockchain.binance.proto.Send.Output.newBuilder().setAddress(ByteString.copyFrom(address));
for (Token coin : output.getCoins()) {
com.tangem.blockchain.binance.proto.Send.Token protCoin =
com.tangem.blockchain.binance.proto.Send.Token.newBuilder().setAmount(coin.getAmount())
.setDenom(coin.getDenom()).build();
builder.addCoins(protCoin);
}
return builder.build();
}
public byte[] encodeTransferMessage(TransferMessage msg)
throws IOException {
com.tangem.blockchain.binance.proto.Send.Builder builder = com.tangem.blockchain.binance.proto.Send.newBuilder();
for (InputOutput input : msg.getInputs()) {
builder.addInputs(toProtoInput(input));
}
for (InputOutput output : msg.getOutputs()) {
builder.addOutputs(toProtoOutput(output));
}
com.tangem.blockchain.binance.proto.Send proto = builder.build();
return EncodeUtils.aminoWrap(proto.toByteArray(), MessageType.Send.getTypePrefixBytes(), false);
}
public byte[] buildTransfer(Transfer transfer)
throws IOException {
TransferMessage msgBean = createTransferMessage(transfer);
byte[] msg = encodeTransferMessage(msgBean);
return prepareForSign(msgBean);
// byte[] signature = encodeSignature(prepareForSign(msgBean));
// byte[] stdTx = encodeStdTx(msg, signature);
// return createRequestBody(stdTx);
}
}

View file

@ -0,0 +1,40 @@
package com.tangem.blockchain.binance.client.encoding.message;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.tangem.blockchain.binance.client.BinanceDexConstants;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder(alphabetic = true)
public class TransferMessage implements BinanceDexTransactionMessage {
private List<InputOutput> inputs;
private List<InputOutput> outputs;
public List<InputOutput> getInputs() {
return inputs;
}
public void setInputs(List<InputOutput> inputs) {
this.inputs = inputs;
}
public List<InputOutput> getOutputs() {
return outputs;
}
public void setOutputs(List<InputOutput> outputs) {
this.outputs = outputs;
}
@Override
public String toString() {
return new ToStringBuilder(this, BinanceDexConstants.BINANCE_DEX_TO_STRING_STYLE)
.append("inputs", inputs)
.append("outputs", outputs)
.toString();
}
}

View file

@ -0,0 +1,165 @@
package com.tangem.blockchain.binance.client.impl;
import android.os.Build;
import androidx.annotation.RequiresApi;
import com.tangem.blockchain.binance.client.*;
import com.tangem.blockchain.binance.client.domain.*;
import com.tangem.blockchain.binance.client.domain.request.ClosedOrdersRequest;
import com.tangem.blockchain.binance.client.domain.request.OpenOrdersRequest;
import com.tangem.blockchain.binance.client.domain.request.TradesRequest;
import com.tangem.blockchain.binance.client.domain.request.TransactionsRequest;
import java.util.List;
import java.util.stream.Collectors;
public class BinanceDexApiAsyncRestClientImpl implements BinanceDexApiAsyncRestClient {
private BinanceDexApi binanceDexApi;
public BinanceDexApiAsyncRestClientImpl(String baseUrl) {
this.binanceDexApi = BinanceDexApiClientGenerator.createService(BinanceDexApi.class, baseUrl);
}
@Override
public void getTime(BinanceDexApiCallback<Time> callback) {
binanceDexApi.getTime().enqueue(new BinanceDexApiCallbackAdapter<>(callback));
}
@Override
public void getNodeInfo(BinanceDexApiCallback<Infos> callback) {
binanceDexApi.getNodeInfo().enqueue(new BinanceDexApiCallbackAdapter<>(callback));
}
@Override
public void getValidators(BinanceDexApiCallback<Validators> callback) {
binanceDexApi.getValidators().enqueue(new BinanceDexApiCallbackAdapter<>(callback));
}
@Override
public void getPeers(BinanceDexApiCallback<List<Peer>> callback) {
binanceDexApi.getPeers().enqueue(new BinanceDexApiCallbackAdapter<>(callback));
}
@Override
public void getMarkets(BinanceDexApiCallback<List<Market>> callback) {
binanceDexApi.getMarkets().enqueue(new BinanceDexApiCallbackAdapter<>(callback));
}
@Override
public void getAccount(String address, BinanceDexApiCallback<Account> callback) {
binanceDexApi.getAccount(address).enqueue(new BinanceDexApiCallbackAdapter<>(callback));
}
@Override
public void getAccountSequence(String address, BinanceDexApiCallback<AccountSequence> callback) {
binanceDexApi.getAccountSequence(address).enqueue(new BinanceDexApiCallbackAdapter<>(callback));
}
@Override
public void getTransactionMetadata(String hash, BinanceDexApiCallback<TransactionMetadata> callback) {
binanceDexApi.getTransactionMetadata(hash).enqueue(new BinanceDexApiCallbackAdapter<>(callback));
}
@Override
public void getTokens(BinanceDexApiCallback<List<Token>> callback) {
binanceDexApi.getTokens().enqueue(new BinanceDexApiCallbackAdapter<>(callback));
}
@Override
public void getOrderBook(String symbol, Integer limit, BinanceDexApiCallback<OrderBook> callback) {
binanceDexApi.getOrderBook(symbol, limit).enqueue(new BinanceDexApiCallbackAdapter<>(callback));
}
@Override
public void getCandleStickBars(String symbol, CandlestickInterval interval,
BinanceDexApiCallback<List<Candlestick>> callback) {
getCandleStickBars(symbol, interval, null, null, null, callback);
}
@Override
public void getCandleStickBars(String symbol, CandlestickInterval interval, Integer limit, Long startTime,
Long endTime, BinanceDexApiCallback<List<Candlestick>> callback) {
binanceDexApi.getCandlestickBars(symbol, interval.getIntervalId(), limit, startTime, endTime)
.enqueue(new BinanceDexApiCallbackAdapter<>(callback));
}
@Override
public void getOpenOrders(String address, BinanceDexApiCallback<OrderList> callback) {
OpenOrdersRequest request = new OpenOrdersRequest();
request.setAddress(address);
getOpenOrders(address, callback);
}
@Override
public void getOpenOrders(OpenOrdersRequest request, BinanceDexApiCallback<OrderList> callback) {
binanceDexApi.getOpenOrders(request.getAddress(), request.getLimit(),
request.getOffset(), request.getSymbol(), request.getTotal()).enqueue(
new BinanceDexApiCallbackAdapter<>(callback));
}
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void getClosedOrders(String address, BinanceDexApiCallback<OrderList> callback) {
ClosedOrdersRequest request = new ClosedOrdersRequest();
request.setAddress(address);
getClosedOrders(request, callback);
}
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void getClosedOrders(ClosedOrdersRequest request, BinanceDexApiCallback<OrderList> callback) {
String sidStr = request.getSide() == null ? null : request.getSide().name();
List<String> statusStrList = null;
if (request.getStatus() != null)
statusStrList = request.getStatus().stream().map(s -> s.name()).collect(Collectors.toList());
binanceDexApi.getClosedOrders(request.getAddress(), request.getEnd(), request.getLimit(),
request.getLimit(), sidStr, request.getStart(), statusStrList, request.getSymbol(),
request.getTotal()).enqueue(new BinanceDexApiCallbackAdapter<>(callback));
}
@Override
public void getOrder(String id, BinanceDexApiCallback<Order> callback) {
binanceDexApi.getOrder(id).enqueue(new BinanceDexApiCallbackAdapter<>(callback));
}
@Override
public void get24HrPriceStatistics(BinanceDexApiCallback<List<TickerStatistics>> callback) {
binanceDexApi.get24HrPriceStatistics().enqueue(new BinanceDexApiCallbackAdapter<>(callback));
}
@Override
public void getTrades(BinanceDexApiCallback<TradePage> callback) {
TradesRequest request = new TradesRequest();
getTrades(request, callback);
}
@Override
public void getTrades(TradesRequest request, BinanceDexApiCallback<TradePage> callback) {
String sideStr = request.getSide() == null ? null : request.getSide().name();
binanceDexApi.getTrades(
request.getAddress(), request.getBuyerOrderId(),
request.getEnd(), request.getHeight(), request.getLimit(), request.getOffset(),
request.getQuoteAsset(), request.getSellerOrderId(), sideStr,
request.getStart(), request.getSymbol(), request.getTotal()).enqueue(
new BinanceDexApiCallbackAdapter<>(callback));
}
@Override
public void getTransactions(String address, BinanceDexApiCallback<TransactionPage> callback) {
TransactionsRequest request = new TransactionsRequest();
request.setAddress(address);
getTransactions(request, callback);
}
@Override
public void getTransactions(TransactionsRequest request, BinanceDexApiCallback<TransactionPage> callback) {
String sideStr = request.getSide() == null ? null : request.getSide().name();
String txTypeStr = request.getTxType() != null ? request.getTxType().name() : null;
binanceDexApi.getTransactions(
request.getAddress(), request.getBlockHeight(), request.getEndTime(),
request.getLimit(), request.getOffset(), sideStr,
request.getStartTime(), request.getTxAsset(), txTypeStr).enqueue(
new BinanceDexApiCallbackAdapter<>(callback));
}
}

View file

@ -0,0 +1,222 @@
package com.tangem.blockchain.binance.client.impl;
import android.os.Build;
import androidx.annotation.RequiresApi;
import com.tangem.blockchain.binance.BinanceAccountData;
import com.tangem.blockchain.binance.client.*;
import com.tangem.blockchain.binance.client.domain.*;
import com.tangem.blockchain.binance.client.domain.broadcast.*;
import com.tangem.blockchain.binance.client.domain.request.ClosedOrdersRequest;
import com.tangem.blockchain.binance.client.domain.request.OpenOrdersRequest;
import com.tangem.blockchain.binance.client.domain.request.TradesRequest;
import com.tangem.blockchain.binance.client.domain.request.TransactionsRequest;
import com.tangem.blockchain.binance.client.encoding.message.TransactionRequestAssembler;
import com.tangem.blockchain.binance.client.encoding.message.TransactionRequestAssemblerExtSign;
import okhttp3.RequestBody;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.stream.Collectors;
/**
* Binance DEX API rest client, supporting synchronous/blocking access Binance DEX's REST API.
*/
public class BinanceDexApiRestClientImpl implements BinanceDexApiRestClient {
private BinanceDexApi binanceDexApi;
public BinanceDexApiRestClientImpl(String baseUrl) {
this.binanceDexApi = BinanceDexApiClientGenerator.createService(BinanceDexApi.class, baseUrl);
}
public Time getTime() {
return BinanceDexApiClientGenerator.executeSync(binanceDexApi.getTime());
}
public Infos getNodeInfo() {
return BinanceDexApiClientGenerator.executeSync(binanceDexApi.getNodeInfo());
}
public Validators getValidators() {
return BinanceDexApiClientGenerator.executeSync(binanceDexApi.getValidators());
}
public List<Peer> getPeers() {
return BinanceDexApiClientGenerator.executeSync(binanceDexApi.getPeers());
}
public List<Market> getMarkets() {
return BinanceDexApiClientGenerator.executeSync(binanceDexApi.getMarkets());
}
public Account getAccount(String address) {
return BinanceDexApiClientGenerator.executeSync(binanceDexApi.getAccount(address));
}
public AccountSequence getAccountSequence(String address) {
return BinanceDexApiClientGenerator.executeSync(binanceDexApi.getAccountSequence(address));
}
public TransactionMetadata getTransactionMetadata(String hash) {
return BinanceDexApiClientGenerator.executeSync(binanceDexApi.getTransactionMetadata(hash));
}
public List<Token> getTokens() {
return BinanceDexApiClientGenerator.executeSync(binanceDexApi.getTokens());
}
public OrderBook getOrderBook(String symbol, Integer limit) {
return BinanceDexApiClientGenerator.executeSync(binanceDexApi.getOrderBook(symbol, limit));
}
public List<Candlestick> getCandleStickBars(String symbol, CandlestickInterval interval) {
return getCandleStickBars(symbol, interval, null, null, null);
}
public List<Candlestick> getCandleStickBars(String symbol, CandlestickInterval interval, Integer limit, Long startTime, Long endTime) {
return BinanceDexApiClientGenerator.executeSync(binanceDexApi.getCandlestickBars(symbol, interval.getIntervalId(), limit, startTime, endTime));
}
public OrderList getOpenOrders(String address) {
OpenOrdersRequest request = new OpenOrdersRequest();
request.setAddress(address);
return getOpenOrders(request);
}
public OrderList getOpenOrders(OpenOrdersRequest request) {
return BinanceDexApiClientGenerator.executeSync(
binanceDexApi.getOpenOrders(request.getAddress(), request.getLimit(),
request.getOffset(), request.getSymbol(), request.getTotal()));
}
@RequiresApi(api = Build.VERSION_CODES.N)
public OrderList getClosedOrders(String address) {
ClosedOrdersRequest request = new ClosedOrdersRequest();
request.setAddress(address);
return getClosedOrders(request);
}
@RequiresApi(api = Build.VERSION_CODES.N)
public OrderList getClosedOrders(ClosedOrdersRequest request) {
String sidStr = request.getSide() == null ? null : request.getSide().name();
List<String> statusStrList = null;
if (request.getStatus() != null)
statusStrList = request.getStatus().stream().map(s -> s.name()).collect(Collectors.toList());
return BinanceDexApiClientGenerator.executeSync(
binanceDexApi.getClosedOrders(request.getAddress(), request.getEnd(), request.getLimit(),
request.getLimit(), sidStr, request.getStart(), statusStrList, request.getSymbol(),
request.getTotal()));
}
public Order getOrder(String id) {
return BinanceDexApiClientGenerator.executeSync(binanceDexApi.getOrder(id));
}
public List<TickerStatistics> get24HrPriceStatistics() {
return BinanceDexApiClientGenerator.executeSync(binanceDexApi.get24HrPriceStatistics());
}
@Override
public TradePage getTrades() {
TradesRequest request = new TradesRequest();
return getTrades(request);
}
@Override
public TradePage getTrades(TradesRequest request) {
String sideStr = request.getSide() == null ? null : request.getSide().name();
return BinanceDexApiClientGenerator.executeSync(
binanceDexApi.getTrades(
request.getAddress(), request.getBuyerOrderId(),
request.getEnd(), request.getHeight(), request.getLimit(), request.getOffset(),
request.getQuoteAsset(), request.getSellerOrderId(), sideStr,
request.getStart(), request.getSymbol(), request.getTotal()));
}
@Override
public TransactionPage getTransactions(String address) {
TransactionsRequest request = new TransactionsRequest();
request.setAddress(address);
return getTransactions(request);
}
@Override
public TransactionPage getTransactions(TransactionsRequest request) {
String sideStr = request.getSide() != null ? request.getSide().name() : null;
String txTypeStr = request.getTxType() != null ? request.getTxType().name() : null;
return BinanceDexApiClientGenerator.executeSync(
binanceDexApi.getTransactions(
request.getAddress(), request.getBlockHeight(), request.getEndTime(),
request.getLimit(), request.getOffset(), sideStr,
request.getStartTime(), request.getTxAsset(), txTypeStr));
}
// Broadcast and handle account sequence
private List<TransactionMetadata> broadcast(RequestBody requestBody, boolean sync, Wallet wallet) {
try {
List<TransactionMetadata> metadatas =
BinanceDexApiClientGenerator.executeSync(binanceDexApi.broadcast(sync, requestBody));
if (!metadatas.isEmpty() && metadatas.get(0).isOk()) {
wallet.increaseAccountSequence();
}
return metadatas;
} catch (BinanceDexApiException e) {
wallet.invalidAccountSequence();
throw e;
}
}
public List<TransactionMetadata> broadcastNoWallet(RequestBody requestBody, boolean sync) throws BinanceDexApiException {
return BinanceDexApiClientGenerator.executeSync(binanceDexApi.broadcast(sync, requestBody));
}
public List<TransactionMetadata> newOrder(NewOrder newOrder, Wallet wallet, TransactionOption options, boolean sync)
throws IOException, NoSuchAlgorithmException {
wallet.ensureWalletIsReady(this);
TransactionRequestAssembler assembler = new TransactionRequestAssembler(wallet, options);
RequestBody requestBody = assembler.buildNewOrder(newOrder);
return broadcast(requestBody, sync, wallet);
}
public List<TransactionMetadata> cancelOrder(CancelOrder cancelOrder, Wallet wallet, TransactionOption options, boolean sync)
throws IOException, NoSuchAlgorithmException {
wallet.ensureWalletIsReady(this);
TransactionRequestAssembler assembler = new TransactionRequestAssembler(wallet, options);
RequestBody requestBody = assembler.buildCancelOrder(cancelOrder);
return broadcast(requestBody, sync, wallet);
}
public List<TransactionMetadata> transfer(Transfer transfer, Wallet wallet, TransactionOption options, boolean sync)
throws IOException, NoSuchAlgorithmException {
wallet.ensureWalletIsReady(this);
TransactionRequestAssembler assembler = new TransactionRequestAssembler(wallet, options);
RequestBody requestBody = assembler.buildTransfer(transfer);
return broadcast(requestBody, sync, wallet);
}
public TransactionRequestAssemblerExtSign prepareTransfer(Transfer transfer, BinanceAccountData binanceAccountData, byte[] pubKeyForSign, TransactionOption options, boolean sync) {
return new TransactionRequestAssemblerExtSign(binanceAccountData, pubKeyForSign, options);
// RequestBody requestBody = assembler.buildTransfer(transfer);
// return broadcast(requestBody, sync, wallet);
}
public List<TransactionMetadata> freeze(TokenFreeze freeze, Wallet wallet, TransactionOption options, boolean sync)
throws IOException, NoSuchAlgorithmException {
wallet.ensureWalletIsReady(this);
TransactionRequestAssembler assembler = new TransactionRequestAssembler(wallet, options);
RequestBody requestBody = assembler.buildTokenFreeze(freeze);
return broadcast(requestBody, sync, wallet);
}
public List<TransactionMetadata> unfreeze(TokenUnfreeze unfreeze, Wallet wallet, TransactionOption options, boolean sync)
throws IOException, NoSuchAlgorithmException {
wallet.ensureWalletIsReady(this);
TransactionRequestAssembler assembler = new TransactionRequestAssembler(wallet, options);
RequestBody requestBody = assembler.buildTokenUnfreeze(unfreeze);
return broadcast(requestBody, sync, wallet);
}
}

View file

@ -0,0 +1,9 @@
package com.tangem.blockchain.binance.network
import retrofit2.Call
import retrofit2.http.GET
interface BinanceApi {
@GET("api/v1/fees")
suspend fun getFees(): List<BinanceFee>
}

View file

@ -0,0 +1,89 @@
package com.tangem.blockchain.binance.network
import com.tangem.blockchain.binance.client.BinanceDexApiClientFactory
import com.tangem.blockchain.binance.client.BinanceDexEnvironment
import com.tangem.blockchain.binance.client.encoding.message.TransactionRequestAssemblerExtSign
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.extensions.Result
import com.tangem.blockchain.common.extensions.SimpleResult
import com.tangem.blockchain.common.extensions.retryIO
import com.tangem.blockchain.common.network.API_BINANCE
import com.tangem.blockchain.common.network.API_BINANCE_TESTNET
import com.tangem.blockchain.common.network.createRetrofitInstance
import okhttp3.RequestBody
import java.math.BigDecimal
class BinanceNetworkManager(isTestNet: Boolean) {
val api = createRetrofitInstance(if (!isTestNet) API_BINANCE else API_BINANCE_TESTNET)
.create(BinanceApi::class.java)
val client = BinanceDexApiClientFactory.newInstance().newRestClient(
if (!isTestNet) BinanceDexEnvironment.PROD.baseUrl else BinanceDexEnvironment.TEST_NET.baseUrl
)
suspend fun getInfo(address: String): Result<BinanceInfoResponse> {
return try {
val accountData = retryIO { client.getAccount(address) }
var coinBalance = BigDecimal.ZERO
for (balance in accountData.balances) {
if (balance.symbol == "BNB") {
coinBalance = balance.free.toBigDecimal()
break
}
}
Result.Success(BinanceInfoResponse(
balance = coinBalance,
accountNumber = accountData.accountNumber.toLong(),
sequence = accountData.sequence
))
} catch (exception: Exception) {
if (exception.message == "account not found") {
Result.Success(BinanceInfoResponse(
balance = BigDecimal.ZERO, //TODO check account not found logic
accountNumber = null,
sequence = null
))
} else {
Result.Failure(exception)
}
}
}
suspend fun getFee(): Result<BigDecimal> {
return try {
val feeData = api.getFees()
var fee: BigDecimal? = null
for (binanceFee in feeData) {
if (binanceFee.transactionFee != null) {
fee = binanceFee.transactionFee?.value?.toBigDecimal()
?.movePointLeft(Blockchain.Binance.decimals.toInt())
break
}
}
return Result.Success(fee ?: throw Exception("Invalid fee response"))
} catch (exception: Exception) {
Result.Failure(exception)
}
}
suspend fun sendTransaction(transaction: ByteArray): SimpleResult {
return try {
val requestBody: RequestBody = TransactionRequestAssemblerExtSign.createRequestBody(transaction)
val response = retryIO { client.broadcastNoWallet(requestBody, true) }
if (response.isNotEmpty() && response[0].isOk) {
SimpleResult.Success
} else {
SimpleResult.Failure(Exception("transaction failed"))
}
} catch (error: Exception) {
SimpleResult.Failure(error)
}
}
}
data class BinanceInfoResponse(
val balance: BigDecimal?,
val accountNumber: Long?,
val sequence: Long?
)

View file

@ -0,0 +1,19 @@
package com.tangem.blockchain.binance.network
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class BinanceFee(
@Json(name = "fixed_fee_params")
var transactionFee: BinanceFeeData? = null
)
@JsonClass(generateAdapter = true)
data class BinanceFeeData(
@Json(name = "msg_type")
var messageType: String? = null,
@Json(name = "fee")
var value: Int? = null
)

View file

@ -0,0 +1,808 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: dex.proto
package com.tangem.blockchain.binance.proto;
/**
* <pre>
* please note the field name is the JSON name.
* </pre>
*
* Protobuf type {@code transaction.CancelOrder}
*/
public final class CancelOrder extends
com.google.protobuf.GeneratedMessageV3 implements
// @@protoc_insertion_point(message_implements:transaction.CancelOrder)
CancelOrderOrBuilder {
private static final long serialVersionUID = 0L;
// Use CancelOrder.newBuilder() to construct.
private CancelOrder(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
super(builder);
}
private CancelOrder() {
sender_ = com.google.protobuf.ByteString.EMPTY;
symbol_ = "";
refid_ = "";
}
@Override
public final com.google.protobuf.UnknownFieldSet
getUnknownFields() {
return this.unknownFields;
}
private CancelOrder(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
this();
if (extensionRegistry == null) {
throw new NullPointerException();
}
int mutable_bitField0_ = 0;
com.google.protobuf.UnknownFieldSet.Builder unknownFields =
com.google.protobuf.UnknownFieldSet.newBuilder();
try {
boolean done = false;
while (!done) {
int tag = input.readTag();
switch (tag) {
case 0:
done = true;
break;
case 10: {
sender_ = input.readBytes();
break;
}
case 18: {
String s = input.readStringRequireUtf8();
symbol_ = s;
break;
}
case 26: {
String s = input.readStringRequireUtf8();
refid_ = s;
break;
}
default: {
if (!parseUnknownField(
input, unknownFields, extensionRegistry, tag)) {
done = true;
}
break;
}
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(this);
} catch (java.io.IOException e) {
throw new com.google.protobuf.InvalidProtocolBufferException(
e).setUnfinishedMessage(this);
} finally {
this.unknownFields = unknownFields.build();
makeExtensionsImmutable();
}
}
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return com.tangem.blockchain.binance.proto.Transaction.internal_static_transaction_CancelOrder_descriptor;
}
@Override
protected FieldAccessorTable
internalGetFieldAccessorTable() {
return com.tangem.blockchain.binance.proto.Transaction.internal_static_transaction_CancelOrder_fieldAccessorTable
.ensureFieldAccessorsInitialized(
com.tangem.blockchain.binance.proto.CancelOrder.class, com.tangem.blockchain.binance.proto.CancelOrder.Builder.class);
}
public static final int SENDER_FIELD_NUMBER = 1;
private com.google.protobuf.ByteString sender_;
/**
* <pre>
* 0x166E681B // hardcoded, object type prefix in 4 bytes
* </pre>
*
* <code>bytes sender = 1;</code>
*/
public com.google.protobuf.ByteString getSender() {
return sender_;
}
public static final int SYMBOL_FIELD_NUMBER = 2;
private volatile Object symbol_;
/**
* <pre>
* symbol for trading pair in full name of the tokens
* </pre>
*
* <code>string symbol = 2;</code>
*/
public String getSymbol() {
Object ref = symbol_;
if (ref instanceof String) {
return (String) ref;
} else {
com.google.protobuf.ByteString bs =
(com.google.protobuf.ByteString) ref;
String s = bs.toStringUtf8();
symbol_ = s;
return s;
}
}
/**
* <pre>
* symbol for trading pair in full name of the tokens
* </pre>
*
* <code>string symbol = 2;</code>
*/
public com.google.protobuf.ByteString
getSymbolBytes() {
Object ref = symbol_;
if (ref instanceof String) {
com.google.protobuf.ByteString b =
com.google.protobuf.ByteString.copyFromUtf8(
(String) ref);
symbol_ = b;
return b;
} else {
return (com.google.protobuf.ByteString) ref;
}
}
public static final int REFID_FIELD_NUMBER = 3;
private volatile Object refid_;
/**
* <pre>
* order id of the one to cancel
* </pre>
*
* <code>string refid = 3;</code>
*/
public String getRefid() {
Object ref = refid_;
if (ref instanceof String) {
return (String) ref;
} else {
com.google.protobuf.ByteString bs =
(com.google.protobuf.ByteString) ref;
String s = bs.toStringUtf8();
refid_ = s;
return s;
}
}
/**
* <pre>
* order id of the one to cancel
* </pre>
*
* <code>string refid = 3;</code>
*/
public com.google.protobuf.ByteString
getRefidBytes() {
Object ref = refid_;
if (ref instanceof String) {
com.google.protobuf.ByteString b =
com.google.protobuf.ByteString.copyFromUtf8(
(String) ref);
refid_ = b;
return b;
} else {
return (com.google.protobuf.ByteString) ref;
}
}
private byte memoizedIsInitialized = -1;
@Override
public final boolean isInitialized() {
byte isInitialized = memoizedIsInitialized;
if (isInitialized == 1) return true;
if (isInitialized == 0) return false;
memoizedIsInitialized = 1;
return true;
}
@Override
public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException {
if (!sender_.isEmpty()) {
output.writeBytes(1, sender_);
}
if (!getSymbolBytes().isEmpty()) {
com.google.protobuf.GeneratedMessageV3.writeString(output, 2, symbol_);
}
if (!getRefidBytes().isEmpty()) {
com.google.protobuf.GeneratedMessageV3.writeString(output, 3, refid_);
}
unknownFields.writeTo(output);
}
@Override
public int getSerializedSize() {
int size = memoizedSize;
if (size != -1) return size;
size = 0;
if (!sender_.isEmpty()) {
size += com.google.protobuf.CodedOutputStream
.computeBytesSize(1, sender_);
}
if (!getSymbolBytes().isEmpty()) {
size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, symbol_);
}
if (!getRefidBytes().isEmpty()) {
size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, refid_);
}
size += unknownFields.getSerializedSize();
memoizedSize = size;
return size;
}
@Override
public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof com.tangem.blockchain.binance.proto.CancelOrder)) {
return super.equals(obj);
}
com.tangem.blockchain.binance.proto.CancelOrder other = (com.tangem.blockchain.binance.proto.CancelOrder) obj;
if (!getSender()
.equals(other.getSender())) return false;
if (!getSymbol()
.equals(other.getSymbol())) return false;
if (!getRefid()
.equals(other.getRefid())) return false;
if (!unknownFields.equals(other.unknownFields)) return false;
return true;
}
@Override
public int hashCode() {
if (memoizedHashCode != 0) {
return memoizedHashCode;
}
int hash = 41;
hash = (19 * hash) + getDescriptor().hashCode();
hash = (37 * hash) + SENDER_FIELD_NUMBER;
hash = (53 * hash) + getSender().hashCode();
hash = (37 * hash) + SYMBOL_FIELD_NUMBER;
hash = (53 * hash) + getSymbol().hashCode();
hash = (37 * hash) + REFID_FIELD_NUMBER;
hash = (53 * hash) + getRefid().hashCode();
hash = (29 * hash) + unknownFields.hashCode();
memoizedHashCode = hash;
return hash;
}
public static com.tangem.blockchain.binance.proto.CancelOrder parseFrom(
java.nio.ByteBuffer data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static com.tangem.blockchain.binance.proto.CancelOrder parseFrom(
java.nio.ByteBuffer data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static com.tangem.blockchain.binance.proto.CancelOrder parseFrom(
com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static com.tangem.blockchain.binance.proto.CancelOrder parseFrom(
com.google.protobuf.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static com.tangem.blockchain.binance.proto.CancelOrder parseFrom(byte[] data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static com.tangem.blockchain.binance.proto.CancelOrder parseFrom(
byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static com.tangem.blockchain.binance.proto.CancelOrder parseFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input);
}
public static com.tangem.blockchain.binance.proto.CancelOrder parseFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input, extensionRegistry);
}
public static com.tangem.blockchain.binance.proto.CancelOrder parseDelimitedFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseDelimitedWithIOException(PARSER, input);
}
public static com.tangem.blockchain.binance.proto.CancelOrder parseDelimitedFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseDelimitedWithIOException(PARSER, input, extensionRegistry);
}
public static com.tangem.blockchain.binance.proto.CancelOrder parseFrom(
com.google.protobuf.CodedInputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input);
}
public static com.tangem.blockchain.binance.proto.CancelOrder parseFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input, extensionRegistry);
}
@Override
public Builder newBuilderForType() { return newBuilder(); }
public static Builder newBuilder() {
return DEFAULT_INSTANCE.toBuilder();
}
public static Builder newBuilder(com.tangem.blockchain.binance.proto.CancelOrder prototype) {
return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
}
@Override
public Builder toBuilder() {
return this == DEFAULT_INSTANCE
? new Builder() : new Builder().mergeFrom(this);
}
@Override
protected Builder newBuilderForType(
BuilderParent parent) {
Builder builder = new Builder(parent);
return builder;
}
/**
* <pre>
* please note the field name is the JSON name.
* </pre>
*
* Protobuf type {@code transaction.CancelOrder}
*/
public static final class Builder extends
com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
// @@protoc_insertion_point(builder_implements:transaction.CancelOrder)
com.tangem.blockchain.binance.proto.CancelOrderOrBuilder {
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return com.tangem.blockchain.binance.proto.Transaction.internal_static_transaction_CancelOrder_descriptor;
}
@Override
protected FieldAccessorTable
internalGetFieldAccessorTable() {
return com.tangem.blockchain.binance.proto.Transaction.internal_static_transaction_CancelOrder_fieldAccessorTable
.ensureFieldAccessorsInitialized(
com.tangem.blockchain.binance.proto.CancelOrder.class, com.tangem.blockchain.binance.proto.CancelOrder.Builder.class);
}
// Construct using com.tangem.blockchain.binance.proto.CancelOrder.newBuilder()
private Builder() {
maybeForceBuilderInitialization();
}
private Builder(
BuilderParent parent) {
super(parent);
maybeForceBuilderInitialization();
}
private void maybeForceBuilderInitialization() {
if (com.google.protobuf.GeneratedMessageV3
.alwaysUseFieldBuilders) {
}
}
@Override
public Builder clear() {
super.clear();
sender_ = com.google.protobuf.ByteString.EMPTY;
symbol_ = "";
refid_ = "";
return this;
}
@Override
public com.google.protobuf.Descriptors.Descriptor
getDescriptorForType() {
return com.tangem.blockchain.binance.proto.Transaction.internal_static_transaction_CancelOrder_descriptor;
}
@Override
public com.tangem.blockchain.binance.proto.CancelOrder getDefaultInstanceForType() {
return com.tangem.blockchain.binance.proto.CancelOrder.getDefaultInstance();
}
@Override
public com.tangem.blockchain.binance.proto.CancelOrder build() {
com.tangem.blockchain.binance.proto.CancelOrder result = buildPartial();
if (!result.isInitialized()) {
throw newUninitializedMessageException(result);
}
return result;
}
@Override
public com.tangem.blockchain.binance.proto.CancelOrder buildPartial() {
com.tangem.blockchain.binance.proto.CancelOrder result = new com.tangem.blockchain.binance.proto.CancelOrder(this);
result.sender_ = sender_;
result.symbol_ = symbol_;
result.refid_ = refid_;
onBuilt();
return result;
}
@Override
public Builder clone() {
return super.clone();
}
@Override
public Builder setField(
com.google.protobuf.Descriptors.FieldDescriptor field,
Object value) {
return super.setField(field, value);
}
@Override
public Builder clearField(
com.google.protobuf.Descriptors.FieldDescriptor field) {
return super.clearField(field);
}
@Override
public Builder clearOneof(
com.google.protobuf.Descriptors.OneofDescriptor oneof) {
return super.clearOneof(oneof);
}
@Override
public Builder setRepeatedField(
com.google.protobuf.Descriptors.FieldDescriptor field,
int index, Object value) {
return super.setRepeatedField(field, index, value);
}
@Override
public Builder addRepeatedField(
com.google.protobuf.Descriptors.FieldDescriptor field,
Object value) {
return super.addRepeatedField(field, value);
}
@Override
public Builder mergeFrom(com.google.protobuf.Message other) {
if (other instanceof com.tangem.blockchain.binance.proto.CancelOrder) {
return mergeFrom((com.tangem.blockchain.binance.proto.CancelOrder)other);
} else {
super.mergeFrom(other);
return this;
}
}
public Builder mergeFrom(com.tangem.blockchain.binance.proto.CancelOrder other) {
if (other == com.tangem.blockchain.binance.proto.CancelOrder.getDefaultInstance()) return this;
if (other.getSender() != com.google.protobuf.ByteString.EMPTY) {
setSender(other.getSender());
}
if (!other.getSymbol().isEmpty()) {
symbol_ = other.symbol_;
onChanged();
}
if (!other.getRefid().isEmpty()) {
refid_ = other.refid_;
onChanged();
}
this.mergeUnknownFields(other.unknownFields);
onChanged();
return this;
}
@Override
public final boolean isInitialized() {
return true;
}
@Override
public Builder mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
com.tangem.blockchain.binance.proto.CancelOrder parsedMessage = null;
try {
parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
parsedMessage = (com.tangem.blockchain.binance.proto.CancelOrder) e.getUnfinishedMessage();
throw e.unwrapIOException();
} finally {
if (parsedMessage != null) {
mergeFrom(parsedMessage);
}
}
return this;
}
private com.google.protobuf.ByteString sender_ = com.google.protobuf.ByteString.EMPTY;
/**
* <pre>
* 0x166E681B // hardcoded, object type prefix in 4 bytes
* </pre>
*
* <code>bytes sender = 1;</code>
*/
public com.google.protobuf.ByteString getSender() {
return sender_;
}
/**
* <pre>
* 0x166E681B // hardcoded, object type prefix in 4 bytes
* </pre>
*
* <code>bytes sender = 1;</code>
*/
public Builder setSender(com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
sender_ = value;
onChanged();
return this;
}
/**
* <pre>
* 0x166E681B // hardcoded, object type prefix in 4 bytes
* </pre>
*
* <code>bytes sender = 1;</code>
*/
public Builder clearSender() {
sender_ = getDefaultInstance().getSender();
onChanged();
return this;
}
private Object symbol_ = "";
/**
* <pre>
* symbol for trading pair in full name of the tokens
* </pre>
*
* <code>string symbol = 2;</code>
*/
public String getSymbol() {
Object ref = symbol_;
if (!(ref instanceof String)) {
com.google.protobuf.ByteString bs =
(com.google.protobuf.ByteString) ref;
String s = bs.toStringUtf8();
symbol_ = s;
return s;
} else {
return (String) ref;
}
}
/**
* <pre>
* symbol for trading pair in full name of the tokens
* </pre>
*
* <code>string symbol = 2;</code>
*/
public com.google.protobuf.ByteString
getSymbolBytes() {
Object ref = symbol_;
if (ref instanceof String) {
com.google.protobuf.ByteString b =
com.google.protobuf.ByteString.copyFromUtf8(
(String) ref);
symbol_ = b;
return b;
} else {
return (com.google.protobuf.ByteString) ref;
}
}
/**
* <pre>
* symbol for trading pair in full name of the tokens
* </pre>
*
* <code>string symbol = 2;</code>
*/
public Builder setSymbol(
String value) {
if (value == null) {
throw new NullPointerException();
}
symbol_ = value;
onChanged();
return this;
}
/**
* <pre>
* symbol for trading pair in full name of the tokens
* </pre>
*
* <code>string symbol = 2;</code>
*/
public Builder clearSymbol() {
symbol_ = getDefaultInstance().getSymbol();
onChanged();
return this;
}
/**
* <pre>
* symbol for trading pair in full name of the tokens
* </pre>
*
* <code>string symbol = 2;</code>
*/
public Builder setSymbolBytes(
com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
checkByteStringIsUtf8(value);
symbol_ = value;
onChanged();
return this;
}
private Object refid_ = "";
/**
* <pre>
* order id of the one to cancel
* </pre>
*
* <code>string refid = 3;</code>
*/
public String getRefid() {
Object ref = refid_;
if (!(ref instanceof String)) {
com.google.protobuf.ByteString bs =
(com.google.protobuf.ByteString) ref;
String s = bs.toStringUtf8();
refid_ = s;
return s;
} else {
return (String) ref;
}
}
/**
* <pre>
* order id of the one to cancel
* </pre>
*
* <code>string refid = 3;</code>
*/
public com.google.protobuf.ByteString
getRefidBytes() {
Object ref = refid_;
if (ref instanceof String) {
com.google.protobuf.ByteString b =
com.google.protobuf.ByteString.copyFromUtf8(
(String) ref);
refid_ = b;
return b;
} else {
return (com.google.protobuf.ByteString) ref;
}
}
/**
* <pre>
* order id of the one to cancel
* </pre>
*
* <code>string refid = 3;</code>
*/
public Builder setRefid(
String value) {
if (value == null) {
throw new NullPointerException();
}
refid_ = value;
onChanged();
return this;
}
/**
* <pre>
* order id of the one to cancel
* </pre>
*
* <code>string refid = 3;</code>
*/
public Builder clearRefid() {
refid_ = getDefaultInstance().getRefid();
onChanged();
return this;
}
/**
* <pre>
* order id of the one to cancel
* </pre>
*
* <code>string refid = 3;</code>
*/
public Builder setRefidBytes(
com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
checkByteStringIsUtf8(value);
refid_ = value;
onChanged();
return this;
}
@Override
public final Builder setUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
return super.setUnknownFields(unknownFields);
}
@Override
public final Builder mergeUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
return super.mergeUnknownFields(unknownFields);
}
// @@protoc_insertion_point(builder_scope:transaction.CancelOrder)
}
// @@protoc_insertion_point(class_scope:transaction.CancelOrder)
private static final com.tangem.blockchain.binance.proto.CancelOrder DEFAULT_INSTANCE;
static {
DEFAULT_INSTANCE = new com.tangem.blockchain.binance.proto.CancelOrder();
}
public static com.tangem.blockchain.binance.proto.CancelOrder getDefaultInstance() {
return DEFAULT_INSTANCE;
}
private static final com.google.protobuf.Parser<CancelOrder>
PARSER = new com.google.protobuf.AbstractParser<CancelOrder>() {
@Override
public CancelOrder parsePartialFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return new CancelOrder(input, extensionRegistry);
}
};
public static com.google.protobuf.Parser<CancelOrder> parser() {
return PARSER;
}
@Override
public com.google.protobuf.Parser<CancelOrder> getParserForType() {
return PARSER;
}
@Override
public com.tangem.blockchain.binance.proto.CancelOrder getDefaultInstanceForType() {
return DEFAULT_INSTANCE;
}
}

View file

@ -0,0 +1,54 @@
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: dex.proto
package com.tangem.blockchain.binance.proto;
public interface CancelOrderOrBuilder extends
// @@protoc_insertion_point(interface_extends:transaction.CancelOrder)
com.google.protobuf.MessageOrBuilder {
/**
* <pre>
* 0x166E681B // hardcoded, object type prefix in 4 bytes
* </pre>
*
* <code>bytes sender = 1;</code>
*/
com.google.protobuf.ByteString getSender();
/**
* <pre>
* symbol for trading pair in full name of the tokens
* </pre>
*
* <code>string symbol = 2;</code>
*/
String getSymbol();
/**
* <pre>
* symbol for trading pair in full name of the tokens
* </pre>
*
* <code>string symbol = 2;</code>
*/
com.google.protobuf.ByteString
getSymbolBytes();
/**
* <pre>
* order id of the one to cancel
* </pre>
*
* <code>string refid = 3;</code>
*/
String getRefid();
/**
* <pre>
* order id of the one to cancel
* </pre>
*
* <code>string refid = 3;</code>
*/
com.google.protobuf.ByteString
getRefidBytes();
}

File diff suppressed because it is too large Load diff

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