{"id":30143153,"url":"https://github.com/phantomydn/1inch-java-sdk","last_synced_at":"2025-08-11T06:50:23.223Z","repository":{"id":305813993,"uuid":"1023418291","full_name":"PhantomYdn/1inch-java-sdk","owner":"PhantomYdn","description":"A Java SDK for the 1inch API, providing easy integration with 1inch's DevPortal API services.","archived":false,"fork":false,"pushed_at":"2025-07-22T06:21:34.000Z","size":80,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-07-22T06:47:57.345Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PhantomYdn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null}},"created_at":"2025-07-21T06:19:59.000Z","updated_at":"2025-07-22T06:21:38.000Z","dependencies_parsed_at":"2025-07-22T06:48:00.745Z","dependency_job_id":"29dc5fa3-e422-4469-9fc1-038a9d44a44c","html_url":"https://github.com/PhantomYdn/1inch-java-sdk","commit_stats":null,"previous_names":["phantomydn/1inch-java-sdk"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/PhantomYdn/1inch-java-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhantomYdn%2F1inch-java-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhantomYdn%2F1inch-java-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhantomYdn%2F1inch-java-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhantomYdn%2F1inch-java-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PhantomYdn","download_url":"https://codeload.github.com/PhantomYdn/1inch-java-sdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhantomYdn%2F1inch-java-sdk/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269843709,"owners_count":24484116,"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","status":"online","status_checked_at":"2025-08-11T02:00:10.019Z","response_time":75,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2025-08-11T06:50:17.579Z","updated_at":"2025-08-11T06:50:23.182Z","avatar_url":"https://github.com/PhantomYdn.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 1inch Java SDK\n\nA comprehensive Java SDK for the 1inch DEX Aggregation Protocol, providing easy integration with 1inch's swap, token, token-details, orderbook, and history services.\n\n## Features\n\n- ✅ Java 11 compatible\n- ✅ Modern reactive programming with RxJava 3\n- ✅ Interface-driven design for easy testing and mocking\n- ✅ Multiple programming approaches: reactive, synchronous, and asynchronous\n- ✅ OkHttp with HTTP/2 support and connection pooling\n- ✅ Type-safe REST API integration with Retrofit 2\n- ✅ Comprehensive error handling\n- ✅ Built-in logging with SLF4J\n- ✅ Full Swap API support with chainId path parameters\n- ✅ Complete Token API with multi-chain support\n- ✅ Token Details API with pricing and chart data\n- ✅ Orderbook API for limit order management\n- ✅ History API for transaction history tracking\n- ✅ Portfolio API for DeFi position tracking and analytics\n- ✅ Balance API for token balance and allowance checking\n- ✅ Price API for real-time token pricing across 60+ currencies\n- ✅ Fusion API for gasless swaps with professional market makers\n- ✅ FusionPlus API for cross-chain gasless swaps with enhanced security\n- ✅ Type-safe models with Jackson and BigInteger precision\n- ✅ Extensive unit test coverage\n\n## Project Structure\n\nThis project is organized as a multi-module Maven project:\n\n- **`oneinch-sdk-core`** - The core SDK functionality with all APIs and models\n- **`oneinch-sdk-examples`** - Example applications demonstrating SDK usage\n\n## Installation\n\nAdd the core SDK dependency to your `pom.xml`:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.oneinch.sdk\u003c/groupId\u003e\n    \u003cartifactId\u003eoneinch-sdk-core\u003c/artifactId\u003e\n    \u003cversion\u003e1.0-SNAPSHOT\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Building from Source\n\n### Build Everything\n```bash\ngit clone https://github.com/1inch/1inch-java-sdk.git\ncd 1inch-java-sdk\nmvn clean install\n```\n\n### Build Only Core SDK\n```bash\nmvn clean install -pl oneinch-sdk-core\n```\n\n### Build Only Examples  \n```bash\nmvn clean install -pl oneinch-sdk-examples\n```\n\n## High-Precision Arithmetic\n\nThe SDK uses `BigInteger` for all amount-related fields to ensure precision when handling cryptocurrency values, which can exceed the range of standard numeric types:\n\n- **Amount fields**: `QuoteRequest.amount`, `SwapRequest.amount`\n- **Response amounts**: `QuoteResponse.dstAmount`, `SwapResponse.dstAmount`\n- **Gas-related fields**: `gasPrice`, `gasLimit`, `gas`\n- **Transaction values**: `TransactionData.value`, `TransactionData.gasPrice`\n- **Token allowances**: `AllowanceResponse.allowance`\n\n```java\nimport java.math.BigInteger;\n\n// Wei amounts (18 decimals for ETH)\nBigInteger oneEth = new BigInteger(\"1000000000000000000\");\nBigInteger halfEth = new BigInteger(\"500000000000000000\");\n\n// Gas price in wei (20 gwei)\nBigInteger gasPrice = new BigInteger(\"20000000000\");\n\nQuoteRequest request = QuoteRequest.builder()\n    .amount(oneEth)\n    .gasPrice(gasPrice)\n    .build();\n```\n\n**Why BigInteger?**\n- Ethereum amounts are measured in wei (10^18 units per ETH)\n- Values can exceed `Long.MAX_VALUE` (9,223,372,036,854,775,807)\n- BigInteger prevents overflow and precision loss\n- Native JSON serialization support via Jackson\n\n## Programming Approaches\n\nThe SDK supports three programming approaches to fit different use cases:\n\n### 🔄 Reactive (RxJava)\n- **Best for**: Complex async workflows, chaining operations, backpressure handling\n- **Returns**: `Single\u003cT\u003e` for reactive composition\n- **Example**: `client.swap().getQuoteRx(request)`\n\n### ⚡ Synchronous \n- **Best for**: Simple scripts, blocking workflows, traditional programming\n- **Returns**: Direct response objects\n- **Example**: `client.swap().getQuote(request)`\n\n### 🚀 Asynchronous (CompletableFuture)\n- **Best for**: Java 8+ async patterns, parallel execution\n- **Returns**: `CompletableFuture\u003cT\u003e` for async composition  \n- **Example**: `client.swap().getQuoteAsync(request)`\n\n## Quick Start\n\n### Reactive Approach\n\n```java\nimport io.oneinch.sdk.client.OneInchClient;\nimport io.oneinch.sdk.model.QuoteRequest;\nimport io.oneinch.sdk.model.QuoteResponse;\nimport lombok.extern.slf4j.Slf4j;\nimport java.math.BigInteger;\n\n@Slf4j\npublic class ReactiveExample {\n    public void getQuote() {\n        // Initialize the client (using ONEINCH_API_KEY environment variable)\n        try (OneInchClient client = OneInchClient.builder()\n                .build()) {\n            \n            // Get a quote for swapping ETH to 1INCH (reactive)\n            QuoteRequest quoteRequest = QuoteRequest.builder()\n                .chainId(1)  // Ethereum\n                .src(\"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\")  // ETH\n                .dst(\"0x111111111117dc0aa78b770fa6a738034120c302\")  // 1INCH\n                .amount(new BigInteger(\"10000000000000000\"))  // 0.01 ETH in wei\n                .includeTokensInfo(true)\n                .build();\n            \n            client.swap().getQuoteRx(quoteRequest)\n                .doOnSuccess(quote -\u003e {\n                    log.info(\"Expected output: {} {}\", quote.getDstAmount(),\n                            quote.getDstToken() != null ? quote.getDstToken().getSymbol() : \"tokens\");\n                })\n                .doOnError(error -\u003e log.error(\"Error getting quote\", error))\n                .subscribe();\n        }\n    }\n}\n```\n\n### Synchronous Approach\n\n```java\nimport lombok.extern.slf4j.Slf4j;\nimport java.math.BigInteger;\n\n@Slf4j\npublic class SynchronousExample {\n    public void getQuote() {\n        try (OneInchClient client = OneInchClient.builder()\n                .apiKey(\"your-api-key-here\")  // Or omit this to use ONEINCH_API_KEY env var\n                .build()) {\n            \n            QuoteRequest quoteRequest = QuoteRequest.builder()\n                .chainId(1)  // Ethereum\n                .src(\"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\")  // ETH\n                .dst(\"0x111111111117dc0aa78b770fa6a738034120c302\")  // 1INCH\n                .amount(new BigInteger(\"10000000000000000\"))  // 0.01 ETH in wei\n                .build();\n            \n            QuoteResponse quote = client.swap().getQuote(quoteRequest);\n            log.info(\"Expected output: {}\", quote.getDstAmount());\n        } catch (OneInchException e) {\n            log.error(\"Error getting quote: {}\", e.getMessage());\n        }\n    }\n}\n```\n\n## API Coverage\n\n### Swap API (`client.swap()`) - **Chain-Specific**\nAll Swap API operations require a specific chainId and operate on that blockchain:\n- ✅ `getQuote(chainId, ...)` - Find the best quote to swap on specific chain\n- ✅ `getSwap(chainId, ...)` - Generate calldata for swap execution on specific chain\n- ✅ `getSpender(chainId)` - Get 1inch Router address for specific chain\n- ✅ `getApproveTransaction(chainId, ...)` - Generate token approval calldata for specific chain\n- ✅ `getAllowance(chainId, ...)` - Check token allowance on specific chain\n\n### Token API (`client.token()`) - **Multi-Chain + Chain-Specific**\nSupports both multi-chain operations and chain-specific queries:\n\n**Multi-Chain Operations:**\n- ✅ `getMultiChainTokens()` - Get whitelisted tokens across all chains\n- ✅ `getMultiChainTokenList()` - Get token list across all chains\n- ✅ `searchMultiChainTokens()` - Search tokens across multiple chains\n\n**Chain-Specific Operations:**\n- ✅ `getTokens(chainId, ...)` - Get whitelisted tokens for specific chain\n- ✅ `getTokenList(chainId, ...)` - Get chain-specific token list in standard format\n- ✅ `searchTokens(chainId, ...)` - Search tokens on specific chain\n- ✅ `getCustomTokens(chainId, ...)` - Get token info for multiple custom addresses on specific chain\n- ✅ `getCustomToken(chainId, address)` - Get token info for single custom address on specific chain\n\n### Token Details API (`client.tokenDetails()`) - **Chain-Specific**\nAll Token Details operations require a specific chainId:\n- ✅ `getTokenDetails(chainId, address, ...)` - Get token details with pricing data for specific chain\n- ✅ `getTokenChart(chainId, address, ...)` - Get token price chart data for specific chain\n- ✅ `getTokenPriceChange(chainId, address, ...)` - Get token price changes over time for specific chain\n- ✅ `getNativeTokenDetails(chainId, ...)` - Get native token details with pricing for specific chain\n- ✅ `getNativeTokenChart(chainId, ...)` - Get native token chart data for specific chain\n- ✅ `getNativeTokenChartByRange(chainId, ...)` - Get native token chart for date range on specific chain\n- ✅ `getNativeTokenChartByInterval(chainId, ...)` - Get native token chart by interval for specific chain\n- ✅ `getNativeTokenPriceChange(chainId, ...)` - Get native token price changes for specific chain\n- ✅ `getMultiChainTokenPriceChange(tokens)` - Get multi-chain token price changes (accepts list of chain/token pairs)\n\n### Orderbook API (`client.orderbook()`) - **Chain-Specific**  \nAll Orderbook operations require a specific chainId:\n- ✅ `createLimitOrder(chainId, ...)` - Create a new limit order on specific chain\n- ✅ `getLimitOrdersByAddress(chainId, address, ...)` - Get orders for specific address on specific chain\n- ✅ `getOrderByOrderHash(chainId, orderHash)` - Get order by hash on specific chain\n- ✅ `getAllLimitOrders(chainId, ...)` - Get all limit orders with filters on specific chain\n- ✅ `getOrdersCount(chainId, ...)` - Get count of orders by filters on specific chain\n- ✅ `getEventsByOrderHash(chainId, orderHash, ...)` - Get events for specific order on specific chain\n- ✅ `getAllEvents(chainId, ...)` - Get all order events on specific chain\n- ✅ `hasActiveOrdersWithPermit(chainId, ...)` - Check active orders with permit on specific chain\n- ✅ `getUniqueActivePairs(chainId, ...)` - Get unique active trading pairs on specific chain\n\n### History API (`client.history()`) - **Multi-Chain**\nHistory operations can work across chains with optional chainId filtering:\n- ✅ `getHistoryEvents(address, chainId?, ...)` - Get transaction history for an address with optional chain filtering\n\n### Portfolio API (`client.portfolio()`) - **Multi-Chain**\nPortfolio operations provide comprehensive DeFi position tracking and analytics:\n- ✅ `getServiceStatus()` - Check Portfolio API service availability\n- ✅ `getSupportedChains()` - Get list of supported blockchain networks\n- ✅ `getSupportedProtocols()` - Get list of supported DeFi protocols\n- ✅ `checkAddresses(addresses)` - Validate wallet addresses for portfolio tracking\n- ✅ `getCurrentValue(request)` - Get current portfolio value breakdown by address, category, and chain\n- ✅ `getProtocolsSnapshot(request)` - Get detailed protocol positions and underlying tokens\n- ✅ `getTokensSnapshot(request)` - Get token positions across all DeFi protocols\n- ✅ `getProtocolsMetrics(request)` - Get profit/loss, ROI, and APR metrics for protocol positions\n- ✅ `getTokensMetrics(request)` - Get profit/loss, ROI, and APR metrics for token positions\n\n### Price API (`client.price()`) - **Chain-Specific**\nReal-time token pricing across multiple currencies and chains:\n- ✅ `getWhitelistPrices(chainId, currency)` - Get prices for all whitelisted tokens on specific chain\n- ✅ `getPrices(request)` - Get prices for specific token addresses with currency conversion\n- ✅ `getPrice(chainId, address, currency)` - Get price for single token with currency conversion\n- ✅ `getSupportedCurrencies(chainId)` - Get list of supported fiat currencies for price conversion\n\n**Currency Support**: 60+ fiat currencies (USD, EUR, JPY, GBP, CNY, etc.) + native Wei format\n**Multi-Chain**: 13+ blockchain networks supported\n\n### Fusion API (`client.fusionOrders()`, `client.fusionQuoter()`, `client.fusionRelayer()`) - **Chain-Specific**\n1inch's revolutionary gasless swap technology with professional market makers:\n- ✅ `getQuote(request)` - Get quotes with auction presets (fast/medium/slow/custom)\n- ✅ `getQuoteWithCustomPresets(request, preset)` - Get quotes with custom auction parameters\n- ✅ `getActiveOrders(request)` - Get currently active orders in the Fusion network\n- ✅ `getSettlementContract(chainId)` - Get settlement contract address for chain\n- ✅ `getOrderByOrderHash(chainId, hash)` - Get order status and fills by hash\n- ✅ `getOrdersByOrderHashes(chainId, request)` - Get multiple orders by hashes\n- ✅ `getOrdersByMaker(request)` - Get order history for specific maker address\n- ✅ `submitOrder(chainId, signedOrder)` - Submit single order to Fusion network\n- ✅ `submitManyOrders(chainId, signedOrders)` - Submit multiple orders in batch\n\n### FusionPlus API (`client.fusionPlusOrders()`, `client.fusionPlusQuoter()`, `client.fusionPlusRelayer()`) - **Cross-Chain**\n1inch's next-generation cross-chain gasless swap technology with enhanced security:\n- ✅ `getQuote(request)` - Get cross-chain quotes with escrow and time lock configurations\n- ✅ `getQuoteWithCustomPresets(request, preset)` - Get cross-chain quotes with custom auction parameters\n- ✅ `buildQuoteTypedData(request, body)` - Build cross-chain orders with EIP712 typed data and secret hashes\n- ✅ `getActiveOrders(request)` - Get currently active cross-chain orders in the FusionPlus network\n- ✅ `getOrderByOrderHash(srcChain, dstChain, hash)` - Get cross-chain order status by hash\n- ✅ `getOrdersByOrderHashes(srcChain, dstChain, hashes)` - Get multiple cross-chain orders by hashes\n- ✅ `getOrdersByMaker(srcChain, dstChain, address, page, limit)` - Get cross-chain order history for maker\n- ✅ `getEscrowEvents(srcChain, dstChain, orderHash, page, limit)` - Get escrow events for cross-chain orders\n- ✅ `getPublicActions(srcChain, dstChain, orderHash)` - Get available public actions for cross-chain orders\n- ✅ `getSupportedChains()` - Get list of supported chains for FusionPlus\n- ✅ `submitOrder(srcChainId, signedOrder)` - Submit single cross-chain order to FusionPlus network\n- ✅ `submitManyOrders(srcChainId, signedOrders)` - Submit multiple cross-chain orders in batch\n- ✅ `submitSecret(chainId, secretInput)` - Submit secret for cross-chain order execution (atomic swap completion)\n\n### Balance API (`client.balance()`) - **Chain-Specific**\nBalance operations provide token balance and allowance checking across different chains:\n- ✅ `getBalances(request)` - Get all token balances for a wallet address on specific chain\n- ✅ `getCustomBalances(request)` - Get balances for specific tokens on specific chain\n- ✅ `getAllowances(request)` - Get token allowances by spender for wallet on specific chain\n- ✅ `getCustomAllowances(request)` - Get allowances for specific tokens by spender on specific chain\n- ✅ `getAllowancesAndBalances(request)` - Get combined balance and allowance data on specific chain\n- ✅ `getCustomAllowancesAndBalances(request)` - Get combined data for specific tokens on specific chain\n- ✅ `getAggregatedBalancesAndAllowances(request)` - Get aggregated data for multiple wallets on specific chain\n- ✅ `getBalancesByMultipleWallets(request)` - Get balances for multiple wallets and tokens on specific chain\n\n## Configuration\n\n### Authentication\nYou need a valid API key from 1inch. Get one at [1inch Developer Portal](https://portal.1inch.dev/).\n\n#### Using Explicit API Key\n```java\nOneInchClient client = OneInchClient.builder()\n    .apiKey(\"your-api-key\")\n    .build();\n```\n\n#### Using Environment Variable\nSet the `ONEINCH_API_KEY` environment variable:\n```bash\nexport ONEINCH_API_KEY=\"your-api-key-here\"\n```\n\nThen create the client without explicitly providing the API key:\n```java\n// Reads API key from ONEINCH_API_KEY environment variable\nOneInchClient client = OneInchClient.builder().build();\n\n// Or use the parameterless constructor\nOneInchClient client = new OneInchClient();\n```\n\n**Priority**: Explicit API key takes precedence over environment variable.\n\n### Custom OkHttp Client\n```java\nOkHttpClient customOkHttpClient = new OkHttpClient.Builder()\n    .connectTimeout(30, TimeUnit.SECONDS)\n    .readTimeout(30, TimeUnit.SECONDS)\n    .build();\n\nOneInchClient client = OneInchClient.builder()\n    .apiKey(\"your-api-key\")\n    .okHttpClient(customOkHttpClient)\n    .build();\n```\n\n## Examples\n\n### Comprehensive Example Classes\n\nThe SDK includes complete example classes demonstrating all APIs:\n\n- **`SwapExample.java`** - Complete swap workflows (reactive, synchronous, parallel)\n- **`TokenExample.java`** - Token list, search, and custom token operations\n- **`TokenDetailsExample.java`** - Token pricing, charts, and market data\n- **`OrderbookExample.java`** - Limit orders, events, and trading pairs\n- **`HistoryExample.java`** - Transaction history tracking and analysis\n- **`HistoryConsoleExample.java`** - Command-line tool for displaying transaction history\n- **`PortfolioExample.java`** - DeFi portfolio tracking, position analysis, and P\u0026L metrics\n- **`BalanceExample.java`** - Token balance and allowance checking across chains\n- **`FusionExample.java`** - Gasless swaps with quotes, order submission, and status tracking\n\n#### Running Examples\n\nTo run the examples, first set your API key:\n```bash\nexport ONEINCH_API_KEY=\"your-api-key-here\"\n```\n\nThen run specific examples:\n```bash\n# Run the QuickStart example\nmvn exec:java -pl oneinch-sdk-examples\n\n# Run the Swap example\nmvn exec:java -pl oneinch-sdk-examples -Dexec.mainClass=\"io.oneinch.sdk.examples.SwapExample\"\n\n# Run the Token example\nmvn exec:java -pl oneinch-sdk-examples -Dexec.mainClass=\"io.oneinch.sdk.examples.TokenExample\"\n\n# Run the Token Details example\nmvn exec:java -pl oneinch-sdk-examples -Dexec.mainClass=\"io.oneinch.sdk.examples.TokenDetailsExample\"\n\n# Run the Orderbook example\nmvn exec:java -pl oneinch-sdk-examples -Dexec.mainClass=\"io.oneinch.sdk.examples.OrderbookExample\"\n\n# Run the History example\nmvn exec:java -pl oneinch-sdk-examples -Dexec.mainClass=\"io.oneinch.sdk.examples.HistoryExample\"\n\n# Run the History Console example (requires address argument)\nmvn exec:java -pl oneinch-sdk-examples -Dexec.mainClass=\"io.oneinch.sdk.examples.HistoryConsoleExample\" -Dexec.args=\"0x111111111117dc0aa78b770fa6a738034120c302\"\n\n# Run the Portfolio example\nmvn exec:java -pl oneinch-sdk-examples -Dexec.mainClass=\"io.oneinch.sdk.examples.PortfolioExample\"\n\n# Run the Balance example\nmvn exec:java -pl oneinch-sdk-examples -Dexec.mainClass=\"io.oneinch.sdk.examples.BalanceExample\"\n\n# Run the Fusion example\nmvn exec:java -pl oneinch-sdk-examples -Dexec.mainClass=\"io.oneinch.sdk.examples.FusionExample\"\n```\n\n### Reactive Swap Flow\n```java\nimport io.reactivex.rxjava3.schedulers.Schedulers;\nimport java.math.BigInteger;\n\ntry (OneInchClient client = OneInchClient.builder()\n        .build()) {  // Uses ONEINCH_API_KEY environment variable\n    \n    BigInteger swapAmount = new BigInteger(\"10000000000000000\"); // 0.01 ETH in wei\n    String walletAddress = \"0x742f4d5b7dbf2e4f0ddeadd3d1b4b8b4c1b8b8b8\";\n    \n    // Reactive chaining with proper error handling\n    client.swap().getSpenderRx(1)  // Ethereum\n        .doOnSuccess(spender -\u003e log.info(\"Spender: {}\", spender.getAddress()))\n        .flatMap(spender -\u003e {\n            // Check allowance\n            AllowanceRequest allowanceRequest = AllowanceRequest.builder()\n                .chainId(1)  // Ethereum\n                .tokenAddress(\"0x111111111117dc0aa78b770fa6a738034120c302\")\n                .walletAddress(walletAddress)\n                .build();\n            return client.swap().getAllowanceRx(allowanceRequest);\n        })\n        .flatMap(allowance -\u003e {\n            // Get quote\n            QuoteRequest quoteRequest = QuoteRequest.builder()\n                .chainId(1)  // Ethereum\n                .src(\"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\")  // ETH\n                .dst(\"0x111111111117dc0aa78b770fa6a738034120c302\")  // 1INCH\n                .amount(swapAmount)\n                .includeTokensInfo(true)\n                .includeGas(true)\n                .build();\n            return client.swap().getQuoteRx(quoteRequest);\n        })\n        .flatMap(quote -\u003e {\n            // Get swap transaction data\n            SwapRequest swapRequest = SwapRequest.builder()\n                .chainId(1)  // Ethereum\n                .src(\"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\")\n                .dst(\"0x111111111117dc0aa78b770fa6a738034120c302\")\n                .amount(swapAmount)\n                .from(walletAddress)\n                .origin(walletAddress)\n                .slippage(1.0)\n                .build();\n            return client.swap().getSwapRx(swapRequest);\n        })\n        .subscribe(\n            swap -\u003e {\n                log.info(\"Swap ready!\");\n                log.info(\"To: {}\", swap.getTx().getTo());\n                log.info(\"Value: {}\", swap.getTx().getValue());\n                log.info(\"Expected output: {}\", swap.getDstAmount());\n            },\n            error -\u003e log.error(\"Swap flow failed\", error)\n        );\n}\n```\n\n### Parallel Reactive Operations\n```java\nimport io.reactivex.rxjava3.core.Single;\nimport java.util.concurrent.TimeUnit;\nimport java.math.BigInteger;\n\n// Run multiple operations in parallel\nSingle\u003cSpenderResponse\u003e spenderSingle = client.swap().getSpenderRx(1)  // Ethereum\n    .subscribeOn(Schedulers.io());\n\nQuoteRequest quoteRequest = QuoteRequest.builder()\n    .chainId(1)  // Ethereum\n    .src(\"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\")  // ETH\n    .dst(\"0x111111111117dc0aa78b770fa6a738034120c302\")  // 1INCH\n    .amount(new BigInteger(\"10000000000000000\"))\n    .build();\n\nSingle\u003cQuoteResponse\u003e quoteSingle = client.swap().getQuoteRx(quoteRequest)\n    .subscribeOn(Schedulers.io());\n\nAllowanceRequest allowanceRequest = AllowanceRequest.builder()\n    .chainId(1)  // Ethereum\n    .tokenAddress(\"0x111111111117dc0aa78b770fa6a738034120c302\")\n    .walletAddress(\"0x742f4d5b7dbf2e4f0ddeadd3d1b4b8b4c1b8b8b8\")\n    .build();\n\nSingle\u003cAllowanceResponse\u003e allowanceSingle = client.swap().getAllowanceRx(allowanceRequest)\n    .subscribeOn(Schedulers.io());\n\n// Combine all results\nSingle.zip(spenderSingle, quoteSingle, allowanceSingle,\n    (spender, quote, allowance) -\u003e {\n        log.info(\"All operations completed!\");\n        return \"Success\";\n    })\n    .timeout(10, TimeUnit.SECONDS)\n    .blockingGet();\n```\n\n### Synchronous Swap Flow\n```java\ntry (OneInchClient client = OneInchClient.builder()\n        .build()) {  // Uses ONEINCH_API_KEY environment variable\n    \n    // 1. Check allowance\n    AllowanceRequest allowanceRequest = AllowanceRequest.builder()\n        .chainId(1)  // Ethereum\n        .tokenAddress(\"0x111111111117dc0aa78b770fa6a738034120c302\")\n        .walletAddress(\"0x742f4d5b7dbf2e4f0ddeadd3d1b4b8b4c1b8b8b8\")\n        .build();\n    \n    AllowanceResponse allowance = client.swap().getAllowance(allowanceRequest);\n    \n    // 2. Get quote\n    QuoteRequest quoteRequest = QuoteRequest.builder()\n        .chainId(1)  // Ethereum\n        .src(\"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\")\n        .dst(\"0x111111111117dc0aa78b770fa6a738034120c302\")\n        .amount(new BigInteger(\"10000000000000000\"))\n        .build();\n    \n    QuoteResponse quote = client.swap().getQuote(quoteRequest);\n    \n    // 3. Execute swap (async with CompletableFuture)\n    SwapRequest swapRequest = SwapRequest.builder()\n        .chainId(1)  // Ethereum\n        .src(\"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\")\n        .dst(\"0x111111111117dc0aa78b770fa6a738034120c302\")\n        .amount(new BigInteger(\"10000000000000000\"))\n        .from(\"0x742f4d5b7dbf2e4f0ddeadd3d1b4b8b4c1b8b8b8\")\n        .origin(\"0x742f4d5b7dbf2e4f0ddeadd3d1b4b8b4c1b8b8b8\")\n        .slippage(1.0)\n        .build();\n    \n    CompletableFuture\u003cSwapResponse\u003e swapFuture = client.swap().getSwapAsync(swapRequest);\n    SwapResponse swap = swapFuture.get(10, TimeUnit.SECONDS);\n    // Execute swap transaction using swap.getTx()...\n}\n```\n\n### Reactive Error Handling\n```java\nclient.swap().getQuoteRx(invalidRequest)\n    .doOnSuccess(quote -\u003e log.info(\"Quote: {}\", quote.getDstAmount()))\n    .doOnError(error -\u003e {\n        if (error instanceof OneInchApiException) {\n            OneInchApiException apiError = (OneInchApiException) error;\n            log.error(\"API Error: {} (Status: {})\", apiError.getError(), apiError.getStatusCode());\n        }\n    })\n    .onErrorReturn(error -\u003e {\n        // Fallback value\n        QuoteResponse fallback = new QuoteResponse();\n        fallback.setDstAmount(BigInteger.ZERO);\n        return fallback;\n    })\n    .subscribe(\n        quote -\u003e log.info(\"Final result: {}\", quote.getDstAmount()),\n        error -\u003e log.error(\"This shouldn't happen with fallback\", error)\n    );\n```\n\n### Token API Examples\n\n#### Get Multi-Chain Token List\n```java\nimport io.oneinch.sdk.model.*;\nimport java.math.BigInteger;\n\ntry (OneInchClient client = OneInchClient.builder().build()) {\n    \n    // Get whitelisted tokens across all chains\n    TokenListRequest request = TokenListRequest.builder()\n            .provider(\"1inch\")\n            .build();\n    \n    // Synchronous\n    List\u003cProviderTokenDto\u003e tokens = client.token().getMultiChainTokens(request);\n    log.info(\"Found {} tokens across all chains\", tokens.size());\n    \n    // Reactive with RxJava\n    client.token().getMultiChainTokensRx(request)\n            .doOnSuccess(result -\u003e {\n                result.stream()\n                        .filter(token -\u003e \"1INCH\".equals(token.getSymbol()))\n                        .forEach(token -\u003e log.info(\"Found 1INCH on chain {}: {}\", \n                                token.getChainId(), token.getAddress()));\n            })\n            .subscribe();\n}\n```\n\n#### Search for Tokens\n```java\n// Search for tokens across multiple chains\nTokenSearchRequest searchRequest = TokenSearchRequest.builder()\n        .query(\"1inch\")\n        .onlyPositiveRating(true)\n        .limit(10)\n        .build();\n\nList\u003cTokenDto\u003e searchResults = client.token().searchMultiChainTokens(searchRequest);\nsearchResults.forEach(token -\u003e \n    log.info(\"Found: {} ({}) on chain {} - Rating: {}\", \n            token.getName(), token.getSymbol(), token.getChainId(), token.getRating()));\n\n// Search on specific chain\nTokenSearchRequest ethSearchRequest = TokenSearchRequest.builder()\n        .chainId(1) // Ethereum\n        .query(\"USDC\")\n        .onlyPositiveRating(true)\n        .build();\n\nCompletableFuture\u003cList\u003cTokenDto\u003e\u003e ethResults = client.token().searchTokensAsync(ethSearchRequest);\nethResults.thenAccept(results -\u003e \n    log.info(\"Found {} USDC tokens on Ethereum\", results.size()));\n```\n\n#### Get Token List for Specific Chain\n```java\n// Get Ethereum token list in standard format\nTokenListRequest ethRequest = TokenListRequest.builder()\n        .chainId(1) // Ethereum\n        .provider(\"1inch\")\n        .build();\n\nTokenListResponse tokenList = client.token().getTokenList(ethRequest);\nlog.info(\"Token list: {} (version {}.{}.{})\", \n        tokenList.getName(),\n        tokenList.getVersion().getMajor(),\n        tokenList.getVersion().getMinor(), \n        tokenList.getVersion().getPatch());\n\n// Find specific tokens\ntokenList.getTokens().stream()\n        .filter(token -\u003e \"USDC\".equals(token.getSymbol()))\n        .findFirst()\n        .ifPresent(usdc -\u003e log.info(\"USDC: {} decimals at {}\", \n                usdc.getDecimals(), usdc.getAddress()));\n```\n\n#### Get Custom Token Information\n```java\n// Get single token info\nInteger chainId = 1; // Ethereum\nString tokenAddress = \"0x111111111117dc0aa78b770fa6a738034120c302\"; // 1INCH\n\nTokenDto tokenInfo = client.token().getCustomToken(chainId, tokenAddress);\nlog.info(\"Token: {} ({}) - {} decimals\", \n        tokenInfo.getName(), tokenInfo.getSymbol(), tokenInfo.getDecimals());\n\n// Get multiple tokens\nCustomTokenRequest multiRequest = CustomTokenRequest.builder()\n        .chainId(1)\n        .addresses(List.of(\n                \"0x111111111117dc0aa78b770fa6a738034120c302\", // 1INCH\n                \"0xA0b86a33E6aB6b6ce4e5a5B7db2e8Df6b1D2b9C7\"  // USDC\n        ))\n        .build();\n\nMap\u003cString, TokenInfo\u003e tokenInfos = client.token().getCustomTokens(multiRequest);\ntokenInfos.forEach((address, info) -\u003e \n    log.info(\"Token at {}: {} ({})\", address, info.getName(), info.getSymbol()));\n```\n\n#### Get Token Details with Pricing\n```java\n// Get native token (ETH) details\nTokenDetailsRequest nativeRequest = TokenDetailsRequest.builder()\n        .chainId(1) // Ethereum\n        .provider(\"coinmarketcap\")\n        .build();\n\nTokenDetailsResponse ethDetails = client.tokenDetails().getNativeTokenDetails(nativeRequest);\nlog.info(\"ETH Details: Market Cap: ${}, 24h Volume: ${}\", \n        ethDetails.getDetails().getMarketCap(),\n        ethDetails.getDetails().getVol24());\n\n// Get token details with pricing\nTokenDetailsRequest tokenDetailsRequest = TokenDetailsRequest.builder()\n        .chainId(1)\n        .contractAddress(\"0x111111111117dc0aa78b770fa6a738034120c302\") // 1INCH\n        .provider(\"coingecko\")\n        .build();\n\n// Reactive approach\nclient.tokenDetails().getTokenDetailsRx(tokenDetailsRequest)\n        .doOnSuccess(details -\u003e {\n            log.info(\"1INCH Token Details:\");\n            log.info(\"  Website: {}\", details.getAssets().getWebsite());\n            log.info(\"  Description: {}\", details.getAssets().getShortDescription());\n            log.info(\"  Market Cap: ${}\", details.getDetails().getMarketCap());\n            log.info(\"  Total Supply: {}\", details.getDetails().getTotalSupply());\n        })\n        .subscribe();\n```\n\n#### Token Operations with Different Programming Models\n```java\n// Synchronous - Simple and blocking\nTokenListRequest request = TokenListRequest.builder()\n        .chainId(1)\n        .provider(\"1inch\")\n        .build();\n\ntry {\n    Map\u003cString, ProviderTokenDto\u003e tokens = client.token().getTokens(request);\n    // Process tokens...\n} catch (OneInchException e) {\n    log.error(\"Failed to get tokens: {}\", e.getMessage());\n}\n\n// Asynchronous with CompletableFuture\nCompletableFuture\u003cMap\u003cString, ProviderTokenDto\u003e\u003e tokensFuture = \n    client.token().getTokensAsync(request);\n\ntokensFuture\n    .thenAccept(tokens -\u003e {\n        // Process tokens...\n        log.info(\"Received {} tokens\", tokens.size());\n    })\n    .exceptionally(throwable -\u003e {\n        log.error(\"Token request failed\", throwable);\n        return null;\n    });\n\n// Reactive with RxJava - Best for complex chains\nclient.token().getTokensRx(request)\n    .flatMap(tokens -\u003e {\n        // Find 1INCH token\n        return Single.fromCallable(() -\u003e \n            tokens.values().stream()\n                .filter(t -\u003e \"1INCH\".equals(t.getSymbol()))\n                .findFirst()\n                .orElse(null)\n        );\n    })\n    .filter(token -\u003e token != null)\n    .flatMap(oneInchToken -\u003e {\n        // Get detailed information\n        TokenDetailsRequest detailsRequest = TokenDetailsRequest.builder()\n                .chainId(oneInchToken.getChainId())\n                .contractAddress(oneInchToken.getAddress())\n                .build();\n        return client.tokenDetails().getTokenDetailsRx(detailsRequest);\n    })\n    .subscribe(\n        details -\u003e log.info(\"1INCH details: {}\", details.getAssets().getName()),\n        error -\u003e log.error(\"Chain failed\", error)\n    );\n```\n\n### History Console Tool\n\nThe SDK includes a convenient command-line tool for exploring transaction history:\n\n#### Usage\n```bash\n# Basic usage - get 10 recent transactions on Ethereum\nmvn exec:java -pl oneinch-sdk-examples \\\n  -Dexec.mainClass=\"io.oneinch.sdk.examples.HistoryConsoleExample\" \\\n  -Dexec.args=\"0x111111111117dc0aa78b770fa6a738034120c302\"\n\n# Get 20 transactions on Polygon (chain ID 137)\nmvn exec:java -pl oneinch-sdk-examples \\\n  -Dexec.mainClass=\"io.oneinch.sdk.examples.HistoryConsoleExample\" \\\n  -Dexec.args=\"0x742f4d5b7dbf2e4f0ddeadd3d1b4b8b4c1b8b8b8 137 20\"\n\n# Get 50 transactions on BSC (chain ID 56)\nmvn exec:java -pl oneinch-sdk-examples \\\n  -Dexec.mainClass=\"io.oneinch.sdk.examples.HistoryConsoleExample\" \\\n  -Dexec.args=\"0x742f4d5b7dbf2e4f0ddeadd3d1b4b8b4c1b8b8b8 56 50\"\n```\n\n#### Arguments\n- **address** (required) - Ethereum address to query\n- **chainId** (optional) - Blockchain network ID (default: 1 for Ethereum)\n  - `1` = Ethereum, `137` = Polygon, `56` = BSC, `42161` = Arbitrum\n- **limit** (optional) - Number of events to fetch (default: 10, max: 10000)\n\n#### Sample Output\n```\n═══════════════════════════════════════════════════════════════════════════════\n📜 TRANSACTION HISTORY\n═══════════════════════════════════════════════════════════════════════════════\nAddress: 0x111111111117dc0aa78b770fa6a738034120c302\nChain:   Ethereum (1)\nEvents:  3 transactions found\n═══════════════════════════════════════════════════════════════════════════════\n\n📋 Event #1 [2023-09-21 15:42:31 UTC]\n   ID: 7279741913753607 | Type: Transaction | Rating: ✅ Reliable\n   Transaction: 0xdd87f...bfc\n   Type: Swap Exact Input | Status: ✅ Completed\n   Chain: Ethereum (1) | Block: 18,182,982\n   Fee: 0.001234 ETH\n\n   Token Actions:\n     ← 1.0 ETH (0x266e...db7 → 0x03f7...329)\n     → 1,337.89 1INCH (0x03f7...329 → 0x266e...db7)\n\n────────────────────────────────────────────────────────────────────────────────\n\n📋 Event #2 [2023-09-20 09:15:22 UTC]\n   ID: 7279741913753606 | Type: Transaction | Rating: ✅ Reliable\n   Transaction: 0xabc12...def\n   Type: Transfer | Status: ✅ Completed\n   Chain: Ethereum (1) | Block: 18,181,445\n   Fee: 0.000456 ETH\n\n   Token Actions:\n     → 100.0 TOKEN (0x123a...789 → 0x456b...012)\n\n═══════════════════════════════════════════════════════════════════════════════\n✅ Successfully displayed 3 transaction events\n═══════════════════════════════════════════════════════════════════════════════\n```\n\n#### Features\n- **Human-readable formatting** - Clean, easy-to-read transaction display\n- **Multi-chain support** - Works with Ethereum, Polygon, BSC, Arbitrum, and more\n- **Token action details** - Shows token transfers with amounts and directions\n- **Error handling** - Clear error messages for common issues\n- **Address validation** - Validates Ethereum address format\n- **Flexible parameters** - Configurable chain ID and result limits\n\n### History API Examples\n\n#### Get Transaction History for Address\n```java\nimport io.oneinch.sdk.model.*;\nimport java.util.List;\n\ntry (OneInchClient client = OneInchClient.builder().build()) {\n    \n    // Get recent transaction history for an address\n    String walletAddress = \"0x111111111117dc0aa78b770fa6a738034120c302\"; // 1INCH token contract\n    \n    HistoryEventsRequest request = HistoryEventsRequest.builder()\n            .address(walletAddress)\n            .limit(10)\n            .chainId(1) // Ethereum\n            .build();\n    \n    // Synchronous\n    HistoryResponseDto response = client.history().getHistoryEvents(request);\n    log.info(\"Found {} history events\", response.getItems().size());\n    \n    // Process each event\n    for (HistoryEventDto event : response.getItems()) {\n        log.info(\"Event ID: {}, Type: {}, Rating: {}\", \n                event.getId(), event.getType(), event.getRating());\n        \n        if (event.getDetails() != null) {\n            TransactionDetailsDto details = event.getDetails();\n            log.info(\"  Transaction: {} on chain {}\", \n                    details.getTxHash(), details.getChainId());\n            log.info(\"  Block: {}, Status: {}, Type: {}\", \n                    details.getBlockNumber(), details.getStatus(), details.getType());\n            \n            // Analyze token actions\n            if (details.getTokenActions() != null) {\n                for (TokenActionDto tokenAction : details.getTokenActions()) {\n                    log.info(\"    Token Action: {} {} tokens {} -\u003e {}\", \n                            tokenAction.getDirection(),\n                            tokenAction.getAmount(),\n                            tokenAction.getFromAddress(),\n                            tokenAction.getToAddress());\n                }\n            }\n        }\n    }\n}\n```\n\n#### History with Time and Token Filters\n```java\n// Get history for specific time range and token\nHistoryEventsRequest filteredRequest = HistoryEventsRequest.builder()\n        .address(\"0x742f4d5b7dbf2e4f0ddeadd3d1b4b8b4c1b8b8b8\")\n        .limit(20)\n        .chainId(1) // Ethereum\n        .tokenAddress(\"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\") // ETH transactions only\n        .fromTimestampMs(\"1694754179096\") // From timestamp in milliseconds\n        .toTimestampMs(\"1695283931212\")   // To timestamp in milliseconds\n        .build();\n\n// Reactive approach with error handling\nclient.history().getHistoryEventsRx(filteredRequest)\n        .doOnSuccess(response -\u003e {\n            log.info(\"Found {} filtered events in time range\", response.getItems().size());\n            \n            // Group by transaction type\n            Map\u003cTransactionType, Long\u003e typeCount = response.getItems().stream()\n                .filter(event -\u003e event.getDetails() != null)\n                .collect(Collectors.groupingBy(\n                    event -\u003e event.getDetails().getType(),\n                    Collectors.counting()\n                ));\n                \n            typeCount.forEach((type, count) -\u003e \n                log.info(\"  {}: {} transactions\", type, count));\n        })\n        .doOnError(error -\u003e log.error(\"Failed to get filtered history\", error))\n        .subscribe();\n```\n\n#### Reactive History Analysis Chain\n```java\n// Complex reactive chain for analyzing transaction patterns\nString targetAddress = \"0x111111111117dc0aa78b770fa6a738034120c302\";\n\nclient.history().getHistoryEventsRx(\n    HistoryEventsRequest.builder()\n        .address(targetAddress)\n        .limit(100)\n        .chainId(1)\n        .build()\n)\n.map(response -\u003e response.getItems())\n.flatMapObservable(events -\u003e Observable.fromIterable(events))\n.filter(event -\u003e event.getDetails() != null)\n.filter(event -\u003e event.getDetails().getType() == TransactionType.SWAP_EXACT_INPUT)\n.groupBy(event -\u003e event.getDetails().getFromAddress()) // Group by sender\n.flatMapSingle(group -\u003e \n    group.reduce(new HashMap\u003cString, BigInteger\u003e(), (acc, event) -\u003e {\n        // Accumulate swap volumes by sender\n        if (event.getDetails().getTokenActions() != null) {\n            for (TokenActionDto action : event.getDetails().getTokenActions()) {\n                if (action.getDirection() == TokenActionDirection.OUT) {\n                    acc.merge(group.getKey(), action.getAmount(), BigInteger::add);\n                }\n            }\n        }\n        return acc;\n    })\n    .map(volumeMap -\u003e Map.entry(group.getKey(), volumeMap.values().stream()\n        .reduce(BigInteger.ZERO, BigInteger::add)))\n)\n.toList()\n.subscribe(\n    senderVolumes -\u003e {\n        log.info(\"Top swap senders by volume:\");\n        senderVolumes.stream()\n            .sorted((a, b) -\u003e b.getValue().compareTo(a.getValue()))\n            .limit(5)\n            .forEach(entry -\u003e log.info(\"  {}: {} wei total volume\", \n                entry.getKey(), entry.getValue()));\n    },\n    error -\u003e log.error(\"Analysis failed\", error)\n);\n```\n\n#### History with All Programming Models\n```java\nHistoryEventsRequest request = HistoryEventsRequest.builder()\n        .address(\"0x111111111117dc0aa78b770fa6a738034120c302\")\n        .limit(5)\n        .chainId(1)\n        .build();\n\n// Synchronous - Simple and blocking\ntry {\n    HistoryResponseDto response = client.history().getHistoryEvents(request);\n    log.info(\"Sync: {} events retrieved\", response.getItems().size());\n} catch (OneInchException e) {\n    log.error(\"Sync failed: {}\", e.getMessage());\n}\n\n// Asynchronous with CompletableFuture\nCompletableFuture\u003cHistoryResponseDto\u003e historyFuture = \n    client.history().getHistoryEventsAsync(request);\n\nhistoryFuture\n    .thenAccept(response -\u003e \n        log.info(\"Async: {} events retrieved\", response.getItems().size()))\n    .exceptionally(throwable -\u003e {\n        log.error(\"Async failed\", throwable);\n        return null;\n    });\n\n// Reactive with RxJava - Best for complex workflows\nclient.history().getHistoryEventsRx(request)\n    .flatMapObservable(response -\u003e Observable.fromIterable(response.getItems()))\n    .filter(event -\u003e event.getRating() == EventRating.RELIABLE)\n    .filter(event -\u003e event.getDetails() != null)\n    .filter(event -\u003e event.getDetails().getType() == TransactionType.TRANSFER)\n    .take(3) // Limit to first 3 reliable transfers\n    .toList()\n    .subscribe(\n        reliableTransfers -\u003e log.info(\"Reactive: Found {} reliable transfers\", \n            reliableTransfers.size()),\n        error -\u003e log.error(\"Reactive failed\", error)\n    );\n```\n\n### Portfolio API Examples\n\nThe Portfolio API v5 provides comprehensive DeFi position tracking and analytics across multiple chains and protocols.\n\n#### Service Information\n```java\ntry (OneInchClient client = OneInchClient.builder().build()) {\n    \n    // Check service status\n    ApiStatusResponse status = client.portfolio().getServiceStatus();\n    log.info(\"Portfolio API available: {}\", status.getIsAvailable());\n    \n    // Get supported chains\n    List\u003cSupportedChainResponse\u003e chains = client.portfolio().getSupportedChains();\n    log.info(\"Supported chains: {}\", chains.size());\n    chains.stream()\n        .limit(3)\n        .forEach(chain -\u003e log.info(\"  Chain: {} ({})\", \n            chain.getChainName(), chain.getChainId()));\n    \n    // Get supported protocols\n    List\u003cSupportedProtocolGroupResponse\u003e protocols = client.portfolio().getSupportedProtocols();\n    log.info(\"Supported protocols: {}\", protocols.size());\n    protocols.stream()\n        .limit(3)\n        .forEach(protocol -\u003e log.info(\"  Protocol: {} on chain {}\", \n            protocol.getProtocolGroupName(), protocol.getChainId()));\n}\n```\n\n#### Current Portfolio Value\n```java\n// Get portfolio value breakdown\nPortfolioV5OverviewRequest request = PortfolioV5OverviewRequest.builder()\n        .addresses(Arrays.asList(\"0x111111111117dc0aa78b770fa6a738034120c302\"))\n        .chainId(1) // Ethereum\n        .build();\n\nCurrentValueResponse currentValue = client.portfolio().getCurrentValue(request);\n\nlog.info(\"Total portfolio value: ${}\", currentValue.getTotal());\n\n// Value by address\ncurrentValue.getByAddress().forEach(addr -\u003e \n    log.info(\"  Address {}: ${}\", addr.getAddress(), addr.getValueUsd()));\n\n// Value by category (DeFi protocols, tokens, etc.)\ncurrentValue.getByCategory().forEach(cat -\u003e \n    log.info(\"  Category {}: ${}\", cat.getCategoryName(), cat.getValueUsd()));\n\n// Value by blockchain\ncurrentValue.getByChain().forEach(chain -\u003e \n    log.info(\"  Chain {}: ${}\", chain.getChainName(), chain.getValueUsd()));\n```\n\n#### Protocol Positions Snapshot\n```java\n// Get detailed protocol positions\nPortfolioV5SnapshotRequest snapshotRequest = PortfolioV5SnapshotRequest.builder()\n        .addresses(Arrays.asList(\"0x111111111117dc0aa78b770fa6a738034120c302\"))\n        .chainId(1) // Ethereum\n        .build();\n\nList\u003cAdapterResult\u003e protocolsSnapshot = client.portfolio().getProtocolsSnapshot(snapshotRequest);\n\nlog.info(\"Found {} protocol positions\", protocolsSnapshot.size());\n\nprotocolsSnapshot.stream()\n    .limit(3)\n    .forEach(position -\u003e {\n        log.info(\"  Protocol: {} - Value: ${}\", \n            position.getProtocolGroupName(), position.getValueUsd());\n        log.info(\"    Contract: {} ({})\", \n            position.getContractName(), position.getContractAddress());\n        log.info(\"    Underlying tokens: {}\", position.getUnderlyingTokens().size());\n        log.info(\"    Reward tokens: {}\", position.getRewardTokens().size());\n    });\n```\n\n#### Token Positions Analysis\n```java\n// Get token positions across all protocols\nList\u003cAdapterResult\u003e tokensSnapshot = client.portfolio().getTokensSnapshot(snapshotRequest);\n\nlog.info(\"Found {} token positions\", tokensSnapshot.size());\n\ntokensSnapshot.stream()\n    .limit(5)\n    .forEach(token -\u003e {\n        log.info(\"  Token: {} ({}) - Value: ${}\", \n            token.getContractName(), token.getContractSymbol(), token.getValueUsd());\n        log.info(\"    Address: {}\", token.getContractAddress());\n        log.info(\"    Locked: {}\", token.getLocked());\n    });\n```\n\n#### P\u0026L and ROI Metrics\n```java\n// Get profit/loss and ROI metrics for protocols\nPortfolioV5MetricsRequest metricsRequest = PortfolioV5MetricsRequest.builder()\n        .addresses(Arrays.asList(\"0x111111111117dc0aa78b770fa6a738034120c302\"))\n        .chainId(1) // Ethereum\n        .build();\n\nList\u003cHistoryMetrics\u003e protocolsMetrics = client.portfolio().getProtocolsMetrics(metricsRequest);\n\nlog.info(\"Found {} protocol metrics\", protocolsMetrics.size());\n\nprotocolsMetrics.stream()\n    .limit(3)\n    .forEach(metric -\u003e {\n        log.info(\"  Position: {}\", metric.getIndex());\n        log.info(\"    Profit (USD): {}\", metric.getProfitAbsUsd());\n        log.info(\"    ROI: {}%\", metric.getRoi() != null ? \n            String.format(\"%.2f\", metric.getRoi() * 100) : \"N/A\");\n        log.info(\"    Weighted APR: {}%\", metric.getWeightedApr() != null ? \n            String.format(\"%.2f\", metric.getWeightedApr() * 100) : \"N/A\");\n        log.info(\"    Holding time: {} days\", metric.getHoldingTimeDays());\n        log.info(\"    Rewards (USD): {}\", metric.getRewardsUsd());\n    });\n```\n\n#### Reactive Portfolio Operations\n```java\n// Reactive portfolio analysis chain\nPortfolioV5OverviewRequest request = PortfolioV5OverviewRequest.builder()\n        .addresses(Arrays.asList(\"0x111111111117dc0aa78b770fa6a738034120c302\"))\n        .chainId(1)\n        .build();\n\nclient.portfolio().getCurrentValueRx(request)\n    .flatMap(currentValue -\u003e {\n        log.info(\"Total value: ${}\", currentValue.getTotal());\n        \n        // Chain to get protocol details\n        PortfolioV5SnapshotRequest snapshotRequest = PortfolioV5SnapshotRequest.builder()\n            .addresses(request.getAddresses())\n            .chainId(request.getChainId())\n            .build();\n        \n        return client.portfolio().getProtocolsSnapshotRx(snapshotRequest);\n    })\n    .flatMap(protocols -\u003e {\n        log.info(\"Protocol positions: {}\", protocols.size());\n        \n        // Chain to get metrics\n        PortfolioV5MetricsRequest metricsRequest = PortfolioV5MetricsRequest.builder()\n            .addresses(request.getAddresses())\n            .chainId(request.getChainId())\n            .build();\n        \n        return client.portfolio().getProtocolsMetricsRx(metricsRequest);\n    })\n    .subscribe(\n        metrics -\u003e {\n            log.info(\"Portfolio analysis complete!\");\n            log.info(\"Found {} protocol metrics\", metrics.size());\n            \n            // Calculate total profit\n            BigDecimal totalProfit = metrics.stream()\n                .filter(m -\u003e m.getProfitAbsUsd() != null)\n                .map(HistoryMetrics::getProfitAbsUsd)\n                .reduce(BigDecimal.ZERO, BigDecimal::add);\n            \n            log.info(\"Total profit: ${}\", totalProfit);\n        },\n        error -\u003e log.error(\"Portfolio analysis failed\", error)\n    );\n```\n\n#### Address Validation\n```java\n// Validate addresses before portfolio operations\nAddressValidationRequest validationRequest = AddressValidationRequest.builder()\n        .addresses(Arrays.asList(\n            \"0x111111111117dc0aa78b770fa6a738034120c302\",\n            \"0x742f4d5b7dbf2e4f0ddeadd3d1b4b8b4c1b8b8b8\"\n        ))\n        .build();\n\nAddressValidationResponse validation = client.portfolio().checkAddresses(validationRequest);\n\nvalidation.getResult().forEach((address, isValid) -\u003e \n    log.info(\"Address {} is {}\", address, isValid ? \"valid\" : \"invalid\"));\n```\n\n### Balance API Examples\n\nThe Balance API provides token balance and allowance checking capabilities across different blockchain networks.\n\n#### Basic Wallet Balance Checking\n```java\nimport java.math.BigInteger;\n\ntry (OneInchClient client = OneInchClient.builder().build()) {\n    \n    // Get all token balances for a wallet\n    BalanceRequest request = BalanceRequest.builder()\n            .chainId(1) // Ethereum\n            .walletAddress(\"0x111111111117dc0aa78b770fa6a738034120c302\")\n            .build();\n    \n    Map\u003cString, BigInteger\u003e balances = client.balance().getBalances(request);\n    \n    log.info(\"Found {} token balances\", balances.size());\n    balances.entrySet().stream()\n            .filter(entry -\u003e !entry.getValue().equals(BigInteger.ZERO))\n            .limit(5)\n            .forEach(entry -\u003e log.info(\"  Token {}: {} wei\", entry.getKey(), entry.getValue()));\n}\n```\n\n#### Custom Token Balance Queries\n```java\n// Check balances for specific tokens only\nCustomBalanceRequest request = CustomBalanceRequest.builder()\n        .chainId(1) // Ethereum\n        .walletAddress(\"0x111111111117dc0aa78b770fa6a738034120c302\")\n        .tokens(Arrays.asList(\n            \"0xA0b86a33E6aB6b6ce4e5a5B7db2e8Df6b1D2b9C7\", // USDC\n            \"0xdAC17F958D2ee523a2206206994597C13D831ec7\"  // USDT\n        ))\n        .build();\n\nMap\u003cString, BigInteger\u003e customBalances = client.balance().getCustomBalances(request);\n\ncustomBalances.forEach((token, balance) -\u003e \n    log.info(\"Token {}: {} wei\", token, balance));\n```\n\n#### Allowance Checking for DEX Interactions\n```java\n// Check token allowances for a DEX router\nAllowanceBalanceRequest request = AllowanceBalanceRequest.builder()\n        .chainId(1) // Ethereum\n        .spender(\"0x1111111254eeb25477b68fb85ed929f73a960582\") // 1inch v5 router\n        .walletAddress(\"0x111111111117dc0aa78b770fa6a738034120c302\")\n        .build();\n\nMap\u003cString, BigInteger\u003e allowances = client.balance().getAllowances(request);\n\nlog.info(\"Token allowances for 1inch router:\");\nallowances.entrySet().stream()\n        .filter(entry -\u003e !entry.getValue().equals(BigInteger.ZERO))\n        .forEach(entry -\u003e log.info(\"  Token {}: {} wei allowance\", entry.getKey(), entry.getValue()));\n```\n\n#### Combined Balance and Allowance Data\n```java\n// Get both balance and allowance in a single call\nAllowanceBalanceRequest request = AllowanceBalanceRequest.builder()\n        .chainId(1) // Ethereum\n        .spender(\"0x1111111254eeb25477b68fb85ed929f73a960582\")\n        .walletAddress(\"0x111111111117dc0aa78b770fa6a738034120c302\")\n        .build();\n\nMap\u003cString, BalanceAndAllowanceItem\u003e combined = client.balance().getAllowancesAndBalances(request);\n\ncombined.entrySet().stream()\n        .limit(5)\n        .forEach(entry -\u003e {\n            BalanceAndAllowanceItem item = entry.getValue();\n            log.info(\"Token {}: balance={} wei, allowance={} wei\", \n                entry.getKey(), item.getBalance(), item.getAllowance());\n        });\n```\n\n#### Multi-Wallet Balance Aggregation\n```java\n// Check balances across multiple wallets for portfolio management\nMultiWalletBalanceRequest request = MultiWalletBalanceRequest.builder()\n        .chainId(1) // Ethereum\n        .wallets(Arrays.asList(\n            \"0x111111111117dc0aa78b770fa6a738034120c302\",\n            \"0x742f4d5b7dbf2e4f0ddeadd3d1b4b8b4c1b8b8b8\"\n        ))\n        .tokens(Arrays.asList(\n            \"0xA0b86a33E6aB6b6ce4e5a5B7db2e8Df6b1D2b9C7\", // USDC\n            \"0xdAC17F958D2ee523a2206206994597C13D831ec7\"  // USDT\n        ))\n        .build();\n\nMap\u003cString, Map\u003cString, BigInteger\u003e\u003e multiWalletBalances = client.balance().getBalancesByMultipleWallets(request);\n\nmultiWalletBalances.forEach((wallet, tokenBalances) -\u003e {\n    log.info(\"Wallet: {}\", wallet);\n    tokenBalances.forEach((token, balance) -\u003e \n        log.info(\"  Token {}: {} wei\", token, balance));\n});\n```\n\n#### Reactive Balance Operations\n```java\n// Reactive balance checking with RxJava\nBalanceRequest request = BalanceRequest.builder()\n        .chainId(1) // Ethereum\n        .walletAddress(\"0x111111111117dc0aa78b770fa6a738034120c302\")\n        .build();\n\nclient.balance().getBalancesRx(request)\n    .flatMap(balances -\u003e {\n        log.info(\"Found {} token balances\", balances.size());\n        \n        // Chain to get allowances\n        AllowanceBalanceRequest allowanceRequest = AllowanceBalanceRequest.builder()\n            .chainId(request.getChainId())\n            .spender(\"0x1111111254eeb25477b68fb85ed929f73a960582\")\n            .walletAddress(request.getWalletAddress())\n            .build();\n            \n        return client.balance().getAllowancesRx(allowanceRequest);\n    })\n    .subscribe(\n        allowances -\u003e {\n            log.info(\"Reactive chain completed!\");\n            log.info(\"Found {} token allowances\", allowances.size());\n        },\n        error -\u003e log.error(\"Reactive balance chain failed\", error)\n    );\n```\n\n## Error Handling\n\nThe SDK provides structured error handling for all programming approaches:\n\n### Synchronous Error Handling\n```java\ntry {\n    QuoteResponse quote = client.swap().getQuote(quoteRequest);\n} catch (OneInchApiException e) {\n    log.error(\"API Error: {} (Status: {}, Request ID: {})\", \n        e.getDescription(), e.getStatusCode(), e.getRequestId());\n} catch (OneInchException e) {\n    log.error(\"SDK Error: {}\", e.getMessage());\n}\n```\n\n### Reactive Error Handling\n```java\nclient.swap().getQuoteRx(quoteRequest)\n    .doOnError(error -\u003e {\n        if (error instanceof OneInchApiException) {\n            OneInchApiException apiError = (OneInchApiException) error;\n            log.error(\"API Error: {}\", apiError.getDescription());\n        } else if (error instanceof OneInchException) {\n            log.error(\"SDK Error: {}\", error.getMessage());\n        }\n    })\n    .subscribe(\n        quote -\u003e log.info(\"Success: {}\", quote.getDstAmount()),\n        error -\u003e log.error(\"Failed\", error)\n    );\n```\n\n## Requirements\n\n- Java 11 or higher\n- Maven 3.6 or higher\n\n## Building\n\n```bash\ngit clone https://github.com/1inch/1inch-java-sdk.git\ncd 1inch-java-sdk\nmvn clean install\n```\n\n## Testing\n\n### Unit Tests\nRun the mock unit tests (no API key required):\n```bash\n# Test all modules\nmvn test\n\n# Test only core SDK\nmvn test -pl oneinch-sdk-core\n```\n\n### Integration Tests\nTo run integration tests with real API calls:\n\n1. **Set up API key configuration**:\n   ```bash\n   # Copy the sample configuration\n   cp test.properties.sample test.properties\n   \n   # Edit test.properties and add your real API key\n   nano test.properties\n   ```\n\n2. **Add your API key to test.properties**:\n   ```properties\n   ONEINCH_API_KEY=your-actual-api-key-here\n   ```\n\n3. **Run integration tests**:\n   ```bash\n   # Run only integration tests\n   mvn test -pl oneinch-sdk-core -Dtest=OneInchIntegrationTest\n   \n   # Or run all tests (unit + integration) \n   mvn test\n   ```\n\n**Note**: `test.properties` is gitignored to prevent accidental commits of API keys. Always use `test.properties.sample` as a reference for the expected format.\n\n## Roadmap\n\nThe 1inch Java SDK is actively developed with a focus on providing comprehensive coverage of the 1inch ecosystem. Here's our development roadmap and current API implementation status.\n\n### Current Implementation Status\n\nThe SDK currently implements **9 out of 19 available 1inch APIs** (47% coverage), providing solid foundational functionality with room for significant expansion.\n\n#### ✅ **Fully Implemented APIs**\n- **Swap API** - Complete swap operations with chain-specific support (12 chains)\n- **Token API** - Multi-chain token lists, search, and custom token information\n- **Token Details API** - Token pricing, charts, and market data\n- **Orderbook API** - Limit order management and trading pair analysis (12 chains)  \n- **History API** - Transaction history tracking and analysis\n- **Portfolio API v5** - Comprehensive DeFi position tracking and P\u0026L analytics\n- **Balance API** - Token balance and allowance checking (13 chains)\n- **Price API** - Real-time token pricing across 60+ fiat currencies (13 chains)\n- **Fusion API** - Gasless swaps with professional market makers and auction system (13 chains)\n\nAll implemented APIs support the triple programming model: **Reactive (RxJava)**, **Synchronous**, and **Asynchronous (CompletableFuture)**.\n\n### Development Roadmap\n\n#### 🚀 **Phase 1: Core Trading Infrastructure** (Q2-Q3 2024)\n**Priority: HIGH** - Essential for advanced trading applications\n\n| API | Status | Chains | Key Features |\n|-----|--------|--------|--------------|\n| **Fusion API** | ✅ **Implemented** | 13 | Gasless swaps, 1inch's core innovation |\n| **FusionPlus API** | ✅ **Implemented** | 12+ | Cross-chain gasless swaps with enhanced security |\n| **Price API** | ✅ **Implemented** | 13 | Real-time pricing across 60+ fiat currencies |\n| **Cross-Chain API** | 🔄 Planned | Multi | Bridge operations and cross-chain liquidity |\n\n**Business Impact**: These APIs are critical for accessing 1inch's competitive advantages, particularly gasless swaps and cross-chain operations.\n\n#### ⚡ **Phase 2: Infrastructure \u0026 Analytics** (Q4 2024)\n**Priority: MEDIUM** - Enhanced user experience and trading tools\n\n| API | Status | Chains | Key Features |\n|-----|--------|--------|--------------|\n| **Gas Price API** | 🔄 Planned | 12 | Optimized gas pricing for better transaction costs |\n| **Charts API** | 🔄 Planned | 12 | Historical price charts and technical analysis |\n| **Transaction Gateway API** | 🔄 Planned | 12 | MEV protection and transaction broadcasting |\n\n#### 🔧 **Phase 3: Specialized Features** (Q1 2025)\n**Priority: LOW** - Niche and specialized use cases\n\n| API | Status | Chains | Key Features |\n|-----|--------|--------|--------------|\n| **Traces API** | 🔄 Planned | 1 | Transaction trace analysis and debugging |\n| **NFT API v2** | 🔄 Planned | 1 | NFT trading and marketplace integration |\n| **Spot Price API** | 🔄 Planned | 1 | High-frequency spot price feeds |\n| **Domains API** | 🔄 Planned | 1 | ENS and domain resolution services |\n| **Web3 API** | 🔄 Planned | 2 | Blockchain data and Web3 utilities |\n\n### Chain Support Matrix\n\nThe SDK aims to provide comprehensive multi-chain support across the 1inch ecosystem:\n\n| Blockchain | Supported APIs | Total Available | Coverage |\n|------------|----------------|-----------------|----------|\n| **Ethereum** | 9/19 | 19 | 47% |\n| **Polygon** | 7/13 | 13 | 54% |\n| **BSC** | 7/13 | 13 | 54% |\n| **Arbitrum** | 7/13 | 13 | 54% |\n| **Optimism** | 7/12 | 12 | 58% |\n| **Avalanche** | 7/12 | 12 | 58% |\n| **Gnosis** | 7/12 | 12 | 58% |\n| **Base** | 6/9 | 9 | 67% |\n| **Linea** | 6/8 | 8 | 75% |\n| **zkSync Era** | 6/8 | 8 | 75% |\n| **Solana** | 4/5 | 5 | 80% |\n| **Sonic** | 5/7 | 7 | 71% |\n| **Unichain** | 5/7 | 7 | 71% |\n\n### Future Enhancements\n\n#### 🎯 **Planned Features**\n- **WebSocket Support** - Real-time price feeds and order updates\n- **Rate Limiting Management** - Intelligent request throttling and queuing\n- **Advanced Error Recovery** - Automatic retry with exponential backoff\n- **Performance Optimizations** - HTTP/2 connection pooling and caching\n- **Metrics \u0026 Monitoring** - Built-in observability and performance tracking\n\n#### 📊 **SDK Improvements**\n- **Enhanced Documentation** - Interactive API documentation with live examples\n- **Code Generation** - Automated model generation from OpenAPI specs\n- **Testing Framework** - Comprehensive integration test suite\n- **Spring Boot Integration** - Auto-configuration and starter modules\n\n### Community \u0026 Contributions\n\n#### 🤝 **How to Help Prioritize Development**\n\nWe welcome community input on roadmap priorities! Here's how you can influence development:\n\n1. **Feature Requests**: [Create an issue](https://github.com/1inch/1inch-java-sdk/issues/new) with your use case\n2. **API Priority Voting**: Comment on roadmap issues to vote for features you need\n3. **Business Case**: Share how specific APIs would benefit your project\n4. **Community Discussion**: Join our [Discord](https://discord.gg/1inch) to discuss priorities\n\n#### 💡 **Contribution Areas**\n- **API Implementation**: Help implement missing APIs following existing patterns\n- **Documentation**: Improve examples and API documentation\n- **Testing**: Add integration tests and edge case coverage\n- **Performance**: Optimize HTTP client configuration and caching\n- **Multi-chain**: Add support for new blockchain networks\n\n#### 🎯 **Current Priority Requests**\nBased on community feedback, these are the most requested features:\n1. ✅ **Fusion API** - Gasless swaps (**COMPLETED**)\n2. ✅ **FusionPlus API** - Cross-chain gasless swaps (**COMPLETED**)\n3. ✅ **Price API** - Real-time pricing (**COMPLETED**)\n4. **Cross-Chain API** - Bridge operations (8+ requests)\n5. **WebSocket Support** - Real-time updates (6+ requests)\n\n### Getting Involved\n\nWant to contribute to the roadmap? We'd love your help:\n\n- **Developers**: Pick up issues labeled `help-wanted` or `good-first-issue`\n- **Companies**: Share your integration requirements and priority APIs\n- **Community**: Provide feedback on API designs and examples\n- **Testers**: Help validate new APIs with real-world use cases\n\nFor development guidelines and contribution process, see our [Contributing](#contributing) section.\n\n---\n\n*Roadmap last updated: January 2025. Timelines are estimates and may change based on community needs and technical complexity.*\n\n## License\n\nThis project is licensed under the MIT License.\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Commit your changes\n4. Push to the branch\n5. Create a Pull Request\n\n## Support\n\nFor issues and questions:\n- [GitHub Issues](https://github.com/1inch/1inch-java-sdk/issues)\n- [1inch Developer Portal](https://portal.1inch.dev/)\n- [1inch Discord](https://discord.gg/1inch)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphantomydn%2F1inch-java-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphantomydn%2F1inch-java-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphantomydn%2F1inch-java-sdk/lists"}