@solana/keychain-fireblocks 0.0.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +124 -0
  2. package/dist/__tests__/fireblocks-signer.integration.test.d.ts +2 -0
  3. package/dist/__tests__/fireblocks-signer.integration.test.d.ts.map +1 -0
  4. package/dist/__tests__/fireblocks-signer.integration.test.js +45 -0
  5. package/dist/__tests__/fireblocks-signer.integration.test.js.map +1 -0
  6. package/dist/__tests__/fireblocks-signer.test.d.ts +2 -0
  7. package/dist/__tests__/fireblocks-signer.test.d.ts.map +1 -0
  8. package/dist/__tests__/fireblocks-signer.test.js +433 -0
  9. package/dist/__tests__/fireblocks-signer.test.js.map +1 -0
  10. package/dist/__tests__/setup.d.ts +7 -0
  11. package/dist/__tests__/setup.d.ts.map +1 -0
  12. package/dist/__tests__/setup.js +57 -0
  13. package/dist/__tests__/setup.js.map +1 -0
  14. package/dist/fireblocks-signer.d.ts +90 -0
  15. package/dist/fireblocks-signer.d.ts.map +1 -0
  16. package/dist/fireblocks-signer.js +354 -0
  17. package/dist/fireblocks-signer.js.map +1 -0
  18. package/dist/index.d.ts +4 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +3 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/jwt.d.ts +11 -0
  23. package/dist/jwt.d.ts.map +1 -0
  24. package/dist/jwt.js +53 -0
  25. package/dist/jwt.js.map +1 -0
  26. package/dist/types.d.ts +113 -0
  27. package/dist/types.d.ts.map +1 -0
  28. package/dist/types.js +30 -0
  29. package/dist/types.js.map +1 -0
  30. package/package.json +56 -9
  31. package/src/__tests__/fireblocks-signer.integration.test.ts +75 -0
  32. package/src/__tests__/fireblocks-signer.test.ts +534 -0
  33. package/src/__tests__/setup.ts +62 -0
  34. package/src/fireblocks-signer.ts +431 -0
  35. package/src/index.ts +9 -0
  36. package/src/jwt.ts +58 -0
  37. package/src/types.ts +140 -0
  38. package/index.js +0 -1
package/README.md ADDED
@@ -0,0 +1,124 @@
1
+ # @solana/keychain-fireblocks
2
+
3
+ Fireblocks-based signer for Solana transactions using Fireblocks' institutional custody API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @solana/keychain-fireblocks
9
+ ```
10
+
11
+ ## Prerequisites
12
+
13
+ 1. A [Fireblocks](https://fireblocks.com) account with API access
14
+ 2. A vault account with Solana (SOL) asset configured
15
+ 3. An API user with signing permissions and RSA 4096 private key
16
+
17
+ Follow the [Fireblocks documentation](https://developers.fireblocks.com/docs/create-direct-custody-wallets) to get started.
18
+
19
+ ## Usage
20
+
21
+ ### Basic Setup
22
+
23
+ ```typescript
24
+ import { FireblocksSigner } from '@solana/keychain-fireblocks';
25
+
26
+ const signer = new FireblocksSigner({
27
+ apiKey: 'your-fireblocks-api-key',
28
+ privateKeyPem: `-----BEGIN PRIVATE KEY-----
29
+ ...your RSA 4096 private key...
30
+ -----END PRIVATE KEY-----`,
31
+ vaultAccountId: '0',
32
+ });
33
+
34
+ // Initialize (fetches public key from Fireblocks)
35
+ await signer.init();
36
+
37
+ console.log('Signer address:', signer.address);
38
+ ```
39
+
40
+ ### Signing Transactions
41
+
42
+ ```typescript
43
+ import { pipe, signTransaction, createTransaction } from '@solana/kit';
44
+
45
+ // Create your transaction
46
+ const transaction = pipe(
47
+ createTransaction({ version: 0 }),
48
+ // ... add instructions
49
+ );
50
+
51
+ // Sign the transaction
52
+ const signedTransaction = await signTransaction([signer], transaction);
53
+ ```
54
+
55
+ ### Signing Messages
56
+
57
+ ```typescript
58
+ import { signMessage } from '@solana/signers';
59
+
60
+ const message = new TextEncoder().encode('Hello, Solana!');
61
+ const signature = await signMessage([signer], message);
62
+ ```
63
+
64
+ ### With Program Call Mode
65
+
66
+ By default, the signer uses RAW signing (signs bytes, you broadcast). Enable `useProgramCall` to have Fireblocks broadcast the transaction:
67
+
68
+ ```typescript
69
+ const signer = new FireblocksSigner({
70
+ apiKey: 'your-fireblocks-api-key',
71
+ privateKeyPem: '...',
72
+ vaultAccountId: '0',
73
+ useProgramCall: true, // Fireblocks signs and broadcasts the transaction to Solana
74
+ });
75
+ ```
76
+
77
+ ### With Devnet
78
+
79
+ ```typescript
80
+ const signer = new FireblocksSigner({
81
+ apiKey: 'your-fireblocks-api-key',
82
+ privateKeyPem: '...',
83
+ vaultAccountId: '0',
84
+ assetId: 'SOL_TEST', // Use devnet asset
85
+ });
86
+ ```
87
+
88
+ ## Configuration
89
+
90
+ ### FireblocksSignerConfig
91
+
92
+ | Field | Type | Required | Default | Description |
93
+ |-------|------|----------|---------|-------------|
94
+ | `apiKey` | `string` | Yes | - | Fireblocks API key (X-API-Key header) |
95
+ | `privateKeyPem` | `string` | Yes | - | RSA 4096 private key in PEM format for JWT signing |
96
+ | `vaultAccountId` | `string` | Yes | - | Fireblocks vault account ID |
97
+ | `apiBaseUrl` | `string` | No | `https://api.fireblocks.io` | Custom API base URL |
98
+ | `assetId` | `string` | No | `SOL` | Asset ID (`SOL` for mainnet, `SOL_TEST` for devnet) |
99
+ | `pollIntervalMs` | `number` | No | `1000` | Polling interval in ms when waiting for transaction completion |
100
+ | `maxPollAttempts` | `number` | No | `60` | Maximum polling attempts before timeout |
101
+ | `requestDelayMs` | `number` | No | `0` | Delay in ms between concurrent signing requests |
102
+ | `useProgramCall` | `boolean` | No | `false` | When true, Fireblocks broadcasts the transaction |
103
+
104
+ ## How It Works
105
+
106
+ 1. **Initialization**: Fetches the vault account's Solana address from Fireblocks API
107
+ 2. **JWT Authentication**: Signs API requests with RS256 JWT using your RSA private key
108
+ 3. **Transaction Creation**: Creates a signing transaction in Fireblocks (RAW or PROGRAM_CALL operation)
109
+ 4. **Signature Extraction**: Extracts the Ed25519 signature from the completed transaction/message
110
+
111
+ ### Signing Modes
112
+
113
+ - **RAW** (default): Signs the message bytes only. You receive the signature and broadcast the transaction yourself.
114
+ - **PROGRAM_CALL**: Fireblocks signs and broadcasts the transaction to Solana. The `txHash` is returned in the response.
115
+
116
+ ## Security Considerations
117
+
118
+ 1. **Private Key Security**: The RSA private key should never be committed to source control. Use environment variables or secure secret management.
119
+ 2. **API Key Rotation**: Rotate API keys periodically according to your security policy.
120
+ 3. **Policy Engine**: Configure Fireblocks Transaction Authorization Policy (TAP) to enforce signing rules.
121
+
122
+ ## License
123
+
124
+ MIT
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=fireblocks-signer.integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fireblocks-signer.integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/fireblocks-signer.integration.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,45 @@
1
+ import { appendTransactionMessageInstructions, createSolanaRpc, createTransactionMessage, pipe, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, signTransactionMessageWithSigners, } from '@solana/kit';
2
+ import { getAddMemoInstruction } from '@solana-program/memo';
3
+ import { config } from 'dotenv';
4
+ import { describe, expect, it } from 'vitest';
5
+ import { FireblocksSigner } from '../fireblocks-signer.js';
6
+ config();
7
+ const REQUIRED_ENV_VARS = ['FIREBLOCKS_API_KEY', 'FIREBLOCKS_PRIVATE_KEY_PEM', 'FIREBLOCKS_VAULT_ACCOUNT_ID'];
8
+ function hasRequiredEnvVars() {
9
+ return REQUIRED_ENV_VARS.every(v => process.env[v]);
10
+ }
11
+ async function createFireblocksSigner() {
12
+ const signer = new FireblocksSigner({
13
+ apiKey: process.env.FIREBLOCKS_API_KEY,
14
+ assetId: process.env.FIREBLOCKS_ASSET_ID ?? 'SOL_TEST',
15
+ privateKeyPem: process.env.FIREBLOCKS_PRIVATE_KEY_PEM,
16
+ useProgramCall: true,
17
+ vaultAccountId: process.env.FIREBLOCKS_VAULT_ACCOUNT_ID,
18
+ });
19
+ await signer.init();
20
+ return signer;
21
+ }
22
+ describe('FireblocksSigner Integration', () => {
23
+ it.skipIf(!hasRequiredEnvVars())('signs transactions with PROGRAM_CALL', async () => {
24
+ const signer = await createFireblocksSigner();
25
+ const rpcUrl = process.env.SOLANA_RPC_URL ?? 'https://api.devnet.solana.com';
26
+ // Get real blockhash from devnet
27
+ const rpc = createSolanaRpc(rpcUrl);
28
+ const { value: { blockhash, lastValidBlockHeight }, } = await rpc.getLatestBlockhash().send();
29
+ // Create memo transaction (doesn't need funds)
30
+ const transaction = pipe(createTransactionMessage({ version: 0 }), tx => setTransactionMessageFeePayerSigner(signer, tx), tx => appendTransactionMessageInstructions([getAddMemoInstruction({ memo: 'Fireblocks test' })], tx), tx => setTransactionMessageLifetimeUsingBlockhash({ blockhash, lastValidBlockHeight }, tx));
31
+ // Sign via Fireblocks (PROGRAM_CALL broadcasts to Solana)
32
+ const signed = await signTransactionMessageWithSigners(transaction);
33
+ // Verify signature returned
34
+ expect(signed.signatures[signer.address]).toBeDefined();
35
+ expect(signed.signatures[signer.address]?.length).toBe(64);
36
+ }, 120000); // 2 minute timeout for PROGRAM_CALL
37
+ // RAW signing not available on Fireblocks testnet/sandbox
38
+ it.skip('signs messages with real API', () => { });
39
+ it.skipIf(!hasRequiredEnvVars())('checks availability', async () => {
40
+ const signer = await createFireblocksSigner();
41
+ const available = await signer.isAvailable();
42
+ expect(available).toBe(true);
43
+ });
44
+ });
45
+ //# sourceMappingURL=fireblocks-signer.integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fireblocks-signer.integration.test.js","sourceRoot":"","sources":["../../src/__tests__/fireblocks-signer.integration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=fireblocks-signer.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fireblocks-signer.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/fireblocks-signer.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,433 @@
1
+ import { generateKeyPairSigner } from '@solana/signers';
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
3
+ import { assertIsSolanaSigner } from '@solana/keychain-core';
4
+ import { FireblocksSigner } from '../fireblocks-signer.js';
5
+ import { TEST_API_KEY, TEST_RSA_PRIVATE_KEY, TEST_VAULT_ACCOUNT_ID } from './setup.js';
6
+ // Mock fetch globally
7
+ global.fetch = vi.fn();
8
+ const mockFetch = global.fetch;
9
+ describe('FireblocksSigner', () => {
10
+ beforeEach(() => {
11
+ vi.resetAllMocks();
12
+ });
13
+ describe('constructor', () => {
14
+ it('creates a FireblocksSigner with valid config', () => {
15
+ const config = {
16
+ apiKey: TEST_API_KEY,
17
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
18
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
19
+ };
20
+ const signer = new FireblocksSigner(config);
21
+ expect(signer).toBeDefined();
22
+ });
23
+ it('should throw error for missing apiKey', () => {
24
+ expect(() => {
25
+ new FireblocksSigner({
26
+ apiKey: '',
27
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
28
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
29
+ });
30
+ }).toThrow('Missing required apiKey field');
31
+ });
32
+ it('should throw error for missing privateKeyPem', () => {
33
+ expect(() => {
34
+ new FireblocksSigner({
35
+ apiKey: TEST_API_KEY,
36
+ privateKeyPem: '',
37
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
38
+ });
39
+ }).toThrow('Missing required privateKeyPem field');
40
+ });
41
+ it('should throw error for missing vaultAccountId', () => {
42
+ expect(() => {
43
+ new FireblocksSigner({
44
+ apiKey: TEST_API_KEY,
45
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
46
+ vaultAccountId: '',
47
+ });
48
+ }).toThrow('Missing required vaultAccountId field');
49
+ });
50
+ it('should validate requestDelayMs', () => {
51
+ expect(() => {
52
+ new FireblocksSigner({
53
+ apiKey: TEST_API_KEY,
54
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
55
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
56
+ requestDelayMs: -1,
57
+ });
58
+ }).toThrow('requestDelayMs must not be negative');
59
+ });
60
+ it('should warn for high requestDelayMs', () => {
61
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
62
+ new FireblocksSigner({
63
+ apiKey: TEST_API_KEY,
64
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
65
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
66
+ requestDelayMs: 5000,
67
+ });
68
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('requestDelayMs is greater than 3000ms'));
69
+ warnSpy.mockRestore();
70
+ });
71
+ it('should use default assetId', () => {
72
+ const signer = new FireblocksSigner({
73
+ apiKey: TEST_API_KEY,
74
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
75
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
76
+ });
77
+ expect(signer).toBeDefined();
78
+ });
79
+ it('should accept custom assetId', () => {
80
+ const signer = new FireblocksSigner({
81
+ apiKey: TEST_API_KEY,
82
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
83
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
84
+ assetId: 'SOL_TEST',
85
+ });
86
+ expect(signer).toBeDefined();
87
+ });
88
+ });
89
+ describe('init', () => {
90
+ it('should initialize signer by fetching public key', async () => {
91
+ const keyPair = await generateKeyPairSigner();
92
+ mockFetch.mockResolvedValueOnce({
93
+ ok: true,
94
+ json: async () => ({ addresses: [{ address: keyPair.address }] }),
95
+ });
96
+ const signer = new FireblocksSigner({
97
+ apiKey: TEST_API_KEY,
98
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
99
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
100
+ });
101
+ await signer.init();
102
+ expect(signer.address).toBe(keyPair.address);
103
+ assertIsSolanaSigner(signer);
104
+ });
105
+ it('should throw error on API failure during init', async () => {
106
+ mockFetch.mockResolvedValueOnce({
107
+ ok: false,
108
+ status: 401,
109
+ text: async () => 'Unauthorized',
110
+ });
111
+ const signer = new FireblocksSigner({
112
+ apiKey: TEST_API_KEY,
113
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
114
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
115
+ });
116
+ await expect(signer.init()).rejects.toThrow('Fireblocks API error: 401');
117
+ });
118
+ it('should throw error on invalid address from API', async () => {
119
+ mockFetch.mockResolvedValueOnce({
120
+ ok: true,
121
+ json: async () => ({ addresses: [{ address: 'invalid-address' }] }),
122
+ });
123
+ const signer = new FireblocksSigner({
124
+ apiKey: TEST_API_KEY,
125
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
126
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
127
+ });
128
+ await expect(signer.init()).rejects.toThrow('Invalid address from Fireblocks');
129
+ });
130
+ it('should not re-initialize if already initialized', async () => {
131
+ const keyPair = await generateKeyPairSigner();
132
+ mockFetch.mockResolvedValueOnce({
133
+ ok: true,
134
+ json: async () => ({ addresses: [{ address: keyPair.address }] }),
135
+ });
136
+ const signer = new FireblocksSigner({
137
+ apiKey: TEST_API_KEY,
138
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
139
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
140
+ });
141
+ await signer.init();
142
+ await signer.init(); // Second call should be a no-op
143
+ expect(mockFetch).toHaveBeenCalledTimes(1);
144
+ });
145
+ });
146
+ describe('address', () => {
147
+ it('should throw error if not initialized', () => {
148
+ const signer = new FireblocksSigner({
149
+ apiKey: TEST_API_KEY,
150
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
151
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
152
+ });
153
+ expect(() => signer.address).toThrow('Signer not initialized');
154
+ });
155
+ });
156
+ describe('signMessages', () => {
157
+ it('should throw error if not initialized', async () => {
158
+ const signer = new FireblocksSigner({
159
+ apiKey: TEST_API_KEY,
160
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
161
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
162
+ });
163
+ const message = {
164
+ content: new Uint8Array([1, 2, 3, 4]),
165
+ signatures: {},
166
+ };
167
+ await expect(signer.signMessages([message])).rejects.toThrow('Signer not initialized');
168
+ });
169
+ it('should sign a message successfully', async () => {
170
+ const keyPair = await generateKeyPairSigner();
171
+ // Mock init fetch
172
+ mockFetch.mockResolvedValueOnce({
173
+ ok: true,
174
+ json: async () => ({ addresses: [{ address: keyPair.address }] }),
175
+ });
176
+ // Mock create transaction
177
+ mockFetch.mockResolvedValueOnce({
178
+ ok: true,
179
+ json: async () => ({ id: 'tx-123', status: 'SUBMITTED' }),
180
+ });
181
+ // Mock poll for completion
182
+ mockFetch.mockResolvedValueOnce({
183
+ ok: true,
184
+ json: async () => ({
185
+ id: 'tx-123',
186
+ status: 'COMPLETED',
187
+ signedMessages: [
188
+ {
189
+ signature: {
190
+ fullSig: '42'.repeat(64), // 64 bytes as hex
191
+ },
192
+ },
193
+ ],
194
+ }),
195
+ });
196
+ const signer = new FireblocksSigner({
197
+ apiKey: TEST_API_KEY,
198
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
199
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
200
+ });
201
+ await signer.init();
202
+ const message = {
203
+ content: new Uint8Array([1, 2, 3, 4]),
204
+ signatures: {},
205
+ };
206
+ const result = await signer.signMessages([message]);
207
+ expect(result).toHaveLength(1);
208
+ expect(result[0]?.[signer.address]).toBeDefined();
209
+ });
210
+ it('should throw error on transaction failure', async () => {
211
+ const keyPair = await generateKeyPairSigner();
212
+ // Mock init fetch
213
+ mockFetch.mockResolvedValueOnce({
214
+ ok: true,
215
+ json: async () => ({ addresses: [{ address: keyPair.address }] }),
216
+ });
217
+ // Mock create transaction
218
+ mockFetch.mockResolvedValueOnce({
219
+ ok: true,
220
+ json: async () => ({ id: 'tx-123', status: 'SUBMITTED' }),
221
+ });
222
+ // Mock poll returning FAILED status
223
+ mockFetch.mockResolvedValueOnce({
224
+ ok: true,
225
+ json: async () => ({
226
+ id: 'tx-123',
227
+ status: 'FAILED',
228
+ }),
229
+ });
230
+ const signer = new FireblocksSigner({
231
+ apiKey: TEST_API_KEY,
232
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
233
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
234
+ });
235
+ await signer.init();
236
+ const message = {
237
+ content: new Uint8Array([1, 2, 3, 4]),
238
+ signatures: {},
239
+ };
240
+ await expect(signer.signMessages([message])).rejects.toThrow('Transaction failed with status: FAILED');
241
+ });
242
+ it('should throw error on invalid signature length', async () => {
243
+ const keyPair = await generateKeyPairSigner();
244
+ // Mock init fetch
245
+ mockFetch.mockResolvedValueOnce({
246
+ ok: true,
247
+ json: async () => ({ addresses: [{ address: keyPair.address }] }),
248
+ });
249
+ // Mock create transaction
250
+ mockFetch.mockResolvedValueOnce({
251
+ ok: true,
252
+ json: async () => ({ id: 'tx-123', status: 'SUBMITTED' }),
253
+ });
254
+ // Mock poll with wrong signature length
255
+ mockFetch.mockResolvedValueOnce({
256
+ ok: true,
257
+ json: async () => ({
258
+ id: 'tx-123',
259
+ status: 'COMPLETED',
260
+ signedMessages: [
261
+ {
262
+ signature: {
263
+ fullSig: '42'.repeat(32), // 32 bytes instead of 64
264
+ },
265
+ },
266
+ ],
267
+ }),
268
+ });
269
+ const signer = new FireblocksSigner({
270
+ apiKey: TEST_API_KEY,
271
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
272
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
273
+ });
274
+ await signer.init();
275
+ const message = {
276
+ content: new Uint8Array([1, 2, 3, 4]),
277
+ signatures: {},
278
+ };
279
+ await expect(signer.signMessages([message])).rejects.toThrow('Invalid signature length');
280
+ });
281
+ });
282
+ describe('signTransactions', () => {
283
+ it('should sign a transaction successfully with RAW signing', async () => {
284
+ const keyPair = await generateKeyPairSigner();
285
+ // Mock init fetch
286
+ mockFetch.mockResolvedValueOnce({
287
+ ok: true,
288
+ json: async () => ({ addresses: [{ address: keyPair.address }] }),
289
+ });
290
+ // Mock create transaction
291
+ mockFetch.mockResolvedValueOnce({
292
+ ok: true,
293
+ json: async () => ({ id: 'tx-123', status: 'SUBMITTED' }),
294
+ });
295
+ // Mock poll for completion
296
+ mockFetch.mockResolvedValueOnce({
297
+ ok: true,
298
+ json: async () => ({
299
+ id: 'tx-123',
300
+ status: 'COMPLETED',
301
+ signedMessages: [
302
+ {
303
+ signature: {
304
+ fullSig: '42'.repeat(64),
305
+ },
306
+ },
307
+ ],
308
+ }),
309
+ });
310
+ const signer = new FireblocksSigner({
311
+ apiKey: TEST_API_KEY,
312
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
313
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
314
+ });
315
+ await signer.init();
316
+ const transaction = {
317
+ messageBytes: new Uint8Array([1, 2, 3, 4]),
318
+ signatures: {},
319
+ };
320
+ const result = await signer.signTransactions([transaction]);
321
+ expect(result).toHaveLength(1);
322
+ expect(result[0]).toHaveProperty(signer.address);
323
+ });
324
+ it('should extract signature from txHash (base58) when signedMessages is absent', async () => {
325
+ const keyPair = await generateKeyPairSigner();
326
+ // Mock init fetch
327
+ mockFetch.mockResolvedValueOnce({
328
+ ok: true,
329
+ json: async () => ({ addresses: [{ address: keyPair.address }] }),
330
+ });
331
+ // Mock create transaction
332
+ mockFetch.mockResolvedValueOnce({
333
+ ok: true,
334
+ json: async () => ({ id: 'tx-123', status: 'SUBMITTED' }),
335
+ });
336
+ // Mock poll for completion - return txHash (base58 encoded 64 bytes) instead of signedMessages
337
+ // This tests the txHash extraction path in pollForSignature
338
+ mockFetch.mockResolvedValueOnce({
339
+ ok: true,
340
+ json: async () => ({
341
+ id: 'tx-123',
342
+ status: 'COMPLETED',
343
+ txHash: '5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW',
344
+ }),
345
+ });
346
+ const signer = new FireblocksSigner({
347
+ apiKey: TEST_API_KEY,
348
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
349
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
350
+ });
351
+ await signer.init();
352
+ const transaction = {
353
+ messageBytes: new Uint8Array([1, 2, 3, 4]),
354
+ signatures: {},
355
+ };
356
+ const result = await signer.signTransactions([transaction]);
357
+ expect(result).toHaveLength(1);
358
+ expect(result[0]).toHaveProperty(signer.address);
359
+ });
360
+ it('should throw error when txHash decodes to invalid length', async () => {
361
+ const keyPair = await generateKeyPairSigner();
362
+ // Mock init fetch
363
+ mockFetch.mockResolvedValueOnce({
364
+ ok: true,
365
+ json: async () => ({ addresses: [{ address: keyPair.address }] }),
366
+ });
367
+ // Mock create transaction
368
+ mockFetch.mockResolvedValueOnce({
369
+ ok: true,
370
+ json: async () => ({ id: 'tx-123', status: 'SUBMITTED' }),
371
+ });
372
+ // Mock poll for completion - return a short base58 string (not 64 bytes)
373
+ mockFetch.mockResolvedValueOnce({
374
+ ok: true,
375
+ json: async () => ({
376
+ id: 'tx-123',
377
+ status: 'COMPLETED',
378
+ txHash: '2abc', // Very short, will decode to fewer than 64 bytes
379
+ }),
380
+ });
381
+ const signer = new FireblocksSigner({
382
+ apiKey: TEST_API_KEY,
383
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
384
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
385
+ });
386
+ await signer.init();
387
+ const transaction = {
388
+ messageBytes: new Uint8Array([1, 2, 3, 4]),
389
+ signatures: {},
390
+ };
391
+ await expect(signer.signTransactions([transaction])).rejects.toThrow('Invalid txHash length');
392
+ });
393
+ });
394
+ describe('isAvailable', () => {
395
+ it('should return true when API is accessible', async () => {
396
+ mockFetch.mockResolvedValueOnce({
397
+ ok: true,
398
+ json: async () => ({ id: TEST_VAULT_ACCOUNT_ID }),
399
+ });
400
+ const signer = new FireblocksSigner({
401
+ apiKey: TEST_API_KEY,
402
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
403
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
404
+ });
405
+ const available = await signer.isAvailable();
406
+ expect(available).toBe(true);
407
+ });
408
+ it('should return false when API returns error', async () => {
409
+ mockFetch.mockResolvedValueOnce({
410
+ ok: false,
411
+ status: 401,
412
+ });
413
+ const signer = new FireblocksSigner({
414
+ apiKey: TEST_API_KEY,
415
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
416
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
417
+ });
418
+ const available = await signer.isAvailable();
419
+ expect(available).toBe(false);
420
+ });
421
+ it('should return false when fetch throws', async () => {
422
+ mockFetch.mockRejectedValueOnce(new Error('Network error'));
423
+ const signer = new FireblocksSigner({
424
+ apiKey: TEST_API_KEY,
425
+ privateKeyPem: TEST_RSA_PRIVATE_KEY,
426
+ vaultAccountId: TEST_VAULT_ACCOUNT_ID,
427
+ });
428
+ const available = await signer.isAvailable();
429
+ expect(available).toBe(false);
430
+ });
431
+ });
432
+ });
433
+ //# sourceMappingURL=fireblocks-signer.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fireblocks-signer.test.js","sourceRoot":"","sources":["../../src/__tests__/fireblocks-signer.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { SignerTestConfig, TestScenario } from '@solana/keychain-test-utils';
2
+ import { FireblocksSigner } from '../fireblocks-signer';
3
+ export declare function getConfig(scenarios: TestScenario[]): Promise<SignerTestConfig<FireblocksSigner>>;
4
+ export declare const TEST_API_KEY = "test-api-key";
5
+ export declare const TEST_VAULT_ACCOUNT_ID = "0";
6
+ export declare const TEST_RSA_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDKKw7fHhfK3/Ts\nrAqsNCrDsjmyBTHx/AUCOTM+tZph2ZOyDSH9nZO4JkzLrW6Vfk7EZvlP3QjLiXEG\nm9qQgAh9sXgp07GicWU5omSILTMdd18yR6aIXVw/YzgjD7EVLRQU6YHc3BYgR8P8\nPBbJcxzYrrUDSGEXX2b44cZO72RxIPM+yeY3ZXiztgFQSpfEIKX488/k/PgUHMHK\n/04VoL/jiQa5dOs44CmHHT6MbBT1Sb/VR0G1hHtfMSIQCtdvzt+VBZhg7sxm50h/\ncT+n0UVOBwEp2IY2x4lzlwOdptZl7P3D1+A2rAbalXg5WO+LVEjx5ym++XbCGyvU\nrlH+ILOPAgMBAAECggEAXio3F5J/N4YgITqzD+mOf69cc0A7NsCRnqsA5PUWbvw2\ncIjwa55BZ1UjkPz7lJML4iwqdNn51j/yzsa6Q3L3QYBvfV/2jbiuku1CUTFobRGk\nXBmGhl6h8H5o79/HthrUjzcCP1qdzbRPo4Vjgbpl1cFuW5STcJ0Fq+gRg8O6b3w7\nA2843mcF9EA9ZFjXpn+VtpzLe4nHVRZFYXvXSlfdYc6WQbThnLLiLQYsVMqhYQAU\nI4c9hfgasfgZ6iCV5hMK2ZPX45+/OVQzjh4+I8zlvNWp2cKNoEhMHU2G/In11yBF\nwHGRuvbwx9Wc4Okqq+GvfTO0jCAinAQQu8C+eIcNcQKBgQDo9dzw2cNsJmaUvaL5\nI7gEtbPdr+CTgVjGoVUIlGeI0OBHt1DJEwczS2tycScE9SUDLdmegYA8ubHsAs/6\nPFEJ+779h9/IDzL3Fe9Zp1fiQgWOKF1uCS7+b8QwFMhh2u0OLWmI1rdFmqX2KCPf\nAfD/Pvp6bgapXTN1EoB3LQ/4PwKBgQDeKZeJMk9CZzWFe+m5x2yzJBK62ZvKzyjZ\nY3IeK75V0xG+Y7ZAb0zTXPkgBpBiQOqdFRgt6bp/S/6Tq/OXfeV9xVURSz4zRtCR\nlRoONL8ZSl0h4VptEjXrYfBnH2j4gtjhnTATJZBp0rYrExbz0jVbQtRzPLs+k3+p\nTuZA8+XwsQKBgCocn8buJpR7UJncugQ9f7tiOVR+waMIg8rMSTnW0ex6jcCJE9J1\nXRzZql+ysrIDuqAbfrZXhJ31l4Mpcv0yQBgE6R6dnEdm7/iYf37+cDWXZ7et9k24\n3UTjYVyrtRlzYNzqOqSg49pyPUQFN47NpAoQEWlmUE/3aCDmqlBg1f0zAoGAamv+\nHUiuUx7hspnTMp1nYsEq/7ryOErYRJqwtec6fB5p54wYZ/FpGe71n/PFAmwadzj9\npjDKl+QthUvfmnhCkOcQgwJKP4Hys2p7WsbFrDXFO0+aY5lPnvwBj0SqojD798e2\nmdVqwmafwS6Z1h6iVJ9E6hbzk1xQ0SfsgLzVL2ECgYBN6fJ99og4fkp4iA5C31TB\nUKlH64yqwxFu4vuVMqBOpGPkdsLNGhE/vpdP7yYxC/MP+v8ow/sCa40Ely20Yqqa\nznT9Ik5JV4eRXyRG9iwllKvcrmczFDIuxFmXPff4G9nmyB9fLQfSM0gD+yDR05Hx\np6B5CCtpBPgD01Vm+bT/JQ==\n-----END PRIVATE KEY-----";
7
+ //# 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,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAwBxD,wBAAsB,SAAS,CAAC,SAAS,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,CAAC,CAKtG;AAED,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAC3C,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,eAAO,MAAM,oBAAoB,usDA2BP,CAAC"}