@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.
- package/README.md +124 -0
- package/dist/__tests__/fireblocks-signer.integration.test.d.ts +2 -0
- package/dist/__tests__/fireblocks-signer.integration.test.d.ts.map +1 -0
- package/dist/__tests__/fireblocks-signer.integration.test.js +45 -0
- package/dist/__tests__/fireblocks-signer.integration.test.js.map +1 -0
- package/dist/__tests__/fireblocks-signer.test.d.ts +2 -0
- package/dist/__tests__/fireblocks-signer.test.d.ts.map +1 -0
- package/dist/__tests__/fireblocks-signer.test.js +433 -0
- package/dist/__tests__/fireblocks-signer.test.js.map +1 -0
- package/dist/__tests__/setup.d.ts +7 -0
- package/dist/__tests__/setup.d.ts.map +1 -0
- package/dist/__tests__/setup.js +57 -0
- package/dist/__tests__/setup.js.map +1 -0
- package/dist/fireblocks-signer.d.ts +90 -0
- package/dist/fireblocks-signer.d.ts.map +1 -0
- package/dist/fireblocks-signer.js +354 -0
- package/dist/fireblocks-signer.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/jwt.d.ts +11 -0
- package/dist/jwt.d.ts.map +1 -0
- package/dist/jwt.js +53 -0
- package/dist/jwt.js.map +1 -0
- package/dist/types.d.ts +113 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +30 -0
- package/dist/types.js.map +1 -0
- package/package.json +56 -9
- package/src/__tests__/fireblocks-signer.integration.test.ts +75 -0
- package/src/__tests__/fireblocks-signer.test.ts +534 -0
- package/src/__tests__/setup.ts +62 -0
- package/src/fireblocks-signer.ts +431 -0
- package/src/index.ts +9 -0
- package/src/jwt.ts +58 -0
- package/src/types.ts +140 -0
- 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 @@
|
|
|
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 @@
|
|
|
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"}
|