@coinbase/agentkit 0.1.2 → 0.2.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 (40) hide show
  1. package/README.md +319 -5
  2. package/dist/action-providers/erc20/schemas.d.ts +2 -2
  3. package/dist/action-providers/index.d.ts +8 -7
  4. package/dist/action-providers/index.js +8 -7
  5. package/dist/action-providers/morpho/schemas.d.ts +4 -4
  6. package/dist/action-providers/spl/index.d.ts +1 -0
  7. package/dist/action-providers/spl/index.js +17 -0
  8. package/dist/action-providers/spl/schemas.d.ts +17 -0
  9. package/dist/action-providers/spl/schemas.js +14 -0
  10. package/dist/action-providers/spl/splActionProvider.d.ts +37 -0
  11. package/dist/action-providers/spl/splActionProvider.js +112 -0
  12. package/dist/action-providers/spl/splActionProvider.test.d.ts +1 -0
  13. package/dist/action-providers/spl/splActionProvider.test.js +206 -0
  14. package/dist/action-providers/wallet/walletActionProvider.d.ts +1 -1
  15. package/dist/action-providers/wallet/walletActionProvider.js +31 -18
  16. package/dist/action-providers/wallet/walletActionProvider.test.js +101 -23
  17. package/dist/network/index.d.ts +2 -1
  18. package/dist/network/index.js +2 -1
  19. package/dist/network/network.d.ts +7 -0
  20. package/dist/network/network.js +46 -1
  21. package/dist/network/svm.d.ts +14 -0
  22. package/dist/network/svm.js +33 -0
  23. package/dist/utils.d.ts +11 -0
  24. package/dist/utils.js +14 -0
  25. package/dist/wallet-providers/cdpWalletProvider.d.ts +13 -0
  26. package/dist/wallet-providers/cdpWalletProvider.js +14 -7
  27. package/dist/wallet-providers/index.d.ts +3 -0
  28. package/dist/wallet-providers/index.js +3 -0
  29. package/dist/wallet-providers/privyWalletProvider.d.ts +70 -0
  30. package/dist/wallet-providers/privyWalletProvider.js +139 -0
  31. package/dist/wallet-providers/solanaKeypairWalletProvider.d.ts +143 -0
  32. package/dist/wallet-providers/solanaKeypairWalletProvider.js +280 -0
  33. package/dist/wallet-providers/solanaKeypairWalletProvider.test.d.ts +1 -0
  34. package/dist/wallet-providers/solanaKeypairWalletProvider.test.js +24 -0
  35. package/dist/wallet-providers/svmWalletProvider.d.ts +56 -0
  36. package/dist/wallet-providers/svmWalletProvider.js +13 -0
  37. package/dist/wallet-providers/viemWalletProvider.d.ts +15 -1
  38. package/dist/wallet-providers/viemWalletProvider.js +22 -3
  39. package/dist/wallet-providers/walletProvider.d.ts +1 -1
  40. package/package.json +4 -1
@@ -0,0 +1,112 @@
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.splActionProvider = exports.SplActionProvider = 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
+ /**
20
+ * SplActionProvider serves as a provider for SPL token actions.
21
+ * It provides SPL token transfer functionality.
22
+ */
23
+ class SplActionProvider extends actionProvider_1.ActionProvider {
24
+ /**
25
+ * Creates a new SplActionProvider instance.
26
+ */
27
+ constructor() {
28
+ super("spl", []);
29
+ }
30
+ /**
31
+ * Transfer SPL tokens to another address.
32
+ *
33
+ * @param walletProvider - The wallet provider to use for the transfer
34
+ * @param args - Transfer parameters including recipient address, mint address, and amount
35
+ * @returns A message indicating success or failure with transaction details
36
+ */
37
+ async transfer(walletProvider, args) {
38
+ try {
39
+ const connection = walletProvider.getConnection();
40
+ const fromPubkey = walletProvider.getPublicKey();
41
+ const toPubkey = new web3_js_1.PublicKey(args.recipient);
42
+ const mintPubkey = new web3_js_1.PublicKey(args.mintAddress);
43
+ const { getMint, getAssociatedTokenAddress, getAccount, createAssociatedTokenAccountInstruction, createTransferCheckedInstruction, } = await import("@solana/spl-token");
44
+ const mintInfo = await getMint(connection, mintPubkey);
45
+ const adjustedAmount = args.amount * Math.pow(10, mintInfo.decimals);
46
+ const sourceAta = await getAssociatedTokenAddress(mintPubkey, fromPubkey);
47
+ const destinationAta = await getAssociatedTokenAddress(mintPubkey, toPubkey);
48
+ const instructions = [];
49
+ const sourceAccount = await getAccount(connection, sourceAta);
50
+ if (sourceAccount.amount < BigInt(adjustedAmount)) {
51
+ throw new Error(`Insufficient token balance. Have ${sourceAccount.amount}, need ${adjustedAmount}`);
52
+ }
53
+ try {
54
+ await getAccount(connection, destinationAta);
55
+ }
56
+ catch {
57
+ instructions.push(createAssociatedTokenAccountInstruction(fromPubkey, destinationAta, toPubkey, mintPubkey));
58
+ }
59
+ instructions.push(createTransferCheckedInstruction(sourceAta, mintPubkey, destinationAta, fromPubkey, adjustedAmount, mintInfo.decimals));
60
+ const tx = new web3_js_1.VersionedTransaction(web3_js_1.MessageV0.compile({
61
+ payerKey: fromPubkey,
62
+ instructions: instructions,
63
+ recentBlockhash: (await connection.getLatestBlockhash()).blockhash,
64
+ }));
65
+ const signature = await walletProvider.signAndSendTransaction(tx);
66
+ await walletProvider.waitForSignatureResult(signature);
67
+ return [
68
+ `Successfully transferred ${args.amount} tokens to ${args.recipient}`,
69
+ `Token mint: ${args.mintAddress}`,
70
+ `Signature: ${signature}`,
71
+ ].join("\n");
72
+ }
73
+ catch (error) {
74
+ return `Error transferring SPL tokens: ${error}`;
75
+ }
76
+ }
77
+ /**
78
+ * Checks if the action provider supports the given network.
79
+ * Only supports Solana networks.
80
+ *
81
+ * @param network - The network to check support for
82
+ * @returns True if the network is a Solana network
83
+ */
84
+ supportsNetwork(network) {
85
+ return network.protocolFamily === "svm";
86
+ }
87
+ }
88
+ exports.SplActionProvider = SplActionProvider;
89
+ __decorate([
90
+ (0, actionDecorator_1.CreateAction)({
91
+ name: "transfer",
92
+ description: `
93
+ This tool will transfer SPL tokens to another address.
94
+ - Amount should be specified in token units (not raw)
95
+ - Recipient must be a valid Solana address
96
+ - Mint address must be a valid SPL token mint
97
+ - Ensures sufficient token balance before transfer
98
+ - Returns transaction details
99
+ `,
100
+ schema: schemas_1.TransferTokenSchema,
101
+ }),
102
+ __metadata("design:type", Function),
103
+ __metadata("design:paramtypes", [svmWalletProvider_1.SvmWalletProvider, void 0]),
104
+ __metadata("design:returntype", Promise)
105
+ ], SplActionProvider.prototype, "transfer", null);
106
+ /**
107
+ * Factory function to create a new SplActionProvider instance.
108
+ *
109
+ * @returns A new SplActionProvider instance
110
+ */
111
+ const splActionProvider = () => new SplActionProvider();
112
+ exports.splActionProvider = splActionProvider;
@@ -0,0 +1,206 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const web3_js_1 = require("@solana/web3.js");
4
+ const splActionProvider_1 = require("./splActionProvider");
5
+ jest.mock("@solana/web3.js", () => ({
6
+ ...jest.requireActual("@solana/web3.js"),
7
+ Connection: jest.fn(),
8
+ SendTransactionError: jest.fn().mockReturnValue({
9
+ message: "Failed to send",
10
+ toString: () => "Failed to send",
11
+ }),
12
+ VersionedTransaction: jest.fn().mockReturnValue({
13
+ sign: jest.fn(),
14
+ }),
15
+ MessageV0: {
16
+ compile: jest.fn().mockReturnValue({}),
17
+ },
18
+ }));
19
+ jest.mock("@solana/spl-token", () => ({
20
+ getAssociatedTokenAddress: jest.fn(),
21
+ getMint: jest.fn(),
22
+ getAccount: jest.fn(),
23
+ createAssociatedTokenAccountInstruction: jest.fn(),
24
+ createTransferCheckedInstruction: jest.fn(),
25
+ }));
26
+ jest.mock("../../wallet-providers/svmWalletProvider");
27
+ describe("SplActionProvider", () => {
28
+ let actionProvider;
29
+ let mockWallet;
30
+ let mockConnection;
31
+ let mockGetAssociatedTokenAddress;
32
+ let mockGetMint;
33
+ let mockGetAccount;
34
+ /**
35
+ * Set up test environment before each test.
36
+ * Initializes mocks and creates fresh instances of required objects.
37
+ */
38
+ beforeEach(() => {
39
+ jest.clearAllMocks();
40
+ const mocked = jest.requireMock("@solana/spl-token");
41
+ mockGetAssociatedTokenAddress = mocked.getAssociatedTokenAddress;
42
+ mockGetMint = mocked.getMint;
43
+ mockGetAccount = mocked.getAccount;
44
+ mockGetMint.mockResolvedValue({ decimals: 6 });
45
+ mockGetAccount.mockRejectedValue(new Error("getAccount mock not implemented for this test"));
46
+ actionProvider = new splActionProvider_1.SplActionProvider();
47
+ mockConnection = {
48
+ getLatestBlockhash: jest.fn().mockResolvedValue({ blockhash: "mockedBlockhash" }),
49
+ };
50
+ const MOCK_SIGNATURE = "mock-signature";
51
+ const mockSignatureReceipt = {
52
+ context: { slot: 1234 },
53
+ value: { err: null },
54
+ };
55
+ mockWallet = {
56
+ getConnection: jest.fn().mockReturnValue(mockConnection),
57
+ getPublicKey: jest.fn().mockReturnValue(new web3_js_1.PublicKey("11111111111111111111111111111111")),
58
+ signAndSendTransaction: jest.fn().mockResolvedValue(MOCK_SIGNATURE),
59
+ waitForSignatureResult: jest.fn().mockResolvedValue(mockSignatureReceipt),
60
+ getAddress: jest.fn().mockReturnValue("11111111111111111111111111111111"),
61
+ getNetwork: jest.fn().mockReturnValue({ protocolFamily: "svm", networkId: "mainnet" }),
62
+ getName: jest.fn().mockReturnValue("mock-wallet"),
63
+ getBalance: jest.fn().mockResolvedValue(BigInt(1000000000)),
64
+ nativeTransfer: jest.fn(),
65
+ };
66
+ });
67
+ describe("constructor", () => {
68
+ /**
69
+ * Test that the SPL action provider is created with the correct name.
70
+ */
71
+ it("should create a provider with correct name", () => {
72
+ expect(actionProvider["name"]).toBe("spl");
73
+ });
74
+ });
75
+ describe("supportsNetwork", () => {
76
+ /**
77
+ * Test that the provider correctly identifies Solana networks as supported.
78
+ */
79
+ it("should return true for Solana networks", () => {
80
+ const network = {
81
+ protocolFamily: "svm",
82
+ networkId: "solana-mainnet",
83
+ };
84
+ expect(actionProvider.supportsNetwork(network)).toBe(true);
85
+ });
86
+ /**
87
+ * Test that the provider correctly identifies non-Solana networks as unsupported.
88
+ */
89
+ it("should return false for non-Solana networks", () => {
90
+ const network = {
91
+ protocolFamily: "evm",
92
+ networkId: "ethereum-mainnet",
93
+ };
94
+ expect(actionProvider.supportsNetwork(network)).toBe(false);
95
+ });
96
+ });
97
+ describe("transfer", () => {
98
+ const MINT_ADDRESS = "So11111111111111111111111111111111111111112";
99
+ const RECIPIENT_ADDRESS = "DjXsn34uz8yCBQ8bevLrEPYYC1RvhHvjzuVF8opNc4K2";
100
+ const SENDER_ADDRESS = "11111111111111111111111111111111";
101
+ const MOCK_SIGNATURE = "mock-signature";
102
+ const transferArgs = {
103
+ recipient: RECIPIENT_ADDRESS,
104
+ mintAddress: MINT_ADDRESS,
105
+ amount: 100,
106
+ };
107
+ const mockTokenAccount = {
108
+ amount: BigInt(1000000000),
109
+ address: new web3_js_1.PublicKey(MINT_ADDRESS),
110
+ mint: new web3_js_1.PublicKey(MINT_ADDRESS),
111
+ owner: new web3_js_1.PublicKey(RECIPIENT_ADDRESS),
112
+ delegate: null,
113
+ delegatedAmount: BigInt(0),
114
+ closeAuthority: null,
115
+ isFrozen: false,
116
+ isNative: false,
117
+ rentExemptReserve: null,
118
+ isInitialized: true,
119
+ tlvData: new Map(),
120
+ };
121
+ const mockSignatureReceipt = {
122
+ context: { slot: 1234 },
123
+ value: { err: null },
124
+ };
125
+ beforeEach(() => {
126
+ mockWallet.getPublicKey.mockReturnValue(new web3_js_1.PublicKey(SENDER_ADDRESS));
127
+ mockWallet.getAddress.mockReturnValue(SENDER_ADDRESS);
128
+ mockWallet.signAndSendTransaction.mockResolvedValue(MOCK_SIGNATURE);
129
+ mockWallet.waitForSignatureResult.mockResolvedValue(mockSignatureReceipt);
130
+ });
131
+ /**
132
+ * Test successful SPL token transfer with all required steps:
133
+ * - Account validation
134
+ * - Instruction creation
135
+ * - Signing
136
+ * - Sending
137
+ * - Receipt confirmation
138
+ */
139
+ it("should successfully transfer SPL tokens", async () => {
140
+ mockGetAccount.mockResolvedValue(mockTokenAccount);
141
+ const result = await actionProvider.transfer(mockWallet, transferArgs);
142
+ expect(mockGetAssociatedTokenAddress).toHaveBeenNthCalledWith(1, new web3_js_1.PublicKey(transferArgs.mintAddress), new web3_js_1.PublicKey(SENDER_ADDRESS));
143
+ expect(mockGetAssociatedTokenAddress).toHaveBeenNthCalledWith(2, new web3_js_1.PublicKey(transferArgs.mintAddress), new web3_js_1.PublicKey(transferArgs.recipient));
144
+ expect(mockGetMint).toHaveBeenCalledWith(mockConnection, new web3_js_1.PublicKey(transferArgs.mintAddress));
145
+ expect(mockGetAccount).toHaveBeenCalled();
146
+ expect(mockWallet.signAndSendTransaction).toHaveBeenCalled();
147
+ expect(mockWallet.waitForSignatureResult).toHaveBeenCalledWith(MOCK_SIGNATURE);
148
+ expect(result).toContain(`Successfully transferred ${transferArgs.amount} tokens`);
149
+ expect(result).toContain(`to ${transferArgs.recipient}`);
150
+ expect(result).toContain(`Token mint: ${transferArgs.mintAddress}`);
151
+ expect(result).toContain(`Signature: ${MOCK_SIGNATURE}`);
152
+ });
153
+ /**
154
+ * Test handling of insufficient balance.
155
+ * Verifies that the provider properly checks token balances and prevents transfers when funds are insufficient.
156
+ */
157
+ it("should handle insufficient balance", async () => {
158
+ mockGetAccount.mockResolvedValue({
159
+ ...mockTokenAccount,
160
+ amount: BigInt(10000000),
161
+ });
162
+ const result = await actionProvider.transfer(mockWallet, transferArgs);
163
+ expect(result).toBe("Error transferring SPL tokens: Error: Insufficient token balance. Have 10000000, need 100000000");
164
+ });
165
+ /**
166
+ * Test handling of Solana-specific send errors.
167
+ * Verifies that the provider properly handles and reports SendTransactionError instances.
168
+ */
169
+ it("should handle SendTransactionError", async () => {
170
+ mockGetAccount.mockResolvedValue(mockTokenAccount);
171
+ const error = new web3_js_1.SendTransactionError({
172
+ logs: [],
173
+ action: "send",
174
+ signature: "mock-signature",
175
+ transactionMessage: "Failed to send",
176
+ });
177
+ mockWallet.signAndSendTransaction.mockRejectedValue(error);
178
+ const result = await actionProvider.transfer(mockWallet, transferArgs);
179
+ expect(result).toBe("Error transferring SPL tokens: Failed to send");
180
+ });
181
+ /**
182
+ * Test handling of general errors during transfer.
183
+ * Verifies that the provider properly handles and reports unexpected errors.
184
+ */
185
+ it("should handle regular errors", async () => {
186
+ mockGetAccount.mockResolvedValue(mockTokenAccount);
187
+ const error = new Error("Regular error message");
188
+ mockWallet.signAndSendTransaction.mockRejectedValue(error);
189
+ const result = await actionProvider.transfer(mockWallet, transferArgs);
190
+ expect(result).toBe("Error transferring SPL tokens: Error: Regular error message");
191
+ });
192
+ /**
193
+ * Test that ATA is created by default when missing
194
+ */
195
+ it("should create ATA by default when missing", async () => {
196
+ mockGetAccount
197
+ .mockResolvedValueOnce(mockTokenAccount)
198
+ .mockRejectedValueOnce(new Error("Account does not exist"))
199
+ .mockResolvedValue(mockTokenAccount);
200
+ const result = await actionProvider.transfer(mockWallet, transferArgs);
201
+ const { createAssociatedTokenAccountInstruction } = jest.requireMock("@solana/spl-token");
202
+ expect(createAssociatedTokenAccountInstruction).toHaveBeenCalled();
203
+ expect(result).toContain(`Successfully transferred ${transferArgs.amount} tokens`);
204
+ });
205
+ });
206
+ });
@@ -20,7 +20,7 @@ export declare class WalletActionProvider extends ActionProvider {
20
20
  */
21
21
  getWalletDetails(walletProvider: WalletProvider, _: z.infer<typeof GetWalletDetailsSchema>): Promise<string>;
22
22
  /**
23
- * Transfers a specified amount of an asset to a destination onchain.
23
+ * Transfers a specified amount of native currency to a destination onchain.
24
24
  *
25
25
  * @param walletProvider - The wallet provider to transfer from.
26
26
  * @param args - The input arguments for the action.
@@ -10,12 +10,16 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.walletActionProvider = exports.WalletActionProvider = void 0;
13
- const decimal_js_1 = require("decimal.js");
14
13
  const zod_1 = require("zod");
15
14
  const actionDecorator_1 = require("../actionDecorator");
16
15
  const actionProvider_1 = require("../actionProvider");
17
16
  const wallet_providers_1 = require("../../wallet-providers");
18
17
  const schemas_1 = require("./schemas");
18
+ const PROTOCOL_FAMILY_TO_TERMINOLOGY = {
19
+ evm: { unit: "WEI", displayUnit: "ETH", type: "Transaction hash", verb: "transaction" },
20
+ svm: { unit: "LAMPORTS", displayUnit: "SOL", type: "Signature", verb: "transfer" },
21
+ };
22
+ const DEFAULT_TERMINOLOGY = { unit: "", displayUnit: "", type: "Hash", verb: "transfer" };
19
23
  /**
20
24
  * WalletActionProvider provides actions for getting basic wallet information.
21
25
  */
@@ -47,24 +51,24 @@ class WalletActionProvider extends actionProvider_1.ActionProvider {
47
51
  const network = walletProvider.getNetwork();
48
52
  const balance = await walletProvider.getBalance();
49
53
  const name = walletProvider.getName();
50
- // Convert balance from Wei to ETH using Decimal for precision
51
- const ethBalance = new decimal_js_1.Decimal(balance.toString()).div(new decimal_js_1.Decimal(10).pow(18));
52
- return `Wallet Details:
53
- - Provider: ${name}
54
- - Address: ${address}
55
- - Network:
56
- * Protocol Family: ${network.protocolFamily}
57
- * Network ID: ${network.networkId || "N/A"}
58
- * Chain ID: ${network.chainId || "N/A"}
59
- - ETH Balance: ${ethBalance.toFixed(6)} ETH
60
- - Native Balance: ${balance.toString()} WEI`;
54
+ const terminology = PROTOCOL_FAMILY_TO_TERMINOLOGY[network.protocolFamily] || DEFAULT_TERMINOLOGY;
55
+ return [
56
+ "Wallet Details:",
57
+ `- Provider: ${name}`,
58
+ `- Address: ${address}`,
59
+ "- Network:",
60
+ ` * Protocol Family: ${network.protocolFamily}`,
61
+ ` * Network ID: ${network.networkId || "N/A"}`,
62
+ ` * Chain ID: ${network.chainId || "N/A"}`,
63
+ `- Native Balance: ${balance.toString()} ${terminology.unit}`,
64
+ ].join("\n");
61
65
  }
62
66
  catch (error) {
63
67
  return `Error getting wallet details: ${error}`;
64
68
  }
65
69
  }
66
70
  /**
67
- * Transfers a specified amount of an asset to a destination onchain.
71
+ * Transfers a specified amount of native currency to a destination onchain.
68
72
  *
69
73
  * @param walletProvider - The wallet provider to transfer from.
70
74
  * @param args - The input arguments for the action.
@@ -72,11 +76,21 @@ class WalletActionProvider extends actionProvider_1.ActionProvider {
72
76
  */
73
77
  async nativeTransfer(walletProvider, args) {
74
78
  try {
79
+ const { protocolFamily } = walletProvider.getNetwork();
80
+ const terminology = PROTOCOL_FAMILY_TO_TERMINOLOGY[protocolFamily] || DEFAULT_TERMINOLOGY;
81
+ if (protocolFamily === "evm" && !args.to.startsWith("0x")) {
82
+ args.to = `0x${args.to}`;
83
+ }
75
84
  const result = await walletProvider.nativeTransfer(args.to, args.value);
76
- return `Transferred ${args.value} ETH to ${args.to}.\nTransaction hash: ${result}`;
85
+ return [
86
+ `Transferred ${args.value} ${terminology.displayUnit} to ${args.to}`,
87
+ `${terminology.type}: ${result}`,
88
+ ].join("\n");
77
89
  }
78
90
  catch (error) {
79
- return `Error transferring the asset: ${error}`;
91
+ const { protocolFamily } = walletProvider.getNetwork();
92
+ const terminology = PROTOCOL_FAMILY_TO_TERMINOLOGY[protocolFamily] || DEFAULT_TERMINOLOGY;
93
+ return `Error during ${terminology.verb}: ${error}`;
80
94
  }
81
95
  }
82
96
  }
@@ -88,8 +102,7 @@ __decorate([
88
102
  This tool will return the details of the connected wallet including:
89
103
  - Wallet address
90
104
  - Network information (protocol family, network ID, chain ID)
91
- - ETH token balance
92
- - Native token balance
105
+ - Native token balance (ETH for EVM networks, SOL for Solana networks)
93
106
  - Wallet provider name
94
107
  `,
95
108
  schema: schemas_1.GetWalletDetailsSchema,
@@ -105,7 +118,7 @@ __decorate([
105
118
  This tool will transfer native tokens from the wallet to another onchain address.
106
119
 
107
120
  It takes the following inputs:
108
- - amount: The amount to transfer in whole units e.g. 1 ETH or 0.00001 ETH
121
+ - amount: The amount to transfer in whole units (e.g. 1 ETH, 0.1 SOL)
109
122
  - destination: The address to receive the funds
110
123
 
111
124
  Important notes:
@@ -4,41 +4,82 @@ const walletActionProvider_1 = require("./walletActionProvider");
4
4
  const schemas_1 = require("./schemas");
5
5
  describe("Wallet Action Provider", () => {
6
6
  const MOCK_ADDRESS = "0xe6b2af36b3bb8d47206a129ff11d5a2de2a63c83";
7
- const MOCK_BALANCE = 1000000000000000000n; // 1 ETH in wei
8
- const MOCK_NETWORK = {
7
+ const MOCK_ETH_BALANCE = 1000000000000000000n;
8
+ const MOCK_SOL_BALANCE = 1000000000n;
9
+ const MOCK_EVM_NETWORK = {
9
10
  protocolFamily: "evm",
10
11
  networkId: "base-sepolia",
11
12
  chainId: "123",
12
13
  };
14
+ const MOCK_SOLANA_NETWORK = {
15
+ protocolFamily: "svm",
16
+ networkId: "mainnet",
17
+ };
18
+ const MOCK_UNKNOWN_NETWORK = {
19
+ protocolFamily: "unknown",
20
+ networkId: "testnet",
21
+ };
13
22
  const MOCK_PROVIDER_NAME = "TestWallet";
14
23
  const MOCK_TRANSACTION_HASH = "0xghijkl987654321";
24
+ const MOCK_SIGNATURE = "mock-signature";
15
25
  let mockWallet;
16
26
  const actionProvider = (0, walletActionProvider_1.walletActionProvider)();
17
27
  beforeEach(() => {
18
28
  mockWallet = {
19
29
  getAddress: jest.fn().mockReturnValue(MOCK_ADDRESS),
20
- getNetwork: jest.fn().mockReturnValue(MOCK_NETWORK),
21
- getBalance: jest.fn().mockResolvedValue(MOCK_BALANCE),
30
+ getNetwork: jest.fn().mockReturnValue(MOCK_EVM_NETWORK),
31
+ getBalance: jest.fn().mockResolvedValue(MOCK_ETH_BALANCE),
22
32
  getName: jest.fn().mockReturnValue(MOCK_PROVIDER_NAME),
23
33
  nativeTransfer: jest.fn().mockResolvedValue(MOCK_TRANSACTION_HASH),
24
34
  };
25
35
  });
26
36
  describe("getWalletDetails", () => {
27
- it("should successfully get wallet details", async () => {
37
+ it("should show WEI balance for EVM networks", async () => {
38
+ mockWallet.getNetwork.mockReturnValue(MOCK_EVM_NETWORK);
39
+ mockWallet.getBalance.mockResolvedValue(MOCK_ETH_BALANCE);
40
+ const response = await actionProvider.getWalletDetails(mockWallet, {});
41
+ const expectedResponse = [
42
+ "Wallet Details:",
43
+ `- Provider: ${MOCK_PROVIDER_NAME}`,
44
+ `- Address: ${MOCK_ADDRESS}`,
45
+ "- Network:",
46
+ ` * Protocol Family: ${MOCK_EVM_NETWORK.protocolFamily}`,
47
+ ` * Network ID: ${MOCK_EVM_NETWORK.networkId}`,
48
+ ` * Chain ID: ${MOCK_EVM_NETWORK.chainId}`,
49
+ `- Native Balance: ${MOCK_ETH_BALANCE.toString()} WEI`,
50
+ ].join("\n");
51
+ expect(response).toBe(expectedResponse);
52
+ });
53
+ it("should show LAMPORTS balance for Solana networks", async () => {
54
+ mockWallet.getNetwork.mockReturnValue(MOCK_SOLANA_NETWORK);
55
+ mockWallet.getBalance.mockResolvedValue(MOCK_SOL_BALANCE);
56
+ const response = await actionProvider.getWalletDetails(mockWallet, {});
57
+ const expectedResponse = [
58
+ "Wallet Details:",
59
+ `- Provider: ${MOCK_PROVIDER_NAME}`,
60
+ `- Address: ${MOCK_ADDRESS}`,
61
+ "- Network:",
62
+ ` * Protocol Family: ${MOCK_SOLANA_NETWORK.protocolFamily}`,
63
+ ` * Network ID: ${MOCK_SOLANA_NETWORK.networkId}`,
64
+ ` * Chain ID: N/A`,
65
+ `- Native Balance: ${MOCK_SOL_BALANCE.toString()} LAMPORTS`,
66
+ ].join("\n");
67
+ expect(response).toBe(expectedResponse);
68
+ });
69
+ it("should handle unknown protocol families", async () => {
70
+ mockWallet.getNetwork.mockReturnValue(MOCK_UNKNOWN_NETWORK);
71
+ mockWallet.getBalance.mockResolvedValue(MOCK_ETH_BALANCE);
28
72
  const response = await actionProvider.getWalletDetails(mockWallet, {});
29
- expect(mockWallet.getAddress).toHaveBeenCalled();
30
- expect(mockWallet.getNetwork).toHaveBeenCalled();
31
- expect(mockWallet.getBalance).toHaveBeenCalled();
32
- expect(mockWallet.getName).toHaveBeenCalled();
33
- const expectedResponse = `Wallet Details:
34
- - Provider: ${MOCK_PROVIDER_NAME}
35
- - Address: ${MOCK_ADDRESS}
36
- - Network:
37
- * Protocol Family: ${MOCK_NETWORK.protocolFamily}
38
- * Network ID: ${MOCK_NETWORK.networkId}
39
- * Chain ID: ${MOCK_NETWORK.chainId}
40
- - ETH Balance: 1.000000 ETH
41
- - Native Balance: ${MOCK_BALANCE.toString()} WEI`;
73
+ const expectedResponse = [
74
+ "Wallet Details:",
75
+ `- Provider: ${MOCK_PROVIDER_NAME}`,
76
+ `- Address: ${MOCK_ADDRESS}`,
77
+ "- Network:",
78
+ ` * Protocol Family: ${MOCK_UNKNOWN_NETWORK.protocolFamily}`,
79
+ ` * Network ID: ${MOCK_UNKNOWN_NETWORK.networkId}`,
80
+ ` * Chain ID: N/A`,
81
+ `- Native Balance: ${MOCK_ETH_BALANCE.toString()} `,
82
+ ].join("\n");
42
83
  expect(response).toBe(expectedResponse);
43
84
  });
44
85
  it("should handle missing network IDs gracefully", async () => {
@@ -48,6 +89,7 @@ describe("Wallet Action Provider", () => {
48
89
  const response = await actionProvider.getWalletDetails(mockWallet, {});
49
90
  expect(response).toContain("Network ID: N/A");
50
91
  expect(response).toContain("Chain ID: N/A");
92
+ expect(response).toContain(`Native Balance: ${MOCK_ETH_BALANCE.toString()} WEI`);
51
93
  });
52
94
  it("should handle errors when getting wallet details", async () => {
53
95
  const error = new Error("Failed to get wallet details");
@@ -57,7 +99,7 @@ describe("Wallet Action Provider", () => {
57
99
  });
58
100
  });
59
101
  describe("Native Transfer", () => {
60
- const MOCK_AMOUNT = "1.5"; // 1.5 ETH
102
+ const MOCK_AMOUNT = "1.5"; // 1.5 ETH/SOL
61
103
  const MOCK_DESTINATION = "0x321";
62
104
  it("should successfully parse valid input", () => {
63
105
  const validInput = {
@@ -75,16 +117,52 @@ describe("Wallet Action Provider", () => {
75
117
  const result = schemas_1.NativeTransferSchema.safeParse(emptyInput);
76
118
  expect(result.success).toBe(false);
77
119
  });
78
- it("should successfully transfer assets", async () => {
120
+ it("should successfully transfer ETH", async () => {
121
+ mockWallet.getNetwork.mockReturnValue(MOCK_EVM_NETWORK);
122
+ mockWallet.nativeTransfer.mockResolvedValue(MOCK_TRANSACTION_HASH);
79
123
  const args = {
80
124
  to: MOCK_DESTINATION,
81
125
  value: MOCK_AMOUNT,
82
126
  };
83
127
  const response = await actionProvider.nativeTransfer(mockWallet, args);
84
128
  expect(mockWallet.nativeTransfer).toHaveBeenCalledWith(MOCK_DESTINATION, MOCK_AMOUNT);
85
- expect(response).toBe(`Transferred ${MOCK_AMOUNT} ETH to ${MOCK_DESTINATION}.\nTransaction hash: ${MOCK_TRANSACTION_HASH}`);
129
+ expect(response).toBe(`Transferred ${MOCK_AMOUNT} ETH to ${MOCK_DESTINATION}\nTransaction hash: ${MOCK_TRANSACTION_HASH}`);
130
+ });
131
+ it("should successfully transfer SOL", async () => {
132
+ mockWallet.getNetwork.mockReturnValue(MOCK_SOLANA_NETWORK);
133
+ mockWallet.nativeTransfer.mockResolvedValue(MOCK_SIGNATURE);
134
+ const args = {
135
+ to: MOCK_DESTINATION,
136
+ value: MOCK_AMOUNT,
137
+ };
138
+ const response = await actionProvider.nativeTransfer(mockWallet, args);
139
+ expect(mockWallet.nativeTransfer).toHaveBeenCalledWith(MOCK_DESTINATION, MOCK_AMOUNT);
140
+ expect(response).toBe(`Transferred ${MOCK_AMOUNT} SOL to ${MOCK_DESTINATION}\nSignature: ${MOCK_SIGNATURE}`);
141
+ });
142
+ it("should handle ETH transfer errors", async () => {
143
+ mockWallet.getNetwork.mockReturnValue(MOCK_EVM_NETWORK);
144
+ const args = {
145
+ to: MOCK_DESTINATION,
146
+ value: MOCK_AMOUNT,
147
+ };
148
+ const error = new Error("Failed to execute transfer");
149
+ mockWallet.nativeTransfer.mockRejectedValue(error);
150
+ const response = await actionProvider.nativeTransfer(mockWallet, args);
151
+ expect(response).toBe(`Error during transaction: ${error}`);
152
+ });
153
+ it("should handle SOL transfer errors", async () => {
154
+ mockWallet.getNetwork.mockReturnValue(MOCK_SOLANA_NETWORK);
155
+ const args = {
156
+ to: MOCK_DESTINATION,
157
+ value: MOCK_AMOUNT,
158
+ };
159
+ const error = new Error("Failed to execute transfer");
160
+ mockWallet.nativeTransfer.mockRejectedValue(error);
161
+ const response = await actionProvider.nativeTransfer(mockWallet, args);
162
+ expect(response).toBe(`Error during transfer: ${error}`);
86
163
  });
87
- it("should handle transfer errors", async () => {
164
+ it("should handle unknown protocol family transfer errors", async () => {
165
+ mockWallet.getNetwork.mockReturnValue(MOCK_UNKNOWN_NETWORK);
88
166
  const args = {
89
167
  to: MOCK_DESTINATION,
90
168
  value: MOCK_AMOUNT,
@@ -92,7 +170,7 @@ describe("Wallet Action Provider", () => {
92
170
  const error = new Error("Failed to execute transfer");
93
171
  mockWallet.nativeTransfer.mockRejectedValue(error);
94
172
  const response = await actionProvider.nativeTransfer(mockWallet, args);
95
- expect(response).toBe(`Error transferring the asset: ${error}`);
173
+ expect(response).toBe(`Error during transfer: ${error}`);
96
174
  });
97
175
  });
98
176
  describe("supportsNetwork", () => {
@@ -1,2 +1,3 @@
1
- export * from "./types";
2
1
  export * from "./network";
2
+ export * from "./svm";
3
+ export * from "./types";
@@ -14,5 +14,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./types"), exports);
18
17
  __exportStar(require("./network"), exports);
18
+ __exportStar(require("./svm"), exports);
19
+ __exportStar(require("./types"), exports);
@@ -11,3 +11,10 @@ export declare const NETWORK_ID_TO_CHAIN_ID: Record<string, string>;
11
11
  * Maps Coinbase network IDs to Viem chain objects
12
12
  */
13
13
  export declare const NETWORK_ID_TO_VIEM_CHAIN: Record<string, Chain>;
14
+ /**
15
+ * Get a chain from the viem chains object
16
+ *
17
+ * @param id - The chain ID
18
+ * @returns The chain
19
+ */
20
+ export declare const getChain: (id: string) => Chain;