# Onramper - documentation
## Overview
The initial goal for the MVP was to intergrate with 1 Dex, Uniswap, for the end goal of offering more tokens that the current gateways can offer and we'd do this by leveraging Uniswap's Liquidity pool style exchange to achieve this.
Imagine a user wants to buy an obscure ERC20 token called "APE". None of the current gateways offer this token for sale. So we turn to Uniswap. The flow now looks like this.
1) user buys ETH. (the L1 transaction)
2) User swaps ET for APE via the /swap route of the widget.
We will refer to these transctions as the "L1" and "L2" steps respectively.
As explained in the backend documentation there is some work to be done to store the rates for the L2 tokens relative to ETH. the "gateway" name displayed for the L2 tokens is displayed in this format:
*Gateway_Exchange* for example *Moonpay_Uniswap*
Folloowing our example, if the user selects "APE" token from gateway "Moonpay_Uniswap", the user then buys ETH from Moonpay. the widget checks if the gateway string contains the name of an exchange we are supporting.
```typescript=
// src/utils.ts
export const knownDexes = ["LIFI", "UNISWAP"];
export const getDexFromGateway = (
gateway: string | undefined
): string | undefined => {
if (!gateway) return undefined;
return gateway.toUpperCase().split("_").at(-1);
};
// Moonpay_Uniswap => true
export const isL2Gateway = (gateway: string | undefined): boolean => {
if (gateway === undefined) return false;
const dex = getDexFromGateway(gateway);
if (dex === undefined) return false;
return knownDexes.includes(dex);
};
```
If the gateway **is* an L2 gateway, they get redirected to the /swap route of the app.
```typescript=
// src/index.tsx
<Route
path="/swap/:txId"
element={
<L2Provider>
<TransactionContextProvider>
<NotificationProvider>
<div style={{ flexGrow: 1, display: "flex" }}>
<NavContainer home={<PaymentProgressView />} />
</div>
</NotificationProvider>
</TransactionContextProvider>
</L2Provider>
}
/>
```
We have split the widget app into several routes using react router.
the root route directs to the usual `<BuyBodyCrypto />` component. And the `/swap/:txId` route directs to the start of the L2 flow. This is also the link structure that should be sent to the user via email to notify them of their soccessfl L2 tranasction. If they click this link they can start the L2 flow.
The PaymentProgressView component takes the txId (generated in step1) and pings the backend to see if the L2 transction has succeeded or not, if it has then the user may proceed to the `<SwapOverviewView />` step.
This is where the swap happens and there are many screens to deal with editing swap details, storing custom recevier addresses (stored in DDB) etc.
It is important to note to the developer that all the details of the swap transaction are stored in the `TransactionContext` state machine. you can find the reducer and actions in the `src/TransactionContext` folder.
It is also important to note what is needed to interact with Uniswap.
1) we need a way to get a quote.
2) Secondly we need some saort of sdk to help us with uniswap
3) Lastly we need to connect a user's wallet to the app.
For point **no. 1**, we deployed a [uniswap router api](https://github.com/onramper/routing-api) to fetch quote data as well as a resulting TrbnsactionRequest object for the particular swap.
For **no. 2** we created a [layer2](https://github.com/onramper/layer2) package with all sort of utility functions, some hooks and some types to help our app interact with uniswap in a type safe way.
For **no. 3** We used [ethers.j](https://docs.ethers.io/v5/) (low-level blockchain js library) together with [useDapp](https://usedapp.io/) (hooks library & state management for blockchain interactions) to interact with the user's wallet and help them perform the swap.
### Adding future dexes.
The Layer2 package is organised thusly:
```shell=
src
|-- core
| |-- constants
| |-- index.ts
| |-- models
| |-- quote
| |-- tokens
| `-- utils
|-- index.tsx
|-- dex1
| |-- constants
| |-- index.ts
| `-- quote.ts
|-- dex2
| |-- constants
| |-- index.ts
| `-- quote.ts
`-- dex3
|-- constants
|-- index.ts
`-- quote.ts
```
The idea is to follow Onramper's gateway "adapter" pattern. For example the main "getQuote" function lives inside the core package. If the Dex is Lifi use Lifi's quote. If the Dex is Uniswap, use uniswap's quote etc. This becomes extensible in the same way that the L1 gateways are.
## Moving from Uniswap to LiFi
Moving fron Uniswap to LiFi actually removed a lot of complexity from the current implementation.
Lifi comes with it's own SDK which, making our layer2 package semi redundant (although we still use some types and utility functions form the core package).
We no longer need the Routing API, as LiFi exposes a public API for us to interact with. We also do not really need to run cron jobs to store rates for L2 tokens as we can just do this on the fly as the user selects their L2 tokens from the dropdown (although this is an inplementaion decision to be made at some point).
## Where are we now
Currently there is a folder here => **widget/package/src/web3**
Inside there is a folder with hooks for web3 specific jobs. Notably there is also a file called **lifi.ts**. It is here that we initialise the SDK's class instance to help us interact with LiFi's quote API.
Here is LiFi full [API reference](https://apidocs.li.fi/reference)
Here is the [SDK documentation](https://docs.li.fi/products/)
To fetch quotes we use LiFi's apoi instead of the uniswap router.
To interact with the API we use LiFi's sdk (together with some items from our layer2's core package)
### Packages added to Widget/package ofr L2 integration
- [ethers.j](https://docs.ethers.io/v5/) (low-level blockchain js library)
- [useDapp](https://usedapp.io/) (hooks library & state management for blockchain interactions)
- [@lifinance/sdk](sdk for interation with LiFi's powerful API)(https://www.npmjs.com/package/@lifinance/sdk)
## Notes on Testing
Central to this application is this interface:
```typescript=
interface TokenInfo {
readonly chainId: number;
readonly address: string;
readonly name: string;
readonly decimals: number;
readonly symbol: string;
readonly logoURI?: string;
}
```
This is the industry standard for crypto tokens in tokenlists. It is used by LiFi as well as Uniswap. If you want to use testnet tokens for the swap, then the chainId for inupt and output tokens must be 3,4, or 5. (We reccommend 3, "Ropsten", because the Moonpay sandbox sends Ropsten ETH during testing.)
### Testnet testing
If we want to interact with LiFi's API (whether getting a quote or fetching chainData etc.) we can either use the mainnet or production endpoint "https://li.quest/v1/", or we can use their testing endpoint whihc returns data only relevant to testnets "https://staging.li.quest/v1/". Onramper should find a reliable way of setting whether we want to use the test environment or production.
Currently there is a check to see if ?prod=true in the url
```typescript=
// if ?prod=true
const isProd = (): boolean => {
const url = new URL(window.location.href);
const prodValue = url.searchParams.get("prod");
if (prodValue) return true;
return false;
};
const lifiUrl = isProd()
? "https://li.quest/v1/"
: "https://staging.li.quest/v1/";
const lifiConfig: ConfigUpdate = {
apiUrl: lifiUrl,
};
export const lifi = new LIFI(lifiConfig);
```
## Mainnet Testing
Sample [url](https://volcano.onramper.dev/swap/lvIyWiZ9lA29VUDqgYIBvw--?prod=true) with known txId in our prod Database (adding prod flag so we use our prod api key as well as LiFi’s prod API)