safehands-pharos 1.4.0 → 1.5.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.
Files changed (124) hide show
  1. package/README.md +174 -63
  2. package/dist/cli.d.ts +5 -5
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +126 -124
  5. package/dist/cli.js.map +1 -1
  6. package/dist/demo.d.ts +1 -1
  7. package/dist/demo.js +171 -171
  8. package/dist/index.d.ts +2 -2
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +73 -65
  11. package/dist/index.js.map +1 -1
  12. package/dist/init.d.ts +1 -1
  13. package/dist/init.js +65 -65
  14. package/dist/lib/constants.d.ts +303 -291
  15. package/dist/lib/constants.d.ts.map +1 -1
  16. package/dist/lib/constants.js +302 -292
  17. package/dist/lib/constants.js.map +1 -1
  18. package/dist/lib/dodoApi.d.ts +78 -78
  19. package/dist/lib/dodoApi.js +196 -196
  20. package/dist/lib/envLoader.d.ts +2 -0
  21. package/dist/lib/envLoader.d.ts.map +1 -0
  22. package/dist/lib/envLoader.js +44 -0
  23. package/dist/lib/envLoader.js.map +1 -0
  24. package/dist/lib/http.d.ts +14 -14
  25. package/dist/lib/http.js +118 -118
  26. package/dist/lib/pharosClient.d.ts +58 -58
  27. package/dist/lib/pharosClient.js +63 -63
  28. package/dist/lib/policy/actionPolicyEngine.d.ts +53 -53
  29. package/dist/lib/policy/actionPolicyEngine.js +212 -212
  30. package/dist/lib/riskEngine.d.ts +26 -26
  31. package/dist/lib/riskEngine.d.ts.map +1 -1
  32. package/dist/lib/riskEngine.js +288 -283
  33. package/dist/lib/riskEngine.js.map +1 -1
  34. package/dist/lib/signer/index.d.ts +24 -24
  35. package/dist/lib/signer/index.js +88 -88
  36. package/dist/lib/testDodoLive.d.ts +1 -1
  37. package/dist/lib/testDodoLive.js +104 -104
  38. package/dist/lib/testLiveSafehands.d.ts +1 -1
  39. package/dist/lib/testLiveSafehands.js +92 -92
  40. package/dist/lib/testRpcLive.d.ts +1 -1
  41. package/dist/lib/testRpcLive.js +88 -88
  42. package/dist/lib/testTools.js +397 -398
  43. package/dist/lib/testX402Live.d.ts +1 -1
  44. package/dist/lib/testX402Live.js +159 -159
  45. package/dist/lib/toolResponse.d.ts +25 -25
  46. package/dist/lib/toolResponse.js +53 -53
  47. package/dist/lib/wallet/index.d.ts +37 -37
  48. package/dist/lib/wallet/index.js +128 -128
  49. package/dist/scripts/checkDeploy.d.ts +1 -1
  50. package/dist/scripts/checkDeploy.js +24 -24
  51. package/dist/scripts/deployRegistry.d.ts +1 -1
  52. package/dist/scripts/deployRegistry.js +100 -100
  53. package/dist/scripts/testRegistry.d.ts +1 -1
  54. package/dist/scripts/testRegistry.js +43 -43
  55. package/dist/tools/approveToken.d.ts +45 -45
  56. package/dist/tools/approveToken.js +85 -85
  57. package/dist/tools/assessRisk.d.ts +79 -79
  58. package/dist/tools/assessRisk.js +104 -104
  59. package/dist/tools/checkAllowance.d.ts +43 -43
  60. package/dist/tools/checkAllowance.js +56 -56
  61. package/dist/tools/checkTokenSecurity.d.ts +46 -46
  62. package/dist/tools/checkTokenSecurity.js +95 -95
  63. package/dist/tools/createAgentWallet.d.ts +28 -26
  64. package/dist/tools/createAgentWallet.d.ts.map +1 -1
  65. package/dist/tools/createAgentWallet.js +82 -58
  66. package/dist/tools/createAgentWallet.js.map +1 -1
  67. package/dist/tools/estimateGas.d.ts +79 -79
  68. package/dist/tools/estimateGas.js +124 -124
  69. package/dist/tools/executeSwap.d.ts +61 -61
  70. package/dist/tools/executeSwap.js +141 -141
  71. package/dist/tools/explainRisk.d.ts +29 -29
  72. package/dist/tools/explainRisk.js +32 -32
  73. package/dist/tools/getAgentWallet.d.ts +21 -21
  74. package/dist/tools/getAgentWallet.js +27 -27
  75. package/dist/tools/getAgentWalletBalance.d.ts +11 -11
  76. package/dist/tools/getAgentWalletBalance.js +70 -70
  77. package/dist/tools/getExecutionHistory.d.ts +49 -49
  78. package/dist/tools/getExecutionHistory.js +154 -154
  79. package/dist/tools/getGasPrice.d.ts +43 -43
  80. package/dist/tools/getGasPrice.js +59 -59
  81. package/dist/tools/getPoolInfo.d.ts +75 -75
  82. package/dist/tools/getPoolInfo.js +137 -137
  83. package/dist/tools/getTokenPrice.d.ts +113 -113
  84. package/dist/tools/getTokenPrice.js +117 -117
  85. package/dist/tools/getTransactionStatus.d.ts +43 -43
  86. package/dist/tools/getTransactionStatus.js +59 -59
  87. package/dist/tools/getWalletBalance.d.ts +68 -68
  88. package/dist/tools/getWalletBalance.js +87 -87
  89. package/dist/tools/publishRiskScore.d.ts +63 -63
  90. package/dist/tools/publishRiskScore.js +88 -88
  91. package/dist/tools/queryRiskRegistry.d.ts +38 -38
  92. package/dist/tools/queryRiskRegistry.js +55 -55
  93. package/dist/tools/safehandsPreflightCheck.d.ts +77 -77
  94. package/dist/tools/safehandsPreflightCheck.js +47 -47
  95. package/dist/tools/safehandsRiskReport.d.ts +81 -81
  96. package/dist/tools/safehandsRiskReport.js +28 -28
  97. package/dist/tools/safehandsSafeExecute.d.ts +20 -20
  98. package/dist/tools/safehandsSafeExecute.js +81 -81
  99. package/dist/tools/safehandsWalletHealth.d.ts +14 -14
  100. package/dist/tools/safehandsWalletHealth.js +103 -103
  101. package/dist/tools/safehandsX402Preflight.d.ts +26 -26
  102. package/dist/tools/safehandsX402Preflight.js +65 -65
  103. package/dist/tools/sendPayment.d.ts +57 -57
  104. package/dist/tools/sendPayment.js +117 -117
  105. package/dist/tools/simulateTransaction.d.ts +60 -60
  106. package/dist/tools/simulateTransaction.js +83 -83
  107. package/dist/tools/tokenRegistryStatus.d.ts +26 -26
  108. package/dist/tools/tokenRegistryStatus.js +96 -96
  109. package/dist/tools/x402PayAndFetch.d.ts +81 -81
  110. package/dist/tools/x402PayAndFetch.js +152 -152
  111. package/dist/x402Server.d.ts +1 -1
  112. package/dist/x402Server.js +300 -252
  113. package/dist/x402Server.js.map +1 -1
  114. package/package.json +6 -16
  115. package/examples/dashboard/index.html +0 -337
  116. package/examples/pharos-skill-engine/SKILL.safehands.md +0 -85
  117. package/examples/pharos-skill-engine/assets/safehands/example-actions.json +0 -49
  118. package/examples/pharos-skill-engine/assets/safehands/policy-defaults.json +0 -11
  119. package/examples/pharos-skill-engine/references/safehands.md +0 -345
  120. package/examples/scenario-hack.ts +0 -38
  121. package/skill/SKILL.md +0 -133
  122. package/skill/assets/safehands/example-actions.json +0 -49
  123. package/skill/assets/safehands/policy-defaults.json +0 -11
  124. package/skill/references/safehands.md +0 -345
@@ -1,25 +1,25 @@
1
- import type { Account } from "viem";
2
- export type SignerMode = "none" | "env" | "managed-testnet" | "external-signer" | "x402-env";
3
- export type SignerPurpose = "write" | "x402";
4
- export interface SignerResult {
5
- account: Account;
6
- address: `0x${string}`;
7
- mode: SignerMode;
8
- }
9
- export interface SignerFailure {
10
- error: {
11
- code: string;
12
- message: string;
13
- };
14
- }
15
- export type GetSignerResult = SignerResult | SignerFailure;
16
- export declare function isSignerFailure(r: GetSignerResult): r is SignerFailure;
17
- /**
18
- * Get a signer for write/payment operations.
19
- * Priority for x402: managed wallet > X402_SIGNER_PRIVATE_KEY > PRIVATE_KEY fallback.
20
- * Priority for writes: managed wallet > PRIVATE_KEY fallback.
21
- */
22
- export declare function getSigner(agentId?: string, options?: {
23
- purpose?: SignerPurpose;
24
- }): Promise<GetSignerResult>;
1
+ import type { Account } from "viem";
2
+ export type SignerMode = "none" | "env" | "managed-testnet" | "external-signer" | "x402-env";
3
+ export type SignerPurpose = "write" | "x402";
4
+ export interface SignerResult {
5
+ account: Account;
6
+ address: `0x${string}`;
7
+ mode: SignerMode;
8
+ }
9
+ export interface SignerFailure {
10
+ error: {
11
+ code: string;
12
+ message: string;
13
+ };
14
+ }
15
+ export type GetSignerResult = SignerResult | SignerFailure;
16
+ export declare function isSignerFailure(r: GetSignerResult): r is SignerFailure;
17
+ /**
18
+ * Get a signer for write/payment operations.
19
+ * Priority for x402: managed wallet > X402_SIGNER_PRIVATE_KEY > PRIVATE_KEY fallback.
20
+ * Priority for writes: managed wallet > PRIVATE_KEY fallback.
21
+ */
22
+ export declare function getSigner(agentId?: string, options?: {
23
+ purpose?: SignerPurpose;
24
+ }): Promise<GetSignerResult>;
25
25
  //# sourceMappingURL=index.d.ts.map
@@ -1,89 +1,89 @@
1
- // ─── SignerProvider ─────────────────────────────────────────────────────
2
- // Abstraction layer for signing. Tools never read process.env.PRIVATE_KEY
3
- // directly — they request a signer through this provider.
4
- // ────────────────────────────────────────────────────────────────────────
5
- import { privateKeyToAccount } from "viem/accounts";
6
- import { walletStore, decryptKey, getEffectiveEncryptionKey } from "../wallet/index.js";
7
- export function isSignerFailure(r) {
8
- return "error" in r;
9
- }
10
- function normalizePrivateKey(pk) {
11
- return (pk.startsWith("0x") ? pk : `0x${pk}`);
12
- }
13
- function accountFromEnvKey(envName, mode) {
14
- const pk = process.env[envName];
15
- if (!pk)
16
- return null;
17
- try {
18
- const account = privateKeyToAccount(normalizePrivateKey(pk));
19
- return { account, address: account.address, mode };
20
- }
21
- catch {
22
- return {
23
- error: {
24
- code: "INVALID_PRIVATE_KEY",
25
- message: `${envName} is not a valid private key.`,
26
- },
27
- };
28
- }
29
- }
30
- async function accountFromManagedWallet(agentId) {
31
- const walletMode = process.env.WALLET_MODE || "none";
32
- if (walletMode !== "managed-testnet" || !agentId)
33
- return null;
34
- if (process.env.WALLET_STORE_PATH && !process.env.WALLET_ENCRYPTION_KEY) {
35
- return {
36
- error: {
37
- code: "WALLET_ENCRYPTION_KEY_REQUIRED",
38
- message: "WALLET_ENCRYPTION_KEY is required when WALLET_STORE_PATH is used for persistent managed-testnet wallets.",
39
- },
40
- };
41
- }
42
- const stored = await walletStore.get(agentId);
43
- if (!stored)
44
- return null;
45
- try {
46
- const privateKey = decryptKey(stored.encryptedKey, getEffectiveEncryptionKey());
47
- const account = privateKeyToAccount(normalizePrivateKey(privateKey));
48
- return { account, address: account.address, mode: "managed-testnet" };
49
- }
50
- catch {
51
- return {
52
- error: {
53
- code: "NO_SIGNER_AVAILABLE",
54
- message: "Managed wallet key could not be decrypted for signing. Check WALLET_ENCRYPTION_KEY matches the key used when the wallet was created.",
55
- },
56
- };
57
- }
58
- }
59
- /**
60
- * Get a signer for write/payment operations.
61
- * Priority for x402: managed wallet > X402_SIGNER_PRIVATE_KEY > PRIVATE_KEY fallback.
62
- * Priority for writes: managed wallet > PRIVATE_KEY fallback.
63
- */
64
- export async function getSigner(agentId, options = {}) {
65
- const purpose = options.purpose || "write";
66
- const managed = await accountFromManagedWallet(agentId);
67
- if (managed)
68
- return managed;
69
- if (purpose === "x402") {
70
- const x402Env = accountFromEnvKey("X402_SIGNER_PRIVATE_KEY", "x402-env");
71
- if (x402Env)
72
- return x402Env;
73
- }
74
- const walletMode = process.env.WALLET_MODE || "none";
75
- if (walletMode === "env" || process.env.PRIVATE_KEY) {
76
- const env = accountFromEnvKey("PRIVATE_KEY", "env");
77
- if (env)
78
- return env;
79
- }
80
- return {
81
- error: {
82
- code: "NO_SIGNER_AVAILABLE",
83
- message: purpose === "x402"
84
- ? "No x402 signer available. Use WALLET_MODE=managed-testnet with agentId, X402_SIGNER_PRIVATE_KEY, or PRIVATE_KEY as testnet developer fallback."
85
- : "No signer available. Use WALLET_MODE=managed-testnet with agentId, or WALLET_MODE=env with PRIVATE_KEY for testnet developer mode.",
86
- },
87
- };
88
- }
1
+ // ─── SignerProvider ─────────────────────────────────────────────────────
2
+ // Abstraction layer for signing. Tools never read process.env.PRIVATE_KEY
3
+ // directly — they request a signer through this provider.
4
+ // ────────────────────────────────────────────────────────────────────────
5
+ import { privateKeyToAccount } from "viem/accounts";
6
+ import { walletStore, decryptKey, getEffectiveEncryptionKey } from "../wallet/index.js";
7
+ export function isSignerFailure(r) {
8
+ return "error" in r;
9
+ }
10
+ function normalizePrivateKey(pk) {
11
+ return (pk.startsWith("0x") ? pk : `0x${pk}`);
12
+ }
13
+ function accountFromEnvKey(envName, mode) {
14
+ const pk = process.env[envName];
15
+ if (!pk)
16
+ return null;
17
+ try {
18
+ const account = privateKeyToAccount(normalizePrivateKey(pk));
19
+ return { account, address: account.address, mode };
20
+ }
21
+ catch {
22
+ return {
23
+ error: {
24
+ code: "INVALID_PRIVATE_KEY",
25
+ message: `${envName} is not a valid private key.`,
26
+ },
27
+ };
28
+ }
29
+ }
30
+ async function accountFromManagedWallet(agentId) {
31
+ const walletMode = process.env.WALLET_MODE || "none";
32
+ if (walletMode !== "managed-testnet" || !agentId)
33
+ return null;
34
+ if (process.env.WALLET_STORE_PATH && !process.env.WALLET_ENCRYPTION_KEY) {
35
+ return {
36
+ error: {
37
+ code: "WALLET_ENCRYPTION_KEY_REQUIRED",
38
+ message: "WALLET_ENCRYPTION_KEY is required when WALLET_STORE_PATH is used for persistent managed-testnet wallets.",
39
+ },
40
+ };
41
+ }
42
+ const stored = await walletStore.get(agentId);
43
+ if (!stored)
44
+ return null;
45
+ try {
46
+ const privateKey = decryptKey(stored.encryptedKey, getEffectiveEncryptionKey());
47
+ const account = privateKeyToAccount(normalizePrivateKey(privateKey));
48
+ return { account, address: account.address, mode: "managed-testnet" };
49
+ }
50
+ catch {
51
+ return {
52
+ error: {
53
+ code: "NO_SIGNER_AVAILABLE",
54
+ message: "Managed wallet key could not be decrypted for signing. Check WALLET_ENCRYPTION_KEY matches the key used when the wallet was created.",
55
+ },
56
+ };
57
+ }
58
+ }
59
+ /**
60
+ * Get a signer for write/payment operations.
61
+ * Priority for x402: managed wallet > X402_SIGNER_PRIVATE_KEY > PRIVATE_KEY fallback.
62
+ * Priority for writes: managed wallet > PRIVATE_KEY fallback.
63
+ */
64
+ export async function getSigner(agentId, options = {}) {
65
+ const purpose = options.purpose || "write";
66
+ const managed = await accountFromManagedWallet(agentId);
67
+ if (managed)
68
+ return managed;
69
+ if (purpose === "x402") {
70
+ const x402Env = accountFromEnvKey("X402_SIGNER_PRIVATE_KEY", "x402-env");
71
+ if (x402Env)
72
+ return x402Env;
73
+ }
74
+ const walletMode = process.env.WALLET_MODE || "none";
75
+ if (walletMode === "env" || process.env.PRIVATE_KEY) {
76
+ const env = accountFromEnvKey("PRIVATE_KEY", "env");
77
+ if (env)
78
+ return env;
79
+ }
80
+ return {
81
+ error: {
82
+ code: "NO_SIGNER_AVAILABLE",
83
+ message: purpose === "x402"
84
+ ? "No x402 signer available. Use WALLET_MODE=managed-testnet with agentId, X402_SIGNER_PRIVATE_KEY, or PRIVATE_KEY as testnet developer fallback."
85
+ : "No signer available. Use WALLET_MODE=managed-testnet with agentId, or WALLET_MODE=env with PRIVATE_KEY for testnet developer mode.",
86
+ },
87
+ };
88
+ }
89
89
  //# sourceMappingURL=index.js.map
@@ -1,2 +1,2 @@
1
- export {};
1
+ export {};
2
2
  //# sourceMappingURL=testDodoLive.d.ts.map
@@ -1,105 +1,105 @@
1
- // ─── Live DODO/FaroSwap Verification ───────────────────────────────────
2
- // Tests DODO API reachability if DODO_API_KEY is present.
3
- // Skips cleanly if API key is missing.
4
- // ────────────────────────────────────────────────────────────────────────
5
- import { DODO_API_BASE, DODO_API_KEY } from "./constants.js";
6
- import { getDodoRoute } from "./dodoApi.js";
7
- const results = [];
8
- async function main() {
9
- console.log("═══════════════════════════════════════════════════════════");
10
- console.log(" SafeHands — DODO/FaroSwap Live Verification");
11
- console.log("═══════════════════════════════════════════════════════════");
12
- console.log(` DODO API Base: ${DODO_API_BASE}`);
13
- const maskedKey = DODO_API_KEY ? `pub_****${DODO_API_KEY.slice(-4)}` : "NOT SET";
14
- console.log(` API Key: ${maskedKey}`);
15
- console.log("");
16
- if (!DODO_API_KEY) {
17
- console.log(" ⏭️ SKIPPED_MISSING_DODO_API_KEY — set DODO_API_KEY to enable live DODO checks.");
18
- results.push({
19
- name: "dodo_api_route_check",
20
- status: "SKIPPED_MISSING_DODO_API_KEY",
21
- detail: "DODO_API_KEY env var not set. This is expected for CI/demo environments.",
22
- });
23
- }
24
- else {
25
- // Try a read-only route quote
26
- try {
27
- const quote = await getDodoRoute({
28
- fromToken: "PHRS",
29
- toToken: "USDC",
30
- amountHuman: "0.000001",
31
- walletAddress: "0x0000000000000000000000000000000000000001",
32
- });
33
- if (quote.routeAvailable && parseFloat(quote.amountOut) > 0) {
34
- results.push({
35
- name: "dodo_api_route_check",
36
- status: "PASS",
37
- detail: `Route found: 0.000001 PHRS → ${quote.amountOut} USDC`,
38
- });
39
- }
40
- else {
41
- results.push({
42
- name: "dodo_api_route_check",
43
- status: "NO_ROUTE_AVAILABLE",
44
- detail: `API reachable. No route available (may be no liquidity).`,
45
- });
46
- }
47
- }
48
- catch (err) {
49
- const msg = err.message || String(err);
50
- if (msg.includes("DODO_API_AUTH_REQUIRED")) {
51
- results.push({
52
- name: "dodo_api_route_check",
53
- status: "DODO_API_AUTH_REQUIRED",
54
- detail: msg,
55
- });
56
- }
57
- else if (msg.includes("DODO_API_UNAVAILABLE") || msg.includes("DODO_API_RATE_LIMITED") || msg.includes("fetch failed") || msg.includes("network timeout")) {
58
- results.push({
59
- name: "dodo_api_route_check",
60
- status: "DODO_API_UNAVAILABLE",
61
- detail: `Network/timeout/rate-limited: ${msg}`,
62
- });
63
- }
64
- else {
65
- results.push({
66
- name: "dodo_api_route_check",
67
- status: "FAIL",
68
- detail: msg,
69
- });
70
- }
71
- }
72
- }
73
- // Router address verification status
74
- results.push({
75
- name: "dodo_approve_address_status",
76
- status: "PASS",
77
- detail: "0x4Cf317b8918FbE8A890c01eDAb7d548555Ac2cE9 — PROJECT_CONFIGURED (not verified by official FaroSwap/DODO docs)",
78
- });
79
- results.push({
80
- name: "dodo_route_proxy_status",
81
- status: "PASS",
82
- detail: "0x819829e5CF6e19F9fED92F6b4CC1edF45a2cC4A2 — PROJECT_CONFIGURED (not verified by official FaroSwap/DODO docs)",
83
- });
84
- // Print results
85
- console.log(`\n${"#".padStart(2)} ${"Status".padEnd(32)} ${"Check".padEnd(34)} Detail`);
86
- console.log("─".repeat(110));
87
- for (const [i, r] of results.entries()) {
88
- const icon = r.status === "PASS" ? "✅" : r.status.startsWith("SKIPPED") ? "⏭️" : "❌";
89
- console.log(`${String(i + 1).padStart(2)} ${icon} ${r.status.padEnd(29)} ${r.name.padEnd(34)} ${r.detail.slice(0, 80)}`);
90
- }
91
- const failed = results.filter(r => r.status === "FAIL");
92
- console.log("─".repeat(110));
93
- console.log(`${results.filter(r => r.status === "PASS").length}/${results.length} checks passed, ${results.filter(r => r.status.startsWith("SKIPPED")).length} skipped.`);
94
- if (failed.length > 0) {
95
- console.error("\nFailed:");
96
- for (const f of failed)
97
- console.error(` - ${f.name}: ${f.detail}`);
98
- process.exit(1);
99
- }
100
- }
101
- main().catch((err) => {
102
- console.error("❌ Unexpected error:", err);
103
- process.exit(1);
104
- });
1
+ // ─── Live DODO/FaroSwap Verification ───────────────────────────────────
2
+ // Tests DODO API reachability if DODO_API_KEY is present.
3
+ // Skips cleanly if API key is missing.
4
+ // ────────────────────────────────────────────────────────────────────────
5
+ import { DODO_API_BASE, DODO_API_KEY } from "./constants.js";
6
+ import { getDodoRoute } from "./dodoApi.js";
7
+ const results = [];
8
+ async function main() {
9
+ console.log("═══════════════════════════════════════════════════════════");
10
+ console.log(" SafeHands — DODO/FaroSwap Live Verification");
11
+ console.log("═══════════════════════════════════════════════════════════");
12
+ console.log(` DODO API Base: ${DODO_API_BASE}`);
13
+ const maskedKey = DODO_API_KEY ? `pub_****${DODO_API_KEY.slice(-4)}` : "NOT SET";
14
+ console.log(` API Key: ${maskedKey}`);
15
+ console.log("");
16
+ if (!DODO_API_KEY) {
17
+ console.log(" ⏭️ SKIPPED_MISSING_DODO_API_KEY — set DODO_API_KEY to enable live DODO checks.");
18
+ results.push({
19
+ name: "dodo_api_route_check",
20
+ status: "SKIPPED_MISSING_DODO_API_KEY",
21
+ detail: "DODO_API_KEY env var not set. This is expected for CI/demo environments.",
22
+ });
23
+ }
24
+ else {
25
+ // Try a read-only route quote
26
+ try {
27
+ const quote = await getDodoRoute({
28
+ fromToken: "PHRS",
29
+ toToken: "USDC",
30
+ amountHuman: "0.000001",
31
+ walletAddress: "0x0000000000000000000000000000000000000001",
32
+ });
33
+ if (quote.routeAvailable && parseFloat(quote.amountOut) > 0) {
34
+ results.push({
35
+ name: "dodo_api_route_check",
36
+ status: "PASS",
37
+ detail: `Route found: 0.000001 PHRS → ${quote.amountOut} USDC`,
38
+ });
39
+ }
40
+ else {
41
+ results.push({
42
+ name: "dodo_api_route_check",
43
+ status: "NO_ROUTE_AVAILABLE",
44
+ detail: `API reachable. No route available (may be no liquidity).`,
45
+ });
46
+ }
47
+ }
48
+ catch (err) {
49
+ const msg = err.message || String(err);
50
+ if (msg.includes("DODO_API_AUTH_REQUIRED")) {
51
+ results.push({
52
+ name: "dodo_api_route_check",
53
+ status: "DODO_API_AUTH_REQUIRED",
54
+ detail: msg,
55
+ });
56
+ }
57
+ else if (msg.includes("DODO_API_UNAVAILABLE") || msg.includes("DODO_API_RATE_LIMITED") || msg.includes("fetch failed") || msg.includes("network timeout")) {
58
+ results.push({
59
+ name: "dodo_api_route_check",
60
+ status: "DODO_API_UNAVAILABLE",
61
+ detail: `Network/timeout/rate-limited: ${msg}`,
62
+ });
63
+ }
64
+ else {
65
+ results.push({
66
+ name: "dodo_api_route_check",
67
+ status: "FAIL",
68
+ detail: msg,
69
+ });
70
+ }
71
+ }
72
+ }
73
+ // Router address verification status
74
+ results.push({
75
+ name: "dodo_approve_address_status",
76
+ status: "PASS",
77
+ detail: "0x4Cf317b8918FbE8A890c01eDAb7d548555Ac2cE9 — PROJECT_CONFIGURED (not verified by official FaroSwap/DODO docs)",
78
+ });
79
+ results.push({
80
+ name: "dodo_route_proxy_status",
81
+ status: "PASS",
82
+ detail: "0x819829e5CF6e19F9fED92F6b4CC1edF45a2cC4A2 — PROJECT_CONFIGURED (not verified by official FaroSwap/DODO docs)",
83
+ });
84
+ // Print results
85
+ console.log(`\n${"#".padStart(2)} ${"Status".padEnd(32)} ${"Check".padEnd(34)} Detail`);
86
+ console.log("─".repeat(110));
87
+ for (const [i, r] of results.entries()) {
88
+ const icon = r.status === "PASS" ? "✅" : r.status.startsWith("SKIPPED") ? "⏭️" : "❌";
89
+ console.log(`${String(i + 1).padStart(2)} ${icon} ${r.status.padEnd(29)} ${r.name.padEnd(34)} ${r.detail.slice(0, 80)}`);
90
+ }
91
+ const failed = results.filter(r => r.status === "FAIL");
92
+ console.log("─".repeat(110));
93
+ console.log(`${results.filter(r => r.status === "PASS").length}/${results.length} checks passed, ${results.filter(r => r.status.startsWith("SKIPPED")).length} skipped.`);
94
+ if (failed.length > 0) {
95
+ console.error("\nFailed:");
96
+ for (const f of failed)
97
+ console.error(` - ${f.name}: ${f.detail}`);
98
+ process.exit(1);
99
+ }
100
+ }
101
+ main().catch((err) => {
102
+ console.error("❌ Unexpected error:", err);
103
+ process.exit(1);
104
+ });
105
105
  //# sourceMappingURL=testDodoLive.js.map
@@ -1,2 +1,2 @@
1
- export {};
1
+ export {};
2
2
  //# sourceMappingURL=testLiveSafehands.d.ts.map
@@ -1,93 +1,93 @@
1
- // ─── Live SafeHands CLI Verification ───────────────────────────────────
2
- // Runs real CLI safety checks without broadcasting transactions.
3
- // All checks are read-only or dry-run preflight checks.
4
- // ────────────────────────────────────────────────────────────────────────
5
- import { spawnSync } from "node:child_process";
6
- import { join } from "node:path";
7
- import { existsSync } from "node:fs";
8
- const results = [];
9
- function runCli(args) {
10
- const entry = join(process.cwd(), "dist", "index.js");
11
- if (!existsSync(entry)) {
12
- console.error("❌ dist/index.js not found. Run: npm run build");
13
- process.exit(1);
14
- }
15
- const result = spawnSync(process.execPath, [entry, ...args], {
16
- cwd: process.cwd(),
17
- env: { ...process.env, WALLET_MODE: "none", WRITE_TOOLS_ENABLED: "false", PRIVATE_KEY: "" },
18
- encoding: "utf8",
19
- timeout: 30_000,
20
- });
21
- return { exitCode: result.status ?? 1, stdout: result.stdout || "", stderr: result.stderr || "" };
22
- }
23
- function parseJson(stdout) {
24
- try {
25
- return JSON.parse(stdout.trim());
26
- }
27
- catch {
28
- return null;
29
- }
30
- }
31
- function check(name, args, expected, validator) {
32
- const { stdout } = runCli(args);
33
- const json = parseJson(stdout);
34
- const passed = json !== null && validator(json);
35
- const actual = json !== null
36
- ? (json.success ? `success: ${JSON.stringify(json.data).slice(0, 120)}` : `error: ${json.error?.code}`)
37
- : `invalid JSON: ${stdout.slice(0, 100)}`;
38
- results.push({ name, status: passed ? "PASS" : "FAIL", expected, actual });
39
- }
40
- console.log("═══════════════════════════════════════════════════════════");
41
- console.log(" SafeHands — Live CLI Verification (read-only)");
42
- console.log("═══════════════════════════════════════════════════════════");
43
- console.log("");
44
- // 1. Wallet health — no wallet configured
45
- check("wallet_health_no_wallet", ["skill", "safehands_wallet_health", "--input-json", "{}"], "valid JSON with status NOT_READY or DEGRADED", (json) => json.success && ["NOT_READY", "DEGRADED"].includes(json.data?.status));
46
- // 2. Token registry — Pharos Skill Engine USDC (DOCS_VERIFIED_FROM_PHAROS_SKILL_ENGINE)
47
- check("token_registry_skill_engine_usdc", ["skill", "token_registry_status", "--input-json", JSON.stringify({ tokenAddress: "0xE0BE08c77f415F577A1B3A9aD7a1Df1479564ec8" })], "SKILL_ENGINE_CANONICAL_TOKEN with DOCS_VERIFIED_FROM_PHAROS_SKILL_ENGINE", (json) => json.success && json.data?.status === "SKILL_ENGINE_CANONICAL_TOKEN" && json.data?.verificationStatus === "DOCS_VERIFIED_FROM_PHAROS_SKILL_ENGINE");
48
- // 3. Token registry — Circle USDC (ALTERNATE_SOURCE_TOKEN)
49
- check("token_registry_circle_usdc", ["skill", "token_registry_status", "--input-json", JSON.stringify({ tokenAddress: "0xcfC8330f4BCAB529c625D12781b1C19466A9Fc8B" })], "ALTERNATE_SOURCE_TOKEN with CIRCLE_REFERENCED_USDC", (json) => json.success && json.data?.status === "ALTERNATE_SOURCE_TOKEN" && json.data?.verificationStatus === "CIRCLE_REFERENCED_USDC");
50
- // 4. Token registry — USDT (DOCS_VERIFIED)
51
- check("token_registry_usdt_docs_verified", ["skill", "token_registry_status", "--input-json", JSON.stringify({ tokenAddress: "0xE7E84B8B4f39C507499c40B4ac199B050e2882d5" })], "CANONICAL_TESTNET_TOKEN with DOCS_VERIFIED", (json) => json.success && json.data?.status === "CANONICAL_TESTNET_TOKEN" && json.data?.verificationStatus === "DOCS_VERIFIED");
52
- // 5. Preflight — unlimited approval → BLOCK
53
- check("preflight_block_unlimited_approval", ["skill", "safehands_preflight_check", "--input-json", JSON.stringify({
54
- actionType: "approve_token",
55
- chainId: 688689,
56
- tokenAddress: "0xE0BE08c77f415F577A1B3A9aD7a1Df1479564ec8",
57
- targetAddress: "0x0000000000000000000000000000000000000001",
58
- amount: "unlimited",
59
- approvalAmount: "max",
60
- })], "decision=BLOCK", (json) => json.success && json.data?.decision === "BLOCK");
61
- // 6. Preflight — mainnet action → BLOCK
62
- check("preflight_block_mainnet", ["skill", "safehands_preflight_check", "--input-json", JSON.stringify({
63
- actionType: "send_payment",
64
- chainId: 1,
65
- isMainnet: true,
66
- targetAddress: "0x0000000000000000000000000000000000000001",
67
- amount: "0.001",
68
- })], "decision=BLOCK", (json) => json.success && json.data?.decision === "BLOCK");
69
- // 7. Preflight — safe testnet action → ALLOW or WARN (not BLOCK)
70
- check("preflight_allow_testnet", ["skill", "safehands_preflight_check", "--input-json", JSON.stringify({
71
- actionType: "send_payment",
72
- chainId: 688689,
73
- isMainnet: false,
74
- amount: "0.001",
75
- recipient: "0x000000000000000000000000000000000000dEaD",
76
- })], "decision=ALLOW or WARN (not BLOCK)", (json) => json.success && json.data?.decision !== "BLOCK");
77
- // Print results
78
- console.log(`\n${"#".padStart(2)} ${"Status".padEnd(8)} ${"Check".padEnd(42)} Expected`);
79
- console.log("─".repeat(100));
80
- for (const [i, r] of results.entries()) {
81
- const icon = r.status === "PASS" ? "✅" : "❌";
82
- console.log(`${String(i + 1).padStart(2)} ${icon} ${r.status.padEnd(5)} ${r.name.padEnd(42)} ${r.expected}`);
83
- }
84
- const failed = results.filter(r => r.status === "FAIL");
85
- console.log("─".repeat(100));
86
- console.log(`${results.length - failed.length}/${results.length} live CLI checks passed.`);
87
- if (failed.length > 0) {
88
- console.error("\nFailed checks:");
89
- for (const f of failed)
90
- console.error(` - ${f.name}: got ${f.actual}`);
91
- process.exit(1);
92
- }
1
+ // ─── Live SafeHands CLI Verification ───────────────────────────────────
2
+ // Runs real CLI safety checks without broadcasting transactions.
3
+ // All checks are read-only or dry-run preflight checks.
4
+ // ────────────────────────────────────────────────────────────────────────
5
+ import { spawnSync } from "node:child_process";
6
+ import { join } from "node:path";
7
+ import { existsSync } from "node:fs";
8
+ const results = [];
9
+ function runCli(args) {
10
+ const entry = join(process.cwd(), "dist", "index.js");
11
+ if (!existsSync(entry)) {
12
+ console.error("❌ dist/index.js not found. Run: npm run build");
13
+ process.exit(1);
14
+ }
15
+ const result = spawnSync(process.execPath, [entry, ...args], {
16
+ cwd: process.cwd(),
17
+ env: { ...process.env, WALLET_MODE: "none", WRITE_TOOLS_ENABLED: "false", PRIVATE_KEY: "" },
18
+ encoding: "utf8",
19
+ timeout: 30_000,
20
+ });
21
+ return { exitCode: result.status ?? 1, stdout: result.stdout || "", stderr: result.stderr || "" };
22
+ }
23
+ function parseJson(stdout) {
24
+ try {
25
+ return JSON.parse(stdout.trim());
26
+ }
27
+ catch {
28
+ return null;
29
+ }
30
+ }
31
+ function check(name, args, expected, validator) {
32
+ const { stdout } = runCli(args);
33
+ const json = parseJson(stdout);
34
+ const passed = json !== null && validator(json);
35
+ const actual = json !== null
36
+ ? (json.success ? `success: ${JSON.stringify(json.data).slice(0, 120)}` : `error: ${json.error?.code}`)
37
+ : `invalid JSON: ${stdout.slice(0, 100)}`;
38
+ results.push({ name, status: passed ? "PASS" : "FAIL", expected, actual });
39
+ }
40
+ console.log("═══════════════════════════════════════════════════════════");
41
+ console.log(" SafeHands — Live CLI Verification (read-only)");
42
+ console.log("═══════════════════════════════════════════════════════════");
43
+ console.log("");
44
+ // 1. Wallet health — no wallet configured
45
+ check("wallet_health_no_wallet", ["skill", "safehands_wallet_health", "--input-json", "{}"], "valid JSON with status NOT_READY or DEGRADED", (json) => json.success && ["NOT_READY", "DEGRADED"].includes(json.data?.status));
46
+ // 2. Token registry — Pharos Skill Engine USDC (DOCS_VERIFIED_FROM_PHAROS_SKILL_ENGINE)
47
+ check("token_registry_skill_engine_usdc", ["skill", "token_registry_status", "--input-json", JSON.stringify({ tokenAddress: "0xE0BE08c77f415F577A1B3A9aD7a1Df1479564ec8" })], "SKILL_ENGINE_CANONICAL_TOKEN with DOCS_VERIFIED_FROM_PHAROS_SKILL_ENGINE", (json) => json.success && json.data?.status === "SKILL_ENGINE_CANONICAL_TOKEN" && json.data?.verificationStatus === "DOCS_VERIFIED_FROM_PHAROS_SKILL_ENGINE");
48
+ // 3. Token registry — Circle USDC (ALTERNATE_SOURCE_TOKEN)
49
+ check("token_registry_circle_usdc", ["skill", "token_registry_status", "--input-json", JSON.stringify({ tokenAddress: "0xcfC8330f4BCAB529c625D12781b1C19466A9Fc8B" })], "ALTERNATE_SOURCE_TOKEN with CIRCLE_REFERENCED_USDC", (json) => json.success && json.data?.status === "ALTERNATE_SOURCE_TOKEN" && json.data?.verificationStatus === "CIRCLE_REFERENCED_USDC");
50
+ // 4. Token registry — USDT (DOCS_VERIFIED)
51
+ check("token_registry_usdt_docs_verified", ["skill", "token_registry_status", "--input-json", JSON.stringify({ tokenAddress: "0xE7E84B8B4f39C507499c40B4ac199B050e2882d5" })], "CANONICAL_TESTNET_TOKEN with DOCS_VERIFIED", (json) => json.success && json.data?.status === "CANONICAL_TESTNET_TOKEN" && json.data?.verificationStatus === "DOCS_VERIFIED");
52
+ // 5. Preflight — unlimited approval → BLOCK
53
+ check("preflight_block_unlimited_approval", ["skill", "safehands_preflight_check", "--input-json", JSON.stringify({
54
+ actionType: "approve_token",
55
+ chainId: 688689,
56
+ tokenAddress: "0xE0BE08c77f415F577A1B3A9aD7a1Df1479564ec8",
57
+ targetAddress: "0x0000000000000000000000000000000000000001",
58
+ amount: "unlimited",
59
+ approvalAmount: "max",
60
+ })], "decision=BLOCK", (json) => json.success && json.data?.decision === "BLOCK");
61
+ // 6. Preflight — mainnet action → BLOCK
62
+ check("preflight_block_mainnet", ["skill", "safehands_preflight_check", "--input-json", JSON.stringify({
63
+ actionType: "send_payment",
64
+ chainId: 1,
65
+ isMainnet: true,
66
+ targetAddress: "0x0000000000000000000000000000000000000001",
67
+ amount: "0.001",
68
+ })], "decision=BLOCK", (json) => json.success && json.data?.decision === "BLOCK");
69
+ // 7. Preflight — safe testnet action → ALLOW or WARN (not BLOCK)
70
+ check("preflight_allow_testnet", ["skill", "safehands_preflight_check", "--input-json", JSON.stringify({
71
+ actionType: "send_payment",
72
+ chainId: 688689,
73
+ isMainnet: false,
74
+ amount: "0.001",
75
+ recipient: "0x000000000000000000000000000000000000dEaD",
76
+ })], "decision=ALLOW or WARN (not BLOCK)", (json) => json.success && json.data?.decision !== "BLOCK");
77
+ // Print results
78
+ console.log(`\n${"#".padStart(2)} ${"Status".padEnd(8)} ${"Check".padEnd(42)} Expected`);
79
+ console.log("─".repeat(100));
80
+ for (const [i, r] of results.entries()) {
81
+ const icon = r.status === "PASS" ? "✅" : "❌";
82
+ console.log(`${String(i + 1).padStart(2)} ${icon} ${r.status.padEnd(5)} ${r.name.padEnd(42)} ${r.expected}`);
83
+ }
84
+ const failed = results.filter(r => r.status === "FAIL");
85
+ console.log("─".repeat(100));
86
+ console.log(`${results.length - failed.length}/${results.length} live CLI checks passed.`);
87
+ if (failed.length > 0) {
88
+ console.error("\nFailed checks:");
89
+ for (const f of failed)
90
+ console.error(` - ${f.name}: got ${f.actual}`);
91
+ process.exit(1);
92
+ }
93
93
  //# sourceMappingURL=testLiveSafehands.js.map