@coinbase/agentkit 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +388 -5
- package/dist/action-providers/erc20/schemas.d.ts +2 -2
- package/dist/action-providers/index.d.ts +8 -7
- package/dist/action-providers/index.js +8 -7
- package/dist/action-providers/morpho/schemas.d.ts +4 -4
- package/dist/action-providers/spl/index.d.ts +1 -0
- package/dist/action-providers/spl/index.js +17 -0
- package/dist/action-providers/spl/schemas.d.ts +30 -0
- package/dist/action-providers/spl/schemas.js +26 -0
- package/dist/action-providers/spl/splActionProvider.d.ts +45 -0
- package/dist/action-providers/spl/splActionProvider.js +160 -0
- package/dist/action-providers/spl/splActionProvider.test.d.ts +1 -0
- package/dist/action-providers/spl/splActionProvider.test.js +263 -0
- package/dist/action-providers/wallet/walletActionProvider.d.ts +1 -1
- package/dist/action-providers/wallet/walletActionProvider.js +31 -18
- package/dist/action-providers/wallet/walletActionProvider.test.js +101 -23
- package/dist/network/index.d.ts +2 -1
- package/dist/network/index.js +2 -1
- package/dist/network/network.d.ts +7 -0
- package/dist/network/network.js +46 -1
- package/dist/network/svm.d.ts +15 -0
- package/dist/network/svm.js +38 -0
- package/dist/utils.d.ts +11 -0
- package/dist/utils.js +14 -0
- package/dist/wallet-providers/cdpWalletProvider.d.ts +13 -0
- package/dist/wallet-providers/cdpWalletProvider.js +14 -7
- package/dist/wallet-providers/index.d.ts +5 -0
- package/dist/wallet-providers/index.js +5 -0
- package/dist/wallet-providers/privyEvmWalletProvider.d.ts +55 -0
- package/dist/wallet-providers/privyEvmWalletProvider.js +140 -0
- package/dist/wallet-providers/privyShared.d.ts +40 -0
- package/dist/wallet-providers/privyShared.js +49 -0
- package/dist/wallet-providers/privySvmWalletProvider.d.ts +128 -0
- package/dist/wallet-providers/privySvmWalletProvider.js +212 -0
- package/dist/wallet-providers/privyWalletProvider.d.ts +35 -0
- package/dist/wallet-providers/privyWalletProvider.js +39 -0
- package/dist/wallet-providers/solanaKeypairWalletProvider.d.ts +143 -0
- package/dist/wallet-providers/solanaKeypairWalletProvider.js +280 -0
- package/dist/wallet-providers/solanaKeypairWalletProvider.test.d.ts +1 -0
- package/dist/wallet-providers/solanaKeypairWalletProvider.test.js +24 -0
- package/dist/wallet-providers/svmWalletProvider.d.ts +56 -0
- package/dist/wallet-providers/svmWalletProvider.js +13 -0
- package/dist/wallet-providers/viemWalletProvider.d.ts +15 -1
- package/dist/wallet-providers/viemWalletProvider.js +22 -3
- package/dist/wallet-providers/walletProvider.d.ts +1 -1
- package/package.json +4 -1
|
@@ -0,0 +1,160 @@
|
|
|
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
|
+
* Get the balance of SPL tokens for an address.
|
|
32
|
+
*
|
|
33
|
+
* @param walletProvider - The wallet provider to use
|
|
34
|
+
* @param args - Parameters including mint address and optional target address
|
|
35
|
+
* @returns A message indicating the token balance
|
|
36
|
+
*/
|
|
37
|
+
async getBalance(walletProvider, args) {
|
|
38
|
+
try {
|
|
39
|
+
const connection = walletProvider.getConnection();
|
|
40
|
+
const mintPubkey = new web3_js_1.PublicKey(args.mintAddress);
|
|
41
|
+
const ownerPubkey = args.address
|
|
42
|
+
? new web3_js_1.PublicKey(args.address)
|
|
43
|
+
: walletProvider.getPublicKey();
|
|
44
|
+
const { getMint, getAssociatedTokenAddress, getAccount } = await import("@solana/spl-token");
|
|
45
|
+
const mintInfo = await getMint(connection, mintPubkey);
|
|
46
|
+
const ata = await getAssociatedTokenAddress(mintPubkey, ownerPubkey);
|
|
47
|
+
try {
|
|
48
|
+
const account = await getAccount(connection, ata);
|
|
49
|
+
const balance = Number(account.amount) / Math.pow(10, mintInfo.decimals);
|
|
50
|
+
return `Balance for ${args.address || "connected wallet"} is ${balance} tokens`;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
if (error.message.includes("could not find account")) {
|
|
54
|
+
return `Balance for ${args.address || "connected wallet"} is 0 tokens`;
|
|
55
|
+
}
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
return `Error getting SPL token balance: ${error}`;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Transfer SPL tokens to another address.
|
|
65
|
+
*
|
|
66
|
+
* @param walletProvider - The wallet provider to use for the transfer
|
|
67
|
+
* @param args - Transfer parameters including recipient address, mint address, and amount
|
|
68
|
+
* @returns A message indicating success or failure with transaction details
|
|
69
|
+
*/
|
|
70
|
+
async transfer(walletProvider, args) {
|
|
71
|
+
try {
|
|
72
|
+
const connection = walletProvider.getConnection();
|
|
73
|
+
const fromPubkey = walletProvider.getPublicKey();
|
|
74
|
+
const toPubkey = new web3_js_1.PublicKey(args.recipient);
|
|
75
|
+
const mintPubkey = new web3_js_1.PublicKey(args.mintAddress);
|
|
76
|
+
const { getMint, getAssociatedTokenAddress, getAccount, createAssociatedTokenAccountInstruction, createTransferCheckedInstruction, } = await import("@solana/spl-token");
|
|
77
|
+
const mintInfo = await getMint(connection, mintPubkey);
|
|
78
|
+
const adjustedAmount = args.amount * Math.pow(10, mintInfo.decimals);
|
|
79
|
+
const sourceAta = await getAssociatedTokenAddress(mintPubkey, fromPubkey);
|
|
80
|
+
const destinationAta = await getAssociatedTokenAddress(mintPubkey, toPubkey);
|
|
81
|
+
const instructions = [];
|
|
82
|
+
const sourceAccount = await getAccount(connection, sourceAta);
|
|
83
|
+
if (sourceAccount.amount < BigInt(adjustedAmount)) {
|
|
84
|
+
throw new Error(`Insufficient token balance. Have ${sourceAccount.amount}, need ${adjustedAmount}`);
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
await getAccount(connection, destinationAta);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
instructions.push(createAssociatedTokenAccountInstruction(fromPubkey, destinationAta, toPubkey, mintPubkey));
|
|
91
|
+
}
|
|
92
|
+
instructions.push(createTransferCheckedInstruction(sourceAta, mintPubkey, destinationAta, fromPubkey, adjustedAmount, mintInfo.decimals));
|
|
93
|
+
const tx = new web3_js_1.VersionedTransaction(web3_js_1.MessageV0.compile({
|
|
94
|
+
payerKey: fromPubkey,
|
|
95
|
+
instructions: instructions,
|
|
96
|
+
recentBlockhash: (await connection.getLatestBlockhash()).blockhash,
|
|
97
|
+
}));
|
|
98
|
+
const signature = await walletProvider.signAndSendTransaction(tx);
|
|
99
|
+
await walletProvider.waitForSignatureResult(signature);
|
|
100
|
+
return [
|
|
101
|
+
`Successfully transferred ${args.amount} tokens to ${args.recipient}`,
|
|
102
|
+
`Token mint: ${args.mintAddress}`,
|
|
103
|
+
`Signature: ${signature}`,
|
|
104
|
+
].join("\n");
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
return `Error transferring SPL tokens: ${error}`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Checks if the action provider supports the given network.
|
|
112
|
+
* Only supports Solana networks.
|
|
113
|
+
*
|
|
114
|
+
* @param network - The network to check support for
|
|
115
|
+
* @returns True if the network is a Solana network
|
|
116
|
+
*/
|
|
117
|
+
supportsNetwork(network) {
|
|
118
|
+
return network.protocolFamily === "svm";
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
exports.SplActionProvider = SplActionProvider;
|
|
122
|
+
__decorate([
|
|
123
|
+
(0, actionDecorator_1.CreateAction)({
|
|
124
|
+
name: "get_balance",
|
|
125
|
+
description: `
|
|
126
|
+
This tool will get the balance of SPL tokens for an address.
|
|
127
|
+
- Mint address must be a valid SPL token mint
|
|
128
|
+
- If no address is provided, uses the connected wallet's address
|
|
129
|
+
- Returns the token balance in token units (not raw)
|
|
130
|
+
`,
|
|
131
|
+
schema: schemas_1.GetBalanceSchema,
|
|
132
|
+
}),
|
|
133
|
+
__metadata("design:type", Function),
|
|
134
|
+
__metadata("design:paramtypes", [svmWalletProvider_1.SvmWalletProvider, void 0]),
|
|
135
|
+
__metadata("design:returntype", Promise)
|
|
136
|
+
], SplActionProvider.prototype, "getBalance", null);
|
|
137
|
+
__decorate([
|
|
138
|
+
(0, actionDecorator_1.CreateAction)({
|
|
139
|
+
name: "transfer",
|
|
140
|
+
description: `
|
|
141
|
+
This tool will transfer SPL tokens to another address.
|
|
142
|
+
- Amount should be specified in token units (not raw)
|
|
143
|
+
- Recipient must be a valid Solana address
|
|
144
|
+
- Mint address must be a valid SPL token mint
|
|
145
|
+
- Ensures sufficient token balance before transfer
|
|
146
|
+
- Returns transaction details
|
|
147
|
+
`,
|
|
148
|
+
schema: schemas_1.TransferTokenSchema,
|
|
149
|
+
}),
|
|
150
|
+
__metadata("design:type", Function),
|
|
151
|
+
__metadata("design:paramtypes", [svmWalletProvider_1.SvmWalletProvider, void 0]),
|
|
152
|
+
__metadata("design:returntype", Promise)
|
|
153
|
+
], SplActionProvider.prototype, "transfer", null);
|
|
154
|
+
/**
|
|
155
|
+
* Factory function to create a new SplActionProvider instance.
|
|
156
|
+
*
|
|
157
|
+
* @returns A new SplActionProvider instance
|
|
158
|
+
*/
|
|
159
|
+
const splActionProvider = () => new SplActionProvider();
|
|
160
|
+
exports.splActionProvider = splActionProvider;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,263 @@
|
|
|
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
|
+
describe("getBalance", () => {
|
|
207
|
+
const MINT_ADDRESS = "So11111111111111111111111111111111111111112";
|
|
208
|
+
const TARGET_ADDRESS = "DjXsn34uz8yCBQ8bevLrEPYYC1RvhHvjzuVF8opNc4K2";
|
|
209
|
+
const SENDER_ADDRESS = "11111111111111111111111111111111";
|
|
210
|
+
const balanceArgs = {
|
|
211
|
+
mintAddress: MINT_ADDRESS,
|
|
212
|
+
};
|
|
213
|
+
const balanceWithAddressArgs = {
|
|
214
|
+
mintAddress: MINT_ADDRESS,
|
|
215
|
+
address: TARGET_ADDRESS,
|
|
216
|
+
};
|
|
217
|
+
const mockTokenAccount = {
|
|
218
|
+
amount: BigInt(1000000000),
|
|
219
|
+
address: new web3_js_1.PublicKey(MINT_ADDRESS),
|
|
220
|
+
mint: new web3_js_1.PublicKey(MINT_ADDRESS),
|
|
221
|
+
owner: new web3_js_1.PublicKey(TARGET_ADDRESS),
|
|
222
|
+
delegate: null,
|
|
223
|
+
delegatedAmount: BigInt(0),
|
|
224
|
+
closeAuthority: null,
|
|
225
|
+
isFrozen: false,
|
|
226
|
+
isNative: false,
|
|
227
|
+
rentExemptReserve: null,
|
|
228
|
+
isInitialized: true,
|
|
229
|
+
tlvData: new Map(),
|
|
230
|
+
};
|
|
231
|
+
beforeEach(() => {
|
|
232
|
+
mockWallet.getPublicKey.mockReturnValue(new web3_js_1.PublicKey(SENDER_ADDRESS));
|
|
233
|
+
mockWallet.getAddress.mockReturnValue(SENDER_ADDRESS);
|
|
234
|
+
});
|
|
235
|
+
it("should get balance for connected wallet", async () => {
|
|
236
|
+
mockGetAccount.mockResolvedValue(mockTokenAccount);
|
|
237
|
+
const result = await actionProvider.getBalance(mockWallet, balanceArgs);
|
|
238
|
+
expect(mockGetAssociatedTokenAddress).toHaveBeenCalledWith(new web3_js_1.PublicKey(balanceArgs.mintAddress), new web3_js_1.PublicKey(SENDER_ADDRESS));
|
|
239
|
+
expect(mockGetMint).toHaveBeenCalledWith(mockConnection, new web3_js_1.PublicKey(balanceArgs.mintAddress));
|
|
240
|
+
expect(mockGetAccount).toHaveBeenCalled();
|
|
241
|
+
expect(result).toBe("Balance for connected wallet is 1000 tokens");
|
|
242
|
+
});
|
|
243
|
+
it("should get balance for specified address", async () => {
|
|
244
|
+
mockGetAccount.mockResolvedValue(mockTokenAccount);
|
|
245
|
+
const result = await actionProvider.getBalance(mockWallet, balanceWithAddressArgs);
|
|
246
|
+
expect(mockGetAssociatedTokenAddress).toHaveBeenCalledWith(new web3_js_1.PublicKey(balanceWithAddressArgs.mintAddress), new web3_js_1.PublicKey(balanceWithAddressArgs.address));
|
|
247
|
+
expect(mockGetMint).toHaveBeenCalledWith(mockConnection, new web3_js_1.PublicKey(balanceWithAddressArgs.mintAddress));
|
|
248
|
+
expect(mockGetAccount).toHaveBeenCalled();
|
|
249
|
+
expect(result).toBe(`Balance for ${TARGET_ADDRESS} is 1000 tokens`);
|
|
250
|
+
});
|
|
251
|
+
it("should handle non-existent token account", async () => {
|
|
252
|
+
mockGetAccount.mockRejectedValue(new Error("could not find account"));
|
|
253
|
+
const result = await actionProvider.getBalance(mockWallet, balanceArgs);
|
|
254
|
+
expect(result).toBe("Balance for connected wallet is 0 tokens");
|
|
255
|
+
});
|
|
256
|
+
it("should handle errors", async () => {
|
|
257
|
+
const error = new Error("Test error");
|
|
258
|
+
mockGetAccount.mockRejectedValue(error);
|
|
259
|
+
const result = await actionProvider.getBalance(mockWallet, balanceArgs);
|
|
260
|
+
expect(result).toBe("Error getting SPL token balance: Error: Test error");
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
});
|
|
@@ -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
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
- Network:
|
|
56
|
-
* Protocol Family: ${network.protocolFamily}
|
|
57
|
-
* Network ID: ${network.networkId || "N/A"}
|
|
58
|
-
* Chain ID: ${network.chainId || "N/A"}
|
|
59
|
-
|
|
60
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
-
|
|
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
|
|
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:
|