@stablecoin.xyz/swap-intent 0.0.0-stage → 0.1.1

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/README.md CHANGED
@@ -1,3 +1,39 @@
1
- # Temporary Holding Version
1
+ # @stablecoin.xyz/swap-intent
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Build a swap with the SBC Swap API (`swap.stablecoin.xyz`) and check the result against what the user asked for, before signing it. This is the same builder and check the Swap MCP runs; both are built from `mcp/` in [better-intents](https://github.com/stablecoinxyz/better-intents).
4
+
5
+ ```ts
6
+ import { buildSignRequest, decodeEvmRequest, decodeSolRequest, checkIntent } from "@stablecoin.xyz/swap-intent";
7
+
8
+ // ui: GET/POST against the Swap API (resolves the JSON body, throws on an error status).
9
+ // chain: reads the user's RfqSwap nonce and the input token's EIP-2612 permit nonce from an RPC.
10
+ const req = await buildSignRequest(
11
+ { ui, chain: { rfqNonce, permitNonce }, net: "mainnet" },
12
+ { inSym: "SBC", fromChain: "base", outSym: "cfUSD", toChain: "solana", uiAmount: 5, user: myEvmAddress, recipient: mySolAddress },
13
+ );
14
+
15
+ const evm = req.kind === "sol-tx" ? undefined : decodeEvmRequest(req);
16
+ const sol = req.kind === "sol-tx" ? await decodeSolRequest(req, { loadAlts }) : undefined;
17
+ const verdict = checkIntent({ req, evm, sol, self: { evm: myEvmAddress, sol: mySolAddress }, now: Date.now() });
18
+ if (!verdict.ok) throw new Error(`refusing to sign: ${verdict.reason}`);
19
+ ```
20
+
21
+ `buildSignRequest` refuses a route the API does not list as live in `/api/capabilities`. Always run `checkIntent` on what it returns: the check, not the builder, is what stands between the API's response and the user's signature. `now` is in milliseconds. Gas top-ups also need `minOut`: the gas floor from a fresh `/api/gas/quote` (see `gasFloorOf` and `gasQuoteQuery`); without it they are refused with `gas-floor-missing`.
22
+
23
+ To follow a cross-chain order, `findOrderOnRails(lookup)` tries each rail in `RAIL` against `GET /api/xchain/status/{orderId}?rail=` and returns the first match. A rail that cannot be read is reported, never read as "no order".
24
+
25
+ `checkIntent` refuses (`{ ok: false, reason }`) when the transaction pays an unknown token, spender, router, escrow or solver; sends the output anywhere but the user's own wallet; has a deadline or expiry out of bounds; pays less than the quoted floor; or, on Solana, carries extra instructions, an unexpected fee payer or an oversized priority fee.
26
+
27
+ ## Addresses are pinned
28
+
29
+ Contract addresses, token mints, decimals and the token table are baked into each published version; nothing else from the registry ships. A client must not trust addresses from the same API that built the transaction, so they are never fetched at runtime. When a contract is redeployed, a new version of this package is published, and older versions refuse transactions that use the new addresses.
30
+
31
+ ## Build and publish (maintainers)
32
+
33
+ ```bash
34
+ npm run build:swap-intent # from the better-intents root
35
+ npm run gate:swap-intent # the signer suites against the built bundle
36
+ cd packages/swap-intent && npm publish
37
+ ```
38
+
39
+ `prepublishOnly` rebuilds from `mcp/` before every publish. Bump `version` in `packages/swap-intent/package.json` first.
@@ -0,0 +1 @@
1
+ export * from "./types/packages/swap-intent/src/index.ts";