# LLMs.txt for Ring Protocol Documentation > Curated reference documentation for reviewed Ring Protocol integration paths # Ring Protocol curated integration context This export is a documentation snapshot, not an audit or a transaction authorization source. Verify the chain ID, contract code, FewFactory mapping, pair, router, spender, recipient, raw amounts, price limits, deadline, and simulation result before signing or submitting a transaction. Do not send assets directly to a listed contract address. ## Security and Risk Ring contracts and pools run on public networks. Transactions are irreversible, pool state can change before a transaction confirms, and permissionless factories can contain assets or pairs that Ring has not reviewed. ## Verify before signing Check all of the following in your own application or contract: 1. The wallet and RPC are connected to the intended chain ID. 2. Every contract has bytecode on that chain and its immutable factory, wrapper, and router references match the [deployment page](/contracts/v2/deployments). 3. `FewFactory.getWrappedToken(underlying)` returns each FewToken used in the path. 4. `Ring Swap Factory.getPair(tokenA, tokenB)` returns each pair used by the route. 5. The sender, recipient, input token, output token, raw amount, native value, minimum output or maximum input, deadline, and calldata selector match the user's intent. 6. A fresh independent price check supports the configured limit. A pool reserve ratio is not an independent oracle. 7. A simulation at the latest block succeeds without unexpected transfers, approvals, callbacks, or recipients. Do not send assets directly to a Factory, Pair, Router, FewToken, wrapper, hook, or Permit2 contract unless the documented function explicitly requires that transfer. A contract address is not a deposit address. ## Approval spenders The correct spender depends on the flow: | Flow | Token being approved | Spender | | --- | --- | --- | | Ring Swap Router swap or add liquidity | Original ERC-20 input | The Ring Swap Router selected for that chain | | Manual FewToken wrap | Original ERC-20 input | The FewToken returned by that chain's `FewFactory` | | Universal Router with Permit2 | Original ERC-20 input | Permit2 for the ERC-20 allowance, then the selected Universal Router in the bounded Permit2 authorization | | Remove Ring Swap liquidity | Pair LP token | The selected Ring Swap Router, or the same router in the LP permit | For a standard ERC-20 approval, prefer an exact amount and clear it after the operation when the token supports that flow. For Permit2, also use a short expiration and signature deadline. Before signing Permit2 data, verify the EIP-712 chain ID, verifying contract, permit type, spender, token, amount, nonce, expiration, and signature deadline. An allowance permit does not by itself authorize a recipient or a specific swap. Verify those fields in the final calldata, and do not sign typed data solely because a quote or website supplied it. ## Pool and token listings Ring Swap factories are permissionless. Anyone may create a wrapper or pair when the contracts allow it, and token metadata can be copied. A pool's existence, an explorer page, a token symbol, or its appearance in a third-party list does not show that Ring reviewed the token or endorses the pool. Use an application-level allowlist for assets and pairs that can receive user funds. For each entry, store the chain ID, underlying token, FewToken, pair, factory, allowed router, and the block at which the relationship was verified. Recheck the relationship before a transaction when the source may have changed. ## Integration surfaces - SDKs calculate values and calldata but do not verify every external address or current pool condition for you. - The Routing API returns a quote from its configured sources. The caller must validate and simulate the response. - AI context files can be stale or incomplete. Never execute generated code or transactions without review. - Wallets, RPC providers, explorers, bridges, indexers, aggregators, and other linked services have their own security and availability risks. ## FewToken controls and backing FewToken behavior includes permissionless wrap and unwrap functions as well as privileged roles. Read [Few Protocol and FewToken](/concepts/few-protocol) before treating a FewToken as a claim on an underlying asset. Role holders, pause state, balances, and issuance history must be checked onchain for the selected network. ## Report a problem For an incorrect public address, link, or documentation page, open a [Ring docs issue](https://github.com/RingProtocol/docs/issues/new) with the affected page, chain ID, contract address, and transaction hash when relevant. For a potential security vulnerability, use the Ring Interface's current [Contact Us channel](https://discord.com/invite/TefBNDZBQP) only to request a private reporting route. Do not post exploit details in a public channel. This site does not currently publish a dedicated private vulnerability-reporting address. Never send a private key, seed phrase, API key, signed transaction, or other secret. --- ## Start Here Ring Protocol uses a wrapped asset layer called FEW to connect assets to trading and liquidity systems. Ring Swap is the native AMM built on that layer. ## Product map | Product | Role | Use it when | | --- | --- | --- | | **Few Protocol** | Maps an original ERC-20 to its supported `FewToken` through a chain-specific `FewFactory` | You need to wrap an asset, resolve a FewToken address, or validate a wrapper | | **Ring Swap (v2)** | Ring's native constant-product AMM and routing system | You need Ring pools, swaps, liquidity, or contract integrations | | **Ring Interface** | The web application for swaps, liquidity, and pool discovery | You want to use Ring without building an integration | | **Uniswap v4 Integration** | An external liquidity environment where FewToken and Few hooks can be used | Your integration specifically targets Uniswap v4 pools or hooks | The `(v2)` in Ring Swap describes its contract design. Ring Swap is the current native AMM, not a legacy section and not one step in a public Ring v2, v3, v4 product ladder. ## Choose a path | Goal | Start here | | --- | --- | | Find a pool or use the web app | [Ring Pool Explorer](https://app.ring.exchange/explorer#/explore/pools) | | Find contract addresses | [Ring Swap deployments](/contracts/v2/deployments) | | Find BSC or HyperEVM pool addresses | [Networks and pools](/contracts/v2/pools) | | Integrate Ring Swap in a contract | [Smart contract quick start](/contracts/v2/guides/smart-contract-integration/quick-start) | | Build quotes and trades in TypeScript | [Ring Swap SDK](/sdk/v2/overview) | | Request executable quotes from a service | [Routing API](/api/routing/overview) | | Resolve or validate a FewToken | [FewToken integration](/contracts/v2/fewtoken/integrating) | | Build with Uniswap v4 hooks or pools | [Uniswap v4 integration](/contracts/v4/overview) | ## Supported Ring Swap networks The maintained Ring Swap deployment reference covers Ethereum, MegaETH, BNB Smart Chain, and HyperEVM. Addresses are chain-specific. Always select the network first, then use the contracts and pools listed for that network and verify them onchain. The published v2 SDK does not support every network in the deployment table. Next, read [How Ring Works](./ring-protocol) for the architecture or go directly to [Ring Swap](/contracts/v2/overview) to start an integration. --- ## How Ring Works Ring separates the asset layer from the trading venue. ```text Original ERC-20 | | a verified FewFactory resolves the supported wrapper v FewToken | +--> Ring Swap pools and routes | +--> supported external integrations, including Uniswap v4 ``` ## 1. Few Protocol provides the asset layer Few Protocol maps an original ERC-20 to a `FewToken`. The published `FewFactory` deployment on each network records that mapping. Verify the factory address, code, Core reference, and reverse wrapper relationship onchain before use. A token name, symbol, token list entry, or existing pool is not enough to establish that a wrapper is supported. Integrations should confirm the mapping through `FewFactory`. ## 2. Ring Swap provides the native trading layer Ring Swap uses FewToken assets in constant-product pairs. Its core contracts are a factory and the pairs created by that factory. Routers provide the normal entry points for swaps and liquidity operations. For a logical route such as: ```text tokenA -> USDC -> tokenB ``` the Ring Swap path uses the corresponding wrappers: ```text fwTokenA -> fwUSDC -> fwTokenB ``` ## 3. Other environments are integrations FewToken can also be used outside Ring Swap. The Uniswap v4 section documents one such integration path. Those pages describe FewToken and Few hooks in Uniswap v4 infrastructure. They do not describe a separate native Ring v4 AMM. ## Integration boundary | Need | Verification source | | --- | --- | | Confirm a FewToken | The independently verified, published `FewFactory` for the selected chain | | Find a Ring Swap pair | The network's Ring Swap Factory or the published pool reference | | Select an approval spender | The exact spender required by the reviewed flow. See [Security and Risk](/security-and-risk#approval-spenders) | | Find current deployments | [Contract deployments](/contracts/v2/deployments) | | Browse Ethereum pools | [Ring Pool Explorer](https://app.ring.exchange/explorer#/explore/pools) | This boundary matters because addresses that look like Ring assets or pools can be created by anyone. Start with the published deployment, then verify it onchain before routing funds or granting approvals. --- ## Few Protocol and FewToken Few Protocol is Ring's asset-wrapping layer. It maps an original ERC-20 to a corresponding `FewToken` that can be used by Ring Swap and supported integrations. ## Published identity Each supported network has a published `FewFactory`. Treat a FewToken as supported only when that factory maps the original token to the wrapper and the deployed wrapper maps back to the same original token: ```solidity address fewToken = IFewFactory(fewFactory).getWrappedToken(originalToken); require(fewToken != address(0), "FewToken not found"); require(IFewWrappedToken(fewToken).token() == originalToken, "underlying mismatch"); ``` If a wrapper address comes from a token list, pool, quote, or third party, resolve its original token and confirm that the published factory maps back to the same wrapper. Before using funds, verify the chain ID, factory bytecode, `core()` reference, and wrapper bytecode onchain rather than trusting a copied address alone. `FewFactory.createToken()` is permissionless. The factory mapping establishes identity for that deployment, but token creation does not mean that Ring reviewed the original token, its issuer, or any pool that uses the wrapper. ## Chain-specific addresses FewToken mappings do not transfer across networks. The same original asset can have a different FewToken address on Ethereum, BNB Smart Chain, HyperEVM, or MegaETH. Use the [deployment page](/contracts/v2/deployments) to select the correct `FewFactory`, then resolve the wrapper on that network. ## Wrap, unwrap, and raw units The standard wrapper functions move the original token into the FewToken contract and mint the same **raw integer amount**. Unwrap burns the caller's FewToken and transfers the same raw amount of the original token from the wrapper. FewToken contracts in the reviewed source declare 18 decimals. An original token may use a different decimal count. Do not describe this as one displayed token for one displayed token without checking both contracts. Build amounts from raw units and test the selected deployment. The standard implementation does not measure how many original tokens a fee-on-transfer token actually delivered before minting. Rebasing, fee-on-transfer, callback, blacklist, and other nonstandard tokens require a separate review. Calling `burn()` destroys FewToken but does not release the original asset. Use `unwrap()` or `unwrapTo()` when the intended result is redemption. ## Privileged roles and pause behavior The reviewed FewToken source also exposes role-controlled supply functions: - An address recognized by the current Core as a minter can call `mint(account, amount)` without depositing the original token into that wrapper. - An address recognized as a burner can call `burnFrom(account, amount)` without an ERC-20 allowance from that account. - The FewFactory governor can change the Core reference. A governor or guardian can pause and unpause the factory. - In the reviewed source, the pause check gates privileged `mint` and `burnFrom`. It does not gate transfers, the caller's own `burn`, `wrap`, or `unwrap`. These are source-level properties, not a statement about who currently holds each role. Before relying on a deployed FewToken, read the factory's current `core()` and `paused()` values, check the Core's governor, guardian, minter, and burner predicates, and review role and supply events for the selected chain. ## Backing checks Underlying held by the wrapper can come from normal wrap calls, while privileged minting can increase supply without a matching transfer into that wrapper. `totalSupply()` alone is therefore not proof that every FewToken can be redeemed. For a value-bearing integration, check the wrapper's current underlying balance, FewToken supply, privileged issuance and burn history, pause state, role holders, and actual unwrap behavior. Apply token-decimal and nonstandard-transfer rules before comparing balances. If your system requires full redemption at all times, enforce that condition as an integration risk limit rather than assuming it from the token name. ## Where FewToken is used - Ring Swap pools store and trade FewToken assets. - Ring Swap routes use FewToken addresses. - Manual wrapping flows interact with the FewToken verified through FewFactory. - Supported external environments can use FewToken through their own pool and hook contracts. For code examples and approval rules, continue to the [FewToken integration guide](/contracts/v2/fewtoken/integrating). --- ## Contract Map Start with Ring Swap unless your integration explicitly targets Uniswap v4. ## Native Ring contracts | Component | Responsibility | Use it for | | --- | --- | --- | | `FewFactory` | Resolves the canonical FewToken for an original ERC-20 | Wrapper discovery and validation | | `FewToken` | Wraps an original asset for use in Ring systems | Manual wrapping and unwrapping | | Ring Swap Factory | Creates and indexes Ring Swap pairs | Pair discovery and validation | | Ring Swap Pair | Holds two FewToken reserves and executes swaps | Reserve reads, LP accounting, and direct pair integrations | | Ring Swap Router | Coordinates normal swap and liquidity flows | Smart contract integrations | | Universal Router | Executes command-based routes across supported paths | Interface and advanced routing flows | | Permit2 | Provides shared allowance and signature-transfer flows | Router approvals | Use [Contract Deployments](/contracts/v2/deployments) for network-specific addresses and [Pools by Network](/contracts/v2/pools) for published pair addresses. ## External integration contracts The [Uniswap v4 Integration](/contracts/v4/overview) section covers PoolManager, PositionManager, hooks, and related contracts used in Uniswap v4 environments. These contracts are not a separate native Ring AMM. ## Choose the correct entry point | Task | Entry point | | --- | --- | | Resolve a FewToken | `FewFactory` | | Find or validate a Ring Swap pair | Ring Swap Factory | | Execute a standard swap | Ring Swap Router or Universal Router | | Provide Ring Swap liquidity | Ring Swap Router | | Build a TypeScript route | [Ring Swap SDK](/sdk/v2/overview) | | Request executable calldata | [Routing API](/api/routing/overview) | | Build a Few hook or use a Uniswap v4 pool | [Uniswap v4 Integration](/contracts/v4/overview) | Do not select a contract from its name alone. Select the network and workflow first, then use the official address published for that path. --- ## Ring Swap Overview # Ring Swap Ring Swap is Ring's native constant-product AMM. Its pools trade FewToken assets, and its routers provide the normal entry points for swaps and liquidity. The `(v2)` label identifies the compatible contract design. It does not make Ring Swap a legacy product. ## When to use Ring Swap Use this section when you need to: - find Ring contract or pair addresses - integrate swaps or liquidity in a smart contract - read pair reserves or LP state - build quotes and trades with the Ring Swap SDK - resolve the FewToken assets used in a route If you are building directly against Uniswap v4 PoolManager, PositionManager, or hook contracts, use the [Uniswap v4 Integration](/contracts/v4/overview) section instead. ## Architecture | Layer | Main components | Purpose | | --- | --- | --- | | Asset | `FewFactory`, `FewToken` | Resolve and wrap the assets used by Ring | | Core AMM | Ring Swap Factory, Pair | Create pools, hold reserves, mint LP tokens, and execute swaps | | Routing | Ring Swap Router, Universal Router, Permit2 | Coordinate user-facing swaps, liquidity, and approvals | | Developer access | Ring Swap SDK, Routing API | Build routes, quotes, and transactions | ## Start by task | Task | Guide | | --- | --- | | Select a network and contract | [Contract Deployments](./deployments) | | Find a BSC or HyperEVM pool | [Pools by Network](./pools) | | Resolve or validate a FewToken | [FewToken Integration](./fewtoken/integrating) | | Execute a swap from a contract | [Smart Contract Quick Start](./guides/smart-contract-integration/quick-start) | | Provide liquidity | [Providing Liquidity](./guides/smart-contract-integration/providing-liquidity) | | Build in TypeScript | [Ring Swap SDK](/sdk/v2/overview) | | Understand the AMM | [Ring Swap Model](./concepts/how-ring-swap-works/ring-swap-model) | ## Source repositories - [Ring Swap core](https://github.com/RingProtocol/few-v2-core) - [Ring Swap periphery](https://github.com/RingProtocol/few-periphery) - [Ring SDKs](https://github.com/RingProtocol/sdks) --- ## Contract Deployments # Ring Swap Contract Deployments This is the maintained address directory for Ring Swap, FewFactory, routers, wrappers, and related contracts. Some partner integrations and older tooling call this deployment family `FewV2`. The product name in these docs is Ring Swap (v2). This page was revised on `2026-08-20`. It is a versioned documentation snapshot, not a live registry or a substitute for onchain verification. Addresses are chain-specific. Select the network before copying an address, check that it has bytecode, and validate the contract's immutable factory, FewFactory, WETH, or wrapper references where applicable. Both reference pages cover Ethereum (`1`), BNB Smart Chain (`56`), HyperEVM (`999`), and MegaETH (`4326`). Pool addresses and discovery notes are documented separately in [Pools by Network](./pools). `UniversalRouter` rows are published Ring routing endpoints. Do not infer that every Interface, API, or route uses that address. Select the execution flow first and allow only the router approved for that flow. Ring-published hook addresses used with external Uniswap v4 infrastructure are documented separately under [Few Hook Contracts](/contracts/v4/guides/hooks/few-hook-contracts). :::warning Addresses are not deposit destinations Do not transfer assets directly to a Factory, Pair, Router, FewFactory, FewToken, wrapper, hook, or Permit2 contract. Call the documented function through a reviewed integration. A listed address does not by itself establish an approval spender, token endorsement, audit result, current liquidity level, or redemption guarantee. ::: Before a transaction, use the [Security and Risk](/security-and-risk) checklist. Verify the chain ID, code, recipient, raw amount, token path, spender, deadline, price limit, and simulation result. ## Mainnet Deployments ### Ethereum Mainnet {#eth-mainnet} - **Chain ID:** `1` - **Explorer:** [Etherscan](https://etherscan.io/) - **Pools:** [Browse live pools in the Ring Pool Explorer](https://app.ring.exchange/explorer#/explore/pools) | Contract | Ethereum Mainnet Address | | --- | --- | | Ring Swap Factory | `0xeb2A625B704d73e82946D8d026E1F588Eed06416` | | Few Factory | `0x7D86394139bf1122E82FDF45Bb4e3b038A4464DD` | | Ring Swap Router | `0x39d1d8fcC5E6EEAf567Bce4e29B94fec956D3519` | | UniversalRouter | `0x24e743CcE93235641f2be8Ce7ffC6330903ab96f` | | Permit2 | `0x000000000022D473030F116dDEE9F6B43aC78BA3` | | FewETHWrapper | `0xAda6059b4F6244Acd8934095Ed0162C5Df6B5ebB` | | Value | Ethereum Mainnet | | --- | --- | | Ring Swap Pair Init Code | `0xa7ae6a5ec37f0c21bbdac560794258c4089b8ae3ffa6e3909b53c6091764a676` | | Few Wrapped Token Init Code | `0x2bdba5734ddf754fb149ef1faa937956c52cfd1f24d68163a95f42d08ec06d38` | ### BNB Smart Chain {#bsc-mainnet} - **Chain ID:** `56` - **Explorer:** [BscScan](https://bscscan.com/) - **Pools:** [BSC reference pool and token mappings](./pools#bnb-smart-chain) | Contract | BNB Smart Chain Address | | --- | --- | | Ring Swap Factory | `0x4De602A30Ad7fEf8223dcf67A9fB704324C4dd9B` | | Few Factory | `0xEeE400Eabfba8F60f4e6B351D8577394BeB972CD` | | Ring Swap Router | `0x20504f37A95eF80e3FC7476c4801fb39AaE6bAd0` | | UniversalRouter | `0x1Fb6ef969D925f0B81245cE28F2cAD95b638CfCC` | | Permit2 | `0x000000000022D473030F116dDEE9F6B43aC78BA3` | | FewETHWrapper | `0xf9d7ff2f6A0c3631A807199276a493Af8097916F` | | Value | BNB Smart Chain | | --- | --- | | Ring Swap Pair Init Code | `0xa7ae6a5ec37f0c21bbdac560794258c4089b8ae3ffa6e3909b53c6091764a676` | | Few Wrapped Token Init Code | `0x2bdba5734ddf754fb149ef1faa937956c52cfd1f24d68163a95f42d08ec06d38` | ### HyperEVM {#hyper-mainnet} - **Chain ID:** `999` - **Explorer:** [HyperEVMScan](https://hyperevmscan.io/) - **Pools:** [HyperEVM factory pools and token mappings](./pools#hyperevm) | Contract | HyperEVM Address | | --- | --- | | Ring Swap Factory | `0x4AfC2e4cA0844ad153B090dc32e207c1DD74a8E4` | | Few Factory | `0x6B65ed7315274eB9EF06A48132EB04D808700b86` | | Ring Swap Router | `0x701D1d675415efA2d2429fB122ccC6dD4FCcA959` | | UniversalRouter | `0xE65081EFa5ad4A196B1Df768716c337e6AB140E9` | | Permit2 | `0x000000000022D473030F116dDEE9F6B43aC78BA3` | | FewETHWrapper | `0x068B60ECbC934b0a0dde20FdFf0dE925b97B971F` | | Value | HyperEVM | | --- | --- | | Ring Swap Pair Init Code | `0xa7ae6a5ec37f0c21bbdac560794258c4089b8ae3ffa6e3909b53c6091764a676` | | Few Wrapped Token Init Code | `0x2bdba5734ddf754fb149ef1faa937956c52cfd1f24d68163a95f42d08ec06d38` | ### MegaETH Mainnet - **Chain ID:** `4326` - **Pools:** [MegaETH pool discovery notes](./pools#megaeth-mainnet) | Contract | MegaETH Mainnet Address | | --- | --- | | WETH | `0x4200000000000000000000000000000000000006` | | Core | `0x732819C68c72D09465B8FaDF8156A79d21E87DCA` | | Few Factory | `0x6AE74eC9D067C734060FC5edB66fC6D48682970E` | | fwWETH | `0x65c46c31E340D6C546309733CF50Ef4d150094C4` | | FewETHWrapper | `0xb0Bd0CD58551b71079F36B198276832242D02C0F` | | Ring Swap Factory | `0x47C436602d2598d0ef4b50888F29a528B6Bccc95` | | V2-Compatible Router | `0xE73442C4b87283D75768F3668B411fc2348B429b` | | Ring Swap Router | `0x88a9A29FA981721C04fdC367ab7e3C83A4C65db9` | | UniversalRouter | `0x9256667638ED96ba4eCb30bD23efD2A182e1bC98` | | Timelock | `0xb0BEa0daA0E57c43d92711f9dF2d0D54CebEEA72` | | Permit2 | `0x000000000022D473030F116dDEE9F6B43aC78BA3` | | Multicall3 | `0xcA11bde05977b3631167028862bE2a173976CA11` | | Value | MegaETH Mainnet | | --- | --- | | Ring Swap Pair Init Code | `0xa7ae6a5ec37f0c21bbdac560794258c4089b8ae3ffa6e3909b53c6091764a676` | | Few Wrapped Token Init Code | `0x2bdba5734ddf754fb149ef1faa937956c52cfd1f24d68163a95f42d08ec06d38` | --- ## Pools by Network # Ring Swap Pools by Network This page lists pool discovery references by network. It does not repeat the full deployment tables; Factory addresses appear only where they help integrators discover pools. Routers, wrappers, Permit2, and the complete contract directory are maintained in [Contract Deployments](./deployments). Both pages cover Ethereum (`1`), BNB Smart Chain (`56`), HyperEVM (`999`), and MegaETH (`4326`) in the same order. | Network | Chain ID | Pool reference | | --- | ---: | --- | | Ethereum | `1` | Live Ring Pool Explorer | | BNB Smart Chain | `56` | Curated reference pool and factory snapshot | | HyperEVM | `999` | Complete factory snapshot at the listed block | | MegaETH | `4326` | Query the Ring Swap Factory; no curated table yet | Pair addresses are chain-specific. Select the network first, then use that network's Ring Swap Factory and FewToken mappings. Some partner APIs call Ring Swap liquidity `FewV2`. This is the network-specific pool reference for that integration name. This page publishes stable integration references, not live liquidity metrics. Reserves and TVL change every block and are intentionally omitted. Ring Swap factories are permissionless. Anyone can create a pair when the contracts allow it. A pair in a factory, this table, a token list, or an explorer is not proof that Ring reviewed or endorses the assets. Use an application-level allowlist and verify every FewToken through FewFactory and every pair through the Ring Swap Factory. :::warning Do not transfer assets to a pair address Pair addresses hold pool reserves and LP accounting. They are not user deposit addresses. Use a reviewed Router or contract integration with a minimum output or maximum input, future deadline, verified recipient, and fresh simulation. ::: ## Ethereum Mainnet - **Chain ID:** `1` - **Contracts:** [Ethereum deployments](./deployments#eth-mainnet) - **Pools:** [Browse Ethereum pools in the Ring Pool Explorer](https://app.ring.exchange/explorer#/explore/pools) Ethereum pools are discovered through the live explorer instead of a static table. ## BNB Smart Chain - **Chain ID:** `56` - **Network aliases:** `BNB Smart Chain`, `BSC` - **Ring Swap Factory:** [`0x4De602A30Ad7fEf8223dcf67A9fB704324C4dd9B`](https://bscscan.com/address/0x4De602A30Ad7fEf8223dcf67A9fB704324C4dd9B) - **Contracts:** [BNB Smart Chain deployments](./deployments#bsc-mainnet) ### Curated reference pool | Pool | Pair address | | --- | --- | | `fwWBNB / fwETH` | [`0xFF1513E452a6033e2d9601a4559bF273f83D5470`](https://bscscan.com/address/0xFF1513E452a6033e2d9601a4559bF273f83D5470) | ### Token mapping | FewToken | Original token | | --- | --- | | `fwWBNB`: [`0x7f0172b75d3823D8aF04feE3A3f6a14aBD68EFE1`](https://bscscan.com/address/0x7f0172b75d3823D8aF04feE3A3f6a14aBD68EFE1) | `WBNB`: [`0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c`](https://bscscan.com/address/0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c) | | `fwETH`: [`0x86fa03945646a99A03543e7e0036361Ffadc73E6`](https://bscscan.com/address/0x86fa03945646a99A03543e7e0036361Ffadc73E6) | `ETH`: [`0x2170Ed0880ac9A755fd29B2688956BD959F933F8`](https://bscscan.com/address/0x2170Ed0880ac9A755fd29B2688956BD959F933F8) | The BSC factory returned 52 pairs at block `116,980,675`. The table above is deliberately curated. It is not a complete factory index, a recommendation, or a guarantee of current liquidity. Integrators that enumerate the permissionless factory must still apply their own token and pair allowlist and validate both FewToken addresses through FewFactory. ## HyperEVM - **Chain ID:** `999` - **Ring Swap Factory:** [`0x4AfC2e4cA0844ad153B090dc32e207c1DD74a8E4`](https://hyperevmscan.io/address/0x4AfC2e4cA0844ad153B090dc32e207c1DD74a8E4) - **Contracts:** [HyperEVM deployments](./deployments#hyper-mainnet) ### Factory pools at the snapshot block | Pool | Pair address | | --- | --- | | `fwUSD₮0 / fwWHYPE` | [`0xf3760B19f1Baa2bFcf6Bd6e5d174e129c80aeD17`](https://hyperevmscan.io/address/0xf3760B19f1Baa2bFcf6Bd6e5d174e129c80aeD17) | | `fwUETH / fwWHYPE` | [`0x0185E8e8B7FDf22638ecB2D781b3EA7E8AA2452a`](https://hyperevmscan.io/address/0x0185E8e8B7FDf22638ecB2D781b3EA7E8AA2452a) | | `fwUSDH / fwUSDC` | [`0xabEd9A9aDe03a80ED98f903Eb9db62DE55C9DDF3`](https://hyperevmscan.io/address/0xabEd9A9aDe03a80ED98f903Eb9db62DE55C9DDF3) | | `fwUSDH / fwUSD₮0` | [`0xf37f1e83BEb55F1b88AF9A8Df1a746e79C222150`](https://hyperevmscan.io/address/0xf37f1e83BEb55F1b88AF9A8Df1a746e79C222150) | | `fwUSD₮0 / fwUSDC` | [`0x8868a630dD13A954D3f8B186508EF6c733BE959F`](https://hyperevmscan.io/address/0x8868a630dD13A954D3f8B186508EF6c733BE959F) | ### Token mapping | FewToken | Original token | | --- | --- | | `fwWHYPE`: [`0x9e1148bC3665a9f7C35F313d89c0432c34928AEf`](https://hyperevmscan.io/address/0x9e1148bC3665a9f7C35F313d89c0432c34928AEf) | `WHYPE`: [`0x5555555555555555555555555555555555555555`](https://hyperevmscan.io/address/0x5555555555555555555555555555555555555555) | | `fwUSD₮0`: [`0x7576dd9a2775bFd789616d9eA7A2af21d06782D0`](https://hyperevmscan.io/address/0x7576dd9a2775bFd789616d9eA7A2af21d06782D0) | `USD₮0`: [`0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb`](https://hyperevmscan.io/address/0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb) | | `fwUETH`: [`0x0C47cbbEDE5d8c6f9614cF770C26c3315205C397`](https://hyperevmscan.io/address/0x0C47cbbEDE5d8c6f9614cF770C26c3315205C397) | `UETH`: [`0xBe6727B535545C67d5cAa73dEa54865B92CF7907`](https://hyperevmscan.io/address/0xBe6727B535545C67d5cAa73dEa54865B92CF7907) | | `fwUSDC`: [`0xd2646b9B02859416D8cBc759F85f0676f6E19974`](https://hyperevmscan.io/address/0xd2646b9B02859416D8cBc759F85f0676f6E19974) | `USDC`: [`0xb88339CB7199b77e23DB6E890353E22632Ba630f`](https://hyperevmscan.io/address/0xb88339CB7199b77e23DB6E890353E22632Ba630f) | | `fwUSDH`: [`0x09D21E89EF332347eb3E1E496f1265a600e364C1`](https://hyperevmscan.io/address/0x09D21E89EF332347eb3E1E496f1265a600e364C1) | `USDH`: [`0x111111a1a0667d36bD57c0A9f569b98057111111`](https://hyperevmscan.io/address/0x111111a1a0667d36bD57c0A9f569b98057111111) | At block `43,670,147`, the HyperEVM factory returned five pairs. All five pair addresses, pair tokens, and FewToken-to-original-token mappings above were read onchain. This records factory state, not token review, price quality, liquidity, or suitability for user funds. ## MegaETH Mainnet - **Chain ID:** `4326` - **Contracts:** [MegaETH deployments](./deployments#megaeth-mainnet) A curated MegaETH pool table is not maintained on this page yet. Integrators should query the published Ring Swap Factory, validate returned FewToken addresses through FewFactory, and apply a separate asset and pair allowlist. The published `@ring-protocol/v2-sdk@1.0.0` does not support MegaETH FewToken and pair derivation. Do not use its MegaETH address helpers until the [SDK support table](/sdk/v2/overview#published-network-support) names a fixed published version. ## Verification snapshot The BSC and HyperEVM tables were checked on `2026-08-20`. A snapshot records the addresses and mappings returned at the listed blocks. It does not prove current code, reserves, trading volume, asset quality, approval safety, or suitability for a particular order size. Recheck the factory and wrapper mappings at the block used for your transaction. --- ## FewToken Integration Ring Swap (v2) keeps compatibility with v2-style AMM integration patterns while introducing `Few Protocol` as a wrapping layer. ## Integration Overview To integrate `Ring Swap (v2)` for swap and liquidity flows, replace your existing v2-style integration points with Ring deployments: - Ring Swap Factory - Ring Swap Pair Init Code - Ring Swap Router - Universal Router ## Key Difference: Few Protocol Wrapping Few Protocol wraps original ERC-20 tokens into `FewToken`. Ring's native swap system, `Ring Swap (v2)`, uses wrapped assets in pools and routes. When integrating: - quote prices with FewToken addresses - construct swap paths with FewToken addresses - resolve wrapped token addresses via FewFactory ## FewToken Address Resolution :::info Verify FewFactory onchain Supported FewToken identity must resolve through the published `FewFactory` for the selected chain. For Ring integrations, a FewToken is supported only when `FewFactory.getWrappedToken(underlying)` returns that wrapper address. Token `name`, `symbol`, a `token()` method, or the existence of a pool do not define whether an address is a supported FewToken. ::: ### Integration rule For each chain, read the published `FewFactory` address from the [Deployments](../deployments) page, then verify its bytecode, `core()` reference, and chain ID onchain. When your code starts from an original ERC-20, resolve the FewToken yourself: ```solidity address wrapper = IFewFactory(fewFactory).getWrappedToken(underlying); require(wrapper != address(0), "no FewToken for token"); ``` When your code receives a wrapper from an external source, validate it before using it in routing, wrapping, or approval logic: ```solidity function _assertCanonicalFewToken(address underlying, address wrapper) internal view { address expected = IFewFactory(fewFactory).getWrappedToken(underlying); require(expected != address(0), "no FewToken for token"); require(expected == wrapper, "non-canonical FewToken"); } ``` Supported FewToken addresses are resolved through `FewFactory`. The following fields are display or discovery data only: - `symbol()` / `name()` - a `token()` method - a `fw` or `Few Wrapped` prefix - whether a RingSwap-style pool exists - whether a quote or route looks profitable ### Approval spender selection ERC-20 approvals grant transfer permission to the spender. Select the spender from the integration path you are using, not from arbitrary route or pool metadata. | Flow | Token being approved | Spender | | --- | --- | --- | | Ring Swap Router swap or add liquidity | Original ERC-20 input | The selected Ring Swap Router | | Manual wrap | Original ERC-20 input | The FewToken returned by `FewFactory.getWrappedToken(underlying)` | | Universal Router with Permit2 | Original ERC-20 input | Permit2 for the ERC-20 allowance, then the selected Universal Router in the bounded Permit2 authorization | | Remove liquidity | Pair LP token | The selected Ring Swap Router, or the same router in the LP permit | Prefer exact amounts and short expiries. Clear temporary allowances when the token and flow support it. Validate every spender against the selected deployment and flow. A Pair, Factory, FewFactory, hook, quote target, or token-list entry is not an approval spender by default. SDK derivation is a convenience, not an authorization check. Compare its result with the deployed FewFactory. External FewToken-looking addresses are unsupported unless they pass the same onchain check. ## Supply and backing boundary The reviewed FewToken source includes both escrow-backed `wrap` and role-controlled `mint`. Privileged minting does not itself transfer the original token into the wrapper. The current Core role holders, pause state, underlying balance, supply, and issuance history must be checked onchain before an integration assumes redemption capacity. FewToken `burn()` destroys the caller's FewToken without transferring the original asset. Use `unwrap()` or `unwrapTo()` for redemption. See [Few Protocol and FewToken](/concepts/few-protocol) for role, pause, raw-unit, and nonstandard-token details. ## Important note Ring Swap (v2) is a native Ring product line. The `v2` label describes the compatible AMM design; it is not part of a public Ring product-version ladder. If you are integrating with v4-related workflows elsewhere in these docs, that should generally be understood as `FewToken` integration with `Uniswap v4`, not as a separate native v4 protocol. ## Swap Path Example If your intended route is: ```text [tokenA, USDC, tokenB] ``` Use this path for Ring Swap: ```text [fwTokenA, fwUSDC, fwTokenB] ``` `fwTokenX` means the FewToken mapped from original token `tokenX`. --- ## Smart Contract Quick Start This guide shows a narrow adapter for one allowlisted Ring Swap pair. It fixes the router, factory, FewFactory, underlying tokens, and FewToken path at deployment so callers cannot redirect funds through an arbitrary contract or pool. The example is an integration pattern, not a deployed or audited contract. Add protocol-specific access control, accounting, emergency behavior, and tests before production use. ## Select and verify a deployment Start from [Ring Swap deployments](../../deployments), then verify the selected addresses onchain: 1. The RPC chain ID equals the intended network. 2. Router, Ring Swap Factory, FewFactory, FewTokens, and pair all have bytecode. 3. The router's immutable getters return the selected factory and FewFactory. 4. `FewFactory.getWrappedToken(underlying)` returns each FewToken. 5. `Ring Swap Factory.getPair(fewTokenIn, fewTokenOut)` returns the selected pair. Do not accept these addresses from calldata, token metadata, a pool list, or a quote response. ## Fixed-pair adapter This example uses OpenZeppelin Contracts 5.x `SafeERC20` and `ReentrancyGuard`: ```solidity pragma solidity ^0.8.20; interface IRingSwapRouter { function factory() external view returns (address); function fewFactory() external view returns (address); function swapExactTokensForTokens( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address recipient, uint256 deadline ) external returns (uint256[] memory amounts); } interface IFewFactory { function getWrappedToken(address underlying) external view returns (address); } interface IFewWrappedToken { function token() external view returns (address); } interface IRingSwapFactory { function getPair(address tokenA, address tokenB) external view returns (address); } contract FixedPairRingSwap is ReentrancyGuard { using SafeERC20 for IERC20; IRingSwapRouter public immutable router; IERC20 public immutable inputToken; address public immutable outputToken; address public immutable fewTokenIn; address public immutable fewTokenOut; address public immutable pair; constructor( address router_, address factory_, address fewFactory_, address inputToken_, address outputToken_, address fewTokenIn_, address fewTokenOut_ ) { require( router_.code.length > 0 && factory_.code.length > 0 && fewFactory_.code.length > 0, "missing deployment code" ); require(inputToken_.code.length > 0 && outputToken_.code.length > 0, "missing token code"); require(fewTokenIn_.code.length > 0 && fewTokenOut_.code.length > 0, "missing FewToken code"); IRingSwapRouter selectedRouter = IRingSwapRouter(router_); require(selectedRouter.factory() == factory_, "router factory mismatch"); require(selectedRouter.fewFactory() == fewFactory_, "router FewFactory mismatch"); IFewFactory selectedFewFactory = IFewFactory(fewFactory_); require(selectedFewFactory.getWrappedToken(inputToken_) == fewTokenIn_, "input wrapper mismatch"); require(selectedFewFactory.getWrappedToken(outputToken_) == fewTokenOut_, "output wrapper mismatch"); require(IFewWrappedToken(fewTokenIn_).token() == inputToken_, "input underlying mismatch"); require(IFewWrappedToken(fewTokenOut_).token() == outputToken_, "output underlying mismatch"); address selectedPair = IRingSwapFactory(factory_).getPair(fewTokenIn_, fewTokenOut_); require(selectedPair != address(0) && selectedPair.code.length > 0, "pair not deployed"); router = selectedRouter; inputToken = IERC20(inputToken_); outputToken = outputToken_; fewTokenIn = fewTokenIn_; fewTokenOut = fewTokenOut_; pair = selectedPair; } function swapExactInput( uint256 amountIn, uint256 amountOutMin, address recipient, uint256 deadline ) external nonReentrant returns (uint256[] memory amounts) { require(amountIn > 0 && amountOutMin > 0, "invalid amount"); require(recipient != address(0), "invalid recipient"); require(deadline > block.timestamp, "expired"); inputToken.safeTransferFrom(msg.sender, address(this), amountIn); inputToken.forceApprove(address(router), amountIn); address[] memory path = new address[](2); path[0] = fewTokenIn; path[1] = fewTokenOut; amounts = router.swapExactTokensForTokens(amountIn, amountOutMin, path, recipient, deadline); inputToken.forceApprove(address(router), 0); } } ``` The caller approves the adapter for the original input token. The adapter approves the selected Ring Swap Router for the same original token and exact amount. The router wraps it internally. The path itself contains FewToken addresses. ## Production checks - Calculate `amountOutMin` from a fresh quote plus an independent price policy. The pair reserve ratio is not an oracle. - Pass a caller-approved future deadline. Do not replace it with `block.timestamp` inside the transaction. - Support only reviewed ERC-20 behavior. Fee-on-transfer, rebasing, callback, and nonstandard approval tokens need dedicated handling and tests. - Simulate the exact call at the latest block and test revert behavior, allowance cleanup, recipient handling, and both token directions. - If the integration needs multiple assets, extend a governance-controlled allowlist with delayed, reviewable changes. Do not accept arbitrary factories, routers, wrappers, pairs, or approval spenders from users. See [Security and Risk](/security-and-risk) for the complete pre-signing checklist. --- ## Implement a Swap Contract integrations need an independent price limit, a fixed or allowlisted execution path, and a caller-approved deadline. A Ring Swap reserve ratio is transaction state, not a manipulation-resistant price source. Start with the [fixed-pair adapter](./quick-start). It validates the router, factory, FewFactory, wrappers, and pair in the constructor and keeps those addresses out of user-controlled calldata. ## Router address semantics The Ring Swap Router uses two address domains in one swap: - The caller holds and approves the original input ERC-20. - The router's `path` contains the FewToken addresses held by the Ring Swap pairs. - The router wraps the original input and unwraps the final FewToken output internally. For a DAI to ETH route, the safety checks and call shape are: ```solidity require(fewFactory.getWrappedToken(address(DAI)) == fwDAI, "DAI wrapper mismatch"); require(fewFactory.getWrappedToken(router.WETH()) == router.fwWETH(), "WETH wrapper mismatch"); require(factory.getPair(fwDAI, router.fwWETH()) == allowedPair, "pair mismatch"); require(deadline > block.timestamp, "expired"); require(amountOutMin > 0, "missing price limit"); DAI.forceApprove(address(router), amountIn); address[] memory path = new address[](2); path[0] = fwDAI; path[1] = router.fwWETH(); router.swapExactTokensForETH(amountIn, amountOutMin, path, recipient, deadline); DAI.forceApprove(address(router), 0); ``` The snippet assumes `DAI` uses OpenZeppelin `SafeERC20`, and that `router`, `factory`, `fewFactory`, `fwDAI`, and `allowedPair` were fixed or approved before the call. Do not copy it into a contract that accepts those values from an untrusted caller. ## Price and transaction limits For an exact-input swap, derive `amountOutMin` from a fresh offchain quote or an independent oracle with a documented staleness bound. For an exact-output swap, set `amountInMax` the same way. The check must remain meaningful if an attacker moves the Ring Swap pool before your transaction. Also validate: - chain ID, input and output tokens, raw token units, and native value - recipient and any refund recipient - each FewToken and pair in a multi-hop route - deadline and quote age - actual allowance spender - simulation result at the latest block Requote or revert when any of these values has changed. See [Security and Risk](/security-and-risk) for Permit2 and Routing API checks. --- ## Providing Liquidity Adding liquidity transfers both assets into a pool and returns LP tokens. The pool reserve ratio can be manipulated, and the first liquidity provider sets the initial ratio. Use an independent price policy before committing assets. ## Use a reviewed allowlist Ring Swap factories are permissionless. A pair's existence does not show that Ring reviewed either token or that the pair is suitable for deposits. A production integration should allow only reviewed entries containing: - chain ID and original token addresses - FewFactory and canonical FewToken addresses - Ring Swap Factory and pair address - allowed Ring Swap Router - token behavior assumptions, including decimals, transfer fees, rebasing, callbacks, and approval behavior - independent price source, freshness bound, and deposit limits Confirm `FewFactory.getWrappedToken(underlying)` and `Ring Swap Factory.getPair(fewTokenA, fewTokenB)` onchain before a deposit. If the pair does not exist, require a separate reviewed pool-creation flow. Do not let a normal deposit create an arbitrary wrapper or pair from user-supplied tokens. ## Set price limits before submission The `amountADesired` and `amountBDesired` values express the intended deposit ratio. Calculate them before the transaction from a fresh independent price observation. Do not read the reserve ratio inside the same transaction and treat it as a fair price. Set `amountAMin` and `amountBMin` from the approved tolerance. These values protect each side of the deposit if the pool state moves before confirmation. They do not protect against a bad external price assumption. For a new pair, require a second review of the initial ratio, minimum locked liquidity, token ordering, and recipient. An incorrect initial ratio can transfer value to the first arbitrageur. ## Approvals and recipient For `addLiquidity` and `addLiquidityETH`, approve the selected Ring Swap Router for the original ERC-20 inputs. The router resolves and wraps the FewTokens internally. Prefer exact allowances and clear temporary allowances after the call when the token supports it. The `to` parameter receives the LP tokens. Validate it separately from token refund and swap recipients. Never use the Pair, Factory, Router, FewFactory, FewToken, Permit2, or a burn address as the LP recipient unless the reviewed design explicitly requires it. Pass a caller-approved future deadline and simulate the exact transaction at the latest block. After execution, verify the actual token amounts deposited, LP tokens received, recipient, remaining allowances, and any refunded dust. See [Security and Risk](/security-and-risk) for the shared address and approval checklist. --- ## Ring Swap SDK Use `@ring-protocol/v2-sdk` for TypeScript and JavaScript integrations with Ring Swap. ```bash yarn add @ring-protocol/v2-sdk @ring-protocol/sdk-core ``` ## Package map | Package | Role | Use directly? | | --- | --- | --- | | `@ring-protocol/v2-sdk` | FewToken-aware pairs, routes, trades, and address helpers | Yes. This is the default Ring Swap SDK | | `@ring-protocol/sdk-core` | Shared token, amount, price, and percentage types | Yes, when constructing SDK inputs | | `@ring-protocol/uniswap-v2-sdk` | Lower-level v2-compatible primitives | Only when you specifically need the base compatibility layer | All three packages are maintained in the [Ring SDK monorepo](https://github.com/RingProtocol/sdks). ## Published network support This table describes `@ring-protocol/v2-sdk@1.0.0`, the package checked on `2026-08-20`. A chain appearing in `@ring-protocol/sdk-core` does not mean the FewToken-aware v2 package supports that chain. | Network | Chain ID | Published v2 SDK status | | --- | --- | --- | | Ethereum Mainnet | `1` | Configured. Verify FewFactory, factory, and init code against the deployment page and onchain before use | | BNB Smart Chain | `56` | Configured. Verify the derived FewToken and pair onchain before use | | HyperEVM | `999` | Configured. Verify the derived FewToken and pair onchain before use | | MegaETH Mainnet | `4326` | **Unsupported in the published package.** Do not use v1.0.0 FewToken or pair-address helpers for MegaETH | MegaETH support becomes available only after a package with the reviewed Ring Swap Factory, FewFactory, and init-code configuration is published and this table names that version. Until then, read addresses from the deployment page and resolve them directly onchain. ## Start by task | Task | Guide | | --- | --- | | Install the SDK and create tokens | [Quick Start](./guides/quick-start) | | Read pair data | [Fetching Data](./guides/fetching-data) | | Calculate prices | [Pricing](./guides/pricing) | | Construct a trade | [Trading](./guides/trading) | | Derive a pair address | [Getting Pair Addresses](./guides/getting-pair-addresses) | ## FewToken rule Ring Swap pools and paths use FewToken addresses. Derive wrappers through SDK configuration only on a supported network, then compare the result with the published and independently verified `FewFactory` onchain. Do not identify a wrapper only from its symbol, name, token-list entry, or the existence of a pool. The v1.0.0 `isFewToken()` helper checks display metadata and must not be used as an authorization or asset-identity check. Confirm `FewFactory.getWrappedToken(underlying) === candidate` onchain. For pair identity, confirm `Ring Swap Factory.getPair(tokenA, tokenB)` rather than accepting a locally derived address alone. Use [Contract Deployments](/contracts/v2/deployments) as the maintained factory and router directory, then verify the selected deployment onchain. If you need a hosted quote service, use the [Routing API](/api/routing/overview) and apply its response-validation checklist. --- ## SDK Quick start The Ring SDK exists to help developers build on top of Ring Swap (v2). It's designed to run in any environment that can execute JavaScript, such as websites and node scripts. `@ring-protocol/v2-sdk` is the FEW-aware SDK layer. It adds helper functions for deriving `FewToken` addresses and for working with Ring Swap pairs while still letting your app reason about the original ERC-20 assets. ## Installation The easiest way to consume the SDK is via npm. Install the package your project uses, together with `sdk-core` and any required runtime dependencies. For most Ring Swap integrations, install: ```bash npm install @ring-protocol/sdk-core @ring-protocol/v2-sdk ``` Use `@ring-protocol/uniswap-v2-sdk` only if you explicitly need the lower-level v2-compatible primitives rather than the FEW-aware Ring layer. ## Usage To run code from the SDK in your application, use an `import` or `require` statement, depending on which your environment supports. Note that the guides following this page will use ES6 syntax. ## ES6 (import) ```typescript const DAI = new Token(ChainId.MAINNET, '0x6B175474E89094C44Da98b954EedeAC495271d0F', 18, 'DAI', 'Dai Stablecoin') const fewDAI = getFewTokenFromOriginalToken(DAI, ChainId.MAINNET) console.log(`The chainId of mainnet is ${ChainId.MAINNET}.`) console.log(`The few token address is ${fewDAI.address}.`) ``` :::warning Use FewFactory-derived addresses `fw` symbols and `Few Wrapped` names are display metadata. The SDK can derive a candidate FewToken address on a supported chain, but routing and approval logic must also require that the selected `FewFactory.getWrappedToken(underlying)` returns that address onchain. The published v1.0.0 package does not support MegaETH FewToken derivation. On any supported chain, verify the derived address against the deployed FewFactory before using it with funds. Do not use `isFewToken()` as an authorization check. ::: ## CommonJS (require) ```typescript const CORE = require('@ring-protocol/sdk-core') const V2_SDK = require('@ring-protocol/v2-sdk') console.log(`The chainId of mainnet is ${CORE.ChainId.MAINNET}.`) ``` ## Reference Comprehensive reference material for the SDK is publicly available in the [Ring SDK monorepo](https://github.com/RingProtocol/sdks). --- ## Fetching Data > Looking for a [quickstart](quick-start)? The SDK needs onchain token and pair data. Treat addresses and metadata as untrusted until they match the selected chain, reviewed deployment, and factory state. # Case 1: Tokens Unsurprisingly, the SDK needs some notion of an ERC-20 token to be able to function. This immediately raises the question of _where data about tokens comes from_. As an example, let's try to represent DAI in a format the SDK can work with. To do so, we need at least 3 pieces of data: a **chainId**, a **token address**, and how many **decimals** the token has. We also may be interested in the **symbol** and/or **name** of the token. For Ring Swap integrations, start by modeling the original ERC-20 token. If you need the token address that Ring Swap pairs actually use on-chain, derive the `FewToken` address from that original token. ## Identifying Data The first two pieces of data, **chainId** and **token address**, come from the integration's reviewed configuration. Do not accept them from token metadata or a quote response. For this Ethereum Mainnet example, the **chainId** is `1` and the configured DAI address is `0x6B175474E89094C44Da98b954EedeAC495271d0F`. Verify the chain, bytecode, and address through an independent source before using it with funds. ## Required Data The next piece of data we need is **decimals**. ### Provided by the User One option here is to simply pass in the correct value, which we may know is `18`. At this point, we're ready to represent DAI as a [Token](../../core/reference/classes/Token.md): ```typescript const chainId = ChainId.MAINNET const tokenAddress = '0x6B175474E89094C44Da98b954EedeAC495271d0F' // must be checksummed const decimals = 18 const DAI = new Token(chainId, tokenAddress, decimals) const fewDAI = getFewTokenFromOriginalToken(DAI, chainId) ``` `fewDAI` is a local candidate. Before routing or approving funds, require the selected deployed `FewFactory.getWrappedToken(DAI.address)` to return `fewDAI.address`. If we don't know or don't want to hardcode the value, we could look it up ourselves via any method of retrieving on-chain data in a function that looks something like: ```typescript async function getDecimals(chainId: ChainId, tokenAddress: string): Promise { // Setup provider, import necessary ABI ... const tokenContract = new ethers.Contract(tokenAddress, erc20abi, provider) return tokenContract["decimals"]() } ``` ## Optional Data Finally, **symbol** and **name** are optional display fields. Contracts can return misleading or malformed metadata, so do not use either field to identify an asset or authorize a route: ```typescript const DAI = new Token(ChainId.MAINNET, '0x6B175474E89094C44Da98b954EedeAC495271d0F', 18, 'DAI', 'Dai Stablecoin') ``` When you are interacting with Ring Swap pairs, derive the wrapped pair token from the original asset: ```typescript const DAI = new Token(ChainId.MAINNET, '0x6B175474E89094C44Da98b954EedeAC495271d0F', 18, 'DAI', 'Dai Stablecoin') const fewDAI = getFewTokenFromOriginalToken(DAI, ChainId.MAINNET) const fewWETH = getFewTokenFromOriginalToken(WETH9[ChainId.MAINNET], ChainId.MAINNET) ``` # Case 2: Pairs Now that we've defined the token inputs, the next step is loading a pair. See [Pair](../../../contracts/v2/reference/smart-contracts/pair) for the contract interface. As an example, let's try to represent a Ring Swap pair for DAI and WETH. The pair contract itself is typically keyed by the `FewToken` addresses, even though your application may still reason about the original DAI and WETH assets. ## Identifying Data Each pair consists of two tokens (see previous section). Note that WETH used by the router is [exported by the SDK Core as WETH9](../../core/reference/overview.md). ## Required Data The data we need is the _reserves_ of the pair. To read more about reserves, see [getReserves](../../../contracts/v2/reference/smart-contracts/pair#getreserves). ### Provided by the User Fetch the pair address from the selected Ring Swap Factory. A local CREATE2 result is only a prediction and must not be used as the sole authority for a value-bearing request. ```typescript const DAI = new Token(ChainId.MAINNET, '0x6B175474E89094C44Da98b954EedeAC495271d0F', 18) const fewDAI = getFewTokenFromOriginalToken(DAI, ChainId.MAINNET) const fewWETH = getFewTokenFromOriginalToken(WETH9[DAI.chainId], DAI.chainId) async function createPair(tokenA: Token, tokenB: Token, factory: ethers.Contract): Promise { if (tokenA.chainId !== tokenB.chainId) throw new Error('chain mismatch') const predictedAddress = Pair.getAddress(tokenA, tokenB) const pairAddress = await factory.getPair(tokenA.address, tokenB.address) if (pairAddress === ethers.constants.AddressZero) throw new Error('pair not deployed') if (pairAddress.toLowerCase() !== predictedAddress.toLowerCase()) throw new Error('pair derivation mismatch') if ((await provider.getCode(pairAddress)) === '0x') throw new Error('pair has no code') // Setup provider, import necessary ABI ... const pairContract = new ethers.Contract(pairAddress, ringV2PairABI, provider) const [onchainToken0, onchainToken1, reserves] = await Promise.all([ pairContract.token0(), pairContract.token1(), pairContract.getReserves(), ]) const [reserve0, reserve1] = reserves const tokens = [tokenA, tokenB] const [token0, token1] = tokens[0].sortsBefore(tokens[1]) ? tokens : [tokens[1], tokens[0]] if (onchainToken0.toLowerCase() !== token0.address.toLowerCase()) throw new Error('token0 mismatch') if (onchainToken1.toLowerCase() !== token1.address.toLowerCase()) throw new Error('token1 mismatch') return new Pair( CurrencyAmount.fromRawAmount(token0, reserve0.toString()), CurrencyAmount.fromRawAmount(token1, reserve1.toString()) ) } // factory must be the reviewed Ring Swap Factory for chainId 1. const pair = await createPair(fewDAI, fewWETH, factory) ``` Verify the factory address and bytecode before this call. Reserves can change every block, so record the quote block, apply an independent price and freshness policy, and simulate the final transaction immediately before submission. --- ## Pricing > Looking for a [quickstart](quick-start)? This guide covers the route **mid price** and a trade's **execution price**. In Ring Swap, the pool state is usually keyed by `FewToken` pairs, while your app may still display prices in terms of the original assets. The FEW-aware SDK handles that bridge for you. # Mid Price The mid price reflects the reserve ratio across one or more pairs. It is the route's marginal spot price before price impact for a nonzero trade. It is not an independent market price, fair-value estimate, or manipulation-resistant oracle. Pool reserves can change within a block and can be moved temporarily. Let's consider the mid price for DAI-WETH (that is, the amount of DAI per 1 WETH). ## Direct The simplest way to get the DAI-WETH mid price is to observe the pair directly: ```typescript const DAI = new Token(ChainId.MAINNET, '0x6B175474E89094C44Da98b954EedeAC495271d0F', 18) const fewDAI = getFewTokenFromOriginalToken(DAI, ChainId.MAINNET) const fewWETH = getFewTokenFromOriginalToken(WETH9[ChainId.MAINNET], ChainId.MAINNET) // To learn how to get Pair data, refer to the previous guide. const pair = await createPair(fewDAI, fewWETH) const route = new Route([pair], WETH9[DAI.chainId], DAI) console.log(route.midPrice.toSignificant(6)) // 1901.08 console.log(route.midPrice.invert().toSignificant(6)) // 0.000526017 ``` You may be wondering why we have to construct a _route_ to get the mid price, as opposed to simply getting it from the pair (which, after all, includes all the necessary data). The reason is simple: a route forces us to be opinionated about the _direction_ of trading. Routes consist of one or more pairs, an input token and an output token (which fully defines a trading path). In this case, we passed WETH as the input token and DAI as the output token, meaning we're interested in a WETH -> DAI trade. Now we understand that the mid price is going to be defined in terms of DAI/WETH. Not to worry though, if we need the WETH/DAI price, we can easily invert. Finally, you may have noticed that we're formatting the price to 6 significant digits. This is because internally, prices are stored as exact-precision fractions, which can be converted to other representations on demand. For a full list of options, see [Price](../../core/reference/classes/Price.md). ## Indirect For the sake of example, let's imagine a direct pair between DAI and WETH _doesn't exist_. In order to get a DAI-WETH mid price we'll need to pick a valid route. Imagine both DAI and WETH have pairs with a third token, USDC. In that case, we can calculate an indirect mid price through the USDC pairs: ```typescript const USDC = new Token(ChainId.MAINNET, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 6) const DAI = new Token(ChainId.MAINNET, '0x6B175474E89094C44Da98b954EedeAC495271d0F', 18) const fewUSDC = getFewTokenFromOriginalToken(USDC, ChainId.MAINNET) const fewDAI = getFewTokenFromOriginalToken(DAI, ChainId.MAINNET) const fewWETH = getFewTokenFromOriginalToken(WETH9[ChainId.MAINNET], ChainId.MAINNET) // To learn how to get Pair data, refer to the previous guide. const USDCWETHPair = await createPair(fewUSDC, fewWETH) const DAIUSDCPair = await createPair(fewDAI, fewUSDC) const route = new Route([USDCWETHPair, DAIUSDCPair], WETH9[ChainId.MAINNET], DAI) console.log(route.midPrice.toSignificant(6)) // 1896.34 console.log(route.midPrice.invert().toSignificant(6)) // 0.000527331 ``` # Execution Price The execution price is the modeled ratio of assets sent and received for a specific trade against the sampled reserves. It includes the trade's price impact but is still not a guaranteed fill or an independent market price. Use an independent price source and freshness policy when a mid or execution price controls a transaction limit, liquidation, valuation, or other value-sensitive decision. Imagine we're interested in trading 1 WETH for DAI: ```typescript const DAI = new Token(ChainId.MAINNET, '0x6B175474E89094C44Da98b954EedeAC495271d0F', 18) const fewDAI = getFewTokenFromOriginalToken(DAI, ChainId.MAINNET) const fewWETH = getFewTokenFromOriginalToken(WETH9[DAI.chainId], DAI.chainId) // To learn how to get Pair data, refer to the previous guide. const pair = await createPair(fewDAI, fewWETH) const route = new Route([pair], WETH9[DAI.chainId], DAI) const trade = new Trade(route, CurrencyAmount.fromRawAmount(WETH9[DAI.chainId], '1000000000000000000'), TradeType.EXACT_INPUT) console.log(trade.executionPrice.toSignificant(6)) // 1894.91 ``` This constructs an exact-input model for 1 WETH using the sampled direct-pair reserves. The execution price is the modeled average DAI per WETH. Re-read pair identity and reserves, enforce the transaction limit, and simulate the final calldata before submission because the pool can change every block. --- ## Trading > Looking for a [quickstart](quick-start)? The SDK calculates routes, amounts, and transaction parameters. It does not send transactions, verify every deployment, or establish an independent market price. Your integration must validate the result before signing or submission. This guide constructs parameters for the [Ring Swap Router](../../../contracts/v2/reference/smart-contracts/router-02) selected from the deployment table. # Sending a Transaction to the Router The example trades 1 ETH for DAI. Pair liquidity lives in FewToken form, while the route and trade APIs can still be expressed in terms of the original assets: ```typescript const DAI = new Token(ChainId.MAINNET, '0x6B175474E89094C44Da98b954EedeAC495271d0F', 18) const fewDAI = getFewTokenFromOriginalToken(DAI, ChainId.MAINNET) const fewWETH = getFewTokenFromOriginalToken(WETH9[DAI.chainId], DAI.chainId) const ETH = Ether.onChain(ChainId.MAINNET) // See the Fetching Data guide to learn how to get Pair data const pair = await createPair(fewDAI, fewWETH) const route = new Route([pair], ETH, DAI) const amountIn = '1000000000000000000' // 1 ETH in wei const trade = new Trade(route, CurrencyAmount.fromRawAmount(ETH, amountIn), TradeType.EXACT_INPUT) ``` The SDK represents native ETH through its wrapped currency internally. Ring Swap's native-asset route starts with the FewToken mapped from the router's configured WETH, and the router handles the ETH, WETH, and FewToken conversions. For an exact native ETH input, use [swapExactETHForTokens](../../../contracts/v2/reference/smart-contracts/router-02#swapexactethfortokens). That Solidity interface for this function is: ```solidity function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts); ``` Construct the router parameters: ```typescript const slippageTolerance = new Percent('50', '10000') // 50 bips, or 0.50% // Router integers use raw units, not human-readable decimal strings. const amountOutMin = trade.minimumAmountOut(slippageTolerance).quotient.toString() // Ring Swap pools and router paths use the FewToken addresses. const path = [fewWETH.address, fewDAI.address] // userRecipient must come from the user's confirmed transaction intent. const to = utils.getAddress(userRecipient) const deadline = Math.floor(Date.now() / 1000) + 60 * 20 // 20 minutes from the current Unix time const value = trade.inputAmount.quotient.toString() ``` The slippage tolerance calculates the minimum DAI output through [minimumAmountOut](../reference/trade#minimumamountout-since-204). It limits execution relative to the sampled reserves, but it does not prove that those reserves represent a fair external price. Apply a separate independent price check. The path is the ordered list of FewToken addresses used by the Ring Swap pairs. For native ETH input, its first element must be the router's configured `fwWETH`, not the original WETH address. The `to` address receives the DAI and must match the user's confirmed recipient. The deadline is the Unix timestamp after which the transaction reverts. Rebuild rather than submit an expired or stale trade. The `value` is the raw ETH amount supplied as `msg.value`. Before submitting, verify the chain ID and the router's `factory()`, `fewFactory()`, `WETH()`, and `fwWETH()` values against the selected deployment. Confirm every FewToken through FewFactory and every pair through the Ring Swap Factory. Decode the final calldata, then simulate the exact transaction at the latest block. Rebuild the trade if the quote or deadline is stale. --- ## Pair Addresses ## getPair The most obvious way to get the address for a pair is to call [getPair](../../../contracts/v2/reference/smart-contracts/factory#getpair) on the factory. If the pair exists, this function will return its address, else `address(0)` (`0x0000000000000000000000000000000000000000`). - The authoritative onchain check for whether that factory has recorded a pair. - Requires an on-chain lookup. ## CREATE2 Ring Swap pair addresses can also be computed _without any on-chain lookups_ because the factory uses [CREATE2](https://eips.ethereum.org/EIPS/eip-1014). In Ring Swap, this is chain-aware: use the factory for the target network and the corresponding entry in `INIT_CODE_HASH_MAP`. | | | | :--------------------- | :----------------------------------------------------------------------------- | | `address` | The [factory address](../../../contracts/v2/reference/smart-contracts/factory) | | `salt` | `keccak256(abi.encodePacked(token0, token1))` | | `keccak256(init_code)` | `INIT_CODE_HASH_MAP[chainId]` | - `token0` must be strictly less than `token1` by sort order. * Can be computed offline. * Requires the ability to perform `keccak256`. * In Ring Swap, `token0` and `token1` should be the actual pair tokens, which are often `FewToken` addresses rather than the original ERC-20 addresses shown to users. A CREATE2 result is only a predicted address. It does not prove that the pair is deployed, belongs to the intended factory, or contains reviewed assets. Confirm `factory.getPair(token0, token1)`, bytecode, `token0()`, and `token1()` before use. ## Examples ### SDK prediction The SDK helper computes the expected CREATE2 address: ```typescript const DAI = new Token(ChainId.MAINNET, '0x6B175474E89094C44Da98b954EedeAC495271d0F', 18, 'DAI', 'Dai Stablecoin') const fewDAI = getFewTokenFromOriginalToken(DAI, ChainId.MAINNET) const fewWETH = getFewTokenFromOriginalToken(WETH9[ChainId.MAINNET], ChainId.MAINNET) const pairAddress = Pair.getAddress(fewDAI, fewWETH) ``` `Pair.getAddress()` relies on the factory and init-code constants in the installed package. The published v1.0.0 package must not be used for MegaETH. On every chain, treat the result as a candidate and require `factory.getPair(fewDAI.address, fewWETH.address)` to return the same address before reading reserves or moving funds. ### Manual TypeScript Example This example makes use of the [Ring V2 SDK](../reference/getting-started). Manual derivation has the same trust boundary as `Pair.getAddress()`: factory state and deployed pair code remain authoritative. ```typescript const chainId = ChainId.MAINNET const DAI = new Token(chainId, '0x6B175474E89094C44Da98b954EedeAC495271d0F', 18, 'DAI', 'Dai Stablecoin') const fewDAI = getFewTokenFromOriginalToken(DAI, chainId) const fewWETH = getFewTokenFromOriginalToken(WETH9[chainId], chainId) const [token0, token1] = fewDAI.sortsBefore(fewWETH) ? [fewDAI, fewWETH] : [fewWETH, fewDAI] const pair = getCreate2Address( FACTORY_ADDRESS_MAP[chainId], keccak256(['bytes'], [pack(['address', 'address'], [token0.address, token1.address])]), INIT_CODE_HASH_MAP[chainId] ) ``` --- ## Routing API # Ring Routing API The Routing API is a partner endpoint that requests a swap quote from the liquidity sources enabled for that partner. A successful response is a point-in-time quote, not a guarantee of execution or the best price available in every market. The caller must validate and simulate the returned transaction before submitting it. ## Endpoint ```text POST https://gateway.ring.exchange/v1/partner/quote ``` A staging environment is available at `https://gateway.testring.org/v1/partner/quote`. Coordinate with the Ring team before targeting it. ## Authentication Every request requires three headers: | Header | Required | Description | | --- | --- | --- | | `x-api-key` | Yes | Partner API key issued by Ring. Keep it on your backend and out of end-user devices, logs, URLs, and source control. | | `x-partner-id` | Yes | Lowercase partner slug assigned during onboarding. The gateway checks that it belongs to the API key. | | `Content-Type` | Yes | `application/json` | A missing or invalid API key returns `403`. A missing or mismatched partner ID returns `400` with `errorCode: VALIDATION_ERROR`. ## Supported chains The partner endpoint currently accepts Ethereum Mainnet (`chainId: 1`). Do not send another chain ID unless Ring has enabled it for your partner account and confirmed the deployment in writing. ## Quick start The example requests an exact-input quote for 100 USDT. USDT has 6 decimals, so the raw amount is `100000000`. Replace the `swapper` placeholder with the checksummed address of your filler contract. The address receives the output. ```bash curl -X POST "https://gateway.ring.exchange/v1/partner/quote" \ -H "Content-Type: application/json" \ -H "x-api-key: YOUR_API_KEY" \ -H "x-partner-id: YOUR_PARTNER_SLUG" \ -d '{ "tokenIn": "0xdAC17F958D2ee523a2206206994597C13D831ec7", "tokenOut": "0x0000000000000000000000000000000000000000", "amount": "100000000", "tokenInChainId": 1, "tokenOutChainId": 1, "swapper": "0xYOUR_CHECKSUMMED_FILLER_ADDRESS", "type": "EXACT_INPUT", "slippageTolerance": 0.5 }' ``` The placeholder is intentionally not a valid address. Do not replace it with a burn address, router, pool, or shared treasury unless that address is the intended output recipient. ### Required fields | Field | Description | | --- | --- | | `tokenIn` / `tokenOut` | Token addresses. Use `0x0000000000000000000000000000000000000000` for native ETH. Verify ERC-20 addresses independently. | | `amount` | Integer string in the token's smallest unit. For `EXACT_INPUT`, it is the input amount. For `EXACT_OUTPUT`, it is the requested output amount. | | `tokenInChainId` / `tokenOutChainId` | Both must be the chain enabled for the partner request. They are currently `1`. | | `swapper` | Filler contract that submits the transaction and receives the output. The generated calldata is bound to this address. | | `type` | `EXACT_INPUT` or `EXACT_OUTPUT`. | ### Optional fields | Field | Default | Description | | --- | --- | --- | | `protocols` | `['FewV2']` | Classic sources to consider. Accepted values are `V2`, `V3`, `V4`, `FewV2`, `mixed`, and `limit`. The partner endpoint defaults to Ring Swap only; the public quote endpoint has a separate default. Availability still depends on chain and partner configuration. | | `slippageTolerance` | None | Maximum slippage percentage. For example, `0.5` means 0.5%. The service accepts values from 0 through 20, but the caller must choose a limit suitable for the order. | | `autoSlippage` | None | Set to `DEFAULT` only when your integration has been reviewed for automatic slippage. | Do not send both `slippageTolerance` and `autoSlippage`. If your risk policy requires a fixed maximum, send `slippageTolerance` and enforce the same bound when validating the response. To make the Ring Swap restriction explicit, send: ```json { "protocols": ["FewV2"] } ``` The presence of a protocol name in the request does not prove that it produced the returned route. Inspect the response and your service logs before reporting source usage. ## Response A successful request returns HTTP `200`. Values below are illustrative and are not a live market quote: ```json { "requestId": "fe67ff8b-79e7-46c7-84d3-b6816d2c136a", "routing": "CLASSIC", "quote": { "chainId": 1, "tradeType": "EXACT_INPUT", "swapper": "0xYOUR_CHECKSUMMED_FILLER_ADDRESS", "input": { "amount": "100000000", "token": "0xdAC17F958D2ee523a2206206994597C13D831ec7" }, "output": { "amount": "40000000000000000", "token": "0x0000000000000000000000000000000000000000", "recipient": "0xYOUR_CHECKSUMMED_FILLER_ADDRESS" }, "methodParameters": { "to": "0x24e743CcE93235641f2be8Ce7ffC6330903ab96f", "calldata": "0x...", "value": "0" }, "route": [], "slippage": 0.5, "gasFee": "662490501387712", "gasFeeUSD": "1.59", "gasUseEstimate": "63592", "quoteId": "d21e3281-5f14-4a4c-8369-d1a7250fca9f" } } ``` `permitData` may also be present when the integration requires a Permit2 signature. ### Validate before execution Treat every response as untrusted transaction input. Before signing or submitting it: 1. Match `requestId` and `quoteId` to the request you just made. Reject stale or replayed application state. 2. Require `quote.chainId`, `tradeType`, `swapper`, input token, output token, input amount, and recipient to match the user's confirmed intent. 3. Check the raw output or input limit against your own slippage and independent price policy. 4. Require `methodParameters.to` to be in the router allowlist approved for that chain and for the sources enabled in your partner configuration. Do not learn this allowlist from the response itself. 5. Decode the calldata and verify its selector, recipient, tokens, path, amount limits, deadline, Permit2 spender, and native value. Reject unknown commands or callbacks. 6. Ensure `methodParameters.value` is zero for an ERC-20 input and equals the intended native input when ETH is used. 7. Requote near submission time, then simulate the exact `{ from, to, data, value }` at the latest block. Reject a revert, unexpected transfer, unknown approval, or changed recipient. The endpoint does not check the filler's balances, allowances, signing policy, or final transaction state. ### Permit2 responses Do not sign `permitData` until the integration has decoded whether it uses Permit2 `AllowanceTransfer`, `SignatureTransfer`, or a witness transfer, and checked the complete EIP-712 domain and message. At minimum, verify: - chain ID and Permit2 verifying contract - owner and allowed spender - token and raw amount - nonce, expiration, and signature deadline - requested transfer amount and final recipient in the submitted calldata An allowance permit does not by itself authorize a particular recipient or prove an intent to execute a particular quote. Claim recipient or quote binding only when the decoded witness type actually signs those fields. Otherwise, enforce them independently when validating the final calldata. Follow the signed-permit requote or submission flow supplied during partner onboarding. Do not append a signature to calldata or reuse a permit across quotes unless the documented flow explicitly requires it. ### Other response fields | Field | Description | | --- | --- | | `routing` | Routing mode used for this response. | | `quote.input.amount`, `quote.output.amount` | Raw integer amounts in each token's smallest unit. They are not always wei. | | `quote.slippage` | Slippage percentage applied by the quote. Confirm it matches the request and your policy. | | `quote.gasFee`, `quote.gasFeeUSD` | Estimates only. Actual gas cost can differ. | | `quote.route` | Ordered route metadata. Validate each source and pool rather than trusting display labels. | | `quote.quoteId`, `requestId` | Correlation IDs for logs and support. They are not execution authorization. | ## Errors | Status | `errorCode` | Cause | | --- | --- | --- | | `400` | `VALIDATION_ERROR` | Missing or malformed field, partner mismatch, or unsupported chain. | | `403` | Not applicable | Missing or invalid API key. The gateway rejects the request. | | `404` | `NO_QUOTES_AVAILABLE` | No configured source returned a usable quote. This does not prove that no market exists elsewhere. | | `429` | `TOO_MANY_REQUESTS` | Rate limit or quota exceeded. Honor `Retry-After`. | | `500` | Varies | Service or upstream failure. Retry only when the request is idempotent, with bounded exponential backoff. | ## Getting access Request access through an established Ring integration contact whose identity you have independently verified. Provide the project name, website or app URL, intended use, estimated traffic, and filler or executor contract address. Ring will provide the API key, partner ID, enabled sources, approved router allowlist, and any partner-specific execution steps through that verified onboarding channel. Do not send credentials, signatures, or other secrets through public issues, chat rooms, or an unverified email address. --- ## Uniswap v4 Integration This section covers FewToken and Few hooks used with Uniswap v4 contracts. ## When to use this section Use it when your workflow directly involves: - Uniswap v4 PoolManager or PositionManager - a Few hook - Uniswap v4 pool creation, swaps, or liquidity management - reading Uniswap v4 pool state For Ring Swap pairs, the Ring Swap Router, or normal FewToken routes, start with [Ring Swap](/contracts/v2/overview). ## Product boundary | Surface | Owner of the AMM design | Role in Ring | | --- | --- | --- | | Ring Swap | Ring | Native FewToken AMM and routing system | | Uniswap v4 | Uniswap | External pool and hook infrastructure used by supported Ring integrations | | Few hooks and periphery | Ring integration code | Connect FewToken workflows to Uniswap v4 | The pages in this section retain Uniswap v4 terminology because they document that external contract environment. They should not be read as a separate native Ring v4 protocol. ## Start by task | Task | Page | | --- | --- | | Find v4 contract addresses | [Deployments](./deployments) | | Create a pool | [Create a Pool](./quickstart/create-pool) | | Execute a swap | [Swap](./quickstart/swap) | | Add or manage liquidity | [Manage Liquidity](./quickstart/manage-liquidity/setup-liquidity) | | Build a hook | [Your First Hook](./guides/hooks/your-first-hook) | | Understand Few hook contracts | [Few Hook Contracts](./guides/hooks/few-hook-contracts) | | Prepare pool data for an aggregator | [FewToken Liquidity and Aggregator Integration](./guides/fewtoken-liquidity-aggregation) | Source: [Ring v4 integration periphery](https://github.com/RingProtocol/v4-periphery). For generic PoolManager, PositionManager, and hook mechanics, use the [official Uniswap v4 documentation](https://docs.uniswap.org/contracts/v4/overview). Ring keeps its main navigation focused on FewToken and Few hook integration pages.