- Notifications
You must be signed in to change notification settings - Fork58
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
horizontalsystems/ethereum-kit-android
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
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.
- 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 by
RxAndroid
- 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
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
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")
EthereumKit
instance requires to be started withstart
command. This start the process of synchronization with the blockchain state.
evmKit.start()evmKit.stop()
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) }
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)}
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) }
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)
erc20Kit.balance?.let { balance->println(balance.toString(10))}
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) }
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) }
val uniswapKit=UniswapKit.getInstance(ethereumKit)// Decorators are needed to detect and decorate transactions as `Uniswap` transactionsUniswapKit.addDecorators(ethereumKit)
// 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) }
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
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.
OneInchKit
is an extension that wraps interactions with1Inch API
.
val oneInchKit=OneInchKit.getInstance(ethereumKit)OneInchKit.addDecorators(ethereumKit)
// 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) }
NftKit support EIP721 and EIP1155
val nftKit=NftKit.getInstance(App.instance, ethereumKit)nftKit.addEip721Decorators()nftKit.addEip1155Decorators()nftKit.addEip721TransactionSyncer()nftKit.addEip1155TransactionSyncer()
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)}")}
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) }
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.
- JDK >= 11
- Android 8 (minSdkVersion 26) or greater
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'}
All features of the library are used in example project. It can be referred as a starting point for usage of the library.
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
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Contributors6
Uh oh!
There was an error while loading.Please reload this page.