@fastnear/intents 1.6.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/README.md +249 -0
- package/dist/cjs/index.cjs +524 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/index.d.cts +209 -0
- package/dist/cjs/node.cjs +188 -0
- package/dist/cjs/node.cjs.map +1 -0
- package/dist/cjs/node.d.cts +21 -0
- package/dist/cjs/relay.cjs +127 -0
- package/dist/cjs/relay.cjs.map +1 -0
- package/dist/cjs/relay.d.cts +40 -0
- package/dist/cjs/types-BQpqppU6.d.cts +343 -0
- package/dist/esm/index.d.ts +209 -0
- package/dist/esm/index.js +8 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/node.d.ts +21 -0
- package/dist/esm/node.js +76 -0
- package/dist/esm/node.js.map +1 -0
- package/dist/esm/one-click.js +84 -0
- package/dist/esm/one-click.js.map +1 -0
- package/dist/esm/relay.d.ts +40 -0
- package/dist/esm/relay.js +85 -0
- package/dist/esm/relay.js.map +1 -0
- package/dist/esm/signing.js +198 -0
- package/dist/esm/signing.js.map +1 -0
- package/dist/esm/types-BQpqppU6.d.ts +343 -0
- package/dist/esm/types.js +11 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/verifier.js +124 -0
- package/dist/esm/verifier.js.map +1 -0
- package/dist/umd/browser.global.js +802 -0
- package/dist/umd/browser.global.js.map +1 -0
- package/package.json +78 -0
package/README.md
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# `@fastnear/intents`
|
|
2
|
+
|
|
3
|
+
NEAR Intents (the multichain intent protocol settled by the
|
|
4
|
+
[`intents.near`](https://docs.near-intents.org/integration/verifier-contract/introduction.md)
|
|
5
|
+
verifier) for end users and AI agents: a zero-dependency typed client for the
|
|
6
|
+
hosted [1Click swap API](https://docs.near-intents.org/integration/distribution-channels/1click-api),
|
|
7
|
+
NEP-413 intent signing with either a connected FastNEAR wallet or a raw
|
|
8
|
+
server-side key, deposit/withdraw/balance helpers for the verifier itself, and
|
|
9
|
+
a JSON-RPC client for the solver relay.
|
|
10
|
+
|
|
11
|
+
Ships as ESM + CJS + a browser IIFE global (`nearIntents`). The browser entry
|
|
12
|
+
never touches private keys — local-key signing lives in
|
|
13
|
+
`@fastnear/intents/node`.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm install @fastnear/intents
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Browser (IIFE globals):
|
|
22
|
+
|
|
23
|
+
```html
|
|
24
|
+
<script src="https://js.fastnear.com/wallet.js"></script>
|
|
25
|
+
<script src="https://js.fastnear.com/intents.js"></script>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quote and track a swap (1Click)
|
|
29
|
+
|
|
30
|
+
Works unauthenticated out of the box — quotes then carry a 0.2% platform fee.
|
|
31
|
+
An API key from [partners.near-intents.org](https://partners.near-intents.org/)
|
|
32
|
+
waives it.
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
import { createOneClickClient } from "@fastnear/intents";
|
|
36
|
+
|
|
37
|
+
const oneClick = createOneClickClient({ apiKey: process.env.ONE_CLICK_API_KEY });
|
|
38
|
+
|
|
39
|
+
// 1. Discover assets — each entry's assetId is used everywhere else.
|
|
40
|
+
const tokens = await oneClick.tokens();
|
|
41
|
+
|
|
42
|
+
// 2. Preview pricing with dry:true (free, no commitment), then commit with
|
|
43
|
+
// dry:false to receive the depositAddress that drives the swap.
|
|
44
|
+
const quote = await oneClick.quote({
|
|
45
|
+
dry: false,
|
|
46
|
+
swapType: "EXACT_INPUT",
|
|
47
|
+
slippageTolerance: 100, // bps
|
|
48
|
+
originAsset: "nep141:wrap.near",
|
|
49
|
+
destinationAsset: "nep141:eth-0xdac17f958d2ee523a2206206994597c13d831ec7.omft.near",
|
|
50
|
+
amount: "1000000000000000000000000",
|
|
51
|
+
depositType: "ORIGIN_CHAIN",
|
|
52
|
+
refundTo: "alice.near",
|
|
53
|
+
refundType: "ORIGIN_CHAIN",
|
|
54
|
+
recipient: "0x2527D02599Ba641c19FEa793cD0F167589a0f10D",
|
|
55
|
+
recipientType: "DESTINATION_CHAIN",
|
|
56
|
+
deadline: new Date(Date.now() + 10 * 60_000).toISOString(),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// 3. Send the input tokens to quote.quote.depositAddress (see deposits below),
|
|
60
|
+
// then poll until SUCCESS | REFUNDED | FAILED.
|
|
61
|
+
const status = await oneClick.status({
|
|
62
|
+
depositAddress: quote.quote.depositAddress,
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Sign intents with a wallet (browser)
|
|
67
|
+
|
|
68
|
+
NEP-413 requires a **full-access key**, so wallets sign with the account's own
|
|
69
|
+
key — FunctionCall-access session keys cannot authorize intents. Wallets
|
|
70
|
+
return the signature as base64; the signer re-encodes it to the
|
|
71
|
+
`ed25519:<base58>` form the verifier expects.
|
|
72
|
+
|
|
73
|
+
```js
|
|
74
|
+
import { createWalletIntentSigner } from "@fastnear/intents";
|
|
75
|
+
// window.nearWallet from https://js.fastnear.com/wallet.js, already connected.
|
|
76
|
+
|
|
77
|
+
const signer = createWalletIntentSigner({ wallet: nearWallet });
|
|
78
|
+
|
|
79
|
+
const signed = await signer.signIntents({
|
|
80
|
+
intents: [
|
|
81
|
+
{
|
|
82
|
+
intent: "token_diff",
|
|
83
|
+
diff: {
|
|
84
|
+
"nep141:usdc.near": "-1000000",
|
|
85
|
+
"nep141:usdt.near": "1000000",
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
});
|
|
90
|
+
// -> { standard: "nep413", payload: {...}, public_key, signature } — ready for
|
|
91
|
+
// oneClick.submitIntent, relay.publishIntent, or intents.near execute_intents.
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Sign intents with a raw key (Node / agents)
|
|
95
|
+
|
|
96
|
+
```js
|
|
97
|
+
import { createOneClickClient } from "@fastnear/intents";
|
|
98
|
+
import { createLocalIntentSigner } from "@fastnear/intents/node";
|
|
99
|
+
|
|
100
|
+
const signer = createLocalIntentSigner({
|
|
101
|
+
accountId: process.env.NEAR_ACCOUNT_ID,
|
|
102
|
+
privateKey: process.env.NEAR_PRIVATE_KEY, // full-access, server-side only
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// INTENTS deposit type: balances already inside intents.near swap without a
|
|
106
|
+
// new on-chain transaction — 1Click builds the payload, you sign and submit.
|
|
107
|
+
const oneClick = createOneClickClient();
|
|
108
|
+
const quote = await oneClick.quote({
|
|
109
|
+
dry: false,
|
|
110
|
+
swapType: "EXACT_INPUT",
|
|
111
|
+
slippageTolerance: 100,
|
|
112
|
+
originAsset: "nep141:wrap.near",
|
|
113
|
+
destinationAsset: "nep141:17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1",
|
|
114
|
+
amount: "1000000000000000000000000",
|
|
115
|
+
depositType: "INTENTS", // input funds already sit inside intents.near
|
|
116
|
+
refundTo: process.env.NEAR_ACCOUNT_ID,
|
|
117
|
+
refundType: "INTENTS",
|
|
118
|
+
recipient: process.env.NEAR_ACCOUNT_ID,
|
|
119
|
+
recipientType: "INTENTS",
|
|
120
|
+
deadline: new Date(Date.now() + 10 * 60_000).toISOString(),
|
|
121
|
+
});
|
|
122
|
+
const { intent } = await oneClick.generateIntent({
|
|
123
|
+
signerId: process.env.NEAR_ACCOUNT_ID,
|
|
124
|
+
depositAddress: quote.quote.depositAddress,
|
|
125
|
+
});
|
|
126
|
+
// The server chose the message, nonce, and recipient. signPayload pins the
|
|
127
|
+
// recipient to intents.near and signs the payload verbatim.
|
|
128
|
+
const signed = await signer.signPayload(intent);
|
|
129
|
+
const { intentHash } = await oneClick.submitIntent({ signedData: signed });
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Deposits, balances, and withdrawals (verifier)
|
|
133
|
+
|
|
134
|
+
Helpers return plain FastNEAR action shapes — pass them to `near.sendTx` or
|
|
135
|
+
`nearWallet.sendTransaction`. Native NEAR must be wrapped first; balances
|
|
136
|
+
inside the verifier are NEP-245 multi-token entries keyed like
|
|
137
|
+
`nep141:<contract>`.
|
|
138
|
+
|
|
139
|
+
```js
|
|
140
|
+
import {
|
|
141
|
+
ftDepositAction,
|
|
142
|
+
wrapNearAction,
|
|
143
|
+
ftWithdrawAction,
|
|
144
|
+
mtBatchBalances,
|
|
145
|
+
} from "@fastnear/intents";
|
|
146
|
+
|
|
147
|
+
// Wrap native NEAR, then deposit the wNEAR into intents.near.
|
|
148
|
+
await near.sendTx({
|
|
149
|
+
receiverId: "wrap.near",
|
|
150
|
+
actions: [wrapNearAction({ amountYocto: "1000000000000000000000000" })],
|
|
151
|
+
});
|
|
152
|
+
await near.sendTx({
|
|
153
|
+
receiverId: "wrap.near",
|
|
154
|
+
actions: [ftDepositAction({ amount: "1000000000000000000000000" })],
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Internal balances (injected view keeps this package api-free).
|
|
158
|
+
const balances = await mtBatchBalances({
|
|
159
|
+
accountId: "alice.near",
|
|
160
|
+
tokenIds: ["nep141:wrap.near", "nep141:usdc.near"],
|
|
161
|
+
view: near.view,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Withdraw back out (plain token id, no nep141: prefix; refundable when msg
|
|
165
|
+
// is omitted).
|
|
166
|
+
await near.sendTx({
|
|
167
|
+
receiverId: "intents.near",
|
|
168
|
+
actions: [
|
|
169
|
+
ftWithdrawAction({
|
|
170
|
+
token: "wrap.near",
|
|
171
|
+
receiverId: "alice.near",
|
|
172
|
+
amount: balances["nep141:wrap.near"],
|
|
173
|
+
}),
|
|
174
|
+
],
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Solver relay (direct flows)
|
|
179
|
+
|
|
180
|
+
The relay brokers quotes between users and solvers and submits matched intent
|
|
181
|
+
bundles to the verifier. It is the lower-level alternative to 1Click; relay
|
|
182
|
+
API keys come from the partner dashboard.
|
|
183
|
+
|
|
184
|
+
```js
|
|
185
|
+
import { createSolverRelayClient } from "@fastnear/intents/relay";
|
|
186
|
+
|
|
187
|
+
const relay = createSolverRelayClient({ apiKey: process.env.RELAY_API_KEY });
|
|
188
|
+
|
|
189
|
+
const quotes = await relay.quote({
|
|
190
|
+
defuse_asset_identifier_in: "nep141:usdc.near",
|
|
191
|
+
defuse_asset_identifier_out: "nep141:usdt.near",
|
|
192
|
+
exact_amount_in: "1000000",
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
const best = quotes?.[0];
|
|
196
|
+
const signed = await signer.signIntents({
|
|
197
|
+
intents: [
|
|
198
|
+
{
|
|
199
|
+
intent: "token_diff",
|
|
200
|
+
diff: {
|
|
201
|
+
"nep141:usdc.near": `-${best.amount_in}`,
|
|
202
|
+
"nep141:usdt.near": best.amount_out,
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
],
|
|
206
|
+
deadline: best.expiration_time,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const { intent_hash } = await relay.publishIntent({
|
|
210
|
+
signedData: signed,
|
|
211
|
+
quoteHashes: [best.quote_hash],
|
|
212
|
+
});
|
|
213
|
+
// Poll: PENDING -> TX_BROADCASTED -> SETTLED
|
|
214
|
+
const status = await relay.getStatus({ intentHash: intent_hash });
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Protocol constraints
|
|
218
|
+
|
|
219
|
+
- Only `intents.near` on NEAR mainnet; there is no meaningful public testnet
|
|
220
|
+
deployment of the intents stack.
|
|
221
|
+
- NEP-413 signatures require a full-access key. The verifier additionally
|
|
222
|
+
checks the key is authorized for the `signer_id` (registered with
|
|
223
|
+
`add_public_key`, or matching an implicit account).
|
|
224
|
+
- Signature encoding is `ed25519:<base58>` — NOT the base64 wallets return.
|
|
225
|
+
The signers in this package own that conversion.
|
|
226
|
+
- Native NEAR is not a verifier asset: wrap to wNEAR on deposit; the
|
|
227
|
+
`native_withdraw` intent is the only native exit.
|
|
228
|
+
- Amounts are base-unit strings everywhere; `token_diff` diffs must net to
|
|
229
|
+
zero per token across the executed batch (a solver signs the mirror diff).
|
|
230
|
+
- Unauthenticated 1Click use adds a 0.2% platform fee to quotes.
|
|
231
|
+
|
|
232
|
+
## Entrypoints
|
|
233
|
+
|
|
234
|
+
- `@fastnear/intents` — types, 1Click client, wallet signer, verifier
|
|
235
|
+
helpers, solver relay re-export (browser-safe; global `nearIntents`)
|
|
236
|
+
- `@fastnear/intents/relay` — solver relay JSON-RPC client
|
|
237
|
+
- `@fastnear/intents/node` — local full-access-key signer (server-side only)
|
|
238
|
+
|
|
239
|
+
## Release gate
|
|
240
|
+
|
|
241
|
+
Run the [mainnet QA runbook](./MAINNET_QA.md) before releasing: the free
|
|
242
|
+
dry smoke (`node scripts/smoke-intents-dry.mjs`) always, and the env-gated
|
|
243
|
+
funded micro swap (`scripts/smoke-intents-mainnet.mjs`) per release.
|
|
244
|
+
|
|
245
|
+
## Upstream
|
|
246
|
+
|
|
247
|
+
- Docs: https://docs.near-intents.org
|
|
248
|
+
- Verifier source: https://github.com/near/intents
|
|
249
|
+
- 1Click OpenAPI: https://1click.chaindefuser.com/docs/v0/openapi.yaml
|