@coinbase/agentkit 0.0.0-nightly-20250903210403 → 0.0.0-nightly-20250905210407
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 +4 -0
- package/dist/action-providers/across/acrossActionProvider.js +3 -3
- package/dist/action-providers/cdp/cdpEvmWalletActionProvider.js +3 -1
- package/dist/action-providers/cdp/cdpSmartWalletActionProvider.js +4 -2
- package/dist/action-providers/compound/constants.d.ts +1 -1
- package/dist/action-providers/compound/constants.js +2 -2
- package/dist/action-providers/erc20/constants.d.ts +35 -135
- package/dist/action-providers/erc20/constants.js +37 -189
- package/dist/action-providers/erc20/erc20ActionProvider.d.ts +9 -1
- package/dist/action-providers/erc20/erc20ActionProvider.js +87 -35
- package/dist/action-providers/erc20/erc20ActionProvider.test.js +115 -52
- package/dist/action-providers/erc20/schemas.d.ts +25 -12
- package/dist/action-providers/erc20/schemas.js +34 -6
- package/dist/action-providers/erc20/utils.d.ts +19 -0
- package/dist/action-providers/erc20/utils.js +54 -0
- package/dist/action-providers/flaunch/constants.d.ts +1 -1
- package/dist/action-providers/flaunch/constants.js +2 -2
- package/dist/action-providers/moonwell/schemas.d.ts +2 -2
- package/dist/action-providers/morpho/morphoActionProvider.js +5 -5
- package/dist/action-providers/morpho/schemas.d.ts +2 -2
- package/dist/action-providers/superfluid/superfluidSuperTokenCreatorActionProvider.js +4 -4
- package/dist/action-providers/superfluid/superfluidWrapperActionProvider.js +3 -3
- package/dist/action-providers/superfluid/superfluidWrapperActionProvider.test.js +2 -2
- package/dist/action-providers/truemarkets/truemarketsActionProvider.js +10 -10
- package/dist/action-providers/wallet/walletActionProvider.js +21 -10
- package/dist/action-providers/wallet/walletActionProvider.test.js +6 -2
- package/dist/action-providers/zeroX/zeroXActionProvider.js +2 -0
- package/dist/wallet-providers/cdpEvmWalletProvider.d.ts +1 -1
- package/dist/wallet-providers/cdpEvmWalletProvider.js +1 -1
- package/dist/wallet-providers/cdpSmartWalletProvider.d.ts +1 -1
- package/dist/wallet-providers/cdpSmartWalletProvider.js +1 -1
- package/dist/wallet-providers/cdpSolanaWalletProvider.d.ts +1 -1
- package/dist/wallet-providers/cdpSolanaWalletProvider.js +7 -7
- package/dist/wallet-providers/cdpSolanaWalletProvider.test.js +15 -12
- package/dist/wallet-providers/legacyCdpSmartWalletProvider.d.ts +1 -1
- package/dist/wallet-providers/legacyCdpSmartWalletProvider.js +1 -1
- package/dist/wallet-providers/legacyCdpWalletProvider.d.ts +1 -1
- package/dist/wallet-providers/legacyCdpWalletProvider.js +1 -1
- package/dist/wallet-providers/privyEvmDelegatedEmbeddedWalletProvider.d.ts +1 -1
- package/dist/wallet-providers/privyEvmDelegatedEmbeddedWalletProvider.js +2 -2
- package/dist/wallet-providers/privyEvmDelegatedEmbeddedWalletProvider.test.js +1 -1
- package/dist/wallet-providers/privyEvmWalletProvider.test.js +1 -1
- package/dist/wallet-providers/solanaKeypairWalletProvider.d.ts +1 -1
- package/dist/wallet-providers/solanaKeypairWalletProvider.js +3 -4
- package/dist/wallet-providers/solanaKeypairWalletProvider.test.js +4 -2
- package/dist/wallet-providers/viemWalletProvider.d.ts +1 -1
- package/dist/wallet-providers/viemWalletProvider.js +2 -2
- package/dist/wallet-providers/viemWalletProvider.test.js +6 -5
- package/dist/wallet-providers/walletProvider.d.ts +1 -1
- package/dist/wallet-providers/zeroDevWalletProvider.d.ts +1 -1
- package/dist/wallet-providers/zeroDevWalletProvider.js +4 -4
- package/dist/wallet-providers/zeroDevWalletProvider.test.js +2 -2
- package/package.json +1 -1
|
@@ -15,6 +15,7 @@ const actionProvider_1 = require("../actionProvider");
|
|
|
15
15
|
const actionDecorator_1 = require("../actionDecorator");
|
|
16
16
|
const schemas_1 = require("./schemas");
|
|
17
17
|
const constants_1 = require("./constants");
|
|
18
|
+
const utils_1 = require("./utils");
|
|
18
19
|
const viem_1 = require("viem");
|
|
19
20
|
const wallet_providers_1 = require("../../wallet-providers");
|
|
20
21
|
/**
|
|
@@ -42,24 +43,12 @@ class ERC20ActionProvider extends actionProvider_1.ActionProvider {
|
|
|
42
43
|
* @returns A message containing the balance.
|
|
43
44
|
*/
|
|
44
45
|
async getBalance(walletProvider, args) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
functionName: "balanceOf",
|
|
50
|
-
args: [walletProvider.getAddress()],
|
|
51
|
-
});
|
|
52
|
-
const decimals = await walletProvider.readContract({
|
|
53
|
-
address: args.contractAddress,
|
|
54
|
-
abi: constants_1.abi,
|
|
55
|
-
functionName: "decimals",
|
|
56
|
-
args: [],
|
|
57
|
-
});
|
|
58
|
-
return `Balance of ${args.contractAddress} is ${(0, viem_1.formatUnits)(balance, decimals)}`;
|
|
59
|
-
}
|
|
60
|
-
catch (error) {
|
|
61
|
-
return `Error getting balance: ${error}`;
|
|
46
|
+
const address = args.address || walletProvider.getAddress();
|
|
47
|
+
const tokenDetails = await (0, utils_1.getTokenDetails)(walletProvider, args.tokenAddress, args.address);
|
|
48
|
+
if (!tokenDetails) {
|
|
49
|
+
return `Error: Could not fetch token details for ${args.tokenAddress}`;
|
|
62
50
|
}
|
|
51
|
+
return `Balance of ${tokenDetails.name} (${args.tokenAddress}) at address ${address} is ${tokenDetails.formattedBalance}`;
|
|
63
52
|
}
|
|
64
53
|
/**
|
|
65
54
|
* Transfers a specified amount of an ERC20 token to a destination onchain.
|
|
@@ -70,11 +59,36 @@ class ERC20ActionProvider extends actionProvider_1.ActionProvider {
|
|
|
70
59
|
*/
|
|
71
60
|
async transfer(walletProvider, args) {
|
|
72
61
|
try {
|
|
62
|
+
// Check token details
|
|
63
|
+
const tokenAddress = (0, viem_1.getAddress)(args.tokenAddress);
|
|
64
|
+
const tokenDetails = await (0, utils_1.getTokenDetails)(walletProvider, args.tokenAddress);
|
|
65
|
+
if (!tokenDetails) {
|
|
66
|
+
return `Error: Could not fetch token details for ${args.tokenAddress}. Please verify the token address is correct.`;
|
|
67
|
+
}
|
|
68
|
+
// Check token balance
|
|
69
|
+
const amountInWei = (0, viem_1.parseUnits)(String(args.amount), tokenDetails.decimals);
|
|
70
|
+
if (tokenDetails.balance < amountInWei) {
|
|
71
|
+
return `Error: Insufficient ${tokenDetails.name} (${args.tokenAddress}) token balance. Requested to send ${args.amount} of ${tokenDetails.name} (${args.tokenAddress}), but only ${tokenDetails.formattedBalance} is available.`;
|
|
72
|
+
}
|
|
73
|
+
// Guardrails to prevent loss of funds
|
|
74
|
+
if (args.tokenAddress === args.destinationAddress) {
|
|
75
|
+
return "Error: Transfer destination is the token contract address. Refusing transfer to prevent loss of funds.";
|
|
76
|
+
}
|
|
77
|
+
if ((await walletProvider
|
|
78
|
+
.getPublicClient()
|
|
79
|
+
.getCode({ address: args.destinationAddress })) !== "0x") {
|
|
80
|
+
// If destination address is a contract, check if its an ERC20 token
|
|
81
|
+
// This assumes if the contract implements name, balance and decimals functions, it is an ERC20 token
|
|
82
|
+
const destinationTokenDetails = await (0, utils_1.getTokenDetails)(walletProvider, args.destinationAddress);
|
|
83
|
+
if (destinationTokenDetails) {
|
|
84
|
+
return "Error: Transfer destination is an ERC20 token contract. Refusing to transfer to prevent loss of funds.";
|
|
85
|
+
}
|
|
86
|
+
// If contract but not an ERC20 token (e.g a smart wallet), allow the transfer
|
|
87
|
+
}
|
|
73
88
|
// Check if we can do gasless transfer
|
|
74
|
-
const
|
|
89
|
+
const isLegacyCdpWallet = walletProvider.getName() === "legacy_cdp_wallet_provider";
|
|
75
90
|
const network = walletProvider.getNetwork();
|
|
76
|
-
const
|
|
77
|
-
const canDoGasless = isCdpWallet &&
|
|
91
|
+
const canDoGasless = isLegacyCdpWallet &&
|
|
78
92
|
((network.networkId === "base-mainnet" && constants_1.BaseTokenToAssetId.has(tokenAddress)) ||
|
|
79
93
|
(network.networkId === "base-sepolia" && constants_1.BaseSepoliaTokenToAssetId.has(tokenAddress)));
|
|
80
94
|
if (canDoGasless) {
|
|
@@ -83,33 +97,59 @@ class ERC20ActionProvider extends actionProvider_1.ActionProvider {
|
|
|
83
97
|
const assetId = network.networkId === "base-mainnet"
|
|
84
98
|
? constants_1.BaseTokenToAssetId.get(tokenAddress)
|
|
85
99
|
: constants_1.BaseSepoliaTokenToAssetId.get(tokenAddress);
|
|
86
|
-
const hash = await cdpWallet.gaslessERC20Transfer(assetId, args.
|
|
100
|
+
const hash = await cdpWallet.gaslessERC20Transfer(assetId, args.destinationAddress, BigInt(args.amount));
|
|
87
101
|
await walletProvider.waitForTransactionReceipt(hash);
|
|
88
|
-
return `Transferred ${args.amount} of ${args.
|
|
102
|
+
return `Transferred ${args.amount} of ${args.tokenAddress} to ${args.destinationAddress} using gasless transfer.\nTransaction hash: ${hash}`;
|
|
89
103
|
}
|
|
90
104
|
// Fallback to regular transfer
|
|
91
105
|
const hash = await walletProvider.sendTransaction({
|
|
92
|
-
to: args.
|
|
106
|
+
to: args.tokenAddress,
|
|
93
107
|
data: (0, viem_1.encodeFunctionData)({
|
|
94
|
-
abi:
|
|
108
|
+
abi: viem_1.erc20Abi,
|
|
95
109
|
functionName: "transfer",
|
|
96
|
-
args: [args.
|
|
110
|
+
args: [args.destinationAddress, amountInWei],
|
|
97
111
|
}),
|
|
98
112
|
});
|
|
99
113
|
await walletProvider.waitForTransactionReceipt(hash);
|
|
100
|
-
return `Transferred ${args.amount} of ${args.
|
|
114
|
+
return `Transferred ${args.amount} of ${tokenDetails?.name} (${args.tokenAddress}) to ${args.destinationAddress}.\nTransaction hash for the transfer: ${hash}`;
|
|
101
115
|
}
|
|
102
116
|
catch (error) {
|
|
103
117
|
return `Error transferring the asset: ${error}`;
|
|
104
118
|
}
|
|
105
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Gets the contract address for a token symbol on the current network.
|
|
122
|
+
*
|
|
123
|
+
* @param walletProvider - The wallet provider to get the network from.
|
|
124
|
+
* @param args - The input arguments for the action.
|
|
125
|
+
* @returns A message containing the token address or an error if not found.
|
|
126
|
+
*/
|
|
127
|
+
async getTokenAddress(walletProvider, args) {
|
|
128
|
+
const network = walletProvider.getNetwork();
|
|
129
|
+
const networkTokens = constants_1.TOKEN_ADDRESSES_BY_SYMBOLS[network.networkId ?? ""];
|
|
130
|
+
const tokenAddress = networkTokens?.[args.symbol];
|
|
131
|
+
if (tokenAddress) {
|
|
132
|
+
return `Token address for ${args.symbol} on ${network.networkId}: ${tokenAddress}`;
|
|
133
|
+
}
|
|
134
|
+
// Get available token symbols for the current network
|
|
135
|
+
const availableSymbols = networkTokens ? Object.keys(networkTokens) : [];
|
|
136
|
+
const availableSymbolsText = availableSymbols.length > 0
|
|
137
|
+
? ` Available token symbols on ${network.networkId}: ${availableSymbols.join(", ")}`
|
|
138
|
+
: ` No token symbols are configured for ${network.networkId}`;
|
|
139
|
+
return `Error: Token symbol "${args.symbol}" not found on ${network.networkId}.${availableSymbolsText}`;
|
|
140
|
+
}
|
|
106
141
|
}
|
|
107
142
|
exports.ERC20ActionProvider = ERC20ActionProvider;
|
|
108
143
|
__decorate([
|
|
109
144
|
(0, actionDecorator_1.CreateAction)({
|
|
110
145
|
name: "get_balance",
|
|
111
146
|
description: `
|
|
112
|
-
This tool will get the balance of an ERC20
|
|
147
|
+
This tool will get the balance of an ERC20 token for a given address.
|
|
148
|
+
It takes the following inputs:
|
|
149
|
+
- tokenAddress: The contract address of the token to get the balance for
|
|
150
|
+
- address: (Optional) The address to check the balance for. If not provided, uses the wallet's address
|
|
151
|
+
Important notes:
|
|
152
|
+
- Never assume token or address, they have to be provided as inputs. If only token symbol is provided, use the get_token_address tool to get the token address first
|
|
113
153
|
`,
|
|
114
154
|
schema: schemas_1.GetBalanceSchema,
|
|
115
155
|
}),
|
|
@@ -121,22 +161,34 @@ __decorate([
|
|
|
121
161
|
(0, actionDecorator_1.CreateAction)({
|
|
122
162
|
name: "transfer",
|
|
123
163
|
description: `
|
|
124
|
-
This tool will transfer an ERC20 token from the wallet to another onchain address.
|
|
164
|
+
This tool will transfer (send) an ERC20 token from the wallet to another onchain address.
|
|
125
165
|
|
|
126
166
|
It takes the following inputs:
|
|
127
|
-
- amount: The amount to transfer
|
|
128
|
-
-
|
|
129
|
-
-
|
|
130
|
-
|
|
167
|
+
- amount: The amount to transfer in whole units (e.g. 10.5 USDC)
|
|
168
|
+
- tokenAddress: The contract address of the token to transfer
|
|
169
|
+
- destinationAddress: Where to send the funds (can be an onchain address, ENS 'example.eth', or Basename 'example.base.eth')
|
|
131
170
|
Important notes:
|
|
132
|
-
-
|
|
133
|
-
|
|
134
|
-
`,
|
|
171
|
+
- Never assume token or destination addresses, they have to be provided as inputs. If only token symbol is provided, use the get_token_address tool to get the token address first
|
|
172
|
+
`,
|
|
135
173
|
schema: schemas_1.TransferSchema,
|
|
136
174
|
}),
|
|
137
175
|
__metadata("design:type", Function),
|
|
138
176
|
__metadata("design:paramtypes", [wallet_providers_1.EvmWalletProvider, void 0]),
|
|
139
177
|
__metadata("design:returntype", Promise)
|
|
140
178
|
], ERC20ActionProvider.prototype, "transfer", null);
|
|
179
|
+
__decorate([
|
|
180
|
+
(0, actionDecorator_1.CreateAction)({
|
|
181
|
+
name: "get_erc20_token_address",
|
|
182
|
+
description: `
|
|
183
|
+
This tool will get the contract address for frequently used ERC20 tokens on different networks.
|
|
184
|
+
It takes the following input:
|
|
185
|
+
- symbol: The token symbol (e.g. USDC, EURC, CBBTC)
|
|
186
|
+
`,
|
|
187
|
+
schema: schemas_1.GetTokenAddressSchema,
|
|
188
|
+
}),
|
|
189
|
+
__metadata("design:type", Function),
|
|
190
|
+
__metadata("design:paramtypes", [wallet_providers_1.EvmWalletProvider, void 0]),
|
|
191
|
+
__metadata("design:returntype", Promise)
|
|
192
|
+
], ERC20ActionProvider.prototype, "getTokenAddress", null);
|
|
141
193
|
const erc20ActionProvider = () => new ERC20ActionProvider();
|
|
142
194
|
exports.erc20ActionProvider = erc20ActionProvider;
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const erc20ActionProvider_1 = require("./erc20ActionProvider");
|
|
4
4
|
const schemas_1 = require("./schemas");
|
|
5
|
-
const viem_1 = require("viem");
|
|
6
|
-
const constants_1 = require("./constants");
|
|
7
5
|
const MOCK_AMOUNT = 15;
|
|
8
6
|
const MOCK_DECIMALS = 6;
|
|
9
7
|
const MOCK_CONTRACT_ADDRESS = "0x1234567890123456789012345678901234567890";
|
|
@@ -12,9 +10,9 @@ const MOCK_ADDRESS = "0x1234567890123456789012345678901234567890";
|
|
|
12
10
|
describe("Transfer Schema", () => {
|
|
13
11
|
it("should successfully parse valid input", () => {
|
|
14
12
|
const validInput = {
|
|
15
|
-
amount: MOCK_AMOUNT,
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
amount: MOCK_AMOUNT.toString(),
|
|
14
|
+
tokenAddress: MOCK_CONTRACT_ADDRESS,
|
|
15
|
+
destinationAddress: MOCK_DESTINATION,
|
|
18
16
|
};
|
|
19
17
|
const result = schemas_1.TransferSchema.safeParse(validInput);
|
|
20
18
|
expect(result.success).toBe(true);
|
|
@@ -28,49 +26,53 @@ describe("Transfer Schema", () => {
|
|
|
28
26
|
});
|
|
29
27
|
describe("Get Balance Action", () => {
|
|
30
28
|
let mockWallet;
|
|
29
|
+
let mockMulticall;
|
|
31
30
|
const actionProvider = (0, erc20ActionProvider_1.erc20ActionProvider)();
|
|
32
31
|
beforeEach(async () => {
|
|
32
|
+
mockMulticall = jest.fn();
|
|
33
|
+
const mockPublicClient = {
|
|
34
|
+
multicall: mockMulticall,
|
|
35
|
+
getCode: jest.fn().mockResolvedValue("0x"),
|
|
36
|
+
};
|
|
33
37
|
mockWallet = {
|
|
34
38
|
getAddress: jest.fn().mockReturnValue(MOCK_ADDRESS),
|
|
35
|
-
|
|
39
|
+
getPublicClient: jest.fn().mockReturnValue(mockPublicClient),
|
|
36
40
|
};
|
|
37
41
|
});
|
|
38
42
|
it("should successfully respond", async () => {
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
mockMulticall.mockResolvedValueOnce([
|
|
44
|
+
{ result: "MockToken" }, // name
|
|
45
|
+
{ result: MOCK_DECIMALS }, // decimals
|
|
46
|
+
{ result: BigInt(MOCK_AMOUNT * 10 ** MOCK_DECIMALS) }, // balance
|
|
47
|
+
]);
|
|
41
48
|
const args = {
|
|
42
|
-
|
|
49
|
+
tokenAddress: MOCK_CONTRACT_ADDRESS,
|
|
43
50
|
};
|
|
44
51
|
const response = await actionProvider.getBalance(mockWallet, args);
|
|
45
|
-
expect(
|
|
46
|
-
|
|
47
|
-
abi: constants_1.abi,
|
|
48
|
-
functionName: "balanceOf",
|
|
49
|
-
args: [mockWallet.getAddress()],
|
|
50
|
-
});
|
|
51
|
-
expect(response).toContain(`Balance of ${MOCK_CONTRACT_ADDRESS} is ${MOCK_AMOUNT / 10 ** MOCK_DECIMALS}`);
|
|
52
|
+
expect(mockMulticall).toHaveBeenCalled();
|
|
53
|
+
expect(response).toContain(`Balance of MockToken (${MOCK_CONTRACT_ADDRESS}) at address ${MOCK_ADDRESS} is ${MOCK_AMOUNT}`);
|
|
52
54
|
});
|
|
53
55
|
it("should fail with an error", async () => {
|
|
54
56
|
const args = {
|
|
55
|
-
|
|
57
|
+
tokenAddress: MOCK_CONTRACT_ADDRESS,
|
|
56
58
|
};
|
|
57
|
-
|
|
58
|
-
mockWallet.readContract.mockRejectedValue(error);
|
|
59
|
+
mockMulticall.mockRejectedValue(new Error("Failed to get balance"));
|
|
59
60
|
const response = await actionProvider.getBalance(mockWallet, args);
|
|
60
|
-
expect(
|
|
61
|
-
|
|
62
|
-
abi: constants_1.abi,
|
|
63
|
-
functionName: "balanceOf",
|
|
64
|
-
args: [mockWallet.getAddress()],
|
|
65
|
-
});
|
|
66
|
-
expect(response).toContain(`Error getting balance: ${error}`);
|
|
61
|
+
expect(mockMulticall).toHaveBeenCalled();
|
|
62
|
+
expect(response).toContain("Error: Could not fetch token details");
|
|
67
63
|
});
|
|
68
64
|
});
|
|
69
65
|
describe("Transfer Action", () => {
|
|
70
66
|
const TRANSACTION_HASH = "0xghijkl987654321";
|
|
71
67
|
let mockWallet;
|
|
68
|
+
let mockMulticall;
|
|
72
69
|
const actionProvider = (0, erc20ActionProvider_1.erc20ActionProvider)();
|
|
73
70
|
beforeEach(async () => {
|
|
71
|
+
mockMulticall = jest.fn();
|
|
72
|
+
const mockPublicClient = {
|
|
73
|
+
multicall: mockMulticall,
|
|
74
|
+
getCode: jest.fn().mockResolvedValue("0x"),
|
|
75
|
+
};
|
|
74
76
|
mockWallet = {
|
|
75
77
|
sendTransaction: jest.fn(),
|
|
76
78
|
waitForTransactionReceipt: jest.fn(),
|
|
@@ -78,47 +80,40 @@ describe("Transfer Action", () => {
|
|
|
78
80
|
getNetwork: jest.fn().mockReturnValue({
|
|
79
81
|
networkId: "base-mainnet",
|
|
80
82
|
}),
|
|
83
|
+
getPublicClient: jest.fn().mockReturnValue(mockPublicClient),
|
|
84
|
+
getAddress: jest.fn().mockReturnValue(MOCK_ADDRESS),
|
|
81
85
|
};
|
|
82
86
|
mockWallet.sendTransaction.mockResolvedValue(TRANSACTION_HASH);
|
|
83
87
|
mockWallet.waitForTransactionReceipt.mockResolvedValue({});
|
|
84
88
|
});
|
|
85
89
|
it("should successfully respond", async () => {
|
|
90
|
+
mockMulticall.mockResolvedValueOnce([
|
|
91
|
+
{ result: "MockToken" }, // name
|
|
92
|
+
{ result: MOCK_DECIMALS }, // decimals
|
|
93
|
+
{ result: BigInt(100000 * 10 ** MOCK_DECIMALS) }, // balance
|
|
94
|
+
]);
|
|
86
95
|
const args = {
|
|
87
|
-
amount:
|
|
88
|
-
|
|
89
|
-
|
|
96
|
+
amount: MOCK_AMOUNT.toString(),
|
|
97
|
+
tokenAddress: MOCK_CONTRACT_ADDRESS,
|
|
98
|
+
destinationAddress: MOCK_DESTINATION,
|
|
90
99
|
};
|
|
91
100
|
const response = await actionProvider.transfer(mockWallet, args);
|
|
92
|
-
expect(
|
|
93
|
-
|
|
94
|
-
data: (0, viem_1.encodeFunctionData)({
|
|
95
|
-
abi: constants_1.abi,
|
|
96
|
-
functionName: "transfer",
|
|
97
|
-
args: [args.destination, BigInt(args.amount)],
|
|
98
|
-
}),
|
|
99
|
-
});
|
|
101
|
+
expect(mockMulticall).toHaveBeenCalled();
|
|
102
|
+
expect(mockWallet.sendTransaction).toHaveBeenCalled();
|
|
100
103
|
expect(mockWallet.waitForTransactionReceipt).toHaveBeenCalledWith(TRANSACTION_HASH);
|
|
101
|
-
expect(response).toContain(`Transferred ${MOCK_AMOUNT} of ${MOCK_CONTRACT_ADDRESS} to ${MOCK_DESTINATION}`);
|
|
104
|
+
expect(response).toContain(`Transferred ${MOCK_AMOUNT} of MockToken (${MOCK_CONTRACT_ADDRESS}) to ${MOCK_DESTINATION}`);
|
|
102
105
|
expect(response).toContain(`Transaction hash for the transfer: ${TRANSACTION_HASH}`);
|
|
103
106
|
});
|
|
104
107
|
it("should fail with an error", async () => {
|
|
108
|
+
mockMulticall.mockRejectedValue(new Error("Failed to get token details"));
|
|
105
109
|
const args = {
|
|
106
|
-
amount:
|
|
107
|
-
|
|
108
|
-
|
|
110
|
+
amount: MOCK_AMOUNT.toString(),
|
|
111
|
+
tokenAddress: MOCK_CONTRACT_ADDRESS,
|
|
112
|
+
destinationAddress: MOCK_DESTINATION,
|
|
109
113
|
};
|
|
110
|
-
const error = new Error("Failed to execute transfer");
|
|
111
|
-
mockWallet.sendTransaction.mockRejectedValue(error);
|
|
112
114
|
const response = await actionProvider.transfer(mockWallet, args);
|
|
113
|
-
expect(
|
|
114
|
-
|
|
115
|
-
data: (0, viem_1.encodeFunctionData)({
|
|
116
|
-
abi: constants_1.abi,
|
|
117
|
-
functionName: "transfer",
|
|
118
|
-
args: [args.destination, BigInt(args.amount)],
|
|
119
|
-
}),
|
|
120
|
-
});
|
|
121
|
-
expect(response).toContain(`Error transferring the asset: ${error}`);
|
|
115
|
+
expect(mockMulticall).toHaveBeenCalled();
|
|
116
|
+
expect(response).toContain("Error: Could not fetch token details");
|
|
122
117
|
});
|
|
123
118
|
describe("supportsNetwork", () => {
|
|
124
119
|
it("should return true when protocolFamily is evm", () => {
|
|
@@ -129,3 +124,71 @@ describe("Transfer Action", () => {
|
|
|
129
124
|
});
|
|
130
125
|
});
|
|
131
126
|
});
|
|
127
|
+
describe("GetTokenAddress Schema", () => {
|
|
128
|
+
it("should successfully parse valid token symbol", () => {
|
|
129
|
+
const validInput = { symbol: "usdc" };
|
|
130
|
+
const result = schemas_1.GetTokenAddressSchema.safeParse(validInput);
|
|
131
|
+
expect(result.success).toBe(true);
|
|
132
|
+
expect(result.data?.symbol).toBe("USDC"); // Should be uppercase
|
|
133
|
+
});
|
|
134
|
+
it("should fail parsing empty symbol", () => {
|
|
135
|
+
const emptyInput = { symbol: "" };
|
|
136
|
+
const result = schemas_1.GetTokenAddressSchema.safeParse(emptyInput);
|
|
137
|
+
expect(result.success).toBe(false);
|
|
138
|
+
});
|
|
139
|
+
it("should fail parsing symbol too long", () => {
|
|
140
|
+
const longInput = { symbol: "VERYLONGTOKENSYMBOL" };
|
|
141
|
+
const result = schemas_1.GetTokenAddressSchema.safeParse(longInput);
|
|
142
|
+
expect(result.success).toBe(false);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
describe("Get Token Address Action", () => {
|
|
146
|
+
let mockWallet;
|
|
147
|
+
const actionProvider = (0, erc20ActionProvider_1.erc20ActionProvider)();
|
|
148
|
+
beforeEach(() => {
|
|
149
|
+
mockWallet = {
|
|
150
|
+
getNetwork: jest.fn(),
|
|
151
|
+
};
|
|
152
|
+
});
|
|
153
|
+
it("should return token address for valid symbol on base-mainnet", async () => {
|
|
154
|
+
mockWallet.getNetwork.mockReturnValue({
|
|
155
|
+
protocolFamily: "evm",
|
|
156
|
+
networkId: "base-mainnet",
|
|
157
|
+
});
|
|
158
|
+
const response = await actionProvider.getTokenAddress(mockWallet, { symbol: "USDC" });
|
|
159
|
+
expect(response).toContain("Token address for USDC on base-mainnet: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913");
|
|
160
|
+
});
|
|
161
|
+
it("should return token address for valid symbol on base-sepolia", async () => {
|
|
162
|
+
mockWallet.getNetwork.mockReturnValue({
|
|
163
|
+
protocolFamily: "evm",
|
|
164
|
+
networkId: "base-sepolia",
|
|
165
|
+
});
|
|
166
|
+
const response = await actionProvider.getTokenAddress(mockWallet, { symbol: "EURC" });
|
|
167
|
+
expect(response).toContain("Token address for EURC on base-sepolia: 0x808456652fdb597867f38412077A9182bf77359F");
|
|
168
|
+
});
|
|
169
|
+
it("should return error for unsupported network", async () => {
|
|
170
|
+
mockWallet.getNetwork.mockReturnValue({
|
|
171
|
+
protocolFamily: "evm",
|
|
172
|
+
networkId: "unsupported-network",
|
|
173
|
+
});
|
|
174
|
+
const response = await actionProvider.getTokenAddress(mockWallet, { symbol: "USDC" });
|
|
175
|
+
expect(response).toContain('Error: Token symbol "USDC" not found on unsupported-network');
|
|
176
|
+
});
|
|
177
|
+
it("should return error for unknown token symbol", async () => {
|
|
178
|
+
mockWallet.getNetwork.mockReturnValue({
|
|
179
|
+
protocolFamily: "evm",
|
|
180
|
+
networkId: "base-mainnet",
|
|
181
|
+
});
|
|
182
|
+
const response = await actionProvider.getTokenAddress(mockWallet, { symbol: "UNKNOWN" });
|
|
183
|
+
expect(response).toContain('Error: Token symbol "UNKNOWN" not found on base-mainnet');
|
|
184
|
+
expect(response).toContain('Error: Token symbol "UNKNOWN" not found on base-mainnet');
|
|
185
|
+
});
|
|
186
|
+
it("should return error when network ID is not available", async () => {
|
|
187
|
+
mockWallet.getNetwork.mockReturnValue({
|
|
188
|
+
protocolFamily: "evm",
|
|
189
|
+
// networkId is undefined
|
|
190
|
+
});
|
|
191
|
+
const response = await actionProvider.getTokenAddress(mockWallet, { symbol: "USDC" });
|
|
192
|
+
expect(response).toContain('Error: Token symbol "USDC" not found on undefined');
|
|
193
|
+
});
|
|
194
|
+
});
|
|
@@ -3,25 +3,38 @@ import { z } from "zod";
|
|
|
3
3
|
* Input schema for transfer action.
|
|
4
4
|
*/
|
|
5
5
|
export declare const TransferSchema: z.ZodObject<{
|
|
6
|
-
amount: z.
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
amount: z.ZodString;
|
|
7
|
+
tokenAddress: z.ZodString;
|
|
8
|
+
destinationAddress: z.ZodString;
|
|
9
9
|
}, "strip", z.ZodTypeAny, {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
amount: string;
|
|
11
|
+
tokenAddress: string;
|
|
12
|
+
destinationAddress: string;
|
|
13
13
|
}, {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
amount: string;
|
|
15
|
+
tokenAddress: string;
|
|
16
|
+
destinationAddress: string;
|
|
17
17
|
}>;
|
|
18
18
|
/**
|
|
19
19
|
* Input schema for get balance action.
|
|
20
20
|
*/
|
|
21
21
|
export declare const GetBalanceSchema: z.ZodObject<{
|
|
22
|
-
|
|
22
|
+
tokenAddress: z.ZodString;
|
|
23
|
+
address: z.ZodOptional<z.ZodString>;
|
|
23
24
|
}, "strip", z.ZodTypeAny, {
|
|
24
|
-
|
|
25
|
+
tokenAddress: string;
|
|
26
|
+
address?: string | undefined;
|
|
25
27
|
}, {
|
|
26
|
-
|
|
28
|
+
tokenAddress: string;
|
|
29
|
+
address?: string | undefined;
|
|
30
|
+
}>;
|
|
31
|
+
/**
|
|
32
|
+
* Input schema for get token address action.
|
|
33
|
+
*/
|
|
34
|
+
export declare const GetTokenAddressSchema: z.ZodObject<{
|
|
35
|
+
symbol: z.ZodString;
|
|
36
|
+
}, "strip", z.ZodTypeAny, {
|
|
37
|
+
symbol: string;
|
|
38
|
+
}, {
|
|
39
|
+
symbol: string;
|
|
27
40
|
}>;
|
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.GetBalanceSchema = exports.TransferSchema = void 0;
|
|
3
|
+
exports.GetTokenAddressSchema = exports.GetBalanceSchema = exports.TransferSchema = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
/**
|
|
6
6
|
* Input schema for transfer action.
|
|
7
7
|
*/
|
|
8
8
|
exports.TransferSchema = zod_1.z
|
|
9
9
|
.object({
|
|
10
|
-
amount: zod_1.z
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
amount: zod_1.z
|
|
11
|
+
.string()
|
|
12
|
+
.describe("The amount of the asset to transfer in whole units (e.g. 1.5 USDC)"),
|
|
13
|
+
tokenAddress: zod_1.z
|
|
14
|
+
.string()
|
|
15
|
+
.regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address format")
|
|
16
|
+
.describe("The contract address of the token to transfer"),
|
|
17
|
+
destinationAddress: zod_1.z
|
|
18
|
+
.string()
|
|
19
|
+
.regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address format")
|
|
20
|
+
.describe("The destination to transfer the funds"),
|
|
13
21
|
})
|
|
14
22
|
.strip()
|
|
15
23
|
.describe("Instructions for transferring assets");
|
|
@@ -18,9 +26,29 @@ exports.TransferSchema = zod_1.z
|
|
|
18
26
|
*/
|
|
19
27
|
exports.GetBalanceSchema = zod_1.z
|
|
20
28
|
.object({
|
|
21
|
-
|
|
29
|
+
tokenAddress: zod_1.z
|
|
22
30
|
.string()
|
|
23
|
-
.
|
|
31
|
+
.regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address format")
|
|
32
|
+
.describe("The contract address of the ERC20 token to get the balance for"),
|
|
33
|
+
address: zod_1.z
|
|
34
|
+
.string()
|
|
35
|
+
.regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address format")
|
|
36
|
+
.optional()
|
|
37
|
+
.describe("The address to check the balance for. If not provided, uses the wallet's address"),
|
|
24
38
|
})
|
|
25
39
|
.strip()
|
|
26
40
|
.describe("Instructions for getting wallet balance");
|
|
41
|
+
/**
|
|
42
|
+
* Input schema for get token address action.
|
|
43
|
+
*/
|
|
44
|
+
exports.GetTokenAddressSchema = zod_1.z
|
|
45
|
+
.object({
|
|
46
|
+
symbol: zod_1.z
|
|
47
|
+
.string()
|
|
48
|
+
.min(1)
|
|
49
|
+
.max(10)
|
|
50
|
+
.toUpperCase()
|
|
51
|
+
.describe("The token symbol (e.g., USDC, WETH, DEGEN)"),
|
|
52
|
+
})
|
|
53
|
+
.strip()
|
|
54
|
+
.describe("Instructions for getting a token's contract address by symbol");
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { EvmWalletProvider } from "../../wallet-providers";
|
|
2
|
+
/**
|
|
3
|
+
* Interface for token details
|
|
4
|
+
*/
|
|
5
|
+
export interface TokenDetails {
|
|
6
|
+
name: string;
|
|
7
|
+
decimals: number;
|
|
8
|
+
balance: bigint;
|
|
9
|
+
formattedBalance: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Gets the details of an ERC20 token including name, decimals, and balance.
|
|
13
|
+
*
|
|
14
|
+
* @param walletProvider - The wallet provider to use for the multicall.
|
|
15
|
+
* @param contractAddress - The contract address of the ERC20 token.
|
|
16
|
+
* @param address - The address to check the balance for. If not provided, uses the wallet's address.
|
|
17
|
+
* @returns A promise that resolves to TokenDetails or null if there's an error.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getTokenDetails(walletProvider: EvmWalletProvider, contractAddress: string, address?: string): Promise<TokenDetails | null>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getTokenDetails = getTokenDetails;
|
|
4
|
+
const viem_1 = require("viem");
|
|
5
|
+
/**
|
|
6
|
+
* Gets the details of an ERC20 token including name, decimals, and balance.
|
|
7
|
+
*
|
|
8
|
+
* @param walletProvider - The wallet provider to use for the multicall.
|
|
9
|
+
* @param contractAddress - The contract address of the ERC20 token.
|
|
10
|
+
* @param address - The address to check the balance for. If not provided, uses the wallet's address.
|
|
11
|
+
* @returns A promise that resolves to TokenDetails or null if there's an error.
|
|
12
|
+
*/
|
|
13
|
+
async function getTokenDetails(walletProvider, contractAddress, address) {
|
|
14
|
+
try {
|
|
15
|
+
const results = await walletProvider.getPublicClient().multicall({
|
|
16
|
+
contracts: [
|
|
17
|
+
{
|
|
18
|
+
address: contractAddress,
|
|
19
|
+
abi: viem_1.erc20Abi,
|
|
20
|
+
functionName: "name",
|
|
21
|
+
args: [],
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
address: contractAddress,
|
|
25
|
+
abi: viem_1.erc20Abi,
|
|
26
|
+
functionName: "decimals",
|
|
27
|
+
args: [],
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
address: contractAddress,
|
|
31
|
+
abi: viem_1.erc20Abi,
|
|
32
|
+
functionName: "balanceOf",
|
|
33
|
+
args: [(address || walletProvider.getAddress())],
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
});
|
|
37
|
+
const name = results[0].result;
|
|
38
|
+
const decimals = results[1]?.result;
|
|
39
|
+
const balance = results[2]?.result;
|
|
40
|
+
if (balance === undefined || decimals === undefined || name === undefined) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const formattedBalance = (0, viem_1.formatUnits)(BigInt(balance), decimals);
|
|
44
|
+
return {
|
|
45
|
+
name,
|
|
46
|
+
decimals,
|
|
47
|
+
balance: BigInt(balance),
|
|
48
|
+
formattedBalance,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Addresses } from "./types";
|
|
2
|
-
import {
|
|
2
|
+
import { erc20Abi as ERC20_ABI } from "viem";
|
|
3
3
|
export { ERC20_ABI };
|
|
4
4
|
export declare const FastFlaunchZapAddress: Addresses;
|
|
5
5
|
export declare const FlaunchPositionManagerAddress: Addresses;
|
|
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.PERMIT_TYPES = exports.PERMIT_DETAILS = exports.PERMIT2_ABI = exports.UNIVERSAL_ROUTER_ABI = exports.URCommands = exports.V4Actions = exports.IV4RouterAbiExactOutput = exports.IV4RouterAbiExactInput = exports.QUOTER_ABI = exports.POSITION_MANAGER_ABI = exports.FAST_FLAUNCH_ZAP_ABI = exports.Permit2Address = exports.UniversalRouterAddress = exports.QuoterAddress = exports.FLETHHooksAddress = exports.FLETHAddress = exports.FlaunchPositionManagerAddress = exports.FastFlaunchZapAddress = exports.ERC20_ABI = void 0;
|
|
4
4
|
const viem_1 = require("viem");
|
|
5
5
|
const chains_1 = require("viem/chains");
|
|
6
|
-
const
|
|
7
|
-
Object.defineProperty(exports, "ERC20_ABI", { enumerable: true, get: function () { return
|
|
6
|
+
const viem_2 = require("viem");
|
|
7
|
+
Object.defineProperty(exports, "ERC20_ABI", { enumerable: true, get: function () { return viem_2.erc20Abi; } });
|
|
8
8
|
exports.FastFlaunchZapAddress = {
|
|
9
9
|
[chains_1.base.id]: "0xd79e27f51ddf9df5ee76106ee192530f474b02f6",
|
|
10
10
|
[chains_1.baseSepolia.id]: "0x251e97446a7019E5DA4860d4CF47291321C693D0",
|
|
@@ -7,12 +7,12 @@ export declare const MintSchema: z.ZodObject<{
|
|
|
7
7
|
tokenAddress: z.ZodString;
|
|
8
8
|
mTokenAddress: z.ZodString;
|
|
9
9
|
}, "strip", z.ZodTypeAny, {
|
|
10
|
-
assets: string;
|
|
11
10
|
tokenAddress: string;
|
|
11
|
+
assets: string;
|
|
12
12
|
mTokenAddress: string;
|
|
13
13
|
}, {
|
|
14
|
-
assets: string;
|
|
15
14
|
tokenAddress: string;
|
|
15
|
+
assets: string;
|
|
16
16
|
mTokenAddress: string;
|
|
17
17
|
}>;
|
|
18
18
|
/**
|