@latchprotocol/widgets 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +649 -0
- package/dist/adapters/binDistribution.d.ts +19 -0
- package/dist/adapters/binDistribution.d.ts.map +1 -0
- package/dist/adapters/protocol.d.ts +409 -0
- package/dist/adapters/protocol.d.ts.map +1 -0
- package/dist/adapters/sale.d.ts +142 -0
- package/dist/adapters/sale.d.ts.map +1 -0
- package/dist/adapters/viem.d.ts +89 -0
- package/dist/adapters/viem.d.ts.map +1 -0
- package/dist/callpath/constants.d.ts +218 -0
- package/dist/callpath/constants.d.ts.map +1 -0
- package/dist/callpath/launch.d.ts +1979 -0
- package/dist/callpath/launch.d.ts.map +1 -0
- package/dist/callpath/liquidity.d.ts +103 -0
- package/dist/callpath/liquidity.d.ts.map +1 -0
- package/dist/callpath/plan.d.ts +34 -0
- package/dist/callpath/plan.d.ts.map +1 -0
- package/dist/callpath/swap.d.ts +129 -0
- package/dist/callpath/swap.d.ts.map +1 -0
- package/dist/chunks/SwapWidget-DgyHAVc8.js +2404 -0
- package/dist/chunks/SwapWidget-DgyHAVc8.js.map +1 -0
- package/dist/chunks/scan-Dhu7f4Nl.js +2497 -0
- package/dist/chunks/scan-Dhu7f4Nl.js.map +1 -0
- package/dist/chunks/useLocker-D1c_NTk-.js +1613 -0
- package/dist/chunks/useLocker-D1c_NTk-.js.map +1 -0
- package/dist/components/LaunchWidget.d.ts +117 -0
- package/dist/components/LaunchWidget.d.ts.map +1 -0
- package/dist/components/LiquidityWidget.d.ts +33 -0
- package/dist/components/LiquidityWidget.d.ts.map +1 -0
- package/dist/components/LockerWidget.d.ts +51 -0
- package/dist/components/LockerWidget.d.ts.map +1 -0
- package/dist/components/LocksWidgets.d.ts +61 -0
- package/dist/components/LocksWidgets.d.ts.map +1 -0
- package/dist/components/SwapWidget.d.ts +165 -0
- package/dist/components/SwapWidget.d.ts.map +1 -0
- package/dist/components/TokenTrustPanel.d.ts +32 -0
- package/dist/components/TokenTrustPanel.d.ts.map +1 -0
- package/dist/components/lockCharts.d.ts +29 -0
- package/dist/components/lockCharts.d.ts.map +1 -0
- package/dist/components/portal.d.ts +10 -0
- package/dist/components/portal.d.ts.map +1 -0
- package/dist/components/primitives.d.ts +139 -0
- package/dist/components/primitives.d.ts.map +1 -0
- package/dist/components/swap/SwapSettings.d.ts +12 -0
- package/dist/components/swap/SwapSettings.d.ts.map +1 -0
- package/dist/components/swap/TokenSelect.d.ts +61 -0
- package/dist/components/swap/TokenSelect.d.ts.map +1 -0
- package/dist/components/swap/state.d.ts +208 -0
- package/dist/components/swap/state.d.ts.map +1 -0
- package/dist/config/chain.d.ts +163 -0
- package/dist/config/chain.d.ts.map +1 -0
- package/dist/config/integrator.d.ts +121 -0
- package/dist/config/integrator.d.ts.map +1 -0
- package/dist/context/WidgetProvider.d.ts +78 -0
- package/dist/context/WidgetProvider.d.ts.map +1 -0
- package/dist/core/clMath.d.ts +98 -0
- package/dist/core/clMath.d.ts.map +1 -0
- package/dist/core/errors.d.ts +18 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/format.d.ts +47 -0
- package/dist/core/format.d.ts.map +1 -0
- package/dist/core/liquidityGuards.d.ts +53 -0
- package/dist/core/liquidityGuards.d.ts.map +1 -0
- package/dist/core/liquidityRefresh.d.ts +35 -0
- package/dist/core/liquidityRefresh.d.ts.map +1 -0
- package/dist/core/math.d.ts +129 -0
- package/dist/core/math.d.ts.map +1 -0
- package/dist/core/pool.d.ts +33 -0
- package/dist/core/pool.d.ts.map +1 -0
- package/dist/core/tokenLists.d.ts +46 -0
- package/dist/core/tokenLists.d.ts.map +1 -0
- package/dist/embed/iframe.d.ts +185 -0
- package/dist/embed/iframe.d.ts.map +1 -0
- package/dist/embed/lockBadge.d.ts +55 -0
- package/dist/embed/lockBadge.d.ts.map +1 -0
- package/dist/embed/webComponent.d.ts +83 -0
- package/dist/embed/webComponent.d.ts.map +1 -0
- package/dist/embed.d.ts +25 -0
- package/dist/embed.d.ts.map +1 -0
- package/dist/embed.js +543 -0
- package/dist/embed.js.map +1 -0
- package/dist/headless.d.ts +60 -0
- package/dist/headless.d.ts.map +1 -0
- package/dist/headless.js +223 -0
- package/dist/headless.js.map +1 -0
- package/dist/hooks/useAsyncResource.d.ts +38 -0
- package/dist/hooks/useAsyncResource.d.ts.map +1 -0
- package/dist/hooks/useLaunch.d.ts +140 -0
- package/dist/hooks/useLaunch.d.ts.map +1 -0
- package/dist/hooks/useLiquidity.d.ts +91 -0
- package/dist/hooks/useLiquidity.d.ts.map +1 -0
- package/dist/hooks/useLocker.d.ts +77 -0
- package/dist/hooks/useLocker.d.ts.map +1 -0
- package/dist/hooks/useLocks.d.ts +33 -0
- package/dist/hooks/useLocks.d.ts.map +1 -0
- package/dist/hooks/useSwapExecute.d.ts +46 -0
- package/dist/hooks/useSwapExecute.d.ts.map +1 -0
- package/dist/hooks/useSwapQuote.d.ts +51 -0
- package/dist/hooks/useSwapQuote.d.ts.map +1 -0
- package/dist/hooks/useTokenLists.d.ts +26 -0
- package/dist/hooks/useTokenLists.d.ts.map +1 -0
- package/dist/hooks/useTokenTrust.d.ts +40 -0
- package/dist/hooks/useTokenTrust.d.ts.map +1 -0
- package/dist/hooks/useTokens.d.ts +15 -0
- package/dist/hooks/useTokens.d.ts.map +1 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1052 -0
- package/dist/index.js.map +1 -0
- package/dist/latch-embed.d.ts +19 -0
- package/dist/latch-embed.d.ts.map +1 -0
- package/dist/latch-embed.js +950 -0
- package/dist/latch-embed.js.map +1 -0
- package/dist/latch-embed.mjs +13162 -0
- package/dist/latch-embed.mjs.map +1 -0
- package/dist/locker/model.d.ts +73 -0
- package/dist/locker/model.d.ts.map +1 -0
- package/dist/locks/embedModel.d.ts +22 -0
- package/dist/locks/embedModel.d.ts.map +1 -0
- package/dist/locks/fetch.d.ts +60 -0
- package/dist/locks/fetch.d.ts.map +1 -0
- package/dist/locks/model.d.ts +143 -0
- package/dist/locks/model.d.ts.map +1 -0
- package/dist/locks/scan.d.ts +25 -0
- package/dist/locks/scan.d.ts.map +1 -0
- package/dist/styles/css.d.ts +32 -0
- package/dist/styles/css.d.ts.map +1 -0
- package/dist/styles.css +895 -0
- package/dist/trust/model.d.ts +48 -0
- package/dist/trust/model.d.ts.map +1 -0
- package/package.json +102 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The swap widget's state, as pure functions.
|
|
3
|
+
*
|
|
4
|
+
* `SwapWidget` renders; everything it decides lives here so it can be tested
|
|
5
|
+
* without a DOM (the unit suite renders through `react-dom/server`, where no
|
|
6
|
+
* effect runs and no button can be pressed). The shape:
|
|
7
|
+
*
|
|
8
|
+
* - A **pair** is unordered but anchored: `token` is the thing being traded,
|
|
9
|
+
* `quote` what it is priced in. A **side** orients it - `buy` pays the quote
|
|
10
|
+
* and receives the token, `sell` the reverse. The Sell / Buy panels always
|
|
11
|
+
* show the oriented view; the anchor is what a host pins with `pair` and what
|
|
12
|
+
* `side` flips over, so a side change never touches the selection itself.
|
|
13
|
+
* - The flip button turns the trade around: the amount the current quote
|
|
14
|
+
* would have delivered becomes the amount you pay (the widget is exact-input
|
|
15
|
+
* only, so the typed number cannot stay on the panel it was typed for), and
|
|
16
|
+
* with no quote in hand the field is cleared. A side change that did not
|
|
17
|
+
* come from the flip (a host's controlled `side`) keeps the typed amount.
|
|
18
|
+
* Either way the quote re-reads and nothing of the old one is shown. The
|
|
19
|
+
* price-impact acknowledgement is reset because it was given for a
|
|
20
|
+
* different trade.
|
|
21
|
+
* - Portions are fractions of the input balance. There is no balance without
|
|
22
|
+
* a wallet, so a portion without one is refused, never estimated.
|
|
23
|
+
*/
|
|
24
|
+
import type { RouteStep, SwapQuoteResult, TokenInfo } from "../../adapters/protocol.js";
|
|
25
|
+
import type { PriceImpactSeverity, QuoteBreakdown } from "../../core/math.js";
|
|
26
|
+
import type { AsyncStatus } from "../../hooks/useAsyncResource.js";
|
|
27
|
+
/** Which way a pinned pair is traded: `buy` pays the quote for the token. */
|
|
28
|
+
export type SwapSide = "buy" | "sell";
|
|
29
|
+
/**
|
|
30
|
+
* A pair for {@link SwapWidget}'s `pair` prop, by address or by `TokenInfo`.
|
|
31
|
+
* `{ token, quote }` is the anchored form; `{ tokenIn, tokenOut }` is the same
|
|
32
|
+
* pair given in its `buy` orientation (`tokenIn` is the quote).
|
|
33
|
+
*/
|
|
34
|
+
export type SwapPair = {
|
|
35
|
+
readonly token: string | TokenInfo;
|
|
36
|
+
readonly quote: string | TokenInfo;
|
|
37
|
+
} | {
|
|
38
|
+
readonly tokenIn: string | TokenInfo;
|
|
39
|
+
readonly tokenOut: string | TokenInfo;
|
|
40
|
+
};
|
|
41
|
+
/** A pair reduced to its anchored form. */
|
|
42
|
+
export interface AnchoredPair<T> {
|
|
43
|
+
readonly token: T;
|
|
44
|
+
readonly quote: T;
|
|
45
|
+
}
|
|
46
|
+
/** The two panels' tokens. */
|
|
47
|
+
export interface OrientedPair<T> {
|
|
48
|
+
readonly tokenIn: T;
|
|
49
|
+
readonly tokenOut: T;
|
|
50
|
+
}
|
|
51
|
+
/** Reduces either `SwapPair` shape to `{ token, quote }`. */
|
|
52
|
+
export declare function normalizePair(pair: SwapPair): AnchoredPair<string | TokenInfo>;
|
|
53
|
+
/** The address of a pair entry, lower-cased. */
|
|
54
|
+
export declare function pairEntryAddress(entry: string | TokenInfo): string;
|
|
55
|
+
/** A stable key for a pair prop, so a re-render with an equal pair is not a re-pin. */
|
|
56
|
+
export declare function pairKey(pair: SwapPair | undefined): string | null;
|
|
57
|
+
/** Finds a token in a list by address, case-insensitively. */
|
|
58
|
+
export declare function findToken(tokens: readonly TokenInfo[], address: string | undefined): TokenInfo | null;
|
|
59
|
+
/**
|
|
60
|
+
* Resolves a pair entry: a `TokenInfo` is taken as given; an address is looked
|
|
61
|
+
* up in the list. `null` means the list does not carry it (the widget then asks
|
|
62
|
+
* the adapter for the token contract).
|
|
63
|
+
*/
|
|
64
|
+
export declare function resolvePairEntry(entry: string | TokenInfo, tokens: readonly TokenInfo[]): TokenInfo | null;
|
|
65
|
+
/** Orients an anchored pair for the panels: `buy` pays the quote. */
|
|
66
|
+
export declare function orientPair<T>(anchor: AnchoredPair<T>, side: SwapSide): OrientedPair<T>;
|
|
67
|
+
/** The inverse of {@link orientPair}: what the panels show, as an anchor. */
|
|
68
|
+
export declare function unorientPair<T>(oriented: OrientedPair<T>, side: SwapSide): AnchoredPair<T>;
|
|
69
|
+
/** The other side. */
|
|
70
|
+
export declare function oppositeSide(side: SwapSide): SwapSide;
|
|
71
|
+
/** The widget's default portion chips: 25%, 50%, 75% and Max (the design's four quick amounts). */
|
|
72
|
+
export declare const DEFAULT_PORTIONS: readonly number[];
|
|
73
|
+
/**
|
|
74
|
+
* Validates a `portions` prop. Every entry must be a finite fraction in
|
|
75
|
+
* `(0, 1]`; the order given is the order rendered. An empty list hides the
|
|
76
|
+
* chips. Throws, like every other bad widget config, rather than rendering a
|
|
77
|
+
* chip that would compute a nonsense amount.
|
|
78
|
+
*/
|
|
79
|
+
export declare function normalizePortions(portions: readonly number[] | undefined): readonly number[];
|
|
80
|
+
/** The chip label for a fraction: `1` is "Max", the rest a percentage. */
|
|
81
|
+
export declare function portionLabel(fraction: number): string;
|
|
82
|
+
/**
|
|
83
|
+
* A fraction of a balance, in the token's smallest unit. On the native asset
|
|
84
|
+
* the whole balance keeps a sliver for gas; any smaller fraction, and any
|
|
85
|
+
* ERC-20, is exact. Uses basis-point precision so `0.333` is not lost.
|
|
86
|
+
*/
|
|
87
|
+
export declare function balancePortion(balance: bigint, fraction: number, token: TokenInfo): bigint;
|
|
88
|
+
/**
|
|
89
|
+
* The amount text a portion chip writes into the input, or `null` when there
|
|
90
|
+
* is nothing to take a portion of: no input token, or no balance because no
|
|
91
|
+
* wallet is connected. `null` is a refusal - the widget never guesses a
|
|
92
|
+
* balance - and the caller decides whether to ask for a wallet.
|
|
93
|
+
*
|
|
94
|
+
* Plain decimal text, exact to the token's decimals and never grouped: it is
|
|
95
|
+
* parsed back by `parseAmount`, which takes no thousands separator.
|
|
96
|
+
*/
|
|
97
|
+
export declare function portionAmountText(token: TokenInfo | null, balance: bigint | null, fraction: number): string | null;
|
|
98
|
+
/** What the widget holds between renders. */
|
|
99
|
+
export interface SwapWidgetState {
|
|
100
|
+
/** The anchored selection; `null` entries mean nothing chosen yet. */
|
|
101
|
+
readonly anchor: AnchoredPair<TokenInfo | null>;
|
|
102
|
+
/** The widget's own side. Ignored while the host controls `side`. */
|
|
103
|
+
readonly side: SwapSide;
|
|
104
|
+
/** The typed input amount, verbatim. */
|
|
105
|
+
readonly amountText: string;
|
|
106
|
+
/** Whether the user acknowledged the current trade's price impact. */
|
|
107
|
+
readonly impactAck: boolean;
|
|
108
|
+
}
|
|
109
|
+
/** Every transition the widget makes. */
|
|
110
|
+
export type SwapWidgetAction =
|
|
111
|
+
/** The token list arrived (or the defaults changed) and nothing is selected yet. */
|
|
112
|
+
{
|
|
113
|
+
readonly type: "seed";
|
|
114
|
+
readonly tokens: readonly TokenInfo[];
|
|
115
|
+
readonly defaultTokenIn?: string;
|
|
116
|
+
readonly defaultTokenOut?: string;
|
|
117
|
+
readonly side: SwapSide;
|
|
118
|
+
}
|
|
119
|
+
/** The host's `pair` resolved. Overrides the selection; keeps the amount. */
|
|
120
|
+
| {
|
|
121
|
+
readonly type: "pin";
|
|
122
|
+
readonly anchor: AnchoredPair<TokenInfo | null>;
|
|
123
|
+
}
|
|
124
|
+
/** The Sell panel's selector picked a token. */
|
|
125
|
+
| {
|
|
126
|
+
readonly type: "select-in";
|
|
127
|
+
readonly token: TokenInfo;
|
|
128
|
+
readonly side: SwapSide;
|
|
129
|
+
}
|
|
130
|
+
/** The Buy panel's selector picked a token. */
|
|
131
|
+
| {
|
|
132
|
+
readonly type: "select-out";
|
|
133
|
+
readonly token: TokenInfo;
|
|
134
|
+
readonly side: SwapSide;
|
|
135
|
+
}
|
|
136
|
+
/** The direction flipped (flip button, `flip()` or a controlled `side` change). */
|
|
137
|
+
| {
|
|
138
|
+
readonly type: "set-side";
|
|
139
|
+
readonly side: SwapSide;
|
|
140
|
+
readonly amountText?: string;
|
|
141
|
+
} | {
|
|
142
|
+
readonly type: "amount";
|
|
143
|
+
readonly text: string;
|
|
144
|
+
} | {
|
|
145
|
+
readonly type: "ack";
|
|
146
|
+
readonly value: boolean;
|
|
147
|
+
};
|
|
148
|
+
/** The state before anything is known. */
|
|
149
|
+
export declare const INITIAL_SWAP_STATE: SwapWidgetState;
|
|
150
|
+
/**
|
|
151
|
+
* The initial state for a mount: a pair given as `TokenInfo`s is selected
|
|
152
|
+
* synchronously, so a locked pair renders its chips on the first frame (and in
|
|
153
|
+
* a server render); an address waits for the list.
|
|
154
|
+
*/
|
|
155
|
+
export declare function initialSwapState(options: {
|
|
156
|
+
readonly pair?: SwapPair;
|
|
157
|
+
readonly side?: SwapSide;
|
|
158
|
+
}): SwapWidgetState;
|
|
159
|
+
/** Applies one action. Pure; the component wraps it in `useReducer`. */
|
|
160
|
+
export declare function swapWidgetReducer(state: SwapWidgetState, action: SwapWidgetAction): SwapWidgetState;
|
|
161
|
+
/** One quote as a host sees it through `onQuote`. Smallest units throughout. */
|
|
162
|
+
export interface SwapQuoteView {
|
|
163
|
+
readonly tokenIn: TokenInfo;
|
|
164
|
+
readonly tokenOut: TokenInfo;
|
|
165
|
+
readonly amountIn: bigint;
|
|
166
|
+
/** What the user receives after the integrator fee. */
|
|
167
|
+
readonly amountOut: bigint;
|
|
168
|
+
/** Output before the integrator fee, as the pool quotes it. */
|
|
169
|
+
readonly grossAmountOut: bigint;
|
|
170
|
+
/** The floor after slippage and the integrator fee - what the transaction enforces. */
|
|
171
|
+
readonly minReceived: bigint;
|
|
172
|
+
readonly integratorFee: bigint;
|
|
173
|
+
readonly slippageBps: number;
|
|
174
|
+
/** `null` when the pool's fee is hook-set: an impact that silently included it would be an invented number. */
|
|
175
|
+
readonly priceImpactBps: number | null;
|
|
176
|
+
readonly priceImpactSeverity: PriceImpactSeverity;
|
|
177
|
+
readonly lpFee: {
|
|
178
|
+
readonly pips: number;
|
|
179
|
+
readonly unknown: boolean;
|
|
180
|
+
/** Ready to print: a percentage, or `dynamic (hook-set)`. */
|
|
181
|
+
readonly label: string;
|
|
182
|
+
};
|
|
183
|
+
readonly route: readonly RouteStep[];
|
|
184
|
+
/** The route's token symbols, input first. */
|
|
185
|
+
readonly routeSymbols: readonly string[];
|
|
186
|
+
/** Output units per input unit, for display. */
|
|
187
|
+
readonly rate: number | null;
|
|
188
|
+
readonly status: AsyncStatus;
|
|
189
|
+
/** `true` while a newer quote is being read over this one. */
|
|
190
|
+
readonly isRefreshing: boolean;
|
|
191
|
+
readonly isMock: boolean;
|
|
192
|
+
readonly updatedAt: number | null;
|
|
193
|
+
}
|
|
194
|
+
/** Symbols along a route, input first, blanks dropped. */
|
|
195
|
+
export declare function routeSymbols(route: readonly RouteStep[]): readonly string[];
|
|
196
|
+
/** Builds the `onQuote` payload, or `null` while there is no quote to report. */
|
|
197
|
+
export declare function buildSwapQuoteView(input: {
|
|
198
|
+
readonly tokenIn: TokenInfo | null;
|
|
199
|
+
readonly tokenOut: TokenInfo | null;
|
|
200
|
+
readonly quote: SwapQuoteResult | null;
|
|
201
|
+
readonly breakdown: QuoteBreakdown | null;
|
|
202
|
+
readonly rate: number | null;
|
|
203
|
+
readonly status: AsyncStatus;
|
|
204
|
+
readonly isRefreshing: boolean;
|
|
205
|
+
readonly isMock: boolean;
|
|
206
|
+
readonly updatedAt: number | null;
|
|
207
|
+
}): SwapQuoteView | null;
|
|
208
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/components/swap/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chain and deployment configuration.
|
|
3
|
+
*
|
|
4
|
+
* LatchProtocol targets many chains, and nothing in this package knows which one
|
|
5
|
+
* you are on. There are no bundled RPC URLs and no address book: every address
|
|
6
|
+
* and every transport arrives from the embedder through a {@link ChainConfig}.
|
|
7
|
+
* That is deliberate - a hardcoded address is a bug that ships to every host.
|
|
8
|
+
*/
|
|
9
|
+
import { type Address, type Transport } from "viem";
|
|
10
|
+
/** Native asset metadata for a chain. */
|
|
11
|
+
export interface NativeCurrencyConfig {
|
|
12
|
+
readonly name: string;
|
|
13
|
+
readonly symbol: string;
|
|
14
|
+
readonly decimals: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Deployed contract addresses.
|
|
18
|
+
*
|
|
19
|
+
* Only `vault` and at least one pool manager are structurally required. The
|
|
20
|
+
* rest are required by the operations that use them, and the widgets fail with
|
|
21
|
+
* a named error rather than a decoding failure when one is missing.
|
|
22
|
+
*/
|
|
23
|
+
export interface ContractAddresses {
|
|
24
|
+
/** The singleton that custodies every token in the protocol. */
|
|
25
|
+
readonly vault: Address;
|
|
26
|
+
/** Concentrated-liquidity pool manager. */
|
|
27
|
+
readonly clPoolManager?: Address;
|
|
28
|
+
/** Liquidity-book (bin) pool manager. */
|
|
29
|
+
readonly binPoolManager?: Address;
|
|
30
|
+
/** Universal router - the entry point for swaps and integrator fees. */
|
|
31
|
+
readonly universalRouter?: Address;
|
|
32
|
+
/** Position manager for concentrated-liquidity positions. */
|
|
33
|
+
readonly clPositionManager?: Address;
|
|
34
|
+
/** Position manager for liquidity-book positions. */
|
|
35
|
+
readonly binPositionManager?: Address;
|
|
36
|
+
/** Permit2, used by the router to pull the input currency. */
|
|
37
|
+
readonly permit2?: Address;
|
|
38
|
+
/** Off-path CL quoter (`CLQuoter`), if one is deployed. Quotes concentrated-liquidity hops. */
|
|
39
|
+
readonly quoter?: Address;
|
|
40
|
+
/** Off-path `BinQuoter`, if one is deployed. Quotes liquidity-book hops. */
|
|
41
|
+
readonly binQuoter?: Address;
|
|
42
|
+
/**
|
|
43
|
+
* `LaunchGuardHook`, the hook that backs the launch widget.
|
|
44
|
+
*
|
|
45
|
+
* Not a launchpad and not a sale contract: it is the hook a launch pool names
|
|
46
|
+
* in its `PoolKey`, and the launch widget reads its per-pool schedule. Leave
|
|
47
|
+
* it unset on a chain where no `LaunchGuardHook` is deployed — the widget
|
|
48
|
+
* renders a "not configured on this chain" state, which is the truth. Setting
|
|
49
|
+
* it to an address that is not a `LaunchGuardHook` produces read failures,
|
|
50
|
+
* not a fallback.
|
|
51
|
+
*/
|
|
52
|
+
readonly launchGuardHook?: Address;
|
|
53
|
+
/**
|
|
54
|
+
* How `launchGuardHook` measures time: `"timestamp"` for the current build,
|
|
55
|
+
* `"contract-block"` for the block-numbered one still deployed on Robinhood.
|
|
56
|
+
* Take it from `LatchDeployment.durationClocks.launchGuardHook` in the SDK.
|
|
57
|
+
* When omitted, the live adapter uses the SDK record if the address matches it,
|
|
58
|
+
* and otherwise asks the hook (`CLOCK_MODE()`), never guessing.
|
|
59
|
+
*/
|
|
60
|
+
readonly launchGuardHookClock?: "timestamp" | "contract-block";
|
|
61
|
+
/**
|
|
62
|
+
* `BinLaunchGuardHook`: the launch guard a Bin (liquidity-book) launch pool
|
|
63
|
+
* names in its `PoolKey`. Same schedule, same gates, same `getLaunch` shape
|
|
64
|
+
* as the CL guard; only ever built on `block.timestamp`. Leave it unset where
|
|
65
|
+
* none is deployed.
|
|
66
|
+
*/
|
|
67
|
+
readonly binLaunchGuardHook?: Address;
|
|
68
|
+
/**
|
|
69
|
+
* `LaunchpadKitV2`, the locked-launch kit. With it set, a launch can be
|
|
70
|
+
* looked up by its TOKEN (`legsOf(token)` names every pool the launch
|
|
71
|
+
* opened) instead of by one pool id. The pools themselves must still be in
|
|
72
|
+
* the host's pool list: the singleton enumerates nothing.
|
|
73
|
+
*/
|
|
74
|
+
readonly launchpadKitV2?: Address;
|
|
75
|
+
}
|
|
76
|
+
/** Everything the widgets need to know about the chain they are pointed at. */
|
|
77
|
+
export interface ChainConfig {
|
|
78
|
+
readonly chainId: number;
|
|
79
|
+
readonly name: string;
|
|
80
|
+
readonly nativeCurrency: NativeCurrencyConfig;
|
|
81
|
+
readonly contracts: ContractAddresses;
|
|
82
|
+
/**
|
|
83
|
+
* viem transport for reads. Omitted when the host drives reads itself (for
|
|
84
|
+
* example through wagmi).
|
|
85
|
+
*/
|
|
86
|
+
readonly transport?: Transport;
|
|
87
|
+
readonly blockExplorerUrl?: string;
|
|
88
|
+
/** Seconds added to `block.timestamp` for transaction deadlines. */
|
|
89
|
+
readonly defaultDeadlineSeconds?: number;
|
|
90
|
+
}
|
|
91
|
+
/** Names of the addresses a caller can require. */
|
|
92
|
+
export type ContractName = keyof ContractAddresses;
|
|
93
|
+
/** Raised when the chain config cannot support a requested operation. */
|
|
94
|
+
export declare class ChainConfigError extends Error {
|
|
95
|
+
readonly chainId: number;
|
|
96
|
+
readonly contract: ContractName | null;
|
|
97
|
+
constructor(message: string, chainId: number, contract?: ContractName | null);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Structural validation of a chain config.
|
|
101
|
+
*
|
|
102
|
+
* Checks shape only. It cannot tell you an address is wrong, just that it is
|
|
103
|
+
* well-formed and present.
|
|
104
|
+
*/
|
|
105
|
+
export declare function assertValidChainConfig(config: ChainConfig): void;
|
|
106
|
+
/**
|
|
107
|
+
* Reads a required address, failing with a message that names what is missing
|
|
108
|
+
* and which operation needed it.
|
|
109
|
+
*/
|
|
110
|
+
export declare function requireContract(config: ChainConfig, name: ContractName, usedFor: string): Address;
|
|
111
|
+
/**
|
|
112
|
+
* The best reading of the clock the NEXT block will carry: the later of the
|
|
113
|
+
* pending block's timestamp and the latest block's, ignoring whichever could
|
|
114
|
+
* not be read; `null` when neither was.
|
|
115
|
+
*
|
|
116
|
+
* WHY THE PENDING BLOCK. `max(latest.timestamp, localNow)` covers an idle
|
|
117
|
+
* chain whose clock matches wall time, and a chain whose clock is AHEAD of
|
|
118
|
+
* wall time (a devnet after `evm_increaseTime`) while it is busy. It does not
|
|
119
|
+
* cover the two together: a chain running ahead of wall time whose last block
|
|
120
|
+
* is older than the deadline window. Its next block is stamped about
|
|
121
|
+
* `localNow + offset`, later than `latest + window`, and `localNow` is below
|
|
122
|
+
* `latest`, so neither term reaches it and the transaction arrives expired.
|
|
123
|
+
* Nothing on the client can know the offset without asking the node; the
|
|
124
|
+
* pending block is that question (anvil and geth-style nodes stamp it with the
|
|
125
|
+
* next block's time). Where the RPC has no pending block it refuses or echoes
|
|
126
|
+
* the latest, and the bound falls back to the latest block's - the residual
|
|
127
|
+
* case is then that one combination on such an RPC, which the window's size
|
|
128
|
+
* (20 minutes by default) makes rare, and the user's wallet reports as the
|
|
129
|
+
* router's deadline error rather than a loss.
|
|
130
|
+
*/
|
|
131
|
+
export declare function nextBlockClock(pending: bigint | null, latest: bigint | null): bigint | null;
|
|
132
|
+
/**
|
|
133
|
+
* Default transaction deadline: base + configured window, as a unix timestamp,
|
|
134
|
+
* where base = max(chain clock, local clock).
|
|
135
|
+
*
|
|
136
|
+
* `nowSeconds` should be the chain's clock (the next block's, see
|
|
137
|
+
* {@link nextBlockClock} and {@link chainDeadline}); the local clock is only
|
|
138
|
+
* the fallback. The later of the two is used, so an idle chain whose last block
|
|
139
|
+
* is old does not produce a deadline that has passed by the time the next
|
|
140
|
+
* block is mined, and a chain ahead of wall time is not given a deadline in
|
|
141
|
+
* its past.
|
|
142
|
+
*/
|
|
143
|
+
export declare function defaultDeadline(config: ChainConfig, nowSeconds?: number | bigint): bigint;
|
|
144
|
+
/**
|
|
145
|
+
* The deadline for a transaction about to be built: the chain's clock (the
|
|
146
|
+
* adapter's `getBlockTimestamp`, which the viem adapter reads from the pending
|
|
147
|
+
* block where the RPC serves one) or the local clock, whichever is later, +
|
|
148
|
+
* the configured window. A failed
|
|
149
|
+
* block read falls back to the local clock rather than blocking the trade.
|
|
150
|
+
*/
|
|
151
|
+
export declare function chainDeadline(config: ChainConfig, adapter: {
|
|
152
|
+
getBlockTimestamp?(): Promise<bigint>;
|
|
153
|
+
}): Promise<bigint>;
|
|
154
|
+
/**
|
|
155
|
+
* Explorer link for a transaction hash, or `null` when no explorer is set.
|
|
156
|
+
*
|
|
157
|
+
* The one place a widget builds an explorer link. An empty (or whitespace-only)
|
|
158
|
+
* `blockExplorerUrl` is NO explorer: a host running against a local devnet
|
|
159
|
+
* passes "" or leaves it out, and a link to "/tx/0x…" would open this page.
|
|
160
|
+
* Callers render the bare hash instead.
|
|
161
|
+
*/
|
|
162
|
+
export declare function explorerTxUrl(config: Pick<ChainConfig, "blockExplorerUrl">, hash: string): string | null;
|
|
163
|
+
//# sourceMappingURL=chain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../../src/config/chain.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integrator fee attribution.
|
|
3
|
+
*
|
|
4
|
+
* This is the module that makes the widgets worth embedding. An integrator -
|
|
5
|
+
* the team whose app hosts the widget - names a `referrer` address and a fee in
|
|
6
|
+
* basis points, and that fee is taken out of the swap's **output** currency and
|
|
7
|
+
* paid to the referrer inside the same transaction as the swap.
|
|
8
|
+
*
|
|
9
|
+
* The fee is not an accounting entry we settle later. It is an action in the
|
|
10
|
+
* swap plan (`TAKE_PORTION`), or a command in the router plan (`PAY_PORTION`),
|
|
11
|
+
* so it either happens atomically with the swap or the whole transaction
|
|
12
|
+
* reverts. Nothing is trusted, escrowed or owed.
|
|
13
|
+
*
|
|
14
|
+
* ## Invariants enforced here
|
|
15
|
+
*
|
|
16
|
+
* 1. `feeBps` is an integer in `[0, MAX_INTEGRATOR_FEE_BPS]`.
|
|
17
|
+
* 2. A non-zero `feeBps` requires a syntactically valid, non-zero `referrer`.
|
|
18
|
+
* Configuring a fee with no destination is a loud failure, never a silent
|
|
19
|
+
* zero: the alternative is a widget that quietly earns the embedder nothing.
|
|
20
|
+
* 3. The predicted fee uses the same arithmetic as the contracts
|
|
21
|
+
* (`amount * bps / 10_000`, truncating), so the number shown in the UI is
|
|
22
|
+
* the number the chain pays out - not an estimate.
|
|
23
|
+
*/
|
|
24
|
+
import { type Address } from "viem";
|
|
25
|
+
/** Basis-point denominator. 10_000 bps = 100%. */
|
|
26
|
+
export declare const BPS_DENOMINATOR = 10000;
|
|
27
|
+
/**
|
|
28
|
+
* Largest integrator fee the widgets will encode, in basis points (1.00%).
|
|
29
|
+
*
|
|
30
|
+
* The on-chain `BipsLibrary.calculatePortion` only rejects values above
|
|
31
|
+
* 10_000 bps, so this ceiling is a client-side policy, not a contract limit.
|
|
32
|
+
* It exists so an embedder cannot ship a widget that quietly takes a third of
|
|
33
|
+
* a user's output, which would poison the widget for every other integrator.
|
|
34
|
+
* Anything above this is a configuration error, not a business decision.
|
|
35
|
+
*/
|
|
36
|
+
export declare const MAX_INTEGRATOR_FEE_BPS = 100;
|
|
37
|
+
/** The zero address, rejected as a fee destination. */
|
|
38
|
+
export declare const ZERO_ADDRESS: Address;
|
|
39
|
+
/**
|
|
40
|
+
* Where the integrator fee is taken in the call path.
|
|
41
|
+
*
|
|
42
|
+
* - `take-portion` - a `TAKE_PORTION` action inside the swap plan. The vault
|
|
43
|
+
* credit is split before anything leaves the singleton, so the router never
|
|
44
|
+
* custodies the fee. This is the default.
|
|
45
|
+
* - `pay-portion` - the swap takes its full output to the router, then a
|
|
46
|
+
* router-level `PAY_PORTION` command forwards the fee and `SWEEP` returns the
|
|
47
|
+
* remainder. Needed when the fee must be taken across a multi-command plan.
|
|
48
|
+
*/
|
|
49
|
+
export type IntegratorFeeMode = "take-portion" | "pay-portion";
|
|
50
|
+
/** Integrator fee configuration, as an embedder writes it. */
|
|
51
|
+
export interface IntegratorConfig {
|
|
52
|
+
/** Address that receives the fee. Required whenever `feeBps > 0`. */
|
|
53
|
+
readonly referrer: Address;
|
|
54
|
+
/** Fee in basis points of the swap output, `0 .. MAX_INTEGRATOR_FEE_BPS`. */
|
|
55
|
+
readonly feeBps: number;
|
|
56
|
+
/** Where in the call path the fee is taken. Defaults to `take-portion`. */
|
|
57
|
+
readonly feeMode?: IntegratorFeeMode;
|
|
58
|
+
/**
|
|
59
|
+
* Free-form label recorded in widget analytics events. Never sent on-chain.
|
|
60
|
+
*/
|
|
61
|
+
readonly label?: string;
|
|
62
|
+
}
|
|
63
|
+
/** Machine-readable reasons an integrator config can be rejected. */
|
|
64
|
+
export type IntegratorConfigErrorCode = "FEE_BPS_NOT_A_NUMBER" | "FEE_BPS_NOT_AN_INTEGER" | "FEE_BPS_NEGATIVE" | "FEE_BPS_ABOVE_MAX" | "REFERRER_MISSING" | "REFERRER_MALFORMED" | "REFERRER_ZERO_ADDRESS" | "FEE_MODE_UNKNOWN";
|
|
65
|
+
/** Thrown when an integrator config cannot be used to build a call path. */
|
|
66
|
+
export declare class IntegratorConfigError extends Error {
|
|
67
|
+
readonly code: IntegratorConfigErrorCode;
|
|
68
|
+
constructor(code: IntegratorConfigErrorCode, message: string);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* A validated integrator config.
|
|
72
|
+
*
|
|
73
|
+
* Only this type reaches the call-path builders. There is no way to construct
|
|
74
|
+
* one except through {@link validateIntegratorConfig}, so an unvalidated fee can
|
|
75
|
+
* never be encoded into a transaction.
|
|
76
|
+
*/
|
|
77
|
+
export interface ResolvedIntegratorConfig {
|
|
78
|
+
readonly referrer: Address;
|
|
79
|
+
readonly feeBps: number;
|
|
80
|
+
readonly feeMode: IntegratorFeeMode;
|
|
81
|
+
readonly label: string | null;
|
|
82
|
+
/** `true` when `feeBps > 0`, i.e. the call path gains a fee step. */
|
|
83
|
+
readonly active: boolean;
|
|
84
|
+
/** Non-fatal configuration remarks worth surfacing in a dev console. */
|
|
85
|
+
readonly warnings: readonly string[];
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Validates and normalises an integrator config.
|
|
89
|
+
*
|
|
90
|
+
* @throws {IntegratorConfigError} on any violation of the documented rules.
|
|
91
|
+
*/
|
|
92
|
+
export declare function validateIntegratorConfig(config: IntegratorConfig): ResolvedIntegratorConfig;
|
|
93
|
+
/** The resolved config used when an embedder configures no integrator at all. */
|
|
94
|
+
export declare const NO_INTEGRATOR_FEE: ResolvedIntegratorConfig;
|
|
95
|
+
/** Validates an optional config, falling back to {@link NO_INTEGRATOR_FEE}. */
|
|
96
|
+
export declare function resolveIntegratorConfig(config: IntegratorConfig | undefined | null): ResolvedIntegratorConfig;
|
|
97
|
+
/**
|
|
98
|
+
* The integrator's cut of `grossAmount`, in the output currency's smallest unit.
|
|
99
|
+
*
|
|
100
|
+
* Mirrors `BipsLibrary.calculatePortion`: multiply first, then divide, so the
|
|
101
|
+
* rounding matches the chain exactly. Integer division truncates, which favours
|
|
102
|
+
* the user by at most one wei.
|
|
103
|
+
*/
|
|
104
|
+
export declare function calculateIntegratorFee(grossAmount: bigint, feeBps: number): bigint;
|
|
105
|
+
/** A gross output amount split into the integrator's cut and the user's. */
|
|
106
|
+
export interface IntegratorFeeSplit {
|
|
107
|
+
/** Output before the integrator fee. */
|
|
108
|
+
readonly grossAmount: bigint;
|
|
109
|
+
/** Amount routed to the referrer. Zero when no fee is active. */
|
|
110
|
+
readonly integratorFee: bigint;
|
|
111
|
+
/** Amount the user actually receives. */
|
|
112
|
+
readonly netAmount: bigint;
|
|
113
|
+
readonly feeBps: number;
|
|
114
|
+
/** Fee destination, or `null` when no fee is active. */
|
|
115
|
+
readonly referrer: Address | null;
|
|
116
|
+
}
|
|
117
|
+
/** Splits a gross output amount according to a validated integrator config. */
|
|
118
|
+
export declare function splitIntegratorFee(grossAmount: bigint, config: ResolvedIntegratorConfig): IntegratorFeeSplit;
|
|
119
|
+
/** Human-readable percentage for a bps value, e.g. `25 -> "0.25%"`. */
|
|
120
|
+
export declare function formatBps(bps: number): string;
|
|
121
|
+
//# sourceMappingURL=integrator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integrator.d.ts","sourceRoot":"","sources":["../../src/config/integrator.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAyB,KAAK,OAAO,EAAE,MAAM,MAAM,CAAC;AAE3D,kDAAkD;AAClD,eAAO,MAAM,eAAe,QAAS,CAAC;AAEtC;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C,uDAAuD;AACvD,eAAO,MAAM,YAAY,EAAE,OAAsD,CAAC;AAElF;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,GAAG,cAAc,GAAG,aAAa,CAAC;AAE/D,8DAA8D;AAC9D,MAAM,WAAW,gBAAgB;IAC/B,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC;IACrC;;OAEG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qEAAqE;AACrE,MAAM,MAAM,yBAAyB,GACjC,sBAAsB,GACtB,wBAAwB,GACxB,kBAAkB,GAClB,mBAAmB,GACnB,kBAAkB,GAClB,oBAAoB,GACpB,uBAAuB,GACvB,kBAAkB,CAAC;AAEvB,4EAA4E;AAC5E,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,IAAI,EAAE,yBAAyB,CAAC;gBAE7B,IAAI,EAAE,yBAAyB,EAAE,OAAO,EAAE,MAAM;CAK7D;AAED;;;;;;GAMG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,qEAAqE;IACrE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAQD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,gBAAgB,GAAG,wBAAwB,CAsG3F;AAED,iFAAiF;AACjF,eAAO,MAAM,iBAAiB,EAAE,wBAO/B,CAAC;AAEF,+EAA+E;AAC/E,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,gBAAgB,GAAG,SAAS,GAAG,IAAI,GAC1C,wBAAwB,CAG1B;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAUlF;AAED,4EAA4E;AAC5E,MAAM,WAAW,kBAAkB;IACjC,wCAAwC;IACxC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,iEAAiE;IACjE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,yCAAyC;IACzC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,wDAAwD;IACxD,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;CACnC;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,wBAAwB,GAC/B,kBAAkB,CAkBpB;AAED,uEAAuE;AACvE,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG7C"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one piece of shared state every widget reads.
|
|
3
|
+
*
|
|
4
|
+
* `WidgetProvider` holds the adapter, the chain config and - critically - the
|
|
5
|
+
* *validated* integrator config. Validation happens once, here, at mount:
|
|
6
|
+
* a bad `feeBps` or a missing `referrer` fails immediately and visibly rather
|
|
7
|
+
* than at the moment a user presses Swap.
|
|
8
|
+
*/
|
|
9
|
+
import { type ReactNode } from "react";
|
|
10
|
+
import type { ProtocolAdapter } from "../adapters/protocol.js";
|
|
11
|
+
import type { ChainConfig } from "../config/chain.js";
|
|
12
|
+
import { type IntegratorConfig, type ResolvedIntegratorConfig } from "../config/integrator.js";
|
|
13
|
+
/** Colour scheme applied to the styled widgets. */
|
|
14
|
+
export type WidgetTheme = "light" | "dark" | "system";
|
|
15
|
+
/** Value exposed to every widget beneath the provider. */
|
|
16
|
+
export interface WidgetContextValue {
|
|
17
|
+
readonly adapter: ProtocolAdapter;
|
|
18
|
+
readonly chain: ChainConfig;
|
|
19
|
+
/** Always validated. Never optional at this layer. */
|
|
20
|
+
readonly integrator: ResolvedIntegratorConfig;
|
|
21
|
+
readonly defaultSlippageBps: number;
|
|
22
|
+
readonly theme: WidgetTheme;
|
|
23
|
+
/** Locale used by number formatting; defaults to the browser's. */
|
|
24
|
+
readonly locale: string | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* What the "Connect wallet" call to action does when pressed, for every
|
|
27
|
+
* widget under this provider. `undefined` leaves that CTA a disabled label.
|
|
28
|
+
*/
|
|
29
|
+
readonly onConnectRequest: (() => void) | undefined;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The context itself. Exported so a host can detect whether a provider is
|
|
33
|
+
* mounted above it (`useContext(WidgetContext) === null`) instead of catching
|
|
34
|
+
* the throw from {@link useWidgetContext}; {@link useOptionalWidgetContext}
|
|
35
|
+
* is the same test as a hook.
|
|
36
|
+
*/
|
|
37
|
+
export declare const WidgetContext: import("react").Context<WidgetContextValue | null>;
|
|
38
|
+
/** Props accepted by {@link WidgetProvider}. */
|
|
39
|
+
export interface WidgetProviderProps {
|
|
40
|
+
/** Where chain reads and writes go. Mock in dev, viem-backed in production. */
|
|
41
|
+
readonly adapter: ProtocolAdapter;
|
|
42
|
+
/**
|
|
43
|
+
* Integrator fee attribution.
|
|
44
|
+
*
|
|
45
|
+
* Omit it and the widgets work, earning you nothing. Supplying it is the
|
|
46
|
+
* entire commercial reason to embed them.
|
|
47
|
+
*/
|
|
48
|
+
readonly integrator?: IntegratorConfig;
|
|
49
|
+
readonly defaultSlippageBps?: number;
|
|
50
|
+
readonly theme?: WidgetTheme;
|
|
51
|
+
readonly locale?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Opens the host's wallet-connect flow (RainbowKit's `openConnectModal`,
|
|
54
|
+
* a custom modal, whatever the host has). While no account is connected the
|
|
55
|
+
* widgets' primary button reads "Connect wallet"; with this set it is an
|
|
56
|
+
* enabled button that calls it, without it the button stays a disabled label
|
|
57
|
+
* and the visitor connects through the host's own control. A widget's own
|
|
58
|
+
* `onConnectRequest` prop overrides this one.
|
|
59
|
+
*/
|
|
60
|
+
readonly onConnectRequest?: () => void;
|
|
61
|
+
readonly children: ReactNode;
|
|
62
|
+
}
|
|
63
|
+
/** Root provider. Wrap every widget in exactly one of these. */
|
|
64
|
+
export declare function WidgetProvider(props: WidgetProviderProps): JSX.Element;
|
|
65
|
+
/** Reads the widget context. Throws when used outside a {@link WidgetProvider}. */
|
|
66
|
+
export declare function useWidgetContext(): WidgetContextValue;
|
|
67
|
+
/**
|
|
68
|
+
* Reads the widget context, or `null` when no {@link WidgetProvider} is
|
|
69
|
+
* mounted above. For hosts that mount the provider late (once a pool
|
|
70
|
+
* directory is read, say) and want to render a waiting state in the
|
|
71
|
+
* meantime without an error boundary.
|
|
72
|
+
*/
|
|
73
|
+
export declare function useOptionalWidgetContext(): WidgetContextValue | null;
|
|
74
|
+
/** Convenience accessor for the adapter. */
|
|
75
|
+
export declare function useProtocolAdapter(): ProtocolAdapter;
|
|
76
|
+
/** Convenience accessor for the validated integrator config. */
|
|
77
|
+
export declare function useIntegrator(): ResolvedIntegratorConfig;
|
|
78
|
+
//# sourceMappingURL=WidgetProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WidgetProvider.d.ts","sourceRoot":"","sources":["../../src/context/WidgetProvider.tsx"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC9B,MAAM,yBAAyB,CAAC;AAGjC,mDAAmD;AACnD,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEtD,0DAA0D;AAC1D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,sDAAsD;IACtD,QAAQ,CAAC,UAAU,EAAE,wBAAwB,CAAC;IAC9C,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,mEAAmE;IACnE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;CACrD;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,oDAAiD,CAAC;AAE5E,gDAAgD;AAChD,MAAM,WAAW,mBAAmB;IAClC,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,gBAAgB,CAAC;IACvC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;OAOG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;CAC9B;AAED,gEAAgE;AAChE,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,GAAG,CAAC,OAAO,CA2DtE;AAED,mFAAmF;AACnF,wBAAgB,gBAAgB,IAAI,kBAAkB,CASrD;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,IAAI,kBAAkB,GAAG,IAAI,CAEpE;AAED,4CAA4C;AAC5C,wBAAgB,kBAAkB,IAAI,eAAe,CAEpD;AAED,gEAAgE;AAChE,wBAAgB,aAAa,IAAI,wBAAwB,CAExD"}
|