Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Comprehensive EVM SDK (Ethereum, Binance Smart Chain, Avalanche, Arbitrum, Optimism, Polygon) for Android, implemented on Kotlin. Create wallets, watch wallets (read-only), sync transactions, filter transactions by type (erc20, bep20, swap transactions etc.), swap using native DEX protocols, connect to DeFi smart contracts using WalletConnect. E…

License

NotificationsYou must be signed in to change notification settings

horizontalsystems/ethereum-kit-android

Repository files navigation

EthereumKit is a native(Kotlin) toolkit for EVM compatible networks. It's implemented and used byUnstoppable Wallet, a multi-currency crypto wallet. It implements a lot of features of the DeFi world natively(no need for WalletConnect) out-of-the-box.

Core Features

  • Restore withmnemonic phrase,BIP39 Seed,EVM private key, or simply anEthereum address
  • Local storage of account data (ETH, Token/NFT balance and transactions)
  • Synchronization overHTTP/WebSocket
  • Watch accounts. Restore with any address
  • Ethereum Name Service(ENS) support
  • EIP-1559 Gas Prices with live updates
  • Reactive-functional API byRxAndroid
  • Implementation of Ethereum's JSON-RPC API
  • Support for Infura and Etherscan
  • Can be extended to natively support any smart contract
  • EIP20 token standard support
  • EIP721 and EIP1155 non-fungible tokens(NFT)
  • Uniswap (PancakeSwap, QuickSwap, Trader Joe) support
  • 1Inch support

Blockchains supported

Any EVM blockchain that supports the Ethereum's RPC API and has an Etherscan-like block explorer can be easily integrated to your wallet usingEthereumKit. The following blockchains are currently integrated toUnstoppable Wallet:

  • Ethereum
  • Binance Smart Chain
  • Polygon
  • ArbitrumOne
  • Optimism
  • Avalanche C-Chain

Usage

Initialization

First you need to initialize anEthereumKit instance

val context=Application()val address=Address("0x..your..address")val evmKit=EthereumKit.getInstance(    context,    address,Chain.Ethereum,RpcSource.ethereumInfuraHttp("projectId","projectSecret"),TransactionSource.ethereumEtherscan("apiKey"),"unique_wallet_id")

Starting and Stopping

EthereumKit instance requires to be started withstart command. This start the process of synchronization with the blockchain state.

evmKit.start()evmKit.stop()

Get wallet data

You can getaccount state,last block height,sync state,transactions sync state and some others synchronously:

evmKit.accountState?.let { state->    state.balance    state.nonce}evmKit.lastBlockHeight

You also can subscribe to Rx observables of those and more:

evmKit.accountStateFlowable.subscribe { state->println("balance:${state.balance}); nonce:${state.nonce}") }evmKit.lastBlockHeightFlowable.subscribe { height->println(height) }evmKit.syncStateFlowable.subscribe { state->println(state) }evmKit.transactionsSyncStateFlowable.subscribe { state->println(state) }// Subscribe to ETH transactions synced by the kitevmKit.getFullTransactionsFlowable(listOf(listOf("ETH"))).subscribe { transactions->println(transactions.size) }// Subscribe to all EVM transactionsevmKit.allTransactionsFlowable.subscribe { transactionsPair->println(transactionsPair.first.size) }

Send Transaction

To send a transaction you need a Signer object. Here's how you can create it using Mnemonic seed phrase:

val seed=Mnemonic().toSeed(listOf("mnemonic","phrase"),"passphrase_if_exists'")val signer=Signer.getInstance(seed,Chain.Ethereum)

Now you can use it to sign an Ethereum transaction:

val toAddress=Address("0x..recipient..address..here")val amount=BigInteger("100000000000000000")// 0.1 ETH in WEIsval gasPrice=GasPrice.Legacy(50_000_000_000)// Construct TransactionData which is the key payload of any EVM transactionval transactionData= ethereumKit.transferTransactionData(toAddress, amount)// Estimate gas for the transactionval estimateGasSingle= ethereumKit.estimateGas(transactionData, gasPrice)// Generate a raw transaction which is ready to be signed. This step also synchronizes the nonceval rawTransactionSingle= estimateGasSingle.flatMap { estimateGasSingle->    ethereumKit.rawTransaction(transactionData, gasPrice, estimateGasSingle)}val sendSingle= rawTransactionSingle.flatMap { rawTransaction->// Sign the transactionval signature= signer.signature(rawTransaction)// Send the transaction to RPC node    ethereumKit.send(rawTransaction, signature)}// This step is needed for Rx reactive code to runval disposables=CompositeDisposable()sendSingle.subscribe { fullTransaction->// ethereumKit.send returns FullTransaction object that contains transaction and a transaction decorationval transaction= fullTransaction.transactionprintln("Transaction sent:${transaction.hash.toHexString()}")println("To:${transaction.to?.let { it.eip55 }}")println("Amount:${transaction.value?.let { it.toString(10) }}")}.let {    disposables.add(it)}

Get ETH transactions

The following code retrieves the transactions that haveETH coin incoming or outgoing, including the transactions whereETH is received in internal transactions.

ethereumKit.getFullTransactionsAsync(listOf(listOf("ETH")))        .subscribe { fullTransactions->for (fullTransactionin fullTransactions) {println("Transaction hash:${fullTransaction.transaction.hash.toHexString()}")when (val decoration= fullTransaction.decoration) {isIncomingDecoration-> {println("From:${decoration.from.eip55}")println("Amount:${decoration.value.toString(10)}")                    }isOutgoingDecoration-> {println("To:${decoration.to.eip55}")println("Amount:${decoration.value.toString(10)}")                    }else-> {}                }            }        }.let {            disposables.add(it)        }

EIP20 tokens

Initialization

val contractAddress=Address("0x..token..contract..address..")val erc20Kit=Erc20Kit.getInstance(context, ethereumKit, contractAddress)// Decorators are needed to detect transactions as `Erc20` transfer/approve transactionsErc20Kit.addTransactionSyncer(ethereumKit)// Erc20 transactions syncer is needed to pull Eip20 transfer transactions from EtherscanErc20Kit.addDecorators(ethereumKit)

Get token balance

erc20Kit.balance?.let { balance->println(balance.toString(10))}

Send Erc20 transfer transaction

val toAddress=Address("0x..recipient..address..here")val amount=BigInteger("100000000000000000")val gasPrice=GasPrice.Legacy(50_000_000_000)// Construct TransactionData which calls a `Transfer` method of the EIP20 compatible smart contractval transactionData= erc20Kit.buildTransferTransactionData(toAddress, amount)ethereumKit.estimateGas(transactionData, gasPrice)        .flatMap { estimateGasSingle->            ethereumKit.rawTransaction(transactionData, gasPrice, estimateGasSingle)        }        .flatMap { rawTransaction->val signature= signer.signature(rawTransaction)            ethereumKit.send(rawTransaction, signature)        }        .subscribe { fullTransaction->println("Transaction sent:${fullTransaction.transaction.hash.toHexString()}")val decoration= fullTransaction.decorationas?OutgoingDecoration?:return@subscribeprintln("To:${decoration.to.eip55}")println("Amount:${decoration.value.toString(10)}")        }.let {            disposables.add(it)        }

Get Erc20 transactions

ethereumKit.getFullTransactionsAsync(listOf(listOf(contractAddress.eip55)))        .subscribe { fullTransactions->for (fullTransactionin fullTransactions) {println("Transaction sent:${fullTransaction.transaction.hash.toHexString()}")when (val decoration= fullTransaction.decoration) {isIncomingDecoration-> {println("From:${decoration.from.eip55}")println("Amount:${decoration.value.toString(10)}")                    }isOutgoingDecoration-> {println("To:${decoration.to.eip55}")println("Amount:${decoration.value.toString(10)}")                    }else-> {}                }            }        }.let {            disposables.add(it)        }

Uniswap

Initialization

val uniswapKit=UniswapKit.getInstance(ethereumKit)// Decorators are needed to detect and decorate transactions as `Uniswap` transactionsUniswapKit.addDecorators(ethereumKit)

Send sample swap transaction

// Sample swap dataval tokenIn= uniswapKit.etherToken()val tokenOut= uniswapKit.token(Address("0x..token..address"),18)val amount=BigDecimal(1)val gasPrice=GasPrice.Legacy(50_000_000_000)// Get SwapData. SwapData is a list of pairs available in Uniswap smart contract at the momentuniswapKit.swapData(tokenIn, tokenOut)        .map { swapData->// Get TradeData. TradeData is the best swap route evaluated by UniswapKitval tradeData= uniswapKit.bestTradeExactIn(swapData, amount)// Convert TradeData to EvmKit TransactionData            uniswapKit.transactionData(tradeData)        }        .flatMap { transactionData->            ethereumKit.estimateGas(transactionData, gasPrice)                    .flatMap { estimateGasSingle->                        ethereumKit.rawTransaction(transactionData, gasPrice, estimateGasSingle)                    }        }        .flatMap { rawTransaction->val signature= signer.signature(rawTransaction)            ethereumKit.send(rawTransaction, signature)        }        .subscribe { fullTransaction->println("Transaction sent:${fullTransaction.transaction.hash.toHexString()}")        }.let {            disposables.add(it)        }

ExactIn/ExactOut

WithUniswapKit you can build swap transaction that either has an exactIn or exactOut amount. That is, if you want to swap exactly 1 ETH to USDT, you getTradeData usingbestTradeExactIn method. Similarly, if you want to swap ETH to USDT and you want to get exactly 1000 USDT, then you getTradeData usingbestTradeExactOut

Trade Options

UniswapKit supportsPrice Impact/Deadline/Recipient options. You can set them inTradeOptions object passed tobestTradeExactIn/bestTradeExactOut methods. Please, look at official Uniswap app documentation to learn about those options.

1Inch

OneInchKit is an extension that wraps interactions with1Inch API.

Initialization

val oneInchKit=OneInchKit.getInstance(ethereumKit)OneInchKit.addDecorators(ethereumKit)

Sample code to get swap data from 1Inch API, sign it and send to RPC node

// Sample swap dataval tokenFromAddress=Address("0x..from..token..address")val tokenToAddress=Address("0x..to..token..address")val amount=BigInteger("100000000000000000")val gasPrice=GasPrice.Legacy(50_000_000_000)// Get Swap object, evaluated transaction data by 1Inch aggregatoroneInchKit.getSwapAsync(        fromToken= tokenFromAddress,        toToken= tokenToAddress,        amount= amount,        slippagePercentage=1F,        recipient=null,        gasPrice= gasPrice)        .flatMap { swap->val tx= swap.transactionval transactionData=TransactionData(tx.to, tx.value, tx.data)            ethereumKit.rawTransaction(transactionData, gasPrice, tx.gasLimit)        }        .flatMap { rawTransaction->val signature= signer.signature(rawTransaction)            ethereumKit.send(rawTransaction, signature)        }        .subscribe { fullTransaction->println("Transaction sent:${fullTransaction.transaction.hash.toHexString()}")        }.let {            disposables.add(it)        }

NFTs

NftKit support EIP721 and EIP1155

Initialization

val nftKit=NftKit.getInstance(App.instance, ethereumKit)nftKit.addEip721Decorators()nftKit.addEip1155Decorators()nftKit.addEip721TransactionSyncer()nftKit.addEip1155TransactionSyncer()

Get NFTs owned by the user

val nftBalances= nftKit.nftBalancesfor (nftBalancein nftBalances) {println("----${nftBalance.balance} pieces of${nftBalance.nft.tokenName} ---")println("Contract Address:${nftBalance.nft.contractAddress.eip55}")println("TokenID:${nftBalance.nft.tokenId.toString(10)}")}

Send an NFT

val nftContractAddress=Address("0x..contract..address")val tokenId=BigInteger("234123894712031638516723498")val to=Address("0x..recipient..address")val gasPrice=GasPrice.Legacy(50_000_000_000)// Construct a TransactionDataval transactionData= nftKit.transferEip721TransactionData(nftContractAddress, to, tokenId)ethereumKit.estimateGas(transactionData, gasPrice)        .flatMap { estimateGasSingle->            ethereumKit.rawTransaction(transactionData, gasPrice, estimateGasSingle)        }        .flatMap { rawTransaction->val signature= signer.signature(rawTransaction)            ethereumKit.send(rawTransaction, signature)        }        .subscribe { fullTransaction->println("Transaction sent:${fullTransaction.transaction.hash.toHexString()}")        }.let {            disposables.add(it)        }

Extending

Smart contract call

In order to send an EVM smart contract call transaction, you need to create an instance ofTransactionData object. Then you can sign and send it as seen above.

Prerequisites

  • JDK >= 11
  • Android 8 (minSdkVersion 26) or greater

Installation

Add the JitPack to module build.gradle

repositories {    maven { url 'https://jitpack.io' }}

Add the following dependency to your build.gradle file:

dependencies {    implementation 'com.github.horizontalsystems:ethereum-kit-android:master-SNAPSHOT'}

Example App

All features of the library are used in example project. It can be referred as a starting point for usage of the library.

License

TheEthereumKit is open source and available under the terms of theMIT License

About

Comprehensive EVM SDK (Ethereum, Binance Smart Chain, Avalanche, Arbitrum, Optimism, Polygon) for Android, implemented on Kotlin. Create wallets, watch wallets (read-only), sync transactions, filter transactions by type (erc20, bep20, swap transactions etc.), swap using native DEX protocols, connect to DeFi smart contracts using WalletConnect. E…

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors6


[8]ページ先頭

©2009-2025 Movatter.jp