shll-skills 5.2.0 → 5.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/mcp.js CHANGED
@@ -996,17 +996,14 @@ server.tool(
996
996
  return { content: [{ type: "text", text: JSON.stringify({ status: "success", hash: result.hash, token, amount, to: recipient }) }] };
997
997
  }
998
998
  );
999
- var OPERATOR_OF_ABI = [{
1000
- type: "function",
1001
- name: "operatorOf",
1002
- inputs: [{ name: "tokenId", type: "uint256" }],
1003
- outputs: [{ name: "", type: "address" }],
1004
- stateMutability: "view"
1005
- }];
999
+ var MY_AGENTS_ABI = [
1000
+ { type: "function", name: "operatorOf", inputs: [{ name: "tokenId", type: "uint256" }], outputs: [{ name: "", type: "address" }], stateMutability: "view" },
1001
+ { type: "function", name: "operatorExpiresOf", inputs: [{ name: "tokenId", type: "uint256" }], outputs: [{ name: "", type: "uint256" }], stateMutability: "view" }
1002
+ ];
1006
1003
  var DEFAULT_INDEXER = "https://indexer-mainnet.shll.run";
1007
1004
  server.tool(
1008
1005
  "my_agents",
1009
- "List all agents where the current operator key is authorized. Returns token IDs, vault addresses, and agent types. Call this first if the user does not specify a token ID.",
1006
+ "List all agents where the current operator key is or was authorized. Returns active agents and expired agents that need renewal.",
1010
1007
  {},
1011
1008
  async () => {
1012
1009
  const { account, publicClient, config } = createClients();
@@ -1023,18 +1020,34 @@ server.tool(
1023
1020
  agents.map(async (a) => {
1024
1021
  const tokenId = BigInt(a.tokenId);
1025
1022
  try {
1026
- const op = await publicClient.readContract({
1027
- address: nfaAddr,
1028
- abi: OPERATOR_OF_ABI,
1029
- functionName: "operatorOf",
1030
- args: [tokenId]
1031
- });
1032
- return op.toLowerCase() === operator ? {
1033
- tokenId: tokenId.toString(),
1034
- vault: a.account || "",
1035
- owner: a.owner || "",
1036
- agentType: a.agentType || "unknown"
1037
- } : null;
1023
+ const [op, opExpires] = await Promise.all([
1024
+ publicClient.readContract({ address: nfaAddr, abi: MY_AGENTS_ABI, functionName: "operatorOf", args: [tokenId] }),
1025
+ publicClient.readContract({ address: nfaAddr, abi: MY_AGENTS_ABI, functionName: "operatorExpiresOf", args: [tokenId] })
1026
+ ]);
1027
+ const isActive = op.toLowerCase() === operator;
1028
+ const now = BigInt(Math.floor(Date.now() / 1e3));
1029
+ const isExpired = !isActive && Number(opExpires) > 0 && now > opExpires;
1030
+ if (isActive) {
1031
+ return {
1032
+ tokenId: tokenId.toString(),
1033
+ vault: a.account || "",
1034
+ owner: a.owner || "",
1035
+ agentType: a.agentType || "unknown",
1036
+ status: "active",
1037
+ operatorExpires: new Date(Number(opExpires) * 1e3).toISOString()
1038
+ };
1039
+ } else if (isExpired) {
1040
+ return {
1041
+ tokenId: tokenId.toString(),
1042
+ vault: a.account || "",
1043
+ owner: a.owner || "",
1044
+ agentType: a.agentType || "unknown",
1045
+ status: "expired",
1046
+ operatorExpires: new Date(Number(opExpires) * 1e3).toISOString(),
1047
+ note: "Operator authorization expired. Renew at https://shll.run/me"
1048
+ };
1049
+ }
1050
+ return null;
1038
1051
  } catch {
1039
1052
  return null;
1040
1053
  }
package/dist/mcp.mjs CHANGED
@@ -507,17 +507,14 @@ server.tool(
507
507
  return { content: [{ type: "text", text: JSON.stringify({ status: "success", hash: result.hash, token, amount, to: recipient }) }] };
508
508
  }
509
509
  );
510
- var OPERATOR_OF_ABI = [{
511
- type: "function",
512
- name: "operatorOf",
513
- inputs: [{ name: "tokenId", type: "uint256" }],
514
- outputs: [{ name: "", type: "address" }],
515
- stateMutability: "view"
516
- }];
510
+ var MY_AGENTS_ABI = [
511
+ { type: "function", name: "operatorOf", inputs: [{ name: "tokenId", type: "uint256" }], outputs: [{ name: "", type: "address" }], stateMutability: "view" },
512
+ { type: "function", name: "operatorExpiresOf", inputs: [{ name: "tokenId", type: "uint256" }], outputs: [{ name: "", type: "uint256" }], stateMutability: "view" }
513
+ ];
517
514
  var DEFAULT_INDEXER = "https://indexer-mainnet.shll.run";
518
515
  server.tool(
519
516
  "my_agents",
520
- "List all agents where the current operator key is authorized. Returns token IDs, vault addresses, and agent types. Call this first if the user does not specify a token ID.",
517
+ "List all agents where the current operator key is or was authorized. Returns active agents and expired agents that need renewal.",
521
518
  {},
522
519
  async () => {
523
520
  const { account, publicClient, config } = createClients();
@@ -534,18 +531,34 @@ server.tool(
534
531
  agents.map(async (a) => {
535
532
  const tokenId = BigInt(a.tokenId);
536
533
  try {
537
- const op = await publicClient.readContract({
538
- address: nfaAddr,
539
- abi: OPERATOR_OF_ABI,
540
- functionName: "operatorOf",
541
- args: [tokenId]
542
- });
543
- return op.toLowerCase() === operator ? {
544
- tokenId: tokenId.toString(),
545
- vault: a.account || "",
546
- owner: a.owner || "",
547
- agentType: a.agentType || "unknown"
548
- } : null;
534
+ const [op, opExpires] = await Promise.all([
535
+ publicClient.readContract({ address: nfaAddr, abi: MY_AGENTS_ABI, functionName: "operatorOf", args: [tokenId] }),
536
+ publicClient.readContract({ address: nfaAddr, abi: MY_AGENTS_ABI, functionName: "operatorExpiresOf", args: [tokenId] })
537
+ ]);
538
+ const isActive = op.toLowerCase() === operator;
539
+ const now = BigInt(Math.floor(Date.now() / 1e3));
540
+ const isExpired = !isActive && Number(opExpires) > 0 && now > opExpires;
541
+ if (isActive) {
542
+ return {
543
+ tokenId: tokenId.toString(),
544
+ vault: a.account || "",
545
+ owner: a.owner || "",
546
+ agentType: a.agentType || "unknown",
547
+ status: "active",
548
+ operatorExpires: new Date(Number(opExpires) * 1e3).toISOString()
549
+ };
550
+ } else if (isExpired) {
551
+ return {
552
+ tokenId: tokenId.toString(),
553
+ vault: a.account || "",
554
+ owner: a.owner || "",
555
+ agentType: a.agentType || "unknown",
556
+ status: "expired",
557
+ operatorExpires: new Date(Number(opExpires) * 1e3).toISOString(),
558
+ note: "Operator authorization expired. Renew at https://shll.run/me"
559
+ };
560
+ }
561
+ return null;
549
562
  } catch {
550
563
  return null;
551
564
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shll-skills",
3
- "version": "5.2.0",
3
+ "version": "5.2.1",
4
4
  "description": "SHLL DeFi Agent — CLI + MCP Server for BSC",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
package/src/mcp.ts CHANGED
@@ -349,7 +349,7 @@ server.tool(
349
349
  async ({ token_id, from, to, amount, dex, slippage }) => {
350
350
  const { publicClient, policyClient } = createClients();
351
351
  const tokenId = BigInt(token_id);
352
- const expiryCheck = await checkAgentExpiry(tokenId); if (expiryCheck.expired) return { content: expiryCheck.content! };
352
+ const expiryCheck = await checkAgentExpiry(tokenId); if (expiryCheck.expired) return { content: expiryCheck.content! };
353
353
  const vault = await policyClient.getVault(tokenId);
354
354
 
355
355
  const fromToken = resolveToken(from);
@@ -454,7 +454,7 @@ server.tool(
454
454
  async ({ token_id, token, amount }) => {
455
455
  const { publicClient, policyClient } = createClients();
456
456
  const tokenId = BigInt(token_id);
457
- const expiryCheck = await checkAgentExpiry(tokenId); if (expiryCheck.expired) return { content: expiryCheck.content! };
457
+ const expiryCheck = await checkAgentExpiry(tokenId); if (expiryCheck.expired) return { content: expiryCheck.content! };
458
458
  const symbol = token.toUpperCase();
459
459
  const vTokenAddr = VENUS_VTOKENS[symbol];
460
460
  if (!vTokenAddr) return { content: [{ type: "text" as const, text: JSON.stringify({ error: `Unsupported: ${symbol}. Use: ${Object.keys(VENUS_VTOKENS).join(", ")}` }) }] };
@@ -500,7 +500,7 @@ server.tool(
500
500
  async ({ token_id, token, amount }) => {
501
501
  const { policyClient } = createClients();
502
502
  const tokenId = BigInt(token_id);
503
- const expiryCheck = await checkAgentExpiry(tokenId); if (expiryCheck.expired) return { content: expiryCheck.content! };
503
+ const expiryCheck = await checkAgentExpiry(tokenId); if (expiryCheck.expired) return { content: expiryCheck.content! };
504
504
  const symbol = token.toUpperCase();
505
505
  const vTokenAddr = VENUS_VTOKENS[symbol];
506
506
  if (!vTokenAddr) return { content: [{ type: "text" as const, text: JSON.stringify({ error: `Unsupported: ${symbol}` }) }] };
@@ -565,7 +565,7 @@ server.tool(
565
565
  async ({ token_id, token, amount, to }) => {
566
566
  const { policyClient } = createClients();
567
567
  const tokenId = BigInt(token_id);
568
- const expiryCheck = await checkAgentExpiry(tokenId); if (expiryCheck.expired) return { content: expiryCheck.content! };
568
+ const expiryCheck = await checkAgentExpiry(tokenId); if (expiryCheck.expired) return { content: expiryCheck.content! };
569
569
  const tokenInfo = resolveToken(token);
570
570
  const amt = parseAmount(amount, tokenInfo.decimals);
571
571
  const recipient = to as Address;
@@ -593,18 +593,16 @@ server.tool(
593
593
  );
594
594
 
595
595
  // ── Tool: my_agents ─────────────────────────────────────
596
- const OPERATOR_OF_ABI = [{
597
- type: "function" as const, name: "operatorOf",
598
- inputs: [{ name: "tokenId", type: "uint256" }],
599
- outputs: [{ name: "", type: "address" }],
600
- stateMutability: "view" as const,
601
- }] as const;
596
+ const MY_AGENTS_ABI = [
597
+ { type: "function" as const, name: "operatorOf", inputs: [{ name: "tokenId", type: "uint256" }], outputs: [{ name: "", type: "address" }], stateMutability: "view" as const },
598
+ { type: "function" as const, name: "operatorExpiresOf", inputs: [{ name: "tokenId", type: "uint256" }], outputs: [{ name: "", type: "uint256" }], stateMutability: "view" as const },
599
+ ] as const;
602
600
 
603
601
  const DEFAULT_INDEXER = "https://indexer-mainnet.shll.run";
604
602
 
605
603
  server.tool(
606
604
  "my_agents",
607
- "List all agents where the current operator key is authorized. Returns token IDs, vault addresses, and agent types. Call this first if the user does not specify a token ID.",
605
+ "List all agents where the current operator key is or was authorized. Returns active agents and expired agents that need renewal.",
608
606
  {},
609
607
  async () => {
610
608
  const { account, publicClient, config } = createClients();
@@ -621,23 +619,34 @@ server.tool(
621
619
  return { content: [{ type: "text" as const, text: JSON.stringify({ operator, agents: [], count: 0 }) }] };
622
620
  }
623
621
 
624
- // 2. Batch check operatorOf for all agents
622
+ // 2. Check operatorOf AND operatorExpiresOf for all agents
625
623
  const checks = await Promise.all(
626
624
  agents.map(async (a) => {
627
625
  const tokenId = BigInt(a.tokenId!);
628
626
  try {
629
- const op = await publicClient.readContract({
630
- address: nfaAddr,
631
- abi: OPERATOR_OF_ABI,
632
- functionName: "operatorOf",
633
- args: [tokenId],
634
- });
635
- return (op as string).toLowerCase() === operator ? {
636
- tokenId: tokenId.toString(),
637
- vault: a.account || "",
638
- owner: a.owner || "",
639
- agentType: a.agentType || "unknown",
640
- } : null;
627
+ const [op, opExpires] = await Promise.all([
628
+ publicClient.readContract({ address: nfaAddr, abi: MY_AGENTS_ABI, functionName: "operatorOf", args: [tokenId] }) as Promise<string>,
629
+ publicClient.readContract({ address: nfaAddr, abi: MY_AGENTS_ABI, functionName: "operatorExpiresOf", args: [tokenId] }) as Promise<bigint>,
630
+ ]);
631
+ const isActive = op.toLowerCase() === operator;
632
+ const now = BigInt(Math.floor(Date.now() / 1000));
633
+ const isExpired = !isActive && Number(opExpires) > 0 && now > opExpires;
634
+
635
+ if (isActive) {
636
+ return {
637
+ tokenId: tokenId.toString(), vault: a.account || "", owner: a.owner || "",
638
+ agentType: a.agentType || "unknown", status: "active" as const,
639
+ operatorExpires: new Date(Number(opExpires) * 1000).toISOString(),
640
+ };
641
+ } else if (isExpired) {
642
+ return {
643
+ tokenId: tokenId.toString(), vault: a.account || "", owner: a.owner || "",
644
+ agentType: a.agentType || "unknown", status: "expired" as const,
645
+ operatorExpires: new Date(Number(opExpires) * 1000).toISOString(),
646
+ note: "Operator authorization expired. Renew at https://shll.run/me",
647
+ };
648
+ }
649
+ return null;
641
650
  } catch { return null; }
642
651
  })
643
652
  );
@@ -663,7 +672,7 @@ server.tool(
663
672
  async ({ token_id, amount }) => {
664
673
  const { policyClient } = createClients();
665
674
  const tokenId = BigInt(token_id);
666
- const expiryCheck = await checkAgentExpiry(tokenId); if (expiryCheck.expired) return { content: expiryCheck.content! };
675
+ const expiryCheck = await checkAgentExpiry(tokenId); if (expiryCheck.expired) return { content: expiryCheck.content! };
667
676
  const amt = parseEther(amount);
668
677
  const data = encodeFunctionData({ abi: WBNB_ABI, functionName: "deposit" });
669
678
  const action: Action = { target: WBNB as Address, value: amt, data };
@@ -687,7 +696,7 @@ server.tool(
687
696
  async ({ token_id, amount }) => {
688
697
  const { policyClient } = createClients();
689
698
  const tokenId = BigInt(token_id);
690
- const expiryCheck = await checkAgentExpiry(tokenId); if (expiryCheck.expired) return { content: expiryCheck.content! };
699
+ const expiryCheck = await checkAgentExpiry(tokenId); if (expiryCheck.expired) return { content: expiryCheck.content! };
691
700
  const amt = parseEther(amount);
692
701
  const data = encodeFunctionData({ abi: WBNB_ABI, functionName: "withdraw", args: [amt] });
693
702
  const action: Action = { target: WBNB as Address, value: 0n, data };
@@ -911,7 +920,7 @@ server.tool(
911
920
 
912
921
  const { account, publicClient, policyClient, config } = createClients();
913
922
  const tokenId = BigInt(token_id);
914
- const expiryCheck = await checkAgentExpiry(tokenId); if (expiryCheck.expired) return { content: expiryCheck.content! };
923
+ const expiryCheck = await checkAgentExpiry(tokenId); if (expiryCheck.expired) return { content: expiryCheck.content! };
915
924
  const walletClient = createWalletClient({ account, chain: bsc, transport: http(config.rpc) });
916
925
  const policies = await policyClient.getPolicies(tokenId);
917
926
  const results: string[] = [];
@@ -1033,7 +1042,7 @@ server.tool(
1033
1042
  async ({ token_id, target, data, value }) => {
1034
1043
  const { policyClient } = createClients();
1035
1044
  const tokenId = BigInt(token_id);
1036
- const expiryCheck = await checkAgentExpiry(tokenId); if (expiryCheck.expired) return { content: expiryCheck.content! };
1045
+ const expiryCheck = await checkAgentExpiry(tokenId); if (expiryCheck.expired) return { content: expiryCheck.content! };
1037
1046
  const action: Action = {
1038
1047
  target: target as Address,
1039
1048
  value: BigInt(value),
@@ -1082,7 +1091,7 @@ server.tool(
1082
1091
  async ({ token_id, actions: rawActions }) => {
1083
1092
  const { policyClient } = createClients();
1084
1093
  const tokenId = BigInt(token_id);
1085
- const expiryCheck = await checkAgentExpiry(tokenId); if (expiryCheck.expired) return { content: expiryCheck.content! };
1094
+ const expiryCheck = await checkAgentExpiry(tokenId); if (expiryCheck.expired) return { content: expiryCheck.content! };
1086
1095
  const actions: Action[] = rawActions.map(a => ({
1087
1096
  target: a.target as Address,
1088
1097
  value: BigInt(a.value || "0"),