@coinbase/agentkit 0.4.0 → 0.6.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.
- package/README.md +103 -7
- package/dist/action-providers/across/acrossActionProvider.d.ts +50 -0
- package/dist/action-providers/across/acrossActionProvider.js +333 -0
- package/dist/action-providers/across/acrossActionProvider.test.d.ts +1 -0
- package/dist/action-providers/across/acrossActionProvider.test.js +391 -0
- package/dist/action-providers/across/constants.d.ts +1 -0
- package/dist/action-providers/across/constants.js +2 -0
- package/dist/action-providers/across/index.d.ts +1 -0
- package/dist/action-providers/across/index.js +17 -0
- package/dist/action-providers/across/schemas.d.ts +36 -0
- package/dist/action-providers/across/schemas.js +46 -0
- package/dist/action-providers/across/utils.d.ts +7 -0
- package/dist/action-providers/across/utils.js +25 -0
- package/dist/action-providers/erc20/constants.d.ts +2 -0
- package/dist/action-providers/erc20/constants.js +12 -1
- package/dist/action-providers/erc20/erc20ActionProvider.js +18 -0
- package/dist/action-providers/erc20/erc20ActionProvider.test.js +4 -0
- package/dist/action-providers/flaunch/constants.d.ts +1078 -0
- package/dist/action-providers/flaunch/constants.js +709 -0
- package/dist/action-providers/flaunch/flaunchActionProvider.d.ts +102 -0
- package/dist/action-providers/flaunch/flaunchActionProvider.js +519 -0
- package/dist/action-providers/flaunch/flaunchActionProvider.test.d.ts +1 -0
- package/dist/action-providers/flaunch/flaunchActionProvider.test.js +307 -0
- package/dist/action-providers/flaunch/index.d.ts +7 -0
- package/dist/action-providers/flaunch/index.js +23 -0
- package/dist/action-providers/flaunch/schemas.d.ts +77 -0
- package/dist/action-providers/flaunch/schemas.js +71 -0
- package/dist/action-providers/flaunch/types.d.ts +64 -0
- package/dist/action-providers/flaunch/types.js +2 -0
- package/dist/action-providers/flaunch/utils.d.ts +60 -0
- package/dist/action-providers/flaunch/utils.js +507 -0
- package/dist/action-providers/index.d.ts +4 -0
- package/dist/action-providers/index.js +4 -0
- package/dist/action-providers/messari/constants.d.ts +17 -0
- package/dist/action-providers/messari/constants.js +20 -0
- package/dist/action-providers/messari/index.d.ts +5 -0
- package/dist/action-providers/messari/index.js +21 -0
- package/dist/action-providers/messari/messariActionProvider.d.ts +42 -0
- package/dist/action-providers/messari/messariActionProvider.js +128 -0
- package/dist/action-providers/messari/messariActionProvider.test.d.ts +1 -0
- package/dist/action-providers/messari/messariActionProvider.test.js +152 -0
- package/dist/action-providers/messari/schemas.d.ts +11 -0
- package/dist/action-providers/messari/schemas.js +16 -0
- package/dist/action-providers/messari/types.d.ts +40 -0
- package/dist/action-providers/messari/types.js +2 -0
- package/dist/action-providers/messari/utils.d.ts +22 -0
- package/dist/action-providers/messari/utils.js +65 -0
- package/dist/action-providers/onramp/index.d.ts +7 -0
- package/dist/action-providers/onramp/index.js +23 -0
- package/dist/action-providers/onramp/onrampActionProvider.d.ts +56 -0
- package/dist/action-providers/onramp/onrampActionProvider.js +109 -0
- package/dist/action-providers/onramp/onrampActionProvider.test.d.ts +1 -0
- package/dist/action-providers/onramp/onrampActionProvider.test.js +97 -0
- package/dist/action-providers/onramp/schemas.d.ts +12 -0
- package/dist/action-providers/onramp/schemas.js +15 -0
- package/dist/action-providers/onramp/types.d.ts +107 -0
- package/dist/action-providers/onramp/types.js +2 -0
- package/dist/action-providers/onramp/utils.d.ts +16 -0
- package/dist/action-providers/onramp/utils.js +56 -0
- package/dist/action-providers/onramp/version.d.ts +2 -0
- package/dist/action-providers/onramp/version.js +5 -0
- package/dist/wallet-providers/cdpWalletProvider.d.ts +11 -2
- package/dist/wallet-providers/cdpWalletProvider.js +44 -10
- package/dist/wallet-providers/cdpWalletProvider.test.d.ts +1 -0
- package/dist/wallet-providers/cdpWalletProvider.test.js +735 -0
- package/dist/wallet-providers/evmWalletProvider.test.d.ts +1 -0
- package/dist/wallet-providers/evmWalletProvider.test.js +56 -0
- package/dist/wallet-providers/index.d.ts +1 -0
- package/dist/wallet-providers/index.js +1 -0
- package/dist/wallet-providers/privyEvmDelegatedEmbeddedWalletProvider.d.ts +167 -0
- package/dist/wallet-providers/privyEvmDelegatedEmbeddedWalletProvider.js +438 -0
- package/dist/wallet-providers/privyEvmDelegatedEmbeddedWalletProvider.test.d.ts +1 -0
- package/dist/wallet-providers/privyEvmDelegatedEmbeddedWalletProvider.test.js +280 -0
- package/dist/wallet-providers/privyEvmWalletProvider.test.d.ts +1 -0
- package/dist/wallet-providers/privyEvmWalletProvider.test.js +331 -0
- package/dist/wallet-providers/privyShared.d.ts +9 -0
- package/dist/wallet-providers/privyShared.js +16 -5
- package/dist/wallet-providers/privySvmWalletProvider.test.d.ts +1 -0
- package/dist/wallet-providers/privySvmWalletProvider.test.js +310 -0
- package/dist/wallet-providers/privyWalletProvider.d.ts +21 -8
- package/dist/wallet-providers/privyWalletProvider.js +39 -7
- package/dist/wallet-providers/privyWalletProvider.test.d.ts +1 -0
- package/dist/wallet-providers/privyWalletProvider.test.js +124 -0
- package/dist/wallet-providers/smartWalletProvider.test.d.ts +1 -0
- package/dist/wallet-providers/smartWalletProvider.test.js +388 -0
- package/dist/wallet-providers/solanaKeypairWalletProvider.test.js +210 -16
- package/dist/wallet-providers/svmWalletProvider.test.d.ts +1 -0
- package/dist/wallet-providers/svmWalletProvider.test.js +55 -0
- package/dist/wallet-providers/viemWalletProvider.test.d.ts +1 -0
- package/dist/wallet-providers/viemWalletProvider.test.js +338 -0
- package/dist/wallet-providers/walletProvider.test.d.ts +1 -0
- package/dist/wallet-providers/walletProvider.test.js +103 -0
- package/package.json +26 -21
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const coinbaseSdk = __importStar(require("@coinbase/coinbase-sdk"));
|
|
37
|
+
global.fetch = jest.fn(() => Promise.resolve({
|
|
38
|
+
ok: true,
|
|
39
|
+
json: () => Promise.resolve({}),
|
|
40
|
+
}));
|
|
41
|
+
jest.mock("../analytics", () => ({
|
|
42
|
+
sendAnalyticsEvent: jest.fn().mockImplementation(() => Promise.resolve()),
|
|
43
|
+
}));
|
|
44
|
+
// =========================================================
|
|
45
|
+
// constants
|
|
46
|
+
// =========================================================
|
|
47
|
+
const MOCK_ADDRESS = "0x742d35Cc6634C0532925a3b844Bc454e4438f44e";
|
|
48
|
+
const MOCK_CHAIN_ID = "1";
|
|
49
|
+
const MOCK_NETWORK_ID = "mainnet";
|
|
50
|
+
const MOCK_TRANSACTION_HASH = "0x9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba";
|
|
51
|
+
const MOCK_BALANCE = BigInt(1000000000000000000);
|
|
52
|
+
const mockPublicClient = {
|
|
53
|
+
waitForTransactionReceipt: jest.fn(),
|
|
54
|
+
readContract: jest.fn(),
|
|
55
|
+
};
|
|
56
|
+
var UserOperationStatus;
|
|
57
|
+
(function (UserOperationStatus) {
|
|
58
|
+
UserOperationStatus["CREATED"] = "created";
|
|
59
|
+
UserOperationStatus["PENDING"] = "pending";
|
|
60
|
+
UserOperationStatus["COMPLETE"] = "complete";
|
|
61
|
+
})(UserOperationStatus || (UserOperationStatus = {}));
|
|
62
|
+
// =========================================================
|
|
63
|
+
// mocks
|
|
64
|
+
// =========================================================
|
|
65
|
+
jest.mock("viem", () => {
|
|
66
|
+
return {
|
|
67
|
+
createPublicClient: jest.fn(() => mockPublicClient),
|
|
68
|
+
http: jest.fn(),
|
|
69
|
+
parseEther: jest.fn((_value) => MOCK_BALANCE),
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
jest.mock("../network", () => {
|
|
73
|
+
return {
|
|
74
|
+
NETWORK_ID_TO_CHAIN_ID: {
|
|
75
|
+
mainnet: "1",
|
|
76
|
+
"base-sepolia": "84532",
|
|
77
|
+
},
|
|
78
|
+
NETWORK_ID_TO_VIEM_CHAIN: {
|
|
79
|
+
mainnet: {},
|
|
80
|
+
"base-sepolia": {},
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
jest.mock("@coinbase/coinbase-sdk", () => {
|
|
85
|
+
return {
|
|
86
|
+
CHAIN_ID_TO_NETWORK_ID: {
|
|
87
|
+
"1": "mainnet",
|
|
88
|
+
"84532": "base-sepolia",
|
|
89
|
+
},
|
|
90
|
+
NETWORK_ID_TO_CHAIN_ID: {
|
|
91
|
+
mainnet: "1",
|
|
92
|
+
"base-sepolia": "84532",
|
|
93
|
+
},
|
|
94
|
+
NETWORK_ID_TO_VIEM_CHAIN: {
|
|
95
|
+
mainnet: {},
|
|
96
|
+
"base-sepolia": {},
|
|
97
|
+
},
|
|
98
|
+
Coinbase: {
|
|
99
|
+
configure: jest.fn(),
|
|
100
|
+
configureFromJson: jest.fn(),
|
|
101
|
+
networks: {
|
|
102
|
+
BaseSepolia: "base-sepolia",
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
waitForUserOperation: jest.fn(),
|
|
106
|
+
createSmartWallet: jest.fn(),
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
// =========================================================
|
|
110
|
+
// tests
|
|
111
|
+
// =========================================================
|
|
112
|
+
describe("SmartWalletProvider", () => {
|
|
113
|
+
let provider;
|
|
114
|
+
let mockNetworkScopedWallet;
|
|
115
|
+
let mockWaitForUserOperation;
|
|
116
|
+
beforeEach(() => {
|
|
117
|
+
jest.clearAllMocks();
|
|
118
|
+
const mockGetBalance = jest.fn();
|
|
119
|
+
mockGetBalance.mockResolvedValue(MOCK_BALANCE);
|
|
120
|
+
const mockSendTransaction = jest.fn();
|
|
121
|
+
mockSendTransaction.mockResolvedValue(MOCK_TRANSACTION_HASH);
|
|
122
|
+
const mockSendUserOperation = jest.fn();
|
|
123
|
+
mockNetworkScopedWallet = {
|
|
124
|
+
address: MOCK_ADDRESS,
|
|
125
|
+
getBalance: mockGetBalance,
|
|
126
|
+
sendTransaction: mockSendTransaction,
|
|
127
|
+
sendUserOperation: mockSendUserOperation,
|
|
128
|
+
};
|
|
129
|
+
const mockUserOperationWait = jest.fn();
|
|
130
|
+
mockUserOperationWait.mockResolvedValue({
|
|
131
|
+
status: UserOperationStatus.COMPLETE,
|
|
132
|
+
transactionHash: MOCK_TRANSACTION_HASH,
|
|
133
|
+
});
|
|
134
|
+
const mockUserOperation = {
|
|
135
|
+
hash: MOCK_TRANSACTION_HASH,
|
|
136
|
+
wait: mockUserOperationWait,
|
|
137
|
+
};
|
|
138
|
+
mockNetworkScopedWallet.sendUserOperation.mockResolvedValue(mockUserOperation);
|
|
139
|
+
mockPublicClient.waitForTransactionReceipt.mockResolvedValue({
|
|
140
|
+
transactionHash: MOCK_TRANSACTION_HASH,
|
|
141
|
+
});
|
|
142
|
+
mockPublicClient.readContract.mockResolvedValue("mock_result");
|
|
143
|
+
provider = {
|
|
144
|
+
sendTransaction: jest.fn(),
|
|
145
|
+
sendUserOperation: jest.fn(),
|
|
146
|
+
waitForTransactionReceipt: jest.fn(),
|
|
147
|
+
signMessage: jest.fn(),
|
|
148
|
+
signTypedData: jest.fn(),
|
|
149
|
+
signTransaction: jest.fn(),
|
|
150
|
+
getAddress: jest.fn(),
|
|
151
|
+
getNetwork: jest.fn(),
|
|
152
|
+
getName: jest.fn(),
|
|
153
|
+
getBalance: jest.fn(),
|
|
154
|
+
readContract: jest.fn(),
|
|
155
|
+
nativeTransfer: jest.fn(),
|
|
156
|
+
_smartWallet: mockNetworkScopedWallet,
|
|
157
|
+
};
|
|
158
|
+
provider.getAddress.mockReturnValue(MOCK_ADDRESS);
|
|
159
|
+
provider.getNetwork.mockReturnValue({
|
|
160
|
+
protocolFamily: "evm",
|
|
161
|
+
networkId: MOCK_NETWORK_ID,
|
|
162
|
+
chainId: MOCK_CHAIN_ID,
|
|
163
|
+
});
|
|
164
|
+
provider.getName.mockReturnValue("smart_wallet_provider");
|
|
165
|
+
provider.getBalance.mockResolvedValue(MOCK_BALANCE);
|
|
166
|
+
provider.sendTransaction.mockImplementation(async (tx) => {
|
|
167
|
+
const _result = await mockNetworkScopedWallet.sendUserOperation({ calls: [tx] });
|
|
168
|
+
const waitResult = await _result.wait();
|
|
169
|
+
if (waitResult.status === "failed") {
|
|
170
|
+
throw new Error(`Transaction failed with status ${waitResult.status}`);
|
|
171
|
+
}
|
|
172
|
+
return _result.hash;
|
|
173
|
+
});
|
|
174
|
+
provider.sendUserOperation.mockImplementation(async (op) => {
|
|
175
|
+
const _result = await mockNetworkScopedWallet.sendUserOperation(op);
|
|
176
|
+
return _result.hash;
|
|
177
|
+
});
|
|
178
|
+
provider.waitForTransactionReceipt.mockImplementation((hash) => mockPublicClient.waitForTransactionReceipt({ hash }));
|
|
179
|
+
provider.readContract.mockImplementation(async (params) => {
|
|
180
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
181
|
+
return mockPublicClient.readContract(params);
|
|
182
|
+
});
|
|
183
|
+
provider.nativeTransfer.mockImplementation(async (to, _value) => {
|
|
184
|
+
await mockNetworkScopedWallet.sendUserOperation({
|
|
185
|
+
calls: [
|
|
186
|
+
{
|
|
187
|
+
to,
|
|
188
|
+
value: BigInt(1000000000000000000),
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
});
|
|
192
|
+
return MOCK_TRANSACTION_HASH;
|
|
193
|
+
});
|
|
194
|
+
const notImplementedError = new Error("Not implemented");
|
|
195
|
+
provider.signMessage.mockRejectedValue(notImplementedError);
|
|
196
|
+
provider.signTypedData.mockRejectedValue(notImplementedError);
|
|
197
|
+
provider.signTransaction.mockRejectedValue(notImplementedError);
|
|
198
|
+
mockWaitForUserOperation = jest.fn();
|
|
199
|
+
mockWaitForUserOperation.mockImplementation((operation) => {
|
|
200
|
+
return operation.wait();
|
|
201
|
+
});
|
|
202
|
+
jest
|
|
203
|
+
.spyOn(coinbaseSdk, "waitForUserOperation")
|
|
204
|
+
.mockImplementation(mockWaitForUserOperation);
|
|
205
|
+
});
|
|
206
|
+
// =========================================================
|
|
207
|
+
// transaction operations
|
|
208
|
+
// =========================================================
|
|
209
|
+
describe("transaction operations", () => {
|
|
210
|
+
it("should send transactions", async () => {
|
|
211
|
+
const transaction = {
|
|
212
|
+
to: "0x1234567890123456789012345678901234567890",
|
|
213
|
+
value: BigInt(1000000000000000000),
|
|
214
|
+
};
|
|
215
|
+
const txHash = await provider.sendTransaction(transaction);
|
|
216
|
+
expect(txHash).toBe(MOCK_TRANSACTION_HASH);
|
|
217
|
+
expect(mockNetworkScopedWallet.sendUserOperation).toHaveBeenCalled();
|
|
218
|
+
});
|
|
219
|
+
it("should send a user operation", async () => {
|
|
220
|
+
const calls = [
|
|
221
|
+
{
|
|
222
|
+
to: "0x1234567890123456789012345678901234567890",
|
|
223
|
+
data: "0xabcdef",
|
|
224
|
+
value: 0n,
|
|
225
|
+
},
|
|
226
|
+
];
|
|
227
|
+
const txHash = await provider.sendUserOperation({ calls });
|
|
228
|
+
expect(txHash).toBe(MOCK_TRANSACTION_HASH);
|
|
229
|
+
expect(mockNetworkScopedWallet.sendUserOperation).toHaveBeenCalledWith({ calls });
|
|
230
|
+
});
|
|
231
|
+
it("should wait for transaction receipts", async () => {
|
|
232
|
+
await provider.waitForTransactionReceipt(MOCK_TRANSACTION_HASH);
|
|
233
|
+
expect(mockPublicClient.waitForTransactionReceipt).toHaveBeenCalled();
|
|
234
|
+
});
|
|
235
|
+
it("should handle transaction failures", async () => {
|
|
236
|
+
mockWaitForUserOperation.mockRejectedValueOnce(new Error("Failed to send transaction"));
|
|
237
|
+
mockNetworkScopedWallet.sendUserOperation.mockRejectedValueOnce(new Error("Failed to send transaction"));
|
|
238
|
+
await expect(provider.sendTransaction({
|
|
239
|
+
to: MOCK_ADDRESS,
|
|
240
|
+
value: MOCK_BALANCE,
|
|
241
|
+
})).rejects.toThrow("Failed to send transaction");
|
|
242
|
+
});
|
|
243
|
+
it("should handle network errors in transactions", async () => {
|
|
244
|
+
mockNetworkScopedWallet.sendUserOperation.mockRejectedValueOnce(new Error("Network connection error"));
|
|
245
|
+
await expect(provider.sendTransaction({
|
|
246
|
+
to: MOCK_ADDRESS,
|
|
247
|
+
value: MOCK_BALANCE,
|
|
248
|
+
})).rejects.toThrow("Network connection error");
|
|
249
|
+
});
|
|
250
|
+
it("should handle invalid address errors", async () => {
|
|
251
|
+
mockNetworkScopedWallet.sendUserOperation.mockRejectedValueOnce(new Error("Invalid address format"));
|
|
252
|
+
const invalidAddressHex = "0xinvalid";
|
|
253
|
+
await expect(provider.sendTransaction({
|
|
254
|
+
to: invalidAddressHex,
|
|
255
|
+
value: MOCK_BALANCE,
|
|
256
|
+
})).rejects.toThrow("Invalid address format");
|
|
257
|
+
});
|
|
258
|
+
it("should handle receipt retrieval failures", async () => {
|
|
259
|
+
mockPublicClient.waitForTransactionReceipt.mockRejectedValueOnce(new Error("Receipt retrieval failed"));
|
|
260
|
+
await expect(provider.waitForTransactionReceipt(MOCK_TRANSACTION_HASH)).rejects.toThrow("Receipt retrieval failed");
|
|
261
|
+
});
|
|
262
|
+
it("should handle operation failures when sending transactions", async () => {
|
|
263
|
+
const mockUserOperationWait = jest.fn();
|
|
264
|
+
mockUserOperationWait.mockResolvedValue({
|
|
265
|
+
status: "failed",
|
|
266
|
+
transactionHash: MOCK_TRANSACTION_HASH,
|
|
267
|
+
});
|
|
268
|
+
const failedOperation = {
|
|
269
|
+
hash: MOCK_TRANSACTION_HASH,
|
|
270
|
+
wait: mockUserOperationWait,
|
|
271
|
+
};
|
|
272
|
+
mockNetworkScopedWallet.sendUserOperation.mockResolvedValueOnce(failedOperation);
|
|
273
|
+
const transaction = {
|
|
274
|
+
to: "0x1234567890123456789012345678901234567890",
|
|
275
|
+
value: BigInt(1000000000000000000),
|
|
276
|
+
};
|
|
277
|
+
await expect(provider.sendTransaction(transaction)).rejects.toThrow("Transaction failed with status failed");
|
|
278
|
+
});
|
|
279
|
+
it("should handle exceptions when sending user operations", async () => {
|
|
280
|
+
mockNetworkScopedWallet.sendUserOperation.mockRejectedValueOnce(new Error("Failed to send"));
|
|
281
|
+
const calls = [
|
|
282
|
+
{
|
|
283
|
+
to: "0x1234567890123456789012345678901234567890",
|
|
284
|
+
data: "0xabcdef",
|
|
285
|
+
value: BigInt(0),
|
|
286
|
+
},
|
|
287
|
+
];
|
|
288
|
+
await expect(provider.sendUserOperation({ calls })).rejects.toThrow("Failed to send");
|
|
289
|
+
});
|
|
290
|
+
it("should handle send user operation timeout", async () => {
|
|
291
|
+
mockNetworkScopedWallet.sendUserOperation.mockRejectedValueOnce(new Error("User operation timed out"));
|
|
292
|
+
const calls = [
|
|
293
|
+
{
|
|
294
|
+
to: "0x1234567890123456789012345678901234567890",
|
|
295
|
+
data: "0xabcdef",
|
|
296
|
+
value: 0n,
|
|
297
|
+
},
|
|
298
|
+
];
|
|
299
|
+
await expect(provider.sendUserOperation({ calls })).rejects.toThrow("User operation timed out");
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
// =========================================================
|
|
303
|
+
// native token transfer operations
|
|
304
|
+
// =========================================================
|
|
305
|
+
describe("native token operations", () => {
|
|
306
|
+
it("should transfer native tokens", async () => {
|
|
307
|
+
const to = "0x1234567890123456789012345678901234567890";
|
|
308
|
+
const value = "1";
|
|
309
|
+
const txHash = await provider.nativeTransfer(to, value);
|
|
310
|
+
expect(mockNetworkScopedWallet.sendUserOperation).toHaveBeenCalled();
|
|
311
|
+
expect(txHash).toBe(MOCK_TRANSACTION_HASH);
|
|
312
|
+
});
|
|
313
|
+
it("should handle operation failures when transferring native tokens", async () => {
|
|
314
|
+
provider.nativeTransfer.mockRejectedValueOnce(new Error("Transfer failed with status failed"));
|
|
315
|
+
const to = "0x1234567890123456789012345678901234567890";
|
|
316
|
+
const value = "1";
|
|
317
|
+
await expect(provider.nativeTransfer(to, value)).rejects.toThrow("Transfer failed with status failed");
|
|
318
|
+
});
|
|
319
|
+
it("should handle invalid address format in native transfer", async () => {
|
|
320
|
+
provider.nativeTransfer.mockRejectedValueOnce(new Error("Invalid address format"));
|
|
321
|
+
const invalidAddress = "not_a_valid_address";
|
|
322
|
+
await expect(provider.nativeTransfer(invalidAddress, "1")).rejects.toThrow("Invalid address format");
|
|
323
|
+
});
|
|
324
|
+
it("should handle network errors in native token transfers", async () => {
|
|
325
|
+
provider.nativeTransfer.mockRejectedValueOnce(new Error("Network error"));
|
|
326
|
+
await expect(provider.nativeTransfer("0x1234567890123456789012345678901234567890", "1")).rejects.toThrow("Network error");
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
// =========================================================
|
|
330
|
+
// contract interaction methods
|
|
331
|
+
// =========================================================
|
|
332
|
+
describe("contract interactions", () => {
|
|
333
|
+
it("should read from contracts", async () => {
|
|
334
|
+
const result = await provider.readContract({
|
|
335
|
+
address: "0x1234567890123456789012345678901234567890",
|
|
336
|
+
abi: [],
|
|
337
|
+
functionName: "balanceOf",
|
|
338
|
+
args: [MOCK_ADDRESS],
|
|
339
|
+
});
|
|
340
|
+
expect(result).toBe("mock_result");
|
|
341
|
+
expect(mockPublicClient.readContract).toHaveBeenCalled();
|
|
342
|
+
});
|
|
343
|
+
it("should handle errors in contract reads", async () => {
|
|
344
|
+
mockPublicClient.readContract.mockRejectedValueOnce(new Error("Contract read failed"));
|
|
345
|
+
await expect(provider.readContract({
|
|
346
|
+
address: "0x1234567890123456789012345678901234567890",
|
|
347
|
+
abi: [],
|
|
348
|
+
functionName: "balanceOf",
|
|
349
|
+
args: [MOCK_ADDRESS],
|
|
350
|
+
})).rejects.toThrow("Contract read failed");
|
|
351
|
+
});
|
|
352
|
+
it("should handle read contract with invalid ABI", async () => {
|
|
353
|
+
const invalidAbi = "not_an_abi";
|
|
354
|
+
const params = {
|
|
355
|
+
address: "0x1234567890123456789012345678901234567890",
|
|
356
|
+
abi: invalidAbi,
|
|
357
|
+
functionName: "balanceOf",
|
|
358
|
+
args: ["0x742d35Cc6634C0532925a3b844Bc454e4438f44e"],
|
|
359
|
+
};
|
|
360
|
+
mockPublicClient.readContract.mockImplementationOnce(() => {
|
|
361
|
+
throw new TypeError("Invalid ABI format");
|
|
362
|
+
});
|
|
363
|
+
await expect(provider.readContract(params)).rejects.toThrow("Invalid ABI format");
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
// =========================================================
|
|
367
|
+
// signing methods (unsupported operations)
|
|
368
|
+
// =========================================================
|
|
369
|
+
describe("unsupported operations", () => {
|
|
370
|
+
it("should throw error on sign message", async () => {
|
|
371
|
+
await expect(provider.signMessage("test")).rejects.toThrow("Not implemented");
|
|
372
|
+
});
|
|
373
|
+
it("should throw error on sign typed data", async () => {
|
|
374
|
+
await expect(provider.signTypedData({
|
|
375
|
+
domain: {},
|
|
376
|
+
types: {},
|
|
377
|
+
primaryType: "",
|
|
378
|
+
message: {},
|
|
379
|
+
})).rejects.toThrow("Not implemented");
|
|
380
|
+
});
|
|
381
|
+
it("should throw error on sign transaction", async () => {
|
|
382
|
+
await expect(provider.signTransaction({
|
|
383
|
+
to: MOCK_ADDRESS,
|
|
384
|
+
value: MOCK_BALANCE,
|
|
385
|
+
})).rejects.toThrow("Not implemented");
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
});
|
|
@@ -1,24 +1,218 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const web3_js_1 = require("@solana/web3.js");
|
|
4
3
|
const solanaKeypairWalletProvider_1 = require("./solanaKeypairWalletProvider");
|
|
4
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
5
5
|
const svm_1 = require("../network/svm");
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
global.fetch = jest.fn(() => Promise.resolve({
|
|
7
|
+
ok: true,
|
|
8
|
+
json: () => Promise.resolve({}),
|
|
9
|
+
}));
|
|
10
|
+
jest.mock("../analytics", () => ({
|
|
11
|
+
sendAnalyticsEvent: jest.fn().mockImplementation(() => Promise.resolve()),
|
|
12
|
+
}));
|
|
13
|
+
jest.mock("@solana/web3.js", () => {
|
|
14
|
+
const originalModule = jest.requireActual("@solana/web3.js");
|
|
15
|
+
return {
|
|
16
|
+
...originalModule,
|
|
17
|
+
Connection: jest.fn().mockImplementation(() => ({
|
|
18
|
+
getGenesisHash: jest.fn().mockResolvedValue(svm_1.SOLANA_DEVNET_GENESIS_BLOCK_HASH),
|
|
19
|
+
getBalance: jest.fn().mockResolvedValue(1000000000),
|
|
20
|
+
getLatestBlockhash: jest.fn().mockResolvedValue({
|
|
21
|
+
blockhash: "test-blockhash",
|
|
22
|
+
lastValidBlockHeight: 123456,
|
|
23
|
+
}),
|
|
24
|
+
sendTransaction: jest.fn().mockResolvedValue("signature123"),
|
|
25
|
+
getSignatureStatus: jest.fn().mockResolvedValue({
|
|
26
|
+
context: { slot: 123 },
|
|
27
|
+
value: { slot: 123, confirmations: 10, err: null },
|
|
28
|
+
}),
|
|
29
|
+
confirmTransaction: jest.fn().mockResolvedValue({
|
|
30
|
+
context: { slot: 123 },
|
|
31
|
+
value: { err: null },
|
|
32
|
+
}),
|
|
33
|
+
requestAirdrop: jest.fn().mockResolvedValue("airdrop-signature"),
|
|
34
|
+
})),
|
|
35
|
+
Keypair: {
|
|
36
|
+
generate: jest.fn().mockReturnValue({
|
|
37
|
+
publicKey: new originalModule.PublicKey("AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM"),
|
|
38
|
+
secretKey: new Uint8Array(32).fill(1),
|
|
39
|
+
sign: jest.fn(),
|
|
40
|
+
}),
|
|
41
|
+
fromSecretKey: jest.fn().mockReturnValue({
|
|
42
|
+
publicKey: new originalModule.PublicKey("AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM"),
|
|
43
|
+
secretKey: new Uint8Array(32).fill(1),
|
|
44
|
+
sign: jest.fn(),
|
|
45
|
+
}),
|
|
46
|
+
},
|
|
47
|
+
PublicKey: originalModule.PublicKey,
|
|
48
|
+
VersionedTransaction: jest.fn().mockImplementation(() => ({
|
|
49
|
+
signatures: [],
|
|
50
|
+
message: { compiledMessage: Buffer.from([]) },
|
|
51
|
+
sign: jest.fn(function (signers) {
|
|
52
|
+
this.signatures = signers.map(() => new Uint8Array(64).fill(1));
|
|
53
|
+
return this;
|
|
54
|
+
}),
|
|
55
|
+
})),
|
|
56
|
+
SystemProgram: {
|
|
57
|
+
transfer: jest.fn().mockReturnValue({
|
|
58
|
+
instructions: [{ programId: "system-program" }],
|
|
59
|
+
}),
|
|
60
|
+
},
|
|
61
|
+
MessageV0: {
|
|
62
|
+
compile: jest.fn().mockReturnValue({
|
|
63
|
+
compiledMessage: Buffer.from([]),
|
|
64
|
+
}),
|
|
65
|
+
},
|
|
66
|
+
TransactionMessage: {
|
|
67
|
+
compile: jest.fn().mockReturnValue({
|
|
68
|
+
compiledMessage: Buffer.from([]),
|
|
69
|
+
}),
|
|
70
|
+
},
|
|
71
|
+
clusterApiUrl: jest.fn().mockImplementation(network => `https://api.${network}.solana.com`),
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
describe("SolanaKeypairWalletProvider", () => {
|
|
75
|
+
let wallet;
|
|
76
|
+
beforeEach(async () => {
|
|
8
77
|
const keypair = web3_js_1.Keypair.generate();
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
78
|
+
wallet = await solanaKeypairWalletProvider_1.SolanaKeypairWalletProvider.fromRpcUrl("https://api.devnet.solana.com", keypair.secretKey);
|
|
79
|
+
});
|
|
80
|
+
describe("initialization methods", () => {
|
|
81
|
+
it("should initialize from constructor", async () => {
|
|
82
|
+
const keypair = web3_js_1.Keypair.generate();
|
|
83
|
+
const rpcUrl = "https://api.devnet.solana.com";
|
|
84
|
+
const provider = new solanaKeypairWalletProvider_1.SolanaKeypairWalletProvider({
|
|
85
|
+
keypair: keypair.secretKey,
|
|
86
|
+
rpcUrl,
|
|
87
|
+
genesisHash: svm_1.SOLANA_DEVNET_GENESIS_BLOCK_HASH,
|
|
88
|
+
});
|
|
89
|
+
expect(provider).toBeInstanceOf(solanaKeypairWalletProvider_1.SolanaKeypairWalletProvider);
|
|
90
|
+
expect(provider.getNetwork()).toEqual(svm_1.SOLANA_NETWORKS[svm_1.SOLANA_DEVNET_GENESIS_BLOCK_HASH]);
|
|
91
|
+
});
|
|
92
|
+
it("should initialize from RPC URL", async () => {
|
|
93
|
+
const keypair = web3_js_1.Keypair.generate();
|
|
94
|
+
const rpcUrl = "https://api.devnet.solana.com";
|
|
95
|
+
const provider = await solanaKeypairWalletProvider_1.SolanaKeypairWalletProvider.fromRpcUrl(rpcUrl, keypair.secretKey);
|
|
96
|
+
expect(provider).toBeInstanceOf(solanaKeypairWalletProvider_1.SolanaKeypairWalletProvider);
|
|
97
|
+
expect(provider.getNetwork()).toEqual(svm_1.SOLANA_NETWORKS[svm_1.SOLANA_DEVNET_GENESIS_BLOCK_HASH]);
|
|
98
|
+
});
|
|
99
|
+
it("should initialize from network ID", async () => {
|
|
100
|
+
const keypair = web3_js_1.Keypair.generate();
|
|
101
|
+
const networkId = "solana-devnet";
|
|
102
|
+
const wallet = await solanaKeypairWalletProvider_1.SolanaKeypairWalletProvider.fromNetwork(networkId, keypair.secretKey);
|
|
103
|
+
expect(web3_js_1.clusterApiUrl).toHaveBeenCalledWith("devnet");
|
|
104
|
+
expect(wallet.getNetwork()).toEqual(svm_1.SOLANA_NETWORKS[svm_1.SOLANA_DEVNET_GENESIS_BLOCK_HASH]);
|
|
105
|
+
});
|
|
106
|
+
it("should initialize from connection", async () => {
|
|
107
|
+
const keypair = web3_js_1.Keypair.generate();
|
|
108
|
+
const connection = new web3_js_1.Connection("https://api.devnet.solana.com");
|
|
109
|
+
const provider = await solanaKeypairWalletProvider_1.SolanaKeypairWalletProvider.fromConnection(connection, keypair.secretKey);
|
|
110
|
+
expect(provider).toBeInstanceOf(solanaKeypairWalletProvider_1.SolanaKeypairWalletProvider);
|
|
111
|
+
expect(provider.getNetwork()).toEqual(svm_1.SOLANA_NETWORKS[svm_1.SOLANA_DEVNET_GENESIS_BLOCK_HASH]);
|
|
112
|
+
});
|
|
16
113
|
});
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
114
|
+
describe("wallet methods", () => {
|
|
115
|
+
it("should get the address", () => {
|
|
116
|
+
expect(wallet.getAddress()).toBe("AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM");
|
|
117
|
+
});
|
|
118
|
+
it("should get the public key", () => {
|
|
119
|
+
const publicKey = wallet.getPublicKey();
|
|
120
|
+
expect(publicKey).toBeInstanceOf(web3_js_1.PublicKey);
|
|
121
|
+
expect(publicKey.toBase58()).toBe("AQoKYV7tYpTrFZN6P5oUufbQKAUr9mNYGe1TTJC9wajM");
|
|
122
|
+
});
|
|
123
|
+
it("should get the network", () => {
|
|
124
|
+
expect(wallet.getNetwork()).toEqual(svm_1.SOLANA_NETWORKS[svm_1.SOLANA_DEVNET_GENESIS_BLOCK_HASH]);
|
|
125
|
+
});
|
|
126
|
+
it("should get the connection", () => {
|
|
127
|
+
expect(wallet.getConnection()).toBeDefined();
|
|
128
|
+
});
|
|
129
|
+
it("should get the balance", async () => {
|
|
130
|
+
const balance = await wallet.getBalance();
|
|
131
|
+
expect(balance).toBe(BigInt(1000000000));
|
|
132
|
+
});
|
|
133
|
+
it("should sign a transaction", async () => {
|
|
134
|
+
const mockTransaction = {
|
|
135
|
+
message: { compiledMessage: Buffer.from([]) },
|
|
136
|
+
signatures: [],
|
|
137
|
+
sign: jest.fn(function (signers) {
|
|
138
|
+
this.signatures = signers.map(() => new Uint8Array(64).fill(1));
|
|
139
|
+
return this;
|
|
140
|
+
}),
|
|
141
|
+
};
|
|
142
|
+
const signedTx = await wallet.signTransaction(mockTransaction);
|
|
143
|
+
expect(mockTransaction.sign).toHaveBeenCalled();
|
|
144
|
+
expect(signedTx).toBe(mockTransaction);
|
|
145
|
+
});
|
|
146
|
+
it("should send a transaction", async () => {
|
|
147
|
+
const mockTransaction = {
|
|
148
|
+
message: { compiledMessage: Buffer.from([]) },
|
|
149
|
+
signatures: [],
|
|
150
|
+
sign: jest.fn(function (signers) {
|
|
151
|
+
this.signatures = signers.map(() => new Uint8Array(64).fill(1));
|
|
152
|
+
return this;
|
|
153
|
+
}),
|
|
154
|
+
};
|
|
155
|
+
const signature = await wallet.sendTransaction(mockTransaction);
|
|
156
|
+
expect(signature).toBe("signature123");
|
|
157
|
+
});
|
|
158
|
+
it("should sign and send a transaction", async () => {
|
|
159
|
+
const mockTransaction = {
|
|
160
|
+
message: { compiledMessage: Buffer.from([]) },
|
|
161
|
+
signatures: [],
|
|
162
|
+
sign: jest.fn(function (signers) {
|
|
163
|
+
this.signatures = signers.map(() => new Uint8Array(64).fill(1));
|
|
164
|
+
return this;
|
|
165
|
+
}),
|
|
166
|
+
};
|
|
167
|
+
const signature = await wallet.signAndSendTransaction(mockTransaction);
|
|
168
|
+
expect(mockTransaction.sign).toHaveBeenCalled();
|
|
169
|
+
expect(signature).toBe("signature123");
|
|
170
|
+
});
|
|
171
|
+
it("should get the signature status", async () => {
|
|
172
|
+
const status = await wallet.getSignatureStatus("signature123");
|
|
173
|
+
expect(status.value).toHaveProperty("slot");
|
|
174
|
+
expect(status.value).toHaveProperty("confirmations");
|
|
175
|
+
});
|
|
176
|
+
it("should wait for signature result", async () => {
|
|
177
|
+
const result = await wallet.waitForSignatureResult("signature123");
|
|
178
|
+
expect(result.value).toHaveProperty("err");
|
|
179
|
+
});
|
|
180
|
+
it("should request an airdrop", async () => {
|
|
181
|
+
const signature = await wallet.requestAirdrop(1000000000);
|
|
182
|
+
expect(signature).toBe("airdrop-signature");
|
|
183
|
+
});
|
|
184
|
+
it("should transfer native tokens", async () => {
|
|
185
|
+
const destination = "EQJqzeeVEnm8rKWQJ5SMTtQBD4xEgixwgzNWKkpeFRZ9";
|
|
186
|
+
const signature = await wallet.nativeTransfer(destination, "0.1");
|
|
187
|
+
expect(signature).toBe("signature123");
|
|
188
|
+
});
|
|
189
|
+
it("should handle insufficient balance when transferring", async () => {
|
|
190
|
+
const connection = wallet.getConnection();
|
|
191
|
+
connection.getBalance.mockResolvedValueOnce(100);
|
|
192
|
+
const destination = "EQJqzeeVEnm8rKWQJ5SMTtQBD4xEgixwgzNWKkpeFRZ9";
|
|
193
|
+
await expect(wallet.nativeTransfer(destination, "1.0")).rejects.toThrow("Insufficient balance");
|
|
194
|
+
});
|
|
195
|
+
it("should handle transaction failure when sending", async () => {
|
|
196
|
+
const connection = wallet.getConnection();
|
|
197
|
+
connection.sendTransaction.mockRejectedValueOnce(new Error("Transaction failed"));
|
|
198
|
+
const mockTransaction = {
|
|
199
|
+
message: { compiledMessage: Buffer.from([]) },
|
|
200
|
+
signatures: [],
|
|
201
|
+
sign: jest.fn(function (signers) {
|
|
202
|
+
this.signatures = signers.map(() => new Uint8Array(64).fill(1));
|
|
203
|
+
return this;
|
|
204
|
+
}),
|
|
205
|
+
};
|
|
206
|
+
await expect(wallet.sendTransaction(mockTransaction)).rejects.toThrow("Transaction failed");
|
|
207
|
+
});
|
|
208
|
+
it("should handle confirmation timeout", async () => {
|
|
209
|
+
const connection = wallet.getConnection();
|
|
210
|
+
connection.confirmTransaction.mockRejectedValueOnce(new Error("Timed out waiting for confirmation"));
|
|
211
|
+
await expect(wallet.waitForSignatureResult("signature123")).rejects.toThrow("Timed out waiting for confirmation");
|
|
212
|
+
});
|
|
213
|
+
it("should handle invalid address when transferring", async () => {
|
|
214
|
+
const destination = "invalid-address";
|
|
215
|
+
await expect(wallet.nativeTransfer(destination, "0.1")).rejects.toThrow();
|
|
216
|
+
});
|
|
23
217
|
});
|
|
24
218
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|