@canton-network/core-signing-fireblocks 0.8.1 → 0.10.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/dist/index.cjs +458 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +443 -155
- package/dist/index.js.map +1 -0
- package/package.json +17 -6
- package/dist/fireblocks.js +0 -288
- package/dist/fireblocks.test.d.ts +0 -2
- package/dist/fireblocks.test.d.ts.map +0 -1
- package/dist/fireblocks.test.js +0 -54
- package/dist/index.test.d.ts +0 -3
- package/dist/index.test.d.ts.map +0 -1
- package/dist/index.test.js +0 -190
package/dist/index.test.js
DELETED
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
// Copyright (c) 2025 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
|
2
|
-
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
import { expect, test } from '@jest/globals';
|
|
4
|
-
import FireblocksSigningDriver from './index.js';
|
|
5
|
-
import { readFileSync } from 'fs-extra';
|
|
6
|
-
import path from 'path';
|
|
7
|
-
import { isRpcError, CC_COIN_TYPE, } from '@canton-network/core-signing-lib';
|
|
8
|
-
import { PublicKeyInformationAlgorithmEnum } from '@fireblocks/ts-sdk';
|
|
9
|
-
const TEST_KEY_NAME = 'test-key-name';
|
|
10
|
-
const TEST_TRANSACTION = 'test-tx';
|
|
11
|
-
const TEST_TRANSACTION_HASH = '88beb0783e394f6128699bad42906374ab64197d260db05bb0cfeeb518ba3ac2';
|
|
12
|
-
const TEST_FIREBLOCKS_DERIVATION_PATH = [42, CC_COIN_TYPE, 4, 0, 0];
|
|
13
|
-
const TEST_FIREBLOCKS_VAULT_ID = TEST_FIREBLOCKS_DERIVATION_PATH.join('-');
|
|
14
|
-
const TEST_FIREBLOCKS_PUBLIC_KEY = '02fefbcc9aebc8a479f211167a9f564df53aefd603a8662d9449a98c1ead2eba';
|
|
15
|
-
const FAKE_TRANSACTION = {
|
|
16
|
-
txId: TEST_TRANSACTION_HASH,
|
|
17
|
-
status: 'signed',
|
|
18
|
-
signature: 'test-signature',
|
|
19
|
-
publicKey: TEST_FIREBLOCKS_PUBLIC_KEY,
|
|
20
|
-
derivationPath: TEST_FIREBLOCKS_DERIVATION_PATH,
|
|
21
|
-
};
|
|
22
|
-
const TEST_AUTH_CONTEXT = {
|
|
23
|
-
userId: 'test-user-id',
|
|
24
|
-
accessToken: 'test-access-token',
|
|
25
|
-
};
|
|
26
|
-
const TEST_BAD_AUTH_CONTEXT = {
|
|
27
|
-
userId: 'bad-user-id',
|
|
28
|
-
accessToken: 'test-access-token',
|
|
29
|
-
};
|
|
30
|
-
jest.mock('./fireblocks', () => {
|
|
31
|
-
const actual = jest.requireActual('./fireblocks');
|
|
32
|
-
if (process.env.FIREBLOCKS_API_KEY) {
|
|
33
|
-
return actual;
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
return {
|
|
37
|
-
// NOTE: beware that the mock's constructor is _not_ typesafe, if the constructor's first argument is changed,
|
|
38
|
-
// the test will fail at runtime, not at compile time
|
|
39
|
-
FireblocksHandler: jest
|
|
40
|
-
.fn()
|
|
41
|
-
.mockImplementation((defaultKey) => {
|
|
42
|
-
return {
|
|
43
|
-
constructor: jest.fn(),
|
|
44
|
-
getPublicKeys: jest
|
|
45
|
-
.fn()
|
|
46
|
-
.mockImplementation((userId) => {
|
|
47
|
-
if (userId === TEST_AUTH_CONTEXT.userId ||
|
|
48
|
-
defaultKey !== undefined) {
|
|
49
|
-
return [
|
|
50
|
-
{
|
|
51
|
-
name: TEST_KEY_NAME,
|
|
52
|
-
publicKey: TEST_FIREBLOCKS_PUBLIC_KEY,
|
|
53
|
-
derivationPath: [
|
|
54
|
-
42,
|
|
55
|
-
CC_COIN_TYPE,
|
|
56
|
-
4,
|
|
57
|
-
0,
|
|
58
|
-
0,
|
|
59
|
-
],
|
|
60
|
-
algorithm: PublicKeyInformationAlgorithmEnum.EddsaEd25519,
|
|
61
|
-
},
|
|
62
|
-
];
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
return {
|
|
66
|
-
error: 'User not found',
|
|
67
|
-
error_description: 'User does not exist in Fireblocks',
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
}),
|
|
71
|
-
getTransactions: jest.fn(() => {
|
|
72
|
-
async function* generator() {
|
|
73
|
-
yield FAKE_TRANSACTION;
|
|
74
|
-
}
|
|
75
|
-
return generator();
|
|
76
|
-
}),
|
|
77
|
-
getTransaction: jest
|
|
78
|
-
.fn()
|
|
79
|
-
.mockResolvedValue(FAKE_TRANSACTION),
|
|
80
|
-
signTransaction: jest.fn().mockResolvedValue({
|
|
81
|
-
txId: TEST_TRANSACTION_HASH,
|
|
82
|
-
status: 'signed',
|
|
83
|
-
}),
|
|
84
|
-
};
|
|
85
|
-
}),
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
export function throwWhenRpcError(value) {
|
|
90
|
-
if (isRpcError(value)) {
|
|
91
|
-
throw new Error(`Expected a valid return, but got an error: ${value.error_description}`);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
async function setupTest(keyName = TEST_KEY_NAME) {
|
|
95
|
-
const apiKey = process.env.FIREBLOCKS_API_KEY;
|
|
96
|
-
const secretLocation = process.env.SECRET_KEY_LOCATION || 'fireblocks_secret.key';
|
|
97
|
-
let keyInfo;
|
|
98
|
-
if (!apiKey) {
|
|
99
|
-
keyInfo = {
|
|
100
|
-
apiKey: 'mocked',
|
|
101
|
-
apiSecret: 'mocked',
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
const secretPath = path.resolve(process.cwd(), secretLocation);
|
|
106
|
-
const apiSecret = readFileSync(secretPath, 'utf8');
|
|
107
|
-
keyInfo = {
|
|
108
|
-
apiKey,
|
|
109
|
-
apiSecret,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
const userApiKeys = new Map([
|
|
113
|
-
[TEST_AUTH_CONTEXT.userId, keyInfo],
|
|
114
|
-
]);
|
|
115
|
-
const signingDriver = new FireblocksSigningDriver({
|
|
116
|
-
defaultKeyInfo: keyInfo,
|
|
117
|
-
userApiKeys,
|
|
118
|
-
});
|
|
119
|
-
const noDefaultSigningDriver = new FireblocksSigningDriver({
|
|
120
|
-
defaultKeyInfo: undefined,
|
|
121
|
-
userApiKeys,
|
|
122
|
-
});
|
|
123
|
-
const key = {
|
|
124
|
-
id: TEST_FIREBLOCKS_VAULT_ID,
|
|
125
|
-
name: keyName,
|
|
126
|
-
publicKey: TEST_FIREBLOCKS_PUBLIC_KEY,
|
|
127
|
-
};
|
|
128
|
-
return {
|
|
129
|
-
signingDriver,
|
|
130
|
-
noDefaultSigningDriver,
|
|
131
|
-
key,
|
|
132
|
-
controller: signingDriver.controller(TEST_AUTH_CONTEXT.userId),
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
test('key creation', async () => {
|
|
136
|
-
const { controller } = await setupTest();
|
|
137
|
-
const err = await controller.createKey({ name: 'test' });
|
|
138
|
-
expect(isRpcError(err)).toBe(true);
|
|
139
|
-
});
|
|
140
|
-
test('non-existing user cannot use driver without a default', async () => {
|
|
141
|
-
const { noDefaultSigningDriver } = await setupTest();
|
|
142
|
-
const err = await noDefaultSigningDriver
|
|
143
|
-
.controller(TEST_BAD_AUTH_CONTEXT.userId)
|
|
144
|
-
.getKeys();
|
|
145
|
-
expect(isRpcError(err)).toBe(true);
|
|
146
|
-
});
|
|
147
|
-
test('non-existing user can use driver that does have a default', async () => {
|
|
148
|
-
const { signingDriver } = await setupTest();
|
|
149
|
-
const keys = await signingDriver
|
|
150
|
-
.controller(TEST_BAD_AUTH_CONTEXT.userId)
|
|
151
|
-
.getKeys();
|
|
152
|
-
expect(isRpcError(keys)).toBe(false);
|
|
153
|
-
});
|
|
154
|
-
test('transaction signature', async () => {
|
|
155
|
-
const { controller, key } = await setupTest();
|
|
156
|
-
const tx = await controller.signTransaction({
|
|
157
|
-
tx: TEST_TRANSACTION,
|
|
158
|
-
txHash: TEST_TRANSACTION_HASH,
|
|
159
|
-
publicKey: key.publicKey,
|
|
160
|
-
});
|
|
161
|
-
throwWhenRpcError(tx);
|
|
162
|
-
// this hash has already been signed so Fireblocks won't bother getting it signed again
|
|
163
|
-
expect(tx.status).toBe('signed');
|
|
164
|
-
const transactionsByKey = await controller.getTransactions({
|
|
165
|
-
publicKeys: [key.publicKey],
|
|
166
|
-
});
|
|
167
|
-
throwWhenRpcError(transactionsByKey);
|
|
168
|
-
expect(transactionsByKey.transactions?.find((t) => t.txId === tx.txId)).toBeDefined();
|
|
169
|
-
const transactionsById = await controller.getTransactions({
|
|
170
|
-
txIds: [tx.txId],
|
|
171
|
-
});
|
|
172
|
-
throwWhenRpcError(transactionsById);
|
|
173
|
-
expect(transactionsById.transactions?.find((t) => t.txId === tx.txId)).toBeDefined();
|
|
174
|
-
const foundTx = await controller.getTransaction({
|
|
175
|
-
txId: tx.txId,
|
|
176
|
-
});
|
|
177
|
-
throwWhenRpcError(foundTx);
|
|
178
|
-
}, 60000);
|
|
179
|
-
test('test config change', async () => {
|
|
180
|
-
const { controller } = await setupTest();
|
|
181
|
-
const newPath = 'new-path';
|
|
182
|
-
const config = await controller.getConfiguration();
|
|
183
|
-
controller.setConfiguration({
|
|
184
|
-
defaultKeyInfo: config.defaultKeyInfo,
|
|
185
|
-
userApiKeys: config.userApiKeys,
|
|
186
|
-
apiPath: newPath,
|
|
187
|
-
});
|
|
188
|
-
const newConfig = await controller.getConfiguration();
|
|
189
|
-
expect(newConfig.apiPath).toBe(newPath);
|
|
190
|
-
});
|