@recoilpay/intent-core 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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Recoil Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,88 @@
1
+ # @recoilpay/intent-core
2
+
3
+ The RecoilPay intent flow without a UI: turn plain English into a cross-chain swap or send, race solvers for a quote, sign, submit, and track the order to settlement.
4
+
5
+ It works in any framework or none. `@recoilpay/intent-react` and the hosted widget are built on it. If you want your own UI, use this directly.
6
+
7
+ ```sh
8
+ npm install @recoilpay/intent-core viem
9
+ ```
10
+
11
+ ## Quick start
12
+
13
+ ```ts
14
+ import { createIntentSession, viemWallet } from '@recoilpay/intent-core';
15
+
16
+ const session = createIntentSession({ hfAccessToken }); // your Hugging Face token; production aggregator by default
17
+
18
+ session.subscribe((state) => render(state)); // re-render on every change
19
+
20
+ await session.run('swap 10 USDC on Base for ETH on Arbitrum');
21
+ // state.phase === 'needsWallet'
22
+
23
+ session.setWallet(viemWallet(walletClient)); // continues on its own
24
+ // state.phase === 'quoted', state.preview has the amounts to show
25
+
26
+ await session.confirm(); // switch chain → approve → sign → submit
27
+ // state.phase goes 'tracking' → 'done'; state.explorerUrl links the fill
28
+ ```
29
+
30
+ ## The state
31
+
32
+ `session.getState()` returns an immutable snapshot, and a new object comes after every change, so it works directly with `useSyncExternalStore`, Svelte stores, signals and similar tools.
33
+
34
+ | Field | Meaning |
35
+ |---|---|
36
+ | `phase` | `idle` · `parsing` · `offTemplate` · `invalid` · `needsWallet` · `quoting` · `quoted` · `switchingChain` · `approving` · `signing` · `submitting` · `tracking` · `done` · `error` |
37
+ | `ready` | The supported-asset list has loaded, so input can be accepted |
38
+ | `hint` | When `offTemplate`, a sentence template to show the user |
39
+ | `issues` | When `invalid`: every problem at once, each with `field`, `kind` and a user-facing `message` |
40
+ | `preview` | When `quoted`: `payAmount`, `paySymbol`, `srcChainName`, `receiveAmount`, `receiveSymbol`, `dstChainName`, `etaSeconds`, `solverCount` |
41
+ | `needsApproval` | A one-time Permit2 approval will happen on confirm |
42
+ | `orderId`, `status`, `explorerUrl` | While tracking and when done |
43
+ | `error` | When `error`: the message to show |
44
+ | `queueIndex`, `queueTotal` | Sentences with several intents ("swap… then send…") run one at a time |
45
+
46
+ Nothing throws. Failures become `phase: 'error'`, `offTemplate` or `invalid`, each with a message written for the end user.
47
+
48
+ ## Wallets
49
+
50
+ The session needs a small `IntentWallet`. From a viem `WalletClient`:
51
+
52
+ ```ts
53
+ import { viemWallet } from '@recoilpay/intent-core';
54
+ session.setWallet(viemWallet(walletClient));
55
+ ```
56
+
57
+ With wagmi, pass the connected wallet client, and pass `null` on disconnect:
58
+
59
+ ```ts
60
+ const { data: walletClient } = useWalletClient();
61
+ useEffect(() => session.setWallet(walletClient ? viemWallet(walletClient) : null), [walletClient]);
62
+ ```
63
+
64
+ Any other wallet SDK can implement `IntentWallet` directly: an address, `getChainId`, `switchChain`, `signTypedData`, `writeContract` and `sendTransaction`.
65
+
66
+ ## Options
67
+
68
+ ```ts
69
+ createIntentSession({
70
+ hfAccessToken, // your Hugging Face token for parsing (setHfAccessToken() to change it)
71
+ apiUrl: 'https://api.recoilpay.com', // default; point at staging or a local aggregator
72
+ wallet, // or set it later with setWallet()
73
+ pollIntervalMs: 2500, // order-status polling
74
+ fetch, // custom fetch (SSR, proxies, tests)
75
+ chainReader, // chain reads; defaults to the aggregator's RPCs
76
+ });
77
+ ```
78
+
79
+ ## Building your own flow
80
+
81
+ Every step is exported on its own: `createApiClient` (parse, chains, supported assets, quotes, orders), `validateIntent`, `resolveIntent`, `buildQuoteRequest`, `signQuote`, the Permit2 helpers, and `interopAddress` (ERC-7930 encoding). The aggregator API is documented at https://docs.recoilpay.com/integrate/.
82
+
83
+ ## Notes
84
+
85
+ - **Testnets only** for now: Base Sepolia, OP Sepolia, Ethereum Sepolia and Polygon Amoy, with mock tokens.
86
+ - **Only the escrow (Permit2) route is requested.** The first swap of a token needs a one-time approval transaction, which `confirm()` handles.
87
+ - **Same-chain sends skip solvers** and go straight from the wallet (`route: 'direct'`).
88
+ - **Natural-language parsing:** Plain-English parsing calls a language model on Hugging Face **from the browser**, with your own access token. The token is visible to anyone who loads your page, so use a fine-grained token with only the "Make calls to Inference Providers" permission, use it for nothing else, and rotate it if it's abused. Without a token, parsing is off and users see an example sentence. `parseIntent()` is exported for use on its own.