# `allow_unsafe`: Preventing & Handling Bad Execution
## Introduction
**The`allow_unsafe` parameter in the requests to `/route` & `/msgs_direct` endpoints is designed to protect users from bad trade execution.**
This parameter indicates whether you want to allow the API to return and execute a route even when our routing engine forecasts low or unknown execution quality:
* `allow_unsafe=false` (default): The API will throw an error instead of returning a route when the routing engine forecasts bad execution quality (i.e. > 10% `price_impact` or difference between USD value in and out) or when execution quality can't be determined.
* `allow_unsafe=true`: The API will return a route for a trade even when the routing engine forecasts bad execution quality (i.e. > 10% `price_impact` or difference between USD value in and out) or when execution quality can't be determined. In these cases, the API appends a `warning` to the response in a `warning` field
**Make sure you understand execution/quote quality measurements first**
Before reading this doc, you should read our documentation on quote quality: [ Understanding Quote Quality Metrics](./understanding-quote-quality-metrics). This provides basic background information about the different ways the Skip Go API measures whether a route will likely give a user a bad execution price, namely the difference between the USD value of the input and the output & on-chain price impact.
## `allow_unsafe=false` Behavior
When `allow_unsafe=false`, the endpoint throws an error when execution quality is poor (as measured by price impact or estimated USD value lost) or when execution quality can't be determined (i.e. neither of these measurements are available).
In particular, if `allow_unsafe=false`, `/route` and `/msgs_direct` return errors when:
* `price_impact > .10`(the swap will move the on-chain price by more than 10%)
* `(usd_amount_in-usd_amount_out)/usd_amount_in)>.10` (greater than 10% of the value of the input is lost)
* Neither of the above metrics can be computed
Below, we provide examples of the responses in each these cases.
The price impact is greater than 10% (`BAD_PRICE_ERROR`):
*
```{
"code": 3,
"message": "swap execution price in route deviates too far from market price. expected price impact: 98.6915%",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "BAD_PRICE_ERROR",
"domain": "skip.build",
"metadata": {}
}
]
}
```
The user loses more than 10% of their USD value (`BAD_PRICE_ERROR`):
*
```{
"code": 3,
"message": "difference in usd value of route input and output is too large. input usd value: 1000 output usd value: 600",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "BAD_PRICE_ERROR",
"domain": "skip.build",
"metadata": {}
}
]
}
```
The `price_impact` and the estimated USD value difference cannot be calculated (`LOW_INFO_ERROR`)
*
```JSON JSON
{
"code": 3,
"message": "unable to determine route safety",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "LOW_INFO_ERROR",
"domain": "skip.build",
"metadata": {}
}
]
}
```
## `allow_unsafe=true` Behavior
When `allow_unsafe=true`, the endpoints will still return routes even when the routing engine forecasts will have unknown or poor execution quality (measured by price\_impact or estimated USD lost), but they will have a `warning` field appended to them.
The `warning` field is populated exactly when the endpoints would return an error if `allow_unsafe` were `false`, namely:
* `price_impact > .10`(the swap will move the on-chain price by more than 10%)
* `(usd_amount_in-usd_amount_out)/usd_amount_in)>.10` (greater than 10% of the value of the input is lost)
* Neither of the above metrics can be computed
Below, we provide examples of the responses in each these cases.
The price impact is greater than 10% (`BAD_PRICE_WARNING`):
*
```JSON JSON
"warning": {
"type": "BAD_PRICE_WARNING",
"message": "swap execution price in route deviates too far from market price. expected price impact: 98.6826%"
}
```
More than 10% of the USD value of the input is lost in the swap (`BAD_PRICE_WARNING`):
*
```"warning": {
"type": "BAD_PRICE_WARNING",
"message": "difference in usd value of route input and output is too large. input usd value: 1000 output usd value: 600"
}
```
The `price_impact` and the estimated USD value difference cannot be calculated (`LOW_INFO_ERROR`)
*
```
"warning": {
"type": "LOW_INFO_WARNING",
"message": "unable to determine route safety"
}
```
## Best Practices for Protecting Users
**Above all else, we recommend setting `allow_unsafe=false`**
In addition, we recommend reading our documentation around [safe API integrations](./safe-swapping-how-to-protect-users-from-harming-themselves) to learn about UX/UI practices that can further help prevent users from performing trades they'll immediately regret.
**Have questions or feedback? Help us get better!**
Join [our Discord](https://skip.build/discord) and select the "Skip Go Developer" role to share your questions and feedback.
# SAFE Swapping: How to Protect Users from Bad Trades
**Summary**
**This doc covers several UI/UX principles we recommend Skip Go API integrators implement to protect users from harming themselves by swapping at bad execution prices. Collectively, we refer to these principles as S.A.F.E.**
The document introduces the S.A.F.E framework and provides detailed guidance for how you can use the information provided in the Skip Go API to implement the framework & give your users a worry-free swapping experience.
### Keeping Users Safe on your Application
Many users are unfamiliar with the technology behind cross-chain swaps and transfers. As a result they will take actions that aren't in their best interests:
1. Execute swaps & transfers they don't understand at unfavorable prices using money they cannot afford to lose (e.g. Spending \$1000 on a new, illiquid meme coin within 2 hours of launch)
2. Accuse **you** (& Skip) of responsibility for their losses (even if your software & ours worked as expected), demand a refund, and publicly vilify & troll you if you do not give one.
To protect both you and the user, we've developed a framework called **S.A.F.E** to help you remember and organize the UX principles that can keep your users safe:
1. **S**hare all available information about expected execution price
2. **A**lert when info indicates an action might be harmful
3. **F**ail transactions that trigger your alerts (i.e. transactions that seem likely to harm users)
4. **E**nforce additional approval stages for users who want to create these transactions anyhow
### S.hare Info
You should share as much information about the estimated swap with your users as possible. Fortunately, the `/fungible/route` and `/fungible/msgs_direct` endpoints return a ton of useful information.
In addition to showing estimated amount in and out (the obvious ones), we recommend showing:
* **Estimated USD value of the amount in** (`response.usd_amount_in`)
* **Estimated USD value of the amount out** (`response.usd_amount_out`)
* **Price Impact** (`response.swap_price_impact_percent`) -- This measures how much the user's expected execution price differs from the current on-chain spot price at time of execution. A high price impact means the user's swap size is large relative to the available on chain liquidity that they're swapping against, which makes a bad price very likely.
* **Swapping Venue** (Available in the `swap_venue` field of the `swap` operation in `response.operations`) - This tells the user what DEX they're actually performing the underlying swap on, which helps avoid confusion about prices. This can be useful information in the event the API returns an usual route and routes the user to a DEX they're unfamiliar with / don't want to use or to a DEX where there's not much liquidity of the token they're swapping (e.g. SEI liquidity on Osmosis is sparse at the time of this writing)
* **Bridge Fee Amounts** (Available in the `transfer` and `axelar_transfer` entries in `response.operations` under `fee_asset` and `fee_amount`) -- These represent the fees that bridges take from the user along the route, denominated in the token(s) they're taking. It's important to show because sometimes bridges take fees unexpectedly (e.g. Noble used to take 0.10% fee on IBC transfers), and sometimes they take large fees (e.g. During periods of high gas prices, Axelar fees can be as high as \$200)
* **USD value of bridge fee amounts** (Available in the `transfer` and `axelar_transfer` entries in `response.operations` under `usd_fee_amount`) -- This gives the user a sense of the actual cost of their fee amounts. In cases of more complex swaps and transfers, the user might have a hard time making sense of the underlying fee tokens because the fees are being charged at an intermediate point in the route
The quote shown to the users should **always** match the transaction that they end up signing. Once you have called `/route` and displayed the quote to the user, a call to `/msgs` is the only way to generate the correct message. (DO NOT call `/msgs_direct` after calling `/route` since this will regenerate the quote)
Alternatively you can call `/msgs_direct` to both generate the quote information and the transaction that needs to be signed with 1 request. Remember that these endpoints are not deterministic and calling either again will generate a different output and your user will not execute the transaction they think they are executing.
### A.lert users to bad prices
We recommend alerting users in the following three scenarios at least:
1. **High Price Impact** (`swap_price_impact > PRICE_IMPACT_THRESHOLD`) : This indicates the user's swap is executing at a considerably worse price than the on-chain spot price -- meaning they're probably getting a worse price than they think they should. It also indicates the size of their trade is large relative to the available on chain liquidity. We recommend using`PRICE_IMPACT_THRESHOLD = 2.5 `in your calculations
2. **High difference in relative USD value in and out** (`(usd_amount_in - usd_amount_out)/usd_amount_in)*100 > USD_REL_VALUE_THRESHOLD` ): This estimates the underlying value the user will lose instantly as a result of swapping, represented as a percentage of the value of their input. A high value for this figure indicates the user is instantly losing a large percentage of the value of their starting tokens. For example, a value of 50 indicates the user loses 50% of the estimated value of their input. We recommend using `USD_REL_VALUE_THRESHOLD=2.5`
3. **High fees** ( `usd_fee_amount / usd_amount_in > FEE_THRESHOLD`) : This indicates that the value of fees charged by bridges used in the route amount to a large percentage of the underlying amount being transferred. If this value is high, user might want to wait until bridging more funds to execute (since bridge fees rarely scale with volume). We recommend setting `FEE_THRESHOLD=.25`
Loud visual emphasis of the values that exceed safe tolerances is the most effective form of alerting. This includes:
* Bolding unusually high/low quote numbers -- or otherwise making them larger than surrounding text/numbers
* Automatically opening drop downs / detail panes that are usually closed by default to display the alert field
* Highlighting the offending quote number in red, yellow, or some other loud color indicating danger and/or greying out other numbers
For example, when a swap exceeds our `PRICE_IMPACT_THRESHOLD` on [go.skip.build](https://go.skip.build), we auto-open the drop-down that normally hides price impact and highlight the whole field in red.

### F.ail Transactions when they're likely to cause user harm
We recommend preventing transactions that may significantly harm the user altogether -- even if your user seems to want to complete the transaction.
We recommend failing/preventing user transactions in the following scenarios:
1. **Greater than 10% difference in relative USD value in and out** `(usd_amount_in - usd_amount_out)/usd_amount_in)*100 > 10`
2. **Greater than 10% price impact** (`swap_price_impact > 10`)
You could can decide how you want to signal this failure to user, e.g. no route found, some form of low liquidity message, or something else entirely.
Preventing transactions altogether that violate your safety thresholds is the strongest form of user safety.
### E.nforce explicit, additional approval
If you do not want to fail transactions that exceed safety thresholds outright, one viable alternative is to require additional stages of user approval before letting the user sign the transaction.
Importantly, this is different and more disruptive than simply warning the user about some aspect of the quote looking unfavorable. This means putting additional clicks between the user and the swap they want to perform, and having them explicitly agree to performing a swap your UI indicates will have a bad price.
For example, this is go.skip.build's warning screen:

* It's very clear that our expectation is that the swap will harm the user with the "Bad Trade Warning" across the top
* The page explicitly reminds the user what the problem is -- foregrounding the predicted price impact and forcing them to acknowledge it again
* The "happy path" or "default" path is to go back -- not to finish the swap (Notice that the "Go Back" button is highlighted)
We recommend requiring additional steps of user approval in the following cases:
1. **Greater than 5% difference in relative USD value in and out** `(usd_amount_in - usd_amount_out)/usd_amount_in)*100 > 5`
2. **Greater than 5% price impact** (`swap_price_impact > 5`)
3. **Price impact AND relative-USD-value-difference cannot be calculated** (i.e. `swap_price_impact`, `usd_amount_out`, and/or `usd_amount_in` are missing)
#### Choosing the right level of protection: warnings, additional approvals, and outright failures
It's important to think about this tradeoff because protecting users often directly trades off against making a cleaner, simpler, and more powerful user experiences. For example, excessive warnings might get annoying to users who know they're trading illiquid shitcoins, and additional steps of approval might frustrate pro traders who care deeply about speed
For any safety metric you might track to determine whether a transaction could harm a user, consider 4 tiers of safety you can implement. From least safe and least disruptive to most safe and most disruptive:
1. **None**: Just let it rip. Don't give the user any heads up. Don't do anything to slow them down or prevent them from trading.
2. **Alert**: Use some visual cue to indicate to the user that they should be wary about swap
3. **Enforce additional approval**: Require additional clicks to actually execute the swap and foreground the warning -- so the user needs to approve it explicitly.
4. **Fail**: Just block / fail / prevent transactions that exceed your safety tolerance bounds outright
Here are some suggestions for navigating this design space:
1. **Set lower trigger thresholds for weaker forms of security and more conservative thresholds for stronger forms of security** (e.g. You could alert users about high price impact at 2.5%, require an additional stage of approval at 10%, and fail the transaction outright at 25%) This approach is nice because it gives users who may be very conservative some indication that they may face some danger without getting in their way too much, while still hard-stopping more inexcusable failures that are probably never acceptable to any trader
2. **Use stronger forms of security when safety tolerances are exceeded for higher value transactions** (e.g. You could use warnings when price impact is greater than 10% for transactions where the amount in is $0-100, additional approvals when amount in is $1,000 - 10,000, and block transactions above \$10k outright if price impact is greater than 10%.
**Have questions or feedback? Help us get better!**
Join [our Discord](https://skip.build/discord) and select the "Skip Go Developer" role to share your questions and feedback.
# Smart Swap
This page introduces the Smart Swap functionality provided by the Skip Go API to improve swap speed, price, and customization.
## Introduction
Smart Swap refers to a feature set that improves swap speed, price, and control.
It currently allows for:
* [External routers](#feature-use-external-routers-to-improve-price-execution) (e.g. Hallswap and Osmosis SQS) for better price execution
* [Route splitting](#feature-route-splitting) for better price execution
* [EVM swaps](#feature-evm-swaps)
If you're using the deprecated `@skip-router` library, you must use version v4.0.0+ to enable Smart Swap.
We strongly recommend using the `@skip-go/client` [TypeScript package](https://www.npmjs.com/package/@skip-go/client), which is actively maintained.
The rest of this document will show you how to use Smart Swap with the `@skip-go/client` library. The only changes you'll notice between this context and the REST API are naming conventions.
# Smart Swap Features
Set your Smart Swap settings in your `skipClient` function call or REST API request body.
## Feature: Use External Routers to Improve Price Execution
The Skip Go API considers multiple internal and external routers to find the route with the best price execution.
Currently supported external swap routers:
1. Skip Go API's in-house Router
2. Hallswap's Dex Aggregator
3. Osmosis's Sidecar Query Service (SQS) (Used in the Osmosis frontend)
### Usage
Pass an empty `smartSwapOptions` object into your route request.
```ts TypeScript (Client)
const route = await skipClient.route({
smartSwapOptions: {}, // You're not required to activate a particular flag for this feature
sourceAssetDenom: "uusdc",
sourceAssetChainID: "noble-1",
destAssetDenom: "utia",
destAssetChainID: "celestia",
amountIn: "1000000", // 1 uusdc
cumulativeAffiliateFeeBPS: "0"
}
```
```JSON JSON (REST API)
// POST /v2/fungible/route
{
"amount_in": "1000000",
"source_asset_denom": "uusdc",
"source_asset_chain_id": "noble-1",
"dest_asset_denom": "utia",
"dest_asset_chain_id": "celestia",
"cumulative_affiliate_fee_bps": "0",
"allow_multi_tx": true,
"smart_swap_options": {}
}
```
That's it! Skip Go API will now consider supported external routers and return the best available option.
## Feature: Route Splitting
Route splitting involves dividing a user's trade into multiple parts and swapping them through different pools. This reduces price impact and can increase the user's output compared to using a single route. It works especially well when one or both tokens being swapped are commonly paired with other assets on a DEX (e.g., OSMO on Osmosis).
### Usage
Pass the `splitRoutes` flag in the `smartSwapOptions` object.
```ts TypeScript (Client)
const route = await skipClient.route({
smartSwapOptions: {
splitRoutes: true
}, // smart swap object
sourceAssetDenom: "uusdc",
sourceAssetChainID: "noble-1",
destAssetDenom: "utia",
destAssetChainID: "celestia",
amountIn: "1000000", // 1 uusdc
cumulativeAffiliateFeeBPS: "0"
}
```
```JSON JSON (REST API)
// POST /v2/fungible/route
{
"amount_in": "1000000",
"source_asset_denom": "uusdc",
"source_asset_chain_id": "noble-1",
"dest_asset_denom": "utia",
"dest_asset_chain_id": "celestia",
"cumulative_affiliate_fee_bps": "0",
"allow_multi_tx": true,
"smart_swap_options": {
"split_routes": true
}
}
```
### Response Changes when using Split Routes
We've added a new `swapType` called `SmartSwapExactCoinIn` that's returned in the `routeResponse` and `msgsDirectResponse` when the provided route is a split route. This new `swapType` has fields that allow for multiple routes, across multiple swap venues.
```ts
export type SmartSwapExactCoinIn = {
swapVenue: SwapVenue;
swapRoutes: SwapRoute[];
};
export type SwapRoute = {
swapAmountIn: string;
denomIn: string;
swapOperations: SwapOperation[];
};
```
## Feature: EVM Swaps
Smart Swap supports bidirectional EVM swaps: go from any asset on an EVM chain to any asset on a Cosmos chain and back again. With EVM swaps, users can onboard to your IBC connected chain in 1 transaction from a broad range of EVM assets, including the memecoins retail loves to hold!
Currently, the API supports swapping on official Uniswap V3 deployments on the following chains:
| Network | Chain ID |
| ------------ | -------- |
| Ethereum | 1 |
| Polygon | 137 |
| Optimism | 10 |
| Arbitrum One | 42161 |
| Base | 8453 |
| BNB Chain | 56 |
| Avalanche | 43114 |
| Blast | 81457 |
| Celo | 42220 |
### Usage
Set the `evmSwaps` flag to true in the `smartSwapOptions` object. If using the deprecated `@skip-router` library, you must be on v5.1.0+ (we strongly recommend migrating to `@skip-go/client` as soon as possible).
```ts TypeScript (Client)
const route = await skipClient.route({
sourceAssetDenom: "arbitrum-native",
sourceAssetChainID: "42161",
destAssetDenom: "ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5",
destAssetChainID: "dydx-mainnet-1",
amountIn: "10000000000000000000",
cumulativeAffiliateFeeBPS: "0",
smartRelay: true,
smartSwapOptions: {
evmSwaps: true
},
}
```
```JSON JSON (REST API)
{ // POST /v2/fungible/route
"amount_in": "10000000000000000000",
"source_asset_denom": "arbitrum-native",
"source_asset_chain_id": "42161",
"dest_asset_denom": "ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5",
"dest_asset_chain_id": "dydx-mainnet-1",
"cumulative_affiliate_fee_bps": "0",
"allow_multi_tx": true,
"smart_relay": true,
"smart_swap_options": {
"evm_swaps": true
},
}
```
### How do EVM Swaps Change the `route` Response?
When an EVM swap occurs in a route, a new operation of type `evm_swap` is returned in the array of `operations` in the `v2/route` and `v2/msgs_direct` response.
If your API use follows the `v2/route` then `v2/msgs` call pattern, this new operation type must be passed to the `v2/msgs` endpoint, so make sure you use the latest [Skip Go Client version](https://www.npmjs.com/package/@skip-go/client) and decode the operation properly.
The `evm_swap` operation type is as follows:
```ts TypeScript
export type EvmSwap = {
inputToken: string;
amountIn: string;
swapCalldata: string;
amountOut: string;
fromChainID: string;
denomIn: string;
denomOut: string;
swapVenues: SwapVenue[];
}
```
```JSON JSON
{
"evm_swap": {
"input_token": "ox", // string (token contract address if an ERC20 token, blank if native)
"amount_in": "100", // string
"swap_calldata": "0x", // string
"amount_out": "123", // string
"from_chain_id": "1", // string
"denom_in": "0x", // string
"denom_out": "0x", // string
"swap_venues": [], // []swap_venue
}
}
```
### How does this Change the `/msgs` and `/status` Response?
Nothing new in particular! The `msg_type` used for EVM swaps is the same `evm_tx` type used for all of our EVM transactions. Similarly, there is no new `transfer_event` type; the swap is atomic with the bridging action (Axelar or CCTP), so the same types are used (`axelar_transfer_info` and `cctp_transfer_info` respectively).
**Have questions or feedback? Help us get better!**
Join [our Discord](https://skip.build/discord) and select the "Skip Go Developer" role to share your questions and feedback.
# Understanding Quote Quality Metrics
This doc covers the various ways route quote quality is measured -- slippage, USD estimates of the amount in and out, and price impact
**Video Summary**
[Here's a video](https://www.loom.com/share/5293719872714557b03db41fb5ca590e) that summarizes the content below.
### Different ways to measure quote quality
* `slippage`: This is the maximum allowable difference between what Skip estimates the price of the swap will execute at and the worst price it can execute at. If the price of the swap turns out to be worse than the slippage tolerance allows, the swap will revert entirely. Slippage does not account for the impact of the user's swap itself because this is incorporated in the estimate. You can still get a "bad price" with *low* slippage if you make a big swap against a low liquidity pool because your swap itself will move the price. As a result, you should think of slippage as tolerance for difference between actual price and quoted price, not a measure of whether the quoted price is "good".
* `usd_estimate_in` and `usd_estimate_out`: These are estimates of the dollar-value of the amount in and amount out. These use coingecko prices that can be a maximum of 5 minutes stale. These values aren't always available because not all tokens are listed on Coingecko (e.g. some meme coins or new coins won't have feeds). This is really useful for providing a sanity check on whether a price is "good" and flagging to users when the difference between estimated input and output dollar values exceeds some threshold as a percentage of the input amount. (For example, we recommend you flag the user when their input dollar value is $100 and their output is $50. This indicates they're receiving a bad price for some reason.)
* `price_impact`: This measures how much the user's expected execution price differs from the current on-chain spot price at time of execution. This is available whenever the underlying DEX makes it feasible to calculate on-chain spot price. This is especially useful when `usd_estimate_in` or `usd_estimate_out` isn't available. A high price impact means the user's swap size is large relative to the available on chain liquidity that they're swapping against, and they're moving the price significantly a lot. Like with USD estimate, we recommend warning users when this exceeds some threshold (e.g. 10%).
### More on `slippage` vs `price_impact`
Some people have asked why are both slippage and price\_impact necessary. The reason is that they are trying to capture fundamentally different concepts:
* slippage = tolerance to the world / liquidity changing between when the API gives you a quote and when the transaction gets executed (0 slippage = "I want to get exactly the amount out that Skip estimates"). Of course, this could still be a bad price if there's high price\_impact, or if the difference between `usd_amount_in` and `usd_amount_out` is large. **Slippage is better understood as a tolerance to volatility, rather than an estimate of execution quality.**
* price impact = A measure of how much you're going to move the on-chain price with your trade. Some folks use the word "slippage" to describe price impact. This is intended to capture your tolerance to low liquidity and bad pricing.
Fundamentally, you can execute a trade that has low price impact but high slippage if you want to execute a volatile trade against a lot of liquidity
### Protecting users with SAFE interfaces
If you're wondering how you should use these values to help protect your users from poor execution prices, we have a whole guide written about how to build a safe swapping interface: [SAFE Swapping: How to Protect Users from Bad Trades](./safe-swapping-how-to-protect-users-from-harming-themselves)! Check it out!
**Have questions or feedback? Help us get better!**
Join [our Discord](https://skip.build/discord) and select the "Skip Go Developer" role to share your questions and feedback.
# CW20 Tokens & Their Limitations
Information about performing CW20 swaps
This page covers the basics of CW20s and the limitations around performing cross-chain actions with CW20 tokens -- compared to tokenfactory and "native" Cosmos assets (aka Bank Module assets).
### CW20 Token Denom Formatting In API Requests
To use CW20 tokens in the Skip Go API, specify the denom as "cw20:" + the token contract address.
Example denom for Astro on Terra2: `cw20:terra1nsuqsk6kh58ulczatwev87ttq2z6r3pusulg9r24mfj2fvtzd4uq3exn26`
### Background
#### What is a CW20 token?
[CW20](https://github.com/CosmWasm/cw-plus/blob/main/packages/cw20/README.md) is the fungible token spec for the CosmWasm (i.e. CW) VM. CosmWasm is the most popular smart contract VM among CosmosSDK blockchains today. At a high-level, CW20 is very similar to ERC20 (the popular EVM fungible token standard).
Contracts that comply with the standard implement the following functionalities:
* Transferring tokens from one account to another
* Sending tokens to a contract along with a message (similar to `callContractWithToken`)
* Tracking balances
* Delegating balance spending to other accounts and contracts
ASTRO (Astroport's governance token) is one CW20 token issued on Terra2.
#### How do CW20 tokens interact with IBC?
[CW20-ICS20](https://github.com/CosmWasm/cw-plus/tree/v0.6.0-beta1/contracts/cw20-ics20) converter contracts make a CW20 token compatible with the ICS20 token transfer standard, so they can be sent to other chains over normal ICS20 transfer channels. When they arrive on the destination chain, they're indistinguishable from bank module and tokenfactory tokens.
These converter contracts are the source of much difficulty when attempting to perform cross-chain actions with CW20s:
* Different converter contracts implement different versions of the ICS20 standard (e.g. Some don't support memos, which are required for post-transfer contract calls and multi-hop transfers)
* On transfer failure, converter contracts just return assets to sender. That means if one of our contracts attempts to send tokens on your behalf unsuccessfully, it will receive the tokens. We can't atomically send them to you.
#### How do CW20 tokens compare to "native" (aka bank module) tokens?
"Native" tokens are tokens where minting, burning, balances, and transfer functionality are managed by the [bank module](https://docs.cosmos.network/v0.46/modules/bank/), instead of by contracts. Unlike CW20s, native tokens are directly compatible with ICS20 and IBC modules. One can send a native token to another chain over a transfer channel just using a `MsgTransfer` -- no conversion contracts or anything of the sort required.
The downside of native tokens is that they're permissioned and deeply ingrained into the chain's state machine. As a result, issuing a new native token requires a chain upgrade. Issuing a CW20 on the other hand, only requires deploying a new contract (just a transaction).
#### How do CW20 tokens compare to "tokenfactory" tokens?
Tokenfactory tokens are created with the [tokenfactory](https://docs.osmosis.zone/osmosis-core/modules/tokenfactory/) module. They're designed to have the best of both worlds of CW20 and native tokens:
* Like CW20s, they're permissionless and users can create new ones just by submitting transactions -- no need to modify the chain's state machine
* Like native tokens, they're directly compatible with IBC out-of-the-box, and the bank module manages their balances + transferring functionality.
This combination of traits leads many to see tokenfactory as a strict improvement on CW20 that devs should prefer in the vast majority of cases. We strongly agree with this conclusion.
Unlike `CW20s` , tokenfactory tokens have no limitations in the cross-chain functionality Skip Go API can offer for them.
### What limitations do CW20 tokens have within the Skip Go API?
At a high-level, basically any multi-chain action--in which the token is on the chain where it was issued for one stage of the action--requires multiple transactions.
In particular, this means you cannot perform the following actions in 1 transaction:
* IBC transfer after purchasing a cw20 asset

* Call a contract on a remote chain after purchasing a cw20 asset (e.g. since this requires an IBC transfer under the hood)

* IBC transfer from a remote chain to the CW20's origin chain then perform a swap or any other post-route action on that chain

In principle, you can use the Skip Go API to construct any of these action sequences across multiple transactions, but it will be more challenging for you and your end users.
**Have questions or feedback? Help us get better!**
Join [our Discord](https://skip.build/discord) and select the "Skip Go Developer" role to share your questions and feedback.
# EVM Transactions
This doc covers how to interact with the EvmTx type returned by the Skip Go API
## Intro
* When a user needs to transfer or swap from an EVM chain (e.g. Ethereum mainnet, Arbitrum, Optimism, etc...), the Skip Go API will return an `EvmTx` type for the developer to pass to the user for signing
* Unlike CosmosSDK transactions, EVM transactions do not have a notion of messages, so this object doesn't correspond 1-to-1 to a "message", which might be a more familiar notion to Cosmos developers
* This doc is intended for CosmosSDK developers who aren't already familiar with the concepts of transaction construction in the EVM and need to use `EvmTx` to help their users move from/to EVM chains.
## `EvmTx` Data Structure
The EvmTx has 4 fields that the developer needs to understand:
* `to`: The address of the smart contract or externally owned account (EOA) with which this transaction interacts, as a hex-string prefixed with 0x (e.g. 0xfc05aD74C6FE2e7046E091D6Ad4F660D2A159762)
* `value`: The amount of `wei` this transaction sends to the contract its interacting with (1 ETH = 1^18 WEI)
* `data`: The calldata this transaction uses to call the smart contract it interacts with, as a hex string. The data bytes will be interpreted according to the application-binary-interface (ABI) of the contract that's being interacted with. If this field is empty, it means the transaction is sending funds to an address, rather than calling a contract.
* `required_erc20_approvals`: The permissions that must be granted to a specific smart contract to spend or transfer a certain amount of their ERC-20 tokens on behalf of the end user. This allows smart contracts to execute expressive flows that may involve moving some amount of the user's ERC-20 tokens
* If this field is non-empty, the approval must be granted, signed, and submitted before the `EvmTx` populated by the other fields in the response can be submitted to the network. Otherwise, it will fail to execute with a permission error.
* Skip's `ERC20Approval` object has 3 fields that define approval:
\_ `token_contract`: The address of the ERC-20 token on which the approval is granted
\_ `spender`: The address of the contract to which the approval will grant spend authority \* `amount`: The amount of `token_contract` tokens the approval will grant the `spender` to spend
* Check out EIP-2612 for more information on ERC-20 approvals.
* `chain_id`: This is the same as in the Cosmos context (simply an identifier for the chain), but it's an int instead of a string
For more information on transactions, check out the Ethereum foundation's [docs](https://ethereum.org/en/developers/docs/transactions/)
## Example constructing & signing an EVM Transaction
### 1. Install Signing Library and Skip Library
To enable EVM transactions in your application, first install an EVM developer library. The most popular options are:
* [viem](https://viem.sh/)
* [ethers.js](https://docs.ethers.org/v5/)
* [web3.js](https://web3js.readthedocs.io/en/v1.10.0/)
The code snippets below use viem.
```Shell Shell
npm i viem
npm i @skip-go/client
```
### 1. Initialize the `SkipClient` client with the EVM `WalletClient` object
All 3 libraries mentioned above allow you to create WalletClient "signer" objects that:
* Use an RPC provider under the hood to query the chain for necessary data to create transactions (e.g. nonce, gas price, etc...)
* Expose an API that allows constructing, signing, and broadcasting transactions
You need to set up the `getEVMSigner` function in the `SkipClient` constructor to initialize this signer object for the a given EVM chain.
For example, with Viem, we do the following:
```TypeScript TypeScript
import { createWalletClient, custom} from 'viem';
import * as chains from 'viem/chains';
import { SkipClient } from '@skip-go/client';
const
const skipClient = new SkipClient({
getEVMSigner: async (chainID) => {
const chain = extractChain({
chains: Object.values(chains),
id: parseInt(chainID)
});
const evmWalletClient = createWalletClient({
chain: chain,
transport: custom(window.ethereum!)
});
return evmWalletClient;
}
});
```
### 2. Request Route using `SkipClient` and get required chain
Next, request your route as normal:
```Typescript TypeScript
const route = await skipClient.route({
amountIn: "1000",
sourceAssetDenom: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
sourceAssetChainID: "1",
destAssetDenom: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
destAssetChainID: "42161",
smartRelay: true,
smartSwapOptions: {
splitRoutes: true
}
};
```
### 3. Get User Addresses for all Required Chains
Use the route to determine the chains for which you need to supply a user address (the source, destination, and all intermediate chains that require a recovery address for receiving tokens in case of a failure)
```TypeScript TypeScript
let userAddresses = []
const requiredAddresses = route.requiredChainAddresses;
// iterate over chain IDs for chains that require addresses
for (const chainID of requiredAddresses) {
// Check that the chain is an EVM chain
if (parseInt(chainID)) {
// use signer library to get address from wallet
const chain = extractChain({
chains: Object.values(chains),
id: parseInt(chainID)
});
const evmWalletClient = createWalletClient({
chain: chain,
transport: custom(window.ethereum!)
});
const [address] = await client.requestAddresses();
// add to map
userAddresses.append({address: address, chainID: chainID})
} else {
// handle cosmos and SVM wallets -- not shown
}
});
return evmWalletClient;
}
```
### 4. Execute the Route using `SkipClient`
Finally, you can use `SkipClient.executeRoute` to prompt the user to sign the approval(s) and transaction, and submit the transaction on chain.
```TypeScript TypeScript
await skipClient.executeRoute({
route:route,
userAddresses: userAddresses
});
```
**Have questions or feedback? Help us get better!**
Join [our Discord](https://skip.build/discord) and select the "Skip Go Developer" role to share your questions and feedback.
# Experimental Features
This page provides a living record of the features that can be turned on with the experimental_features flag
### Background
The `experimental_features` parameter on `/route` and `/msgs_direct` gives us a consistent mechanism for rolling out new features to the folks who want to adopt them ASAP in an "opt-in" fashion, without threatening to destabilize power users who might want the new hottness.
*(Of course, we avoid shipping changes that are technically breaking no matter what. But we've found that even additive changes can break some integrators).*
We will probably auto-activate most features that we soft launch in `experimental_features` within a few weeks or months of the initial launch -- especially when the feature makes a strict improvement to end user UX (e.g. adding a new DEX or bridge).
The `experimental_features` parameter accepts an array of strings, where each string identifies a feature. The rest of this doc describes each experimental feature currently in prod, when the feature will become opt-out (rather than opt-in), and gives the feature's identifier.
### Stargate ("stargate")
**Description:** Support for routing over the Stargate V2 bridge on EVM chains incl. Sei EVM
**Opt-out switch**: Stargate routing will auto-activate on March 1 2025
**Identifier:** "stargate"
**Have questions or feedback? Help us get better!**
Join [our Discord](https://skip.build/discord) and select the "Skip Go Developer" role to share your questions and feedback.
# Go Fast
A brief overview of the Go Fast Transfer system
Read the whitepaper [here](https://skip-protocol.notion.site/EXT-Skip-Go-Fast-b30bc47ecc114871bc856184633b504b).
Find integration details for Go Fast [here](../client/advanced-features#use-the-go-fast-transfer-system).
# Overview
Go Fast is a decentralized bridging protocol, built by Skip, designed to enable rapid and secure cross-chain transactions across major blockchain ecosystems such as Ethereum, Cosmos, and Solana. Go Fast accelerates cross-chain actions by up to 25 times, reducing onboarding times from 10+ minutes to seconds.
# How it Works
The Go Fast Protocol lets you quickly move assets and execute smart contracts between two different blockchains: the source chain and the destination chain. Here’s a simple breakdown of how it all happens.
To start, you—the user—initiate a transfer by calling the `submitOrder` function on the protocol contract on your current blockchain (source chain). In this step, you specify the assets, any message you want to send, and the address on the destination chain. This information is then broadcasted as an intent.
Permissionless participants called solvers, who watch for these intents, ingest the event emitted from the Go Fast contracts. When they see the intent submitted, they evaluate whether they can fulfill the intent based on their resources on the destination chain and the potential reward for fulfilling it. If a solver agrees to fulfill the intent, they call the `fillOrder` function on the protocol contract deployed on the destination chain.
This step transfers the specified assets and processes any additional actions, like executing a contract call with the provided message payload. From your perspective, the assets or messages appear on the destination chain almost instantly, marking the transfer as complete.
After fulfilling the transfer, the solver seeks to recover the assets they fronted, plus any earned fees. They do this by calling the `initiateSettlement` function on the destination chain's Go Fast smart contract, listing the intents they fulfilled. The protocol verifies the solver’s actions, then sends a secure message back to the source chain through a cross-chain messaging system.
A relayer delivers this message to the source chain, where the settle function on the protocol contract verifies the solver’s fulfillment of each intent. Once confirmed, the solver receives back the assets they provided and any earned fees on the source chain.
# Can I become a solver?
Yes! Go Fast is a permissionless protocol, so anybody can run a solver!
**Open-Source Reference Solver Implementation:** To help you get started quickly, we've open-sourced a reference implementation of a solver that handles everything—from monitoring events to filling orders, settling transactions, and rebalancing. All you need to do is set up the config with the chains you want to solve for, provide node endpoints to use, and customize your capital and rebalancing preferences. Check out the repo [here](https://github.com/skip-mev/skip-go-fast-solver).
**Open-Source Protocol Contracts:** Although we recommend starting with the open-source solver, ambitious solvers are already modifying the reference implementation or developing their own solving systems. If you fall under this category, another useful resource will be our open-source Solidity and CosmWasm protocol contracts to integrate directly. You can find them [here](https://github.com/skip-mev/go-fast-contracts).
If you have any questions about setting up a solver, please don't hesitate to reach out to us!
# What chains are supported today?
Currently, Go Fast supports the following source chains:
1. Ethereum Mainnet
2. Arbitrum
3. Avalanche
4. Base
5. Optimism
6. Polygon
And the following destination chains:
1. Any IBC-connected chain supported by Skip Go
# What is the fee model for Go Fast?
Go Fast works by having solvers use their own capital to fill orders as quickly as possible, where the solvers take on the re-org risk of the source chain. The Go Fast protocol compensates solvers by paying them a fee (denoted by the difference in the input and output amount of the user's order). The fee is composed of three parts, a basis points fee on the transfer size, a source gas fee, and a destination gas fee.
Currently, the basis points fee on transfer size paid to solvers is 10 basis points across all transfer sizes. As the protocol evolves, the basis points fee charged is expected to decrease as transfer size increases.
The source and destination gas fees are determined dynamically based on the source and destination chains and their current gas costs, optimized to minimize costs while covering settlement and rebalancing for solvers.
# How do I integrate Go Fast into my application?
For instructions on integrating Go Fast using the `@skip-go/client`, see the [Advanced Features guide](../client/advanced-features#use-the-go-fast-transfer-system).
If you're using the Widget, refer to the [Widget Configuration](../widget/configuration#routeconfig).
Note that enabling Go Fast prioritizes speed over lower fees. For more cost-efficient routes, it's recommended to leave Go Fast disabled.
# Cross-chain Failure Cases
This page covers the different ways our cross-chain swaps + transfers might fail to help identify failures and manage user expectations
## Failures during IBC Transfers and Swaps
There are two types of IBC failures that may occur when a user attempts to traverse a swap / transfer route produced by the Skip Go API.
1. **Pre-Swap / swap failures**
* **What:** These are failures in the sequence of ICS-20 transfers leading up to the swap or a failure in the swap itself (usually due to slippage).
* **Outcome / What to Expect:** The users' original source tokens are returned their starting address on the source chain
* **Common causes:**
* Inactive relayers on a channel allow a packet to timeout
* Slippage (the amount out for the swap turns out to be less than the user's specified minimum, i.e. their slippage exceeds their tolerance)
* The user / frontend provides an invalid recovery address
* An IBC client on the destination chain has expired
* **Examples:** Consider a route where the source asset is ATOM on Neutron, the destination asset is STRIDE on Stride, and the swap takes place on Osmosis:
* The user's tokens transfer from Neutron to the Hub to Osmosis. The swap initiates but the price of STRIDE has gotten so high that the swap exceeds slippage tolerance and fails. A sequence of error acks is propagated back to the Hub then Neutron, releasing the user’s ATOM to their address on Neutron where they started
* The user attempts to transfer tokens from Neutron to the hub, but the packet isn't picked up by a relayer for more than 5 minutes (past the timeout\_timestamp). When a relayer finally comes online, it relays a timeout message to Neutron, releasing the user's ATOM back to their address on Neutron where they first had it.
* **For transfer-only routes:** This is the only kind of failure that may happen on a route that only contains transfers. Either the user's tokens will reach their destination chain as intended, or they will wind up with the same tokens, on the same chain where they started.

2. **Post-swap failures:**
* **Description**: These are failures that occur on the sequence of transfers between the swap venue chain and the user's destination chain, after the user's origin tokens have already been successfully swapped for their desired destination asset.
* **Outcome / What to Expect**: The user's newly purchased destination asset tokens will be transferred to their address on the swap chain. (This is the address passed to `chains_to_addresses` in `/fungible/msgs` for the chain where the swap takes place, which is given by `swap_venue.chain_id` in the response from `/fungible/route`)
* **Common failure sources:**
* Inactive relayers on a channel allow a packet to timeout
* The user / frontend provides an invalid address for the destination chain
* An IBC client on the destination chain has expired
* **Examples:** Consider a route where the source asset is ATOM on Neutron, the destination asset is STRIDE on Stride, and the swap takes place on Osmosis:
* Suppose the swap took place and the transfer to Stride has been initiated, but the Relayer between Osmosis and Stride is down. So the packet’s timeout occurs after 5 minutes. When the Relayer comes back online after 8 minutes, it relays a timeout message to Osmosis, releasing the user’s STRIDE, which gets forwarded to their Osmosis address

## Axelar Failures
Axelar transfers can be tracked on [Axelarscan](https://axelarscan.io/). Often, Axelar transfers are delayed by Axelar's relayer or execution services. If a transaction is taking longer than expected, users can visit Axelarscan, find their transaction, and manually execute the steps needed to get the transfer through. See the [Axelar docs](https://docs.axelar.dev/dev/general-message-passing/recovery) for details on how to use Axelarscan.
Internally, the Skip Go API may use Axelar's General Message Passing service to move assets between EVM and Cosmos. There are similar failure modes for Axelar as there are for IBC:
1. **Swap failures**
* **What:** Axelar GMP takes user assets from an EVM chain to the swap chain. The swap can still fail at this point due to a timeout or slippage.
* **Outcome / What to Expect:** The user receives the Axelar-transferred token on the chain where the swap was supposed to take place at their recovery address. (Note this is different from the IBC swap failure case where the user receives the swap token back on the source chain)
* **Common failure sources:**
* Slow relaying from Axelar causes a timeout, and the swap is not attempted.
* Slippage (the amount out for the swap turns out to be less than the user's specified minimum, i.e. their slippage exceeds their tolerance)
2. **Post-swap failures**
* Once the swap is executed, Axelar is no longer involved, and the same rules that apply to IBC post-swap failures apply here, so the **Post-swap failures** section above applies.
## CCTP Failures
Routes that use CCTP transfers rely on Circle to produce attestations. The Circle attestation service waits for a specified number of on-chain block confirmations before producing an attestation. The number of block confirmations required is specified by Circle in their documentation [here](https://developers.circle.com/stablecoins/docs/required-block-confirmations).
If Circle's attestation service experiences an outage, malfunction, or otherwise becomes unresponsive, CCTP transfers will continue to burn assets on the source chain, but will not be able to mint assets on the destination chain. In this case, funds that have been burned to initiate a CCTP transfer will be inaccessible until the Circle attestation service recovers.
## Hyperlane Failures
Each Hyperlane token transfer route is secured by an Interchain Security Module (ISM) designated by the deployer of the Hyperlane Warp Route Contracts (the interface to send tokens across chains using Hyperlane). The ISM defines the requirements for a message to be successfully processed on the destination chain.
The most common ISM is a Multisig ISM where "Validators" of a specific Hyperlane route sign attestations that a specific message on an origin chain is a valid message to be processed on the destination chain. In the case where the set of Validators have not hit the required signature threshold to successfully process a Hyperlane message on the receiving chain, funds will not be accessible by the user on either chain until the threshold is met (once met, funds will be sent to the user on the destination chain). This generalizes to the different requirements for different ISMs. The Hyperlane documentation explains the different types of ISMs in more detail: [https://docs.hyperlane.xyz/docs/reference/ISM/specify-your-ISM](https://docs.hyperlane.xyz/docs/reference/ISM/specify-your-ISM)
## Go Fast Failures
If a transfer timeout occurs, meaning a user's intent does not receive a response from solvers within a predefined time frame, the solver initiates a refund process to ensure that users do not lose funds.
Here's a breakdown of what happens in the event of a timeout:
1. Intent Expiration: When a user initiates an intent by calling the `submitOrder` function on the source chain, a time limit is specified. Solvers monitor the intent and assess whether they can fulfill it within this period. If no solver fills the intent before the timeout, the refund process begins.
2. Refunds: Once the timeout period is reached without fulfillment, the solver calls a function on the contract to trigger a refund process. This is handled on-chain, and includes any fees initially allocated from the user for solver compensation.
**Failures might occur for each transaction in a multi-tx sequence**
In the event of a multi-tx route, each transaction may suffer from the kinds of failures noted above. This means it's technically inaccurate to say that tokens will always end up on the initial chain or the chain where the swap takes place. More accurately, tokens may end up on each chain where a transaction is initiated or the chain where the swap takes place.
For instance, if a pre-swap failure takes place on the second transaction in a sequence, the tokens will end up on the chain that transaction targeted. In our example above, if the transfer from Cosmos Hub to Osmosis required a separate user transaction and the Neutron to Hub leg of the route succeeded in the first transaction, the ATOM tokens would end up in the user's account on the Hub if the swap exceeds maximum slippage.
**We're working to make these failures even less common**
* In the short term, we're working to add packet tracking + live relayer + client status to the API to help identify when packets get stuck and prevent folks from using channels where they're likely to get stuck in the first place
* In the medium term, we are working to add priority multi-hop relaying into the API.
* In the long term, we're working to build better incentives for relaying, so relayers don't need to run as charities. (Relayers do not receive fees or payment of any kind today and subsidize gas for users cross-chain)
**Have questions or feedback? Help us get better!**
Join [our Discord](https://skip.build/discord) and select the "Skip Go Developer" role to share your questions and feedback.
# IBC Token Routing: Problem + Skip Go API Routing Algorithm
This page describes the IBC token routing problem and the algorithm Skip Go API uses to select / recommend token denoms and IBC paths
**tl;dr**
The routing problem:
1. IBC tags assets based on the sequence of IBC channels they have been transferred over, so the same asset transferred over two different paths will have two different denoms
2. Usually, there's only 1 "correct" (i.e. highly liquid) version of each asset on each chain (and frequently there are none)
Skip Go API solves this problem by:
1. Sending assets to their origin chain
2. Find the shortest path from the origin chain to the destination chain, and using the most liquid path when there are multiple distinct shortest paths.
3. Plus, staying flexible to unusual exceptions
## Routing Problem
### IBC Tokens Get Their Names & Identities from Their Paths
IBC transfers data over "channels" that connect two chains. Channels are identified by human-readable port names (e.g. "transfer") and channel IDs (e.g. channel-1). For example, consider a transfer channel between Terra2 and Axelar:

*Notice that both chains maintain their own channel IDs for the channel, which might not be the same. As an analogy, you might think of the different chains as cities and the channel as a road connecting them. IBC packets are cars driving across the road*
When transferring a fungible token from one chain to another over a channel, the denomination of the token on the destination chain is uniquely and predictably determined by the source denomination + the channel(s) over which the token was transferred. Specifically the denomination algorithm is:
```text Naming Algorithm
ibc_denom = 'ibc/' + hash('path' + 'base_denom')
```
*`hash` is typically the sha256 hash function*
Continuing the example from above, the denom of this version of WETH.axl on Terra2 is:
```text axlWETH on Terra2
axlweth_on_terra2_denom = 'ibc/' + hash('transfer/channel-6/weth-wei')
axlweth_on_terra2_denom = 'ibc/BC8A77AFBD872FDC32A348D3FB10CC09277C266CFE52081DE341C7EC6752E674'
```
### So Different Paths Produce Different Tokens
Now that you understand that IBC denoms get their names from their paths, you understand the crux of the routing problem: **The same asset transferred to the same destination over two different paths will have different denominations.**
Continuing the example from above, WETH.axl transferred directly from Axelar to Terra2 will have a different denom than WETH.axl transferred through Osmosis:

To make matters worse, multiple channels can exist between the same two chains (IBC is permissionless afterall), and IBC uses channel identifiers--not chain identifiers--to construct denoms. That means two different versions of the same asset will exist on the destination chain even when tokens are transferred from the same source chain, if they're transferred over two different channels:

**Why don't we just consider them equivalent anyway and move on?**
Some folks who don’t work with bridges on a regular basis view this path tagging as a bug, or might think we should just consider these different versions of the same asset as fungible anyway. But that's not advisable!
The route-based denom construction is a critical security feature because the chain where the token has been transferred to is effectively trusting the validator set of the chain from which the token was transferred.
Applied to the example here, this trust model means using the purple version of WETH.axl implies trusting the Osmosis validator set AND the Axelar validator set, while using the blue version of WETH.axl only requires trusting the Axelar validator set.
### There are many paths between two chains, but usually only 1 useful version of each asset
Right now, there are about 70 IBC-enabled chains. At least one channel exists between almost every pair in this set. This dense graph of channels contains a very large number of different paths between almost any two chains, which creates many opportunities for "token winding" or "mis-pathing", where a user sends an asset through a suboptimal path of channels from one chain to another and ends up with an illiquid / unusable version of their token.
Mis-pathing almost always produces a practically useless + illiquid version of their token on the destination chain because there's usually only 1 useful version of a given asset on a given destination chain (if that). (There are over 50 versions of ATOM on JUNO!)
As a result, we need to be very careful to send the user through the correct sequence of channels. The next section explains our token routing algorithm.
## Routing Algorithm
**Insight about routing: The correct route depends on the chains + the asset in question**
Notice that the correct route for a particular asset A on a particular chain Chain-1 to another chain Chain-2 depends not only on the channels that exist between chain-1 and chain-2, but also on what asset-A is.
This is because asset A is defined by its path from its origin. Consider the following two cases:
* If asset-A is native to Chain-1, perhaps it can be routed directly over a channel to Chain-2. This would yield a simple asset given by path of Chain-1->Chain-2
* If asset-A originated on another chain (e.g. Chain-3), it's very unlikely that transferring directly over a channel to Chain-2 would give the correct version of asset A on Chain-2. This would yield a more complex denom given by path of Chain-3->Chain-1->Chain-2, which is probably wrong if Chain-3 and Chain-2 are directly connected.
* Instead, the asset should probably be routed back through the channel that connects Chain-1 to Chain-3 first, then sent over the channel to Chain-2. This yields a path of Chain-1->Chain-3->Chain-2, and a final denom given by the path Chain-3->Chain-2
Ultimately, we use a very simple routing algorithm:
1. Route the given asset back to origin chain (i.e. "unwind" it)
2. Check whether any *high-priority* manual overrides exist for the given asset on the given destination chain. If so, recommend the path from the source that produces this *high-priority* version of the asset
3. If no *high priority* manual overrides exist:
1. If at least 1 single-hop path to the destination chain exists (i.e. if origin chain and destination chain are directly connected over IBC), recommend the most liquid direct path.
2. If no direct path exists (or if the client on the direct path is expired, or none of the asset has been transferred over the direct path), do not recommend any asset
A few notes about our data collection:
* We run nodes for every supported chain to ensure we always have low-latency access to high quality data
* We index client + channel status of every channel + client on all the chains we support every couple of hours to ensure we never recommend a path that relayers have abandoned or forgotten about.
* We index the liquidity of every token transferred over every channel on every Cosmos chain every few hours to ensure our liquidity data is up to date. And we closely monitor anomalous, short-term liquidity movements to prevent attacks
# SVM Transactions
This document explains how to use Skip Go API and Client TypeScript Package to construct SVM transactions.
## Intro
* When a user needs to transfer or swap from an SVM chain (e.g. Solana), the Skip Go API will return an `SvmTx` type for the developer to pass to the user for signing
* This doc is intended for CosmosSDK and EVM developers who aren't already familiar with the concepts of transaction construction in the SVM and need to use `SvmTx` to help their users move from/to Solana and other SVM chains.
* **Due to the difficult nature of including Solana transactions on chain during times of high network congestion, we HIGHLY recommend using the `/submit` endpoint to avoid dealing with complex retry logic and/or multiple RPC providers for submission reliability. Skip Go API's `/submit` endpoint implements best practices for Solana transactions submission for you!**
## Interact with Solana Wallets
We recommend using [@solana/wallet-adapter](https://github.com/anza-xyz/wallet-adapter#readme) to interact with Solana wallets and build transactions. It provides a standardized `Adapter` object that wraps all major Solana wallets (e.g. Phantom, Backpack, etc...), as well as visual React components for wallet selection. See [here](https://github.com/anza-xyz/wallet-adapter/blob/master/PACKAGES.md) for all the supported wallets.
## Set up the `SkipClient` to use a Solana wallet
All you need to do is initialize the `getSVMSigner` method in `SkipClient.options` to extract the `@solana/wallet-adapter-base` from the user's connected wallet of choice:
```TypeScript TypeScript
import { useWallet } from "@solana/wallet-adapter-react";
import { PhantomWalletName } from "@solana/wallet-adapter-phantom"
import { SkipClient } from '@skip-go/client';
const { wallets } = useWallet();
const skipClient = new SkipClient({
getSVMSigner: async (chainID) => {
const { svm } = trackWallet.get();
const solanaWallet = wallets.find((w) => w.adapter.name === PhantomWalletName);
return solanaWallet
}
});
```
After this point, you can use `route`, `executeRoute`, and the other methods of `SkipClient` as you normally would.
The rest of these docs cover the underlying details of the data structures, in case you need them.
## Understand `SvmTx` Data Structure
The `SvmTx` has 2 fields that the developer needs to understand:
* `chain_id`: The ID of the chain that this transaction should be submitted to
* `tx`: This is the base64 encoded bytes of the transaction you should have the end user sign.
### Info on `SvmTx.tx`
This is a fully constructed transaction. You don't need to change it or add anything to it to prepare it for signing. You just need to sign it and have the user submit it on chain within about 1 minute (or the nonce will expire).
For more detail, the transaction already includes:
* User's nonce (In Solana, this is actually a recent blockhash by default)
* Instructions (Solana's equivalent to messages)
* Base transaction fees (Set to the default of 500 lamports per signature)
* Priority fees (More info on how we set these below)
For more information on transactions, check out the Solana's official [docs](https://solana.com/docs/core/transactions)
#### Signing `tx`
[Skip Go Client](https://www.npmjs.com/package/@skip-go/client) takes care of all of the complexity of signing the transaction that gets returned in `SvmTx.tx`.
You just need to have set the `getSVMSigner` method in the `SkipClientOptions` object in the `SkipClient` constructor then use `executeRoute` or `executeTxs`.
#### How Priority Fees are Set
Solana "priority fees" affect how likely it is a transaction gets included in a block. Unlike for many other major blockchain networks, Solana's priority fees are evaluated "locally". In other words, the size of the fee is compared to other transactions that access the same pieces of state (e.g. the same DEX pool, the same token contract etc...):
* If the fee is low relative to other transactions that access the same state, the transaction is unlikely to get included.
* If its high relative to these other transactions accessing similar state, its likely to be included
As a result, transactions that touch "congested" or "popular" state will be the most expensive.
At this time, we are setting priority fees to match the 90% percentile of priority fees for the "wif" pool state on Jupiter, which we believe is highly congested state. This is a very conservative setting, but it even with these "high amounts", fees are still fractions of a cent.
**Have questions or feedback? Help us get better!**
Join [our Discord](https://skip.build/discord) and select the "Skip Go Developer" role to share your questions and feedback.
# Get /v2/fungible/assets
swagger get /v2/fungible/assets
Get supported assets. Optionally limit to assets on a given chain and/or native assets.
# Get /v2/fungible/venues
swagger get /v2/fungible/venues
Get supported swap venues.
# Post /v2/fungible/assets_between_chains
swagger post /v2/fungible/assets_between_chains
Given 2 chain IDs, returns a list of equivalent assets that can be transferred
# Post /v2/fungible/assets_from_source
swagger post /v2/fungible/assets_from_source
Get assets that can be reached from a source via transfers under different conditions (e.g. single vs multiple txs)
# Post /v2/fungible/ibc_origin_assets
swagger post /v2/fungible/ibc_origin_assets
Get origin assets from a given list of denoms and chain IDs.
# Post /v2/fungible/msgs
swagger post /v2/fungible/msgs
This supports cross-chain actions among EVM chains, Cosmos chains, and between them. Returns minimal number of messages required to execute a multi-chain swap or transfer. Input consists of the output of route with additional information required for message construction (e.g. destination addresses for each chain)
# Post /v2/fungible/msgs_direct
swagger post /v2/fungible/msgs_direct
This supports cross-chain actions among EVM chains, Cosmos chains, and between them. Returns minimal number of messages required to execute a multi-chain swap or transfer. This is a convenience endpoint that combines /route and /msgs into a single call.
# Post /v2/fungible/route
swagger post /v2/fungible/route
This supports cross-chain actions among EVM chains, Cosmos chains, and between them. Returns the sequence of transfers and/or swaps to reach the given destination asset from the given source asset, along with estimated amount out. Commonly called before /msgs to generate route info and quote.
# Get /v2/info/bridges
swagger get /v2/info/bridges
Get all supported bridges
# Get /v2/info/chains
swagger get /v2/info/chains
Get all supported chains along with additional data useful for building applications + frontends that interface with them (e.g. logo URI, IBC capabilities, fee assets, bech32 prefix, etc...)
# Post /v2/info/balances
swagger post /v2/info/balances
Get the balances of a given set of assets on a given chain and wallet address. Compatible with all Skip Go-supported assets, excluding CW20 assets, across SVM, EVM, and Cosmos chains.
# Get /v2/tx/status
swagger get /v2/tx/status
Get the status of the specified transaction and any subsequent IBC or Axelar transfers if routing assets cross chain. The transaction must have previously been submitted to either the /submit or /track endpoints.
# Post /v2/tx/submit
swagger post /v2/tx/submit
Submit a signed base64 encoded transaction to be broadcast to the specified network. On successful submission, the status of the transaction and any subsequent IBC or Axelar transfers can be queried through the /status endpoint.
# Post /v2/tx/track
swagger post /v2/tx/track
Requests tracking of a transaction that has already landed on-chain but was not broadcast through the Skip Go API. The status of a tracked transaction and subsequent IBC or Axelar transfers if routing assets cross chain can be queried through the /status endpoint.
# Advanced Features
This page details advanced features and utilities in the Skip Go client library.
## Adding custom messages before or after route execution
The `executeRoute` method now accepts `beforeMsg` and `afterMsg` parameter to allow for the execution of custom Cosmos messages before and/or after the route is executed. This is useful for executing custom messages that are not part of the route definition.
```typescript
const msg = JSON.stringify({
fromAddress: 'cosmos1...', // Replace with sender address
toAddress: 'cosmos1...', // Replace with recipient address
amount: [{
denom: 'uatom', // Replace with the actual denom, e.g., 'uatom' for ATOM
amount: '1000000' // Replace with the actual amount (in smallest unit, e.g., micro-ATOM)
}]
});
await skip.executeRoute({
route,
userAddresses,
beforeMsg: { msg, msgTypeURL: '/cosmos.bank.v1beta1.MsgSend' }
});
```
## Use the Go Fast Transfer system
The `route` method accepts a `goFast` parameter to enable the Go Fast Transfers. Then pass this route to the `executeRoute` method to execute.
```typescript
import { SkipClient } from '@skip-go/client';
const skip = new SkipClient({
// ...config,
});
const route = await skip.route({
goFast: true
// ... other params,
});
await skip.executeRoute({
route,
// ...other params
});
```
# Balances, Gas and Transaction Fee Utilities
This page details the utility functions for token balances, gas calculations, and transaction fees in Skip Go.
## Getting token balances
To query token balances, you can use the `balances` method on your `SkipClient` instance or via the [REST API](https://docs.skip.build/go/api-reference/prod/info/post-v2infobalances). You have the option to specify a set of token denoms to query or leave the array empty to fetch balances for all denoms associated with an address.
* **When no denoms are specified**: The response will include only the denoms for which you have a balance.
* **When denoms are specified**: The response will include balances for all the specified denoms. If you have no balance for a given denom, it will be included with a balance of zero.
If there is an error fetching a given denom (e.g. the chain is down), the response will include an error message for that denom.
The balance query is currently compatible with all Skip Go-supported assets, excluding CW20 assets, across SVM, EVM, and Cosmos chains.
Learn how to setup your `SkipClient` instance in the [Getting Started](../client/getting-started) guide.
```ts TypeScript (Client)
const balances = await skipClient.balances({
chains: {
"noble-1": {
address: noble.address, // noblef8js...
denoms: ["uusdc"]
},
"osmosis-1": {
address: osmosis.address, // osmois8fo...
denoms: [] // Fetch all denoms for address
}
}
});
```
```JSON JSON (REST API)
// POST /v2/info/balances
{
"chains": {
"137": {
"address": "0x24a9267cE9e0a8F4467B584FDDa12baf1Df772B5",
"denoms": [
"polygon-native",
"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359"
]
},
"osmosis-1": {
"address": "osmo12xufazw43lanl8dkvf3l7y9zzm8n3zswftw2yc",
"denoms": [] // Fetch all denoms for address
}
}
}
```
## Getting info about gas and fees
**Video Overview**
Here's a [video overview](https://www.loom.com/share/063e96e126d2422bb621b5b0ecf9be2c) of our gas and transaction fee tooling.
These functions are useful for getting information about our default gas and fee values or for estimating the fee for a particular transaction (e.g. so you can build a working MAX button).
### `SkipClient.getRecommendedGasPrice`
This returns the gas price (i.e. the price of a single unit of gas) the API recommends you use for transactions on a particular chain.
```ts
async getRecommendedGasPrice(chainID: string) -> GasPrice
```
`GasPrice` is a [cosmjs](https://cosmos.github.io/cosmjs/latest/stargate/classes/GasPrice.html) type giving the recommended fee denom and recommend price amount (fee/gas):
```ts
type GasPrice = {
denom: string;
amount: Decimal
}
```
### `SkipClient.getFeeInfoForChain`
This will return high, medium, and low gas prices for a particular chain, given by `chainID`, along with the default fee denom as a `FeeAsset` object:
```ts
type FeeAsset = {
denom: string;
gasPrice: GasPriceInfo;
};
type GasPriceInfo = {
low: string;
average: string;
high: string;
};
```
An undefined response indicates that the API cannot find up-to-date gas price information for the chain.
### `SkipClient.getFeeForMessage`
This will give you the estimated fee and gas for a particular multichainMsg returned by the API.
```ts
async getFeeForMessage(
msg: MultiChainMsg,
gasAmountMultiplier: number = DEFAULT_GAS_MULTIPLIER,
signer?: OfflineSigner,
gasPrice?: GasPrice,
)
```
If you provide no additional arguments other than your signer and message, it will use the default gas price and gas amount multipliers in the skip-router, but you can override anything to customize your estimation for your use case:
* You can override the gas price in the `gasPrice` argument (By default, we're pulling this data from various chain registries and serving it through the API)
* You can override the gas amount multiplier, which provides a multiplicative buffer for the amount of gas the chain estimates a transaction will consume, in the `gasAmountMultiplier` argument. (By default, this is `1.5`)
The return type of the function is a `cosmjs.StdFee`, which includes the following fields:
* `amount`: The estimated fee amount and denom for the fee
* `gas`: The gas amount for the transaction
## Settings on `ExecuteRouteOptions` for customizing how gas & fees are set on transactions
### `ExecuteRouteOptions.getGasPrice`
This field in `ExecuteRouteOptions` allows you to override our default gas price on a per chain basis for any transactions created in the router (e.g. in `executeRoute`):
`getGasPrice?: (chainID: string) => Promise;`
The argument is a function that takes in a chain ID and returns a gas price for that chain as a `GasPrice` object from CosmJS
```ts
type GasPrice = {
denom: string;
amount: Decimal
}
```
If you provide a function that only returns a price for a subset of chains, the router will use its default price in cases where yours is missing. If it can't find a default price for a chain, it will error.
### `ExecuteRouteOptions.gasAmountMultiplier`
This field in `ExecuteRouteOptions` allows you to override the default gas multiplier used by default in the SDK. The default value is 1.5. Increasing this value provides higher confidence that transactions will not run out of gas while executing, but increases the fee for the end user.
The gas multiplier increases a transaction's `gasAmount` multiplicatively. To get a final gas amount, the router:
* Simulates a transaction to get an initial gasAmount
* Multiplies the gas consumed in the simulation by `gasAmountMultiplier`
# Getting Started
@skip-go/client is a TypeScript library that streamlines interaction with the Skip Go API, enabling cross-chain swaps and transfers across multiple ecosystems.
Anxious to get started? See a live example of this [code](https://github.com/skip-mev/skip-go-example) in our [example app](https://skip-next-simple-example.vercel.app/).
Install the library using npm or yarn:
```Shell npm
npm install @skip-go/client
```
```Shell yarn
yarn add @skip-go/client
```
If you're using `yarn` (or another package manager that doesn't install peer dependencies by default)
you may need to install these peer dependencies as well:
```bash
yarn add viem @solana/web3.js
```
To start integrating with the Skip Go API, initialize a `SkipClient` instance. This `skipClient` provides helper methods for common actions such as querying assets and chains, constructing routes, and executing transactions.
```ts
import { SkipClient } from "@skip-go/client";
const skipClient = new SkipClient({
// Signers will be set up in the following section
});
```
The SkipClient constructor accepts an optional configuration object of type `SkipClientOptions`. Here's a brief overview:
* `apiURL?: string`: Override the default API URL
* `endpointOptions?: EndpointOptions`: Provide RPC and REST endpoints for specific chains
* `aminoTypes?: AminoConverters`: Additional amino types to be for message encoding
* `registryTypes?: Iterable<[string, GeneratedType]>`: Additional registry types
To execute transactions, you need to set up signers for the ecosystems you plan to interact with. Below are examples for Cosmos SDK, EVM, and Solana (SVM). Note that for EVM and SVM, you'll need to install additional libraries.
### Signer Setup
```ts Cosmos Signer
// For Cosmos transactions, we'll use Keplr wallet from the window object
const getCosmosSigner = async (chainID: string) => {
const key = await window.keplr?.getKey(chainID);
if (!key) throw new Error("Keplr not installed or chain not added");
return key.isNanoLedger
? window.keplr?.getOfflineSignerOnlyAmino(chainID)
: window.keplr?.getOfflineSigner(chainID);
};
```
```ts EVM Signer
// For EVM transactions, we'll use MetaMask and viem
// npm install viem
import { createWalletClient, custom, Account } from "viem";
import { mainnet } from 'viem/chains';
const getEVMSigner = async () => {
const ethereum = window.ethereum;
if (!ethereum) throw new Error("MetaMask not installed");
const accounts = await ethereum.request({ method: 'eth_requestAccounts' }) as Account[];
const account = accounts?.[0]
if (!account) throw new Error('No accounts found');
const client = createWalletClient({
account,
chain: mainnet,
transport: custom(window.ethereum),
});
return client;
}
```
```ts SVM Signer
// For Solana transactions, we'll use the Phantom wallet adapter
// npm install @solana/wallet-adapter-phantom
import { PhantomWalletAdapter } from '@solana/wallet-adapter-phantom';
const getSVMSigner = async () => {
const phantom = new PhantomWalletAdapter();
await phantom.connect();
return phantom;
};
```
### Finalizing the Client Initialization
Now, pass the signers and your optional configuration options into your `SkipClient` instance:
```ts
const skipClient = new SkipClient({
getCosmosSigner,
getEVMSigner,
getSVMSigner,
// ...configOptions,
});
```
With your client initialized, you can query balances, supported chains and assets.
```ts List of Supported Chains
// returns a Chain[] of all supported Cosmos mainnet chains
const cosmosChains = await skipClient.chains();
// include EVM and SVM chains
const allChains = await skipClient.chains({
includeEVM: true,
includeSVM: true,
});
// only show testnet chains
const testnetChains = await skipClient.chains({
onlyTestnets: true
});
```
```ts Map of Supported Assets
// returns `Record
const assets = await skipClient.assets({
includeEvmAssets: true,
includeSvmAssets: true,
});
// get assets filtered by chain ID
const assets = await client.assets({
chainID: 'cosmoshub-4'
includeCW20Assets: true,
})
```
```ts Map of Token Balances
// returns a map of assets by chain ID
// includes all Skip Go-supported assets, excluding CW20 assets, across SVM, EVM, and Cosmos chains
const balances = await skipClient.balances({
"chains": {
"137": {
address: "0x24a9267cE9e0a8F4467B584FDDa12baf1Df772B5",
denoms: [
"polygon-native",
"0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359"
]
},
"osmosis-1": {
address: "osmo12xufazw43lanl8dkvf3l7y9zzm8n3zswftw2yc",
denoms: [
"uosmo"
]
}
}
});
```
Once you've selected your source and destination chains and tokens, you can generate a route and get a quote. See it in context [here](https://github.com/skip-mev/skip-go-example/blob/d68ec668ebaa230325ad31658b547bd27c42ac49/pages/index.tsx#L46).
```ts Swap ATOM for OSMO
const route = await skipClient.route({
amountIn: "1000000", // Desired amount in smallest denomination (e.g., uatom)
sourceAssetDenom: "uatom",
sourceAssetChainID: "cosmoshub-4",
destAssetDenom: "uosmo",
destAssetChainID: "osmosis-1",
cumulativeAffiliateFeeBPS: '0',
});
```
```ts Swap ETH for TIA
const route = await skipClient.route({
amountOut: "1000000", // Desired amount out
sourceAssetDenom: "ethereum-native",
sourceAssetChainID: "1", // Ethereum mainnet chain ID
destAssetDenom: "utia",
destAssetChainID: "celestia",
smartRelay: true,
smartSwapOptions: {
splitRoutes: true,
evmSwaps: true
},
});
```
```ts Transfer USDC from Solana to Noble
const route = await skipClient.route({
sourceAssetDenom: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
sourceAssetChainID: "solana",
destAssetDenom: "uusdc",
destAssetChainID: "noble-1",
amountIn: "1000000",
smartRelay: true
});
```
Read more about [affiliate fees](../general/affiliate-fees), [Smart Relay](../general/smart-relay) and [EVM Swaps](../advanced-swapping/smart-swap-options#feature-evm-swaps).
After generating a route, you need to provide user addresses for the required chains. The `route.requiredChainAddresses` array lists the chain IDs for which addresses are needed.
**Only use addresses your user can sign for.**
Funds could get stuck in any address you provide, including intermediate chains in certain failure conditions. Ensure your user can sign for each address you provide.
See [Cross-chain Failure Cases](../advanced-transfer/handling-cross-chain-failure-cases) for more details.
We recommend storing the user's addresses and creating a function like [`getAddress`](https://github.com/skip-mev/skip-go-example/blob/c55d9208bb46fbf1a4934000e7ec4196d8ccdca4/pages/index.tsx#L99) that retrieves the address based on the chain ID.
```ts
// get user addresses for each requiredChainAddress to execute the route
const userAddresses = await Promise.all(
route.requiredChainAddresses.map(async (chainID) => ({
chainID,
address: await getAddress(chainID),
}))
);
```
Once you have a route, you can execute it in a single function call by passing in the route, the user addresses for at least the chains the route includes, and optional callback functions. This also registers the transaction for tracking.
```ts
await skipClient.executeRoute({
route,
userAddresses,
// Executes after all of the operations triggered by a user's signature complete.
// For multi-tx routes that require multiple user signatures, this will be called once for each tx in sequence
onTransactionCompleted: async (chainID, txHash, status) => {
console.log(
`Route completed with tx hash: ${txHash} & status: ${status.state}`
);
},
// called after the transaction that the user signs gets broadcast on chain
onTransactionBroadcast: async ({ txHash, chainID }) => {
console.log(`Transaction broadcasted with tx hash: ${txHash}`);
},
// called after the transaction that the user signs is successfully registered for tracking
onTransactionTracked: async ({ txHash, chainID }) => {
console.log(`Transaction tracked with tx hash: ${txHash}`);
},
// called after the user signs a transaction
onTransactionSigned: async ({ chainID }) => {
console.log(`Transaction signed with chain ID: ${chainID}`);
},
// validate gas balance on each chain
onValidateGasBalance: async ({ chainID, txIndex, status }) => {
console.log(`Validating gas balance for chain ${chainID}...`);
},
});
```
For routes that consist of multiple transactions, this will monitor each transaction until it completes, then generate the transaction for the next step and prompt the user to sign it.
Alternatively, the route object allows you to generate, sign, and submit messages individually. You can also implement your own solutions for any or all of these steps. For more details on these lower-level functions, refer to `skipClient.messages`, `skipClient.signMultiChainMessageDirect`, and `skipClient.submitTransaction`.
Once the user has signed a transaction to execute a cross-chain action, you can track it with:
* `skipClient.trackTransaction`: Requests tracking for a transaction that's already been submitted to the network through an RPC, using the transaction hash
* `skipClient.submitTransaction`: Publishes the signed transaction to the network & begins tracking the cross-chain actions this transaction produces
After you've used one of these two functions to kick-off realtime tracking for a cross-chain action, you can request the current status of the transaction using `skipClient.transactionStatus`.
We also provide a `waitForTransaction` helper function that hangs until the entire cross-chain action flow has completed, which you can use instead of configuring your own polling via `transactionStatus`.
**Have questions or feedback? Help us get better!**
Join [our Discord](https://skip.build/discord) and select the "Skip Go Developer" role to share your questions and feedback.
# Migration Guide
Both the Skip Router SDK `@skip-router/core` and Skip Go Core `@skip-go/core`
are deprecated. Please migrate to Skip Go Client `@skip-go/client`, our
actively maintained [TypeScript package](https://www.npmjs.com/package/@skip-go/client).
### 4.0.0 Breaking changes
* Removed `clientID` param in `SkipClient`
* Added `apiKey` param in `SkipClient`
* Added `requiredChainAddresses` in `SkipClient.route` response
* Added `smartSwapOptions` in `SkipClient.route`request
```JavaScript JavaScript
smartSwapOptions:{
splitRoutes: boolean
}
```
### 3.0.0 Breaking Changes
* Changed Param Type: `userAddresses` from a map of chainIDs to addresses to an array of `UserAddress` types:
*
```TypeScript TypeScript
export interface UserAddress {
chainID: string;
address: string;
}
```
### 2.0.0 Breaking changes
* Removed Method: `SkipClient.executeMultiChainMessage`
* Renamed Method: `SkipClient.getGasAmountForMessage` -> `SkipClient.getCosmosGasAmountForMessage`
* Renamed Method: `SkipClient.getFeeForMessage` -> `SkipClient.getCosmosFeeForMe`
* Renamed Type: `MultiChainMsg` -> `CosmosMsg`
* Renamed Method & Params changed: `SkipClient.executeMultiChainMsgs`-> `SkipClient.executeTxs`
```Diff Diff
const client = new SkipClient({
apiURL: SKIP_API_URL,
// ... rest of your configs
});
- client.executeMultiChainMsgs({
+ client.executeTxs({
...options
- msgs: types.Msg[]
+ txs: types.Tx[]
})
```
* Param Changed in `SkipClient.executeCosmosMessage`: `message:MultiChainMsg` -> `messages: CosmosMsg[]`
```Diff Diff
const client = new SkipClient({
apiURL: SKIP_API_URL,
// ... rest of your configs
});
client.executeCosmosMessage({
...options
- message: MultiChainMsg
+ messages: CosmosMsg[]
})
```
# Setting Affiliate Fees
This page covers how integrators can earn affiliate fees on swaps.
### Overview
Many teams use Skip Go as a source of a revenue for their project by charging fees on swaps. (Charging fees on transfers will be possible in the future!). We refer to these fees throughout the product and documentation as "affiliate fees"
Skip Go's affiliate fee functionality is simple but flexible -- supporting a large variety of bespoke fee collection scenarios:
* Set your desired fee level on each swap (so you can offer lower fees to your most loyal users)
* Set the account that receives the fee on each swap (so you can account for funds easily & separate revenue into different tranches)
* Divide the fee up in customizable proportions among different accounts (so you can create referral/affiliate revenue sharing programs with partners and KOLs)
### Affiliate Fees Work
1. **At this time, affiliate fees can only be collected on swaps**. We do not support collecting affiliate fees on routes that only consist of transfers (e.g. CCTP transfers, IBC transfers, etc...) even when there are multi-hop transfers. Please contact us if charging fees on transfers is important to you
2. **Affiliate fees are collected on the chain where the last swap takes place**: Skip Go aggregates over swap venues (DEXes, orderbooks, liquid staking protocols, etc...) on many different chains. Some routes even contain multiple swaps. For each individual cross-chain or single chain swap where you collect a fee, the fee is applied on the last swap and sent to an address you specify on the chain where the last swap takes place
3. **Affiliate fees are collected/denominated in the output token of each swap**: For example, if a user swaps OSMO to ATOM, your fee collection address will earn a fee in ATOM
4. **Affiliate fees are calculated using the minimum output amount, which is set based on our estimated execution price after accounting for the user's slippage tolerance** : For example, consider an ATOM to OSMO swap where min amount out is 10 uosmo and the cumulative fees are 1000 bps or 10%. If the swap successfully executes, the affiliate fee will be 1 uosmo. It will be 1 uosmo regardless of whether the user actually gets 10, 11, or 12 uosmo out of the swap
### How to Use Affiliate Fees
There are two simple steps involved in using affiliate fees:
1. **Incorporate the fee into the quote** : You need to request the route & quote with the total fee amount (in basis points) you will collect, so Skip Go can deduct this automatically from the estimated `amount_out` it returns to the user. This ensures the quote you show the user already accounts for the fee, and they won't receive any unexpectedly low amount.
2. **Set the address(es) to receive the fee**: You also need to tell Skip Go the exact address(es) to send the fee revenue to. You need to pass a list of addresses and specify a fee amount (in basis points) for each to collect.
### Incorporating Fees with `/route` and `/msgs`
When executing swaps using the `/route` and `/msgs` endpoints, you can incorporate affiliate fees by specifying the total fee during the `/route` request and detailing the fee recipients during the `/msgs` request. Below is a comprehensive guide on how to correctly implement this.
1. **Set Total Fee in `/route` Request**
In your `/route` request, include the `cumulative_affiliate_fee_bps` parameter to specify the total fee you wish to collect, expressed in basis points (bps).
* **Definition**: 1% fee = 100 basis points.
* **Example**: To collect a **0.75%** fee, set `cumulative_affiliate_fee_bps` to `"75"`.
```json
{
"cumulative_affiliate_fee_bps": "75",
// ...other parameters
}
```
If you're using `@skip-go/client`, use camelCase: `cumulativeAffiliateFeeBps`.
2. **Identify Swap Chain**
After the `/route` request, use the `swap_venue.chain_id` field in the response to determine which chain the swap will occur on. You'll need this information to provide valid recipient addresses in the next step.
3. **Specify Fee Recipients in `/msgs` Request**
In your `/msgs` request, define the `chainIdsToAffiliates` object to allocate fees to specific addresses on the relevant chains.
##### Structure:
```json
{
"chainIdsToAffiliates": {
"": {
"affiliates": [
{
"basisPointsFee": "",
"address": ""
},
// ...additional affiliates
]
},
// ...additional chains
}
}
```
##### Example:
```json
{
"chainIdsToAffiliates": {
"noble-1": {
"affiliates": [
{
"basisPointsFee": "100", // 1% fee
"address": "noble1..."
},
{
"basisPointsFee": "100", // 1% fee
"address": "noble2..."
}
]
},
"osmosis-1": {
"affiliates": [
{
"basisPointsFee": "200", // 2% fee
"address": "osmo1..."
}
]
}
}
}
```
**Notes:**
* The **sum** of `basisPointsFee` values across all affiliates **on the swap chain** must equal the `cumulative_affiliate_fee_bps` set in the `/route` request.
* All addresses must be **valid on the chain where the swap will take place**. Invalid addresses will result in a `400` error.
* If using `@skip-go/client`, remember to use camelCase (e.g., `basisPointsFee`) in the config.
### Incorporating Fees with `/msgs_direct`
We recommend using `/route` and `/msgs` over `/msgs_direct` due to the added complexity when handling fees with `/msgs_direct`.
When using the `/msgs_direct` endpoint, you need to specify affiliate fees for **every possible chain** the swap might occur on since the swap chain is determined during the request.
### Steps:
1. **Define `chainIdsToAffiliates` for All Potential Swap Chains**
* Use the `chainIdsToAffiliates` object to map each potential `chain_id` to its corresponding affiliates.
* For each `chain_id`, provide a list of `affiliates`, each with:
* `basisPointsFee`: The fee amount in basis points (bps).
* `address`: The recipient's address on that chain.
2. **Include Entries for Every Possible Chain**
* Retrieve all potential swap chains by querying the `/v2/fungible/swap_venues` endpoint.
* Include an entry in `chainIdsToAffiliates` for each `chain_id` from the list.
3. **Ensure Fee Consistency Across Chains**
* The **sum** of `basisPointsFee` values for affiliates on each chain must be **equal** across all chains.
* This consistency is necessary because the fee amount used in the swap must be the same, regardless of which chain the swap occurs on.
* If the fee sums differ between chains, the request will return an error.
***
### Example Request:
```json
{
"chainIdsToAffiliates": {
"noble-1": {
"affiliates": [
{
"basisPointsFee": "100", // 1% fee
"address": "noble1..."
},
{
"basisPointsFee": "100", // 1% fee
"address": "noble2..."
}
]
},
"osmosis-1": {
"affiliates": [
{
"basisPointsFee": "200", // 2% fee
"address": "osmo1..."
}
]
},
// Include entries for all other potential chains
},
// ...other parameters
}
```
**Notes:**
* In the example above, the total fee for each chain is **200 bps (2%)**.
* Ensure that all addresses are **valid** on their respective chains.
**Have questions or feedback? Help us get better!**
Join [our Discord](https://skip.build/discord) and select the "Skip Go Developer" role to share your questions and feedback.
# Requesting & Using API Keys
## Summary
Authentication and authorization for the Skip Go API are managed via API keys.
This document covers:
1. Why you should use an API key
2. How to get your key set up
3. How to use the key in your requests
**API Keys have replaced `client_id`**
Historically, we used the `client_id` passed as a request parameter to identify and authenticate integrators. This system has been fully deprecated. If you're currently using `client_id`, you should transition to using an API key.
(We're making this transition because `client_id` didn't abide by best practices for security, and we could only attach limited functionality to it, since it was passed in the request body instead of a header.)
## Benefits of using an API key
Technically, you can access most of the basic functionality of the Skip Go API without an API key. But there are numerous benefits to authenticating yourself with a key:
* **No rate limit**: Integrators that do not pass a valid API key in their requests will be subject to a restrictive global rate limit, shared with all other unauthenticated users.
* **Improved fee revenue share pricing**: Unauthenticated integrators will be subject to a 25% revenue share on their fee revenue by default. Authenticated integrators who use API keys will be subject to a cheaper 20% revenue share by default.
* **Access to privileged features:** Integrators who authenticate with an API key will receive access to premium features that we cannot offer to the general public (e.g. Gas estimation APIs, universal balance query APIs, etc...)
* **Metrics on your volume and revenue:** Authenticated integrators will receive access to monthly statistics regarding their total swap and transfer volume and the amount of fee revenue they've earned. They will also receive annual transaction data for taxes.
## How to get an API Key
### 1. Request an API Key
Open a support ticket on our [Discord](https://skip.build/discord) and tell our customer support that you'd like an API key.
Please provide the following information in your request to help us get to know your project:
1. Your name (or pseudo-anon name) and contact info (ideally Telegram, but possibly Email, Signal, etc...)
2. Your project name
3. A brief, 1-2 sentence description of your project
The customer support team member at Skip will establish an official channel of communication between Skip and your project (e.g. an email thread or a telegram group etc...).
### 2. Store the API Key Securely
**You should store the API key immediately when you create it. We do not store your raw API key in our server for security reasons, so we will not be able to access it for you if you lose it.**
It is important to keep your API key private. Anyone with your API key can make requests to the Skip Go API as you, getting access to your rate limit, privileged features, and affecting your revenue and volume statistics.
## How to use an API key
### Via REST API
You should pass your API key in every call to the Skip Go API using the `authorization` HTTP header.
For example:
```
curl -X 'POST' \
'https://api.skip.build/v2/fungible/route' \
-H 'accept: application/json' \
-H 'authorization: ' \
-H 'Content-Type: application/json' \
-d '{
"amount_in": "1000000",
"source_asset_denom": "uusdc",
"source_asset_chain_id": "axelar-dojo-1",
"dest_asset_denom": "uatom",
"dest_asset_chain_id": "cosmoshub-4",
"cumulative_affiliate_fee_bps": "0",
"allow_multi_tx": true,
"client_id": "skip-api-docs"
}'
```
### Via `@skip-go/client`
For users of the `@skip-go/client` TypeScript package, the `apiKey` can be included in the `SkipClientOptions` object when constructing a `SkipClient`. After you include it in construction, the `SkipClient` will handle passing it in the `authorization` header of all requests.
For example:
```typescript
import { SkipClient, SKIP_API_URL } from "@skip-go/client";
const client = new SkipClient({
apiKey: ,
});
```
### Setup a Proxy to Receive Skip Go API Requests and Add the API Key
To keep your API key secure and private, we recommend that you proxy the API requests from the frontend to your own backend--where you can add your API key in the header before forwarding the request to the Skip Go API.
The snippets below show you how to use Next.js/Vercel for this kind of proxying. It only takes a moment to set up.
pages/api/skip/handler.[tsnext.config.js@skip-router.env](mailto:tsnext.config.js@skip-router.env)
```typescript
// This handler runs server-side in Vercel and receive requests from the frontend
// sent to APP_URL/api/skip
import type { NextApiRequest } from 'next';
import { PageConfig } from 'next';
import { API_URL } from '@/constants/api';
export const config: PageConfig = {
api: {
externalResolver: true,
bodyParser: false,
},
runtime: 'edge',
};
export default async function handler(req: NextApiRequest) {
try {
const splitter = '/api/skip/';
const [...args] = req.url!.split(splitter).pop()!.split('/');
const uri = [API_URL, ...args].join('/');
const headers = new Headers();
if (process.env.SKIP_API_KEY) {
headers.set('authorization', process.env.SKIP_API_KEY);
}
return fetch(uri, {
body: req.body,
method: req.method,
headers,
});
} catch (error) {
const data = JSON.stringify({ error });
return new Response(data, { status: 500 });
}
}
```
```typescript
// This config maps the requests to APP_URL/api/skip to the handler we just defined
rewrites: async () => [
{
source: "/api/skip/(.*)",
destination: "/api/skip/handler",
},
],
// other config...
```
```typescript
// This configures your router to make requests to your proxy service instead of
// the standard Skip Go API backend directly
import { SkipClient } from '@skip-go/client';
const appUrl =
process.env.NEXT_PUBLIC_VERCEL_ENV === 'preview' ||
process.env.NEXT_PUBLIC_VERCEL_ENV === 'staging'
? typeof window !== 'undefined'
? `https://${window.location.hostname}`
: process.env.NEXT_PUBLIC_VERCEL_URL
: 'https://';
const client = new SkipClient({
// you don't need to pass apiKey since you already have it in your proxy handler
apiURL: `${appUrl}/api/skip`,
});
```
```
// These are environment variables you set in Vercel
// to store your API key securely in the backend
SKIP_API_KEY=
```
## How to Request Volume & Revenue Statistics
Just return to your official communication channel with Skip (probably a Telegram channel) and request the data. We can share monthly reports. Eventually, we will create a customer portal with dashboards, so you'll have access to all the data you need in a self-service manner.
**Have questions or feedback? Help us get better!**
Join [our Discord](https://skip.build/discord) and select the "Skip Go Developer" role to share your questions and feedback.
# FAQ
### General / Background
#### How can I get help using Skip Go?
You can reach us easily at [support@skip.build](mailto:support@skip.build) or in [our developer support channel on Telegram](https://t.me/+3y5biSyZRPIwZWIx)
#### Who uses Skip Go?
Many teams use Skip Go to make it easier for them to build multi-chain flows, including:
* Every major interchain wallet (Keplr, Leap, IBC wallet, Terra Station, all the metamask snap teams)
* Osmosis asset deposit page
* Many major interchain dapps (e.g. Stargaze, Stride, Astroport, Cosmos Millions)
* Many interchain defi frontends (e.g. Coinhall, fortytwo.money)
* TrustWallet
* Our own frontend ([https://go.skip.build](https://go.skip.build))
* ...and many more
#### How many chains does Skip Go API support?
More than 70+. We support:
* Almost every IBC-enabled chain
* Every EVM chain Axelar supports
* Every EVM chain and rollup Hyperlane supports
* Every chain CCTP supports
...with more coming soon!
#### Which bridges and message passing protocols does Skip Go support?
* IBC
* Hyperlane
* Axelar
* CCTP
* Neutron's native bridge
...with more coming soon!
#### What DEXes does the Skip Go support?
* Osmosis
* Astroport across Terra, Neutron, Sei, and Injective
* White Whale across Terra, Migaloo, and Chihuahua
...with many more coming soon
#### How do I get Skip Go API to support my chain?
Please see the [Chain Support Requirements](/support-requirements/chain-support-requirements) document to ensure your chain meets the necessary requirements and submit the chain support request form linked in that doc.
#### How do I get the Skip Go API to support my token?
Please complete the necessary steps detailed in the [Token & Route Support Requirements](/support-requirements/token-support-requirements) doc.
#### How do I get the Skip Go API to support a route for a particular token to a remote chain?
Please complete the necessary steps detailed in the [Token & Route Support Requirements](/support-requirements/token-support-requirements) doc for the destination chain and token in question.
#### How do I get the Skip Go API to route swaps to my swap venue or DEX?
Please see the [Swap Venue Requirements](/support-requirements/swap-venue-requirements) page to ensure your DEX meets the necessary requirements then submit the swap venue request form linked in that doc.
#### How long does it take to build an application with Skip Go?
15-30 minutes
#### Why do I keep getting rate limited?
You need to request an API key from the core team to use Skip Go without limitations.
Pass your API key into all requests with the `client_id` parameter.
#### Does the Skip Go API cost anything?
No, not at this time. We offer unlimited usage at zero cost.
In the future we will introduce two pricing plans:
1. **Fee revenue sharing, unlimited usage**: For customers who use Skip Go API's fee functionality to charge their end-users fees on swaps, we will collect a portion of the fee revenue that you earn. Higher volume users will unlock lower fee tiers.
2. **API Usage Pricing**: For customers who do not charge fees, we will offer monthly and annual plans that allow usage of the API up to some number of requests per month. We will offer several pricing tiers, where higher tiers support higher rate limits and more monthly requests (similar to coingecko, infura, etc..)
#### I have questions, comments, or concerns about Skip Go. How can I get in touch with you?
Join [our Discord](https://skip.build/discord) and select the "Skip Go Developer" role to share your questions and feedback.
### Refunds and other financial policies
#### Does Skip ever refund users for swaps or transfers with "bad prices"?
**No.**
Users are responsible for the transactions they sign in all cases:
1. **If our smart contracts behave as expected (i.e. amount\_out exceeds min\_amount\_out signed by the user or amount\_in is less than max\_amount\_in signed), Skip will not offer users refunds, slippage rebates, or any other form of compensation for any reason**. Skip does not accept or bare any financial, legal, or practical responsibility for lost funds in the event a user or integrator believes a particular route is inadequate, bad, supoptimal, low liquidity, or otherwise not performant enough.
2. **If the smart contracts Skip Go depends on do not behave as expected, users who encounter and suffer bugs may report them in exchange for a bug bounty payment**. See the section on our bug bounty policy below.
Integrators are solely and completely responsible for building UIs that maximally protect users from harming themselves by swapping or transferring at unfavorable prices. To help facilitate this goal, we provide:
* Detailed information about quote quality, on-chain liquidity, fees, and price estimates in our API response objects (e.g. estimates of the USD value of amount in and amount out, on-chain price impact, etc...)
* Extensive guidance about how to build S.A.F.E. interfaces in our docs: [SAFE Swapping: How to protect users from harming themselves](/advanced-swapping/safe-swapping-how-to-protect-users-from-harming-themselves)
* Hands-on interface design feedback based on years of working with dozens of top interfaces
#### Does Skip provide refunds to users if an interface created an transaction that called a Skip contract incorrectly?
**No**
1. If an integrator or end user misuses one of our contracts intentionally or by accident (e.g. calls the contract with incorrect call data, sends tokens to a contract not designed to receive tokens), Skip bares no financial, legal, or operational responsibility for funds that may be lost as a result.
2. Skip and its affiliates do not have the ability to upgrade contracts to receive or "unstick" lost funds even if we wanted to. We do not own or control the contracts in Skip Go any more than you do.
#### Are there any circumstances under which Skip would offer a refund to an end user for any reason?
**No**
Skip accepts no legal, financial, or operational responsibility for the applications the integrators of the Skip Go API create using its data and services. Skip also accepts no legal, financial, or operational responsibility for the positive or negative financial outcomes of the swaps, transfers, and other transactions that end users may create in these interfaces.
Even in the event a user lost funds as a result of a bug, Skip does not claim any legal, financial, or practical liability for lost funds. In these cases, users may report the bug to Skip's bug bounty program.
### Bug Bounty Policy
#### Does Skip Go offer bug bounties?
Skip may provide a financial bug bounty of up to \$25,000 as compensation to users who report a reproducible catastrophic failure of a smart contract or other piece of software that the Skip team developed. Examples of catastrophic failures include:
* Receiving fewer tokens in the output of a swap than specified and signed over in the min\_amount\_out field of the transaction calldata
* Total loss of funds resulting from a transaction where the call data is correctly formed -- in other words, where the contract call data matches the specification provided by the Skip team and generated by the Skip Go API product
The size of the bug payment is determined at Skip's sole discretion. It may depend on a variety of factors, including: quality, accuracy, and timeliness of the report & severity/exploitability of the bug. Skip is not legally obligated to provide any payment amount.
In the event a user lost funds as a result of a bug, Skip does not claim any legal, financial, or practical liability for lost funds. The size of the bug bounty will not depend directly or indirectly on the amount of funds the user lost. The bug bounty does not constitute a refund under any definition. It is a reward for identifying and characterizing gross failures in intended behavior of the Skip software.
#### How do I report a bug to the bug bounty program?
Please get in touch with our team at [support@skip.build](mailto:support@skip.build) if you believe you have a bug to report.
### Technical Support
#### Is go.skip.build open source? Where can I find the code?
* Yes! The code for go.skip.build -- our multi-chain DEX aggregator + swapping/transferring interface is open source
* You can find the code at [https://github.com/skip-mev/skip-go-app](https://github.com/skip-mev/skip-go-app) -- Feel free to use it to guide your own integration
#### Where is the OpenAPI Swagger?
You can find the Swagger page here: [https://api-swagger.skip.build](https://api-swagger.skip.build). And you can find the OpenAPI generating doc here: [https://api-swagger.skip.build/swagger.yml](https://api-swagger.skip.build/swagger.yml).
#### What's the default IBC-Transfer timeout on the messages returned by `/fungible/msgs` and `/fungible/msgs_direct`?
* 5 minutes
#### What technologies does Skip Go use under the hood?
* IBC and...
* `ibc-hooks`: Enables the Skip Go swap contracts to be executed as callbacks of IBC transfers, which enables constructing transactions that can transfer tokens to a chain with a swap venue, perform a swap, and transfer them out -- without multiple signing events / transactions.
* Skip Go will likely not support DEXes on any chains that do not have `ibc-hooks` or equivalent functionality
* `Packet-forward-middleware`(PFM): Enables incoming IBC transfers from one chain to atomically initiate outgoing transfers to other chains. This allows the chain with PFM to function as the intermediate chain on a multi-hop route. This is especially valuable for chains that issue assets for use throughout the interchain (e.g. Stride + stATOM, Noble + USDC, Axelar + axlUSDC)
* (This [article we wrote](https://ideas.skip.build/t/how-to-give-ibc-superpowers/81) goes into more detail about both technologies and how to adopt them on your chain)
* [Axelar](https://axelar.network/): A cross-chain messaging protocol that supports a wide variety of EVM chains and connects to Cosmos
* [CCTP](https://www.circle.com/en/cross-chain-transfer-protocol): A cross-chain messaging protocol built by Circle (the issuer of USDC) to move USDC between chains without trusting any parties other than Circle (which USDC users already trust implicitly)
* [Hyperlane](https://www.hyperlane.xyz/): A cross-chain messaging protocol that allows developers to deploy permissionlessly and choose their own security module
* [Go Fast](https://skip-protocol.notion.site/EXT-Skip-Go-Fast-b30bc47ecc114871bc856184633b504b): A decentralized bridging protocol that enables faster-than-finality cross-chain actions across EVM and Cosmos
#### How do affiliate fees work?
* Affiliate fees are fees developers using Skip Go charge their end-users on swaps. We support multiple parties taking and sharing fees. For example, if a defi frontend uses the widget a wallet team builds and distributes, the makers of the widget and the users of the widget can separately charge affiliate fees.
* Fees are calculated in basis points or "bps". One basis point equals one one-hundredth of a percent. So 100 bps = 1% fee
* **Affiliate fees are calculated based off the minimum amount out and are taken/denominated in the output token.** For example, consider an ATOM to OSMO swap where min amount out is 10 uosmo and the cumulative fees are 1000 bps or 10%. If the swap successfully executes, the affiliate fee will be 1 uosmo. It will be 1 uosmo regardless of whether the user actually gets 10, 11, or 12 uosmo out of the swap.
* **When performing a swap with an exact amount in, affiliate fees are accounted for in the `amount_out` returned by `/route`**. More plainly, the Skip Go API subtracts off expected affiliate fees prior to the `amount_out` calculation, so that it represents an accurate estimate of what the user will receive at the end of the swap, net of fees. To be exact, the user will probably receive more than the amount out because the actual fee is not known at the time of this calculation / estimate. It's not known until later when slippage is set. So the user will end up paying `slippage_percent`\*`amount_out` less than the API predicts. This is good for the user because the estimated amount out will likely be lower than the actual amount they receive, offering a buffer that protects the user from the effects of slippage.
#### Why does `/assets_from_source` only return assets that are reachable via transfers but not swaps?
We're considering adding support for swappable destinations to `/assets_from_source`, but we're not prioritizing it because almost every asset is reachable via swapping from every other asset. So for 99.99% of use cases, this endpoint would just return a massive amount of fairly uninformative data, if we added destinations reachable via swaps.
#### Why does the Skip Go API sometimes say a route doesn't exist when it should (e.g. transferring ATOM to Stargaze)?
There are two common reasons Skip Go API is missing a route that a user thinks might exist:
1. **No one has ever used it:** By default, the Skip Go API does not recommend channels that have never been used or denoms that it has not seen. For example, if no one has transferred Neutron to Stargaze, the Skip Go API will not recommend a route to do so -- even if a direct connection exists between the two chains.
2. **Expired clients:** Frequently, existing connections between chains expire when they're not used for a period of time that exceeds the "light client trusting period. The Skip Go API indexes all chains every couple of hours to identify these cases and prevent users from accidentally attempting transfers.
*A common gotcha:* `/assets_from_source` only returns assets reachable in a single transaction by default. If you'd like to have access to routes that require multiple transactions, set the `allow_multi_tx` flag to `true` in the input.
#### How long does relaying an IBC packet take?
It depends on many factors, including how many relayers are covering a particular channel, block times, the time-to-finality of the source chain, whether relayers are live, how many packets relayers are waiting to batch together, and much more...
**In short, it can range from several seconds to minutes (or never) in the worst case.** After a timeout window, a packet won't be valid on the destination chain when it gets relayed. This timeout is set to 5 minutes for all packets created via the Skip Go API. It's important to understand what happens to user tokens in the event of timeouts. You can read about that in [Cross-chain Failure Cases](../advanced-transfer/handling-cross-chain-failure-cases)
For now, we recommend making a small warning or disclaimer to users on your application, similar to the following:
> This swap contains at least one IBC transfer.
>
> IBC transfers usually take 10-30 seconds, depending on block times + how quickly relayers ferry packets. But relayers frequently crash or fail to relay packets for hours or days on some chains (especially chains with low IBC volume).
>
> At this time, \[OUR APPLICATION]does not relay packets itself, so your swap/transfer may hang in an incomplete state. If this happens, your funds are stuck, not lost. They will be returned to you once a relayer comes back online and informs the source chain that the packet has timed out. Timeouts are set to 5 minutes but relayers may take longer to come online and process the timeout.
#### Why is the time to relay a packet so variable? And why can IBC relaying be unreliable today?
IBC relayers do not receive payments for relaying user packets or for relaying light client updates. In fact, they have to pay gas for the every packet they relay. That means relaying is strictly a charitable, money-losing operation with fixed infrastructure costs from running nodes + the relayer process, as well as variable costs from user gas.
#### How long does it take to transfer between Cosmos and EVM ecosystem?
In general, transfers take as long as it takes for the source chain to "finalize". That means:
* Transfers originating on EVM chains will take 30 minutes or more. The reason is that most EVM chains take a long time (30+ minutes) to finalize, which means the bridges we rely on do not register the tokens on the source chain as "locked" in the bridge for at least that long.
* Transfers originating on Cosmos chains will finish in less than 30 seconds usually (barring IBC relayer failures) because Cosmos chains have "fast" or "single slot finality". Almost as soon as the block that contains your transfer gets created, its included irreversibly in the chain
#### If Skip doesn't charge fees, how come some simple transfers seem to have a fee taken out of them?
This happens because many of the bridges (which Skip rely on) take fees to pay for gas and the cost of operating their protocol.
```ts entrypointsignAmino
import { TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx";
const txRaw = await signAmino(
client,
signer as OfflineAminoSigner,
msgJSON.sender,
[
{
typeUrl: multiHopMsg.msg_type_url,
value: msg.value,
},
],
{
amount: [coin(0, feeInfo.denom)],
gas: `${simulatedGas * 1.2}`,
},
"",
{
accountNumber: acc?.accountNumber ?? 0,
sequence: acc?.sequence ?? 0,
chainId: multiHopMsg.chain_id,
}
);
const txBytes = TxRaw.encode(txRaw).finish();
tx = await client.broadcastTx(txBytes, undefined, undefined);
```
```ts
async function signAmino(
client: SigningStargateClient,
signer: OfflineAminoSigner,
signerAddress: string,
messages: readonly EncodeObject[],
fee: StdFee,
memo: string,
{ accountNumber, sequence, chainId }: SignerData
) {
const aminoTypes = new AminoTypes(createDefaultAminoConverters());
const accountFromSigner = (await signer.getAccounts()).find(
(account) => account.address === signerAddress
);
if (!accountFromSigner) {
throw new Error("Failed to retrieve account from signer");
}
const pubkey = encodePubkey(encodeSecp256k1Pubkey(accountFromSigner.pubkey));
const signMode = SignMode.SIGN_MODE_LEGACY_AMINO_JSON;
const msgs = messages.map((msg) => aminoTypes.toAmino(msg));
msgs[0].value.memo = messages[0].value.memo;
const signDoc = makeSignDoc(
msgs,
fee,
chainId,
memo,
accountNumber,
sequence
);
const { signature, signed } = await signer.signAmino(signerAddress, signDoc);
const signedTxBody = {
messages: signed.msgs.map((msg) => aminoTypes.fromAmino(msg)),
memo: signed.memo,
};
signedTxBody.messages[0].value.memo = messages[0].value.memo;
const signedTxBodyEncodeObject: TxBodyEncodeObject = {
typeUrl: "/cosmos.tx.v1beta1.TxBody",
value: signedTxBody,
};
const signedTxBodyBytes = client.registry.encode(signedTxBodyEncodeObject);
const signedGasLimit = Int53.fromString(signed.fee.gas).toNumber();
const signedSequence = Int53.fromString(signed.sequence).toNumber();
const signedAuthInfoBytes = makeAuthInfoBytes(
[{ pubkey, sequence: signedSequence }],
signed.fee.amount,
signedGasLimit,
signed.fee.granter,
signed.fee.payer,
signMode
);
return TxRaw.fromPartial({
bodyBytes: signedTxBodyBytes,
authInfoBytes: signedAuthInfoBytes,
signatures: [fromBase64(signature.signature)],
});
}
```
#### How should I set gas prices for Cosmos transactions?
We recommend setting Cosmos chain gas prices using the chainapsis keplr-chain-registry: [https://github.com/chainapsis/keplr-chain-registry](https://github.com/chainapsis/keplr-chain-registry). In our experience, this registry overestimates gas prices somewhat -- but this leads to a very good UX in Cosmos because:
* Transactions almost always make it on chain
* Gas prices are very cheap -- so overestimation is not costly
Soon, the Skip Go API will surface recommended gas price too, and we will release a client-side library that will abstract away this area of concern.
#### How should I set gas amount for Cosmos transactions?
We recommend using the [Gas and Fee Tooling](/client/balance-gas-and-fee-tooling) available in the [Skip Go Client TypeScript Package](https://www.npmjs.com/package/@skip-go/client).
#### What does it mean when the docs say an endpoint is in "ALPHA" or "BETA"?
This means we may make breaking changes to them at any time.
#### What does `cumulative_fee_bps` in `/route` mean?
This is where you specify the fee amount in bps aka "bips". (1 bp = 1 / 100th of a percent; 100 bps = 1%)
By specifying it in route, the Skip Go API can adjust the quote that it gives back to you, so that it shows output token estimate net of fees. This ensures the amount the end user gets out of the swap always aligns with their expectations.
The parameter uses the word "cumulative" (i.e. summing over a set) because the API supports multiple partners charging affiliate fees. This parameter should be set to the sum of all of those component fees. (For example, if a widget provider charges a 5 bp fee, and the frontend developer integrating that widget charges a 10 bp fee, `cumulative_fee_bps=15`)
### Misc
#### Is Skip doing anything to make IBC relaying more reliable?
* In the short term, we are adding real time data about relayer + channel health to Skip Go API, so we can accurately predict how long it will take to relay a packet over a channel + the packet tracking + relaying into the API.
* In the medium term, we're going to enable multi-chain relaying through Skip Go API. This will be a paid service.
* In the long term, we're working to build better incentives for relaying, so relayers don't need to run as charities. (Relayers do not receive fees or payment of any kind today and subsidize gas for users cross-chain)
# Getting Fee Info
Understand how Skip Go handles user-facing fees
## Background
This doc describes functionality in Skip Go for accessing standardized information about the various fees that a user can incur while swapping or transferring. Common fees include:
* Affiliate fees (e.g. fees you charge the user for swapping on your frontend)
* Bridge and relayer fees
* Smart Relayer fees
* Gas fees
## Understanding incurred fees from all sources: `estimated_fees`
`estimated_fees` in the response of `/route` and `/msgs_direct` provides a `Fee` array where each entry gives information about a particular fee.
Each `Fee` object in the array will have the following attributes:
* `fee_type`: Enum giving the kind of fee — `SMART_RELAY` , `SWAP` , `BRIDGE`, `RELAY` , `GAS`
* `bridge_id` : If the fee is a relayer fee (`RELAY`) or a bridge fee (`BRIDGE`), this gives the ID of the bridge charging the fee (or the bridge where the relayer is providing a service)
* `amount` : The amount of the fee (expressed in the token the fee will be charged in)
* `usd_amount`: Estimated USD value of the fee
* `origin_asset` : An `Asset` object containing useful metadata for displaying and identifying the token in which the fee is denominated
* `chain_id` : Chain ID where the fee will be collected
* `denom` : Denom of the token in which the fee is denominated
* `tx_index`: The zero-indexed identifier of the transaction where the user will incur this fee (For multi-transaction routes, fees may be incurred after the first transaction)
* `operation_index`: The zero-indexed entry in the operations array where the user will incur this fee
**Development in Progress - Only a subset of fees supported today**
For now, only the Smart Relay fee will appear in the `estimated_fees` array.
We will add other kinds of fees (e.g. swap fees, bridge fees, public relayer fees) over time. For now, these can be found in the `operations` field attached to the `operation` where they're incurred.
**Have questions or feedback? Help us get better!**
Join [our Discord](https://skip.build/discord) and select the "Skip Go Developer" role to share your questions and feedback.
# Introduction
This pages explains what the Skip Go API is, gives examples of applications built with it, and provides guidance on standard ways to use it.

## 👋 Introduction
Welcome to the Skip Go API docs!
**Skip Go API is an end-to-end interoperability platform that enables developers to create seamless cross-chain experiences for their end users with a variety of underlying DEXes and cross-chain messaging protocols, including IBC, CCTP, Hyperlane, and Axelar. We're on a mission to make all interop dead easy for developers and their users!**
Unlike most aggregators, Skip Go API is based around the idea of composing many underlying bridging and swapping operations to create multi-hop routes that can connect any two chains and tokens in a single transaction. The goal is to help developers build interfaces where users can teleport any token to any chain from wherever they might be.
We’ve designed it so that even developers who are completely new to interoperability and have never worked with any of the bridges or DEXes we use can build applications and frontends that feel magical and offer:
* Any-to-any cross-chain swaps with built-in cross-chain DEX aggregation under the hood (e.g. Swap OSMO on Neutron for ARCH on Archway in a single transaction)
* Onboarding to a sovereign chain from an origin chain or token in any ecosystem (e.g. Onboard to Sei from ETH on Blast)
* Unified bridge-and-act flows (e.g. Transfer and buy an NFT in a single transaction)
* Multi-hop cross-chain transfers with automatic denom & path recommendations for any asset and chain (e.g. Get the most liquid version of ATOM on Terra2)
* Composite bridging paths that use multiple underlying bridges for different stages of the path (e.g. Transfer USDC from Base to Injective over CCTP and IBC behind the scenes)
* Real-time cross-chain workflow tracking, along with gas + completion timing estimates
* Protection from common cross-chain UX failures (e.g. bridging to a chain where the end user doesn’t have gas)\
... and much more
Skip Go API includes several different endpoint types which allow developers to choose their level of abstraction and build a wide variety of cross-chain applications. These include:
* **High-level endpoints** that return fully-formed messages and transactions
* **Low-level endpoints** that return detailed pathing data about all the "operations" that make up a route
* **Utility endpoints** for multi-chain transaction + packet submission, relaying, tracking, and simulation
**What does it cost?**
The Skip Go API is free to use and integrate with. You will have very limited access if you do not have an API key from us. Please join [our Discord](https://skip.build/discord) and request one.
## 3 Basic Ways to Use the Skip Go API
There are 3 ways to leverage Skip Go API to build cross-chain swapping & transferring experiences, depending on whether you're optimizing for control or for integration speed.
Use REST endpoints for low-level control over your interactions.
Use the TypeScript library to abstract the complexity of making HTTP calls and access related helper functionality.
Embed the Skip Go Widget in your frontend in a single line of code to launch with no developer effort.
# Transaction Tracking
This document covers the tooling provided in Skip Go for tracking transaction status across multiple chains and bridge hops.
## Background
The `/v2/tx` endpoints include unified APIs that broadcast transactions and provide insight into the status of transactions and their subsequent cross-chain actions.
You can use the `/v2/tx` endpoints to track the progress of a cross-chain transfer or swap in realtime -- no matter how many chains or bridges the transfer touches. (For more advanced use cases, the endpoints support tracking multiple distinct transfers initiated in a single transaction).
You can also use it to identify failure cases (e.g. a swap that fails due to slippage, an IBC transfer that fails due to inactive relayers) and determine where the user's tokens will become available.
For example, if one of your end users initiates a swap that begins with ATOM on Neutron and concludes with JUNO on Juno, you can use the lifecycle tracking to report when the ATOM moves from Neutron to the Hub, when it reaches Osmosis, and when the JUNO finally arrives safely on Juno.

## Basics
At a high-level, the transaction tracking works in two stages:
1. Inform our tracking engine that you want to track a particular transaction by submitting it to the chain via `/v2/tx/submit` or submitting it to your own Node RPC then calling `/v2/tx/track`
2. Query the transaction status at some regular interval to get updates on it's progress
**Tracking Multiple Independent Routes**
You can use the endpoint to track multiple transfers initiated in a single transaction, where the status of transfer `i` is given by entry `i` in the `transfers` array. For example, I could transfer ATOM to the Cosmos Hub and OSMO to Osmosis in a single transaction and track them with `transfers[0]` and `transfers[1]` respectively.
For a single transfer that has multiple hops (e.g. transferring ATOM to the Cosmos Hub then to Osmosis), you can track the status of each hop using the entries of `transfers[i].transfer_sequence`
The status endpoint provides a mixture of high-level fields to keep track of the basic progress of your route and low-level fields to provide high visbility into the individual transactions that make up a single transfer.
### Important high-level `/v2/tx/status` fields
Each entry in the `transfers` array corresponds to a single route that may contain many steps, and each entry in `transfer_sequence` will contain very detailed information about each step in that route.
But there a few high-level fields in each `transfers` entry that you'll find useful no matter what your route does or what bridges it involves:
* `state`: The basic status of your route. **This lets you report the basic state of the route to the user (e.g. in progress, failed, etc...)**
* `STATE_SUBMITTED`: Indicates the transaction has been accepted for tracking but no on chain evidence has been found yet.
* `STATE_ABANDONED`: Tracking has stopped after 30 minutes without progress. There is likely a relayer outage, an undetected out of gas error, or some other problem.
* `STATE_PENDING`: The route is in progress and no errors have occurred yet
* `STATE_PENDING_ERROR`: The route is in progress and an error has occurred somewhere, but the error is currently propagating, so the user doesn't have their tokens returned yet. (This state will only occur for protocols that require an *acknowledgement* on the source chain to process an error. IBC only at this time)
* `STATE_COMPLETED_SUCCESS`: The route has completed successfully and the user has their tokens on the destination (indicated by `transfer_asset_release`)
* `STATE_COMPLETED_ERROR`: The route errored somewhere and the user has their tokens unlocked in one of their wallets. Their tokens are either on the source chain, an intermediate chain, or the destination chain but in the wrong asset. ( `transfer_asset_release` indicates where the tokens are)
* `next_blocking_transfer`: Gives the index of the entry in `transfer_sequence` that corresponds to the currently propagating transfer that is immediately blocking the release of the user's tokens -- `next_blocking_transfer.transfer_sequence_index` (it could be propagating forward or it could be propagating an error ack backward). **This lets you tell the user exactly which operation is pending at a given time**
* `transfer_asset_release`: Info about where the users tokens will be released when the route completes. This populates on `STATE_PENDING_ERROR`, `STATE_COMPLETED_SUCCESS`, or `STATE_COMPLETED_ERROR`. **This lets you tell the user where to recover their funds in the event of a success or failure** *(If you want to better understand how to predict this or where funds might end up, see [Cross-chain Failure Cases](../advanced-transfer/handling-cross-chain-failure-cases))*
* `transfer_asset_release.released`: Boolean given whether the funds are currently available (if the state is`STATE_PENDING_ERROR` , this will be `false`)
* `transfer_asset_release.chain_id`: Chain where the assets are released or will be released
* `transfer_asset_release.denom`: Denom of the tokens the user will have
### Detailed Info: Using`transfer_sequence`
The `transfer_sequence` array consists of `TransferEvent` objects, which give detailed information about an individual transfer operation. The object acts as a wrapper around one details object for each bridge we support:
* `CCTPTransferInfo`
* `IBCTransferInfo`
* `AxelarTransferInfo`
* `HyperlaneTransferInfo`
* `GoFastTransferInfo`
* `StargateTransferInfo`
Each one contains slightly different data and statuses corresponding to the details of their bridge, but they all contain some standard info:
* `from_chain_id`
* `to_chain_id`
* Transactions and block explorer links for all of the significant events in the transfer (send tx, receive tx, and sometimes acknowledge tx)
* A status field giving the status of the transfer, which can vary based on bridge
#### IBC Transfer Data
The `state` field in the `IBCTransferInfo` entries in the `transfer_sequence` array have the following meanings:
* `TRANSFER_UNKNOWN`: The transfer state is unknown
* `TRANSFER_PENDING` - The send packet for the transfer has been committed and the transfer is pending
* `TRANSFER_PENDING_ERROR` - There has been a problem with the transfer (e.g. the packet has timed out) but the user doesn't have their funds unlocked yet because the error is still propagating
* `TRANSFER_RECEIVED`- The transfer packet has been received by the destination chain. It can still fail and revert if it is part of a multi-hop PFM transfer
* `TRANSFER_SUCCESS` - The transfer has been successfully completed and will not revert
* `TRANSFER_FAILURE` - The transfer
`packet_txs` contain transaction hashes, chain IDs, and block explorer links for up to 4 transactions:
* `send_tx`: The packet being sent from the source chain
* `receive_tx`: The packet being received on the destination chain
* `timeout_tx`: The packet being timed out on the destination chain
* `acknowledge_tx`: The successful or failed acknowledgement of the packet on the source chain
#### Axelar Transfer Data
When one of the transfers is an Axelar transfer, the `transfer_sequence` array will give an `axelar_transfer` (`AxelarTransferInfo`), instead of an `ibc_transfer`, which contains different data because:
* The Skip Go API may utilize send\_token or contract\_call\_with\_token (two underlying Axelar protocols) depending on which is cheaper and which is required to execute the user's intent
* Axelar does not have a notion of packets or acks, like IBC does
* Axelar provides a nice high level UI (Axelarscan) to track the status of their transfers
More precise details about all the fields are below:
* `type` : an enum of `AXELAR_TRANSFER_SEND_TOKEN` and `AXELAR_TRANSFER_CONTRACT_CALL_WITH_TOKEN` which indicate whether the Axelar transfer is a [Send Token](https://docs.axelar.dev/dev/send-tokens/overview) or a [Contract Call With Token](https://docs.axelar.dev/dev/general-message-passing/gmp-tokens-with-messages) transfer respectively.
* `axelar_scan_link`: Gives the link to Axelar's bridge explorer (which can help track down and unstick transactions)
* `state` field indicates the current state of the Axelar transfer using the following values:
* `AXELAR_TRANSFER_UNKNOWN` - The transfer state is unknown
* `AXELAR_TRANSFER_PENDING_CONFIRMATION` - The transfer has been initiated but is pending confirmation by the Axelar network
* `AXELAR_TRANSFER_PENDING_RECEIPT` - The transfer has been confirmed by the Axelar network and is pending receipt at the destination
* `AXELAR_TRANSFER_SUCCESS` - The transfer has been completed successfully and assets have been received at the destination
* `AXELAR_TRANSFER_FAILURE` - The transfer has failed
* `txs` field schema depends on the `type` of the transfer
* If `type` is `AXELAR_TRANSFER_SEND_TOKEN`, there are 3 txs:
* `send_tx` (initiating the transfer)
* `confirm_tx`(confirming the transfer on axelar)
* `execute_tx` (executing the transfer on the destination)
* If `type` is `AXELAR_TRANSFER_CONTRACT_CALL_WITH_TOKEN`:
* `send_tx` (initiating the transfer)
* `gas_paid_tx` (paying for the relayer gas on the source chain)
* `approve_tx` (approving the transaction on Axelar - only exists when the destination chain is an EVM chain)
* `confirm_tx`(confirming the transfer on Axelar - only exists when destination chain is a Cosmos chain)
* `execute_tx` (executing the transfer on the destination)
#### CCTP Transfer Data
When one of the transfers is a CCTP transfer, the `transfer_sequence` array will give a `cctp_transfer` (`CCTPTransferInfo`), instead of an `ibc_transfer`, which contains different data because:
* CCTP works by Circle attesting to & signing off on transfers
* There's no notion of an acknowledgement in CCTP
More precise details about the different/new fields are below:
* `state` gives the status of the CCTP transfer:
* `CCTP_TRANSFER_UNKNOWN` - Unknown error
* `CCTP_TRANSFER_SENT` - The burn transaction on the source chain has executed
* `CCTP_TRANSFER_PENDING_CONFIRMATION` - CCTP transfer is pending confirmation by the cctp attestation api
* `CCTP_TRANSFER_CONFIRMED` - CCTP transfer has been confirmed by the cctp attestation api but not yet received on the destination chain
* `CCTP_TRANSFER_RECEIVED` - CCTP transfer has been received at the destination chain
* `txs` contains the chain IDs, block explorer links, and hashes for two transactions:
* `send_tx`: The transaction submitted the CCTP burn action on the source chain to initiate the transfer
* `receive_tx`: The transaction on the destination chain where the user receives their funds
#### Hyperlane Transfer Data
When one of the transfers is a Hyperlane transfer, the `transfer_sequence` array will give a `hyperlane_transfer` (`HyperlaneTransferInfo`), instead of an `ibc_transfer`, which contains different data because:
* Hyperlane is a very flexible protocol where the notion of "approving/verifying" the transfer is undefined / up to the bridge developer to implement
* There's no notion of an acknowledgement in Hyperlane
More precise details about the different/new fields are below:
* `state` gives the status of the Hyperlane transfer:
* `HYPERLANE_TRANSFER_UNKNOWN` - Unknown error
* `HYPERLANE_TRANSFER_SENT` - The Hyperlane transfer transaction on the source chain has executed
* `HYPERLANE_TRANSFER_FAILED` - The Hyperlane transfer failed
* `HYPERLANE_TRANSFER_RECEIVED` - The Hyperlane transfer has been received at the destination chain
* `txs` contains the chain IDs, block explorer links, and hashes for two transactions:
* `send_tx`: The transaction submitted the CCTP burn action on the source chain to initiate the transfer
* `receive_tx`: The transaction on the destination chain where the user receives their funds
### OPInit Transfer Data
When one of the transfers is a OPInit transfer, the `transfer_sequence` array will give a `op_init_transfer` (`OPInitTransferInfo`), instead of an `ibc_transfer`, which contains different data because:
* The OPInit bridge is the Initia ecosystem's native bridging solution facilitating transfers between Initia and the Minitias.
* There's no notion of an acknowledgement in the OPInit bridge
More precise details about the different/new fields are below:
* `state` gives the status of the OPInit transfer:
* `OPINIT_TRANSFER_UNKNOWN` - Unknown error
* `OPINIT_TRANSFER_SENT` - The deposit transaction on the source chain has executed
* `OPINIT_TRANSFER_RECEIVED` - OPInit transfer has been received at the destination chain
* `txs` contains the chain IDs, block explorer links, and hashes for two transactions:
* `send_tx`: The transaction that submitted the OPInit deposit action on the source chain to initiate the transfer
* `receive_tx`: The transaction on the destination chain where the user receives their funds
### Go Fast Transfer Data
When one of the transfers is a `GoFastTransfer`, the `transfer_sequence` array will include a `go_fast_transfer` (`GoFastTransferInfo`). This field includes specific information about user-initiated intents and solver fulfillments, which require specific data fields to track the transfer process.
Below are detailed explanations of the different fields and their purposes:
* `from_chain_id`: The chain ID where the transfer originates (source chain).
* `to_chain_id`: The chain ID where the assets are being sent (destination chain).
* `state`: Indicates the current status of the transfer. Possible values are:
* `GO_FAST_TRANSFER_UNKNOWN`: An unknown error has occurred.
* `GO_FAST_TRANSFER_SENT`: The user's intent has been successfully submitted on the source chain.
* `GO_FAST_POST_ACTION_FAILED`: The transfer's post-intent action failed. For example a swap on the destination chain failed due to slippage.
* `GO_FAST_TRANSFER_TIMEOUT`: The transfer did not complete within the expected time frame.
* `GO_FAST_TRANSFER_FILLED`: The transfer was successfully fulfilled on the destination chain.
* `GO_FAST_TRANSFER_REFUNDED`: The user's assets have been refunded on the source chain.
* `txs`: Contains transaction details related to the GoFast transfer:
* `order_submitted_tx`: The transaction where the user called initiateIntent on the source chain.
* `order_filled_tx`: The transaction where the solver called fulfill on the destination chain.
* `order_refunded_tx`: The transaction where the user received a refund on the source chain, if applicable.
* `order_timeout_tx`: The transaction indicating a timeout occurred in the transfer process.
* `error_message`: A message describing the error that occurred during the transfer, if applicable.
When tracking a Go Fast transfer, you can use the `GoFastTransferInfo` to monitor the progress and status of your asset transfer between chains. For instance, if the state is `GO_FAST_TRANSFER_FILLED`, you know that the transfer was successful and your assets should be available on the destination chain. If the state is `GO_FAST_TRANSFER_TIMEOUT`, you can check the `orderTimeoutTx` for details on the timeout event.
### Stargate Transfer Data
When one of the transfers is a `StargateTransfer`, the `transfer_sequence` array will include a `stargate_transfer` (`StargateTransferInfo`). This provides detailed information about a cross-chain asset transfer powered by Stargate, a popular cross-chain bridging protocol.
Below are detailed explanations of the fields and their purposes:
* `from_chain_id`: The chain ID where the transfer originates (source chain).
* `to_chain_id`: The chain ID where the assets are being sent (destination chain).
* `state`: Indicates the current status of the Stargate transfer. Possible values are:
* `STARGATE_TRANSFER_UNKNOWN`: An unknown error has occurred or the state cannot be determined.
* `STARGATE_TRANSFER_SENT`: The transfer has been successfully initiated on the source chain (i.e., the assets have left the source chain and are in transit).
* `STARGATE_TRANSFER_RECEIVED`: The transfer has been successfully completed on the destination chain (i.e., the assets are now available at the recipient address on the destination chain).
* `STARGATE_TRANSFER_FAILED`: The transfer encountered an error during bridging and did not complete as intended.
* `txs`: Contains transaction details related to the Stargate transfer.
* `send_tx`: The transaction on the source chain that initiated the Stargate transfer.
* `receive_tx`: The transaction on the destination chain where the assets were received.
* `error_tx`: A transaction (if any) related to the failure of the transfer.
When monitoring a Stargate transfer, you can use `StargateTransferInfo` to confirm that your assets have safely bridged between chains or identify if and where a problem has occurred.
The Go Fast Protocol involves interactions with solvers who fulfill transfer intents. The additional transaction fields help provide transparency and traceability throughout the transfer process, ensuring users can track each step and identify any issues that may arise.
## Detailed Example of Typical Usage
This will walk through an example of how a developer would use the api to track the progress of a route that may include multiple
In this particular example, we'll cover a simple 2-hop IBC transfer from axelar to the cosmoshub through osmosis.
*Usage is similar for tracking Axelar transfers or transfers that include multiple hops over distinct bridges but the data structures change slightly depending on what underlying bridge is being used*
### 1. Call `/tx/submit` to broadcast a transaction
Post a signed user transaction (that you can form using `/fungible` endpoints) to the `/submit` endpoint. The Skip Go API will handle the broadcasting of this transaction and asynchronously begin tracking the status of this transaction and any subsequent transfers.
A successful response looks like the following:
```JSON
{
"tx_hash": "AAEA76709215A808AF6D7FC2B8FBB8746BC1F196E46FFAE84B79C6F6CD0A79C9"
}
```
It indicates that the transaction was accepted by the Skip Go API and its status can be tracked using the returned `tx_hash`.
The transaction is broadcast using `BROADCAST_MODE_SYNC` and in the event that a transaction is rejected by the node, the `/submit` endpoint will return a 400 response along with the failure reason as shown below:
```JSON
{
"code": 3,
"message": "insufficient fees; got: 0uosmo which converts to 0uosmo. required: 2000uosmo: insufficient fee",
"details": []
}
```
**Tracking a transaction that was not broadcast using `/submit`**
If a transaction was not broadcast through the `/submit` endpoint and has already landed on chain, the `/track` endpoint can be used to initiate tracking of the transaction's progress.
### 2. Call `/status` to query the status of the transaction and IBC transfer progress
Skip Go API continually indexes chain state to determine the state of the transaction and the subsequent IBC transfer progress. This information can be queried using the `/status` endpoint.
It will initially yield a response that looks like the following:
* There's a top-level `transfers` field, which gives an array where each entry corresponds to a **single sequence of transfers**. This does not mean there's one entry in the `transfers` field for every bridging operation. In general, one `transfer` could consist of an arbitrarily long sequence of swaps and transfers over potentially multiple bridges. `transfers` is an array because one transaction can initiate potentially several distinct and independent transfers (e.g. transferring OSMO to Osmosis and ATOM to the Hub) in the same tx.
* The `state` field will give `STATE_SUBMITTED` indicating the transaction has been accepted for tracking by the Skip Go API but no events have been indexed yet:
```JSON
{
"transfers": [
{
"state": "STATE_SUBMITTED",
"transfer_sequence": [],
"next_blocking_transfer": null,
"transfer_asset_release": null,
"error": null
}
]
}
```
Once indexing for the transaction has begun, the `state` will change to `STATE_PENDING`.
* The status of any transfers along the transfer sequence will be returned in the `transfer_sequence` field as shown in the example response below.
* The entries in the `transfer_sequence` correspond to transfers and will be represented by different objects depending on which bridge is being used (e.g. Axelar or IBC).
* The `next_blocking_transfer` field gives some information about the next blocking transfer in the`transfer_sequence` field.
* The `transfer_sequence_index` indicates which transfer in the `transfer_sequence` field is blocking progress.
* The `transfer_asset_release` field will be populated with information about the asset release as it is becomes known.
* The `chain_id` and `denom` fields indicate the location and asset being released.
* The `released` field indicates whether the assets are accessible. The `transfer_asset_release` field may become populated in advance of asset release if it can be determined with certainty where the eventual release will be. This will happen for example in a transfer sequence that is a PFM-enabled sequence of IBC transfers when one hop fails due to packet timeout or an acknowledgement failure. The transfer sequence will revert and the `transfer_asset_release` field will indicate that the assets will be released on the initial chain.
```JSON
{
"transfers": [
{
"state": "STATE_PENDING",
"transfer_sequence": [
{
"ibc_transfer": {
"from_chain_id": "axelar_dojo-1",
"to_chain_id": "osmosis-1",
"state": "TRANSFER_PENDING",
"packet": {
"send_tx": {
"chain_id": "axelar-dojo-1",
"tx_hash": "AAEA76709215A808AF6D7FC2B8FBB8746BC1F196E46FFAE84B79C6F6CD0A79C9",
"explorer_link": "https://www.mintscan.io/axelar/transactions/AAEA76709215A808AF6D7FC2B8FBB8746BC1F196E46FFAE84B79C6F6CD0A79C9"
},
"receive_tx": null,
"acknowledge_tx": null,
"timeout_tx": null,
"error": null
}
}
}
],
"next_blocking_transfer": {
"transfer_sequence_index": 0
},
"transfer_asset_release": null,
"error": null
}
]
}
```
The transfer assets will be released before all expected acknowledgements have been indexed. When the transfer sequence has reached this state, the `status` will be updated to `STATE_RECEIVED` as shown in the example response below. Note that `transfer_asset_release` now indicates the chain ID of the chain where the assets are released and the denomination of the released assets.
```JSON
{
"transfers": [
{
"state": "STATE_COMPLETED_SUCCESS",
"transfer_sequence": [
{
"ibc_transfer": {
"from_chain_id": "axelar_dojo-1",
"to_chain_id": "osmosis-1",
"state": "TRANSFER_PENDING",
"packet": {
"send_tx": {
"chain_id": "axelar-dojo-1",
"tx_hash": "AAEA76709215A808AF6D7FC2B8FBB8746BC1F196E46FFAE84B79C6F6CD0A79C9",
"explorer_link": "https://www.mintscan.io/axelar/transactions/AAEA76709215A808AF6D7FC2B8FBB8746BC1F196E46FFAE84B79C6F6CD0A79C9"
},
"receive_tx": {
"chain_id": "osmosis-1",
"tx_hash": "082A6C8024998EC277C2B90BFDDB323CCA506C24A6730C658B9B6DC653198E3D",
"explorer_link": "https://www.mintscan.io/osmosis/transactions/082A6C8024998EC277C2B90BFDDB323CCA506C24A6730C658B9B6DC653198E3D"
},
"acknowledge_tx": null,
"timeout_tx": null,
"error": null
}
}
},
{
"ibc_transfer": {
"from_chain_id": "osmosis-1",
"to_chain_id": "cosmoshub-4",
"state": "TRANSFER_SUCCESS",
"packet": {
"send_tx": {
"chain_id": "osmosis-1",
"tx_hash": "082A6C8024998EC277C2B90BFDDB323CCA506C24A6730C658B9B6DC653198E3D",
"explorer_link": "https://www.mintscan.io/osmosis/transactions/082A6C8024998EC277C2B90BFDDB323CCA506C24A6730C658B9B6DC653198E3D"
},
"receive_tx": {
"chain_id": "cosmoshub-4",
"tx_hash": "913E2542EBFEF2E885C19DD9C4F8ECB6ADAFFE59D60BB108FAD94FBABF9C5671",
"explorer_link": "https://www.mintscan.io/cosmos/transactions/913E2542EBFEF2E885C19DD9C4F8ECB6ADAFFE59D60BB108FAD94FBABF9C5671"
},
"acknowledge_tx": null,
"timeout_tx": null,
"error": null
}
}
}
],
"next_blocking_transfer": null,
"transfer_asset_release": {
"chain_id": "cosmoshub-4",
"denom": "uatom",
"released": true
},
"error": null
}
]
}
```
Once it has been determined that all packets along the transfer sequence have either been acknowledged or timed out, `state` will be updated to `STATE_COMPLETED_SUCCESS` as shown in the example response below. Note that `next_blocking_transfer` is now null since the transfer is complete.
```JSON
{
"transfers": [
{
"state": "STATE_COMPLETED_SUCCESS",
"transfer_sequence": [
{
"ibc_transfer": {
"from_chain_id": "axelar_dojo-1",
"to_chain_id": "osmosis-1",
"state": "TRANSFER_SUCCESS",
"packet": {
"send_tx": {
"chain_id": "axelar-dojo-1",
"tx_hash": "AAEA76709215A808AF6D7FC2B8FBB8746BC1F196E46FFAE84B79C6F6CD0A79C9",
"explorer_link": "https://www.mintscan.io/axelar/transactions/AAEA76709215A808AF6D7FC2B8FBB8746BC1F196E46FFAE84B79C6F6CD0A79C9"
},
"receive_tx": {
"chain_id": "osmosis-1",
"tx_hash": "082A6C8024998EC277C2B90BFDDB323CCA506C24A6730C658B9B6DC653198E3D",
"explorer_link": "https://www.mintscan.io/osmosis/transactions/082A6C8024998EC277C2B90BFDDB323CCA506C24A6730C658B9B6DC653198E3D"
},
"acknowledge_tx": {
"chain_id": "axelar-dojo-1",
"tx_hash": "C9A36F94A5B2CA9C7ABF20402561E46FD8B80EBAC4F0D5B7C01F978E34285CCA",
"explorer_link": "https://www.mintscan.io/axelar/transactions/C9A36F94A5B2CA9C7ABF20402561E46FD8B80EBAC4F0D5B7C01F978E34285CCA"
},
"timeout_tx": null,
"error": null
}
}
},
{
"ibc_transfer": {
"from_chain_id": "osmosis-1",
"to_chain_id": "cosmoshub-4",
"state": "TRANSFER_SUCCESS",
"packet": {
"send_tx": {
"chain_id": "osmosis-1",
"tx_hash": "082A6C8024998EC277C2B90BFDDB323CCA506C24A6730C658B9B6DC653198E3D",
"explorer_link": "https://www.mintscan.io/osmosis/transactions/082A6C8024998EC277C2B90BFDDB323CCA506C24A6730C658B9B6DC653198E3D"
},
"receive_tx": {
"chain_id": "cosmoshub-4",
"tx_hash": "913E2542EBFEF2E885C19DD9C4F8ECB6ADAFFE59D60BB108FAD94FBABF9C5671",
"explorer_link": "https://www.mintscan.io/cosmos/transactions/913E2542EBFEF2E885C19DD9C4F8ECB6ADAFFE59D60BB108FAD94FBABF9C5671"
},
"acknowledge_tx": {
"chain_id": "osmosis-1",
"tx_hash": "1EDB2886E6FD59D6B9C096FBADB1A52585745694F4DFEE3A3CD3FF0153307EBC",
"explorer_link": "https://www.mintscan.io/osmosis/transactions/1EDB2886E6FD59D6B9C096FBADB1A52585745694F4DFEE3A3CD3FF0153307EBC"
},
"timeout_tx": null,
"error": null
}
}
}
],
"next_blocking_transfer": null,
"transfer_asset_release": {
"chain_id": "cosmoshub-4",
"denom": "uatom",
"released": true
},
"error": null
}
]
}
```
Any packet acknowledgement errors will be surfaced in the error field for the relevant packet as follows:
```JSON
{
"transfers": [
{
"state": "STATE_COMPLETED_ERROR",
"transfer_sequence": [
{
"ibc_transfer": {
"from_chain_id": "osmosis-1",
"to_chain_id": "cosmoshub-4",
"state": "TRANSFER_FAILED",
"packet": {
"send_tx": {
"chain_id": "osmosis-1",
"tx_hash": "112714A8144019161CAAA8317016505A9A1DDF5DA7B146320A640814DDFA41C0",
"explorer_link": "https://www.mintscan.io/osmosis/transactions/112714A8144019161CAAA8317016505A9A1DDF5DA7B146320A640814DDFA41C0"
},
"receive_tx": {
"chain_id": "cosmoshub-4",
"tx_hash": "E7FB2152D8EA58D7F377D6E8DC4172C99791346214387B65676A723FCFC7C980",
"explorer_link": "https://www.mintscan.io/osmosis/cosmos/E7FB2152D8EA58D7F377D6E8DC4172C99791346214387B65676A723FCFC7C98"
},
"acknowledge_tx": {
"chain_id": "osmosis-1",
"tx_hash": "8C9C1FA55E73CD03F04813B51C697C1D98E326E1C71AB568A2D23BF8AEAFFEC7",
"explorer_link": "https://www.mintscan.io/osmosis/transactions/8C9C1FA55E73CD03F04813B51C697C1D98E326E1C71AB568A2D23BF8AEAFFEC7"
},
"timeout_tx": null,
"error": {
"code": 1,
"message": "ABCI code: 1: error handling packet: see events for details"
}
}
}
}
],
"next_blocking_transfer": null,
"transfer_asset_release": {
"chain_id": "osmosis-1",
"denom": "uosmo",
"released": true
},
"error": null
}
]
}
```
Any execution errors for the initial transaction will be surfaced in the error field at the top level of the response as follows:
```JSON
{
"transfers": [
{
"state": "STATE_COMPLETED_ERROR",
"transfer_sequence": [],
"next_blocking_transfer": null,
"transfer_asset_release": null,
"error": {
"code": 11,
"message": "out of gas in location: Loading CosmWasm module: sudo; gasWanted: 200000, gasUsed: 259553: out of gas"
}
}
]
}
```
# Overview & Common Usage Patterns
## Summary
This doc provides a high-level overview of the different kinds of methods available in the Skip Go API & describes how integrators typically use them in combination to create a cross-chain swapping frontend like [go.skip.build](https://go.skip.build).
See the [API reference](/api-reference/prod) for more information on each endpoint.
## Overview of Methods
### `/info` methods: Functionality for Retrieving General Purpose Info
The `/info` endpoints & their counterparts in `SkipClient` provide general purpose metadata about the chains and bridges that the Skip Go API supports.
The most important `info` methods include:
* `/v2/info/chains` (`SkipClient.chains`): Get info about all supported chains, including capabilities, address type, logo, etc...
* `/v2/info/bridges`: Get basic info about all supported bridges, including logo and name
### `/fungible` methods: Functionality for fungible token swaps and transfers
The `/v2/fungible` endpoints & their counterparts in `SkipClient` provide APIs for cross-chain swaps and transfers of fungible tokens.
In the background, the API provides automatic DEX aggregation, bridge routing, denom recommendation, and relaying for all actions.
The most important `fungible` methods include :
* `/v2/fungible/route` (`SkipClient.route`): Get a swap/transfer route and quote between a pair of tokens & chains. You can customize this request significantly to only consider particular DEXes, bridges; to add route splitting for better prices; and much more.
* `/v2/fungible/msgs` (`SkipClient.msgs` ): Generates the transaction data for the transaction(s) the user must sign to execute a given route
* `/v2/fungible/msgs_direct` (`SkipClient.msgsDirect`) : Generates a route, quote, and associated transaction data at the same time
* `/v2/fungible/venues`(`SkipClient.venues`): Get metadata for all supported swapping venues (DEXes, liquid staking protocols, etc...), including name and logo.
(There are many other providing more specific functionality for power users. See API docs for more details.)
### `/tx` methods: Functionality for Tracking Inflight transactions
The `/v2/tx` endpoints & their counterparts in `SkipClient` provide functionality for submitting transactions and tracking the status of cross-chain transactions with a unified interface across all underlying hops & bridge types.
The most important `tx` methods include:
* `/v2/tx/submit`(`SkipClient.submitTransaction`): Submits a transaction on chain through Skip's nodes and registers the transaction for tracking with Skip Go API *(Recommended especially for Solana and other high congestion networks where successfully submitting a transaction can be tricky)*
* `/v2/tx/track`(`SkipClient.trackTransaction`): Registers a transaction for tracking with Skip Go API (Often used instead of `/submit` when an integrator has their own chain nodes for submitting)
* `/v2/tx/status` (`SkipClient.transactionStatus`) : Get the current status of a multi-hop transaction
[`/tx` API reference](https://docs.skip.build/go/api-reference/prod/transaction/post-v2txsubmit)
## Typical Usage in Cross-chain Swapping Frontend
On a cross-chain swapping and transferring frontend, integrators typically:
1. Use the `info` methods to populate the list of potential starting & ending chains & assets

2. Use `/fungible/route` (`SkipClient.route`) to get a quote when the user selects all their chains & tokens and inputs one of their amounts

3. Use `/fungible/msgs` (`SkipClient.msgs`) to get a transaction for the user to sign after they've locked in the route & begun the transaction creation process

4. Use `/tx/track`(`SkipClient.trackTransaction`) to register the transaction for tracking (or `/tx/submit` to register and submit it on-chain)
5. Use `/status` (`SkipClient.transactionStatus`) to get the real-time status of the transaction as it progresses across bridges and/or chains.

# Post-Route Actions
How to specify actions to perform after a route of transfers/swaps is completed
Use the `post_route_handler` parameter of `/v2/fungible/msgs` endpoint to define actions that will be executed on the destination chain after a route transfer or swap is completed. These actions are executed within the same transaction as the original swap or transfer.
This handler allows developers to build omni-chain and omni-token workflows where users can swap, liquid stake, deposit, buy an NFT, or take any other action starting from any chain or any token in Cosmos -- all in a single transaction.
This parameter currently supports:
1. CosmWasm contract calls on the destination chain
2. `autopilot` support for liquid staking interactions on Stride
### Background Info
All `post_route` actions must have the following characteristics:
* **Permissionless:** Skip Go can only support permissionless actions because the underlying protocols (e.g. ibc-hooks, packet-forward-middleware) derive the addresses they use to call contracts based on the origin of the transfer. This means one user originating on two different chains or starting with two different tokens will eventually call the final contract / module with different addresses. You can only reliably permission actions that you know will 1) always originate on the same chain and 2) always take the same path to the destination chain. In general, we recommend not making this assumption unless you are an interoperability expert
* **Single-token input:** The underlying IBC transfer protocol (ICS-20) doesn't support transfers of more than 1 token denom in a single transfer message, so we can only send 1 token denom to the final contract or module at a time. This means the contract or module in the `post_route_handler` must not require multiple token denoms sent to it simultaneously. For example, a classic LP action where the user must provide tokens in both sides of the pool simultaneously would not work.
**Use authority-delegation with local address for permissionless actions that enable permissioned follow-ups**
Commonly, the first interaction with a contract is permissionless, but it awards the end-user some kind of permissioned authority to perform follow-on actions (e.g. staking enables unstaking + collecting rewards; depositing enables withdrawing and earning yield) or receipt tokens (e.g. LPing produces LP receipt tokens).
As a cross-chain caller, you should generally avoid contracts that implicitly delegate these authorities or give receipt tokens to the caller because the caller will depend on the path the user has taken over IBC. You should look for contracts to imply authority delegation -- i.e. contracts that explicitly assign permissions to an address in the calldata that may be different than the caller and address sending the tokens. Examples of this pattern are:
* Astroport’s `receiver` parameter in the `provide_liquidity` message
* Mars’ `on_behalf_of` parameter in the `deposit` message
* Astroport’s `to` parameter in the `swap` message
We recommend setting these authority delegation parameters to the user's local address on the destination chain, so they can perform future actions locally.
### CosmWasm
To call a CosmWasm contract on the destination chain, the following requirements must be satisfied:
1. The destination chain supports CosmWasm & `ibc-hooks`.
2. The chain in the route immediately before the destination chain supports IBC memos as well as `packet-forward-middleware`.
To specify a CosmWasm contract call on the destination chain, pass a `wasm_msg` as the `post_route_handler` in the `/v2/fungible/msgs` call with:
* `contract_address`: The target contract address
* `msg`: JSON string of the message to pass to the contract
In addition, set the destination address in the `address_list` to the address of the contract.
For example, this is a request for a transfer of USDC from Axelar to Neutron, with a post-route handler that swaps the USDC to Neutron using an Astroport pool on Neutron:
```json
{
"source_asset_denom": "uusdc",
"source_asset_chain_id": "axelar-dojo-1",
"dest_asset_denom": "ibc/F082B65C88E4B6D5EF1DB243CDA1D331D002759E938A0F5CD3FFDC5D53B3E349",
"dest_asset_chain_id": "neutron-1",
"amount_in": "1000000",
"amount_out": "1000000",
"address_list": [
"axelar1x8ad0zyw52mvndh7hlnafrg0gt284ga7u3rez0",
"neutron1l3gtxnwjuy65rzk63k352d52ad0f2sh89kgrqwczgt56jc8nmc3qh5kag3"
],
"operations": [
{
"transfer": {
"port": "transfer",
"channel": "channel-78",
"chain_id": "axelar-dojo-1",
"pfm_enabled": false,
"dest_denom": "ibc/F082B65C88E4B6D5EF1DB243CDA1D331D002759E938A0F5CD3FFDC5D53B3E349",
"supports_memo": true
}
}
],
"post_route_handler": {
"wasm_msg": {
"contract_address": "neutron1l3gtxnwjuy65rzk63k352d52ad0f2sh89kgrqwczgt56jc8nmc3qh5kag3",
"msg": "{\"swap\":{\"offer_asset\":{\"info\":{\"native_token\":{\"denom\":\"ibc/F082B65C88E4B6D5EF1DB243CDA1D331D002759E938A0F5CD3FFDC5D53B3E349\"}},\"amount\":\"10000\"},\"to\":\"neutron1x8ad0zyw52mvndh7hlnafrg0gt284ga7uqunnf\"}}"
}
}
}
```
Note that the last address provided in the `address_list` is the address of the pool contract on Neutron, rather than a user address.
The message returned from this request uses `ibc-hooks` on Neutron to perform the CosmWasm contract call atomically with the IBC transfer.
### Autopilot
To use Autopilot after route actions, the following requirements must be satisfied:
1. The destination chain supports the `autopilot` module. Currently, this means the destination chain must be `stride-1`.
2. The chain in the route immediately before the destination chain supports IBC memos as well as `packet-forward-middleware`.
To specify an Autopilot action on the destination chain, pass a `autopilot_msg` as the `post_route_handler` in the `/v2/fungible/msgs` call with:
* `receiver`: Set to the address on behalf of which you're performing the action
* `action`: An enum giving the action that you wish to execute
* This may be one of `LIQUID_STAKE` (for liquid staking an asset) or `CLAIM` for updating airdrop claim addresses.
For example, this is a request for a transfer of ATOM from Cosmos Hub to Stride, with a post-route handler that atomically liquid stakes the transferred ATOM on Stride, sending stATOM to the specific receiver on Stride:
```json
{
"source_asset_denom": "uatom",
"source_asset_chain_id": "cosmoshub-4",
"dest_asset_denom": "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2",
"dest_asset_chain_id": "stride-1",
"amount_in": "1000000",
"amount_out": "1000000",
"address_list": [
"cosmos1x8ad0zyw52mvndh7hlnafrg0gt284ga7cl43fw",
"stride1x8ad0zyw52mvndh7hlnafrg0gt284ga7m54daz"
],
"operations": [
{
"transfer": {
"port": "transfer",
"channel": "channel-391",
"chain_id": "cosmoshub-4",
"pfm_enabled": true,
"dest_denom": "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2",
"supports_memo": true
}
}
],
"post_route_handler": {
"autopilot_msg": {
"receiver": "stride1x8ad0zyw52mvndh7hlnafrg0gt284ga7m54daz",
"action": "LIQUID_STAKE"
}
}
}
```
**Have questions or feedback? Help us get better!**
Join [our Discord](https://skip.build/discord) and select the "Skip Go Developer" role to share your questions and feedback.
# Quickstart Guide
This guide walks you through the process of setting up and using the Skip Go Client to perform a cross-chain from USDC on Noble to TIA on Celestia.
For a more in-depth guide, check out our [detailed walkthrough](../client/getting-started), which covers both Solana and EVM transactions. You can also explore more about [EVM Transactions](/advanced-transfer/evm-transactions) or dive into the specifics of [SVM Transactions](/advanced-transfer/svm-transaction-details).
## Prerequisites
* Browser environment setup with **Keplr** installed (`create-next-app` is recommended)
* **Node.js** and **npm**
Install the library using npm or yarn:
```Shell npm
npm install @skip-go/client
```
```Shell yarn
yarn add @skip-go/client
```
To start integrating with the Skip Go API, initialize a `SkipClient` instance. This `skipClient` provides helper methods for common actions such as querying assets and chains, constructing routes, and executing transactions.
```ts
import { SkipClient } from "@skip-go/client";
const skipClient = new SkipClient({
getCosmosSigner = async (chainID: string) => {
const key = await window.keplr?.getKey(chainID);
if (!key) throw new Error("Keplr not installed or chain not added");
return key.isNanoLedger
? window.keplr?.getOfflineSignerOnlyAmino(chainID)
: window.keplr?.getOfflineSigner(chainID);
};
});
```
Now, we can use the `SkipClient.route` function to request a quote and route to swap USDC on Noble to TIA on Celestia.
```ts
const route = await skipClient.route({
sourceAssetDenom: 'uusdc',
sourceAssetChainID: 'noble-1',
destAssetDenom: 'utia',
destAssetChainID: 'celestia',
amountIn: '1000000', // 1 uusdc
smartRelay: true
});
```
**Understanding the Route Response**
The route response contains important information about the swap process:
* **`amountOut`**: The estimated amount the user will receive after the swap, net of all fees and price impact
* **`requiredChainAddresses`**: Chain IDs where you need to provide user addresses when generating the transaction
* **`operations`**: Steps involved in moving from the source to the destination token
For more details, see the [/route](/api-reference/prod/fungible/post-v2fungibleroute) endpoint reference.
After generating a route, you need to provide user addresses for the required chains. The `route.requiredChainAddresses` array lists the chain IDs for which addresses are needed.
**Only use addresses your user can sign for.**
Funds could get stuck in any address you provide, including intermediate chains in certain failure conditions. Ensure your user can sign for each address you provide.
See [Cross-chain Failure Cases](../advanced-transfer/handling-cross-chain-failure-cases) for more details.
We recommend storing the user's addresses and creating a function like `getAddress` that retrieves the address based on the chain ID (see an example [here](https://github.com/skip-mev/skip-go-example/blob/c55d9208bb46fbf1a4934000e7ec4196d8ccdca4/pages/index.tsx#L99)).
```ts
// get user addresses for each requiredChainAddress to execute the route
const userAddresses = await Promise.all(
route.requiredChainAddresses.map(async (chainID) => ({
chainID,
address: await getAddress(chainID),
}))
);
```
**Never attempt to derive an address on one chain from an address on another chain**
Whenever you need a user address, please request it from the corresponding wallet or signer. Do not attempt to use bech32 cross-chain derivation.
If you attempt to derive an address on one chain from an address on another chain, you may derive an address that the user cannot actually sign for if the two chains have different address-derivation processes. For example, if you derive a Cosmos address from an Ethereum address, you will get an address that the user cannot sign for and thus risk lost tokens.
Once you have a route, you can execute it in a single function call by passing in the route, the user addresses for at least the chains the route includes, and optional callback functions. This also registers the transaction for tracking.
```ts
await skipClient.executeRoute({
route,
userAddresses,
// Executes after all of the operations triggered by a user's signature complete.
onTransactionCompleted: async (chainID, txHash, status) => {
console.log(
`Route completed with tx hash: ${txHash} & status: ${status.state}`
);
},
onTransactionBroadcast: async ({ txHash, chainID }) => {
console.log(`Transaction broadcasted with tx hash: ${txHash}`);
},
onTransactionTracked: async ({ txHash, chainID }) => {
console.log(`Transaction tracked with tx hash: ${txHash}`);
},
});
```
Once the transaction is complete, you'll have new TIA in your Celestia address!
# Smart Relay
This page covers Smart Relay -- Skip Go API's universal cross-chain data & token delivery service
This document introduces Skip Go API’s Smart Relay functionality — the fastest & most reliable way to get your users where they’re going over any bridge supported by Skip Go. Smart Relay is an alternative to public bridge relayers. It's designed to enable users to access more swap and transfer routes in fewer transactions with greater speed and reliability.
**We strongly advise all integrators who want to offer top-notch user experiences to activate Smart Relay.**
**If you do not use Smart Relay, your performance will suffer:**
* Many routes will not be available (e.g. Bridging Solana to Base, Solana to any Cosmos chain)
* Many routes will require more transactions (e.g. Bridging USDC from Ethereum to Osmosis will require 2 transactions, instead of 1)
* Transfers will get stuck more frequently
You turn it on simply by setting `smart_relay=true` in `/msgs_direct` or `/route`.
This document covers:
* What Smart Relay is
* The bridges Smart Relay supports today (& whats next)
* How to use Smart Relay
* The factors that affect the price of Smart Relay
**What is relaying?**
In general, relaying refers to the act of executing a cross-chain message/action by constructing the cross-chain proofs and submitting the burn/mint/wrap/ack proof transactions to the destination & source chains that are required to deliver the message.
All bridges and general message passing protocols (IBC, Axelar, Wormhole, CCTP, etc…) have some notion of relaying but sometimes it goes by different names.
## Background
Smart Relay is a **intent-aware**, **user-centric**, **universal** relayer with better performance guarantees than public relayers for all bridges and routes we support. We offer it at a small cost to the end-user and no cost to the developer/integrator. In short, Smart Relay helps users get to more destinations, in fewer transactions, and at faster speeds than via public relayers — no matter how many bridges or chains stand between them and their destination.
Smart Relay is huge improvement over existing relaying systems, made possible by intelligent integration with Skip Go's routing capabilities.:
* **Intent-aware**: Traditional relayers are unaware of what the user is trying to accomplish beyond the first hop of a transfer, but usually transfers are a part of a broader sequence of swaps, transfers, and actions. Smart Relayer has the context of the user's end-to-end cross-chain intent, and it can use this information to optimize its execution plan.
* For example, Smart Relay can reduce the number of transactions a user must sign in a route by automatically triggering the second bridge in a route when delivering the packet for the first bridge (e.g. Triggering IBC from CCTP).
* It can also use this information to prepare the user's destination address to receive the transfer (e.g. Dust it with gas even if there's no way to perform an atomic swap, or initialize a token account on Solana, etc...).
* **User-centric**: Traditional relayers are focused on specific "channels" or "bridges," simply transferring all packets for a single bridge route from one chain to another. Once that task is complete, they consider their job done. In contrast, Smart Relayers prioritize the user, not the bridge. Instead of clearing packets on one bridge at a time, they transfer all packets associated with a specific user across multiple bridges or hops, ensuring the user reaches their destination efficiently.
* It also offers a deeply simplified payment experience for users that's designed for multi-hop: pay once in the source chain, in the token you're transferring, and receive high quality relaying at every leg of the route thereafter.
* **Universal**: Traditional relayers only support 1 or 2 chains or ecosystems at a time for a single bridge, making cross-ecosystem transfers fraught. Many routes have no relayers or just spotty coverage. Smart Relay was designed to support all ecosystems and all bridges from the start. It already supports EVM, Solana/SVM, Cosmos, and modular -- with more chains, bridges, and routes routinely added.
The cost of Smart Relay is determined dynamically based on the factors covered below. The gas prices and bridge fees involved in a route are the principal determinants of that cost.
## State of Smart Relay
Today, Smart Relay supports:
* CCTP
We are currently building out support for:
* IBC
* Hyperlane
* Axelar
For the bridges that Smart Relay does not support today, Skip Go uses public or enshrined relayers — at whatever cost they’re typically made available to users. (These are free for IBC and have some fee associated with them for others). All costs users will incur will always be made transparent in the relevant endpoint responses.
## How to Use Smart Relay
### How to activate Smart Relay
1. On `/route` or `/msgs_direct`, pass `smart_relay=true`
2. If using `/msgs`, ensure that you are passing the `smart_relay_fee_quote` object provided in the `cctp_transfer` operation from the `/route` response into your `/msgs` request.
* If you're using the @skip-go/client library, version 0.8.0 and above supports this automatically. If you're integrating the API directly and decoding the `/route` response operations before passing them back into `msgs`, simply ensure you're decoding this new field properly and passing it back through!
3. Sign the transaction as usual, and submit the signed transaction to the Skip Go API via `/track` or `/submit` as normal
* **NOTE: We HIGHLY recommend using `/submit` to submit Smart Relay transactions on chain to avoid issues incurred by submitting a transaction on chain but not sending it to the `/track` endpoint.**
That’s it! Smart Relay will take care of executing your cross-chain actions across all bridges it currently supports.
### How to determine what Smart Relay will cost the user
In the response to `/route` , `/msgs_direct` and `/msgs`, the cost of Smart Relay will appear in the `estimated_fees` array with `fee_type` set to `SMART_RELAY`. See [Getting Fee Info](./fee-info) for more info about `estimated_fees`
For multi-tx routes, the user may pay up to 1 Smart Relay fee per transaction.
The fee for each transaction pays for all Smart Relay operations in that particular transaction. This prevents Smart Relay from accepting payment prematurely to perform operations for the latter transactions, since the latter transactions may not get signed or executed.
You can use the `tx_index` attribute on the `estimated_fees` entries to identify which Smart Relay fee corresponds to which transaction in the route. (e.g. `tx_index=0` indicates this is the fee for the first transaction in the route)
### What Determines the Cost of Smart Relaying
Smart Relay incurs a user cost because Smart Relay involves actually submitting transactions to various chains and incurring transaction fees as a result.
* **Operations**: The cost of relaying a route depends on the operations in the route, since these affect the amount of gas Smart Relay consumes (e.g. routes that include swaps will require higher gas amounts & involve more expensive relaying)
* **The cost of gas:** Most networks have dynamic fee markets, where the price of gas increases during periods of high network load. Smart Relay takes this into account when generating a quote
* **Token Exchange Rates:** The token the user pays their fee in and the token Smart Relaying pays gas fees in may differ, so exchange rates affect the price the end user experiences. (e.g. If the user pays in OSMO for a route that terminates on Ethereum mainnet, Smart Relay will need to pay fees in ETH, so the amount of OSMO the user pays will depend on the OSMO/ETH spot price.)
### How to properly use the Smart Relay Fee Quote
Skip Go dynamically calculates the Smart Relay fee to be paid based on the underlying costs in real-time.
Although you should use the information in the `estimated_fees` array for display purposes, `cctp_transfer` includes a `smart_relay_fee_quote`, providing necessary information for proper use of the dynamic relaying fee system. Specifically, the `smart_relay_fee_quote` object contains information about the smart relay fee to be paid and when the quote expires (after which the quoted amount may no longer be valid and the transaction may not be succesfully relayed).
If you're using the `/msgs` endpoint, ensure that you are passing the `smart_relay_fee_quote` object provided in the `cctp_transfer` operation from the `/route` response into your `/msgs` request. This is necessary to ensure the transaction generated by the API matches the fee quoted in the `/route` request. If the quote is not passed back into the `/msgs` request, a new quote will be generated in the `/msgs` call that may be different than what was quoted previously in the `/route` request. Version `0.8.0` and above of the `@skip-go/client` library supports this automatically. If you're integrating the API directly and decoding the `/route` response operations before passing them back into `/msgs`, simply ensure you're decoding this new field properly and passing it back through! See the `SmartRelayFeeQuote` below:
```text TypeScript
export type SmartRelayFeeQuote = {
feeAmount: string;
feeDenom: string;
feePaymentAddress: string;
relayerAddress: string;
expiration: Date;
}
```
```JSON JSON
{
"smart_relay_fee_quote": {
"fee_amount": "100000", // string
"fee_denom": "uusdc", // string
"fee_payment_address": "0x123", // string
"relayer_address": "0x123", // string
"expiration": "2024-08-30T05:28:05Z" // string
}
}
```
# Supported Ecosystems
**Activate Smart Relay (`smart_relay=true`) for global coverage of all chains, bridges, and routes**
There are many routes that will return a RouteNotFound error if `smart_relay=false` because there are not public relayers that support them. This includes all routes to and from Solana, as well as CCTP routes to and from Polygon, Base, and several other L2s.
As a result, if you want your users to be able to transfer their tokens over all routes, we recommend using [Smart Relay](/general/smart-relay).
Skip Go API is a universal interoperability platform. It can be used to swap and transfer tokens within and between all major ecosystems in crypto over many major bridges. We're constantly adding new bridges, new chains, new routes on already-supported bridges, and new multi-hop routes by composing multiple bridges together.
This document gives a high level overview of the different ecosystems and bridges Skip Go API supports, including how to onboard assets into each ecosystem, when different bridges are used, and what DEXes are supported.
For each major ecosystem, this document identifies:
* The bridges over which Skip Go API can route users into and out of the ecosystem
* The bridges over which Skip Go API can route users within the ecosystem
* The DEXes where Skip Go API can swap within the ecosystem
The very short summary is that our Cosmos ecosystem support is most mature, followed by Ethereum, followed by Solana.
## Cosmos Support Details
**Onboard and offboard via**:
* Axelar (Move major tokens to Ethereum, Polygon, Avalanche, and ETH L2s)
* CCTP (Move USDC to all major Ethereum L2s, Polygon, Avalanche, and Solana)
* Hyperlane (Move TIA to ETH L2s and sovereign rollups)
* Go Fast (Move assets at faster-than-finality speeds)
**Move within the ecosystem via:**
* IBC
**Swap within the ecosystem on:**
* Osmosis
* Astroport (on 3+ chains)
* White Whale (on 3+ chains)
* InitiaDEX
* Astrovault (on Archway)
* Dojoswap (on Injective)
* Helix (on Injective)
## Ethereum Support Details
**Never attempt to derive Cosmos Addresses from Ethereum Addresses (or vice versa)**
Whenever you need an address on a chain for a user, please request it from the corresponding wallet.
If you attempt to derive an address on one chain from an address on another chain, you may derive an address that the user cannot actually sign for if the two chains have different address-derivation processes. For example, if you derive a Cosmos address from an Ethereum address, you will get an address that the user cannot sign for or use.
So don't ever try to derive one address from another -- even for intermediate addresses. (Intermediate addresses may be used for fund recovery if there is some kind of failure on an intermediate chain. Failures could include a timeout, a swap exceeding slippage tolerance, or any other unexpected execution path. We assume users can sign for intermediate addresses, even if they shouldn't have to.)
**Onboard and offboard via:**
* CCTP (Move USDC to/from Cosmos and Solana)
* Axelar (Move ETH, MATIC, ARB, and other major tokens to/from Cosmos)
* Hyperlane (Move ETH to sovereign rollups)
* Go Fast (Move assets at faster-than-finality speeds)
**Move within ecosystem via:**
* Axelar (Move major assets among all major ETH L2s, Polygon, and Avalanche)
**Skip Go API does not support swapping on any DEXes within the Ethereum ecosystem at this time**
## Solana Support Details
**Onboard and offboard via:**
* CCTP (Move USDC to/from Cosmos and Ethereum Eco)
**Move within ecosystem via:**
* NA -- Solana is just 1 chain
**Skip Go API does not support swapping on any DEXes within the Solana ecosystem at this time**
# Upcoming Features
This page highlights a few of the features we're cooking up 🧑🍳. Please get in touch with us if you'd like us to prioritize any of these or add something else to our roadmap
#### New bridges
* Wormhole
* Union
* Bifrost
* Synapse
* Initia's native bridge
#### More DEXes
We're currently adding support for:
* Kujira's native DEX
* Stride (conversions between TOKEN + stTOKEN)
**Have questions or feedback? Help us get better!**
Join [our Discord](https://skip.build/discord) and select the "Skip Go Developer" role to share your questions and feedback.
# Privacy Policy
**PRIVACY POLICY**
Last Revised: October 20, 2024
This Privacy Policy (“**Privacy Policy**”) explains how Skip Protocol, Inc. (“**we**,” “**our**,” or “**us**”) collects, uses and discloses information that we obtain about visitors (“**you**” and “**your**”) who access and use the skip.build website, together with all sub-domains, and any other websites that may be offered by us from time to time (the “**Website**”), the “Skip:Go” front-end user interface hosted by Skip at go.skip.build (the “**Interface**”), and any other web applications or software that may be offered by Skip from time to time (collectively, the “**Services**”).
By visiting the Website, Interface or using any other Services, you acknowledge and agree to this Privacy Policy and that your data (including Personal Information, as defined below) will be handled by us in accordance with this Privacy Policy. The Services may contain feeds or links to third-party websites, applications or services, such as user interfaces for decentralized exchanges, bridges or any other types of websites, applications or services. If you visit third-party websites, applications or services, any information collected is governed by the terms and conditions and privacy policies of such third-parties. This Privacy Policy does not apply to information collected through third-party websites, applications or services that you may access through the Services. We are not responsible for the content of third-party websites, and your use of such third-party websites is at your own risk.
This Privacy Policy applies globally. If you are a resident of the European Economic Area (“**EEA**”) or the United Kingdom (“**UK**”), please review the “Notice to Residents of the EEA and the UK” section below for important information about how we collect and use your Personal Information and your rights under the General Data Protection Regulation (“**GDPR**”) and the UK General Data Protection Regulation (“**UK GDPR**”).
Please review this Privacy Policy carefully. If you have any questions, please reach out via the “Contact Us” information provided below.
**Personal Information That We Collect**
We, and third parties working on our behalf, collect and process the Personal Information that you directly provide to us through the Services. We may also collect and process Personal Information that is provided to us from other sources. “Personal Information” includes any information that, alone or in combination with other information, can be used to identify you, such as a personal identifier (*e.g.*, name, phone number or email address), an identification number, online identifiers or inferences about your preferences. Personal Information does not include information that is de-identified or aggregated such that it cannot be used to identify individuals. Personal Information also includes “personal data,” as such term is defined under the GDPR or the UK GDPR.
We may collect the following Personal Information: name, email address, social media handles, digital wallet addresses, publicly available blockchain data and usage data about devices you use to access the Services, such as device manufacturer, operating system, browser information, domain name, location and internet protocol (“**IP**”) address (collectively, “**Automatically Collected Information**”). We may also collect other information, which may be publicly available, or that we may acquire through third-party sources.
**Personal Information Used and Disclosed to Third Parties**
We, or third parties on our behalf may, use the Personal Information, including Automatically Collected Information, that we have about you to enforce our Terms of Service and this Privacy Policy, to provide the Services, communicate with you regarding your requests, analyze Services usage, for marketing and advertising purposes, to operate our referral or incentive program, to detect fraud or misuse to comply with our legal or regulatory obligations, with your consent or otherwise for valid business purposes, to help us improve your experience with the Services, to enforce eligibility requirements and record IP addresses, browser types, internet service provider and usage metrics. We may sell or share your personal information, as such term is defined under data privacy laws, to third parties for advertising and marketing purposes, including to provide advertising relevant to you.
\
We may also share your Personal Information in the following circumstances:
* Designated Service Providers. We may share your Personal Information with companies that we contract with in order to provide the Services (“**Service Providers**”). For example, Service Providers may: (i) provide products or services to you on our behalf; (ii) create or maintain our networks, systems, databases or analytics; (iii) provide other general support; (iv) respond to inquiries; (v) provide marketing services and advertising relevant to you; (vi) monitor and analyze the use and functionality of our Services; and (vii) other relevant internal business operations and purposes. Information disclosed to third parties may include aggregated and/or de-identified information derived from your Personal Information. We may disclose Automatically Collected Information obtained from your use of the Services to our Service Providers.
* Affiliates. We may share your Personal Information with companies under common ownership and control of us, including our subsidiaries and affiliates.
* Legal or Regulatory Obligations. We may disclose your Personal Information if we believe that such disclosure is necessary to satisfy our legal or regulatory obligations. This may include: (i) to comply with the law or in response to a subpoena, court order, government request or other legal process; (ii) to produce relevant documents or information in connection with litigation, arbitration, mediation, adjudication, government or internal investigations or other legal or administrative proceedings; (iii) to protect the interests, rights, safety or property of us, or any of our subsidiaries, affiliates, employees or users of the Services; (iv) to monitor compliance with and enforce the Terms of Service; (v) to operate the systems that are designed to allow the Services to function properly; (vi) for internal research purposes or managing the use of our copyrighted materials; or (vii) if we reasonably believe that a disclosure is necessary.
* Business Transactions. In the event that we go through a business transition, such as a merger, acquisition by another company, reorganization or sale of a portion of its assets, some or all of your Personal Information may be transferred in connection with the proposed transaction.
* Consent. With your consent or at your direction, such as sharing with your representatives or third parties.
**Cookies and Other Data Collection Technologies**
We utilize cookies and other data collection technologies on our Services. A cookie is a small text file placed on your computer that helps us understand how you and our other visitors use the Services, to enhance the user experience through different features and functionality and to analyze and compile usage data. Personal Information collected by cookies may include your device’s IP address, browser type, operating system, computer platform, web pages viewed and/or the date and time of your visit. For example, we may use cookies to remember your preferences or settings. We may also use Software Development Kits (“**SDKs**”) on the Services for services related to on-ramping and maintenance of crypto wallets. SDKs are a collection of tools or libraries that we may use to add functionality to the Services.
Most browsers include tools to manage or disable cookies. You can visit the help function on most browsers to modify how your browser handles cookies. However, if you disable cookies, some features of the Services may not function properly.
Cookies can be categorized by how long they remain on your device. All cookies have expiration dates in them that determine how long they stay in your browser. There are two broad categories of duration:
Session Cookies. Session cookies are temporary cookies that exist only during an online session and are not stored on your computer or mobile device.
Persistent Cookies. Persistent cookies are those placed on your computer or mobile device for a pre-determined length of time when you visit our Website, Interface or otherwise access the Services. Persistent cookies remain on your device until deleted manually or automatically.
To assist us with the various uses and purposes described in this Privacy Policy, your Personal Information, including information collected by cookies or similar data collection technologies, may be aggregated, analyzed or linked to other information we have about you (including information from other online and offline sources). For example, we may use Service Providers to collect information about your use of the Services, such as pages viewed via the Website, to provide us reports about your use of the Services.
Global Privacy Control. The Global Privacy Control (“**GPC**”) is a method for individuals to opt-out of the sale or sharing of their personal information, as such term is described under applicable data protection laws, via a user-enabled privacy control that is available on certain internet browsers. Our systems are not configured to detect or respond to the GPC. You can learn more about the GPC [here](https://globalprivacycontrol.org/).
“Do Not Track” Signals. Some web browsers have “Do Not Track” or similar features that allow you to tell each website you visit that you do not want your activities on that website tracked. Currently, the Services do not respond to “Do Not Track” signals and will continue to collect information about you even if your browser’s “Do Not Track” functionality is activated. Please note that your selection of the “Do Not Track” option provided by your browser may not have any effect on our collection of cookie information.
**Notice to Residents of the EEA and the UK**
If you are a resident of the EEA or the UK, you have the rights under the GDPR or the UK GDPR. We are required to comply with the GDPR, the UK GDPR and applicable local laws with respect to certain Personal Information we collect. If you are a resident of the EEA or the UK, the GDPR and the UK GDPR provides you with certain rights and choices regarding your Personal Information and how you can exercise those rights. Please note that we do not collect Special Categories of Personal Information, as such term is defined under the GDPR and the UK GDPR.
Legal Bases for Processing Your Personal Information. We collect and process Personal Information for the following legal bases:
* We process your Personal Information with your valid, explicit consent.
* We process your Personal Information when necessary to perform our agreements with you.
* We process your Personal Information in pursuit of our legitimate interests. Examples of these legitimate interests include operation and improvement of the Services, personalization of content on the Services and made available via the Services, and protection from fraud or security threats.
* We process your Personal Information when necessary to ensure compliance with a legal obligation to which we are subject.
* We process your Personal Information to protection an individual’s vital interests.
**Your Rights With Respect To Personal Information.** Subject to certain conditions, if you are a resident of the EEA or UK and have submitted Personal Information to us, you have the right to access, correct, delete, or object to or restrict the use of certain Personal Information covered by this Privacy Policy. You may also have the right to request the following: a copy of your Personal Information in a structured, commonly used and machine-readable format and/or request that we transmit that Personal Information to a third party where this is technically feasible, and that we refrain from processing Personal Information. To honor any requests, we will take steps (and may need to collect information from you) to verify your identity. You can also designate an authorized agent to make a request on your behalf. If you use an authorized agent, please include written permission that you have designated that agent to make the request or proof of the agent’s power of attorney. We may follow up with you to verify your identity before processing your authorized agent’s request.
We will only use Personal Information provided in the verification process for identity verification purposes. Please note that if you exercise such rights, this may affect our ability to provide the Services to you. While we will make reasonable efforts to accommodate your request, we also reserve the right to impose certain restrictions and requirements on such requests or deny certain requests, to the extent allowed or required by applicable law. For inquiries about your Personal Information, please contact us through one of the methods listed in the “Contact Us” Section below. You have the right to lodge a complaint about the processing of your Personal Information with a supervisory authority.
Withdrawal of Consent. Where you have given us valid, explicit consent to collect, use and process your Personal Information, we will rely on your valid, explicit consent. In instances in which we have based our processing of your Personal Information on your consent, you have the right to withdraw your consent. To withdraw such consent, please contact us through the methods listed below. Please note that when you withdraw consent, we might not be able to provide you with the Services. In certain situations, we may continue to process your Personal Information after you have withdrawn consent and requested that we delete your Personal Information, if we have a legal basis to do so. For example, we may retain certain information if we need to do so to comply with a legal obligation or if it is necessary to do so to pursue our legitimate interest in keeping the Services safe and secure.
International Transfers of Personal Information. We are headquartered and operate in the United States. If you visit or use the Services, or contact us from outside the United States, please be advised that (i) any Personal Information you provide to us or that we automatically collect will be transferred to the United States; and (ii) by using or submitting Personal Information through the Services, you explicitly authorize the transfer to and subsequent processing in the United States, and other countries in which we operate, in accordance with this Privacy Policy. Please be advised that the United States and other countries may not offer the same privacy protections as the laws of the jurisdiction where you reside.
**Data Retention**
We retain Personal Information we collect as long as it is necessary and relevant to fulfill the purposes outlined in this Privacy Policy. Subject to applicable law, we may also retain Personal Information to resolve disputes, enforce any of our terms of service or engage in other actions permitted by applicable law.
**Children’s Privacy**
The Services are intended for users 18 years of age or older. You are not permitted to use the Services if you are younger than 18 years of age without parental or guardian consent. In accordance with applicable children’s data protection laws, we do not knowingly collect Personal Information from children under the age of 18. If we learn we have collected or received Personal Information from a child under 18 years of age without authorization, verification or parental consent, we will promptly delete that information.
**Security of Your Personal Information**
We maintain administrative, physical and technical safeguards designed to protect the Personal Information we collect and maintain. However, no data transmission over the internet is ever 100% secure. As a result, while we strive to protect your information, we cannot guarantee or warrant the security of any information you transmit via the Services.
**“Shine the Light” Law**
Under California Civil Code Section 1798.83, California residents are entitled to request and obtain from us once per calendar year information about when we share your Personal Information with third parties for those third parties’ own direct marketing purposes. To request this information, please contact us by email and indicate “California Shine the Light” in the subject line. In the past year, we have not shared Personal Information with third parties for those third parties’ own direct marketing purposes.
**Email Marketing**
We, or third parties on our behalf, may use your Personal Information to contact you with newsletters, marketing or promotional materials and other information that may be of interest to you. You may opt-out of receiving any, or all, of these communications from us by following the unsubscribe link or instructions provided in any email sent by us or on our behalf or by contacting us.
Your option not to receive marketing material shall not preclude us from: corresponding with you, by email or otherwise, regarding your relationship with us; accessing your Personal Information for our internal business purposes; or disclosing your Personal Information as described in this Privacy Policy for purposes other than sending you marketing materials.
**Notification of Changes**
We reserve the right to update, modify or change this Privacy Policy from time to time. If we make a material change to the way we intend to use your Personal Information, we will notify you by updating this Privacy Policy and modifying the date updated at the beginning of this Privacy Policy. We encourage you to review the Privacy Policy whenever you access the Services to stay informed about our privacy practices.
**Contact Us**
We seek to resolve any issues that you have with our privacy practices. If you have questions or complaints regarding this Privacy Policy, please contact us at through email at: [support@skip.money](mailto:support@skip.money) or by telephone at: [+1 (646) 258-3405](tel:6462583405). Please include “Privacy” in the subject line of your inquiry.
# Terms of Service
**TERMS OF SERVICE**
Last Revised: August 9, 2024
These Terms of Service (the “**Terms**”) constitute a legally binding agreement made between you (“**you**”), and Skip Protocol, Inc. (“**Skip**,” “**we**,” or “**us**”), concerning your access to and use of the skip.build website, together with all sub-domains, and any other websites that may be offered by Skip from time to time (the “**Website**”), the “Skip:Go” front-end user interface hosted by Skip at go.skip.build (the “**Interface**”), and any other web applications or software that may be offered by Skip from time to time (collectively, the “**Services**”). By accessing or using the Services, you agree that you have read, understand and accept all of the terms and conditions contained in the Terms. If you do not agree to all of the Terms, you may not access or use the Services.
**Amendment of the Terms**. We may amend or modify the Terms at any time by posting the revised version on the Website and/or providing a copy to you (“**Revised Terms**”). Such Revised Terms shall be effective as of the time the Revised Terms are posted on the Website. Your continued use of the Services after the posting of Revised Terms constitutes your acceptance of such Revised Terms. If you do not agree with any such revisions, your sole and exclusive remedy is to terminate your use of the Services.
**Technical Services Only**. THE SERVICES INCLUDE, AMONG OTHER THINGS, A WEB-BASED USER INTERFACE THAT ALLOWS USERS TO ENGAGE IN A VARIETY OF BLOCKCHAIN-BASED CRYPTO ASSET TRANSACTIONS VIA PERMISSIONLESS, PUBLIC BLOCKCHAINS AND BLOCKCHAIN-NATIVE DEVELOPER TOOLS. THE INTERFACE ENABLES USERS TO INTERACT DIRECTLY WITH ONCHAIN SMART CONTRACTS THAT FUNCTION DETERMINISTICALLY AND ARE NOT OPERATED OR CONTROLLED (WHETHER VIA ADMINISTRATIVE KEYS OR OTHERWISE) BY SKIP. SKIP IS NOT A BROKER, DEALER, EXCHANGE, INVESTMENT ADVISER, CUSTODIAN OR FINANCIAL SERVICE PROVIDER OF ANY KIND. WE DO NOT HAVE A FIDUCIARY RELATIONSHIP OR OBLIGATION TO YOU IN CONNECTION WITH THE SERVICES.
**Binding Arbitration; Class Action and Jury Trial Waiver**. PLEASE BE AWARE THAT SECTION 9 (DISPUTE RESOLUTION; AGREEMENT TO ARBITRATE) GOVERNS THE RESOLUTION OF DISPUTES BETWEEN YOU AND SKIP. SECTION 9 INCLUDES AN AGREEMENT TO ARBITRATE WHICH REQUIRES, WITH LIMITED EXCEPTIONS, THAT ALL DISPUTES BETWEEN YOU AND US SHALL BE RESOLVED BY BINDING AND FINAL ARBITRATION. SECTION 9 ALSO CONTAINS A CLASS ACTION AND JURY TRIAL WAIVER. PLEASE READ SECTION 9 CAREFULLY.
**Privacy Policy**. Your personal information and privacy are important to us. The collection, use and sharing of your personal information through the Services and while you use the Services are subject to our [Privacy Policy](../legal-and-privacy/privacy-policy) which is hereby incorporated into the Terms.
1. **Eligibility**. To be eligible to access or use the Services, you must satisfy each of the following eligibility requirements:
1. You are at least eighteen (18) years of age, or are the legal age for entering into legally binding agreements under applicable law;
2. You are not, nor are you an entity that is, or an entity owned or controlled by any person or entity that is, or conducting any activities itself or on behalf of any person or entity that is: the subject of any sanctions administered or enforced by the U.S. Department of the Treasury’s Office of Foreign Assets Control, the U.S. Department of State or any other governmental authority with jurisdiction over the party; identified on the Denied Persons, Entity or Unverified Lists of the U.S. Department of Commerce’s Bureau of Industry and Security; or located, organized or resident in a country or territory that is, or whose government is, the subject of economic sanctions, including, without limitation, Russia, Crimea, Cuba, Iran, North Korea or Syria (each, a “**Restricted Person**”); and
3. You are not accessing or using the Services on behalf of a Restricted Person.
2. **Use of the Protocol**.
1. The Protocol and the Interface. The Services include the Interface, which allows users to access and interact with onchain smart contracts designed to facilitate cross-chain transactions (the “**Protocol**”). Skip contributed to the development of certain of the onchain smart contracts comprising the Protocol, but does not control or operate these smart contracts. The Interface is not the exclusive or sole means to access the Protocol, which is comprised of smart contracts that operate on various permissionless, public blockchains. Please review the Protocol software code and related documentation before using the Services to access or interact with the Protocol to learn more about the code, rules and requirements of the Protocol. For the avoidance of doubt, the Protocol is **not** a part or component of the Services and Skip does not control, maintain administrative rights over or operate the Protocol.
2. Prior Versions of the Protocol. New versions and upgrades to the Protocol may be released from time to time. The Services may not be compatible with prior, abandoned or outdated versions of the Protocol. Skip undertakes no responsibility or obligation to update or maintain support for legacy versions of the Protocol.
3. Protocol Fees. You acknowledge and agree that the Protocol may from time to time assess service fees (“**Protocol Fees**”) directly from you in accordance with the Protocol’s rules or as a result of third-part applications that the Protocol utilizes.
3. **Accessing the Services; Informational Resources**.
1. Connecting a Wallet. To access and use certain aspects of the Services, you will be required to connect a compatible blockchain digital wallet (“**Wallet**”). By connecting a Wallet to the Services, you agree to abide by the terms and conditions of the applicable software provider or developer that developed and/or maintains the applicable Wallet software available to you. You are solely responsible for reviewing the terms of use, technology and security protocols associated with your Wallet software. Skip does not offer Wallet software or take custody, possession or control of your crypto assets at any time as Skip does not maintain any administrative control over the smart contracts that comprise the Protocol. You are solely responsible for maintaining the security of your Wallet, including your credentials, private key and/or seed phrase. Skip shall not be liable for any acts or omissions by you in connection with your Wallet or any security incident related to your Wallet.
2. Cross-Chain Transactions. You may use the Services to interact with Protocol smart contracts on various blockchain networks to facilitate the exchange of crypto assets on a source blockchain network for crypto assets on a destination blockchain network. When you exchange crypto assets on a source network for crypto assets on a destination network, you will receive the crypto assets on the destination network within a separate blockchain address on the destination network. The purchased crypto assets will appear in your Wallet on the destination network, but will not appear in your Wallet on the source network. You own, control, and are responsible for all crypto assets held in and exchanged via your Wallet and Skip is not liable or responsible for any crypto assets that are destroyed or irretrievably lost by users through the cross-chain transaction process.
3. Representations and Warranties. By accessing the Services, you represent and warrant to each of the following: (i) any crypto assets you interact with via the Services have been legally obtained by, and belong to, you; (ii) you will not provide any false, inaccurate or misleading information while using the Services, or engage in any activity that operates to defraud or would be viewed as reasonably having a material adverse effect on Skip, other users of the Services or any other person or entity; (iii) you will not use the Services to transmit or exchange crypto assets that are the direct or indirect proceeds of any criminal or fraudulent activity, including, without limitation, terrorism, money laundering or tax evasion; and you will pay all fees (including Protocol Fees, if any) necessary for interacting with the blockchain networks supported by the Services, including all transaction fees or “gas”, as well as all fees charged by us or any third party for your use of the Services, any blockchain network.
4. Informational Resources. We may make certain informational resources relating to the Services and the Protocol, including, without limitation, technical documentation, blog posts, data, articles, tutorials, social media posts and other informational content published by us, our employees or marketing partners (“**Informational Resources**”), available to you as part of the Services. You acknowledge and agree that all such Informational Resources are intended for informational and educational purposes only and may not be the exclusive or sole source of information regarding the Services and/or the Protocol. Skip shall not be responsible or liable for any damage or loss caused or alleged to be caused by or in connection with the use or reliance on any Informational Resources.
4. **Prohibited Activities**.
1. You shall not engage in any activities that negatively affect the technical performance of the Services, bypass or circumvent security features of the Services or otherwise disrupt or interfere with the functioning of the Services. You shall not violate or attempt to violate the security of the Services or otherwise misuse the foregoing, including by: (i) using any part of the Services or accessing data not intended for you or logging onto a server or an account that you are not authorized to access (including by using a virtual private network or “VPN” to access such data); (ii) disabling, removing, defeating or avoiding any security device or system; (iii) attempting to probe, scan or test the vulnerability of the Services or to breach security or authentication measures without proper authorization; (iv) attempting to interfere with the Services functionality, including but not limited to via means of submitting any malware or computer programming routines that may damage, disrupt or interfere with, intercept or expropriate any system or data, overloading, “flooding,” “spamming,” “mailbombing” or “crashing” the Services or the Protocol when using the Services; (v) forging any transmission control protocol/internet protocol packet header or any part of the header information in any email or posting; (vi) using the Services or the Protocol in a manner that exceeds reasonable request volume or constitutes excessive or abusive usage; or (vii) providing false, misleading or inaccurate information to the Services, such as information related to your location whether by use of a VPN or otherwise.
2. You shall not, directly or indirectly: (i) disassemble, decompile, reverse engineer or use any other means to attempt to discover any source code of the Services, or the underlying ideas, file formats, algorithms or trade secrets therein (unless such source code is open sourced); (ii) encumber, sublicense, transfer, rent, lease, time-share or use the Services in any service bureau arrangement or otherwise for the benefit of any third party; (iii) copy, distribute, manufacture, adapt, create derivative works of, translate, localize, port or otherwise modify any software code or documentation for the Services; (iv) knowingly introduce into the Services or the Protocol any malicious code, computer virus, spyware, scareware, Trojan horses, worms, malware or any other similar harmful, malicious or hidden programs or data; (v) use the Services to infringe upon, violate or misappropriate any third party’s intellectual property rights, violating any law or regulation or being defamatory, trade libelous, threatening or harassing; or (vi) authorize or permit any third party to engage in any of the foregoing proscribed acts. For the avoidance of doubt, the restrictions set forth in this Section are in addition to, and in no way limit, any other restrictions or obligations applicable to you set forth in the Terms.
3. You shall not use the Services to engage in illegal activity of any kind, including, without limitation, any activity that would violate, or assist in violation of, any law, statute, ordinance, regulation or sanctions programs administered under any applicable law, including but not limited to the U.S. Department of Treasury’s Office of Foreign Assets Control or which would involve proceeds of any unlawful activity.
5. **Intellectual Property**.
1. License. The Services and all of its contents as a whole and in part are protected by copyrights, trademarks, service marks, trade names, international treaties and/or other proprietary rights and applicable laws, and are owned or controlled by Skip, its affiliates and licensors. You agree to protect the proprietary rights of us and all others having rights in the Services. Subject to the Terms, we grant you a limited, revocable, non-exclusive, non-sublicensable, non-transferable license to use the Services for your own personal or legitimate business purposes. You acquire absolutely no rights or licenses in or to the Services or materials contained within the Services and the limited right for you to access and use the Services in accordance with the Terms. Except for the limited license granted in these Terms, Skip and its licensors retain all right, title, interest and all proprietary rights in and to the Services, including, without limitation, copyrights, patents, trademarks, service marks and trade names. Skip may change, suspend or discontinue any aspect of the Services at any time, without any liability or obligation to you. Skip, its licensors and service providers reserve all other rights afforded to them but not granted in these Terms.
2. Third-Party Licenses. Notwithstanding anything to the contrary in the Terms, the Services may contain software components released under separate open-source or business-source license terms, in which case those license terms will govern such software components.
3. Feedback. With respect to any feedback you provide to Skip (whether orally or in writing) concerning the Services, including any features or functionalities thereof, and including identifying potential errors and improvements (“**Feedback**”), you hereby grant to Skip an exclusive, worldwide, perpetual, fully paid-up, royalty free, fully-sublicensable (through multiple tiers of sublicensees) and freely assignable and transferable license to use any Feedback for any purpose without payment or restriction. It is further understood that Skip’s use of Feedback, if any, may be used by Skip in its sole discretion, and that Skip shall in no way be obliged to make any payment to you for or make use of any kind of the Feedback or part thereof.
4. Use of Trademarks and Other Marks or Rights. You may not use any of our trademarks, trade names, service marks, copyrights or logos, or our partners’, affiliated entities’, licensors’, or their licensors’ trademarks, trade names, service marks, copyrights or logos, including but not limited to the Skip name, in any manner that creates the impression that such items: (i) belong to or are associated with you or indicate the sponsorship or approval of us, our licensors, any partners, affiliates or their licensors; or (ii) except as otherwise provided herein, are used with our licensors’, partners’, affiliates’, or their licensors’ consent, and you acknowledge that you have no ownership rights in or to any such items.
6. **Term; Termination**.
1. The Terms are effective beginning when you accept the Terms or first access or use the Services and ending when terminated as set forth in Section 6.2.
2. Your right to use and access the Services will automatically terminate in the event you fail to comply with any of the terms and conditions of the Terms. Termination will be effective without notice.
3. Upon termination of the Terms, your license rights will immediately terminate and you must immediately cease all use of the Services. Sections 4-11 of the Terms shall survive any such termination.
7. **Risks**.
1. You acknowledge and understand that the Services, the Protocol and certain crypto assets, blockchain-based protocols and/or blockchain networks may not be available or appropriate for use in all jurisdictions and you may be subject to legal and regulatory compliance obligations in connection with your use of the Services in certain jurisdictions. By accessing or using the Services, you agree that you are solely and entirely responsible for compliance with all laws and regulations that may apply to you. You further agree that we have no obligation to inform you of any potential liabilities or violations of law or regulation that may arise in connection with your access and use of the Services, the Protocol via the Services, crypto assets, blockchain-based protocols and/or blockchain networks and that we are not liable in any respect for any failure by you to comply with any applicable laws or regulations.
2. You acknowledge that the Services incorporate experimental and novel technology and that the use of such technology involves a high degree of risk. For example, there are numerous reasons the Services, the Protocol, a blockchain-based protocol or blockchain network that you use in connection with the Services could fail in an unexpected way, resulting in the total and absolute loss of your crypto assets. You hereby agree that you assume all risks in connection with your use of the Services and expressly waive and release Skip from any and all liability, claims, causes of action or damages arising out of or in any way relating to you obtaining or using Services.
3. You understand and accept the risk of operational challenges related to the Services. For example, the Services, the Protocol, blockchain-based protocols and/or blockchain networks may experience cyber-attacks, unexpected surges in transaction volume, botting or activity or other operational or technical difficulties or vulnerabilities that may cause interruptions related to your use of the Services. You agree to accept the risk of a failure of the Services resulting from unanticipated or heightened technical difficulties or vulnerabilities, including those resulting from cyber-attacks. You agree to not hold Skip liable for any related losses.
4. You agree that Skip is not responsible for any crypto asset that you receive, transfer, bridge, hold, lose or otherwise use or misuse in connection with the Services. Additionally, you agree that Skip is not responsible for any tax obligations that you incur in connection with your use of the Services.
5. You understand that all transactions conducted through the Services and the Protocol via the Services are automatically processed onchain. By engaging in transactions using the Services, you acknowledge and consent to the automatic processing of all transactions in connection with the Services. You acknowledge and agree that onchain smart contracts may programmatically facilitate the transfer of crypto assets in connection with your transactions. You further acknowledge and agree that Skip does not take possession, custody or control over your crypto assets at any time or maintain administrative control over the smart contracts that comprise the Protocol.
6. You understand that the Ethereum, Cosmos and Solana blockchain networks (and all other networks with which the Services may be compatible, such as IBC-compatible networks) remain under development, which creates technological and security risks when using the Services in addition to uncertainty relating to crypto assets and transactions. You acknowledge that the cost of transacting on blockchain networks is variable and may increase at any time, thereby impacting any activities taking place on such blockchains, which may result in significant price fluctuations or increased prices when using the Services.
7. THE SERVICES RELY ON EMERGING TECHNOLOGIES, INCLUDING, BUT NOT LIMITED TO, CRYPTOGRAPHY, SMART CONTRACTS, ROUTERS, RELAYERS AND CROSS-CHAIN PROOFS. SOME FUNCTIONALITY IS SUBJECT TO INCREASED RISK THROUGH YOUR POTENTIAL MISUSE, SUCH AS MISUSES RELATED TO PUBLIC/PRIVATE KEY CRYPTOGRAPHY. BY USING THE SERVICES YOU EXPLICITLY ACKNOWLEDGE AND ACCEPT THESE HEIGHTENED RISKS. SKIP SHALL NOT BE LIABLE FOR THE FAILURE OF ANY MESSAGE TO SEND TO OR BE RECEIVED BY THE INTENDED RECIPIENT IN THE INTENDED FORM, OR FOR DIMINUTION OF VALUE OF ANY CRYPTO ASSET ON ANY BLOCKCHAIN NETWORKS, AND SKIP MAKES NO REPRESENTATIONS OR WARRANTIES WITH RESPECT TO SAME.
8. **Disclaimer of Warranties; Limitation of Liability; Indemnification**.
1. EXCEPT AS EXPRESSLY SET FORTH HEREIN, THE SERVICES ARE ISSUED ON AN “AS-IS” AND “AS AVAILABLE” BASIS AND SKIP DOES NOT MAKE ANY WARRANTIES WITH RESPECT TO SUCH “AS-IS” AND “AS AVAILABLE” BASIS OR OTHERWISE IN CONNECTION WITH THE TERMS (EXCEPT AS EXPRESSLY PROVIDED HEREIN) AND SKIP HEREBY DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES AND CONDITIONS, INCLUDING ANY WARRANTIES OR CONDITIONS OF NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AVAILABILITY, ERROR-FREE OR UNINTERRUPTED OPERATION, AND ANY WARRANTIES ARISING FROM A COURSE OF DEALING, COURSE OF PERFORMANCE OR USAGE OF TRADE. TO THE EXTENT THAT SKIP MAY NOT, AS A MATTER OF APPLICABLE LAW, DISCLAIM ANY IMPLIED WARRANTY OR CONDITION, THE SCOPE AND DURATION OF SUCH WARRANTY OR CONDITION SHALL BE APPLIED TO THE MINIMUM EXTENT PERMITTED UNDER SUCH APPLICABLE LAW.
2. IN NO EVENT SHALL SKIP BE LIABLE TO YOU FOR ANY CONSEQUENTIAL, INDIRECT, INCIDENTAL OR SPECIAL DAMAGES OF ANY TYPE OR NATURE HOWEVER ARISING, INCLUDING, WITHOUT LIMITATION, EXEMPLARY OR PUNITIVE DAMAGES, LOST DATA, LOST PROFITS OR REVENUES OR DIMINUTION IN VALUE, ARISING OUT OF OR RELATING TO THE SERVICES OR YOUR USE OF THE PROTOCOL VIA THE SERVICES, WHETHER OR NOT THE POSSIBILITY OF SUCH DAMAGES HAS BEEN DISCLOSED TO OR COULD HAVE BEEN REASONABLY FORESEEN BY YOU, REGARDLESS OF THE LEGAL OR EQUITABLE THEORY (WHETHER IN CONTRACT, TORT OR OTHERWISE) UPON WHICH THE CLAIM IS BASED. IN ADDITION, UNDER NO CIRCUMSTANCES SHALL SKIP’S AGGREGATE LIABILITY UNDER THE TERMS EXCEED ONE-HUNDRED U.S. DOLLARS (\$100.00).
3. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF CERTAIN WARRANTIES OR THE LIMITATION OR EXCLUSION OF LIABILITY FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES. ACCORDINGLY, SOME OF THE LIMITATIONS SET FORTH ABOVE MAY NOT APPLY TO YOU. IF YOU ARE DISSATISFIED WITH THE SERVICES, YOU UNDERSTAND AND AGREE THAT YOUR SOLE AND EXCLUSIVE REMEDY IS TO DISCONTINUE USING THE SERVICES.
4. You agree, at your own expense, to indemnify, defend and hold harmless Skip and our partners and affiliates and their respective owners, members, agents, directors, officers, employees, representatives, affiliates, successors and assigns against any claim, suit, action or other proceeding from and against any and all claims, damages, liabilities, costs and expenses, including reasonable attorneys’ and experts’ fees, arising out of or in connection with the Services, or any third-party protocols, software or applications, links or blockchain-based protocols accessible via the Services, including but not limited to: (i) any breach or violation of the Terms by you; (ii) material, information or content submitted or provided by you; (iii) your use of the Services (including, for the avoidance of doubt, your use of the Services to access the Protocol) or (iv) any deletions, additions, insertions or alterations to, or any unauthorized use of, the Services by you. You agree to pay any and all costs, damages and expenses, including but not limited to reasonable attorneys’ fees and costs awarded against or otherwise incurred by or in connection with or arising from any such claim, suit, action or proceeding attributable to any such claim. We reserve the right, at our own expense, to assume the exclusive defense and control of any matter otherwise subject to indemnification by you, in which event you will fully cooperate with us in asserting any available defense.
9. **Dispute Resolution; Agreement to Arbitrate**.
1. All disputes, claims and controversies, whether based on past, present or future events, arising out of or relating to statutory or common law claims, the breach, termination, enforcement, interpretation or validity of any provision of the Terms and the determination of the scope or applicability of your agreement to arbitrate any dispute, claim or controversy originating from the Terms, will be determined by binding arbitration in the State of Delaware, before a single arbitrator. The arbitration will be administered by the American Arbitration Association (“**AAA**”), in accordance with the AAA Consumer Arbitration Rules.
2. The arbitrator will apply the substantive law of the State of Delaware, excluding its conflict or choice of law rules.
3. Nothing in the Terms will preclude the parties from seeking provisional remedies in aid of arbitration from a court of appropriate jurisdiction.
4. A party must notify the other party of its intent to commence arbitration prior to commencing arbitration. You may provide such notice to Skip at the email address set forth in Section 11.2. The notice must specify the date on which the arbitration demand is intended to be filed, which must be at least thirty (30) days after the date of the notice. During this time period, the parties will meet for the purpose of resolving the dispute prior to commencing arbitration.
5. Subject to Section 9.4, each party may commence arbitration by providing to the AAA and the other party to the dispute a written demand for arbitration, stating the subject of the dispute and the relief requested.
6. Subject to the disclaimers and limitations of liability stated in the Terms, the appointed arbitrators may award monetary damages and any other remedies allowed by the laws of the State of Delaware. In making a determination, the arbitrator will not have the authority to modify any term of the Terms. The arbitrator will deliver a reasoned, written decision with respect to the dispute to each party, who will promptly act in accordance with the arbitrator’s decision. Any award (including interim or final remedies) may be confirmed in or enforced by a court located in the State of Delaware. The decision of the arbitrator will be final and binding on the parties, and will not be subject to appeal or review.
7. Subject to applicable law, the party initiating the arbitration will be responsible for paying the applicable filing fee. Each party will advance one-half of the fees and expenses of the arbitrator, the costs of the attendance of the arbitration reporter at the arbitration hearing and the costs of the arbitration facility. In any arbitration arising out of or relating to the Terms, the arbitrator will award to the prevailing party, if any, the costs and attorneys’ fees reasonably incurred by the prevailing party in connection with those aspects of its claims or defenses on which it prevails, and any opposing awards of costs and legal fees awards will be offset.
8. The parties will keep confidential the existence of the arbitration, the arbitration proceeding, the hearing and the arbitrator’s decision, except: (i) as necessary to prepare for and conduct the arbitration hearing on the merits; (ii) in connection with a court application for a preliminary remedy, or confirmation of an arbitrator’s decision or its enforcement; (iii) Skip may disclose the arbitrator’s decision in confidential settlement negotiations; (iv) each party may disclose as necessary to professional advisors that are subject to a strict duty of confidentiality; and (v) as applicable law otherwise requires. The parties, witnesses and arbitrator will treat as confidential and will not disclose to any third person (other than witnesses or experts) any documentary or other evidence produced in any arbitration, except as applicable law so requires or if the evidence was obtained from the public domain or was otherwise obtained independently from the arbitration.
9. In the case of a conflict between the provisions of this Section 9 and the rules of the AAA, the provisions of this Section 9 shall prevail.
10. To the extent permitted by applicable law, any dispute arising out of or relating to the Terms, whether in arbitration or in court, shall be conducted only on an individual basis and not in a class, consolidated or representative action. Notwithstanding any other provision of the Terms or the rules of the AAA, disputes regarding the interpretation, applicability or enforceability of this class waiver may be resolved only by a court and not by an arbitrator. If this waiver of class or consolidated actions is deemed invalid or unenforceable, neither party is entitled to arbitration.
11. If for any reason a claim or dispute proceeds in court rather than through arbitration, each party knowingly and irrevocably waives any right to trial by jury in any action, proceeding or counterclaim arising out of or relating to the Terms.
10. **Third-Party Services**.
1. By using the Services, you may view and have access to the content, products, services, blockchain-based protocols, blockchain networks, software or applications of one or more third parties (“**Third-Party Services**”), via linked or plugged in technologies to the Services. Your reliance on, access or use of any Third-Party Services in connection with using the Services will also be governed by the terms and conditions and policies of the applicable third-party service provider (*e.g.*, a Wallet provider). You understand and agree that any such third-party terms and conditions and policies may involve fees or other charges and include disclaimers or particular risk warnings about the reliance on or the accuracy of any information or with using such third-party services. It is your responsibility to understand the terms and conditions and policies of any such third-party service provider, including how those service providers use any of your data or other information under their privacy policies. Any such terms and conditions and policies may provide for less security than Skip. You understand and agree that any Third-Party Services are provided for your convenience only. We do not verify or control any Third-Party Services, and as a result, we do not guarantee, endorse or recommend any Third-Party Services to any or all users of the Services. We are therefore not responsible for the availability, content, validity, timeliness, completeness, reliability, integrity, quality, legality, usefulness, safety or accuracy of any Third-Party Services, or any intellectual property rights therein, that may be linked to or from the Services. Your reliance on, access and use of any Third-Party Services is at your own risk, and we disclaim all responsibility and liability for any losses that result out of same. We have no responsibility for Third-Party Services that may be misleading, incomplete, erroneous, offensive, indecent or otherwise objectionable to you or under the law in your jurisdiction, or which contain malware, vulnerabilities or any other types of malicious software, smart contracts, domains or computer code. The choice to rely on, access and use Third-Party Services is in your own discretion, and you are solely responsible for ensuring that your reliance, access or use is in compliance with all applicable laws. For the avoidance of doubt, we do not: (i) make any warranty, express or implied, with respect to the use of the links provided on or to the Services; (ii) verify or guarantee the accuracy, completeness, usefulness or adequacy of any other websites, services, goods or other Third-Party Services that may be linked to or from the Services; or (iii) make any endorsement, express or implied, of any other websites, services, goods or other Third-Party Services that may be linked to or from Services. For the avoidance of doubt, this paragraph shall be interpreted broadly and covers websites, blockchain-based protocols and other crypto-native technologies, such as cross-chain bridges, decentralized exchanges and all other blockchain-based protocols accessible via the Services or any links made available through the Services. Any statements, opinions or other information made available by third parties, including users, are solely those of the respective author(s) or distributor(s). We reserve the right to change, suspend, remove, disable or impose access restrictions or limits on any Third-Party Service at any time and without prior notice to you.
2. WE DISCLAIM ANY AND ALL LIABILITY, INCLUDING ANY EXPRESS OR IMPLIED WARRANTIES, WHETHER ORAL OR WRITTEN, FOR WEBSITES, SERVICES, GOODS, INFORMATION, ADVERTISEMENTS OR OTHER THIRD-PARTY SERVICES THAT MAY BE LINKED TO OR FROM, OR PROVIDED THROUGH, THE SERVICES. YOU ACKNOWLEDGE THAT NO REPRESENTATION HAS BEEN MADE BY US AS TO THE FITNESS OF THE WEBSITES, SERVICES, GOODS, ADVERTISEMENTS OR OTHER THIRD-PARTY SERVICES THAT MAY BE LINKED TO, FROM OR PROVIDED THROUGH, THE SERVICES. YOUR USE OF THIRD-PARTY SERVICES IS AT YOUR SOLE RISK AND IS SUBJECT TO ANY ADDITIONAL TERMS, CONDITIONS AND POLICIES APPLICABLE TO SUCH THIRD-PARTY SERVICES (SUCH AS TERMS OF USE OR THE PRIVACY POLICY OF THE PROVIDERS OF SUCH THIRD-PARTY SERVICES).
3. You may also link to the Services provided that you do so in a way that indicates that the link is direct to the Services and is fair and not misleading. You may not integrate or make use of all or part of the Services in ways that would confuse or mislead visitors as to the nature and origin of the Services’ content.
11. **General Provisions**.
1. Electronic Communications. By accessing or using the Services, you consent to receive electronic communications.
2. Notices. Skip may provide you with notice and other communications via electronic communications as permitted by Section 11.1. You may provide us with notice by sending an email address to [support@skip.money](mailto:support@skip.money). All notices will be deemed effective upon dispatch.
3. Waivers. For a waiver to be deemed effective, a waiver must be in a writing signed by the waiving party. The failure of either party to enforce any provision of the Terms will not constitute a waiver of that party’s rights to subsequently enforce the provision.
4. Cumulative Rights; Injunctions. The rights and remedies of the parties under the Terms are cumulative, and each party may exercise any of its rights and enforce any of its remedies under the Terms, along with all other rights and remedies available to it at law, in equity or otherwise. Any material breach by a party of the Terms could cause the non-breaching party irreparable harm for which the non-breaching party has no adequate remedies at law. Accordingly, the non-breaching party is entitled to seek specific performance or injunctive relief for any such breach.
5. Severability. If any provision of the Terms is declared to be invalid, illegal or unenforceable by a court of competent jurisdiction, then the validity, legality and enforceability of the remaining provisions contained herein shall not be affected thereby and the remainder of the provisions of the Terms shall remain valid, legal and enforceable to the fullest extent permitted by law.
6. Accessibility. We are committed to helping those with disabilities access the Services. We strive to provide an excellent online experience for our users – including those with sight, hearing and other disabilities. If you have difficulty using or accessing any element of the Services or if you have any Feedback regarding accessibility of the Services, please feel free to contact us at [support@skip.money](mailto:support@skip.money).
7. Force Majeure. Skip shall have no liability for any failure or delay resulting from any condition beyond our reasonable control, including but not limited to governmental action or acts of terrorism, earthquake, fire, flood, other acts of God, labor conditions, power failures, equipment failures and Internet or blockchain network disturbances.
8. Successors and Assigns. You may not transfer or assign the Terms or any rights or obligations hereunder, by operation of law or otherwise and any such attempted assignment shall be void. Skip reserves the right to freely transfer or assign the Terms and the rights and obligations hereunder to any third party at any time without your consent and prior notice to you. If you object to any such transfer or assignment, you may stop using the Services.
9. Relationship of the Parties. Nothing contained in the Terms shall constitute you and Skip as members of any partnership, joint venture, association, syndicate, unincorporated business or similar assignment as a result of or by virtue of the relationship established by the Terms.
10. Governing Law. The Terms shall be solely and exclusively governed, construed and enforced in accordance with the laws of the State of Delaware without giving effect to conflict of law rules or principles that would cause the application of the laws of any other jurisdiction.
11. Entire Agreement. The Terms constitute the entire agreement and understanding between you and Skip, and supersedes all previous communications, representations or agreements, whether written or oral, with respect to the subject matter hereof.
12. No Third-Party Beneficiaries. The Terms are not intended and shall not be construed to create any rights or remedies in any parties other than you and Skip and other Skip affiliates, which each shall be a third-party beneficiary of the Terms, and no other person shall assert any rights as a third-party beneficiary hereunder.
# REST API
Selected updates and improvements to the Skip Go REST API.
## September 28, 2024
* Speed and performance improvements for `/balances` endpoint
## August 21, 2024
* Add `/balances` endpoint
# Client Library
Selected updates and improvements to the `@skip-go/client` library.
## v0.10.3
* The `executeRoute` method now accepts `beforeMsg` and `afterMsg` parameter to allow for the execution of custom Cosmos messages before/after the route is executed. This is useful for executing custom messages that are not part of the route definition.
```typescript
// An example of how to use the `beforeMsg` parameter with a MsgSend
const msg = JSON.stringify({
fromAddress: 'cosmos1...', // Replace with sender address
toAddress: 'cosmos1...', // Replace with recipient address
amount: [{
denom: 'uatom', // Replace with the actual denom, e.g., 'uatom' for ATOM
amount: '1000000' // Replace with the actual amount (in smallest unit, e.g., micro-ATOM)
}]
});
await skip.executeRoute({
route,
userAddresses,
beforeMsg: { msg, msgTypeURL: '/cosmos.bank.v1beta1.MsgSend' }
});
```
## v0.9.3
* Update client to include solana support via public RPC and show warning when public infrastructure is not overriden.
## v0.9.0
* Add `/balance` methods query API endpoint. See the [documentation](../client/balance-gas-and-fee-tooling) and the [API reference](/api-reference/prod/info/post-v2infobalances) for more details.
# null
Stay up to date with Skip Go's latest features and improvements.
A library that streamlines interaction with the Skip Go API, enabling cross-chain swaps and transfers across multiple ecosystems
Seamless cross-chain bridging, swapping, and transferring functionality in an easy to integrate React or Web component
REST endpoints for low-level control over your interactions.
# Widget
Selected updates and improvements to the `@skip-go/widget` [npm package](https://www.npmjs.com/package/@skip-go/client).
## v2.5.2
* Change default fee asset selection on chain change.
## v2.5.0
* Fix max button & corresponding gas calculation and
* Remove gas amount option in settings
# Chain Support Requirements
This document describes what new chains need to do the support Skip Go API
## Background
* New chains often want Skip Go API to add support for their chain as a source + destination for tokens because the API powers cross-chain swaps + transfers in all the major cosmos wallets (Leap, Keplr, IBC Wallet, Metamask Snap) and many popular DeFi aggregators and dapp frontends (e.g. Stargaze). As a result, being added to the Skip Go API instantly offers distribution across the interchain
* This document covers the basic requirements chains must satisfy and steps their contributors must complete in order for Skip Go API to support them
* **You can use [this form ](https://skip-protocol.notion.site/Request-to-add-Chain-Support-to-Skip-API-637ae5353fd3460b957eacf4c407f0d2?pvs=4)to submit information about your chain to Skip and track your progress through the required steps**
**Want help at the beginning of this process?**
Getting connected to IBC, Axelar, CCTP, or Hyperlane can be hard. Even choosing among them is a challenge. We're happy to provide guidance and hands-on support to serious teams early in their journey -- even before they've made a choice of interop protocol if helpful!
**This guide assumes using IBC for Interop**
The rest of this guide assumes you want Skip to support users interacting with your chain primarily over IBC.
The Skip Go API supports other bridges and interop protocols in addition to IBC, including Hyperlane, CCTP, and Axelar. If you're using one of these, please get in contact with us on [our Discord](https://skip.build/discord), and we will help guide you through it to the extent we can.
These other interop protocols are less standardized and/or less permissionless than IBC, so the process of adding support for new chains is more bespoke and varies by protocol. We're happy to help where we can, providing guidance, implementation, and introductions where necessary
## 1. Satisfy the following basic requirements
1. Provides clear instructions for permissionlessly running a full node and joining the network. Commonly instructions should include:
1. Link to genesis file
2. Full node binary or instructions for building binary from source code
3. Public peer / seeder nodes
4. Public RPCs
2. Chain metadata is available in a commonly used chain registry (e.g. [https://github.com/cosmos/chain-registry](https://github.com/cosmos/chain-registry)). Metadata should include:
1. Chain name (and optionally "pretty name"
2. Website
3. chain\_id
4. Bech32 prefix
5. slip44 (aka "coin type")
6. Fee information (with denom, low price, average price, and high price)
7. Logo URIs
8. Persistent peer lists
9. Public RPCs\
*This metadata and the chain registry of choice might differ for EVM chains. Please use your best judgement of whats required*
3. IBC, Axelar, and/or Hyperlane support
## 2. Configure IBC Machinery
*Here we set up IBC clients, channels, and relayers.*
**What is a relayer?**
Relayers are the off-chain actors that:
* Keep IBC light clients up to date (Regular updates are required to prevent "expiration")
* Monitor chains for outbound IBC packets, grab them, and send the packet data and packet proof to the destination chain
*The easiest way to complete the steps below is to use the ibc relayer software ([Hermes](https://github.com/informalsystems/hermes) or [Relayer](https://github.com/cosmos/relayer). The CLIs of both support channel and client instantiation.*
For each chain that you want your chain to have a direct IBC transfer path to, you must complete steps to ensure IBC works properly:
1. Create a light client of the remote chain on your chain, and a light client of your chain on the remote chain
2. Create a ICS-20 "transfer" channel between these two clients
**Don't create more than 1 channel between your chain and a remote chain**
Your chain only needs 1 transfer channel for each chain it should communicate with directly.
All tokens from your chain can be transferred to a particular remote chain over the same channel.
Additional transfer channels may create confusion and liquidity fragmentation since users will need to pick which channel to transfer over (The Skip Go API automates this choice for the apps and users that use it, but others might not be so lucky)
1. Ensure there is at least 1 reliable relayer covering the channel (who can keep the light clients up to date and ferry packets between the two chains over time)
**What if I don't want to run my own relayers?**
Get in touch with us on [our Discord](https://skip.build/discord).
We have great relationships with all the top relayer operators in the Cosmos ecosystem and can put you in touch with them.
## 3. Submit your chain support request to Skip!
Now, submit [this form](https://skip-protocol.notion.site/Request-to-add-Chain-Support-to-Skip-API-637ae5353fd3460b957eacf4c407f0d2?pvs=4) to Skip with all the necessary information filled in
## 4. Configure support for each asset minted on your chain
For each native asset that you want to ensure users can transfer over the
1. Transfer a non-zero amount of the token over the channel
2. Confirm that the token successfully gets transferred to the destination chain
3. **Leave the transferred tokens on the destination chain**
**Why is this required?**
Warm starting the channels kicks off Skip's intelligent routing suggestions for folks bridging to and from your chain. We choose routes between chains that ensure users are always receiving the most desirable version of their chosen token on their destination chain.
As a part of providing good user experiences for everyone using the API, we don't enable users to bridge assets to new chains where no one has previously bridged that asset. (Often times, for ordinary users, taking an existing token to a chain it doesn't exist leaves them stuck on that new chain with a useless token). That's why we need to "warm start" channels -- to enable recommending them as bridging routes.
**Have questions or feedback? Help us get better!**
Join [our Discord](https://skip.build/discord) and select the "Skip Go Developer" role to share your questions and feedback.
# Swap Venue Requirements
This document covers what Skip Go API requires of DEXes to support them as potential swapping venues within the API's cross-chain DEX aggregation functionality. At the end, the document provides instructions for helping the Skip team add your DEX to the API as a swapping venue
## Background
* DEXes often want Skip Go API to add support for their DEX as a swapping venue because the API powers cross-chain swaps + transfers in all the major cosmos wallets (Leap, Keplr, IBC Wallet, Metamask Snap) and cross-chain DEX aggregation to many popular defi aggregator and dapp frontends (e.g. Stargaze). As a result, being added to the Skip Go API instantly offers distribution across the interchain for your DEX
* The Skip Go API’s swapping system is currently built in CosmWasm and can support swapping assets on Cosmos SDK modules (ex: Osmosis Poolmanager) and other CosmWasm contracts (ex: Astroport DEX) that can be queried and executed by Skip Go API’s CosmWasm contracts.
* **You can use [this form ](https://skip-protocol.notion.site/Request-to-add-Swapping-Venue-to-Skip-API-104299e5ec644d95acbef320926da041?pvs=4)to submit information about your swapping venue to Skip and track your progress through the required steps**
### Chain Requirements
1. The chain must already be supported by the Skip Go API
1. Use the `/info/chains` endpoint to query a list of actively supported chains: [/v2/info/chains](/api-reference/prod/info/get-v2infochains)
2. If your chain is not already supported, follow the instructions in [Chain Support Requirements](./chain-support-requirements) to request support
3. ***This is a pre-requisite***
2. CosmWasm Support
3. IBC support
4. ibc-hooks Support (Check out [our blog post about ibc-hooks](https://ideas.skip.build/t/how-to-give-ibc-superpowers/81))
### Module / Contract Requirements
### General
1. The module / contract must be able to be called by the Skip Go API’s CosmWasm contracts. For Cosmos SDK modules, this will require the module queries described below to be whitelisted and queryable by CosmWasm contracts ([see Osmosis for an example](https://github.com/osmosis-labs/osmosis/blob/d7eb3b7018cde0557216237c84f063b3915af650/wasmbinding/stargate%5Fwhitelist.go#L169)).
#### Execution Messages
1. Supports a “Swap Exact In” method where a user specifies an input asset and path to swap, and the module / contract swaps the given user asset to the user’s desired output asset and sends it to the user ([see Osmosis for a module example](https://github.com/osmosis-labs/osmosis/blob/d7eb3b7018cde0557216237c84f063b3915af650/x/poolmanager/msg%5Fserver.go#L22), or [Astroport for a contract example](https://github.com/astroport-fi/astroport-core/blob/52af83eab04c620ac40019f7cc9cee433d0c601e/contracts/router/src/contract.rs#L74)).
1. Inputs into the swap:
1. An asset (Native cosmos coin or CW20 token, incl. denom and amount)
2. A path (can be a single pool, or multiple pools if designed like a router)
2. Outputs of the swap:
1. An asset
2. NICE TO HAVE (Optional): Supports a “Swap Exact Out” method where a user specifies a desired output asset, a path to swap through to achieve that asset, and a maximum amount of an input asset to swap, and the module / contracts swaps in the exact input asset needed to acquire the specified output asset and sends it to the user ([see Osmosis for a module example](https://github.com/osmosis-labs/osmosis/blob/d7eb3b7018cde0557216237c84f063b3915af650/x/poolmanager/msg%5Fserver.go#L48)).
### Query Messages
3. Exposes a “Swap Exact In Simulation” method where a user can put the inputs that would be used in the “Swap Exact In” execution method, and gets a response from the query that specifies the asset they would receive if executing the method ([see Osmosis for a module example](https://github.com/osmosis-labs/osmosis/blob/d7eb3b7018cde0557216237c84f063b3915af650/x/poolmanager/client/grpc/grpc%5Fquery.go#L113), or [Astroport for a contract example](https://github.com/astroport-fi/astroport-core/blob/52af83eab04c620ac40019f7cc9cee433d0c601e/contracts/router/src/contract.rs#L240)).
4. Exposes a “Swap Exact Out Simulation” method where a user can input the asset desired and a given pool / path, and the query returns the asset required to swap in to receive the output asset desired ([see Osmosis for a module example](https://github.com/osmosis-labs/osmosis/blob/d7eb3b7018cde0557216237c84f063b3915af650/x/poolmanager/client/grpc/grpc%5Fquery.go#L93), or [Astroport for a contract example](https://github.com/astroport-fi/astroport-core/blob/52af83eab04c620ac40019f7cc9cee433d0c601e/contracts/pair/src/contract.rs#L892)).
## Getting Skip to add support for your DEX
If your DEX and the chain its deployed on meets all of the functionality requirements described above, please fill out [this support request form](https://skip-protocol.notion.site/Template-for-Request-to-add-Swapping-Venue-to-Skip-API-104299e5ec644d95acbef320926da041?pvs=4) and submit it to [support@skip.build](mailto:support@skip.build) or TG:@bpiv400. The form will help us scope how much work is required on our side to add support, guide our implementation, and inform our decision for how quickly to prioritize it in our roadmap (e.g. based on swapping volume + liquidity, and clarity of the technical information)
# Token & Route Support Requirements
This document describes the steps you must complete for the Skip Go API to begin providing new routes for users to transfer a token over to various remote chains using IBC.
## Background
* New tokens often want Skip Go API to add support for transferring their token to other chains because the API powers cross-chain swaps + transfers in all the major cosmos wallets (Leap, Keplr, IBC Wallet, Metamask Snap) and cross-chain DEX aggregation for many popular defi aggregator and dapp frontends (e.g. Stargaze). As a result, being added to the Skip Go API instantly offers distribution across the interchain for a new token
* This document covers the basic requirements tokens must satisfy and steps their contributors must complete in order for Skip Go API to support transferring them throughout the interchain
**Guide assumes using IBC for interop**
This guide assumes you're using IBC to transfer your token between chains.
The Skip Go API supports other bridges and interop protocols in addition to IBC, including Hyperlane, CCTP, and Axelar. If you're using one of these, please get in contact with us on [our Discord](https://skip.build/discord).
and we will help guide you through it to the extent we can.
These other interop protocols are less standardized and/or less permissionless than IBC, so the process of adding support for transferring new tokens over them is more bespoke and varies by protocol. We're happy to help where we can, providing guidance, implementation, and introductions where necessary.
## 1. Satisfy the following basic requirements
1. The chain where the token is issued must already be supported by the Skip Go API
1. Use the `/info/chains` endpoint to query a list of actively supported chains: [/v2/info/chains](/api-reference/prod/info/get-v2infochains)
2. If the chain is not already supported, follow the instructions in [Chain Support Requirements](./chain-support-requirements) to request support
3. ***This is a pre-requisite***
2. The Skip Go API must also support the remote chains to which you wish users to be able to transfer the asset
1. Use the `/info/chains` endpoint to query a list of actively supported chains: [/v2/info/chains](/api-reference/prod/info/get-v2infochains)
2. If the chain is not already supported, follow the instructions in [Chain Support Requirements](./chain-support-requirements) to request support
3. ***This is a pre-requisite***
3. Token metadata is available in a commonly used chain registry (e.g. [Cosmos Chain Registry](https://github.com/cosmos/chain-registry)) . Metadata should include at least:
1. Denom (programmatic string identifier)
2. Symbol (aka "ticker")
3. Asset name (human readable denom)
4. Display name (aka pretty name)
5. Decimals / exponent
6. Images
7. coingecko\_id (if applicable)
8. Description
4. Ensure IBC relayers are actively monitoring and relaying packets on all channels over which you want users to transfer your token (See [Chain Support Requirements](./chain-support-requirements) for more info on relayers.)
## 2. "Warm Start" your Asset Routes
For each destination chain:
1. Pick a channel that you would like to be the canonical channel for transferring the asset to this destination chain
2. Transfer a non-zero amount of the token over the channel
3. Confirm that the token successfully gets transferred to the destination chain
4. **Leave the transferred tokens on the destination chain**
**How do I pick a channel for a destination chain?**
If you're launching a new chain, you should just pick whatever channel your team has set up. Usually, there's just one highly-trafficked and well-relayed channel between two chains over which all assets are transferred. (In theory, there can be many because IBC is permissionless, but usually relayers are only monitoring 1 and creating more adds confusion for all parties)
If you're launching a new token on a chain that already has a vibrant IBC ecosystem and has already issued tokens that are widely used throughout the interchain (e.g. Osmosis or Neutron), you should probably use the same channel the well-established tokens use, since relayers are most likely to support these ones. To see which channel this is, call the [/v2/fungible/recommend\_assets](/api-reference/prod/fungible/get-v2fungibleassets) endpoint with the following values:
* `source_denom`: A well-established token on the chain where your asset is issued (e.g. `uatom`)
* `source_chain_id`: The `chain_id` of the chain where your asset is issued (`e.g. cosmoshub-4`)
* `dest_chain_id`: The `chain_id` of the chain to which you want to be able to transfer your asset (e.g. `osmosis-1`)
The channel you want to use is available in the response in `recommendations[0].asset.trace`
**How do I transfer tokens over my chosen channel before Skip Go API supports it?**
The easiest way to transfer tokens over a channel before official Skip Go API support is to use Keplr's developer mode. To enable developer mode in the Keplr extension, open the hamburger menu, click on settings, then click advanced, then activate the toggle for "Developer Mode".
Once developer mode is active, at the bottom of the main page you should see "Advanced IBC Transfer". Click on this then follow the instructions for inputting your token and desired channel ID.
**Why is this required?**
Warm starting the channels kicks off Skip's intelligent routing suggestions for folks bridging to and from your chain. We choose routes between chains that ensure users are always receiving the most desirable version of their chosen token on their destination chain.
As a part of providing good user experiences for everyone using the API, we don't enable users to bridge assets to new chains where no one has previously bridged that asset. (Often times, for ordinary users, taking an existing token to a chain it doesn't exist leaves them stuck on that new chain with a useless token). That's why we need to "warm start" channels -- to enable recommending them as bridging routes.
## 3. Wait up to 24 hours and verify
Skip's intelligent route detection should automatically detect new routes for all assets and chains that meet the above requirements in 4-8 hours. This will not happen immediately. Please ensure you wait the necessary amount of time.
After you've let enough time pass, you can verify that Skip Go API supports the new routes you've configured using the [/v2/fungible/recommend\_assets](/api-reference/prod/fungible/get-v2fungibleassets) endpoint. For each destination chain you've configured, call this endpoint with the following data:
* `source_denom`: Your token
* `source_chain_id`: The chain on which your token is issued
* `dest_chain_id`: The chain to which you've warm-started an IBC route in the previous step
## Common questions
### I want a CW20 token added to Skip Go, what do I need to do to add it?
1. To add a CW20 token, you should first make sure its usable (either has ibc20-cw20 converter contracts deployed to IBC transfer the token or source-chain swappable on a swap venue used by Skip Go).
2. Once confirmed usable, you must add the CW20 token's metadata to a registry we support indexing from. The easiest one is likely the [Cosmos Chain Registry](https://github.com/cosmos/chain-registry), you can check out an example of a CW20 token entry here in [Archway's assetlist.json](https://github.com/cosmos/chain-registry/blob/master/archway/assetlist.json).
3. Once the PR is merged into a registry, our indexing will add it to the API on our next indexing run (hourly).
# Configuration
This page details your widget configuration options. Tweak it to fit your exact user experience needs!
# Component Props
The `Widget` component accepts the following props.
### `defaultRoute`
Customizes the initial route displayed on widget load. Query supported assets using the Skip Go API [/assets](https://docs.skip.build/go/api-reference/prod/fungible/get-v2fungibleassets) endpoint. Setting this triggers a route request on render.
```ts
defaultRoute?: {
amountIn?: number;
amountOut?: number;
srcChainId?: string;
srcAssetDenom?: string;
destChainId?: string;
destAssetDenom?: string;
};
```
* `amountIn`: Preset input amount for exact amount in request.
* `amountOut`: Preset output amount for exact amount out request. If both specified, only `amountIn` is used.
* `srcChainId` : Source chain ID.
* `srcAssetDenom`: Source asset denomination.
* `destChainId`: Destination chain ID.
* `destAssetDenom`: Destination asset denomination.
### `routeConfig`
Customizes enabled route types.
```ts
routeConfig?: {
experimentalFeatures?: ['hyperlane', 'cctp', 'stargate'];
allowMultiTx?: boolean;
allowUnsafe?: boolean;
bridges?: ('IBC' | 'AXELAR' | 'CCTP' | 'HYPERLANE' | 'GO_FAST')[];
swapVenues?: {
name: string;
chainId: string;
}[];
goFast?: boolean;
smartSwapOptions?: SmartSwapOptions;
};
```
* `allowMultiTx`: Allow multi-transaction routes. Default: true.
* `allowUnsafe`: Allow unsafe routes. Default: false. [More info](../advanced-swapping/allow_unsafe-preventing-handling-bad-execution).
* `bridges`: Restrict routing to specific bridges. Default: empty (all bridges).
* `swapVenues`: Restrict routing to specific swap venues. Default: empty (all venues).
* `goFast`: Enable Go Fast transfers. Default: false. [More info](../advanced-transfer/go-fast).
* `smartSwapOptions`: Advanced swapping features like EVM Swaps and split trade routes. [More info](../advanced-swapping/smart-swap-options).
### `filter`
Limits source and destination chains and assets.
```ts
filter?: {
source?: Record;
destination?: Record;
};
```
Example:
```ts
{
source: {
'noble-1': undefined,
},
destination: {
'cosmoshub-4': ['uatom', 'ibc/2181AAB0218EAC24BC9F86BD1364FBBFA3E6E3FCC25E88E3E68C15DC6E752D86'],
'agoric-3': ['ibc/FE98AAD68F02F03565E9FA39A5E627946699B2B07115889ED812D8BA639576A9'],
'osmosis-1': undefined,
}
}
```
### `settings`
Sets defaults for user-customizable settings.
```ts
settings?: {
customGasAmount?: number;
slippage?: number;
};
```
* `customGasAmount`: Gas amount for CosmosSDK chain transactions. Default: `300_000`.
* `slippage`: Default slippage percentage (0-100) for CosmosSDK chain swaps. Default: `1`.
### `onlyTestnet`
`onlyTestnet`: Boolean to show only testnet data. Default: false (mainnet data only).
### `endpointOptions`
Override default Skip proxied endpoints. Whitelisting required, reach out [here](https://skip.build/discord).
```ts
endpointOptions?: {
endpoints?: Record;
getRpcEndpointForChain?: (chainID: string) => Promise;
getRestEndpointForChain?: (chainID: string) => Promise;
};
```
### `apiUrl`
String to override default Skip Go API proxied endpoints. Whitelisting required, reach out [here](https://skip.build/discord).
### `brandColor`
Customizes the main highlight color of the widget
### `theme`
Advanced widget appearance customization options
```tsx
theme? = {
brandColor: string;
primary: {
background: {
normal: string;
};
text: {
normal: string;
lowContrast: string;
ultraLowContrast: string;
};
ghostButtonHover: string;
};
secondary: {
background: {
normal: string;
transparent: string;
hover: string;
};
};
success: {
text: string;
};
warning: {
background: string;
text: string;
};
error: {
background: string;
text: string;
};
};
```
### `chainIdsToAffiliates`
Define fees per chain and recipient addresses.
Total basisPointsFee must be consistent across chains. Addresses must be valid for respective chains.
```ts
chainIdsToAffiliates: {
'noble-1': {
affiliates: [{
basisPointsFee: '100', // 1% fee
address: 'noble..1', // address to receive fee
},
{
basisPointsFee: '100', // 1% fee
address: 'noble...2', // address to receive fee
}]
},
'osmosis-1': {
affiliates: [{
basisPointsFee: '200', // 2% fee
address: 'osmo...1', // address to receive fee
},]
}
}
```
### `callbacks`
Event handling functions.
```ts
onWalletConnected?: (params: {
walletName?: string;
chainIdToAddressMap: Record;
address?: string;
}) => void;
onWalletDisconnected?: (params: {
walletName?: string;
chainType?: string;
}) => void;
onTransactionBroadcasted?: (params: {
txHash: string;
chainId: string;
explorerLink?: string;
sourceAddress: string;
destinationAddress: string;
sourceAssetDenom: string;
sourceAssetChainID: string;
destAssetDenom: string;
destAssetChainID: string;
}) => void;
onTransactionComplete?: (params: {
txHash: string;
chainId: string;
explorerLink?: string;
sourceAddress: string;
destinationAddress: string;
sourceAssetDenom: string;
sourceAssetChainID: string;
destAssetDenom: string;
destAssetChainID: string;
}) => void;
onTransactionFailed?: (params: { error: Error }) => void;
```
* `onWalletConnected`: Called when a wallet is connected.
* `onWalletDisconnected`: Called when a wallet is disconnected.
* `onTransactionBroadcasted`: Called when a transaction is broadcasted. This is called multiple times for multi-transaction routes.
* `onTransactionComplete`: Triggered when a transaction is completed.
* `onTransactionFailed`: Triggered when a transaction fails.
### `connectedAddresses` & `signers`
If your application has already connected to a user's wallet (e.g., via MetaMask for EVM networks, Phantom for Solana, or Keplr for Cosmos), you **must provide both** the `connectedAddresses` and corresponding signer functions in order to enable the widget’s injected wallet functionality.\
See an implementation example [here](https://github.com/skip-mev/skip-go/tree/staging/examples/nextjs/src/app/injected/page.tsx).
`WalletClient` comes from the [`viem` package](https://viem.sh/docs/clients/wallet.html). `Adapter` comes from the [`@solana/wallet-adapter-base` package](https://solana.com/developers/cookbook/wallets/connect-wallet-react). And `OfflineSigner` comes from the [`@cosmjs` package](https://docs.keplr.app/api/cosmjs.html).
* **Type:** `Record`
**Example:**
```typescript
const connectedAddresses: Record = {
"1": "0x123...abc", // Ethereum mainnet address
"cosmoshub-4": "cosmos1...", // Cosmos Hub address
"solana": "3n9...xyz", // Solana address
// ... add more chain IDs and addresses as needed
};
```
### Signer Functions
Each signer function below must be implemented to fully leverage the injected wallet capabilities:
* **`getCosmosSigner(): Promise`**\
Returns a Cosmos-compatible signer.
* **`getEVMSigner(): Promise`**\
Returns an EVM-compatible signer (e.g., from `viem`).
* **`getSVMSigner(): Promise`**\
Returns a Solana-compatible signer, such as a `PhantomWalletAdapter`.
**Complete Example for injected wallet functionality:**
```jsx
```
# FAQ
## How do I fix the "Buffer is not defined" error?
If you see a 'Buffer is not defined' error when using @skip-go/widget, it's likely because the widget depends on Node.js modules that aren't available in the browser. To fix this, you'll need to add polyfills for those modules.
Here are some polyfill plugins for common environments:
* [Webpack](https://www.npmjs.com/package/node-polyfill-webpack-plugin)
* [Rollup](https://www.npmjs.com/package/rollup-plugin-polyfill-node)
* [Vite](https://www.npmjs.com/package/vite-plugin-node-polyfills)
* [ESBuild](https://www.npmjs.com/package/esbuild-plugins-node-modules-polyfill)
## Should I put the widget inside a container with a fixed size?
It is recommended to wrap the widget with a container element that has a fixed size. This helps to prevent layout shifting as the widget uses the shadow-dom (which needs to be rendered client-side). We recommend a height of `640px` and a width of `500px`.
# Getting Started
# Overview
The Skip Go `Widget` is the easiest way to onboard users and capital from anywhere in the world to your corner of the sovereign web! The widget provides seamless cross-chain bridging, swapping, and transferring functionality in an easy to integrate React or [Web component](./web-component.mdx).
# Useful Links
* [Skip Go Repository](https://github.com/skip-mev/skip-go)
* [Example Widget Implementation](https://github.com/skip-mev/skip-go/tree/main/examples/nextjs)
# Quickstart Guide
This guide will walk you though how to integrate the `Widget` into your React app.
Starting from scratch? It's recommended to use a React framework like [Next.js](https://nextjs.org/docs/getting-started/installation) or [Create React App](https://create-react-app.dev/docs/getting-started) to get up and running quickly.
```shell NPM
npm install @skip-go/widget
```
```shell Yarn
yarn add @tanstack/react-query viem wagmi
```
If you're using `yarn` (or another package manager that doesn't install peer dependencies by default)
you may need to install these peer dependencies as well:
```bash
yarn add @tanstack/react-query viem wagmi
```
Next, use the `Widget` component to render the swap interface:
```typescript
import { Widget } from '@skip-go/widget';
const SwapPage = () => {
return (
);
};
```
Now that you have the widget integrated, it's time to configure the user experience. Find more details on widget configuration [here](./configuration).
If there's any functionality or configurations you'd like to see in the widget, we'd love for you to contribute by opening up an issue or pull request in [the repository](https://github.com/skip-mev/skip-go/tree/main/packages/widget) or by joining [our Discord](https://skip.build/discord) and giving us a shout!
# Widget V2 Migration Guide
This guide provides a concise overview of the changes needed to migrate your existing Widget V1 implementation to Widget V2.
## 1. Update Dependency (`latest` or `^3.0.0`)
```shell NPM
npm install @skip-go/widget@latest
```
```shell Yarn
yarn add @skip-go/widget@latest
```
If you're using `yarn` (or another package manager that doesn't install peer dependencies by default)
you may need to install these peer dependencies as well:
```bash
yarn add @tanstack/react-query graz react react-dom viem wagmi
```
## 2. `theme` Prop Changes
### More Customization Options
You can pass either `light`, `dark`, or a custom theme object with granular
control over the widget's appearance.
**Before:**
```tsx
```
**After:**
```tsx
```
The custom theme object has the following structure:
```tsx
theme = {
brandColor: string;
primary: {
background: {
normal: string;
transparent: string;
};
text: {
normal: string;
lowContrast: string;
ultraLowContrast: string;
};
ghostButtonHover: string;
};
secondary: {
background: {
normal: string;
transparent: string;
hover: string;
};
};
success: {
text: string;
};
warning: {
background: string;
text: string;
};
error: {
background: string;
text: string;
};
};
```
## 3. Prop Spelling Changes
### `chainID` Renamed to `chainId`
### `apiURL` Renamed to `apiUrl`
Update all instances of `chainID` to `chainId`, notably in the `defaultRoute` prop.
**Before:**
```tsx
```
**After:**
```tsx
```
## 4. Temporarily Disabled Features
The following props will be reintroduced in future versions of `Widget`.
### a. `connectedWallet` Prop
The connectedWallet prop, which allowed passing a custom wallet provider, isn't currently supported.
### b. `CallbackStore` Callback Props
The `onWalletConnected`, `onWalletDisconnected`, `onTransactionBroadcasted`, `onTransactionComplete`, and `onTransactionFailed` callback props aren't currently supported.
## 5. Removed Features
### a. `persistWidgetState`
This prop is no longer supported, as the `Widget` persists state by default.
### b. `toasterProps`
The `toasterProps` prop has been removed because the `Widget` no longer generates notifications.
### c. `makeDestinationWallets`
The `makeDestinationWallets` prop has been removed. The `Widget` now automatically generates destination wallets from connected wallets or manual user entry.
By implementing these changes, you can successfully migrate your application from Widget V1 to Widget V2. For further assistance, refer to the official documentation or reach out to the [support team](https://discord.com/channels/1010553709987639406/1210022796797677589).
# Web Component
For non-React applications, the Skip Go `Widget` is available as a web component.
# Installation
You can import the web component in two ways:
## 1. NPM
```ts
import('@skip-go/widget-web-component');
```
Note: Ensure Node has sufficient memory allocated: `CopyNODE_OPTIONS=--max-old-space-size=32384`
This can be added to npm scripts in `package.json`, a `.env file`, or used when running Node directly.
## 2. Script Tag or CDN (Recommended)
```html
```
## Usage
Props are the same as [`WidgetProps`](./configuration), but passed as attributes in kebab-case. Use strings or stringified objects for complex props.
```tsx
```
## Performance Considerations
It's recommended to lazy load this component as it comes pre-bundled with all dependencies, which may impact load times, especially in development environments.