@defuse-protocol/nearintents-mpp-sdk 0.0.0 → 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/LICENSE +21 -0
- package/README.md +235 -0
- package/dist/Errors.d.ts +57 -0
- package/dist/Errors.d.ts.map +1 -0
- package/dist/Errors.js +54 -0
- package/dist/Errors.js.map +1 -0
- package/dist/Methods.d.ts +44 -0
- package/dist/Methods.d.ts.map +1 -0
- package/dist/Methods.js +23 -0
- package/dist/Methods.js.map +1 -0
- package/dist/Types.d.ts +125 -0
- package/dist/Types.d.ts.map +1 -0
- package/dist/Types.js +195 -0
- package/dist/Types.js.map +1 -0
- package/dist/client/Charge.d.ts +141 -0
- package/dist/client/Charge.d.ts.map +1 -0
- package/dist/client/Charge.js +167 -0
- package/dist/client/Charge.js.map +1 -0
- package/dist/client/index.d.ts +5 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +5 -0
- package/dist/client/index.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/OneClick.d.ts +243 -0
- package/dist/internal/OneClick.d.ts.map +1 -0
- package/dist/internal/OneClick.js +422 -0
- package/dist/internal/OneClick.js.map +1 -0
- package/dist/server/Charge.d.ts +241 -0
- package/dist/server/Charge.d.ts.map +1 -0
- package/dist/server/Charge.js +404 -0
- package/dist/server/Charge.js.map +1 -0
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +5 -0
- package/dist/server/index.js.map +1 -0
- package/package.json +87 -9
- package/src/Errors.ts +86 -0
- package/src/Methods.ts +24 -0
- package/src/Types.ts +256 -0
- package/src/client/Charge.ts +268 -0
- package/src/client/index.ts +4 -0
- package/src/index.ts +4 -0
- package/src/internal/OneClick.ts +634 -0
- package/src/server/Charge.ts +621 -0
- package/src/server/index.ts +4 -0
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
import { Errors, Method, Store } from 'mppx';
|
|
2
|
+
import { SettlementFailedError, SettlementTimeoutError, SettlementUnavailableError, } from '../Errors.js';
|
|
3
|
+
import * as OneClick from '../internal/OneClick.js';
|
|
4
|
+
import * as Methods from '../Methods.js';
|
|
5
|
+
import * as Types from '../Types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Creates a `nearintents` charge method for usage on the server.
|
|
8
|
+
*
|
|
9
|
+
* Each 402 challenge carries a unique single-use 1Click deposit address as
|
|
10
|
+
* `recipient` (minted via a wet `EXACT_OUTPUT` quote and cached with early
|
|
11
|
+
* refresh so the challenge `expires` always precedes the quote deadline).
|
|
12
|
+
* Verification confirms the client's deposit by 1Click status observation,
|
|
13
|
+
* drives the swap to a terminal state, and issues the extended receipt on
|
|
14
|
+
* `SUCCESS`.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { Mppx } from 'mppx/server'
|
|
19
|
+
* import { nearintents } from '@defuse-protocol/nearintents-mpp-sdk/server'
|
|
20
|
+
*
|
|
21
|
+
* const mppx = Mppx.create({
|
|
22
|
+
* secretKey: process.env.MPP_SECRET_KEY!,
|
|
23
|
+
* methods: [
|
|
24
|
+
* nearintents.charge({
|
|
25
|
+
* originAsset: 'eip155:42161/erc20:0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
|
|
26
|
+
* destinationAsset: 'near:mainnet/nep141:1720…33a1',
|
|
27
|
+
* destinationRecipient: 'merchant.near',
|
|
28
|
+
* refundTo: '0x2527D02599Ba641c19FEa793cD0F9a6e8457C317',
|
|
29
|
+
* amountOut: '1000000',
|
|
30
|
+
* oneClick: { jwt: process.env.ONE_CLICK_JWT },
|
|
31
|
+
* }),
|
|
32
|
+
* ],
|
|
33
|
+
* })
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export function charge(parameters) {
|
|
37
|
+
const { amountOut: defaultAmountOut, description, destinationAsset, destinationRecipient, externalId, oneClick = {}, originAsset,
|
|
38
|
+
// Distribution-channel attribution: every 1Click swap minted by this
|
|
39
|
+
// payment method carries the "mpp" referral (mirrors the x402 gateway).
|
|
40
|
+
referral = 'mpp', refundTo, slippageTolerance = 100, } = parameters;
|
|
41
|
+
// Merchant observability: settlement progress is reported as structured
|
|
42
|
+
// events (the library never logs). A throwing handler must not affect
|
|
43
|
+
// payment processing.
|
|
44
|
+
const emit = (event) => {
|
|
45
|
+
try {
|
|
46
|
+
parameters.onEvent?.(event);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// Observer errors are the observer's problem.
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
// Fail fast on malformed merchant config (throws at construction time).
|
|
53
|
+
const originNetwork = Types.chainOf(originAsset);
|
|
54
|
+
const destinationNetwork = Types.chainOf(destinationAsset);
|
|
55
|
+
const expiresWindowMs = (parameters.expiresWindow ?? 300) * 1000;
|
|
56
|
+
const quoteDeadlineBufferMs = (parameters.quoteDeadlineBuffer ?? 900) * 1000;
|
|
57
|
+
const pollIntervalMs = parameters.pollInterval ?? 2000;
|
|
58
|
+
const store = Store.from((parameters.store ?? Store.memory()), { keyPrefix: parameters.storeKeyPrefix ?? '' });
|
|
59
|
+
// Token list is fetched lazily and re-fetched once on an unresolved asset
|
|
60
|
+
// (the list evolves); a persistent miss is a merchant-config error.
|
|
61
|
+
let assetMapPromise;
|
|
62
|
+
function getAssetMap(refresh = false) {
|
|
63
|
+
if (!assetMapPromise || refresh) {
|
|
64
|
+
assetMapPromise = OneClick.getTokens(oneClick)
|
|
65
|
+
.then((tokens) => OneClick.createAssetMap(tokens, oneClick))
|
|
66
|
+
.catch((error) => {
|
|
67
|
+
assetMapPromise = undefined;
|
|
68
|
+
throw error;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return assetMapPromise;
|
|
72
|
+
}
|
|
73
|
+
async function resolveAssetId(caip19Id) {
|
|
74
|
+
let assetId = (await getAssetMap()).toAssetId(caip19Id);
|
|
75
|
+
if (!assetId)
|
|
76
|
+
assetId = (await getAssetMap(true)).toAssetId(caip19Id);
|
|
77
|
+
if (!assetId)
|
|
78
|
+
throw new Error(`nearintents-mpp-sdk: asset "${caip19Id}" is not on the 1Click token list — check the merchant configuration (or extend oneClick.networks).`);
|
|
79
|
+
return assetId;
|
|
80
|
+
}
|
|
81
|
+
const depositKey = (address) => `nearintents-mpp-sdk:deposit:${address}`;
|
|
82
|
+
const quoteKey = (identity) => `nearintents-mpp-sdk:quote:${identity}`;
|
|
83
|
+
const hashKey = (hash) => `nearintents-mpp-sdk:hash:${hash.toLowerCase()}`;
|
|
84
|
+
function identityOf(amountOut) {
|
|
85
|
+
return [
|
|
86
|
+
originAsset,
|
|
87
|
+
destinationAsset,
|
|
88
|
+
amountOut,
|
|
89
|
+
destinationRecipient,
|
|
90
|
+
refundTo,
|
|
91
|
+
slippageTolerance,
|
|
92
|
+
referral,
|
|
93
|
+
].join('|');
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Returns the route's active canonical request, minting a fresh 1Click
|
|
97
|
+
* quote when there is none — or when the cached one is stale (early
|
|
98
|
+
* refresh: a quote is stale once `now + expiresWindow > quote deadline`,
|
|
99
|
+
* so the challenge `expires` always precedes the active quote's deadline).
|
|
100
|
+
*/
|
|
101
|
+
async function resolveActiveRequest(amountOut) {
|
|
102
|
+
const identity = identityOf(amountOut);
|
|
103
|
+
const pointer = await store.get(quoteKey(identity));
|
|
104
|
+
if (pointer && pointer.identity === identity) {
|
|
105
|
+
const deposit = await store.get(depositKey(pointer.depositAddress));
|
|
106
|
+
if (deposit &&
|
|
107
|
+
deposit.state === 'active' &&
|
|
108
|
+
deposit.identity === identity &&
|
|
109
|
+
Date.parse(deposit.deadline) > Date.now() + expiresWindowMs) {
|
|
110
|
+
emit({ type: 'quote.reused', depositAddress: deposit.request.recipient });
|
|
111
|
+
return deposit.request;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const [originAssetId, destinationAssetId] = await Promise.all([
|
|
115
|
+
resolveAssetId(originAsset),
|
|
116
|
+
resolveAssetId(destinationAsset),
|
|
117
|
+
]);
|
|
118
|
+
const requestedDeadline = new Date(Date.now() + expiresWindowMs + quoteDeadlineBufferMs).toISOString();
|
|
119
|
+
const { quote } = await OneClick.quote(oneClick, {
|
|
120
|
+
originAsset: originAssetId,
|
|
121
|
+
destinationAsset: destinationAssetId,
|
|
122
|
+
amountOut,
|
|
123
|
+
recipient: destinationRecipient,
|
|
124
|
+
refundTo,
|
|
125
|
+
slippageTolerance,
|
|
126
|
+
deadline: requestedDeadline,
|
|
127
|
+
referral,
|
|
128
|
+
});
|
|
129
|
+
// Spec §Expiry: `expires` MUST be at or before the quote deadline. The
|
|
130
|
+
// backend's deadline is authoritative; if it cannot cover the route's
|
|
131
|
+
// static expires window, the route is misconfigured — fail loud.
|
|
132
|
+
if (Date.parse(quote.deadline) <= Date.now() + expiresWindowMs)
|
|
133
|
+
throw new Error(`nearintents-mpp-sdk: 1Click quote deadline (${quote.deadline}) does not cover the route's expires window (${expiresWindowMs / 1000}s) — lower expiresWindow or raise quoteDeadlineBuffer.`);
|
|
134
|
+
const request = {
|
|
135
|
+
amount: quote.amountIn,
|
|
136
|
+
currency: originAsset,
|
|
137
|
+
recipient: quote.depositAddress,
|
|
138
|
+
...(description !== undefined && { description }),
|
|
139
|
+
...(externalId !== undefined && { externalId }),
|
|
140
|
+
methodDetails: {
|
|
141
|
+
originNetwork,
|
|
142
|
+
destinationNetwork,
|
|
143
|
+
destinationAsset,
|
|
144
|
+
destinationRecipient,
|
|
145
|
+
amountOut,
|
|
146
|
+
minAmountIn: quote.minAmountIn,
|
|
147
|
+
depositMemo: quote.depositMemo ?? null,
|
|
148
|
+
slippageTolerance,
|
|
149
|
+
timeEstimate: quote.timeEstimate,
|
|
150
|
+
refundTo,
|
|
151
|
+
settlementBackend: Types.settlementBackend,
|
|
152
|
+
credentialTypes: [...Types.credentialTypes],
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
await store.put(depositKey(quote.depositAddress), {
|
|
156
|
+
identity,
|
|
157
|
+
request,
|
|
158
|
+
deadline: quote.deadline,
|
|
159
|
+
timeEstimate: quote.timeEstimate,
|
|
160
|
+
depositMemo: quote.depositMemo ?? null,
|
|
161
|
+
state: 'active',
|
|
162
|
+
});
|
|
163
|
+
await store.put(quoteKey(identity), { identity, depositAddress: quote.depositAddress });
|
|
164
|
+
emit({
|
|
165
|
+
type: 'quote.minted',
|
|
166
|
+
depositAddress: quote.depositAddress,
|
|
167
|
+
amountIn: quote.amountIn,
|
|
168
|
+
minAmountIn: quote.minAmountIn,
|
|
169
|
+
amountOut,
|
|
170
|
+
deadline: quote.deadline,
|
|
171
|
+
timeEstimate: quote.timeEstimate,
|
|
172
|
+
});
|
|
173
|
+
return request;
|
|
174
|
+
}
|
|
175
|
+
/** Marks a deposit spent and drops the cache pointer so the next 402 mints fresh. */
|
|
176
|
+
async function retireDeposit(depositAddress, identity) {
|
|
177
|
+
await store.update(depositKey(depositAddress), (current) => {
|
|
178
|
+
if (!current)
|
|
179
|
+
return { op: 'noop', result: undefined };
|
|
180
|
+
return { op: 'set', value: { ...current, state: 'settled' }, result: undefined };
|
|
181
|
+
});
|
|
182
|
+
await store.update(quoteKey(identity), (current) => {
|
|
183
|
+
if (current?.depositAddress !== depositAddress)
|
|
184
|
+
return { op: 'noop', result: undefined };
|
|
185
|
+
return { op: 'delete', result: undefined };
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/** Atomically claims `hash` as in-flight. Expired leases are reclaimable. */
|
|
189
|
+
async function claimHash(hash, leaseUntil) {
|
|
190
|
+
return store.update(hashKey(hash), (current) => {
|
|
191
|
+
if (current?.state === 'consumed')
|
|
192
|
+
return { op: 'noop', result: 'consumed' };
|
|
193
|
+
if (current?.state === 'inflight' && current.leaseUntil > Date.now())
|
|
194
|
+
return { op: 'noop', result: 'inflight' };
|
|
195
|
+
return { op: 'set', value: { state: 'inflight', leaseUntil }, result: 'claimed' };
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
return Method.toServer(Methods.charge, {
|
|
199
|
+
// Valid canonical placeholder — replaced by the request hook on every
|
|
200
|
+
// real path; only the fallback challenge (request hook threw a
|
|
201
|
+
// PaymentError) ever serializes it.
|
|
202
|
+
defaults: {
|
|
203
|
+
amount: '0',
|
|
204
|
+
currency: originAsset,
|
|
205
|
+
recipient: 'unavailable',
|
|
206
|
+
...(description !== undefined && { description }),
|
|
207
|
+
...(externalId !== undefined && { externalId }),
|
|
208
|
+
methodDetails: {
|
|
209
|
+
originNetwork,
|
|
210
|
+
destinationNetwork,
|
|
211
|
+
destinationAsset,
|
|
212
|
+
destinationRecipient,
|
|
213
|
+
amountOut: defaultAmountOut ?? '0',
|
|
214
|
+
minAmountIn: '0',
|
|
215
|
+
depositMemo: null,
|
|
216
|
+
slippageTolerance,
|
|
217
|
+
refundTo,
|
|
218
|
+
settlementBackend: Types.settlementBackend,
|
|
219
|
+
credentialTypes: [...Types.credentialTypes],
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
// Spec §Challenge Binding: the deposit address, amount, and source asset
|
|
223
|
+
// are challenge-specific. Binding them means a rotated quote yields a
|
|
224
|
+
// binding mismatch → 402 with a fresh challenge (the client-recovery flow).
|
|
225
|
+
stableBinding(request) {
|
|
226
|
+
const { amount, currency, methodDetails, recipient } = request;
|
|
227
|
+
return { amount, currency, originNetwork: methodDetails.originNetwork, recipient };
|
|
228
|
+
},
|
|
229
|
+
async request({ credential, request }) {
|
|
230
|
+
const amountOut = request.methodDetails?.amountOut ??
|
|
231
|
+
defaultAmountOut;
|
|
232
|
+
if (!amountOut || amountOut === '0')
|
|
233
|
+
throw new Error('nearintents-mpp-sdk: amountOut is required — set it in charge({ amountOut }) or per route via methodDetails.amountOut.');
|
|
234
|
+
// Credential-bearing request: resolve the quote the challenge was
|
|
235
|
+
// minted from (store lookup keyed by deposit address) — never mint a
|
|
236
|
+
// quote for a credential. Note the echoed challenge is NOT yet
|
|
237
|
+
// HMAC-verified here; the lookup returns OUR stored request, so a
|
|
238
|
+
// forged recipient can at most cause a cache-limited quote refresh.
|
|
239
|
+
if (credential) {
|
|
240
|
+
const recipient = credential.challenge.request?.recipient;
|
|
241
|
+
if (typeof recipient === 'string' && recipient) {
|
|
242
|
+
const deposit = await store.get(depositKey(recipient));
|
|
243
|
+
if (deposit &&
|
|
244
|
+
deposit.state === 'active' &&
|
|
245
|
+
deposit.identity === identityOf(amountOut) &&
|
|
246
|
+
Date.parse(deposit.deadline) > Date.now())
|
|
247
|
+
return deposit.request;
|
|
248
|
+
}
|
|
249
|
+
// Unknown, spent, or expired deposit address: fall through to the
|
|
250
|
+
// current active quote. The stableBinding mismatch then yields a 402
|
|
251
|
+
// carrying this fresh challenge — the spec's client-recovery flow.
|
|
252
|
+
}
|
|
253
|
+
return resolveActiveRequest(amountOut);
|
|
254
|
+
},
|
|
255
|
+
async verify({ credential, request }) {
|
|
256
|
+
const { challenge } = credential;
|
|
257
|
+
const resolved = (() => {
|
|
258
|
+
const parsed = Methods.charge.schema.request.safeParse(request);
|
|
259
|
+
if (parsed.success)
|
|
260
|
+
return parsed.data;
|
|
261
|
+
return request;
|
|
262
|
+
})();
|
|
263
|
+
const payload = credential.payload;
|
|
264
|
+
if (payload.type !== 'hash')
|
|
265
|
+
throw new Errors.InvalidPayloadError({ reason: 'only "hash" credentials are accepted' });
|
|
266
|
+
const hash = payload.hash;
|
|
267
|
+
// Spec §Verification step 4: the deposit address must correspond to an
|
|
268
|
+
// active, non-expired, non-settled quote in the server's state.
|
|
269
|
+
const recipient = resolved.recipient;
|
|
270
|
+
const deposit = await store.get(depositKey(recipient));
|
|
271
|
+
if (!deposit)
|
|
272
|
+
throw new Errors.InvalidChallengeError({
|
|
273
|
+
id: challenge.id,
|
|
274
|
+
reason: 'no active quote for this deposit address',
|
|
275
|
+
});
|
|
276
|
+
if (deposit.state === 'settled')
|
|
277
|
+
throw new Errors.InvalidChallengeError({
|
|
278
|
+
id: challenge.id,
|
|
279
|
+
reason: 'the quote for this deposit address is already settled',
|
|
280
|
+
});
|
|
281
|
+
if (Date.parse(deposit.deadline) <= Date.now())
|
|
282
|
+
throw new Errors.PaymentExpiredError({ expires: deposit.deadline });
|
|
283
|
+
const settlementTimeoutMs = (parameters.settlementTimeout ?? deposit.timeEstimate + 120) * 1000;
|
|
284
|
+
// Spec §Verification step 5 / §Replay: claim the hash in-flight
|
|
285
|
+
// atomically; consume permanently only on a terminal settlement state.
|
|
286
|
+
// The lease covers the settlement budget so a crashed settlement never
|
|
287
|
+
// strands a legitimate retry.
|
|
288
|
+
const claim = await claimHash(hash, Date.now() + settlementTimeoutMs + 60_000);
|
|
289
|
+
if (claim === 'consumed')
|
|
290
|
+
throw new Errors.VerificationFailedError({
|
|
291
|
+
reason: 'transaction hash has already been used',
|
|
292
|
+
});
|
|
293
|
+
if (claim === 'inflight')
|
|
294
|
+
throw new Errors.VerificationFailedError({
|
|
295
|
+
reason: 'settlement for this transaction hash is already in progress',
|
|
296
|
+
});
|
|
297
|
+
let hashOutcome = 'release';
|
|
298
|
+
try {
|
|
299
|
+
// Spec §Settlement step 1: notify the backend (optional accelerator;
|
|
300
|
+
// status observation below is authoritative, so failures are benign).
|
|
301
|
+
const accepted = await OneClick.submitDeposit(oneClick, {
|
|
302
|
+
txHash: hash,
|
|
303
|
+
depositAddress: recipient,
|
|
304
|
+
...(deposit.depositMemo !== null && { memo: deposit.depositMemo }),
|
|
305
|
+
}).then(() => true, () => false);
|
|
306
|
+
emit({ type: 'deposit.submitted', depositAddress: recipient, originTxHash: hash, accepted });
|
|
307
|
+
// Spec §Settlement step 2 + §Verification step 3: poll to a terminal
|
|
308
|
+
// status; the backend detecting a qualifying deposit at `recipient`
|
|
309
|
+
// IS the deposit confirmation (status-observation mode).
|
|
310
|
+
const status = await OneClick.pollToTerminal(oneClick, {
|
|
311
|
+
depositAddress: recipient,
|
|
312
|
+
...(deposit.depositMemo !== null && { depositMemo: deposit.depositMemo }),
|
|
313
|
+
timeoutMs: settlementTimeoutMs,
|
|
314
|
+
intervalMs: pollIntervalMs,
|
|
315
|
+
onStatus: (observed) => emit({ type: 'settlement.status', depositAddress: recipient, status: observed }),
|
|
316
|
+
});
|
|
317
|
+
// Any terminal state spends the quote and its deposit address —
|
|
318
|
+
// including SUCCESS whose observed deposits don't match the presented
|
|
319
|
+
// hash (below). Retiring here, before that match check, is deliberate:
|
|
320
|
+
// once the backend reaches SUCCESS the deposit is delivered, so the
|
|
321
|
+
// quote MUST leave rotation regardless of which credential presented
|
|
322
|
+
// it. Deferring the retire until after a match check would strand a
|
|
323
|
+
// backend-settled deposit as "active" in the store, and a later
|
|
324
|
+
// cache hit could hand a fresh payer an already-spent deposit address.
|
|
325
|
+
await retireDeposit(recipient, deposit.identity);
|
|
326
|
+
emit({
|
|
327
|
+
type: 'settlement.terminal',
|
|
328
|
+
depositAddress: recipient,
|
|
329
|
+
originTxHash: hash,
|
|
330
|
+
status: status.status,
|
|
331
|
+
...(OneClick.destinationTxHash(status) !== undefined && {
|
|
332
|
+
destinationTxHash: OneClick.destinationTxHash(status),
|
|
333
|
+
}),
|
|
334
|
+
});
|
|
335
|
+
if (status.status === 'SUCCESS') {
|
|
336
|
+
// Deposit confirmation: the presented hash must be among the
|
|
337
|
+
// origin-chain transactions the backend observed for this address.
|
|
338
|
+
if (!OneClick.matchesOriginTx(status, hash))
|
|
339
|
+
throw new Errors.VerificationFailedError({
|
|
340
|
+
reason: 'the presented transaction hash is not among the deposits observed for this address',
|
|
341
|
+
});
|
|
342
|
+
hashOutcome = 'consume';
|
|
343
|
+
const reference = OneClick.destinationTxHash(status) ?? status.swapDetails?.nearTxHashes?.[0];
|
|
344
|
+
// The merchant has been paid at this point; a missing reference is
|
|
345
|
+
// a backend anomaly worth failing loudly on (500), not a 402.
|
|
346
|
+
if (!reference)
|
|
347
|
+
throw new Error(`nearintents-mpp-sdk: swap for ${recipient} reached SUCCESS but reported no settlement transaction hash.`);
|
|
348
|
+
const receipt = Types.toReceipt({
|
|
349
|
+
challengeId: challenge.id,
|
|
350
|
+
reference,
|
|
351
|
+
originTxHash: hash,
|
|
352
|
+
destinationNetwork: resolved.methodDetails.destinationNetwork,
|
|
353
|
+
...(resolved.externalId !== undefined && { externalId: resolved.externalId }),
|
|
354
|
+
});
|
|
355
|
+
emit({
|
|
356
|
+
type: 'receipt.issued',
|
|
357
|
+
challengeId: challenge.id,
|
|
358
|
+
depositAddress: recipient,
|
|
359
|
+
originTxHash: hash,
|
|
360
|
+
reference,
|
|
361
|
+
});
|
|
362
|
+
return receipt;
|
|
363
|
+
}
|
|
364
|
+
// Non-success terminal (FAILED/REFUNDED/INCOMPLETE_DEPOSIT): the
|
|
365
|
+
// deposit is refunded to refundTo and the hash can never deliver —
|
|
366
|
+
// consume it. The client recovers with a fresh challenge.
|
|
367
|
+
hashOutcome = 'consume';
|
|
368
|
+
throw (OneClick.terminalError(status) ??
|
|
369
|
+
new SettlementFailedError({ reason: `unexpected terminal status ${status.status}` }));
|
|
370
|
+
}
|
|
371
|
+
catch (error) {
|
|
372
|
+
// Backend unavailability / settlement timeout: 5xx, never
|
|
373
|
+
// verification-failed; do not settle, release the claim so the same
|
|
374
|
+
// credential can be re-presented.
|
|
375
|
+
if (error instanceof OneClick.OneClickUnavailableError) {
|
|
376
|
+
emit({
|
|
377
|
+
type: 'settlement.suspended',
|
|
378
|
+
depositAddress: recipient,
|
|
379
|
+
originTxHash: hash,
|
|
380
|
+
reason: 'unavailable',
|
|
381
|
+
});
|
|
382
|
+
throw new SettlementUnavailableError({ reason: error.message });
|
|
383
|
+
}
|
|
384
|
+
if (error instanceof OneClick.PollTimeoutError) {
|
|
385
|
+
emit({
|
|
386
|
+
type: 'settlement.suspended',
|
|
387
|
+
depositAddress: recipient,
|
|
388
|
+
originTxHash: hash,
|
|
389
|
+
reason: 'timeout',
|
|
390
|
+
});
|
|
391
|
+
throw new SettlementTimeoutError({ timeoutMs: settlementTimeoutMs });
|
|
392
|
+
}
|
|
393
|
+
throw error;
|
|
394
|
+
}
|
|
395
|
+
finally {
|
|
396
|
+
if (hashOutcome === 'consume')
|
|
397
|
+
await store.put(hashKey(hash), { state: 'consumed' });
|
|
398
|
+
else
|
|
399
|
+
await store.delete(hashKey(hash));
|
|
400
|
+
}
|
|
401
|
+
},
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
//# sourceMappingURL=Charge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Charge.js","sourceRoot":"","sources":["../../src/server/Charge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,cAAc,CAAA;AACtC,OAAO,KAAK,OAAO,MAAM,eAAe,CAAA;AACxC,OAAO,KAAK,KAAK,MAAM,aAAa,CAAA;AACpC,OAAO,KAAK,WAAW,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,cAAc,CAAA;AACtC,OAAO,KAAK,OAAO,MAAM,eAAe,CAAA;AACxC,OAAO,KAAK,KAAK,MAAM,aAAa,CAAA;AACpC,OAAO,KAAK,WAAW,MAAM,aAAa,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,12 +1,90 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defuse-protocol/nearintents-mpp-sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Reference implementation of the `nearintents` payment method for MPP (Machine Payments Protocol) — cross-chain HTTP 402 payments settled by NEAR Intents. Extends mppx.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public",
|
|
10
|
+
"provenance": true
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/defuse-protocol/nearintents-mpp-sdk.git"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://github.com/defuse-protocol/nearintents-mpp-sdk#readme",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/defuse-protocol/nearintents-mpp-sdk/issues"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"mpp",
|
|
22
|
+
"machine-payments",
|
|
23
|
+
"http-402",
|
|
24
|
+
"payments",
|
|
25
|
+
"near",
|
|
26
|
+
"near-intents",
|
|
27
|
+
"cross-chain",
|
|
28
|
+
"typescript"
|
|
29
|
+
],
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"src",
|
|
33
|
+
"!src/**/*.test.ts"
|
|
34
|
+
],
|
|
35
|
+
"main": "./dist/index.js",
|
|
36
|
+
"exports": {
|
|
37
|
+
".": {
|
|
38
|
+
"types": "./dist/index.d.ts",
|
|
39
|
+
"default": "./dist/index.js"
|
|
40
|
+
},
|
|
41
|
+
"./client": {
|
|
42
|
+
"types": "./dist/client/index.d.ts",
|
|
43
|
+
"default": "./dist/client/index.js"
|
|
44
|
+
},
|
|
45
|
+
"./server": {
|
|
46
|
+
"types": "./dist/server/index.d.ts",
|
|
47
|
+
"default": "./dist/server/index.js"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=20"
|
|
8
52
|
},
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"zod": "^4.4.3"
|
|
55
|
+
},
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"mppx": "0.8.13",
|
|
58
|
+
"viem": "^2.0.0"
|
|
59
|
+
},
|
|
60
|
+
"peerDependenciesMeta": {
|
|
61
|
+
"viem": {
|
|
62
|
+
"optional": true
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"@biomejs/biome": "^2.5.4",
|
|
67
|
+
"@changesets/cli": "^2.31.1",
|
|
68
|
+
"@types/node": "^26.1.1",
|
|
69
|
+
"mppx": "0.8.13",
|
|
70
|
+
"tsx": "^4.23.1",
|
|
71
|
+
"typescript": "~6.0.3",
|
|
72
|
+
"viem": "^2.55.4",
|
|
73
|
+
"vitest": "^4.1.10"
|
|
74
|
+
},
|
|
75
|
+
"scripts": {
|
|
76
|
+
"build": "tsc -p tsconfig.build.json",
|
|
77
|
+
"changeset": "changeset",
|
|
78
|
+
"check": "pnpm check:types && pnpm lint && pnpm test",
|
|
79
|
+
"check:types": "tsc --noEmit",
|
|
80
|
+
"demo:app": "pnpm -C demo/app dev",
|
|
81
|
+
"demo:build": "pnpm -C demo/app install && pnpm -C demo/app build",
|
|
82
|
+
"demo:server": "tsx --env-file-if-exists=.env demo/server/index.ts",
|
|
83
|
+
"example:client": "tsx --env-file-if-exists=.env examples/client.ts",
|
|
84
|
+
"example:server": "tsx --env-file-if-exists=.env examples/server.ts",
|
|
85
|
+
"lint": "biome check .",
|
|
86
|
+
"lint:fix": "biome check --write .",
|
|
87
|
+
"release": "pnpm build && changeset publish",
|
|
88
|
+
"test": "vitest run"
|
|
89
|
+
}
|
|
90
|
+
}
|
package/src/Errors.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Errors } from 'mppx'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The deposit was verified but the cross-chain swap did not complete
|
|
5
|
+
* (1Click terminal status `FAILED` or `REFUNDED`). The deposit is refunded to
|
|
6
|
+
* `methodDetails.refundTo`; the client recovers with a fresh challenge.
|
|
7
|
+
*
|
|
8
|
+
* Additional error code registered by the `nearintents` spec (§Error Codes).
|
|
9
|
+
*/
|
|
10
|
+
export class SettlementFailedError extends Errors.PaymentError {
|
|
11
|
+
override readonly name = 'SettlementFailedError'
|
|
12
|
+
readonly title = 'Settlement Failed'
|
|
13
|
+
override readonly status: number = 402
|
|
14
|
+
readonly type = 'https://paymentauth.org/problems/settlement-failed'
|
|
15
|
+
|
|
16
|
+
constructor(options: SettlementFailedError.Options = {}) {
|
|
17
|
+
const { reason } = options
|
|
18
|
+
super(
|
|
19
|
+
reason
|
|
20
|
+
? `Settlement failed: ${reason}.`
|
|
21
|
+
: 'Settlement failed: the cross-chain swap did not complete; the deposit is refunded to the refund address.',
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export declare namespace SettlementFailedError {
|
|
27
|
+
type Options = {
|
|
28
|
+
/** Reason settlement failed (e.g. the 1Click refund reason). */
|
|
29
|
+
reason?: string | undefined
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The 1Click backend was unreachable during a required check. Per the spec
|
|
35
|
+
* (§Verification), this MUST surface as an HTTP 5xx — never as
|
|
36
|
+
* `verification-failed` — and the credential MUST NOT be settled or consumed.
|
|
37
|
+
* The client retries the same credential once the backend recovers.
|
|
38
|
+
*/
|
|
39
|
+
export class SettlementUnavailableError extends Errors.PaymentError {
|
|
40
|
+
override readonly name = 'SettlementUnavailableError'
|
|
41
|
+
readonly title = 'Settlement Backend Unavailable'
|
|
42
|
+
override readonly status: number = 503
|
|
43
|
+
readonly type = 'https://paymentauth.org/problems/server-error'
|
|
44
|
+
|
|
45
|
+
constructor(options: SettlementUnavailableError.Options = {}) {
|
|
46
|
+
const { reason } = options
|
|
47
|
+
super(
|
|
48
|
+
reason
|
|
49
|
+
? `Settlement backend unavailable: ${reason}.`
|
|
50
|
+
: 'Settlement backend unavailable; retry the same credential later.',
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export declare namespace SettlementUnavailableError {
|
|
56
|
+
type Options = {
|
|
57
|
+
reason?: string | undefined
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Settlement did not reach a terminal state within the server's time budget.
|
|
63
|
+
* The swap may still complete; the credential is NOT consumed, so the client
|
|
64
|
+
* can re-present the same credential later (or wait for the refund path).
|
|
65
|
+
*/
|
|
66
|
+
export class SettlementTimeoutError extends Errors.PaymentError {
|
|
67
|
+
override readonly name = 'SettlementTimeoutError'
|
|
68
|
+
readonly title = 'Settlement Timeout'
|
|
69
|
+
override readonly status: number = 504
|
|
70
|
+
readonly type = 'https://paymentauth.org/problems/server-error'
|
|
71
|
+
|
|
72
|
+
constructor(options: SettlementTimeoutError.Options = {}) {
|
|
73
|
+
const { timeoutMs } = options
|
|
74
|
+
super(
|
|
75
|
+
`Settlement did not reach a terminal state${
|
|
76
|
+
timeoutMs !== undefined ? ` within ${timeoutMs}ms` : ''
|
|
77
|
+
}; re-present the same credential later.`,
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export declare namespace SettlementTimeoutError {
|
|
83
|
+
type Options = {
|
|
84
|
+
timeoutMs?: number | undefined
|
|
85
|
+
}
|
|
86
|
+
}
|
package/src/Methods.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Method } from 'mppx'
|
|
2
|
+
|
|
3
|
+
import * as Types from './Types.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* NEAR Intents charge method — shared schema used by both server and client.
|
|
7
|
+
*
|
|
8
|
+
* The challenge `request` carries the origin-chain leg the client must pay
|
|
9
|
+
* (`recipient` is a unique single-use 1Click deposit address) plus the
|
|
10
|
+
* merchant's destination leg in `methodDetails`. The credential payload is
|
|
11
|
+
* the client's confirmed origin-chain deposit transaction hash (push mode).
|
|
12
|
+
*
|
|
13
|
+
* Spec: docs/spec/draft-nearintents-charge-00.md
|
|
14
|
+
*/
|
|
15
|
+
export const charge = Method.from({
|
|
16
|
+
name: Types.paymentMethod,
|
|
17
|
+
intent: Types.chargeIntent,
|
|
18
|
+
schema: {
|
|
19
|
+
credential: {
|
|
20
|
+
payload: Types.HashPayloadSchema,
|
|
21
|
+
},
|
|
22
|
+
request: Types.ChargeRequestSchema,
|
|
23
|
+
},
|
|
24
|
+
})
|