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.
- package/README.md +174 -63
- package/dist/cli.d.ts +5 -5
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +126 -124
- package/dist/cli.js.map +1 -1
- package/dist/demo.d.ts +1 -1
- package/dist/demo.js +171 -171
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +73 -65
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +1 -1
- package/dist/init.js +65 -65
- package/dist/lib/constants.d.ts +303 -291
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +302 -292
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/dodoApi.d.ts +78 -78
- package/dist/lib/dodoApi.js +196 -196
- package/dist/lib/envLoader.d.ts +2 -0
- package/dist/lib/envLoader.d.ts.map +1 -0
- package/dist/lib/envLoader.js +44 -0
- package/dist/lib/envLoader.js.map +1 -0
- package/dist/lib/http.d.ts +14 -14
- package/dist/lib/http.js +118 -118
- package/dist/lib/pharosClient.d.ts +58 -58
- package/dist/lib/pharosClient.js +63 -63
- package/dist/lib/policy/actionPolicyEngine.d.ts +53 -53
- package/dist/lib/policy/actionPolicyEngine.js +212 -212
- package/dist/lib/riskEngine.d.ts +26 -26
- package/dist/lib/riskEngine.d.ts.map +1 -1
- package/dist/lib/riskEngine.js +288 -283
- package/dist/lib/riskEngine.js.map +1 -1
- package/dist/lib/signer/index.d.ts +24 -24
- package/dist/lib/signer/index.js +88 -88
- package/dist/lib/testDodoLive.d.ts +1 -1
- package/dist/lib/testDodoLive.js +104 -104
- package/dist/lib/testLiveSafehands.d.ts +1 -1
- package/dist/lib/testLiveSafehands.js +92 -92
- package/dist/lib/testRpcLive.d.ts +1 -1
- package/dist/lib/testRpcLive.js +88 -88
- package/dist/lib/testTools.js +397 -398
- package/dist/lib/testX402Live.d.ts +1 -1
- package/dist/lib/testX402Live.js +159 -159
- package/dist/lib/toolResponse.d.ts +25 -25
- package/dist/lib/toolResponse.js +53 -53
- package/dist/lib/wallet/index.d.ts +37 -37
- package/dist/lib/wallet/index.js +128 -128
- package/dist/scripts/checkDeploy.d.ts +1 -1
- package/dist/scripts/checkDeploy.js +24 -24
- package/dist/scripts/deployRegistry.d.ts +1 -1
- package/dist/scripts/deployRegistry.js +100 -100
- package/dist/scripts/testRegistry.d.ts +1 -1
- package/dist/scripts/testRegistry.js +43 -43
- package/dist/tools/approveToken.d.ts +45 -45
- package/dist/tools/approveToken.js +85 -85
- package/dist/tools/assessRisk.d.ts +79 -79
- package/dist/tools/assessRisk.js +104 -104
- package/dist/tools/checkAllowance.d.ts +43 -43
- package/dist/tools/checkAllowance.js +56 -56
- package/dist/tools/checkTokenSecurity.d.ts +46 -46
- package/dist/tools/checkTokenSecurity.js +95 -95
- package/dist/tools/createAgentWallet.d.ts +28 -26
- package/dist/tools/createAgentWallet.d.ts.map +1 -1
- package/dist/tools/createAgentWallet.js +82 -58
- package/dist/tools/createAgentWallet.js.map +1 -1
- package/dist/tools/estimateGas.d.ts +79 -79
- package/dist/tools/estimateGas.js +124 -124
- package/dist/tools/executeSwap.d.ts +61 -61
- package/dist/tools/executeSwap.js +141 -141
- package/dist/tools/explainRisk.d.ts +29 -29
- package/dist/tools/explainRisk.js +32 -32
- package/dist/tools/getAgentWallet.d.ts +21 -21
- package/dist/tools/getAgentWallet.js +27 -27
- package/dist/tools/getAgentWalletBalance.d.ts +11 -11
- package/dist/tools/getAgentWalletBalance.js +70 -70
- package/dist/tools/getExecutionHistory.d.ts +49 -49
- package/dist/tools/getExecutionHistory.js +154 -154
- package/dist/tools/getGasPrice.d.ts +43 -43
- package/dist/tools/getGasPrice.js +59 -59
- package/dist/tools/getPoolInfo.d.ts +75 -75
- package/dist/tools/getPoolInfo.js +137 -137
- package/dist/tools/getTokenPrice.d.ts +113 -113
- package/dist/tools/getTokenPrice.js +117 -117
- package/dist/tools/getTransactionStatus.d.ts +43 -43
- package/dist/tools/getTransactionStatus.js +59 -59
- package/dist/tools/getWalletBalance.d.ts +68 -68
- package/dist/tools/getWalletBalance.js +87 -87
- package/dist/tools/publishRiskScore.d.ts +63 -63
- package/dist/tools/publishRiskScore.js +88 -88
- package/dist/tools/queryRiskRegistry.d.ts +38 -38
- package/dist/tools/queryRiskRegistry.js +55 -55
- package/dist/tools/safehandsPreflightCheck.d.ts +77 -77
- package/dist/tools/safehandsPreflightCheck.js +47 -47
- package/dist/tools/safehandsRiskReport.d.ts +81 -81
- package/dist/tools/safehandsRiskReport.js +28 -28
- package/dist/tools/safehandsSafeExecute.d.ts +20 -20
- package/dist/tools/safehandsSafeExecute.js +81 -81
- package/dist/tools/safehandsWalletHealth.d.ts +14 -14
- package/dist/tools/safehandsWalletHealth.js +103 -103
- package/dist/tools/safehandsX402Preflight.d.ts +26 -26
- package/dist/tools/safehandsX402Preflight.js +65 -65
- package/dist/tools/sendPayment.d.ts +57 -57
- package/dist/tools/sendPayment.js +117 -117
- package/dist/tools/simulateTransaction.d.ts +60 -60
- package/dist/tools/simulateTransaction.js +83 -83
- package/dist/tools/tokenRegistryStatus.d.ts +26 -26
- package/dist/tools/tokenRegistryStatus.js +96 -96
- package/dist/tools/x402PayAndFetch.d.ts +81 -81
- package/dist/tools/x402PayAndFetch.js +152 -152
- package/dist/x402Server.d.ts +1 -1
- package/dist/x402Server.js +300 -252
- package/dist/x402Server.js.map +1 -1
- package/package.json +6 -16
- package/examples/dashboard/index.html +0 -337
- package/examples/pharos-skill-engine/SKILL.safehands.md +0 -85
- package/examples/pharos-skill-engine/assets/safehands/example-actions.json +0 -49
- package/examples/pharos-skill-engine/assets/safehands/policy-defaults.json +0 -11
- package/examples/pharos-skill-engine/references/safehands.md +0 -345
- package/examples/scenario-hack.ts +0 -38
- package/skill/SKILL.md +0 -133
- package/skill/assets/safehands/example-actions.json +0 -49
- package/skill/assets/safehands/policy-defaults.json +0 -11
- package/skill/references/safehands.md +0 -345
|
@@ -1,118 +1,118 @@
|
|
|
1
|
-
// ─── Tool: send_payment ────────────────────────────────────────────────
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
import { publicClient, createPharosWalletClientFromAccount, getExplorerUrl } from "../lib/pharosClient.js";
|
|
4
|
-
import { isAddress, parseEther, formatEther } from "viem";
|
|
5
|
-
import { assessRisk } from "../lib/riskEngine.js";
|
|
6
|
-
import { fail, ok, classifyExternalError } from "../lib/toolResponse.js";
|
|
7
|
-
import { MAX_BALANCE_USAGE_PCT, RISK_BLOCK_THRESHOLD, MAX_TX_AMOUNT_PHRS, CHAIN_ID, PHAROS_ENVIRONMENT } from "../lib/constants.js";
|
|
8
|
-
import { getSigner, isSignerFailure } from "../lib/signer/index.js";
|
|
9
|
-
import { evaluateActionPolicy } from "../lib/policy/actionPolicyEngine.js";
|
|
10
|
-
import { checkDailyLimit, recordSpend, estimateUsd } from "../lib/spendAccumulator.js";
|
|
11
|
-
export const sendPaymentSchema = z.object({
|
|
12
|
-
toAddress: z.string(),
|
|
13
|
-
amount: z.string(),
|
|
14
|
-
memo: z.string().optional(),
|
|
15
|
-
agentId: z.string().optional().describe("Managed testnet wallet agentId when WALLET_MODE=managed-testnet"),
|
|
16
|
-
});
|
|
17
|
-
export const sendPaymentTool = {
|
|
18
|
-
name: "send_payment",
|
|
19
|
-
description: "Send native PHRS with pre-flight validation. Checks address validity, balance sufficiency, and warns on high exposure.",
|
|
20
|
-
inputSchema: sendPaymentSchema,
|
|
21
|
-
};
|
|
22
|
-
export async function handleSendPayment(raw) {
|
|
23
|
-
if (process.env.WRITE_TOOLS_ENABLED !== "true") {
|
|
24
|
-
return fail("WRITE_TOOLS_DISABLED", "send_payment is disabled by default. Set WRITE_TOOLS_ENABLED=true only for trusted testnet execution.", false, "send_payment");
|
|
25
|
-
}
|
|
26
|
-
const input = sendPaymentSchema.parse(raw);
|
|
27
|
-
const signer = await getSigner(input.agentId);
|
|
28
|
-
if (isSignerFailure(signer)) {
|
|
29
|
-
return fail(signer.error.code, signer.error.message, false, "send_payment");
|
|
30
|
-
}
|
|
31
|
-
const walletAddress = signer.address;
|
|
32
|
-
const policy = evaluateActionPolicy({
|
|
33
|
-
actionType: "send_payment",
|
|
34
|
-
amount: input.amount,
|
|
35
|
-
amountUnit: "PHRS",
|
|
36
|
-
recipient: input.toAddress,
|
|
37
|
-
recipientVerified: false,
|
|
38
|
-
chainId: CHAIN_ID,
|
|
39
|
-
environment: PHAROS_ENVIRONMENT,
|
|
40
|
-
isMainnet: false,
|
|
41
|
-
signerAvailable: true,
|
|
42
|
-
requiresSigner: true,
|
|
43
|
-
});
|
|
44
|
-
if (policy.decision === "BLOCK") {
|
|
45
|
-
return fail("POLICY_BLOCKED", policy.reasons.join(" ") || "Payment blocked by SafeHands policy.", false, "send_payment");
|
|
46
|
-
}
|
|
47
|
-
if (Number(input.amount) > Number(MAX_TX_AMOUNT_PHRS)) {
|
|
48
|
-
return fail("TX_LIMIT_EXCEEDED", `Payment amount exceeds configured testnet limit (${MAX_TX_AMOUNT_PHRS} PHRS).`, false, "send_payment");
|
|
49
|
-
}
|
|
50
|
-
const amountUsd = estimateUsd(input.amount, "PHRS");
|
|
51
|
-
const dailyCheck = checkDailyLimit(walletAddress, amountUsd);
|
|
52
|
-
if (!dailyCheck.allowed) {
|
|
53
|
-
return fail("DAILY_SPEND_LIMIT_EXCEEDED", `Daily spend limit reached. Spent $${dailyCheck.currentUsd.toFixed(2)} of $${dailyCheck.limitUsd.toFixed(2)} USD today. Remaining: $${dailyCheck.remainingUsd.toFixed(2)}. Resets at UTC midnight.`, false, "send_payment");
|
|
54
|
-
}
|
|
55
|
-
const warnings = [];
|
|
56
|
-
const validation = { addressValid: false, balanceSufficient: false, warnings };
|
|
57
|
-
if (!isAddress(input.toAddress)) {
|
|
58
|
-
return fail("INVALID_WALLET_ADDRESS", "Invalid recipient address", false, "send_payment");
|
|
59
|
-
}
|
|
60
|
-
validation.addressValid = true;
|
|
61
|
-
if (input.toAddress === "0x0000000000000000000000000000000000000000") {
|
|
62
|
-
return fail("ZERO_ADDRESS_BLOCKED", "Cannot send to zero address", false, "send_payment");
|
|
63
|
-
}
|
|
64
|
-
if (input.toAddress.toLowerCase() === walletAddress.toLowerCase()) {
|
|
65
|
-
warnings.push("Sending to own address");
|
|
66
|
-
}
|
|
67
|
-
const amountWei = parseEther(input.amount);
|
|
68
|
-
const balance = await publicClient.getBalance({ address: walletAddress });
|
|
69
|
-
const gasEstimate = parseEther("0.01");
|
|
70
|
-
if (balance < amountWei + gasEstimate) {
|
|
71
|
-
return fail("INSUFFICIENT_TESTNET_BALANCE", `Insufficient balance: have ${formatEther(balance)} PHRS, need ${input.amount} + gas`, false, "send_payment");
|
|
72
|
-
}
|
|
73
|
-
validation.balanceSufficient = true;
|
|
74
|
-
const usagePct = Number((amountWei * 100n) / balance);
|
|
75
|
-
if (usagePct > MAX_BALANCE_USAGE_PCT) {
|
|
76
|
-
warnings.push(`Using ${usagePct}% of wallet balance — high exposure`);
|
|
77
|
-
}
|
|
78
|
-
const risk = await assessRisk({
|
|
79
|
-
action: "transfer",
|
|
80
|
-
amount: input.amount,
|
|
81
|
-
toAddress: input.toAddress,
|
|
82
|
-
walletAddress,
|
|
83
|
-
});
|
|
84
|
-
if (risk.riskScore > RISK_BLOCK_THRESHOLD) {
|
|
85
|
-
return fail("POLICY_BLOCKED", `Payment blocked — risk score ${risk.riskScore}/100: ${risk.suggestion}`, false, "send_payment");
|
|
86
|
-
}
|
|
87
|
-
try {
|
|
88
|
-
const wallet = createPharosWalletClientFromAccount(signer.account);
|
|
89
|
-
const txHash = await wallet.sendTransaction({
|
|
90
|
-
to: input.toAddress,
|
|
91
|
-
value: amountWei,
|
|
92
|
-
});
|
|
93
|
-
const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
|
|
94
|
-
if (receipt.status !== "success") {
|
|
95
|
-
return fail("TX_REVERTED", "send_payment transaction was mined but reverted on-chain.", false, "send_payment");
|
|
96
|
-
}
|
|
97
|
-
recordSpend(walletAddress, amountUsd);
|
|
98
|
-
return ok({
|
|
99
|
-
txHash,
|
|
100
|
-
explorerUrl: getExplorerUrl(txHash),
|
|
101
|
-
amountSent: input.amount,
|
|
102
|
-
signerMode: signer.mode,
|
|
103
|
-
walletAddress,
|
|
104
|
-
gasUsed: receipt.gasUsed.toString(),
|
|
105
|
-
validation,
|
|
106
|
-
policy,
|
|
107
|
-
riskAssessment: {
|
|
108
|
-
riskScore: risk.riskScore,
|
|
109
|
-
wasBlocked: false,
|
|
110
|
-
},
|
|
111
|
-
source: "send_payment",
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
catch (err) {
|
|
115
|
-
return classifyExternalError("pharos_rpc", err);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
1
|
+
// ─── Tool: send_payment ────────────────────────────────────────────────
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { publicClient, createPharosWalletClientFromAccount, getExplorerUrl } from "../lib/pharosClient.js";
|
|
4
|
+
import { isAddress, parseEther, formatEther } from "viem";
|
|
5
|
+
import { assessRisk } from "../lib/riskEngine.js";
|
|
6
|
+
import { fail, ok, classifyExternalError } from "../lib/toolResponse.js";
|
|
7
|
+
import { MAX_BALANCE_USAGE_PCT, RISK_BLOCK_THRESHOLD, MAX_TX_AMOUNT_PHRS, CHAIN_ID, PHAROS_ENVIRONMENT } from "../lib/constants.js";
|
|
8
|
+
import { getSigner, isSignerFailure } from "../lib/signer/index.js";
|
|
9
|
+
import { evaluateActionPolicy } from "../lib/policy/actionPolicyEngine.js";
|
|
10
|
+
import { checkDailyLimit, recordSpend, estimateUsd } from "../lib/spendAccumulator.js";
|
|
11
|
+
export const sendPaymentSchema = z.object({
|
|
12
|
+
toAddress: z.string(),
|
|
13
|
+
amount: z.string(),
|
|
14
|
+
memo: z.string().optional(),
|
|
15
|
+
agentId: z.string().optional().describe("Managed testnet wallet agentId when WALLET_MODE=managed-testnet"),
|
|
16
|
+
});
|
|
17
|
+
export const sendPaymentTool = {
|
|
18
|
+
name: "send_payment",
|
|
19
|
+
description: "Send native PHRS with pre-flight validation. Checks address validity, balance sufficiency, and warns on high exposure.",
|
|
20
|
+
inputSchema: sendPaymentSchema,
|
|
21
|
+
};
|
|
22
|
+
export async function handleSendPayment(raw) {
|
|
23
|
+
if (process.env.WRITE_TOOLS_ENABLED !== "true") {
|
|
24
|
+
return fail("WRITE_TOOLS_DISABLED", "send_payment is disabled by default. Set WRITE_TOOLS_ENABLED=true only for trusted testnet execution.", false, "send_payment");
|
|
25
|
+
}
|
|
26
|
+
const input = sendPaymentSchema.parse(raw);
|
|
27
|
+
const signer = await getSigner(input.agentId);
|
|
28
|
+
if (isSignerFailure(signer)) {
|
|
29
|
+
return fail(signer.error.code, signer.error.message, false, "send_payment");
|
|
30
|
+
}
|
|
31
|
+
const walletAddress = signer.address;
|
|
32
|
+
const policy = evaluateActionPolicy({
|
|
33
|
+
actionType: "send_payment",
|
|
34
|
+
amount: input.amount,
|
|
35
|
+
amountUnit: "PHRS",
|
|
36
|
+
recipient: input.toAddress,
|
|
37
|
+
recipientVerified: false,
|
|
38
|
+
chainId: CHAIN_ID,
|
|
39
|
+
environment: PHAROS_ENVIRONMENT,
|
|
40
|
+
isMainnet: false,
|
|
41
|
+
signerAvailable: true,
|
|
42
|
+
requiresSigner: true,
|
|
43
|
+
});
|
|
44
|
+
if (policy.decision === "BLOCK") {
|
|
45
|
+
return fail("POLICY_BLOCKED", policy.reasons.join(" ") || "Payment blocked by SafeHands policy.", false, "send_payment");
|
|
46
|
+
}
|
|
47
|
+
if (Number(input.amount) > Number(MAX_TX_AMOUNT_PHRS)) {
|
|
48
|
+
return fail("TX_LIMIT_EXCEEDED", `Payment amount exceeds configured testnet limit (${MAX_TX_AMOUNT_PHRS} PHRS).`, false, "send_payment");
|
|
49
|
+
}
|
|
50
|
+
const amountUsd = estimateUsd(input.amount, "PHRS");
|
|
51
|
+
const dailyCheck = checkDailyLimit(walletAddress, amountUsd);
|
|
52
|
+
if (!dailyCheck.allowed) {
|
|
53
|
+
return fail("DAILY_SPEND_LIMIT_EXCEEDED", `Daily spend limit reached. Spent $${dailyCheck.currentUsd.toFixed(2)} of $${dailyCheck.limitUsd.toFixed(2)} USD today. Remaining: $${dailyCheck.remainingUsd.toFixed(2)}. Resets at UTC midnight.`, false, "send_payment");
|
|
54
|
+
}
|
|
55
|
+
const warnings = [];
|
|
56
|
+
const validation = { addressValid: false, balanceSufficient: false, warnings };
|
|
57
|
+
if (!isAddress(input.toAddress)) {
|
|
58
|
+
return fail("INVALID_WALLET_ADDRESS", "Invalid recipient address", false, "send_payment");
|
|
59
|
+
}
|
|
60
|
+
validation.addressValid = true;
|
|
61
|
+
if (input.toAddress === "0x0000000000000000000000000000000000000000") {
|
|
62
|
+
return fail("ZERO_ADDRESS_BLOCKED", "Cannot send to zero address", false, "send_payment");
|
|
63
|
+
}
|
|
64
|
+
if (input.toAddress.toLowerCase() === walletAddress.toLowerCase()) {
|
|
65
|
+
warnings.push("Sending to own address");
|
|
66
|
+
}
|
|
67
|
+
const amountWei = parseEther(input.amount);
|
|
68
|
+
const balance = await publicClient.getBalance({ address: walletAddress });
|
|
69
|
+
const gasEstimate = parseEther("0.01");
|
|
70
|
+
if (balance < amountWei + gasEstimate) {
|
|
71
|
+
return fail("INSUFFICIENT_TESTNET_BALANCE", `Insufficient balance: have ${formatEther(balance)} PHRS, need ${input.amount} + gas`, false, "send_payment");
|
|
72
|
+
}
|
|
73
|
+
validation.balanceSufficient = true;
|
|
74
|
+
const usagePct = Number((amountWei * 100n) / balance);
|
|
75
|
+
if (usagePct > MAX_BALANCE_USAGE_PCT) {
|
|
76
|
+
warnings.push(`Using ${usagePct}% of wallet balance — high exposure`);
|
|
77
|
+
}
|
|
78
|
+
const risk = await assessRisk({
|
|
79
|
+
action: "transfer",
|
|
80
|
+
amount: input.amount,
|
|
81
|
+
toAddress: input.toAddress,
|
|
82
|
+
walletAddress,
|
|
83
|
+
});
|
|
84
|
+
if (risk.riskScore > RISK_BLOCK_THRESHOLD) {
|
|
85
|
+
return fail("POLICY_BLOCKED", `Payment blocked — risk score ${risk.riskScore}/100: ${risk.suggestion}`, false, "send_payment");
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
const wallet = createPharosWalletClientFromAccount(signer.account);
|
|
89
|
+
const txHash = await wallet.sendTransaction({
|
|
90
|
+
to: input.toAddress,
|
|
91
|
+
value: amountWei,
|
|
92
|
+
});
|
|
93
|
+
const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
|
|
94
|
+
if (receipt.status !== "success") {
|
|
95
|
+
return fail("TX_REVERTED", "send_payment transaction was mined but reverted on-chain.", false, "send_payment");
|
|
96
|
+
}
|
|
97
|
+
recordSpend(walletAddress, amountUsd);
|
|
98
|
+
return ok({
|
|
99
|
+
txHash,
|
|
100
|
+
explorerUrl: getExplorerUrl(txHash),
|
|
101
|
+
amountSent: input.amount,
|
|
102
|
+
signerMode: signer.mode,
|
|
103
|
+
walletAddress,
|
|
104
|
+
gasUsed: receipt.gasUsed.toString(),
|
|
105
|
+
validation,
|
|
106
|
+
policy,
|
|
107
|
+
riskAssessment: {
|
|
108
|
+
riskScore: risk.riskScore,
|
|
109
|
+
wasBlocked: false,
|
|
110
|
+
},
|
|
111
|
+
source: "send_payment",
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
return classifyExternalError("pharos_rpc", err);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
118
|
//# sourceMappingURL=sendPayment.js.map
|
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
export declare const simulateTransactionSchema: z.ZodObject<{
|
|
3
|
-
action: z.ZodEnum<["swap", "transfer"]>;
|
|
4
|
-
tokenIn: z.ZodOptional<z.ZodString>;
|
|
5
|
-
tokenOut: z.ZodOptional<z.ZodString>;
|
|
6
|
-
amount: z.ZodString;
|
|
7
|
-
toAddress: z.ZodOptional<z.ZodString>;
|
|
8
|
-
walletAddress: z.ZodString;
|
|
9
|
-
}, "strip", z.ZodTypeAny, {
|
|
10
|
-
amount: string;
|
|
11
|
-
walletAddress: string;
|
|
12
|
-
action: "transfer" | "swap";
|
|
13
|
-
tokenIn?: string | undefined;
|
|
14
|
-
tokenOut?: string | undefined;
|
|
15
|
-
toAddress?: string | undefined;
|
|
16
|
-
}, {
|
|
17
|
-
amount: string;
|
|
18
|
-
walletAddress: string;
|
|
19
|
-
action: "transfer" | "swap";
|
|
20
|
-
tokenIn?: string | undefined;
|
|
21
|
-
tokenOut?: string | undefined;
|
|
22
|
-
toAddress?: string | undefined;
|
|
23
|
-
}>;
|
|
24
|
-
export type SimulateTransactionInput = z.infer<typeof simulateTransactionSchema>;
|
|
25
|
-
export declare const simulateTransactionTool: {
|
|
26
|
-
name: string;
|
|
27
|
-
description: string;
|
|
28
|
-
inputSchema: z.ZodObject<{
|
|
29
|
-
action: z.ZodEnum<["swap", "transfer"]>;
|
|
30
|
-
tokenIn: z.ZodOptional<z.ZodString>;
|
|
31
|
-
tokenOut: z.ZodOptional<z.ZodString>;
|
|
32
|
-
amount: z.ZodString;
|
|
33
|
-
toAddress: z.ZodOptional<z.ZodString>;
|
|
34
|
-
walletAddress: z.ZodString;
|
|
35
|
-
}, "strip", z.ZodTypeAny, {
|
|
36
|
-
amount: string;
|
|
37
|
-
walletAddress: string;
|
|
38
|
-
action: "transfer" | "swap";
|
|
39
|
-
tokenIn?: string | undefined;
|
|
40
|
-
tokenOut?: string | undefined;
|
|
41
|
-
toAddress?: string | undefined;
|
|
42
|
-
}, {
|
|
43
|
-
amount: string;
|
|
44
|
-
walletAddress: string;
|
|
45
|
-
action: "transfer" | "swap";
|
|
46
|
-
tokenIn?: string | undefined;
|
|
47
|
-
tokenOut?: string | undefined;
|
|
48
|
-
toAddress?: string | undefined;
|
|
49
|
-
}>;
|
|
50
|
-
};
|
|
51
|
-
export declare function handleSimulateTransaction(input: SimulateTransactionInput): Promise<import("../lib/toolResponse.js").ToolFailure | import("../lib/toolResponse.js").ToolSuccess<{
|
|
52
|
-
wouldSucceed: boolean;
|
|
53
|
-
expectedOutput: string;
|
|
54
|
-
gasEstimate: string;
|
|
55
|
-
balanceChanges: {
|
|
56
|
-
token: string;
|
|
57
|
-
delta: string;
|
|
58
|
-
}[];
|
|
59
|
-
warnings: string[];
|
|
60
|
-
}>>;
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const simulateTransactionSchema: z.ZodObject<{
|
|
3
|
+
action: z.ZodEnum<["swap", "transfer"]>;
|
|
4
|
+
tokenIn: z.ZodOptional<z.ZodString>;
|
|
5
|
+
tokenOut: z.ZodOptional<z.ZodString>;
|
|
6
|
+
amount: z.ZodString;
|
|
7
|
+
toAddress: z.ZodOptional<z.ZodString>;
|
|
8
|
+
walletAddress: z.ZodString;
|
|
9
|
+
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
amount: string;
|
|
11
|
+
walletAddress: string;
|
|
12
|
+
action: "transfer" | "swap";
|
|
13
|
+
tokenIn?: string | undefined;
|
|
14
|
+
tokenOut?: string | undefined;
|
|
15
|
+
toAddress?: string | undefined;
|
|
16
|
+
}, {
|
|
17
|
+
amount: string;
|
|
18
|
+
walletAddress: string;
|
|
19
|
+
action: "transfer" | "swap";
|
|
20
|
+
tokenIn?: string | undefined;
|
|
21
|
+
tokenOut?: string | undefined;
|
|
22
|
+
toAddress?: string | undefined;
|
|
23
|
+
}>;
|
|
24
|
+
export type SimulateTransactionInput = z.infer<typeof simulateTransactionSchema>;
|
|
25
|
+
export declare const simulateTransactionTool: {
|
|
26
|
+
name: string;
|
|
27
|
+
description: string;
|
|
28
|
+
inputSchema: z.ZodObject<{
|
|
29
|
+
action: z.ZodEnum<["swap", "transfer"]>;
|
|
30
|
+
tokenIn: z.ZodOptional<z.ZodString>;
|
|
31
|
+
tokenOut: z.ZodOptional<z.ZodString>;
|
|
32
|
+
amount: z.ZodString;
|
|
33
|
+
toAddress: z.ZodOptional<z.ZodString>;
|
|
34
|
+
walletAddress: z.ZodString;
|
|
35
|
+
}, "strip", z.ZodTypeAny, {
|
|
36
|
+
amount: string;
|
|
37
|
+
walletAddress: string;
|
|
38
|
+
action: "transfer" | "swap";
|
|
39
|
+
tokenIn?: string | undefined;
|
|
40
|
+
tokenOut?: string | undefined;
|
|
41
|
+
toAddress?: string | undefined;
|
|
42
|
+
}, {
|
|
43
|
+
amount: string;
|
|
44
|
+
walletAddress: string;
|
|
45
|
+
action: "transfer" | "swap";
|
|
46
|
+
tokenIn?: string | undefined;
|
|
47
|
+
tokenOut?: string | undefined;
|
|
48
|
+
toAddress?: string | undefined;
|
|
49
|
+
}>;
|
|
50
|
+
};
|
|
51
|
+
export declare function handleSimulateTransaction(input: SimulateTransactionInput): Promise<import("../lib/toolResponse.js").ToolFailure | import("../lib/toolResponse.js").ToolSuccess<{
|
|
52
|
+
wouldSucceed: boolean;
|
|
53
|
+
expectedOutput: string;
|
|
54
|
+
gasEstimate: string;
|
|
55
|
+
balanceChanges: {
|
|
56
|
+
token: string;
|
|
57
|
+
delta: string;
|
|
58
|
+
}[];
|
|
59
|
+
warnings: string[];
|
|
60
|
+
}>>;
|
|
61
61
|
//# sourceMappingURL=simulateTransaction.d.ts.map
|
|
@@ -1,84 +1,84 @@
|
|
|
1
|
-
// ─── Tool: simulate_transaction ────────────────────────────────────────
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
import { publicClient } from "../lib/pharosClient.js";
|
|
4
|
-
import { getDodoRoute } from "../lib/dodoApi.js";
|
|
5
|
-
import { parseEther, formatEther } from "viem";
|
|
6
|
-
import { ok, fail } from "../lib/toolResponse.js";
|
|
7
|
-
export const simulateTransactionSchema = z.object({
|
|
8
|
-
action: z.enum(["swap", "transfer"]),
|
|
9
|
-
tokenIn: z.string().optional(),
|
|
10
|
-
tokenOut: z.string().optional(),
|
|
11
|
-
amount: z.string(),
|
|
12
|
-
toAddress: z.string().optional(),
|
|
13
|
-
walletAddress: z.string(),
|
|
14
|
-
});
|
|
15
|
-
export const simulateTransactionTool = {
|
|
16
|
-
name: "simulate_transaction",
|
|
17
|
-
description: "Dry run a swap or transfer via eth_call — no gas spent. Returns expected output, gas estimate, and revert reasons.",
|
|
18
|
-
inputSchema: simulateTransactionSchema,
|
|
19
|
-
};
|
|
20
|
-
export async function handleSimulateTransaction(input) {
|
|
21
|
-
const warnings = [];
|
|
22
|
-
const balanceChanges = [];
|
|
23
|
-
try {
|
|
24
|
-
if (input.action === "swap") {
|
|
25
|
-
if (!input.tokenIn || !input.tokenOut) {
|
|
26
|
-
return fail("INVALID_INPUT", "tokenIn and tokenOut required for swap simulation", false, "simulate_transaction");
|
|
27
|
-
}
|
|
28
|
-
const quote = await getDodoRoute({
|
|
29
|
-
fromToken: input.tokenIn,
|
|
30
|
-
toToken: input.tokenOut,
|
|
31
|
-
amountHuman: input.amount,
|
|
32
|
-
walletAddress: input.walletAddress,
|
|
33
|
-
});
|
|
34
|
-
if (!quote.routeAvailable) {
|
|
35
|
-
return fail("NO_ROUTE_AVAILABLE", "No swap route available", true, "simulate_transaction");
|
|
36
|
-
}
|
|
37
|
-
// Simulate via eth_call
|
|
38
|
-
try {
|
|
39
|
-
await publicClient.call({
|
|
40
|
-
to: quote.to,
|
|
41
|
-
data: quote.calldata,
|
|
42
|
-
value: BigInt(quote.value),
|
|
43
|
-
account: input.walletAddress,
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
catch (err) {
|
|
47
|
-
const msg = err.message;
|
|
48
|
-
if (msg.includes("revert")) {
|
|
49
|
-
return fail("SIMULATION_REVERTED", msg, false, "simulate_transaction");
|
|
50
|
-
}
|
|
51
|
-
warnings.push(`Simulation warning: ${msg}`);
|
|
52
|
-
}
|
|
53
|
-
balanceChanges.push({ token: input.tokenIn, delta: `-${input.amount}` });
|
|
54
|
-
balanceChanges.push({ token: input.tokenOut, delta: `+${quote.amountOut}` });
|
|
55
|
-
return ok({ wouldSucceed: true, expectedOutput: quote.amountOut, gasEstimate: quote.gasLimit, balanceChanges, warnings });
|
|
56
|
-
}
|
|
57
|
-
// Transfer simulation
|
|
58
|
-
if (!input.toAddress) {
|
|
59
|
-
return fail("INVALID_INPUT", "toAddress required for transfer simulation", false, "simulate_transaction");
|
|
60
|
-
}
|
|
61
|
-
const amountWei = parseEther(input.amount);
|
|
62
|
-
const balance = await publicClient.getBalance({ address: input.walletAddress });
|
|
63
|
-
if (balance < amountWei) {
|
|
64
|
-
return fail("INSUFFICIENT_TESTNET_BALANCE", `Insufficient balance: have ${formatEther(balance)}, need ${input.amount}`, false, "simulate_transaction");
|
|
65
|
-
}
|
|
66
|
-
const gasEstimate = await publicClient.estimateGas({
|
|
67
|
-
to: input.toAddress,
|
|
68
|
-
value: amountWei,
|
|
69
|
-
account: input.walletAddress,
|
|
70
|
-
});
|
|
71
|
-
balanceChanges.push({ token: "PHRS", delta: `-${input.amount}` });
|
|
72
|
-
return ok({
|
|
73
|
-
wouldSucceed: true,
|
|
74
|
-
expectedOutput: input.amount,
|
|
75
|
-
gasEstimate: gasEstimate.toString(),
|
|
76
|
-
balanceChanges,
|
|
77
|
-
warnings,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
catch (err) {
|
|
81
|
-
return fail("SIMULATION_FAILED", err.message, true, "simulate_transaction");
|
|
82
|
-
}
|
|
83
|
-
}
|
|
1
|
+
// ─── Tool: simulate_transaction ────────────────────────────────────────
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { publicClient } from "../lib/pharosClient.js";
|
|
4
|
+
import { getDodoRoute } from "../lib/dodoApi.js";
|
|
5
|
+
import { parseEther, formatEther } from "viem";
|
|
6
|
+
import { ok, fail } from "../lib/toolResponse.js";
|
|
7
|
+
export const simulateTransactionSchema = z.object({
|
|
8
|
+
action: z.enum(["swap", "transfer"]),
|
|
9
|
+
tokenIn: z.string().optional(),
|
|
10
|
+
tokenOut: z.string().optional(),
|
|
11
|
+
amount: z.string(),
|
|
12
|
+
toAddress: z.string().optional(),
|
|
13
|
+
walletAddress: z.string(),
|
|
14
|
+
});
|
|
15
|
+
export const simulateTransactionTool = {
|
|
16
|
+
name: "simulate_transaction",
|
|
17
|
+
description: "Dry run a swap or transfer via eth_call — no gas spent. Returns expected output, gas estimate, and revert reasons.",
|
|
18
|
+
inputSchema: simulateTransactionSchema,
|
|
19
|
+
};
|
|
20
|
+
export async function handleSimulateTransaction(input) {
|
|
21
|
+
const warnings = [];
|
|
22
|
+
const balanceChanges = [];
|
|
23
|
+
try {
|
|
24
|
+
if (input.action === "swap") {
|
|
25
|
+
if (!input.tokenIn || !input.tokenOut) {
|
|
26
|
+
return fail("INVALID_INPUT", "tokenIn and tokenOut required for swap simulation", false, "simulate_transaction");
|
|
27
|
+
}
|
|
28
|
+
const quote = await getDodoRoute({
|
|
29
|
+
fromToken: input.tokenIn,
|
|
30
|
+
toToken: input.tokenOut,
|
|
31
|
+
amountHuman: input.amount,
|
|
32
|
+
walletAddress: input.walletAddress,
|
|
33
|
+
});
|
|
34
|
+
if (!quote.routeAvailable) {
|
|
35
|
+
return fail("NO_ROUTE_AVAILABLE", "No swap route available", true, "simulate_transaction");
|
|
36
|
+
}
|
|
37
|
+
// Simulate via eth_call
|
|
38
|
+
try {
|
|
39
|
+
await publicClient.call({
|
|
40
|
+
to: quote.to,
|
|
41
|
+
data: quote.calldata,
|
|
42
|
+
value: BigInt(quote.value),
|
|
43
|
+
account: input.walletAddress,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
const msg = err.message;
|
|
48
|
+
if (msg.includes("revert")) {
|
|
49
|
+
return fail("SIMULATION_REVERTED", msg, false, "simulate_transaction");
|
|
50
|
+
}
|
|
51
|
+
warnings.push(`Simulation warning: ${msg}`);
|
|
52
|
+
}
|
|
53
|
+
balanceChanges.push({ token: input.tokenIn, delta: `-${input.amount}` });
|
|
54
|
+
balanceChanges.push({ token: input.tokenOut, delta: `+${quote.amountOut}` });
|
|
55
|
+
return ok({ wouldSucceed: true, expectedOutput: quote.amountOut, gasEstimate: quote.gasLimit, balanceChanges, warnings });
|
|
56
|
+
}
|
|
57
|
+
// Transfer simulation
|
|
58
|
+
if (!input.toAddress) {
|
|
59
|
+
return fail("INVALID_INPUT", "toAddress required for transfer simulation", false, "simulate_transaction");
|
|
60
|
+
}
|
|
61
|
+
const amountWei = parseEther(input.amount);
|
|
62
|
+
const balance = await publicClient.getBalance({ address: input.walletAddress });
|
|
63
|
+
if (balance < amountWei) {
|
|
64
|
+
return fail("INSUFFICIENT_TESTNET_BALANCE", `Insufficient balance: have ${formatEther(balance)}, need ${input.amount}`, false, "simulate_transaction");
|
|
65
|
+
}
|
|
66
|
+
const gasEstimate = await publicClient.estimateGas({
|
|
67
|
+
to: input.toAddress,
|
|
68
|
+
value: amountWei,
|
|
69
|
+
account: input.walletAddress,
|
|
70
|
+
});
|
|
71
|
+
balanceChanges.push({ token: "PHRS", delta: `-${input.amount}` });
|
|
72
|
+
return ok({
|
|
73
|
+
wouldSucceed: true,
|
|
74
|
+
expectedOutput: input.amount,
|
|
75
|
+
gasEstimate: gasEstimate.toString(),
|
|
76
|
+
balanceChanges,
|
|
77
|
+
warnings,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
return fail("SIMULATION_FAILED", err.message, true, "simulate_transaction");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
84
|
//# sourceMappingURL=simulateTransaction.js.map
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { type ToolResponse } from "../lib/toolResponse.js";
|
|
3
|
-
export declare const tokenRegistryStatusSchema: z.ZodObject<{
|
|
4
|
-
token: z.ZodOptional<z.ZodString>;
|
|
5
|
-
tokenAddress: z.ZodOptional<z.ZodString>;
|
|
6
|
-
}, "strip", z.ZodTypeAny, {
|
|
7
|
-
token?: string | undefined;
|
|
8
|
-
tokenAddress?: string | undefined;
|
|
9
|
-
}, {
|
|
10
|
-
token?: string | undefined;
|
|
11
|
-
tokenAddress?: string | undefined;
|
|
12
|
-
}>;
|
|
13
|
-
export type TokenRegistryStatusInput = z.input<typeof tokenRegistryStatusSchema>;
|
|
14
|
-
export type TokenRegistryStatusValue = "CANONICAL_TESTNET_TOKEN" | "SKILL_ENGINE_CANONICAL_TOKEN" | "ALTERNATE_SOURCE_TOKEN" | "CUSTOM_NON_REGISTRY" | "UNKNOWN" | "INVALID_ADDRESS";
|
|
15
|
-
export declare function classifyTokenRegistryStatus(token: string): {
|
|
16
|
-
input: string;
|
|
17
|
-
normalizedAddress: any;
|
|
18
|
-
symbol: any;
|
|
19
|
-
status: TokenRegistryStatusValue;
|
|
20
|
-
verificationStatus: any;
|
|
21
|
-
docsSource: any;
|
|
22
|
-
chainId: number;
|
|
23
|
-
environment: string;
|
|
24
|
-
isMainnet: boolean;
|
|
25
|
-
};
|
|
26
|
-
export declare function handleTokenRegistryStatus(raw: TokenRegistryStatusInput): Promise<ToolResponse<unknown>>;
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { type ToolResponse } from "../lib/toolResponse.js";
|
|
3
|
+
export declare const tokenRegistryStatusSchema: z.ZodObject<{
|
|
4
|
+
token: z.ZodOptional<z.ZodString>;
|
|
5
|
+
tokenAddress: z.ZodOptional<z.ZodString>;
|
|
6
|
+
}, "strip", z.ZodTypeAny, {
|
|
7
|
+
token?: string | undefined;
|
|
8
|
+
tokenAddress?: string | undefined;
|
|
9
|
+
}, {
|
|
10
|
+
token?: string | undefined;
|
|
11
|
+
tokenAddress?: string | undefined;
|
|
12
|
+
}>;
|
|
13
|
+
export type TokenRegistryStatusInput = z.input<typeof tokenRegistryStatusSchema>;
|
|
14
|
+
export type TokenRegistryStatusValue = "CANONICAL_TESTNET_TOKEN" | "SKILL_ENGINE_CANONICAL_TOKEN" | "ALTERNATE_SOURCE_TOKEN" | "CUSTOM_NON_REGISTRY" | "UNKNOWN" | "INVALID_ADDRESS";
|
|
15
|
+
export declare function classifyTokenRegistryStatus(token: string): {
|
|
16
|
+
input: string;
|
|
17
|
+
normalizedAddress: any;
|
|
18
|
+
symbol: any;
|
|
19
|
+
status: TokenRegistryStatusValue;
|
|
20
|
+
verificationStatus: any;
|
|
21
|
+
docsSource: any;
|
|
22
|
+
chainId: number;
|
|
23
|
+
environment: string;
|
|
24
|
+
isMainnet: boolean;
|
|
25
|
+
};
|
|
26
|
+
export declare function handleTokenRegistryStatus(raw: TokenRegistryStatusInput): Promise<ToolResponse<unknown>>;
|
|
27
27
|
//# sourceMappingURL=tokenRegistryStatus.d.ts.map
|