@solana/keychain-cdp 0.0.0 → 1.0.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 ADDED
@@ -0,0 +1,100 @@
1
+ # @solana/keychain-cdp
2
+
3
+ Coinbase Developer Platform (CDP) signer for Solana transactions using CDP's managed wallet infrastructure.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @solana/keychain-cdp
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Create and Initialize
14
+
15
+ ```typescript
16
+ import { createCdpSigner } from '@solana/keychain-cdp';
17
+
18
+ // API keys are created at https://portal.cdp.coinbase.com
19
+ const signer = await createCdpSigner({
20
+ cdpApiKeyId: process.env.CDP_API_KEY_ID!,
21
+ cdpApiKeySecret: process.env.CDP_API_KEY_SECRET!,
22
+ cdpWalletSecret: process.env.CDP_WALLET_SECRET!,
23
+ address: process.env.CDP_SOLANA_ADDRESS!,
24
+ });
25
+
26
+ console.log('Signer address:', signer.address);
27
+ ```
28
+
29
+ ### Sign Messages
30
+
31
+ ```typescript
32
+ import { createSignableMessage } from '@solana/signers';
33
+
34
+ const message = createSignableMessage('Hello, CDP!');
35
+ const [signatures] = await signer.signMessages([message]);
36
+ ```
37
+
38
+ ### Sign Transactions
39
+
40
+ ```typescript
41
+ import {
42
+ createTransactionMessage,
43
+ pipe,
44
+ setTransactionMessageFeePayerSigner,
45
+ setTransactionMessageLifetimeUsingBlockhash,
46
+ signTransactionMessageWithSigners,
47
+ } from '@solana/kit';
48
+
49
+ const transaction = pipe(
50
+ createTransactionMessage({ version: 0 }),
51
+ tx => setTransactionMessageFeePayerSigner(signer, tx),
52
+ tx => setTransactionMessageLifetimeUsingBlockhash({ blockhash, lastValidBlockHeight }, tx),
53
+ );
54
+ const signed = await signTransactionMessageWithSigners(transaction);
55
+ ```
56
+
57
+ ### Check Availability
58
+
59
+ ```typescript
60
+ const available = await signer.isAvailable();
61
+ console.log('CDP API available:', available);
62
+ ```
63
+
64
+ ## API Reference
65
+
66
+ ### `createCdpSigner(config)`
67
+
68
+ Creates and initializes a new CdpSigner instance.
69
+
70
+ **Config options:**
71
+
72
+ - `cdpApiKeyId` (string, required): CDP API key ID
73
+ - `cdpApiKeySecret` (string, required): Base64-encoded Ed25519 key (64 bytes: seed || pubkey)
74
+ - `cdpWalletSecret` (string, required): Base64-encoded PKCS#8 DER EC (P-256) private key
75
+ - `address` (string, required): Solana account address managed by CDP
76
+ - `baseUrl` (string, optional): Custom API base URL (defaults to `https://api.cdp.coinbase.com`)
77
+ - `requestDelayMs` (number, optional): Delay in ms between concurrent signing requests to avoid rate limits (default: 0)
78
+
79
+ **Returns:** `Promise<CdpSigner>`
80
+
81
+ ### Methods
82
+
83
+ - `signMessages(messages)`: Signs one or more messages (UTF-8 strings only)
84
+ - `signTransactions(transactions)`: Signs one or more transactions
85
+ - `isAvailable()`: Checks if the CDP API is reachable
86
+ - `address`: Read-only property containing the signer's Solana address
87
+
88
+ ## How It Works
89
+
90
+ 1. **Initialization**: Validates Ed25519 API key (seed/pubkey match) and loads P-256 wallet key
91
+ 2. **Authentication**: Every signing request sends two JWTs — an Ed25519 auth JWT and an ES256 wallet JWT with request body hash
92
+ 3. **Signing**: Sends transactions/messages to CDP's signing API endpoint
93
+ 4. **Extraction**: For transactions, uses `extractSignatureFromWireTransaction` to extract the signer's signature from CDP's signed wire transaction. For messages, decodes the base58-encoded signature directly from the response.
94
+
95
+ ## Security Notes
96
+
97
+ - Store your `cdpApiKeySecret` and `cdpWalletSecret` securely (use environment variables)
98
+ - Never expose credentials in client-side code
99
+ - This signer is intended for server-side use or secure environments
100
+ - CDP handles key management — your signing keys never leave CDP's infrastructure
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cdp-signer.integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp-signer.integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/cdp-signer.integration.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ import { runSignerIntegrationTest } from '@solana/keychain-test-utils';
2
+ import { config } from 'dotenv';
3
+ import { describe, it } from 'vitest';
4
+ import { getConfig } from './setup.js';
5
+ config();
6
+ describe('CdpSigner Integration', () => {
7
+ it.skipIf(!process.env.CDP_API_KEY_ID)('signs transactions with real API', async () => {
8
+ await runSignerIntegrationTest(await getConfig(['signTransaction']));
9
+ });
10
+ it.skipIf(!process.env.CDP_API_KEY_ID)('signs messages with real API', async () => {
11
+ await runSignerIntegrationTest(await getConfig(['signMessage']));
12
+ });
13
+ it.skipIf(!process.env.CDP_API_KEY_ID)('simulates transactions with real API', async () => {
14
+ await runSignerIntegrationTest(await getConfig(['simulateTransaction']));
15
+ });
16
+ });
17
+ //# sourceMappingURL=cdp-signer.integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp-signer.integration.test.js","sourceRoot":"","sources":["../../src/__tests__/cdp-signer.integration.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,EAAE,CAAC;AAET,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAClF,MAAM,wBAAwB,CAAC,MAAM,SAAS,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;QAC9E,MAAM,wBAAwB,CAAC,MAAM,SAAS,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACtF,MAAM,wBAAwB,CAAC,MAAM,SAAS,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cdp-signer.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp-signer.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/cdp-signer.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,269 @@
1
+ import * as nodeCrypto from 'node:crypto';
2
+ import { assertIsSolanaSigner } from '@solana/keychain-core';
3
+ import { generateKeyPairSigner } from '@solana/signers';
4
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
5
+ vi.mock('@solana/keychain-core', async (importOriginal) => {
6
+ const mod = await importOriginal();
7
+ return {
8
+ ...mod,
9
+ assertSignatureValid: vi.fn(),
10
+ sanitizeRemoteErrorResponse: mod.sanitizeRemoteErrorResponse ??
11
+ ((text) => `${text
12
+ .replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/g, ' ')
13
+ .replace(/\s+/g, ' ')
14
+ .trim()
15
+ .slice(0, 256)} [truncated]`),
16
+ };
17
+ });
18
+ import { CdpSigner } from '../cdp-signer.js';
19
+ // --- Valid test credentials ---
20
+ // Generate a real Ed25519 keypair so that createKeyPairFromBytes seed↔pubkey validation passes.
21
+ // Ed25519 PKCS#8 DER: 16-byte header + 32-byte seed
22
+ // Ed25519 SPKI DER: 12-byte header + 32-byte public key
23
+ function generateTestApiKeySecret() {
24
+ const { privateKey, publicKey } = nodeCrypto.generateKeyPairSync('ed25519');
25
+ const pkcs8 = privateKey.export({ format: 'der', type: 'pkcs8' });
26
+ const seed = pkcs8.subarray(16, 48);
27
+ const spki = publicKey.export({ format: 'der', type: 'spki' });
28
+ const pubKeyBytes = spki.subarray(12, 44);
29
+ return Buffer.concat([seed, pubKeyBytes]).toString('base64');
30
+ }
31
+ const TEST_CDP_API_KEY_SECRET = generateTestApiKeySecret();
32
+ // P-256 PKCS#8 DER (67 bytes)
33
+ const TEST_CDP_WALLET_SECRET = Buffer.from([
34
+ // outer SEQUENCE (65 bytes)
35
+ 0x30, 0x41,
36
+ // version INTEGER 0
37
+ 0x02, 0x01, 0x00,
38
+ // AlgorithmIdentifier SEQUENCE (19 bytes)
39
+ 0x30, 0x13,
40
+ // OID ecPublicKey (1.2.840.10045.2.1)
41
+ 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
42
+ // OID prime256v1 (1.2.840.10045.3.1.7)
43
+ 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
44
+ // privateKey OCTET STRING (39 bytes)
45
+ 0x04, 0x27,
46
+ // ECPrivateKey SEQUENCE (37 bytes)
47
+ 0x30, 0x25,
48
+ // version INTEGER 1
49
+ 0x02, 0x01, 0x01,
50
+ // privateKey OCTET STRING (32 bytes) — scalar 0x01...01 is in [1, n-1] for P-256
51
+ 0x04, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
52
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
53
+ ]).toString('base64');
54
+ // Mock global fetch
55
+ const mockFetch = vi.fn();
56
+ vi.stubGlobal('fetch', mockFetch);
57
+ // Mock wire transaction (same real-structure tx used across keychain tests)
58
+ const MOCK_B64_WIRE_TX = 'Af1fCRSrZ9ASprap8D3ZLPsbzeCs6uihvj/jfjm3UrAY72by5zKMRd7YAIbJCl9gyRHQbw+xdklET2ZNmZi3iA2AAQABAurnRuGN5bfL2osZZMdGlvL1qz8k0GbdLhiP1fICgkmsBUpTWpkpIQZNJOhxYNo4fHw1td28kruB5B+oQEEFRI1NhzEgE0w/YfwaeZi2Ns/mLoZvq2Sx5NVQg7Am7wrjGwEBAAxIZWxsbywgUHJpdnkA';
59
+ vi.mock('@solana/transactions', async () => {
60
+ const actual = await vi.importActual('@solana/transactions');
61
+ return {
62
+ ...actual,
63
+ getBase64EncodedWireTransaction: vi.fn(() => MOCK_B64_WIRE_TX),
64
+ };
65
+ });
66
+ const createMockTransaction = () => {
67
+ return {};
68
+ };
69
+ // A valid base58 Solana address for tests
70
+ const TEST_ADDRESS = '7EcDhSYGxXyscszYEp35KHN8vvw3svAuLKTzXwCFLtV';
71
+ function makeConfig(overrides) {
72
+ return {
73
+ cdpApiKeyId: 'test-api-key-name',
74
+ cdpApiKeySecret: TEST_CDP_API_KEY_SECRET,
75
+ cdpWalletSecret: TEST_CDP_WALLET_SECRET,
76
+ address: TEST_ADDRESS,
77
+ ...overrides,
78
+ };
79
+ }
80
+ describe('CdpSigner', () => {
81
+ beforeEach(() => {
82
+ vi.resetAllMocks();
83
+ });
84
+ describe('create()', () => {
85
+ it('creates a CdpSigner with valid config', async () => {
86
+ const signer = await CdpSigner.create(makeConfig());
87
+ expect(signer.address).toBe(TEST_ADDRESS);
88
+ assertIsSolanaSigner(signer);
89
+ expect(signer.signMessages).toBeDefined();
90
+ expect(signer.signTransactions).toBeDefined();
91
+ expect(signer.isAvailable).toBeDefined();
92
+ });
93
+ it('throws CONFIG_ERROR for missing cdpApiKeyId', async () => {
94
+ await expect(CdpSigner.create(makeConfig({ cdpApiKeyId: '' }))).rejects.toThrow('Missing required cdpApiKeyId field');
95
+ });
96
+ it('throws CONFIG_ERROR for missing cdpApiKeySecret', async () => {
97
+ await expect(CdpSigner.create(makeConfig({ cdpApiKeySecret: '' }))).rejects.toThrow('Missing required cdpApiKeySecret field');
98
+ });
99
+ it('throws CONFIG_ERROR for missing cdpWalletSecret', async () => {
100
+ await expect(CdpSigner.create(makeConfig({ cdpWalletSecret: '' }))).rejects.toThrow('Missing required cdpWalletSecret field');
101
+ });
102
+ it('throws CONFIG_ERROR for missing address', async () => {
103
+ await expect(CdpSigner.create(makeConfig({ address: '' }))).rejects.toThrow('Missing required address field');
104
+ });
105
+ it('throws CONFIG_ERROR for invalid address', async () => {
106
+ await expect(CdpSigner.create(makeConfig({ address: 'not-a-valid-address' }))).rejects.toThrow('Invalid Solana address format');
107
+ });
108
+ it('throws CONFIG_ERROR for negative requestDelayMs', async () => {
109
+ await expect(CdpSigner.create(makeConfig({ requestDelayMs: -1 }))).rejects.toThrow('requestDelayMs must not be negative');
110
+ });
111
+ it('warns for high requestDelayMs', async () => {
112
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
113
+ await CdpSigner.create(makeConfig({ requestDelayMs: 5000 }));
114
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('requestDelayMs is greater than 3000ms'));
115
+ warnSpy.mockRestore();
116
+ });
117
+ it('accepts custom baseUrl', async () => {
118
+ const signer = await CdpSigner.create(makeConfig({ baseUrl: 'https://custom.example.com' }));
119
+ expect(signer).toBeDefined();
120
+ });
121
+ it('throws CONFIG_ERROR when baseUrl is not a valid URL', async () => {
122
+ await expect(CdpSigner.create(makeConfig({ baseUrl: 'not-a-url' }))).rejects.toMatchObject({
123
+ code: 'SIGNER_CONFIG_ERROR',
124
+ message: expect.stringContaining('baseUrl is not a valid URL'),
125
+ });
126
+ });
127
+ it('throws CONFIG_ERROR when baseUrl does not use HTTPS', async () => {
128
+ await expect(CdpSigner.create(makeConfig({ baseUrl: 'http://api.cdp.coinbase.com' }))).rejects.toMatchObject({
129
+ code: 'SIGNER_CONFIG_ERROR',
130
+ message: expect.stringContaining('baseUrl must use HTTPS'),
131
+ });
132
+ });
133
+ it('accepts requestDelayMs of 0', async () => {
134
+ const signer = await CdpSigner.create(makeConfig({ requestDelayMs: 0 }));
135
+ expect(signer).toBeDefined();
136
+ });
137
+ it('throws CONFIG_ERROR when Ed25519 pubkey does not match seed', async () => {
138
+ // 64 bytes where seed and pubkey are mismatched (all 0x42)
139
+ const mismatchedKey = Buffer.alloc(64, 0x42).toString('base64');
140
+ await expect(CdpSigner.create(makeConfig({ cdpApiKeySecret: mismatchedKey }))).rejects.toThrow('Invalid cdpApiKeySecret');
141
+ });
142
+ });
143
+ describe('signMessages', () => {
144
+ it('signs a message and returns a signature dictionary', async () => {
145
+ // Base58-encoded 64-byte signature
146
+ const base58Sig = '5LfnqEfGPFBaHHeQBiNkgQ2EPy4FkVLKE7cjMYc7gv6EjE8Vs5gqaXcZHjpxr3yj5TMt7j3JdJPkXfnwXxXiNAh';
147
+ mockFetch.mockResolvedValue(new Response(JSON.stringify({ signature: base58Sig }), { status: 200 }));
148
+ const signer = await CdpSigner.create(makeConfig());
149
+ const message = { content: new TextEncoder().encode('hello'), signatures: {} };
150
+ const result = await signer.signMessages([message]);
151
+ expect(result).toHaveLength(1);
152
+ expect(result[0]?.[TEST_ADDRESS]).toBeDefined();
153
+ expect(mockFetch).toHaveBeenCalledTimes(1);
154
+ const [url, init] = mockFetch.mock.calls[0];
155
+ expect(url).toContain('/sign/message');
156
+ expect(JSON.parse(init.body)).toMatchObject({ message: 'hello' });
157
+ });
158
+ it('handles multiple messages with requestDelayMs', async () => {
159
+ const base58Sig = '5LfnqEfGPFBaHHeQBiNkgQ2EPy4FkVLKE7cjMYc7gv6EjE8Vs5gqaXcZHjpxr3yj5TMt7j3JdJPkXfnwXxXiNAh';
160
+ // Use mockImplementation so each concurrent call gets a fresh Response (body can only be read once)
161
+ mockFetch.mockImplementation(() => Promise.resolve(new Response(JSON.stringify({ signature: base58Sig }), { status: 200 })));
162
+ const signer = await CdpSigner.create(makeConfig({ requestDelayMs: 10 }));
163
+ const messages = [
164
+ { content: new TextEncoder().encode('one'), signatures: {} },
165
+ { content: new TextEncoder().encode('two'), signatures: {} },
166
+ ];
167
+ const startTime = Date.now();
168
+ const result = await signer.signMessages(messages);
169
+ const elapsed = Date.now() - startTime;
170
+ expect(result).toHaveLength(2);
171
+ expect(elapsed).toBeGreaterThanOrEqual(8); // at least one 10ms delay
172
+ });
173
+ it('throws HTTP_ERROR on network failure', async () => {
174
+ mockFetch.mockRejectedValue(new Error('Network error'));
175
+ const signer = await CdpSigner.create(makeConfig());
176
+ const message = { content: new TextEncoder().encode('hello'), signatures: {} };
177
+ await expect(signer.signMessages([message])).rejects.toThrow('CDP signMessage network request failed');
178
+ });
179
+ it('throws REMOTE_API_ERROR on non-2xx response', async () => {
180
+ mockFetch.mockResolvedValue(new Response('{"error":"Unauthorized"}', { status: 401 }));
181
+ const signer = await CdpSigner.create(makeConfig());
182
+ const message = { content: new TextEncoder().encode('hello'), signatures: {} };
183
+ await expect(signer.signMessages([message])).rejects.toThrow('CDP signMessage API error: 401');
184
+ });
185
+ it('throws SIGNING_FAILED for invalid signature length', async () => {
186
+ // Return a base58 string that decodes to != 64 bytes (small value)
187
+ mockFetch.mockResolvedValue(new Response(JSON.stringify({ signature: '1' }), { status: 200 }));
188
+ const signer = await CdpSigner.create(makeConfig());
189
+ const message = { content: new TextEncoder().encode('hello'), signatures: {} };
190
+ await expect(signer.signMessages([message])).rejects.toThrow('Invalid signature length');
191
+ });
192
+ it('throws SERIALIZATION_ERROR for invalid UTF-8 message', async () => {
193
+ const signer = await CdpSigner.create(makeConfig());
194
+ const message = { content: new Uint8Array([0xff]), signatures: {} };
195
+ await expect(signer.signMessages([message])).rejects.toThrow('CDP signMessage requires a valid UTF-8 message');
196
+ });
197
+ });
198
+ describe('signTransactions', () => {
199
+ it('accepts a key pair address as the signer address', async () => {
200
+ const keyPair = await generateKeyPairSigner();
201
+ const signer = await CdpSigner.create(makeConfig({ address: keyPair.address }));
202
+ expect(signer.address).toBe(keyPair.address);
203
+ });
204
+ it('calls CDP signTransaction with the correct address and wire transaction', async () => {
205
+ mockFetch.mockResolvedValue(new Response(JSON.stringify({ signedTransaction: MOCK_B64_WIRE_TX }), { status: 200 }));
206
+ const signer = await CdpSigner.create(makeConfig());
207
+ const mockTx = createMockTransaction();
208
+ // The CDP call succeeds; extractSignatureFromWireTransaction throws because
209
+ // MOCK_B64_WIRE_TX was not signed by TEST_ADDRESS (integration tests cover success path)
210
+ await expect(signer.signTransactions([mockTx])).rejects.toThrow();
211
+ expect(mockFetch).toHaveBeenCalledTimes(1);
212
+ const [url, init] = mockFetch.mock.calls[0];
213
+ expect(url).toContain('/sign/transaction');
214
+ expect(JSON.parse(init.body)).toMatchObject({ transaction: MOCK_B64_WIRE_TX });
215
+ });
216
+ it('throws HTTP_ERROR on network failure', async () => {
217
+ mockFetch.mockRejectedValue(new Error('Network error'));
218
+ const signer = await CdpSigner.create(makeConfig());
219
+ const mockTx = createMockTransaction();
220
+ await expect(signer.signTransactions([mockTx])).rejects.toThrow('CDP signTransaction network request failed');
221
+ });
222
+ it('throws REMOTE_API_ERROR on non-2xx response', async () => {
223
+ mockFetch.mockResolvedValue(new Response('{"error":"Forbidden"}', { status: 403 }));
224
+ const signer = await CdpSigner.create(makeConfig());
225
+ const mockTx = createMockTransaction();
226
+ await expect(signer.signTransactions([mockTx])).rejects.toThrow('CDP signTransaction API error: 403');
227
+ });
228
+ });
229
+ describe('isAvailable', () => {
230
+ it('returns true when the account is accessible', async () => {
231
+ mockFetch.mockResolvedValue(new Response(JSON.stringify({ address: TEST_ADDRESS }), { status: 200 }));
232
+ const signer = await CdpSigner.create(makeConfig());
233
+ const available = await signer.isAvailable();
234
+ expect(available).toBe(true);
235
+ expect(mockFetch).toHaveBeenCalledTimes(1);
236
+ const [url] = mockFetch.mock.calls[0];
237
+ expect(url).toContain(TEST_ADDRESS);
238
+ });
239
+ it('returns false when the account is not found', async () => {
240
+ mockFetch.mockResolvedValue(new Response('', { status: 404 }));
241
+ const signer = await CdpSigner.create(makeConfig());
242
+ const available = await signer.isAvailable();
243
+ expect(available).toBe(false);
244
+ });
245
+ it('returns false when the CDP API is unreachable', async () => {
246
+ mockFetch.mockRejectedValue(new Error('Network error'));
247
+ const signer = await CdpSigner.create(makeConfig());
248
+ const available = await signer.isAvailable();
249
+ expect(available).toBe(false);
250
+ });
251
+ it('returns false on 401 unauthorized', async () => {
252
+ mockFetch.mockResolvedValue(new Response('', { status: 401 }));
253
+ const signer = await CdpSigner.create(makeConfig());
254
+ const available = await signer.isAvailable();
255
+ expect(available).toBe(false);
256
+ });
257
+ it('returns false when auth header generation fails', async () => {
258
+ const signer = await CdpSigner.create(makeConfig());
259
+ const subtleSignSpy = vi
260
+ .spyOn(globalThis.crypto.subtle, 'sign')
261
+ .mockRejectedValueOnce(new Error('sign failed'));
262
+ const available = await signer.isAvailable();
263
+ expect(available).toBe(false);
264
+ expect(mockFetch).not.toHaveBeenCalled();
265
+ subtleSignSpy.mockRestore();
266
+ });
267
+ });
268
+ });
269
+ //# sourceMappingURL=cdp-signer.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp-signer.test.js","sourceRoot":"","sources":["../../src/__tests__/cdp-signer.test.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,aAAa,CAAC;AAG1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAOxD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9D,EAAE,CAAC,IAAI,CAAC,uBAAuB,EAAE,KAAK,EAAC,cAAc,EAAC,EAAE;IACpD,MAAM,GAAG,GAAG,MAAM,cAAc,EAA0C,CAAC;IAC3E,OAAO;QACH,GAAG,GAAG;QACN,oBAAoB,EAAE,EAAE,CAAC,EAAE,EAAE;QAC7B,2BAA2B,EACvB,GAAG,CAAC,2BAA2B;YAC/B,CAAC,CAAC,IAAY,EAAE,EAAE,CACd,GAAG,IAAI;iBACF,OAAO,CAAC,iDAAiD,EAAE,GAAG,CAAC;iBAC/D,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;iBACpB,IAAI,EAAE;iBACN,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,cAAc,CAAC;KAC5C,CAAC;AACN,CAAC,CAAC,CAAC;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAG7C,iCAAiC;AAEjC,gGAAgG;AAChG,oDAAoD;AACpD,0DAA0D;AAC1D,SAAS,wBAAwB;IAC7B,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,UAAU,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;IAC5E,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAW,CAAC;IAC5E,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,CAAW,CAAC;IACzE,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IAC1C,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,uBAAuB,GAAG,wBAAwB,EAAE,CAAC;AAE3D,8BAA8B;AAC9B,MAAM,sBAAsB,GAAG,MAAM,CAAC,IAAI,CAAC;IACvC,4BAA4B;IAC5B,IAAI,EAAE,IAAI;IACV,oBAAoB;IACpB,IAAI,EAAE,IAAI,EAAE,IAAI;IAChB,0CAA0C;IAC1C,IAAI,EAAE,IAAI;IACV,sCAAsC;IACtC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IACpD,uCAAuC;IACvC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAC1D,qCAAqC;IACrC,IAAI,EAAE,IAAI;IACV,mCAAmC;IACnC,IAAI,EAAE,IAAI;IACV,oBAAoB;IACpB,IAAI,EAAE,IAAI,EAAE,IAAI;IAChB,iFAAiF;IACjF,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAChH,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;CAC3F,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAEtB,oBAAoB;AACpB,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;AAC1B,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;AAElC,4EAA4E;AAC5E,MAAM,gBAAgB,GAClB,sPAAsR,CAAC;AAE3R,EAAE,CAAC,IAAI,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;IACvC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,YAAY,CAAwC,sBAAsB,CAAC,CAAC;IACpG,OAAO;QACH,GAAG,MAAM;QACT,+BAA+B,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC;KACjE,CAAC;AACN,CAAC,CAAC,CAAC;AAEH,MAAM,qBAAqB,GAAG,GAAuE,EAAE;IACnG,OAAO,EAAwE,CAAC;AACpF,CAAC,CAAC;AAEF,0CAA0C;AAC1C,MAAM,YAAY,GAAG,6CAA6C,CAAC;AAEnE,SAAS,UAAU,CAAC,SAAoC;IACpD,OAAO;QACH,WAAW,EAAE,mBAAmB;QAChC,eAAe,EAAE,uBAAuB;QACxC,eAAe,EAAE,sBAAsB;QACvC,OAAO,EAAE,YAAY;QACrB,GAAG,SAAS;KACf,CAAC;AACN,CAAC;AAED,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACvB,UAAU,CAAC,GAAG,EAAE;QACZ,EAAE,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;QACtB,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;YACnD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YAEpD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC1C,oBAAoB,CAAC,MAAM,CAAC,CAAC;YAC7B,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE,CAAC;YAC1C,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,WAAW,EAAE,CAAC;YAC9C,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YACzD,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAC3E,oCAAoC,CACvC,CAAC;QACN,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;YAC7D,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,eAAe,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAC/E,wCAAwC,CAC3C,CAAC;QACN,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;YAC7D,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,eAAe,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAC/E,wCAAwC,CAC3C,CAAC;QACN,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;YACrD,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CACvE,gCAAgC,CACnC,CAAC;QACN,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;YACrD,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAC1F,+BAA+B,CAClC,CAAC;QACN,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;YAC7D,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAC9E,qCAAqC,CACxC,CAAC;QACN,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;YAC3C,MAAM,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACvE,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YAC7D,MAAM,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,MAAM,CAAC,gBAAgB,CAAC,uCAAuC,CAAC,CAAC,CAAC;YACvG,OAAO,CAAC,WAAW,EAAE,CAAC;QAC1B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;YACpC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,4BAA4B,EAAE,CAAC,CAAC,CAAC;YAC7F,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;YACjE,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;gBACvF,IAAI,EAAE,qBAAqB;gBAC3B,OAAO,EAAE,MAAM,CAAC,gBAAgB,CAAC,4BAA4B,CAAC;aACjE,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;YACjE,MAAM,MAAM,CACR,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,6BAA6B,EAAE,CAAC,CAAC,CAC3E,CAAC,OAAO,CAAC,aAAa,CAAC;gBACpB,IAAI,EAAE,qBAAqB;gBAC3B,OAAO,EAAE,MAAM,CAAC,gBAAgB,CAAC,wBAAwB,CAAC;aAC7D,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;YACzC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YACzE,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;YACzE,2DAA2D;YAC3D,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAChE,MAAM,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,eAAe,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAC1F,yBAAyB,CAC5B,CAAC;QACN,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC1B,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;YAChE,mCAAmC;YACnC,MAAM,SAAS,GAAG,yFAAyF,CAAC;YAC5G,SAAS,CAAC,iBAAiB,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;YAErG,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YACpD,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;YAC/E,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;YAEpD,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC/B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,YAAuB,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;YAC3D,MAAM,CAAC,SAAS,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;YAC3C,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAA0B,CAAC;YACrE,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;YACvC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAc,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAChF,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;YAC3D,MAAM,SAAS,GAAG,yFAAyF,CAAC;YAC5G,oGAAoG;YACpG,SAAS,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAC9B,OAAO,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAC3F,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,cAAc,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;YAC1E,MAAM,QAAQ,GAAG;gBACb,EAAE,OAAO,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE;gBAC5D,EAAE,OAAO,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE;aAC/D,CAAC;YAEF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC7B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YACnD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;YAEvC,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC/B,MAAM,CAAC,OAAO,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,0BAA0B;QACzE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;YAClD,SAAS,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;YAExD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YACpD,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;YAE/E,MAAM,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC;QAC3G,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YACzD,SAAS,CAAC,iBAAiB,CAAC,IAAI,QAAQ,CAAC,0BAA0B,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;YAEvF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YACpD,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;YAE/E,MAAM,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,gCAAgC,CAAC,CAAC;QACnG,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;YAChE,mEAAmE;YACnE,SAAS,CAAC,iBAAiB,CACvB,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CACpE,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YACpD,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;YAE/E,MAAM,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC;QAC7F,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;YAClE,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YACpD,MAAM,OAAO,GAAG,EAAE,OAAO,EAAE,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;YAEpE,MAAM,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CACxD,gDAAgD,CACnD,CAAC;QACN,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC9B,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;YAC9D,MAAM,OAAO,GAAG,MAAM,qBAAqB,EAAE,CAAC;YAC9C,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAChF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yEAAyE,EAAE,KAAK,IAAI,EAAE;YACrF,SAAS,CAAC,iBAAiB,CACvB,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CACzF,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YACpD,MAAM,MAAM,GAAG,qBAAqB,EAAE,CAAC;YAEvC,4EAA4E;YAC5E,yFAAyF;YACzF,MAAM,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YAElE,MAAM,CAAC,SAAS,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;YAC3C,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAA0B,CAAC;YACrE,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;YAC3C,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAc,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,WAAW,EAAE,gBAAgB,EAAE,CAAC,CAAC;QAC7F,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;YAClD,SAAS,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;YAExD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YACpD,MAAM,MAAM,GAAG,qBAAqB,EAAE,CAAC;YAEvC,MAAM,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAC3D,4CAA4C,CAC/C,CAAC;QACN,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YACzD,SAAS,CAAC,iBAAiB,CAAC,IAAI,QAAQ,CAAC,uBAAuB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;YAEpF,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YACpD,MAAM,MAAM,GAAG,qBAAqB,EAAE,CAAC;YAEvC,MAAM,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,oCAAoC,CAAC,CAAC;QAC1G,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;QACzB,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YACzD,SAAS,CAAC,iBAAiB,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;YAEtG,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YACpD,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;YAE7C,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7B,MAAM,CAAC,SAAS,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;YAC3C,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAA0B,CAAC;YAC/D,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YACzD,SAAS,CAAC,iBAAiB,CAAC,IAAI,QAAQ,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;YAE/D,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YACpD,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;YAE7C,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;YAC3D,SAAS,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;YAExD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YACpD,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;YAE7C,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;YAC/C,SAAS,CAAC,iBAAiB,CAAC,IAAI,QAAQ,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;YAE/D,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YACpD,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;YAE7C,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;YAC7D,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YACpD,MAAM,aAAa,GAAG,EAAE;iBACnB,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;iBACvC,qBAAqB,CAAC,IAAI,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC;YAErD,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;YAE7C,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC9B,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;YACzC,aAAa,CAAC,WAAW,EAAE,CAAC;QAChC,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { SolanaSigner } from '@solana/keychain-core';
2
+ import type { SignerTestConfig, TestScenario } from '@solana/keychain-test-utils';
3
+ export declare function getConfig(scenarios: TestScenario[]): Promise<SignerTestConfig<SolanaSigner>>;
4
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/__tests__/setup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAmBlF,wBAAsB,SAAS,CAAC,SAAS,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,CAKlG"}
@@ -0,0 +1,20 @@
1
+ import { createCdpSigner } from '../cdp-signer.js';
2
+ const SIGNER_TYPE = 'cdp';
3
+ const REQUIRED_ENV_VARS = ['CDP_API_KEY_ID', 'CDP_API_KEY_SECRET', 'CDP_WALLET_SECRET', 'CDP_SOLANA_ADDRESS'];
4
+ const CONFIG = {
5
+ createSigner: () => createCdpSigner({
6
+ cdpApiKeyId: process.env.CDP_API_KEY_ID,
7
+ cdpApiKeySecret: process.env.CDP_API_KEY_SECRET,
8
+ cdpWalletSecret: process.env.CDP_WALLET_SECRET,
9
+ address: process.env.CDP_SOLANA_ADDRESS,
10
+ }),
11
+ requiredEnvVars: REQUIRED_ENV_VARS,
12
+ signerType: SIGNER_TYPE,
13
+ };
14
+ export async function getConfig(scenarios) {
15
+ return {
16
+ ...CONFIG,
17
+ testScenarios: scenarios,
18
+ };
19
+ }
20
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/__tests__/setup.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,MAAM,WAAW,GAAG,KAAK,CAAC;AAC1B,MAAM,iBAAiB,GAAG,CAAC,gBAAgB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,oBAAoB,CAAC,CAAC;AAE9G,MAAM,MAAM,GAAmC;IAC3C,YAAY,EAAE,GAAG,EAAE,CACf,eAAe,CAAC;QACZ,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,cAAe;QACxC,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAmB;QAChD,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAkB;QAC/C,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAmB;KAC3C,CAAC;IACN,eAAe,EAAE,iBAAiB;IAClC,UAAU,EAAE,WAAW;CAC1B,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,SAAyB;IACrD,OAAO;QACH,GAAG,MAAM;QACT,aAAa,EAAE,SAAS;KAC3B,CAAC;AACN,CAAC"}
@@ -0,0 +1,85 @@
1
+ import { Address } from '@solana/addresses';
2
+ import { SolanaSigner } from '@solana/keychain-core';
3
+ import type { SignableMessage, SignatureDictionary } from '@solana/signers';
4
+ import { type Transaction, type TransactionWithinSizeLimit, type TransactionWithLifetime } from '@solana/transactions';
5
+ import type { CdpSignerConfig } from './types.js';
6
+ /**
7
+ * Create and initialize a CDP-backed signer.
8
+ *
9
+ * @throws {SignerError} `SIGNER_CONFIG_ERROR` when required config is missing or invalid.
10
+ */
11
+ export declare function createCdpSigner<TAddress extends string = string>(config: CdpSignerConfig): Promise<SolanaSigner<TAddress>>;
12
+ /**
13
+ * CDP-based Solana signer using Coinbase Developer Platform's managed key infrastructure.
14
+ *
15
+ * Makes direct HTTP calls to the CDP REST API — no vendor SDK required.
16
+ * Authentication uses two JWTs per signing request:
17
+ * - `Authorization: Bearer <jwt>` — signed with the CDP API private key (Ed25519)
18
+ * - `X-Wallet-Auth: <jwt>` — signed with the wallet secret (always ES256)
19
+ *
20
+ * The CDP account address must be provided at construction time.
21
+ * Use CDP's API or dashboard to create a Solana account first.
22
+ *
23
+ * Use the static `create()` factory to construct an instance — it validates the
24
+ * Ed25519 key pair (seed↔pubkey match) and loads both keys asynchronously.
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const signer = await CdpSigner.create({
29
+ * cdpApiKeyId: process.env.CDP_API_KEY_ID!,
30
+ * cdpApiKeySecret: process.env.CDP_API_KEY_SECRET!,
31
+ * cdpWalletSecret: process.env.CDP_WALLET_SECRET!,
32
+ * address: process.env.CDP_SOLANA_ADDRESS!,
33
+ * });
34
+ * const signed = await signTransactionMessageWithSigners(transactionMessage, [signer]);
35
+ * ```
36
+ *
37
+ * @deprecated Prefer `createCdpSigner()`. Class export will be removed in a future version.
38
+ */
39
+ export declare class CdpSigner<TAddress extends string = string> implements SolanaSigner<TAddress> {
40
+ readonly address: Address<TAddress>;
41
+ private readonly apiKeyId;
42
+ private readonly apiKey;
43
+ private readonly walletKey;
44
+ private readonly apiHost;
45
+ private readonly baseUrl;
46
+ private readonly requestDelayMs;
47
+ private constructor();
48
+ /**
49
+ * Create and initialize a CdpSigner.
50
+ *
51
+ * Validates the Ed25519 API key (seed↔pubkey match via `createKeyPairFromBytes`)
52
+ * and loads the P-256 wallet key. Both keys are loaded in parallel.
53
+ * @deprecated Use `createCdpSigner()` instead.
54
+ */
55
+ static create<TAddress extends string = string>(config: CdpSignerConfig): Promise<CdpSigner<TAddress>>;
56
+ private delay;
57
+ private decodeMessageBytes;
58
+ private buildPostHeaders;
59
+ private buildGetHeaders;
60
+ /**
61
+ * Sign a UTF-8 message string using the CDP API.
62
+ * @returns The 64-byte Ed25519 signature.
63
+ */
64
+ private callSignMessage;
65
+ /**
66
+ * Sign a base64-encoded wire transaction using the CDP API.
67
+ * @returns The fully-signed wire transaction (base64-encoded).
68
+ */
69
+ private callSignTransaction;
70
+ /**
71
+ * Sign multiple messages using the CDP API.
72
+ * Message bytes are decoded as UTF-8 before sending to the CDP signMessage endpoint.
73
+ */
74
+ signMessages(messages: readonly SignableMessage[]): Promise<readonly SignatureDictionary[]>;
75
+ /**
76
+ * Sign multiple transactions using the CDP API.
77
+ * Returns the signature extracted from the fully-signed wire transaction.
78
+ */
79
+ signTransactions(transactions: readonly (Transaction & TransactionWithinSizeLimit & TransactionWithLifetime)[]): Promise<readonly SignatureDictionary[]>;
80
+ /**
81
+ * Check if the CDP API is reachable and this specific account is accessible.
82
+ */
83
+ isAvailable(): Promise<boolean>;
84
+ }
85
+ //# sourceMappingURL=cdp-signer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp-signer.d.ts","sourceRoot":"","sources":["../src/cdp-signer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAmB,MAAM,mBAAmB,CAAC;AAE7D,OAAO,EAOH,YAAY,EAEf,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAGH,KAAK,WAAW,EAChB,KAAK,0BAA0B,EAC/B,KAAK,uBAAuB,EAC/B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,eAAe,EAAgD,MAAM,YAAY,CAAC;AAEhG;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM,EAClE,MAAM,EAAE,eAAe,GACxB,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAEjC;AAkJD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,SAAS,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM,CAAE,YAAW,YAAY,CAAC,QAAQ,CAAC;IACtF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IAExC,OAAO;IAkBP;;;;;;OAMG;WACU,MAAM,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAoE9F,KAAK;IAMnB,OAAO,CAAC,kBAAkB;YAYZ,gBAAgB;YAYhB,eAAe;IAO7B;;;OAGG;YACW,eAAe;IAqD7B;;;OAGG;YACW,mBAAmB;IA6CjC;;;OAGG;IACG,YAAY,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,GAAG,OAAO,CAAC,SAAS,mBAAmB,EAAE,CAAC;IAmBjG;;;OAGG;IACG,gBAAgB,CAClB,YAAY,EAAE,SAAS,CAAC,WAAW,GAAG,0BAA0B,GAAG,uBAAuB,CAAC,EAAE,GAC9F,OAAO,CAAC,SAAS,mBAAmB,EAAE,CAAC;IA2B1C;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;CAaxC"}