@piprail/sdk 1.14.0 → 1.15.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.
Files changed (31) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +27 -754
  3. package/dist/{algorand-OIHGJN5S.cjs → algorand-EJ3S2V7E.cjs} +17 -17
  4. package/dist/{algorand-7EUZYL2Z.js → algorand-F3OYB534.js} +1 -1
  5. package/dist/{aptos-WDWZOU25.cjs → aptos-GJGIZHNI.cjs} +16 -16
  6. package/dist/{aptos-CDEYDDM5.js → aptos-SUXOVP7B.js} +1 -1
  7. package/dist/{chunk-H3A4KWLJ.js → chunk-ILPABTI2.js} +6 -0
  8. package/dist/{chunk-FTKVCP6K.cjs → chunk-PA6YD3HL.cjs} +17 -11
  9. package/dist/index.cjs +493 -115
  10. package/dist/index.d.cts +264 -12
  11. package/dist/index.d.ts +264 -12
  12. package/dist/index.js +403 -25
  13. package/dist/{near-DT6LRIKB.js → near-LM7S3WUD.js} +1 -1
  14. package/dist/{near-FUH3VAXT.cjs → near-ZJLZE26R.cjs} +19 -19
  15. package/dist/{solana-QUVXPKBZ.cjs → solana-MPPE6K24.cjs} +14 -14
  16. package/dist/{solana-3TRYD4QB.js → solana-WDKWWF33.js} +1 -1
  17. package/dist/{stellar-IK3UML6O.js → stellar-FIJPQZVW.js} +1 -1
  18. package/dist/{stellar-APZEBFAD.cjs → stellar-XHLLNHQP.cjs} +21 -21
  19. package/dist/{sui-L7BQNJWO.cjs → sui-6CVLEXLA.cjs} +17 -17
  20. package/dist/{sui-VSE63WQM.js → sui-B7AVN7NK.js} +1 -1
  21. package/dist/{ton-QHGQLJX2.js → ton-CHJ26BVA.js} +1 -1
  22. package/dist/{ton-5DLKKOFE.cjs → ton-RNEFN25G.cjs} +14 -14
  23. package/dist/{tron-2N2GA62O.js → tron-DD3JDROV.js} +1 -1
  24. package/dist/{tron-HHIT6WKY.cjs → tron-TKJHNFGM.cjs} +24 -24
  25. package/dist/{xrpl-2GZMDYW5.js → xrpl-GTUPP6SK.js} +1 -1
  26. package/dist/{xrpl-USEG4AHX.cjs → xrpl-XN2NBNGI.cjs} +21 -21
  27. package/package.json +1 -5
  28. package/CHAINS.md +0 -179
  29. package/DISCOVERY.md +0 -420
  30. package/ERRORS.md +0 -269
  31. package/STANDARDS.md +0 -128
@@ -8,7 +8,7 @@ var _chunkCQREG5LEcjs = require('./chunk-CQREG5LE.cjs');
8
8
 
9
9
 
10
10
 
11
- var _chunkFTKVCP6Kcjs = require('./chunk-FTKVCP6K.cjs');
11
+ var _chunkPA6YD3HLcjs = require('./chunk-PA6YD3HL.cjs');
12
12
 
13
13
  // src/drivers/ton/index.ts
14
14
  var _core = require('@ton/core');
@@ -74,7 +74,7 @@ async function waitForSeqno(opened, from, { tries = 30, intervalMs = 2e3 } = {})
74
74
  }
75
75
  if (current > from) return;
76
76
  }
77
- throw new (0, _chunkFTKVCP6Kcjs.ConfirmationTimeoutError)(
77
+ throw new (0, _chunkPA6YD3HLcjs.ConfirmationTimeoutError)(
78
78
  `TON wallet seqno did not advance past ${from} \u2014 the payment may not have been accepted.`
79
79
  );
80
80
  }
@@ -202,17 +202,17 @@ var _crypto = require('@ton/crypto');
202
202
 
203
203
  function assertTonWallet(wallet, network) {
204
204
  if (typeof wallet !== "object" || wallet === null) {
205
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
205
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
206
206
  `chain ${network} is TON; wallet must be { mnemonic } (24 words) or { keyPair }.`
207
207
  );
208
208
  }
209
209
  if ("privateKey" in wallet || "walletClient" in wallet) {
210
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
210
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
211
211
  `chain ${network} is TON; an EVM wallet can't be used \u2014 pass { mnemonic } (24 words) or { keyPair }.`
212
212
  );
213
213
  }
214
214
  if (!("mnemonic" in wallet) && !("keyPair" in wallet)) {
215
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
215
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
216
216
  `chain ${network} is TON; wallet must be { mnemonic } (24 words) or { keyPair }.`
217
217
  );
218
218
  }
@@ -227,7 +227,7 @@ async function resolveTonWallet(config) {
227
227
  } else if (config.keyPair) {
228
228
  keyPair = config.keyPair;
229
229
  } else {
230
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)("TON wallet needs { mnemonic } (24 words) or { keyPair }.");
230
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)("TON wallet needs { mnemonic } (24 words) or { keyPair }.");
231
231
  }
232
232
  const contract = version === "v5r1" ? _ton.WalletContractV5R1.create({ workchain: 0, publicKey: keyPair.publicKey }) : _ton.WalletContractV4.create({ workchain: 0, publicKey: keyPair.publicKey });
233
233
  return { keyPair, contract };
@@ -270,15 +270,15 @@ function makeTonNetwork(preset, rpcUrl) {
270
270
  const info = preset.tokens[token.toUpperCase()];
271
271
  if (!info) {
272
272
  const known = Object.keys(preset.tokens).join(", ") || "(none built in)";
273
- throw new (0, _chunkFTKVCP6Kcjs.UnknownTokenError)(
273
+ throw new (0, _chunkPA6YD3HLcjs.UnknownTokenError)(
274
274
  `token "${token}" isn't built in for TON (known: ${known}). Note: native USDC doesn't exist on TON. Pass { master, decimals } for a custom jetton, or use 'native'.`
275
275
  );
276
276
  }
277
277
  return { asset: info.master, decimals: info.decimals, symbol: info.symbol };
278
278
  }
279
- _chunkFTKVCP6Kcjs.rejectForeignToken.call(void 0, token, "ton", network);
279
+ _chunkPA6YD3HLcjs.rejectForeignToken.call(void 0, token, "ton", network);
280
280
  if (!("master" in token)) {
281
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
281
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
282
282
  `chain ${network} is TON; a custom token must be { master, decimals }.`
283
283
  );
284
284
  }
@@ -297,14 +297,14 @@ function makeTonNetwork(preset, rpcUrl) {
297
297
  },
298
298
  assertValidPayTo(payTo) {
299
299
  if (payTo.startsWith("0x")) {
300
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
300
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
301
301
  `chain ${network} is TON, but payTo "${payTo}" looks like an EVM address.`
302
302
  );
303
303
  }
304
304
  try {
305
305
  _core.Address.parse(payTo);
306
306
  } catch (e6) {
307
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
307
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
308
308
  `chain ${network} is TON, but payTo "${payTo}" is not a valid TON address.`
309
309
  );
310
310
  }
@@ -320,7 +320,7 @@ function makeTonNetwork(preset, rpcUrl) {
320
320
  const watch = await watchAccountFor(accept);
321
321
  return encodeRef(watch, accept.extra.nonce);
322
322
  } catch (err) {
323
- throw _nullishCoalesce(_chunkFTKVCP6Kcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
323
+ throw _nullishCoalesce(_chunkPA6YD3HLcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
324
324
  }
325
325
  },
326
326
  async confirm(ref) {
@@ -339,12 +339,12 @@ function makeTonNetwork(preset, rpcUrl) {
339
339
  if (inc && inc.comment === nonce) return { height: tx.lt.toString() };
340
340
  }
341
341
  }
342
- throw new (0, _chunkFTKVCP6Kcjs.ConfirmationTimeoutError)(`TON payment for nonce ${nonce} did not settle in time.`);
342
+ throw new (0, _chunkPA6YD3HLcjs.ConfirmationTimeoutError)(`TON payment for nonce ${nonce} did not settle in time.`);
343
343
  },
344
344
  async estimateCost(accept) {
345
345
  const fee = accept.asset === "native" ? 10000000n : 50000000n;
346
346
  const detail = accept.asset === "native" ? "~0.01 TON network fee" : "~0.05 TON attached for the jetton transfer (leftover refunded)";
347
- return _chunkFTKVCP6Kcjs.nativeCost.call(void 0, { symbol: "TON", decimals: TON_DECIMALS, fee, basis: "heuristic", detail });
347
+ return _chunkPA6YD3HLcjs.nativeCost.call(void 0, { symbol: "TON", decimals: TON_DECIMALS, fee, basis: "heuristic", detail });
348
348
  },
349
349
  async balanceOf(wallet, asset) {
350
350
  let owner;
@@ -9,7 +9,7 @@ import {
9
9
  nativeCost,
10
10
  rejectForeignToken,
11
11
  toInsufficientFundsError
12
- } from "./chunk-H3A4KWLJ.js";
12
+ } from "./chunk-ILPABTI2.js";
13
13
 
14
14
  // src/drivers/tron/index.ts
15
15
  import { TronWeb } from "tronweb";
@@ -9,7 +9,7 @@ var _chunkCQREG5LEcjs = require('./chunk-CQREG5LE.cjs');
9
9
 
10
10
 
11
11
 
12
- var _chunkFTKVCP6Kcjs = require('./chunk-FTKVCP6K.cjs');
12
+ var _chunkPA6YD3HLcjs = require('./chunk-PA6YD3HL.cjs');
13
13
 
14
14
  // src/drivers/tron/index.ts
15
15
  var _tronweb = require('tronweb');
@@ -61,7 +61,7 @@ async function payTron(params) {
61
61
  return _nullishCoalesce(_nullishCoalesce(broadcast.txid, () => ( _optionalChain([broadcast, 'access', _7 => _7.transaction, 'optionalAccess', _8 => _8.txID]))), () => ( signed.txID));
62
62
  }
63
63
  if (isTronAffordability(broadcast.code, broadcast.message)) {
64
- throw new (0, _chunkFTKVCP6Kcjs.InsufficientFundsError)(
64
+ throw new (0, _chunkPA6YD3HLcjs.InsufficientFundsError)(
65
65
  `Tron payment rejected (${_nullishCoalesce(broadcast.code, () => ( "broadcast"))}): not enough TRX for energy/bandwidth, or insufficient token balance.`
66
66
  );
67
67
  }
@@ -69,8 +69,8 @@ async function payTron(params) {
69
69
  `Tron broadcast failed: ${_nullishCoalesce(broadcast.code, () => ( ""))} ${decodeMaybeHex(broadcast.message)}`.trim()
70
70
  );
71
71
  } catch (err) {
72
- if (err instanceof _chunkFTKVCP6Kcjs.InsufficientFundsError) throw err;
73
- throw _nullishCoalesce(_chunkFTKVCP6Kcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
72
+ if (err instanceof _chunkPA6YD3HLcjs.InsufficientFundsError) throw err;
73
+ throw _nullishCoalesce(_chunkPA6YD3HLcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
74
74
  }
75
75
  }
76
76
  async function payTronNative(params) {
@@ -83,7 +83,7 @@ async function payTronNative(params) {
83
83
  return _nullishCoalesce(_nullishCoalesce(broadcast.txid, () => ( _optionalChain([broadcast, 'access', _11 => _11.transaction, 'optionalAccess', _12 => _12.txID]))), () => ( signed.txID));
84
84
  }
85
85
  if (isTronAffordability(broadcast.code, broadcast.message)) {
86
- throw new (0, _chunkFTKVCP6Kcjs.InsufficientFundsError)(
86
+ throw new (0, _chunkPA6YD3HLcjs.InsufficientFundsError)(
87
87
  `Tron TRX payment rejected (${_nullishCoalesce(broadcast.code, () => ( "broadcast"))}): not enough TRX for the amount plus bandwidth (and the ~1 TRX account-creation fee if the recipient is new).`
88
88
  );
89
89
  }
@@ -91,8 +91,8 @@ async function payTronNative(params) {
91
91
  `Tron TRX broadcast failed: ${_nullishCoalesce(broadcast.code, () => ( ""))} ${decodeMaybeHex(broadcast.message)}`.trim()
92
92
  );
93
93
  } catch (err) {
94
- if (err instanceof _chunkFTKVCP6Kcjs.InsufficientFundsError) throw err;
95
- throw _nullishCoalesce(_chunkFTKVCP6Kcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
94
+ if (err instanceof _chunkPA6YD3HLcjs.InsufficientFundsError) throw err;
95
+ throw _nullishCoalesce(_chunkPA6YD3HLcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
96
96
  }
97
97
  }
98
98
  function decodeMaybeHex(message) {
@@ -263,22 +263,22 @@ function txNotFound(txid) {
263
263
  // src/drivers/tron/wallet.ts
264
264
  function assertTronWallet(wallet, network) {
265
265
  if (typeof wallet !== "object" || wallet === null) {
266
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
266
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
267
267
  `chain ${network} is Tron; wallet must be { privateKey } (32-byte hex).`
268
268
  );
269
269
  }
270
270
  if ("walletClient" in wallet) {
271
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
271
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
272
272
  `chain ${network} is Tron; a viem { walletClient } can't be used \u2014 pass { privateKey } (32-byte hex).`
273
273
  );
274
274
  }
275
275
  if ("secretKey" in wallet || "signer" in wallet || "mnemonic" in wallet || "keyPair" in wallet || "secret" in wallet || "keypair" in wallet || "seed" in wallet) {
276
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
276
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
277
277
  `chain ${network} is Tron; that looks like a Solana/TON/Stellar/XRPL wallet \u2014 pass { privateKey } (32-byte hex).`
278
278
  );
279
279
  }
280
280
  if (!("privateKey" in wallet)) {
281
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
281
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
282
282
  `chain ${network} is Tron; wallet must be { privateKey } (32-byte hex).`
283
283
  );
284
284
  }
@@ -286,11 +286,11 @@ function assertTronWallet(wallet, network) {
286
286
  }
287
287
  function resolveTronPrivateKey(config) {
288
288
  if (!config.privateKey) {
289
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)("Tron wallet needs { privateKey } (32-byte hex).");
289
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)("Tron wallet needs { privateKey } (32-byte hex).");
290
290
  }
291
291
  const hex = config.privateKey.replace(/^0x/i, "").toLowerCase();
292
292
  if (!/^[0-9a-f]{64}$/.test(hex)) {
293
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
293
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
294
294
  "Tron wallet { privateKey } must be a 32-byte hex string (64 hex chars)."
295
295
  );
296
296
  }
@@ -340,21 +340,21 @@ function makeTronNetwork(preset, rpcUrl) {
340
340
  const info = preset.tokens[token.toUpperCase()];
341
341
  if (!info) {
342
342
  const known = Object.keys(preset.tokens).join(", ") || "(none built in)";
343
- throw new (0, _chunkFTKVCP6Kcjs.UnknownTokenError)(
343
+ throw new (0, _chunkPA6YD3HLcjs.UnknownTokenError)(
344
344
  `token "${token}" isn't built in for Tron (known: ${known}). Note: native USDC doesn't exist on Tron. Pass { address, decimals } for a custom TRC-20.`
345
345
  );
346
346
  }
347
347
  return { asset: info.address, decimals: info.decimals, symbol: info.symbol };
348
348
  }
349
- _chunkFTKVCP6Kcjs.rejectForeignToken.call(void 0, token, "tron", network);
349
+ _chunkPA6YD3HLcjs.rejectForeignToken.call(void 0, token, "tron", network);
350
350
  if (!("address" in token)) {
351
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
351
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
352
352
  `chain ${network} is Tron; a custom token must be { address, decimals } (Base58 T\u2026 contract).`
353
353
  );
354
354
  }
355
355
  const t = token;
356
356
  if (t.address.startsWith("0x") || !tronWeb.isAddress(t.address)) {
357
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
357
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
358
358
  `chain ${network} is Tron, but token address "${t.address}" is not a valid Tron contract (T\u2026).`
359
359
  );
360
360
  }
@@ -373,12 +373,12 @@ function makeTronNetwork(preset, rpcUrl) {
373
373
  },
374
374
  assertValidPayTo(payTo) {
375
375
  if (payTo.startsWith("0x")) {
376
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
376
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
377
377
  `chain ${network} is Tron, but payTo "${payTo}" looks like an EVM address.`
378
378
  );
379
379
  }
380
380
  if (!tronWeb.isAddress(payTo)) {
381
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
381
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
382
382
  `chain ${network} is Tron, but payTo "${payTo}" is not a valid Tron address (T\u2026).`
383
383
  );
384
384
  }
@@ -390,7 +390,7 @@ function makeTronNetwork(preset, rpcUrl) {
390
390
  const privateKey = resolveTronPrivateKey(wallet._native);
391
391
  const from = tronWeb.address.fromPrivateKey(privateKey);
392
392
  if (!from) {
393
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)("Tron wallet { privateKey } could not derive an address.");
393
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)("Tron wallet { privateKey } could not derive an address.");
394
394
  }
395
395
  if (accept.asset === "native") {
396
396
  return payTronNative({ client: tronWeb, from, privateKey, accept });
@@ -413,11 +413,11 @@ function makeTronNetwork(preset, rpcUrl) {
413
413
  }
414
414
  await _chunkCQREG5LEcjs.delay.call(void 0, 2500);
415
415
  }
416
- throw new (0, _chunkFTKVCP6Kcjs.ConfirmationTimeoutError)(`Tron tx ${txid} did not solidify in time.`);
416
+ throw new (0, _chunkPA6YD3HLcjs.ConfirmationTimeoutError)(`Tron tx ${txid} did not solidify in time.`);
417
417
  },
418
418
  async estimateCost(accept, opts) {
419
419
  if (accept.asset === "native") {
420
- return _chunkFTKVCP6Kcjs.nativeCost.call(void 0, {
420
+ return _chunkPA6YD3HLcjs.nativeCost.call(void 0, {
421
421
  symbol: "TRX",
422
422
  decimals: TRX_DECIMALS,
423
423
  fee: 1300000n,
@@ -441,7 +441,7 @@ function makeTronNetwork(preset, rpcUrl) {
441
441
  );
442
442
  const energy = BigInt(_nullishCoalesce(r.energy_used, () => ( 0)));
443
443
  if (energy > 0n) {
444
- return _chunkFTKVCP6Kcjs.nativeCost.call(void 0, {
444
+ return _chunkPA6YD3HLcjs.nativeCost.call(void 0, {
445
445
  symbol: "TRX",
446
446
  decimals: TRX_DECIMALS,
447
447
  fee: energy * ENERGY_PRICE + BANDWIDTH_SUN,
@@ -452,7 +452,7 @@ function makeTronNetwork(preset, rpcUrl) {
452
452
  } catch (e8) {
453
453
  }
454
454
  }
455
- return _chunkFTKVCP6Kcjs.nativeCost.call(void 0, {
455
+ return _chunkPA6YD3HLcjs.nativeCost.call(void 0, {
456
456
  symbol: "TRX",
457
457
  decimals: TRX_DECIMALS,
458
458
  fee: 30000n * ENERGY_PRICE + BANDWIDTH_SUN,
@@ -12,7 +12,7 @@ import {
12
12
  parseUnits,
13
13
  rejectForeignToken,
14
14
  toInsufficientFundsError
15
- } from "./chunk-H3A4KWLJ.js";
15
+ } from "./chunk-ILPABTI2.js";
16
16
 
17
17
  // src/drivers/xrpl/index.ts
18
18
  import { isValidClassicAddress } from "xrpl";
@@ -12,7 +12,7 @@ var _chunkCQREG5LEcjs = require('./chunk-CQREG5LE.cjs');
12
12
 
13
13
 
14
14
 
15
- var _chunkFTKVCP6Kcjs = require('./chunk-FTKVCP6K.cjs');
15
+ var _chunkPA6YD3HLcjs = require('./chunk-PA6YD3HL.cjs');
16
16
 
17
17
  // src/drivers/xrpl/index.ts
18
18
  var _xrpl = require('xrpl');
@@ -94,17 +94,17 @@ async function payXrpl(params) {
94
94
  const code = res.engine_result;
95
95
  if (code.startsWith("tes")) return _nullishCoalesce(_optionalChain([res, 'access', _ => _.tx_json, 'optionalAccess', _2 => _2.hash]), () => ( signed.hash));
96
96
  const recipientMsg = recipientNotReadyMessage(code);
97
- if (recipientMsg) throw new (0, _chunkFTKVCP6Kcjs.RecipientNotReadyError)(recipientMsg, { cause: makeEngineError(res) });
97
+ if (recipientMsg) throw new (0, _chunkPA6YD3HLcjs.RecipientNotReadyError)(recipientMsg, { cause: makeEngineError(res) });
98
98
  if (isAffordabilityCode(code)) {
99
- throw new (0, _chunkFTKVCP6Kcjs.InsufficientFundsError)(
99
+ throw new (0, _chunkPA6YD3HLcjs.InsufficientFundsError)(
100
100
  `XRPL payment rejected: the sender can't cover it \u2014 balance or the 1 XRP base reserve. (XRPL: ${code})`,
101
101
  { cause: makeEngineError(res) }
102
102
  );
103
103
  }
104
104
  throw makeEngineError(res);
105
105
  } catch (err) {
106
- if (err instanceof _chunkFTKVCP6Kcjs.InsufficientFundsError || err instanceof _chunkFTKVCP6Kcjs.RecipientNotReadyError) throw err;
107
- throw _nullishCoalesce(_chunkFTKVCP6Kcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
106
+ if (err instanceof _chunkPA6YD3HLcjs.InsufficientFundsError || err instanceof _chunkPA6YD3HLcjs.RecipientNotReadyError) throw err;
107
+ throw _nullishCoalesce(_chunkPA6YD3HLcjs.toInsufficientFundsError.call(void 0, err), () => ( err));
108
108
  }
109
109
  }
110
110
  function amountForAccept(accept) {
@@ -229,7 +229,7 @@ function deliveredBaseUnits(delivered, want, decimals) {
229
229
  return null;
230
230
  }
231
231
  try {
232
- return _chunkFTKVCP6Kcjs.floorUnits.call(void 0, delivered.value, decimals);
232
+ return _chunkPA6YD3HLcjs.floorUnits.call(void 0, delivered.value, decimals);
233
233
  } catch (e3) {
234
234
  return null;
235
235
  }
@@ -253,22 +253,22 @@ function rpcFailed(nonce) {
253
253
 
254
254
  function assertXrplWallet(wallet, network) {
255
255
  if (typeof wallet !== "object" || wallet === null) {
256
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
256
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
257
257
  `chain ${network} is XRPL; wallet must be { seed } (s\u2026 seed) or { wallet }.`
258
258
  );
259
259
  }
260
260
  if ("privateKey" in wallet || "walletClient" in wallet) {
261
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
261
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
262
262
  `chain ${network} is XRPL; an EVM wallet can't be used \u2014 pass { seed } (s\u2026 seed) or { wallet }.`
263
263
  );
264
264
  }
265
265
  if ("secretKey" in wallet || "signer" in wallet || "mnemonic" in wallet || "keyPair" in wallet || "secret" in wallet || "keypair" in wallet) {
266
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
266
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
267
267
  `chain ${network} is XRPL; that looks like a Solana/TON/Stellar wallet \u2014 pass { seed } (s\u2026 seed) or { wallet }.`
268
268
  );
269
269
  }
270
270
  if (!("seed" in wallet) && !("wallet" in wallet)) {
271
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
271
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
272
272
  `chain ${network} is XRPL; wallet must be { seed } (s\u2026 seed) or { wallet }.`
273
273
  );
274
274
  }
@@ -278,11 +278,11 @@ function resolveXrplWallet(config) {
278
278
  if (config.wallet) return config.wallet;
279
279
  if (config.seed) {
280
280
  if (!_xrpl.isValidSecret.call(void 0, config.seed)) {
281
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)("XRPL wallet { seed } is not a valid s\u2026 secret seed.");
281
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)("XRPL wallet { seed } is not a valid s\u2026 secret seed.");
282
282
  }
283
283
  return _xrpl.Wallet.fromSeed(config.seed);
284
284
  }
285
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)("XRPL wallet needs { seed } (s\u2026 seed) or { wallet }.");
285
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)("XRPL wallet needs { seed } (s\u2026 seed) or { wallet }.");
286
286
  }
287
287
 
288
288
  // src/drivers/xrpl/index.ts
@@ -357,7 +357,7 @@ function makeXrplNetwork(preset, rpcUrl) {
357
357
  const info = preset.tokens[token.toUpperCase()];
358
358
  if (!info) {
359
359
  const known = Object.keys(preset.tokens).join(", ") || "(none built in)";
360
- throw new (0, _chunkFTKVCP6Kcjs.UnknownTokenError)(
360
+ throw new (0, _chunkPA6YD3HLcjs.UnknownTokenError)(
361
361
  `token "${token}" isn't built in for XRPL (known: ${known}). Pass { issuer, currencyHex, decimals } for a custom IOU, or use 'native'.`
362
362
  );
363
363
  }
@@ -367,10 +367,10 @@ function makeXrplNetwork(preset, rpcUrl) {
367
367
  symbol: info.symbol
368
368
  };
369
369
  }
370
- _chunkFTKVCP6Kcjs.rejectForeignToken.call(void 0, token, "xrpl", network);
370
+ _chunkPA6YD3HLcjs.rejectForeignToken.call(void 0, token, "xrpl", network);
371
371
  const t = token;
372
372
  if (!t.issuer || !t.currencyHex || typeof t.decimals !== "number") {
373
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
373
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
374
374
  `chain ${network} is XRPL; a custom token must be { issuer, currencyHex, decimals }.`
375
375
  );
376
376
  }
@@ -391,12 +391,12 @@ function makeXrplNetwork(preset, rpcUrl) {
391
391
  },
392
392
  assertValidPayTo(payTo) {
393
393
  if (payTo.startsWith("0x")) {
394
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
394
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
395
395
  `chain ${network} is XRPL, but payTo "${payTo}" looks like an EVM address.`
396
396
  );
397
397
  }
398
398
  if (!_xrpl.isValidClassicAddress.call(void 0, payTo)) {
399
- throw new (0, _chunkFTKVCP6Kcjs.WrongFamilyError)(
399
+ throw new (0, _chunkPA6YD3HLcjs.WrongFamilyError)(
400
400
  `chain ${network} is XRPL, but payTo "${payTo}" is not a valid XRPL account (r\u2026).`
401
401
  );
402
402
  }
@@ -419,14 +419,14 @@ function makeXrplNetwork(preset, rpcUrl) {
419
419
  }
420
420
  await _chunkCQREG5LEcjs.delay.call(void 0, 1500);
421
421
  }
422
- throw new (0, _chunkFTKVCP6Kcjs.ConfirmationTimeoutError)(`XRPL tx ${ref} not validated on-ledger in time.`);
422
+ throw new (0, _chunkPA6YD3HLcjs.ConfirmationTimeoutError)(`XRPL tx ${ref} not validated on-ledger in time.`);
423
423
  },
424
424
  async estimateCost() {
425
425
  try {
426
426
  const drops = await payClient.feeDrops();
427
427
  const n = Number(drops);
428
428
  const fee = BigInt(Number.isFinite(n) && n > 12 ? Math.ceil(n) : 12);
429
- return _chunkFTKVCP6Kcjs.nativeCost.call(void 0, {
429
+ return _chunkPA6YD3HLcjs.nativeCost.call(void 0, {
430
430
  symbol: XRP_SYMBOL,
431
431
  decimals: XRP_DECIMALS,
432
432
  fee,
@@ -434,7 +434,7 @@ function makeXrplNetwork(preset, rpcUrl) {
434
434
  detail: `network fee ${fee} drops`
435
435
  });
436
436
  } catch (e5) {
437
- return _chunkFTKVCP6Kcjs.nativeCost.call(void 0, {
437
+ return _chunkPA6YD3HLcjs.nativeCost.call(void 0, {
438
438
  symbol: XRP_SYMBOL,
439
439
  decimals: XRP_DECIMALS,
440
440
  fee: 12n,
@@ -471,7 +471,7 @@ function makeXrplNetwork(preset, rpcUrl) {
471
471
  const line = r.lines.find(
472
472
  (l) => l.currency.toUpperCase() === (_nullishCoalesce(currencyHex, () => ( ""))).toUpperCase() && l.account === issuer
473
473
  );
474
- token = line ? _chunkFTKVCP6Kcjs.parseUnits.call(void 0, line.balance, XRP_DECIMALS) : 0n;
474
+ token = line ? _chunkPA6YD3HLcjs.parseUnits.call(void 0, line.balance, XRP_DECIMALS) : 0n;
475
475
  } catch (e) {
476
476
  token = isXrplActNotFound(e) ? 0n : null;
477
477
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@piprail/sdk",
3
- "version": "1.14.0",
3
+ "version": "1.15.1",
4
4
  "description": "Accept x402 crypto payments across 29 chains — every major EVM chain plus Solana, TON, Tron, NEAR, Sui, Aptos, Algorand, Stellar & XRPL — in a couple of lines. No backend, no database, no fee; payments settle straight to your wallet.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -21,10 +21,6 @@
21
21
  "files": [
22
22
  "dist",
23
23
  "README.md",
24
- "CHAINS.md",
25
- "ERRORS.md",
26
- "STANDARDS.md",
27
- "DISCOVERY.md",
28
24
  "CHANGELOG.md",
29
25
  "LICENSE"
30
26
  ],
package/CHAINS.md DELETED
@@ -1,179 +0,0 @@
1
- # Chain support & per-chain setup
2
-
3
- PipRail works the same way on every chain — `requirePayment({ chain, token, amount, payTo })`
4
- to charge, `new PipRailClient({ chain, wallet }).fetch(url)` to pay. But the chains
5
- themselves differ, and a few have **setup steps you must do before a wallet can pay or
6
- receive**. This page is the exact list.
7
-
8
- **Most chains need nothing special.** The ones with caveats are **NEAR**, **TON**,
9
- **Stellar**, **XRPL**, **Tron**, and **Algorand** (USDC needs a one-time ASA opt-in) —
10
- read those sections before you ship them.
11
-
12
- ## At a glance
13
-
14
- | Chain(s) | Pay in native coin? | Built-in stablecoins | Receiver needs setup? | Wallet input |
15
- |---|:--:|---|---|---|
16
- | **EVM** (Ethereum, Base, Arbitrum, Optimism, Polygon, BNB, Avalanche, Mantle, Sonic, Linea, Scroll, Celo, zkSync, Unichain, World Chain, Sei, Injective, HyperEVM, Monad, Kaia, + any EVM chain) | ✅ ETH/BNB/POL/… | USDC (all **except Kaia**) · USDT (all **except Base, World Chain, Sei, HyperEVM, Monad**) · **EURC** (Ethereum, Base, Avalanche) | No | `{ privateKey }` |
17
- | **Solana** | ✅ SOL | USDC · USDT | No (payer creates the recipient's token account) | `{ secretKey }` |
18
- | **Sui** | ✅ SUI | USDC (no USDT) | No | `{ privateKey }` (`suiprivkey1…`) |
19
- | **Aptos** | ✅ APT | USDC · USDT | No (primary FA store auto-creates) | `{ privateKey }` (`ed25519-priv-0x…`) |
20
- | **Algorand** | ✅ ALGO | **USDC only** (Tether deprecated USDT) | USDC: ⚠️ **ASA opt-in** · **native ALGO: none** | `{ mnemonic }` (25 words) |
21
- | **Stellar** | ✅ XLM | USDC · EURC | ⚠️ **Yes — trustline + funded account** | `{ secret }` (`S…`) |
22
- | **XRP Ledger** | ✅ XRP | USDC · RLUSD (no USDT) | ⚠️ **Yes — trustline + activated account** | `{ seed }` (`s…`) |
23
- | **TON** | ✅ TON | **USD₮ only** (no USDC) | No (payer's gas auto-deploys the jetton wallet) | `{ mnemonic }` (24 words) |
24
- | **Tron** | ✅ TRX | **USD₮ only** (no USDC) | No | `{ privateKey }` |
25
- | **NEAR** | ✅ NEAR | USDC · USDT | tokens: ⚠️ `storage_deposit` · **native NEAR: none** | `{ accountId, privateKey }` |
26
-
27
- > **`token: 'native'`** (paying in the chain's own coin) is accepted on **every family** —
28
- > EVM, Solana, Sui, Aptos, Algorand, Stellar, XRPL, TON, NEAR, **and Tron** (native TRX,
29
- > digest-bound). No exceptions. On NEAR, native is the **zero-setup** path: no `storage_deposit`,
30
- > and a transfer even creates a fresh recipient (the NEP-141 token path still needs
31
- > `storage_deposit`).
32
- >
33
- > **Custom tokens** work everywhere with no allowlist: EVM `{ address, decimals }` ·
34
- > Solana `{ mint, decimals }` · Sui `{ coinType, decimals }` · Aptos `{ metadata, decimals }` ·
35
- > Algorand `{ assetId, decimals }` · TON `{ master, decimals }` ·
36
- > Tron `{ address, decimals }` · NEAR `{ contractId, decimals }` · Stellar
37
- > `{ issuer, code, decimals }` · XRPL `{ issuer, currencyHex, decimals }`.
38
-
39
- **Universal:** the public default RPC on every chain is rate-limited — **pass your own
40
- `rpcUrl`** in production (there's no separate API-key field; fold any key into the URL).
41
-
42
- ---
43
-
44
- ## Chains with no caveats
45
-
46
- ### EVM — Ethereum, Base, Arbitrum, Optimism, Polygon, BNB, Avalanche, …
47
- - **Pay in:** native coin (`'native'`), `'USDC'`, `'USDT'`, `'EURC'` (where issued), or a custom `{ address, decimals }`.
48
- - **USDT gap:** built in on every preset **except Base, World Chain, Sei, HyperEVM, and Monad** (USDC only there). **Kaia** is the inverse — **USD₮ only** (no Circle-native USDC on Kaia).
49
- - **EURC:** Circle's euro stablecoin is built in on **Ethereum, Base, and Avalanche** (EIP-3009, 6-dp, addresses verified on-chain). Its EIP-712 domain name differs per deployment (`"Euro Coin"` on Ethereum/Avalanche, `"EURC"` on Base) — the SDK reads it on-chain, so `exact` payments are correct everywhere. Like USDC, it's `exact`-payable.
50
- - **Decimals:** on **BNB Chain**, Binance-Peg USDC/USDT are **18 decimals**, not 6 (the SDK handles it; don't hardcode 6).
51
- - **Stablecoin provenance — issuer-native vs bridged (every shipped address verified on-chain 2026-06-08, incl. bridge markers).** Every address is the correct, canonical, 1:1-redeemable dollar token on its chain; what varies is *who issues it*. You request it as `'USDC'` / `'USDT'` either way — provenance matters only if you specifically require issuer-native settlement.
52
- - **USDC** is **Circle-native** on every preset **except** **BNB** (Binance-Peg, 18-dp), **Mantle** (OP canonical-bridge), and **Scroll** (Bridged-USDC-Standard) — the last two are backed 1:1 by Circle USDC on Ethereum but are **not** Circle-issued on that chain (absent from Circle's native-USDC list).
53
- - **USDT** is **Tether-native** on **Ethereum, Avalanche, Celo, Kaia** (EVM) and **Solana, Tron, TON, NEAR, Aptos** (non-EVM). Everywhere else it's bridged: **USDT0** (LayerZero omnichain, on-chain `symbol()` = `USD₮0`) on **Arbitrum, Polygon, Unichain**; a **canonical-bridge** token (chain-minted, backed by Tether's Ethereum USDT — not Tether-issued) on **Optimism, zkSync, Sonic, Linea, Injective, Mantle, Scroll**; and **Binance-Peg** (18-dp) on **BNB**. The on-chain `symbol()` may read `USDT`, `USD₮`, `USDt`, or `USD₮0`; all resolve via `token: 'USDT'`.
54
- - **Receiver setup:** none — any `0x…` address receives ERC-20 or native immediately.
55
- - **Any other EVM chain:** pass a viem `Chain` or `{ id, rpcUrl }` + `token: { address, decimals }`.
56
-
57
- ### Solana
58
- - **Pay in:** `'native'` (SOL), `'USDC'`, `'USDT'`, or `{ mint, decimals }`.
59
- - **Receiver setup:** none — the payer's transaction idempotently creates the recipient's token account and pays its ~0.00204 SOL rent. **Pass the recipient's wallet address as `payTo`, not a token-account address.**
60
- - **Payer:** needs SOL for gas + a funded source token account for the SPL token.
61
-
62
- ### Sui
63
- - **Pay in:** `'native'` (SUI), `'USDC'`, or `{ coinType, decimals }`. **No built-in USDT** (only Wormhole-bridged exists — supply it as a custom coin if needed).
64
- - **Receiver setup:** none — any `0x…` (32-byte) Sui address receives immediately.
65
- - **Payer:** needs SUI for gas even when paying USDC, and must already hold a coin object of the asset.
66
-
67
- ---
68
-
69
- ## ⚠️ Chains with caveats — read before shipping
70
-
71
- ### NEAR — native is zero-setup; tokens need `storage_deposit`
72
- - **Native NEAR works and is the easy path.** `token: 'native'` pays in NEAR (24dp) via
73
- digest-binding (like EVM/Solana/Sui) — **no `storage_deposit`, no receiver setup**, and a
74
- transfer even **creates a fresh implicit recipient**. Use it when price volatility is fine
75
- and you want zero setup. *(NEAR is the volatile gas coin; for stable pricing pay in a token.)*
76
- - **Tokens (USDC/USDT/custom NEP-141) need `storage_deposit` (NEP-145).** Before an account
77
- can *receive* a token, it must be storage-registered on **that exact token contract** — a
78
- one-time ~0.00125 NEAR call, **per account per token** (else the payer's `ft_transfer`
79
- panics). Both the **merchant (`payTo`)** and the **payer** must be registered on the token.
80
- Pay in a token via `'USDC'`, `'USDT'`, or a custom `{ contractId, decimals }`.
81
- - **Wallet:** `{ accountId, privateKey }` — NEAR needs *both* an account id and an `ed25519:…` secret key (not just a private key).
82
- - **Implicit accounts** (64-hex) don't exist until funded with NEAR — fund the account first (a native payment to one *creates* it).
83
- - **Built-in USDC is Circle's native contract** (`17208628…36133a1`), **not** the bridged `…factory.bridge.near` (USDC.e). Don't confuse them.
84
- - **Do not route through NEAR Intents/solvers** — that re-introduces a third-party facilitator. PipRail uses plain transfers + local receipt verification on purpose.
85
-
86
- ### TON — USD₮ (or native TON), and you need an API-keyed RPC
87
- - **Built-in token is USD₮ only** — **native USDC does not exist on TON** (Circle doesn't issue it; `token: 'USDC'` throws). Pay in `'USDT'`, `'native'` (Toncoin), or a custom jetton `{ master, decimals }`.
88
- - **An RPC API key is effectively required.** The default keyless toncenter endpoint is rate-limited (~1 req/s) and will stall `confirm()`/`verify()` (they poll + read archival history). Use a keyed, archival-capable endpoint and **put the key in the URL**:
89
- ```ts
90
- requirePayment({ chain: 'ton', token: 'USDT', amount: '0.05', payTo,
91
- rpcUrl: 'https://toncenter.com/api/v2/jsonRPC?api_key=YOUR_KEY' })
92
- ```
93
- (Free keys: message **@tonapibot** on Telegram, or sign up at toncenter.com.)
94
- - **Receiver setup:** none — the payer's attached gas (~0.05 TON, leftover refunded) auto-deploys the merchant's jetton wallet on first receipt. The payer needs Toncoin for gas even when paying USD₮.
95
- - **Async settlement:** value crosses contracts, so a credit can take seconds to appear; the proof is a locator (`ton:<jetton-wallet>|<nonce>`), not a tx hash, and the nonce rides in the transfer comment to bind it.
96
- - **Wallet:** a 24-word `{ mnemonic }` (or `{ keyPair }`), wallet version `v4` (default) or `v5r1` — must match the version your funded address was created with.
97
-
98
- ### Tron — USD₮ (or native TRX), and gas is real money
99
- - **Pay in:** `'USDT'` (built in), **`'native'` (TRX, digest-bound)**, or a custom TRC-20 `{ address, decimals }`. **No built-in USDC** (Circle discontinued native USDC on Tron). USD₮ is the default (TRX is volatile gas); native TRX is there for completeness — a plain TransferContract, verified by txid + recency + single-use.
100
- - **Gas is expensive and paid in TRX.** A USD₮ transfer burns Energy (~30k unstaked ≈ several TRX). The payer must hold **TRX as well as USDT**. Use `client.estimateCost(url)` to budget payment + TRX gas. (Tip for tiny test sends: rent energy from a service like TronZap/feee.io for ~1–2 TRX instead of burning ~27.) A first **native** TRX payment to a brand-new recipient also pays Tron's ~1 TRX account-creation fee (sender side).
101
- - **Finality is slow-ish:** verification waits for the tx to solidify (~19 blocks, ~57s); until then it reads as `tx_not_found` and is retried.
102
- - **Wallet:** `{ privateKey }` (32-byte hex, same format as EVM); addresses are Base58 `T…`.
103
-
104
- ### Algorand — USDC needs a one-time ASA opt-in (native ALGO doesn't)
105
- - **Pay in:** `'native'` (ALGO, the zero-setup path), `'USDC'`, or a custom ASA `{ assetId, decimals }`. **USDC only for the stablecoin** — Tether deprecated/froze USDT on Algorand (2025-09-01), so it's not built in (pass it as a custom ASA if you must).
106
- - **Receiving USDC needs an ASA opt-in.** Before an account can *receive* USDC (ASA `31566704`) — or any ASA — it must **opt into that asset** once: a 0-amount asset-transfer to itself, which raises its minimum balance by 0.1 ALGO (locked, recoverable). No opt-in → the payment fails and PipRail returns `RECIPIENT_NOT_READY`. **Native ALGO needs no opt-in.** The payer is implicitly opted-in if it already holds USDC. The one-time opt-in is plain `algosdk` (PipRail stays a payments SDK, not a wallet manager):
107
- ```ts
108
- import algosdk from 'algosdk'
109
- const algod = new algosdk.Algodv2('', 'https://mainnet-api.algonode.cloud', '')
110
- const sp = await algod.getTransactionParams().do()
111
- const optIn = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({
112
- sender: account.addr, receiver: account.addr, amount: 0, assetIndex: 31566704, suggestedParams: sp,
113
- })
114
- await algod.sendRawTransaction(optIn.signTxn(account.sk)).do() // one-time, per account per ASA
115
- ```
116
- - **Fast + cheap:** ~3s single-step finality, flat 0.001 ALGO min fee. The challenge nonce rides in the transaction's **note field** (Template A), so the proof is bound to its challenge; verify reads the merchant account's inbound transfers via the indexer.
117
- - **x402:** Algorand's `exact` scheme is part of the official x402 standard, but the incumbent on-chain path uses a hosted **facilitator** — PipRail is the **backendless, no-facilitator** option (payer broadcasts, merchant verifies locally).
118
- - **Wallet:** `{ mnemonic }` (a 25-word Algorand recovery phrase) or `{ account }` (an algosdk `{ addr, sk }`).
119
- - **Endpoints:** `rpcUrl` overrides the **algod** endpoint (submit/params); the verify-side **indexer** uses the public AlgoNode default (override needs are rare; the public indexer is production-grade for the inbound-transfer read).
120
-
121
- ### Stellar — the receiver needs a trustline + a funded account
122
- - **Pay in:** `'native'` (XLM), `'USDC'`, `'EURC'`, or a custom `{ issuer, code, decimals }`.
123
- - **Receiving an issued asset needs a one-time TRUSTLINE.** The merchant (`payTo`) must (1) **exist** on-chain (funded above the ~1 XLM base reserve) and (2) hold a **trustline** (`changeTrust`) for that exact `code+issuer` *before* it can receive. No trustline → the payment fails. Each trustline locks **+0.5 XLM** of reserve. The **payer** likewise needs its own trustline to hold/send the asset.
124
- - **Accounts must exist:** this driver sends a payment, it does **not** create accounts — both ends must already be funded above reserve.
125
- - **Reserves are locked, not spent** — recoverable.
126
- - **Wallet:** `{ secret }` (an `S…` Ed25519 seed) or `{ keypair }`.
127
-
128
- ### XRP Ledger — the receiver needs activation + a trustline
129
- - **Pay in:** `'native'` (XRP), `'USDC'`, `'RLUSD'`, or a custom `{ issuer, currencyHex, decimals }`. **No built-in USDT** on XRPL.
130
- - **Receiving an IOU needs activation + a TRUSTLINE.** The merchant (`payTo`) must be an **activated** account (holding the ~1 XRP base reserve) **and** hold a **trustline** to the issuer's currency before its first IOU payment — otherwise it fails. Native XRP needs no trustline. The payer must be activated + trustlined too.
131
- - **Reserves locked, not spent** (~1 XRP base + an owner reserve per trustline) — recoverable.
132
- - **RLUSD** requires a DestinationTag; the SDK sets a nonce-derived one automatically.
133
- - **Wallet:** `{ seed }` (an `s…` family seed) or `{ wallet }`.
134
-
135
- ---
136
-
137
- ## Errors you'll see — and what they actually mean
138
-
139
- A payment that "won't go through" is almost always a **chain requirement**, not an SDK bug.
140
- PipRail maps every such case to a typed error (stable `.code`) with a plain-language fix, and
141
- **echoes the raw chain code** in the message + keeps the original on `err.cause`. The two you'll
142
- meet in practice:
143
-
144
- **`INSUFFICIENT_FUNDS`** — the **payer** can't cover it → fund the payer (token, native gas, or
145
- the chain's reserve).
146
-
147
- **`RECIPIENT_NOT_READY`** — the **recipient** (`payTo`) isn't set up to receive on this chain yet.
148
- Fix the *recipient*, not the payer:
149
-
150
- | You see (raw → mapped) | Chain | What it means | Fix |
151
- |---|---|---|---|
152
- | `tecNO_DST_INSUF_XRP` / `tecNO_DST` | XRPL | the `payTo` account isn't activated (an XRPL account needs ≥1 XRP base reserve to exist) | send the recipient ≥1 XRP to activate it |
153
- | `tecNO_LINE` / `tecPATH_DRY` | XRPL | recipient has no trustline for the IOU (USDC/RLUSD) | add the trustline on the recipient |
154
- | `tecDST_TAG_NEEDED` | XRPL | recipient requires a DestinationTag (PipRail sets one automatically) | — |
155
- | `op_no_destination` | Stellar | the `payTo` account doesn't exist | create it with ≥1 XLM (base reserve) |
156
- | `op_no_trust` | Stellar | recipient has no trustline for the asset | add the trustline (+0.5 XLM reserve) |
157
- | `… is not registered` | NEAR | recipient isn't `storage_deposit`-registered on the token | call `storage_deposit` once (~0.00125 NEAR) |
158
- | `must optin` / `asset … missing from <payTo>` | Algorand | recipient hasn't opted into the USDC ASA | opt the recipient into the ASA once (0-amount self-transfer, +0.1 ALGO min balance) |
159
-
160
- Everything else (EVM, Solana, Sui, Tron, native TON/NEAR) needs no recipient setup, so you'll
161
- only ever see `INSUFFICIENT_FUNDS` there if the payer is short. Full taxonomy: **[ERRORS.md](./ERRORS.md)**.
162
-
163
- ---
164
-
165
- ## How the proof is bound (for the security-curious)
166
-
167
- Every chain proves the *same* facts locally (succeeded · recent · moved ≥ amount of the
168
- right asset to `payTo`), but binds the proof to your challenge differently:
169
-
170
- - **Memo-bound** (the challenge nonce is written on-chain): **NEAR tokens** (ft_transfer
171
- memo), **TON** (transfer comment), **Stellar** (`MEMO_HASH = sha256(nonce)`), **XRPL**
172
- (Memo + a derived DestinationTag), **Algorand** (the transaction's note field — native ALGO
173
- and USDC alike).
174
- - **Digest-bound** (no on-chain nonce; the proof is the tx id, made single-use by the gate
175
- + a recency window): **EVM**, **Solana**, **Sui**, **Aptos**, **Tron**, and **native NEAR**. For
176
- these, a persistent `isUsed`/`markUsed` store + a tight `maxTimeoutSeconds` are
177
- load-bearing in multi-instance deployments (the default used-set is single-process).
178
-
179
- (So NEAR uses *both*: its NEP-141 token path is memo-bound, while native NEAR is digest-bound.)