basileus-agentkit-plugin 0.1.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 (69) hide show
  1. package/.nvmrc +1 -0
  2. package/.prettierrc +7 -0
  3. package/dist/actions/aleph.d.ts +2 -0
  4. package/dist/actions/aleph.js +114 -0
  5. package/dist/actions/aleph.js.map +1 -0
  6. package/dist/actions/compound/compoundActionProvider.d.ts +2 -0
  7. package/dist/actions/compound/compoundActionProvider.js +130 -0
  8. package/dist/actions/compound/compoundActionProvider.js.map +1 -0
  9. package/dist/actions/compound/constants.d.ts +194 -0
  10. package/dist/actions/compound/constants.js +134 -0
  11. package/dist/actions/compound/constants.js.map +1 -0
  12. package/dist/actions/compound/index.d.ts +1 -0
  13. package/dist/actions/compound/index.js +2 -0
  14. package/dist/actions/compound/index.js.map +1 -0
  15. package/dist/actions/compound/schemas.d.ts +42 -0
  16. package/dist/actions/compound/schemas.js +41 -0
  17. package/dist/actions/compound/schemas.js.map +1 -0
  18. package/dist/actions/compound/utils.d.ts +15 -0
  19. package/dist/actions/compound/utils.js +260 -0
  20. package/dist/actions/compound/utils.js.map +1 -0
  21. package/dist/actions/constants.d.ts +69 -0
  22. package/dist/actions/constants.js +50 -0
  23. package/dist/actions/constants.js.map +1 -0
  24. package/dist/actions/index.d.ts +2 -0
  25. package/dist/actions/index.js +3 -0
  26. package/dist/actions/index.js.map +1 -0
  27. package/dist/agent-loop.d.ts +14 -0
  28. package/dist/agent-loop.js +60 -0
  29. package/dist/agent-loop.js.map +1 -0
  30. package/dist/aleph-publisher.d.ts +9 -0
  31. package/dist/aleph-publisher.js +41 -0
  32. package/dist/aleph-publisher.js.map +1 -0
  33. package/dist/index.d.ts +11 -0
  34. package/dist/index.js +9 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/summarizer.d.ts +3 -0
  37. package/dist/summarizer.js +21 -0
  38. package/dist/summarizer.js.map +1 -0
  39. package/dist/tools.d.ts +6 -0
  40. package/dist/tools.js +30 -0
  41. package/dist/tools.js.map +1 -0
  42. package/dist/types.d.ts +15 -0
  43. package/dist/types.js +2 -0
  44. package/dist/types.js.map +1 -0
  45. package/dist/wallet.d.ts +17520 -0
  46. package/dist/wallet.js +47 -0
  47. package/dist/wallet.js.map +1 -0
  48. package/dist/x402-tracker.d.ts +2 -0
  49. package/dist/x402-tracker.js +39 -0
  50. package/dist/x402-tracker.js.map +1 -0
  51. package/eslint.config.js +26 -0
  52. package/package.json +86 -0
  53. package/src/actions/aleph.ts +145 -0
  54. package/src/actions/compound/compoundActionProvider.ts +166 -0
  55. package/src/actions/compound/constants.ts +140 -0
  56. package/src/actions/compound/index.ts +1 -0
  57. package/src/actions/compound/schemas.ts +45 -0
  58. package/src/actions/compound/utils.ts +367 -0
  59. package/src/actions/constants.ts +53 -0
  60. package/src/actions/index.ts +2 -0
  61. package/src/agent-loop.ts +93 -0
  62. package/src/aleph-publisher.ts +44 -0
  63. package/src/index.ts +11 -0
  64. package/src/summarizer.ts +30 -0
  65. package/src/tools.ts +40 -0
  66. package/src/types.ts +17 -0
  67. package/src/wallet.ts +73 -0
  68. package/src/x402-tracker.ts +43 -0
  69. package/tsconfig.json +15 -0
package/dist/wallet.js ADDED
@@ -0,0 +1,47 @@
1
+ import { createWalletClient, createPublicClient, http, formatUnits, } from "viem";
2
+ import { privateKeyToAccount } from "viem/accounts";
3
+ import { erc20Abi } from "viem";
4
+ import { ViemWalletProvider } from "@coinbase/agentkit";
5
+ import { Attribution } from "ox/erc8021";
6
+ const BUILDER_CODE = "bc_kj26kx76";
7
+ // USDC on Base mainnet
8
+ const USDC_BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
9
+ // USDC on Base Sepolia
10
+ const USDC_BASE_SEPOLIA = "0x036CbD53842c5426634e7929541eC2318f3dCF7e";
11
+ export async function createAgentWallet(privateKey, chain, rpcUrl) {
12
+ const account = privateKeyToAccount(privateKey);
13
+ const dataSuffix = Attribution.toDataSuffix({ codes: [BUILDER_CODE] });
14
+ const walletClient = createWalletClient({
15
+ account,
16
+ chain,
17
+ transport: http(rpcUrl),
18
+ dataSuffix,
19
+ });
20
+ const publicClient = createPublicClient({
21
+ chain,
22
+ transport: http(rpcUrl),
23
+ });
24
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
+ const provider = new ViemWalletProvider(walletClient);
26
+ const usdcAddress = chain.id === 8453 ? USDC_BASE : USDC_BASE_SEPOLIA;
27
+ return { walletClient, publicClient, provider, account, usdcAddress };
28
+ }
29
+ export async function getBalances(wallet) {
30
+ const { publicClient, account, usdcAddress, walletClient } = wallet;
31
+ const [ethBal, usdcBal] = await Promise.all([
32
+ publicClient.getBalance({ address: account.address }),
33
+ publicClient.readContract({
34
+ address: usdcAddress,
35
+ abi: erc20Abi,
36
+ functionName: "balanceOf",
37
+ args: [account.address],
38
+ }),
39
+ ]);
40
+ return {
41
+ address: account.address,
42
+ ethBalance: formatUnits(ethBal, 18),
43
+ usdcBalance: formatUnits(usdcBal, 6),
44
+ chainName: walletClient.chain?.name ?? "unknown",
45
+ };
46
+ }
47
+ //# sourceMappingURL=wallet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wallet.js","sourceRoot":"","sources":["../src/wallet.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,IAAI,EACJ,WAAW,GAGZ,MAAM,MAAM,CAAC;AACd,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAChC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,YAAY,GAAG,aAAa,CAAC;AAEnC,uBAAuB;AACvB,MAAM,SAAS,GAAG,4CAAqD,CAAC;AACxE,uBAAuB;AACvB,MAAM,iBAAiB,GAAG,4CAAqD,CAAC;AAShF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,UAAe,EAAE,KAAY,EAAE,MAAe;IACpF,MAAM,OAAO,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;IAChD,MAAM,UAAU,GAAG,WAAW,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IAEvE,MAAM,YAAY,GAAG,kBAAkB,CAAC;QACtC,OAAO;QACP,KAAK;QACL,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC;QACvB,UAAU;KACX,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG,kBAAkB,CAAC;QACtC,KAAK;QACL,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC;KACxB,CAAC,CAAC;IAEH,8DAA8D;IAC9D,MAAM,QAAQ,GAAG,IAAI,kBAAkB,CAAC,YAAmB,CAAC,CAAC;IAE7D,MAAM,WAAW,GAAG,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,CAAC;IAEtE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;AACxE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAqD;IAErD,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,GAAG,MAAM,CAAC;IAEpE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC1C,YAAY,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;QACrD,YAAY,CAAC,YAAY,CAAC;YACxB,OAAO,EAAE,WAAW;YACpB,GAAG,EAAE,QAAQ;YACb,YAAY,EAAE,WAAW;YACzB,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;SACxB,CAAC;KACH,CAAC,CAAC;IAEH,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC;QACnC,WAAW,EAAE,WAAW,CAAC,OAAiB,EAAE,CAAC,CAAC;QAC9C,SAAS,EAAE,YAAY,CAAC,KAAK,EAAE,IAAI,IAAI,SAAS;KACjD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function installX402Tracker(): void;
2
+ export declare function drainX402TxHashes(): string[];
@@ -0,0 +1,39 @@
1
+ let paymentTxHashes = [];
2
+ let installed = false;
3
+ export function installX402Tracker() {
4
+ if (installed)
5
+ return;
6
+ const originalFetch = globalThis.fetch;
7
+ globalThis.fetch = async (...args) => {
8
+ const response = await originalFetch(...args);
9
+ const receipt = response.headers.get("x-payment-receipt");
10
+ if (receipt && /^0x[a-fA-F0-9]{64}$/.test(receipt)) {
11
+ paymentTxHashes.push(receipt);
12
+ console.log(`[x402] Captured payment tx: ${receipt.slice(0, 14)}...`);
13
+ return response;
14
+ }
15
+ const paymentHeader = response.headers.get("payment-response");
16
+ if (paymentHeader) {
17
+ try {
18
+ const decoded = JSON.parse(atob(paymentHeader));
19
+ const txHash = decoded.transaction ?? decoded.txHash;
20
+ if (txHash && typeof txHash === "string") {
21
+ paymentTxHashes.push(txHash);
22
+ console.log(`[x402] Captured payment tx: ${txHash.slice(0, 14)}...`);
23
+ }
24
+ }
25
+ catch {
26
+ console.warn("[x402] Failed to decode payment-response header");
27
+ }
28
+ }
29
+ return response;
30
+ };
31
+ installed = true;
32
+ console.log("[x402] Fetch interceptor installed");
33
+ }
34
+ export function drainX402TxHashes() {
35
+ const hashes = [...paymentTxHashes];
36
+ paymentTxHashes = [];
37
+ return hashes;
38
+ }
39
+ //# sourceMappingURL=x402-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"x402-tracker.js","sourceRoot":"","sources":["../src/x402-tracker.ts"],"names":[],"mappings":"AAAA,IAAI,eAAe,GAAa,EAAE,CAAC;AACnC,IAAI,SAAS,GAAG,KAAK,CAAC;AAEtB,MAAM,UAAU,kBAAkB;IAChC,IAAI,SAAS;QAAE,OAAO;IACtB,MAAM,aAAa,GAAG,UAAU,CAAC,KAAK,CAAC;IAEvC,UAAU,CAAC,KAAK,GAAG,KAAK,EAAE,GAAG,IAA8B,EAAqB,EAAE;QAChF,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,GAAG,IAAI,CAAC,CAAC;QAE9C,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QAC1D,IAAI,OAAO,IAAI,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACnD,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC9B,OAAO,CAAC,GAAG,CAAC,+BAA+B,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;YACtE,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,MAAM,aAAa,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAC/D,IAAI,aAAa,EAAE,CAAC;YAClB,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;gBAChD,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC;gBACrD,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;oBACzC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBAC7B,OAAO,CAAC,GAAG,CAAC,+BAA+B,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;gBACvE,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;YAClE,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAC;IAEF,SAAS,GAAG,IAAI,CAAC;IACjB,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,MAAM,MAAM,GAAG,CAAC,GAAG,eAAe,CAAC,CAAC;IACpC,eAAe,GAAG,EAAE,CAAC;IACrB,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,26 @@
1
+ import tseslint from "@typescript-eslint/eslint-plugin";
2
+ import tsparser from "@typescript-eslint/parser";
3
+
4
+ export default [
5
+ {
6
+ files: ["src/**/*.ts"],
7
+ languageOptions: {
8
+ parser: tsparser,
9
+ parserOptions: {
10
+ ecmaVersion: "latest",
11
+ sourceType: "module",
12
+ },
13
+ },
14
+ plugins: {
15
+ "@typescript-eslint": tseslint,
16
+ },
17
+ rules: {
18
+ ...tseslint.configs.recommended.rules,
19
+ "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
20
+ "@typescript-eslint/no-explicit-any": "warn",
21
+ },
22
+ },
23
+ {
24
+ ignores: ["dist/"],
25
+ },
26
+ ];
package/package.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "basileus-agentkit-plugin",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/RezaRahemtola/ETHDenver-2026",
8
+ "directory": "basileus-agentkit-plugin"
9
+ },
10
+ "main": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ },
17
+ "./x402": {
18
+ "types": "./dist/x402-tracker.d.ts",
19
+ "import": "./dist/x402-tracker.js"
20
+ },
21
+ "./aleph": {
22
+ "types": "./dist/aleph-publisher.d.ts",
23
+ "import": "./dist/aleph-publisher.js"
24
+ },
25
+ "./agent-loop": {
26
+ "types": "./dist/agent-loop.d.ts",
27
+ "import": "./dist/agent-loop.js"
28
+ },
29
+ "./tools": {
30
+ "types": "./dist/tools.d.ts",
31
+ "import": "./dist/tools.js"
32
+ },
33
+ "./summarizer": {
34
+ "types": "./dist/summarizer.d.ts",
35
+ "import": "./dist/summarizer.js"
36
+ },
37
+ "./actions": {
38
+ "types": "./dist/actions/index.d.ts",
39
+ "import": "./dist/actions/index.js"
40
+ },
41
+ "./actions/aleph": {
42
+ "types": "./dist/actions/aleph.d.ts",
43
+ "import": "./dist/actions/aleph.js"
44
+ },
45
+ "./actions/compound": {
46
+ "types": "./dist/actions/compound/index.d.ts",
47
+ "import": "./dist/actions/compound/index.js"
48
+ },
49
+ "./wallet": {
50
+ "types": "./dist/wallet.d.ts",
51
+ "import": "./dist/wallet.js"
52
+ }
53
+ },
54
+ "scripts": {
55
+ "build": "tsc",
56
+ "typecheck": "tsc --noEmit",
57
+ "lint": "eslint src/",
58
+ "format": "prettier --write src/",
59
+ "format:check": "prettier --check src/"
60
+ },
61
+ "peerDependencies": {
62
+ "@blockrun/llm": "^0.3.0",
63
+ "@coinbase/agentkit": "^0.10.4",
64
+ "viem": "^2.0.0"
65
+ },
66
+ "dependencies": {
67
+ "@aleph-sdk/client": "^1.4.5",
68
+ "@aleph-sdk/ethereum": "^1.5.0",
69
+ "@aleph-sdk/message": "^1.6.3",
70
+ "decimal.js": "^10.0.0",
71
+ "ox": "^0.12.4",
72
+ "zod": "^3.0.0",
73
+ "zod-to-json-schema": "^3.25.0"
74
+ },
75
+ "devDependencies": {
76
+ "@blockrun/llm": "^0.3.0",
77
+ "@coinbase/agentkit": "^0.10.4",
78
+ "@types/node": "^22.0.0",
79
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
80
+ "@typescript-eslint/parser": "^8.0.0",
81
+ "eslint": "^9.0.0",
82
+ "prettier": "^3.8.1",
83
+ "typescript": "^5.7.0",
84
+ "viem": "^2.45.3"
85
+ }
86
+ }
@@ -0,0 +1,145 @@
1
+ import { z } from "zod";
2
+ import {
3
+ customActionProvider,
4
+ EvmWalletProvider,
5
+ SuperfluidQueryActionProvider,
6
+ } from "@coinbase/agentkit";
7
+ import { createPublicClient, formatUnits, http, parseEther, encodeFunctionData } from "viem";
8
+ import { base } from "viem/chains";
9
+ import {
10
+ ALEPH_ADDRESS,
11
+ WETH_ADDRESS,
12
+ UNISWAP_ROUTER,
13
+ UNISWAP_ALEPH_POOL,
14
+ uniswapV3PoolAbi,
15
+ uniswapRouterAbi,
16
+ } from "./constants.js";
17
+
18
+ const balanceOfAbi = [
19
+ {
20
+ inputs: [{ name: "account", type: "address" }],
21
+ name: "balanceOf",
22
+ outputs: [{ name: "", type: "uint256" }],
23
+ stateMutability: "view",
24
+ type: "function",
25
+ },
26
+ ] as const;
27
+
28
+ export function createAlephActionProvider(rpcUrl?: string) {
29
+ const publicClient = createPublicClient({
30
+ chain: base,
31
+ transport: http(rpcUrl),
32
+ });
33
+
34
+ return customActionProvider<EvmWalletProvider>([
35
+ {
36
+ name: "get_aleph_info",
37
+ description:
38
+ "Get your current ALEPH balance, hourly consumption rate, estimated hours of compute left, ETH balance, and ALEPH/ETH price. Use this to decide whether you need to buy more ALEPH.",
39
+ schema: z.object({}),
40
+ invoke: async (walletProvider: EvmWalletProvider, _args: unknown) => {
41
+ try {
42
+ const address = walletProvider.getAddress() as `0x${string}`;
43
+
44
+ const sfQuery = new SuperfluidQueryActionProvider();
45
+ const streamsResult = await sfQuery.queryStreams(walletProvider);
46
+
47
+ let alephPerHour = 0;
48
+ try {
49
+ const jsonStr = streamsResult.replace("Current outflows are ", "");
50
+ const outflows = JSON.parse(jsonStr) as Array<{
51
+ currentFlowRate: string;
52
+ token: { symbol: string };
53
+ receiver: { id: string };
54
+ }>;
55
+ const alephOutflows = outflows.filter((o) =>
56
+ o.token.symbol.toLowerCase().includes("aleph"),
57
+ );
58
+ const totalFlowRate = alephOutflows.reduce(
59
+ (sum, o) => sum + BigInt(o.currentFlowRate),
60
+ 0n,
61
+ );
62
+ alephPerHour = parseFloat(formatUnits(totalFlowRate * 3600n, 18));
63
+ } catch {
64
+ // No outflows or parse error
65
+ }
66
+
67
+ const rawBalance = await publicClient.readContract({
68
+ address: ALEPH_ADDRESS,
69
+ abi: balanceOfAbi,
70
+ functionName: "balanceOf",
71
+ args: [address],
72
+ });
73
+ const alephBalance = parseFloat(formatUnits(rawBalance, 18));
74
+
75
+ let hoursLeft = 1000000;
76
+ if (alephPerHour > 0) {
77
+ hoursLeft = Math.round(alephBalance / alephPerHour);
78
+ }
79
+
80
+ const ethBalanceWei = await publicClient.getBalance({ address });
81
+ const ethBalance = parseFloat(formatUnits(ethBalanceWei, 18));
82
+
83
+ const slot0 = await publicClient.readContract({
84
+ address: UNISWAP_ALEPH_POOL,
85
+ abi: uniswapV3PoolAbi,
86
+ functionName: "slot0",
87
+ });
88
+ const sqrtPriceX96 = slot0[0];
89
+ const price = Number(sqrtPriceX96) / 2 ** 96;
90
+ const alephPerEth = price * price;
91
+
92
+ return JSON.stringify({
93
+ aleph_balance: Math.round(alephBalance * 1000) / 1000,
94
+ aleph_consumed_per_hour: Math.round(alephPerHour * 1000) / 1000,
95
+ hours_left_until_death: hoursLeft,
96
+ eth_balance: Math.round(ethBalance * 10000) / 10000,
97
+ aleph_per_eth: Math.round(alephPerEth * 100) / 100,
98
+ });
99
+ } catch (err) {
100
+ return `Error getting ALEPH info: ${err instanceof Error ? err.message : String(err)}`;
101
+ }
102
+ },
103
+ },
104
+ {
105
+ name: "swap_eth_to_aleph",
106
+ description:
107
+ "Swap ETH to ALEPH via Uniswap V3 to pay for your computing. Provide the amount of ETH to swap.",
108
+ schema: z.object({
109
+ ethAmount: z.string().describe("Amount of ETH to swap, e.g. '0.01'"),
110
+ }),
111
+ invoke: async (walletProvider: EvmWalletProvider, args: { ethAmount: string }) => {
112
+ try {
113
+ const amountInWei = parseEther(args.ethAmount);
114
+ const address = walletProvider.getAddress() as `0x${string}`;
115
+
116
+ const data = encodeFunctionData({
117
+ abi: uniswapRouterAbi,
118
+ functionName: "exactInputSingle",
119
+ args: [
120
+ {
121
+ tokenIn: WETH_ADDRESS,
122
+ tokenOut: ALEPH_ADDRESS,
123
+ fee: 10000,
124
+ recipient: address,
125
+ amountIn: amountInWei,
126
+ amountOutMinimum: 0n,
127
+ sqrtPriceLimitX96: 0n,
128
+ },
129
+ ],
130
+ });
131
+
132
+ const txHash = await walletProvider.sendTransaction({
133
+ to: UNISWAP_ROUTER,
134
+ data,
135
+ value: amountInWei,
136
+ });
137
+
138
+ return `Swap transaction sent. Hash: ${txHash}`;
139
+ } catch (err) {
140
+ return `Error swapping ETH to ALEPH: ${err instanceof Error ? err.message : String(err)}`;
141
+ }
142
+ },
143
+ },
144
+ ]);
145
+ }
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Fixed Compound action provider — local copy with base asset fixes.
3
+ *
4
+ * Fixes from upstream @coinbase/agentkit:
5
+ * - get_portfolio: reads base asset supply via Comet.balanceOf() (was missing)
6
+ * - withdraw: for base asset (USDC), checks balanceOf instead of collateralBalanceOf
7
+ *
8
+ * Uses customActionProvider (no decorators) so tsx/esbuild can run it.
9
+ * TODO: Remove this directory once agentkit merges the fix.
10
+ */
11
+ import { encodeFunctionData, formatUnits, parseUnits, erc20Abi } from "viem";
12
+ import { customActionProvider, EvmWalletProvider } from "@coinbase/agentkit";
13
+ import { COMET_ABI } from "./constants.js";
14
+ import {
15
+ CompoundSupplySchema,
16
+ CompoundWithdrawSchema,
17
+ CompoundPortfolioSchema,
18
+ } from "./schemas.js";
19
+ import {
20
+ getBaseAssetBalance,
21
+ getCollateralBalance,
22
+ getHealthRatio,
23
+ getHealthRatioAfterWithdraw,
24
+ getTokenBalance,
25
+ getTokenDecimals,
26
+ getTokenSymbol,
27
+ getPortfolioDetailsMarkdown,
28
+ getCometAddress,
29
+ getAssetAddress,
30
+ getBaseTokenAddress,
31
+ } from "./utils.js";
32
+
33
+ async function approve(
34
+ wallet: EvmWalletProvider,
35
+ tokenAddress: string,
36
+ spenderAddress: string,
37
+ amount: bigint,
38
+ ): Promise<string> {
39
+ try {
40
+ const data = encodeFunctionData({
41
+ abi: erc20Abi,
42
+ functionName: "approve",
43
+ args: [spenderAddress as `0x${string}`, amount],
44
+ });
45
+ const txHash = await wallet.sendTransaction({
46
+ to: tokenAddress as `0x${string}`,
47
+ data,
48
+ });
49
+ await wallet.waitForTransactionReceipt(txHash);
50
+ return `Successfully approved ${spenderAddress} to spend ${amount} tokens`;
51
+ } catch (error) {
52
+ return `Error approving tokens: ${error}`;
53
+ }
54
+ }
55
+
56
+ export const compoundFixedProvider = customActionProvider<EvmWalletProvider>([
57
+ {
58
+ name: "compound_supply",
59
+ description:
60
+ "Supply assets to Compound. assetId: 'weth', 'cbeth', 'cbbtc', 'wsteth', or 'usdc'. amount: human-readable.",
61
+ schema: CompoundSupplySchema,
62
+ invoke: async (wallet, args) => {
63
+ try {
64
+ const network = wallet.getNetwork();
65
+ const cometAddress = getCometAddress(network);
66
+ const tokenAddress = getAssetAddress(network, args.assetId);
67
+
68
+ const decimals = await getTokenDecimals(wallet, tokenAddress);
69
+ const amountAtomic = parseUnits(args.amount, decimals);
70
+
71
+ const walletBalance = await getTokenBalance(wallet, tokenAddress);
72
+ if (walletBalance < amountAtomic) {
73
+ const humanBalance = formatUnits(walletBalance, decimals);
74
+ return `Error: Insufficient balance. You have ${humanBalance}, but trying to supply ${args.amount}`;
75
+ }
76
+
77
+ const approvalResult = await approve(wallet, tokenAddress, cometAddress, amountAtomic);
78
+ if (approvalResult.startsWith("Error")) {
79
+ return `Error approving token: ${approvalResult}`;
80
+ }
81
+
82
+ const data = encodeFunctionData({
83
+ abi: COMET_ABI,
84
+ functionName: "supply",
85
+ args: [tokenAddress, amountAtomic],
86
+ });
87
+ const txHash = await wallet.sendTransaction({ to: cometAddress, data });
88
+ await wallet.waitForTransactionReceipt(txHash);
89
+
90
+ const sym = await getTokenSymbol(wallet, tokenAddress);
91
+ return `Supplied ${args.amount} ${sym} to Compound.\nTransaction hash: ${txHash}`;
92
+ } catch (err) {
93
+ return `Error supplying to Compound: ${err instanceof Error ? err.message : err}`;
94
+ }
95
+ },
96
+ },
97
+ {
98
+ name: "compound_withdraw",
99
+ description:
100
+ "Withdraw assets from Compound. assetId: 'weth', 'cbeth', 'cbbtc', 'wsteth', or 'usdc'. amount: human-readable.",
101
+ schema: CompoundWithdrawSchema,
102
+ invoke: async (wallet, args) => {
103
+ try {
104
+ const cometAddress = getCometAddress(wallet.getNetwork());
105
+ const tokenAddress = getAssetAddress(wallet.getNetwork(), args.assetId);
106
+
107
+ const decimals = await getTokenDecimals(wallet, tokenAddress);
108
+ const amountAtomic = parseUnits(args.amount, decimals);
109
+
110
+ const baseTokenAddress = await getBaseTokenAddress(wallet, cometAddress);
111
+ const isBaseAsset = tokenAddress.toLowerCase() === baseTokenAddress.toLowerCase();
112
+
113
+ if (isBaseAsset) {
114
+ const baseBalance = await getBaseAssetBalance(wallet, cometAddress);
115
+ if (amountAtomic > baseBalance) {
116
+ return `Error: Insufficient balance. Trying to withdraw ${args.amount}, but only have ${formatUnits(baseBalance, decimals)} supplied`;
117
+ }
118
+ } else {
119
+ const collateralBalance = await getCollateralBalance(wallet, cometAddress, tokenAddress);
120
+ if (amountAtomic > collateralBalance) {
121
+ return `Error: Insufficient balance. Trying to withdraw ${args.amount}, but only have ${formatUnits(collateralBalance, decimals)} supplied`;
122
+ }
123
+
124
+ const projectedHealth = await getHealthRatioAfterWithdraw(
125
+ wallet,
126
+ cometAddress,
127
+ tokenAddress,
128
+ amountAtomic,
129
+ );
130
+ if (projectedHealth.lessThan(1)) {
131
+ return `Error: Withdrawing ${args.amount} would result in unhealthy position. Health ratio would be ${projectedHealth.toFixed(2)}`;
132
+ }
133
+ }
134
+
135
+ const data = encodeFunctionData({
136
+ abi: COMET_ABI,
137
+ functionName: "withdraw",
138
+ args: [tokenAddress, amountAtomic],
139
+ });
140
+ const txHash = await wallet.sendTransaction({ to: cometAddress, data });
141
+ await wallet.waitForTransactionReceipt(txHash);
142
+
143
+ const sym = await getTokenSymbol(wallet, tokenAddress);
144
+ const health = await getHealthRatio(wallet, cometAddress);
145
+ return `Withdrawn ${args.amount} ${sym} from Compound.\nTransaction hash: ${txHash}\nHealth ratio: ${health.toFixed(2)}`;
146
+ } catch (err) {
147
+ return `Error withdrawing from Compound: ${err instanceof Error ? err.message : err}`;
148
+ }
149
+ },
150
+ },
151
+ {
152
+ name: "compound_get_portfolio",
153
+ description:
154
+ "Get Compound portfolio: base asset supply (earns APY), collateral balances, borrow positions.",
155
+ schema: CompoundPortfolioSchema,
156
+ // NOTE: must have 2 params so customActionProvider passes wallet as first arg
157
+ invoke: async (wallet, _args) => {
158
+ try {
159
+ const cometAddress = getCometAddress(wallet.getNetwork());
160
+ return await getPortfolioDetailsMarkdown(wallet, cometAddress);
161
+ } catch (err) {
162
+ return `Error getting portfolio: ${err instanceof Error ? err.message : err}`;
163
+ }
164
+ },
165
+ },
166
+ ]);
@@ -0,0 +1,140 @@
1
+ import { type Address } from "viem";
2
+ import { erc20Abi as ERC20_ABI } from "viem";
3
+
4
+ export const SUPPORTED_NETWORKS = ["base-mainnet", "base-sepolia"];
5
+
6
+ export const COMET_ADDRESSES: Record<string, Address> = {
7
+ "base-mainnet": "0xb125E6687d4313864e53df431d5425969c15Eb2F",
8
+ "base-sepolia": "0x571621Ce60Cebb0c1D442B5afb38B1663C6Bf017",
9
+ };
10
+
11
+ export const ASSET_ADDRESSES: Record<string, Record<string, Address>> = {
12
+ "base-mainnet": {
13
+ weth: "0x4200000000000000000000000000000000000006",
14
+ cbeth: "0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22",
15
+ cbbtc: "0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf",
16
+ wsteth: "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452",
17
+ usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
18
+ },
19
+ "base-sepolia": {
20
+ weth: "0x4200000000000000000000000000000000000006",
21
+ usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
22
+ wsteth: "0x774eD9EDB0C5202dF9A86183804b5D9E99dC6CA3",
23
+ },
24
+ };
25
+
26
+ export { ERC20_ABI };
27
+
28
+ export const COMET_ABI = [
29
+ {
30
+ inputs: [
31
+ { internalType: "address", name: "asset", type: "address" },
32
+ { internalType: "uint256", name: "amount", type: "uint256" },
33
+ ],
34
+ name: "supply",
35
+ outputs: [],
36
+ stateMutability: "nonpayable",
37
+ type: "function",
38
+ },
39
+ {
40
+ inputs: [
41
+ { internalType: "address", name: "asset", type: "address" },
42
+ { internalType: "uint256", name: "amount", type: "uint256" },
43
+ ],
44
+ name: "withdraw",
45
+ outputs: [],
46
+ stateMutability: "nonpayable",
47
+ type: "function",
48
+ },
49
+ {
50
+ inputs: [{ internalType: "address", name: "priceFeed", type: "address" }],
51
+ name: "getPrice",
52
+ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
53
+ stateMutability: "view",
54
+ type: "function",
55
+ },
56
+ {
57
+ inputs: [{ internalType: "address", name: "account", type: "address" }],
58
+ name: "borrowBalanceOf",
59
+ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
60
+ stateMutability: "view",
61
+ type: "function",
62
+ },
63
+ {
64
+ inputs: [],
65
+ name: "numAssets",
66
+ outputs: [{ internalType: "uint8", name: "", type: "uint8" }],
67
+ stateMutability: "view",
68
+ type: "function",
69
+ },
70
+ {
71
+ inputs: [{ internalType: "uint8", name: "i", type: "uint8" }],
72
+ name: "getAssetInfo",
73
+ outputs: [
74
+ {
75
+ components: [
76
+ { internalType: "uint8", name: "offset", type: "uint8" },
77
+ { internalType: "address", name: "asset", type: "address" },
78
+ { internalType: "address", name: "priceFeed", type: "address" },
79
+ { internalType: "uint64", name: "scale", type: "uint64" },
80
+ { internalType: "uint64", name: "borrowCollateralFactor", type: "uint64" },
81
+ { internalType: "uint64", name: "liquidateCollateralFactor", type: "uint64" },
82
+ { internalType: "uint64", name: "liquidationFactor", type: "uint64" },
83
+ { internalType: "uint128", name: "supplyCap", type: "uint128" },
84
+ ],
85
+ internalType: "struct CometCore.AssetInfo",
86
+ name: "",
87
+ type: "tuple",
88
+ },
89
+ ],
90
+ stateMutability: "view",
91
+ type: "function",
92
+ },
93
+ {
94
+ inputs: [],
95
+ name: "baseToken",
96
+ outputs: [{ internalType: "address", name: "", type: "address" }],
97
+ stateMutability: "view",
98
+ type: "function",
99
+ },
100
+ {
101
+ inputs: [],
102
+ name: "baseTokenPriceFeed",
103
+ outputs: [{ internalType: "address", name: "", type: "address" }],
104
+ stateMutability: "view",
105
+ type: "function",
106
+ },
107
+ {
108
+ inputs: [
109
+ { internalType: "address", name: "account", type: "address" },
110
+ { internalType: "address", name: "asset", type: "address" },
111
+ ],
112
+ name: "collateralBalanceOf",
113
+ outputs: [{ internalType: "uint128", name: "balance", type: "uint128" }],
114
+ stateMutability: "view",
115
+ type: "function",
116
+ },
117
+ {
118
+ inputs: [{ internalType: "address", name: "account", type: "address" }],
119
+ name: "balanceOf",
120
+ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
121
+ stateMutability: "view",
122
+ type: "function",
123
+ },
124
+ ] as const;
125
+
126
+ export const PRICE_FEED_ABI = [
127
+ {
128
+ inputs: [],
129
+ name: "latestRoundData",
130
+ outputs: [
131
+ { name: "roundId", type: "uint80" },
132
+ { name: "answer", type: "int256" },
133
+ { name: "startedAt", type: "uint256" },
134
+ { name: "updatedAt", type: "uint256" },
135
+ { name: "answeredInRound", type: "uint80" },
136
+ ],
137
+ stateMutability: "view",
138
+ type: "function",
139
+ },
140
+ ] as const;
@@ -0,0 +1 @@
1
+ export { compoundFixedProvider } from "./compoundActionProvider.js";