@piprail/sdk 2.4.0 → 2.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/CHANGELOG.md +55 -0
- package/dist/index.cjs +177 -7
- package/dist/index.d.cts +31 -9
- package/dist/index.d.ts +31 -9
- package/dist/index.js +175 -5
- package/dist/{near-DI2I3MAV.cjs → near-H5AQ253I.cjs} +300 -24
- package/dist/{near-MTYBCUYM.js → near-OTPQD6BI.js} +287 -11
- package/package.json +6 -1
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
|
|
12
|
+
|
|
11
13
|
var _chunkJG6KRAW6cjs = require('./chunk-JG6KRAW6.cjs');
|
|
12
14
|
|
|
13
15
|
// src/drivers/near/index.ts
|
|
@@ -15,6 +17,11 @@ var _nearapijs = require('near-api-js');
|
|
|
15
17
|
|
|
16
18
|
// src/drivers/near/chains.ts
|
|
17
19
|
var NEAR_DECIMALS = 24;
|
|
20
|
+
function isValidNearAccountId(id) {
|
|
21
|
+
if (id.startsWith("0x")) return false;
|
|
22
|
+
if (id.length < 2 || id.length > 64) return false;
|
|
23
|
+
return /^(([a-z\d]+[-_])*[a-z\d]+\.)*([a-z\d]+[-_])*[a-z\d]+$/.test(id);
|
|
24
|
+
}
|
|
18
25
|
var NEAR_MAINNET = {
|
|
19
26
|
caip2: "near:mainnet",
|
|
20
27
|
defaultRpc: "https://free.rpc.fastnear.com",
|
|
@@ -92,6 +99,190 @@ function isNearAffordability(err) {
|
|
|
92
99
|
return /not enough|doesn't have enough|does not have enough|lack ?balance|exceeds .*balance|insufficient/i.test(m);
|
|
93
100
|
}
|
|
94
101
|
|
|
102
|
+
// src/drivers/near/exact.ts
|
|
103
|
+
|
|
104
|
+
var _borsh = require('borsh');
|
|
105
|
+
var FT_TRANSFER_GAS2 = 30000000000000n;
|
|
106
|
+
var ONE_YOCTO2 = 1n;
|
|
107
|
+
var ESTIMATED_BLOCK_SECONDS = 1;
|
|
108
|
+
var NONCE_BLOCK_MULTIPLIER = 1000000n;
|
|
109
|
+
async function payExactNear(input) {
|
|
110
|
+
const { signer, senderId, blockHeight, accessKeyNonce, accept } = input;
|
|
111
|
+
if (accept.asset === "native") {
|
|
112
|
+
throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)(
|
|
113
|
+
"NEAR exact is NEP-141-only (an ft_transfer); native NEAR is not exact-payable. Pay via onchain-proof."
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
if (!isValidNearAccountId(accept.asset)) {
|
|
117
|
+
throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)(`NEAR exact: asset "${accept.asset}" must be a NEP-141 contract account id.`);
|
|
118
|
+
}
|
|
119
|
+
if (!isValidNearAccountId(accept.payTo)) {
|
|
120
|
+
throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)(`NEAR exact: payTo "${accept.payTo}" is not a valid NEAR account id.`);
|
|
121
|
+
}
|
|
122
|
+
if (!isValidNearAccountId(senderId)) {
|
|
123
|
+
throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)(`NEAR exact: sender "${senderId}" is not a valid NEAR account id.`);
|
|
124
|
+
}
|
|
125
|
+
const t = accept.maxTimeoutSeconds;
|
|
126
|
+
if (!Number.isInteger(t) || t <= 0) {
|
|
127
|
+
throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)("NEAR exact: maxTimeoutSeconds must be a positive integer.");
|
|
128
|
+
}
|
|
129
|
+
const timeoutBlocks = BigInt(Math.max(1, Math.ceil(t / ESTIMATED_BLOCK_SECONDS)));
|
|
130
|
+
const maxBlockHeight = blockHeight + timeoutBlocks;
|
|
131
|
+
const nonce = accessKeyNonce + 1n;
|
|
132
|
+
if (nonce >= blockHeight * NONCE_BLOCK_MULTIPLIER) {
|
|
133
|
+
throw new (0, _chunkJG6KRAW6cjs.UnsupportedSchemeError)(
|
|
134
|
+
"NEAR exact: the access-key nonce is at the protocol ceiling for this block height; cannot build a delegate action."
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
const publicKey = await signer.getPublicKey();
|
|
138
|
+
const action = _nearapijs.actions.functionCall(
|
|
139
|
+
"ft_transfer",
|
|
140
|
+
{ receiver_id: accept.payTo, amount: accept.amount },
|
|
141
|
+
FT_TRANSFER_GAS2,
|
|
142
|
+
ONE_YOCTO2
|
|
143
|
+
);
|
|
144
|
+
const delegateAction = _nearapijs.buildDelegateAction.call(void 0, {
|
|
145
|
+
senderId,
|
|
146
|
+
receiverId: accept.asset,
|
|
147
|
+
actions: [action],
|
|
148
|
+
nonce,
|
|
149
|
+
maxBlockHeight,
|
|
150
|
+
publicKey
|
|
151
|
+
});
|
|
152
|
+
const { signedDelegate } = await signer.signDelegateAction(delegateAction);
|
|
153
|
+
const encoded = _nearapijs.encodeSignedDelegate.call(void 0, signedDelegate);
|
|
154
|
+
return {
|
|
155
|
+
payload: { signedDelegateAction: Buffer.from(encoded).toString("base64") },
|
|
156
|
+
payerFrom: senderId,
|
|
157
|
+
// A stable id for THIS authorization (single-use on-chain via the access-key nonce): the
|
|
158
|
+
// client records it as the spend ref and re-presents the SAME signed action on a retry.
|
|
159
|
+
nonce: `${senderId}:${nonce.toString()}`
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
var MAX_RELAY_GAS = 300000000000000n;
|
|
163
|
+
var b64decode = (s) => new Uint8Array(Buffer.from(s, "base64"));
|
|
164
|
+
function shorten(msg) {
|
|
165
|
+
const oneLine = msg.replace(/\s+/g, " ").trim();
|
|
166
|
+
return oneLine.length > 200 ? `${oneLine.slice(0, 200)}\u2026` : oneLine;
|
|
167
|
+
}
|
|
168
|
+
function fail(error, detail) {
|
|
169
|
+
return { ok: false, error, detail };
|
|
170
|
+
}
|
|
171
|
+
function verifyExactNear(payload, accept, currentBlockHeight) {
|
|
172
|
+
if (accept.asset === "native" || !isValidNearAccountId(accept.asset)) {
|
|
173
|
+
return fail("transfer_not_found", `NEAR exact rail asset "${accept.asset}" is not a NEP-141 contract.`);
|
|
174
|
+
}
|
|
175
|
+
if (typeof _optionalChain([payload, 'optionalAccess', _ => _.signedDelegateAction]) !== "string") {
|
|
176
|
+
return fail("signature_invalid", "NEAR exact payload is missing signedDelegateAction.");
|
|
177
|
+
}
|
|
178
|
+
let decoded;
|
|
179
|
+
try {
|
|
180
|
+
decoded = _borsh.deserialize.call(void 0, _nearapijs.SCHEMA.SignedDelegate, b64decode(payload.signedDelegateAction));
|
|
181
|
+
} catch (err) {
|
|
182
|
+
return fail("signature_invalid", `Unparseable SignedDelegateAction: ${shorten(err instanceof Error ? err.message : String(err))}.`);
|
|
183
|
+
}
|
|
184
|
+
const da = _optionalChain([decoded, 'optionalAccess', _2 => _2.delegateAction]);
|
|
185
|
+
const sig = _optionalChain([decoded, 'optionalAccess', _3 => _3.signature]);
|
|
186
|
+
if (!da || sig == null) return fail("signature_invalid", "SignedDelegateAction is missing its delegate action or signature.");
|
|
187
|
+
if (!Array.isArray(da.actions) || da.actions.length !== 1) {
|
|
188
|
+
return fail("transfer_not_found", `the delegate must carry exactly one action, got ${_nullishCoalesce(_optionalChain([da, 'access', _4 => _4.actions, 'optionalAccess', _5 => _5.length]), () => ( 0))}.`);
|
|
189
|
+
}
|
|
190
|
+
const fc = _optionalChain([da, 'access', _6 => _6.actions, 'access', _7 => _7[0], 'optionalAccess', _8 => _8.functionCall]);
|
|
191
|
+
if (!fc || fc.methodName !== "ft_transfer") {
|
|
192
|
+
return fail("transfer_not_found", `the delegated action is not an ft_transfer (got "${_nullishCoalesce(_optionalChain([fc, 'optionalAccess', _9 => _9.methodName]), () => ( "none"))}").`);
|
|
193
|
+
}
|
|
194
|
+
if (da.receiverId !== accept.asset) {
|
|
195
|
+
return fail("transfer_not_found", `delegate receiver ${da.receiverId} \u2260 token contract ${accept.asset}.`);
|
|
196
|
+
}
|
|
197
|
+
let args;
|
|
198
|
+
try {
|
|
199
|
+
args = JSON.parse(Buffer.from(_nullishCoalesce(fc.args, () => ( new Uint8Array()))).toString());
|
|
200
|
+
} catch (e2) {
|
|
201
|
+
return fail("transfer_not_found", "the ft_transfer args are not valid JSON.");
|
|
202
|
+
}
|
|
203
|
+
if (args.receiver_id !== accept.payTo) {
|
|
204
|
+
return fail("wrong_recipient", `ft_transfer pays ${String(args.receiver_id)}, not payTo ${accept.payTo}.`);
|
|
205
|
+
}
|
|
206
|
+
if (typeof args.amount !== "string" || !/^\d+$/.test(args.amount) || BigInt(args.amount) < BigInt(accept.amount)) {
|
|
207
|
+
return fail("amount_too_low", `ft_transfer pays ${String(args.amount)} of the token, required ${accept.amount}.`);
|
|
208
|
+
}
|
|
209
|
+
let deposit;
|
|
210
|
+
let gas;
|
|
211
|
+
try {
|
|
212
|
+
deposit = BigInt(_nullishCoalesce(fc.deposit, () => ( 0)));
|
|
213
|
+
gas = BigInt(_nullishCoalesce(fc.gas, () => ( 0)));
|
|
214
|
+
} catch (e3) {
|
|
215
|
+
return fail("signature_invalid", "the ft_transfer has a malformed gas/deposit.");
|
|
216
|
+
}
|
|
217
|
+
if (deposit !== ONE_YOCTO2) {
|
|
218
|
+
return fail("signature_invalid", `attached deposit ${deposit} \u2260 the required 1 yoctoNEAR (relayer drain guard).`);
|
|
219
|
+
}
|
|
220
|
+
if (gas > MAX_RELAY_GAS) {
|
|
221
|
+
return fail("signature_invalid", `delegated gas ${gas} exceeds the ${MAX_RELAY_GAS} cap (relayer drain guard).`);
|
|
222
|
+
}
|
|
223
|
+
if (currentBlockHeight !== null) {
|
|
224
|
+
let maxBlock;
|
|
225
|
+
try {
|
|
226
|
+
maxBlock = BigInt(_nullishCoalesce(da.maxBlockHeight, () => ( 0)));
|
|
227
|
+
} catch (e4) {
|
|
228
|
+
return fail("signature_invalid", "the delegate has a malformed max_block_height.");
|
|
229
|
+
}
|
|
230
|
+
if (maxBlock <= currentBlockHeight) {
|
|
231
|
+
return fail("payment_expired", `the delegate expired (max_block_height ${maxBlock} \u2264 current ${currentBlockHeight}).`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (!da.senderId || !isValidNearAccountId(String(da.senderId))) {
|
|
235
|
+
return fail("signature_invalid", `the delegate sender "${String(da.senderId)}" is not a valid NEAR account id.`);
|
|
236
|
+
}
|
|
237
|
+
return { ok: true, senderId: String(da.senderId), delegateAction: new (0, _nearapijs.DelegateAction)(da), signature: sig };
|
|
238
|
+
}
|
|
239
|
+
async function verifyAndSettleExactNear(input) {
|
|
240
|
+
const { client, payload, accept } = input;
|
|
241
|
+
let height = null;
|
|
242
|
+
try {
|
|
243
|
+
height = await client.currentBlockHeight();
|
|
244
|
+
} catch (e5) {
|
|
245
|
+
}
|
|
246
|
+
const v = verifyExactNear(payload, accept, height);
|
|
247
|
+
if (!v.ok) return v;
|
|
248
|
+
let result;
|
|
249
|
+
try {
|
|
250
|
+
result = await client.relay({ senderId: v.senderId, delegateAction: v.delegateAction, signature: v.signature });
|
|
251
|
+
} catch (err) {
|
|
252
|
+
const m = err instanceof Error ? err.message : String(err);
|
|
253
|
+
if (/invalid.*nonce|nonce.*used|DelegateActionInvalidNonce/i.test(m)) {
|
|
254
|
+
return fail("tx_already_used", `this delegate was already used (single-use nonce): ${shorten(m)}.`);
|
|
255
|
+
}
|
|
256
|
+
if (/expired|DelegateActionExpired|max_block_height|deadline/i.test(m)) {
|
|
257
|
+
return fail("payment_expired", `the delegate expired before it landed: ${shorten(m)}.`);
|
|
258
|
+
}
|
|
259
|
+
if (/not enough|insufficient|exceeded the prepaid gas|NotEnoughBalance|doesn't have enough|is not registered/i.test(m)) {
|
|
260
|
+
return fail("tx_reverted", `the ft_transfer would fail on chain: ${shorten(m)}.`);
|
|
261
|
+
}
|
|
262
|
+
throw new (0, _chunkJG6KRAW6cjs.SettlementError)(
|
|
263
|
+
`NEAR exact settle: the relayer could not submit the delegate (${shorten(m)}). The buyer's signed delegate is still valid \u2014 fund/fix the relayer and the buyer can re-present it.`,
|
|
264
|
+
{ cause: err }
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
if (!result.innerSuccess) {
|
|
268
|
+
return fail("tx_reverted", `the ft_transfer receipt did not succeed on chain (tx ${result.txHash}).`);
|
|
269
|
+
}
|
|
270
|
+
return {
|
|
271
|
+
ok: true,
|
|
272
|
+
receipt: {
|
|
273
|
+
scheme: "exact",
|
|
274
|
+
success: true,
|
|
275
|
+
network: accept.network,
|
|
276
|
+
transaction: result.txHash,
|
|
277
|
+
asset: accept.asset,
|
|
278
|
+
amount: accept.amount,
|
|
279
|
+
payer: v.senderId,
|
|
280
|
+
payTo: accept.payTo,
|
|
281
|
+
verifiedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
95
286
|
// src/drivers/near/verify.ts
|
|
96
287
|
function parseFtTransferEvent(line) {
|
|
97
288
|
const marker = "EVENT_JSON:";
|
|
@@ -102,7 +293,7 @@ function parseFtTransferEvent(line) {
|
|
|
102
293
|
if (ev.standard === "nep141" && ev.event === "ft_transfer" && Array.isArray(ev.data)) {
|
|
103
294
|
return ev.data;
|
|
104
295
|
}
|
|
105
|
-
} catch (
|
|
296
|
+
} catch (e6) {
|
|
106
297
|
}
|
|
107
298
|
return null;
|
|
108
299
|
}
|
|
@@ -113,7 +304,7 @@ async function verifyNear(params) {
|
|
|
113
304
|
let tx;
|
|
114
305
|
try {
|
|
115
306
|
tx = await reader.txStatus(hash, senderId);
|
|
116
|
-
} catch (
|
|
307
|
+
} catch (e7) {
|
|
117
308
|
return txNotFound(hash);
|
|
118
309
|
}
|
|
119
310
|
if (!tx) return txNotFound(hash);
|
|
@@ -134,7 +325,7 @@ async function verifyNear(params) {
|
|
|
134
325
|
let paid2;
|
|
135
326
|
try {
|
|
136
327
|
paid2 = BigInt(_nullishCoalesce(tx.nativeDeposit, () => ( "0")));
|
|
137
|
-
} catch (
|
|
328
|
+
} catch (e8) {
|
|
138
329
|
paid2 = 0n;
|
|
139
330
|
}
|
|
140
331
|
if (paid2 < required) {
|
|
@@ -176,7 +367,7 @@ async function verifyNear(params) {
|
|
|
176
367
|
if (d.new_owner_id === accept.payTo && (_nullishCoalesce(d.memo, () => ( ""))) === nonce) {
|
|
177
368
|
try {
|
|
178
369
|
paid += BigInt(_nullishCoalesce(d.amount, () => ( "0")));
|
|
179
|
-
} catch (
|
|
370
|
+
} catch (e9) {
|
|
180
371
|
}
|
|
181
372
|
if (!payer) payer = _nullishCoalesce(d.old_owner_id, () => ( ""));
|
|
182
373
|
}
|
|
@@ -253,11 +444,6 @@ var nearDriver = {
|
|
|
253
444
|
return makeNearNetwork(NEAR_MAINNET, rpcUrl);
|
|
254
445
|
}
|
|
255
446
|
};
|
|
256
|
-
function isValidNearAccountId(id) {
|
|
257
|
-
if (id.startsWith("0x")) return false;
|
|
258
|
-
if (id.length < 2 || id.length > 64) return false;
|
|
259
|
-
return /^(([a-z\d]+[-_])*[a-z\d]+\.)*([a-z\d]+[-_])*[a-z\d]+$/.test(id);
|
|
260
|
-
}
|
|
261
447
|
function makeNearNetwork(preset, rpcUrl) {
|
|
262
448
|
const provider = new (0, _nearapijs.JsonRpcProvider)({ url: rpcUrl });
|
|
263
449
|
const network = preset.caip2;
|
|
@@ -276,18 +462,18 @@ function makeNearNetwork(preset, rpcUrl) {
|
|
|
276
462
|
logs: _nullishCoalesce(r.outcome.logs, () => ( []))
|
|
277
463
|
}));
|
|
278
464
|
const txn = outcome.transaction;
|
|
279
|
-
const receiverId = _optionalChain([txn, 'optionalAccess',
|
|
280
|
-
const nativeDeposit = sumTransferDeposits(_optionalChain([txn, 'optionalAccess',
|
|
465
|
+
const receiverId = _optionalChain([txn, 'optionalAccess', _10 => _10.receiver_id]);
|
|
466
|
+
const nativeDeposit = sumTransferDeposits(_optionalChain([txn, 'optionalAccess', _11 => _11.actions])).toString();
|
|
281
467
|
let timestampMs;
|
|
282
468
|
try {
|
|
283
|
-
const blockHash = _optionalChain([outcome, 'access',
|
|
469
|
+
const blockHash = _optionalChain([outcome, 'access', _12 => _12.transaction_outcome, 'optionalAccess', _13 => _13.block_hash]);
|
|
284
470
|
if (blockHash) {
|
|
285
471
|
const block = await provider.viewBlock({ blockId: blockHash });
|
|
286
472
|
const header = block.header;
|
|
287
|
-
const ns = _nullishCoalesce(_optionalChain([header, 'optionalAccess',
|
|
473
|
+
const ns = _nullishCoalesce(_optionalChain([header, 'optionalAccess', _14 => _14.timestamp_nanosec]), () => ( (_optionalChain([header, 'optionalAccess', _15 => _15.timestamp]) != null ? String(header.timestamp) : void 0)));
|
|
288
474
|
if (ns != null) timestampMs = Number(BigInt(ns) / 1000000n);
|
|
289
475
|
}
|
|
290
|
-
} catch (
|
|
476
|
+
} catch (e10) {
|
|
291
477
|
}
|
|
292
478
|
return { success, receipts, receiverId, nativeDeposit, timestampMs };
|
|
293
479
|
}
|
|
@@ -349,7 +535,7 @@ function makeNearNetwork(preset, rpcUrl) {
|
|
|
349
535
|
const { accountId, signer } = resolveNearWallet(wallet._native);
|
|
350
536
|
const account = new (0, _nearapijs.Account)(accountId, provider, signer);
|
|
351
537
|
const hashOf = (outcome) => {
|
|
352
|
-
const hash2 = _optionalChain([outcome, 'access',
|
|
538
|
+
const hash2 = _optionalChain([outcome, 'access', _16 => _16.transaction, 'optionalAccess', _17 => _17.hash]);
|
|
353
539
|
if (!hash2) throw new Error("NEAR: signAndSendTransaction returned no tx hash.");
|
|
354
540
|
return hash2;
|
|
355
541
|
};
|
|
@@ -379,7 +565,7 @@ function makeNearNetwork(preset, rpcUrl) {
|
|
|
379
565
|
try {
|
|
380
566
|
const tx = await reader.txStatus(hash, senderId);
|
|
381
567
|
if (tx && tx.success) return { height: "0" };
|
|
382
|
-
} catch (
|
|
568
|
+
} catch (e11) {
|
|
383
569
|
}
|
|
384
570
|
throw new (0, _chunkJG6KRAW6cjs.ConfirmationTimeoutError)(`NEAR tx ${hash} not confirmed in time.`);
|
|
385
571
|
},
|
|
@@ -396,7 +582,7 @@ function makeNearNetwork(preset, rpcUrl) {
|
|
|
396
582
|
let accountId;
|
|
397
583
|
try {
|
|
398
584
|
accountId = resolveNearWallet(wallet._native).accountId;
|
|
399
|
-
} catch (
|
|
585
|
+
} catch (e12) {
|
|
400
586
|
return { token: null, native: null };
|
|
401
587
|
}
|
|
402
588
|
let native = null;
|
|
@@ -408,7 +594,7 @@ function makeNearNetwork(preset, rpcUrl) {
|
|
|
408
594
|
});
|
|
409
595
|
native = r.amount != null ? BigInt(r.amount) : null;
|
|
410
596
|
} catch (e) {
|
|
411
|
-
native = /does not exist|UNKNOWN_ACCOUNT/i.test(String(_nullishCoalesce(_optionalChain([e, 'optionalAccess',
|
|
597
|
+
native = /does not exist|UNKNOWN_ACCOUNT/i.test(String(_nullishCoalesce(_optionalChain([e, 'optionalAccess', _18 => _18.message]), () => ( e)))) ? 0n : null;
|
|
412
598
|
}
|
|
413
599
|
if (asset === "native") return { token: native, native };
|
|
414
600
|
let token = null;
|
|
@@ -422,7 +608,7 @@ function makeNearNetwork(preset, rpcUrl) {
|
|
|
422
608
|
});
|
|
423
609
|
token = r.result ? BigInt(JSON.parse(Buffer.from(r.result).toString())) : null;
|
|
424
610
|
} catch (e) {
|
|
425
|
-
token = /does not exist|not registered|UNKNOWN_ACCOUNT/i.test(String(_nullishCoalesce(_optionalChain([e, 'optionalAccess',
|
|
611
|
+
token = /does not exist|not registered|UNKNOWN_ACCOUNT/i.test(String(_nullishCoalesce(_optionalChain([e, 'optionalAccess', _19 => _19.message]), () => ( e)))) ? 0n : null;
|
|
426
612
|
}
|
|
427
613
|
return { token, native };
|
|
428
614
|
},
|
|
@@ -438,13 +624,103 @@ function makeNearNetwork(preset, rpcUrl) {
|
|
|
438
624
|
});
|
|
439
625
|
const parsed = r.result ? JSON.parse(Buffer.from(r.result).toString()) : null;
|
|
440
626
|
return parsed == null ? { ready: false, reason: "NOT_REGISTERED" } : { ready: true };
|
|
441
|
-
} catch (
|
|
627
|
+
} catch (e13) {
|
|
442
628
|
return { ready: "unknown" };
|
|
443
629
|
}
|
|
444
630
|
},
|
|
445
631
|
async verify(ref, accept) {
|
|
446
632
|
const { senderId, hash } = decodeRef(ref);
|
|
447
633
|
return verifyNear({ reader, hash, senderId, accept });
|
|
634
|
+
},
|
|
635
|
+
// Standard x402 `exact` rail, BUYER side — build a NEP-366 SignedDelegateAction authorizing one
|
|
636
|
+
// NEP-141 ft_transfer (per scheme_exact_near.md). The buyer signs with its FULL-ACCESS key and
|
|
637
|
+
// spends ZERO NEAR; a keyless facilitator's relayer prepays the gas + 1 yoctoNEAR and submits.
|
|
638
|
+
// NEAR exact is NEP-141-only + facilitator-settled (see ./exact.ts for why) — native NEAR isn't
|
|
639
|
+
// exact-payable. Pre-reads the access-key nonce + final block height, then defers to payExactNear.
|
|
640
|
+
async payExact(wallet, accept) {
|
|
641
|
+
const { accountId, signer } = resolveNearWallet(wallet._native);
|
|
642
|
+
const publicKey = await signer.getPublicKey();
|
|
643
|
+
const [accessKey, block] = await Promise.all([
|
|
644
|
+
provider.query({
|
|
645
|
+
request_type: "view_access_key",
|
|
646
|
+
finality: "final",
|
|
647
|
+
account_id: accountId,
|
|
648
|
+
public_key: publicKey.toString()
|
|
649
|
+
}),
|
|
650
|
+
provider.viewBlock({ finality: "final" })
|
|
651
|
+
]);
|
|
652
|
+
const accessKeyNonce = BigInt(_nullishCoalesce(accessKey.nonce, () => ( 0)));
|
|
653
|
+
const blockHeight = BigInt(_nullishCoalesce(_optionalChain([block, 'access', _20 => _20.header, 'optionalAccess', _21 => _21.height]), () => ( 0)));
|
|
654
|
+
const { payload, payerFrom, nonce } = await payExactNear({
|
|
655
|
+
signer,
|
|
656
|
+
senderId: accountId,
|
|
657
|
+
blockHeight,
|
|
658
|
+
accessKeyNonce,
|
|
659
|
+
accept
|
|
660
|
+
});
|
|
661
|
+
return { payload, accepted: accept, payerFrom, nonce };
|
|
662
|
+
},
|
|
663
|
+
// The gate's rail-advertisement SPI. NEAR exact is NEP-141-only. The fee payer (the relayer that
|
|
664
|
+
// prepays gas + the 1 yocto, so the BUYER pays nothing) comes from EITHER the merchant's own bound
|
|
665
|
+
// `relayer` (SELF mode — what works today) OR a facilitator-provided `feePayer` (facilitator mode —
|
|
666
|
+
// for when a NEAR x402 facilitator ships; none does yet). `null` for native / non-NEP-141 / when no
|
|
667
|
+
// fee payer is available. The buyer's SignedDelegateAction is self-contained, so `feePayer` rides in
|
|
668
|
+
// `extra` only for observability + (future) facilitator forwarding.
|
|
669
|
+
async resolveExactRail({ asset, relayer, feePayer }) {
|
|
670
|
+
if (asset === "native" || !isValidNearAccountId(asset)) return null;
|
|
671
|
+
let fp = feePayer;
|
|
672
|
+
if (!fp && relayer) {
|
|
673
|
+
try {
|
|
674
|
+
fp = resolveNearWallet(relayer._native).accountId;
|
|
675
|
+
} catch (e14) {
|
|
676
|
+
return null;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
if (!fp) return null;
|
|
680
|
+
return { method: "near", extra: { feePayer: fp } };
|
|
681
|
+
},
|
|
682
|
+
// Standard x402 `exact` rail, SELLER side (SELF-SETTLE) — decode + verify the inbound delegate
|
|
683
|
+
// against the trusted accept, then RELAY it from the merchant's own NEAR relayer (which prepays the
|
|
684
|
+
// sub-cent gas + the 1 yocto). The buyer stays gasless. THIS is how a NEAR gate gets paid today
|
|
685
|
+
// (no third-party facilitator settles NEAR yet). The drain guard (gas/deposit caps) lives in
|
|
686
|
+
// verifyAndSettleExactNear, invisible to the gate.
|
|
687
|
+
async settleExactSelf({ relayer, payload, accept }) {
|
|
688
|
+
if (!("signedDelegateAction" in payload)) {
|
|
689
|
+
return { ok: false, error: "signature_invalid", detail: "NEAR exact expects a { signedDelegateAction } payload." };
|
|
690
|
+
}
|
|
691
|
+
let relayerWallet;
|
|
692
|
+
try {
|
|
693
|
+
relayerWallet = resolveNearWallet(relayer._native);
|
|
694
|
+
} catch (err) {
|
|
695
|
+
throw new (0, _chunkJG6KRAW6cjs.SettlementError)(
|
|
696
|
+
`NEAR exact settle: the relayer wallet is invalid (${err instanceof Error ? err.message : String(err)}).`,
|
|
697
|
+
{ cause: err }
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
const relayerAccount = new (0, _nearapijs.Account)(relayerWallet.accountId, provider, relayerWallet.signer);
|
|
701
|
+
const isSuccess = (s) => typeof s === "object" && s !== null && "SuccessValue" in s;
|
|
702
|
+
const client = {
|
|
703
|
+
async currentBlockHeight() {
|
|
704
|
+
try {
|
|
705
|
+
const b = await provider.viewBlock({ finality: "final" });
|
|
706
|
+
return _optionalChain([b, 'access', _22 => _22.header, 'optionalAccess', _23 => _23.height]) != null ? BigInt(b.header.height) : null;
|
|
707
|
+
} catch (e15) {
|
|
708
|
+
return null;
|
|
709
|
+
}
|
|
710
|
+
},
|
|
711
|
+
async relay({ senderId, delegateAction, signature }) {
|
|
712
|
+
const outcome = await relayerAccount.signAndSendTransaction({
|
|
713
|
+
receiverId: senderId,
|
|
714
|
+
actions: [_nearapijs.actions.signedDelegate({ delegateAction, signature })],
|
|
715
|
+
waitUntil: "FINAL"
|
|
716
|
+
});
|
|
717
|
+
const txHash = _nullishCoalesce(_optionalChain([outcome, 'access', _24 => _24.transaction, 'optionalAccess', _25 => _25.hash]), () => ( ""));
|
|
718
|
+
const tokenReceipt = (_nullishCoalesce(outcome.receipts_outcome, () => ( []))).find((r) => _optionalChain([r, 'access', _26 => _26.outcome, 'optionalAccess', _27 => _27.executor_id]) === accept.asset);
|
|
719
|
+
const innerSuccess = tokenReceipt ? isSuccess(_optionalChain([tokenReceipt, 'access', _28 => _28.outcome, 'optionalAccess', _29 => _29.status])) : isSuccess(outcome.status);
|
|
720
|
+
return { txHash, innerSuccess };
|
|
721
|
+
}
|
|
722
|
+
};
|
|
723
|
+
return verifyAndSettleExactNear({ client, payload, accept });
|
|
448
724
|
}
|
|
449
725
|
};
|
|
450
726
|
}
|
|
@@ -456,15 +732,15 @@ function decodeRef(ref) {
|
|
|
456
732
|
if (i < 0) return { senderId: "", hash: ref };
|
|
457
733
|
return { senderId: ref.slice(0, i), hash: ref.slice(i + 1) };
|
|
458
734
|
}
|
|
459
|
-
function sumTransferDeposits(
|
|
460
|
-
if (!Array.isArray(
|
|
735
|
+
function sumTransferDeposits(actions3) {
|
|
736
|
+
if (!Array.isArray(actions3)) return 0n;
|
|
461
737
|
let sum = 0n;
|
|
462
|
-
for (const a of
|
|
738
|
+
for (const a of actions3) {
|
|
463
739
|
const t = _nullishCoalesce(a.Transfer, () => ( a.transfer));
|
|
464
740
|
if (t && t.deposit != null) {
|
|
465
741
|
try {
|
|
466
742
|
sum += BigInt(t.deposit);
|
|
467
|
-
} catch (
|
|
743
|
+
} catch (e16) {
|
|
468
744
|
}
|
|
469
745
|
}
|
|
470
746
|
}
|