shll-skills 5.5.1 → 5.5.2
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/SKILL.md +2 -0
- package/dist/index.js +74 -2
- package/dist/index.mjs +74 -2
- package/dist/mcp.js +93 -2
- package/dist/mcp.mjs +93 -2
- package/package.json +2 -2
- package/src/index.ts +97 -25
- package/src/mcp.ts +114 -29
package/SKILL.md
CHANGED
|
@@ -153,6 +153,8 @@ If `-l/--listing-id` is omitted, `setup-guide` auto-selects an active listing fr
|
|
|
153
153
|
- `shll-run four-buy --token <address> -a <bnb> -k <tokenId>`
|
|
154
154
|
- `shll-run four-sell --token <address> -a <tokenAmount> -k <tokenId>`
|
|
155
155
|
|
|
156
|
+
`four-buy` amount unit is BNB, not USD. If user gives a USD target, convert to BNB first and confirm final BNB amount before execution.
|
|
157
|
+
|
|
156
158
|
### Read-only and audit
|
|
157
159
|
|
|
158
160
|
- `shll-run portfolio -k <tokenId>`
|
package/dist/index.js
CHANGED
|
@@ -2747,13 +2747,17 @@ fourBuyCmd.action(async (opts) => {
|
|
|
2747
2747
|
const tokenAddr = opts.token;
|
|
2748
2748
|
const slippage = Number(opts.slippage);
|
|
2749
2749
|
const bnbAmount = parseAmount(opts.amount, 18);
|
|
2750
|
+
if (bnbAmount <= 0n) {
|
|
2751
|
+
outputError("Invalid amount.", "four-buy amount must be a positive BNB value.");
|
|
2752
|
+
process.exit(1);
|
|
2753
|
+
}
|
|
2750
2754
|
const info = await publicClient.readContract({
|
|
2751
2755
|
address: FOUR_MEME_HELPER_V3,
|
|
2752
2756
|
abi: FOUR_MEME_HELPER_ABI,
|
|
2753
2757
|
functionName: "getTokenInfo",
|
|
2754
2758
|
args: [tokenAddr]
|
|
2755
2759
|
});
|
|
2756
|
-
const [version, tokenManager, quote, , , , , , , , , liquidityAdded] = info;
|
|
2760
|
+
const [version, tokenManager, quote, , , minTradingFee, , , , , , liquidityAdded] = info;
|
|
2757
2761
|
if (liquidityAdded) {
|
|
2758
2762
|
output({ status: "error", message: "Token has already migrated to DEX. Use the 'swap' command instead of 'four-buy'." });
|
|
2759
2763
|
process.exit(1);
|
|
@@ -2763,6 +2767,20 @@ fourBuyCmd.action(async (opts) => {
|
|
|
2763
2767
|
output({ status: "error", message: `Token uses BEP20 quote (${quote}), not BNB. BEP20 quote pairs are not yet supported in this tool.` });
|
|
2764
2768
|
process.exit(1);
|
|
2765
2769
|
}
|
|
2770
|
+
if (bnbAmount < minTradingFee) {
|
|
2771
|
+
outputError(
|
|
2772
|
+
"Input amount is below Four.meme minimum trading fee threshold.",
|
|
2773
|
+
"Increase --amount and retry.",
|
|
2774
|
+
{
|
|
2775
|
+
token: tokenAddr,
|
|
2776
|
+
inputBnb: opts.amount,
|
|
2777
|
+
inputWei: bnbAmount.toString(),
|
|
2778
|
+
minTradingFeeWei: minTradingFee.toString(),
|
|
2779
|
+
minTradingFeeBnb: (Number(minTradingFee) / 1e18).toFixed(6)
|
|
2780
|
+
}
|
|
2781
|
+
);
|
|
2782
|
+
process.exit(1);
|
|
2783
|
+
}
|
|
2766
2784
|
const tryBuyResult = await publicClient.readContract({
|
|
2767
2785
|
address: FOUR_MEME_HELPER_V3,
|
|
2768
2786
|
abi: FOUR_MEME_HELPER_ABI,
|
|
@@ -2770,6 +2788,48 @@ fourBuyCmd.action(async (opts) => {
|
|
|
2770
2788
|
args: [tokenAddr, 0n, bnbAmount]
|
|
2771
2789
|
});
|
|
2772
2790
|
const [, , estimatedAmount, estimatedCost, estimatedFee, amountMsgValue] = tryBuyResult;
|
|
2791
|
+
if (amountMsgValue < minTradingFee) {
|
|
2792
|
+
outputError(
|
|
2793
|
+
"Computed payable amount is below Four.meme minimum trading fee threshold.",
|
|
2794
|
+
"Increase --amount and retry.",
|
|
2795
|
+
{
|
|
2796
|
+
token: tokenAddr,
|
|
2797
|
+
inputBnb: opts.amount,
|
|
2798
|
+
payableWei: amountMsgValue.toString(),
|
|
2799
|
+
minTradingFeeWei: minTradingFee.toString(),
|
|
2800
|
+
minTradingFeeBnb: (Number(minTradingFee) / 1e18).toFixed(6)
|
|
2801
|
+
}
|
|
2802
|
+
);
|
|
2803
|
+
process.exit(1);
|
|
2804
|
+
}
|
|
2805
|
+
if (estimatedAmount <= 0n || amountMsgValue <= 0n) {
|
|
2806
|
+
outputError(
|
|
2807
|
+
"four-buy quote returned zero output.",
|
|
2808
|
+
"Requested amount is likely too small for this market. Increase --amount and retry.",
|
|
2809
|
+
{
|
|
2810
|
+
token: tokenAddr,
|
|
2811
|
+
inputBnb: opts.amount,
|
|
2812
|
+
estimatedCostWei: estimatedCost.toString(),
|
|
2813
|
+
estimatedFeeWei: estimatedFee.toString()
|
|
2814
|
+
}
|
|
2815
|
+
);
|
|
2816
|
+
process.exit(1);
|
|
2817
|
+
}
|
|
2818
|
+
const vaultBnbBalance = await publicClient.getBalance({ address: vault });
|
|
2819
|
+
if (amountMsgValue > vaultBnbBalance) {
|
|
2820
|
+
outputError(
|
|
2821
|
+
"Vault BNB balance is insufficient for four-buy.",
|
|
2822
|
+
"Deposit more BNB to vault or reduce --amount, then retry.",
|
|
2823
|
+
{
|
|
2824
|
+
vault,
|
|
2825
|
+
requiredBnb: (Number(amountMsgValue) / 1e18).toFixed(6),
|
|
2826
|
+
availableBnb: (Number(vaultBnbBalance) / 1e18).toFixed(6),
|
|
2827
|
+
requiredWei: amountMsgValue.toString(),
|
|
2828
|
+
availableWei: vaultBnbBalance.toString()
|
|
2829
|
+
}
|
|
2830
|
+
);
|
|
2831
|
+
process.exit(1);
|
|
2832
|
+
}
|
|
2773
2833
|
const minAmount = estimatedAmount * BigInt(100 - slippage) / 100n;
|
|
2774
2834
|
const alignedMinAmount = minAmount / 1000000000n * 1000000000n;
|
|
2775
2835
|
output({
|
|
@@ -2800,7 +2860,19 @@ fourBuyCmd.action(async (opts) => {
|
|
|
2800
2860
|
output({ status: "rejected", reason: simResult.reason });
|
|
2801
2861
|
process.exit(0);
|
|
2802
2862
|
}
|
|
2803
|
-
|
|
2863
|
+
let result;
|
|
2864
|
+
try {
|
|
2865
|
+
result = await client.execute(tokenId, action, true);
|
|
2866
|
+
} catch (error) {
|
|
2867
|
+
const message = error instanceof Error ? error.message : "Unknown execution revert";
|
|
2868
|
+
outputError(
|
|
2869
|
+
"four-buy execution reverted on-chain.",
|
|
2870
|
+
"Likely market-side failure (amount too small, temporary pool state change, or token-side constraint).",
|
|
2871
|
+
{ reason: message, token: tokenAddr, inputBnb: opts.amount }
|
|
2872
|
+
);
|
|
2873
|
+
process.exit(1);
|
|
2874
|
+
return;
|
|
2875
|
+
}
|
|
2804
2876
|
output({
|
|
2805
2877
|
status: "success",
|
|
2806
2878
|
hash: result.hash,
|
package/dist/index.mjs
CHANGED
|
@@ -2259,13 +2259,17 @@ fourBuyCmd.action(async (opts) => {
|
|
|
2259
2259
|
const tokenAddr = opts.token;
|
|
2260
2260
|
const slippage = Number(opts.slippage);
|
|
2261
2261
|
const bnbAmount = parseAmount(opts.amount, 18);
|
|
2262
|
+
if (bnbAmount <= 0n) {
|
|
2263
|
+
outputError("Invalid amount.", "four-buy amount must be a positive BNB value.");
|
|
2264
|
+
process.exit(1);
|
|
2265
|
+
}
|
|
2262
2266
|
const info = await publicClient.readContract({
|
|
2263
2267
|
address: FOUR_MEME_HELPER_V3,
|
|
2264
2268
|
abi: FOUR_MEME_HELPER_ABI,
|
|
2265
2269
|
functionName: "getTokenInfo",
|
|
2266
2270
|
args: [tokenAddr]
|
|
2267
2271
|
});
|
|
2268
|
-
const [version, tokenManager, quote, , , , , , , , , liquidityAdded] = info;
|
|
2272
|
+
const [version, tokenManager, quote, , , minTradingFee, , , , , , liquidityAdded] = info;
|
|
2269
2273
|
if (liquidityAdded) {
|
|
2270
2274
|
output({ status: "error", message: "Token has already migrated to DEX. Use the 'swap' command instead of 'four-buy'." });
|
|
2271
2275
|
process.exit(1);
|
|
@@ -2275,6 +2279,20 @@ fourBuyCmd.action(async (opts) => {
|
|
|
2275
2279
|
output({ status: "error", message: `Token uses BEP20 quote (${quote}), not BNB. BEP20 quote pairs are not yet supported in this tool.` });
|
|
2276
2280
|
process.exit(1);
|
|
2277
2281
|
}
|
|
2282
|
+
if (bnbAmount < minTradingFee) {
|
|
2283
|
+
outputError(
|
|
2284
|
+
"Input amount is below Four.meme minimum trading fee threshold.",
|
|
2285
|
+
"Increase --amount and retry.",
|
|
2286
|
+
{
|
|
2287
|
+
token: tokenAddr,
|
|
2288
|
+
inputBnb: opts.amount,
|
|
2289
|
+
inputWei: bnbAmount.toString(),
|
|
2290
|
+
minTradingFeeWei: minTradingFee.toString(),
|
|
2291
|
+
minTradingFeeBnb: (Number(minTradingFee) / 1e18).toFixed(6)
|
|
2292
|
+
}
|
|
2293
|
+
);
|
|
2294
|
+
process.exit(1);
|
|
2295
|
+
}
|
|
2278
2296
|
const tryBuyResult = await publicClient.readContract({
|
|
2279
2297
|
address: FOUR_MEME_HELPER_V3,
|
|
2280
2298
|
abi: FOUR_MEME_HELPER_ABI,
|
|
@@ -2282,6 +2300,48 @@ fourBuyCmd.action(async (opts) => {
|
|
|
2282
2300
|
args: [tokenAddr, 0n, bnbAmount]
|
|
2283
2301
|
});
|
|
2284
2302
|
const [, , estimatedAmount, estimatedCost, estimatedFee, amountMsgValue] = tryBuyResult;
|
|
2303
|
+
if (amountMsgValue < minTradingFee) {
|
|
2304
|
+
outputError(
|
|
2305
|
+
"Computed payable amount is below Four.meme minimum trading fee threshold.",
|
|
2306
|
+
"Increase --amount and retry.",
|
|
2307
|
+
{
|
|
2308
|
+
token: tokenAddr,
|
|
2309
|
+
inputBnb: opts.amount,
|
|
2310
|
+
payableWei: amountMsgValue.toString(),
|
|
2311
|
+
minTradingFeeWei: minTradingFee.toString(),
|
|
2312
|
+
minTradingFeeBnb: (Number(minTradingFee) / 1e18).toFixed(6)
|
|
2313
|
+
}
|
|
2314
|
+
);
|
|
2315
|
+
process.exit(1);
|
|
2316
|
+
}
|
|
2317
|
+
if (estimatedAmount <= 0n || amountMsgValue <= 0n) {
|
|
2318
|
+
outputError(
|
|
2319
|
+
"four-buy quote returned zero output.",
|
|
2320
|
+
"Requested amount is likely too small for this market. Increase --amount and retry.",
|
|
2321
|
+
{
|
|
2322
|
+
token: tokenAddr,
|
|
2323
|
+
inputBnb: opts.amount,
|
|
2324
|
+
estimatedCostWei: estimatedCost.toString(),
|
|
2325
|
+
estimatedFeeWei: estimatedFee.toString()
|
|
2326
|
+
}
|
|
2327
|
+
);
|
|
2328
|
+
process.exit(1);
|
|
2329
|
+
}
|
|
2330
|
+
const vaultBnbBalance = await publicClient.getBalance({ address: vault });
|
|
2331
|
+
if (amountMsgValue > vaultBnbBalance) {
|
|
2332
|
+
outputError(
|
|
2333
|
+
"Vault BNB balance is insufficient for four-buy.",
|
|
2334
|
+
"Deposit more BNB to vault or reduce --amount, then retry.",
|
|
2335
|
+
{
|
|
2336
|
+
vault,
|
|
2337
|
+
requiredBnb: (Number(amountMsgValue) / 1e18).toFixed(6),
|
|
2338
|
+
availableBnb: (Number(vaultBnbBalance) / 1e18).toFixed(6),
|
|
2339
|
+
requiredWei: amountMsgValue.toString(),
|
|
2340
|
+
availableWei: vaultBnbBalance.toString()
|
|
2341
|
+
}
|
|
2342
|
+
);
|
|
2343
|
+
process.exit(1);
|
|
2344
|
+
}
|
|
2285
2345
|
const minAmount = estimatedAmount * BigInt(100 - slippage) / 100n;
|
|
2286
2346
|
const alignedMinAmount = minAmount / 1000000000n * 1000000000n;
|
|
2287
2347
|
output({
|
|
@@ -2312,7 +2372,19 @@ fourBuyCmd.action(async (opts) => {
|
|
|
2312
2372
|
output({ status: "rejected", reason: simResult.reason });
|
|
2313
2373
|
process.exit(0);
|
|
2314
2374
|
}
|
|
2315
|
-
|
|
2375
|
+
let result;
|
|
2376
|
+
try {
|
|
2377
|
+
result = await client.execute(tokenId, action, true);
|
|
2378
|
+
} catch (error) {
|
|
2379
|
+
const message = error instanceof Error ? error.message : "Unknown execution revert";
|
|
2380
|
+
outputError(
|
|
2381
|
+
"four-buy execution reverted on-chain.",
|
|
2382
|
+
"Likely market-side failure (amount too small, temporary pool state change, or token-side constraint).",
|
|
2383
|
+
{ reason: message, token: tokenAddr, inputBnb: opts.amount }
|
|
2384
|
+
);
|
|
2385
|
+
process.exit(1);
|
|
2386
|
+
return;
|
|
2387
|
+
}
|
|
2316
2388
|
output({
|
|
2317
2389
|
status: "success",
|
|
2318
2390
|
hash: result.hash,
|
package/dist/mcp.js
CHANGED
|
@@ -2035,19 +2035,47 @@ server.tool(
|
|
|
2035
2035
|
if (expiryCheck.blocked) return { content: expiryCheck.content };
|
|
2036
2036
|
const tokenAddr = token;
|
|
2037
2037
|
const bnbAmount = parseAmount(amount, 18);
|
|
2038
|
+
if (bnbAmount <= 0n) {
|
|
2039
|
+
return {
|
|
2040
|
+
content: [{
|
|
2041
|
+
type: "text",
|
|
2042
|
+
text: JSON.stringify({
|
|
2043
|
+
status: "error",
|
|
2044
|
+
message: "Invalid amount. four_buy amount must be a positive BNB value."
|
|
2045
|
+
})
|
|
2046
|
+
}]
|
|
2047
|
+
};
|
|
2048
|
+
}
|
|
2049
|
+
const vault = await policyClient.getVault(tokenId);
|
|
2038
2050
|
const info = await publicClient.readContract({
|
|
2039
2051
|
address: FOUR_MEME_HELPER_V3,
|
|
2040
2052
|
abi: FOUR_MEME_HELPER_ABI,
|
|
2041
2053
|
functionName: "getTokenInfo",
|
|
2042
2054
|
args: [tokenAddr]
|
|
2043
2055
|
});
|
|
2044
|
-
const [version, tokenManager, quote, , , , , , , , , liquidityAdded] = info;
|
|
2056
|
+
const [version, tokenManager, quote, , , minTradingFee, , , , , , liquidityAdded] = info;
|
|
2045
2057
|
if (liquidityAdded) {
|
|
2046
2058
|
return { content: [{ type: "text", text: JSON.stringify({ status: "error", message: "Token has already migrated to DEX. Use the 'swap' tool instead." }) }] };
|
|
2047
2059
|
}
|
|
2048
2060
|
if (quote !== "0x0000000000000000000000000000000000000000") {
|
|
2049
2061
|
return { content: [{ type: "text", text: JSON.stringify({ status: "error", message: `Token uses BEP20 quote (${quote}), not BNB. BEP20 pairs not yet supported.` }) }] };
|
|
2050
2062
|
}
|
|
2063
|
+
if (bnbAmount < minTradingFee) {
|
|
2064
|
+
return {
|
|
2065
|
+
content: [{
|
|
2066
|
+
type: "text",
|
|
2067
|
+
text: JSON.stringify({
|
|
2068
|
+
status: "error",
|
|
2069
|
+
message: "Input amount is below Four.meme minimum trading fee threshold.",
|
|
2070
|
+
next_step: "Increase amount and retry.",
|
|
2071
|
+
token: tokenAddr,
|
|
2072
|
+
inputWei: bnbAmount.toString(),
|
|
2073
|
+
minTradingFeeWei: minTradingFee.toString(),
|
|
2074
|
+
minTradingFeeBnb: (Number(minTradingFee) / 1e18).toFixed(6)
|
|
2075
|
+
})
|
|
2076
|
+
}]
|
|
2077
|
+
};
|
|
2078
|
+
}
|
|
2051
2079
|
const tryBuyResult = await publicClient.readContract({
|
|
2052
2080
|
address: FOUR_MEME_HELPER_V3,
|
|
2053
2081
|
abi: FOUR_MEME_HELPER_ABI,
|
|
@@ -2055,6 +2083,53 @@ server.tool(
|
|
|
2055
2083
|
args: [tokenAddr, 0n, bnbAmount]
|
|
2056
2084
|
});
|
|
2057
2085
|
const [, , estimatedAmount, , estimatedFee, amountMsgValue] = tryBuyResult;
|
|
2086
|
+
if (amountMsgValue < minTradingFee) {
|
|
2087
|
+
return {
|
|
2088
|
+
content: [{
|
|
2089
|
+
type: "text",
|
|
2090
|
+
text: JSON.stringify({
|
|
2091
|
+
status: "error",
|
|
2092
|
+
message: "Computed payable amount is below Four.meme minimum trading fee threshold.",
|
|
2093
|
+
next_step: "Increase amount and retry.",
|
|
2094
|
+
token: tokenAddr,
|
|
2095
|
+
payableWei: amountMsgValue.toString(),
|
|
2096
|
+
minTradingFeeWei: minTradingFee.toString(),
|
|
2097
|
+
minTradingFeeBnb: (Number(minTradingFee) / 1e18).toFixed(6)
|
|
2098
|
+
})
|
|
2099
|
+
}]
|
|
2100
|
+
};
|
|
2101
|
+
}
|
|
2102
|
+
if (estimatedAmount <= 0n || amountMsgValue <= 0n) {
|
|
2103
|
+
return {
|
|
2104
|
+
content: [{
|
|
2105
|
+
type: "text",
|
|
2106
|
+
text: JSON.stringify({
|
|
2107
|
+
status: "error",
|
|
2108
|
+
message: "four_buy quote returned zero output. Requested amount is likely too small for this market.",
|
|
2109
|
+
next_step: "Increase amount and retry.",
|
|
2110
|
+
token: tokenAddr
|
|
2111
|
+
})
|
|
2112
|
+
}]
|
|
2113
|
+
};
|
|
2114
|
+
}
|
|
2115
|
+
const vaultBnbBalance = await publicClient.getBalance({ address: vault });
|
|
2116
|
+
if (amountMsgValue > vaultBnbBalance) {
|
|
2117
|
+
return {
|
|
2118
|
+
content: [{
|
|
2119
|
+
type: "text",
|
|
2120
|
+
text: JSON.stringify({
|
|
2121
|
+
status: "error",
|
|
2122
|
+
message: "Vault BNB balance is insufficient for four_buy.",
|
|
2123
|
+
next_step: "Deposit more BNB to vault or reduce amount, then retry.",
|
|
2124
|
+
vault,
|
|
2125
|
+
requiredBnb: (Number(amountMsgValue) / 1e18).toFixed(6),
|
|
2126
|
+
availableBnb: (Number(vaultBnbBalance) / 1e18).toFixed(6),
|
|
2127
|
+
requiredWei: amountMsgValue.toString(),
|
|
2128
|
+
availableWei: vaultBnbBalance.toString()
|
|
2129
|
+
})
|
|
2130
|
+
}]
|
|
2131
|
+
};
|
|
2132
|
+
}
|
|
2058
2133
|
const minAmount = estimatedAmount * BigInt(100 - slippage) / 100n;
|
|
2059
2134
|
const alignedMinAmount = minAmount / 1000000000n * 1000000000n;
|
|
2060
2135
|
let data;
|
|
@@ -2066,7 +2141,23 @@ server.tool(
|
|
|
2066
2141
|
const action = { target: tokenManager, value: amountMsgValue, data };
|
|
2067
2142
|
const sim = await policyClient.validate(tokenId, action);
|
|
2068
2143
|
if (!sim.ok) return { content: [{ type: "text", text: JSON.stringify({ status: "rejected", reason: sim.reason, ...policyRejectionHelp(sim.reason, token_id) }) }] };
|
|
2069
|
-
|
|
2144
|
+
let result;
|
|
2145
|
+
try {
|
|
2146
|
+
result = await policyClient.execute(tokenId, action, true);
|
|
2147
|
+
} catch (error) {
|
|
2148
|
+
const message = error instanceof Error ? error.message : "Unknown execution revert";
|
|
2149
|
+
return {
|
|
2150
|
+
content: [{
|
|
2151
|
+
type: "text",
|
|
2152
|
+
text: JSON.stringify({
|
|
2153
|
+
status: "error",
|
|
2154
|
+
message: "four_buy execution reverted on-chain",
|
|
2155
|
+
reason: message,
|
|
2156
|
+
hint: "This is usually market-side failure (amount too small, temporary pool state change, or token-side constraint), not a PolicyGuard rejection."
|
|
2157
|
+
})
|
|
2158
|
+
}]
|
|
2159
|
+
};
|
|
2160
|
+
}
|
|
2070
2161
|
return {
|
|
2071
2162
|
content: [{
|
|
2072
2163
|
type: "text",
|
package/dist/mcp.mjs
CHANGED
|
@@ -1547,19 +1547,47 @@ server.tool(
|
|
|
1547
1547
|
if (expiryCheck.blocked) return { content: expiryCheck.content };
|
|
1548
1548
|
const tokenAddr = token;
|
|
1549
1549
|
const bnbAmount = parseAmount(amount, 18);
|
|
1550
|
+
if (bnbAmount <= 0n) {
|
|
1551
|
+
return {
|
|
1552
|
+
content: [{
|
|
1553
|
+
type: "text",
|
|
1554
|
+
text: JSON.stringify({
|
|
1555
|
+
status: "error",
|
|
1556
|
+
message: "Invalid amount. four_buy amount must be a positive BNB value."
|
|
1557
|
+
})
|
|
1558
|
+
}]
|
|
1559
|
+
};
|
|
1560
|
+
}
|
|
1561
|
+
const vault = await policyClient.getVault(tokenId);
|
|
1550
1562
|
const info = await publicClient.readContract({
|
|
1551
1563
|
address: FOUR_MEME_HELPER_V3,
|
|
1552
1564
|
abi: FOUR_MEME_HELPER_ABI,
|
|
1553
1565
|
functionName: "getTokenInfo",
|
|
1554
1566
|
args: [tokenAddr]
|
|
1555
1567
|
});
|
|
1556
|
-
const [version, tokenManager, quote, , , , , , , , , liquidityAdded] = info;
|
|
1568
|
+
const [version, tokenManager, quote, , , minTradingFee, , , , , , liquidityAdded] = info;
|
|
1557
1569
|
if (liquidityAdded) {
|
|
1558
1570
|
return { content: [{ type: "text", text: JSON.stringify({ status: "error", message: "Token has already migrated to DEX. Use the 'swap' tool instead." }) }] };
|
|
1559
1571
|
}
|
|
1560
1572
|
if (quote !== "0x0000000000000000000000000000000000000000") {
|
|
1561
1573
|
return { content: [{ type: "text", text: JSON.stringify({ status: "error", message: `Token uses BEP20 quote (${quote}), not BNB. BEP20 pairs not yet supported.` }) }] };
|
|
1562
1574
|
}
|
|
1575
|
+
if (bnbAmount < minTradingFee) {
|
|
1576
|
+
return {
|
|
1577
|
+
content: [{
|
|
1578
|
+
type: "text",
|
|
1579
|
+
text: JSON.stringify({
|
|
1580
|
+
status: "error",
|
|
1581
|
+
message: "Input amount is below Four.meme minimum trading fee threshold.",
|
|
1582
|
+
next_step: "Increase amount and retry.",
|
|
1583
|
+
token: tokenAddr,
|
|
1584
|
+
inputWei: bnbAmount.toString(),
|
|
1585
|
+
minTradingFeeWei: minTradingFee.toString(),
|
|
1586
|
+
minTradingFeeBnb: (Number(minTradingFee) / 1e18).toFixed(6)
|
|
1587
|
+
})
|
|
1588
|
+
}]
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1563
1591
|
const tryBuyResult = await publicClient.readContract({
|
|
1564
1592
|
address: FOUR_MEME_HELPER_V3,
|
|
1565
1593
|
abi: FOUR_MEME_HELPER_ABI,
|
|
@@ -1567,6 +1595,53 @@ server.tool(
|
|
|
1567
1595
|
args: [tokenAddr, 0n, bnbAmount]
|
|
1568
1596
|
});
|
|
1569
1597
|
const [, , estimatedAmount, , estimatedFee, amountMsgValue] = tryBuyResult;
|
|
1598
|
+
if (amountMsgValue < minTradingFee) {
|
|
1599
|
+
return {
|
|
1600
|
+
content: [{
|
|
1601
|
+
type: "text",
|
|
1602
|
+
text: JSON.stringify({
|
|
1603
|
+
status: "error",
|
|
1604
|
+
message: "Computed payable amount is below Four.meme minimum trading fee threshold.",
|
|
1605
|
+
next_step: "Increase amount and retry.",
|
|
1606
|
+
token: tokenAddr,
|
|
1607
|
+
payableWei: amountMsgValue.toString(),
|
|
1608
|
+
minTradingFeeWei: minTradingFee.toString(),
|
|
1609
|
+
minTradingFeeBnb: (Number(minTradingFee) / 1e18).toFixed(6)
|
|
1610
|
+
})
|
|
1611
|
+
}]
|
|
1612
|
+
};
|
|
1613
|
+
}
|
|
1614
|
+
if (estimatedAmount <= 0n || amountMsgValue <= 0n) {
|
|
1615
|
+
return {
|
|
1616
|
+
content: [{
|
|
1617
|
+
type: "text",
|
|
1618
|
+
text: JSON.stringify({
|
|
1619
|
+
status: "error",
|
|
1620
|
+
message: "four_buy quote returned zero output. Requested amount is likely too small for this market.",
|
|
1621
|
+
next_step: "Increase amount and retry.",
|
|
1622
|
+
token: tokenAddr
|
|
1623
|
+
})
|
|
1624
|
+
}]
|
|
1625
|
+
};
|
|
1626
|
+
}
|
|
1627
|
+
const vaultBnbBalance = await publicClient.getBalance({ address: vault });
|
|
1628
|
+
if (amountMsgValue > vaultBnbBalance) {
|
|
1629
|
+
return {
|
|
1630
|
+
content: [{
|
|
1631
|
+
type: "text",
|
|
1632
|
+
text: JSON.stringify({
|
|
1633
|
+
status: "error",
|
|
1634
|
+
message: "Vault BNB balance is insufficient for four_buy.",
|
|
1635
|
+
next_step: "Deposit more BNB to vault or reduce amount, then retry.",
|
|
1636
|
+
vault,
|
|
1637
|
+
requiredBnb: (Number(amountMsgValue) / 1e18).toFixed(6),
|
|
1638
|
+
availableBnb: (Number(vaultBnbBalance) / 1e18).toFixed(6),
|
|
1639
|
+
requiredWei: amountMsgValue.toString(),
|
|
1640
|
+
availableWei: vaultBnbBalance.toString()
|
|
1641
|
+
})
|
|
1642
|
+
}]
|
|
1643
|
+
};
|
|
1644
|
+
}
|
|
1570
1645
|
const minAmount = estimatedAmount * BigInt(100 - slippage) / 100n;
|
|
1571
1646
|
const alignedMinAmount = minAmount / 1000000000n * 1000000000n;
|
|
1572
1647
|
let data;
|
|
@@ -1578,7 +1653,23 @@ server.tool(
|
|
|
1578
1653
|
const action = { target: tokenManager, value: amountMsgValue, data };
|
|
1579
1654
|
const sim = await policyClient.validate(tokenId, action);
|
|
1580
1655
|
if (!sim.ok) return { content: [{ type: "text", text: JSON.stringify({ status: "rejected", reason: sim.reason, ...policyRejectionHelp(sim.reason, token_id) }) }] };
|
|
1581
|
-
|
|
1656
|
+
let result;
|
|
1657
|
+
try {
|
|
1658
|
+
result = await policyClient.execute(tokenId, action, true);
|
|
1659
|
+
} catch (error) {
|
|
1660
|
+
const message = error instanceof Error ? error.message : "Unknown execution revert";
|
|
1661
|
+
return {
|
|
1662
|
+
content: [{
|
|
1663
|
+
type: "text",
|
|
1664
|
+
text: JSON.stringify({
|
|
1665
|
+
status: "error",
|
|
1666
|
+
message: "four_buy execution reverted on-chain",
|
|
1667
|
+
reason: message,
|
|
1668
|
+
hint: "This is usually market-side failure (amount too small, temporary pool state change, or token-side constraint), not a PolicyGuard rejection."
|
|
1669
|
+
})
|
|
1670
|
+
}]
|
|
1671
|
+
};
|
|
1672
|
+
}
|
|
1582
1673
|
return {
|
|
1583
1674
|
content: [{
|
|
1584
1675
|
type: "text",
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -2746,18 +2746,22 @@ fourBuyCmd.action(async (opts) => {
|
|
|
2746
2746
|
const publicClient = createPublicClient({ chain: bsc, transport: http(rpcUrl) });
|
|
2747
2747
|
const vault = await client.getVault(tokenId);
|
|
2748
2748
|
|
|
2749
|
-
const tokenAddr = opts.token as Address;
|
|
2750
|
-
const slippage = Number(opts.slippage);
|
|
2751
|
-
const bnbAmount = parseAmount(opts.amount, 18);
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2749
|
+
const tokenAddr = opts.token as Address;
|
|
2750
|
+
const slippage = Number(opts.slippage);
|
|
2751
|
+
const bnbAmount = parseAmount(opts.amount, 18);
|
|
2752
|
+
if (bnbAmount <= 0n) {
|
|
2753
|
+
outputError("Invalid amount.", "four-buy amount must be a positive BNB value.");
|
|
2754
|
+
process.exit(1);
|
|
2755
|
+
}
|
|
2756
|
+
|
|
2757
|
+
// 1. Get token info to check status
|
|
2758
|
+
const info = await publicClient.readContract({
|
|
2759
|
+
address: FOUR_MEME_HELPER_V3,
|
|
2760
|
+
abi: FOUR_MEME_HELPER_ABI,
|
|
2757
2761
|
functionName: "getTokenInfo",
|
|
2758
2762
|
args: [tokenAddr],
|
|
2759
2763
|
});
|
|
2760
|
-
const [version, tokenManager, quote, , , , , , , , , liquidityAdded] = info;
|
|
2764
|
+
const [version, tokenManager, quote, , , minTradingFee, , , , , , liquidityAdded] = info;
|
|
2761
2765
|
|
|
2762
2766
|
if (liquidityAdded) {
|
|
2763
2767
|
output({ status: "error", message: "Token has already migrated to DEX. Use the 'swap' command instead of 'four-buy'." });
|
|
@@ -2765,19 +2769,75 @@ fourBuyCmd.action(async (opts) => {
|
|
|
2765
2769
|
}
|
|
2766
2770
|
|
|
2767
2771
|
const isQuoteBNB = quote === "0x0000000000000000000000000000000000000000";
|
|
2768
|
-
if (!isQuoteBNB) {
|
|
2769
|
-
output({ status: "error", message: `Token uses BEP20 quote (${quote}), not BNB. BEP20 quote pairs are not yet supported in this tool.` });
|
|
2770
|
-
process.exit(1);
|
|
2771
|
-
}
|
|
2772
|
+
if (!isQuoteBNB) {
|
|
2773
|
+
output({ status: "error", message: `Token uses BEP20 quote (${quote}), not BNB. BEP20 quote pairs are not yet supported in this tool.` });
|
|
2774
|
+
process.exit(1);
|
|
2775
|
+
}
|
|
2776
|
+
if (bnbAmount < minTradingFee) {
|
|
2777
|
+
outputError(
|
|
2778
|
+
"Input amount is below Four.meme minimum trading fee threshold.",
|
|
2779
|
+
"Increase --amount and retry.",
|
|
2780
|
+
{
|
|
2781
|
+
token: tokenAddr,
|
|
2782
|
+
inputBnb: opts.amount,
|
|
2783
|
+
inputWei: bnbAmount.toString(),
|
|
2784
|
+
minTradingFeeWei: minTradingFee.toString(),
|
|
2785
|
+
minTradingFeeBnb: (Number(minTradingFee) / 1e18).toFixed(6),
|
|
2786
|
+
},
|
|
2787
|
+
);
|
|
2788
|
+
process.exit(1);
|
|
2789
|
+
}
|
|
2772
2790
|
|
|
2773
2791
|
// 2. Pre-calculate buy estimate
|
|
2774
|
-
const tryBuyResult = await publicClient.readContract({
|
|
2775
|
-
address: FOUR_MEME_HELPER_V3,
|
|
2776
|
-
abi: FOUR_MEME_HELPER_ABI,
|
|
2777
|
-
functionName: "tryBuy",
|
|
2778
|
-
args: [tokenAddr, 0n, bnbAmount],
|
|
2779
|
-
});
|
|
2780
|
-
const [, , estimatedAmount, estimatedCost, estimatedFee, amountMsgValue] = tryBuyResult;
|
|
2792
|
+
const tryBuyResult = await publicClient.readContract({
|
|
2793
|
+
address: FOUR_MEME_HELPER_V3,
|
|
2794
|
+
abi: FOUR_MEME_HELPER_ABI,
|
|
2795
|
+
functionName: "tryBuy",
|
|
2796
|
+
args: [tokenAddr, 0n, bnbAmount],
|
|
2797
|
+
});
|
|
2798
|
+
const [, , estimatedAmount, estimatedCost, estimatedFee, amountMsgValue] = tryBuyResult;
|
|
2799
|
+
if (amountMsgValue < minTradingFee) {
|
|
2800
|
+
outputError(
|
|
2801
|
+
"Computed payable amount is below Four.meme minimum trading fee threshold.",
|
|
2802
|
+
"Increase --amount and retry.",
|
|
2803
|
+
{
|
|
2804
|
+
token: tokenAddr,
|
|
2805
|
+
inputBnb: opts.amount,
|
|
2806
|
+
payableWei: amountMsgValue.toString(),
|
|
2807
|
+
minTradingFeeWei: minTradingFee.toString(),
|
|
2808
|
+
minTradingFeeBnb: (Number(minTradingFee) / 1e18).toFixed(6),
|
|
2809
|
+
},
|
|
2810
|
+
);
|
|
2811
|
+
process.exit(1);
|
|
2812
|
+
}
|
|
2813
|
+
if (estimatedAmount <= 0n || amountMsgValue <= 0n) {
|
|
2814
|
+
outputError(
|
|
2815
|
+
"four-buy quote returned zero output.",
|
|
2816
|
+
"Requested amount is likely too small for this market. Increase --amount and retry.",
|
|
2817
|
+
{
|
|
2818
|
+
token: tokenAddr,
|
|
2819
|
+
inputBnb: opts.amount,
|
|
2820
|
+
estimatedCostWei: estimatedCost.toString(),
|
|
2821
|
+
estimatedFeeWei: estimatedFee.toString(),
|
|
2822
|
+
},
|
|
2823
|
+
);
|
|
2824
|
+
process.exit(1);
|
|
2825
|
+
}
|
|
2826
|
+
const vaultBnbBalance = await publicClient.getBalance({ address: vault });
|
|
2827
|
+
if (amountMsgValue > vaultBnbBalance) {
|
|
2828
|
+
outputError(
|
|
2829
|
+
"Vault BNB balance is insufficient for four-buy.",
|
|
2830
|
+
"Deposit more BNB to vault or reduce --amount, then retry.",
|
|
2831
|
+
{
|
|
2832
|
+
vault,
|
|
2833
|
+
requiredBnb: (Number(amountMsgValue) / 1e18).toFixed(6),
|
|
2834
|
+
availableBnb: (Number(vaultBnbBalance) / 1e18).toFixed(6),
|
|
2835
|
+
requiredWei: amountMsgValue.toString(),
|
|
2836
|
+
availableWei: vaultBnbBalance.toString(),
|
|
2837
|
+
},
|
|
2838
|
+
);
|
|
2839
|
+
process.exit(1);
|
|
2840
|
+
}
|
|
2781
2841
|
|
|
2782
2842
|
// Align to GWEI precision (Four.meme requirement)
|
|
2783
2843
|
const minAmount = (estimatedAmount * BigInt(100 - slippage)) / 100n;
|
|
@@ -2818,11 +2878,23 @@ fourBuyCmd.action(async (opts) => {
|
|
|
2818
2878
|
process.exit(0);
|
|
2819
2879
|
}
|
|
2820
2880
|
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2881
|
+
let result: { hash: Hex };
|
|
2882
|
+
try {
|
|
2883
|
+
result = await client.execute(tokenId, action, true);
|
|
2884
|
+
} catch (error: unknown) {
|
|
2885
|
+
const message = error instanceof Error ? error.message : "Unknown execution revert";
|
|
2886
|
+
outputError(
|
|
2887
|
+
"four-buy execution reverted on-chain.",
|
|
2888
|
+
"Likely market-side failure (amount too small, temporary pool state change, or token-side constraint).",
|
|
2889
|
+
{ reason: message, token: tokenAddr, inputBnb: opts.amount },
|
|
2890
|
+
);
|
|
2891
|
+
process.exit(1);
|
|
2892
|
+
return;
|
|
2893
|
+
}
|
|
2894
|
+
output({
|
|
2895
|
+
status: "success",
|
|
2896
|
+
hash: result.hash,
|
|
2897
|
+
protocol: "four.meme",
|
|
2826
2898
|
action: "buy",
|
|
2827
2899
|
bnbSpent: opts.amount,
|
|
2828
2900
|
estimatedTokens: (Number(estimatedAmount) / 1e18).toFixed(4),
|
package/src/mcp.ts
CHANGED
|
@@ -1730,39 +1730,109 @@ server.tool(
|
|
|
1730
1730
|
amount: z.string().describe("BNB amount to spend (human-readable, e.g. 0.01)"),
|
|
1731
1731
|
slippage: z.number().default(10).describe("Slippage tolerance percent (default: 10, meme tokens are volatile)"),
|
|
1732
1732
|
},
|
|
1733
|
-
async ({ token_id, token, amount, slippage }) => {
|
|
1734
|
-
const { publicClient, policyClient } = createClients();
|
|
1735
|
-
const tokenId = BigInt(token_id);
|
|
1736
|
-
const expiryCheck = await checkAgentExpiry(tokenId);
|
|
1737
|
-
if (expiryCheck.blocked) return { content: expiryCheck.content! };
|
|
1738
|
-
|
|
1739
|
-
const tokenAddr = token as Address;
|
|
1740
|
-
const bnbAmount = parseAmount(amount, 18);
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1733
|
+
async ({ token_id, token, amount, slippage }) => {
|
|
1734
|
+
const { publicClient, policyClient } = createClients();
|
|
1735
|
+
const tokenId = BigInt(token_id);
|
|
1736
|
+
const expiryCheck = await checkAgentExpiry(tokenId);
|
|
1737
|
+
if (expiryCheck.blocked) return { content: expiryCheck.content! };
|
|
1738
|
+
|
|
1739
|
+
const tokenAddr = token as Address;
|
|
1740
|
+
const bnbAmount = parseAmount(amount, 18);
|
|
1741
|
+
if (bnbAmount <= 0n) {
|
|
1742
|
+
return {
|
|
1743
|
+
content: [{
|
|
1744
|
+
type: "text" as const, text: JSON.stringify({
|
|
1745
|
+
status: "error",
|
|
1746
|
+
message: "Invalid amount. four_buy amount must be a positive BNB value.",
|
|
1747
|
+
})
|
|
1748
|
+
}],
|
|
1749
|
+
};
|
|
1750
|
+
}
|
|
1751
|
+
const vault = await policyClient.getVault(tokenId);
|
|
1752
|
+
|
|
1753
|
+
// 1. Get token info
|
|
1754
|
+
const info = await publicClient.readContract({
|
|
1755
|
+
address: FOUR_MEME_HELPER_V3,
|
|
1756
|
+
abi: FOUR_MEME_HELPER_ABI,
|
|
1746
1757
|
functionName: "getTokenInfo",
|
|
1747
1758
|
args: [tokenAddr],
|
|
1748
1759
|
});
|
|
1749
|
-
const [version, tokenManager, quote, , , , , , , , , liquidityAdded] = info;
|
|
1760
|
+
const [version, tokenManager, quote, , , minTradingFee, , , , , , liquidityAdded] = info;
|
|
1750
1761
|
|
|
1751
1762
|
if (liquidityAdded) {
|
|
1752
1763
|
return { content: [{ type: "text" as const, text: JSON.stringify({ status: "error", message: "Token has already migrated to DEX. Use the 'swap' tool instead." }) }] };
|
|
1753
1764
|
}
|
|
1754
|
-
if (quote !== "0x0000000000000000000000000000000000000000") {
|
|
1755
|
-
return { content: [{ type: "text" as const, text: JSON.stringify({ status: "error", message: `Token uses BEP20 quote (${quote}), not BNB. BEP20 pairs not yet supported.` }) }] };
|
|
1756
|
-
}
|
|
1765
|
+
if (quote !== "0x0000000000000000000000000000000000000000") {
|
|
1766
|
+
return { content: [{ type: "text" as const, text: JSON.stringify({ status: "error", message: `Token uses BEP20 quote (${quote}), not BNB. BEP20 pairs not yet supported.` }) }] };
|
|
1767
|
+
}
|
|
1768
|
+
if (bnbAmount < minTradingFee) {
|
|
1769
|
+
return {
|
|
1770
|
+
content: [{
|
|
1771
|
+
type: "text" as const, text: JSON.stringify({
|
|
1772
|
+
status: "error",
|
|
1773
|
+
message: "Input amount is below Four.meme minimum trading fee threshold.",
|
|
1774
|
+
next_step: "Increase amount and retry.",
|
|
1775
|
+
token: tokenAddr,
|
|
1776
|
+
inputWei: bnbAmount.toString(),
|
|
1777
|
+
minTradingFeeWei: minTradingFee.toString(),
|
|
1778
|
+
minTradingFeeBnb: (Number(minTradingFee) / 1e18).toFixed(6),
|
|
1779
|
+
})
|
|
1780
|
+
}],
|
|
1781
|
+
};
|
|
1782
|
+
}
|
|
1757
1783
|
|
|
1758
1784
|
// 2. Pre-calculate
|
|
1759
|
-
const tryBuyResult = await publicClient.readContract({
|
|
1760
|
-
address: FOUR_MEME_HELPER_V3,
|
|
1761
|
-
abi: FOUR_MEME_HELPER_ABI,
|
|
1762
|
-
functionName: "tryBuy",
|
|
1763
|
-
args: [tokenAddr, 0n, bnbAmount],
|
|
1764
|
-
});
|
|
1765
|
-
const [, , estimatedAmount, , estimatedFee, amountMsgValue] = tryBuyResult;
|
|
1785
|
+
const tryBuyResult = await publicClient.readContract({
|
|
1786
|
+
address: FOUR_MEME_HELPER_V3,
|
|
1787
|
+
abi: FOUR_MEME_HELPER_ABI,
|
|
1788
|
+
functionName: "tryBuy",
|
|
1789
|
+
args: [tokenAddr, 0n, bnbAmount],
|
|
1790
|
+
});
|
|
1791
|
+
const [, , estimatedAmount, , estimatedFee, amountMsgValue] = tryBuyResult;
|
|
1792
|
+
if (amountMsgValue < minTradingFee) {
|
|
1793
|
+
return {
|
|
1794
|
+
content: [{
|
|
1795
|
+
type: "text" as const, text: JSON.stringify({
|
|
1796
|
+
status: "error",
|
|
1797
|
+
message: "Computed payable amount is below Four.meme minimum trading fee threshold.",
|
|
1798
|
+
next_step: "Increase amount and retry.",
|
|
1799
|
+
token: tokenAddr,
|
|
1800
|
+
payableWei: amountMsgValue.toString(),
|
|
1801
|
+
minTradingFeeWei: minTradingFee.toString(),
|
|
1802
|
+
minTradingFeeBnb: (Number(minTradingFee) / 1e18).toFixed(6),
|
|
1803
|
+
})
|
|
1804
|
+
}],
|
|
1805
|
+
};
|
|
1806
|
+
}
|
|
1807
|
+
if (estimatedAmount <= 0n || amountMsgValue <= 0n) {
|
|
1808
|
+
return {
|
|
1809
|
+
content: [{
|
|
1810
|
+
type: "text" as const, text: JSON.stringify({
|
|
1811
|
+
status: "error",
|
|
1812
|
+
message: "four_buy quote returned zero output. Requested amount is likely too small for this market.",
|
|
1813
|
+
next_step: "Increase amount and retry.",
|
|
1814
|
+
token: tokenAddr,
|
|
1815
|
+
})
|
|
1816
|
+
}],
|
|
1817
|
+
};
|
|
1818
|
+
}
|
|
1819
|
+
const vaultBnbBalance = await publicClient.getBalance({ address: vault });
|
|
1820
|
+
if (amountMsgValue > vaultBnbBalance) {
|
|
1821
|
+
return {
|
|
1822
|
+
content: [{
|
|
1823
|
+
type: "text" as const, text: JSON.stringify({
|
|
1824
|
+
status: "error",
|
|
1825
|
+
message: "Vault BNB balance is insufficient for four_buy.",
|
|
1826
|
+
next_step: "Deposit more BNB to vault or reduce amount, then retry.",
|
|
1827
|
+
vault,
|
|
1828
|
+
requiredBnb: (Number(amountMsgValue) / 1e18).toFixed(6),
|
|
1829
|
+
availableBnb: (Number(vaultBnbBalance) / 1e18).toFixed(6),
|
|
1830
|
+
requiredWei: amountMsgValue.toString(),
|
|
1831
|
+
availableWei: vaultBnbBalance.toString(),
|
|
1832
|
+
})
|
|
1833
|
+
}],
|
|
1834
|
+
};
|
|
1835
|
+
}
|
|
1766
1836
|
|
|
1767
1837
|
// Align to GWEI precision (Four.meme requirement)
|
|
1768
1838
|
const minAmount = (estimatedAmount * BigInt(100 - slippage)) / 100n;
|
|
@@ -1781,11 +1851,26 @@ server.tool(
|
|
|
1781
1851
|
const sim = await policyClient.validate(tokenId, action);
|
|
1782
1852
|
if (!sim.ok) return { content: [{ type: "text" as const, text: JSON.stringify({ status: "rejected", reason: sim.reason, ...policyRejectionHelp(sim.reason, token_id) }) }] };
|
|
1783
1853
|
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1854
|
+
let result: { hash: Hex };
|
|
1855
|
+
try {
|
|
1856
|
+
result = await policyClient.execute(tokenId, action, true);
|
|
1857
|
+
} catch (error: unknown) {
|
|
1858
|
+
const message = error instanceof Error ? error.message : "Unknown execution revert";
|
|
1859
|
+
return {
|
|
1860
|
+
content: [{
|
|
1861
|
+
type: "text" as const, text: JSON.stringify({
|
|
1862
|
+
status: "error",
|
|
1863
|
+
message: "four_buy execution reverted on-chain",
|
|
1864
|
+
reason: message,
|
|
1865
|
+
hint: "This is usually market-side failure (amount too small, temporary pool state change, or token-side constraint), not a PolicyGuard rejection.",
|
|
1866
|
+
})
|
|
1867
|
+
}],
|
|
1868
|
+
};
|
|
1869
|
+
}
|
|
1870
|
+
return {
|
|
1871
|
+
content: [{
|
|
1872
|
+
type: "text" as const, text: JSON.stringify({
|
|
1873
|
+
status: "success", hash: result.hash, protocol: "four.meme", action: "buy",
|
|
1789
1874
|
bnbSpent: amount,
|
|
1790
1875
|
estimatedTokens: (Number(estimatedAmount) / 1e18).toFixed(4),
|
|
1791
1876
|
fee: (Number(estimatedFee) / 1e18).toFixed(6),
|