@gibs/quotes
v1.20.0
Published
Isomorphic core for asking cross-chain bridge aggregators (LI.FI, Relay, NEAR Intents) for display and execution quotes — the wire contract, refusal reading, and the shared guards a host wraps every upstream call in. Runs unchanged in a browser or in Node
Maintainers
Readme
@gibs/quotes
An isomorphic core for asking cross-chain bridge aggregators (LI.FI, Relay, NEAR Intents) for display and execution quotes. It runs unchanged in a browser, in Node, or in React Native.
The package holds the wire contract, the refusal reader, the carriers, and the guards a host wraps around every upstream call. For the full integration guide, read llms.txt in this package.
Install
npm install @gibs/quotes viemviem is a peer dependency. The supported range is >=2.35.0 <3.
Requirements
- Node 20 or later, a modern browser, or React Native 0.77 or later under Hermes.
importloads the ECMAScript module build (dist/).requireloads the CommonJS build (dist/cjs/).- React Native needs no change to
metro.config.js, noresolveRequesthook, no jesttransformIgnorePatternsand no polyfill. It runs on React Native's ownURLandURLSearchParams, which React Native 0.77 implements only in part: no code in the package reads them. Metro in React Native 0.79 or later reads theexportsmap. Metro in 0.77 and 0.78 ignores it, and finds each subpath through a folder the package ships for it (for examplecarriers/lifi/package.json), which points at the CommonJS build.
Example
import { createQuoteClient, type QuoteClientConfig } from '@gibs/quotes'
const config: QuoteClientConfig = {
// 'direct' lets the client ask the aggregators itself when no service answers.
fallback: 'direct',
}
const client = createQuoteClient(config)
// A snapshot of the client's own counters.
console.log(client.statsSnapshot())To ask for quotes, call client.displayQuotes(request). The request shape is DisplayQuoteRequest, and llms.txt describes it.
Overriding swap routers
searchBridgeRoutes swaps on PulseX V1 and V2 on PulseChain by default. Pass
swapVenues to use other routers. A chain you name replaces that chain's default
list. A chain you leave out keeps its defaults. An empty list switches swaps off
on that chain. A venue on any chain builds swap steps on that chain.
import { searchBridgeRoutes } from '@gibs/quotes/search'
import type { SwapVenues } from '@gibs/bridge-sdk'
const swapVenues: SwapVenues = {
1: [{
kind: 'uniswap-v2',
chainId: 1,
router: '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
factory: '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f',
feeBasisPoints: 30,
}],
}
// await searchBridgeRoutes({ ...input, swapVenues })The search asks getAmountsOut of the router each swap step names. It also
prices PulseChain tokens on the routers in the venues. To sign the result, pass the
same swapVenues to planCandidateExecution from @gibs/bridge-sdk.
Same-asset bridging
A bridge delivers the same asset on the other chain. A native coin goes to a native coin. An ERC-20 goes to its own counterpart. Changing one token into another is a swap.
counterpartOf from @gibs/quotes/search finds that counterpart:
import { counterpartOf } from '@gibs/quotes/search';
const found = await counterpartOf({ token: { address }, fromChainId: 1, toChainId: 8453, fetch, signal });
// { kind: 'native' } | { kind: 'token', token, rule } | nullThe rules run in this order. Each is strict. Anything unsure answers null.
native: a native coin maps to the far native coin.omnibridge-pair: to or from PulseChain, only the gib.show omnibridge pairs decide. LI.FI is never asked about PulseChain.lifi-coin-key: between other chains, a verified LI.FI token with the samecoinKey, when the key names exactly one verified token on each chain.lifi-symbol-name-price: when no sharedcoinKeydecides, the same symbol (unique on each chain), the same name, and prices within 3 percent (COUNTERPART_PRICE_TOLERANCE).
searchBridgeRoutes takes a mode that uses the answer:
| mode | Serves |
| -------- | ----------------------------------------------------------------- |
| 'both' | Everything. This is the default and the old behaviour. |
| 'bridge' | Only routes that deliver the counterpart. Swaps inside a route stay allowed, so Ether to Pulse keeps its PulseX step. |
| 'swap' | Only routes that deliver another asset. |
When the mode cannot be met, the search returns at once with no routes and one
entry in refusals that says why. It asks no quote first. 'bridge' and
'swap' read LI.FI lists for two chains that are not PulseChain, so a host
that switches LI.FI off gets no counterpart there.
The search also drops duplicate routes. Two routes that run the same carriers
in the same order, on the same venues, and deliver the same amount are one
route. The better-ranked copy stays, with its pathKey unchanged.
A live check of counterpartOf runs only when you set GIBS_LIVE=1:
GIBS_LIVE=1 npx vitest run src/search/counterpart.live.test.ts.
Subpath exports
The root entry re-exports most modules. Subpaths such as @gibs/quotes/quote-guards, @gibs/quotes/upstream, @gibs/quotes/carriers/relay, and @gibs/quotes/search let you load one module alone.
License
ISC
