@piprail/sdk 2.0.0 → 2.0.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/CHANGELOG.md +30 -0
- package/dist/{algorand-RJ4DRWHV.js → algorand-GSFVZTBF.js} +1 -1
- package/dist/{algorand-RUDF55XY.cjs → algorand-HZS43N4P.cjs} +16 -16
- package/dist/{aptos-SMEQXIYJ.js → aptos-RIL56C7L.js} +1 -1
- package/dist/{aptos-PESRG2EQ.cjs → aptos-TRCCJRZA.cjs} +15 -15
- package/dist/{chunk-47VEOHZN.js → chunk-7XK22JSQ.js} +1 -1
- package/dist/{chunk-DKQXW454.cjs → chunk-JG6KRAW6.cjs} +1 -1
- package/dist/index.cjs +269 -192
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +160 -83
- package/dist/{near-VWBV3SUW.cjs → near-DI2I3MAV.cjs} +18 -18
- package/dist/{near-CHE7B2CY.js → near-MTYBCUYM.js} +1 -1
- package/dist/{solana-DTO2R3AT.js → solana-E4MD6JJ6.js} +14 -3
- package/dist/{solana-OIHRPGX2.cjs → solana-TLHL2KNY.cjs} +41 -30
- package/dist/{stellar-AF7PYMMF.cjs → stellar-FW6C6FBE.cjs} +21 -21
- package/dist/{stellar-T5VONOEO.js → stellar-U5NCRIOJ.js} +2 -2
- package/dist/{sui-3TF5XVRT.cjs → sui-47C2KEZI.cjs} +16 -16
- package/dist/{sui-J53NYMVL.js → sui-Y53M4GUM.js} +1 -1
- package/dist/{ton-CPK57L2O.js → ton-5ZPT5PSP.js} +12 -2
- package/dist/{ton-ZEI7YUK7.cjs → ton-MMPKWT6N.cjs} +24 -14
- package/dist/{tron-5B3Q4SMF.cjs → tron-JOT4STIG.cjs} +26 -23
- package/dist/{tron-LZRCDRZC.js → tron-WYS4X2I5.js} +4 -1
- package/dist/{xrpl-AH4FFC2C.js → xrpl-2MZEOIFY.js} +1 -1
- package/dist/{xrpl-BL4QXOVN.cjs → xrpl-PECT4IMX.cjs} +20 -20
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,35 @@ All notable changes to `@piprail/sdk` are documented here. The format
|
|
|
4
4
|
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the
|
|
5
5
|
versions follow [Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [2.0.1] — 2026-06-15 — clearer typed errors (robustness; no API change)
|
|
8
|
+
|
|
9
|
+
A patch release hardening error reporting at every wrong-input boundary — found by a
|
|
10
|
+
repo-wide adversarial fuzzing pass. **No behaviour change for correct input**, no API change;
|
|
11
|
+
every fix turns a raw/cryptic library error into a typed `PipRailError` per [`ERRORS.md`](ERRORS.md).
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **Wallet `{ key }` validation is now uniform + typed.** A malformed or wrong-family key throws a
|
|
16
|
+
clear `WrongFamilyError` instead of leaking a library error:
|
|
17
|
+
- **EVM** — a non-`0x…`/short/garbage key (e.g. a base58 secret, or one missing `0x`) →
|
|
18
|
+
`WrongFamilyError` (was viem's raw `invalid private key, expected hex or 32 bytes`).
|
|
19
|
+
- **Solana** — a `0x…` EVM key or non-base58 secret → `WrongFamilyError` (was `Non-base58 character`).
|
|
20
|
+
- **TON** — an invalid/typo'd mnemonic → `WrongFamilyError` at use (was a silent **wrong-wallet**
|
|
21
|
+
derivation that only failed later as an opaque network error); now validated via `mnemonicValidate`.
|
|
22
|
+
- **A malformed 402 challenge yields a typed `InvalidEnvelopeError`, never a raw `TypeError`.** An
|
|
23
|
+
`accepts[]` entry missing its `extra` block (on an unrecognised token), or a non-string `amount`,
|
|
24
|
+
is now rejected cleanly across `quote` / `estimateCost` / `planPayment` / `canAfford` / `fetch`
|
|
25
|
+
(a recognised token still prices gracefully from the SDK's own decimals).
|
|
26
|
+
- **Read-only agent tools funnel expected errors into a structured result.** `piprail_quote_payment`,
|
|
27
|
+
`piprail_plan_payment`, `piprail_discover`, `piprail_register`, and `piprail_budget` now return
|
|
28
|
+
`{ ok:false, code, reason, explain }` for a typed SDK error (e.g. `WALLET_REQUIRED` on a read-only
|
|
29
|
+
client) — mirroring `piprail_pay_request` — instead of an opaque error; a genuine non-SDK error is
|
|
30
|
+
still re-thrown.
|
|
31
|
+
- **A no-gas wallet's settlement failure maps to `InsufficientFundsError`.** viem's gas-estimation
|
|
32
|
+
shortfall phrasing (`gas required exceeds allowance`) is now classified as `INSUFFICIENT_FUNDS`
|
|
33
|
+
(was a raw multi-line viem dump); an ERC-20 `insufficient allowance` (approve) is deliberately NOT
|
|
34
|
+
mis-classified.
|
|
35
|
+
|
|
7
36
|
## [2.0.0] — 2026-06-15 — one wallet field: `key` (BREAKING)
|
|
8
37
|
|
|
9
38
|
### Changed — the wallet secret is a single `key` field on every chain (BREAKING)
|
|
@@ -1102,6 +1131,7 @@ straight into your wallet. The API is small and self-contained.
|
|
|
1102
1131
|
to your wallet; PipRail never holds funds.
|
|
1103
1132
|
- `viem ^2.21` is a peer dependency. Node 20+ or a modern browser.
|
|
1104
1133
|
|
|
1134
|
+
[2.0.1]: https://www.npmjs.com/package/@piprail/sdk
|
|
1105
1135
|
[2.0.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
1106
1136
|
[1.25.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
1107
1137
|
[1.24.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
var
|
|
11
|
+
var _chunkJG6KRAW6cjs = require('./chunk-JG6KRAW6.cjs');
|
|
12
12
|
|
|
13
13
|
// src/drivers/algorand/index.ts
|
|
14
14
|
var _algosdk = require('algosdk'); var _algosdk2 = _interopRequireDefault(_algosdk);
|
|
@@ -56,13 +56,13 @@ async function payAlgorand(params) {
|
|
|
56
56
|
} catch (err) {
|
|
57
57
|
const mapped = mapAlgorandError(err, accept.payTo);
|
|
58
58
|
if (mapped) throw mapped;
|
|
59
|
-
throw _nullishCoalesce(
|
|
59
|
+
throw _nullishCoalesce(_chunkJG6KRAW6cjs.toInsufficientFundsError.call(void 0, err), () => ( err));
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
function mapAlgorandError(err, payTo) {
|
|
63
63
|
const m = err instanceof Error ? err.message : String(err);
|
|
64
64
|
if (/must optin/i.test(m) || /missing from/i.test(m) && m.includes(payTo)) {
|
|
65
|
-
return new (0,
|
|
65
|
+
return new (0, _chunkJG6KRAW6cjs.RecipientNotReadyError)(
|
|
66
66
|
`Algorand recipient ${payTo} hasn't opted into this asset \u2014 it must opt in (a 0-amount asset transfer to itself) before it can receive. (Algorand: ${firstLine(m)})`,
|
|
67
67
|
{ cause: err }
|
|
68
68
|
);
|
|
@@ -70,7 +70,7 @@ function mapAlgorandError(err, payTo) {
|
|
|
70
70
|
if (/overspend|below min|min(imum)? balance|tried to spend|balance \d+ below|asset \d+ missing from|insufficient|underflow/i.test(
|
|
71
71
|
m
|
|
72
72
|
)) {
|
|
73
|
-
return new (0,
|
|
73
|
+
return new (0, _chunkJG6KRAW6cjs.InsufficientFundsError)(
|
|
74
74
|
`Algorand payment failed: the sender can't cover it \u2014 token balance, ALGO for fees, the 0.1-ALGO minimum balance, or a missing asset opt-in on the sender. (Algorand: ${firstLine(m)})`,
|
|
75
75
|
{ cause: err }
|
|
76
76
|
);
|
|
@@ -158,13 +158,13 @@ function rpcFailed(nonce) {
|
|
|
158
158
|
|
|
159
159
|
function assertAlgorandWallet(wallet, network) {
|
|
160
160
|
if (typeof wallet !== "object" || wallet === null) {
|
|
161
|
-
throw new (0,
|
|
161
|
+
throw new (0, _chunkJG6KRAW6cjs.WrongFamilyError)(
|
|
162
162
|
`chain ${network} is Algorand; wallet must be { key } (25-word mnemonic) or { account }.`
|
|
163
163
|
);
|
|
164
164
|
}
|
|
165
|
-
|
|
165
|
+
_chunkJG6KRAW6cjs.assertNoLegacyWalletKey.call(void 0, wallet, "Algorand");
|
|
166
166
|
if (!("key" in wallet) && !("account" in wallet)) {
|
|
167
|
-
throw new (0,
|
|
167
|
+
throw new (0, _chunkJG6KRAW6cjs.WrongFamilyError)(
|
|
168
168
|
`chain ${network} is Algorand; wallet must be { key } (25-word mnemonic) or { account }.`
|
|
169
169
|
);
|
|
170
170
|
}
|
|
@@ -179,13 +179,13 @@ function resolveAlgorandWallet(config) {
|
|
|
179
179
|
const { addr, sk } = _algosdk2.default.mnemonicToSecretKey(config.key);
|
|
180
180
|
return { addr: addr.toString(), sk };
|
|
181
181
|
} catch (cause) {
|
|
182
|
-
throw new (0,
|
|
182
|
+
throw new (0, _chunkJG6KRAW6cjs.WrongFamilyError)(
|
|
183
183
|
"Algorand wallet { key } is not a valid 25-word Algorand mnemonic.",
|
|
184
184
|
{ cause }
|
|
185
185
|
);
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
|
-
throw new (0,
|
|
188
|
+
throw new (0, _chunkJG6KRAW6cjs.WrongFamilyError)("Algorand wallet needs { key } (25-word mnemonic) or { account }.");
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
// src/drivers/algorand/index.ts
|
|
@@ -240,16 +240,16 @@ function makeAlgorandNetwork(preset, algodUrl) {
|
|
|
240
240
|
const info = preset.tokens[token.toUpperCase()];
|
|
241
241
|
if (!info) {
|
|
242
242
|
const known = Object.keys(preset.tokens).join(", ") || "(none built in)";
|
|
243
|
-
throw new (0,
|
|
243
|
+
throw new (0, _chunkJG6KRAW6cjs.UnknownTokenError)(
|
|
244
244
|
`token "${token}" isn't built in for Algorand (known: ${known}). Pass { assetId, decimals } for a custom ASA, or use 'native'.`
|
|
245
245
|
);
|
|
246
246
|
}
|
|
247
247
|
return { asset: algorandAssetId(info.assetId), decimals: info.decimals, symbol: info.symbol };
|
|
248
248
|
}
|
|
249
|
-
|
|
249
|
+
_chunkJG6KRAW6cjs.rejectForeignToken.call(void 0, token, "algorand", network);
|
|
250
250
|
const t = token;
|
|
251
251
|
if (typeof t.assetId !== "number" || typeof t.decimals !== "number") {
|
|
252
|
-
throw new (0,
|
|
252
|
+
throw new (0, _chunkJG6KRAW6cjs.WrongFamilyError)(
|
|
253
253
|
`chain ${network} is Algorand; a custom token must be { assetId, decimals }.`
|
|
254
254
|
);
|
|
255
255
|
}
|
|
@@ -270,12 +270,12 @@ function makeAlgorandNetwork(preset, algodUrl) {
|
|
|
270
270
|
},
|
|
271
271
|
assertValidPayTo(payTo) {
|
|
272
272
|
if (payTo.startsWith("0x")) {
|
|
273
|
-
throw new (0,
|
|
273
|
+
throw new (0, _chunkJG6KRAW6cjs.WrongFamilyError)(
|
|
274
274
|
`chain ${network} is Algorand, but payTo "${payTo}" looks like an EVM address.`
|
|
275
275
|
);
|
|
276
276
|
}
|
|
277
277
|
if (!_algosdk2.default.isValidAddress(payTo)) {
|
|
278
|
-
throw new (0,
|
|
278
|
+
throw new (0, _chunkJG6KRAW6cjs.WrongFamilyError)(
|
|
279
279
|
`chain ${network} is Algorand, but payTo "${payTo}" is not a valid Algorand address.`
|
|
280
280
|
);
|
|
281
281
|
}
|
|
@@ -292,13 +292,13 @@ function makeAlgorandNetwork(preset, algodUrl) {
|
|
|
292
292
|
const info = await _algosdk2.default.waitForConfirmation(algod, ref, 10);
|
|
293
293
|
return { height: String(_nullishCoalesce(info.confirmedRound, () => ( 0))) };
|
|
294
294
|
} catch (err) {
|
|
295
|
-
throw new (0,
|
|
295
|
+
throw new (0, _chunkJG6KRAW6cjs.ConfirmationTimeoutError)(`Algorand tx ${ref} did not confirm in time.`, {
|
|
296
296
|
cause: err
|
|
297
297
|
});
|
|
298
298
|
}
|
|
299
299
|
},
|
|
300
300
|
async estimateCost() {
|
|
301
|
-
return
|
|
301
|
+
return _chunkJG6KRAW6cjs.nativeCost.call(void 0, {
|
|
302
302
|
symbol: ALGO_SYMBOL,
|
|
303
303
|
decimals: ALGO_DECIMALS,
|
|
304
304
|
fee: 1000n,
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
var
|
|
10
|
+
var _chunkJG6KRAW6cjs = require('./chunk-JG6KRAW6.cjs');
|
|
11
11
|
|
|
12
12
|
// src/drivers/aptos/index.ts
|
|
13
13
|
var _tssdk = require('@aptos-labs/ts-sdk');
|
|
@@ -56,14 +56,14 @@ async function payAptos(params) {
|
|
|
56
56
|
const res = await client.signSubmit({ signer, transaction });
|
|
57
57
|
return res.hash;
|
|
58
58
|
} catch (err) {
|
|
59
|
-
if (err instanceof
|
|
59
|
+
if (err instanceof _chunkJG6KRAW6cjs.InsufficientFundsError) throw err;
|
|
60
60
|
if (isAptosAffordability(err)) {
|
|
61
|
-
throw new (0,
|
|
61
|
+
throw new (0, _chunkJG6KRAW6cjs.InsufficientFundsError)(
|
|
62
62
|
err instanceof Error ? err.message : "Insufficient APT/token balance for the payment.",
|
|
63
63
|
{ cause: err }
|
|
64
64
|
);
|
|
65
65
|
}
|
|
66
|
-
throw _nullishCoalesce(
|
|
66
|
+
throw _nullishCoalesce(_chunkJG6KRAW6cjs.toInsufficientFundsError.call(void 0, err), () => ( err));
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
function isAptosAffordability(err) {
|
|
@@ -147,13 +147,13 @@ function txNotFound(hash) {
|
|
|
147
147
|
|
|
148
148
|
function assertAptosWallet(wallet, network) {
|
|
149
149
|
if (typeof wallet !== "object" || wallet === null) {
|
|
150
|
-
throw new (0,
|
|
150
|
+
throw new (0, _chunkJG6KRAW6cjs.WrongFamilyError)(
|
|
151
151
|
`chain ${network} is Aptos; wallet must be { key } (ed25519-priv-0x\u2026) or { account }.`
|
|
152
152
|
);
|
|
153
153
|
}
|
|
154
|
-
|
|
154
|
+
_chunkJG6KRAW6cjs.assertNoLegacyWalletKey.call(void 0, wallet, "Aptos");
|
|
155
155
|
if (!("key" in wallet) && !("account" in wallet)) {
|
|
156
|
-
throw new (0,
|
|
156
|
+
throw new (0, _chunkJG6KRAW6cjs.WrongFamilyError)(
|
|
157
157
|
`chain ${network} is Aptos; wallet must be { key } (ed25519-priv-0x\u2026) or { account }.`
|
|
158
158
|
);
|
|
159
159
|
}
|
|
@@ -165,13 +165,13 @@ function resolveAptosAccount(config) {
|
|
|
165
165
|
try {
|
|
166
166
|
return _tssdk.Account.fromPrivateKey({ privateKey: new (0, _tssdk.Ed25519PrivateKey)(config.key) });
|
|
167
167
|
} catch (cause) {
|
|
168
|
-
throw new (0,
|
|
168
|
+
throw new (0, _chunkJG6KRAW6cjs.WrongFamilyError)(
|
|
169
169
|
"Aptos wallet { key } is not a valid ed25519 secret (ed25519-priv-0x\u2026 or 0x\u2026 hex).",
|
|
170
170
|
{ cause }
|
|
171
171
|
);
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
|
-
throw new (0,
|
|
174
|
+
throw new (0, _chunkJG6KRAW6cjs.WrongFamilyError)("Aptos wallet needs { key } (ed25519-priv-0x\u2026) or { account }.");
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
// src/drivers/aptos/index.ts
|
|
@@ -243,16 +243,16 @@ function makeAptosNetwork(preset, rpcUrl) {
|
|
|
243
243
|
const info = preset.tokens[token.toUpperCase()];
|
|
244
244
|
if (!info) {
|
|
245
245
|
const known = Object.keys(preset.tokens).join(", ") || "(none built in)";
|
|
246
|
-
throw new (0,
|
|
246
|
+
throw new (0, _chunkJG6KRAW6cjs.UnknownTokenError)(
|
|
247
247
|
`token "${token}" isn't built in for Aptos (known: ${known}). Pass { metadata, decimals } for a custom Fungible Asset, or use 'native'.`
|
|
248
248
|
);
|
|
249
249
|
}
|
|
250
250
|
return { asset: info.metadata, decimals: info.decimals, symbol: info.symbol };
|
|
251
251
|
}
|
|
252
|
-
|
|
252
|
+
_chunkJG6KRAW6cjs.rejectForeignToken.call(void 0, token, "aptos", network);
|
|
253
253
|
const t = token;
|
|
254
254
|
if (!t.metadata || typeof t.decimals !== "number") {
|
|
255
|
-
throw new (0,
|
|
255
|
+
throw new (0, _chunkJG6KRAW6cjs.WrongFamilyError)(
|
|
256
256
|
`chain ${network} is Aptos; a custom token must be { metadata, decimals }.`
|
|
257
257
|
);
|
|
258
258
|
}
|
|
@@ -279,7 +279,7 @@ function makeAptosNetwork(preset, rpcUrl) {
|
|
|
279
279
|
valid = false;
|
|
280
280
|
}
|
|
281
281
|
if (!valid || evmLike) {
|
|
282
|
-
throw new (0,
|
|
282
|
+
throw new (0, _chunkJG6KRAW6cjs.WrongFamilyError)(
|
|
283
283
|
`chain ${network} is Aptos, but payTo "${payTo}" is not a valid Aptos address (0x + 32 bytes).`
|
|
284
284
|
);
|
|
285
285
|
}
|
|
@@ -301,11 +301,11 @@ function makeAptosNetwork(preset, rpcUrl) {
|
|
|
301
301
|
const tx = await aptos.waitForTransaction({ transactionHash: ref });
|
|
302
302
|
return { height: String(_nullishCoalesce(tx.version, () => ( "0"))) };
|
|
303
303
|
} catch (err) {
|
|
304
|
-
throw new (0,
|
|
304
|
+
throw new (0, _chunkJG6KRAW6cjs.ConfirmationTimeoutError)(`Aptos tx ${ref} did not finalize in time.`, { cause: err });
|
|
305
305
|
}
|
|
306
306
|
},
|
|
307
307
|
async estimateCost() {
|
|
308
|
-
return
|
|
308
|
+
return _chunkJG6KRAW6cjs.nativeCost.call(void 0, {
|
|
309
309
|
symbol: APT_SYMBOL,
|
|
310
310
|
decimals: APT_DECIMALS,
|
|
311
311
|
fee: 100000n,
|
|
@@ -13,7 +13,7 @@ var RecipientNotReadyError = class extends PipRailError {
|
|
|
13
13
|
};
|
|
14
14
|
function toInsufficientFundsError(err) {
|
|
15
15
|
const message = err instanceof Error ? err.message : String(err);
|
|
16
|
-
if (/insufficient (funds|balance|lamports|fee)|not enough|exceeds (the )?balance|underfunded|low[_ ]?reserve|debit the account/i.test(
|
|
16
|
+
if (/insufficient (funds|balance|lamports|fee)|not enough|exceeds (the )?balance|underfunded|low[_ ]?reserve|debit the account|gas required exceeds (the )?allowance/i.test(
|
|
17
17
|
message
|
|
18
18
|
)) {
|
|
19
19
|
return new InsufficientFundsError(
|
|
@@ -13,7 +13,7 @@ var RecipientNotReadyError = (_class2 = class extends PipRailError {constructor(
|
|
|
13
13
|
}, _class2);
|
|
14
14
|
function toInsufficientFundsError(err) {
|
|
15
15
|
const message = err instanceof Error ? err.message : String(err);
|
|
16
|
-
if (/insufficient (funds|balance|lamports|fee)|not enough|exceeds (the )?balance|underfunded|low[_ ]?reserve|debit the account/i.test(
|
|
16
|
+
if (/insufficient (funds|balance|lamports|fee)|not enough|exceeds (the )?balance|underfunded|low[_ ]?reserve|debit the account|gas required exceeds (the )?allowance/i.test(
|
|
17
17
|
message
|
|
18
18
|
)) {
|
|
19
19
|
return new InsufficientFundsError(
|