@coinbase/agentkit 0.2.0 → 0.2.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.
Files changed (39) hide show
  1. package/README.md +88 -2
  2. package/dist/action-providers/cdp/cdpApiActionProvider.d.ts +5 -3
  3. package/dist/action-providers/cdp/cdpApiActionProvider.js +15 -4
  4. package/dist/action-providers/cdp/cdpApiActionProvider.test.js +14 -2
  5. package/dist/action-providers/cdp/cdpWalletActionProvider.js +4 -1
  6. package/dist/action-providers/index.d.ts +2 -0
  7. package/dist/action-providers/index.js +2 -0
  8. package/dist/action-providers/jupiter/index.d.ts +1 -0
  9. package/dist/action-providers/jupiter/index.js +17 -0
  10. package/dist/action-providers/jupiter/jupiterActionProvider.d.ts +36 -0
  11. package/dist/action-providers/jupiter/jupiterActionProvider.js +115 -0
  12. package/dist/action-providers/jupiter/jupiterActionProvider.test.d.ts +1 -0
  13. package/dist/action-providers/jupiter/jupiterActionProvider.test.js +146 -0
  14. package/dist/action-providers/jupiter/schemas.d.ts +20 -0
  15. package/dist/action-providers/jupiter/schemas.js +20 -0
  16. package/dist/action-providers/spl/schemas.d.ts +13 -0
  17. package/dist/action-providers/spl/schemas.js +13 -1
  18. package/dist/action-providers/spl/splActionProvider.d.ts +9 -1
  19. package/dist/action-providers/spl/splActionProvider.js +62 -1
  20. package/dist/action-providers/spl/splActionProvider.test.js +101 -7
  21. package/dist/action-providers/wow/constants.js +1 -1
  22. package/dist/action-providers/wow/wowActionProvider.d.ts +4 -4
  23. package/dist/action-providers/wow/wowActionProvider.js +19 -19
  24. package/dist/action-providers/wow/wowActionProvider.test.js +14 -10
  25. package/dist/analytics/sendAnalyticsEvent.js +1 -0
  26. package/dist/network/svm.d.ts +1 -0
  27. package/dist/network/svm.js +6 -1
  28. package/dist/wallet-providers/cdpWalletProvider.js +1 -1
  29. package/dist/wallet-providers/index.d.ts +2 -0
  30. package/dist/wallet-providers/index.js +2 -0
  31. package/dist/wallet-providers/privyEvmWalletProvider.d.ts +55 -0
  32. package/dist/wallet-providers/privyEvmWalletProvider.js +140 -0
  33. package/dist/wallet-providers/privyShared.d.ts +40 -0
  34. package/dist/wallet-providers/privyShared.js +49 -0
  35. package/dist/wallet-providers/privySvmWalletProvider.d.ts +128 -0
  36. package/dist/wallet-providers/privySvmWalletProvider.js +212 -0
  37. package/dist/wallet-providers/privyWalletProvider.d.ts +21 -56
  38. package/dist/wallet-providers/privyWalletProvider.js +18 -118
  39. package/package.json +2 -1
package/README.md CHANGED
@@ -34,6 +34,10 @@ AgentKit is a framework for easily enabling AI agents to take actions onchain. I
34
34
  - [SolanaKeypairWalletProvider](#solanakeypairwalletprovider)
35
35
  - [Network Configuration](#solana-network-configuration)
36
36
  - [RPC URL Configuration](#rpc-url-configuration)
37
+ - [PrivyWalletProvider](#privywalletprovider-solana)
38
+ - [Connection Configuration](#connection-configuration)
39
+ - [Authorization Keys](#authorization-keys)
40
+ - [Exporting Privy Wallet information](#exporting-privy-wallet-information)
37
41
  - [Contributing](#contributing)
38
42
 
39
43
  ## Getting Started
@@ -290,6 +294,15 @@ const agent = createReactAgent({
290
294
  </tr>
291
295
  </table>
292
296
  </details>
297
+ <details>
298
+ <summary><strong>Jupiter</strong></summary>
299
+ <table width="100%">
300
+ <tr>
301
+ <td width="200"><code>swap</code></td>
302
+ <td width="768">Swap tokens on Solana using the Jupiter DEX aggregator.</td>
303
+ </tr>
304
+ </table>
305
+ </details>
293
306
 
294
307
  ## Creating an Action Provider
295
308
 
@@ -556,10 +569,10 @@ const walletProvider = new ViemWalletProvider(client, {
556
569
  The `PrivyWalletProvider` is a wallet provider that uses [Privy Server Wallets](https://docs.privy.io/guide/server-wallets/). This implementation extends the `ViemWalletProvider`.
557
570
 
558
571
  ```typescript
559
- import { PrivyWalletProvider } from "@coinbase/agentkit";
572
+ import { PrivyWalletProvider, PrivyWalletConfig } from "@coinbase/agentkit";
560
573
 
561
574
  // Configure Wallet Provider
562
- const config = {
575
+ const config: PrivyWalletConfig = {
563
576
  appId: "PRIVY_APP_ID",
564
577
  appSecret: "PRIVY_APP_SECRET",
565
578
  chainId: "84532", // base-sepolia
@@ -598,11 +611,14 @@ const walletData = await walletProvider.exportWallet();
598
611
 
599
612
  SVM:
600
613
  - [SolanaKeypairWalletProvider](https://github.com/coinbase/agentkit/blob/main/typescript/agentkit/src/wallet-providers/solanaKeypairWalletProvider.ts)
614
+ - [PrivyWalletProvider](https://github.com/coinbase/agentkit/blob/main/typescript/agentkit/src/wallet-providers/privySvmWalletProvider.ts)
601
615
 
602
616
  ### SolanaKeypairWalletProvider
603
617
 
604
618
  The `SolanaKeypairWalletProvider` is a wallet provider that uses the API [Solana web3.js](https://solana-labs.github.io/solana-web3.js/).
605
619
 
620
+ NOTE: It is highly recommended to use a dedicated RPC provider. See [here](https://solana.com/rpc) for more info on Solana RPC infrastructure, and see [here](#rpc-url-configuration) for instructions on configuring `SolanaKeypairWalletProvider` with a custom RPC URL.
621
+
606
622
  #### Solana Network Configuration
607
623
 
608
624
  The `SolanaKeypairWalletProvider` can be configured to use a specific network by passing the `networkId` parameter to the `fromNetwork` method. The `networkId` is the ID of the Solana network you want to use. Valid values are `solana-mainnet`, `solana-devnet` and `solana-testnet`.
@@ -634,6 +650,76 @@ const rpcUrl = process.env.SOLANA_RPC_URL;
634
650
  const walletProvider = await SolanaKeypairWalletProvider.fromRpcUrl(network, privateKey);
635
651
  ```
636
652
 
653
+ ### PrivyWalletProvider (Solana)
654
+
655
+ The `PrivyWalletProvider` is a wallet provider that uses [Privy Server Wallets](https://docs.privy.io/guide/server-wallets/).
656
+
657
+ NOTE: It is highly recommended to use a dedicated RPC provider. See [here](https://solana.com/rpc) for more info on Solana RPC infrastructure, and see [here](#connection-configuration) for instructions on configuring `PrivyWalletProvider` with a custom RPC URL.
658
+
659
+ ```typescript
660
+ import { PrivyWalletProvider, PrivyWalletConfig } from "@coinbase/agentkit";
661
+
662
+ // Configure Wallet Provider
663
+ const config: PrivyWalletConfig = {
664
+ appId: "PRIVY_APP_ID",
665
+ appSecret: "PRIVY_APP_SECRET",
666
+ chainType: "solana", // optional, defaults to "evm". Make sure to set this to "solana" if you want to use Solana!
667
+ networkId: "solana-devnet", // optional, defaults to "solana-devnet"
668
+ walletId: "PRIVY_WALLET_ID", // optional, otherwise a new wallet will be created
669
+ authorizationPrivateKey: PRIVY_WALLET_AUTHORIZATION_PRIVATE_KEY, // optional, required if your account is using authorization keys
670
+ authorizationKeyId: PRIVY_WALLET_AUTHORIZATION_KEY_ID, // optional, only required to create a new wallet if walletId is not provided
671
+ };
672
+
673
+ const walletProvider = await PrivyWalletProvider.configureWithWallet(config);
674
+ ```
675
+
676
+ #### Connection Configuration
677
+
678
+ Optionally, you can configure your own `@solana/web3.js` connection by passing the `connection` parameter to the `configureWithWallet` method.
679
+
680
+ ```typescript
681
+ import { PrivyWalletProvider, PrivyWalletConfig } from "@coinbase/agentkit";
682
+
683
+ const connection = new Connection("YOUR_RPC_URL");
684
+
685
+ // Configure Wallet Provider
686
+ const config: PrivyWalletConfig = {
687
+ appId: "PRIVY_APP_ID",
688
+ appSecret: "PRIVY_APP_SECRET",
689
+ connection,
690
+ chainType: "solana", // optional, defaults to "evm". Make sure to set this to "solana" if you want to use Solana!
691
+ networkId: "solana-devnet", // optional, defaults to "solana-devnet"
692
+ walletId: "PRIVY_WALLET_ID", // optional, otherwise a new wallet will be created
693
+ authorizationPrivateKey: PRIVY_WALLET_AUTHORIZATION_PRIVATE_KEY, // optional, required if your account is using authorization keys
694
+ authorizationKeyId: PRIVY_WALLET_AUTHORIZATION_KEY_ID, // optional, only required to create a new wallet if walletId is not provided
695
+ };
696
+
697
+ const walletProvider = await PrivyWalletProvider.configureWithWallet(config);
698
+ ```
699
+
700
+ #### Authorization Keys
701
+
702
+ Privy offers the option to use authorization keys to secure your server wallets.
703
+
704
+ You can manage authorization keys from your [Privy dashboard](https://dashboard.privy.io/account) or programmatically [using the API](https://docs.privy.io/guide/server-wallets/authorization/signatures).
705
+
706
+ When using authorization keys, you must provide the `authorizationPrivateKey` and `authorizationKeyId` parameters to the `configureWithWallet` method if you are creating a new wallet. Please note that when creating a key, if you enable "Create and modify wallets", you will be required to use that key when creating new wallets via the PrivyWalletProvider.
707
+
708
+ #### Exporting Privy Wallet information
709
+
710
+ The `PrivyWalletProvider` can export wallet information by calling the `exportWallet` method.
711
+
712
+ ```typescript
713
+ const walletData = await walletProvider.exportWallet();
714
+
715
+ // walletData will be in the following format:
716
+ {
717
+ walletId: string;
718
+ authorizationKey: string | undefined;
719
+ networkId: string | undefined;
720
+ }
721
+ ```
722
+
637
723
  ## Contributing
638
724
 
639
725
  See [CONTRIBUTING.md](../../CONTRIBUTING.md) for more information.
@@ -1,14 +1,14 @@
1
1
  import { z } from "zod";
2
2
  import { ActionProvider } from "../actionProvider";
3
3
  import { Network } from "../../network";
4
- import { CdpProviderConfig, EvmWalletProvider } from "../../wallet-providers";
4
+ import { CdpProviderConfig, WalletProvider } from "../../wallet-providers";
5
5
  import { AddressReputationSchema, RequestFaucetFundsSchema } from "./schemas";
6
6
  /**
7
7
  * CdpApiActionProvider is an action provider for CDP API.
8
8
  *
9
9
  * This provider is used for any action that uses the CDP API, but does not require a CDP Wallet.
10
10
  */
11
- export declare class CdpApiActionProvider extends ActionProvider<EvmWalletProvider> {
11
+ export declare class CdpApiActionProvider extends ActionProvider<WalletProvider> {
12
12
  /**
13
13
  * Constructor for the CdpApiActionProvider class.
14
14
  *
@@ -29,10 +29,12 @@ export declare class CdpApiActionProvider extends ActionProvider<EvmWalletProvid
29
29
  * @param args - The input arguments for the action.
30
30
  * @returns A confirmation message with transaction details.
31
31
  */
32
- faucet(walletProvider: EvmWalletProvider, args: z.infer<typeof RequestFaucetFundsSchema>): Promise<string>;
32
+ faucet(walletProvider: WalletProvider, args: z.infer<typeof RequestFaucetFundsSchema>): Promise<string>;
33
33
  /**
34
34
  * Checks if the Cdp action provider supports the given network.
35
35
  *
36
+ * NOTE: Network scoping is done at the action implementation level
37
+ *
36
38
  * @param _ - The network to check.
37
39
  * @returns True if the Cdp action provider supports the network, false otherwise.
38
40
  */
@@ -33,6 +33,8 @@ class CdpApiActionProvider extends actionProvider_1.ActionProvider {
33
33
  /**
34
34
  * Checks if the Cdp action provider supports the given network.
35
35
  *
36
+ * NOTE: Network scoping is done at the action implementation level
37
+ *
36
38
  * @param _ - The network to check.
37
39
  * @returns True if the Cdp action provider supports the network, false otherwise.
38
40
  */
@@ -40,7 +42,7 @@ class CdpApiActionProvider extends actionProvider_1.ActionProvider {
40
42
  if (config.apiKeyName && config.apiKeyPrivateKey) {
41
43
  coinbase_sdk_1.Coinbase.configure({
42
44
  apiKeyName: config.apiKeyName,
43
- privateKey: config.apiKeyPrivateKey,
45
+ privateKey: config.apiKeyPrivateKey?.replace(/\\n/g, "\n"),
44
46
  source: "agentkit",
45
47
  sourceVersion: package_json_1.version,
46
48
  });
@@ -56,6 +58,9 @@ class CdpApiActionProvider extends actionProvider_1.ActionProvider {
56
58
  * @returns A string containing reputation data or error message
57
59
  */
58
60
  async addressReputation(args) {
61
+ if (args.network.includes("solana")) {
62
+ return "Address reputation is only supported on Ethereum networks.";
63
+ }
59
64
  try {
60
65
  const address = new coinbase_sdk_1.ExternalAddress(args.network, args.address);
61
66
  const reputation = await address.reputation();
@@ -73,10 +78,14 @@ class CdpApiActionProvider extends actionProvider_1.ActionProvider {
73
78
  * @returns A confirmation message with transaction details.
74
79
  */
75
80
  async faucet(walletProvider, args) {
81
+ const network = walletProvider.getNetwork();
82
+ if (network.networkId !== "base-sepolia" && network.networkId !== "solana-devnet") {
83
+ return `Faucet is only allowed on 'base-sepolia' or 'solana-devnet'.`;
84
+ }
76
85
  try {
77
86
  const address = new coinbase_sdk_1.ExternalAddress(walletProvider.getNetwork().networkId, walletProvider.getAddress());
78
87
  const faucetTx = await address.faucet(args.assetId || undefined);
79
- const result = await faucetTx.wait();
88
+ const result = await faucetTx.wait({ timeoutSeconds: 60 });
80
89
  return `Received ${args.assetId || "ETH"} from the faucet. Transaction: ${result.getTransactionLink()}`;
81
90
  }
82
91
  catch (error) {
@@ -104,13 +113,15 @@ __decorate([
104
113
  (0, actionDecorator_1.CreateAction)({
105
114
  name: "request_faucet_funds",
106
115
  description: `This tool will request test tokens from the faucet for the default address in the wallet. It takes the wallet and asset ID as input.
107
- If no asset ID is provided the faucet defaults to ETH. Faucet is only allowed on 'base-sepolia' and can only provide asset ID 'eth' or 'usdc'.
116
+ Faucet is only allowed on 'base-sepolia' or 'solana-devnet'.
117
+ If fauceting on 'base-sepolia', user can only provide asset ID 'eth' or 'usdc', if no asset ID is provided, the faucet will default to 'eth'.
118
+ If fauceting on 'solana-devnet', user can only provide asset ID 'sol', if no asset ID is provided, the faucet will default to 'sol'.
108
119
  You are not allowed to faucet with any other network or asset ID. If you are on another network, suggest that the user sends you some ETH
109
120
  from another wallet and provide the user with your wallet details.`,
110
121
  schema: schemas_1.RequestFaucetFundsSchema,
111
122
  }),
112
123
  __metadata("design:type", Function),
113
- __metadata("design:paramtypes", [wallet_providers_1.EvmWalletProvider, void 0]),
124
+ __metadata("design:paramtypes", [wallet_providers_1.WalletProvider, void 0]),
114
125
  __metadata("design:returntype", Promise)
115
126
  ], CdpApiActionProvider.prototype, "faucet", null);
116
127
  const cdpApiActionProvider = (config = {}) => new CdpApiActionProvider(config);
@@ -2,9 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const cdpApiActionProvider_1 = require("./cdpApiActionProvider");
4
4
  const schemas_1 = require("./schemas");
5
- // Mock the entire module
6
5
  jest.mock("@coinbase/coinbase-sdk");
7
- // Get the mocked constructor
8
6
  const { ExternalAddress } = jest.requireMock("@coinbase/coinbase-sdk");
9
7
  describe("CDP API Action Provider Input Schemas", () => {
10
8
  describe("Address Reputation Schema", () => {
@@ -93,6 +91,14 @@ describe("CDP API Action Provider", () => {
93
91
  expect(mockExternalAddressInstance.reputation).toHaveBeenCalledTimes(1);
94
92
  expect(result).toBe(`Error checking address reputation: ${error}`);
95
93
  });
94
+ it("should return error if not on Ethereum network", async () => {
95
+ const args = {
96
+ address: "0xe6b2af36b3bb8d47206a129ff11d5a2de2a63c83",
97
+ network: "solana-devnet",
98
+ };
99
+ const result = await actionProvider.addressReputation(args);
100
+ expect(result).toBe("Address reputation is only supported on Ethereum networks.");
101
+ });
96
102
  });
97
103
  describe("faucet", () => {
98
104
  beforeEach(() => {
@@ -130,5 +136,11 @@ describe("CDP API Action Provider", () => {
130
136
  const result = await actionProvider.faucet(mockWallet, args);
131
137
  expect(result).toBe(`Error requesting faucet funds: ${error}`);
132
138
  });
139
+ it("should return error if not on base-sepolia or solana-devnet", async () => {
140
+ mockWallet.getNetwork.mockReturnValue({ networkId: "solana-mainnet", protocolFamily: "svm" });
141
+ const args = {};
142
+ const result = await actionProvider.faucet(mockWallet, args);
143
+ expect(result).toBe("Faucet is only allowed on 'base-sepolia' or 'solana-devnet'.");
144
+ });
133
145
  });
134
146
  });
@@ -38,7 +38,10 @@ class CdpWalletActionProvider extends actionProvider_1.ActionProvider {
38
38
  */
39
39
  this.supportsNetwork = (_) => true;
40
40
  if (config.apiKeyName && config.apiKeyPrivateKey) {
41
- coinbase_sdk_1.Coinbase.configure({ apiKeyName: config.apiKeyName, privateKey: config.apiKeyPrivateKey });
41
+ coinbase_sdk_1.Coinbase.configure({
42
+ apiKeyName: config.apiKeyName,
43
+ privateKey: config.apiKeyPrivateKey?.replace(/\\n/g, "\n"),
44
+ });
42
45
  }
43
46
  else {
44
47
  coinbase_sdk_1.Coinbase.configureFromJson();
@@ -7,6 +7,7 @@ export * from "./cdp";
7
7
  export * from "./erc20";
8
8
  export * from "./erc721";
9
9
  export * from "./farcaster";
10
+ export * from "./jupiter";
10
11
  export * from "./pyth";
11
12
  export * from "./moonwell";
12
13
  export * from "./morpho";
@@ -14,3 +15,4 @@ export * from "./spl";
14
15
  export * from "./twitter";
15
16
  export * from "./wallet";
16
17
  export * from "./weth";
18
+ export * from "./wow";
@@ -23,6 +23,7 @@ __exportStar(require("./cdp"), exports);
23
23
  __exportStar(require("./erc20"), exports);
24
24
  __exportStar(require("./erc721"), exports);
25
25
  __exportStar(require("./farcaster"), exports);
26
+ __exportStar(require("./jupiter"), exports);
26
27
  __exportStar(require("./pyth"), exports);
27
28
  __exportStar(require("./moonwell"), exports);
28
29
  __exportStar(require("./morpho"), exports);
@@ -30,3 +31,4 @@ __exportStar(require("./spl"), exports);
30
31
  __exportStar(require("./twitter"), exports);
31
32
  __exportStar(require("./wallet"), exports);
32
33
  __exportStar(require("./weth"), exports);
34
+ __exportStar(require("./wow"), exports);
@@ -0,0 +1 @@
1
+ export * from "./jupiterActionProvider";
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./jupiterActionProvider"), exports);
@@ -0,0 +1,36 @@
1
+ import { ActionProvider } from "../actionProvider";
2
+ import { Network } from "../../network";
3
+ import { SvmWalletProvider } from "../../wallet-providers/svmWalletProvider";
4
+ import { z } from "zod";
5
+ import { SwapTokenSchema } from "./schemas";
6
+ /**
7
+ * JupiterActionProvider handles token swaps using Jupiter's API.
8
+ */
9
+ export declare class JupiterActionProvider extends ActionProvider<SvmWalletProvider> {
10
+ /**
11
+ * Initializes Jupiter API client.
12
+ */
13
+ constructor();
14
+ /**
15
+ * Swaps tokens using Jupiter's API.
16
+ *
17
+ * @param walletProvider - The wallet provider to use for the swap
18
+ * @param args - Swap parameters including input token, output token, and amount
19
+ * @returns A message indicating success or failure with transaction details
20
+ */
21
+ swap(walletProvider: SvmWalletProvider, args: z.infer<typeof SwapTokenSchema>): Promise<string>;
22
+ /**
23
+ * Checks if the action provider supports the given network.
24
+ * Only supports Solana networks.
25
+ *
26
+ * @param network - The network to check support for
27
+ * @returns True if the network is a Solana network
28
+ */
29
+ supportsNetwork(network: Network): boolean;
30
+ }
31
+ /**
32
+ * Factory function to create a new JupiterActionProvider instance.
33
+ *
34
+ * @returns A new JupiterActionProvider instance
35
+ */
36
+ export declare const jupiterActionProvider: () => JupiterActionProvider;
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.jupiterActionProvider = exports.JupiterActionProvider = void 0;
13
+ const actionProvider_1 = require("../actionProvider");
14
+ const svmWalletProvider_1 = require("../../wallet-providers/svmWalletProvider");
15
+ const zod_1 = require("zod");
16
+ const actionDecorator_1 = require("../actionDecorator");
17
+ const schemas_1 = require("./schemas");
18
+ const web3_js_1 = require("@solana/web3.js");
19
+ const api_1 = require("@jup-ag/api");
20
+ /**
21
+ * JupiterActionProvider handles token swaps using Jupiter's API.
22
+ */
23
+ class JupiterActionProvider extends actionProvider_1.ActionProvider {
24
+ /**
25
+ * Initializes Jupiter API client.
26
+ */
27
+ constructor() {
28
+ super("jupiter", []);
29
+ }
30
+ /**
31
+ * Swaps tokens using Jupiter's API.
32
+ *
33
+ * @param walletProvider - The wallet provider to use for the swap
34
+ * @param args - Swap parameters including input token, output token, and amount
35
+ * @returns A message indicating success or failure with transaction details
36
+ */
37
+ async swap(walletProvider, args) {
38
+ try {
39
+ const jupiterApi = (0, api_1.createJupiterApiClient)();
40
+ const userPublicKey = walletProvider.getPublicKey();
41
+ const inputMint = new web3_js_1.PublicKey(args.inputMint);
42
+ const outputMint = new web3_js_1.PublicKey(args.outputMint);
43
+ const { getMint } = await import("@solana/spl-token");
44
+ let mintInfo;
45
+ try {
46
+ mintInfo = await getMint(walletProvider.getConnection(), inputMint);
47
+ }
48
+ catch (error) {
49
+ return `Failed to fetch mint info for mint address ${args.inputMint}. Error: ${error}`;
50
+ }
51
+ const amount = args.amount * 10 ** mintInfo.decimals;
52
+ const quoteResponse = await jupiterApi.quoteGet({
53
+ inputMint: inputMint.toBase58(),
54
+ outputMint: outputMint.toBase58(),
55
+ amount: amount,
56
+ slippageBps: args.slippageBps || 50, // 0.5% default slippage
57
+ });
58
+ if (!quoteResponse) {
59
+ throw new Error("Failed to get a swap quote.");
60
+ }
61
+ const swapRequest = {
62
+ userPublicKey: userPublicKey.toBase58(),
63
+ wrapAndUnwrapSol: true,
64
+ useSharedAccounts: true, // Optimize for low transaction costs
65
+ quoteResponse,
66
+ };
67
+ const swapResponse = await jupiterApi.swapPost({ swapRequest });
68
+ if (!swapResponse || !swapResponse.swapTransaction) {
69
+ throw new Error("Failed to generate swap transaction.");
70
+ }
71
+ const transactionBuffer = Buffer.from(swapResponse.swapTransaction, "base64");
72
+ const tx = web3_js_1.VersionedTransaction.deserialize(transactionBuffer);
73
+ const signature = await walletProvider.signAndSendTransaction(tx);
74
+ await walletProvider.waitForSignatureResult(signature);
75
+ return `Successfully swapped ${args.amount} tokens! Signature: ${signature}`;
76
+ }
77
+ catch (error) {
78
+ return `Error swapping tokens: ${error}`;
79
+ }
80
+ }
81
+ /**
82
+ * Checks if the action provider supports the given network.
83
+ * Only supports Solana networks.
84
+ *
85
+ * @param network - The network to check support for
86
+ * @returns True if the network is a Solana network
87
+ */
88
+ supportsNetwork(network) {
89
+ return network.protocolFamily == "svm" && network.networkId === "solana-mainnet";
90
+ }
91
+ }
92
+ exports.JupiterActionProvider = JupiterActionProvider;
93
+ __decorate([
94
+ (0, actionDecorator_1.CreateAction)({
95
+ name: "swap",
96
+ description: `
97
+ Swaps tokens using Jupiter's DEX aggregator.
98
+ - Input and output tokens must be valid SPL token mints.
99
+ - Ensures sufficient balance before executing swap.
100
+ - If says "SOL" as the input or output, use the mint address So11111111111111111111111111111111111111112
101
+ NOTE: Only available on Solana mainnet.
102
+ `,
103
+ schema: schemas_1.SwapTokenSchema,
104
+ }),
105
+ __metadata("design:type", Function),
106
+ __metadata("design:paramtypes", [svmWalletProvider_1.SvmWalletProvider, void 0]),
107
+ __metadata("design:returntype", Promise)
108
+ ], JupiterActionProvider.prototype, "swap", null);
109
+ /**
110
+ * Factory function to create a new JupiterActionProvider instance.
111
+ *
112
+ * @returns A new JupiterActionProvider instance
113
+ */
114
+ const jupiterActionProvider = () => new JupiterActionProvider();
115
+ exports.jupiterActionProvider = jupiterActionProvider;
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const web3_js_1 = require("@solana/web3.js");
4
+ const jupiterActionProvider_1 = require("./jupiterActionProvider");
5
+ const api_1 = require("@jup-ag/api");
6
+ // Default SPL token decimals for tests
7
+ const DECIMALS = 6;
8
+ // Mock the @solana/web3.js module
9
+ jest.mock("@solana/web3.js", () => ({
10
+ // Preserve the actual implementation of @solana/web3.js while overriding specific methods
11
+ ...jest.requireActual("@solana/web3.js"),
12
+ // Mock the Solana Connection class to prevent real network calls
13
+ Connection: jest.fn(),
14
+ // Mock the VersionedTransaction class and its deserialize method
15
+ VersionedTransaction: {
16
+ deserialize: jest.fn().mockReturnValue({
17
+ // Mock the sign method to prevent actual signing operations
18
+ sign: jest.fn(),
19
+ }),
20
+ },
21
+ // Mock the MessageV0 class and its compile method to return an empty object
22
+ MessageV0: {
23
+ compile: jest.fn().mockReturnValue({}),
24
+ },
25
+ }));
26
+ // Mock the @solana/spl-token module
27
+ jest.mock("@solana/spl-token", () => ({
28
+ // Preserve the actual implementation of @solana/spl-token while overriding specific methods
29
+ ...jest.requireActual("@solana/spl-token"),
30
+ // Mock getMint to always return a fixed decimal value for tokens
31
+ getMint: jest.fn().mockReturnValue({ decimals: DECIMALS }),
32
+ }));
33
+ // Mock the @jup-ag/api module
34
+ jest.mock("@jup-ag/api", () => ({
35
+ // Mock the createJupiterApiClient function to return an object with mocked methods
36
+ createJupiterApiClient: jest.fn().mockReturnValue({
37
+ // Mock the quoteGet method, which fetches the best swap route
38
+ quoteGet: jest.fn(),
39
+ // Mock the swapPost method, which generates the swap transaction
40
+ swapPost: jest.fn(),
41
+ }),
42
+ }));
43
+ // Mock the custom wallet provider used for Solana transactions
44
+ jest.mock("../../wallet-providers/svmWalletProvider");
45
+ describe("JupiterActionProvider", () => {
46
+ let actionProvider;
47
+ let mockWallet;
48
+ let mockConnection;
49
+ let mockJupiterApi;
50
+ let mockQuoteGet;
51
+ let mockSwapPost;
52
+ beforeEach(() => {
53
+ jest.clearAllMocks(); // Reset mocks before each test to ensure no test interference
54
+ // Create a mock Jupiter API client with mocked methods
55
+ mockJupiterApi = (0, api_1.createJupiterApiClient)();
56
+ mockQuoteGet = mockJupiterApi.quoteGet;
57
+ mockSwapPost = mockJupiterApi.swapPost;
58
+ // Initialize the action provider
59
+ actionProvider = new jupiterActionProvider_1.JupiterActionProvider();
60
+ // Mock the Solana connection to avoid real network requests
61
+ mockConnection = {
62
+ getLatestBlockhash: jest.fn().mockResolvedValue({ blockhash: "mockedBlockhash" }),
63
+ };
64
+ // Mock the wallet provider with necessary methods
65
+ mockWallet = {
66
+ getConnection: jest.fn().mockReturnValue(mockConnection), // Return the mocked connection
67
+ getPublicKey: jest.fn().mockReturnValue(new web3_js_1.PublicKey("11111111111111111111111111111111")),
68
+ signAndSendTransaction: jest.fn().mockResolvedValue("mock-signature"),
69
+ waitForSignatureResult: jest.fn().mockResolvedValue({
70
+ context: { slot: 1234 },
71
+ value: { err: null },
72
+ }),
73
+ getAddress: jest.fn().mockReturnValue("11111111111111111111111111111111"),
74
+ getNetwork: jest.fn().mockReturnValue({ protocolFamily: "svm", networkId: "solana-mainnet" }),
75
+ getName: jest.fn().mockReturnValue("mock-wallet"),
76
+ getBalance: jest.fn().mockResolvedValue(BigInt(1000000000)),
77
+ nativeTransfer: jest.fn(),
78
+ };
79
+ });
80
+ /**
81
+ * Test cases for the swap function of JupiterActionProvider
82
+ */
83
+ describe("swap", () => {
84
+ const INPUT_MINT = "So11111111111111111111111111111111111111112"; // Mock SOL mint address
85
+ const OUTPUT_MINT = "BXXkv6FbfHZmKbMmy6KvaakKt6bYjhbjmhvJ92kp92Mw"; // Mock token mint address
86
+ const MOCK_SIGNATURE = "mock-signature";
87
+ // Mock arguments for swapping tokens
88
+ const swapArgs = {
89
+ inputMint: INPUT_MINT,
90
+ outputMint: OUTPUT_MINT,
91
+ amount: 1000, // User-specified amount
92
+ slippageBps: 50, // Slippage tolerance
93
+ };
94
+ /**
95
+ * Test successful token swap execution
96
+ */
97
+ it("should successfully swap tokens", async () => {
98
+ // Mock a successful quote response from Jupiter
99
+ mockQuoteGet.mockResolvedValue({ route: "mock-route" });
100
+ // Mock a successful swap transaction response from Jupiter
101
+ mockSwapPost.mockResolvedValue({
102
+ swapTransaction: Buffer.from("mock-transaction").toString("base64"),
103
+ });
104
+ // Call the swap function
105
+ const result = await actionProvider.swap(mockWallet, swapArgs);
106
+ // Verify that Jupiter was called with correct parameters
107
+ expect(mockQuoteGet).toHaveBeenCalledWith({
108
+ inputMint: INPUT_MINT,
109
+ outputMint: OUTPUT_MINT,
110
+ amount: swapArgs.amount * 10 ** DECIMALS, // Ensure correct decimal conversion
111
+ slippageBps: swapArgs.slippageBps,
112
+ });
113
+ expect(mockSwapPost).toHaveBeenCalled();
114
+ expect(mockWallet.waitForSignatureResult).toHaveBeenCalledWith(MOCK_SIGNATURE);
115
+ expect(result).toContain("Successfully swapped");
116
+ });
117
+ /**
118
+ * Test handling of errors when retrieving a swap quote
119
+ */
120
+ it("should handle swap quote errors", async () => {
121
+ mockQuoteGet.mockRejectedValue(new Error("Quote error")); // Simulate an API failure
122
+ const result = await actionProvider.swap(mockWallet, swapArgs);
123
+ expect(result).toBe("Error swapping tokens: Error: Quote error");
124
+ });
125
+ /**
126
+ * Test handling of errors when posting a swap transaction
127
+ */
128
+ it("should handle swap transaction errors", async () => {
129
+ mockQuoteGet.mockResolvedValue({ route: "mock-route" });
130
+ mockSwapPost.mockRejectedValue(new Error("Swap transaction error")); // Simulate a failure
131
+ const result = await actionProvider.swap(mockWallet, swapArgs);
132
+ expect(result).toBe("Error swapping tokens: Error: Swap transaction error");
133
+ });
134
+ });
135
+ describe("supportsNetwork", () => {
136
+ test.each([
137
+ [{ protocolFamily: "svm", networkId: "solana-mainnet" }, true, "solana mainnet"],
138
+ [{ protocolFamily: "svm", networkId: "solana-devnet" }, false, "solana devnet"],
139
+ [{ protocolFamily: "evm", networkId: "ethereum-mainnet" }, false, "ethereum mainnet"],
140
+ [{ protocolFamily: "evm", networkId: "solana-mainnet" }, false, "wrong protocol family"],
141
+ [{ protocolFamily: "svm", networkId: "ethereum-mainnet" }, false, "wrong network id"],
142
+ ])("should return %p for %s", (network, expected) => {
143
+ expect(actionProvider.supportsNetwork(network)).toBe(expected);
144
+ });
145
+ });
146
+ });
@@ -0,0 +1,20 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Schema for swapping tokens using Jupiter.
4
+ */
5
+ export declare const SwapTokenSchema: z.ZodObject<{
6
+ inputMint: z.ZodString;
7
+ outputMint: z.ZodString;
8
+ amount: z.ZodNumber;
9
+ slippageBps: z.ZodDefault<z.ZodNumber>;
10
+ }, "strip", z.ZodTypeAny, {
11
+ amount: number;
12
+ inputMint: string;
13
+ outputMint: string;
14
+ slippageBps: number;
15
+ }, {
16
+ amount: number;
17
+ inputMint: string;
18
+ outputMint: string;
19
+ slippageBps?: number | undefined;
20
+ }>;