{"id":20055580,"url":"https://github.com/horizontalsystems/ethereum-kit-android","last_synced_at":"2025-04-04T22:07:23.369Z","repository":{"id":34556479,"uuid":"152531605","full_name":"horizontalsystems/ethereum-kit-android","owner":"horizontalsystems","description":"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. Easily extendable to work with custom smart contracts. Full support for EIP1159.","archived":false,"fork":false,"pushed_at":"2025-02-28T11:30:09.000Z","size":32529,"stargazers_count":108,"open_issues_count":11,"forks_count":57,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-03-28T21:07:27.296Z","etag":null,"topics":["arbitrum","avalanche","avalanche-c-chain","bep20","binance-smart-chain","eip1159","erc-20","erc20","ethereum","ethereum-library","ethereum-sdk","ethereum-wallet","evm","matic","nft","optimism","polygon","solana","web3"],"latest_commit_sha":null,"homepage":"https://unstoppable.money","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/horizontalsystems.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-10-11T04:34:31.000Z","updated_at":"2025-02-28T11:30:12.000Z","dependencies_parsed_at":"2024-03-01T07:30:13.239Z","dependency_job_id":"7cbc8015-ad2a-4d89-ba48-bcd1e8af8883","html_url":"https://github.com/horizontalsystems/ethereum-kit-android","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/horizontalsystems%2Fethereum-kit-android","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/horizontalsystems%2Fethereum-kit-android/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/horizontalsystems%2Fethereum-kit-android/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/horizontalsystems%2Fethereum-kit-android/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/horizontalsystems","download_url":"https://codeload.github.com/horizontalsystems/ethereum-kit-android/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247256112,"owners_count":20909240,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arbitrum","avalanche","avalanche-c-chain","bep20","binance-smart-chain","eip1159","erc-20","erc20","ethereum","ethereum-library","ethereum-sdk","ethereum-wallet","evm","matic","nft","optimism","polygon","solana","web3"],"created_at":"2024-11-13T12:48:32.343Z","updated_at":"2025-04-04T22:07:23.350Z","avatar_url":"https://github.com/horizontalsystems.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# EthereumKit\n\n`EthereumKit` is a native(Kotlin) toolkit for EVM compatible networks. It's implemented and used by [Unstoppable Wallet](https://github.com/horizontalsystems/unstoppable-wallet-android), a multi-currency crypto wallet. It implements a lot of features of the DeFi world natively *(no need for WalletConnect)* out-of-the-box.\n\n## Core Features\n\n- [x] Restore with **mnemonic phrase**, **BIP39 Seed**, **EVM private key**, or simply an **Ethereum address**\n- [x] Local storage of account data (ETH, Token/NFT balance and transactions)\n- [x] Synchronization over **HTTP/WebSocket**\n- [x] **Watch accounts**. Restore with any address\n- [x] Ethereum Name Service **(ENS) support**\n- [x] **EIP-1559** Gas Prices with live updates\n- [x] Reactive-functional API by [`RxAndroid`](https://github.com/ReactiveX/RxAndroid)\n- [x] Implementation of Ethereum's JSON-RPC API\n- [x] Support for Infura and Etherscan\n- [x] Can be extended to natively support any smart contract\n- [x] EIP20 token standard support\n- [x] EIP721 and EIP1155 non-fungible tokens(NFT)\n- [x] Uniswap (PancakeSwap, QuickSwap, Trader Joe) support\n- [x] 1Inch support\n\n## Blockchains supported\n\nAny EVM blockchain that supports the Ethereum's RPC API and has an Etherscan-like block explorer can be easily integrated to your wallet using `EthereumKit`. The following blockchains are currently integrated to `Unstoppable Wallet`:\n\n- Ethereum\n- Binance Smart Chain\n- Polygon\n- ArbitrumOne\n- Optimism\n- Avalanche C-Chain\n\n\n## Usage\n\n### Initialization\n\nFirst you need to initialize an `EthereumKit` instance\n\n```kotlin\nval context = Application()\nval address = Address(\"0x..your..address\")\n\nval evmKit = EthereumKit.getInstance(\n    context,\n    address,\n    Chain.Ethereum,\n    RpcSource.ethereumInfuraHttp(\"projectId\", \"projectSecret\"),\n    TransactionSource.ethereumEtherscan(\"apiKey\"),\n    \"unique_wallet_id\"\n)\n```\n\n### Starting and Stopping\n\n`EthereumKit` instance requires to be started with `start` command. This start the process of synchronization with the blockchain state.\n\n```kotlin\nevmKit.start()\nevmKit.stop()\n```\n\n### Get wallet data\n\nYou can get `account state`, `last block height`, `sync state`, `transactions sync state` and some others synchronously:\n\n```kotlin\nevmKit.accountState?.let { state -\u003e\n    state.balance\n    state.nonce\n}\n\nevmKit.lastBlockHeight\n```\n\nYou also can subscribe to Rx observables of those and more:\n\n```kotlin\nevmKit.accountStateFlowable.subscribe { state -\u003e println(\"balance: ${state.balance}); nonce: ${state.nonce}\") }\nevmKit.lastBlockHeightFlowable.subscribe { height -\u003e println(height) }\nevmKit.syncStateFlowable.subscribe { state -\u003e println(state) }\nevmKit.transactionsSyncStateFlowable.subscribe { state -\u003e println(state) }\n\n// Subscribe to ETH transactions synced by the kit\nevmKit.getFullTransactionsFlowable(listOf(listOf(\"ETH\"))).subscribe { transactions -\u003e \n    println(transactions.size) \n}\n\n// Subscribe to all EVM transactions\nevmKit.allTransactionsFlowable.subscribe { transactionsPair -\u003e \n    println(transactionsPair.first.size) \n}\n```\n\n### Send Transaction\n\nTo send a transaction you need a Signer object. Here's how you can create it using Mnemonic seed phrase:\n\n```kotlin\nval seed = Mnemonic().toSeed(listOf(\"mnemonic\", \"phrase\"), \"passphrase_if_exists'\")\nval signer = Signer.getInstance(seed, Chain.Ethereum)\n```\n\n\nNow you can use it to sign an Ethereum transaction:\n\n\n```kotlin\nval toAddress = Address(\"0x..recipient..address..here\")\nval amount = BigInteger(\"100000000000000000\")                         // 0.1 ETH in WEIs\nval gasPrice = GasPrice.Legacy(50_000_000_000)\n\n// Construct TransactionData which is the key payload of any EVM transaction\nval transactionData = ethereumKit.transferTransactionData(toAddress, amount)\n\n// Estimate gas for the transaction\nval estimateGasSingle = ethereumKit.estimateGas(transactionData, gasPrice)\n\n// Generate a raw transaction which is ready to be signed. This step also synchronizes the nonce\nval rawTransactionSingle = estimateGasSingle.flatMap { estimateGasSingle -\u003e\n    ethereumKit.rawTransaction(transactionData, gasPrice, estimateGasSingle)\n}\n\nval sendSingle = rawTransactionSingle.flatMap { rawTransaction -\u003e\n    // Sign the transaction\n    val signature = signer.signature(rawTransaction)\n\n    // Send the transaction to RPC node\n    ethereumKit.send(rawTransaction, signature)\n}\n\n// This step is needed for Rx reactive code to run\nval disposables = CompositeDisposable()\n\nsendSingle.subscribe { fullTransaction -\u003e\n    // ethereumKit.send returns FullTransaction object that contains transaction and a transaction decoration\n    val transaction = fullTransaction.transaction\n\n    println(\"Transaction sent: ${transaction.hash.toHexString()}\")\n    println(\"To: ${transaction.to?.let { it.eip55 }}\")\n    println(\"Amount: ${transaction.value?.let { it.toString(10) }}\")\n}.let {\n    disposables.add(it)\n}\n```\n\n### Get ETH transactions\n\nThe following code retrieves the transactions that have `ETH` coin incoming or outgoing, including the transactions where `ETH` is received in internal transactions.\n\n```kotlin\nethereumKit.getFullTransactionsAsync(listOf(listOf(\"ETH\")))\n        .subscribe { fullTransactions -\u003e\n            for (fullTransaction in fullTransactions) {\n                println(\"Transaction hash: ${fullTransaction.transaction.hash.toHexString()}\")\n\n                when (val decoration = fullTransaction.decoration) {\n                    is IncomingDecoration -\u003e {\n                        println(\"From: ${decoration.from.eip55}\")\n                        println(\"Amount: ${decoration.value.toString(10)}\")\n                    }\n\n                    is OutgoingDecoration -\u003e {\n                        println(\"To: ${decoration.to.eip55}\")\n                        println(\"Amount: ${decoration.value.toString(10)}\")\n                    }\n                    \n                    else -\u003e {}\n                }\n            }\n        }.let {\n            disposables.add(it)\n        }\n```\n\n## EIP20 tokens\n\n### Initialization\n\n```kotlin\nval contractAddress = Address(\"0x..token..contract..address..\")\nval erc20Kit = Erc20Kit.getInstance(context, ethereumKit, contractAddress)\n\n// Decorators are needed to detect transactions as `Erc20` transfer/approve transactions\nErc20Kit.addTransactionSyncer(ethereumKit)\n        \n// Erc20 transactions syncer is needed to pull Eip20 transfer transactions from Etherscan\nErc20Kit.addDecorators(ethereumKit)\n```\n\n### Get token balance\n\n```kotlin\nerc20Kit.balance?.let { balance -\u003e\n    println(balance.toString(10))\n}\n```\n\n### Send Erc20 transfer transaction\n\n```kotlin\nval toAddress = Address(\"0x..recipient..address..here\")\nval amount = BigInteger(\"100000000000000000\")\nval gasPrice = GasPrice.Legacy(50_000_000_000)\n\n// Construct TransactionData which calls a `Transfer` method of the EIP20 compatible smart contract\nval transactionData = erc20Kit.buildTransferTransactionData(toAddress, amount)\n\nethereumKit.estimateGas(transactionData, gasPrice)\n        .flatMap { estimateGasSingle -\u003e\n            ethereumKit.rawTransaction(transactionData, gasPrice, estimateGasSingle)\n        }\n        .flatMap { rawTransaction -\u003e\n            val signature = signer.signature(rawTransaction)\n            ethereumKit.send(rawTransaction, signature)\n        }\n        .subscribe { fullTransaction -\u003e\n            println(\"Transaction sent: ${fullTransaction.transaction.hash.toHexString()}\")\n\n            val decoration = fullTransaction.decoration as? OutgoingDecoration ?: return@subscribe\n                    \n            println(\"To: ${decoration.to.eip55}\")\n            println(\"Amount: ${decoration.value.toString(10)}\")\n        }.let {\n            disposables.add(it)\n        }\n```\n\n\n### Get Erc20 transactions\n\n```kotlin\nethereumKit.getFullTransactionsAsync(listOf(listOf(contractAddress.eip55)))\n        .subscribe { fullTransactions -\u003e\n            for (fullTransaction in fullTransactions) {\n                println(\"Transaction sent: ${fullTransaction.transaction.hash.toHexString()}\")\n\n                when (val decoration = fullTransaction.decoration) {\n                    is IncomingDecoration -\u003e {\n                        println(\"From: ${decoration.from.eip55}\")\n                        println(\"Amount: ${decoration.value.toString(10)}\")\n                    }\n\n                    is OutgoingDecoration -\u003e {\n                        println(\"To: ${decoration.to.eip55}\")\n                        println(\"Amount: ${decoration.value.toString(10)}\")\n                    }\n\n                    else -\u003e {}\n                }\n            }\n        }.let {\n            disposables.add(it)\n        }\n```\n\n## Uniswap\n\n### Initialization\n\n```kotlin\nval uniswapKit = UniswapKit.getInstance(ethereumKit)\n\n// Decorators are needed to detect and decorate transactions as `Uniswap` transactions\nUniswapKit.addDecorators(ethereumKit)\n```\n\n### Send sample swap transaction\n\n```kotlin\n// Sample swap data\nval tokenIn = uniswapKit.etherToken()\nval tokenOut = uniswapKit.token(Address(\"0x..token..address\"), 18)\nval amount = BigDecimal(1)\nval gasPrice = GasPrice.Legacy(50_000_000_000)\n\n// Get SwapData. SwapData is a list of pairs available in Uniswap smart contract at the moment\nuniswapKit.swapData(tokenIn, tokenOut)\n        .map { swapData -\u003e\n            // Get TradeData. TradeData is the best swap route evaluated by UniswapKit\n            val tradeData = uniswapKit.bestTradeExactIn(swapData, amount)\n\n            // Convert TradeData to EvmKit TransactionData\n            uniswapKit.transactionData(tradeData)\n        }\n        .flatMap { transactionData -\u003e\n            ethereumKit.estimateGas(transactionData, gasPrice)\n                    .flatMap { estimateGasSingle -\u003e\n                        ethereumKit.rawTransaction(transactionData, gasPrice, estimateGasSingle)\n                    }\n        }\n        .flatMap { rawTransaction -\u003e\n            val signature = signer.signature(rawTransaction)\n            ethereumKit.send(rawTransaction, signature)\n        }\n        .subscribe { fullTransaction -\u003e\n            println(\"Transaction sent: ${fullTransaction.transaction.hash.toHexString()}\")\n        }.let {\n            disposables.add(it)\n        }\n```\n\n### ExactIn/ExactOut\n\nWith `UniswapKit` you can build swap transaction that either has an exact `In` or exact `Out` amount. That is, if you want to swap exactly 1 ETH to USDT, you get `TradeData` using `bestTradeExactIn` method. Similarly, if you want to swap ETH to USDT and you want to get exactly 1000 USDT, then you get `TradeData` using `bestTradeExactOut`\n\n### Trade Options\n\n`UniswapKit` supports `Price Impact/Deadline/Recipient` options. You can set them in `TradeOptions` object passed to `bestTradeExactIn/bestTradeExactOut` methods. Please, look at official Uniswap app documentation to learn about those options.\n\n\n## 1Inch\n\n`OneInchKit` is an extension that wraps interactions with [`1Inch API`](https://docs.1inch.io/docs/aggregation-protocol/api/swagger/).\n\n### Initialization\n\n\n```kotlin\nval oneInchKit = OneInchKit.getInstance(ethereumKit)\nOneInchKit.addDecorators(ethereumKit)\n```\n\n### Sample code to get swap data from 1Inch API, sign it and send to RPC node\n\n```kotlin\n// Sample swap data\nval tokenFromAddress = Address(\"0x..from..token..address\")\nval tokenToAddress = Address(\"0x..to..token..address\")\nval amount = BigInteger(\"100000000000000000\")\nval gasPrice = GasPrice.Legacy(50_000_000_000)\n\n// Get Swap object, evaluated transaction data by 1Inch aggregator\noneInchKit.getSwapAsync(\n        fromToken = tokenFromAddress,\n        toToken = tokenToAddress,\n        amount = amount,\n        slippagePercentage = 1F,\n        recipient = null,\n        gasPrice = gasPrice\n)\n        .flatMap { swap -\u003e\n            val tx = swap.transaction\n            val transactionData = TransactionData(tx.to, tx.value, tx.data)\n\n            ethereumKit.rawTransaction(transactionData, gasPrice, tx.gasLimit)\n        }\n        .flatMap { rawTransaction -\u003e\n            val signature = signer.signature(rawTransaction)\n            ethereumKit.send(rawTransaction, signature)\n        }\n        .subscribe { fullTransaction -\u003e\n            println(\"Transaction sent: ${fullTransaction.transaction.hash.toHexString()}\")\n        }.let {\n            disposables.add(it)\n        }\n```\n\n## NFTs\n\nNftKit support EIP721 and EIP1155\n\n### Initialization\n\n```kotlin\nval nftKit = NftKit.getInstance(App.instance, ethereumKit)\n\nnftKit.addEip721Decorators()\nnftKit.addEip1155Decorators()\n\nnftKit.addEip721TransactionSyncer()\nnftKit.addEip1155TransactionSyncer()\n```\n\n### Get NFTs owned by the user\n\n```kotlin\nval nftBalances = nftKit.nftBalances\n\nfor (nftBalance in nftBalances) {\n    println(\"---- ${nftBalance.balance} pieces of ${nftBalance.nft.tokenName} ---\")\n    println(\"Contract Address: ${nftBalance.nft.contractAddress.eip55}\")\n    println(\"TokenID: ${nftBalance.nft.tokenId.toString(10)}\")\n}\n```\n\n\n### Send an NFT\n\n```kotlin\nval nftContractAddress = Address(\"0x..contract..address\")\nval tokenId = BigInteger(\"234123894712031638516723498\")\nval to = Address(\"0x..recipient..address\")\nval gasPrice = GasPrice.Legacy(50_000_000_000)\n\n// Construct a TransactionData\nval transactionData = nftKit.transferEip721TransactionData(nftContractAddress, to, tokenId)\n\nethereumKit.estimateGas(transactionData, gasPrice)\n        .flatMap { estimateGasSingle -\u003e\n            ethereumKit.rawTransaction(transactionData, gasPrice, estimateGasSingle)\n        }\n        .flatMap { rawTransaction -\u003e\n            val signature = signer.signature(rawTransaction)\n            ethereumKit.send(rawTransaction, signature)\n        }\n        .subscribe { fullTransaction -\u003e\n            println(\"Transaction sent: ${fullTransaction.transaction.hash.toHexString()}\")\n        }.let {\n            disposables.add(it)\n        }\n```\n\n\n## Extending\n\n### Smart contract call\n\nIn order to send an EVM smart contract call transaction, you need to create an instance of `TransactionData` object. Then you can sign and send it as seen above.\n\n\n## Prerequisites\n* JDK \u003e= 11\n* Android 8 (minSdkVersion 26) or greater\n\n## Installation\nAdd the JitPack to module build.gradle\n```\nrepositories {\n    maven { url 'https://jitpack.io' }\n}\n```\nAdd the following dependency to your build.gradle file:\n```\ndependencies {\n    implementation 'com.github.horizontalsystems:ethereum-kit-android:master-SNAPSHOT'\n}\n```\n\n## Example App\n\nAll features of the library are used in example project. It can be referred as a starting point for usage of the library.\n* [Example App](https://github.com/horizontalsystems/ethereum-kit-android/tree/master/app)\n\n## License\n\nThe `EthereumKit` is open source and available under the terms of the [MIT License](https://github.com/horizontalsystems/ethereum-kit-android/blob/master/LICENSE)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhorizontalsystems%2Fethereum-kit-android","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhorizontalsystems%2Fethereum-kit-android","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhorizontalsystems%2Fethereum-kit-android/lists"}